1
0
mirror of https://github.com/jaandrle/deka-dom-el synced 2024-11-21 15:39:36 +01:00

🔤 separate/extrapolate references to one place

This commit is contained in:
Jan Andrle 2024-05-31 14:14:48 +02:00
parent 8dc3e49d98
commit 6dd5a582e7
Signed by: jaandrle
GPG Key ID: B3A25AED155AFFAB
10 changed files with 145 additions and 44 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -10,7 +10,7 @@ S.observedAttributes;
// “internal” utils
import { lifecyclesToEvents } from "deka-dom-el";
</code></div><h3 id="h-custom-elements-introduction"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-custom-elements-introduction" tabindex="-1">#</a> Custom Elements Introduction</h3><p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements" title="Article about custom elements on MDN">Using custom elements</a></p><div class="code" data-js="todo"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">class CustomHTMLElement extends HTMLElement{
</code></div><h3 id="h-custom-elements-introduction"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-custom-elements-introduction" tabindex="-1">#</a> Custom Elements Introduction</h3><p><a title="MDN documentation page for Custom Elements" href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements">Using custom elements</a></p><div class="code" data-js="todo"><!--<dde:mark type="component" name="code" host="parentElement" ssr/>--><code class="language-js">class CustomHTMLElement extends HTMLElement{
static tagName = "custom-element"; // just suggestion, we can use `el(CustomHTMLElement.tagName)`
static observedAttributes= [ "custom-attribute" ];
constructor(){
@ -31,4 +31,4 @@ import { lifecyclesToEvents } from "deka-dom-el";
set customAttribute(value){ this.setAttribute("custom-attribute", value); }
}
customElements.define(CustomHTMLElement.tagName, CustomHTMLElement);
</code></div><p><a href="https://gist.github.com/WebReflection/ec9f6687842aa385477c4afca625bbf4" title="Ideas and tips from WebReflection">Handy Custom Elements' Patterns</a></p><div class="notice"><!--<dde:mark type="component" name="mnemonic" host="parentElement" ssr/>--><h3 id="h-mnemonic"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-mnemonic" tabindex="-1">#</a> Mnemonic</h3><ul><li><code>customElementRender(&lt;custom-element&gt;, &lt;render-function&gt;[, &lt;properties&gt;])</code> — use function to render DOM structure for given &lt;custom-element&gt;</li><li><code>customElementWithDDE(&lt;custom-element&gt;)</code> — register &lt;custom-element&gt; to DDE library, see also `lifecyclesToEvents`, can be also used as decorator</li><li><code>observedAttributes(&lt;custom-element&gt;)</code> — returns record of observed attributes (keys uses camelCase)</li><li><code>S.observedAttributes(&lt;custom-element&gt;)</code> — returns record of observed attributes (keys uses camelCase and values are signals)</li><li><code>lifecyclesToEvents(&lt;class-declaration&gt;)</code> — convert lifecycle methods to events, can be also used as decorator</li></ul></div><div class="prevNext"><!--<dde:mark type="component" name="prevNext" host="parentElement" ssr/>--><a rel="prev" href="p05-scopes" title="Organizing UI into components"><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->Scopes and components (previous)</a><!--<dde:mark type="component" name="pageLink" host="this" ssr/>--></div></main></body></html>
</code></div><p><a title="Ideas and tips from WebReflection" href="https://gist.github.com/WebReflection/ec9f6687842aa385477c4afca625bbf4">Handy Custom Elements' Patterns</a></p><div class="notice"><!--<dde:mark type="component" name="mnemonic" host="parentElement" ssr/>--><h3 id="h-mnemonic"><!--<dde:mark type="component" name="h3" host="parentElement" ssr/>--><a href="#h-mnemonic" tabindex="-1">#</a> Mnemonic</h3><ul><li><code>customElementRender(&lt;custom-element&gt;, &lt;render-function&gt;[, &lt;properties&gt;])</code> — use function to render DOM structure for given &lt;custom-element&gt;</li><li><code>customElementWithDDE(&lt;custom-element&gt;)</code> — register &lt;custom-element&gt; to DDE library, see also `lifecyclesToEvents`, can be also used as decorator</li><li><code>observedAttributes(&lt;custom-element&gt;)</code> — returns record of observed attributes (keys uses camelCase)</li><li><code>S.observedAttributes(&lt;custom-element&gt;)</code> — returns record of observed attributes (keys uses camelCase and values are signals)</li><li><code>lifecyclesToEvents(&lt;class-declaration&gt;)</code> — convert lifecycle methods to events, can be also used as decorator</li></ul></div><div class="prevNext"><!--<dde:mark type="component" name="prevNext" host="parentElement" ssr/>--><a rel="prev" href="p05-scopes" title="Organizing UI into components"><!--<dde:mark type="component" name="pageLink" host="parentElement" ssr/>-->Scopes and components (previous)</a><!--<dde:mark type="component" name="pageLink" host="this" ssr/>--></div></main></body></html>

View File

@ -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:"
),

View File

@ -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(

View File

@ -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",
},
/** Publishsubscribe pattern */
wiki_pubsub: {
title: "Wikipedia: Publishsubscribe 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: "Publishsubscribe pattern", href: "https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern", title: "Wikipedia: Publishsubscribe pattern" }),
" (compare for example with ", el("a", { textContent: "fpubsub library", href: "https://www.npmjs.com/package/fpubsub", title: "NPM package: fpubsub" }), ").",
el("a", { textContent: "Publishsubscribe 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(<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",

View File

@ -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(

View File

@ -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)