1
0
mirror of https://github.com/jaandrle/deka-dom-el synced 2024-11-27 10:19:37 +01:00
deka-dom-el/docs/p04-observables.html

150 lines
147 KiB
HTML
Raw Normal View History

<!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 observables."><title>`deka-dom-el` — Observables 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://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` — Observables and reactivity</h1><p>Handling reactivity in UI via observables.</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-observables" title="Handling reactivity in UI via observables." class="current">4. Observables 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. Custom elements</a></nav><main><h2>Using observables 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, observables may be a viable approach.</p><div class="code" data-js="todo"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">// use NPM or for example https://cdn.jsdelivr.net/gh/jaandrle/deka-
2023-11-29 18:25:21 +01:00
import { O, observable } from "deka-dom-el/observables";
O===observable
/** @type {ddeObservable} */
/** @type {ddeAction} */
/** @type {ddeActions} */
2024-05-17 22:13:16 +02:00
</code></div><h3 id="h-introducing-observables"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-introducing-observables" tabindex="-1">#</a> Introducing observables</h3><p>Using observables, 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 observable value changes. Similarly, in a&nbsp;remaining part (γ), we can update the observable value.</p><!--<dde:mark type="component" name="example" host="this" ssr/>--><div id="code-example-1-v1fw44pkzuo" class="example"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">import { O } from "./esm-with-observables.js";
2023-11-24 20:41:04 +01:00
// α — `observable` represents a&nbsp;reactive value
const observable= O(0);
// β — just reacts on observable changes
O.on(observable, console.log);
// γ — just updates the value
2023-11-29 18:25:21 +01:00
const update= ()=&gt; observable(observable()+1);
update();
const interval= 5*1000;
setTimeout(clearInterval, 10*interval,
setInterval(update, interval));
2024-05-17 22:13:16 +02:00
</code></div><script>Flems(document.getElementById("code-example-1-v1fw44pkzuo"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { O } from \\\"./esm-with-observables.js\\\";\\n// α `observable` represents a reactive value\\nconst observable= O(0);\\n// β just reacts on observable changes\\nO.on(observable, console.log);\\n// γ just updates the value\\nconst update= ()=> observable(observable()+1);\\n\\nupdate();\\nconst interval= 5*1000;\\nsetTimeout(clearInterval, 10*interval,\\n\\tsetInterval(update, interval));\\n\"},{\"name\":\"esm-with-observables.js\",\"content\":\"// src/observables-common.js\\nvar k = {\\n\\tisObservable(t) {\\n\\t\\treturn !1;\\n\\t},\\n\\tprocessReactiveAttribute(t, e, n, r) {\\n\\t\\treturn n;\\n\\t}\\n};\\nfunction B(t, e = !0) {\\n\\treturn e ? Object.assign(k, t) : (Object.setPrototypeOf(t, k), t);\\n}\\nfunction W(t) {\\n\\treturn k.isPrototypeOf(t) && t !== k ? t : k;\\n}\\n\\n// src/helpers.js\\nvar T = (...t) => Object.prototype.hasOwnProperty.call(...t);\\nfunction A(t) {\\n\\treturn typeof t > \\\"u\\\";\\n}\\nfunction X(t) {\\n\\tlet e = typeof t;\\n\\treturn e !== \\\"object\\\" ? e : t === null ? \\\"null\\\" : Object.prototype.toString.call(t);\\n}\\nfunction q(t, e) {\\n\\tif (!t || !(t instanceof AbortSignal))\\n\\t\\treturn !0;\\n\\tif (!t.aborted)\\n\\t\\treturn t.addEventListener(\\\"abort\\\", e), function() {\\n\\t\\t\\tt.removeEventListener(\\\"abort\\\", e);\\n\\t\\t};\\n}\\nfunction F(t, e) {\\n\\tlet { observedAttributes: n = [] } = t.constructor;\\n\\treturn n.reduce(function(r, o) {\\n\\t\\treturn r[pt(o)] = e(t, o), r;\\n\\t}, {});\\n}\\nfunction pt(t) {\\n\\treturn t.replace(/-./g, (e) => e[1].toUpperCase());\\n}\\n\\n// src/dom-common.js\\nvar d = {\\n\\tsetDeleteAttr: lt,\\n\\tssr: \\\"\\\",\\n\\tD: globalThis.document,\\n\\tF: globalThis.DocumentFragment,\\n\\tH: globalThis.HTMLElement,\\n\\tS: globalThis.SVGElement,\\n\\tM: globalThis.MutationObserver\\n};\\nfunction lt(t, e, n) {\\n\\tif (Reflect.set(t, e, n), !!A(n)) {\\n\\t\\tif (Reflect.deleteProperty(t, e), t instanceof d.H && t.getAttribute(e) === \\\"undefined\\\")\\n\\t\\t\\treturn t.removeAttribute(e);\\n\\t\\tif (Reflect.get(t, e) === \\\"undefined\\\")\\n\\t\\t\\treturn Reflect.set(t, e, \\\"\\\");\\n\\t}\\n}\\nvar C = \\\"__dde_lifecyclesToEvents\\\", y = \\\"dde:connected\\\", S = \\\"dde:disconnected\\\", P = \\\"dde:attributeChanged\\\";\\n\\n// src/dom.js\\nvar _ = [{\\n\\tget scope() {\\n\\t\\treturn d.D.body;\\n\\t},\\n\\thost: (t) => t ? t(d.D.body) : d.D.body,\\n\\tprevent: !0\\n}], m = {\\n\\tget current() {\\n\\t\\treturn _[_.length - 1];\\n\\t},\\n\\tget host() {\\n\\t\\treturn this.current.host;\\n\\t},\\n\\tpreventDefault() {\\n\\t\\tlet { current: t } = this;\\n\\t\\treturn t.prevent = !0, t;\\n\\t},\\n\\tget state() {\\n\\t\\treturn [..._];\\n\\t},\\n\\tpush(t = {}) {\\n\\t\\treturn _.push(Object.assign({}, this.current, { prevent: !1 }, t));\\n\\t},\\n\\tpushRoot() {\\n\\t\\treturn _.push(_[0]);\\n\\t},\\n\\tpop() {\\n\\t\\tif (_.length !== 1)\\n\\t\\t\\treturn _.pop();\\n\\t}\\n};\\nfunction Y(...t) {\\n\\treturn this.appendOriginal(...t), this;\\n}\\nfunction ht(t) {\\n\\treturn t.append === Y || (t.appendOriginal = t.append, t.append = Y), t;\\n}\\nvar $;\\nfunction M(t, e, ...n) {\\n\\tlet r = W(this), o = 0, c, s;\\n\\tswitch ((Object(e) !== e || r.isObservable(e)) && (e = { textContent: e }), !0) {\\n\\t\\tcase typeof t == \\\"function\\\": {\\n\\t\\t\\to = 1, m.push({ scope: t, host: (...g) => g.length ? (o === 1 ? n.unshift(...g) : g.forEach((l) => l(s)), void 0) : s }), c = t(e || void 0);\\n\\t\\t\\tlet a = c instanceof d.F;\\n\\t\\t\\tif (c.nodeName === \\\"#comment\\\")\\n\\t\\t\\t\\tbreak;\\n\\t\\t\\tlet h = M.mark({\\n\\t\\t\\t\\ttype: \\\"component\\\",\\n\\t\\t\\t\\tname: t.name,\\n\\t\\t\\t\\thost: a ? \\\"this\\\" : \\\"parentElement\\\"\\n\\t\\t\\t});\\n\\t\\t\\tc.prepend(h), a && (s = h);\\n\\t\\t\\tbreak;\\n\\t\\t}\\n\\t\\tcase t === \\\"#text\\\":\\n\\t\\t\\tc = j.call(this, d.D.createTextNode(\\\"\\\"), e);\\n\\t\\t\\tbreak;\\n\
2023-11-24 20:41:04 +01:00
const observable= O(0);
// computation pattern
const double= O(()=&gt; 2*observable());
const ac= new AbortController();
O.on(observable, v=&gt; console.log("observable", v), { signal: ac.signal });
O.on(double, v=&gt; console.log("double", v), { signal: ac.signal });
observable(observable()+1);
2023-11-29 18:25:21 +01:00
const interval= 5 * 1000;
2023-11-24 20:41:04 +01:00
const id= setInterval(()=&gt; observable(observable()+1), interval);
ac.signal.addEventListener("abort",
()=&gt; setTimeout(()=&gt; clearInterval(id), 2*interval));
setTimeout(()=&gt; ac.abort(), 3*interval)
2024-05-17 22:13:16 +02:00
</code></div><script>Flems(document.getElementById("code-example-1-1ti9ynadhw5c"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { O } from \\\"./esm-with-observables.js\\\";\\nconst observable= O(0);\\n// computation pattern\\nconst double= O(()=> 2*observable());\\n\\nconst ac= new AbortController();\\nO.on(observable, v=> console.log(\\\"observable\\\", v), { signal: ac.signal });\\nO.on(double, v=> console.log(\\\"double\\\", v), { signal: ac.signal });\\n\\nobservable(observable()+1);\\nconst interval= 5 * 1000;\\nconst id= setInterval(()=> observable(observable()+1), interval);\\nac.signal.addEventListener(\\\"abort\\\",\\n\\t()=> setTimeout(()=> clearInterval(id), 2*interval));\\n\\nsetTimeout(()=> ac.abort(), 3*interval)\\n\"},{\"name\":\"esm-with-observables.js\",\"content\":\"// src/observables-common.js\\nvar k = {\\n\\tisObservable(t) {\\n\\t\\treturn !1;\\n\\t},\\n\\tprocessReactiveAttribute(t, e, n, r) {\\n\\t\\treturn n;\\n\\t}\\n};\\nfunction B(t, e = !0) {\\n\\treturn e ? Object.assign(k, t) : (Object.setPrototypeOf(t, k), t);\\n}\\nfunction W(t) {\\n\\treturn k.isPrototypeOf(t) && t !== k ? t : k;\\n}\\n\\n// src/helpers.js\\nvar T = (...t) => Object.prototype.hasOwnProperty.call(...t);\\nfunction A(t) {\\n\\treturn typeof t > \\\"u\\\";\\n}\\nfunction X(t) {\\n\\tlet e = typeof t;\\n\\treturn e !== \\\"object\\\" ? e : t === null ? \\\"null\\\" : Object.prototype.toString.call(t);\\n}\\nfunction q(t, e) {\\n\\tif (!t || !(t instanceof AbortSignal))\\n\\t\\treturn !0;\\n\\tif (!t.aborted)\\n\\t\\treturn t.addEventListener(\\\"abort\\\", e), function() {\\n\\t\\t\\tt.removeEventListener(\\\"abort\\\", e);\\n\\t\\t};\\n}\\nfunction F(t, e) {\\n\\tlet { observedAttributes: n = [] } = t.constructor;\\n\\treturn n.reduce(function(r, o) {\\n\\t\\treturn r[pt(o)] = e(t, o), r;\\n\\t}, {});\\n}\\nfunction pt(t) {\\n\\treturn t.replace(/-./g, (e) => e[1].toUpperCase());\\n}\\n\\n// src/dom-common.js\\nvar d = {\\n\\tsetDeleteAttr: lt,\\n\\tssr: \\\"\\\",\\n\\tD: globalThis.document,\\n\\tF: globalThis.DocumentFragment,\\n\\tH: globalThis.HTMLElement,\\n\\tS: globalThis.SVGElement,\\n\\tM: globalThis.MutationObserver\\n};\\nfunction lt(t, e, n) {\\n\\tif (Reflect.set(t, e, n), !!A(n)) {\\n\\t\\tif (Reflect.deleteProperty(t, e), t instanceof d.H && t.getAttribute(e) === \\\"undefined\\\")\\n\\t\\t\\treturn t.removeAttribute(e);\\n\\t\\tif (Reflect.get(t, e) === \\\"undefined\\\")\\n\\t\\t\\treturn Reflect.set(t, e, \\\"\\\");\\n\\t}\\n}\\nvar C = \\\"__dde_lifecyclesToEvents\\\", y = \\\"dde:connected\\\", S = \\\"dde:disconnected\\\", P = \\\"dde:attributeChanged\\\";\\n\\n// src/dom.js\\nvar _ = [{\\n\\tget scope() {\\n\\t\\treturn d.D.body;\\n\\t},\\n\\thost: (t) => t ? t(d.D.body) : d.D.body,\\n\\tprevent: !0\\n}], m = {\\n\\tget current() {\\n\\t\\treturn _[_.length - 1];\\n\\t},\\n\\tget host() {\\n\\t\\treturn this.current.host;\\n\\t},\\n\\tpreventDefault() {\\n\\t\\tlet { current: t } = this;\\n\\t\\treturn t.prevent = !0, t;\\n\\t},\\n\\tget state() {\\n\\t\\treturn [..._];\\n\\t},\\n\\tpush(t = {}) {\\n\\t\\treturn _.push(Object.assign({}, this.current, { prevent: !1 }, t));\\n\\t},\\n\\tpushRoot() {\\n\\t\\treturn _.push(_[0]);\\n\\t},\\n\\tpop() {\\n\\t\\tif (_.length !== 1)\\n\\t\\t\\treturn _.pop();\\n\\t}\\n};\\nfunction Y(...t) {\\n\\treturn this.appendOriginal(...t), this;\\n}\\nfunction ht(t) {\\n\\treturn t.append === Y || (t.appendOriginal = t.append, t.append = Y), t;\\n}\\nvar $;\\nfunction M(t, e, ...n) {\\n\\tlet r = W(this), o = 0, c, s;\\n\\tswitch ((Object(e) !== e || r.isObservable(e)) && (e = { textContent: e }), !0) {\\n\\t\\tcase typeof t == \\\"function\\\": {\\n\\t\\t\\to = 1, m.push({ scope: t, host: (...g) => g.length ? (o === 1 ? n.unshift(...g) : g.forEach((l) => l(s)), void 0) : s }), c = t(e || void 0);\\n\\t\\t\\tlet a = c instanceof d.F;\\n\\t\\t\\tif (c.nodeName === \\\"#comment\\\")\\n\\t\\t\\t\\tbreak;\\n\\t\\t\\tlet h = M.mark({\\n\\t\\t\\t\\ttype: \\\"component\\\",\\n\\t\\t\\t\\tname: t.name,\\n\\t\\t\\t\\thost: a ? \\\"this\\\" : \\\"parentElement\
2023-11-29 18:25:21 +01:00
const observable= O(0, {
increaseOnlyOdd(add){
console.info(add);
if(add%2 === 0) return this.stopPropagation();
this.value+= add;
}
});
O.on(observable, console.log);
const oninterval= ()=&gt;
O.action(observable, "increaseOnlyOdd", Math.floor(Math.random()*100));
const interval= 5*1000;
setTimeout(
clearInterval,
10*interval,
setInterval(oninterval, interval)
);
2024-05-17 22:13:16 +02:00
</code></div><script>Flems(document.getElementById("code-example-1-ny81g2qun6o"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { O } from \\\"./esm-with-observables.js\\\";\\nconst observable= O(0, {\\n\\tincreaseOnlyOdd(add){\\n\\t\\tconsole.info(add);\\n\\t\\tif(add%2 === 0) return this.stopPropagation();\\n\\t\\tthis.value+= add;\\n\\t}\\n});\\nO.on(observable, console.log);\\nconst oninterval= ()=>\\n\\tO.action(observable, \\\"increaseOnlyOdd\\\", Math.floor(Math.random()*100));\\n\\nconst interval= 5*1000;\\nsetTimeout(\\n\\tclearInterval,\\n\\t10*interval,\\n\\tsetInterval(oninterval, interval)\\n);\\n\"},{\"name\":\"esm-with-observables.js\",\"content\":\"// src/observables-common.js\\nvar k = {\\n\\tisObservable(t) {\\n\\t\\treturn !1;\\n\\t},\\n\\tprocessReactiveAttribute(t, e, n, r) {\\n\\t\\treturn n;\\n\\t}\\n};\\nfunction B(t, e = !0) {\\n\\treturn e ? Object.assign(k, t) : (Object.setPrototypeOf(t, k), t);\\n}\\nfunction W(t) {\\n\\treturn k.isPrototypeOf(t) && t !== k ? t : k;\\n}\\n\\n// src/helpers.js\\nvar T = (...t) => Object.prototype.hasOwnProperty.call(...t);\\nfunction A(t) {\\n\\treturn typeof t > \\\"u\\\";\\n}\\nfunction X(t) {\\n\\tlet e = typeof t;\\n\\treturn e !== \\\"object\\\" ? e : t === null ? \\\"null\\\" : Object.prototype.toString.call(t);\\n}\\nfunction q(t, e) {\\n\\tif (!t || !(t instanceof AbortSignal))\\n\\t\\treturn !0;\\n\\tif (!t.aborted)\\n\\t\\treturn t.addEventListener(\\\"abort\\\", e), function() {\\n\\t\\t\\tt.removeEventListener(\\\"abort\\\", e);\\n\\t\\t};\\n}\\nfunction F(t, e) {\\n\\tlet { observedAttributes: n = [] } = t.constructor;\\n\\treturn n.reduce(function(r, o) {\\n\\t\\treturn r[pt(o)] = e(t, o), r;\\n\\t}, {});\\n}\\nfunction pt(t) {\\n\\treturn t.replace(/-./g, (e) => e[1].toUpperCase());\\n}\\n\\n// src/dom-common.js\\nvar d = {\\n\\tsetDeleteAttr: lt,\\n\\tssr: \\\"\\\",\\n\\tD: globalThis.document,\\n\\tF: globalThis.DocumentFragment,\\n\\tH: globalThis.HTMLElement,\\n\\tS: globalThis.SVGElement,\\n\\tM: globalThis.MutationObserver\\n};\\nfunction lt(t, e, n) {\\n\\tif (Reflect.set(t, e, n), !!A(n)) {\\n\\t\\tif (Reflect.deleteProperty(t, e), t instanceof d.H && t.getAttribute(e) === \\\"undefined\\\")\\n\\t\\t\\treturn t.removeAttribute(e);\\n\\t\\tif (Reflect.get(t, e) === \\\"undefined\\\")\\n\\t\\t\\treturn Reflect.set(t, e, \\\"\\\");\\n\\t}\\n}\\nvar C = \\\"__dde_lifecyclesToEvents\\\", y = \\\"dde:connected\\\", S = \\\"dde:disconnected\\\", P = \\\"dde:attributeChanged\\\";\\n\\n// src/dom.js\\nvar _ = [{\\n\\tget scope() {\\n\\t\\treturn d.D.body;\\n\\t},\\n\\thost: (t) => t ? t(d.D.body) : d.D.body,\\n\\tprevent: !0\\n}], m = {\\n\\tget current() {\\n\\t\\treturn _[_.length - 1];\\n\\t},\\n\\tget host() {\\n\\t\\treturn this.current.host;\\n\\t},\\n\\tpreventDefault() {\\n\\t\\tlet { current: t } = this;\\n\\t\\treturn t.prevent = !0, t;\\n\\t},\\n\\tget state() {\\n\\t\\treturn [..._];\\n\\t},\\n\\tpush(t = {}) {\\n\\t\\treturn _.push(Object.assign({}, this.current, { prevent: !1 }, t));\\n\\t},\\n\\tpushRoot() {\\n\\t\\treturn _.push(_[0]);\\n\\t},\\n\\tpop() {\\n\\t\\tif (_.length !== 1)\\n\\t\\t\\treturn _.pop();\\n\\t}\\n};\\nfunction Y(...t) {\\n\\treturn this.appendOriginal(...t), this;\\n}\\nfunction ht(t) {\\n\\treturn t.append === Y || (t.appendOriginal = t.append, t.append = Y), t;\\n}\\nvar $;\\nfunction M(t, e, ...n) {\\n\\tlet r = W(this), o = 0, c, s;\\n\\tswitch ((Object(e) !== e || r.isObservable(e)) && (e = { textContent: e }), !0) {\\n\\t\\tcase typeof t == \\\"function\\\": {\\n\\t\\t\\to = 1, m.push({ scope: t, host: (...g) => g.length ? (o === 1 ? n.unshift(...g) : g.forEach((l) => l(s)), void 0) : s }), c = t(e || void 0);\\n\\t\\t\\tlet a = c instanceof d.F;\\n\\t\\t\\tif (c.nodeName === \\\"#comment\\\")\\n\\t\\t\\t\\tbreak;\\n\\t\\t\\tlet h = M.mark({\\n\\t\\t\\t\\ttype: \\\"component\\\",\\n\\t\\t\\t\\tname: t.name,\\n\\t\\t\\t\\thost: a ? \\\"this\\\" : \\\"parentElement\\\"\\n\\t\\t\\t});\\n\\t\\t\\tc.prepend(h), a && (s = h);\\n\\t\\t\\tbreak;\\n\\t\\t}\\n\\t\\tcase t === \\\"#text\\\":\\n\\
2023-11-29 18:25:21 +01:00
const todos= O([], {
push(item){
this.value.push(O(item));
},
pop(){
const removed= this.value.pop();
if(removed) O.clear(removed);
},
[O.symbols.onclear](){ // this covers `O.clear(todos)`
O.clear(...this.value);
}
});
2024-05-17 22:13:16 +02:00
import { el, on } from "./esm-with-observables.js";
2023-11-29 18:25:21 +01:00
/** @type {ddeElementAddon&lt;HTMLFormElement&gt;} */
const onsubmit= on("submit", function(event){
event.preventDefault();
const data= new FormData(this);
switch (data.get("op")){
case "A"/*dd*/:
O.action(todos, "push", data.get("todo"));
break;
case "E"/*dit*/: {
const last= todos().at(-1);
if(!last) break;
last(data.get("todo"));
break;
}
case "R"/*emove*/:
O.action(todos, "pop");
break;
}
});
document.body.append(
el("ul").append(
O.el(todos, todos=&gt;
todos.map(textContent=&gt; el("li", textContent)))
),
el("form", null, onsubmit).append(
el("input", { type: "text", name: "todo", placeholder: "Todos text" }),
el(radio, { textContent: "Add", checked: true }),
el(radio, { textContent: "Edit last" }),
el(radio, { textContent: "Remove" }),
el("button", "Submit")
)
);
document.head.append(
el("style", "form{ display: flex; flex-flow: column nowrap; }")
);
function radio({ textContent, checked= false }){
return el("label").append(
el("input", { type: "radio", name: "op", value: textContent[0], checked }),
" ",textContent
)
}
2024-05-17 22:13:16 +02:00
</code></div><script>Flems(document.getElementById("code-example-1-ihanc6k9v9c"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { O } from \\\"./esm-with-observables.js\\\";\\nconst todos= O([], {\\n\\tpush(item){\\n\\t\\tthis.value.push(O(item));\\n\\t},\\n\\tpop(){\\n\\t\\tconst removed= this.value.pop();\\n\\t\\tif(removed) O.clear(removed);\\n\\t},\\n\\t[O.symbols.onclear](){ // this covers `O.clear(todos)`\\n\\t\\tO.clear(...this.value);\\n\\t}\\n});\\n\\nimport { el, on } from \\\"./esm-with-observables.js\\\";\\n/** @type {ddeElementAddon<HTMLFormElement>} */\\nconst onsubmit= on(\\\"submit\\\", function(event){\\n\\tevent.preventDefault();\\n\\tconst data= new FormData(this);\\n\\tswitch (data.get(\\\"op\\\")){\\n\\t\\tcase \\\"A\\\"/*dd*/:\\n\\t\\t\\tO.action(todos, \\\"push\\\", data.get(\\\"todo\\\"));\\n\\t\\t\\tbreak;\\n\\t\\tcase \\\"E\\\"/*dit*/: {\\n\\t\\t\\tconst last= todos().at(-1);\\n\\t\\t\\tif(!last) break;\\n\\t\\t\\tlast(data.get(\\\"todo\\\"));\\n\\t\\t\\tbreak;\\n\\t\\t}\\n\\t\\tcase \\\"R\\\"/*emove*/:\\n\\t\\t\\tO.action(todos, \\\"pop\\\");\\n\\t\\t\\tbreak;\\n\\t}\\n});\\ndocument.body.append(\\n\\tel(\\\"ul\\\").append(\\n\\t\\tO.el(todos, todos=>\\n\\t\\t\\ttodos.map(textContent=> el(\\\"li\\\", textContent)))\\n\\t),\\n\\tel(\\\"form\\\", null, onsubmit).append(\\n\\t\\tel(\\\"input\\\", { type: \\\"text\\\", name: \\\"todo\\\", placeholder: \\\"Todos text\\\" }),\\n\\t\\tel(radio, { textContent: \\\"Add\\\", checked: true }),\\n\\t\\tel(radio, { textContent: \\\"Edit last\\\" }),\\n\\t\\tel(radio, { textContent: \\\"Remove\\\" }),\\n\\t\\tel(\\\"button\\\", \\\"Submit\\\")\\n\\t)\\n);\\ndocument.head.append(\\n\\tel(\\\"style\\\", \\\"form{ display: flex; flex-flow: column nowrap; }\\\")\\n);\\nfunction radio({ textContent, checked= false }){\\n\\treturn el(\\\"label\\\").append(\\n\\t\\tel(\\\"input\\\", { type: \\\"radio\\\", name: \\\"op\\\", value: textContent[0], checked }),\\n\\t\\t\\\" \\\",textContent\\n\\t)\\n}\\n\"},{\"name\":\"esm-with-observables.js\",\"content\":\"// src/observables-common.js\\nvar k = {\\n\\tisObservable(t) {\\n\\t\\treturn !1;\\n\\t},\\n\\tprocessReactiveAttribute(t, e, n, r) {\\n\\t\\treturn n;\\n\\t}\\n};\\nfunction B(t, e = !0) {\\n\\treturn e ? Object.assign(k, t) : (Object.setPrototypeOf(t, k), t);\\n}\\nfunction W(t) {\\n\\treturn k.isPrototypeOf(t) && t !== k ? t : k;\\n}\\n\\n// src/helpers.js\\nvar T = (...t) => Object.prototype.hasOwnProperty.call(...t);\\nfunction A(t) {\\n\\treturn typeof t > \\\"u\\\";\\n}\\nfunction X(t) {\\n\\tlet e = typeof t;\\n\\treturn e !== \\\"object\\\" ? e : t === null ? \\\"null\\\" : Object.prototype.toString.call(t);\\n}\\nfunction q(t, e) {\\n\\tif (!t || !(t instanceof AbortSignal))\\n\\t\\treturn !0;\\n\\tif (!t.aborted)\\n\\t\\treturn t.addEventListener(\\\"abort\\\", e), function() {\\n\\t\\t\\tt.removeEventListener(\\\"abort\\\", e);\\n\\t\\t};\\n}\\nfunction F(t, e) {\\n\\tlet { observedAttributes: n = [] } = t.constructor;\\n\\treturn n.reduce(function(r, o) {\\n\\t\\treturn r[pt(o)] = e(t, o), r;\\n\\t}, {});\\n}\\nfunction pt(t) {\\n\\treturn t.replace(/-./g, (e) => e[1].toUpperCase());\\n}\\n\\n// src/dom-common.js\\nvar d = {\\n\\tsetDeleteAttr: lt,\\n\\tssr: \\\"\\\",\\n\\tD: globalThis.document,\\n\\tF: globalThis.DocumentFragment,\\n\\tH: globalThis.HTMLElement,\\n\\tS: globalThis.SVGElement,\\n\\tM: globalThis.MutationObserver\\n};\\nfunction lt(t, e, n) {\\n\\tif (Reflect.set(t, e, n), !!A(n)) {\\n\\t\\tif (Reflect.deleteProperty(t, e), t instanceof d.H && t.getAttribute(e) === \\\"undefined\\\")\\n\\t\\t\\treturn t.removeAttribute(e);\\n\\t\\tif (Reflect.get(t, e) === \\\"undefined\\\")\\n\\t\\t\\treturn Reflect.set(t, e, \\\"\\\");\\n\\t}\\n}\\nvar C = \\\"__dde_lifecyclesToEvents\\\", y = \\\"dde:connected\\\", S = \\\"dde:disconnected\\\", P = \\\"dde:attributeChanged\\\";\\n\\n// src/dom.js\\nvar _ = [{\\n\\tget scope() {\\n\\t\\treturn d.D.body;\\n\\t},\\n\\thost: (t) => t ? t(d.D.body) : d.D.body,\\n\\tprevent: !0\\n}], m = {\\n\\tget current() {\\n\\t\\treturn _[_.leng
2023-11-29 18:25:21 +01:00
const count= O(0);
2024-05-17 22:13:16 +02:00
import { el } from "./esm-with-observables.js";
2023-11-29 18:25:21 +01:00
document.body.append(
el("p", O(()=&gt; "Currently: "+count())),
el("p", { classList: { red: O(()=&gt; count()%2) }, dataset: { count }, textContent: "Attributes example" })
);
document.head.append(
el("style", ".red { color: red; }")
);
const interval= 5 * 1000;
setTimeout(clearInterval, 10*interval,
setInterval(()=&gt; count(count()+1), interval));
2024-05-17 22:13:16 +02:00
</code></div><script>Flems(document.getElementById("code-example-1-ehcq40v0h5k"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { O } from \\\"./esm-with-observables.js\\\";\\nconst count= O(0);\\n\\nimport { el } from \\\"./esm-with-observables.js\\\";\\ndocument.body.append(\\n\\tel(\\\"p\\\", O(()=> \\\"Currently: \\\"+count())),\\n\\tel(\\\"p\\\", { classList: { red: O(()=> count()%2) }, dataset: { count }, textContent: \\\"Attributes example\\\" })\\n);\\ndocument.head.append(\\n\\tel(\\\"style\\\", \\\".red { color: red; }\\\")\\n);\\n\\nconst interval= 5 * 1000;\\nsetTimeout(clearInterval, 10*interval,\\n\\tsetInterval(()=> count(count()+1), interval));\\n\"},{\"name\":\"esm-with-observables.js\",\"content\":\"// src/observables-common.js\\nvar k = {\\n\\tisObservable(t) {\\n\\t\\treturn !1;\\n\\t},\\n\\tprocessReactiveAttribute(t, e, n, r) {\\n\\t\\treturn n;\\n\\t}\\n};\\nfunction B(t, e = !0) {\\n\\treturn e ? Object.assign(k, t) : (Object.setPrototypeOf(t, k), t);\\n}\\nfunction W(t) {\\n\\treturn k.isPrototypeOf(t) && t !== k ? t : k;\\n}\\n\\n// src/helpers.js\\nvar T = (...t) => Object.prototype.hasOwnProperty.call(...t);\\nfunction A(t) {\\n\\treturn typeof t > \\\"u\\\";\\n}\\nfunction X(t) {\\n\\tlet e = typeof t;\\n\\treturn e !== \\\"object\\\" ? e : t === null ? \\\"null\\\" : Object.prototype.toString.call(t);\\n}\\nfunction q(t, e) {\\n\\tif (!t || !(t instanceof AbortSignal))\\n\\t\\treturn !0;\\n\\tif (!t.aborted)\\n\\t\\treturn t.addEventListener(\\\"abort\\\", e), function() {\\n\\t\\t\\tt.removeEventListener(\\\"abort\\\", e);\\n\\t\\t};\\n}\\nfunction F(t, e) {\\n\\tlet { observedAttributes: n = [] } = t.constructor;\\n\\treturn n.reduce(function(r, o) {\\n\\t\\treturn r[pt(o)] = e(t, o), r;\\n\\t}, {});\\n}\\nfunction pt(t) {\\n\\treturn t.replace(/-./g, (e) => e[1].toUpperCase());\\n}\\n\\n// src/dom-common.js\\nvar d = {\\n\\tsetDeleteAttr: lt,\\n\\tssr: \\\"\\\",\\n\\tD: globalThis.document,\\n\\tF: globalThis.DocumentFragment,\\n\\tH: globalThis.HTMLElement,\\n\\tS: globalThis.SVGElement,\\n\\tM: globalThis.MutationObserver\\n};\\nfunction lt(t, e, n) {\\n\\tif (Reflect.set(t, e, n), !!A(n)) {\\n\\t\\tif (Reflect.deleteProperty(t, e), t instanceof d.H && t.getAttribute(e) === \\\"undefined\\\")\\n\\t\\t\\treturn t.removeAttribute(e);\\n\\t\\tif (Reflect.get(t, e) === \\\"undefined\\\")\\n\\t\\t\\treturn Reflect.set(t, e, \\\"\\\");\\n\\t}\\n}\\nvar C = \\\"__dde_lifecyclesToEvents\\\", y = \\\"dde:connected\\\", S = \\\"dde:disconnected\\\", P = \\\"dde:attributeChanged\\\";\\n\\n// src/dom.js\\nvar _ = [{\\n\\tget scope() {\\n\\t\\treturn d.D.body;\\n\\t},\\n\\thost: (t) => t ? t(d.D.body) : d.D.body,\\n\\tprevent: !0\\n}], m = {\\n\\tget current() {\\n\\t\\treturn _[_.length - 1];\\n\\t},\\n\\tget host() {\\n\\t\\treturn this.current.host;\\n\\t},\\n\\tpreventDefault() {\\n\\t\\tlet { current: t } = this;\\n\\t\\treturn t.prevent = !0, t;\\n\\t},\\n\\tget state() {\\n\\t\\treturn [..._];\\n\\t},\\n\\tpush(t = {}) {\\n\\t\\treturn _.push(Object.assign({}, this.current, { prevent: !1 }, t));\\n\\t},\\n\\tpushRoot() {\\n\\t\\treturn _.push(_[0]);\\n\\t},\\n\\tpop() {\\n\\t\\tif (_.length !== 1)\\n\\t\\t\\treturn _.pop();\\n\\t}\\n};\\nfunction Y(...t) {\\n\\treturn this.appendOriginal(...t), this;\\n}\\nfunction ht(t) {\\n\\treturn t.append === Y || (t.appendOriginal = t.append, t.append = Y), t;\\n}\\nvar $;\\nfunction M(t, e, ...n) {\\n\\tlet r = W(this), o = 0, c, s;\\n\\tswitch ((Object(e) !== e || r.isObservable(e)) && (e = { textContent: e }), !0) {\\n\\t\\tcase typeof t == \\\"function\\\": {\\n\\t\\t\\to = 1, m.push({ scope: t, host: (...g) => g.length ? (o === 1 ? n.unshift(...g) : g.forEach((l) => l(s)), void 0) : s }), c = t(e || void 0);\\n\\t\\t\\tlet a = c instanceof d.F;\\n\\t\\t\\tif (c.nodeName === \\\"#comment\\\")\\n\\t\\t\\t\\tbreak;\\n\\t\\t\\tlet h = M.mark({\\n\\t\\t\\t\\ttype: \\\"component\\\",\\n\\t\\t\\t\\tname: t.name,\\n\\t\\t\\t\\thost: a ? \\\"this\\\" : \\\"parentElement\\\"\\n\\t\\t\\t});\\n\\t\\t\\tc.prepend(h), a && (s = h);\\n\\t\\t\\tb
2023-11-29 18:25:21 +01:00
const count= O(0, {
add(){ this.value= this.value + Math.round(Math.random()*10); }
});
const numbers= O([ count() ], {
push(next){ this.value.push(next); }
});
2024-05-17 22:13:16 +02:00
import { el } from "./esm-with-observables.js";
2023-11-29 18:25:21 +01:00
document.body.append(
O.el(count, count=&gt; count%2
? el("p", "Last number is odd.")
: el()
),
el("p", "Lucky numbers:"),
el("ul").append(
O.el(numbers, numbers=&gt; numbers.toReversed()
.map(n=&gt; el("li", n)))
)
);
const interval= 5*1000;
setTimeout(clearInterval, 10*interval, setInterval(function(){
O.action(count, "add");
O.action(numbers, "push", count());
}, interval));
2024-05-17 22:13:16 +02:00
</code></div><script>Flems(document.getElementById("code-example-2-8r8qappf8mo"), JSON.parse("{\"files\":[{\"name\":\".js\",\"content\":\"import { O } from \\\"./esm-with-observables.js\\\";\\nconst count= O(0, {\\n\\tadd(){ this.value= this.value + Math.round(Math.random()*10); }\\n});\\nconst numbers= O([ count() ], {\\n\\tpush(next){ this.value.push(next); }\\n});\\n\\nimport { el } from \\\"./esm-with-observables.js\\\";\\ndocument.body.append(\\n\\tO.el(count, count=> count%2\\n\\t\\t? el(\\\"p\\\", \\\"Last number is odd.\\\")\\n\\t\\t: el()\\n\\t),\\n\\tel(\\\"p\\\", \\\"Lucky numbers:\\\"),\\n\\tel(\\\"ul\\\").append(\\n\\t\\tO.el(numbers, numbers=> numbers.toReversed()\\n\\t\\t\\t.map(n=> el(\\\"li\\\", n)))\\n\\t)\\n);\\n\\nconst interval= 5*1000;\\nsetTimeout(clearInterval, 10*interval, setInterval(function(){\\n\\tO.action(count, \\\"add\\\");\\n\\tO.action(numbers, \\\"push\\\", count());\\n}, interval));\\n\"},{\"name\":\"esm-with-observables.js\",\"content\":\"// src/observables-common.js\\nvar k = {\\n\\tisObservable(t) {\\n\\t\\treturn !1;\\n\\t},\\n\\tprocessReactiveAttribute(t, e, n, r) {\\n\\t\\treturn n;\\n\\t}\\n};\\nfunction B(t, e = !0) {\\n\\treturn e ? Object.assign(k, t) : (Object.setPrototypeOf(t, k), t);\\n}\\nfunction W(t) {\\n\\treturn k.isPrototypeOf(t) && t !== k ? t : k;\\n}\\n\\n// src/helpers.js\\nvar T = (...t) => Object.prototype.hasOwnProperty.call(...t);\\nfunction A(t) {\\n\\treturn typeof t > \\\"u\\\";\\n}\\nfunction X(t) {\\n\\tlet e = typeof t;\\n\\treturn e !== \\\"object\\\" ? e : t === null ? \\\"null\\\" : Object.prototype.toString.call(t);\\n}\\nfunction q(t, e) {\\n\\tif (!t || !(t instanceof AbortSignal))\\n\\t\\treturn !0;\\n\\tif (!t.aborted)\\n\\t\\treturn t.addEventListener(\\\"abort\\\", e), function() {\\n\\t\\t\\tt.removeEventListener(\\\"abort\\\", e);\\n\\t\\t};\\n}\\nfunction F(t, e) {\\n\\tlet { observedAttributes: n = [] } = t.constructor;\\n\\treturn n.reduce(function(r, o) {\\n\\t\\treturn r[pt(o)] = e(t, o), r;\\n\\t}, {});\\n}\\nfunction pt(t) {\\n\\treturn t.replace(/-./g, (e) => e[1].toUpperCase());\\n}\\n\\n// src/dom-common.js\\nvar d = {\\n\\tsetDeleteAttr: lt,\\n\\tssr: \\\"\\\",\\n\\tD: globalThis.document,\\n\\tF: globalThis.DocumentFragment,\\n\\tH: globalThis.HTMLElement,\\n\\tS: globalThis.SVGElement,\\n\\tM: globalThis.MutationObserver\\n};\\nfunction lt(t, e, n) {\\n\\tif (Reflect.set(t, e, n), !!A(n)) {\\n\\t\\tif (Reflect.deleteProperty(t, e), t instanceof d.H && t.getAttribute(e) === \\\"undefined\\\")\\n\\t\\t\\treturn t.removeAttribute(e);\\n\\t\\tif (Reflect.get(t, e) === \\\"undefined\\\")\\n\\t\\t\\treturn Reflect.set(t, e, \\\"\\\");\\n\\t}\\n}\\nvar C = \\\"__dde_lifecyclesToEvents\\\", y = \\\"dde:connected\\\", S = \\\"dde:disconnected\\\", P = \\\"dde:attributeChanged\\\";\\n\\n// src/dom.js\\nvar _ = [{\\n\\tget scope() {\\n\\t\\treturn d.D.body;\\n\\t},\\n\\thost: (t) => t ? t(d.D.body) : d.D.body,\\n\\tprevent: !0\\n}], m = {\\n\\tget current() {\\n\\t\\treturn _[_.length - 1];\\n\\t},\\n\\tget host() {\\n\\t\\treturn this.current.host;\\n\\t},\\n\\tpreventDefault() {\\n\\t\\tlet { current: t } = this;\\n\\t\\treturn t.prevent = !0, t;\\n\\t},\\n\\tget state() {\\n\\t\\treturn [..._];\\n\\t},\\n\\tpush(t = {}) {\\n\\t\\treturn _.push(Object.assign({}, this.current, { prevent: !1 }, t));\\n\\t},\\n\\tpushRoot() {\\n\\t\\treturn _.push(_[0]);\\n\\t},\\n\\tpop() {\\n\\t\\tif (_.length !== 1)\\n\\t\\t\\treturn _.pop();\\n\\t}\\n};\\nfunction Y(...t) {\\n\\treturn this.appendOriginal(...t), this;\\n}\\nfunction ht(t) {\\n\\treturn t.append === Y || (t.appendOriginal = t.append, t.append = Y), t;\\n}\\nvar $;\\nfunction M(t, e, ...n) {\\n\\tlet r = W(this), o = 0, c, s;\\n\\tswitch ((Object(e) !== e || r.isObservable(e)) && (e = { textContent: e }), !0) {\\n\\t\\tcase typeof t == \\\"function\\\": {\\n\\t\\t\\to = 1, m.push({ scope: t, host: (...g) => g.length ? (o === 1 ? n.unshift(...g) : g.forEach((l) => l(s)), void 0) : s }), c = t(e || void 0);\\n\\t\\t\\tlet a = c instanceof d.F;\\n\\t\\t\\tif (c.nodeName === \\\"#comment\\\