mirror of
https://github.com/jaandrle/deka-dom-el
synced 2025-07-01 20:32:13 +02:00
🔤 texts helpers
infuture may be also translations
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
class CustomHTMLElement extends HTMLElement{
|
||||
static tagName = "custom-element"; // just suggestion, we can use `el(CustomHTMLElement.tagName)`
|
||||
static tagName= "custom-element"; // just suggestion, we can use `el(CustomHTMLElement.tagName)`
|
||||
static observedAttributes= [ "custom-attribute" ];
|
||||
constructor(){
|
||||
super();
|
||||
|
5
docs_src/components/examples/introducing/3ps.js
Normal file
5
docs_src/components/examples/introducing/3ps.js
Normal file
@ -0,0 +1,5 @@
|
||||
const onchage=
|
||||
event=>
|
||||
console.log("Reacting to the:", event); // A
|
||||
input.addEventListener("change", onchange); // B
|
||||
input.dispatchEvent(new Event("change")); // C
|
@ -1,41 +1,53 @@
|
||||
import { t, T } from "./utils/index.js";
|
||||
export const info= {
|
||||
href: "./",
|
||||
title: "Introduction",
|
||||
description: "Introducing a library.",
|
||||
title: t`Introduction`,
|
||||
description: t`Introducing a library.`,
|
||||
};
|
||||
|
||||
import { el } from "deka-dom-el";
|
||||
import { simplePage } from "./layout/simplePage.html.js";
|
||||
import { h3 } from "./components/pageUtils.html.js";
|
||||
import { example } from "./components/example.html.js";
|
||||
import { code } from "./components/code.html.js";
|
||||
/** @param {string} url */
|
||||
const fileURL= url=> new URL(url, import.meta.url);
|
||||
const references= {
|
||||
};
|
||||
/** @param {import("./types.d.ts").PageAttrs} attrs */
|
||||
export function page({ pkg, info }){
|
||||
const page_id= info.id;
|
||||
return el(simplePage, { info, pkg }).append(
|
||||
el("p", "The library tries to provide pure JavaScript tool(s) to create reactive interfaces."),
|
||||
el("p").append(
|
||||
"We start with creating and modifying a static elements and end up with UI templates.",
|
||||
" ",
|
||||
el("i").append(
|
||||
"From ", el("code", "document.createElement"), " to ", el("code", "el"), "."
|
||||
),
|
||||
" ",
|
||||
"Then we go through the native events system and the way to include it declaratively in UI templates.",
|
||||
" ",
|
||||
el("i").append(
|
||||
"From ", el("code", "element.addEventListener"), " to ", el("code", "on"), "."
|
||||
),
|
||||
),
|
||||
el("p").append(
|
||||
"Next step is providing interactivity not only for our UI templates.",
|
||||
" ",
|
||||
"We introduce signals (", el("code", "S"), ") and how them incorporate to UI templates.",
|
||||
),
|
||||
el("p").append(
|
||||
"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."
|
||||
),
|
||||
el(example, { src: new URL("./components/examples/helloWorld.js", import.meta.url), page_id }),
|
||||
el("p", t`The library tries to provide pure JavaScript tool(s) to create reactive interfaces using …`),
|
||||
el(h3, t`Event-driven programming (3 parts separation ≡ 3PS)`),
|
||||
el("p").append(t`
|
||||
Let's introduce the basic principle on which the library is built. We'll use the JavaScript listener as
|
||||
a starting point.
|
||||
`),
|
||||
el(code, { src: fileURL("./components/examples/introducing/3ps.js"), page_id }),
|
||||
el("p").append(t`
|
||||
As we can see, in the code at location “A” we define how to react when the function is called with
|
||||
any event as an argument. At that moment, we don't care who/why/how the function was called. Similarly,
|
||||
at point “B”, we reference to a function to be called on the event without caring 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 don't care if/how someone is listening for the event.
|
||||
`),
|
||||
|
||||
el("p").append(...T`
|
||||
We start with creating and modifying a static elements and end up with UI templates.
|
||||
${el("em").append(...T`From ${el("code", "document.createElement")} to ${el("code", "el")}.`)}.
|
||||
Then we go through the native events system and the way to include it declaratively in UI templates.
|
||||
${el("em").append(...T`From ${el("code", "element.addEventListener")} to ${el("code", "on")}.`)}
|
||||
`),
|
||||
el("p").append(...T`
|
||||
Next step is providing interactivity not only for our UI templates.
|
||||
We introduce signals (${el("code", "S")}) and how them incorporate to UI templates.
|
||||
`),
|
||||
el("p").append(...T`
|
||||
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.
|
||||
`),
|
||||
el(example, { src: fileURL("./components/examples/introducing/helloWorld.js"), page_id }),
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { T, t } from "./utils/index.js";
|
||||
export const info= {
|
||||
title: "Elements",
|
||||
description: "Basic concepts of elements modifications and creations.",
|
||||
title: t`Elements`,
|
||||
description: t`Basic concepts of elements modifications and creations.`,
|
||||
};
|
||||
|
||||
import { el } from "deka-dom-el";
|
||||
@ -14,32 +15,32 @@ const fileURL= url=> new URL(url, import.meta.url);
|
||||
const references= {
|
||||
/** document.createElement() */
|
||||
mdn_create: {
|
||||
title: "MDN documentation page for document.createElement()",
|
||||
title: t`MDN documentation page for document.createElement()`,
|
||||
href: "https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement",
|
||||
},
|
||||
/** Interface Description Language (`el.textContent`) */
|
||||
mdn_idl: {
|
||||
title: "MDN page about Interface Description Language",
|
||||
title: t`MDN page about Interface Description Language`,
|
||||
href: "https://developer.mozilla.org/en-US/docs/Glossary/IDL",
|
||||
},
|
||||
/** HTMLElement */
|
||||
mdn_el: {
|
||||
title: "MDN documentation page for HTMLElement",
|
||||
title: t`MDN documentation page for HTMLElement`,
|
||||
href: "https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement"
|
||||
},
|
||||
/** HTMLParagraphElement */
|
||||
mdn_p: {
|
||||
title: "MDN documentation page for HTMLParagraphElement (`p` tag)",
|
||||
title: t`MDN documentation page for HTMLParagraphElement (\`p\` tag)`,
|
||||
href: "https://developer.mozilla.org/en-US/docs/Web/API/HTMLParagraphElement"
|
||||
},
|
||||
/** `[a, b] = [1, 2]` */
|
||||
mdn_destruct: {
|
||||
title: "MDN page about destructuring assignment syntax (e.g. `[a, b] = [1, 2]`)",
|
||||
title: t`MDN page about destructuring assignment syntax (e.g. \`[a, b] = [1, 2]\`)`,
|
||||
href: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment",
|
||||
},
|
||||
/** document.createElementNS() */
|
||||
mdn_ns: {
|
||||
title: "MDN documentation page for document.createElementNS() (e.g. for SVG elements)",
|
||||
title: t`MDN documentation page for document.createElementNS() (e.g. for SVG elements)`,
|
||||
href: "https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS",
|
||||
}
|
||||
};
|
||||
@ -47,103 +48,106 @@ const references= {
|
||||
export function page({ pkg, info }){
|
||||
const page_id= info.id;
|
||||
return el(simplePage, { info, pkg }).append(
|
||||
el("h2", "Native JavaScript DOM elements creations"),
|
||||
el("p", "Let’s go through all patterns we would like to use and what needs to be improved for better experience."),
|
||||
el("h2", t`Native JavaScript DOM elements creations`),
|
||||
el("p", t`
|
||||
Let’s go through all patterns we would like to use and what needs to be improved for better experience.
|
||||
`),
|
||||
|
||||
el(code, { src: fileURL("./components/examples/elements/intro.js"), page_id }),
|
||||
|
||||
el(h3, "Creating element(s) (with custom attributes)"),
|
||||
el("p").append(
|
||||
"You can create a native DOM element by using the ", el("a", references.mdn_create).append( el("code", "document.createElement()") ), ". ",
|
||||
"It is also possible to provide a some attribute(s) declaratively using ", el("code", "Object.assign()"), ". ",
|
||||
"More precisely, this way you can sets some ",
|
||||
el("a", references.mdn_idl).append(
|
||||
el("abbr", { textContent: "IDL", title: "Interface Description Language" })
|
||||
), " also known as a JavaScript property."
|
||||
),
|
||||
el(h3, t`Creating element(s) (with custom attributes)`),
|
||||
el("p").append(...T`
|
||||
You can create a native DOM element by using the ${el("a", references.mdn_create).append(
|
||||
el("code", "document.createElement()") )}. It is also possible to provide a some attribute(s) declaratively
|
||||
using ${el("code", "Object.assign()")}. More precisely, this way you can sets some
|
||||
${el("a", references.mdn_idl).append( el("abbr", { textContent: "IDL", title: "Interface Description Language" }))}
|
||||
also known as a JavaScript property.
|
||||
`),
|
||||
el(example, { src: fileURL("./components/examples/elements/nativeCreateElement.js"), page_id }),
|
||||
el("p").append(
|
||||
"To make this easier, you can use the ", el("code", "el"), " function. ",
|
||||
"Internally in basic examples, it is wrapper around ", el("code", "assign(document.createElement(…), { … })"), "."
|
||||
),
|
||||
el("p").append(...T`
|
||||
To make this easier, you can use the ${el("code", "el")} function. Internally in basic examples,
|
||||
it is wrapper around ${el("code", "assign(document.createElement(…), { … })")}.
|
||||
`),
|
||||
el(example, { src: fileURL("./components/examples/elements/dekaCreateElement.js"), page_id }),
|
||||
el("p").append(
|
||||
"The ", el("code", "assign"), " function provides improved behaviour of ", el("code", "Object.assign()"), ". ",
|
||||
"You can declaratively sets any IDL and attribute of the given element. ",
|
||||
"Function prefers IDL and fallback to the ", el("code", "element.setAttribute"), " if there is no writable property in the element prototype."
|
||||
),
|
||||
el("p").append(
|
||||
"You can study all JavaScript elements interfaces to the corresponding HTML elements. ",
|
||||
"All HTML elements inherits from ", el("a", { textContent: "HTMLElement", ...references.mdn_el }), ". ",
|
||||
"To see all available IDLs for example for paragraphs, see ", el("a", { textContent: "HTMLParagraphElement", ...references.mdn_p }), ". ",
|
||||
"Moreover, the ", el("code", "assign"), " provides a way to sets declaratively some convenient properties:"
|
||||
),
|
||||
el("p").append(...T`
|
||||
The ${el("code", "assign")} function provides improved behaviour of ${el("code", "Object.assign()")}.
|
||||
You can declaratively sets any IDL and attribute of the given element. Function prefers IDL and fallback
|
||||
to the ${el("code", "element.setAttribute")} if there is no writable property in the element prototype.
|
||||
`),
|
||||
el("p").append(...T`
|
||||
You can study all JavaScript elements interfaces to the corresponding HTML elements. All HTML elements
|
||||
inherits from ${el("a", { textContent: "HTMLElement", ...references.mdn_el })}. To see
|
||||
all available IDLs for example for paragraphs, see ${el("a", { textContent: "HTMLParagraphElement", ...references.mdn_p })}.
|
||||
Moreover, the ${el("code", "assign")} provides a way to sets declaratively some convenient properties:
|
||||
`),
|
||||
el("ul").append(
|
||||
el("li").append(
|
||||
"It is possible to sets ", el("code", "data-*"), "/", el("code", "aria-*"), " attributes using object notation."
|
||||
),
|
||||
el("li").append(
|
||||
"In opposite, it is also possible to sets ", el("code", "data-*"), "/", el("code", "aria-*"), " attribute using camelCase notation."
|
||||
),
|
||||
el("li").append(
|
||||
"You can use string or object as a value for ", el("code", "style"), " property."
|
||||
),
|
||||
el("li").append(
|
||||
el("code", "className"), " (IDL – preffered)/", el("code", "class"), " are ways to add CSS class to the element. ",
|
||||
"You can use string (similarly to ", el("code", "class=\"…\"") ," syntax in HTML) or array of strings. ",
|
||||
"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 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. ",
|
||||
"Also for some IDL the corresponding attribute is removed as it can be confusing. ",
|
||||
el("em").append(
|
||||
"For example, natievly the element’s ", el("code", "id"), " is removed by setting the IDL to an empty string."
|
||||
)
|
||||
),
|
||||
el("li").append(
|
||||
"You can use ", el("code", "="), " or ", el("code", "."), " to force processing given key as attribute/property of the element."
|
||||
)
|
||||
),
|
||||
el("p").append(
|
||||
"For processing, the ", el("code", "assign"), " internally uses ", el("code", "assignAttribute"), " and ", el("code", "classListDeclarative"), "."
|
||||
el("li").append(...T`
|
||||
It is possible to sets ${el("code", "data-*")}/${el("code", "aria-*")} attributes using object notation.
|
||||
`),
|
||||
el("li").append(...T`
|
||||
In opposite, it is also possible to sets ${el("code", "data-*")}/${el("code", "aria-*")} attribute
|
||||
using camelCase notation.
|
||||
`),
|
||||
el("li").append(...T`You can use string or object as a value for ${el("code", "style")} property.`),
|
||||
el("li").append(...T`
|
||||
${el("code", "className")} (IDL – preffered)/${el("code", "class")} are ways to add CSS classes
|
||||
to the element. You can use string (similarly to ${el("code", "class=\"…\"")} syntax in HTML) or
|
||||
array of strings. This is handy to concat conditional classes.
|
||||
`),
|
||||
el("li").append(...T`
|
||||
Use ${el("code", "classList")} to toggle specific classes. This will be handy later when
|
||||
the reactivity via signals is beeing introduced.
|
||||
`),
|
||||
el("li").append(...T`
|
||||
The ${el("code", "assign")} also accepts the ${el("code", "undefined")} as a value for any property
|
||||
to remove it from the element declaratively. Also for some IDL the corresponding attribute is removed
|
||||
as it can be confusing. ${el("em").append(...T`For example, natievly the element’s ${el("code", "id")}
|
||||
is removed by setting the IDL to an empty string.`)}
|
||||
`),
|
||||
el("li").append(...T`
|
||||
You can use ${el("code", "=")} or ${el("code", ".")} to force processing given key as attribute/property
|
||||
of the element.
|
||||
`)
|
||||
),
|
||||
el("p").append(...T`
|
||||
For processing, the ${el("code", "assign")} internally uses ${el("code", "assignAttribute")} and
|
||||
${el("code", "classListDeclarative")}.
|
||||
`),
|
||||
el(example, { src: fileURL("./components/examples/elements/dekaAssign.js"), page_id }),
|
||||
|
||||
el(h3, "Native JavaScript templating"),
|
||||
el("p", "By default, the native JS has no good way to define HTML template using DOM API:"),
|
||||
el(h3, t`Native JavaScript templating`),
|
||||
el("p", t`By default, the native JS has no good way to define HTML template using DOM API:`),
|
||||
el(example, { src: fileURL("./components/examples/elements/nativeAppend.js"), page_id }),
|
||||
el("p").append(
|
||||
"This library therefore overwrites the ", el("code", "append"), " method of created elements to always return parent element."
|
||||
),
|
||||
el("p").append(...T`
|
||||
This library therefore overwrites the ${el("code", "append")} method of created elements to always return
|
||||
parent element.
|
||||
`),
|
||||
el(example, { src: fileURL("./components/examples/elements/dekaAppend.js"), page_id }),
|
||||
|
||||
|
||||
el(h3, "Basic (state-less) components"),
|
||||
el("p").append(
|
||||
"You can use functions for encapsulation (repeating) logic. ",
|
||||
"The ", el("code", "el"), " accepts function as first argument. ",
|
||||
"In that case, the function should return dom elements and the second argument for ", el("code", "el"), " is argument for given element."
|
||||
),
|
||||
el(h3, t`Basic (state-less) components`),
|
||||
el("p").append(...T`
|
||||
You can use functions for encapsulation (repeating) logic. The ${el("code", "el")} accepts function
|
||||
as first argument. In that case, the function should return dom elements and the second argument for
|
||||
${el("code", "el")} is argument for given element.
|
||||
`),
|
||||
el(example, { src: fileURL("./components/examples/elements/dekaBasicComponent.js"), page_id }),
|
||||
el("p").append(
|
||||
"As you can see, in case of state-less/basic components there is no difference",
|
||||
" between calling component function directly or using ", el("code", "el"), " function.",
|
||||
),
|
||||
el("p", { className: "notice" }).append(
|
||||
"It is nice to use similar naming convention as native DOM API. ",
|
||||
"This allows us to use ", el("a", { textContent: "the destructuring assignment syntax", ...references.mdn_destruct }),
|
||||
" and keep track of the native API (things are best remembered through regular use).",
|
||||
),
|
||||
el("p").append(...T`
|
||||
As you can see, in case of state-less/basic components there is no difference between calling component
|
||||
function directly or using ${el("code", "el")} function.
|
||||
`),
|
||||
el("p", { className: "notice" }).append(...T`
|
||||
It is nice to use similar naming convention as native DOM API. This allows us to use
|
||||
${el("a", { textContent: t`the destructuring assignment syntax`, ...references.mdn_destruct })} and keep
|
||||
track of the native API (things are best remembered through regular use).
|
||||
`),
|
||||
|
||||
el(h3, "Creating non-HTML elements"),
|
||||
el("p").append(
|
||||
"Similarly to the native DOM API (", el("a", references.mdn_ns).append(el("code", "document.createElementNS")), ") for non-HTML elements",
|
||||
" we need to tell JavaScript which kind of the element to create.",
|
||||
" We can use the ", el("code", "elNS"), " function:"
|
||||
),
|
||||
el(h3, t`Creating non-HTML elements`),
|
||||
el("p").append(...T`
|
||||
Similarly to the native DOM API (${el("a", references.mdn_ns).append(el("code", "document.createElementNS"))})
|
||||
for non-HTML elements we need to tell JavaScript which kind of the element to create. We can use
|
||||
the ${el("code", "elNS")} function:
|
||||
`),
|
||||
el(example, { src: fileURL("./components/examples/elements/dekaElNS.js"), page_id }),
|
||||
|
||||
el(mnemonic)
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { T, t } from "./utils/index.js";
|
||||
export const info= {
|
||||
title: "Events and Addons",
|
||||
description: "Using not only events in UI declaratively.",
|
||||
title: t`Events and Addons`,
|
||||
description: t`Using not only events in UI declaratively.`,
|
||||
};
|
||||
|
||||
import { el } from "deka-dom-el";
|
||||
@ -14,12 +15,12 @@ const fileURL= url=> new URL(url, import.meta.url);
|
||||
const references= {
|
||||
/** element.addEventListener() */
|
||||
mdn_listen: {
|
||||
title: "MDN documentation page for elemetn.addEventListener",
|
||||
title: t`MDN documentation page for elemetn.addEventListener`,
|
||||
href: "https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener",
|
||||
},
|
||||
/** AbortSignal+element.addEventListener */
|
||||
mdn_abortListener: {
|
||||
title: "MDN documentation page for using AbortSignal with element.addEventListener",
|
||||
title: t`MDN documentation page for using AbortSignal with element.addEventListener`,
|
||||
href: "https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#signal",
|
||||
},
|
||||
/** comparison listening options by WebReflection */
|
||||
@ -36,7 +37,7 @@ const references= {
|
||||
},
|
||||
/** Readding the element to the DOM fix by Vue */
|
||||
vue_fix: {
|
||||
title: "Vue and Web Components, lifecycle implementation readding the element to the DOM",
|
||||
title: t`Vue and Web Components, lifecycle implementation readding the element to the DOM`,
|
||||
href: "https://vuejs.org/guide/extras/web-components.html#lifecycle",
|
||||
}
|
||||
};
|
||||
@ -44,115 +45,103 @@ const references= {
|
||||
export function page({ pkg, info }){
|
||||
const page_id= info.id;
|
||||
return el(simplePage, { info, pkg }).append(
|
||||
el("h2", "Listenning to the native DOM events and other Addons"),
|
||||
el("p").append(
|
||||
"We quickly introduce helper to listening to the native DOM events.",
|
||||
" ",
|
||||
"And library syntax/pattern so-called ", el("em", "Addon"), " to",
|
||||
" incorporate not only this in UI templates declaratively."
|
||||
),
|
||||
el("h2", t`Listenning to the native DOM events and other Addons`),
|
||||
el("p").append(...T`
|
||||
We quickly introduce helper to listening to the native DOM events. And library syntax/pattern so-called
|
||||
${el("em", t`Addon`)} to incorporate not only this in UI templates declaratively.
|
||||
`),
|
||||
|
||||
el(code, { src: fileURL("./components/examples/events/intro.js"), page_id }),
|
||||
|
||||
el(h3, "Events and listenners"),
|
||||
el("p").append(
|
||||
"In JavaScript you can listen to the native DOM events of the given element by using ",
|
||||
el("a", references.mdn_listen).append( el("code", "element.addEventListener(type, listener, options)") ), ".",
|
||||
" ",
|
||||
"The library provides an alternative (", el("code", "on"), ") accepting the differen order",
|
||||
" of the arguments:"
|
||||
),
|
||||
el(h3, t`Events and listenners`),
|
||||
el("p").append(...T`
|
||||
In JavaScript you can listen to the native DOM events of the given element by using
|
||||
${el("a", references.mdn_listen).append( el("code", "element.addEventListener(type, listener, options)") )}.
|
||||
The library provides an alternative (${el("code", "on")}) accepting the differen order of the arguments:
|
||||
`),
|
||||
el(example, { src: fileURL("./components/examples/events/compare.js"), page_id }),
|
||||
el("p").append(
|
||||
"…this is actually one of the two differences. The another one is that ", el("code", "on"),
|
||||
" accepts only object as the ", el("code", "options"), " (but it is still optional)."
|
||||
),
|
||||
el("p", { className: "notice" }).append(
|
||||
"The other difference is that there is ", el("strong", "no"), " ", el("code", "off"), " function.",
|
||||
" ",
|
||||
"You can remove listener declaratively using ", el("a", { textContent: "AbortSignal", ...references.mdn_abortListener }),
|
||||
":"
|
||||
),
|
||||
el("p").append(...T`
|
||||
…this is actually one of the two differences. The another one is that ${el("code", "on")} accepts only
|
||||
object as the ${el("code", "options")} (but it is still optional).
|
||||
`),
|
||||
el("p", { className: "notice" }).append(...T`
|
||||
The other difference is that there is ${el("strong", "no")} ${el("code", "off")} function. You can remove
|
||||
listener declaratively using ${el("a", { textContent: "AbortSignal", ...references.mdn_abortListener })}:
|
||||
`),
|
||||
el(example, { src: fileURL("./components/examples/events/abortSignal.js"), page_id }),
|
||||
el("div", { className: "notice" }).append(
|
||||
el("p", "So, there are (typically) three ways to handle events. You can use:"),
|
||||
el("p", t`So, there are (typically) three ways to handle events. You can use:`),
|
||||
el("ul").append(
|
||||
el("li").append( el("code", `el("button", { textContent: "click me", "=onclick": "console.log(event)" })`)),
|
||||
el("li").append( el("code", `el("button", { textContent: "click me", onclick: console.log })`)),
|
||||
el("li").append( el("code", `el("button", { textContent: "click me" }, on("click", console.log))`))
|
||||
),
|
||||
el("p").append(
|
||||
"In the first example we force to use HTML attribute (it corresponds to ", el("code", `<button onclick="console.log(event)">click me</button>`), ").",
|
||||
" ",
|
||||
el("em", "Side note: this can be useful in case of SSR."),
|
||||
" ",
|
||||
"To study difference, you can read a nice summary here: ", el("a", { textContent: "GIST @WebReflection/web_events.md", ...references.web_events }), "."
|
||||
)
|
||||
el("p").append(...T`
|
||||
In the first example we force to use HTML attribute (it corresponds to
|
||||
${el("code", `<button onclick="console.log(event)">click me</button>`)}). ${el("em", t`Side note:
|
||||
this can be useful in case of SSR.`)} To study difference, you can read a nice summary here:
|
||||
${el("a", { textContent: "GIST @WebReflection/web_events.md", ...references.web_events })}.
|
||||
`)
|
||||
),
|
||||
|
||||
el(h3, "Addons"),
|
||||
el("p").append(
|
||||
"From practical point of view, ", el("em", "Addons"), " are just functions that accept any html element",
|
||||
" as their first parameter. You can see that the ", el("code", "on(…)"), " fullfills this requirement."
|
||||
),
|
||||
el("p").append(
|
||||
"You can use Addons as ≥3rd argument of ", el("code", "el"), " function. This way is possible to extends",
|
||||
" you templates by additional (3rd party) functionalities. But for now mainly, you can add events listeners:"
|
||||
),
|
||||
el(h3, t`Addons`),
|
||||
el("p").append(...T`
|
||||
From practical point of view, ${el("em", t`Addons`)} are just functions that accept any HTML element as
|
||||
their first parameter. You can see that the ${el("code", "on(…)")} fullfills this requirement.
|
||||
`),
|
||||
el("p").append(...T`
|
||||
You can use Addons as ≥3rd argument of ${el("code", "el")} function. This way is possible to extends your
|
||||
templates by additional (3rd party) functionalities. But for now mainly, you can add events listeners:
|
||||
`),
|
||||
el(example, { src: fileURL("./components/examples/events/templateWithListeners.js"), page_id }),
|
||||
el("p").append(
|
||||
"As the example shows, you can also provide types in JSDoc+TypeScript by using global type ", el("code", "ddeElementAddon"), ".",
|
||||
" ",
|
||||
"Also notice, you can use Addons to get element reference.",
|
||||
),
|
||||
el(h3, "Life-cycle events"),
|
||||
el("p").append(
|
||||
"Addons are called immediately when the element is created, even it is not connected to live DOM yet.",
|
||||
" ",
|
||||
"Therefore, you can understand the Addon to be “oncreate” event."
|
||||
),
|
||||
el("p").append(
|
||||
"The library provide three additional live-cycle events corresponding to how they are named in",
|
||||
" a case of custom elements: ", el("code", "on.connected"), ", ", el("code", "on.disconnected"),
|
||||
" and ", el("code", "on.attributeChanged"), "."
|
||||
),
|
||||
el("p").append(...T`
|
||||
As the example shows, you can also provide types in JSDoc+TypeScript by using global type
|
||||
${el("code", "ddeElementAddon")}. Also notice, you can use Addons to get element reference.
|
||||
`),
|
||||
el(h3, t`Life-cycle events`),
|
||||
el("p").append(...T`
|
||||
Addons are called immediately when the element is created, even it is not connected to live DOM yet.
|
||||
Therefore, you can understand the Addon to be “oncreate” event.
|
||||
`),
|
||||
el("p").append(...T`
|
||||
The library provide three additional live-cycle events corresponding to how they are named in a case of
|
||||
custom elements: ${el("code", "on.connected")}, ${el("code", "on.disconnected")} and ${el("code", "on.attributeChanged")}.
|
||||
`),
|
||||
el(example, { src: fileURL("./components/examples/events/live-cycle.js"), page_id }),
|
||||
el("p").append(
|
||||
"For Custom elements, we will later introduce a way to replace ", el("code", "*Callback"),
|
||||
" syntax with ", el("code", "dde:*"), " events. The ", el("code", "on.*"), " functions then",
|
||||
" listen to the appropriate Custom Elements events (see ", el("a", { textContent: "Custom element lifecycle callbacks | MDN", ...references.mdn_customElement }), ")."
|
||||
),
|
||||
el("p").append(
|
||||
"But, in case of regular elemnets the ", el("a", references.mdn_mutation).append(el("code", "MutationObserver"), " | MDN"),
|
||||
" is internaly used to track these events. Therefore, there are some drawbacks:",
|
||||
),
|
||||
el("p").append(...T`
|
||||
For Custom elements, we will later introduce a way to replace ${el("code", "*Callback")} syntax with
|
||||
${el("code", "dde:*")} events. The ${el("code", "on.*")} functions then listen to the appropriate
|
||||
Custom Elements events (see ${el("a", { textContent: t`Custom element lifecycle callbacks | MDN`, ...references.mdn_customElement })}).
|
||||
`),
|
||||
el("p").append(...T`
|
||||
But, in case of regular elemnets the ${el("a", references.mdn_mutation).append(el("code", "MutationObserver"), " | MDN")}
|
||||
is internaly used to track these events. Therefore, there are some drawbacks:
|
||||
`),
|
||||
el("ul").append(
|
||||
el("li").append(
|
||||
"To proper listener registration, you need to use ", el("code", "on.*"), " not `on(\"dde:*\", …)`!"
|
||||
),
|
||||
el("li").append(
|
||||
"Use sparingly! Internally, library must loop of all registered events and fires event properly.",
|
||||
" ",
|
||||
el("strong", "It is good practice to use the fact that if an element is removed, its children are also removed!"),
|
||||
" ",
|
||||
"In this spirit, we will introduce later the ", el("strong", "host"), " syntax to register",
|
||||
" clean up procedures when the component is removed from the app."
|
||||
),
|
||||
),
|
||||
el("p").append(
|
||||
"To provide intuitive behaviour, similar also to how the life-cycle events works in other",
|
||||
" frameworks/libraries, deka-dom-el library ensures that ", el("code", "on.connected"),
|
||||
" and ", el("code", "on.disconnected"), " are called only once and only when the element",
|
||||
" is (dis)connected to live DOM. The solution is inspired by ", el("a", { textContent: "Vue", ...references.vue_fix }), ".",
|
||||
" For using native behaviour re-(dis)connecting element, use:"
|
||||
el("li").append(...T`
|
||||
To proper listener registration, you need to use ${el("code", "on.*")} not \`on("dde:*", …)\`!
|
||||
`),
|
||||
el("li").append(...T`
|
||||
Use sparingly! Internally, library must loop of all registered events and fires event properly.
|
||||
${el("strong", t`It is good practice to use the fact that if an element is removed, its children are
|
||||
also removed!`)} In this spirit, we will introduce later the ${el("strong", t`host`)} syntax to
|
||||
register, clean up procedures when the component is removed from the app.
|
||||
`),
|
||||
),
|
||||
el("p").append(...T`
|
||||
To provide intuitive behaviour, similar also to how the life-cycle events works in other
|
||||
frameworks/libraries, deka-dom-el library ensures that ${el("code", "on.connected")} and
|
||||
${el("code", "on.disconnected")} are called only once and only when the element, is (dis)connected to
|
||||
live DOM. The solution is inspired by ${el("a", { textContent: "Vue", ...references.vue_fix })}. For using
|
||||
native behaviour re-(dis)connecting element, use:
|
||||
`),
|
||||
el("ul").append(
|
||||
el("li").append("custom ", el("code", "MutationObserver"), " or logic in (dis)", el("code", "connectedCallback"), " or…"),
|
||||
el("li").append("re-add ", el("code", "on.connected"), " or ", el("code", "on.disconnected"), " listeners.")
|
||||
el("li").append(...T`custom ${el("code", "MutationObserver")} or logic in (dis)${el("code", "connectedCallback")} or…`),
|
||||
el("li").append(...T`re-add ${el("code", "on.connected")} or ${el("code", "on.disconnected")} listeners.`)
|
||||
),
|
||||
|
||||
el(h3, "Final notes"),
|
||||
el("p", "The library also provides a method to dispatch the events."),
|
||||
el(h3, t`Final notes`),
|
||||
el("p", t`The library also provides a method to dispatch the events.`),
|
||||
el(example, { src: fileURL("./components/examples/events/compareDispatch.js"), page_id }),
|
||||
|
||||
el(mnemonic)
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { T, t } from "./utils/index.js";
|
||||
export const info= {
|
||||
title: "Signals and reactivity",
|
||||
description: "Handling reactivity in UI via signals.",
|
||||
title: t`Signals and reactivity`,
|
||||
description: t`Handling reactivity in UI via signals.`,
|
||||
};
|
||||
|
||||
import { el } from "deka-dom-el";
|
||||
@ -14,27 +15,27 @@ const fileURL= url=> new URL(url, import.meta.url);
|
||||
const references= {
|
||||
/** Event-driven programming */
|
||||
wiki_event_driven: {
|
||||
title: "Wikipedia: Event-driven programming",
|
||||
title: t`Wikipedia: Event-driven programming`,
|
||||
href: "https://en.wikipedia.org/wiki/Event-driven_programming",
|
||||
},
|
||||
/** Publish–subscribe pattern */
|
||||
wiki_pubsub: {
|
||||
title: "Wikipedia: Publish–subscribe pattern",
|
||||
title: t`Wikipedia: Publish–subscribe pattern`,
|
||||
href: "https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern",
|
||||
},
|
||||
/** NPM package: fpubsub */
|
||||
fpubsub: {
|
||||
title: "NPM package: fpubsub",
|
||||
title: t`NPM package: fpubsub`,
|
||||
href: "https://www.npmjs.com/package/fpubsub",
|
||||
},
|
||||
/** JS Primitives | MDN */
|
||||
mdn_primitive: {
|
||||
title: "Primitive | MDN",
|
||||
title: t`Primitive | MDN`,
|
||||
href: "https://developer.mozilla.org/en-US/docs/Glossary/Primitive",
|
||||
},
|
||||
/** useReducer */
|
||||
mdn_use_reducer: {
|
||||
title: "useReducer hook | React docs",
|
||||
title: t`useReducer hook | React docs`,
|
||||
href: "https://react.dev/reference/react/useReducer",
|
||||
}
|
||||
};
|
||||
@ -42,90 +43,80 @@ const references= {
|
||||
export function page({ pkg, info }){
|
||||
const page_id= info.id;
|
||||
return el(simplePage, { info, pkg }).append(
|
||||
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,",
|
||||
" signals may be a viable approach.",
|
||||
),
|
||||
el("h2", t`Using signals to manage reactivity`),
|
||||
el("p").append(...T`
|
||||
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, signals may be a viable approach.
|
||||
`),
|
||||
el(code, { src: fileURL("./components/examples/signals/intro.js"), page_id }),
|
||||
|
||||
el(h3, "Introducing signals"),
|
||||
el("p").append(
|
||||
"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 signal value changes. Similarly, in a remaining part (γ), we",
|
||||
" can update the signal value."
|
||||
),
|
||||
el(h3, t`Introducing signals`),
|
||||
el("p").append(...T`
|
||||
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 signal value
|
||||
changes. Similarly, in a remaining part (γ), we can update the signal value.
|
||||
`),
|
||||
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", ...references.wiki_event_driven }),
|
||||
" and ",
|
||||
el("a", { textContent: "Publish–subscribe pattern", ...references.wiki_pubsub }),
|
||||
" (compare for example with ", el("a", { textContent: "fpubsub library", ...references.fpubsub }), ").",
|
||||
" All three parts can be in some manner independent and still connected",
|
||||
" to the same reactive entity."
|
||||
),
|
||||
el("p").append(
|
||||
"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 signal):"
|
||||
),
|
||||
el("p").append(...T`
|
||||
All this is just an example of
|
||||
${el("a", { textContent: t`Event-driven programming`, ...references.wiki_event_driven })} and
|
||||
${el("a", { textContent: t`Publish–subscribe pattern`, ...references.wiki_pubsub })} (compare for example
|
||||
with ${el("a", { textContent: t`fpubsub library`, ...references.fpubsub })}). All three parts can be in
|
||||
some manner independent and still connected to the same reactive entity.
|
||||
`),
|
||||
el("p").append(...T`
|
||||
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('${t`a new value`}')`)}. For listenning the signal value changes, use
|
||||
${el("code", "S.on(signal, console.log)")}.
|
||||
`),
|
||||
el("p").append(...T`
|
||||
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 signal):
|
||||
`),
|
||||
el(example, { src: fileURL("./components/examples/signals/computations-abort.js"), page_id }),
|
||||
|
||||
el(h3, "Signals and actions"),
|
||||
el("p").append(
|
||||
el("code", "S(/* primitive */)"), " allows you to declare simple reactive variables, typically",
|
||||
" around ", el("em", "immutable"), " ", el("a", { textContent: "primitive types", ...references.mdn_primitive }), ".",
|
||||
" ",
|
||||
"However, it may also be necessary to use reactive arrays, objects, or other complex reactive structures."
|
||||
),
|
||||
el(h3, t`Signals and actions`),
|
||||
el("p").append(...T`
|
||||
${el("code", `S(/* ${t`primitive`} */)`)} allows you to declare simple reactive variables, typically, around
|
||||
${el("em", t`immutable`)} ${el("a", { textContent: t`primitive types`, ...references.mdn_primitive })}.
|
||||
However, it may also be necessary to use reactive arrays, objects, or other complex reactive structures.
|
||||
`),
|
||||
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("p", t`…but typical user-case is object/array (maps, sets and other mutable objects):`),
|
||||
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", ...references.mdn_use_reducer }),
|
||||
" 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", "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"), ")."
|
||||
),
|
||||
el("p").append(...T`
|
||||
In some way, you can compare it with ${el("a", { textContent: "useReducer", ...references.mdn_use_reducer })}
|
||||
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", "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")}).
|
||||
`),
|
||||
|
||||
el(h3, "Reactive DOM attributes and elements"),
|
||||
el("p", "There are on basic level two distinc situation to mirror dynamic value into the DOM/UI"),
|
||||
el(h3, t`Reactive DOM attributes and elements`),
|
||||
el("p", t`There are on basic level two distinc situation to mirror dynamic value into the DOM/UI`),
|
||||
el("ol").append(
|
||||
el("li", "to change some attribute(s) of existing element(s)"),
|
||||
el("li", "to generate elements itself dynamically – this covers conditions and loops")
|
||||
el("li", t`to change some attribute(s) of existing element(s)`),
|
||||
el("li", t`to generate elements itself dynamically – this covers conditions and loops`)
|
||||
),
|
||||
el(example, { src: fileURL("./components/examples/signals/dom-attrs.js"), page_id }),
|
||||
el("p").append(
|
||||
"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 signal” (see above) like ", el("code", "assign(element, { textContent: S(()=> 'Hello '+WorldSignal()) })"), ".",
|
||||
" ",
|
||||
"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 signal value use ", el("code", "S.el(signal, DOMgenerator)"), ".",
|
||||
" This was already used in the todo example above or see:"
|
||||
),
|
||||
el("p").append(...T`
|
||||
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(...T`
|
||||
For computation, you can use the “derived signal” (see above) like
|
||||
${el("code", "assign(element, { textContent: S(()=> 'Hello '+WorldSignal()) })")}. 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(...T`
|
||||
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/signals/dom-el.js"), page_id }),
|
||||
|
||||
el(mnemonic)
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { T, t } from "./utils/index.js";
|
||||
export const info= {
|
||||
title: "Scopes and components",
|
||||
description: "Organizing UI into components",
|
||||
title: t`Scopes and components`,
|
||||
description: t`Organizing UI into components`,
|
||||
};
|
||||
|
||||
import { el } from "deka-dom-el";
|
||||
@ -14,12 +15,12 @@ const fileURL= url=> new URL(url, import.meta.url);
|
||||
const references= {
|
||||
/** Garbage collection on MDN */
|
||||
garbage_collection: {
|
||||
title: "MDN documentation page for Garbage collection",
|
||||
title: t`MDN documentation page for Garbage collection`,
|
||||
href: "https://developer.mozilla.org/en-US/docs/Glossary/Garbage_collection",
|
||||
},
|
||||
/** Signals */
|
||||
signals: {
|
||||
title: "Signals section on this library",
|
||||
title: t`Signals section on this library`,
|
||||
href: "./p04-signals#h-introducing-signals",
|
||||
}
|
||||
};
|
||||
@ -27,62 +28,58 @@ const references= {
|
||||
export function page({ pkg, info }){
|
||||
const page_id= info.id;
|
||||
return el(simplePage, { info, pkg }).append(
|
||||
el("h2", "Using functions as UI components"),
|
||||
el("p").append(
|
||||
"For state-less components we can use functions as UI components (see “Elements” page).",
|
||||
" But in real life, we may need to handle the component live-cycle and provide",
|
||||
" JavaScript the way to properly use the ", el("a", { textContent: "Garbage collection", ...references.garbage_collection }), "."
|
||||
),
|
||||
el("h2", t`Using functions as UI components`),
|
||||
el("p").append(...T`
|
||||
For state-less components we can use functions as UI components (see “Elements” page). But in real life,
|
||||
we may need to handle the component live-cycle and provide JavaScript the way to properly use
|
||||
the ${el("a", { textContent: t`Garbage collection`, ...references.garbage_collection })}.
|
||||
`),
|
||||
el(code, { src: fileURL("./components/examples/scopes/intro.js"), page_id }),
|
||||
el("p").append(
|
||||
"The library therefore use ", el("em", "scopes"), " to provide these functionalities.",
|
||||
),
|
||||
el("p").append(...T`The library therefore use ${el("em", t`scopes`)} to provide these functionalities.`),
|
||||
|
||||
el(h3, "Scopes and hosts"),
|
||||
el("p").append(
|
||||
"The ", el("strong", "host"), " is the name for the element representing the component.",
|
||||
" This is typically element returned by function. To get reference, you can use ",
|
||||
el("code", "scope.host()"), " to applly addons just use ", el("code", "scope.host(...<addons>)"), "."
|
||||
),
|
||||
el(h3, t`Scopes and hosts`),
|
||||
el("p").append(...T`
|
||||
The ${el("strong", "host")} is the name for the element representing the component. This is typically
|
||||
element returned by function. To get reference, you can use ${el("code", "scope.host()")} to applly addons
|
||||
just use ${el("code", "scope.host(...<addons>)")}.
|
||||
`),
|
||||
el(example, { src: fileURL("./components/examples/scopes/scopes-and-hosts.js"), page_id }),
|
||||
el("p").append(
|
||||
"To better understanding we implement function ", el("code", "elClass"), " helping to create",
|
||||
" component as class instances."
|
||||
),
|
||||
el("p").append(...T`
|
||||
To better understanding we implement function ${el("code", "elClass")} helping to create 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("p").append(...T`
|
||||
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, 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(h3, t`Scopes, signals and cleaning magic`),
|
||||
el("p").append(...T`
|
||||
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 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 */)"), "."
|
||||
),
|
||||
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.disconnected(/* remove the listener */)(host())"), " to the host element."
|
||||
),
|
||||
el("p", { className: "notice" }).append(
|
||||
"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", ...references.signals }), "."
|
||||
),
|
||||
el("p").append(...T`
|
||||
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, /* ${t`update the paragraph`} */)`)}.
|
||||
`),
|
||||
el("p").append(...T`
|
||||
This listener must be removed when the component is removed from the DOM. To do it, the library assign
|
||||
internally ${el("code", `on.disconnected(/* ${t`remove the listener`} */)(host())`)} to the host element.
|
||||
`),
|
||||
el("p", { className: "notice" }).append(...T`
|
||||
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", ...references.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 signals)",
|
||||
" and imperative manipulation of elements.",
|
||||
),
|
||||
el("p").append(...T`
|
||||
Strictly speaking, the imperative way of using the library is not prohibited. 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 }),
|
||||
|
||||
el(mnemonic)
|
||||
|
@ -1,3 +1,4 @@
|
||||
export { t } from "./utils/index.js";
|
||||
export const path_target= {
|
||||
root: "docs/",
|
||||
css: "docs/"
|
||||
|
52
docs_src/utils/index.js
Normal file
52
docs_src/utils/index.js
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* This is helper to write texts in code more readable
|
||||
* and doesn’t inpact the finally generated text in HTML.
|
||||
*
|
||||
* ```js
|
||||
* t`
|
||||
* Hello ${el("b", "world")}!
|
||||
* How are you?
|
||||
* ` === "Hello <b>world</b>! How are you?"
|
||||
* ```
|
||||
*
|
||||
* In future, this can be expanded to allow translations.
|
||||
*
|
||||
* ```js
|
||||
* t(key)`text`; // for example
|
||||
* ```
|
||||
*
|
||||
* @param {TemplateStringsArray} strings
|
||||
* @param {...(string|Node)} values
|
||||
* @returns {(string|Node)[]}
|
||||
* */
|
||||
export function T(strings, ...values){
|
||||
const out= [];
|
||||
tT(s=> out.push(s), strings, ...values);
|
||||
return out;
|
||||
}
|
||||
/**
|
||||
* Similarly to {@link T}, but for only strings.
|
||||
* @param {TemplateStringsArray} strings
|
||||
* @param {...string} values
|
||||
* @returns {string}
|
||||
* */
|
||||
export function t(strings, ...values){
|
||||
let out= "";
|
||||
tT(s=> out+= s, strings, ...values);
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {(input: string|Node)=> void} callback
|
||||
* @param {TemplateStringsArray} strings
|
||||
* @param {...(string|Node)} values
|
||||
* */
|
||||
function tT(callback, strings, ...values){
|
||||
const { length }= strings;
|
||||
const last= length-1;
|
||||
for(let i= 0; i<length; i++){
|
||||
const out= strings[i].replace(/\n\s+/g, " ");
|
||||
callback(!i ? out.trimStart() : i===last ? out.trimEnd() : out);
|
||||
if(i<values.length) callback(values[i]);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user