1
0
mirror of https://github.com/jaandrle/deka-dom-el synced 2024-11-23 09:09:38 +01:00
deka-dom-el/docs/index.html

22 lines
38 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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://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&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><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&nbsp;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=&gt;
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(()=&gt;
"Hello World "+"🎉".repeat(clicks()) // B
)),
el("button", {
type: "button",
onclick: ()=&gt; 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&nbsp;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: Modelviewviewmodel" href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel">MVVM</a> or <a title="Wikipedia: Modelviewcontroller" 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>