1
0
mirror of https://github.com/jaandrle/deka-dom-el synced 2025-07-01 04:12:14 +02:00

🎉 docs/scopes

This commit is contained in:
2023-12-04 18:19:30 +01:00
parent fb14d51cb4
commit 5c3f3e1de1
8 changed files with 271 additions and 27 deletions

View File

@ -1,4 +1,4 @@
import { chainableAppend, el, scope } from "deka-dom-el";
import { el } from "deka-dom-el";
class Test {
constructor(params){
this._params= params;
@ -13,22 +13,25 @@ document.body.append(
elClass(Test, { textContent: "Hello World" })
);
function elClass(c, props, ...addons){
import { chainableAppend, scope } from "deka-dom-el";
function elClass(_class, attributes, ...addons){
let element, element_host;
scope.push({
scope: c, //just informative purposes
host: (...c)=> c.length
? (!element
? addons.unshift(...c)
: c.forEach(c=> c(element_host)), undefined)
: element_host
scope: _class, //just informative purposes
host: (...addons_append)=> addons_append.length
? (
!element
? addons.unshift(...addons_append)
: addons_append.forEach(c=> c(element_host))
, undefined)
: element_host
});
const C= new c(props);
element= C.render();
const is_fragment= el instanceof DocumentFragment;
const instance= new _class(attributes);
element= instance.render();
const is_fragment= element instanceof DocumentFragment;
const el_mark= el.mark({ //this creates html comment `<dde:mark …/>`
type: "class-component",
name: C.name,
name: _class.name,
host: is_fragment ? "this" : "parentElement",
});
element.prepend(el_mark);

View File

@ -0,0 +1,19 @@
import { el, empty } from "deka-dom-el";
document.body.append(
el(component),
el("button", {
textContent: "Remove",
onclick: ()=> empty(document.body),
type: "button"
})
);
import { on } from "deka-dom-el";
import { O } from "deka-dom-el/observables";
function component(){
const textContent= O("Click to change text.");
const onclickChange= on("click", function redispatch(){
textContent("Text changed! "+(new Date()).toString())
});
return el("p", textContent, onclickChange);
}

View File

@ -0,0 +1,35 @@
/* PSEUDO-CODE!!! */
import { el } from "deka-dom-el";
import { O } from "deka-dom-el/observables";
function component(){
/* prepare changeable data */
const dataA= O("data");
const dataB= O("data");
/* define data flow (can be asynchronous) */
fetchAPI().then(data_new=> dataA(data_new));
setTimeout(()=> dataB("DATA"));
/* declarative UI */
return el().append(
el("h1", {
textContent: "Example",
/* declarative attribute(s) */
classList: { declarative: dataB }
}),
el("ul").append(
/* declarative element(s) */
O.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)))
)
);
}
function subcomponent({ id }){
/* prepare changeable data */
const textContent= O("…");
/* define data flow (can be asynchronous) */
fetchAPI(id).then(text=> textContent(text));
/* declarative UI */
return el("li", { textContent, dataId: id });
}

View File

@ -0,0 +1,18 @@
import { el, scope, on, dispatchEvent } from "deka-dom-el";
document.body.append(
el(component)
);
function component(){
const { host }= scope; // good practise!
host(
console.log,
on("click", function redispatch(){
// this `host` ↘ still corresponds to the host ↖ of the component
dispatchEvent("redispatch")(host());
})
);
// this `host` ↘ still corresponds to the host ↖ of the component
setTimeout(()=> dispatchEvent("timeout")(host()), 750)
return el("p", "Clickable paragraph!");
}

View File

@ -0,0 +1,30 @@
/* PSEUDO-CODE!!! */
import { el, on, scope } from "deka-dom-el";
function component(){
const ul= el("ul");
const ac= new AbortController();
fetchAPI({ signal: ac.signal }).then(data=> {
data.forEach(d=> ul.append(el("li", d)));
});
scope.host(
/* element was remove before data fetched */
on.disconnected(()=> ac.abort())
);
return ul;
/**
* NEVER EVER!!
* let data;
* fetchAPI().then(d=> data= O(d));
*
* OR NEVER EVER!!
* const ul= el("ul");
* fetchAPI().then(d=> {
* const data= O("data");
* ul.append(el("li", data));
* });
*
* // THE HOST IS PROBABLY DIFFERENT THAN
* // YOU EXPECT AND OBSERVABLES MAY BE
* // UNEXPECTEDLY REMOVED!!!
* */
}

View File

@ -1,3 +1,3 @@
// use NPM or for example https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js
import { scope, el, on } from "deka-dom-el";
import { scope, el } from "deka-dom-el";
/** @type {ddeElementAddon} */

View File

@ -35,6 +35,40 @@ export function page({ pkg, info }){
" component as class instances."
),
el(example, { src: fileURL("./components/examples/scopes/class-component.js"), page_id }),
el("p").append(
"As you can see, the ", el("code", "scope.host()"), " is stored temporarily and synchronously.",
" Therefore, at least in the beginning of using library, it is the good practise to store",
" ", el("code", "host"), " in the root of your component. As it may be changed, typically when",
" there is asynchronous code in the component."
),
el(code, { src: fileURL("./components/examples/scopes/good-practise.js"), page_id }),
el(h3, "Scopes, observables 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"),
" is changed. Internally, there is association between ", el("code", "textContent"), " and the paragraph",
" similar to using ", el("code", "S.on(textContent, /* update the paragraph */)"), "."
),
el("p").append(
"This listener must be removed when the component is removed from the DOM. To do it, the library",
" assign internally ", el("code", "on.disconnect(/* 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" }), "."
),
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)",
" and imperative manipulation of elements.",
),
el(code, { src: fileURL("./components/examples/scopes/imperative.js"), page_id }),
el(mnemonic)
);