1
0
mirror of https://github.com/jaandrle/deka-dom-el synced 2025-04-11 15:15:33 +02:00

🔤 T now uses DocumentFragment

This commit is contained in:
Jan Andrle 2025-03-13 12:58:38 +01:00
parent 25d475ec04
commit 0a2d17ac6f
Signed by: jaandrle
GPG Key ID: B3A25AED155AFFAB
14 changed files with 330 additions and 328 deletions

View File

@ -27,7 +27,7 @@ const references= {
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("p").append(...T` el("p").append(T`
Welcome to Deka DOM Elements (dd<el> or DDE) a lightweight library for building dynamic UIs with Welcome to Deka DOM Elements (dd<el> or DDE) a lightweight library for building dynamic UIs with
a declarative syntax that stays close to the native DOM API. dd<el> gives you powerful reactive tools a declarative syntax that stays close to the native DOM API. dd<el> gives you powerful reactive tools
without the complexity and overhead of larger frameworks. without the complexity and overhead of larger frameworks.
@ -45,7 +45,7 @@ export function page({ pkg, info }){
el(example, { src: fileURL("./components/examples/introducing/helloWorld.js"), page_id }), el(example, { src: fileURL("./components/examples/introducing/helloWorld.js"), page_id }),
el(h3, { textContent: t`The 3PS Pattern: A Better Way to Build UIs`, id: "h-3ps" }), el(h3, { textContent: t`The 3PS Pattern: A Better Way to Build UIs`, id: "h-3ps" }),
el("p").append(...T` el("p").append(T`
At the heart of dd<el> is the 3PS (3-Part Separation) pattern. This simple yet powerful approach helps you At the heart of dd<el> is the 3PS (3-Part Separation) pattern. This simple yet powerful approach helps you
organize your UI code into three distinct areas, making your applications more maintainable and easier organize your UI code into three distinct areas, making your applications more maintainable and easier
to reason about. to reason about.
@ -62,22 +62,22 @@ export function page({ pkg, info }){
) )
) )
), ),
el("p").append(...T` el("p").append(T`
The 3PS pattern separates your code into three clear parts: The 3PS pattern separates your code into three clear parts:
`), `),
el("ol").append( el("ol").append(
el("li").append(...T` el("li").append(T`
${el("strong", "Create State")}: Define your applications reactive data using signals ${el("strong", "Create State")}: Define your applications reactive data using signals
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Bind to Elements")}: Define how UI elements react to state changes ${el("strong", "Bind to Elements")}: Define how UI elements react to state changes
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Update State")}: Modify state in response to user events or other triggers ${el("strong", "Update State")}: Modify state in response to user events or other triggers
`) `)
), ),
el("p").append(...T` el("p").append(T`
By separating these concerns, your code becomes more modular, testable, and easier to maintain. This By separating these concerns, your code becomes more modular, testable, and easier to maintain. This
approach shares principles with more formal patterns like ${el("a", { textContent: "MVVM", approach shares principles with more formal patterns like ${el("a", { textContent: "MVVM",
...references.w_mvv })} and ${el("a", { textContent: "MVC", ...references.w_mvc })}, but with less ...references.w_mvv })} and ${el("a", { textContent: "MVC", ...references.w_mvc })}, but with less
@ -85,7 +85,7 @@ export function page({ pkg, info }){
`), `),
el("div", { className: "note" }).append( el("div", { className: "note" }).append(
el("p").append(...T` el("p").append(T`
The 3PS pattern becomes especially powerful when combined with components, allowing you to create The 3PS pattern becomes especially powerful when combined with components, allowing you to create
reusable pieces of UI with encapsulated state and behavior. Youll learn more about this in the reusable pieces of UI with encapsulated state and behavior. Youll learn more about this in the
following sections. following sections.
@ -93,36 +93,36 @@ export function page({ pkg, info }){
), ),
el(h3, t`How to Use This Documentation`), el(h3, t`How to Use This Documentation`),
el("p").append(...T` el("p").append(T`
This guide will take you through dd<el>s features step by step: This guide will take you through dd<el>s features step by step:
`), `),
el("ol", { start: 2 }).append( el("ol", { start: 2 }).append(
el("li").append(...T`${el("a", { href: "p02-elements.html" }).append(el("strong", "Elements"))} — Creating el("li").append(T`${el("a", { href: "p02-elements.html" }).append(el("strong", "Elements"))} — Creating
and manipulating DOM elements`), and manipulating DOM elements`),
el("li").append(...T`${el("a", { href: "p03-events.html" }).append(el("strong", "Events and Addons"))} — el("li").append(T`${el("a", { href: "p03-events.html" }).append(el("strong", "Events and Addons"))} —
Handling user interactions and lifecycle events`), Handling user interactions and lifecycle events`),
el("li").append(...T`${el("a", { href: "p04-signals.html" }).append(el("strong", "Signals"))} — Adding el("li").append(T`${el("a", { href: "p04-signals.html" }).append(el("strong", "Signals"))} — Adding
reactivity to your UI`), reactivity to your UI`),
el("li").append(...T`${el("a", { href: "p05-scopes.html" }).append(el("strong", "Scopes"))} — Managing el("li").append(T`${el("a", { href: "p05-scopes.html" }).append(el("strong", "Scopes"))} — Managing
component lifecycles`), component lifecycles`),
el("li").append(...T`${el("a", { href: "p06-customElement.html" }).append(el("strong", "Web Components"))} — el("li").append(T`${el("a", { href: "p06-customElement.html" }).append(el("strong", "Web Components"))} —
Building native custom elements`), Building native custom elements`),
el("li").append(...T`${el("a", { href: "p07-debugging.html" }).append(el("strong", "Debugging"))} — Tools to el("li").append(T`${el("a", { href: "p07-debugging.html" }).append(el("strong", "Debugging"))} — Tools to
help you build and fix your apps`), help you build and fix your apps`),
el("li").append(...T`${el("a", { href: "p08-extensions.html" }).append(el("strong", "Extensions"))} — el("li").append(T`${el("a", { href: "p08-extensions.html" }).append(el("strong", "Extensions"))} —
Integrating third-party functionalities`), Integrating third-party functionalities`),
el("li").append(...T`${el("a", { href: "p09-optimization.html" }) el("li").append(T`${el("a", { href: "p09-optimization.html" })
.append(el("strong", "Performance Optimization"))} Techniques for optimizing your applications`), .append(el("strong", "Performance Optimization"))} Techniques for optimizing your applications`),
el("li").append(...T`${el("a", { href: "p10-todomvc.html" }).append(el("strong", "TodoMVC"))} — A real-world el("li").append(T`${el("a", { href: "p10-todomvc.html" }).append(el("strong", "TodoMVC"))} — A real-world
application implementation`), application implementation`),
el("li").append(...T`${el("a", { href: "p11-ssr.html" }).append(el("strong", "SSR"))} — Server-side el("li").append(T`${el("a", { href: "p11-ssr.html" }).append(el("strong", "SSR"))} — Server-side
rendering with dd<el>`), rendering with dd<el>`),
el("li").append(...T`${el("a", { href: "p12-ireland.html" }).append(el("strong", "Ireland Components"))} — el("li").append(T`${el("a", { href: "p12-ireland.html" }).append(el("strong", "Ireland Components"))} —
Interactive demos with server-side pre-rendering`), Interactive demos with server-side pre-rendering`),
el("li").append(...T`${el("a", { href: "p13-appendix.html" }).append(el("strong", "Appendix & Summary"))} — el("li").append(T`${el("a", { href: "p13-appendix.html" }).append(el("strong", "Appendix & Summary"))} —
Comprehensive reference and best practices`), Comprehensive reference and best practices`),
), ),
el("p").append(...T` el("p").append(T`
Each section builds on the previous ones, so we recommend following them in order. Each section builds on the previous ones, so we recommend following them in order.
Lets get started with the basics of creating elements! Lets get started with the basics of creating elements!
`), `),

View File

@ -49,7 +49,7 @@ const references= {
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("p").append(...T` el("p").append(T`
Building user interfaces in JavaScript often involves creating and manipulating DOM elements. Building user interfaces in JavaScript often involves creating and manipulating DOM elements.
dd<el> provides a simple yet powerful approach to element creation that is declarative, chainable, dd<el> provides a simple yet powerful approach to element creation that is declarative, chainable,
and maintains a clean syntax close to HTML structure. and maintains a clean syntax close to HTML structure.
@ -68,7 +68,7 @@ export function page({ pkg, info }){
el(code, { src: fileURL("./components/examples/elements/intro.js"), page_id }), el(code, { src: fileURL("./components/examples/elements/intro.js"), page_id }),
el(h3, t`Creating Elements: Native vs dd<el>`), el(h3, t`Creating Elements: Native vs dd<el>`),
el("p").append(...T` el("p").append(T`
In standard JavaScript, you create DOM elements using the In standard JavaScript, you create DOM elements using the
${el("a", references.mdn_create).append(el("code", "document.createElement()"))} method ${el("a", references.mdn_create).append(el("code", "document.createElement()"))} method
and then set properties individually or with ${el("code", "Object.assign()")}: and then set properties individually or with ${el("code", "Object.assign()")}:
@ -85,14 +85,14 @@ export function page({ pkg, info }){
) )
) )
), ),
el("p").append(...T` el("p").append(T`
The ${el("code", "el")} function provides a simple wrapper around ${el("code", "document.createElement")} The ${el("code", "el")} function provides a simple wrapper around ${el("code", "document.createElement")}
with enhanced property assignment. with enhanced property assignment.
`), `),
el(example, { src: fileURL("./components/examples/elements/dekaCreateElement.js"), page_id }), el(example, { src: fileURL("./components/examples/elements/dekaCreateElement.js"), page_id }),
el(h3, t`Advanced Property Assignment`), el(h3, t`Advanced Property Assignment`),
el("p").append(...T` el("p").append(T`
The ${el("code", "assign")} function is the heart of dd<el>s element property handling. It is internally The ${el("code", "assign")} function is the heart of dd<el>s element property handling. It is internally
used to assign properties using the ${el("code", "el")} function. ${el("code", "assign")} provides used to assign properties using the ${el("code", "el")} function. ${el("code", "assign")} provides
intelligent assignment of both ${el("a", { textContent: "properties (IDL)", ...references.mdn_idl })} intelligent assignment of both ${el("a", { textContent: "properties (IDL)", ...references.mdn_idl })}
@ -104,28 +104,28 @@ export function page({ pkg, info }){
el("dd", t`Prefers IDL properties, falls back to setAttribute() when no writable property exists`), el("dd", t`Prefers IDL properties, falls back to setAttribute() when no writable property exists`),
el("dt", t`Data and ARIA Attributes`), el("dt", t`Data and ARIA Attributes`),
el("dd").append(...T`Both ${el("code", "dataset")}.* and ${el("code", "data-")}* syntaxes supported el("dd").append(T`Both ${el("code", "dataset")}.* and ${el("code", "data-")}* syntaxes supported
(same for ${el("em", "ARIA")})`), (same for ${el("em", "ARIA")})`),
el("dt", t`Style Handling`), el("dt", t`Style Handling`),
el("dd").append(...T`Accepts string or object notation for ${el("code", "style")} property`), el("dd").append(T`Accepts string or object notation for ${el("code", "style")} property`),
el("dt", t`Class Management`), el("dt", t`Class Management`),
el("dd").append(...T`Works with ${el("code", "className")}, ${el("code", "class")}, or ${el("code", el("dd").append(T`Works with ${el("code", "className")}, ${el("code", "class")}, or ${el("code",
"classList")} object for toggling classes`), "classList")} object for toggling classes`),
el("dt", t`Force Modes`), el("dt", t`Force Modes`),
el("dd").append(...T`Use ${el("code", "=")} prefix to force attribute mode, ${el("code", ".")} prefix to el("dd").append(T`Use ${el("code", "=")} prefix to force attribute mode, ${el("code", ".")} prefix to
force property mode`), force property mode`),
el("dt", t`Attribute Removal`), el("dt", t`Attribute Removal`),
el("dd").append(...T`Pass ${el("code", "undefined")} to remove a property or attribute`) el("dd").append(T`Pass ${el("code", "undefined")} to remove a property or attribute`)
) )
), ),
el(example, { src: fileURL("./components/examples/elements/dekaAssign.js"), page_id }), el(example, { src: fileURL("./components/examples/elements/dekaAssign.js"), page_id }),
el("div", { className: "note" }).append( el("div", { className: "note" }).append(
el("p").append(...T` el("p").append(T`
You can explore standard HTML element properties in the MDN documentation for You can explore standard HTML element properties in the MDN documentation for
${el("a", { textContent: "HTMLElement", ...references.mdn_el })} (base class) ${el("a", { textContent: "HTMLElement", ...references.mdn_el })} (base class)
and specific element interfaces like ${el("a", { textContent: "HTMLParagraphElement", ...references.mdn_p })}. and specific element interfaces like ${el("a", { textContent: "HTMLParagraphElement", ...references.mdn_p })}.
@ -133,7 +133,7 @@ export function page({ pkg, info }){
), ),
el(h3, t`Building DOM Trees with Chainable Methods`), el(h3, t`Building DOM Trees with Chainable Methods`),
el("p").append(...T` el("p").append(T`
One of the most powerful features of dd<el> is its approach to building element trees. One of the most powerful features of dd<el> is its approach to building element trees.
Unlike the native DOM API which doesnt return the parent after ${el("code", "append()")}, dd<el>s Unlike the native DOM API which doesnt return the parent after ${el("code", "append()")}, dd<el>s
${el("code", "append()")} always returns the parent element: ${el("code", "append()")} always returns the parent element:
@ -150,28 +150,28 @@ export function page({ pkg, info }){
) )
) )
), ),
el("p").append(...T` el("p").append(T`
This chainable pattern is much cleaner and easier to follow, especially for deeply nested elements. This chainable pattern is much cleaner and easier to follow, especially for deeply nested elements.
It also makes it simple to add multiple children to a parent element in a single fluent expression. It also makes it simple to add multiple children to a parent element in a single fluent expression.
`), `),
el(example, { src: fileURL("./components/examples/elements/dekaAppend.js"), page_id }), el(example, { src: fileURL("./components/examples/elements/dekaAppend.js"), page_id }),
el(h3, t`Using Components to Build UI Fragments`), el(h3, t`Using Components to Build UI Fragments`),
el("p").append(...T` el("p").append(T`
The ${el("code", "el")} function is overloaded to support both tag names and function components. The ${el("code", "el")} function is overloaded to support both tag names and function components.
This lets you refactor complex UI trees into reusable pieces: This lets you refactor complex UI trees into reusable pieces:
`), `),
el(example, { src: fileURL("./components/examples/elements/dekaBasicComponent.js"), page_id }), el(example, { src: fileURL("./components/examples/elements/dekaBasicComponent.js"), page_id }),
el("p").append(...T` el("p").append(T`
Component functions receive the properties object as their first argument, just like regular elements. Component functions receive the properties object as their first argument, just like regular elements.
This makes it easy to pass data down to components and create reusable UI fragments. This makes it easy to pass data down to components and create reusable UI fragments.
`), `),
el("div", { className: "tip" }).append( el("div", { className: "tip" }).append(
el("p").append(...T` el("p").append(T`
Its helpful to use naming conventions similar to native DOM elements for your components. Its helpful to use naming conventions similar to native DOM elements for your components.
This allows you to keeps your code consistent with the DOM API. This allows you to keeps your code consistent with the DOM API.
`), `),
el("p").append(...T` el("p").append(T`
Use ${el("a", { textContent: "destructuring assignment", ...references.mdn_destruct })} Use ${el("a", { textContent: "destructuring assignment", ...references.mdn_destruct })}
to extract the properties from the ${el("code", "props")} and pass them to the component element: to extract the properties from the ${el("code", "props")} and pass them to the component element:
${el("code", "function component({ className }){ return el(\"p\", { className }); }")} for make ${el("code", "function component({ className }){ return el(\"p\", { className }); }")} for make
@ -180,29 +180,29 @@ export function page({ pkg, info }){
), ),
el(h3, t`Working with SVG and Other Namespaces`), el(h3, t`Working with SVG and Other Namespaces`),
el("p").append(...T` el("p").append(T`
For non-HTML elements like SVG, MathML, or custom namespaces, dd<el> provides the ${el("code", "elNS")} For non-HTML elements like SVG, MathML, or custom namespaces, dd<el> provides the ${el("code", "elNS")}
function which corresponds to the native ${el("a", references.mdn_ns).append(el("code", function which corresponds to the native ${el("a", references.mdn_ns).append(el("code",
"document.createElementNS"))}: "document.createElementNS"))}:
`), `),
el(example, { src: fileURL("./components/examples/elements/dekaElNS.js"), page_id }), el(example, { src: fileURL("./components/examples/elements/dekaElNS.js"), page_id }),
el("p").append(...T` el("p").append(T`
This function returns a namespace-specific element creator, allowing you to work with any element type This function returns a namespace-specific element creator, allowing you to work with any element type
using the same consistent interface. using the same consistent interface.
`), `),
el(h3, t`Best Practices for Declarative DOM Creation`), el(h3, t`Best Practices for Declarative DOM Creation`),
el("ol").append( el("ol").append(
el("li").append(...T` el("li").append(T`
${el("strong", "Use component functions for reusable UI fragments:")} Extract common UI patterns ${el("strong", "Use component functions for reusable UI fragments:")} Extract common UI patterns
into reusable functions that return elements. into reusable functions that return elements.
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Leverage destructuring for cleaner component code:")} Use ${el("strong", "Leverage destructuring for cleaner component code:")} Use
${el("a", { textContent: "destructuring", ...references.mdn_destruct })} to extract properties ${el("a", { textContent: "destructuring", ...references.mdn_destruct })} to extract properties
from the props object for cleaner component code. from the props object for cleaner component code.
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Leverage chainable methods for better performance:")} Use chainable methods ${el("strong", "Leverage chainable methods for better performance:")} Use chainable methods
${el("code", ".append()")} to build complex DOM trees for better performance and cleaner code. ${el("code", ".append()")} to build complex DOM trees for better performance and cleaner code.
`), `),

View File

@ -41,7 +41,7 @@ const references= {
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("p").append(...T` el("p").append(T`
Events are at the core of interactive web applications. dd<el> provides a clean, declarative approach to Events are at the core of interactive web applications. dd<el> provides a clean, declarative approach to
handling DOM events and extends this pattern with a powerful Addon system to incorporate additional handling DOM events and extends this pattern with a powerful Addon system to incorporate additional
functionalities into your UI templates. functionalities into your UI templates.
@ -60,7 +60,7 @@ export function page({ pkg, info }){
el(code, { src: fileURL("./components/examples/events/intro.js"), page_id }), el(code, { src: fileURL("./components/examples/events/intro.js"), page_id }),
el(h3, t`Events and Listeners: Two Approaches`), el(h3, t`Events and Listeners: Two Approaches`),
el("p").append(...T` el("p").append(T`
In JavaScript you can listen to native DOM events using In JavaScript you can listen to native DOM events using
${el("a", references.mdn_listen).append(el("code", "element.addEventListener(type, listener, options)"))}. ${el("a", references.mdn_listen).append(el("code", "element.addEventListener(type, listener, options)"))}.
dd<el> provides an alternative approach with arguments ordered differently to better fit its declarative dd<el> provides an alternative approach with arguments ordered differently to better fit its declarative
@ -78,7 +78,7 @@ export function page({ pkg, info }){
) )
) )
), ),
el("p").append(...T` el("p").append(T`
The main benefit of dd<el>s approach is that it works as an Addon (see below), making it easy to integrate The main benefit of dd<el>s approach is that it works as an Addon (see below), making it easy to integrate
directly into element declarations. directly into element declarations.
`), `),
@ -86,13 +86,13 @@ export function page({ pkg, info }){
el(h3, t`Removing Event Listeners`), el(h3, t`Removing Event Listeners`),
el("div", { className: "note" }).append( el("div", { className: "note" }).append(
el("p").append(...T` el("p").append(T`
Unlike the native addEventListener/removeEventListener pattern, dd<el> uses the ${el("a", { Unlike the native addEventListener/removeEventListener pattern, dd<el> uses the ${el("a", {
textContent: "AbortSignal", ...references.mdn_abortListener })} for declarative approach for removal: textContent: "AbortSignal", ...references.mdn_abortListener })} for declarative approach for removal:
`) `)
), ),
el(example, { src: fileURL("./components/examples/events/abortSignal.js"), page_id }), el(example, { src: fileURL("./components/examples/events/abortSignal.js"), page_id }),
el("p").append(...T` el("p").append(T`
This is the same for signals (see next section) and works well with scopes and library extendability ( This is the same for signals (see next section) and works well with scopes and library extendability (
see scopes and extensions section). see scopes and extensions section).
`), `),
@ -102,7 +102,7 @@ export function page({ pkg, info }){
el("div", { className: "tab", dataTab: "html-attr" }).append( el("div", { className: "tab", dataTab: "html-attr" }).append(
el("h4", t`HTML Attribute Style`), el("h4", t`HTML Attribute Style`),
el(code, { src: fileURL("./components/examples/events/attribute-event.js"), page_id }), el(code, { src: fileURL("./components/examples/events/attribute-event.js"), page_id }),
el("p").append(...T` el("p").append(T`
Forces usage as an HTML attribute. Corresponds to Forces usage as an HTML attribute. Corresponds to
${el("code", `<button onclick="console.log(event)">click me</button>`)}. This can be particularly ${el("code", `<button onclick="console.log(event)">click me</button>`)}. This can be particularly
useful for SSR scenarios. useful for SSR scenarios.
@ -119,13 +119,13 @@ export function page({ pkg, info }){
el("p", t`Uses the addon pattern (so adds the event listener to the element), see above.`) el("p", t`Uses the addon pattern (so adds the event listener to the element), see above.`)
) )
), ),
el("p").append(...T` el("p").append(T`
For a deeper comparison of these approaches, see For a deeper comparison of these approaches, see
${el("a", { textContent: "WebReflections detailed analysis", ...references.web_events })}. ${el("a", { textContent: "WebReflections detailed analysis", ...references.web_events })}.
`), `),
el(h3, t`Understanding Addons`), el(h3, t`Understanding Addons`),
el("p").append(...T` el("p").append(T`
Addons are a powerful pattern in dd<el> that extends beyond just event handling. Addons are a powerful pattern in dd<el> that extends beyond just event handling.
An Addon is any function that accepts an HTML element as its first parameter. An Addon is any function that accepts an HTML element as its first parameter.
`), `),
@ -139,22 +139,22 @@ export function page({ pkg, info }){
el("li", t`Capture element references`) el("li", t`Capture element references`)
) )
), ),
el("p").append(...T` el("p").append(T`
You can use Addons as 3rd argument of the ${el("code", "el")} function, making it possible to You can use Addons as 3rd argument of the ${el("code", "el")} function, making it possible to
extend your templates with additional functionality: extend your templates with additional functionality:
`), `),
el(example, { src: fileURL("./components/examples/events/templateWithListeners.js"), page_id }), el(example, { src: fileURL("./components/examples/events/templateWithListeners.js"), page_id }),
el("p").append(...T` el("p").append(T`
As the example shows, you can provide types in JSDoc+TypeScript using the global type As the example shows, you can provide types in JSDoc+TypeScript using the global type
${el("code", "ddeElementAddon")}. Notice how Addons can also be used to get element references. ${el("code", "ddeElementAddon")}. Notice how Addons can also be used to get element references.
`), `),
el(h3, t`Lifecycle Events`), el(h3, t`Lifecycle Events`),
el("p").append(...T` el("p").append(T`
Addons are called immediately when an element is created, even before its connected to the live DOM. Addons are called immediately when an element is created, even before its connected to the live DOM.
You can think of an Addon as an "oncreate" event handler. You can think of an Addon as an "oncreate" event handler.
`), `),
el("p").append(...T` el("p").append(T`
dd<el> provides two additional lifecycle events that correspond to ${el("a", { textContent: dd<el> provides two additional lifecycle events that correspond to ${el("a", { textContent:
"custom element", ...references.mdn_customElements })} lifecycle callbacks: "custom element", ...references.mdn_customElements })} lifecycle callbacks:
`), `),
@ -170,7 +170,7 @@ export function page({ pkg, info }){
el(example, { src: fileURL("./components/examples/events/live-cycle.js"), page_id }), el(example, { src: fileURL("./components/examples/events/live-cycle.js"), page_id }),
el("div", { className: "note" }).append( el("div", { className: "note" }).append(
el("p").append(...T` el("p").append(T`
For regular elements (non-custom elements), dd<el> uses ${el("a", For regular elements (non-custom elements), dd<el> uses ${el("a",
references.mdn_mutation).append(el("code", "MutationObserver"), " | MDN")} internally to track references.mdn_mutation).append(el("code", "MutationObserver"), " | MDN")} internally to track
lifecycle events. lifecycle events.
@ -179,28 +179,28 @@ export function page({ pkg, info }){
el("div", { className: "warning" }).append( el("div", { className: "warning" }).append(
el("ul").append( el("ul").append(
el("li").append(...T` el("li").append(T`
Always use ${el("code", "on.*")} functions as library must ensure proper (MutationObserver) Always use ${el("code", "on.*")} functions as library must ensure proper (MutationObserver)
registration, not ${el("code", "on('dde:*', ...)")}, even the native event system is used with event registration, not ${el("code", "on('dde:*', ...)")}, even the native event system is used with event
names prefixed with ${el("code", "dde:")}. names prefixed with ${el("code", "dde:")}.
`), `),
el("li").append(...T` el("li").append(T`
Use lifecycle events sparingly, as they require internal tracking Use lifecycle events sparingly, as they require internal tracking
`), `),
el("li").append(...T` el("li").append(T`
Leverage parent-child relationships: when a parent is removed, all children are also removed Leverage parent-child relationships: when a parent is removed, all children are also removed
`), `),
el("li").append(...T` el("li").append(T`
see section later in documentation regarding hosts elements see section later in documentation regarding hosts elements
`), `),
el("li").append(...T` el("li").append(T`
dd<el> ensures that connected/disconnected events fire only once for better predictability dd<el> ensures that connected/disconnected events fire only once for better predictability
`) `)
) )
), ),
el(h3, t`Dispatching Custom Events`), el(h3, t`Dispatching Custom Events`),
el("p").append(...T` el("p").append(T`
This makes it easy to implement component communication through events, following standard web platform This makes it easy to implement component communication through events, following standard web platform
patterns. The curried approach allows for easy reuse of event dispatchers throughout your application. patterns. The curried approach allows for easy reuse of event dispatchers throughout your application.
`), `),
@ -209,17 +209,17 @@ export function page({ pkg, info }){
el(h3, t`Best Practices`), el(h3, t`Best Practices`),
el("ol").append( el("ol").append(
el("li").append(...T` el("li").append(T`
${el("strong", "Clean up listeners")}: Use AbortSignal to prevent memory leaks ${el("strong", "Clean up listeners")}: Use AbortSignal to prevent memory leaks
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Leverage lifecycle events")}: For component setup and teardown ${el("strong", "Leverage lifecycle events")}: For component setup and teardown
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Delegate when possible")}: Add listeners to container elements when handling many ${el("strong", "Delegate when possible")}: Add listeners to container elements when handling many
similar elements similar elements
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Maintain consistency")}: Choose one event binding approach and stick with it ${el("strong", "Maintain consistency")}: Choose one event binding approach and stick with it
`) `)
), ),

View File

@ -44,7 +44,7 @@ const references= {
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("p").append(...T` el("p").append(T`
Signals provide a simple yet powerful way to create reactive applications with dd<el>. They handle the Signals provide a simple yet powerful way to create reactive applications with dd<el>. They handle the
fundamental challenge of keeping your UI in sync with changing data in a declarative, efficient way. fundamental challenge of keeping your UI in sync with changing data in a declarative, efficient way.
`), `),
@ -55,13 +55,13 @@ export function page({ pkg, info }){
el("li", t`Automatic UI updates when data changes`), el("li", t`Automatic UI updates when data changes`),
el("li", t`Clean separation between data, logic, and UI`), el("li", t`Clean separation between data, logic, and UI`),
el("li", t`Small runtime with minimal overhead`), el("li", t`Small runtime with minimal overhead`),
el("li").append(...T`${el("strong", "In future")} no dependencies or framework lock-in`) el("li").append(T`${el("strong", "In future")} no dependencies or framework lock-in`)
) )
), ),
el(code, { src: fileURL("./components/examples/signals/intro.js"), page_id }), el(code, { src: fileURL("./components/examples/signals/intro.js"), page_id }),
el(h3, t`The 3-Part Structure of Signals`), el(h3, t`The 3-Part Structure of Signals`),
el("p").append(...T` el("p").append(T`
Signals organize your code into three distinct parts, following the Signals organize your code into three distinct parts, following the
${el("a", { textContent: t`3PS principle`, href: "./#h-3ps" })}: ${el("a", { textContent: t`3PS principle`, href: "./#h-3ps" })}:
`), `),
@ -85,7 +85,7 @@ export function page({ pkg, info }){
el(example, { src: fileURL("./components/examples/signals/signals.js"), page_id }), el(example, { src: fileURL("./components/examples/signals/signals.js"), page_id }),
el("div", { className: "note" }).append( el("div", { className: "note" }).append(
el("p").append(...T` el("p").append(T`
Signals implement the ${el("a", { textContent: t`Publishsubscribe pattern`, ...references.wiki_pubsub Signals implement the ${el("a", { textContent: t`Publishsubscribe pattern`, ...references.wiki_pubsub
})}, a form of ${el("a", { textContent: t`Event-driven programming`, ...references.wiki_event_driven })}, a form of ${el("a", { textContent: t`Event-driven programming`, ...references.wiki_event_driven
})}. This architecture allows different parts of your application to stay synchronized through })}. This architecture allows different parts of your application to stay synchronized through
@ -110,30 +110,30 @@ export function page({ pkg, info }){
el("dd", t`S.on(signal, callback) → runs callback whenever signal changes`), el("dd", t`S.on(signal, callback) → runs callback whenever signal changes`),
el("dt", t`Unsubscribing`), el("dt", t`Unsubscribing`),
el("dd").append(...T`S.on(signal, callback, { signal: abortController.signal }) → Similarly to the el("dd").append(T`S.on(signal, callback, { signal: abortController.signal }) → Similarly to the
${el("code", "on")} function to register DOM events listener.`) ${el("code", "on")} function to register DOM events listener.`)
) )
), ),
el("p").append(...T` el("p").append(T`
Signals can be created with any type of value, but they work best with ${el("a", { textContent: Signals can be created with any type of value, but they work best with ${el("a", { textContent:
t`primitive types`, ...references.mdn_primitive })} like strings, numbers, and booleans. For complex t`primitive types`, ...references.mdn_primitive })} like strings, numbers, and booleans. For complex
data types like objects and arrays, youll want to use Actions (covered below). data types like objects and arrays, youll want to use Actions (covered below).
`), `),
el(h3, t`Derived Signals: Computed Values`), el(h3, t`Derived Signals: Computed Values`),
el("p").append(...T` el("p").append(T`
Computed values (also called derived signals) automatically update when their dependencies change. Computed values (also called derived signals) automatically update when their dependencies change.
Create them by passing ${el("strong", "a function")} to ${el("code", "S()")}: Create them by passing ${el("strong", "a function")} to ${el("code", "S()")}:
`), `),
el(example, { src: fileURL("./components/examples/signals/derived.js"), page_id }), el(example, { src: fileURL("./components/examples/signals/derived.js"), page_id }),
el("p").append(...T` el("p").append(T`
Derived signals are read-only - you cant call ${el("code", ".set()")} on them. Their value is always Derived signals are read-only - you cant call ${el("code", ".set()")} on them. Their value is always
computed from their dependencies. Theyre perfect for transforming or combining data from other signals. computed from their dependencies. Theyre perfect for transforming or combining data from other signals.
`), `),
el(example, { src: fileURL("./components/examples/signals/computations-abort.js"), page_id }), el(example, { src: fileURL("./components/examples/signals/computations-abort.js"), page_id }),
el(h3, t`Signal Actions: For Complex State`), el(h3, t`Signal Actions: For Complex State`),
el("p").append(...T` el("p").append(T`
When working with objects, arrays, or other complex data structures. Signal Actions provide When working with objects, arrays, or other complex data structures. Signal Actions provide
a structured way to modify state while maintaining reactivity. a structured way to modify state while maintaining reactivity.
`), `),
@ -164,7 +164,7 @@ export function page({ pkg, info }){
`, page_id })) `, page_id }))
), ),
), ),
el("p").append(...T` el("p").append(T`
In some way, you can compare it with ${el("a", { textContent: "useReducer", ...references.mdn_use_reducer })} 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 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>)")} then invoke (dispatch) registered action by calling ${el("code", "S.action(<signal>, <name>, ...<args>)")}
@ -174,7 +174,7 @@ export function page({ pkg, info }){
`), `),
el(example, { src: fileURL("./components/examples/signals/actions-demo.js"), page_id }), el(example, { src: fileURL("./components/examples/signals/actions-demo.js"), page_id }),
el("p").append(...T` el("p").append(T`
Actions provide these benefits: Actions provide these benefits:
`), `),
el("ul").append( el("ul").append(
@ -183,17 +183,17 @@ export function page({ pkg, info }){
el("li", t`Prevent accidental direct mutations`), el("li", t`Prevent accidental direct mutations`),
el("li", t`Act similar to reducers in other state management libraries`) el("li", t`Act similar to reducers in other state management libraries`)
), ),
el("p").append(...T` el("p").append(T`
Heres a more complete example of a todo list using signal actions: Heres a more complete example of a todo list using signal actions:
`), `),
el(example, { src: fileURL("./components/examples/signals/actions-todos.js"), page_id }), el(example, { src: fileURL("./components/examples/signals/actions-todos.js"), page_id }),
el("div", { className: "tip" }).append( el("div", { className: "tip" }).append(
el("p").append(...T` el("p").append(T`
${el("strong", "Special Action Methods")}: Signal actions can implement special lifecycle hooks: ${el("strong", "Special Action Methods")}: Signal actions can implement special lifecycle hooks:
`), `),
el("ul").append( el("ul").append(
el("li").append(...T` el("li").append(T`
${el("code", "[S.symbols.onclear]()")} - Called when the signal is cleared. Use it to clean up ${el("code", "[S.symbols.onclear]()")} - Called when the signal is cleared. Use it to clean up
resources. resources.
`), `),
@ -201,7 +201,7 @@ export function page({ pkg, info }){
), ),
el(h3, t`Connecting Signals to the DOM`), el(h3, t`Connecting Signals to the DOM`),
el("p").append(...T` el("p").append(T`
Signals really shine when connected to your UI. dd<el> provides several ways to bind signals to DOM elements: Signals really shine when connected to your UI. dd<el> provides several ways to bind signals to DOM elements:
`), `),
@ -245,37 +245,37 @@ export function page({ pkg, info }){
) )
), ),
el("p").append(...T` el("p").append(T`
The ${el("code", "assign")} and ${el("code", "el")} functions detect signals automatically and handle binding. The ${el("code", "assign")} and ${el("code", "el")} functions detect signals automatically and handle binding.
You can use special properties like ${el("code", "dataset")}, ${el("code", "ariaset")}, and You can use special properties like ${el("code", "dataset")}, ${el("code", "ariaset")}, and
${el("code", "classList")} for fine-grained control over specific attribute types. ${el("code", "classList")} for fine-grained control over specific attribute types.
`), `),
el(example, { src: fileURL("./components/examples/signals/dom-attrs.js"), page_id }), el(example, { src: fileURL("./components/examples/signals/dom-attrs.js"), page_id }),
el("p").append(...T` el("p").append(T`
${el("code", "S.el()")} is especially powerful for conditional rendering and lists: ${el("code", "S.el()")} is especially powerful for conditional rendering and lists:
`), `),
el(example, { src: fileURL("./components/examples/signals/dom-el.js"), page_id }), el(example, { src: fileURL("./components/examples/signals/dom-el.js"), page_id }),
el(h3, t`Best Practices for Signals`), el(h3, t`Best Practices for Signals`),
el("p").append(...T` el("p").append(T`
Follow these guidelines to get the most out of signals: Follow these guidelines to get the most out of signals:
`), `),
el("ol").append( el("ol").append(
el("li").append(...T` el("li").append(T`
${el("strong", "Keep signals small and focused")}: Use many small signals rather than a few large ones ${el("strong", "Keep signals small and focused")}: Use many small signals rather than a few large ones
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Use derived signals for computations")}: Dont recompute values in multiple places ${el("strong", "Use derived signals for computations")}: Dont recompute values in multiple places
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Clean up signal subscriptions")}: Use AbortController (scope.host()) to prevent memory ${el("strong", "Clean up signal subscriptions")}: Use AbortController (scope.host()) to prevent memory
leaks leaks
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Use actions for complex state")}: Dont directly mutate objects or arrays in signals ${el("strong", "Use actions for complex state")}: Dont directly mutate objects or arrays in signals
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Avoid infinite loops")}: Be careful when one signal updates another in a subscription ${el("strong", "Avoid infinite loops")}: Be careful when one signal updates another in a subscription
`) `)
), ),

View File

@ -29,21 +29,21 @@ const references= {
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("p").append(...T` el("p").append(T`
For state-less components we can use functions as UI components (see Elements page). But in real life, For state-less components we can use functions as UI components (see Elements page). But in real life,
we may need to handle the components life-cycle and provide JavaScript the way to properly use we may need to handle the components life-cycle and provide JavaScript the way to properly use
the ${el("a", { textContent: t`Garbage collection`, ...references.garbage_collection })}. the ${el("a", { textContent: t`Garbage collection`, ...references.garbage_collection })}.
`), `),
el(code, { src: fileURL("./components/examples/scopes/intro.js"), page_id }), el(code, { src: fileURL("./components/examples/scopes/intro.js"), page_id }),
el("p").append(...T`The library therefore uses ${el("em", t`scopes`)} to provide these functionalities.`), el("p").append(T`The library therefore uses ${el("em", t`scopes`)} to provide these functionalities.`),
el(h3, t`Understanding Host Elements and Scopes`), el(h3, t`Understanding Host Elements and Scopes`),
el("p").append(...T` el("p").append(T`
The ${el("strong", "host")} is the name for the element representing the component. This is typically the The ${el("strong", "host")} is the name for the element representing the component. This is typically the
element returned by a function. To get a reference, you can use ${el("code", "scope.host()")}. To apply addons, element returned by a function. To get a reference, you can use ${el("code", "scope.host()")}. To apply addons,
just use ${el("code", "scope.host(...<addons>)")}. just use ${el("code", "scope.host(...<addons>)")}.
`), `),
el("p").append(...T` el("p").append(T`
Scopes are primarily needed when signals are used in DOM templates (with ${el("code", "el")}, ${el("code", Scopes are primarily needed when signals are used in DOM templates (with ${el("code", "el")}, ${el("code",
"assign")}, or ${el("code", "S.el")}). They provide a way for automatically removing signal listeners "assign")}, or ${el("code", "S.el")}). They provide a way for automatically removing signal listeners
and cleaning up unused signals when components are removed from the DOM. and cleaning up unused signals when components are removed from the DOM.
@ -86,19 +86,19 @@ export function page({ pkg, info }){
el(example, { src: fileURL("./components/examples/scopes/scopes-and-hosts.js"), page_id }), el(example, { src: fileURL("./components/examples/scopes/scopes-and-hosts.js"), page_id }),
el("div", { className: "tip" }).append( el("div", { className: "tip" }).append(
el("p").append(...T` el("p").append(T`
${el("strong", "Best Practice:")} Always capture the host reference (or other scope related values) at ${el("strong", "Best Practice:")} Always capture the host reference (or other scope related values) at
the beginning of your component function using ${el("code", "const { host } = scope")} to avoid the beginning of your component function using ${el("code", "const { host } = scope")} to avoid
scope-related issues, especially with ${el("em", "asynchronous code")}. scope-related issues, especially with ${el("em", "asynchronous code")}.
`), `),
el("p").append(...T` el("p").append(T`
If you are interested in the implementation details, see Class-Based Components section. If you are interested in the implementation details, see Class-Based Components section.
`) `)
), ),
el(code, { src: fileURL("./components/examples/scopes/good-practise.js"), page_id }), el(code, { src: fileURL("./components/examples/scopes/good-practise.js"), page_id }),
el(h3, t`Class-Based Components`), el(h3, t`Class-Based Components`),
el("p").append(...T` el("p").append(T`
While functional components are the primary pattern in dd<el>, you can also create class-based components. While functional components are the primary pattern in dd<el>, you can also create class-based components.
For this, we implement function ${el("code", "elClass")} and use it to demonstrate implementation details For this, we implement function ${el("code", "elClass")} and use it to demonstrate implementation details
for better understanding of the scope logic. for better understanding of the scope logic.
@ -106,7 +106,7 @@ export function page({ pkg, info }){
el(example, { src: fileURL("./components/examples/scopes/class-component.js"), page_id }), el(example, { src: fileURL("./components/examples/scopes/class-component.js"), page_id }),
el(h3, t`Automatic Cleanup with Scopes`), el(h3, t`Automatic Cleanup with Scopes`),
el("p").append(...T` el("p").append(T`
One of the most powerful features of scopes is automatic cleanup when components are removed from the DOM. One of the most powerful features of scopes is automatic cleanup when components are removed from the DOM.
This prevents memory leaks and ensures resources are properly released. This prevents memory leaks and ensures resources are properly released.
`), `),
@ -126,7 +126,7 @@ export function page({ pkg, info }){
el(example, { src: fileURL("./components/examples/scopes/cleaning.js"), page_id }), el(example, { src: fileURL("./components/examples/scopes/cleaning.js"), page_id }),
el("div", { className: "note" }).append( el("div", { className: "note" }).append(
el("p").append(...T` el("p").append(T`
In this example, when you click "Remove", the component is removed from the DOM, and all its associated In this example, when you click "Remove", the component is removed from the DOM, and all its associated
resources are automatically cleaned up, including ${el("em", resources are automatically cleaned up, including ${el("em",
"the signal subscription that updates the text content")}. This happens because the library "the signal subscription that updates the text content")}. This happens because the library
@ -135,12 +135,12 @@ export function page({ pkg, info }){
), ),
el(h3, t`Declarative vs Imperative Components`), el(h3, t`Declarative vs Imperative Components`),
el("p").append(...T` el("p").append(T`
The library DOM API and signals work best when used declaratively. It means you split your apps logic The library DOM API and signals work best when used declaratively. It means you split your apps logic
into three parts as introduced in ${el("a", { textContent: "Signals (3PS)", ...references.signals })}. into three parts as introduced in ${el("a", { textContent: "Signals (3PS)", ...references.signals })}.
`), `),
el("div", { className: "note" }).append( el("div", { className: "note" }).append(
el("p").append(...T` el("p").append(T`
Strictly speaking, the imperative way of using the library is not prohibited. Just be careful to avoid Strictly speaking, the imperative way of using the library is not prohibited. Just be careful to avoid
mixing the declarative approach (using signals) with imperative manipulation of elements. mixing the declarative approach (using signals) with imperative manipulation of elements.
`) `)
@ -165,20 +165,20 @@ export function page({ pkg, info }){
el(h3, t`Best Practices for Scopes and Components`), el(h3, t`Best Practices for Scopes and Components`),
el("ol").append( el("ol").append(
el("li").append(...T` el("li").append(T`
${el("strong", "Capture host early:")} Use ${el("code", "const { host } = scope")} at component start ${el("strong", "Capture host early:")} Use ${el("code", "const { host } = scope")} at component start
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Define signals as constants:")} ${el("code", "const counter = S(0);")} ${el("strong", "Define signals as constants:")} ${el("code", "const counter = S(0);")}
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Prefer declarative patterns:")} Use signals to drive UI updates rather than manual DOM ${el("strong", "Prefer declarative patterns:")} Use signals to drive UI updates rather than manual DOM
manipulation manipulation
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Keep components focused:")} Each component should do one thing well ${el("strong", "Keep components focused:")} Each component should do one thing well
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Add explicit cleanup:")} For resources not managed by dd<el>, use ${el("code", ${el("strong", "Add explicit cleanup:")} For resources not managed by dd<el>, use ${el("code",
"on.disconnected")} "on.disconnected")}
`) `)

View File

@ -59,7 +59,7 @@ const references= {
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("p").append(...T` el("p").append(T`
dd<el> pairs powerfully with ${el("a", references.mdn_web_components).append(el("strong", t`Web dd<el> pairs powerfully with ${el("a", references.mdn_web_components).append(el("strong", t`Web
Components`))} to create reusable, encapsulated custom elements with all the benefits of dd<el>s Components`))} to create reusable, encapsulated custom elements with all the benefits of dd<el>s
declarative DOM construction and reactivity system. declarative DOM construction and reactivity system.
@ -76,29 +76,29 @@ export function page({ pkg, info }){
el(code, { src: fileURL("./components/examples/customElement/intro.js"), page_id }), el(code, { src: fileURL("./components/examples/customElement/intro.js"), page_id }),
el(h3, t`Getting Started: Web Components Basics`), el(h3, t`Getting Started: Web Components Basics`),
el("p").append(...T` el("p").append(T`
Web Components are a set of standard browser APIs that let you create custom HTML elements with Web Components are a set of standard browser APIs that let you create custom HTML elements with
encapsulated functionality. They consist of three main technologies: encapsulated functionality. They consist of three main technologies:
`), `),
el("ul").append( el("ul").append(
el("li").append(...T` el("li").append(T`
${el("strong", "Custom Elements:")} Create your own HTML tags with JS-defined behavior ${el("strong", "Custom Elements:")} Create your own HTML tags with JS-defined behavior
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Shadow DOM:")} Encapsulate styles and markup within a component ${el("strong", "Shadow DOM:")} Encapsulate styles and markup within a component
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "HTML Templates:")} Define reusable markup structures (${el("em", ${el("strong", "HTML Templates:")} Define reusable markup structures (${el("em",
"the dd<el> replaces this part")}) "the dd<el> replaces this part")})
`) `)
), ),
el("p").append(...T` el("p").append(T`
Lets start with a basic Custom Element example without dd<el> to establish the foundation: Lets start with a basic Custom Element example without dd<el> to establish the foundation:
`), `),
el(code, { src: fileURL("./components/examples/customElement/native-basic.js"), page_id }), el(code, { src: fileURL("./components/examples/customElement/native-basic.js"), page_id }),
el("div", { className: "note" }).append( el("div", { className: "note" }).append(
el("p").append(...T` el("p").append(T`
For complete information on Web Components, see the For complete information on Web Components, see the
${el("a", references.mdn_custom_elements).append(el("strong", t`MDN documentation`))}. ${el("a", references.mdn_custom_elements).append(el("strong", t`MDN documentation`))}.
Also, ${el("a", references.custom_elements_tips).append(el("strong", t`Handy Custom Elements Patterns`))} Also, ${el("a", references.custom_elements_tips).append(el("strong", t`Handy Custom Elements Patterns`))}
@ -107,10 +107,10 @@ export function page({ pkg, info }){
), ),
el(h3, t`dd<el> Integration: Step 1 - Event Handling`), el(h3, t`dd<el> Integration: Step 1 - Event Handling`),
el("p").append(...T` el("p").append(T`
The first step in integrating dd<el> with Web Components is enabling dd<el>s event system to work with your The first step in integrating dd<el> with Web Components is enabling dd<el>s event system to work with your
Custom Elements. This is done with ${el("code", "customElementWithDDE")}, which makes your Custom Element Custom Elements. This is done with ${el("code", "customElementWithDDE")}, which makes your Custom Element
compatible with dd<el>s event handling. (${el("em").append(...T`Notice that customElementWithDDE is compatible with dd<el>s event handling. (${el("em").append(T`Notice that customElementWithDDE is
actually`)} ${el("a", { textContent: "decorator", ...references.decorators })}) actually`)} ${el("a", { textContent: "decorator", ...references.decorators })})
`), `),
el("div", { className: "function-table" }).append( el("div", { className: "function-table" }).append(
@ -127,14 +127,14 @@ export function page({ pkg, info }){
el(example, { src: fileURL("./components/examples/customElement/customElementWithDDE.js"), page_id }), el(example, { src: fileURL("./components/examples/customElement/customElementWithDDE.js"), page_id }),
el("div", { className: "tip" }).append( el("div", { className: "tip" }).append(
el("p").append(...T` el("p").append(T`
${el("strong", "Key Point:")} The ${el("code", "customElementWithDDE")} function adds event dispatching ${el("strong", "Key Point:")} The ${el("code", "customElementWithDDE")} function adds event dispatching
to your Custom Element lifecycle methods, making them work seamlessly with dd<el>s event system. to your Custom Element lifecycle methods, making them work seamlessly with dd<el>s event system.
`) `)
), ),
el(h3, t`dd<el> Integration: Step 2 - Rendering Components`), el(h3, t`dd<el> Integration: Step 2 - Rendering Components`),
el("p").append(...T` el("p").append(T`
The next step is to use dd<el>s component rendering within your Custom Element. This is done with The next step is to use dd<el>s component rendering within your Custom Element. This is done with
${el("code", "customElementRender")}, which connects your dd<el> component function to the Custom Element. ${el("code", "customElementRender")}, which connects your dd<el> component function to the Custom Element.
`), `),
@ -159,32 +159,32 @@ export function page({ pkg, info }){
el(example, { src: fileURL("./components/examples/customElement/dde.js"), page_id }), el(example, { src: fileURL("./components/examples/customElement/dde.js"), page_id }),
el("div", { className: "note" }).append( el("div", { className: "note" }).append(
el("p").append(...T` el("p").append(T`
In this example, were using Shadow DOM (${el("code", "this.attachShadow()")}) for encapsulation, In this example, were using Shadow DOM (${el("code", "this.attachShadow()")}) for encapsulation,
but you can also render directly to the element with ${el("code", "customElementRender(this, ...)")}. but you can also render directly to the element with ${el("code", "customElementRender(this, ...)")}.
`) `)
), ),
el(h3, t`Reactive Web Components with Signals`), el(h3, t`Reactive Web Components with Signals`),
el("p").append(...T` el("p").append(T`
One of the most powerful features of integrating dd<el> with Web Components is connecting HTML attributes One of the most powerful features of integrating dd<el> with Web Components is connecting HTML attributes
to dd<el>s reactive signals system. This creates truly reactive custom elements. to dd<el>s reactive signals system. This creates truly reactive custom elements.
`), `),
el("div", { className: "tip" }).append( el("div", { className: "tip" }).append(
el("p").append(...T` el("p").append(T`
${el("strong", "Two Ways to Handle Attributes:")} ${el("strong", "Two Ways to Handle Attributes:")}
`), `),
el("ol").append( el("ol").append(
el("li").append(...T` el("li").append(T`
Using standard attribute access (${el("code", "this.getAttribute(<name>)")}) - Passes attributes as Using standard attribute access (${el("code", "this.getAttribute(<name>)")}) - Passes attributes as
regular values (static) regular values (static)
`), `),
el("li").append(...T` el("li").append(T`
${el("code", "S.observedAttributes")} - Transforms attributes into signals (reactive) ${el("code", "S.observedAttributes")} - Transforms attributes into signals (reactive)
`) `)
) )
), ),
el("p").append(...T` el("p").append(T`
Using the ${el("code", "S.observedAttributes")} creates a reactive connection between your elements Using the ${el("code", "S.observedAttributes")} creates a reactive connection between your elements
attributes and its internal rendering. When attributes change, your component automatically updates! attributes and its internal rendering. When attributes change, your component automatically updates!
`), `),
@ -203,7 +203,7 @@ export function page({ pkg, info }){
), ),
el(h3, t`Working with Shadow DOM`), el(h3, t`Working with Shadow DOM`),
el("p").append(...T` el("p").append(T`
Shadow DOM provides encapsulation for your components styles and markup. When using dd<el> with Shadow DOM, Shadow DOM provides encapsulation for your components styles and markup. When using dd<el> with Shadow DOM,
you get the best of both worlds: encapsulation plus declarative DOM creation. you get the best of both worlds: encapsulation plus declarative DOM creation.
`), `),
@ -223,14 +223,14 @@ export function page({ pkg, info }){
), ),
el(example, { src: fileURL("./components/examples/customElement/shadowRoot.js"), page_id }), el(example, { src: fileURL("./components/examples/customElement/shadowRoot.js"), page_id }),
el("p").append(...T` el("p").append(T`
For more information on Shadow DOM, see For more information on Shadow DOM, see
${el("a", { textContent: t`Using Shadow DOM`, ...references.mdn_shadow_dom_depth })}, or the comprehensive ${el("a", { textContent: t`Using Shadow DOM`, ...references.mdn_shadow_dom_depth })}, or the comprehensive
${el("a", { textContent: t`Shadow DOM in Depth`, ...references.shadow_dom_depth })}. ${el("a", { textContent: t`Shadow DOM in Depth`, ...references.shadow_dom_depth })}.
`), `),
el(h3, t`Working with Slots`), el(h3, t`Working with Slots`),
el("p").append(...T` el("p").append(T`
Besides the encapsulation, the Shadow DOM allows for using the ${el("a", references.mdn_shadow_dom_slot).append( Besides the encapsulation, the Shadow DOM allows for using the ${el("a", references.mdn_shadow_dom_slot).append(
el("strong", t`<slot>`), t` element(s)`)}. You can simulate this feature using ${el("code", "simulateSlots")}: el("strong", t`<slot>`), t` element(s)`)}. You can simulate this feature using ${el("code", "simulateSlots")}:
`), `),
@ -246,23 +246,23 @@ export function page({ pkg, info }){
), ),
el(h3, t`Best Practices for Web Components with dd<el>`), el(h3, t`Best Practices for Web Components with dd<el>`),
el("p").append(...T` el("p").append(T`
When combining dd<el> with Web Components, follow these recommendations: When combining dd<el> with Web Components, follow these recommendations:
`), `),
el("ol").append( el("ol").append(
el("li").append(...T` el("li").append(T`
${el("strong", "Always use customElementWithDDE")} to enable event integration ${el("strong", "Always use customElementWithDDE")} to enable event integration
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Prefer S.observedAttributes")} for reactive attribute connections ${el("strong", "Prefer S.observedAttributes")} for reactive attribute connections
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Create reusable component functions")} that your custom elements render ${el("strong", "Create reusable component functions")} that your custom elements render
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Use scope.host()")} to clean up event listeners and subscriptions ${el("strong", "Use scope.host()")} to clean up event listeners and subscriptions
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Add setters and getters")} for better property access to your element ${el("strong", "Add setters and getters")} for better property access to your element
`) `)
), ),

View File

@ -17,19 +17,19 @@ const fileURL= url=> new URL(url, import.meta.url);
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("p").append(...T` el("p").append(T`
Debugging is an essential part of application development. This guide provides techniques Debugging is an essential part of application development. This guide provides techniques
and best practices for debugging applications built with dd<el>, with a focus on signals. and best practices for debugging applications built with dd<el>, with a focus on signals.
`), `),
el(h3, t`Debugging signals`), el(h3, t`Debugging signals`),
el("p").append(...T` el("p").append(T`
Signals are reactive primitives that update the UI when their values change. When debugging signals, Signals are reactive primitives that update the UI when their values change. When debugging signals,
you need to track their values, understand their dependencies, and identify why updates are or aren't happening. you need to track their values, understand their dependencies, and identify why updates are or aren't happening.
`), `),
el("h4", t`Inspecting signal values`), el("h4", t`Inspecting signal values`),
el("p").append(...T` el("p").append(T`
The simplest way to debug a signal is to log its current value by calling the get method: The simplest way to debug a signal is to log its current value by calling the get method:
`), `),
el(code, { content: ` el(code, { content: `
@ -38,7 +38,7 @@ export function page({ pkg, info }){
// without triggering updates // without triggering updates
console.log('Current value:', signal.valueOf()); console.log('Current value:', signal.valueOf());
`, page_id }), `, page_id }),
el("p").append(...T` el("p").append(T`
You can also monitor signal changes by adding a listener: You can also monitor signal changes by adding a listener:
`), `),
el(code, { content: ` el(code, { content: `
@ -47,7 +47,7 @@ export function page({ pkg, info }){
`, page_id }), `, page_id }),
el("h4", t`Debugging derived signals`), el("h4", t`Debugging derived signals`),
el("p").append(...T` el("p").append(T`
With derived signals (created with ${el("code", "S(() => computation))")}), debugging is a bit more complex With derived signals (created with ${el("code", "S(() => computation))")}), debugging is a bit more complex
because the value depends on other signals. To understand why a derived signal isnt updating correctly: because the value depends on other signals. To understand why a derived signal isnt updating correctly:
`), `),
@ -69,7 +69,7 @@ export function page({ pkg, info }){
el(code, { src: fileURL("./components/examples/debugging/mutations.js"), page_id }), el(code, { src: fileURL("./components/examples/debugging/mutations.js"), page_id }),
el("h4", t`Memory leaks with signal listeners`), el("h4", t`Memory leaks with signal listeners`),
el("p").append(...T` el("p").append(T`
Signal listeners can cause memory leaks if not properly cleaned up. Always use AbortSignal Signal listeners can cause memory leaks if not properly cleaned up. Always use AbortSignal
to cancel listeners. to cancel listeners.
`), `),
@ -84,12 +84,12 @@ export function page({ pkg, info }){
el(code, { src: fileURL("./components/examples/debugging/debouncing.js"), page_id }), el(code, { src: fileURL("./components/examples/debugging/debouncing.js"), page_id }),
el(h3, t`Browser DevTools tips for dd<el>`), el(h3, t`Browser DevTools tips for dd<el>`),
el("p").append(...T` el("p").append(T`
When debugging in the browser, dd<el> provides several helpful DevTools-friendly features: When debugging in the browser, dd<el> provides several helpful DevTools-friendly features:
`), `),
el("h4", t`Identifying components in the DOM`), el("h4", t`Identifying components in the DOM`),
el("p").append(...T` el("p").append(T`
dd<el> marks components in the DOM with special comment nodes to help you identify component boundaries. dd<el> marks components in the DOM with special comment nodes to help you identify component boundaries.
Components created with ${el("code", "el(ComponentFunction)")} are marked with comment nodes Components created with ${el("code", "el(ComponentFunction)")} are marked with comment nodes
${el("code", `<!--<dde:mark type="component" name="MyComponent" host="parentElement"/>-->`)} and ${el("code", `<!--<dde:mark type="component" name="MyComponent" host="parentElement"/>-->`)} and
@ -102,23 +102,23 @@ export function page({ pkg, info }){
), ),
el("h4", t`Finding reactive elements in the DOM`), el("h4", t`Finding reactive elements in the DOM`),
el("p").append(...T` el("p").append(T`
When using ${el("code", "S.el()")}, dd<el> creates reactive elements in the DOM When using ${el("code", "S.el()")}, dd<el> creates reactive elements in the DOM
that are automatically updated when signal values change. These elements are wrapped in special that are automatically updated when signal values change. These elements are wrapped in special
comment nodes for debugging (to be true they are also used internally, so please do not edit them by hand): comment nodes for debugging (to be true they are also used internally, so please do not edit them by hand):
`), `),
el(code, { src: fileURL("./components/examples/debugging/dom-reactive-mark.html"), page_id }), el(code, { src: fileURL("./components/examples/debugging/dom-reactive-mark.html"), page_id }),
el("p").append(...T` el("p").append(T`
This is particularly useful when debugging why a reactive section isnt updating as expected. This is particularly useful when debugging why a reactive section isnt updating as expected.
You can inspect the elements between the comment nodes to see their current state and the You can inspect the elements between the comment nodes to see their current state and the
signal connections through \`__dde_reactive\` of the host element. signal connections through \`__dde_reactive\` of the host element.
`), `),
el("h4", t`DOM inspection properties`), el("h4", t`DOM inspection properties`),
el("p").append(...T` el("p").append(T`
Elements created with the dd<el> library have special properties to aid in debugging: Elements created with the dd<el> library have special properties to aid in debugging:
`), `),
el("p").append(...T` el("p").append(T`
${el("code", "<element>.__dde_reactive")} - An array property on DOM elements that tracks signal-to-element ${el("code", "<element>.__dde_reactive")} - An array property on DOM elements that tracks signal-to-element
relationships. This allows you to quickly identify which elements are reactive and what signals theyre relationships. This allows you to quickly identify which elements are reactive and what signals theyre
bound to. Each entry in the array contains: bound to. Each entry in the array contains:
@ -128,14 +128,14 @@ export function page({ pkg, info }){
el("li", t`Additional context information about the element or attribute`), el("li", t`Additional context information about the element or attribute`),
el("li", t`Automatically managed by signal.el(), signal.observedAttributes(), and processReactiveAttribute()`) el("li", t`Automatically managed by signal.el(), signal.observedAttributes(), and processReactiveAttribute()`)
), ),
el("p").append(...T` el("p").append(T`
These properties make it easier to understand the reactive structure of your application when inspecting These properties make it easier to understand the reactive structure of your application when inspecting
elements. elements.
`), `),
el(example, { src: fileURL("./components/examples/signals/debugging-dom.js"), page_id }), el(example, { src: fileURL("./components/examples/signals/debugging-dom.js"), page_id }),
el("h4", t`Examining signal connections`), el("h4", t`Examining signal connections`),
el("p").append(...T` el("p").append(T`
${el("code", "<signal>.__dde_signal")} - A Symbol property used to identify and store the internal state of ${el("code", "<signal>.__dde_signal")} - A Symbol property used to identify and store the internal state of
signal objects. It contains the following information: signal objects. It contains the following information:
`), `),
@ -147,10 +147,10 @@ export function page({ pkg, info }){
el("li", t`defined: Stack trace information for debugging`), el("li", t`defined: Stack trace information for debugging`),
el("li", t`readonly: Boolean flag indicating if the signal is read-only`) el("li", t`readonly: Boolean flag indicating if the signal is read-only`)
), ),
el("p").append(...T` el("p").append(T`
to determine the current value of the signal, call ${el("code", "signal.valueOf()")}. to determine the current value of the signal, call ${el("code", "signal.valueOf()")}.
`), `),
el("p").append(...T` el("p").append(T`
You can inspect (host) element relationships and bindings with signals in the DevTools console using You can inspect (host) element relationships and bindings with signals in the DevTools console using
${el("code", "$0.__dde_reactive")} (for currently selected element). In the console you will see a list of ${el("code", "$0.__dde_reactive")} (for currently selected element). In the console you will see a list of
${el("code", `[ [ signal, listener ], element, property ]`)}, where: ${el("code", `[ [ signal, listener ], element, property ]`)}, where:
@ -161,26 +161,26 @@ export function page({ pkg, info }){
el("li", t`element — the DOM element that is bound to the signal`), el("li", t`element — the DOM element that is bound to the signal`),
el("li", t`property — the attribute or property name which is changing based on the signal`), el("li", t`property — the attribute or property name which is changing based on the signal`),
), ),
el("p").append(...T` el("p").append(T`
the structure of \`__dde_reactive\` utilizes the browsers behavior of packing the first field, the structure of \`__dde_reactive\` utilizes the browsers behavior of packing the first field,
so you can see the element and property that changes in the console right away. so you can see the element and property that changes in the console right away.
`), `),
el("h4", t`Debugging with breakpoints`), el("h4", t`Debugging with breakpoints`),
el("p").append(...T` el("p").append(T`
Effective use of breakpoints can help track signal flow: Effective use of breakpoints can help track signal flow:
`), `),
el("ul").append( el("ul").append(
el("li").append(...T` el("li").append(T`
Set breakpoints in signal update methods to track when values change Set breakpoints in signal update methods to track when values change
`), `),
el("li").append(...T` el("li").append(T`
Use conditional breakpoints to only break when specific signals change to certain values Use conditional breakpoints to only break when specific signals change to certain values
`), `),
el("li").append(...T` el("li").append(T`
Set breakpoints in your signal computation functions to see when derived signals recalculate Set breakpoints in your signal computation functions to see when derived signals recalculate
`), `),
el("li").append(...T` el("li").append(T`
Use performance profiling to identify bottlenecks in signal updates Use performance profiling to identify bottlenecks in signal updates
`) `)
), ),

View File

@ -16,21 +16,21 @@ const fileURL= url=> new URL(url, import.meta.url);
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("p").append(...T` el("p").append(T`
dd<el> is designed with extensibility in mind. This page covers how to separate dd<el> is designed with extensibility in mind. This page covers how to separate
third-party functionalities and integrate them seamlessly with the library, focusing on third-party functionalities and integrate them seamlessly with the library, focusing on
proper resource cleanup and interoperability. proper resource cleanup and interoperability.
`), `),
el(h3, t`DOM Element Extensions with Addons`), el(h3, t`DOM Element Extensions with Addons`),
el("p").append(...T` el("p").append(T`
The primary method for extending DOM elements in dd<el> is through the Addon pattern. The primary method for extending DOM elements in dd<el> is through the Addon pattern.
Addons are functions that take an element and applying some functionality to it. This pattern enables Addons are functions that take an element and applying some functionality to it. This pattern enables
a clean, functional approach to element enhancement. a clean, functional approach to element enhancement.
`), `),
el("div", { className: "callout" }).append( el("div", { className: "callout" }).append(
el("h4", t`What are Addons?`), el("h4", t`What are Addons?`),
el("p").append(...T` el("p").append(T`
Addons are simply functions with the signature: (element) => void. They: Addons are simply functions with the signature: (element) => void. They:
`), `),
el("ul").append( el("ul").append(
@ -52,13 +52,13 @@ export function page({ pkg, info }){
`, page_id }), `, page_id }),
el(h3, t`Resource Cleanup with Abort Signals`), el(h3, t`Resource Cleanup with Abort Signals`),
el("p").append(...T` el("p").append(T`
When extending elements with functionality that uses resources like event listeners, timers, When extending elements with functionality that uses resources like event listeners, timers,
or external subscriptions, its critical to clean up these resources when the element is removed or external subscriptions, its critical to clean up these resources when the element is removed
from the DOM. dd<el> provides utilities for this through AbortSignal integration. from the DOM. dd<el> provides utilities for this through AbortSignal integration.
`), `),
el("div", { className: "tip" }).append( el("div", { className: "tip" }).append(
el("p").append(...T` el("p").append(T`
The ${el("code", "scope.signal")} property creates an AbortSignal that automatically The ${el("code", "scope.signal")} property creates an AbortSignal that automatically
triggers when an element is disconnected from the DOM, making cleanup much easier to manage. triggers when an element is disconnected from the DOM, making cleanup much easier to manage.
`) `)
@ -86,7 +86,7 @@ export function page({ pkg, info }){
`, page_id }), `, page_id }),
el(h3, t`Building Library-Independent Extensions`), el(h3, t`Building Library-Independent Extensions`),
el("p").append(...T` el("p").append(T`
When creating extensions, its a good practice to make them as library-independent as possible. When creating extensions, its a good practice to make them as library-independent as possible.
This approach enables better interoperability and future-proofing. This approach enables better interoperability and future-proofing.
`), `),
@ -125,13 +125,13 @@ export function page({ pkg, info }){
), ),
el(h3, t`Signal Extensions and Factory Patterns`), el(h3, t`Signal Extensions and Factory Patterns`),
el("p").append(...T` el("p").append(T`
Unlike DOM elements, signal functionality in dd<el> currently lacks a standardized Unlike DOM elements, signal functionality in dd<el> currently lacks a standardized
way to create library-independent extensions. This is because signals are implemented way to create library-independent extensions. This is because signals are implemented
differently across libraries. differently across libraries.
`), `),
el("div", { className: "note" }).append( el("div", { className: "note" }).append(
el("p").append(...T` el("p").append(T`
In the future, JavaScript may include built-in signals through the In the future, JavaScript may include built-in signals through the
${el("a", { href: "https://github.com/tc39/proposal-signals", textContent: "TC39 Signals Proposal" })}. ${el("a", { href: "https://github.com/tc39/proposal-signals", textContent: "TC39 Signals Proposal" })}.
dd<el> is designed with future compatibility in mind and will hopefully support these dd<el> is designed with future compatibility in mind and will hopefully support these
@ -140,7 +140,7 @@ export function page({ pkg, info }){
), ),
el("h4", t`The Signal Factory Pattern`), el("h4", t`The Signal Factory Pattern`),
el("p").append(...T` el("p").append(T`
A powerful approach for extending signal functionality is the "Signal Factory" pattern. A powerful approach for extending signal functionality is the "Signal Factory" pattern.
This approach encapsulates specific behavior in a function that creates and configures a signal. This approach encapsulates specific behavior in a function that creates and configures a signal.
`), `),
@ -191,13 +191,13 @@ export function page({ pkg, info }){
) )
), ),
el("p").append(...T` el("p").append(T`
Note how the factory accepts the signal constructor as a parameter, making it easier to test Note how the factory accepts the signal constructor as a parameter, making it easier to test
and potentially migrate to different signal implementations in the future. and potentially migrate to different signal implementations in the future.
`), `),
el("h4", t`Other Signal Extension Approaches`), el("h4", t`Other Signal Extension Approaches`),
el("p").append(...T` el("p").append(T`
For simpler cases, you can also extend signals with clear interfaces and isolation to make For simpler cases, you can also extend signals with clear interfaces and isolation to make
future migration easier. future migration easier.
`), `),
@ -221,7 +221,7 @@ export function page({ pkg, info }){
`, page_id }), `, page_id }),
el("div", { className: "tip" }).append( el("div", { className: "tip" }).append(
el("p").append(...T` el("p").append(T`
When designing signal extensions, consider creating specialized signals for common patterns like: When designing signal extensions, consider creating specialized signals for common patterns like:
forms, API requests, persistence, animations, or routing. These can significantly reduce forms, API requests, persistence, animations, or routing. These can significantly reduce
boilerplate code in your applications. boilerplate code in your applications.
@ -229,19 +229,19 @@ export function page({ pkg, info }){
), ),
el(h3, t`Using Signals Independently`), el(h3, t`Using Signals Independently`),
el("p").append(...T` el("p").append(T`
While signals are tightly integrated with DDEs DOM elements, you can also use them independently. While signals are tightly integrated with DDEs DOM elements, you can also use them independently.
This can be useful when you need reactivity in non-UI code or want to integrate with other libraries. This can be useful when you need reactivity in non-UI code or want to integrate with other libraries.
`), `),
el("p").append(...T` el("p").append(T`
There are two ways to import signals: There are two ways to import signals:
`), `),
el("ol").append( el("ol").append(
el("li").append(...T` el("li").append(T`
${el("strong", "Standard import")}: ${el("code", `import { S } from "deka-dom-el/signals";`)} ${el("strong", "Standard import")}: ${el("code", `import { S } from "deka-dom-el/signals";`)}
This automatically registers signals with DDEs DOM reactivity system This automatically registers signals with DDEs DOM reactivity system
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Independent import")}: ${el("code", `import { S } from "deka-dom-el/src/signals-lib";`)} ${el("strong", "Independent import")}: ${el("code", `import { S } from "deka-dom-el/src/signals-lib";`)}
This gives you just the signal system without DOM integration This gives you just the signal system without DOM integration
`) `)
@ -261,7 +261,7 @@ export function page({ pkg, info }){
count.set(5); // Logs: 5 count.set(5); // Logs: 5
console.log(doubled.get()); // 10 console.log(doubled.get()); // 10
`, page_id }), `, page_id }),
el("p").append(...T` el("p").append(T`
The independent signals API includes all core functionality (${el("code", "S()")}, ${el("code", "S.on()")}, The independent signals API includes all core functionality (${el("code", "S()")}, ${el("code", "S.on()")},
${el("code", "S.action()")}). ${el("code", "S.action()")}).
`), `),
@ -276,27 +276,27 @@ export function page({ pkg, info }){
el(h3, t`Best Practices for Extensions`), el(h3, t`Best Practices for Extensions`),
el("ol").append( el("ol").append(
el("li").append(...T` el("li").append(T`
${el("strong", "Use AbortSignals for cleanup:")} Always implement proper resource cleanup with ${el("strong", "Use AbortSignals for cleanup:")} Always implement proper resource cleanup with
${el("code", "scope.signal")} or similar mechanisms ${el("code", "scope.signal")} or similar mechanisms
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Separate core logic from library adaptation:")} Make your core functionality work ${el("strong", "Separate core logic from library adaptation:")} Make your core functionality work
with standard DOM APIs when possible with standard DOM APIs when possible
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Use signal factories for common patterns:")} Create reusable signal factories that encapsulate ${el("strong", "Use signal factories for common patterns:")} Create reusable signal factories that encapsulate
domain-specific behavior and state logic domain-specific behavior and state logic
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Document clearly:")} Provide clear documentation on how your extension works ${el("strong", "Document clearly:")} Provide clear documentation on how your extension works
and what resources it uses and what resources it uses
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Follow the Addon pattern:")} Keep to the (element) => element signature for ${el("strong", "Follow the Addon pattern:")} Keep to the (element) => element signature for
DOM element extensions DOM element extensions
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Avoid modifying global state:")} Extensions should be self-contained and not ${el("strong", "Avoid modifying global state:")} Extensions should be self-contained and not
affect other parts of the application affect other parts of the application
`) `)

View File

@ -45,7 +45,7 @@ const references= {
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("p").append(...T` el("p").append(T`
As your applications grow, performance becomes increasingly important. dd<el> provides several As your applications grow, performance becomes increasingly important. dd<el> provides several
techniques to optimize rendering performance, especially when dealing with large lists or frequently techniques to optimize rendering performance, especially when dealing with large lists or frequently
updating components. This guide focuses on memoization and other optimization strategies. updating components. This guide focuses on memoization and other optimization strategies.
@ -63,7 +63,7 @@ export function page({ pkg, info }){
el(code, { src: fileURL("./components/examples/optimization/intro.js"), page_id }), el(code, { src: fileURL("./components/examples/optimization/intro.js"), page_id }),
el(h3, t`Memoization with memo: Native vs dd<el>`), el(h3, t`Memoization with memo: Native vs dd<el>`),
el("p").append(...T` el("p").append(T`
In standard JavaScript applications, optimizing list rendering often involves manual caching In standard JavaScript applications, optimizing list rendering often involves manual caching
or relying on complex virtual DOM diffing algorithms. dd<el>'s ${el("code", "memo")} function or relying on complex virtual DOM diffing algorithms. dd<el>'s ${el("code", "memo")} function
provides a simpler, more direct approach: provides a simpler, more direct approach:
@ -106,13 +106,13 @@ export function page({ pkg, info }){
) )
) )
), ),
el("p").append(...T` el("p").append(T`
The ${el("a", references.memo_docs).append(el("code", "memo"))} function in dd<el> allows you to The ${el("a", references.memo_docs).append(el("code", "memo"))} function in dd<el> allows you to
cache and reuse DOM elements instead of recreating them on every render, which can cache and reuse DOM elements instead of recreating them on every render, which can
significantly improve performance for components that render frequently or contain heavy computations. significantly improve performance for components that render frequently or contain heavy computations.
`), `),
el("p").append(...T` el("p").append(T`
The memo system is particularly useful for: The memo system is particularly useful for:
`), `),
el("ul").append( el("ul").append(
@ -122,7 +122,7 @@ export function page({ pkg, info }){
), ),
el(h3, t`Using memo with Signal Rendering`), el(h3, t`Using memo with Signal Rendering`),
el("p").append(...T` el("p").append(T`
The most common use case for memoization is within ${el("code", "S.el()")} when rendering lists with The most common use case for memoization is within ${el("code", "S.el()")} when rendering lists with
${el("code", "map()")}: ${el("code", "map()")}:
`), `),
@ -136,7 +136,7 @@ export function page({ pkg, info }){
)))) ))))
`, page_id }), `, page_id }),
el("p").append(...T` el("p").append(T`
The ${el("code", "memo")} function in this context: The ${el("code", "memo")} function in this context:
`), `),
el("ol").append( el("ol").append(
@ -149,7 +149,7 @@ export function page({ pkg, info }){
el(example, { src: fileURL("./components/examples/optimization/memo.js"), page_id }), el(example, { src: fileURL("./components/examples/optimization/memo.js"), page_id }),
el(h3, t`Creating Memoization Scopes`), el(h3, t`Creating Memoization Scopes`),
el("p").append(...T` el("p").append(T`
The ${el("code", "memo()")} uses cache store defined via the ${el("code", "memo.scope")} function. The ${el("code", "memo()")} uses cache store defined via the ${el("code", "memo.scope")} function.
That is actually what the ${el("code", "S.el")} is doing under the hood: That is actually what the ${el("code", "S.el")} is doing under the hood:
`), `),
@ -173,7 +173,7 @@ export function page({ pkg, info }){
); );
`, page_id }), `, page_id }),
el("p").append(...T` el("p").append(T`
The scope function accepts options to customize its behavior: The scope function accepts options to customize its behavior:
`), `),
el(code, { content: ` el(code, { content: `
@ -193,12 +193,12 @@ export function page({ pkg, info }){
el("div", { className: "function-table" }).append( el("div", { className: "function-table" }).append(
el("dl").append( el("dl").append(
el("dt", t`onlyLast Option`), el("dt", t`onlyLast Option`),
el("dd").append(...T`Only keeps the cache from the most recent function call, el("dd").append(T`Only keeps the cache from the most recent function call,
which is useful when the entire collection is replaced. ${el("strong", "This is default behavior of ") which is useful when the entire collection is replaced. ${el("strong", "This is default behavior of ")
.append(el("code", "S.el"))}!`), .append(el("code", "S.el"))}!`),
el("dt", t`signal Option`), el("dt", t`signal Option`),
el("dd").append(...T`An ${el("a", references.mdn_abort).append(el("code", "AbortSignal"))} el("dd").append(T`An ${el("a", references.mdn_abort).append(el("code", "AbortSignal"))}
that will clear the cache when aborted, helping with memory management`) that will clear the cache when aborted, helping with memory management`)
) )
), ),
@ -206,7 +206,7 @@ export function page({ pkg, info }){
el(h3, t`Additional Optimization Techniques`), el(h3, t`Additional Optimization Techniques`),
el("h4", t`Minimizing Signal Updates`), el("h4", t`Minimizing Signal Updates`),
el("p").append(...T` el("p").append(T`
Signals are efficient, but unnecessary updates can impact performance: Signals are efficient, but unnecessary updates can impact performance:
`), `),
el("ul").append( el("ul").append(
@ -217,7 +217,7 @@ export function page({ pkg, info }){
), ),
el("h4", t`Optimizing List Rendering`), el("h4", t`Optimizing List Rendering`),
el("p").append(...T` el("p").append(T`
Beyond memoization, consider these approaches for optimizing list rendering: Beyond memoization, consider these approaches for optimizing list rendering:
`), `),
el("ul").append( el("ul").append(
@ -228,17 +228,17 @@ export function page({ pkg, info }){
), ),
el("div", { className: "tip" }).append( el("div", { className: "tip" }).append(
el("p").append(...T` el("p").append(T`
Memoization works best when your keys are stable and unique. Use IDs or other persistent Memoization works best when your keys are stable and unique. Use IDs or other persistent
identifiers rather than array indices, which can change when items are reordered. identifiers rather than array indices, which can change when items are reordered.
`), `),
el("p").append(...T` el("p").append(T`
Alternatively you can use any jsonable value as key, when the primitive values arent enough. Alternatively you can use any jsonable value as key, when the primitive values arent enough.
`) `)
), ),
el("h4", t`Memory Management`), el("h4", t`Memory Management`),
el("p").append(...T` el("p").append(T`
To prevent memory leaks and reduce memory consumption: To prevent memory leaks and reduce memory consumption:
`), `),
el("ul").append( el("ul").append(
@ -249,7 +249,7 @@ export function page({ pkg, info }){
), ),
el("h4", t`Choosing the Right Optimization Approach`), el("h4", t`Choosing the Right Optimization Approach`),
el("p").append(...T` el("p").append(T`
While memo is powerful, it's not always the best solution: While memo is powerful, it's not always the best solution:
`), `),
el("table").append( el("table").append(
@ -280,12 +280,12 @@ export function page({ pkg, info }){
), ),
el(h3, t`Known Issues and Limitations`), el(h3, t`Known Issues and Limitations`),
el("p").append(...T` el("p").append(T`
While memoization is a powerful optimization technique, there are some limitations and edge cases to be aware of: While memoization is a powerful optimization technique, there are some limitations and edge cases to be aware of:
`), `),
el("h4", t`Document Fragments and Memoization`), el("h4", t`Document Fragments and Memoization`),
el("p").append(...T` el("p").append(T`
One important limitation to understand is how memoization interacts with One important limitation to understand is how memoization interacts with
${el("a", references.mdn_fragment).append("DocumentFragment")} objects. ${el("a", references.mdn_fragment).append("DocumentFragment")} objects.
Functions like ${el("code", "S.el")} internally use DocumentFragment to efficiently handle multiple elements, Functions like ${el("code", "S.el")} internally use DocumentFragment to efficiently handle multiple elements,
@ -305,7 +305,7 @@ export function page({ pkg, info }){
container.append(memoizedFragment); // Nothing gets appended container.append(memoizedFragment); // Nothing gets appended
`, page_id }), `, page_id }),
el("p").append(...T` el("p").append(T`
This happens because a DocumentFragment is emptied when it's appended to the DOM. When the fragment This happens because a DocumentFragment is emptied when it's appended to the DOM. When the fragment
is cached by memo and reused, it's already empty. is cached by memo and reused, it's already empty.
`), `),
@ -327,7 +327,7 @@ export function page({ pkg, info }){
`, page_id }) `, page_id })
), ),
el("p").append(...T` el("p").append(T`
Generally, you should either: Generally, you should either:
`), `),
el("ol").append( el("ol").append(
@ -337,7 +337,7 @@ export function page({ pkg, info }){
), ),
el("div", { className: "note" }).append( el("div", { className: "note" }).append(
el("p").append(...T` el("p").append(T`
This limitation isn't specific to dd<el> but is related to how DocumentFragment works in the DOM. This limitation isn't specific to dd<el> but is related to how DocumentFragment works in the DOM.
Once a fragment is appended to the DOM, its child nodes are moved from the fragment to the target element, Once a fragment is appended to the DOM, its child nodes are moved from the fragment to the target element,
leaving the original fragment empty. leaving the original fragment empty.
@ -345,11 +345,11 @@ export function page({ pkg, info }){
), ),
el(h3, t`Performance Debugging`), el(h3, t`Performance Debugging`),
el("p").append(...T` el("p").append(T`
To identify performance bottlenecks in your dd<el> applications: To identify performance bottlenecks in your dd<el> applications:
`), `),
el("ol").append( el("ol").append(
el("li").append(...T`Use ${el("a", references.mdn_perf).append("browser performance tools")} to profile el("li").append(T`Use ${el("a", references.mdn_perf).append("browser performance tools")} to profile
rendering times`), rendering times`),
el("li", t`Check for excessive signal updates using S.on() listeners with console.log`), el("li", t`Check for excessive signal updates using S.on() listeners with console.log`),
el("li", t`Verify memo usage by inspecting cache hit rates`), el("li", t`Verify memo usage by inspecting cache hit rates`),
@ -357,26 +357,26 @@ export function page({ pkg, info }){
), ),
el("div", { className: "note" }).append( el("div", { className: "note" }).append(
el("p").append(...T` el("p").append(T`
For more details on debugging, see the ${el("a", { href: "p07-debugging.html", textContent: "Debugging" })} page. For more details on debugging, see the ${el("a", { href: "p07-debugging.html", textContent: "Debugging" })} page.
`) `)
), ),
el(h3, t`Best Practices for Optimized Rendering`), el(h3, t`Best Practices for Optimized Rendering`),
el("ol").append( el("ol").append(
el("li").append(...T` el("li").append(T`
${el("strong", "Use memo for list items:")} Memoize items in lists, especially when they contain complex components. ${el("strong", "Use memo for list items:")} Memoize items in lists, especially when they contain complex components.
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Clean up with AbortSignals:")} Connect memo caches to component lifecycles using AbortSignals. ${el("strong", "Clean up with AbortSignals:")} Connect memo caches to component lifecycles using AbortSignals.
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Profile before optimizing:")} Identify actual bottlenecks before adding optimization. ${el("strong", "Profile before optimizing:")} Identify actual bottlenecks before adding optimization.
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Use derived signals:")} Compute derived values efficiently with signal computations. ${el("strong", "Use derived signals:")} Compute derived values efficiently with signal computations.
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Avoid memoizing fragments:")} Memoize individual elements or use container elements ${el("strong", "Avoid memoizing fragments:")} Memoize individual elements or use container elements
instead of DocumentFragments. instead of DocumentFragments.
`) `)

View File

@ -45,7 +45,7 @@ const references= {
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("p").append(...T` el("p").append(T`
${el("a", references.todomvc).append("TodoMVC")} is a project that helps developers compare different ${el("a", references.todomvc).append("TodoMVC")} is a project that helps developers compare different
frameworks by implementing the same todo application. This implementation showcases how dd<el> frameworks by implementing the same todo application. This implementation showcases how dd<el>
can be used to build a complete, real-world application with all the expected features of a modern can be used to build a complete, real-world application with all the expected features of a modern
@ -63,7 +63,7 @@ export function page({ pkg, info }){
el("li", t`Component scopes for proper encapsulation`) el("li", t`Component scopes for proper encapsulation`)
) )
), ),
el("p").append(...T` el("p").append(T`
Below is a fully working TodoMVC implementation. You can interact with it directly in this Below is a fully working TodoMVC implementation. You can interact with it directly in this
documentation page. The example demonstrates how dd<el> handles common app development documentation page. The example demonstrates how dd<el> handles common app development
challenges in a clean, maintainable way. challenges in a clean, maintainable way.
@ -72,7 +72,7 @@ export function page({ pkg, info }){
el(example, { src: fileURL("./components/examples/reallife/todomvc.js"), variant: "big", page_id }), el(example, { src: fileURL("./components/examples/reallife/todomvc.js"), variant: "big", page_id }),
el(h3, t`Application Architecture Overview`), el(h3, t`Application Architecture Overview`),
el("p").append(...T` el("p").append(T`
The TodoMVC implementation is structured around several key components: The TodoMVC implementation is structured around several key components:
`), `),
el("div", { className: "function-table" }).append( el("div", { className: "function-table" }).append(
@ -96,7 +96,7 @@ export function page({ pkg, info }){
), ),
el(h3, t`Reactive State Management with Signals`), el(h3, t`Reactive State Management with Signals`),
el("p").append(...T` el("p").append(T`
The application uses three primary signals to manage state: The application uses three primary signals to manage state:
`), `),
el(code, { content: ` el(code, { content: `
@ -118,7 +118,7 @@ export function page({ pkg, info }){
}); });
`, page_id }), `, page_id }),
el("p").append(...T` el("p").append(T`
The ${el("code", "todosSignal")} function creates a custom signal with actions for manipulating the todos: The ${el("code", "todosSignal")} function creates a custom signal with actions for manipulating the todos:
`), `),
el(code, { content: ` el(code, { content: `
@ -200,7 +200,7 @@ export function page({ pkg, info }){
`, page_id }), `, page_id }),
el("div", { className: "note" }).append( el("div", { className: "note" }).append(
el("p").append(...T` el("p").append(T`
Using ${el("a", references.mdn_storage).append("localStorage")} allows the application to persist todos Using ${el("a", references.mdn_storage).append("localStorage")} allows the application to persist todos
even when the page is refreshed. The ${el("code", "S.on")} listener ensures todos are saved even when the page is refreshed. The ${el("code", "S.on")} listener ensures todos are saved
after every state change, providing automatic persistence without explicit calls. after every state change, providing automatic persistence without explicit calls.
@ -208,7 +208,7 @@ export function page({ pkg, info }){
), ),
el(h3, t`Integration of Signals and Reactive UI`), el(h3, t`Integration of Signals and Reactive UI`),
el("p").append(...T` el("p").append(T`
The implementation demonstrates a clean integration between signal state and reactive UI: The implementation demonstrates a clean integration between signal state and reactive UI:
`), `),
@ -233,7 +233,7 @@ export function page({ pkg, info }){
) )
`, page_id }), `, page_id }),
el("p").append(...T` el("p").append(T`
The derived signal automatically recalculates whenever either the todos list or the current filter changes, The derived signal automatically recalculates whenever either the todos list or the current filter changes,
ensuring the UI always shows the correct filtered todos. ensuring the UI always shows the correct filtered todos.
`), `),
@ -268,7 +268,7 @@ export function page({ pkg, info }){
} }
`, page_id }), `, page_id }),
el("p").append(...T` el("p").append(T`
The TodoItem component maintains its own local UI state with signals, providing immediate The TodoItem component maintains its own local UI state with signals, providing immediate
UI feedback while still communicating changes to the parent via events. UI feedback while still communicating changes to the parent via events.
`), `),
@ -289,14 +289,14 @@ export function page({ pkg, info }){
`, page_id }), `, page_id }),
el("div", { className: "tip" }).append( el("div", { className: "tip" }).append(
el("p").append(...T` el("p").append(T`
Binding signals directly to element properties creates a reactive UI that automatically updates Binding signals directly to element properties creates a reactive UI that automatically updates
when state changes, without the need for explicit DOM manipulation or virtual DOM diffing. when state changes, without the need for explicit DOM manipulation or virtual DOM diffing.
`) `)
), ),
el(h3, t`Performance Optimization with Memoization`), el(h3, t`Performance Optimization with Memoization`),
el("p").append(...T` el("p").append(T`
The implementation uses ${el("code", "memo")} to optimize performance in several key areas: The implementation uses ${el("code", "memo")} to optimize performance in several key areas:
`), `),
@ -309,7 +309,7 @@ export function page({ pkg, info }){
) )
`, page_id }), `, page_id }),
el("p").append(...T` el("p").append(T`
This approach ensures that: This approach ensures that:
`), `),
el("ul").append( el("ul").append(
@ -329,14 +329,14 @@ export function page({ pkg, info }){
)) ))
`, page_id }), `, page_id }),
el("p").append(...T` el("p").append(T`
By memoizing based on the todos length, the entire footer component is only re-rendered By memoizing based on the todos length, the entire footer component is only re-rendered
when todos are added or removed, not when their properties change. This improves performance when todos are added or removed, not when their properties change. This improves performance
by avoiding unnecessary DOM operations. by avoiding unnecessary DOM operations.
`), `),
el("div", { className: "tip" }).append( el("div", { className: "tip" }).append(
el("p").append(...T` el("p").append(T`
Memoization is especially important for UI elements that are expensive to render or that contain Memoization is especially important for UI elements that are expensive to render or that contain
many child elements. The ${el("code", "memo")} function allows precise control over when components many child elements. The ${el("code", "memo")} function allows precise control over when components
should re-render, avoiding the overhead of virtual DOM diffing algorithms. should re-render, avoiding the overhead of virtual DOM diffing algorithms.
@ -344,13 +344,13 @@ export function page({ pkg, info }){
), ),
el(h3, t`Component-Based Architecture with Events`), el(h3, t`Component-Based Architecture with Events`),
el("p").append(...T` el("p").append(T`
The TodoMVC implementation demonstrates a clean component architecture with custom events The TodoMVC implementation demonstrates a clean component architecture with custom events
for communication between components: for communication between components:
`), `),
el("h4", t`1. Main Component Event Handling`), el("h4", t`1. Main Component Event Handling`),
el("p").append(...T` el("p").append(T`
The main Todos component sets up event listeners to handle actions from child components: The main Todos component sets up event listeners to handle actions from child components:
`), `),
el(code, { content: ` el(code, { content: `
@ -360,7 +360,7 @@ export function page({ pkg, info }){
`, page_id }), `, page_id }),
el("h4", t`2. The TodoItem Component with Scopes and Local State`), el("h4", t`2. The TodoItem Component with Scopes and Local State`),
el("p").append(...T` el("p").append(T`
Each todo item is rendered by the TodoItem component that uses scopes, local signals, and custom events: Each todo item is rendered by the TodoItem component that uses scopes, local signals, and custom events:
`), `),
el(code, { content: ` el(code, { content: `
@ -403,7 +403,7 @@ export function page({ pkg, info }){
`, page_id }), `, page_id }),
el("div", { className: "tip" }).append( el("div", { className: "tip" }).append(
el("p").append(...T` el("p").append(T`
Using ${el("code", "scope")} and ${el("a", references.mdn_events).append("custom events")} Using ${el("code", "scope")} and ${el("a", references.mdn_events).append("custom events")}
creates a clean separation of concerns. Each TodoItem component dispatches events up to the parent creates a clean separation of concerns. Each TodoItem component dispatches events up to the parent
without directly manipulating the application state, following a unidirectional data flow pattern. without directly manipulating the application state, following a unidirectional data flow pattern.
@ -411,7 +411,7 @@ export function page({ pkg, info }){
), ),
el(h3, t`Improved DOM Updates with classList`), el(h3, t`Improved DOM Updates with classList`),
el("p").append(...T` el("p").append(T`
The implementation uses the reactive ${el("code", "classList")} property for efficient class updates: The implementation uses the reactive ${el("code", "classList")} property for efficient class updates:
`), `),
el(code, { content: ` el(code, { content: `
@ -423,7 +423,7 @@ export function page({ pkg, info }){
); );
`, page_id }), `, page_id }),
el("p").append(...T` el("p").append(T`
Benefits of using ${el("code", "classList")}: Benefits of using ${el("code", "classList")}:
`), `),
el("ul").append( el("ul").append(
@ -434,7 +434,7 @@ export function page({ pkg, info }){
), ),
el(h3, t`Improved Focus Management`), el(h3, t`Improved Focus Management`),
el("p").append(...T` el("p").append(T`
The implementation uses a dedicated function for managing focus in edit inputs: The implementation uses a dedicated function for managing focus in edit inputs:
`), `),
el(code, { content: ` el(code, { content: `
@ -462,7 +462,7 @@ export function page({ pkg, info }){
}, onBlurEdit, onKeyDown, addFocus) }, onBlurEdit, onKeyDown, addFocus)
`, page_id }), `, page_id }),
el("p").append(...T` el("p").append(T`
This approach offers several advantages: This approach offers several advantages:
`), `),
el("ul").append( el("ul").append(
@ -473,7 +473,7 @@ export function page({ pkg, info }){
), ),
el("div", { className: "note" }).append( el("div", { className: "note" }).append(
el("p").append(...T` el("p").append(T`
Using ${el("a", references.mdn_raf).append("requestAnimationFrame")} ensures that the focus operation Using ${el("a", references.mdn_raf).append("requestAnimationFrame")} ensures that the focus operation
happens after the browser has finished rendering the DOM changes, which is more reliable than happens after the browser has finished rendering the DOM changes, which is more reliable than
using setTimeout. using setTimeout.
@ -481,7 +481,7 @@ export function page({ pkg, info }){
), ),
el(h3, t`Efficient Conditional Rendering`), el(h3, t`Efficient Conditional Rendering`),
el("p").append(...T` el("p").append(T`
The implementation uses signals for efficient conditional rendering: The implementation uses signals for efficient conditional rendering:
`), `),
@ -520,7 +520,7 @@ export function page({ pkg, info }){
`, page_id }), `, page_id }),
el("div", { className: "note" }).append( el("div", { className: "note" }).append(
el("p").append(...T` el("p").append(T`
Unlike frameworks that use a virtual DOM, dd<el> directly updates only the specific DOM elements Unlike frameworks that use a virtual DOM, dd<el> directly updates only the specific DOM elements
that need to change. This approach is often more efficient for small to medium-sized applications, that need to change. This approach is often more efficient for small to medium-sized applications,
especially when combined with strategic memoization. especially when combined with strategic memoization.
@ -528,7 +528,7 @@ export function page({ pkg, info }){
), ),
el(h3, t`Type Safety with JSDoc Comments`), el(h3, t`Type Safety with JSDoc Comments`),
el("p").append(...T` el("p").append(T`
The implementation uses comprehensive JSDoc comments to provide type safety without requiring TypeScript: The implementation uses comprehensive JSDoc comments to provide type safety without requiring TypeScript:
`), `),
el(code, { content: ` el(code, { content: `
@ -566,7 +566,7 @@ export function page({ pkg, info }){
`, page_id }), `, page_id }),
el("div", { className: "tip" }).append( el("div", { className: "tip" }).append(
el("p").append(...T` el("p").append(T`
Using JSDoc comments provides many of the benefits of TypeScript (autocomplete, type checking, Using JSDoc comments provides many of the benefits of TypeScript (autocomplete, type checking,
documentation) while maintaining pure JavaScript code. This approach works well with modern documentation) while maintaining pure JavaScript code. This approach works well with modern
IDEs that support JSDoc type inference. IDEs that support JSDoc type inference.
@ -575,41 +575,41 @@ export function page({ pkg, info }){
el(h3, t`Best Practices Demonstrated`), el(h3, t`Best Practices Demonstrated`),
el("ol").append( el("ol").append(
el("li").append(...T` el("li").append(T`
${el("strong", "Component Composition:")} Breaking the UI into focused, reusable components ${el("strong", "Component Composition:")} Breaking the UI into focused, reusable components
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Performance Optimization:")} Strategic memoization to minimize DOM operations ${el("strong", "Performance Optimization:")} Strategic memoization to minimize DOM operations
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Reactive State Management:")} Using signals with derived computations ${el("strong", "Reactive State Management:")} Using signals with derived computations
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Event-Based Communication:")} Using custom events for component communication ${el("strong", "Event-Based Communication:")} Using custom events for component communication
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Local Component State:")} Maintaining UI state within components for better encapsulation ${el("strong", "Local Component State:")} Maintaining UI state within components for better encapsulation
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Declarative Class Management:")} Using the classList property for cleaner class handling ${el("strong", "Declarative Class Management:")} Using the classList property for cleaner class handling
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Focus Management:")} Reliable input focus with requestAnimationFrame ${el("strong", "Focus Management:")} Reliable input focus with requestAnimationFrame
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Persistent Storage:")} Automatically saving application state with signal listeners ${el("strong", "Persistent Storage:")} Automatically saving application state with signal listeners
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Type Safety:")} Using comprehensive JSDoc comments for type checking and documentation ${el("strong", "Type Safety:")} Using comprehensive JSDoc comments for type checking and documentation
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Composable Event Handlers:")} Attaching multiple event handlers to elements ${el("strong", "Composable Event Handlers:")} Attaching multiple event handlers to elements
`) `)
), ),
el("div", { className: "callout" }).append( el("div", { className: "callout" }).append(
el("h4", t`Key Takeaways`), el("h4", t`Key Takeaways`),
el("p").append(...T` el("p").append(T`
This TodoMVC implementation showcases the strengths of dd<el> for building real-world applications: This TodoMVC implementation showcases the strengths of dd<el> for building real-world applications:
`), `),
el("ul").append( el("ul").append(
@ -622,7 +622,7 @@ export function page({ pkg, info }){
) )
), ),
el("p").append(...T` el("p").append(T`
You can find the ${el("a", references.github_example).append("complete source code")} for this example on GitHub. You can find the ${el("a", references.github_example).append("complete source code")} for this example on GitHub.
Feel free to use it as a reference for your own projects or as a starting point for more complex applications. Feel free to use it as a reference for your own projects or as a starting point for more complex applications.
`), `),

View File

@ -17,7 +17,7 @@ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("div", { className: "warning" }).append( el("div", { className: "warning" }).append(
el("p").append(...T` el("p").append(T`
This part of the documentation is primarily intended for technical enthusiasts and authors of This part of the documentation is primarily intended for technical enthusiasts and authors of
3rd-party libraries. It describes an advanced feature, not a core part of the library. Most users will 3rd-party libraries. It describes an advanced feature, not a core part of the library. Most users will
not need to implement this functionality directly in their applications. This capability will hopefully not need to implement this functionality directly in their applications. This capability will hopefully
@ -25,21 +25,21 @@ export function page({ pkg, info }){
dd<el>. dd<el>.
`) `)
), ),
el("p").append(...T` el("p").append(T`
dd<el> isnt limited to browser environments. Thanks to its flexible architecture, dd<el> isnt limited to browser environments. Thanks to its flexible architecture,
it can be used for server-side rendering (SSR) to generate static HTML files. it can be used for server-side rendering (SSR) to generate static HTML files.
This is achieved through integration with for example ${el("a", { href: "https://github.com/tmpvar/jsdom", This is achieved through integration with for example ${el("a", { href: "https://github.com/tmpvar/jsdom",
textContent: "jsdom" })}, a JavaScript implementation of web standards for Node.js. textContent: "jsdom" })}, a JavaScript implementation of web standards for Node.js.
`), `),
el("p").append(...T` el("p").append(T`
Additionally, you might consider using these alternative solutions: Additionally, you might consider using these alternative solutions:
`), `),
el("ul").append( el("ul").append(
el("li").append(...T` el("li").append(T`
${el("a", { href: "https://github.com/capricorn86/happy-dom", textContent: "happy-dom" })} ${el("a", { href: "https://github.com/capricorn86/happy-dom", textContent: "happy-dom" })}
A JavaScript implementation of a web browser without its graphical user interface thats faster than jsdom A JavaScript implementation of a web browser without its graphical user interface thats faster than jsdom
`), `),
el("li").append(...T` el("li").append(T`
${el("a", { href: "https://github.com/WebReflection/linkedom", textContent: "linkedom" })} ${el("a", { href: "https://github.com/WebReflection/linkedom", textContent: "linkedom" })}
A lightweight DOM implementation specifically designed for SSR with significantly better performance A lightweight DOM implementation specifically designed for SSR with significantly better performance
than jsdom than jsdom
@ -48,7 +48,7 @@ export function page({ pkg, info }){
el(code, { src: fileURL("./components/examples/ssr/intro.js"), page_id }), el(code, { src: fileURL("./components/examples/ssr/intro.js"), page_id }),
el(h3, t`Why Server-Side Rendering?`), el(h3, t`Why Server-Side Rendering?`),
el("p").append(...T` el("p").append(T`
SSR offers several benefits: SSR offers several benefits:
`), `),
el("ul").append( el("ul").append(
@ -60,7 +60,7 @@ export function page({ pkg, info }){
), ),
el(h3, t`How jsdom Integration Works`), el(h3, t`How jsdom Integration Works`),
el("p").append(...T` el("p").append(T`
The jsdom export in dd<el> provides the necessary tools to use the library in Node.js The jsdom export in dd<el> provides the necessary tools to use the library in Node.js
by integrating with jsdom. Heres what it does: by integrating with jsdom. Heres what it does:
`), `),
@ -74,55 +74,55 @@ export function page({ pkg, info }){
el(code, { src: fileURL("./components/examples/ssr/start.js"), page_id }), el(code, { src: fileURL("./components/examples/ssr/start.js"), page_id }),
el(h3, t`Basic SSR Example`), el(h3, t`Basic SSR Example`),
el("p").append(...T` el("p").append(T`
Heres a simple example of how to use dd<el> for server-side rendering in a Node.js script: Heres a simple example of how to use dd<el> for server-side rendering in a Node.js script:
`), `),
el(code, { src: fileURL("./components/examples/ssr/basic-example.js"), page_id }), el(code, { src: fileURL("./components/examples/ssr/basic-example.js"), page_id }),
el(h3, t`Building a Static Site Generator`), el(h3, t`Building a Static Site Generator`),
el("p").append(...T` el("p").append(T`
You can build a complete static site generator with dd<el>. In fact, this documentation site You can build a complete static site generator with dd<el>. In fact, this documentation site
is built using dd<el> for server-side rendering! Heres how the documentation build process works: is built using dd<el> for server-side rendering! Heres how the documentation build process works:
`), `),
el(code, { src: fileURL("./components/examples/ssr/static-site-generator.js"), page_id }), el(code, { src: fileURL("./components/examples/ssr/static-site-generator.js"), page_id }),
el(h3, t`Working with Async Content in SSR`), el(h3, t`Working with Async Content in SSR`),
el("p").append(...T` el("p").append(T`
The jsdom export includes a queue system to handle asynchronous operations during rendering. The jsdom export includes a queue system to handle asynchronous operations during rendering.
This is crucial for components that fetch data or perform other async tasks. This is crucial for components that fetch data or perform other async tasks.
`), `),
el(code, { src: fileURL("./components/examples/ssr/async-data.js"), page_id }), el(code, { src: fileURL("./components/examples/ssr/async-data.js"), page_id }),
el(h3, t`Working with Dynamic Imports for SSR`), el(h3, t`Working with Dynamic Imports for SSR`),
el("p").append(...T` el("p").append(T`
When structuring server-side rendering code, a crucial pattern to follow is using dynamic imports When structuring server-side rendering code, a crucial pattern to follow is using dynamic imports
for both the deka-dom-el/jsdom module and your page components. for both the deka-dom-el/jsdom module and your page components.
`), `),
el("p").append(...T` el("p").append(T`
Why is this important? Why is this important?
`), `),
el("ul").append( el("ul").append(
el("li").append(...T` el("li").append(T`
${el("strong", "Static imports are hoisted:")} JavaScript hoists import statements to the top of the file, ${el("strong", "Static imports are hoisted:")} JavaScript hoists import statements to the top of the file,
executing them before any other code executing them before any other code
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Environment registration timing:")} The jsdom module auto-registers the DOM environment ${el("strong", "Environment registration timing:")} The jsdom module auto-registers the DOM environment
when imported, which must happen ${el("em", "after")} youve created your JSDOM instance and when imported, which must happen ${el("em", "after")} youve created your JSDOM instance and
${el("em", "before")} you import your components using ${el("code", "import { el } from \"deka-dom-el\";")}. ${el("em", "before")} you import your components using ${el("code", "import { el } from \"deka-dom-el\";")}.
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Correct initialization order:")} You need to control the exact sequence of: ${el("strong", "Correct initialization order:")} You need to control the exact sequence of:
create JSDOM register environment import components create JSDOM register environment import components
`) `)
), ),
el("p").append(...T` el("p").append(T`
Follow this pattern when creating server-side rendered pages: Follow this pattern when creating server-side rendered pages:
`), `),
el(code, { src: fileURL("./components/examples/ssr/pages.js"), page_id }), el(code, { src: fileURL("./components/examples/ssr/pages.js"), page_id }),
el(h3, t`SSR Considerations and Limitations`), el(h3, t`SSR Considerations and Limitations`),
el("p").append(...T` el("p").append(T`
When using dd<el> for SSR, keep these considerations in mind: When using dd<el> for SSR, keep these considerations in mind:
`), `),
el("ul").append( el("ul").append(
@ -131,19 +131,19 @@ export function page({ pkg, info }){
el("li", t`Some DOM features may behave differently in jsdom compared to real browsers`), el("li", t`Some DOM features may behave differently in jsdom compared to real browsers`),
el("li", t`For large sites, you may need to optimize memory usage by creating a new jsdom instance for each page`) el("li", t`For large sites, you may need to optimize memory usage by creating a new jsdom instance for each page`)
), ),
el("p").append(...T` el("p").append(T`
For advanced SSR applications, consider implementing hydration on the client-side to restore For advanced SSR applications, consider implementing hydration on the client-side to restore
interactivity after the initial render. interactivity after the initial render.
`), `),
el(h3, t`Real Example: How This Documentation is Built`), el(h3, t`Real Example: How This Documentation is Built`),
el("p").append(...T` el("p").append(T`
This documentation site itself is built using dd<el>s SSR capabilities. This documentation site itself is built using dd<el>s SSR capabilities.
The build process collects all page components, renders them with jsdom, and outputs static HTML files. The build process collects all page components, renders them with jsdom, and outputs static HTML files.
`), `),
el(code, { src: fileURL("./components/examples/ssr/static-site-generator.js"), page_id }), el(code, { src: fileURL("./components/examples/ssr/static-site-generator.js"), page_id }),
el("p").append(...T` el("p").append(T`
The resulting static files can be deployed to any static hosting service, The resulting static files can be deployed to any static hosting service,
providing fast loading times and excellent SEO without the need for client-side JavaScript providing fast loading times and excellent SEO without the need for client-side JavaScript
to render the initial content. to render the initial content.

View File

@ -19,7 +19,7 @@ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("div", { className: "warning" }).append( el("div", { className: "warning" }).append(
el("p").append(...T` el("p").append(T`
This part of the documentation is primarily intended for technical enthusiasts and authors of This part of the documentation is primarily intended for technical enthusiasts and authors of
3rd-party libraries. It describes an advanced feature, not a core part of the library. Most users will 3rd-party libraries. It describes an advanced feature, not a core part of the library. Most users will
not need to implement this functionality directly in their applications. This capability will hopefully not need to implement this functionality directly in their applications. This capability will hopefully
@ -29,7 +29,7 @@ export function page({ pkg, info }){
), ),
el(h3, t`What Are Ireland Components?`), el(h3, t`What Are Ireland Components?`),
el("p").append(...T` el("p").append(T`
Ireland components are a special type of component that: Ireland components are a special type of component that:
`), `),
el("ul").append( el("ul").append(
@ -38,24 +38,24 @@ export function page({ pkg, info }){
), ),
el(h3, t`How Ireland Components Work`), el(h3, t`How Ireland Components Work`),
el("p").append(...T` el("p").append(T`
The Ireland component system consists of several parts working together: The Ireland component system consists of several parts working together:
`), `),
el("ol").append( el("ol").append(
el("li").append(...T` el("li").append(T`
${el("strong", "Server-side rendering:")} Components are pre-rendered during the documentation build process ${el("strong", "Server-side rendering:")} Components are pre-rendered during the documentation build process
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Component registration:")} Source files are copied to the documentation output directory ${el("strong", "Component registration:")} Source files are copied to the documentation output directory
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Client-side scripting:")} JavaScript code is generated to load and render components ${el("strong", "Client-side scripting:")} JavaScript code is generated to load and render components
`), `),
), ),
el(h3, t`Implementation Architecture`), el(h3, t`Implementation Architecture`),
el("p").append(...T` el("p").append(T`
The core of the Ireland system is implemented in ${el("code", "docs/components/ireland.html.js")}. The core of the Ireland system is implemented in ${el("code", "docs/components/ireland.html.js")}.
It integrates with the SSR build process using the ${el("code", "registerClientFile")} function It integrates with the SSR build process using the ${el("code", "registerClientFile")} function
from ${el("code", "docs/ssr.js")}. from ${el("code", "docs/ssr.js")}.
@ -69,7 +69,7 @@ export function page({ pkg, info }){
}) })
`, page_id }), `, page_id }),
el("p").append(...T` el("p").append(T`
During the build process (${el("code", "bs/docs.js")}), the following happens: During the build process (${el("code", "bs/docs.js")}), the following happens:
`), `),
@ -81,7 +81,7 @@ export function page({ pkg, info }){
), ),
el(h3, t`Core Implementation Details`), el(h3, t`Core Implementation Details`),
el("p").append(...T` el("p").append(T`
Let's look at the key parts of the ireland component implementation: Let's look at the key parts of the ireland component implementation:
`), `),
@ -253,7 +253,7 @@ export function page({ pkg, info }){
`, page_id }), `, page_id }),
el(h3, t`Live Example`), el(h3, t`Live Example`),
el("p").append(...T` el("p").append(T`
Heres a live example of an Ireland component showing a standard counter. Heres a live example of an Ireland component showing a standard counter.
The component is defined in ${el("code", "docs/components/examples/ireland-test/counter.js")} and The component is defined in ${el("code", "docs/components/examples/ireland-test/counter.js")} and
rendered with the Ireland component system: rendered with the Ireland component system:
@ -269,21 +269,21 @@ export function page({ pkg, info }){
page_id page_id
}), }),
el("p").append(...T` el("p").append(T`
When the page is loaded, the component is also loaded and rendered. The counter state is maintained When the page is loaded, the component is also loaded and rendered. The counter state is maintained
using signals, allowing for reactive updates as you click the buttons to increment and decrement the using signals, allowing for reactive updates as you click the buttons to increment and decrement the
value. value.
`), `),
el(h3, t`Practical Considerations and Limitations`), el(h3, t`Practical Considerations and Limitations`),
el("p").append(...T` el("p").append(T`
When implementing Ireland components in real documentation, there are several important When implementing Ireland components in real documentation, there are several important
considerations to keep in mind: considerations to keep in mind:
`), `),
el("div", { className: "warning" }).append( el("div", { className: "warning" }).append(
el("h4", t`Module Resolution and Bundling`), el("h4", t`Module Resolution and Bundling`),
el("p").append(...T` el("p").append(T`
The examples shown here use bare module specifiers like ${el("code", The examples shown here use bare module specifiers like ${el("code",
`import { el } from "deka-dom-el"`)} which arent supported in all browsers without importmaps. `import { el } from "deka-dom-el"`)} which arent supported in all browsers without importmaps.
In a production implementation, you would need to: `), In a production implementation, you would need to: `),
@ -292,7 +292,7 @@ export function page({ pkg, info }){
el("li", t`Bundle component dependencies to avoid multiple requests`), el("li", t`Bundle component dependencies to avoid multiple requests`),
el("li", t`Ensure all module dependencies are properly resolved and copied to the output directory`) el("li", t`Ensure all module dependencies are properly resolved and copied to the output directory`)
), ),
el("p").append(...T` el("p").append(T`
In this documentation, we replace the paths with ${el("code", "./esm-with-signals.js")} and provide In this documentation, we replace the paths with ${el("code", "./esm-with-signals.js")} and provide
a bundled version of the library, but more complex components might require a dedicated bundling step. a bundled version of the library, but more complex components might require a dedicated bundling step.
`) `)
@ -300,7 +300,7 @@ export function page({ pkg, info }){
el("div", { className: "note" }).append( el("div", { className: "note" }).append(
el("h4", t`Component Dependencies`), el("h4", t`Component Dependencies`),
el("p").append(...T` el("p").append(T`
Real-world components typically depend on multiple modules and assets. The Ireland system would need Real-world components typically depend on multiple modules and assets. The Ireland system would need
to be extended to: to be extended to:
`), `),
@ -312,7 +312,7 @@ export function page({ pkg, info }){
), ),
el(h3, t`Advanced Usage`), el(h3, t`Advanced Usage`),
el("p").append(...T` el("p").append(T`
The Ireland system can be extended in several ways to address these limitations: The Ireland system can be extended in several ways to address these limitations:
`), `),
@ -325,7 +325,7 @@ export function page({ pkg, info }){
el("li", t`Implement state persistence between runs`) el("li", t`Implement state persistence between runs`)
), ),
el("p").append(...T` el("p").append(T`
This documentation site itself is built using the techniques described here, This documentation site itself is built using the techniques described here,
showcasing how dd<el> can be used to create both the documentation and showcasing how dd<el> can be used to create both the documentation and
the interactive examples within it. The implementation here is simplified for clarity, the interactive examples within it. The implementation here is simplified for clarity,

View File

@ -32,45 +32,45 @@ const references= {
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("p").append(...T` el("p").append(T`
This reference guide provides a comprehensive summary of dd<el>'s key concepts, best practices, This reference guide provides a comprehensive summary of dd<el>'s key concepts, best practices,
case studies, and advanced techniques. Use it as a quick reference when working with the library case studies, and advanced techniques. Use it as a quick reference when working with the library
or to deepen your understanding of its design principles and patterns. or to deepen your understanding of its design principles and patterns.
`), `),
el(h3, t`Core Principles of dd<el>`), el(h3, t`Core Principles of dd<el>`),
el("p").append(...T` el("p").append(T`
At its foundation, dd<el> is built on several core principles that shape its design and usage: At its foundation, dd<el> is built on several core principles that shape its design and usage:
`), `),
el("div", { className: "callout" }).append( el("div", { className: "callout" }).append(
el("h4", t`Guiding Principles`), el("h4", t`Guiding Principles`),
el("ul").append( el("ul").append(
el("li").append(...T` el("li").append(T`
${el("strong", "DOM-First Approach:")} Working directly with the real DOM instead of virtual DOM ${el("strong", "DOM-First Approach:")} Working directly with the real DOM instead of virtual DOM
abstractions abstractions
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Declarative Syntax:")} Creating UIs by describing what they should look like, not ${el("strong", "Declarative Syntax:")} Creating UIs by describing what they should look like, not
how to create them how to create them
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Minimal Overhead:")} Staying close to standard Web APIs without unnecessary ${el("strong", "Minimal Overhead:")} Staying close to standard Web APIs without unnecessary
abstractions abstractions
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Progressive Enhancement:")} Starting simple and adding complexity only when needed ${el("strong", "Progressive Enhancement:")} Starting simple and adding complexity only when needed
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Functional Composition:")} Building UIs through function composition rather than ${el("strong", "Functional Composition:")} Building UIs through function composition rather than
inheritance inheritance
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Clear Patterns:")} Promoting maintainable code organization with the 3PS pattern ${el("strong", "Clear Patterns:")} Promoting maintainable code organization with the 3PS pattern
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Targeted Reactivity:")} Using signals for efficient, fine-grained updates ${el("strong", "Targeted Reactivity:")} Using signals for efficient, fine-grained updates
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Unix Philosophy:")} Doing one thing well and allowing composability with other tools ${el("strong", "Unix Philosophy:")} Doing one thing well and allowing composability with other tools
`) `)
) )
@ -79,7 +79,7 @@ export function page({ pkg, info }){
el(h3, t`Case Studies & Real-World Applications`), el(h3, t`Case Studies & Real-World Applications`),
el("h4", t`TodoMVC Implementation`), el("h4", t`TodoMVC Implementation`),
el("p").append(...T` el("p").append(T`
The ${el("a", references.todomvc).append("TodoMVC implementation")} showcases how dd<el> handles a complete, The ${el("a", references.todomvc).append("TodoMVC implementation")} showcases how dd<el> handles a complete,
real-world application with all standard features of a modern web app: real-world application with all standard features of a modern web app:
`), `),
@ -92,40 +92,40 @@ export function page({ pkg, info }){
el("li", t`Custom event system for component communication`), el("li", t`Custom event system for component communication`),
el("li", t`Proper focus management and accessibility`) el("li", t`Proper focus management and accessibility`)
), ),
el("p").append(...T` el("p").append(T`
Key takeaways from the TodoMVC example: Key takeaways from the TodoMVC example:
`), `),
el("ul").append( el("ul").append(
el("li").append(...T` el("li").append(T`
Signal factories like ${el("code", "routerSignal")} and ${el("code", "todosSignal")} Signal factories like ${el("code", "routerSignal")} and ${el("code", "todosSignal")}
encapsulate related functionality encapsulate related functionality
`), `),
el("li").append(...T` el("li").append(T`
Custom events provide clean communication between components Custom events provide clean communication between components
`), `),
el("li").append(...T` el("li").append(T`
Targeted memoization improves rendering performance dramatically Targeted memoization improves rendering performance dramatically
`), `),
el("li").append(...T` el("li").append(T`
Derived signals simplify complex UI logic like filtering Derived signals simplify complex UI logic like filtering
`) `)
), ),
el("h4", t`Migrating from Traditional Approaches`), el("h4", t`Migrating from Traditional Approaches`),
el("p").append(...T` el("p").append(T`
When migrating from traditional DOM manipulation or other frameworks to dd<el>: When migrating from traditional DOM manipulation or other frameworks to dd<el>:
`), `),
el("ol").append( el("ol").append(
el("li").append(...T` el("li").append(T`
${el("strong", "Start with state:")}: Convert global variables or ad-hoc state to signals ${el("strong", "Start with state:")}: Convert global variables or ad-hoc state to signals
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Replace query selectors:")}: Replace getElementById/querySelector with direct references to elements ${el("strong", "Replace query selectors:")}: Replace getElementById/querySelector with direct references to elements
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Convert imperative updates:")}: Replace manual DOM updates with declarative signal bindings ${el("strong", "Convert imperative updates:")}: Replace manual DOM updates with declarative signal bindings
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Refactor into components:")}: Organize related UI elements into component functions ${el("strong", "Refactor into components:")}: Organize related UI elements into component functions
`) `)
), ),
@ -211,19 +211,19 @@ export function page({ pkg, info }){
el("div").append( el("div").append(
el("h4", t`Code Organization`), el("h4", t`Code Organization`),
el("ul").append( el("ul").append(
el("li").append(...T` el("li").append(T`
${el("strong", "Follow the 3PS pattern:")}: Separate state creation, binding to elements, and state updates ${el("strong", "Follow the 3PS pattern:")}: Separate state creation, binding to elements, and state updates
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Use component functions:")}: Create reusable UI components as functions ${el("strong", "Use component functions:")}: Create reusable UI components as functions
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Create signal factories:")}: Extract reusable signal patterns into factory functions ${el("strong", "Create signal factories:")}: Extract reusable signal patterns into factory functions
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Leverage scopes:")}: Use scope for component context and clean resource management ${el("strong", "Leverage scopes:")}: Use scope for component context and clean resource management
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Event delegation:")}: Prefer component-level event handlers over many individual handlers ${el("strong", "Event delegation:")}: Prefer component-level event handlers over many individual handlers
`) `)
) )
@ -232,23 +232,23 @@ export function page({ pkg, info }){
el("div").append( el("div").append(
el("h4", t`Performance Optimization`), el("h4", t`Performance Optimization`),
el("ul").append( el("ul").append(
el("li").append(...T` el("li").append(T`
${el("strong", "Memoize list items:")}: Use ${el("code", "memo")} for items in frequently-updated lists ${el("strong", "Memoize list items:")}: Use ${el("code", "memo")} for items in frequently-updated lists
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Avoid unnecessary signal updates:")}: Only update signals when values actually change ${el("strong", "Avoid unnecessary signal updates:")}: Only update signals when values actually change
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Use AbortSignals:")}: Clean up resources when components are removed ${el("strong", "Use AbortSignals:")}: Clean up resources when components are removed
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Prefer derived signals:")}: Use computed values instead of manual updates ${el("strong", "Prefer derived signals:")}: Use computed values instead of manual updates
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Avoid memoizing fragments:")}: Never memoize DocumentFragments, only individual elements ${el("strong", "Avoid memoizing fragments:")}: Never memoize DocumentFragments, only individual elements
`) `)
), ),
el("p").append(...T` el("p").append(T`
See the ${el("a", references.performance).append("Performance Optimization Guide")} for detailed strategies. See the ${el("a", references.performance).append("Performance Optimization Guide")} for detailed strategies.
`) `)
), ),
@ -324,56 +324,56 @@ export function page({ pkg, info }){
), ),
el(h3, t`Looking Ahead: Future Directions`), el(h3, t`Looking Ahead: Future Directions`),
el("p").append(...T` el("p").append(T`
The dd<el> library continues to evolve, with several areas of focus for future development: The dd<el> library continues to evolve, with several areas of focus for future development:
`), `),
el("ul").append( el("ul").append(
el("li").append(...T` el("li").append(T`
${el("strong", "Future Compatibility:")} Alignment with the TC39 Signals proposal for native browser support ${el("strong", "Future Compatibility:")} Alignment with the TC39 Signals proposal for native browser support
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "SSR Improvements:")} Enhanced server-side rendering capabilities ${el("strong", "SSR Improvements:")} Enhanced server-side rendering capabilities
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Ecosystem Growth:")} More utilities, patterns, and integrations with other libraries ${el("strong", "Ecosystem Growth:")} More utilities, patterns, and integrations with other libraries
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "Documentation Expansion:")} Additional examples, tutorials, and best practices ${el("strong", "Documentation Expansion:")} Additional examples, tutorials, and best practices
`), `),
el("li").append(...T` el("li").append(T`
${el("strong", "TypeScript Enhancements:")} Improved type definitions and inference ${el("strong", "TypeScript Enhancements:")} Improved type definitions and inference
`) `)
), ),
el(h3, t`Contribution and Community`), el(h3, t`Contribution and Community`),
el("p").append(...T` el("p").append(T`
dd<el> is an open-source project that welcomes contributions from the community: dd<el> is an open-source project that welcomes contributions from the community:
`), `),
el("ul").append( el("ul").append(
el("li").append(...T` el("li").append(T`
${el("a", references.github).append("GitHub Repository")}: Star, fork, and contribute to the project ${el("a", references.github).append("GitHub Repository")}: Star, fork, and contribute to the project
`), `),
el("li").append(...T` el("li").append(T`
Bug reports and feature requests: Open issues on GitHub Bug reports and feature requests: Open issues on GitHub
`), `),
el("li").append(...T` el("li").append(T`
Documentation improvements: Help expand and clarify these guides Documentation improvements: Help expand and clarify these guides
`), `),
el("li").append(...T` el("li").append(T`
Examples and case studies: Share your implementations and solutions Examples and case studies: Share your implementations and solutions
`) `)
), ),
el("div", { className: "callout" }).append( el("div", { className: "callout" }).append(
el("h4", t`Final Thoughts`), el("h4", t`Final Thoughts`),
el("p").append(...T` el("p").append(T`
dd<el> provides a lightweight yet powerful approach to building modern web interfaces dd<el> provides a lightweight yet powerful approach to building modern web interfaces
with minimal overhead and maximal flexibility. By embracing standard web technologies with minimal overhead and maximal flexibility. By embracing standard web technologies
rather than abstracting them away, it offers a development experience that scales rather than abstracting them away, it offers a development experience that scales
from simple interactive elements to complex applications while remaining close from simple interactive elements to complex applications while remaining close
to what makes the web platform powerful. to what makes the web platform powerful.
`), `),
el("p").append(...T` el("p").append(T`
Whether you're building a small interactive component or a full-featured application, Whether you're building a small interactive component or a full-featured application,
dd<el>'s combination of declarative syntax, targeted reactivity, and pragmatic design dd<el>'s combination of declarative syntax, targeted reactivity, and pragmatic design
provides the tools you need without the complexity you don't. provides the tools you need without the complexity you don't.

View File

@ -17,12 +17,14 @@
* *
* @param {TemplateStringsArray} strings * @param {TemplateStringsArray} strings
* @param {...(string|Node)} values * @param {...(string|Node)} values
* @returns {(string|Node)[]} * @returns {DocumentFragment}
* */ * */
export function T(strings, ...values){ export function T(strings, ...values){
const out= []; const out= [];
tT(s=> out.push(s), strings, ...values); tT(s=> out.push(s), strings, ...values);
return out; const fragment= document.createDocumentFragment();
fragment.append(...out);
return fragment;
} }
/** /**
* Similarly to {@link T}, but for only strings. * Similarly to {@link T}, but for only strings.