You can create a native DOM element by using the document.createElement(). It is also possible to provide a some attribute(s) declaratively using Object.assign(). More precisely, this way you can sets some IDL also known as a JavaScript property.
You can create a native DOM element by using the document.createElement(). It is also possible to provide a some attribute(s) declaratively using Object.assign(). More precisely, this way you can sets some IDL also known as a JavaScript property.
The assign function provides improved behaviour of Object.assign(). You can declaratively sets any IDL and attribute of the given element. Function prefers IDL and fallback to the element.setAttribute if there is no writable property in the element prototype.
You can study all JavaScript elements interfaces to the corresponding HTML elements. All HTML elements inherits from HTMLElement. To see all available IDLs for example for paragraphs, see HTMLParagraphElement. Moreover, the assign provides a way to sets declaratively some convenient properties:
It is possible to sets data-*/aria-* attributes using object notation.
In opposite, it is also possible to sets data-*/aria-* attribute using camelCase notation.
You can use string or object as a value for style property.
className (IDL – preffered)/class are ways to add CSS class to the element. You can use string (similarly to class="…" syntax in HTML) or array of strings. This is handy to concat conditional classes.
Use classList to toggle specific classes. This will be handy later when the reactivity via signals is beeing introduced.
The assign also accepts the 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. For example, natievly the element’s id is removed by setting the IDL to an empty string.
You can use = or . to force processing given key as attribute/property of the element.
For processing, the assign internally uses assignAttribute and classListDeclarative.
import { assign, assignAttribute, classListDeclarative } from "./esm-with-signals.js";
+
The assign function provides improved behaviour of Object.assign(). You can declaratively sets any IDL and attribute of the given element. Function prefers IDL and fallback to the element.setAttribute if there is no writable property in the element prototype.
You can study all JavaScript elements interfaces to the corresponding HTML elements. All HTML elements inherits from HTMLElement. To see all available IDLs for example for paragraphs, see HTMLParagraphElement. Moreover, the assign provides a way to sets declaratively some convenient properties:
It is possible to sets data-*/aria-* attributes using object notation.
In opposite, it is also possible to sets data-*/aria-* attribute using camelCase notation.
You can use string or object as a value for style property.
className (IDL – preffered)/class are ways to add CSS class to the element. You can use string (similarly to class="…" syntax in HTML) or array of strings. This is handy to concat conditional classes.
Use classList to toggle specific classes. This will be handy later when the reactivity via signals is beeing introduced.
The assign also accepts the 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. For example, natievly the element’s id is removed by setting the IDL to an empty string.
You can use = or . to force processing given key as attribute/property of the element.
For processing, the assign internally uses assignAttribute and classListDeclarative.
As you can see, in case of state-less/basic components there is no difference between calling component function directly or using el function.
It is nice to use similar naming convention as native DOM API. This allows us to use the destructuring assignment syntax and keep track of the native API (things are best remembered through regular use).
Similarly to the native DOM API (document.createElementNS) for non-HTML elements we need to tell JavaScript which kind of the element to create. We can use the elNS function:
import { elNS, assign } from "./esm-with-signals.js";
+
As you can see, in case of state-less/basic components there is no difference between calling component function directly or using el function.
It is nice to use similar naming convention as native DOM API. This allows us to use the destructuring assignment syntax and keep track of the native API (things are best remembered through regular use).
Similarly to the native DOM API (document.createElementNS) for non-HTML elements we need to tell JavaScript which kind of the element to create. We can use the elNS function:
In JavaScript you can listen to the native DOM events of the given element by using element.addEventListener(type, listener, options). The library provides an alternative (on) accepting the differen order of the arguments:
In JavaScript you can listen to the native DOM events of the given element by using element.addEventListener(type, listener, options). The library provides an alternative (on) accepting the differen order of the arguments:
…this is actually one of the two differences. The another one is that on accepts only object as the options (but it is still optional).
The other difference is that there is nooff function. You can remove listener declaratively using AbortSignal:
import { el, on } from "./esm-with-signals.js";
+
…this is actually one of the two differences. The another one is that on accepts only object as the options (but it is still optional).
The other difference is that there is nooff function. You can remove listener declaratively using AbortSignal:
import { el, on } from "./esm-with-signals.js";
const log= mark=> console.log.bind(console, mark);
const abort_controller= new AbortController();
@@ -67,7 +67,7 @@ document.body.append(
function log({ type, detail }){
console.log({ _this: this, type, detail });
}
-
For Custom elements, we will later introduce a way to replace *Callback syntax with dde:* events. The on.* functions then listen to the appropriate Custom Elements events (see Custom element lifecycle callbacks | MDN).
But, in case of regular elemnets the MutationObserver | MDN is internaly used to track these events. Therefore, there are some drawbacks:
To proper listener registration, you need to use on.* not `on("dde:*", …)`!
Use sparingly! Internally, library must loop of all registered events and fires event properly. 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 host syntax to register clean up procedures when the component is removed from the app.
To provide intuitive behaviour, similar also to how the life-cycle events works in other frameworks/libraries, deka-dom-el library ensures that on.connected and on.disconnected are called only once and only when the element is (dis)connected to live DOM. The solution is inspired by Vue. For using native behaviour re-(dis)connecting element, use:
custom MutationObserver or logic in (dis)connectedCallback or…
The library also provides a method to dispatch the events.
import { el, on, dispatchEvent } from "./esm-with-signals.js";
+
For Custom elements, we will later introduce a way to replace *Callback syntax with dde:* events. The on.* functions then listen to the appropriate Custom Elements events (see Custom element lifecycle callbacks | MDN).
But, in case of regular elemnets the MutationObserver | MDN is internaly used to track these events. Therefore, there are some drawbacks:
To proper listener registration, you need to use on.* not `on("dde:*", …)`!
Use sparingly! Internally, library must loop of all registered events and fires event properly. 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 host syntax to register clean up procedures when the component is removed from the app.
To provide intuitive behaviour, similar also to how the life-cycle events works in other frameworks/libraries, deka-dom-el library ensures that on.connected and on.disconnected are called only once and only when the element is (dis)connected to live DOM. The solution is inspired by Vue. For using native behaviour re-(dis)connecting element, use:
custom MutationObserver or logic in (dis)connectedCallback or…
Signals are implemented in the library as functions. To see current value of signal, just call it without any arguments console.log(signal()). To update the signal value, pass any argument signal('a new value'). For listenning the signal value changes, use S.on(signal, console.log).
Similarly to the on function to register DOM events listener. You can use AbortController/AbortSignal to off/stop listenning. In example, you also found the way for representing “live” piece of code computation pattern (derived signal):
Signals are implemented in the library as functions. To see current value of signal, just call it without any arguments console.log(signal()). To update the signal value, pass any argument signal('a new value'). For listenning the signal value changes, use S.on(signal, console.log).
Similarly to the on function to register DOM events listener. You can use AbortController/AbortSignal to off/stop listenning. In example, you also found the way for representing “live” piece of code computation pattern (derived signal):
In some way, you can compare it with useReducer hook from React. So, the S(<data>, <actions>) pattern creates a store “machine”. We can then invoke (dispatch) registered action by calling S.action(<signal>, <name>, ...<args>) after the action call the signal calls all its listeners. This can be stopped by calling 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 (this.value).
There are on basic level two distinc situation to mirror dynamic value into the DOM/UI
to change some attribute(s) of existing element(s)
to generate elements itself dynamically – this covers conditions and loops
import { S } from "./esm-with-signals.js";
+
In some way, you can compare it with useReducer hook from React. So, the S(<data>, <actions>) pattern creates a store “machine”. We can then invoke (dispatch) registered action by calling S.action(<signal>, <name>, ...<args>) after the action call the signal calls all its listeners. This can be stopped by calling 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 (this.value).
There are on basic level two distinc situation to mirror dynamic value into the DOM/UI
to change some attribute(s) of existing element(s)
to generate elements itself dynamically – this covers conditions and loops
import { S } from "./esm-with-signals.js";
const count= S(0);
import { el } from "./esm-with-signals.js";
diff --git a/docs/p05-scopes.html b/docs/p05-scopes.html
index 70bb807..162f927 100644
--- a/docs/p05-scopes.html
+++ b/docs/p05-scopes.html
@@ -1,4 +1,4 @@
-`deka-dom-el` — Scopes and components
`deka-dom-el` — Scopes and components
Organizing UI into components
Using functions as UI components
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 Garbage collection.
// use NPM or for example https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js
+`deka-dom-el` — Scopes and components
`deka-dom-el` — Scopes and components
Organizing UI into components
Using functions as UI components
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 Garbage collection.
// 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} */
The library therefore use scopes to provide these functionalities.
The host is the name for the element representing the component. This is typically element returned by function. To get reference, you can use scope.host() to applly addons just use scope.host(...<addons>).
import { el, on, scope } from "./esm-with-signals.js";
@@ -114,7 +114,7 @@ function component(){
});
return el("p", textContent, onclickChange);
}
-
The text content of the paragraph is changing when the value of the signal textContent is changed. Internally, there is association between textContent and the paragraph similar to using S.on(textContent, /* update the paragraph */).
This listener must be removed when the component is removed from the DOM. To do it, the library assign internally on.disconnected(/* remove the listener */)(host()) to the host element.
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 Signals.
/* PSEUDO-CODE!!! */
+
The text content of the paragraph is changing when the value of the signal textContent is changed. Internally, there is association between textContent and the paragraph similar to using S.on(textContent, /* update the paragraph */).
This listener must be removed when the component is removed from the DOM. To do it, the library assign internally on.disconnected(/* remove the listener */)(host()) to the host element.
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 Signals.
/* PSEUDO-CODE!!! */
import { el } from "deka-dom-el";
import { S } from "deka-dom-el/signals";
function component(){
diff --git a/docs/p06-customElement.html b/docs/p06-customElement.html
index f6229a7..a7b5cc8 100644
--- a/docs/p06-customElement.html
+++ b/docs/p06-customElement.html
@@ -10,7 +10,7 @@ S.observedAttributes;
// “internal” utils
import { lifecyclesToEvents } from "deka-dom-el";
-
\ No newline at end of file
diff --git a/docs_src/p02-elements.html.js b/docs_src/p02-elements.html.js
index 5c20766..03e676c 100644
--- a/docs_src/p02-elements.html.js
+++ b/docs_src/p02-elements.html.js
@@ -11,6 +11,38 @@ import { mnemonic } from "./components/mnemonic/elements-init.js";
import { code } from "./components/code.html.js";
/** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url);
+const references= {
+ /** document.createElement() */
+ mdn_create: {
+ title: "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",
+ href: "https://developer.mozilla.org/en-US/docs/Glossary/IDL",
+ },
+ /** HTMLElement */
+ mdn_el: {
+ title: "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)",
+ 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]`)",
+ 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)",
+ href: "https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS",
+ }
+};
/** @param {import("./types.d.ts").PageAttrs} attrs */
export function page({ pkg, info }){
const page_id= info.id;
@@ -22,16 +54,10 @@ export function page({ pkg, info }){
el(h3, "Creating element(s) (with custom attributes)"),
el("p").append(
- "You can create a native DOM element by using the ",
- el("a", { href: "https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement", title: "MDN documentation for document.createElement()" }).append(
- el("code", "document.createElement()")
- ), ". ",
+ "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", {
- href: "https://developer.mozilla.org/en-US/docs/Glossary/IDL",
- title: "MDN page about Interface Description Language"
- }).append(
+ el("a", references.mdn_idl).append(
el("abbr", { textContent: "IDL", title: "Interface Description Language" })
), " also known as a JavaScript property."
),
@@ -48,8 +74,8 @@ export function page({ pkg, info }){
),
el("p").append(
"You can study all JavaScript elements interfaces to the corresponding HTML elements. ",
- "All HTML elements inherits from ", el("a", { textContent: "HTMLElement", href: "https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement" }), ". ",
- "To see all available IDLs for example for paragraphs, see ", el("a", { textContent: "HTMLParagraphElement", href: "https://developer.mozilla.org/en-US/docs/Web/API/HTMLParagraphElement" }), ". ",
+ "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(
@@ -108,13 +134,13 @@ export function page({ pkg, info }){
),
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", href: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment", title: "Destructuring assignment | MDN" }),
+ "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(h3, "Creating non-HTML elements"),
el("p").append(
- "Similarly to the native DOM API (", el("a", { href: "https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS", title: "MDN" }).append(el("code", "document.createElementNS")), ") for non-HTML elements",
+ "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:"
),
diff --git a/docs_src/p03-events.html.js b/docs_src/p03-events.html.js
index 9611ed4..b75281e 100644
--- a/docs_src/p03-events.html.js
+++ b/docs_src/p03-events.html.js
@@ -11,6 +11,35 @@ import { mnemonic } from "./components/mnemonic/events-init.js";
import { code } from "./components/code.html.js";
/** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url);
+const references= {
+ /** element.addEventListener() */
+ mdn_listen: {
+ title: "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",
+ href: "https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#signal",
+ },
+ /** comparison listening options by WebReflection */
+ web_events: {
+ href: "https://gist.github.com/WebReflection/b404c36f46371e3b1173bf5492acc944",
+ },
+ /** Custom Element lifecycle callbacks */
+ mdn_customElement: {
+ href: "https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks"
+ },
+ /** MutationObserver */
+ mdn_mutation: {
+ href: "https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver",
+ },
+ /** Readding the element to the DOM fix by Vue */
+ vue_fix: {
+ title: "Vue and Web Components, lifecycle implementation readding the element to the DOM",
+ href: "https://vuejs.org/guide/extras/web-components.html#lifecycle",
+ }
+};
/** @param {import("./types.d.ts").PageAttrs} attrs */
export function page({ pkg, info }){
const page_id= info.id;
@@ -28,9 +57,7 @@ export function page({ pkg, info }){
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", { href: "https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener", title: "addEventListener on MDN" }).append(
- el("code", "element.addEventListener(type, listener, options)")
- ), ".",
+ 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:"
@@ -43,7 +70,7 @@ export function page({ pkg, info }){
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", href: "https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#signal", title: "part of addEventListener on MDN" }),
+ "You can remove listener declaratively using ", el("a", { textContent: "AbortSignal", ...references.mdn_abortListener }),
":"
),
el(example, { src: fileURL("./components/examples/events/abortSignal.js"), page_id }),
@@ -59,7 +86,7 @@ export function page({ pkg, info }){
" ",
el("em", "Side note: this can be useful in case of SSR."),
" ",
- "To study difference, you can read a nice summary here: ", el("a", { href: "https://gist.github.com/WebReflection/b404c36f46371e3b1173bf5492acc944", textContent: "GIST @WebReflection/web_events.md" }), "."
+ "To study difference, you can read a nice summary here: ", el("a", { textContent: "GIST @WebReflection/web_events.md", ...references.web_events }), "."
)
),
@@ -93,10 +120,10 @@ export function page({ pkg, info }){
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", href: "https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks" }), ")."
+ " 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", { href: "https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver" }).append(el("code", "MutationObserver"), " | MDN"),
+ "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(
@@ -116,7 +143,7 @@ export function page({ pkg, info }){
"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", href: "https://vuejs.org/guide/extras/web-components.html#lifecycle", title: "Vue and Web Components | Lifecycle" }), ".",
+ " 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(
diff --git a/docs_src/p04-signals.html.js b/docs_src/p04-signals.html.js
index d7d480c..ea0eba2 100644
--- a/docs_src/p04-signals.html.js
+++ b/docs_src/p04-signals.html.js
@@ -11,7 +11,33 @@ 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);
-
+const references= {
+ /** Event-driven programming */
+ wiki_event_driven: {
+ title: "Wikipedia: Event-driven programming",
+ href: "https://en.wikipedia.org/wiki/Event-driven_programming",
+ },
+ /** Publish–subscribe pattern */
+ wiki_pubsub: {
+ title: "Wikipedia: Publish–subscribe pattern",
+ href: "https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern",
+ },
+ /** NPM package: fpubsub */
+ fpubsub: {
+ title: "NPM package: fpubsub",
+ href: "https://www.npmjs.com/package/fpubsub",
+ },
+ /** JS Primitives | MDN */
+ mdn_primitive: {
+ title: "Primitive | MDN",
+ href: "https://developer.mozilla.org/en-US/docs/Glossary/Primitive",
+ },
+ /** useReducer */
+ mdn_use_reducer: {
+ title: "useReducer hook | React docs",
+ href: "https://react.dev/reference/react/useReducer",
+ }
+};
/** @param {import("./types.d.ts").PageAttrs} attrs */
export function page({ pkg, info }){
const page_id= info.id;
@@ -36,10 +62,10 @@ export function page({ pkg, info }){
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" }),
+ el("a", { textContent: "Event-driven programming", ...references.wiki_event_driven }),
" and ",
- el("a", { textContent: "Publish–subscribe pattern", href: "https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern", title: "Wikipedia: Publish–subscribe pattern" }),
- " (compare for example with ", el("a", { textContent: "fpubsub library", href: "https://www.npmjs.com/package/fpubsub", title: "NPM package: fpubsub" }), ").",
+ 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."
),
@@ -60,7 +86,7 @@ export function page({ pkg, info }){
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", title: "Primitive | MDN", href: "https://developer.mozilla.org/en-US/docs/Glossary/Primitive" }), ".",
+ " 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."
),
@@ -68,7 +94,7 @@ export function page({ pkg, info }){
el("p", "…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", href: "https://react.dev/reference/react/useReducer", title: "useReducer hook | React docs" }),
+ "In some way, you can compare it with ", el("a", { textContent: "useReducer", ...references.mdn_use_reducer }),
" hook from React. So, the ", el("code", "S(, )"), " pattern creates",
" a store “machine”. We can then invoke (dispatch) registered action by calling",
" ", el("code", "S.action(, , ...)"), " after the action call",
diff --git a/docs_src/p05-scopes.html.js b/docs_src/p05-scopes.html.js
index 78e6cbe..733b34b 100644
--- a/docs_src/p05-scopes.html.js
+++ b/docs_src/p05-scopes.html.js
@@ -11,7 +11,18 @@ import { mnemonic } from "./components/mnemonic/scopes-init.js";
import { code } from "./components/code.html.js";
/** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url);
-
+const references= {
+ /** Garbage collection on MDN */
+ garbage_collection: {
+ title: "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",
+ href: "./p04-signals#h-introducing-signals",
+ }
+};
/** @param {import("./types.d.ts").PageAttrs} attrs */
export function page({ pkg, info }){
const page_id= info.id;
@@ -20,7 +31,7 @@ export function page({ pkg, info }){
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", href: "https://developer.mozilla.org/en-US/docs/Glossary/Garbage_collection", title: "Garbage collection | MDN" }), "."
+ " JavaScript the way to properly use the ", el("a", { textContent: "Garbage collection", ...references.garbage_collection }), "."
),
el(code, { src: fileURL("./components/examples/scopes/intro.js"), page_id }),
el("p").append(
@@ -64,7 +75,7 @@ export function page({ pkg, info }){
),
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", href: "http://localhost:40911/docs/p04-signals#h-introducing-signals" }), "."
+ " 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(
diff --git a/docs_src/p06-customElement.html.js b/docs_src/p06-customElement.html.js
index 605e507..0233522 100644
--- a/docs_src/p06-customElement.html.js
+++ b/docs_src/p06-customElement.html.js
@@ -11,7 +11,18 @@ import { mnemonic } from "./components/mnemonic/customElement-init.js";
import { code } from "./components/code.html.js";
/** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url);
-
+const references= {
+ /** Custom Elements on MDN */
+ custom_elements: {
+ title: "MDN documentation page for Custom Elements",
+ href: "https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements",
+ },
+ /** Custom Elements tips from WebReflection */
+ custom_elements_tips: {
+ title: "Ideas and tips from WebReflection",
+ href: "https://gist.github.com/WebReflection/ec9f6687842aa385477c4afca625bbf4",
+ }
+};
/** @param {import("./types.d.ts").PageAttrs} attrs */
export function page({ pkg, info }){
const page_id= info.id;
@@ -24,11 +35,11 @@ export function page({ pkg, info }){
el(h3, "Custom Elements Introduction"),
el("p").append(
- el("a", { textContent: "Using custom elements", href: "https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements", title: "Article about custom elements on MDN" })
+ el("a", { textContent: "Using custom elements", ...references.custom_elements })
),
el(code, { src: fileURL("./components/examples/customElement/native-basic.js"), page_id }),
el("p").append(
- el("a", { textContent: "Handy Custom Elements' Patterns", href: "https://gist.github.com/WebReflection/ec9f6687842aa385477c4afca625bbf4", title: "Ideas and tips from WebReflection" })
+ el("a", { textContent: "Handy Custom Elements' Patterns", ...references.custom_elements_tips })
),
el(mnemonic)