mirror of
https://github.com/jaandrle/deka-dom-el
synced 2025-07-01 04:12:14 +02:00
⚡ Replace “observable” term with “signal” (#19)
* ⚡ refact docs to make editing (now renaming observables to signal) easier * ⚡ ⚡ use signal(s) term isntead of observable(s) * ⚡ 🔤 version + typo * 🐛 customElement example (0→S) * 📺 version in package-lock.json
This commit is contained in:
@ -14,7 +14,7 @@ ${host}{
|
||||
}
|
||||
`;
|
||||
|
||||
const dde_content= s.cat(new URL("../../dist/esm-with-observables.js", import.meta.url)).toString();
|
||||
const dde_content= s.cat(new URL("../../dist/esm-with-signals.js", import.meta.url)).toString();
|
||||
|
||||
import { el } from "deka-dom-el";
|
||||
import { code } from "./code.html.js";
|
||||
@ -29,7 +29,7 @@ import { relative } from "node:path";
|
||||
export function example({ src, language= "js", page_id }){
|
||||
registerClientPart(page_id);
|
||||
const content= s.cat(src).toString()
|
||||
.replaceAll(/ from "deka-dom-el(\/observables)?";/g, ' from "./esm-with-observables.js";');
|
||||
.replaceAll(/ from "deka-dom-el(\/signals)?";/g, ' from "./esm-with-signals.js";');
|
||||
const id= "code-example-"+generateCodeId(src);
|
||||
return el().append(
|
||||
el(code, { id, content, language, className: example.name }),
|
||||
@ -38,7 +38,7 @@ export function example({ src, language= "js", page_id }){
|
||||
}
|
||||
function elCode({ id, content, extension: name }){
|
||||
const options= JSON.stringify({
|
||||
files: [{ name, content }, { name: "esm-with-observables.js", content: dde_content }],
|
||||
files: [{ name, content }, { name: "esm-with-signals.js", content: dde_content }],
|
||||
toolbar: false
|
||||
});
|
||||
return el("script", `Flems(document.getElementById("${id}"), JSON.parse(${JSON.stringify(options)}));`);
|
||||
|
@ -1,12 +1,12 @@
|
||||
// use NPM or for example https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js
|
||||
// use NPM or for example https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js
|
||||
import {
|
||||
customElementRender,
|
||||
customElementWithDDE,
|
||||
observedAttributes,
|
||||
} from "deka-dom-el";
|
||||
/** @type {ddePublicElementTagNameMap} */
|
||||
import { O } from "deka-dom-el/observables";
|
||||
O.observedAttributes;
|
||||
import { S } from "deka-dom-el/signals";
|
||||
S.observedAttributes;
|
||||
|
||||
// “internal” utils
|
||||
import { lifecyclesToEvents } from "deka-dom-el";
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { el } from "deka-dom-el";
|
||||
import { O } from "deka-dom-el/observables";
|
||||
const clicks= O(0);
|
||||
import { S } from "deka-dom-el/signals";
|
||||
const clicks= S(0);
|
||||
document.body.append(
|
||||
el().append(
|
||||
el("p", O(()=>
|
||||
el("p", S(()=>
|
||||
"Hello World "+"🎉".repeat(clicks())
|
||||
)),
|
||||
el("button", {
|
||||
|
@ -1,16 +0,0 @@
|
||||
import { O } from "deka-dom-el/observables";
|
||||
const observable= O(0);
|
||||
// computation pattern
|
||||
const double= O(()=> 2*observable());
|
||||
|
||||
const ac= new AbortController();
|
||||
O.on(observable, v=> console.log("observable", v), { signal: ac.signal });
|
||||
O.on(double, v=> console.log("double", v), { signal: ac.signal });
|
||||
|
||||
observable(observable()+1);
|
||||
const interval= 5 * 1000;
|
||||
const id= setInterval(()=> observable(observable()+1), interval);
|
||||
ac.signal.addEventListener("abort",
|
||||
()=> setTimeout(()=> clearInterval(id), 2*interval));
|
||||
|
||||
setTimeout(()=> ac.abort(), 3*interval)
|
@ -1,6 +0,0 @@
|
||||
// use NPM or for example https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js
|
||||
import { O, observable } from "deka-dom-el/observables";
|
||||
O===observable
|
||||
/** @type {ddeObservable} */
|
||||
/** @type {ddeAction} */
|
||||
/** @type {ddeActions} */
|
@ -1,12 +0,0 @@
|
||||
import { O } from "deka-dom-el/observables";
|
||||
// α — `observable` represents a reactive value
|
||||
const observable= O(0);
|
||||
// β — just reacts on observable changes
|
||||
O.on(observable, console.log);
|
||||
// γ — just updates the value
|
||||
const update= ()=> observable(observable()+1);
|
||||
|
||||
update();
|
||||
const interval= 5*1000;
|
||||
setTimeout(clearInterval, 10*interval,
|
||||
setInterval(update, interval));
|
@ -7,9 +7,9 @@ document.body.append(
|
||||
type: "button"
|
||||
})
|
||||
);
|
||||
import { O } from "deka-dom-el/observables";
|
||||
import { S } from "deka-dom-el/signals";
|
||||
function component(){
|
||||
const textContent= O("Click to change text.");
|
||||
const textContent= S("Click to change text.");
|
||||
|
||||
const onclickChange= on("click", function redispatch(){
|
||||
textContent("Text changed! "+(new Date()).toString())
|
||||
|
@ -1,10 +1,10 @@
|
||||
/* PSEUDO-CODE!!! */
|
||||
import { el } from "deka-dom-el";
|
||||
import { O } from "deka-dom-el/observables";
|
||||
import { S } from "deka-dom-el/signals";
|
||||
function component(){
|
||||
/* prepare changeable data */
|
||||
const dataA= O("data");
|
||||
const dataB= O("data");
|
||||
const dataA= S("data");
|
||||
const dataB= S("data");
|
||||
/* define data flow (can be asynchronous) */
|
||||
fetchAPI().then(data_new=> dataA(data_new));
|
||||
setTimeout(()=> dataB("DATA"));
|
||||
@ -17,17 +17,17 @@ function component(){
|
||||
}),
|
||||
el("ul").append(
|
||||
/* declarative element(s) */
|
||||
O.el(dataA, data=> data.map(d=> el("li", d)))
|
||||
S.el(dataA, data=> data.map(d=> el("li", d)))
|
||||
),
|
||||
el("ul").append(
|
||||
/* declarative component(s) */
|
||||
O.el(dataA, data=> data.map(d=> el(subcomponent, d)))
|
||||
S.el(dataA, data=> data.map(d=> el(subcomponent, d)))
|
||||
)
|
||||
);
|
||||
}
|
||||
function subcomponent({ id }){
|
||||
/* prepare changeable data */
|
||||
const textContent= O("…");
|
||||
const textContent= S("…");
|
||||
/* define data flow (can be asynchronous) */
|
||||
fetchAPI(id).then(text=> textContent(text));
|
||||
/* declarative UI */
|
||||
|
@ -1,3 +1,3 @@
|
||||
// use NPM or for example https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js
|
||||
// use NPM or for example https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js
|
||||
import { scope, el } from "deka-dom-el";
|
||||
/** @type {ddeElementAddon} */
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { O } from "deka-dom-el/observables";
|
||||
const observable= O(0, {
|
||||
import { S } from "deka-dom-el/signals";
|
||||
const signal= S(0, {
|
||||
increaseOnlyOdd(add){
|
||||
console.info(add);
|
||||
if(add%2 === 0) return this.stopPropagation();
|
||||
this.value+= add;
|
||||
}
|
||||
});
|
||||
O.on(observable, console.log);
|
||||
S.on(signal, console.log);
|
||||
const oninterval= ()=>
|
||||
O.action(observable, "increaseOnlyOdd", Math.floor(Math.random()*100));
|
||||
S.action(signal, "increaseOnlyOdd", Math.floor(Math.random()*100));
|
||||
|
||||
const interval= 5*1000;
|
||||
setTimeout(
|
@ -1,14 +1,14 @@
|
||||
import { O } from "deka-dom-el/observables";
|
||||
const todos= O([], {
|
||||
import { S } from "deka-dom-el/signals";
|
||||
const todos= S([], {
|
||||
push(item){
|
||||
this.value.push(O(item));
|
||||
this.value.push(S(item));
|
||||
},
|
||||
pop(){
|
||||
const removed= this.value.pop();
|
||||
if(removed) O.clear(removed);
|
||||
if(removed) S.clear(removed);
|
||||
},
|
||||
[O.symbols.onclear](){ // this covers `O.clear(todos)`
|
||||
O.clear(...this.value);
|
||||
[S.symbols.onclear](){ // this covers `O.clear(todos)`
|
||||
S.clear(...this.value);
|
||||
}
|
||||
});
|
||||
|
||||
@ -19,7 +19,7 @@ const onsubmit= on("submit", function(event){
|
||||
const data= new FormData(this);
|
||||
switch (data.get("op")){
|
||||
case "A"/*dd*/:
|
||||
O.action(todos, "push", data.get("todo"));
|
||||
S.action(todos, "push", data.get("todo"));
|
||||
break;
|
||||
case "E"/*dit*/: {
|
||||
const last= todos().at(-1);
|
||||
@ -28,13 +28,13 @@ const onsubmit= on("submit", function(event){
|
||||
break;
|
||||
}
|
||||
case "R"/*emove*/:
|
||||
O.action(todos, "pop");
|
||||
S.action(todos, "pop");
|
||||
break;
|
||||
}
|
||||
});
|
||||
document.body.append(
|
||||
el("ul").append(
|
||||
O.el(todos, todos=>
|
||||
S.el(todos, todos=>
|
||||
todos.map(textContent=> el("li", textContent)))
|
||||
),
|
||||
el("form", null, onsubmit).append(
|
16
docs_src/components/examples/signals/computations-abort.js
Normal file
16
docs_src/components/examples/signals/computations-abort.js
Normal file
@ -0,0 +1,16 @@
|
||||
import { S } from "deka-dom-el/signals";
|
||||
const signal= S(0);
|
||||
// computation pattern
|
||||
const double= S(()=> 2*signal());
|
||||
|
||||
const ac= new AbortController();
|
||||
S.on(signal, v=> console.log("signal", v), { signal: ac.signal });
|
||||
S.on(double, v=> console.log("double", v), { signal: ac.signal });
|
||||
|
||||
signal(signal()+1);
|
||||
const interval= 5 * 1000;
|
||||
const id= setInterval(()=> signal(signal()+1), interval);
|
||||
ac.signal.addEventListener("abort",
|
||||
()=> setTimeout(()=> clearInterval(id), 2*interval));
|
||||
|
||||
setTimeout(()=> ac.abort(), 3*interval)
|
@ -1,10 +1,10 @@
|
||||
import { O } from "deka-dom-el/observables";
|
||||
const count= O(0);
|
||||
import { S } from "deka-dom-el/signals";
|
||||
const count= S(0);
|
||||
|
||||
import { el } from "deka-dom-el";
|
||||
document.body.append(
|
||||
el("p", O(()=> "Currently: "+count())),
|
||||
el("p", { classList: { red: O(()=> count()%2) }, dataset: { count }, textContent: "Attributes example" })
|
||||
el("p", S(()=> "Currently: "+count())),
|
||||
el("p", { classList: { red: S(()=> count()%2) }, dataset: { count }, textContent: "Attributes example" })
|
||||
);
|
||||
document.head.append(
|
||||
el("style", ".red { color: red; }")
|
@ -1,26 +1,26 @@
|
||||
import { O } from "deka-dom-el/observables";
|
||||
const count= O(0, {
|
||||
import { S } from "deka-dom-el/signals";
|
||||
const count= S(0, {
|
||||
add(){ this.value= this.value + Math.round(Math.random()*10); }
|
||||
});
|
||||
const numbers= O([ count() ], {
|
||||
const numbers= S([ count() ], {
|
||||
push(next){ this.value.push(next); }
|
||||
});
|
||||
|
||||
import { el } from "deka-dom-el";
|
||||
document.body.append(
|
||||
O.el(count, count=> count%2
|
||||
S.el(count, count=> count%2
|
||||
? el("p", "Last number is odd.")
|
||||
: el()
|
||||
),
|
||||
el("p", "Lucky numbers:"),
|
||||
el("ul").append(
|
||||
O.el(numbers, numbers=> numbers.toReversed()
|
||||
S.el(numbers, numbers=> numbers.toReversed()
|
||||
.map(n=> el("li", n)))
|
||||
)
|
||||
);
|
||||
|
||||
const interval= 5*1000;
|
||||
setTimeout(clearInterval, 10*interval, setInterval(function(){
|
||||
O.action(count, "add");
|
||||
O.action(numbers, "push", count());
|
||||
S.action(count, "add");
|
||||
S.action(numbers, "push", count());
|
||||
}, interval));
|
6
docs_src/components/examples/signals/intro.js
Normal file
6
docs_src/components/examples/signals/intro.js
Normal file
@ -0,0 +1,6 @@
|
||||
// use NPM or for example https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js
|
||||
import { S, signal } from "deka-dom-el/signals";
|
||||
S===signal
|
||||
/** @type {ddeSignal} */
|
||||
/** @type {ddeAction} */
|
||||
/** @type {ddeActions} */
|
12
docs_src/components/examples/signals/signals.js
Normal file
12
docs_src/components/examples/signals/signals.js
Normal file
@ -0,0 +1,12 @@
|
||||
import { S } from "deka-dom-el/signals";
|
||||
// α — `signal` represents a reactive value
|
||||
const signal= S(0);
|
||||
// β — just reacts on signal changes
|
||||
S.on(signal, console.log);
|
||||
// γ — just updates the value
|
||||
const update= ()=> signal(signal()+1);
|
||||
|
||||
update();
|
||||
const interval= 5*1000;
|
||||
setTimeout(clearInterval, 10*interval,
|
||||
setInterval(update, interval));
|
@ -13,7 +13,7 @@ export function mnemonic(){
|
||||
el("code", "observedAttributes(<custom-element>)"), " — returns record of observed attributes (keys uses camelCase)",
|
||||
),
|
||||
el("li").append(
|
||||
el("code", "O.observedAttributes(<custom-element>)"), " — returns record of observed attributes (keys uses camelCase and values are observables)",
|
||||
el("code", "S.observedAttributes(<custom-element>)"), " — returns record of observed attributes (keys uses camelCase and values are signals)",
|
||||
),
|
||||
el("li").append(
|
||||
el("code", "lifecyclesToEvents(<class-declaration>)"), " — convert lifecycle methods to events, can be also used as decorator",
|
||||
|
@ -1,28 +0,0 @@
|
||||
import { el } from "deka-dom-el";
|
||||
import { mnemonicUl } from "../mnemonicUl.html.js";
|
||||
|
||||
export function mnemonic(){
|
||||
return mnemonicUl().append(
|
||||
el("li").append(
|
||||
el("code", "O(<value>)"), " — observable: reactive value",
|
||||
),
|
||||
el("li").append(
|
||||
el("code", "O(()=> <computation>)"), " — read-only observable: reactive value dependent on calculation using other observables",
|
||||
),
|
||||
el("li").append(
|
||||
el("code", "O.on(<observable>, <listener>[, <options>])"), " — listen to the observable value changes",
|
||||
),
|
||||
el("li").append(
|
||||
el("code", "O.clear(...<observables>)"), " — off and clear observables",
|
||||
),
|
||||
el("li").append(
|
||||
el("code", "O(<value>, <actions>)"), " — observable: pattern to create complex reactive objects/arrays",
|
||||
),
|
||||
el("li").append(
|
||||
el("code", "O.action(<observable>, <action-name>, ...<action-arguments>)"), " — invoke an action for given observable"
|
||||
),
|
||||
el("li").append(
|
||||
el("code", "O.el(<observable>, <function-returning-dom>)"), " — render partial dom structure (template) based on the current observable value",
|
||||
)
|
||||
);
|
||||
}
|
28
docs_src/components/mnemonic/signals-init.js
Normal file
28
docs_src/components/mnemonic/signals-init.js
Normal file
@ -0,0 +1,28 @@
|
||||
import { el } from "deka-dom-el";
|
||||
import { mnemonicUl } from "../mnemonicUl.html.js";
|
||||
|
||||
export function mnemonic(){
|
||||
return mnemonicUl().append(
|
||||
el("li").append(
|
||||
el("code", "S(<value>)"), " — signal: reactive value",
|
||||
),
|
||||
el("li").append(
|
||||
el("code", "S(()=> <computation>)"), " — read-only signal: reactive value dependent on calculation using other signals",
|
||||
),
|
||||
el("li").append(
|
||||
el("code", "S.on(<signal>, <listener>[, <options>])"), " — listen to the signal value changes",
|
||||
),
|
||||
el("li").append(
|
||||
el("code", "S.clear(...<signals>)"), " — off and clear signals",
|
||||
),
|
||||
el("li").append(
|
||||
el("code", "S(<value>, <actions>)"), " — signal: pattern to create complex reactive objects/arrays",
|
||||
),
|
||||
el("li").append(
|
||||
el("code", "S.action(<signal>, <action-name>, ...<action-arguments>)"), " — invoke an action for given signal"
|
||||
),
|
||||
el("li").append(
|
||||
el("code", "S.el(<signal>, <function-returning-dom>)"), " — render partial dom structure (template) based on the current signal value",
|
||||
)
|
||||
);
|
||||
}
|
@ -1,6 +1,11 @@
|
||||
import { simplePage } from "./layout/simplePage.html.js";
|
||||
export const info= {
|
||||
href: "./",
|
||||
title: "Introduction",
|
||||
description: "Introducing a library.",
|
||||
};
|
||||
|
||||
import { el } from "deka-dom-el";
|
||||
import { simplePage } from "./layout/simplePage.html.js";
|
||||
import { example } from "./components/example.html.js";
|
||||
/** @param {import("./types.d.ts").PageAttrs} attrs */
|
||||
export function page({ pkg, info }){
|
||||
@ -23,10 +28,10 @@ export function page({ pkg, info }){
|
||||
el("p").append(
|
||||
"Next step is providing interactivity not only for our UI templates.",
|
||||
" ",
|
||||
"We introduce observables (", el("code", "O"), ") and how them incorporate to UI templates.",
|
||||
"We introduce signals (", el("code", "O"), ") and how them incorporate to UI templates.",
|
||||
),
|
||||
el("p").append(
|
||||
"Now we will clarify how the observables are incorporated into our templates with regard ",
|
||||
"Now we will clarify how the signals are incorporated into our templates with regard ",
|
||||
"to application performance. This is not the only reason the library uses ",
|
||||
el("code", "scope"), "s. We will look at how they work in components represented ",
|
||||
"in JavaScript by functions."
|
||||
|
@ -1,6 +1,10 @@
|
||||
import { simplePage } from "./layout/simplePage.html.js";
|
||||
export const info= {
|
||||
title: "Elements",
|
||||
description: "Basic concepts of elements modifications and creations.",
|
||||
};
|
||||
|
||||
import { el } from "deka-dom-el";
|
||||
import { simplePage } from "./layout/simplePage.html.js";
|
||||
import { example } from "./components/example.html.js";
|
||||
import { h3 } from "./components/pageUtils.html.js";
|
||||
import { mnemonic } from "./components/mnemonic/elements-init.js";
|
||||
@ -64,7 +68,7 @@ export function page({ pkg, info }){
|
||||
"This is handy to concat conditional classes."
|
||||
),
|
||||
el("li").append(
|
||||
"Use ", el("code", "classList"), " to toggle specific classes. This will be handy later when the reactivity via observables is beeing introduced.",
|
||||
"Use ", el("code", "classList"), " to toggle specific classes. This will be handy later when the reactivity via signals is beeing introduced.",
|
||||
),
|
||||
el("li").append(
|
||||
"The ", el("code", "assign"), " also accepts the ", el("code", "undefined"), " as a value for any property to remove it from the element declaratively. ",
|
||||
|
@ -1,6 +1,10 @@
|
||||
import { simplePage } from "./layout/simplePage.html.js";
|
||||
export const info= {
|
||||
title: "Events and Addons",
|
||||
description: "Using not only events in UI declaratively.",
|
||||
};
|
||||
|
||||
import { el } from "deka-dom-el";
|
||||
import { simplePage } from "./layout/simplePage.html.js";
|
||||
import { example } from "./components/example.html.js";
|
||||
import { h3 } from "./components/pageUtils.html.js";
|
||||
import { mnemonic } from "./components/mnemonic/events-init.js";
|
||||
|
@ -1,9 +1,13 @@
|
||||
import { simplePage } from "./layout/simplePage.html.js";
|
||||
export const info= {
|
||||
title: "Signals and reactivity",
|
||||
description: "Handling reactivity in UI via signals.",
|
||||
};
|
||||
|
||||
import { el } from "deka-dom-el";
|
||||
import { simplePage } from "./layout/simplePage.html.js";
|
||||
import { example } from "./components/example.html.js";
|
||||
import { h3 } from "./components/pageUtils.html.js";
|
||||
import { mnemonic } from "./components/mnemonic/observables-init.js";
|
||||
import { mnemonic } from "./components/mnemonic/signals-init.js";
|
||||
import { code } from "./components/code.html.js";
|
||||
/** @param {string} url */
|
||||
const fileURL= url=> new URL(url, import.meta.url);
|
||||
@ -12,24 +16,24 @@ const fileURL= url=> new URL(url, import.meta.url);
|
||||
export function page({ pkg, info }){
|
||||
const page_id= info.id;
|
||||
return el(simplePage, { info, pkg }).append(
|
||||
el("h2", "Using observables to manage reactivity"),
|
||||
el("h2", "Using signals to manage reactivity"),
|
||||
el("p").append(
|
||||
"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.",
|
||||
" signals may be a viable approach.",
|
||||
),
|
||||
el(code, { src: fileURL("./components/examples/observables/intro.js"), page_id }),
|
||||
el(code, { src: fileURL("./components/examples/signals/intro.js"), page_id }),
|
||||
|
||||
el(h3, "Introducing observables"),
|
||||
el(h3, "Introducing signals"),
|
||||
el("p").append(
|
||||
"Using observables, we split program logic into the three parts.",
|
||||
"Using signals, we split program logic into the three parts.",
|
||||
" Firstly (α), we create a variable (constant) representing reactive",
|
||||
" value. Somewhere later, we can register (β) a logic reacting",
|
||||
" to the observable value changes. Similarly, in a remaining part (γ), we",
|
||||
" can update the observable value."
|
||||
" to the signal value changes. Similarly, in a remaining part (γ), we",
|
||||
" can update the signal value."
|
||||
),
|
||||
el(example, { src: fileURL("./components/examples/observables/observables.js"), page_id }),
|
||||
el(example, { src: fileURL("./components/examples/signals/signals.js"), page_id }),
|
||||
el("p").append(
|
||||
"All this is just an example of ",
|
||||
el("a", { textContent: "Event-driven programming", href: "https://en.wikipedia.org/wiki/Event-driven_programming", title: "Wikipedia: Event-driven programming" }),
|
||||
@ -40,35 +44,35 @@ export function page({ pkg, info }){
|
||||
" to the same reactive entity."
|
||||
),
|
||||
el("p").append(
|
||||
"Observables are implemented in the library as functions. To see current value",
|
||||
" of observable, just call it without any arguments ", el("code", "console.log(observable())"), ".",
|
||||
" To update the observable value, pass any argument ", el("code", "observable('a new value')"), ".",
|
||||
" For listenning the observable value changes, use ", el("code", "O.on(observable, console.log)"), "."
|
||||
"Signals are implemented in the library as functions. To see current value",
|
||||
" of signal, just call it without any arguments ", el("code", "console.log(signal())"), ".",
|
||||
" To update the signal value, pass any argument ", el("code", "signal('a new value')"), ".",
|
||||
" For listenning the signal value changes, use ", el("code", "S.on(signal, console.log)"), "."
|
||||
),
|
||||
el("p").append(
|
||||
"Similarly to the ", el("code", "on"), " function to register DOM events listener.",
|
||||
" You can use ", el("code", "AbortController"), "/", el("code", "AbortSignal"), " to",
|
||||
" ", el("em", "off"), "/stop listenning. In example, you also found the way for representing",
|
||||
" “live” piece of code computation pattern (derived observable):"
|
||||
" “live” piece of code computation pattern (derived signal):"
|
||||
),
|
||||
el(example, { src: fileURL("./components/examples/observables/computations-abort.js"), page_id }),
|
||||
el(example, { src: fileURL("./components/examples/signals/computations-abort.js"), page_id }),
|
||||
|
||||
el(h3, "Observables and actions"),
|
||||
el(h3, "Signals and actions"),
|
||||
el("p").append(
|
||||
el("code", "O(/* primitive */)"), " allows you to declare simple reactive variables, typically",
|
||||
el("code", "S(/* primitive */)"), " allows you to declare simple reactive variables, typically",
|
||||
" around ", el("em", "immutable"), " ", el("a", { textContent: "primitive types", title: "Primitive | MDN", href: "https://developer.mozilla.org/en-US/docs/Glossary/Primitive" }), ".",
|
||||
" ",
|
||||
"However, it may also be necessary to use reactive arrays, objects, or other complex reactive structures."
|
||||
),
|
||||
el(example, { src: fileURL("./components/examples/observables/actions-demo.js"), page_id }),
|
||||
el(example, { src: fileURL("./components/examples/signals/actions-demo.js"), page_id }),
|
||||
el("p", "…but typical user-case is object/array (maps, sets and other mutable objects):"),
|
||||
el(example, { src: fileURL("./components/examples/observables/actions-todos.js"), page_id }),
|
||||
el(example, { src: fileURL("./components/examples/signals/actions-todos.js"), page_id }),
|
||||
el("p").append(
|
||||
"In some way, you can compare it with ", el("a", { textContent: "useReducer", href: "https://react.dev/reference/react/useReducer", title: "useReducer hook | React docs" }),
|
||||
" hook from React. So, the ", el("code", "O(<data>, <actions>)"), " pattern creates",
|
||||
" hook from React. So, the ", el("code", "S(<data>, <actions>)"), " pattern creates",
|
||||
" a store “machine”. We can then invoke (dispatch) registered action by calling",
|
||||
" ", el("code", "O.action(<observable>, <name>, ...<args>)"), " after the action call",
|
||||
" the observable calls all its listeners. This can be stopped by calling ", el("code", "this.stopPropagation()"),
|
||||
" ", el("code", "S.action(<signal>, <name>, ...<args>)"), " after the action call",
|
||||
" the signal calls all its listeners. This can be stopped by calling ", el("code", "this.stopPropagation()"),
|
||||
" in the method representing the given action. As it can be seen in examples, the “store” value is",
|
||||
" available also in the function for given action (", el("code", "this.value"), ")."
|
||||
),
|
||||
@ -79,24 +83,24 @@ export function page({ pkg, info }){
|
||||
el("li", "to change some attribute(s) of existing element(s)"),
|
||||
el("li", "to generate elements itself dynamically – this covers conditions and loops")
|
||||
),
|
||||
el(example, { src: fileURL("./components/examples/observables/dom-attrs.js"), page_id }),
|
||||
el(example, { src: fileURL("./components/examples/signals/dom-attrs.js"), page_id }),
|
||||
el("p").append(
|
||||
"To derived attribute based on value of observable variable just use the observable as",
|
||||
" a value of the attribute (", el("code", "assign(element, { attribute: O('value') })"), ").",
|
||||
"To derived attribute based on value of signal variable just use the signal as",
|
||||
" a value of the attribute (", el("code", "assign(element, { attribute: S('value') })"), ").",
|
||||
" ", el("code", "assign"), "/", el("code", "el"), " provides ways to glue reactive attributes/classes",
|
||||
" more granularly into the DOM. Just use dedicated build-in attributes ", el("code", "dataset"), ", ",
|
||||
el("code", "ariaset"), " and ", el("code", "classList"), "."
|
||||
),
|
||||
el("p").append(
|
||||
"For computation, you can use the “derived observable” (see above) like ", el("code", "assign(element, { textContent: O(()=> 'Hello '+WorldObservable()) })"), ".",
|
||||
"For computation, you can use the “derived signal” (see above) like ", el("code", "assign(element, { textContent: S(()=> 'Hello '+WorldSignal()) })"), ".",
|
||||
" ",
|
||||
"This is read-only observable its value is computed based on given function and updated when any observable used in the function changes."
|
||||
"This is read-only signal its value is computed based on given function and updated when any signal used in the function changes."
|
||||
),
|
||||
el("p").append(
|
||||
"To represent part of the template filled dynamically based on the observable value use ", el("code", "O.el(observable, DOMgenerator)"), ".",
|
||||
"To represent part of the template filled dynamically based on the signal value use ", el("code", "S.el(signal, DOMgenerator)"), ".",
|
||||
" This was already used in the todo example above or see:"
|
||||
),
|
||||
el(example, { src: fileURL("./components/examples/observables/dom-el.js"), page_id }),
|
||||
el(example, { src: fileURL("./components/examples/signals/dom-el.js"), page_id }),
|
||||
|
||||
el(mnemonic)
|
||||
);
|
@ -1,6 +1,10 @@
|
||||
import { simplePage } from "./layout/simplePage.html.js";
|
||||
export const info= {
|
||||
title: "Scopes and components",
|
||||
description: "Organizing UI into components",
|
||||
};
|
||||
|
||||
import { el } from "deka-dom-el";
|
||||
import { simplePage } from "./layout/simplePage.html.js";
|
||||
import { example } from "./components/example.html.js";
|
||||
import { h3 } from "./components/pageUtils.html.js";
|
||||
import { mnemonic } from "./components/mnemonic/scopes-init.js";
|
||||
@ -43,14 +47,14 @@ export function page({ pkg, info }){
|
||||
),
|
||||
el(code, { src: fileURL("./components/examples/scopes/good-practise.js"), page_id }),
|
||||
|
||||
el(h3, "Scopes, observables and cleaning magic"),
|
||||
el(h3, "Scopes, signals and cleaning magic"),
|
||||
el("p").append(
|
||||
"The ", el("code", "host"), " is internally used to register the cleaning procedure,",
|
||||
" when the component (", el("code", "host"), " element) is removed from the DOM."
|
||||
),
|
||||
el(example, { src: fileURL("./components/examples/scopes/cleaning.js"), page_id }),
|
||||
el("p").append(
|
||||
"The text content of the paragraph is changing when the value of the observable ", el("code", "textContent"),
|
||||
"The text content of the paragraph is changing when the value of the signal ", el("code", "textContent"),
|
||||
" is changed. Internally, there is association between ", el("code", "textContent"), " and the paragraph",
|
||||
" similar to using ", el("code", "S.on(textContent, /* update the paragraph */)"), "."
|
||||
),
|
||||
@ -59,13 +63,13 @@ export function page({ pkg, info }){
|
||||
" assign internally ", el("code", "on.disconnected(/* remove the listener */)(host())"), " to the host element."
|
||||
),
|
||||
el("p", { className: "notice" }).append(
|
||||
"The library DOM API and observables works ideally when used declaratively.",
|
||||
" It means, you split your app logic into three parts as it was itroduced in ", el("a", { textContent: "Observables", href: "http://localhost:40911/docs/p04-observables#h-introducing-observables" }), "."
|
||||
"The library DOM API and signals works ideally when used declaratively.",
|
||||
" It means, you split your app logic into three parts as it was itroduced in ", el("a", { textContent: "Signals", href: "http://localhost:40911/docs/p04-signals#h-introducing-signals" }), "."
|
||||
),
|
||||
el(code, { src: fileURL("./components/examples/scopes/declarative.js"), page_id }),
|
||||
el("p").append(
|
||||
"Strictly speaking, the imperative way of using the library is not prohibited.",
|
||||
" Just be careful (rather avoid) mixing declarative approach (using observables)",
|
||||
" Just be careful (rather avoid) mixing declarative approach (using signals)",
|
||||
" and imperative manipulation of elements.",
|
||||
),
|
||||
el(code, { src: fileURL("./components/examples/scopes/imperative.js"), page_id }),
|
||||
|
@ -1,6 +1,10 @@
|
||||
import { simplePage } from "./layout/simplePage.html.js";
|
||||
export const info= {
|
||||
title: "Custom elements",
|
||||
description: "Using custom elements in combinantion with DDE",
|
||||
};
|
||||
|
||||
import { el } from "deka-dom-el";
|
||||
import { simplePage } from "./layout/simplePage.html.js";
|
||||
import { example } from "./components/example.html.js";
|
||||
import { h3 } from "./components/pageUtils.html.js";
|
||||
import { mnemonic } from "./components/mnemonic/customElement-init.js";
|
||||
|
@ -2,14 +2,11 @@ export const path_target= {
|
||||
root: "docs/",
|
||||
css: "docs/"
|
||||
};
|
||||
export const pages= [
|
||||
{ id: "index", href: "./", title: "Introduction", description: "Introducing a library." },
|
||||
{ id: "p02-elements", href: "p02-elements", title: "Elements", description: "Basic concepts of elements modifications and creations." },
|
||||
{ id: "p03-events", href: "p03-events", title: "Events and Addons", description: "Using not only events in UI declaratively." },
|
||||
{ id: "p04-observables", href: "p04-observables", title: "Observables and reactivity", description: "Handling reactivity in UI via observables." },
|
||||
{ id: "p05-scopes", href: "p05-scopes", title: "Scopes and components", description: "Organizing UI into components" },
|
||||
{ id: "p06-customElement", href: "p06-customElement", title: "Custom elements", description: "Using custom elements in combinantion with DDE" },
|
||||
];
|
||||
/**
|
||||
* This variable will be filled with the list of pages during the build process (see `bs/docs.js`).
|
||||
* @type {import("./types.d.ts").Info[]}
|
||||
* */
|
||||
export let pages= [];
|
||||
/**
|
||||
* @typedef registerClientFile
|
||||
* @type {function}
|
||||
|
Reference in New Issue
Block a user