1
0
mirror of https://github.com/jaandrle/deka-dom-el synced 2024-11-21 23:39:37 +01:00

docs mainly signals

This commit is contained in:
Jan Andrle 2023-11-23 18:36:26 +01:00
parent 0d5033780d
commit 6a293d75a6
Signed by: jaandrle
GPG Key ID: B3A25AED155AFFAB
11 changed files with 154 additions and 101 deletions

View File

@ -1,4 +1,4 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Introducing a&nbsp;library."><title>`deka-dom-el` — Introduction</title><!--<dde:mark type="component" name="metaAuthor" host="this" ssr/>--><meta name="author" content="Jan Andrle"><link type="text/plain" rel="author" href="https://jaandrle.github.io/humans.txt"><meta name="generator" content="deka-dom-el"><!--<dde:mark type="component" name="metaTwitter" host="this" ssr/>--><meta name="twitter:card" content="summary_large_image"><meta name="twitter:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="twitter:title" content="deka-dom-el"><meta name="twitter:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="twitter:creator" content="@jaandrle"><!--<dde:mark type="component" name="metaFacebook" host="this" ssr/>--><meta name="og:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="og:title" content="deka-dom-el"><meta name="og:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="og:creator" content="@jaandrle"><script src="https://flems.io/flems.html" type="text/javascript" charset="utf-8"></script><link rel="stylesheet" href="global.css"></head><body><!--<dde:mark type="component" name="page" host="this" ssr/>--><!--<dde:mark type="component" name="header" host="this" ssr/>--><header><h1>`deka-dom-el` — Introduction</h1><p>Introducing a&nbsp;library.</p></header><nav><a href="https://github.com/jaandrle/deka-dom-el"><svg class="icon" viewBox="0 0 32 32"><!--<dde:mark type="component" name="iconGitHub" host="parentElement" ssr/>--><path d="M 16,0.395c -8.836,0 -16,7.163 -16,16c 0,7.069 4.585,13.067 10.942,15.182c 0.8,0.148 1.094,-0.347 1.094,-0.77c 0,-0.381 -0.015,-1.642 -0.022,-2.979c -4.452,0.968 -5.391,-1.888 -5.391,-1.888c -0.728,-1.849 -1.776,-2.341 -1.776,-2.341c -1.452,-0.993 0.11,-0.973 0.11,-0.973c 1.606,0.113 2.452,1.649 2.452,1.649c 1.427,2.446 3.743,1.739 4.656,1.33c 0.143,-1.034 0.558,-1.74 1.016,-2.14c -3.554,-0.404 -7.29,-1.777 -7.29,-7.907c 0,-1.747 0.625,-3.174 1.649,-4.295c -0.166,-0.403 -0.714,-2.03 0.155,-4.234c 0,0 1.344,-0.43 4.401,1.64c 1.276,-0.355 2.645,-0.532 4.005,-0.539c 1.359,0.006 2.729,0.184 4.008,0.539c 3.054,-2.07 4.395,-1.64 4.395,-1.64c 0.871,2.204 0.323,3.831 0.157,4.234c 1.026,1.12 1.647,2.548 1.647,4.295c 0,6.145 -3.743,7.498 -7.306,7.895c 0.574,0.497 1.085,1.47 1.085,2.963c 0,2.141 -0.019,3.864 -0.019,4.391c 0,0.426 0.288,0.925 1.099,0.768c 6.354,-2.118 10.933,-8.113 10.933,-15.18c 0,-8.837 -7.164,-16 -16,-16Z"></path></svg>GitHub</a><a href="./" title="Introducing a&nbsp;library." class="current">1. Introduction</a><a href="p02-elements" title="Basic concepts of elements modifications and creations.">2. Elements</a><a href="p03-events" title="Using not only events in UI declaratively.">3. Events and Addons</a></nav><main><p>The library tries to provide pure JavaScript tool(s) to create reactive interfaces.</p><p>We start with creating and modifying a&nbsp;static elements and end up with UI templates. <i>From <code>document.createElement</code> to <code>el</code>.</i> Then we go through the native events system and the way to include it declaratively in UI templates. <i>From <code>element.addEventListener</code> to <code>on</code>.</i></p><p>Next step is providing interactivity not only for our UI templates. We introduce signals (<code>S</code>) and how them incorporate to UI templates.</p><p>Now we will clarify how the signals are incorporated into our templates with regard to application performance. This is not the only reason the library uses <code>scope</code>s. We will look at how they work in components represented in JavaScript by functions.</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-exquzbx4inc" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { el } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Introducing a&nbsp;library."><title>`deka-dom-el` — Introduction</title><!--<dde:mark type="component" name="metaAuthor" host="this" ssr/>--><meta name="author" content="Jan Andrle"><link type="text/plain" rel="author" href="https://jaandrle.github.io/humans.txt"><meta name="generator" content="deka-dom-el"><!--<dde:mark type="component" name="metaTwitter" host="this" ssr/>--><meta name="twitter:card" content="summary_large_image"><meta name="twitter:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="twitter:title" content="deka-dom-el"><meta name="twitter:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="twitter:creator" content="@jaandrle"><!--<dde:mark type="component" name="metaFacebook" host="this" ssr/>--><meta name="og:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="og:title" content="deka-dom-el"><meta name="og:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="og:creator" content="@jaandrle"><script src="https://flems.io/flems.html" type="text/javascript" charset="utf-8"></script><link rel="stylesheet" href="global.css"></head><body><!--<dde:mark type="component" name="page" host="this" ssr/>--><!--<dde:mark type="component" name="header" host="this" ssr/>--><header><h1>`deka-dom-el` — Introduction</h1><p>Introducing a&nbsp;library.</p></header><nav><a href="https://github.com/jaandrle/deka-dom-el"><svg class="icon" viewBox="0 0 32 32"><!--<dde:mark type="component" name="iconGitHub" host="parentElement" ssr/>--><path d="M 16,0.395c -8.836,0 -16,7.163 -16,16c 0,7.069 4.585,13.067 10.942,15.182c 0.8,0.148 1.094,-0.347 1.094,-0.77c 0,-0.381 -0.015,-1.642 -0.022,-2.979c -4.452,0.968 -5.391,-1.888 -5.391,-1.888c -0.728,-1.849 -1.776,-2.341 -1.776,-2.341c -1.452,-0.993 0.11,-0.973 0.11,-0.973c 1.606,0.113 2.452,1.649 2.452,1.649c 1.427,2.446 3.743,1.739 4.656,1.33c 0.143,-1.034 0.558,-1.74 1.016,-2.14c -3.554,-0.404 -7.29,-1.777 -7.29,-7.907c 0,-1.747 0.625,-3.174 1.649,-4.295c -0.166,-0.403 -0.714,-2.03 0.155,-4.234c 0,0 1.344,-0.43 4.401,1.64c 1.276,-0.355 2.645,-0.532 4.005,-0.539c 1.359,0.006 2.729,0.184 4.008,0.539c 3.054,-2.07 4.395,-1.64 4.395,-1.64c 0.871,2.204 0.323,3.831 0.157,4.234c 1.026,1.12 1.647,2.548 1.647,4.295c 0,6.145 -3.743,7.498 -7.306,7.895c 0.574,0.497 1.085,1.47 1.085,2.963c 0,2.141 -0.019,3.864 -0.019,4.391c 0,0.426 0.288,0.925 1.099,0.768c 6.354,-2.118 10.933,-8.113 10.933,-15.18c 0,-8.837 -7.164,-16 -16,-16Z"></path></svg>GitHub</a><a href="./" title="Introducing a&nbsp;library." class="current">1. Introduction</a><a href="p02-elements" title="Basic concepts of elements modifications and creations.">2. Elements</a><a href="p03-events" title="Using not only events in UI declaratively.">3. Events and Addons</a><a href="p04-signals" title="Handling reactivity in UI via signals.">4. Signals and reactivity</a></nav><main><p>The library tries to provide pure JavaScript tool(s) to create reactive interfaces.</p><p>We start with creating and modifying a&nbsp;static elements and end up with UI templates. <i>From <code>document.createElement</code> to <code>el</code>.</i> Then we go through the native events system and the way to include it declaratively in UI templates. <i>From <code>element.addEventListener</code> to <code>on</code>.</i></p><p>Next step is providing interactivity not only for our UI templates. We introduce signals (<code>S</code>) and how them incorporate to UI templates.</p><p>Now we will clarify how the signals are incorporated into our templates with regard to application performance. This is not the only reason the library uses <code>scope</code>s. We will look at how they work in components represented in JavaScript by functions.</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-exquzbx4inc" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { el } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js";
import { S } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; import { S } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js";
const clicks= S(0); const clicks= S(0);
document.body.append( document.body.append(

View File

@ -1,4 +1,4 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Basic concepts of elements modifications and creations."><title>`deka-dom-el` — Elements</title><!--<dde:mark type="component" name="metaAuthor" host="this" ssr/>--><meta name="author" content="Jan Andrle"><link type="text/plain" rel="author" href="https://jaandrle.github.io/humans.txt"><meta name="generator" content="deka-dom-el"><!--<dde:mark type="component" name="metaTwitter" host="this" ssr/>--><meta name="twitter:card" content="summary_large_image"><meta name="twitter:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="twitter:title" content="deka-dom-el"><meta name="twitter:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="twitter:creator" content="@jaandrle"><!--<dde:mark type="component" name="metaFacebook" host="this" ssr/>--><meta name="og:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="og:title" content="deka-dom-el"><meta name="og:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="og:creator" content="@jaandrle"><script src="https://flems.io/flems.html" type="text/javascript" charset="utf-8"></script><link rel="stylesheet" href="global.css"></head><body><!--<dde:mark type="component" name="page" host="this" ssr/>--><!--<dde:mark type="component" name="header" host="this" ssr/>--><header><h1>`deka-dom-el` — Elements</h1><p>Basic concepts of elements modifications and creations.</p></header><nav><a href="https://github.com/jaandrle/deka-dom-el"><svg class="icon" viewBox="0 0 32 32"><!--<dde:mark type="component" name="iconGitHub" host="parentElement" ssr/>--><path d="M 16,0.395c -8.836,0 -16,7.163 -16,16c 0,7.069 4.585,13.067 10.942,15.182c 0.8,0.148 1.094,-0.347 1.094,-0.77c 0,-0.381 -0.015,-1.642 -0.022,-2.979c -4.452,0.968 -5.391,-1.888 -5.391,-1.888c -0.728,-1.849 -1.776,-2.341 -1.776,-2.341c -1.452,-0.993 0.11,-0.973 0.11,-0.973c 1.606,0.113 2.452,1.649 2.452,1.649c 1.427,2.446 3.743,1.739 4.656,1.33c 0.143,-1.034 0.558,-1.74 1.016,-2.14c -3.554,-0.404 -7.29,-1.777 -7.29,-7.907c 0,-1.747 0.625,-3.174 1.649,-4.295c -0.166,-0.403 -0.714,-2.03 0.155,-4.234c 0,0 1.344,-0.43 4.401,1.64c 1.276,-0.355 2.645,-0.532 4.005,-0.539c 1.359,0.006 2.729,0.184 4.008,0.539c 3.054,-2.07 4.395,-1.64 4.395,-1.64c 0.871,2.204 0.323,3.831 0.157,4.234c 1.026,1.12 1.647,2.548 1.647,4.295c 0,6.145 -3.743,7.498 -7.306,7.895c 0.574,0.497 1.085,1.47 1.085,2.963c 0,2.141 -0.019,3.864 -0.019,4.391c 0,0.426 0.288,0.925 1.099,0.768c 6.354,-2.118 10.933,-8.113 10.933,-15.18c 0,-8.837 -7.164,-16 -16,-16Z"></path></svg>GitHub</a><a href="./" title="Introducing a&nbsp;library.">1. Introduction</a><a href="p02-elements" title="Basic concepts of elements modifications and creations." class="current">2. Elements</a><a href="p03-events" title="Using not only events in UI declaratively.">3. Events and Addons</a></nav><main><h2>Native JavaScript DOM elements creations</h2><p>Lets go through all patterns we would like to use and what needs to be improved for better experience.</p><h3 id="h-creating-elements-with-custom-attributes"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-creating-elements-with-custom-attributes" tabindex="-1">§</a> Creating element(s) (with custom attributes)</h3><p>You can create a native DOM element by using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement" title="MDN documentation for document.createElement()"><code>document.createElement()</code></a>. It is also possible to provide a&nbsp;some attribute(s) declaratively using <code>Object.assign()</code>. More precisely, this way you can sets some <a href="https://developer.mozilla.org/en-US/docs/Glossary/IDL" title="MDN page about Interface Description Language"><abbr title="Interface Description Language">IDL</abbr></a> also known as a JavaScript property.</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-nkz9lcdhykg" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">document.body.append( <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Basic concepts of elements modifications and creations."><title>`deka-dom-el` — Elements</title><!--<dde:mark type="component" name="metaAuthor" host="this" ssr/>--><meta name="author" content="Jan Andrle"><link type="text/plain" rel="author" href="https://jaandrle.github.io/humans.txt"><meta name="generator" content="deka-dom-el"><!--<dde:mark type="component" name="metaTwitter" host="this" ssr/>--><meta name="twitter:card" content="summary_large_image"><meta name="twitter:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="twitter:title" content="deka-dom-el"><meta name="twitter:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="twitter:creator" content="@jaandrle"><!--<dde:mark type="component" name="metaFacebook" host="this" ssr/>--><meta name="og:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="og:title" content="deka-dom-el"><meta name="og:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="og:creator" content="@jaandrle"><script src="https://flems.io/flems.html" type="text/javascript" charset="utf-8"></script><link rel="stylesheet" href="global.css"></head><body><!--<dde:mark type="component" name="page" host="this" ssr/>--><!--<dde:mark type="component" name="header" host="this" ssr/>--><header><h1>`deka-dom-el` — Elements</h1><p>Basic concepts of elements modifications and creations.</p></header><nav><a href="https://github.com/jaandrle/deka-dom-el"><svg class="icon" viewBox="0 0 32 32"><!--<dde:mark type="component" name="iconGitHub" host="parentElement" ssr/>--><path d="M 16,0.395c -8.836,0 -16,7.163 -16,16c 0,7.069 4.585,13.067 10.942,15.182c 0.8,0.148 1.094,-0.347 1.094,-0.77c 0,-0.381 -0.015,-1.642 -0.022,-2.979c -4.452,0.968 -5.391,-1.888 -5.391,-1.888c -0.728,-1.849 -1.776,-2.341 -1.776,-2.341c -1.452,-0.993 0.11,-0.973 0.11,-0.973c 1.606,0.113 2.452,1.649 2.452,1.649c 1.427,2.446 3.743,1.739 4.656,1.33c 0.143,-1.034 0.558,-1.74 1.016,-2.14c -3.554,-0.404 -7.29,-1.777 -7.29,-7.907c 0,-1.747 0.625,-3.174 1.649,-4.295c -0.166,-0.403 -0.714,-2.03 0.155,-4.234c 0,0 1.344,-0.43 4.401,1.64c 1.276,-0.355 2.645,-0.532 4.005,-0.539c 1.359,0.006 2.729,0.184 4.008,0.539c 3.054,-2.07 4.395,-1.64 4.395,-1.64c 0.871,2.204 0.323,3.831 0.157,4.234c 1.026,1.12 1.647,2.548 1.647,4.295c 0,6.145 -3.743,7.498 -7.306,7.895c 0.574,0.497 1.085,1.47 1.085,2.963c 0,2.141 -0.019,3.864 -0.019,4.391c 0,0.426 0.288,0.925 1.099,0.768c 6.354,-2.118 10.933,-8.113 10.933,-15.18c 0,-8.837 -7.164,-16 -16,-16Z"></path></svg>GitHub</a><a href="./" title="Introducing a&nbsp;library.">1. Introduction</a><a href="p02-elements" title="Basic concepts of elements modifications and creations." class="current">2. Elements</a><a href="p03-events" title="Using not only events in UI declaratively.">3. Events and Addons</a><a href="p04-signals" title="Handling reactivity in UI via signals.">4. Signals and reactivity</a></nav><main><h2>Native JavaScript DOM elements creations</h2><p>Lets go through all patterns we would like to use and what needs to be improved for better experience.</p><h3 id="h-creating-elements-with-custom-attributes"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-creating-elements-with-custom-attributes" tabindex="-1">#</a> Creating element(s) (with custom attributes)</h3><p>You can create a native DOM element by using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement" title="MDN documentation for document.createElement()"><code>document.createElement()</code></a>. It is also possible to provide a&nbsp;some attribute(s) declaratively using <code>Object.assign()</code>. More precisely, this way you can sets some <a href="https://developer.mozilla.org/en-US/docs/Glossary/IDL" title="MDN page about Interface Description Language"><abbr title="Interface Description Language">IDL</abbr></a> also known as a JavaScript property.</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-nkz9lcdhykg" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">document.body.append(
document.createElement("div") document.createElement("div")
); );
console.log( console.log(
@ -56,7 +56,7 @@ console.log("paragraph.something=", paragraph.something);
document.body.append( document.body.append(
paragraph paragraph
); );
</code></div><script>Flems(document.getElementById("code-example-1-iro9ncxa4bc"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { assign, assignAttribute, classListDeclarative } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\nconst paragraph= document.createElement(\\\"p\\\");\\n\\nassignAttribute(paragraph, \\\"textContent\\\", \\\"Hello, world!\\\");\\n\\nassignAttribute(paragraph, \\\"style\\\", \\\"color: red; font-weight: bold;\\\");\\nassignAttribute(paragraph, \\\"style\\\", { color: \\\"navy\\\" });\\n\\nassignAttribute(paragraph, \\\"dataTest1\\\", \\\"v1\\\");\\nassignAttribute(paragraph, \\\"dataset\\\", { test2: \\\"v2\\\" });\\n\\nassign(paragraph, { //textContent and style see above\\n\\tariaLabel: \\\"v1\\\", //data* see above\\n\\tariaset: { role: \\\"none\\\" }, // dataset see above\\n\\t\\\"=onclick\\\": \\\"console.log(event)\\\",\\n\\tonmouseout: console.info,\\n\\t\\\".something\\\": \\\"something\\\",\\n\\tclassList: {} //see below\\n});\\n\\nclassListDeclarative(paragraph, {\\n\\tclassAdd: true,\\n\\tclassRemove: false,\\n\\tclassAdd1: 1,\\n\\tclassRemove1: 0,\\n\\tclassToggle: -1\\n});\\n\\nconsole.log(paragraph.outerHTML);\\nconsole.log(\\\"paragraph.something=\\\", paragraph.something);\\ndocument.body.append(\\n\\tparagraph\\n);\\n\"}],\"toolbar\":false}"));</script><h3 id="h-native-javascript-templating"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-native-javascript-templating" tabindex="-1">§</a> Native JavaScript templating</h3><p>By default, the native JS has no good way to define HTML template using DOM API:</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-b6a1hbrxh7s" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">document.body.append( </code></div><script>Flems(document.getElementById("code-example-1-iro9ncxa4bc"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { assign, assignAttribute, classListDeclarative } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\nconst paragraph= document.createElement(\\\"p\\\");\\n\\nassignAttribute(paragraph, \\\"textContent\\\", \\\"Hello, world!\\\");\\n\\nassignAttribute(paragraph, \\\"style\\\", \\\"color: red; font-weight: bold;\\\");\\nassignAttribute(paragraph, \\\"style\\\", { color: \\\"navy\\\" });\\n\\nassignAttribute(paragraph, \\\"dataTest1\\\", \\\"v1\\\");\\nassignAttribute(paragraph, \\\"dataset\\\", { test2: \\\"v2\\\" });\\n\\nassign(paragraph, { //textContent and style see above\\n\\tariaLabel: \\\"v1\\\", //data* see above\\n\\tariaset: { role: \\\"none\\\" }, // dataset see above\\n\\t\\\"=onclick\\\": \\\"console.log(event)\\\",\\n\\tonmouseout: console.info,\\n\\t\\\".something\\\": \\\"something\\\",\\n\\tclassList: {} //see below\\n});\\n\\nclassListDeclarative(paragraph, {\\n\\tclassAdd: true,\\n\\tclassRemove: false,\\n\\tclassAdd1: 1,\\n\\tclassRemove1: 0,\\n\\tclassToggle: -1\\n});\\n\\nconsole.log(paragraph.outerHTML);\\nconsole.log(\\\"paragraph.something=\\\", paragraph.something);\\ndocument.body.append(\\n\\tparagraph\\n);\\n\"}],\"toolbar\":false}"));</script><h3 id="h-native-javascript-templating"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-native-javascript-templating" tabindex="-1">#</a> Native JavaScript templating</h3><p>By default, the native JS has no good way to define HTML template using DOM API:</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-b6a1hbrxh7s" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">document.body.append(
document.createElement("div"), document.createElement("div"),
document.createElement("span"), document.createElement("span"),
document.createElement("main") document.createElement("main")
@ -102,7 +102,7 @@ document.body.append(
) )
) )
); );
</code></div><script>Flems(document.getElementById("code-example-2-iro9ncxa4bc"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\ndocument.head.append(\\n\\tel(\\\"style\\\").append(\\n\\t\\t\\\"tr, td{ border: 1px solid red; padding: 1em; }\\\",\\n\\t\\t\\\"table{ border-collapse: collapse; }\\\"\\n\\t)\\n);\\ndocument.body.append(\\n\\tel(\\\"p\\\", \\\"Example of a complex template. Using for example nesting lists:\\\"),\\n\\tel(\\\"ul\\\").append(\\n\\t\\tel(\\\"li\\\", \\\"List item 1\\\"),\\n\\t\\tel(\\\"li\\\").append(\\n\\t\\t\\tel(\\\"ul\\\").append(\\n\\t\\t\\t\\tel(\\\"li\\\", \\\"Nested list item 1\\\"),\\n\\t\\t\\t)\\n\\t\\t)\\n\\t),\\n\\tel(\\\"table\\\").append(\\n\\t\\tel(\\\"tr\\\").append(\\n\\t\\t\\tel(\\\"td\\\", \\\"Row 1 Col 1\\\"),\\n\\t\\t\\tel(\\\"td\\\", \\\"Row 1 Col 2\\\")\\n\\t\\t)\\n\\t)\\n);\\n\\nimport { chainableAppend } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\n/** @param {keyof HTMLElementTagNameMap} tag */\\nconst createElement= tag=> chainableAppend(document.createElement(tag));\\ndocument.body.append(\\n\\tcreateElement(\\\"p\\\").append(\\n\\t\\tcreateElement(\\\"em\\\").append(\\n\\t\\t\\t\\\"You can also use `chainableAppend`!\\\"\\n\\t\\t)\\n\\t)\\n);\\n\"}],\"toolbar\":false}"));</script><h3 id="h-basic-state-less-components"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-basic-state-less-components" tabindex="-1">§</a> Basic (state-less) components</h3><p>You can use functions for encapsulation (repeating) logic. The <code>el</code> accepts function as first argument. In that case, the function should return dom elements and the second argument for <code>el</code> is argument for given element.</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-320zz4y072o" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { el } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; </code></div><script>Flems(document.getElementById("code-example-2-iro9ncxa4bc"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\ndocument.head.append(\\n\\tel(\\\"style\\\").append(\\n\\t\\t\\\"tr, td{ border: 1px solid red; padding: 1em; }\\\",\\n\\t\\t\\\"table{ border-collapse: collapse; }\\\"\\n\\t)\\n);\\ndocument.body.append(\\n\\tel(\\\"p\\\", \\\"Example of a complex template. Using for example nesting lists:\\\"),\\n\\tel(\\\"ul\\\").append(\\n\\t\\tel(\\\"li\\\", \\\"List item 1\\\"),\\n\\t\\tel(\\\"li\\\").append(\\n\\t\\t\\tel(\\\"ul\\\").append(\\n\\t\\t\\t\\tel(\\\"li\\\", \\\"Nested list item 1\\\"),\\n\\t\\t\\t)\\n\\t\\t)\\n\\t),\\n\\tel(\\\"table\\\").append(\\n\\t\\tel(\\\"tr\\\").append(\\n\\t\\t\\tel(\\\"td\\\", \\\"Row 1 Col 1\\\"),\\n\\t\\t\\tel(\\\"td\\\", \\\"Row 1 Col 2\\\")\\n\\t\\t)\\n\\t)\\n);\\n\\nimport { chainableAppend } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\n/** @param {keyof HTMLElementTagNameMap} tag */\\nconst createElement= tag=> chainableAppend(document.createElement(tag));\\ndocument.body.append(\\n\\tcreateElement(\\\"p\\\").append(\\n\\t\\tcreateElement(\\\"em\\\").append(\\n\\t\\t\\t\\\"You can also use `chainableAppend`!\\\"\\n\\t\\t)\\n\\t)\\n);\\n\"}],\"toolbar\":false}"));</script><h3 id="h-basic-state-less-components"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-basic-state-less-components" tabindex="-1">#</a> Basic (state-less) components</h3><p>You can use functions for encapsulation (repeating) logic. The <code>el</code> accepts function as first argument. In that case, the function should return dom elements and the second argument for <code>el</code> is argument for given element.</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-320zz4y072o" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { el } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js";
document.head.append( document.head.append(
el("style").append( el("style").append(
".class1{ font-weight: bold; }", ".class1{ font-weight: bold; }",
@ -119,7 +119,7 @@ function component({ className, textContent }){
el("p", textContent) el("p", textContent)
); );
} }
</code></div><script>Flems(document.getElementById("code-example-1-320zz4y072o"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\ndocument.head.append(\\n\\tel(\\\"style\\\").append(\\n\\t\\t\\\".class1{ font-weight: bold; }\\\",\\n\\t\\t\\\".class2{ color: purple; }\\\"\\n\\t)\\n);\\ndocument.body.append(\\n\\tel(component, { className: \\\"class2\\\", textContent: \\\"Hello World!\\\" }),\\n\\tcomponent({ className: \\\"class2\\\", textContent: \\\"Hello World!\\\" })\\n);\\n\\nfunction component({ className, textContent }){\\n\\treturn el(\\\"div\\\", { className: [ \\\"class1\\\", className ] }).append(\\n\\t\\tel(\\\"p\\\", textContent)\\n\\t);\\n}\\n\"}],\"toolbar\":false}"));</script><p>As you can see, in case of state-less/basic components there is no difference between calling component function directly or using <code>el</code> function.</p><p class="notice">It is nice to use similar naming convention as native DOM API. This allows us to use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment" title="Destructuring assignment | MDN">the destructuring assignment syntax</a> and keep track of the native API (things are best remembered through regular use).</p><h3 id="h-creating-non-html-elements"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-creating-non-html-elements" tabindex="-1">§</a> Creating non-HTML elements</h3><p>Similarly to the native DOM API (<a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS" title="MDN"><code>document.createElementNS</code></a>) for non-HTML elements we need to tell JavaScript which kind of the element to create. We can use the <code>elNS</code> function:</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-bcjydb50gdc" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { elNS, assign } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; </code></div><script>Flems(document.getElementById("code-example-1-320zz4y072o"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\ndocument.head.append(\\n\\tel(\\\"style\\\").append(\\n\\t\\t\\\".class1{ font-weight: bold; }\\\",\\n\\t\\t\\\".class2{ color: purple; }\\\"\\n\\t)\\n);\\ndocument.body.append(\\n\\tel(component, { className: \\\"class2\\\", textContent: \\\"Hello World!\\\" }),\\n\\tcomponent({ className: \\\"class2\\\", textContent: \\\"Hello World!\\\" })\\n);\\n\\nfunction component({ className, textContent }){\\n\\treturn el(\\\"div\\\", { className: [ \\\"class1\\\", className ] }).append(\\n\\t\\tel(\\\"p\\\", textContent)\\n\\t);\\n}\\n\"}],\"toolbar\":false}"));</script><p>As you can see, in case of state-less/basic components there is no difference between calling component function directly or using <code>el</code> function.</p><p class="notice">It is nice to use similar naming convention as native DOM API. This allows us to use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment" title="Destructuring assignment | MDN">the destructuring assignment syntax</a> and keep track of the native API (things are best remembered through regular use).</p><h3 id="h-creating-non-html-elements"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-creating-non-html-elements" tabindex="-1">#</a> Creating non-HTML elements</h3><p>Similarly to the native DOM API (<a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS" title="MDN"><code>document.createElementNS</code></a>) for non-HTML elements we need to tell JavaScript which kind of the element to create. We can use the <code>elNS</code> function:</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-bcjydb50gdc" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { elNS, assign } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js";
const elSVG= elNS("http://www.w3.org/2000/svg"); const elSVG= elNS("http://www.w3.org/2000/svg");
const elMath= elNS("http://www.w3.org/1998/Math/MathML"); const elMath= elNS("http://www.w3.org/1998/Math/MathML");
document.body.append( document.body.append(
@ -130,4 +130,4 @@ document.body.append(
console.log( console.log(
document.body.innerHTML.includes("&lt;svg&gt;&lt;/svg&gt;&lt;math&gt;&lt;/math&gt;") document.body.innerHTML.includes("&lt;svg&gt;&lt;/svg&gt;&lt;math&gt;&lt;/math&gt;")
) )
</code></div><script>Flems(document.getElementById("code-example-1-bcjydb50gdc"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { elNS, assign } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\nconst elSVG= elNS(\\\"http://www.w3.org/2000/svg\\\");\\nconst elMath= elNS(\\\"http://www.w3.org/1998/Math/MathML\\\");\\ndocument.body.append(\\n\\telSVG(\\\"svg\\\"), // see https://developer.mozilla.org/en-US/docs/Web/SVG and https://developer.mozilla.org/en-US/docs/Web/API/SVGElement\\n\\telMath(\\\"math\\\") // see https://developer.mozilla.org/en-US/docs/Web/MathML and https://developer.mozilla.org/en-US/docs/Web/MathML/Global_attributes\\n);\\n\\nconsole.log(\\n\\tdocument.body.innerHTML.includes(\\\"<svg></svg><math></math>\\\")\\n)\\n\"}],\"toolbar\":false}"));</script><div class="prevNext"><!--<dde:mark type="component" name="prevNext" host="parentElement" ssr/>--><a rel="prev" href="./" title="Introducing a&nbsp;library."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->Introduction (previous)</a><a rel="next" href="p03-events" title="Using not only events in UI declaratively."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->(next) Events and Addons</a></div></main></body></html> </code></div><script>Flems(document.getElementById("code-example-1-bcjydb50gdc"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { elNS, assign } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\nconst elSVG= elNS(\\\"http://www.w3.org/2000/svg\\\");\\nconst elMath= elNS(\\\"http://www.w3.org/1998/Math/MathML\\\");\\ndocument.body.append(\\n\\telSVG(\\\"svg\\\"), // see https://developer.mozilla.org/en-US/docs/Web/SVG and https://developer.mozilla.org/en-US/docs/Web/API/SVGElement\\n\\telMath(\\\"math\\\") // see https://developer.mozilla.org/en-US/docs/Web/MathML and https://developer.mozilla.org/en-US/docs/Web/MathML/Global_attributes\\n);\\n\\nconsole.log(\\n\\tdocument.body.innerHTML.includes(\\\"<svg></svg><math></math>\\\")\\n)\\n\"}],\"toolbar\":false}"));</script><div class="notice"><p>Mnemonic</p><ul><li><code>assign(&lt;element&gt;, ...&lt;idl-objects&gt;): &lt;element&gt;</code> — assign properties to the element</li><li><code>el(&lt;tag-name&gt;, &lt;primitive&gt;)[.append(...)]: &lt;element-from-tag-name&gt;</code> — simple element containing only text</li><li><code>el(&lt;tag-name&gt;, &lt;idl-object&gt;)[.append(...)]: &lt;element-from-tag-name&gt;</code> — element with more properties</li><li><code>el(&lt;function&gt;, &lt;function-argument(s)&gt;)[.append(...)]: &lt;element-returned-by-function&gt;</code> — using component represented by function</li><li><code>el(&lt;...&gt;, &lt;...&gt;, ...&lt;addons&gt;)</code> — see following page</li><li><code>elNS(&lt;namespace&gt;)(&lt;as-el-see-above&gt;)[.append(...)]: &lt;element-based-on-arguments&gt;</code> — typically SVG elements</li></ul></div><div class="prevNext"><!--<dde:mark type="component" name="prevNext" host="parentElement" ssr/>--><a rel="prev" href="./" title="Introducing a&nbsp;library."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->Introduction (previous)</a><a rel="next" href="p03-events" title="Using not only events in UI declaratively."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->(next) Events and Addons</a></div></main></body></html>

View File

@ -1,4 +1,4 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Using not only events in UI declaratively."><title>`deka-dom-el` — Events and Addons</title><!--<dde:mark type="component" name="metaAuthor" host="this" ssr/>--><meta name="author" content="Jan Andrle"><link type="text/plain" rel="author" href="https://jaandrle.github.io/humans.txt"><meta name="generator" content="deka-dom-el"><!--<dde:mark type="component" name="metaTwitter" host="this" ssr/>--><meta name="twitter:card" content="summary_large_image"><meta name="twitter:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="twitter:title" content="deka-dom-el"><meta name="twitter:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="twitter:creator" content="@jaandrle"><!--<dde:mark type="component" name="metaFacebook" host="this" ssr/>--><meta name="og:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="og:title" content="deka-dom-el"><meta name="og:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="og:creator" content="@jaandrle"><script src="https://flems.io/flems.html" type="text/javascript" charset="utf-8"></script><link rel="stylesheet" href="global.css"></head><body><!--<dde:mark type="component" name="page" host="this" ssr/>--><!--<dde:mark type="component" name="header" host="this" ssr/>--><header><h1>`deka-dom-el` — Events and Addons</h1><p>Using not only events in UI declaratively.</p></header><nav><a href="https://github.com/jaandrle/deka-dom-el"><svg class="icon" viewBox="0 0 32 32"><!--<dde:mark type="component" name="iconGitHub" host="parentElement" ssr/>--><path d="M 16,0.395c -8.836,0 -16,7.163 -16,16c 0,7.069 4.585,13.067 10.942,15.182c 0.8,0.148 1.094,-0.347 1.094,-0.77c 0,-0.381 -0.015,-1.642 -0.022,-2.979c -4.452,0.968 -5.391,-1.888 -5.391,-1.888c -0.728,-1.849 -1.776,-2.341 -1.776,-2.341c -1.452,-0.993 0.11,-0.973 0.11,-0.973c 1.606,0.113 2.452,1.649 2.452,1.649c 1.427,2.446 3.743,1.739 4.656,1.33c 0.143,-1.034 0.558,-1.74 1.016,-2.14c -3.554,-0.404 -7.29,-1.777 -7.29,-7.907c 0,-1.747 0.625,-3.174 1.649,-4.295c -0.166,-0.403 -0.714,-2.03 0.155,-4.234c 0,0 1.344,-0.43 4.401,1.64c 1.276,-0.355 2.645,-0.532 4.005,-0.539c 1.359,0.006 2.729,0.184 4.008,0.539c 3.054,-2.07 4.395,-1.64 4.395,-1.64c 0.871,2.204 0.323,3.831 0.157,4.234c 1.026,1.12 1.647,2.548 1.647,4.295c 0,6.145 -3.743,7.498 -7.306,7.895c 0.574,0.497 1.085,1.47 1.085,2.963c 0,2.141 -0.019,3.864 -0.019,4.391c 0,0.426 0.288,0.925 1.099,0.768c 6.354,-2.118 10.933,-8.113 10.933,-15.18c 0,-8.837 -7.164,-16 -16,-16Z"></path></svg>GitHub</a><a href="./" title="Introducing a&nbsp;library.">1. Introduction</a><a href="p02-elements" title="Basic concepts of elements modifications and creations.">2. Elements</a><a href="p03-events" title="Using not only events in UI declaratively." class="current">3. Events and Addons</a></nav><main><h2>Listenning to the native DOM events and other Addons</h2><p>We quickly introduce helper to listening to the native DOM events. And library syntax/pattern so-called <em>Addon</em> to incorporate not only this in UI templates declaratively.</p><h3 id="h-events-and-listenners"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-events-and-listenners" tabindex="-1">§</a> Events and listenners</h3><p>In JavaScript you can listen to the native DOM events of the given element by using <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener" title="addEventListener on MDN"><code>element.addEventListener(type, listener, options)</code></a>. The library provides an alternative (<code>on</code>) accepting the differen order of the arguments:</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-1wmddlo83w68" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Using not only events in UI declaratively."><title>`deka-dom-el` — Events and Addons</title><!--<dde:mark type="component" name="metaAuthor" host="this" ssr/>--><meta name="author" content="Jan Andrle"><link type="text/plain" rel="author" href="https://jaandrle.github.io/humans.txt"><meta name="generator" content="deka-dom-el"><!--<dde:mark type="component" name="metaTwitter" host="this" ssr/>--><meta name="twitter:card" content="summary_large_image"><meta name="twitter:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="twitter:title" content="deka-dom-el"><meta name="twitter:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="twitter:creator" content="@jaandrle"><!--<dde:mark type="component" name="metaFacebook" host="this" ssr/>--><meta name="og:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="og:title" content="deka-dom-el"><meta name="og:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="og:creator" content="@jaandrle"><script src="https://flems.io/flems.html" type="text/javascript" charset="utf-8"></script><link rel="stylesheet" href="global.css"></head><body><!--<dde:mark type="component" name="page" host="this" ssr/>--><!--<dde:mark type="component" name="header" host="this" ssr/>--><header><h1>`deka-dom-el` — Events and Addons</h1><p>Using not only events in UI declaratively.</p></header><nav><a href="https://github.com/jaandrle/deka-dom-el"><svg class="icon" viewBox="0 0 32 32"><!--<dde:mark type="component" name="iconGitHub" host="parentElement" ssr/>--><path d="M 16,0.395c -8.836,0 -16,7.163 -16,16c 0,7.069 4.585,13.067 10.942,15.182c 0.8,0.148 1.094,-0.347 1.094,-0.77c 0,-0.381 -0.015,-1.642 -0.022,-2.979c -4.452,0.968 -5.391,-1.888 -5.391,-1.888c -0.728,-1.849 -1.776,-2.341 -1.776,-2.341c -1.452,-0.993 0.11,-0.973 0.11,-0.973c 1.606,0.113 2.452,1.649 2.452,1.649c 1.427,2.446 3.743,1.739 4.656,1.33c 0.143,-1.034 0.558,-1.74 1.016,-2.14c -3.554,-0.404 -7.29,-1.777 -7.29,-7.907c 0,-1.747 0.625,-3.174 1.649,-4.295c -0.166,-0.403 -0.714,-2.03 0.155,-4.234c 0,0 1.344,-0.43 4.401,1.64c 1.276,-0.355 2.645,-0.532 4.005,-0.539c 1.359,0.006 2.729,0.184 4.008,0.539c 3.054,-2.07 4.395,-1.64 4.395,-1.64c 0.871,2.204 0.323,3.831 0.157,4.234c 1.026,1.12 1.647,2.548 1.647,4.295c 0,6.145 -3.743,7.498 -7.306,7.895c 0.574,0.497 1.085,1.47 1.085,2.963c 0,2.141 -0.019,3.864 -0.019,4.391c 0,0.426 0.288,0.925 1.099,0.768c 6.354,-2.118 10.933,-8.113 10.933,-15.18c 0,-8.837 -7.164,-16 -16,-16Z"></path></svg>GitHub</a><a href="./" title="Introducing a&nbsp;library.">1. Introduction</a><a href="p02-elements" title="Basic concepts of elements modifications and creations.">2. Elements</a><a href="p03-events" title="Using not only events in UI declaratively." class="current">3. Events and Addons</a><a href="p04-signals" title="Handling reactivity in UI via signals.">4. Signals and reactivity</a></nav><main><h2>Listenning to the native DOM events and other Addons</h2><p>We quickly introduce helper to listening to the native DOM events. And library syntax/pattern so-called <em>Addon</em> to incorporate not only this in UI templates declaratively.</p><h3 id="h-events-and-listenners"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-events-and-listenners" tabindex="-1">#</a> Events and listenners</h3><p>In JavaScript you can listen to the native DOM events of the given element by using <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener" title="addEventListener on MDN"><code>element.addEventListener(type, listener, options)</code></a>. The library provides an alternative (<code>on</code>) accepting the differen order of the arguments:</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-1wmddlo83w68" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js";
const log= mark=&gt; console.log.bind(console, mark); const log= mark=&gt; console.log.bind(console, mark);
const button= el("button", "Test click"); const button= el("button", "Test click");
@ -21,7 +21,7 @@ on("click", log("`on`"), { signal })(button);
document.body.append( document.body.append(
button, " ", el("button", { textContent: "Off", onclick: ()=&gt; abort_controller.abort() }) button, " ", el("button", { textContent: "Off", onclick: ()=&gt; abort_controller.abort() })
); );
</code></div><script>Flems(document.getElementById("code-example-1-8r8qappf8mo"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el, on } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\nconst log= mark=> console.log.bind(console, mark);\\n\\nconst abort_controller= new AbortController();\\nconst { signal }= abort_controller;\\n\\nconst button= el(\\\"button\\\", \\\"Test click\\\");\\nbutton.addEventListener(\\\"click\\\", log(\\\"`addEventListener`\\\"), { signal });\\non(\\\"click\\\", log(\\\"`on`\\\"), { signal })(button);\\n\\ndocument.body.append(\\n\\tbutton, \\\" \\\", el(\\\"button\\\", { textContent: \\\"Off\\\", onclick: ()=> abort_controller.abort() })\\n);\\n\"}],\"toolbar\":false}"));</script><div class="notice"><p>So, there are (typically) three ways to handle events. You can use:</p><ul><li><code>el("button", { textContent: "click me", "=onclick": "console.log(event)" })</code></li><li><code>el("button", { textContent: "click me", onclick: console.log })</code></li><li><code>el("button", { textContent: "click me" }, on("click", console.log))</code></li></ul><p>In the first example we force to use HTML attribute (it corresponds to <code>&lt;button onclick="console.log(event)"&gt;click me&lt;/button&gt;</code>). <em>Side note: this can be useful in case of SSR.</em> To study difference, you can read a nice summary here: <a href="https://gist.github.com/WebReflection/b404c36f46371e3b1173bf5492acc944">GIST @WebReflection/web_events.md</a>.</p></div><h3 id="h-addons"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-addons" tabindex="-1">§</a> Addons</h3><p>From practical point of view, <em>Addons</em> are just functions that accept any html element as their first parameter. You can see that the <code>on(…)</code> fullfills this requirement.</p><p>You can use Addons as ≥3rd argument of <code>el</code> function. This way is possible to extends you templates by additional (3rd party) functionalities. But for now mainly, you can add events listeners:</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-6jtsnxfqzm4" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; </code></div><script>Flems(document.getElementById("code-example-1-8r8qappf8mo"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el, on } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\nconst log= mark=> console.log.bind(console, mark);\\n\\nconst abort_controller= new AbortController();\\nconst { signal }= abort_controller;\\n\\nconst button= el(\\\"button\\\", \\\"Test click\\\");\\nbutton.addEventListener(\\\"click\\\", log(\\\"`addEventListener`\\\"), { signal });\\non(\\\"click\\\", log(\\\"`on`\\\"), { signal })(button);\\n\\ndocument.body.append(\\n\\tbutton, \\\" \\\", el(\\\"button\\\", { textContent: \\\"Off\\\", onclick: ()=> abort_controller.abort() })\\n);\\n\"}],\"toolbar\":false}"));</script><div class="notice"><p>So, there are (typically) three ways to handle events. You can use:</p><ul><li><code>el("button", { textContent: "click me", "=onclick": "console.log(event)" })</code></li><li><code>el("button", { textContent: "click me", onclick: console.log })</code></li><li><code>el("button", { textContent: "click me" }, on("click", console.log))</code></li></ul><p>In the first example we force to use HTML attribute (it corresponds to <code>&lt;button onclick="console.log(event)"&gt;click me&lt;/button&gt;</code>). <em>Side note: this can be useful in case of SSR.</em> To study difference, you can read a nice summary here: <a href="https://gist.github.com/WebReflection/b404c36f46371e3b1173bf5492acc944">GIST @WebReflection/web_events.md</a>.</p></div><h3 id="h-addons"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-addons" tabindex="-1">#</a> Addons</h3><p>From practical point of view, <em>Addons</em> are just functions that accept any html element as their first parameter. You can see that the <code>on(…)</code> fullfills this requirement.</p><p>You can use Addons as ≥3rd argument of <code>el</code> function. This way is possible to extends you templates by additional (3rd party) functionalities. But for now mainly, you can add events listeners:</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-6jtsnxfqzm4" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js";
const abort_controller= new AbortController(); const abort_controller= new AbortController();
const { signal }= abort_controller; const { signal }= abort_controller;
/** @type {ddeElementAddon&lt;HTMLButtonElement&gt;} */ /** @type {ddeElementAddon&lt;HTMLButtonElement&gt;} */
@ -45,7 +45,7 @@ function update(event){
"\n" "\n"
); );
} }
</code></div><script>Flems(document.getElementById("code-example-1-6jtsnxfqzm4"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el, on } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\nconst abort_controller= new AbortController();\\nconst { signal }= abort_controller;\\n/** @type {ddeElementAddon<HTMLButtonElement>} */\\nconst onclickOff= on(\\\"click\\\", ()=> abort_controller.abort(), { signal });\\n/** @type {(ref?: HTMLOutputElement)=> HTMLOutputElement | null} */\\nconst ref= (store=> ref=> ref ? (store= ref) : store)(null);\\n\\ndocument.body.append(\\n\\tel(\\\"button\\\", \\\"Test `on`\\\",\\n\\t\\ton(\\\"click\\\", console.log, { signal }),\\n\\t\\ton(\\\"click\\\", update, { signal }),\\n\\t\\ton(\\\"mouseup\\\", update, { signal })),\\n\\t\\\" \\\",\\n\\tel(\\\"button\\\", \\\"Off\\\", onclickOff),\\n\\tel(\\\"output\\\", { style: { display: \\\"block\\\", whiteSpace: \\\"pre\\\" } }, ref)\\n);\\n/** @param {MouseEvent} event @this {HTMLButtonElement} */\\nfunction update(event){\\n\\tref().append(\\n\\t\\tevent.type,\\n\\t\\t\\\"\\\\n\\\"\\n\\t);\\n}\\n\"}],\"toolbar\":false}"));</script><p>As the example shows, you can also provide types in JSDoc+TypeScript by using global type <code>ddeElementAddon</code>. Also notice, you can use Addons to get element reference.</p><h3 id="h-life-cycle-events"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-life-cycle-events" tabindex="-1">§</a> Life-cycle events</h3><p>Addons are called immediately when the element is created, even it is not connected to live DOM yet. Therefore, you can understand the Addon to be “oncreate” event.</p><p>The library provide three additional live-cycle events corresponding to how they are named in a case of custom elements: <code>on.connected</code>, <code>on.disconnected</code> and <code>on.attributeChanged</code>.</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-35hjjp3e4js" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; </code></div><script>Flems(document.getElementById("code-example-1-6jtsnxfqzm4"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el, on } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\nconst abort_controller= new AbortController();\\nconst { signal }= abort_controller;\\n/** @type {ddeElementAddon<HTMLButtonElement>} */\\nconst onclickOff= on(\\\"click\\\", ()=> abort_controller.abort(), { signal });\\n/** @type {(ref?: HTMLOutputElement)=> HTMLOutputElement | null} */\\nconst ref= (store=> ref=> ref ? (store= ref) : store)(null);\\n\\ndocument.body.append(\\n\\tel(\\\"button\\\", \\\"Test `on`\\\",\\n\\t\\ton(\\\"click\\\", console.log, { signal }),\\n\\t\\ton(\\\"click\\\", update, { signal }),\\n\\t\\ton(\\\"mouseup\\\", update, { signal })),\\n\\t\\\" \\\",\\n\\tel(\\\"button\\\", \\\"Off\\\", onclickOff),\\n\\tel(\\\"output\\\", { style: { display: \\\"block\\\", whiteSpace: \\\"pre\\\" } }, ref)\\n);\\n/** @param {MouseEvent} event @this {HTMLButtonElement} */\\nfunction update(event){\\n\\tref().append(\\n\\t\\tevent.type,\\n\\t\\t\\\"\\\\n\\\"\\n\\t);\\n}\\n\"}],\"toolbar\":false}"));</script><p>As the example shows, you can also provide types in JSDoc+TypeScript by using global type <code>ddeElementAddon</code>. Also notice, you can use Addons to get element reference.</p><h3 id="h-life-cycle-events"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-life-cycle-events" tabindex="-1">#</a> Life-cycle events</h3><p>Addons are called immediately when the element is created, even it is not connected to live DOM yet. Therefore, you can understand the Addon to be “oncreate” event.</p><p>The library provide three additional live-cycle events corresponding to how they are named in a case of custom elements: <code>on.connected</code>, <code>on.disconnected</code> and <code>on.attributeChanged</code>.</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-35hjjp3e4js" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js";
const paragraph= el("p", "See live-cycle events in console.", const paragraph= el("p", "See live-cycle events in console.",
el=&gt; log({ type: "dde:created", detail: el }), el=&gt; log({ type: "dde:created", detail: el }),
on.connected(log), on.connected(log),
@ -63,7 +63,7 @@ document.body.append(
function log({ type, detail }){ function log({ type, detail }){
console.log({ _this: this, type, detail }); console.log({ _this: this, type, detail });
} }
</code></div><script>Flems(document.getElementById("code-example-1-35hjjp3e4js"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el, on } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\nconst paragraph= el(\\\"p\\\", \\\"See live-cycle events in console.\\\",\\n\\tel=> log({ type: \\\"dde:created\\\", detail: el }),\\n\\ton.connected(log),\\n\\ton.disconnected(log),\\n\\ton.attributeChanged(log));\\n\\ndocument.body.append(\\n\\tparagraph,\\n\\tel(\\\"button\\\", \\\"Update attribute\\\", on(\\\"click\\\", ()=> paragraph.setAttribute(\\\"test\\\", Math.random().toString()))),\\n\\t\\\" \\\",\\n\\tel(\\\"button\\\", \\\"Remove\\\", on(\\\"click\\\", ()=> paragraph.remove()))\\n);\\n\\n/** @param {Partial<CustomEvent>} event */\\nfunction log({ type, detail }){\\n\\tconsole.log({ _this: this, type, detail });\\n}\\n\"}],\"toolbar\":false}"));</script><p>For Custom elements, we will later introduce a way to replace <code>*Callback</code> syntax with <code>dde:*</code> events. The <code>on.*</code> functions then listen to the appropriate Custom Elements events (see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks">Custom element lifecycle callbacks | MDN</a>).</p><p>But, in case of regular elemnets the <a href="https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver"><code>MutationObserver</code> | MDN</a> is internaly used to track these events. Therefore, there are some drawbacks:</p><ul><li>To proper listener registration, you need to use <code>on.*</code> not `on("dde:*", …)`!</li><li>Use sparingly! Internally, library must loop of all registered events and fires event properly. <strong>It is good practice to use the fact that if an element is removed, its children are also removed!</strong> In this spirit, we will introduce later the <strong>host</strong> syntax to register clean up procedures when the component is removed from the app.</li></ul><h3 id="h-final-notes"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-final-notes" tabindex="-1">§</a> Final notes</h3><p>The library also provides a&nbsp;method to dispatch the events.</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-2-b6a1hbrxh7s" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { el, on, dispatchEvent } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; </code></div><script>Flems(document.getElementById("code-example-1-35hjjp3e4js"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el, on } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\nconst paragraph= el(\\\"p\\\", \\\"See live-cycle events in console.\\\",\\n\\tel=> log({ type: \\\"dde:created\\\", detail: el }),\\n\\ton.connected(log),\\n\\ton.disconnected(log),\\n\\ton.attributeChanged(log));\\n\\ndocument.body.append(\\n\\tparagraph,\\n\\tel(\\\"button\\\", \\\"Update attribute\\\", on(\\\"click\\\", ()=> paragraph.setAttribute(\\\"test\\\", Math.random().toString()))),\\n\\t\\\" \\\",\\n\\tel(\\\"button\\\", \\\"Remove\\\", on(\\\"click\\\", ()=> paragraph.remove()))\\n);\\n\\n/** @param {Partial<CustomEvent>} event */\\nfunction log({ type, detail }){\\n\\tconsole.log({ _this: this, type, detail });\\n}\\n\"}],\"toolbar\":false}"));</script><p>For Custom elements, we will later introduce a way to replace <code>*Callback</code> syntax with <code>dde:*</code> events. The <code>on.*</code> functions then listen to the appropriate Custom Elements events (see <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks">Custom element lifecycle callbacks | MDN</a>).</p><p>But, in case of regular elemnets the <a href="https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver"><code>MutationObserver</code> | MDN</a> is internaly used to track these events. Therefore, there are some drawbacks:</p><ul><li>To proper listener registration, you need to use <code>on.*</code> not `on("dde:*", …)`!</li><li>Use sparingly! Internally, library must loop of all registered events and fires event properly. <strong>It is good practice to use the fact that if an element is removed, its children are also removed!</strong> In this spirit, we will introduce later the <strong>host</strong> syntax to register clean up procedures when the component is removed from the app.</li></ul><h3 id="h-final-notes"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-final-notes" tabindex="-1">#</a> Final notes</h3><p>The library also provides a&nbsp;method to dispatch the events.</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-2-b6a1hbrxh7s" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { el, on, dispatchEvent } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js";
document.body.append( document.body.append(
el("p", "Listenning to `test` event.", on("test", console.log)).append( el("p", "Listenning to `test` event.", on("test", console.log)).append(
el("br"), el("br"),
@ -87,4 +87,4 @@ function dde(){
function ddeOptions(){ function ddeOptions(){
dispatchEvent("test", { bubbles: true })(this, "hi"); dispatchEvent("test", { bubbles: true })(this, "hi");
} }
</code></div><script>Flems(document.getElementById("code-example-2-b6a1hbrxh7s"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el, on, dispatchEvent } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\ndocument.body.append(\\n\\tel(\\\"p\\\", \\\"Listenning to `test` event.\\\", on(\\\"test\\\", console.log)).append(\\n\\t\\tel(\\\"br\\\"),\\n\\t\\tel(\\\"button\\\", \\\"native\\\", on(\\\"click\\\", native)),\\n\\t\\t\\\" \\\",\\n\\t\\tel(\\\"button\\\", \\\"dde\\\", on(\\\"click\\\", dde)),\\n\\t\\t\\\" \\\",\\n\\t\\tel(\\\"button\\\", \\\"dde with options\\\", on(\\\"click\\\", ddeOptions))\\n\\t)\\n);\\nfunction native(){\\n\\tthis.dispatchEvent(\\n\\t\\tnew CustomEvent(\\\"test\\\",\\n\\t\\t\\t{ bubbles: true, detail: \\\"hi\\\" }\\n\\t\\t)\\n\\t);\\n}\\nfunction dde(){\\n\\tdispatchEvent(\\\"test\\\")(this.parentElement, \\\"hi\\\");\\n}\\nfunction ddeOptions(){\\n\\tdispatchEvent(\\\"test\\\", { bubbles: true })(this, \\\"hi\\\");\\n}\\n\"}],\"toolbar\":false}"));</script><div class="prevNext"><!--<dde:mark type="component" name="prevNext" host="parentElement" ssr/>--><a rel="prev" href="p02-elements" title="Basic concepts of elements modifications and creations."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->Elements (previous)</a><!--<dde:mark type="component" name="pageLink" host="this" ssr/>--></div></main></body></html> </code></div><script>Flems(document.getElementById("code-example-2-b6a1hbrxh7s"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el, on, dispatchEvent } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\ndocument.body.append(\\n\\tel(\\\"p\\\", \\\"Listenning to `test` event.\\\", on(\\\"test\\\", console.log)).append(\\n\\t\\tel(\\\"br\\\"),\\n\\t\\tel(\\\"button\\\", \\\"native\\\", on(\\\"click\\\", native)),\\n\\t\\t\\\" \\\",\\n\\t\\tel(\\\"button\\\", \\\"dde\\\", on(\\\"click\\\", dde)),\\n\\t\\t\\\" \\\",\\n\\t\\tel(\\\"button\\\", \\\"dde with options\\\", on(\\\"click\\\", ddeOptions))\\n\\t)\\n);\\nfunction native(){\\n\\tthis.dispatchEvent(\\n\\t\\tnew CustomEvent(\\\"test\\\",\\n\\t\\t\\t{ bubbles: true, detail: \\\"hi\\\" }\\n\\t\\t)\\n\\t);\\n}\\nfunction dde(){\\n\\tdispatchEvent(\\\"test\\\")(this.parentElement, \\\"hi\\\");\\n}\\nfunction ddeOptions(){\\n\\tdispatchEvent(\\\"test\\\", { bubbles: true })(this, \\\"hi\\\");\\n}\\n\"}],\"toolbar\":false}"));</script><div class="notice"><p>Mnemonic</p><ul><li><code>on(&lt;event&gt;, &lt;listener&gt;[, &lt;options&gt;])(&lt;element&gt;)</code> — just <code>&lt;element&gt;.addEventListener(&lt;event&gt;, &lt;listener&gt;[, &lt;options&gt;])</code></li><li><code>on.&lt;live-cycle&gt;(&lt;event&gt;, &lt;listener&gt;[, &lt;options&gt;])(&lt;element&gt;)</code> — corresponds to custom elemnets callbacks <code>&lt;live-cycle&gt;Callback(...){...}</code>. To connect to custom element see following page, else it is simulated by MutationObserver.</li><li><code>dispatchEvent(&lt;event&gt;[, &lt;options&gt;])(element)</code> — just <code>&lt;element&gt;.dispatchEvent(new Event(&lt;event&gt;[, &lt;options&gt;]))</code></li><li><code>dispatchEvent(&lt;event&gt;[, &lt;options&gt;])(element, detail)</code> — just <code>&lt;element&gt;.dispatchEvent(new CustomEvent(&lt;event&gt;, { detail, ...&lt;options&gt; }))</code></li></ul></div><div class="prevNext"><!--<dde:mark type="component" name="prevNext" host="parentElement" ssr/>--><a rel="prev" href="p02-elements" title="Basic concepts of elements modifications and creations."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->Elements (previous)</a><a rel="next" href="p04-signals" title="Handling reactivity in UI via signals."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->(next) Signals and reactivity</a></div></main></body></html>

25
docs/p04-signals.html Normal file
View File

@ -0,0 +1,25 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Handling reactivity in UI via signals."><title>`deka-dom-el` — Signals and reactivity</title><!--<dde:mark type="component" name="metaAuthor" host="this" ssr/>--><meta name="author" content="Jan Andrle"><link type="text/plain" rel="author" href="https://jaandrle.github.io/humans.txt"><meta name="generator" content="deka-dom-el"><!--<dde:mark type="component" name="metaTwitter" host="this" ssr/>--><meta name="twitter:card" content="summary_large_image"><meta name="twitter:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="twitter:title" content="deka-dom-el"><meta name="twitter:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="twitter:creator" content="@jaandrle"><!--<dde:mark type="component" name="metaFacebook" host="this" ssr/>--><meta name="og:url" content="https://github.com/jaandrle/deka-dom-el"><meta name="og:title" content="deka-dom-el"><meta name="og:description" content="A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks."><meta name="og:creator" content="@jaandrle"><script src="https://flems.io/flems.html" type="text/javascript" charset="utf-8"></script><link rel="stylesheet" href="global.css"></head><body><!--<dde:mark type="component" name="page" host="this" ssr/>--><!--<dde:mark type="component" name="header" host="this" ssr/>--><header><h1>`deka-dom-el` — Signals and reactivity</h1><p>Handling reactivity in UI via signals.</p></header><nav><a href="https://github.com/jaandrle/deka-dom-el"><svg class="icon" viewBox="0 0 32 32"><!--<dde:mark type="component" name="iconGitHub" host="parentElement" ssr/>--><path d="M 16,0.395c -8.836,0 -16,7.163 -16,16c 0,7.069 4.585,13.067 10.942,15.182c 0.8,0.148 1.094,-0.347 1.094,-0.77c 0,-0.381 -0.015,-1.642 -0.022,-2.979c -4.452,0.968 -5.391,-1.888 -5.391,-1.888c -0.728,-1.849 -1.776,-2.341 -1.776,-2.341c -1.452,-0.993 0.11,-0.973 0.11,-0.973c 1.606,0.113 2.452,1.649 2.452,1.649c 1.427,2.446 3.743,1.739 4.656,1.33c 0.143,-1.034 0.558,-1.74 1.016,-2.14c -3.554,-0.404 -7.29,-1.777 -7.29,-7.907c 0,-1.747 0.625,-3.174 1.649,-4.295c -0.166,-0.403 -0.714,-2.03 0.155,-4.234c 0,0 1.344,-0.43 4.401,1.64c 1.276,-0.355 2.645,-0.532 4.005,-0.539c 1.359,0.006 2.729,0.184 4.008,0.539c 3.054,-2.07 4.395,-1.64 4.395,-1.64c 0.871,2.204 0.323,3.831 0.157,4.234c 1.026,1.12 1.647,2.548 1.647,4.295c 0,6.145 -3.743,7.498 -7.306,7.895c 0.574,0.497 1.085,1.47 1.085,2.963c 0,2.141 -0.019,3.864 -0.019,4.391c 0,0.426 0.288,0.925 1.099,0.768c 6.354,-2.118 10.933,-8.113 10.933,-15.18c 0,-8.837 -7.164,-16 -16,-16Z"></path></svg>GitHub</a><a href="./" title="Introducing a&nbsp;library.">1. Introduction</a><a href="p02-elements" title="Basic concepts of elements modifications and creations.">2. Elements</a><a href="p03-events" title="Using not only events in UI declaratively.">3. Events and Addons</a><a href="p04-signals" title="Handling reactivity in UI via signals." class="current">4. Signals and reactivity</a></nav><main><h2>Using signals to manage reactivity</h2><p>How a program responds to variable data or user interactions is one of the fundamental problems of programming. If we desire to solve the issue in a declarative manner, signals may be a viable approach.</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-opc0krfvn3k" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { S } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js";
// α — `signal` represents a&nbsp;reactive value
const signal= S(0);
// β — just reacts on signal changes
S.on(signal, console.log);
// γ — just updates the value
signal(signal()+1);
setInterval(()=&gt; signal(signal()+1), 5000);
</code></div><script>Flems(document.getElementById("code-example-1-opc0krfvn3k"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { S } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\n// α — `signal` represents a reactive value\\nconst signal= S(0);\\n// β — just reacts on signal changes\\nS.on(signal, console.log);\\n// γ — just updates the value\\nsignal(signal()+1);\\nsetInterval(()=> signal(signal()+1), 5000);\\n\"}],\"toolbar\":false}"));</script><h3 id="h-introducing-signals"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-introducing-signals" tabindex="-1">#</a> Introducing signals</h3><p>Using signals, we split program logic into the three parts. Firstly (α), we create a&nbsp;variable (constant) representing reactive value. Somewhere later, we can register (β) a&nbsp;logic reacting to the signal value changes. Similarly, in a&nbsp;remaining part (γ), we can update the signal value.</p><p>All this is just an&nbsp;example of <a href="https://en.wikipedia.org/wiki/Event-driven_programming" title="Wikipedia: Event-driven programming">Event-driven programming</a> and <a href="https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern" title="Wikipedia: Publishsubscribe pattern">Publishsubscribe pattern</a> (compare for example with <a href="https://www.npmjs.com/package/fpubsub" title="NPM package: fpubsub">fpubsub library</a>). All three parts can be in some manner independent and still connected to the same reactive entity.</p><p>Signals are implemented in the library as functions. To see current value of signal, just call it without any arguments <code>console.log(signal())</code>. To update the signal value, pass any argument <code>signal('a new value')</code>. For listenning the signal value changes, use <code>S.on(signal, console.log)</code>.</p><p>Similarly to the <code>on</code> function to register DOM events listener. You can use <code>AbortController</code>/<code>AbortSignal</code> to <em>off</em>/stop listenning. For representing “live” piece of code computation pattern:</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-e9cfsaeb64o" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { S } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js";
const signal= S(0);
// computation pattern
const double= S(()=&gt; 2*signal());
const ac= new AbortController();
S.on(signal, v=&gt; console.log("signal", v), { signal: ac.signal });
S.on(double, v=&gt; console.log("double", v), { signal: ac.signal });
signal(signal()+1);
const interval= 5000;
const id= setInterval(()=&gt; signal(signal()+1), interval);
ac.signal.addEventListener("abort",
()=&gt; setTimeout(()=&gt; clearInterval(id), 2*interval));
setTimeout(()=&gt; ac.abort(), 3*interval)
</code></div><script>Flems(document.getElementById("code-example-1-e9cfsaeb64o"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { S } from \\\"https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js\\\";\\nconst signal= S(0);\\n// computation pattern\\nconst double= S(()=> 2*signal());\\n\\nconst ac= new AbortController();\\nS.on(signal, v=> console.log(\\\"signal\\\", v), { signal: ac.signal });\\nS.on(double, v=> console.log(\\\"double\\\", v), { signal: ac.signal });\\n\\nsignal(signal()+1);\\nconst interval= 5000;\\nconst id= setInterval(()=> signal(signal()+1), interval);\\nac.signal.addEventListener(\\\"abort\\\",\\n\\t()=> setTimeout(()=> clearInterval(id), 2*interval));\\n\\nsetTimeout(()=> ac.abort(), 3*interval)\\n\"}],\"toolbar\":false}"));</script><div class="notice"><p>Mnemonic</p><ul><li><code>S(&lt;value&gt;)</code> — signal: reactive value</li><li><code>S(()=&gt; &lt;computation&gt;)</code> — signal: reactive value dependent on calculation using other signals</li><li><code>S.on(&lt;signal&gt;, &lt;listener&gt;[, &lt;options&gt;])</code> — listen to the signal value changes</li><li><code>S.clear(...&lt;signals&gt;)</code> — off and clear signals</li><li><code>S(&lt;value&gt;, &lt;actions&gt;)</code> — signal: pattern to create complex reactive objects/arrays</li><li><code>S.action(&lt;signal&gt;, &lt;action-name&gt;, ...&lt;action-arguments&gt;)</code> — invoke an&nbsp;action for given signal</li></ul></div></main></body></html>

View File

@ -0,0 +1,16 @@
import { S } from "deka-dom-el/signals";
const signal= S(0);
// computation pattern
const double= S(()=> 2*signal());
const ac= new AbortController();
S.on(signal, v=> console.log("signal", v), { signal: ac.signal });
S.on(double, v=> console.log("double", v), { signal: ac.signal });
signal(signal()+1);
const interval= 5000;
const id= setInterval(()=> signal(signal()+1), interval);
ac.signal.addEventListener("abort",
()=> setTimeout(()=> clearInterval(id), 2*interval));
setTimeout(()=> ac.abort(), 3*interval)

View File

@ -0,0 +1,8 @@
import { S } from "deka-dom-el/signals";
// α — `signal` represents a reactive value
const signal= S(0);
// β — just reacts on signal changes
S.on(signal, console.log);
// γ — just updates the value
signal(signal()+1);
setInterval(()=> signal(signal()+1), 5000);

View File

@ -24,7 +24,7 @@ import { el } from "../../index.js";
export function h3({ textContent, id }){ export function h3({ textContent, id }){
if(!id) id= "h-"+textContent.toLowerCase().replaceAll(/\s/g, "-").replaceAll(/[^a-z-]/g, ""); if(!id) id= "h-"+textContent.toLowerCase().replaceAll(/\s/g, "-").replaceAll(/[^a-z-]/g, "");
return el("h3", { id }).append( return el("h3", { id }).append(
el("a", { textContent: "§", href: "#"+id, tabIndex: -1 }), el("a", { textContent: "#", href: "#"+id, tabIndex: -1 }),
" ", textContent " ", textContent
); );
} }

View File

@ -117,6 +117,30 @@ export function page({ pkg, info }){
), ),
el(example, { src: fileURL("./components/examples/elements/dekaElNS.js"), page_id }), el(example, { src: fileURL("./components/examples/elements/dekaElNS.js"), page_id }),
el("div", { className: "notice" }).append(
el("p", "Mnemonic"),
el("ul").append(
el("li").append(
el("code", "assign(<element>, ...<idl-objects>): <element>"), " — assign properties to the element",
),
el("li").append(
el("code", "el(<tag-name>, <primitive>)[.append(...)]: <element-from-tag-name>"), " — simple element containing only text",
),
el("li").append(
el("code", "el(<tag-name>, <idl-object>)[.append(...)]: <element-from-tag-name>"), " — element with more properties",
),
el("li").append(
el("code", "el(<function>, <function-argument(s)>)[.append(...)]: <element-returned-by-function>"), " — using component represented by function",
),
el("li").append(
el("code", "el(<...>, <...>, ...<addons>)"), " — see following page"
),
el("li").append(
el("code", "elNS(<namespace>)(<as-el-see-above>)[.append(...)]: <element-based-on-arguments>"), " — typically SVG elements",
)
)
),
el(prevNext, info) el(prevNext, info)
) )
); );

View File

@ -114,6 +114,25 @@ export function page({ pkg, info }){
el("p", "The library also provides a method to dispatch the events."), el("p", "The library also provides a method to dispatch the events."),
el(example, { src: fileURL("./components/examples/events/compareDispatch.js"), page_id }), el(example, { src: fileURL("./components/examples/events/compareDispatch.js"), page_id }),
el("div", { className: "notice" }).append(
el("p", "Mnemonic"),
el("ul").append(
el("li").append(
el("code", "on(<event>, <listener>[, <options>])(<element>)"), " — just ", el("code", "<element>.addEventListener(<event>, <listener>[, <options>])")
),
el("li").append(
el("code", "on.<live-cycle>(<event>, <listener>[, <options>])(<element>)"), " — corresponds to custom elemnets callbacks ", el("code", "<live-cycle>Callback(...){...}"),
". To connect to custom element see following page, else it is simulated by MutationObserver."
),
el("li").append(
el("code", "dispatchEvent(<event>[, <options>])(element)"), " — just ", el("code", "<element>.dispatchEvent(new Event(<event>[, <options>]))")
),
el("li").append(
el("code", "dispatchEvent(<event>[, <options>])(element, detail)"), " — just ", el("code", "<element>.dispatchEvent(new CustomEvent(<event>, { detail, ...<options> }))")
),
)
),
el(prevNext, info) el(prevNext, info)
) )
); );

View File

@ -14,107 +14,67 @@ export function page({ pkg, info }){
return el().append( return el().append(
el(header, { info, pkg }), el(header, { info, pkg }),
el("main").append( el("main").append(
el("h2", "Listenning to the native DOM events and other Addons"), el("h2", "Using signals to manage reactivity"),
el("p").append( el("p").append(
"We quickly introduce helper to listening to the native DOM events.", "How a program responds to variable data or user",
" ", " interactions is one of the fundamental problems of programming.",
"And library syntax/pattern so-called ", el("em", "Addon"), " to", " If we desire to solve the issue in a declarative manner,",
" incorporate not only this in UI templates declaratively." " signals may be a viable approach.",
), ),
el(example, { src: fileURL("./components/examples/signals/intro.js"), page_id }),
el(h3, "Events and listenners"), el(h3, "Introducing signals"),
el("p").append( el("p").append(
"In JavaScript you can listen to the native DOM events of the given element by using ", "Using signals, we split program logic into the three parts.",
el("a", { href: "https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener", title: "addEventListener on MDN" }).append( " Firstly (α), we create a variable (constant) representing reactive",
el("code", "element.addEventListener(type, listener, options)") " value. Somewhere later, we can register (β) a logic reacting",
), ".", " to the signal value changes. Similarly, in a remaining part (γ), we",
" ", " can update the signal value."
"The library provides an alternative (", el("code", "on"), ") accepting the differen order",
" of the arguments:"
), ),
el(example, { src: fileURL("./components/examples/events/compare.js"), page_id }),
el("p").append( el("p").append(
"…this is actually one of the two differences. The another one is that ", el("code", "on"), "All this is just an example of ",
" accepts only object as the ", el("code", "options"), " (but it is still optional)." el("a", { textContent: "Event-driven programming", href: "https://en.wikipedia.org/wiki/Event-driven_programming", title: "Wikipedia: Event-driven programming" }),
" and ",
el("a", { textContent: "Publishsubscribe pattern", href: "https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern", title: "Wikipedia: Publishsubscribe pattern" }),
" (compare for example with ", el("a", { textContent: "fpubsub library", href: "https://www.npmjs.com/package/fpubsub", title: "NPM package: fpubsub" }), ").",
" All three parts can be in some manner independent and still connected",
" to the same reactive entity."
), ),
el("p", { className: "notice" }).append( el("p").append(
"The other difference is that there is ", el("strong", "no"), " ", el("code", "off"), " function.", "Signals are implemented in the library as functions. To see current value",
" ", " of signal, just call it without any arguments ", el("code", "console.log(signal())"), ".",
"You can remove listener declaratively using ", el("a", { textContent: "AbortSignal", href: "https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#signal", title: "part of addEventListener on MDN" }), " To update the signal value, pass any argument ", el("code", "signal('a new value')"), ".",
":" " For listenning the signal value changes, use ", el("code", "S.on(signal, console.log)"), "."
), ),
el(example, { src: fileURL("./components/examples/events/abortSignal.js"), page_id }), el("p").append(
"Similarly to the ", el("code", "on"), " function to register DOM events listener.",
" You can use ", el("code", "AbortController"), "/", el("code", "AbortSignal"), " to",
" ", el("em", "off"), "/stop listenning. For representing “live” piece of code computation pattern:"
),
el(example, { src: fileURL("./components/examples/signals/computations-abort.js"), page_id }),
el("div", { className: "notice" }).append( el("div", { className: "notice" }).append(
el("p", "So, there are (typically) three ways to handle events. You can use:"), el("p", "Mnemonic"),
el("ul").append( el("ul").append(
el("li").append( el("code", `el("button", { textContent: "click me", "=onclick": "console.log(event)" })`)), el("li").append(
el("li").append( el("code", `el("button", { textContent: "click me", onclick: console.log })`)), el("code", "S(<value>)"), " — signal: reactive value",
el("li").append( el("code", `el("button", { textContent: "click me" }, on("click", console.log))`))
), ),
el("p").append( el("li").append(
"In the first example we force to use HTML attribute (it corresponds to ", el("code", `<button onclick="console.log(event)">click me</button>`), ").", el("code", "S(()=> <computation>)"), " — signal: reactive value dependent on calculation using other signals",
" ", ),
el("em", "Side note: this can be useful in case of SSR."), el("li").append(
" ", el("code", "S.on(<signal>, <listener>[, <options>])"), " — listen to the signal value changes",
"To study difference, you can read a nice summary here: ", el("a", { href: "https://gist.github.com/WebReflection/b404c36f46371e3b1173bf5492acc944", textContent: "GIST @WebReflection/web_events.md" }), "." ),
el("li").append(
el("code", "S.clear(...<signals>)"), " — off and clear signals",
),
el("li").append(
el("code", "S(<value>, <actions>)"), " — signal: pattern to create complex reactive objects/arrays",
),
el("li").append(
el("code", "S.action(<signal>, <action-name>, ...<action-arguments>)"), " — invoke an action for given signal"
)
) )
), ),
el(h3, "Addons"),
el("p").append(
"From practical point of view, ", el("em", "Addons"), " are just functions that accept any html element",
" as their first parameter. You can see that the ", el("code", "on(…)"), " fullfills this requirement."
),
el("p").append(
"You can use Addons as ≥3rd argument of ", el("code", "el"), " function. This way is possible to extends",
" you templates by additional (3rd party) functionalities. But for now mainly, you can add events listeners:"
),
el(example, { src: fileURL("./components/examples/events/templateWithListeners.js"), page_id }),
el("p").append(
"As the example shows, you can also provide types in JSDoc+TypeScript by using global type ", el("code", "ddeElementAddon"), ".",
" ",
"Also notice, you can use Addons to get element reference.",
),
el(h3, "Life-cycle events"),
el("p").append(
"Addons are called immediately when the element is created, even it is not connected to live DOM yet.",
" ",
"Therefore, you can understand the Addon to be “oncreate” event."
),
el("p").append(
"The library provide three additional live-cycle events corresponding to how they are named in",
" a case of custom elements: ", el("code", "on.connected"), ", ", el("code", "on.disconnected"),
" and ", el("code", "on.attributeChanged"), "."
),
el(example, { src: fileURL("./components/examples/events/live-cycle.js"), page_id }),
el("p").append(
"For Custom elements, we will later introduce a way to replace ", el("code", "*Callback"),
" syntax with ", el("code", "dde:*"), " events. The ", el("code", "on.*"), " functions then",
" listen to the appropriate Custom Elements events (see ", el("a", { textContent: "Custom element lifecycle callbacks | MDN", href: "https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks" }), ")."
),
el("p").append(
"But, in case of regular elemnets the ", el("a", { href: "https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver" }).append(el("code", "MutationObserver"), " | MDN"),
" is internaly used to track these events. Therefore, there are some drawbacks:",
),
el("ul").append(
el("li").append(
"To proper listener registration, you need to use ", el("code", "on.*"), " not `on(\"dde:*\", …)`!"
),
el("li").append(
"Use sparingly! Internally, library must loop of all registered events and fires event properly.",
" ",
el("strong", "It is good practice to use the fact that if an element is removed, its children are also removed!"),
" ",
"In this spirit, we will introduce later the ", el("strong", "host"), " syntax to register",
" clean up procedures when the component is removed from the app."
),
),
el(h3, "Final notes"),
el("p", "The library also provides a method to dispatch the events."),
el(example, { src: fileURL("./components/examples/events/compareDispatch.js"), page_id }),
el(prevNext, info)
) )
); );
} }

View File

@ -6,6 +6,7 @@ export const pages= [
{ id: "index", href: "./", title: "Introduction", description: "Introducing a library." }, { id: "index", href: "./", title: "Introduction", description: "Introducing a library." },
{ id: "p02-elements", href: "p02-elements", title: "Elements", description: "Basic concepts of elements modifications and creations." }, { id: "p02-elements", href: "p02-elements", title: "Elements", description: "Basic concepts of elements modifications and creations." },
{ id: "p03-events", href: "p03-events", title: "Events and Addons", description: "Using not only events in UI declaratively." }, { id: "p03-events", href: "p03-events", title: "Events and Addons", description: "Using not only events in UI declaratively." },
{ id: "p04-signals", href: "p04-signals", title: "Signals and reactivity", description: "Handling reactivity in UI via signals." },
]; ];
/** /**
* @typedef registerClientFile * @typedef registerClientFile