mirror of
https://github.com/jaandrle/deka-dom-el
synced 2024-11-23 09:09:38 +01:00
22 lines
38 KiB
HTML
22 lines
38 KiB
HTML
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Introducing a 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://cdn.jsdelivr.net/npm/shiki@0.9" defer=""></script><script type="module" src="code.js.js"></script><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="simplePage" host="this" ssr/>--><!--<dde:mark type="component" name="header" host="this" ssr/>--><header><h1>`deka-dom-el` — Introduction</h1><p>Introducing a 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 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><a href="p05-scopes" title="Organizing UI into components">5. Scopes and components</a><a href="p06-customElement" title="Using custom elements in combinantion with DDE">6. Web Components</a></nav><main><p>The library tries to provide pure JavaScript tool(s) to create reactive interfaces using …</p><h3 id="h-event-driven-programming--parts-separation--ps"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-event-driven-programming--parts-separation--ps" tabindex="-1">#</a> Event-driven programming (3 parts separation ≡ 3PS)</h3><p>Let's introduce the basic principle on which the library is built. We'll use the JavaScript listener as a starting point. </p><div class="code" data-js="todo"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">// pseudo code!
|
||
const onchage=
|
||
event=>
|
||
console.log("Reacting to the:", event); // A
|
||
input.addEventListener("change", onchange); // B
|
||
input.dispatchEvent(new Event("change")); // C
|
||
</code></div><p>As we can see, in the code at location “A” we define <em>how to react</em> when the function is called with any event as an argument. At that moment, we <em>don't care who/why/how</em> the function was called. Similarly, at point “B”, we reference to a function to be called on the event <em>without caring</em> what the function will do at that time. Finally, at point “C”, we tell the application that a change has occurred, in the input, and we <em>don't care if/how someone</em> is listening for the event.</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-8meex5b3tyo" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { el } from "./esm-with-signals.js";
|
||
import { S } from "./esm-with-signals.js";
|
||
const clicks= S(0); // A
|
||
document.body.append(
|
||
el().append(
|
||
el("p", S(()=>
|
||
"Hello World "+"🎉".repeat(clicks()) // B
|
||
)),
|
||
el("button", {
|
||
type: "button",
|
||
onclick: ()=> clicks(clicks()+1), // C
|
||
textContent: "Fire",
|
||
})
|
||
)
|
||
);
|
||
</code></div><script>Flems(document.getElementById("code-example-1-8meex5b3tyo"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { el } from \\\"./esm-with-signals.js\\\";\\nimport { S } from \\\"./esm-with-signals.js\\\";\\nconst clicks= S(0); // A\\ndocument.body.append(\\n\\tel().append(\\n\\t\\tel(\\\"p\\\", S(()=>\\n\\t\\t\\t\\\"Hello World \\\"+\\\"🎉\\\".repeat(clicks()) // B\\n\\t\\t)),\\n\\t\\tel(\\\"button\\\", {\\n\\t\\t\\ttype: \\\"button\\\",\\n\\t\\t\\tonclick: ()=> clicks(clicks()+1), // C\\n\\t\\t\\ttextContent: \\\"Fire\\\",\\n\\t\\t})\\n\\t)\\n);\\n\"},{\"name\":\"esm-with-signals.js\",\"content\":\"// src/signals-common.js\\nvar signals_global = {\\n\\tisSignal(attributes) {\\n\\t\\treturn false;\\n\\t},\\n\\tprocessReactiveAttribute(obj, key, attr, set) {\\n\\t\\treturn attr;\\n\\t}\\n};\\nfunction registerReactivity(def, global = true) {\\n\\tif (global) return Object.assign(signals_global, def);\\n\\tObject.setPrototypeOf(def, signals_global);\\n\\treturn def;\\n}\\nfunction signals(_this) {\\n\\treturn signals_global.isPrototypeOf(_this) && _this !== signals_global ? _this : signals_global;\\n}\\n\\n// src/helpers.js\\nvar hasOwn = (...a) => Object.prototype.hasOwnProperty.call(...a);\\nfunction isUndef(value) {\\n\\treturn typeof value === \\\"undefined\\\";\\n}\\nfunction typeOf(v) {\\n\\tconst t = typeof v;\\n\\tif (t !== \\\"object\\\") return t;\\n\\tif (v === null) return \\\"null\\\";\\n\\treturn Object.prototype.toString.call(v);\\n}\\nfunction onAbort(signal2, listener) {\\n\\tif (!signal2 || !(signal2 instanceof AbortSignal))\\n\\t\\treturn true;\\n\\tif (signal2.aborted)\\n\\t\\treturn;\\n\\tsignal2.addEventListener(\\\"abort\\\", listener);\\n\\treturn function cleanUp() {\\n\\t\\tsignal2.removeEventListener(\\\"abort\\\", listener);\\n\\t};\\n}\\nfunction observedAttributes(instance, observedAttribute2) {\\n\\tconst { observedAttributes: observedAttributes3 = [] } = instance.constructor;\\n\\treturn observedAttributes3.reduce(function(out, name) {\\n\\t\\tout[kebabToCamel(name)] = observedAttribute2(instance, name);\\n\\t\\treturn out;\\n\\t}, {});\\n}\\nfunction kebabToCamel(name) {\\n\\treturn name.replace(/-./g, (x) => x[1].toUpperCase());\\n}\\n\\n// src/dom-common.js\\nvar enviroment = {\\n\\tsetDeleteAttr,\\n\\tssr: \\\"\\\",\\n\\tD: globalThis.document,\\n\\tF: globalThis.DocumentFragment,\\n\\tH: globalThis.HTMLElement,\\n\\tS: globalThis.SVGElement,\\n\\tM: globalThis.MutationObserver\\n};\\nfunction setDeleteAttr(obj, prop, val) {\\n\\tReflect.set(obj, prop, val);\\n\\tif (!isUndef(val)) return;\\n\\tReflect.deleteProperty(obj, prop);\\n\\tif (obj instanceof enviroment.H && obj.getAttribute(prop) === \\\"undefined\\\")\\n\\t\\treturn obj.removeAttribute(prop);\\n\\tif (Reflect.get(obj, prop) === \\\"undefined\\\")\\n\\t\\treturn Reflect.set(obj, prop, \\\"\\\");\\n}\\nvar keyLTE = \\\"__dde_lifecyclesToEvents\\\";\\nvar evc = \\\"dde:connected\\\";\\nvar evd = \\\"dde:disconnected\\\";\\nvar eva = \\\"dde:attributeChanged\\\";\\n\\n// src/dom.js\\nvar scopes = [{\\n\\tget scope() {\\n\\t\\treturn enviroment.D.body;\\n\\t},\\n\\thost: (c) => c ? c(enviroment.D.body) : enviroment.D.body,\\n\\tprevent: true\\n}];\\nvar scope = {\\n\\tget current() {\\n\\t\\treturn scopes[scopes.length - 1];\\n\\t},\\n\\tget host() {\\n\\t\\treturn this.current.host;\\n\\t},\\n\\tpreventDefault() {\\n\\t\\tconst { current } = this;\\n\\t\\tcurrent.prevent = true;\\n\\t\\treturn current;\\n\\t},\\n\\tget state() {\\n\\t\\treturn [...scopes];\\n\\t},\\n\\tpush(s = {}) {\\n\\t\\treturn scopes.push(Object.assign({}, this.current, { prevent: false }, s));\\n\\t},\\n\\tpushRoot() {\\n\\t\\treturn scopes.push(scopes[0]);\\n\\t},\\n\\tpop() {\\n\\t\\tif (scopes.length === 1) return;\\n\\t\\treturn scopes.pop();\\n\\t}\\n};\\nfunction append(...els) {\\n\\tthis.appendOriginal(...els);\\n\\treturn this;\\n}\\nfunction chainableAppend(el) {\\n\\tif (el.append === append) return el;\\n\\tel.appendOriginal = el.append;\\n\\tel.append = append;\\n\\treturn el;\\n}\\nvar namespace;\\nfunction createElement(tag, attributes, ...addons) {\\n\\tconst s = signals(this);\\n\\tlet scoped = 0;\\n\\tlet el, el_host;\\n\\tif (Object(attributes) !== attributes || s.isSignal(attributes))\\n\\t\\tattributes = { textContent: attributes };\\n\\tswitch (true) {\\n\\t\\tcase typeof tag === \\\"function\\\": {\\n\\t\\t\\tscoped = 1;\\n\\t\\t\\tscope.push({ scope: tag, host: (...c) => c.length ? (scoped === 1 ? addons.unshift(...c) : c.forEach((c2) => c2(el_host)), void 0) : el_host });\\n\\t\\t\\tel = tag(attributes || void 0);\\n\\t\\t\\tconst is_fragment = el instanceof enviroment.F;\\n\\t\\t\\tif (el.nodeName === \\\"#comment\\\") break;\\n\\t\\t\\tconst el_mark = createElement.mark({\\n\\t\\t\\t\\ttype: \\\"component\\\",\\n\\t\\t\\t\\tname: tag.name,\\n\\t\\t\\t\\thost: is_fragment ? \\\"this\\\" : \\\"parentElement\\\"\\n\\t\\t\\t});\\n\\t\\t\\tel.prepend(el_mark);\\n\\t\\t\\tif (is_fragment) el_host = el_mark;\\n\\t\\t\\tbreak;\\n\\t\\t}\\n\\t\\tcase tag === \\\"#text\\\":\\n\\t\\t\\tel = assign.call(this, enviroment.D.createTextNode(\\\"\\\"), attributes);\\n\\t\\t\\tbreak;\\n\\t\\tcase (tag === \\\"<>\\\" || !tag):\\n\\t\\t\\tel = assign.call(this, enviroment.D.createDocumentFragment(), attributes);\\n\\t\\t\\tbreak;\\n\\t\\tcase Boolean(namespace):\\n\\t\\t\\tel = assign.call(this, enviroment.D.createElementNS(namespace, tag), attributes);\\n\\t\\t\\tbreak;\\n\\t\\tcase !el:\\n\\t\\t\\tel = assign.call(this, enviroment.D.createElement(tag), attributes);\\n\\t}\\n\\tchainableAppend(el);\\n\\tif (!el_host) el_host = el;\\n\\taddons.forEach((c) => c(el_host));\\n\\tif (scoped) scope.pop();\\n\\tscoped = 2;\\n\\treturn el;\\n}\\nfunction simulateSlots(element, root, mapper) {\\n\\tif (typeof root !== \\\"object\\\") {\\n\\t\\tmapper = root;\\n\\t\\troot = element;\\n\\t}\\n\\tconst _default = Symbol.for(\\\"default\\\");\\n\\tconst slots = Array.from(root.querySelectorAll(\\\"slot\\\")).reduce((out, curr) => Reflect.set(out, curr.name || _default, curr) && out, {});\\n\\tconst has_d = hasOwn(slots, _default);\\n\\telement.append = new Proxy(element.append, {\\n\\t\\tapply(orig, _, els) {\\n\\t\\t\\tif (els[0] === root) return orig.apply(element, els);\\n\\t\\t\\tif (!els.length) return element;\\n\\t\\t\\tconst d = enviroment.D.createDocumentFragment();\\n\\t\\t\\tfor (const el of els) {\\n\\t\\t\\t\\tif (!el || !el.slot) {\\n\\t\\t\\t\\t\\tif (has_d) d.append(el);\\n\\t\\t\\t\\t\\tcontinue;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tconst name = el.slot;\\n\\t\\t\\t\\tconst slot = slots[name];\\n\\t\\t\\t\\telementAttribute(el, \\\"remove\\\", \\\"slot\\\");\\n\\t\\t\\t\\tif (!slot) continue;\\n\\t\\t\\t\\tsimulateSlotReplace(slot, el, mapper);\\n\\t\\t\\t\\tReflect.deleteProperty(slots, name);\\n\\t\\t\\t}\\n\\t\\t\\tif (has_d) {\\n\\t\\t\\t\\tslots[_default].replaceWith(d);\\n\\t\\t\\t\\tReflect.deleteProperty(slots, _default);\\n\\t\\t\\t}\\n\\t\\t\\telement.append = orig;\\n\\t\\t\\treturn element;\\n\\t\\t}\\n\\t});\\n\\tif (element !== root) {\\n\\t\\tconst els = Array.from(element.childNodes);\\n\\t\\tels.forEach((el) => el.remove());\\n\\t\\telement.append(...els);\\n\\t}\\n\\treturn root;\\n}\\nfunction simulateSlotReplace(slot, element, mapper) {\\n\\tif (mapper) mapper(slot, element);\\n\\ttry {\\n\\t\\tslot.replaceWith(assign(element, { className: [element.className, slot.className], dataset: { ...slot.dataset } }));\\n\\t} catch (_) {\\n\\t\\tslot.replaceWith(element);\\n\\t}\\n}\\ncreateElement.mark = function(attrs, is_open = false) {\\n\\tattrs = Object.entries(attrs).map(([n, v]) => n + `=\\\"${v}\\\"`).join(\\\" \\\");\\n\\tconst end = is_open ? \\\"\\\" : \\\"/\\\";\\n\\tconst out = enviroment.D.createComment(`<dde:mark ${attrs}${enviroment.ssr}${end}>`);\\n\\tif (is_open) out.end = enviroment.D.createComment(\\\"</dde:mark>\\\");\\n\\treturn out;\\n};\\nfunction createElementNS(ns) {\\n\\tconst _this = this;\\n\\treturn function createElementNSCurried(...rest) {\\n\\t\\tnamespace = ns;\\n\\t\\tconst el = createElement.call(_this, ...rest);\\n\\t\\tnamespace = void 0;\\n\\t\\treturn el;\\n\\t};\\n}\\nvar assign_context = /* @__PURE__ */ new WeakMap();\\nvar { setDeleteAttr: setDeleteAttr2 } = enviroment;\\nfunction assign(element, ...attributes) {\\n\\tif (!attributes.length) return element;\\n\\tassign_context.set(element, assignContext(element, this));\\n\\tfor (const [key, value] of Object.entries(Object.assign({}, ...attributes)))\\n\\t\\tassignAttribute.call(this, element, key, value);\\n\\tassign_context.delete(element);\\n\\treturn element;\\n}\\nfunction assignAttribute(element, key, value) {\\n\\tconst { setRemoveAttr, s } = assignContext(element, this);\\n\\tconst _this = this;\\n\\tvalue = s.processReactiveAttribute(\\n\\t\\telement,\\n\\t\\tkey,\\n\\t\\tvalue,\\n\\t\\t(key2, value2) => assignAttribute.call(_this, element, key2, value2)\\n\\t);\\n\\tconst [k] = key;\\n\\tif (\\\"=\\\" === k) return setRemoveAttr(key.slice(1), value);\\n\\tif (\\\".\\\" === k) return setDelete(element, key.slice(1), value);\\n\\tif (/(aria|data)([A-Z])/.test(key)) {\\n\\t\\tkey = key.replace(/([a-z])([A-Z])/g, \\\"$1-$2\\\").toLowerCase();\\n\\t\\treturn setRemoveAttr(key, value);\\n\\t}\\n\\tif (\\\"className\\\" === key) key = \\\"class\\\";\\n\\tswitch (key) {\\n\\t\\tcase \\\"xlink:href\\\":\\n\\t\\t\\treturn setRemoveAttr(key, value, \\\"http://www.w3.org/1999/xlink\\\");\\n\\t\\tcase \\\"textContent\\\":\\n\\t\\t\\treturn setDeleteAttr2(element, key, value);\\n\\t\\tcase \\\"style\\\":\\n\\t\\t\\tif (typeof value !== \\\"object\\\") break;\\n\\t\\t/* falls through */\\n\\t\\tcase \\\"dataset\\\":\\n\\t\\t\\treturn forEachEntries(s, value, setDelete.bind(null, element[key]));\\n\\t\\tcase \\\"ariaset\\\":\\n\\t\\t\\treturn forEachEntries(s, value, (key2, val) => setRemoveAttr(\\\"aria-\\\" + key2, val));\\n\\t\\tcase \\\"classList\\\":\\n\\t\\t\\treturn classListDeclarative.call(_this, element, value);\\n\\t}\\n\\treturn isPropSetter(element, key) ? setDeleteAttr2(element, key, value) : setRemoveAttr(key, value);\\n}\\nfunction assignContext(element, _this) {\\n\\tif (assign_context.has(element)) return assign_context.get(element);\\n\\tconst is_svg = element instanceof enviroment.S;\\n\\tconst setRemoveAttr = (is_svg ? setRemoveNS : setRemove).bind(null, element, \\\"Attribute\\\");\\n\\tconst s = signals(_this);\\n\\treturn { setRemoveAttr, s };\\n}\\nfunction classListDeclarative(element, toggle) {\\n\\tconst s = signals(this);\\n\\tforEachEntries(\\n\\t\\ts,\\n\\t\\ttoggle,\\n\\t\\t(class_name, val) => element.classList.toggle(class_name, val === -1 ? void 0 : Boolean(val))\\n\\t);\\n\\treturn element;\\n}\\nfunction empty(el) {\\n\\tArray.from(el.children).forEach((el2) => el2.remove());\\n\\treturn el;\\n}\\nfunction elementAttribute(element, op, key, value) {\\n\\tif (element instanceof enviroment.H)\\n\\t\\treturn element[op + \\\"Attribute\\\"](key, value);\\n\\treturn element[op + \\\"AttributeNS\\\"](null, key, value);\\n}\\nfunction isPropSetter(el, key) {\\n\\tif (!(key in el)) return false;\\n\\tconst des = getPropDescriptor(el, key);\\n\\treturn !isUndef(des.set);\\n}\\nfunction getPropDescriptor(p, key) {\\n\\tp = Object.getPrototypeOf(p);\\n\\tif (!p) return {};\\n\\tconst des = Object.getOwnPropertyDescriptor(p, key);\\n\\tif (!des) return getPropDescriptor(p, key);\\n\\treturn des;\\n}\\nfunction forEachEntries(s, obj, cb) {\\n\\tif (typeof obj !== \\\"object\\\" || obj === null) return;\\n\\treturn Object.entries(obj).forEach(function process([key, val]) {\\n\\t\\tif (!key) return;\\n\\t\\tval = s.processReactiveAttribute(obj, key, val, cb);\\n\\t\\tcb(key, val);\\n\\t});\\n}\\nfunction attrArrToStr(attr) {\\n\\treturn Array.isArray(attr) ? attr.filter(Boolean).join(\\\" \\\") : attr;\\n}\\nfunction setRemove(obj, prop, key, val) {\\n\\treturn obj[(isUndef(val) ? \\\"remove\\\" : \\\"set\\\") + prop](key, attrArrToStr(val));\\n}\\nfunction setRemoveNS(obj, prop, key, val, ns = null) {\\n\\treturn obj[(isUndef(val) ? \\\"remove\\\" : \\\"set\\\") + prop + \\\"NS\\\"](ns, key, attrArrToStr(val));\\n}\\nfunction setDelete(obj, key, val) {\\n\\tReflect.set(obj, key, val);\\n\\tif (!isUndef(val)) return;\\n\\treturn Reflect.deleteProperty(obj, key);\\n}\\n\\n// src/events-observer.js\\nvar c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, {\\n\\tget() {\\n\\t\\treturn () => {\\n\\t\\t};\\n\\t}\\n});\\nfunction connectionsChangesObserverConstructor() {\\n\\tconst store = /* @__PURE__ */ new Map();\\n\\tlet is_observing = false;\\n\\tconst observerListener = (stop2) => function(mutations) {\\n\\t\\tfor (const mutation of mutations) {\\n\\t\\t\\tif (mutation.type !== \\\"childList\\\") continue;\\n\\t\\t\\tif (observerAdded(mutation.addedNodes, true)) {\\n\\t\\t\\t\\tstop2();\\n\\t\\t\\t\\tcontinue;\\n\\t\\t\\t}\\n\\t\\t\\tif (observerRemoved(mutation.removedNodes, true))\\n\\t\\t\\t\\tstop2();\\n\\t\\t}\\n\\t};\\n\\tconst observer = new enviroment.M(observerListener(stop));\\n\\treturn {\\n\\t\\tobserve(element) {\\n\\t\\t\\tconst o = new enviroment.M(observerListener(() => {\\n\\t\\t\\t}));\\n\\t\\t\\to.observe(element, { childList: true, subtree: true });\\n\\t\\t\\treturn () => o.disconnect();\\n\\t\\t},\\n\\t\\tonConnected(element, listener) {\\n\\t\\t\\tstart();\\n\\t\\t\\tconst listeners = getElementStore(element);\\n\\t\\t\\tif (listeners.connected.has(listener)) return;\\n\\t\\t\\tlisteners.connected.add(listener);\\n\\t\\t\\tlisteners.length_c += 1;\\n\\t\\t},\\n\\t\\toffConnected(element, listener) {\\n\\t\\t\\tif (!store.has(element)) return;\\n\\t\\t\\tconst ls = store.get(element);\\n\\t\\t\\tif (!ls.connected.has(listener)) return;\\n\\t\\t\\tls.connected.delete(listener);\\n\\t\\t\\tls.length_c -= 1;\\n\\t\\t\\tcleanWhenOff(element, ls);\\n\\t\\t},\\n\\t\\tonDisconnected(element, listener) {\\n\\t\\t\\tstart();\\n\\t\\t\\tconst listeners = getElementStore(element);\\n\\t\\t\\tif (listeners.disconnected.has(listener)) return;\\n\\t\\t\\tlisteners.disconnected.add(listener);\\n\\t\\t\\tlisteners.length_d += 1;\\n\\t\\t},\\n\\t\\toffDisconnected(element, listener) {\\n\\t\\t\\tif (!store.has(element)) return;\\n\\t\\t\\tconst ls = store.get(element);\\n\\t\\t\\tif (!ls.disconnected.has(listener)) return;\\n\\t\\t\\tls.disconnected.delete(listener);\\n\\t\\t\\tls.length_d -= 1;\\n\\t\\t\\tcleanWhenOff(element, ls);\\n\\t\\t}\\n\\t};\\n\\tfunction cleanWhenOff(element, ls) {\\n\\t\\tif (ls.length_c || ls.length_d)\\n\\t\\t\\treturn;\\n\\t\\tstore.delete(element);\\n\\t\\tstop();\\n\\t}\\n\\tfunction getElementStore(element) {\\n\\t\\tif (store.has(element)) return store.get(element);\\n\\t\\tconst out = {\\n\\t\\t\\tconnected: /* @__PURE__ */ new WeakSet(),\\n\\t\\t\\tlength_c: 0,\\n\\t\\t\\tdisconnected: /* @__PURE__ */ new WeakSet(),\\n\\t\\t\\tlength_d: 0\\n\\t\\t};\\n\\t\\tstore.set(element, out);\\n\\t\\treturn out;\\n\\t}\\n\\tfunction start() {\\n\\t\\tif (is_observing) return;\\n\\t\\tis_observing = true;\\n\\t\\tobserver.observe(enviroment.D.body, { childList: true, subtree: true });\\n\\t}\\n\\tfunction stop() {\\n\\t\\tif (!is_observing || store.size) return;\\n\\t\\tis_observing = false;\\n\\t\\tobserver.disconnect();\\n\\t}\\n\\tfunction requestIdle() {\\n\\t\\treturn new Promise(function(resolve) {\\n\\t\\t\\t(requestIdleCallback || requestAnimationFrame)(resolve);\\n\\t\\t});\\n\\t}\\n\\tasync function collectChildren(element) {\\n\\t\\tif (store.size > 30)\\n\\t\\t\\tawait requestIdle();\\n\\t\\tconst out = [];\\n\\t\\tif (!(element instanceof Node)) return out;\\n\\t\\tfor (const el of store.keys()) {\\n\\t\\t\\tif (el === element || !(el instanceof Node)) continue;\\n\\t\\t\\tif (element.contains(el))\\n\\t\\t\\t\\tout.push(el);\\n\\t\\t}\\n\\t\\treturn out;\\n\\t}\\n\\tfunction observerAdded(addedNodes, is_root) {\\n\\t\\tlet out = false;\\n\\t\\tfor (const element of addedNodes) {\\n\\t\\t\\tif (is_root) collectChildren(element).then(observerAdded);\\n\\t\\t\\tif (!store.has(element)) continue;\\n\\t\\t\\tconst ls = store.get(element);\\n\\t\\t\\tif (!ls.length_c) continue;\\n\\t\\t\\telement.dispatchEvent(new Event(evc));\\n\\t\\t\\tls.connected = /* @__PURE__ */ new WeakSet();\\n\\t\\t\\tls.length_c = 0;\\n\\t\\t\\tif (!ls.length_d) store.delete(element);\\n\\t\\t\\tout = true;\\n\\t\\t}\\n\\t\\treturn out;\\n\\t}\\n\\tfunction observerRemoved(removedNodes, is_root) {\\n\\t\\tlet out = false;\\n\\t\\tfor (const element of removedNodes) {\\n\\t\\t\\tif (is_root) collectChildren(element).then(observerRemoved);\\n\\t\\t\\tif (!store.has(element)) continue;\\n\\t\\t\\tconst ls = store.get(element);\\n\\t\\t\\tif (!ls.length_d) continue;\\n\\t\\t\\t(globalThis.queueMicrotask || setTimeout)(dispatchRemove(element));\\n\\t\\t\\tout = true;\\n\\t\\t}\\n\\t\\treturn out;\\n\\t}\\n\\tfunction dispatchRemove(element) {\\n\\t\\treturn () => {\\n\\t\\t\\tif (element.isConnected) return;\\n\\t\\t\\telement.dispatchEvent(new Event(evd));\\n\\t\\t\\tstore.delete(element);\\n\\t\\t};\\n\\t}\\n}\\n\\n// src/customElement.js\\nfunction customElementRender(custom_element, target, render, props = observedAttributes2) {\\n\\tscope.push({\\n\\t\\tscope: custom_element,\\n\\t\\thost: (...c) => c.length ? c.forEach((c2) => c2(custom_element)) : custom_element\\n\\t});\\n\\tif (typeof props === \\\"function\\\") props = props.call(custom_element, custom_element);\\n\\tconst is_lte = custom_element[keyLTE];\\n\\tif (!is_lte) lifecyclesToEvents(custom_element);\\n\\tconst out = render.call(custom_element, props);\\n\\tif (!is_lte) custom_element.dispatchEvent(new Event(evc));\\n\\tif (target.nodeType === 11 && typeof target.mode === \\\"string\\\")\\n\\t\\tcustom_element.addEventListener(evd, c_ch_o.observe(target), { once: true });\\n\\tscope.pop();\\n\\treturn target.append(out);\\n}\\nfunction lifecyclesToEvents(class_declaration) {\\n\\twrapMethod(class_declaration.prototype, \\\"connectedCallback\\\", function(target, thisArg, detail) {\\n\\t\\ttarget.apply(thisArg, detail);\\n\\t\\tthisArg.dispatchEvent(new Event(evc));\\n\\t});\\n\\twrapMethod(class_declaration.prototype, \\\"disconnectedCallback\\\", function(target, thisArg, detail) {\\n\\t\\ttarget.apply(thisArg, detail);\\n\\t\\t(globalThis.queueMicrotask || setTimeout)(\\n\\t\\t\\t() => !thisArg.isConnected && thisArg.dispatchEvent(new Event(evd))\\n\\t\\t);\\n\\t});\\n\\twrapMethod(class_declaration.prototype, \\\"attributeChangedCallback\\\", function(target, thisArg, detail) {\\n\\t\\tconst [attribute, , value] = detail;\\n\\t\\tthisArg.dispatchEvent(new CustomEvent(eva, {\\n\\t\\t\\tdetail: [attribute, value]\\n\\t\\t}));\\n\\t\\ttarget.apply(thisArg, detail);\\n\\t});\\n\\tclass_declaration.prototype[keyLTE] = true;\\n\\treturn class_declaration;\\n}\\nfunction wrapMethod(obj, method, apply) {\\n\\tobj[method] = new Proxy(obj[method] || (() => {\\n\\t}), { apply });\\n}\\nfunction observedAttributes2(instance) {\\n\\treturn observedAttributes(instance, (i, n) => i.getAttribute(n));\\n}\\n\\n// src/events.js\\nfunction dispatchEvent(name, options, host) {\\n\\tif (!options) options = {};\\n\\treturn function dispatch(element, ...d) {\\n\\t\\tif (host) {\\n\\t\\t\\td.unshift(element);\\n\\t\\t\\telement = typeof host === \\\"function\\\" ? host() : host;\\n\\t\\t}\\n\\t\\tconst event = d.length ? new CustomEvent(name, Object.assign({ detail: d[0] }, options)) : new Event(name, options);\\n\\t\\treturn element.dispatchEvent(event);\\n\\t};\\n}\\nfunction on(event, listener, options) {\\n\\treturn function registerElement(element) {\\n\\t\\telement.addEventListener(event, listener, options);\\n\\t\\treturn element;\\n\\t};\\n}\\nvar lifeOptions = (obj) => Object.assign({}, typeof obj === \\\"object\\\" ? obj : null, { once: true });\\non.connected = function(listener, options) {\\n\\toptions = lifeOptions(options);\\n\\treturn function registerElement(element) {\\n\\t\\telement.addEventListener(evc, listener, options);\\n\\t\\tif (element[keyLTE]) return element;\\n\\t\\tif (element.isConnected) return element.dispatchEvent(new Event(evc)), element;\\n\\t\\tconst c = onAbort(options.signal, () => c_ch_o.offConnected(element, listener));\\n\\t\\tif (c) c_ch_o.onConnected(element, listener);\\n\\t\\treturn element;\\n\\t};\\n};\\non.disconnected = function(listener, options) {\\n\\toptions = lifeOptions(options);\\n\\treturn function registerElement(element) {\\n\\t\\telement.addEventListener(evd, listener, options);\\n\\t\\tif (element[keyLTE]) return element;\\n\\t\\tconst c = onAbort(options.signal, () => c_ch_o.offDisconnected(element, listener));\\n\\t\\tif (c) c_ch_o.onDisconnected(element, listener);\\n\\t\\treturn element;\\n\\t};\\n};\\nvar store_abort = /* @__PURE__ */ new WeakMap();\\non.disconnectedAsAbort = function(host) {\\n\\tif (store_abort.has(host)) return store_abort.get(host);\\n\\tconst a = new AbortController();\\n\\tstore_abort.set(host, a);\\n\\thost(on.disconnected(() => a.abort()));\\n\\treturn a;\\n};\\nvar els_attribute_store = /* @__PURE__ */ new WeakSet();\\non.attributeChanged = function(listener, options) {\\n\\tif (typeof options !== \\\"object\\\")\\n\\t\\toptions = {};\\n\\treturn function registerElement(element) {\\n\\t\\telement.addEventListener(eva, listener, options);\\n\\t\\tif (element[keyLTE] || els_attribute_store.has(element))\\n\\t\\t\\treturn element;\\n\\t\\tif (!enviroment.M) return element;\\n\\t\\tconst observer = new enviroment.M(function(mutations) {\\n\\t\\t\\tfor (const { attributeName, target } of mutations)\\n\\t\\t\\t\\ttarget.dispatchEvent(\\n\\t\\t\\t\\t\\tnew CustomEvent(eva, { detail: [attributeName, target.getAttribute(attributeName)] })\\n\\t\\t\\t\\t);\\n\\t\\t});\\n\\t\\tconst c = onAbort(options.signal, () => observer.disconnect());\\n\\t\\tif (c) observer.observe(element, { attributes: true });\\n\\t\\treturn element;\\n\\t};\\n};\\n\\n// src/signals-lib.js\\nvar mark = \\\"__dde_signal\\\";\\nfunction isSignal(candidate) {\\n\\ttry {\\n\\t\\treturn hasOwn(candidate, mark);\\n\\t} catch (e) {\\n\\t\\treturn false;\\n\\t}\\n}\\nvar stack_watch = [];\\nvar deps = /* @__PURE__ */ new WeakMap();\\nfunction signal(value, actions) {\\n\\tif (typeof value !== \\\"function\\\")\\n\\t\\treturn create(false, value, actions);\\n\\tif (isSignal(value)) return value;\\n\\tconst out = create(true);\\n\\tconst contextReWatch = function() {\\n\\t\\tconst [origin, ...deps_old] = deps.get(contextReWatch);\\n\\t\\tdeps.set(contextReWatch, /* @__PURE__ */ new Set([origin]));\\n\\t\\tstack_watch.push(contextReWatch);\\n\\t\\twrite(out, value());\\n\\t\\tstack_watch.pop();\\n\\t\\tif (!deps_old.length) return;\\n\\t\\tconst deps_curr = deps.get(contextReWatch);\\n\\t\\tfor (const dep_signal of deps_old) {\\n\\t\\t\\tif (deps_curr.has(dep_signal)) continue;\\n\\t\\t\\tremoveSignalListener(dep_signal, contextReWatch);\\n\\t\\t}\\n\\t};\\n\\tdeps.set(out[mark], contextReWatch);\\n\\tdeps.set(contextReWatch, /* @__PURE__ */ new Set([out]));\\n\\tcontextReWatch();\\n\\treturn out;\\n}\\nsignal.action = function(s, name, ...a) {\\n\\tconst M = s[mark], { actions } = M;\\n\\tif (!actions || !(name in actions))\\n\\t\\tthrow new Error(`'${s}' has no action with name '${name}'!`);\\n\\tactions[name].apply(M, a);\\n\\tif (M.skip) return delete M.skip;\\n\\tM.listeners.forEach((l) => l(M.value));\\n};\\nsignal.on = function on2(s, listener, options = {}) {\\n\\tconst { signal: as } = options;\\n\\tif (as && as.aborted) return;\\n\\tif (Array.isArray(s)) return s.forEach((s2) => on2(s2, listener, options));\\n\\taddSignalListener(s, listener);\\n\\tif (as) as.addEventListener(\\\"abort\\\", () => removeSignalListener(s, listener));\\n};\\nsignal.symbols = {\\n\\t//signal: mark,\\n\\tonclear: Symbol.for(\\\"Signal.onclear\\\")\\n};\\nsignal.clear = function(...signals2) {\\n\\tfor (const s of signals2) {\\n\\t\\tconst M = s[mark];\\n\\t\\tif (!M) continue;\\n\\t\\tdelete s.toJSON;\\n\\t\\tM.onclear.forEach((f) => f.call(M));\\n\\t\\tclearListDeps(s, M);\\n\\t\\tdelete s[mark];\\n\\t}\\n\\tfunction clearListDeps(s, o) {\\n\\t\\to.listeners.forEach((l) => {\\n\\t\\t\\to.listeners.delete(l);\\n\\t\\t\\tif (!deps.has(l)) return;\\n\\t\\t\\tconst ls = deps.get(l);\\n\\t\\t\\tls.delete(s);\\n\\t\\t\\tif (ls.size > 1) return;\\n\\t\\t\\ts.clear(...ls);\\n\\t\\t\\tdeps.delete(l);\\n\\t\\t});\\n\\t}\\n};\\nvar key_reactive = \\\"__dde_reactive\\\";\\nsignal.el = function(s, map) {\\n\\tconst mark_start = createElement.mark({ type: \\\"reactive\\\" }, true);\\n\\tconst mark_end = mark_start.end;\\n\\tconst out = enviroment.D.createDocumentFragment();\\n\\tout.append(mark_start, mark_end);\\n\\tconst { current } = scope;\\n\\tlet cache = {};\\n\\tconst reRenderReactiveElement = (v) => {\\n\\t\\tif (!mark_start.parentNode || !mark_end.parentNode)\\n\\t\\t\\treturn removeSignalListener(s, reRenderReactiveElement);\\n\\t\\tconst cache_tmp = cache;\\n\\t\\tcache = {};\\n\\t\\tscope.push(current);\\n\\t\\tlet els = map(v, function useCache(key, fun) {\\n\\t\\t\\tlet value;\\n\\t\\t\\tif (hasOwn(cache_tmp, key)) {\\n\\t\\t\\t\\tvalue = cache_tmp[key];\\n\\t\\t\\t\\tdelete cache_tmp[key];\\n\\t\\t\\t} else\\n\\t\\t\\t\\tvalue = fun();\\n\\t\\t\\tcache[key] = value;\\n\\t\\t\\treturn value;\\n\\t\\t});\\n\\t\\tscope.pop();\\n\\t\\tif (!Array.isArray(els))\\n\\t\\t\\tels = [els];\\n\\t\\tconst el_start_rm = document.createComment(\\\"\\\");\\n\\t\\tels.push(el_start_rm);\\n\\t\\tmark_start.after(...els);\\n\\t\\tlet el_r;\\n\\t\\twhile ((el_r = el_start_rm.nextSibling) && el_r !== mark_end)\\n\\t\\t\\tel_r.remove();\\n\\t\\tel_start_rm.remove();\\n\\t\\tif (mark_start.isConnected)\\n\\t\\t\\trequestCleanUpReactives(current.host());\\n\\t};\\n\\taddSignalListener(s, reRenderReactiveElement);\\n\\tremoveSignalsFromElements(s, reRenderReactiveElement, mark_start, map);\\n\\treRenderReactiveElement(s());\\n\\treturn out;\\n};\\nfunction requestCleanUpReactives(host) {\\n\\tif (!host || !host[key_reactive]) return;\\n\\t(requestIdleCallback || setTimeout)(function() {\\n\\t\\thost[key_reactive] = host[key_reactive].filter(([s, el]) => el.isConnected ? true : (removeSignalListener(...s), false));\\n\\t});\\n}\\nvar observedAttributeActions = {\\n\\t_set(value) {\\n\\t\\tthis.value = value;\\n\\t}\\n};\\nfunction observedAttribute(store) {\\n\\treturn function(instance, name) {\\n\\t\\tconst varS = (...args) => !args.length ? read(varS) : instance.setAttribute(name, ...args);\\n\\t\\tconst out = toSignal(varS, instance.getAttribute(name), observedAttributeActions);\\n\\t\\tstore[name] = out;\\n\\t\\treturn out;\\n\\t};\\n}\\nvar key_attributes = \\\"__dde_attributes\\\";\\nsignal.observedAttributes = function(element) {\\n\\tconst store = element[key_attributes] = {};\\n\\tconst attrs = observedAttributes(element, observedAttribute(store));\\n\\ton.attributeChanged(function attributeChangeToSignal({ detail }) {\\n\\t\\t/*! This maps attributes to signals (`S.observedAttributes`).\\n\\t\\t\\t* Investigate `__dde_attributes` key of the element.*/\\n\\t\\tconst [name, value] = detail;\\n\\t\\tconst curr = this[key_attributes][name];\\n\\t\\tif (curr) return signal.action(curr, \\\"_set\\\", value);\\n\\t})(element);\\n\\ton.disconnected(function() {\\n\\t\\t/*! This removes all signals mapped to attributes (`S.observedAttributes`).\\n\\t\\t\\t* Investigate `__dde_attributes` key of the element.*/\\n\\t\\tsignal.clear(...Object.values(this[key_attributes]));\\n\\t})(element);\\n\\treturn attrs;\\n};\\nvar signals_config = {\\n\\tisSignal,\\n\\tprocessReactiveAttribute(element, key, attrs, set) {\\n\\t\\tif (!isSignal(attrs)) return attrs;\\n\\t\\tconst l = (attr) => {\\n\\t\\t\\tif (!element.isConnected)\\n\\t\\t\\t\\treturn removeSignalListener(attrs, l);\\n\\t\\t\\tset(key, attr);\\n\\t\\t};\\n\\t\\taddSignalListener(attrs, l);\\n\\t\\tremoveSignalsFromElements(attrs, l, element, key);\\n\\t\\treturn attrs();\\n\\t}\\n};\\nfunction removeSignalsFromElements(s, listener, ...notes) {\\n\\tconst { current } = scope;\\n\\tif (current.prevent) return;\\n\\tcurrent.host(function(element) {\\n\\t\\tif (!element[key_reactive]) {\\n\\t\\t\\telement[key_reactive] = [];\\n\\t\\t\\ton.disconnected(\\n\\t\\t\\t\\t() => (\\n\\t\\t\\t\\t\\t/*!\\n\\t\\t\\t\\t\\t* Clears all Signals listeners added in the current scope/host (`S.el`, `assign`, …?).\\n\\t\\t\\t\\t\\t* You can investigate the `__dde_reactive` key of the element.\\n\\t\\t\\t\\t\\t* */\\n\\t\\t\\t\\t\\telement[key_reactive].forEach(([[s2, listener2]]) => removeSignalListener(s2, listener2, s2[mark] && s2[mark].host && s2[mark].host() === element))\\n\\t\\t\\t\\t)\\n\\t\\t\\t)(element);\\n\\t\\t}\\n\\t\\telement[key_reactive].push([[s, listener], ...notes]);\\n\\t});\\n}\\nfunction create(is_readonly, value, actions) {\\n\\tconst varS = is_readonly ? () => read(varS) : (...value2) => value2.length ? write(varS, ...value2) : read(varS);\\n\\treturn toSignal(varS, value, actions, is_readonly);\\n}\\nvar protoSigal = Object.assign(/* @__PURE__ */ Object.create(null), {\\n\\tstopPropagation() {\\n\\t\\tthis.skip = true;\\n\\t}\\n});\\nvar SignalDefined = class extends Error {\\n\\tconstructor() {\\n\\t\\tsuper();\\n\\t\\tconst [curr, ...rest] = this.stack.split(\\\"\\\\n\\\");\\n\\t\\tconst curr_file = curr.slice(curr.indexOf(\\\"@\\\"), curr.indexOf(\\\".js:\\\") + 4);\\n\\t\\tthis.stack = rest.find((l) => !l.includes(curr_file));\\n\\t}\\n};\\nfunction toSignal(s, value, actions, readonly = false) {\\n\\tconst onclear = [];\\n\\tif (typeOf(actions) !== \\\"[object Object]\\\")\\n\\t\\tactions = {};\\n\\tconst { onclear: ocs } = signal.symbols;\\n\\tif (actions[ocs]) {\\n\\t\\tonclear.push(actions[ocs]);\\n\\t\\tdelete actions[ocs];\\n\\t}\\n\\tconst { host } = scope;\\n\\tReflect.defineProperty(s, mark, {\\n\\t\\tvalue: {\\n\\t\\t\\tvalue,\\n\\t\\t\\tactions,\\n\\t\\t\\tonclear,\\n\\t\\t\\thost,\\n\\t\\t\\tlisteners: /* @__PURE__ */ new Set(),\\n\\t\\t\\tdefined: new SignalDefined().stack,\\n\\t\\t\\treadonly\\n\\t\\t},\\n\\t\\tenumerable: false,\\n\\t\\twritable: false,\\n\\t\\tconfigurable: true\\n\\t});\\n\\ts.toJSON = () => s();\\n\\ts.valueOf = () => s[mark] && s[mark].value;\\n\\tObject.setPrototypeOf(s[mark], protoSigal);\\n\\treturn s;\\n}\\nfunction currentContext() {\\n\\treturn stack_watch[stack_watch.length - 1];\\n}\\nfunction read(s) {\\n\\tif (!s[mark]) return;\\n\\tconst { value, listeners } = s[mark];\\n\\tconst context = currentContext();\\n\\tif (context) listeners.add(context);\\n\\tif (deps.has(context)) deps.get(context).add(s);\\n\\treturn value;\\n}\\nfunction write(s, value, force) {\\n\\tif (!s[mark]) return;\\n\\tconst M = s[mark];\\n\\tif (!force && M.value === value) return;\\n\\tM.value = value;\\n\\tM.listeners.forEach((l) => l(value));\\n\\treturn value;\\n}\\nfunction addSignalListener(s, listener) {\\n\\tif (!s[mark]) return;\\n\\treturn s[mark].listeners.add(listener);\\n}\\nfunction removeSignalListener(s, listener, clear_when_empty) {\\n\\tconst M = s[mark];\\n\\tif (!M) return;\\n\\tconst out = M.listeners.delete(listener);\\n\\tif (clear_when_empty && !M.listeners.size) {\\n\\t\\tsignal.clear(s);\\n\\t\\tif (!deps.has(M)) return out;\\n\\t\\tconst c = deps.get(M);\\n\\t\\tif (!deps.has(c)) return out;\\n\\t\\tdeps.get(c).forEach((sig) => removeSignalListener(sig, c, true));\\n\\t}\\n\\treturn out;\\n}\\n\\n// signals.js\\nregisterReactivity(signals_config);\\nexport {\\n\\tsignal as S,\\n\\tassign,\\n\\tassignAttribute,\\n\\tchainableAppend,\\n\\tclassListDeclarative,\\n\\tcreateElement,\\n\\tcreateElementNS,\\n\\tcustomElementRender,\\n\\tlifecyclesToEvents as customElementWithDDE,\\n\\tdispatchEvent,\\n\\tcreateElement as el,\\n\\tcreateElementNS as elNS,\\n\\telementAttribute,\\n\\tempty,\\n\\tisSignal,\\n\\tlifecyclesToEvents,\\n\\tobservedAttributes2 as observedAttributes,\\n\\ton,\\n\\tregisterReactivity,\\n\\tscope,\\n\\tsignal,\\n\\tsimulateSlots\\n};\\n\"}],\"toolbar\":false}"));</script><p>The library introduces a new “type” of variable/constant called <em>signal</em> allowing us to to use introduced 3PS pattern in our applications. As you can see it in the example above.</p><p>Also please notice that there is very similar 3PS pattern used for separate creation of UI and business logic. </p><p>The 3PS is very simplified definition of the pattern. There are more deep/academic definitions more precisely describe usage in specific situations, see for example <a title="Wikipedia: Model–view–viewmodel" href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel">MVVM</a> or <a title="Wikipedia: Model–view–controller" href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">MVC</a>.</p><h3 id="h-organization-of-the-documentation"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-organization-of-the-documentation" tabindex="-1">#</a> Organization of the documentation</h3><div class="prevNext"><!--<dde:mark type="component" name="prevNext" host="parentElement" ssr/>--><!--<dde:mark type="component" name="pageLink" host="this" ssr/>--><a rel="next" href="p02-elements" title="Basic concepts of elements modifications and creations."><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->(next) Elements</a></div></main></body></html> |