From f0dfdfde54de17e357c1c70b40c855ece50f9876 Mon Sep 17 00:00:00 2001 From: Jan Andrle Date: Sun, 16 Mar 2025 11:30:42 +0100 Subject: [PATCH] =?UTF-8?q?v0.9.2=20=E2=80=94=20:bug:=20types,=20:zap:=20o?= =?UTF-8?q?n.defer=20and=20other=20small=20:zap:=20=20(#36)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :abc: :zap: T now uses DocumentFragment * :abc: * :abc: :zap: * :bug: lint * :zap: cleanup * :zap: :abc: lib download * :zap: :abc: ui * :zap: reorganize files * :zap: on.host * :bug: on.* types * :zap: :abc: cdn * :abc: converter * :bug: signal.set(value, force) * :zap: :abc: * :abc: :zap: converter - convert also comments * :zap: bs/build * :abc: ui p14 * :abc: * :abc: Examples * :abc: * :bug: now only el(..., string|number) * :bug: fixes #38 * :abc: * :zap: on.host → on.defer * :abc: * :tv: --- README.md | 49 +- bs/build.js | 12 +- bs/dev/.build.js | 76 +- dist/esm-with-signals.d.min.ts | 641 ---------------- dist/esm-with-signals.d.ts | 31 +- dist/esm-with-signals.js | 203 ++--- dist/esm-with-signals.min.d.ts | 31 +- dist/esm-with-signals.min.js | 8 +- dist/esm.d.min.ts | 568 -------------- dist/esm.d.ts | 31 +- dist/esm.js | 183 ++--- dist/esm.min.d.ts | 31 +- dist/esm.min.js | 2 +- dist/iife-with-signals.d.ts | 31 +- dist/iife-with-signals.js | 203 ++--- dist/iife-with-signals.min.d.ts | 31 +- dist/iife-with-signals.min.js | 8 +- dist/iife.d.ts | 31 +- dist/iife.js | 183 ++--- dist/iife.min.d.ts | 31 +- dist/iife.min.js | 2 +- docs/assets/devtools.png | Bin 0 -> 148296 bytes docs/components/code.html.js | 2 +- docs/components/converter.html.js | 176 +++++ docs/components/converter.js.js | 384 ++++++++++ docs/components/example.html.js | 4 +- .../examples/case-studies/data-dashboard.js | 394 ++++++++++ .../examples/case-studies/image-gallery.js | 417 ++++++++++ .../examples/case-studies/interactive-form.js | 342 +++++++++ .../examples/case-studies/task-manager.js | 715 ++++++++++++++++++ .../examples/debugging/debouncing.js | 60 +- docs/components/examples/events/live-cycle.js | 31 +- .../examples/introducing/helloWorld.js | 26 +- .../examples/ireland-test/counter.js | 2 +- docs/components/examples/reallife/todomvc.js | 136 ++-- .../examples/signals/actions-todos.js | 2 +- docs/components/getLibraryUrl.html.js | 83 ++ docs/components/getLibraryUrl.js.js | 92 +++ docs/components/ireland.html.js | 45 +- docs/components/mnemonic/signals-init.js | 11 +- .../{scrollTop.css.js => scrollTop.html.js} | 11 + docs/global.css.js | 35 +- docs/index.html.js | 89 ++- docs/layout/simplePage.html.js | 7 +- docs/p02-elements.html.js | 44 +- docs/p03-events.html.js | 69 +- docs/p04-signals.html.js | 53 +- docs/p05-scopes.html.js | 34 +- docs/p06-customElement.html.js | 52 +- docs/p07-debugging.html.js | 188 +++-- docs/p08-extensions.html.js | 47 +- docs/p09-optimization.html.js | 126 +-- docs/p10-todomvc.html.js | 144 ++-- docs/p11-ssr.html.js | 40 +- docs/p12-ireland.html.js | 34 +- docs/p13-appendix.html.js | 296 ++++++-- docs/p14-converter.html.js | 53 ++ docs/p15-examples.html.js | 63 ++ docs/utils/index.js | 6 +- examples/components/3rd-party.js | 51 -- examples/components/fullNameComponent.js | 42 - examples/components/todosComponent.js | 93 --- examples/components/webComponent.js | 70 -- examples/exports.js | 30 - examples/index-nosignals.html | 26 - examples/index.html | 16 - examples/index.js | 30 - index.d.ts | 48 +- index.js | 6 +- jsdom.js | 2 +- package-lock.json | 4 +- package.json | 2 +- signals.d.ts | 2 +- src/{dom-common.js => dom-lib/common.js} | 2 +- src/{ => dom-lib}/customElement.js | 45 +- src/{dom.js => dom-lib/el.js} | 190 +---- src/{ => dom-lib}/events-observer.js | 4 +- src/{ => dom-lib}/events.js | 6 +- src/dom-lib/helpers.js | 57 ++ src/dom-lib/index.js | 4 + src/dom-lib/scopes.js | 82 ++ src/signals-lib/helpers.js | 16 +- src/signals-lib/signals-lib.js | 16 +- 83 files changed, 4624 insertions(+), 2919 deletions(-) delete mode 100644 dist/esm-with-signals.d.min.ts delete mode 100644 dist/esm.d.min.ts create mode 100644 docs/assets/devtools.png create mode 100644 docs/components/converter.html.js create mode 100644 docs/components/converter.js.js create mode 100644 docs/components/examples/case-studies/data-dashboard.js create mode 100644 docs/components/examples/case-studies/image-gallery.js create mode 100644 docs/components/examples/case-studies/interactive-form.js create mode 100644 docs/components/examples/case-studies/task-manager.js create mode 100644 docs/components/getLibraryUrl.html.js create mode 100644 docs/components/getLibraryUrl.js.js rename docs/components/{scrollTop.css.js => scrollTop.html.js} (75%) create mode 100644 docs/p14-converter.html.js create mode 100644 docs/p15-examples.html.js delete mode 100644 examples/components/3rd-party.js delete mode 100644 examples/components/fullNameComponent.js delete mode 100644 examples/components/todosComponent.js delete mode 100644 examples/components/webComponent.js delete mode 100644 examples/exports.js delete mode 100644 examples/index-nosignals.html delete mode 100644 examples/index.html delete mode 100644 examples/index.js rename src/{dom-common.js => dom-lib/common.js} (97%) rename src/{ => dom-lib}/customElement.js (61%) rename src/{dom.js => dom-lib/el.js} (61%) rename src/{ => dom-lib}/events-observer.js (98%) rename src/{ => dom-lib}/events.js (95%) create mode 100644 src/dom-lib/helpers.js create mode 100644 src/dom-lib/index.js create mode 100644 src/dom-lib/scopes.js diff --git a/README.md b/README.md index 13a5c1a..55a1f73 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ function EmojiCounter({ initial }) { el("p", { className: "output", textContent: S(() => - `Hello World ${emoji.get().repeat(clicks.get())}`), + `Hello World ${emoji.get().repeat(count.get())}`), }), // 🎮 Controls - Update state on events @@ -39,12 +39,12 @@ function EmojiCounter({ initial }) { on("click", () => count.set(count.get() + 1)) ), - el("select", null, + el("select", null, on.host(el=> el.value= initial), on("change", e => emoji.set(e.target.value)) ).append( - el(Option, "🎉", isSelected), - el(Option, "🚀", isSelected), - el(Option, "💖", isSelected), + el(Option, "🎉"), + el(Option, "🚀"), + el(Option, "💖"), ) ); } @@ -93,18 +93,30 @@ into existing projects. # npm install deka-dom-el ``` -#### Direct Script +#### CDN / Direct Script + +For CDN links and various build formats (ESM/IIFE, with/without signals, minified/unminified), see the [interactive +format selector](https://jaandrle.github.io/deka-dom-el/) on the documentation site. + ```html + - + + + ``` ### Documentation -- [**Interactive Guide**](https://jaandrle.github.io/deka-dom-el): WIP -- [Examples](./examples/): TBD/WIP +- [**Interactive Guide**](https://jaandrle.github.io/deka-dom-el) +- [**Examples**](https://jaandrle.github.io/deka-dom-el/p15-examples.html) ## Understanding Signals @@ -117,10 +129,17 @@ Signals are the reactive backbone of Deka DOM Elements: ## Inspiration and Alternatives -- [vanjs-org/van](https://github.com/vanjs-org/van) - World's smallest reactive UI framework -- [adamhaile/S](https://github.com/adamhaile/S) - Simple, clean, fast reactive programming -- [hyperhype/hyperscript](https://github.com/hyperhype/hyperscript) - Create HyperText with JavaScript -- [potch/signals](https://github.com/potch/signals) - A small reactive signals library -- [jaandrle/dollar_dom_component](https://github.com/jaandrle/dollar_dom_component) - +- [vanjs-org/van](https://github.com/vanjs-org/van) — World's smallest reactive UI framework +- [adamhaile/S](https://github.com/adamhaile/S) — Simple, clean, fast reactive programming +- [hyperhype/hyperscript](https://github.com/hyperhype/hyperscript) — Create HyperText with JavaScript +- [potch/signals](https://github.com/potch/signals) — A small reactive signals library +- [AseasRoa/paintor](https://github.com/AseasRoa/paintor) - JavaScript library for building reactive client-side user + interfaces or HTML code. +- [pota](https://pota.quack.uy/) — small and pluggable Reactive Web Renderer. It's compiler-less, includes an html + function, and a optimized babel preset in case you fancy JSX. +- [jaandrle/dollar_dom_component](https://github.com/jaandrle/dollar_dom_component) — Functional DOM components without JSX/virtual DOM -- [mxjp/rvx: A signal based frontend framework](https://github.com/mxjp/rvx) +- [TarekRaafat/eleva](https://github.com/TarekRaafat/eleva) — A minimalist, lightweight, pure vanilla JavaScript + frontend runtime framework. +- [didi/mpx](https://github.com/didi/mpx) — Mpx,一款具有优秀开发体验和深度性能优化的增强型跨端小程序框架 +- [mxjp/rvx](https://github.com/mxjp/rvx) — A signal based frontend framework diff --git a/bs/build.js b/bs/build.js index 477a301..f45cdc8 100755 --- a/bs/build.js +++ b/bs/build.js @@ -5,18 +5,18 @@ const files= [ "index", "index-with-signals" ]; $.api("") .command("main", "Build main files", { default: true }) .option("--no-types", "Also generate d.ts files", false) -.action(async function main({ types }){ - const regular = await build({ +.action(function main({ types }){ + const regular = build({ files, filesOut, minify: "no", types, }); - const min = await build({ + const min = build({ files, filesOut(file, mark= "esm"){ const out= filesOut(file, mark); - const idx= out.lastIndexOf("."); + const idx= out.indexOf("."); return out.slice(0, idx)+".min"+out.slice(idx); }, minify: "full", @@ -25,8 +25,8 @@ $.api("") return $.exit(regular + min); }) .command("signals", "Build only signals (for example for analysis)") -.action(async function signals(){ - const regular = await build({ +.action(function signals(){ + const regular = build({ files: [ "signals" ], filesOut(file){ return "dist/."+file; }, minify: "no", diff --git a/bs/dev/.build.js b/bs/dev/.build.js index ac2f13d..8e7a251 100644 --- a/bs/dev/.build.js +++ b/bs/dev/.build.js @@ -1,4 +1,5 @@ #!/usr/bin/env -S npx nodejsscript +import { buildSync as esbuildSync } from "esbuild"; const css= echo.css` .info{ color: gray; } `; @@ -8,8 +9,7 @@ export function build({ files, filesOut, minify= "partial", iife= true, types= t const file= file_root+".js"; echo(`Processing ${file} (minified: ${minify})`); const out= filesOut(file); - const esbuild_output= buildEsbuild({ file, out, minify }); - echoVariant(esbuild_output.stderr.split("\n")[1].trim()); + esbuild({ file, out, minify }); if(types){ const file_dts= file_root+".d.ts"; @@ -31,14 +31,13 @@ export function build({ files, filesOut, minify= "partial", iife= true, types= t const name= "DDE"; const out= filesOut(file_root+".js", fileMark); - const params= [ - "--format=iife", - "--global-name="+name, - ]; - const dde_output= buildEsbuild({ file, out, minify, params }); - echoVariant(`${out} (${name})`) + const params= { + format: "iife", + globalName: name + }; + esbuild({ file, out, minify, params }); - if(!types) return dde_output; + if(!types) return; const file_dts= file_root+".d.ts"; const file_dts_out= filesOut(file_dts, fileMark); echoVariant(file_dts_out, true); @@ -48,8 +47,6 @@ export function build({ files, filesOut, minify= "partial", iife= true, types= t entry: file_dts, }) echoVariant(file_dts_out); - - return dde_output; } } export function buildDts({ bundle, entry, name }){ @@ -64,46 +61,39 @@ export function buildDts({ bundle, entry, name }){ ].filter(Boolean).join(" "), { out, entry }); return dts_b_g_output; } -class ErrorEsbuild extends Error{ - constructor({ code, stderr }){ - super(stderr); - this.code= code; - this.stderr= stderr; - } -} -function buildEsbuild({ file, out, minify= "partial", params= [] }){ - try { - return esbuild({ file, out, minify, params }); - } catch(e){ - if(e instanceof ErrorEsbuild) - return $.exit(e.code, echo(e.stderr)); - throw e; - } -} -export function esbuild({ file, out, minify= "partial", params= [] }){ - const esbuild_output= s.$().run([ - "npx esbuild '::file::'", - "--platform=neutral", - "--bundle", - minifyOption(minify), - "--legal-comments=inline", - "--packages=external", - ...params, - "--outfile='::out::'" - ].filter(Boolean).join(" "), { file, out }); - if(esbuild_output.code) - throw new ErrorEsbuild(esbuild_output); +export function esbuild({ file, out, minify= "partial", params= {} }){ + const esbuild_output= esbuildSync({ + entryPoints: [file], + outfile: out, + platform: "neutral", + bundle: true, + legalComments: "inline", + packages: "external", + metafile: true, + ...minifyOption(minify), + ...params + }); pipe( f=> f.replace(/^ +/gm, m=> "\t".repeat(m.length/2)), f=> s.echo(f).to(out) )(s.cat(out)); + + echoVariant(metaToLineStatus(esbuild_output.metafile, out)); return esbuild_output; } /** @param {"no"|"full"|"partial"} level */ function minifyOption(level= "partial"){ - if("no"===level) return undefined; - if("full"===level) return "--minify"; - return "--minify-syntax --minify-identifiers"; + if("no"===level) return { minify: false }; + if("full"===level) return { minify: true }; + return { minifySyntax: true, minifyIdentifiers: true }; +} +function metaToLineStatus(meta, file){ + const status= meta.outputs[file]; + if(!status) return `? ${file}: unknown`; + const { bytes }= status; + const kbytes= bytes/1024; + const kbytesR= kbytes.toFixed(2); + return `${file}: ${kbytesR} kB`; } function echoVariant(name, todo= false){ if(todo) return echo.use("-R", "~ "+name); diff --git a/dist/esm-with-signals.d.min.ts b/dist/esm-with-signals.d.min.ts deleted file mode 100644 index 49490b4..0000000 --- a/dist/esm-with-signals.d.min.ts +++ /dev/null @@ -1,641 +0,0 @@ -declare global{ /* ddeSignal */ } -type CustomElementTagNameMap= { '#text': Text, '#comment': Comment } -type SupportedElement= - HTMLElementTagNameMap[keyof HTMLElementTagNameMap] - | SVGElementTagNameMap[keyof SVGElementTagNameMap] - | MathMLElementTagNameMap[keyof MathMLElementTagNameMap] - | CustomElementTagNameMap[keyof CustomElementTagNameMap] -declare global { - type ddeComponentAttributes= Record | undefined; - type ddeElementAddon= (element: El)=> any; - type ddeString= string | ddeSignal - type ddeStringable= ddeString | number | ddeSignal -} -type PascalCase= -`${Capitalize}${string}`; -type AttrsModified= { - /** - * Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API). - */ - style: Partial | ddeString - | Partial<{ [K in keyof CSSStyleDeclaration]: ddeSignal }> - /** - * Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1. - * In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))` - * for others. - */ - classList: Record>, - /** - * Used by the dataset HTML attribute to represent data for custom attributes added to elements. - * Values are converted to string (see {@link DOMStringMap}). - * - * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMStringMap) - * */ - dataset: Record, - /** - * Sets `aria-*` simiraly to `dataset` - * */ - ariaset: Record, -} & Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, ddeString> - & Record<`.${string}`, any> -type _fromElsInterfaces= Omit; -type IsReadonly = - T extends { readonly [P in K]: T[K] } ? true : false; -/** - * Just element attributtes - * - * In most cases, you can use native propertie such as - * [MDN WEB/API/Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) and so on - * (e.g. [`Text`](https://developer.mozilla.org/en-US/docs/Web/API/Text)). - * - * There is added support for `data[A-Z].*`/`aria[A-Z].*` to be converted to the kebab-case alternatives. - * @private - */ -type ElementAttributes= Partial<{ - [K in keyof _fromElsInterfaces]: - _fromElsInterfaces[K] extends ((...p: any[])=> any) - ? _fromElsInterfaces[K] | ((...p: Parameters<_fromElsInterfaces[K]>)=> - ddeSignal[K]>>) - : (IsReadonly<_fromElsInterfaces, K> extends false - ? _fromElsInterfaces[K] | ddeSignal<_fromElsInterfaces[K]> - : ddeStringable) -} & AttrsModified> & Record; -export function classListDeclarative( - element: El, - classList: AttrsModified["classList"] -): El -export function assign(element: El, ...attrs_array: ElementAttributes[]): El -export function assignAttribute>( - element: El, - attr: ATT, - value: ElementAttributes[ATT] -): ElementAttributes[ATT] - -type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagNameMap; -export namespace el { - /** - * Creates a marker comment for elements - * - * @param attrs - Marker attributes - * @param [is_open=false] - Whether the marker is open-ended - * @returns Comment node marker - */ - export function mark( - attrs: { type: "component"|"reactive"|"later", name?: string, host?: "this"|"parentElement" }, - is_open?: boolean - ): Comment; -} - -export function el< - A extends ddeComponentAttributes, - EL extends SupportedElement | ddeDocumentFragment ->( - component: (attr: A, ...rest: any[])=> EL, - attrs?: NoInfer, - ...addons: ddeElementAddon[] -): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] - ? EL - : ( EL extends ddeDocumentFragment ? EL : ddeHTMLElement ) -export function el< - A extends { textContent: ddeStringable }, - EL extends SupportedElement | ddeDocumentFragment ->( - component: (attr: A, ...rest: any[])=> EL, - attrs?: NoInfer["textContent"], - ...addons: ddeElementAddon[] -): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] - ? EL - : ( EL extends ddeDocumentFragment ? EL : ddeHTMLElement ) -export function el< - TAG extends keyof ExtendedHTMLElementTagNameMap, ->( - tag_name: TAG, - attrs?: ElementAttributes]> | ddeStringable, - ...addons: ddeElementAddon< - ExtendedHTMLElementTagNameMap[NoInfer] - >[], // TODO: for now addons must have the same element -): TAG extends keyof ddeHTMLElementTagNameMap ? ddeHTMLElementTagNameMap[TAG] : ddeHTMLElement -export function el( - tag_name?: "<>", -): ddeDocumentFragment -export function el( - tag_name: string, - attrs?: ElementAttributes | ddeStringable, - ...addons: ddeElementAddon[] -): ddeHTMLElement -export { el as createElement } - -export function elNS( - namespace: "http://www.w3.org/2000/svg" -): < - TAG extends keyof SVGElementTagNameMap & string, - EL extends ( TAG extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[TAG] : SVGElement ), ->( - tag_name: TAG, - attrs?: ElementAttributes> | ddeStringable, - ...addons: ddeElementAddon>[] -)=> TAG extends keyof ddeSVGElementTagNameMap ? ddeSVGElementTagNameMap[TAG] : ddeSVGElement -export function elNS( - namespace: "http://www.w3.org/1998/Math/MathML" -): < - TAG extends keyof MathMLElementTagNameMap & string, - EL extends ( TAG extends keyof MathMLElementTagNameMap ? MathMLElementTagNameMap[TAG] : MathMLElement ), ->( - tag_name: TAG, - attrs?: ddeStringable | Partial<{ - [key in keyof EL]: EL[key] | ddeSignal | string | number | boolean - }>, - ...addons: ddeElementAddon>[] -)=> ddeMathMLElement -export function elNS( - namespace: string -): ( - tag_name: string, - attrs?: string | ddeStringable | Record, - ...addons: ddeElementAddon[] -)=> SupportedElement -export { elNS as createElementNS } - -export function chainableAppend(el: EL): EL; -/** Simulate slots for ddeComponents */ -export function simulateSlots( - root: EL, -): EL -/** - * Simulate slots in Custom Elements without using `shadowRoot`. - * @param el Custom Element root element - * @param body Body of the custom element - * */ -export function simulateSlots( - el: HTMLElement, - body: EL, -): EL - -export function dispatchEvent(name: keyof DocumentEventMap | string, element: SupportedElement): - (data?: any)=> void; -export function dispatchEvent(name: keyof DocumentEventMap | string, options?: EventInit): - (element: SupportedElement, data?: any)=> void; -export function dispatchEvent( - name: keyof DocumentEventMap | string, - options: EventInit | null, - element: SupportedElement | (()=> SupportedElement) -): (data?: any)=> void; -interface On{ - /** Listens to the DOM event. See {@link Document.addEventListener} */ - < - Event extends keyof DocumentEventMap, - EE extends ddeElementAddon= ddeElementAddon, - >( - type: Event, - listener: (this: EE extends ddeElementAddon ? El : never, ev: DocumentEventMap[Event]) => any, - options?: AddEventListenerOptions - ) : EE; - < - EE extends ddeElementAddon= ddeElementAddon, - >( - type: string, - listener: (this: EE extends ddeElementAddon ? El : never, ev: Event | CustomEvent ) => any, - options?: AddEventListenerOptions - ) : EE; - /** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line - connected< - EE extends ddeElementAddon, - El extends ( EE extends ddeElementAddon ? El : never ) - >( - listener: (this: El, event: CustomEvent) => any, - options?: AddEventListenerOptions - ) : EE; - /** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line - disconnected< - EE extends ddeElementAddon, - El extends ( EE extends ddeElementAddon ? El : never ) - >( - listener: (this: El, event: CustomEvent) => any, - options?: AddEventListenerOptions - ) : EE; - /** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line - attributeChanged< - EE extends ddeElementAddon, - El extends ( EE extends ddeElementAddon ? El : never ) - >( - listener: (this: El, event: CustomEvent<[ string, string ]>) => any, - options?: AddEventListenerOptions - ) : EE; -} -export const on: On; - -type Scope= { - scope: Node | Function | Object, - host: ddeElementAddon, - custom_element: false | HTMLElement, - prevent: boolean -}; -/** Current scope created last time the `el(Function)` was invoke. (Or {@link scope.push}) */ -export const scope: { - current: Scope, - /** Stops all automatizations. E. g. signals used as attributes in current scope - * registers removing these listeners (and clean signal if no other listeners are detected) - * on `disconnected` event. */ - preventDefault(prevent: T): T, - /** - * This represents reference to the current host element — `scope.host()`. - * It can be also used to register Addon(s) (functions to be called when component is initized) - * — `scope.host(on.connected(console.log))`. - * */ - host: (...addons: ddeElementAddon[])=> HTMLElement, - - state: Scope[], - /** Adds new child scope. All attributes are inherited by default. */ - push(scope?: Partial): ReturnType["push"]>, - /** Adds root scope as a child of the current scope. */ - pushRoot(): ReturnType["push"]>, - /** Removes last/current child scope. */ - pop(): ReturnType["pop"]>, -}; - -export function customElementRender< - EL extends HTMLElement, - P extends any = Record> ->( - target: ShadowRoot | EL, - render: (props: P)=> SupportedElement | DocumentFragment, - props?: P | ((el: EL)=> P) -): EL -export function customElementWithDDE HTMLElement)>(custom_element: EL): EL -export function lifecyclesToEvents HTMLElement)>(custom_element: EL): EL -export function observedAttributes(custom_element: HTMLElement): Record - -/** - * This is used primarly for server side rendering. To be sure that all async operations - * are finished before the page is sent to the client. - * ``` - * // on component - * function component(){ - * … - * queue(fetch(...).then(...)); - * } - * - * // building the page - * async function build(){ - * const { component }= await import("./component.js"); - * document.body.append(el(component)); - * await queue(); - * retutn document.body.innerHTML; - * } - * ``` - * */ -export function queue(promise?: Promise): Promise; - -/* TypeScript MEH */ -declare global{ - type ddeAppend= (...nodes: (Node | string)[])=> el; - - interface ddeDocumentFragment extends DocumentFragment{ append: ddeAppend; } - interface ddeHTMLElement extends HTMLElement{ append: ddeAppend; } - interface ddeSVGElement extends SVGElement{ append: ddeAppend; } - interface ddeMathMLElement extends MathMLElement{ append: ddeAppend; } - - interface ddeHTMLElementTagNameMap { - "a": ddeHTMLAnchorElement; - "area": ddeHTMLAreaElement; - "audio": ddeHTMLAudioElement; - "base": ddeHTMLBaseElement; - "blockquote": ddeHTMLQuoteElement; - "body": ddeHTMLBodyElement; - "br": ddeHTMLBRElement; - "button": ddeHTMLButtonElement; - "canvas": ddeHTMLCanvasElement; - "caption": ddeHTMLTableCaptionElement; - "col": ddeHTMLTableColElement; - "colgroup": ddeHTMLTableColElement; - "data": ddeHTMLDataElement; - "datalist": ddeHTMLDataListElement; - "del": ddeHTMLModElement; - "details": ddeHTMLDetailsElement; - "dialog": ddeHTMLDialogElement; - "div": ddeHTMLDivElement; - "dl": ddeHTMLDListElement; - "embed": ddeHTMLEmbedElement; - "fieldset": ddeHTMLFieldSetElement; - "form": ddeHTMLFormElement; - "h1": ddeHTMLHeadingElement; - "h2": ddeHTMLHeadingElement; - "h3": ddeHTMLHeadingElement; - "h4": ddeHTMLHeadingElement; - "h5": ddeHTMLHeadingElement; - "h6": ddeHTMLHeadingElement; - "head": ddeHTMLHeadElement; - "hr": ddeHTMLHRElement; - "html": ddeHTMLHtmlElement; - "iframe": ddeHTMLIFrameElement; - "img": ddeHTMLImageElement; - "input": ddeHTMLInputElement; - "ins": ddeHTMLModElement; - "label": ddeHTMLLabelElement; - "legend": ddeHTMLLegendElement; - "li": ddeHTMLLIElement; - "link": ddeHTMLLinkElement; - "map": ddeHTMLMapElement; - "menu": ddeHTMLMenuElement; - "meta": ddeHTMLMetaElement; - "meter": ddeHTMLMeterElement; - "object": ddeHTMLObjectElement; - "ol": ddeHTMLOListElement; - "optgroup": ddeHTMLOptGroupElement; - "option": ddeHTMLOptionElement; - "output": ddeHTMLOutputElement; - "p": ddeHTMLParagraphElement; - "picture": ddeHTMLPictureElement; - "pre": ddeHTMLPreElement; - "progress": ddeHTMLProgressElement; - "q": ddeHTMLQuoteElement; - "script": ddeHTMLScriptElement; - "select": ddeHTMLSelectElement; - "slot": ddeHTMLSlotElement; - "source": ddeHTMLSourceElement; - "span": ddeHTMLSpanElement; - "style": ddeHTMLStyleElement; - "table": ddeHTMLTableElement; - "tbody": ddeHTMLTableSectionElement; - "td": ddeHTMLTableCellElement; - "template": ddeHTMLTemplateElement; - "textarea": ddeHTMLTextAreaElement; - "tfoot": ddeHTMLTableSectionElement; - "th": ddeHTMLTableCellElement; - "thead": ddeHTMLTableSectionElement; - "time": ddeHTMLTimeElement; - "title": ddeHTMLTitleElement; - "tr": ddeHTMLTableRowElement; - "track": ddeHTMLTrackElement; - "ul": ddeHTMLUListElement; - "video": ddeHTMLVideoElement; - } - interface ddeSVGElementTagNameMap { - "a": ddeSVGAElement; - "animate": ddeSVGAnimateElement; - "animateMotion": ddeSVGAnimateMotionElement; - "animateTransform": ddeSVGAnimateTransformElement; - "circle": ddeSVGCircleElement; - "clipPath": ddeSVGClipPathElement; - "defs": ddeSVGDefsElement; - "desc": ddeSVGDescElement; - "ellipse": ddeSVGEllipseElement; - "feBlend": ddeSVGFEBlendElement; - "feColorMatrix": ddeSVGFEColorMatrixElement; - "feComponentTransfer": ddeSVGFEComponentTransferElement; - "feComposite": ddeSVGFECompositeElement; - "feConvolveMatrix": ddeSVGFEConvolveMatrixElement; - "feDiffuseLighting": ddeSVGFEDiffuseLightingElement; - "feDisplacementMap": ddeSVGFEDisplacementMapElement; - "feDistantLight": ddeSVGFEDistantLightElement; - "feDropShadow": ddeSVGFEDropShadowElement; - "feFlood": ddeSVGFEFloodElement; - "feFuncA": ddeSVGFEFuncAElement; - "feFuncB": ddeSVGFEFuncBElement; - "feFuncG": ddeSVGFEFuncGElement; - "feFuncR": ddeSVGFEFuncRElement; - "feGaussianBlur": ddeSVGFEGaussianBlurElement; - "feImage": ddeSVGFEImageElement; - "feMerge": ddeSVGFEMergeElement; - "feMergeNode": ddeSVGFEMergeNodeElement; - "feMorphology": ddeSVGFEMorphologyElement; - "feOffset": ddeSVGFEOffsetElement; - "fePointLight": ddeSVGFEPointLightElement; - "feSpecularLighting": ddeSVGFESpecularLightingElement; - "feSpotLight": ddeSVGFESpotLightElement; - "feTile": ddeSVGFETileElement; - "feTurbulence": ddeSVGFETurbulenceElement; - "filter": ddeSVGFilterElement; - "foreignObject": ddeSVGForeignObjectElement; - "g": ddeSVGGElement; - "image": ddeSVGImageElement; - "line": ddeSVGLineElement; - "linearGradient": ddeSVGLinearGradientElement; - "marker": ddeSVGMarkerElement; - "mask": ddeSVGMaskElement; - "metadata": ddeSVGMetadataElement; - "mpath": ddeSVGMPathElement; - "path": ddeSVGPathElement; - "pattern": ddeSVGPatternElement; - "polygon": ddeSVGPolygonElement; - "polyline": ddeSVGPolylineElement; - "radialGradient": ddeSVGRadialGradientElement; - "rect": ddeSVGRectElement; - "script": ddeSVGScriptElement; - "set": ddeSVGSetElement; - "stop": ddeSVGStopElement; - "style": ddeSVGStyleElement; - "svg": ddeSVGSVGElement; - "switch": ddeSVGSwitchElement; - "symbol": ddeSVGSymbolElement; - "text": ddeSVGTextElement; - "textPath": ddeSVGTextPathElement; - "title": ddeSVGTitleElement; - "tspan": ddeSVGTSpanElement; - "use": ddeSVGUseElement; - "view": ddeSVGViewElement; - } -} - -// editorconfig-checker-disable -interface ddeHTMLAnchorElement extends HTMLAnchorElement{ append: ddeAppend; } -interface ddeHTMLAreaElement extends HTMLAreaElement{ append: ddeAppend; } -interface ddeHTMLAudioElement extends HTMLAudioElement{ append: ddeAppend; } -interface ddeHTMLBaseElement extends HTMLBaseElement{ append: ddeAppend; } -interface ddeHTMLQuoteElement extends HTMLQuoteElement{ append: ddeAppend; } -interface ddeHTMLBodyElement extends HTMLBodyElement{ append: ddeAppend; } -interface ddeHTMLBRElement extends HTMLBRElement{ append: ddeAppend; } -interface ddeHTMLButtonElement extends HTMLButtonElement{ append: ddeAppend; } -interface ddeHTMLCanvasElement extends HTMLCanvasElement{ append: ddeAppend; } -interface ddeHTMLTableCaptionElement extends HTMLTableCaptionElement{ append: ddeAppend; } -interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend; } -interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend; } -interface ddeHTMLDataElement extends HTMLDataElement{ append: ddeAppend; } -interface ddeHTMLDataListElement extends HTMLDataListElement{ append: ddeAppend; } -interface ddeHTMLModElement extends HTMLModElement{ append: ddeAppend; } -interface ddeHTMLDetailsElement extends HTMLDetailsElement{ append: ddeAppend; } -interface ddeHTMLDialogElement extends HTMLDialogElement{ append: ddeAppend; } -interface ddeHTMLDivElement extends HTMLDivElement{ append: ddeAppend; } -interface ddeHTMLDListElement extends HTMLDListElement{ append: ddeAppend; } -interface ddeHTMLEmbedElement extends HTMLEmbedElement{ append: ddeAppend; } -interface ddeHTMLFieldSetElement extends HTMLFieldSetElement{ append: ddeAppend; } -interface ddeHTMLFormElement extends HTMLFormElement{ append: ddeAppend; } -interface ddeHTMLHeadingElement extends HTMLHeadingElement{ append: ddeAppend; } -interface ddeHTMLHeadElement extends HTMLHeadElement{ append: ddeAppend; } -interface ddeHTMLHRElement extends HTMLHRElement{ append: ddeAppend; } -interface ddeHTMLHtmlElement extends HTMLHtmlElement{ append: ddeAppend; } -interface ddeHTMLIFrameElement extends HTMLIFrameElement{ append: ddeAppend; } -interface ddeHTMLImageElement extends HTMLImageElement{ append: ddeAppend; } -interface ddeHTMLInputElement extends HTMLInputElement{ append: ddeAppend; } -interface ddeHTMLLabelElement extends HTMLLabelElement{ append: ddeAppend; } -interface ddeHTMLLegendElement extends HTMLLegendElement{ append: ddeAppend; } -interface ddeHTMLLIElement extends HTMLLIElement{ append: ddeAppend; } -interface ddeHTMLLinkElement extends HTMLLinkElement{ append: ddeAppend; } -interface ddeHTMLMapElement extends HTMLMapElement{ append: ddeAppend; } -interface ddeHTMLMenuElement extends HTMLMenuElement{ append: ddeAppend; } -interface ddeHTMLMetaElement extends HTMLMetaElement{ append: ddeAppend; } -interface ddeHTMLMeterElement extends HTMLMeterElement{ append: ddeAppend; } -interface ddeHTMLObjectElement extends HTMLObjectElement{ append: ddeAppend; } -interface ddeHTMLOListElement extends HTMLOListElement{ append: ddeAppend; } -interface ddeHTMLOptGroupElement extends HTMLOptGroupElement{ append: ddeAppend; } -interface ddeHTMLOptionElement extends HTMLOptionElement{ append: ddeAppend; } -interface ddeHTMLOutputElement extends HTMLOutputElement{ append: ddeAppend; } -interface ddeHTMLParagraphElement extends HTMLParagraphElement{ append: ddeAppend; } -interface ddeHTMLPictureElement extends HTMLPictureElement{ append: ddeAppend; } -interface ddeHTMLPreElement extends HTMLPreElement{ append: ddeAppend; } -interface ddeHTMLProgressElement extends HTMLProgressElement{ append: ddeAppend; } -interface ddeHTMLScriptElement extends HTMLScriptElement{ append: ddeAppend; } -interface ddeHTMLSelectElement extends HTMLSelectElement{ append: ddeAppend; } -interface ddeHTMLSlotElement extends HTMLSlotElement{ append: ddeAppend; } -interface ddeHTMLSourceElement extends HTMLSourceElement{ append: ddeAppend; } -interface ddeHTMLSpanElement extends HTMLSpanElement{ append: ddeAppend; } -interface ddeHTMLStyleElement extends HTMLStyleElement{ append: ddeAppend; } -interface ddeHTMLTableElement extends HTMLTableElement{ append: ddeAppend; } -interface ddeHTMLTableSectionElement extends HTMLTableSectionElement{ append: ddeAppend; } -interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend; } -interface ddeHTMLTemplateElement extends HTMLTemplateElement{ append: ddeAppend; } -interface ddeHTMLTextAreaElement extends HTMLTextAreaElement{ append: ddeAppend; } -interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend; } -interface ddeHTMLTimeElement extends HTMLTimeElement{ append: ddeAppend; } -interface ddeHTMLTitleElement extends HTMLTitleElement{ append: ddeAppend; } -interface ddeHTMLTableRowElement extends HTMLTableRowElement{ append: ddeAppend; } -interface ddeHTMLTrackElement extends HTMLTrackElement{ append: ddeAppend; } -interface ddeHTMLUListElement extends HTMLUListElement{ append: ddeAppend; } -interface ddeHTMLVideoElement extends HTMLVideoElement{ append: ddeAppend; } -interface ddeSVGAElement extends SVGAElement{ append: ddeAppend; } -interface ddeSVGAnimateElement extends SVGAnimateElement{ append: ddeAppend; } -interface ddeSVGAnimateMotionElement extends SVGAnimateMotionElement{ append: ddeAppend; } -interface ddeSVGAnimateTransformElement extends SVGAnimateTransformElement{ append: ddeAppend; } -interface ddeSVGCircleElement extends SVGCircleElement{ append: ddeAppend; } -interface ddeSVGClipPathElement extends SVGClipPathElement{ append: ddeAppend; } -interface ddeSVGDefsElement extends SVGDefsElement{ append: ddeAppend; } -interface ddeSVGDescElement extends SVGDescElement{ append: ddeAppend; } -interface ddeSVGEllipseElement extends SVGEllipseElement{ append: ddeAppend; } -interface ddeSVGFEBlendElement extends SVGFEBlendElement{ append: ddeAppend; } -interface ddeSVGFEColorMatrixElement extends SVGFEColorMatrixElement{ append: ddeAppend; } -interface ddeSVGFEComponentTransferElement extends SVGFEComponentTransferElement{ append: ddeAppend; } -interface ddeSVGFECompositeElement extends SVGFECompositeElement{ append: ddeAppend; } -interface ddeSVGFEConvolveMatrixElement extends SVGFEConvolveMatrixElement{ append: ddeAppend; } -interface ddeSVGFEDiffuseLightingElement extends SVGFEDiffuseLightingElement{ append: ddeAppend; } -interface ddeSVGFEDisplacementMapElement extends SVGFEDisplacementMapElement{ append: ddeAppend; } -interface ddeSVGFEDistantLightElement extends SVGFEDistantLightElement{ append: ddeAppend; } -interface ddeSVGFEDropShadowElement extends SVGFEDropShadowElement{ append: ddeAppend; } -interface ddeSVGFEFloodElement extends SVGFEFloodElement{ append: ddeAppend; } -interface ddeSVGFEFuncAElement extends SVGFEFuncAElement{ append: ddeAppend; } -interface ddeSVGFEFuncBElement extends SVGFEFuncBElement{ append: ddeAppend; } -interface ddeSVGFEFuncGElement extends SVGFEFuncGElement{ append: ddeAppend; } -interface ddeSVGFEFuncRElement extends SVGFEFuncRElement{ append: ddeAppend; } -interface ddeSVGFEGaussianBlurElement extends SVGFEGaussianBlurElement{ append: ddeAppend; } -interface ddeSVGFEImageElement extends SVGFEImageElement{ append: ddeAppend; } -interface ddeSVGFEMergeElement extends SVGFEMergeElement{ append: ddeAppend; } -interface ddeSVGFEMergeNodeElement extends SVGFEMergeNodeElement{ append: ddeAppend; } -interface ddeSVGFEMorphologyElement extends SVGFEMorphologyElement{ append: ddeAppend; } -interface ddeSVGFEOffsetElement extends SVGFEOffsetElement{ append: ddeAppend; } -interface ddeSVGFEPointLightElement extends SVGFEPointLightElement{ append: ddeAppend; } -interface ddeSVGFESpecularLightingElement extends SVGFESpecularLightingElement{ append: ddeAppend; } -interface ddeSVGFESpotLightElement extends SVGFESpotLightElement{ append: ddeAppend; } -interface ddeSVGFETileElement extends SVGFETileElement{ append: ddeAppend; } -interface ddeSVGFETurbulenceElement extends SVGFETurbulenceElement{ append: ddeAppend; } -interface ddeSVGFilterElement extends SVGFilterElement{ append: ddeAppend; } -interface ddeSVGForeignObjectElement extends SVGForeignObjectElement{ append: ddeAppend; } -interface ddeSVGGElement extends SVGGElement{ append: ddeAppend; } -interface ddeSVGImageElement extends SVGImageElement{ append: ddeAppend; } -interface ddeSVGLineElement extends SVGLineElement{ append: ddeAppend; } -interface ddeSVGLinearGradientElement extends SVGLinearGradientElement{ append: ddeAppend; } -interface ddeSVGMarkerElement extends SVGMarkerElement{ append: ddeAppend; } -interface ddeSVGMaskElement extends SVGMaskElement{ append: ddeAppend; } -interface ddeSVGMetadataElement extends SVGMetadataElement{ append: ddeAppend; } -interface ddeSVGMPathElement extends SVGMPathElement{ append: ddeAppend; } -interface ddeSVGPathElement extends SVGPathElement{ append: ddeAppend; } -interface ddeSVGPatternElement extends SVGPatternElement{ append: ddeAppend; } -interface ddeSVGPolygonElement extends SVGPolygonElement{ append: ddeAppend; } -interface ddeSVGPolylineElement extends SVGPolylineElement{ append: ddeAppend; } -interface ddeSVGRadialGradientElement extends SVGRadialGradientElement{ append: ddeAppend; } -interface ddeSVGRectElement extends SVGRectElement{ append: ddeAppend; } -interface ddeSVGScriptElement extends SVGScriptElement{ append: ddeAppend; } -interface ddeSVGSetElement extends SVGSetElement{ append: ddeAppend; } -interface ddeSVGStopElement extends SVGStopElement{ append: ddeAppend; } -interface ddeSVGStyleElement extends SVGStyleElement{ append: ddeAppend; } -interface ddeSVGSVGElement extends SVGSVGElement{ append: ddeAppend; } -interface ddeSVGSwitchElement extends SVGSwitchElement{ append: ddeAppend; } -interface ddeSVGSymbolElement extends SVGSymbolElement{ append: ddeAppend; } -interface ddeSVGTextElement extends SVGTextElement{ append: ddeAppend; } -interface ddeSVGTextPathElement extends SVGTextPathElement{ append: ddeAppend; } -interface ddeSVGTitleElement extends SVGTitleElement{ append: ddeAppend; } -interface ddeSVGTSpanElement extends SVGTSpanElement{ append: ddeAppend; } -interface ddeSVGUseElement extends SVGUseElement{ append: ddeAppend; } -interface ddeSVGViewElement extends SVGViewElement{ append: ddeAppend; } -// editorconfig-checker-enable -export interface Signal { - /** The current value of the signal */ - get(): V; - /** Set new value of the signal */ - set(value: V): V; - toJSON(): V; - valueOf(): V; -} -type Action= (this: { value: V, stopPropagation(): void }, ...a: any[])=> typeof signal._ | void; -//type SymbolSignal= Symbol; -type SymbolOnclear= symbol; -type Actions= Record>; -type OnListenerOptions= Pick & { first_time?: boolean }; -interface signal{ - _: Symbol - /** - * Computations signal. This creates a signal which is computed from other signals. - * */ - any>(computation: V): Signal, {}> - /** - * Simple example: - * ```js - * const hello= S("Hello Signal"); - * ``` - * …simple todo signal: - * ```js - * const todos= S([], { - * add(v){ this.value.push(S(v)); }, - * remove(i){ this.value.splice(i, 1); }, - * [S.symbols.onclear](){ S.clear(...this.value); }, - * }); - * ``` - * …computed signal: - * ```js - * const name= S("Jan"); - * const surname= S("Andrle"); - * const fullname= S(()=> name.get()+" "+surname.get()); - * ``` - * @param value Initial signal value. Or function computing value from other signals. - * @param actions Use to define actions on the signal. Such as add item to the array. - * There is also a reserved function `S.symbol.onclear` which is called when the signal is cleared - * by `S.clear`. - * */ - >(value: V, actions?: A): Signal; - action>, A extends (S extends Signal ? A : never), N extends keyof A>( - signal: S, - name: N, - ...params: A[N] extends (...args: infer P)=> any ? P : never - ): void; - clear(...signals: Signal[]): void; - on(signal: Signal, onchange: (a: T)=> void, options?: OnListenerOptions): void; - symbols: { - //signal: SymbolSignal; - onclear: SymbolOnclear; - } - /** - * Reactive element, which is rendered based on the given signal. - * ```js - * S.el(signal, value=> value ? el("b", "True") : el("i", "False")); - * S.el(listS, list=> list.map(li=> el("li", li))); - * ``` - * */ - el(signal: Signal, el: (v: S)=> Element | Element[] | DocumentFragment): DocumentFragment; - - observedAttributes(custom_element: HTMLElement): Record>; -} -export const signal: signal; -export const S: signal; -declare global { - type ddeSignal= Signal; - type ddeAction= Action - type ddeActions= Actions -} \ No newline at end of file diff --git a/dist/esm-with-signals.d.ts b/dist/esm-with-signals.d.ts index c22a98a..1cf65ca 100644 --- a/dist/esm-with-signals.d.ts +++ b/dist/esm-with-signals.d.ts @@ -4,7 +4,7 @@ export interface Signal { /** The current value of the signal */ get(): V; /** Set new value of the signal */ - set(value: V): V; + set(value: V, force?: boolean): V; toJSON(): V; valueOf(): V; } @@ -173,17 +173,30 @@ declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options? declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host): (data?: any) => void; export interface On { /** Listens to the DOM event. See {@link Document.addEventListener} */ - = ddeElementAddon>(type: Event, listener: (this: EE extends ddeElementAddon ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE; + (type: Event, listener: (this: EL, ev: DocumentEventMap[Event] & { + target: EL; + }) => any, options?: AddEventListenerOptions): ddeElementAddon; = ddeElementAddon>(type: string, listener: (this: EE extends ddeElementAddon ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; /** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - connected, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent) => any, options?: AddEventListenerOptions): EE; + connected(listener: (this: EL, event: CustomEvent>) => any, options?: AddEventListenerOptions): ddeElementAddon; /** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - disconnected, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent) => any, options?: AddEventListenerOptions): EE; - /** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - attributeChanged, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent<[ - string, - string - ]>) => any, options?: AddEventListenerOptions): EE; + disconnected(listener: (this: EL, event: CustomEvent) => any, options?: AddEventListenerOptions): ddeElementAddon; + /** + * Fires after the next tick of the Javascript event loop. + * This is handy for example to apply some property depending on the element content: + * ```js + * const selected= "Z"; + * //... + * return el("form").append( + * el("select", null, on.defer(e=> e.value=selected)).append( + * el("option", { value: "A", textContent: "A" }), + * //... + * el("option", { value: "Z", textContent: "Z" }), + * ), + * ); + * ``` + * */ + defer(listener: (element: EL) => any): ddeElementAddon; } export const on: On; export type Scope = { diff --git a/dist/esm-with-signals.js b/dist/esm-with-signals.js index d223107..06a87bb 100644 --- a/dist/esm-with-signals.js +++ b/dist/esm-with-signals.js @@ -55,38 +55,7 @@ var Defined = class extends Error { } }; -// src/signals-lib/common.js -var signals_global = { - /** - * Checks if a value is a signal - * @param {any} attributes - Value to check - * @returns {boolean} Whether the value is a signal - */ - isSignal(attributes) { - return false; - }, - /** - * Processes an attribute that might be reactive - * @param {Element} obj - Element that owns the attribute - * @param {string} key - Attribute name - * @param {any} attr - Attribute value - * @param {Function} set - Function to set the attribute - * @returns {any} Processed attribute value - */ - processReactiveAttribute(obj, key, attr, set) { - return attr; - } -}; -function registerReactivity(def, global = true) { - if (global) return oAssign(signals_global, def); - Object.setPrototypeOf(def, signals_global); - return def; -} -function signals(_this) { - return isProtoFrom(_this, signals_global) && _this !== signals_global ? _this : signals_global; -} - -// src/dom-common.js +// src/dom-lib/common.js var enviroment = { setDeleteAttr, ssr: "", @@ -112,7 +81,7 @@ var evc = "dde:connected"; var evd = "dde:disconnected"; var eva = "dde:attributeChanged"; -// src/events-observer.js +// src/dom-lib/events-observer.js var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { get() { return () => { @@ -276,7 +245,7 @@ function connectionsChangesObserverConstructor() { } } -// src/events.js +// src/dom-lib/events.js function dispatchEvent(name, options, host) { if (typeof options === "function") { host = options; @@ -298,6 +267,7 @@ function on(event, listener, options) { return element; }; } +on.defer = (fn) => setTimeout.bind(null, fn, 0); var lifeOptions = (obj) => oAssign({}, typeof obj === "object" ? obj : null, { once: true }); on.connected = function(listener, options) { options = lifeOptions(options); @@ -321,10 +291,7 @@ on.disconnected = function(listener, options) { }; }; -// src/dom.js -function queue(promise) { - return enviroment.q(promise); -} +// src/dom-lib/scopes.js var scopes = [{ get scope() { return enviroment.D.body; @@ -399,6 +366,60 @@ var scope = { return scopes.pop(); } }; + +// src/signals-lib/common.js +var signals_global = { + /** + * Checks if a value is a signal + * @param {any} attributes - Value to check + * @returns {boolean} Whether the value is a signal + */ + isSignal(attributes) { + return false; + }, + /** + * Processes an attribute that might be reactive + * @param {Element} obj - Element that owns the attribute + * @param {string} key - Attribute name + * @param {any} attr - Attribute value + * @param {Function} set - Function to set the attribute + * @returns {any} Processed attribute value + */ + processReactiveAttribute(obj, key, attr, set) { + return attr; + } +}; +function registerReactivity(def, global = true) { + if (global) return oAssign(signals_global, def); + Object.setPrototypeOf(def, signals_global); + return def; +} +function signals(_this) { + return isProtoFrom(_this, signals_global) && _this !== signals_global ? _this : signals_global; +} + +// src/dom-lib/helpers.js +function setRemove(obj, prop, key, val) { + return obj[(isUndef(val) ? "remove" : "set") + prop](key, val); +} +function setRemoveNS(obj, prop, key, val, ns = null) { + return obj[(isUndef(val) ? "remove" : "set") + prop + "NS"](ns, key, val); +} +function setDelete(obj, key, val) { + Reflect.set(obj, key, val); + if (!isUndef(val)) return; + return Reflect.deleteProperty(obj, key); +} +function elementAttribute(element, op, key, value) { + if (isInstance(element, enviroment.H)) + return element[op + "Attribute"](key, value); + return element[op + "AttributeNS"](null, key, value); +} + +// src/dom-lib/el.js +function queue(promise) { + return enviroment.q(promise); +} function append(...els) { this.appendOriginal(...els); return this; @@ -414,7 +435,8 @@ function createElement(tag, attributes, ...addons) { const s = signals(this); let scoped = 0; let el, el_host; - if (Object(attributes) !== attributes || s.isSignal(attributes)) + const att_type = typeof attributes; + if (att_type === "string" || att_type === "number" || s.isSignal(attributes)) attributes = { textContent: attributes }; switch (true) { case typeof tag === "function": { @@ -468,38 +490,6 @@ function createElementNS(ns) { return el; }; } -function simulateSlots(element, root = element) { - const mark_e = "\xB9\u2070", mark_s = "\u2713"; - const slots = Object.fromEntries( - Array.from(root.querySelectorAll("slot")).filter((s) => !s.name.endsWith(mark_e)).map((s) => [s.name += mark_e, s]) - ); - element.append = new Proxy(element.append, { - apply(orig, _, els) { - if (els[0] === root) return orig.apply(element, els); - for (const el of els) { - const name = (el.slot || "") + mark_e; - try { - elementAttribute(el, "remove", "slot"); - } catch (_error) { - } - const slot = slots[name]; - if (!slot) return; - if (!slot.name.startsWith(mark_s)) { - slot.childNodes.forEach((c) => c.remove()); - slot.name = mark_s + name; - } - slot.append(el); - } - element.append = orig; - return element; - } - }); - if (element !== root) { - const els = Array.from(element.childNodes); - element.append(...els); - } - return root; -} var assign_context = /* @__PURE__ */ new WeakMap(); var { setDeleteAttr: setDeleteAttr2 } = enviroment; function assign(element, ...attributes) { @@ -562,11 +552,6 @@ function classListDeclarative(element, toggle) { ); return element; } -function elementAttribute(element, op, key, value) { - if (isInstance(element, enviroment.H)) - return element[op + "Attribute"](key, value); - return element[op + "AttributeNS"](null, key, value); -} function isPropSetter(el, key) { if (!(key in el)) return false; const des = getPropDescriptor(el, key); @@ -590,19 +575,40 @@ function forEachEntries(s, target, element, obj, cb) { cb(key, val); }); } -function setRemove(obj, prop, key, val) { - return obj[(isUndef(val) ? "remove" : "set") + prop](key, val); -} -function setRemoveNS(obj, prop, key, val, ns = null) { - return obj[(isUndef(val) ? "remove" : "set") + prop + "NS"](ns, key, val); -} -function setDelete(obj, key, val) { - Reflect.set(obj, key, val); - if (!isUndef(val)) return; - return Reflect.deleteProperty(obj, key); -} -// src/customElement.js +// src/dom-lib/customElement.js +function simulateSlots(element, root = element) { + const mark_e = "\xB9\u2070", mark_s = "\u2713"; + const slots = Object.fromEntries( + Array.from(root.querySelectorAll("slot")).filter((s) => !s.name.endsWith(mark_e)).map((s) => [s.name += mark_e, s]) + ); + element.append = new Proxy(element.append, { + apply(orig, _, els) { + if (els[0] === root) return orig.apply(element, els); + for (const el of els) { + const name = (el.slot || "") + mark_e; + try { + elementAttribute(el, "remove", "slot"); + } catch (_error) { + } + const slot = slots[name]; + if (!slot) return; + if (!slot.name.startsWith(mark_s)) { + slot.childNodes.forEach((c) => c.remove()); + slot.name = mark_s + name; + } + slot.append(el); + } + element.append = orig; + return element; + } + }); + if (element !== root) { + const els = Array.from(element.childNodes); + element.append(...els); + } + return root; +} function customElementRender(target, render, props = {}) { const custom_element = target.host || target; scope.push({ @@ -683,19 +689,19 @@ memo.scope = function memoScope(fun, { signal: signal2, onlyLast } = {}) { // src/signals-lib/helpers.js var mark = "__dde_signal"; var queueSignalWrite = /* @__PURE__ */ (() => { - let pendingSignals = /* @__PURE__ */ new Set(); + let pendingSignals = /* @__PURE__ */ new Map(); let scheduled = false; function flushSignals() { scheduled = false; const todo = pendingSignals; - pendingSignals = /* @__PURE__ */ new Set(); - for (const signal2 of todo) { + pendingSignals = /* @__PURE__ */ new Map(); + for (const [signal2, force] of todo) { const M = signal2[mark]; - if (M) M.listeners.forEach((l) => l(M.value)); + if (M) M.listeners.forEach((l) => l(M.value, force)); } } - return function(s) { - pendingSignals.add(s); + return function(s, force = false) { + pendingSignals.set(s, pendingSignals.get(s) || force); if (scheduled) return; scheduled = true; queueMicrotask(flushSignals); @@ -732,11 +738,11 @@ function signal(value, actions) { return create(false, value, actions); if (isSignal(value)) return value; const out = create(true); - function contextReWatch() { + function contextReWatch(_, force) { const [origin, ...deps_old] = deps.get(contextReWatch); deps.set(contextReWatch, /* @__PURE__ */ new Set([origin])); stack_watch.push(contextReWatch); - write(out, value()); + write(out, value(), force); stack_watch.pop(); if (!deps_old.length) return; const deps_curr = deps.get(contextReWatch); @@ -758,7 +764,7 @@ signal.action = function(s, name, ...a) { throw new Error(`Action "${name}" not defined. See ${mark}.actions.`); actions[name].apply(M, a); if (M.skip) return delete M.skip; - queueSignalWrite(s); + queueSignalWrite(s, true); }; signal.on = function on2(s, listener, options = {}) { const { signal: as } = options; @@ -967,7 +973,7 @@ function write(s, value, force) { const M = s[mark]; if (!M || !force && M.value === value) return; M.value = value; - queueSignalWrite(s); + queueSignalWrite(s, force); return value; } function addSignalListener(s, listener) { @@ -1004,7 +1010,6 @@ export { dispatchEvent, createElement as el, createElementNS as elNS, - elementAttribute, isSignal, lifecyclesToEvents, memo, diff --git a/dist/esm-with-signals.min.d.ts b/dist/esm-with-signals.min.d.ts index c22a98a..1cf65ca 100644 --- a/dist/esm-with-signals.min.d.ts +++ b/dist/esm-with-signals.min.d.ts @@ -4,7 +4,7 @@ export interface Signal { /** The current value of the signal */ get(): V; /** Set new value of the signal */ - set(value: V): V; + set(value: V, force?: boolean): V; toJSON(): V; valueOf(): V; } @@ -173,17 +173,30 @@ declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options? declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host): (data?: any) => void; export interface On { /** Listens to the DOM event. See {@link Document.addEventListener} */ - = ddeElementAddon>(type: Event, listener: (this: EE extends ddeElementAddon ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE; + (type: Event, listener: (this: EL, ev: DocumentEventMap[Event] & { + target: EL; + }) => any, options?: AddEventListenerOptions): ddeElementAddon; = ddeElementAddon>(type: string, listener: (this: EE extends ddeElementAddon ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; /** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - connected, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent) => any, options?: AddEventListenerOptions): EE; + connected(listener: (this: EL, event: CustomEvent>) => any, options?: AddEventListenerOptions): ddeElementAddon; /** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - disconnected, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent) => any, options?: AddEventListenerOptions): EE; - /** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - attributeChanged, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent<[ - string, - string - ]>) => any, options?: AddEventListenerOptions): EE; + disconnected(listener: (this: EL, event: CustomEvent) => any, options?: AddEventListenerOptions): ddeElementAddon; + /** + * Fires after the next tick of the Javascript event loop. + * This is handy for example to apply some property depending on the element content: + * ```js + * const selected= "Z"; + * //... + * return el("form").append( + * el("select", null, on.defer(e=> e.value=selected)).append( + * el("option", { value: "A", textContent: "A" }), + * //... + * el("option", { value: "Z", textContent: "Z" }), + * ), + * ); + * ``` + * */ + defer(listener: (element: EL) => any): ddeElementAddon; } export const on: On; export type Scope = { diff --git a/dist/esm-with-signals.min.js b/dist/esm-with-signals.min.js index b44560e..e73ec54 100644 --- a/dist/esm-with-signals.min.js +++ b/dist/esm-with-signals.min.js @@ -1,4 +1,4 @@ -var W=(...t)=>Object.prototype.hasOwnProperty.call(...t);function C(t){return typeof t>"u"}function nt(t){let e=typeof t;return e!=="object"?e:t===null?"null":Object.prototype.toString.call(t)}function S(t,e){return t instanceof e}function rt(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function v(t=null,e={}){return Object.create(t,e)}function x(...t){return Object.assign(...t)}function Z(t,e){if(!t||!S(t,AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}function ot(t,e){let{observedAttributes:n=[]}=t.constructor;return n.reduce(function(r,o){return r[Et(o)]=e(t,o),r},{})}function Et(t){return t.replace(/-./g,e=>e[1].toUpperCase())}var P=class extends Error{constructor(){super();let[e,...n]=this.stack.split(` -`),r=e.slice(e.indexOf("@"),e.indexOf(".js:")+4),o=r.includes("src/helpers.js")?"src/":r;this.stack=n.find(c=>!c.includes(o))||e}get compact(){let{stack:e}=this;return e.slice(0,e.indexOf("@")+1)+"\u2026"+e.slice(e.lastIndexOf("/"))}};var j={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function G(t,e=!0){return e?x(j,t):(Object.setPrototypeOf(t,j),t)}function F(t){return rt(t,j)&&t!==j?t:j}var l={setDeleteAttr:_t,ssr:"",D:globalThis.document,N:globalThis.Node,F:globalThis.DocumentFragment,H:globalThis.HTMLElement,S:globalThis.SVGElement,M:globalThis.MutationObserver,q:t=>t||Promise.resolve()};function _t(t,e,n){if(Reflect.set(t,e,n),!!C(n)){if(Reflect.deleteProperty(t,e),S(t,l.H)&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var k="__dde_lifecyclesToEvents",y="dde:connected",D="dde:disconnected",I="dde:attributeChanged";var R=l.M?St():new Proxy({},{get(){return()=>{}}});function St(){let t=new Map,e=!1,n=u=>function(a){for(let f of a)if(f.type==="childList"){if(h(f.addedNodes,!0)){u();continue}O(f.removedNodes,!0)&&u()}},r=new l.M(n(i));return{observe(u){let a=new l.M(n(()=>{}));return a.observe(u,{childList:!0,subtree:!0}),()=>a.disconnect()},onConnected(u,a){s();let f=c(u);f.connected.has(a)||(f.connected.add(a),f.length_c+=1)},offConnected(u,a){if(!t.has(u))return;let f=t.get(u);f.connected.has(a)&&(f.connected.delete(a),f.length_c-=1,o(u,f))},onDisconnected(u,a){s();let f=c(u);f.disconnected.has(a)||(f.disconnected.add(a),f.length_d+=1)},offDisconnected(u,a){if(!t.has(u))return;let f=t.get(u);f.disconnected.delete(a),f.length_d-=1,o(u,f)}};function o(u,a){a.length_c||a.length_d||(t.delete(u),i())}function c(u){if(t.has(u))return t.get(u);let a={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(u,a),a}function s(){e||(e=!0,r.observe(l.D.body,{childList:!0,subtree:!0}))}function i(){!e||t.size||(e=!1,r.disconnect())}function d(){return new Promise(function(u){(requestIdleCallback||requestAnimationFrame)(u)})}async function g(u){t.size>30&&await d();let a=[];if(!S(u,l.N))return a;for(let f of t.keys())f===u||!S(f,l.N)||u.contains(f)&&a.push(f);return a}function h(u,a){let f=!1;for(let _ of u){if(a&&g(_).then(h),!t.has(_))continue;let M=t.get(_);M.length_c&&(_.dispatchEvent(new Event(y)),M.connected=new WeakSet,M.length_c=0,M.length_d||t.delete(_),f=!0)}return f}function O(u,a){let f=!1;for(let _ of u)a&&g(_).then(O),!(!t.has(_)||!t.get(_).length_d)&&((globalThis.queueMicrotask||setTimeout)(xt(_)),f=!0);return f}function xt(u){return()=>{u.isConnected||(u.dispatchEvent(new Event(D)),t.delete(u))}}}function Zt(t,e,n){return typeof e=="function"&&(n=e,e=null),e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let s=c.length?new CustomEvent(t,x({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(s)}}function w(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var ct=t=>x({},typeof t=="object"?t:null,{once:!0});w.connected=function(t,e){return e=ct(e),function(r){return r.addEventListener(y,t,e),r[k]?r:r.isConnected?(r.dispatchEvent(new Event(y)),r):(Z(e.signal,()=>R.offConnected(r,t))&&R.onConnected(r,t),r)}};w.disconnected=function(t,e){return e=ct(e),function(r){return r.addEventListener(D,t,e),r[k]||Z(e.signal,()=>R.offDisconnected(r,t))&&R.onDisconnected(r,t),r}};function te(t){return l.q(t)}var A=[{get scope(){return l.D.body},host:t=>t?t(l.D.body):l.D.body,prevent:!0}],V=new WeakMap,E={get current(){return A[A.length-1]},get host(){return this.current.host},get signal(){let{host:t}=this;if(V.has(t))return V.get(t);let e=new AbortController;return V.set(t,e),t(w.disconnected(()=>e.abort())),e.signal},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...A]},push(t={}){return A.push(x({},this.current,{prevent:!1},t))},pushRoot(){return A.push(A[0])},pop(){if(A.length!==1)return A.pop()}};function st(...t){return this.appendOriginal(...t),this}function wt(t){return t.append===st||(t.appendOriginal=t.append,t.append=st),t}var U;function q(t,e,...n){let r=F(this),o=0,c,s;switch((Object(e)!==e||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let i=(...h)=>h.length?(o===1?n.unshift(...h):h.forEach(O=>O(s)),void 0):s;E.push({scope:t,host:i}),c=t(e||void 0);let d=S(c,l.F);if(c.nodeName==="#comment")break;let g=q.mark({type:"component",name:t.name,host:d?"this":"parentElement"});c.prepend(g),d&&(s=g);break}case t==="#text":c=$.call(this,l.D.createTextNode(""),e);break;case(t==="<>"||!t):c=$.call(this,l.D.createDocumentFragment(),e);break;case!!U:c=$.call(this,l.D.createElementNS(U,t),e);break;case!c:c=$.call(this,l.D.createElement(t),e)}return wt(c),s||(s=c),n.forEach(i=>i(s)),o&&E.pop(),o=2,c}q.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=l.D.createComment(``);return e&&(r.end=l.D.createComment("")),r};function ee(t){let e=this;return function(...r){U=t;let o=q.call(e,...r);return U=void 0,o}}function ne(t,e=t){let n="\xB9\u2070",r="\u2713",o=Object.fromEntries(Array.from(e.querySelectorAll("slot")).filter(c=>!c.name.endsWith(n)).map(c=>[c.name+=n,c]));if(t.append=new Proxy(t.append,{apply(c,s,i){if(i[0]===e)return c.apply(t,i);for(let d of i){let g=(d.slot||"")+n;try{At(d,"remove","slot")}catch{}let h=o[g];if(!h)return;h.name.startsWith(r)||(h.childNodes.forEach(O=>O.remove()),h.name=r+g),h.append(d)}return t.append=c,t}}),t!==e){let c=Array.from(t.childNodes);t.append(...c)}return e}var z=new WeakMap,{setDeleteAttr:it}=l;function $(t,...e){if(!e.length)return t;z.set(t,at(t,this));for(let[n,r]of Object.entries(x({},...e)))ft.call(this,t,n,r);return z.delete(t),t}function ft(t,e,n){let{setRemoveAttr:r,s:o}=at(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(i,d)=>ft.call(c,t,i,d));let[s]=e;if(s==="=")return r(e.slice(1),n);if(s===".")return ut(t,e.slice(1),n);if(/(aria|data)([A-Z])/.test(e))return e=e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),r(e,n);switch(e==="className"&&(e="class"),e){case"xlink:href":return r(e,n,"http://www.w3.org/1999/xlink");case"textContent":return it(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return K(o,e,t,n,ut.bind(null,t[e]));case"ariaset":return K(o,e,t,n,(i,d)=>r("aria-"+i,d));case"classList":return yt.call(c,t,n)}return Ot(t,e)?it(t,e,n):r(e,n)}function at(t,e){if(z.has(t))return z.get(t);let r=(S(t,l.S)?Dt:Ct).bind(null,t,"Attribute"),o=F(e);return{setRemoveAttr:r,s:o}}function yt(t,e){let n=F(this);return K(n,"classList",t,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function At(t,e,n,r){return S(t,l.H)?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function Ot(t,e){if(!(e in t))return!1;let n=dt(t,e);return!C(n.set)}function dt(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||dt(t,e)}function K(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([i,d]){i&&(i=new c(i),i.target=e,d=t.processReactiveAttribute(n,i,d,o),o(i,d))})}function Ct(t,e,n,r){return t[(C(r)?"remove":"set")+e](n,r)}function Dt(t,e,n,r,o=null){return t[(C(r)?"remove":"set")+e+"NS"](o,n,r)}function ut(t,e,n){if(Reflect.set(t,e,n),!!C(n))return Reflect.deleteProperty(t,e)}function ie(t,e,n={}){let r=t.host||t;E.push({scope:r,host:(...s)=>s.length?s.forEach(i=>i(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[k];o||Rt(r);let c=e.call(r,n);return o||r.dispatchEvent(new Event(y)),t.nodeType===11&&typeof t.mode=="string"&&r.addEventListener(D,R.observe(t),{once:!0}),E.pop(),t.append(c)}function Rt(t){return Q(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(y))}),Q(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(D)))}),Q(t.prototype,"attributeChangedCallback",function(e,n,r){let[o,,c]=r;n.dispatchEvent(new CustomEvent(I,{detail:[o,c]})),e.apply(n,r)}),t.prototype[k]=!0,t}function Q(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}var lt="__dde_memo",H=[];function T(t,e){if(!H.length)return e(t);let n=typeof t=="object"?JSON.stringify(t):t,[{cache:r,after:o}]=H;return o(n,W(r,n)?r[n]:e(t))}T.isScope=function(t){return t[lt]};T.scope=function(e,{signal:n,onlyLast:r}={}){let o=v();function c(...s){if(n&&n.aborted)return e.apply(this,s);let i=r?o:v();H.unshift({cache:o,after(g,h){return i[g]=h}});let d=e.apply(this,s);return H.shift(),o=i,d}return c[lt]=!0,c.clear=()=>o=v(),n&&n.addEventListener("abort",c.clear),c};var p="__dde_signal",X=(()=>{let t=new Set,e=!1;function n(){e=!1;let r=t;t=new Set;for(let o of r){let c=o[p];c&&c.listeners.forEach(s=>s(c.value))}}return function(r){t.add(r),!e&&(e=!0,queueMicrotask(n))}})();var tt=v(null,{get:{value(){return ht(this)}},set:{value(...t){return vt(this,...t)}},toJSON:{value(){return ht(this)}},valueOf:{value(){return this[p]&&this[p].value}}}),Lt=v(tt,{set:{value(){}}});function J(t){return t&&t[p]}var B=[],b=new WeakMap;function m(t,e){if(typeof t!="function")return pt(!1,t,e);if(J(t))return t;let n=pt(!0);function r(){let[o,...c]=b.get(r);if(b.set(r,new Set([o])),B.push(r),vt(n,t()),B.pop(),!c.length)return;let s=b.get(r);for(let i of c)s.has(i)||N(i,r)}return b.set(n[p],r),b.set(r,new Set([n])),r(),n}m.action=function(t,e,...n){let r=t[p];if(!r)return;let{actions:o}=r;if(!o||!W(o,e))throw new Error(`Action "${e}" not defined. See ${p}.actions.`);if(o[e].apply(r,n),r.skip)return delete r.skip;X(t)};m.on=function t(e,n,r={}){let{signal:o}=r;if(!(o&&o.aborted)){if(Array.isArray(e))return e.forEach(c=>t(c,n,r));et(e,n),o&&o.addEventListener("abort",()=>N(e,n))}};m.symbols={onclear:Symbol.for("Signal.onclear")};m.clear=function(...t){for(let n of t){let r=n[p];r&&(delete n.toJSON,r.onclear.forEach(o=>o.call(r)),e(n,r),delete n[p])}function e(n,r){r.listeners.forEach(o=>{if(r.listeners.delete(o),!b.has(o))return;let c=b.get(o);c.delete(n),!(c.size>1)&&(n.clear(...c),b.delete(o))})}};var L="__dde_reactive";m.el=function(t,e){e=T.isScope(e)?e:T.scope(e,{onlyLast:!0});let n=q.mark({type:"reactive",source:new P().compact},!0),r=n.end,o=l.D.createDocumentFragment();o.append(n,r);let{current:c}=E,s=i=>{if(!n.parentNode||!r.parentNode)return N(t,s);E.push(c);let d=e(i);E.pop(),Array.isArray(d)||(d=[d]);let g=document.createComment("");d.push(g),n.after(...d);let h;for(;(h=g.nextSibling)&&h!==r;)h.remove();g.remove(),n.isConnected&&Nt(c.host())};return et(t,s),mt(t,s,n,e),s(t.get()),c.host(w.disconnected(()=>e.clear())),o};function Nt(t){!t||!t[L]||(requestIdleCallback||setTimeout)(function(){t[L]=t[L].filter(([e,n])=>n.isConnected?!0:(N(...e),!1))})}var kt={_set(t){this.value=t}};function Tt(t){return function(e,n){let r=v(tt,{set:{value(...c){return e.setAttribute(n,...c)}}}),o=bt(r,e.getAttribute(n),kt);return t[n]=o,o}}var Y="__dde_attributes";m.observedAttributes=function(t){let e=t[Y]={},n=ot(t,Tt(e));return w(I,function({detail:o}){/*! This maps attributes to signals (`S.observedAttributes`). - Investigate `__dde_attributes` key of the element. */let[c,s]=o,i=this[Y][c];if(i)return m.action(i,"_set",s)})(t),w.disconnected(function(){/*! This removes all signals mapped to attributes (`S.observedAttributes`). - Investigate `__dde_attributes` key of the element. */m.clear(...Object.values(this[Y]))})(t),n};var gt={isSignal:J,processReactiveAttribute(t,e,n,r){if(!J(n))return n;let o=c=>{if(!t.isConnected)return N(n,o);r(e,c)};return et(n,o),mt(n,o,t,e),n.get()}};function mt(t,e,...n){let{current:r}=E;r.host(function(o){if(o[L])return o[L].push([[t,e],...n]);o[L]=[],!r.prevent&&w.disconnected(()=>o[L].forEach(([[c,s]])=>N(c,s,c[p]&&c[p].host&&c[p].host()===o)))(o)})}var Mt=new FinalizationRegistry(function(t){m.clear({[p]:t})});function pt(t,e,n){let r=v(t?Lt:tt),o=bt(r,e,n,t);return Mt.register(o,o[p]),o}var Pt=x(v(),{stopPropagation(){this.skip=!0}});function bt(t,e,n,r=!1){let o=[];nt(n)!=="[object Object]"&&(n={});let{onclear:c}=m.symbols;n[c]&&(o.push(n[c]),delete n[c]);let{host:s}=E;return Reflect.defineProperty(t,p,{value:x(v(Pt),{value:e,actions:n,onclear:o,host:s,listeners:new Set,defined:new P().stack,readonly:r}),enumerable:!1,writable:!1,configurable:!0}),t}function jt(){return B[B.length-1]}function ht(t){if(!t[p])return;let{value:e,listeners:n}=t[p],r=jt();return r&&n.add(r),b.has(r)&&b.get(r).add(t),e}function vt(t,e,n){let r=t[p];if(!(!r||!n&&r.value===e))return r.value=e,X(t),e}function et(t,e){if(t[p])return t[p].listeners.add(e)}function N(t,e,n){let r=t[p];if(!r)return;let{listeners:o}=r,c=o.delete(e);if(!c||!n||o.size)return c;m.clear(t);let s=b.get(r);if(!s)return c;let i=b.get(s);if(!i)return c;for(let d of i)N(d,s,!0);return c}G(gt);export{m as S,$ as assign,ft as assignAttribute,wt as chainableAppend,yt as classListDeclarative,q as createElement,ee as createElementNS,ie as customElementRender,Rt as customElementWithDDE,Zt as dispatchEvent,q as el,ee as elNS,At as elementAttribute,J as isSignal,Rt as lifecyclesToEvents,T as memo,w as on,te as queue,G as registerReactivity,E as scope,m as signal,ne as simulateSlots}; +var W=(...t)=>Object.prototype.hasOwnProperty.call(...t);function A(t){return typeof t>"u"}function ot(t){let e=typeof t;return e!=="object"?e:t===null?"null":Object.prototype.toString.call(t)}function E(t,e){return t instanceof e}function ct(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function _(t=null,e={}){return Object.create(t,e)}function v(...t){return Object.assign(...t)}function G(t,e){if(!t||!E(t,AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}function st(t,e){let{observedAttributes:n=[]}=t.constructor;return n.reduce(function(r,o){return r[wt(o)]=e(t,o),r},{})}function wt(t){return t.replace(/-./g,e=>e[1].toUpperCase())}var P=class extends Error{constructor(){super();let[e,...n]=this.stack.split(` +`),r=e.slice(e.indexOf("@"),e.indexOf(".js:")+4),o=r.includes("src/helpers.js")?"src/":r;this.stack=n.find(c=>!c.includes(o))||e}get compact(){let{stack:e}=this;return e.slice(0,e.indexOf("@")+1)+"\u2026"+e.slice(e.lastIndexOf("/"))}};var d={setDeleteAttr:yt,ssr:"",D:globalThis.document,N:globalThis.Node,F:globalThis.DocumentFragment,H:globalThis.HTMLElement,S:globalThis.SVGElement,M:globalThis.MutationObserver,q:t=>t||Promise.resolve()};function yt(t,e,n){if(Reflect.set(t,e,n),!!A(n)){if(Reflect.deleteProperty(t,e),E(t,d.H)&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var k="__dde_lifecyclesToEvents",C="dde:connected",R="dde:disconnected",F="dde:attributeChanged";var D=d.M?At():new Proxy({},{get(){return()=>{}}});function At(){let t=new Map,e=!1,n=u=>function(p){for(let f of p)if(f.type==="childList"){if(m(f.addedNodes,!0)){u();continue}y(f.removedNodes,!0)&&u()}},r=new d.M(n(i));return{observe(u){let p=new d.M(n(()=>{}));return p.observe(u,{childList:!0,subtree:!0}),()=>p.disconnect()},onConnected(u,p){s();let f=c(u);f.connected.has(p)||(f.connected.add(p),f.length_c+=1)},offConnected(u,p){if(!t.has(u))return;let f=t.get(u);f.connected.has(p)&&(f.connected.delete(p),f.length_c-=1,o(u,f))},onDisconnected(u,p){s();let f=c(u);f.disconnected.has(p)||(f.disconnected.add(p),f.length_d+=1)},offDisconnected(u,p){if(!t.has(u))return;let f=t.get(u);f.disconnected.delete(p),f.length_d-=1,o(u,f)}};function o(u,p){p.length_c||p.length_d||(t.delete(u),i())}function c(u){if(t.has(u))return t.get(u);let p={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(u,p),p}function s(){e||(e=!0,r.observe(d.D.body,{childList:!0,subtree:!0}))}function i(){!e||t.size||(e=!1,r.disconnect())}function a(){return new Promise(function(u){(requestIdleCallback||requestAnimationFrame)(u)})}async function h(u){t.size>30&&await a();let p=[];if(!E(u,d.N))return p;for(let f of t.keys())f===u||!E(f,d.N)||u.contains(f)&&p.push(f);return p}function m(u,p){let f=!1;for(let S of u){if(p&&h(S).then(m),!t.has(S))continue;let T=t.get(S);T.length_c&&(S.dispatchEvent(new Event(C)),T.connected=new WeakSet,T.length_c=0,T.length_d||t.delete(S),f=!0)}return f}function y(u,p){let f=!1;for(let S of u)p&&h(S).then(y),!(!t.has(S)||!t.get(S).length_d)&&((globalThis.queueMicrotask||setTimeout)(Z(S)),f=!0);return f}function Z(u){return()=>{u.isConnected||(u.dispatchEvent(new Event(R)),t.delete(u))}}}function Jt(t,e,n){return typeof e=="function"&&(n=e,e=null),e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let s=c.length?new CustomEvent(t,v({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(s)}}function w(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}w.defer=t=>setTimeout.bind(null,t,0);var it=t=>v({},typeof t=="object"?t:null,{once:!0});w.connected=function(t,e){return e=it(e),function(r){return r.addEventListener(C,t,e),r[k]?r:r.isConnected?(r.dispatchEvent(new Event(C)),r):(G(e.signal,()=>D.offConnected(r,t))&&D.onConnected(r,t),r)}};w.disconnected=function(t,e){return e=it(e),function(r){return r.addEventListener(R,t,e),r[k]||G(e.signal,()=>D.offDisconnected(r,t))&&D.onDisconnected(r,t),r}};var O=[{get scope(){return d.D.body},host:t=>t?t(d.D.body):d.D.body,prevent:!0}],V=new WeakMap,b={get current(){return O[O.length-1]},get host(){return this.current.host},get signal(){let{host:t}=this;if(V.has(t))return V.get(t);let e=new AbortController;return V.set(t,e),t(w.disconnected(()=>e.abort())),e.signal},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...O]},push(t={}){return O.push(v({},this.current,{prevent:!1},t))},pushRoot(){return O.push(O[0])},pop(){if(O.length!==1)return O.pop()}};var q={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function K(t,e=!0){return e?v(q,t):(Object.setPrototypeOf(t,q),t)}function I(t){return ct(t,q)&&t!==q?t:q}function ut(t,e,n,r){return t[(A(r)?"remove":"set")+e](n,r)}function ft(t,e,n,r,o=null){return t[(A(r)?"remove":"set")+e+"NS"](o,n,r)}function Q(t,e,n){if(Reflect.set(t,e,n),!!A(n))return Reflect.deleteProperty(t,e)}function at(t,e,n,r){return E(t,d.H)?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function se(t){return d.q(t)}function pt(...t){return this.appendOriginal(...t),this}function Ct(t){return t.append===pt||(t.appendOriginal=t.append,t.append=pt),t}var $;function j(t,e,...n){let r=I(this),o=0,c,s,i=typeof e;switch((i==="string"||i==="number"||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let a=(...y)=>y.length?(o===1?n.unshift(...y):y.forEach(Z=>Z(s)),void 0):s;b.push({scope:t,host:a}),c=t(e||void 0);let h=E(c,d.F);if(c.nodeName==="#comment")break;let m=j.mark({type:"component",name:t.name,host:h?"this":"parentElement"});c.prepend(m),h&&(s=m);break}case t==="#text":c=U.call(this,d.D.createTextNode(""),e);break;case(t==="<>"||!t):c=U.call(this,d.D.createDocumentFragment(),e);break;case!!$:c=U.call(this,d.D.createElementNS($,t),e);break;case!c:c=U.call(this,d.D.createElement(t),e)}return Ct(c),s||(s=c),n.forEach(a=>a(s)),o&&b.pop(),o=2,c}j.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=d.D.createComment(``);return e&&(r.end=d.D.createComment("")),r};function ue(t){let e=this;return function(...r){$=t;let o=j.call(e,...r);return $=void 0,o}}var z=new WeakMap,{setDeleteAttr:dt}=d;function U(t,...e){if(!e.length)return t;z.set(t,ht(t,this));for(let[n,r]of Object.entries(v({},...e)))lt.call(this,t,n,r);return z.delete(t),t}function lt(t,e,n){let{setRemoveAttr:r,s:o}=ht(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(i,a)=>lt.call(c,t,i,a));let[s]=e;if(s==="=")return r(e.slice(1),n);if(s===".")return Q(t,e.slice(1),n);if(/(aria|data)([A-Z])/.test(e))return e=e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),r(e,n);switch(e==="className"&&(e="class"),e){case"xlink:href":return r(e,n,"http://www.w3.org/1999/xlink");case"textContent":return dt(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return X(o,e,t,n,Q.bind(null,t[e]));case"ariaset":return X(o,e,t,n,(i,a)=>r("aria-"+i,a));case"classList":return Ot.call(c,t,n)}return Rt(t,e)?dt(t,e,n):r(e,n)}function ht(t,e){if(z.has(t))return z.get(t);let r=(E(t,d.S)?ft:ut).bind(null,t,"Attribute"),o=I(e);return{setRemoveAttr:r,s:o}}function Ot(t,e){let n=I(this);return X(n,"classList",t,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function Rt(t,e){if(!(e in t))return!1;let n=mt(t,e);return!A(n.set)}function mt(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||mt(t,e)}function X(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([i,a]){i&&(i=new c(i),i.target=e,a=t.processReactiveAttribute(n,i,a,o),o(i,a))})}function ge(t,e=t){let n="\xB9\u2070",r="\u2713",o=Object.fromEntries(Array.from(e.querySelectorAll("slot")).filter(c=>!c.name.endsWith(n)).map(c=>[c.name+=n,c]));if(t.append=new Proxy(t.append,{apply(c,s,i){if(i[0]===e)return c.apply(t,i);for(let a of i){let h=(a.slot||"")+n;try{at(a,"remove","slot")}catch{}let m=o[h];if(!m)return;m.name.startsWith(r)||(m.childNodes.forEach(y=>y.remove()),m.name=r+h),m.append(a)}return t.append=c,t}}),t!==e){let c=Array.from(t.childNodes);t.append(...c)}return e}function ve(t,e,n={}){let r=t.host||t;b.push({scope:r,host:(...s)=>s.length?s.forEach(i=>i(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[k];o||Dt(r);let c=e.call(r,n);return o||r.dispatchEvent(new Event(C)),t.nodeType===11&&typeof t.mode=="string"&&r.addEventListener(R,D.observe(t),{once:!0}),b.pop(),t.append(c)}function Dt(t){return Y(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(C))}),Y(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(R)))}),Y(t.prototype,"attributeChangedCallback",function(e,n,r){let[o,,c]=r;n.dispatchEvent(new CustomEvent(F,{detail:[o,c]})),e.apply(n,r)}),t.prototype[k]=!0,t}function Y(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}var gt="__dde_memo",H=[];function M(t,e){if(!H.length)return e(t);let n=typeof t=="object"?JSON.stringify(t):t,[{cache:r,after:o}]=H;return o(n,W(r,n)?r[n]:e(t))}M.isScope=function(t){return t[gt]};M.scope=function(e,{signal:n,onlyLast:r}={}){let o=_();function c(...s){if(n&&n.aborted)return e.apply(this,s);let i=r?o:_();H.unshift({cache:o,after(h,m){return i[h]=m}});let a=e.apply(this,s);return H.shift(),o=i,a}return c[gt]=!0,c.clear=()=>o=_(),n&&n.addEventListener("abort",c.clear),c};var l="__dde_signal",tt=(()=>{let t=new Map,e=!1;function n(){e=!1;let r=t;t=new Map;for(let[o,c]of r){let s=o[l];s&&s.listeners.forEach(i=>i(s.value,c))}}return function(r,o=!1){t.set(r,t.get(r)||o),!e&&(e=!0,queueMicrotask(n))}})();var nt=_(null,{get:{value(){return bt(this)}},set:{value(...t){return St(this,...t)}},toJSON:{value(){return bt(this)}},valueOf:{value(){return this[l]&&this[l].value}}}),Lt=_(nt,{set:{value(){}}});function J(t){return t&&t[l]}var B=[],x=new WeakMap;function g(t,e){if(typeof t!="function")return vt(!1,t,e);if(J(t))return t;let n=vt(!0);function r(o,c){let[s,...i]=x.get(r);if(x.set(r,new Set([s])),B.push(r),St(n,t(),c),B.pop(),!i.length)return;let a=x.get(r);for(let h of i)a.has(h)||N(h,r)}return x.set(n[l],r),x.set(r,new Set([n])),r(),n}g.action=function(t,e,...n){let r=t[l];if(!r)return;let{actions:o}=r;if(!o||!W(o,e))throw new Error(`Action "${e}" not defined. See ${l}.actions.`);if(o[e].apply(r,n),r.skip)return delete r.skip;tt(t,!0)};g.on=function t(e,n,r={}){let{signal:o}=r;if(!(o&&o.aborted)){if(Array.isArray(e))return e.forEach(c=>t(c,n,r));rt(e,n),o&&o.addEventListener("abort",()=>N(e,n))}};g.symbols={onclear:Symbol.for("Signal.onclear")};g.clear=function(...t){for(let n of t){let r=n[l];r&&(delete n.toJSON,r.onclear.forEach(o=>o.call(r)),e(n,r),delete n[l])}function e(n,r){r.listeners.forEach(o=>{if(r.listeners.delete(o),!x.has(o))return;let c=x.get(o);c.delete(n),!(c.size>1)&&(n.clear(...c),x.delete(o))})}};var L="__dde_reactive";g.el=function(t,e){e=M.isScope(e)?e:M.scope(e,{onlyLast:!0});let n=j.mark({type:"reactive",source:new P().compact},!0),r=n.end,o=d.D.createDocumentFragment();o.append(n,r);let{current:c}=b,s=i=>{if(!n.parentNode||!r.parentNode)return N(t,s);b.push(c);let a=e(i);b.pop(),Array.isArray(a)||(a=[a]);let h=document.createComment("");a.push(h),n.after(...a);let m;for(;(m=h.nextSibling)&&m!==r;)m.remove();h.remove(),n.isConnected&&Nt(c.host())};return rt(t,s),Et(t,s,n,e),s(t.get()),c.host(w.disconnected(()=>e.clear())),o};function Nt(t){!t||!t[L]||(requestIdleCallback||setTimeout)(function(){t[L]=t[L].filter(([e,n])=>n.isConnected?!0:(N(...e),!1))})}var kt={_set(t){this.value=t}};function Mt(t){return function(e,n){let r=_(nt,{set:{value(...c){return e.setAttribute(n,...c)}}}),o=_t(r,e.getAttribute(n),kt);return t[n]=o,o}}var et="__dde_attributes";g.observedAttributes=function(t){let e=t[et]={},n=st(t,Mt(e));return w(F,function({detail:o}){/*! This maps attributes to signals (`S.observedAttributes`). + Investigate `__dde_attributes` key of the element. */let[c,s]=o,i=this[et][c];if(i)return g.action(i,"_set",s)})(t),w.disconnected(function(){/*! This removes all signals mapped to attributes (`S.observedAttributes`). + Investigate `__dde_attributes` key of the element. */g.clear(...Object.values(this[et]))})(t),n};var xt={isSignal:J,processReactiveAttribute(t,e,n,r){if(!J(n))return n;let o=c=>{if(!t.isConnected)return N(n,o);r(e,c)};return rt(n,o),Et(n,o,t,e),n.get()}};function Et(t,e,...n){let{current:r}=b;r.host(function(o){if(o[L])return o[L].push([[t,e],...n]);o[L]=[],!r.prevent&&w.disconnected(()=>o[L].forEach(([[c,s]])=>N(c,s,c[l]&&c[l].host&&c[l].host()===o)))(o)})}var Tt=new FinalizationRegistry(function(t){g.clear({[l]:t})});function vt(t,e,n){let r=_(t?Lt:nt),o=_t(r,e,n,t);return Tt.register(o,o[l]),o}var Pt=v(_(),{stopPropagation(){this.skip=!0}});function _t(t,e,n,r=!1){let o=[];ot(n)!=="[object Object]"&&(n={});let{onclear:c}=g.symbols;n[c]&&(o.push(n[c]),delete n[c]);let{host:s}=b;return Reflect.defineProperty(t,l,{value:v(_(Pt),{value:e,actions:n,onclear:o,host:s,listeners:new Set,defined:new P().stack,readonly:r}),enumerable:!1,writable:!1,configurable:!0}),t}function qt(){return B[B.length-1]}function bt(t){if(!t[l])return;let{value:e,listeners:n}=t[l],r=qt();return r&&n.add(r),x.has(r)&&x.get(r).add(t),e}function St(t,e,n){let r=t[l];if(!(!r||!n&&r.value===e))return r.value=e,tt(t,n),e}function rt(t,e){if(t[l])return t[l].listeners.add(e)}function N(t,e,n){let r=t[l];if(!r)return;let{listeners:o}=r,c=o.delete(e);if(!c||!n||o.size)return c;g.clear(t);let s=x.get(r);if(!s)return c;let i=x.get(s);if(!i)return c;for(let a of i)N(a,s,!0);return c}K(xt);export{g as S,U as assign,lt as assignAttribute,Ct as chainableAppend,Ot as classListDeclarative,j as createElement,ue as createElementNS,ve as customElementRender,Dt as customElementWithDDE,Jt as dispatchEvent,j as el,ue as elNS,J as isSignal,Dt as lifecyclesToEvents,M as memo,w as on,se as queue,K as registerReactivity,b as scope,g as signal,ge as simulateSlots}; diff --git a/dist/esm.d.min.ts b/dist/esm.d.min.ts deleted file mode 100644 index 9ac112a..0000000 --- a/dist/esm.d.min.ts +++ /dev/null @@ -1,568 +0,0 @@ -declare global{ /* ddeSignal */ } -type CustomElementTagNameMap= { '#text': Text, '#comment': Comment } -type SupportedElement= - HTMLElementTagNameMap[keyof HTMLElementTagNameMap] - | SVGElementTagNameMap[keyof SVGElementTagNameMap] - | MathMLElementTagNameMap[keyof MathMLElementTagNameMap] - | CustomElementTagNameMap[keyof CustomElementTagNameMap] -declare global { - type ddeComponentAttributes= Record | undefined; - type ddeElementAddon= (element: El)=> any; - type ddeString= string | ddeSignal - type ddeStringable= ddeString | number | ddeSignal -} -type PascalCase= -`${Capitalize}${string}`; -type AttrsModified= { - /** - * Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API). - */ - style: Partial | ddeString - | Partial<{ [K in keyof CSSStyleDeclaration]: ddeSignal }> - /** - * Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1. - * In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))` - * for others. - */ - classList: Record>, - /** - * Used by the dataset HTML attribute to represent data for custom attributes added to elements. - * Values are converted to string (see {@link DOMStringMap}). - * - * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMStringMap) - * */ - dataset: Record, - /** - * Sets `aria-*` simiraly to `dataset` - * */ - ariaset: Record, -} & Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, ddeString> - & Record<`.${string}`, any> -type _fromElsInterfaces= Omit; -type IsReadonly = - T extends { readonly [P in K]: T[K] } ? true : false; -/** - * Just element attributtes - * - * In most cases, you can use native propertie such as - * [MDN WEB/API/Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) and so on - * (e.g. [`Text`](https://developer.mozilla.org/en-US/docs/Web/API/Text)). - * - * There is added support for `data[A-Z].*`/`aria[A-Z].*` to be converted to the kebab-case alternatives. - * @private - */ -type ElementAttributes= Partial<{ - [K in keyof _fromElsInterfaces]: - _fromElsInterfaces[K] extends ((...p: any[])=> any) - ? _fromElsInterfaces[K] | ((...p: Parameters<_fromElsInterfaces[K]>)=> - ddeSignal[K]>>) - : (IsReadonly<_fromElsInterfaces, K> extends false - ? _fromElsInterfaces[K] | ddeSignal<_fromElsInterfaces[K]> - : ddeStringable) -} & AttrsModified> & Record; -export function classListDeclarative( - element: El, - classList: AttrsModified["classList"] -): El -export function assign(element: El, ...attrs_array: ElementAttributes[]): El -export function assignAttribute>( - element: El, - attr: ATT, - value: ElementAttributes[ATT] -): ElementAttributes[ATT] - -type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagNameMap; -export namespace el { - /** - * Creates a marker comment for elements - * - * @param attrs - Marker attributes - * @param [is_open=false] - Whether the marker is open-ended - * @returns Comment node marker - */ - export function mark( - attrs: { type: "component"|"reactive"|"later", name?: string, host?: "this"|"parentElement" }, - is_open?: boolean - ): Comment; -} - -export function el< - A extends ddeComponentAttributes, - EL extends SupportedElement | ddeDocumentFragment ->( - component: (attr: A, ...rest: any[])=> EL, - attrs?: NoInfer, - ...addons: ddeElementAddon[] -): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] - ? EL - : ( EL extends ddeDocumentFragment ? EL : ddeHTMLElement ) -export function el< - A extends { textContent: ddeStringable }, - EL extends SupportedElement | ddeDocumentFragment ->( - component: (attr: A, ...rest: any[])=> EL, - attrs?: NoInfer["textContent"], - ...addons: ddeElementAddon[] -): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] - ? EL - : ( EL extends ddeDocumentFragment ? EL : ddeHTMLElement ) -export function el< - TAG extends keyof ExtendedHTMLElementTagNameMap, ->( - tag_name: TAG, - attrs?: ElementAttributes]> | ddeStringable, - ...addons: ddeElementAddon< - ExtendedHTMLElementTagNameMap[NoInfer] - >[], // TODO: for now addons must have the same element -): TAG extends keyof ddeHTMLElementTagNameMap ? ddeHTMLElementTagNameMap[TAG] : ddeHTMLElement -export function el( - tag_name?: "<>", -): ddeDocumentFragment -export function el( - tag_name: string, - attrs?: ElementAttributes | ddeStringable, - ...addons: ddeElementAddon[] -): ddeHTMLElement -export { el as createElement } - -export function elNS( - namespace: "http://www.w3.org/2000/svg" -): < - TAG extends keyof SVGElementTagNameMap & string, - EL extends ( TAG extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[TAG] : SVGElement ), ->( - tag_name: TAG, - attrs?: ElementAttributes> | ddeStringable, - ...addons: ddeElementAddon>[] -)=> TAG extends keyof ddeSVGElementTagNameMap ? ddeSVGElementTagNameMap[TAG] : ddeSVGElement -export function elNS( - namespace: "http://www.w3.org/1998/Math/MathML" -): < - TAG extends keyof MathMLElementTagNameMap & string, - EL extends ( TAG extends keyof MathMLElementTagNameMap ? MathMLElementTagNameMap[TAG] : MathMLElement ), ->( - tag_name: TAG, - attrs?: ddeStringable | Partial<{ - [key in keyof EL]: EL[key] | ddeSignal | string | number | boolean - }>, - ...addons: ddeElementAddon>[] -)=> ddeMathMLElement -export function elNS( - namespace: string -): ( - tag_name: string, - attrs?: string | ddeStringable | Record, - ...addons: ddeElementAddon[] -)=> SupportedElement -export { elNS as createElementNS } - -export function chainableAppend(el: EL): EL; -/** Simulate slots for ddeComponents */ -export function simulateSlots( - root: EL, -): EL -/** - * Simulate slots in Custom Elements without using `shadowRoot`. - * @param el Custom Element root element - * @param body Body of the custom element - * */ -export function simulateSlots( - el: HTMLElement, - body: EL, -): EL - -export function dispatchEvent(name: keyof DocumentEventMap | string, element: SupportedElement): - (data?: any)=> void; -export function dispatchEvent(name: keyof DocumentEventMap | string, options?: EventInit): - (element: SupportedElement, data?: any)=> void; -export function dispatchEvent( - name: keyof DocumentEventMap | string, - options: EventInit | null, - element: SupportedElement | (()=> SupportedElement) -): (data?: any)=> void; -interface On{ - /** Listens to the DOM event. See {@link Document.addEventListener} */ - < - Event extends keyof DocumentEventMap, - EE extends ddeElementAddon= ddeElementAddon, - >( - type: Event, - listener: (this: EE extends ddeElementAddon ? El : never, ev: DocumentEventMap[Event]) => any, - options?: AddEventListenerOptions - ) : EE; - < - EE extends ddeElementAddon= ddeElementAddon, - >( - type: string, - listener: (this: EE extends ddeElementAddon ? El : never, ev: Event | CustomEvent ) => any, - options?: AddEventListenerOptions - ) : EE; - /** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line - connected< - EE extends ddeElementAddon, - El extends ( EE extends ddeElementAddon ? El : never ) - >( - listener: (this: El, event: CustomEvent) => any, - options?: AddEventListenerOptions - ) : EE; - /** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line - disconnected< - EE extends ddeElementAddon, - El extends ( EE extends ddeElementAddon ? El : never ) - >( - listener: (this: El, event: CustomEvent) => any, - options?: AddEventListenerOptions - ) : EE; - /** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line - attributeChanged< - EE extends ddeElementAddon, - El extends ( EE extends ddeElementAddon ? El : never ) - >( - listener: (this: El, event: CustomEvent<[ string, string ]>) => any, - options?: AddEventListenerOptions - ) : EE; -} -export const on: On; - -type Scope= { - scope: Node | Function | Object, - host: ddeElementAddon, - custom_element: false | HTMLElement, - prevent: boolean -}; -/** Current scope created last time the `el(Function)` was invoke. (Or {@link scope.push}) */ -export const scope: { - current: Scope, - /** Stops all automatizations. E. g. signals used as attributes in current scope - * registers removing these listeners (and clean signal if no other listeners are detected) - * on `disconnected` event. */ - preventDefault(prevent: T): T, - /** - * This represents reference to the current host element — `scope.host()`. - * It can be also used to register Addon(s) (functions to be called when component is initized) - * — `scope.host(on.connected(console.log))`. - * */ - host: (...addons: ddeElementAddon[])=> HTMLElement, - - state: Scope[], - /** Adds new child scope. All attributes are inherited by default. */ - push(scope?: Partial): ReturnType["push"]>, - /** Adds root scope as a child of the current scope. */ - pushRoot(): ReturnType["push"]>, - /** Removes last/current child scope. */ - pop(): ReturnType["pop"]>, -}; - -export function customElementRender< - EL extends HTMLElement, - P extends any = Record> ->( - target: ShadowRoot | EL, - render: (props: P)=> SupportedElement | DocumentFragment, - props?: P | ((el: EL)=> P) -): EL -export function customElementWithDDE HTMLElement)>(custom_element: EL): EL -export function lifecyclesToEvents HTMLElement)>(custom_element: EL): EL -export function observedAttributes(custom_element: HTMLElement): Record - -/** - * This is used primarly for server side rendering. To be sure that all async operations - * are finished before the page is sent to the client. - * ``` - * // on component - * function component(){ - * … - * queue(fetch(...).then(...)); - * } - * - * // building the page - * async function build(){ - * const { component }= await import("./component.js"); - * document.body.append(el(component)); - * await queue(); - * retutn document.body.innerHTML; - * } - * ``` - * */ -export function queue(promise?: Promise): Promise; - -/* TypeScript MEH */ -declare global{ - type ddeAppend= (...nodes: (Node | string)[])=> el; - - interface ddeDocumentFragment extends DocumentFragment{ append: ddeAppend; } - interface ddeHTMLElement extends HTMLElement{ append: ddeAppend; } - interface ddeSVGElement extends SVGElement{ append: ddeAppend; } - interface ddeMathMLElement extends MathMLElement{ append: ddeAppend; } - - interface ddeHTMLElementTagNameMap { - "a": ddeHTMLAnchorElement; - "area": ddeHTMLAreaElement; - "audio": ddeHTMLAudioElement; - "base": ddeHTMLBaseElement; - "blockquote": ddeHTMLQuoteElement; - "body": ddeHTMLBodyElement; - "br": ddeHTMLBRElement; - "button": ddeHTMLButtonElement; - "canvas": ddeHTMLCanvasElement; - "caption": ddeHTMLTableCaptionElement; - "col": ddeHTMLTableColElement; - "colgroup": ddeHTMLTableColElement; - "data": ddeHTMLDataElement; - "datalist": ddeHTMLDataListElement; - "del": ddeHTMLModElement; - "details": ddeHTMLDetailsElement; - "dialog": ddeHTMLDialogElement; - "div": ddeHTMLDivElement; - "dl": ddeHTMLDListElement; - "embed": ddeHTMLEmbedElement; - "fieldset": ddeHTMLFieldSetElement; - "form": ddeHTMLFormElement; - "h1": ddeHTMLHeadingElement; - "h2": ddeHTMLHeadingElement; - "h3": ddeHTMLHeadingElement; - "h4": ddeHTMLHeadingElement; - "h5": ddeHTMLHeadingElement; - "h6": ddeHTMLHeadingElement; - "head": ddeHTMLHeadElement; - "hr": ddeHTMLHRElement; - "html": ddeHTMLHtmlElement; - "iframe": ddeHTMLIFrameElement; - "img": ddeHTMLImageElement; - "input": ddeHTMLInputElement; - "ins": ddeHTMLModElement; - "label": ddeHTMLLabelElement; - "legend": ddeHTMLLegendElement; - "li": ddeHTMLLIElement; - "link": ddeHTMLLinkElement; - "map": ddeHTMLMapElement; - "menu": ddeHTMLMenuElement; - "meta": ddeHTMLMetaElement; - "meter": ddeHTMLMeterElement; - "object": ddeHTMLObjectElement; - "ol": ddeHTMLOListElement; - "optgroup": ddeHTMLOptGroupElement; - "option": ddeHTMLOptionElement; - "output": ddeHTMLOutputElement; - "p": ddeHTMLParagraphElement; - "picture": ddeHTMLPictureElement; - "pre": ddeHTMLPreElement; - "progress": ddeHTMLProgressElement; - "q": ddeHTMLQuoteElement; - "script": ddeHTMLScriptElement; - "select": ddeHTMLSelectElement; - "slot": ddeHTMLSlotElement; - "source": ddeHTMLSourceElement; - "span": ddeHTMLSpanElement; - "style": ddeHTMLStyleElement; - "table": ddeHTMLTableElement; - "tbody": ddeHTMLTableSectionElement; - "td": ddeHTMLTableCellElement; - "template": ddeHTMLTemplateElement; - "textarea": ddeHTMLTextAreaElement; - "tfoot": ddeHTMLTableSectionElement; - "th": ddeHTMLTableCellElement; - "thead": ddeHTMLTableSectionElement; - "time": ddeHTMLTimeElement; - "title": ddeHTMLTitleElement; - "tr": ddeHTMLTableRowElement; - "track": ddeHTMLTrackElement; - "ul": ddeHTMLUListElement; - "video": ddeHTMLVideoElement; - } - interface ddeSVGElementTagNameMap { - "a": ddeSVGAElement; - "animate": ddeSVGAnimateElement; - "animateMotion": ddeSVGAnimateMotionElement; - "animateTransform": ddeSVGAnimateTransformElement; - "circle": ddeSVGCircleElement; - "clipPath": ddeSVGClipPathElement; - "defs": ddeSVGDefsElement; - "desc": ddeSVGDescElement; - "ellipse": ddeSVGEllipseElement; - "feBlend": ddeSVGFEBlendElement; - "feColorMatrix": ddeSVGFEColorMatrixElement; - "feComponentTransfer": ddeSVGFEComponentTransferElement; - "feComposite": ddeSVGFECompositeElement; - "feConvolveMatrix": ddeSVGFEConvolveMatrixElement; - "feDiffuseLighting": ddeSVGFEDiffuseLightingElement; - "feDisplacementMap": ddeSVGFEDisplacementMapElement; - "feDistantLight": ddeSVGFEDistantLightElement; - "feDropShadow": ddeSVGFEDropShadowElement; - "feFlood": ddeSVGFEFloodElement; - "feFuncA": ddeSVGFEFuncAElement; - "feFuncB": ddeSVGFEFuncBElement; - "feFuncG": ddeSVGFEFuncGElement; - "feFuncR": ddeSVGFEFuncRElement; - "feGaussianBlur": ddeSVGFEGaussianBlurElement; - "feImage": ddeSVGFEImageElement; - "feMerge": ddeSVGFEMergeElement; - "feMergeNode": ddeSVGFEMergeNodeElement; - "feMorphology": ddeSVGFEMorphologyElement; - "feOffset": ddeSVGFEOffsetElement; - "fePointLight": ddeSVGFEPointLightElement; - "feSpecularLighting": ddeSVGFESpecularLightingElement; - "feSpotLight": ddeSVGFESpotLightElement; - "feTile": ddeSVGFETileElement; - "feTurbulence": ddeSVGFETurbulenceElement; - "filter": ddeSVGFilterElement; - "foreignObject": ddeSVGForeignObjectElement; - "g": ddeSVGGElement; - "image": ddeSVGImageElement; - "line": ddeSVGLineElement; - "linearGradient": ddeSVGLinearGradientElement; - "marker": ddeSVGMarkerElement; - "mask": ddeSVGMaskElement; - "metadata": ddeSVGMetadataElement; - "mpath": ddeSVGMPathElement; - "path": ddeSVGPathElement; - "pattern": ddeSVGPatternElement; - "polygon": ddeSVGPolygonElement; - "polyline": ddeSVGPolylineElement; - "radialGradient": ddeSVGRadialGradientElement; - "rect": ddeSVGRectElement; - "script": ddeSVGScriptElement; - "set": ddeSVGSetElement; - "stop": ddeSVGStopElement; - "style": ddeSVGStyleElement; - "svg": ddeSVGSVGElement; - "switch": ddeSVGSwitchElement; - "symbol": ddeSVGSymbolElement; - "text": ddeSVGTextElement; - "textPath": ddeSVGTextPathElement; - "title": ddeSVGTitleElement; - "tspan": ddeSVGTSpanElement; - "use": ddeSVGUseElement; - "view": ddeSVGViewElement; - } -} - -// editorconfig-checker-disable -interface ddeHTMLAnchorElement extends HTMLAnchorElement{ append: ddeAppend; } -interface ddeHTMLAreaElement extends HTMLAreaElement{ append: ddeAppend; } -interface ddeHTMLAudioElement extends HTMLAudioElement{ append: ddeAppend; } -interface ddeHTMLBaseElement extends HTMLBaseElement{ append: ddeAppend; } -interface ddeHTMLQuoteElement extends HTMLQuoteElement{ append: ddeAppend; } -interface ddeHTMLBodyElement extends HTMLBodyElement{ append: ddeAppend; } -interface ddeHTMLBRElement extends HTMLBRElement{ append: ddeAppend; } -interface ddeHTMLButtonElement extends HTMLButtonElement{ append: ddeAppend; } -interface ddeHTMLCanvasElement extends HTMLCanvasElement{ append: ddeAppend; } -interface ddeHTMLTableCaptionElement extends HTMLTableCaptionElement{ append: ddeAppend; } -interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend; } -interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend; } -interface ddeHTMLDataElement extends HTMLDataElement{ append: ddeAppend; } -interface ddeHTMLDataListElement extends HTMLDataListElement{ append: ddeAppend; } -interface ddeHTMLModElement extends HTMLModElement{ append: ddeAppend; } -interface ddeHTMLDetailsElement extends HTMLDetailsElement{ append: ddeAppend; } -interface ddeHTMLDialogElement extends HTMLDialogElement{ append: ddeAppend; } -interface ddeHTMLDivElement extends HTMLDivElement{ append: ddeAppend; } -interface ddeHTMLDListElement extends HTMLDListElement{ append: ddeAppend; } -interface ddeHTMLEmbedElement extends HTMLEmbedElement{ append: ddeAppend; } -interface ddeHTMLFieldSetElement extends HTMLFieldSetElement{ append: ddeAppend; } -interface ddeHTMLFormElement extends HTMLFormElement{ append: ddeAppend; } -interface ddeHTMLHeadingElement extends HTMLHeadingElement{ append: ddeAppend; } -interface ddeHTMLHeadElement extends HTMLHeadElement{ append: ddeAppend; } -interface ddeHTMLHRElement extends HTMLHRElement{ append: ddeAppend; } -interface ddeHTMLHtmlElement extends HTMLHtmlElement{ append: ddeAppend; } -interface ddeHTMLIFrameElement extends HTMLIFrameElement{ append: ddeAppend; } -interface ddeHTMLImageElement extends HTMLImageElement{ append: ddeAppend; } -interface ddeHTMLInputElement extends HTMLInputElement{ append: ddeAppend; } -interface ddeHTMLLabelElement extends HTMLLabelElement{ append: ddeAppend; } -interface ddeHTMLLegendElement extends HTMLLegendElement{ append: ddeAppend; } -interface ddeHTMLLIElement extends HTMLLIElement{ append: ddeAppend; } -interface ddeHTMLLinkElement extends HTMLLinkElement{ append: ddeAppend; } -interface ddeHTMLMapElement extends HTMLMapElement{ append: ddeAppend; } -interface ddeHTMLMenuElement extends HTMLMenuElement{ append: ddeAppend; } -interface ddeHTMLMetaElement extends HTMLMetaElement{ append: ddeAppend; } -interface ddeHTMLMeterElement extends HTMLMeterElement{ append: ddeAppend; } -interface ddeHTMLObjectElement extends HTMLObjectElement{ append: ddeAppend; } -interface ddeHTMLOListElement extends HTMLOListElement{ append: ddeAppend; } -interface ddeHTMLOptGroupElement extends HTMLOptGroupElement{ append: ddeAppend; } -interface ddeHTMLOptionElement extends HTMLOptionElement{ append: ddeAppend; } -interface ddeHTMLOutputElement extends HTMLOutputElement{ append: ddeAppend; } -interface ddeHTMLParagraphElement extends HTMLParagraphElement{ append: ddeAppend; } -interface ddeHTMLPictureElement extends HTMLPictureElement{ append: ddeAppend; } -interface ddeHTMLPreElement extends HTMLPreElement{ append: ddeAppend; } -interface ddeHTMLProgressElement extends HTMLProgressElement{ append: ddeAppend; } -interface ddeHTMLScriptElement extends HTMLScriptElement{ append: ddeAppend; } -interface ddeHTMLSelectElement extends HTMLSelectElement{ append: ddeAppend; } -interface ddeHTMLSlotElement extends HTMLSlotElement{ append: ddeAppend; } -interface ddeHTMLSourceElement extends HTMLSourceElement{ append: ddeAppend; } -interface ddeHTMLSpanElement extends HTMLSpanElement{ append: ddeAppend; } -interface ddeHTMLStyleElement extends HTMLStyleElement{ append: ddeAppend; } -interface ddeHTMLTableElement extends HTMLTableElement{ append: ddeAppend; } -interface ddeHTMLTableSectionElement extends HTMLTableSectionElement{ append: ddeAppend; } -interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend; } -interface ddeHTMLTemplateElement extends HTMLTemplateElement{ append: ddeAppend; } -interface ddeHTMLTextAreaElement extends HTMLTextAreaElement{ append: ddeAppend; } -interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend; } -interface ddeHTMLTimeElement extends HTMLTimeElement{ append: ddeAppend; } -interface ddeHTMLTitleElement extends HTMLTitleElement{ append: ddeAppend; } -interface ddeHTMLTableRowElement extends HTMLTableRowElement{ append: ddeAppend; } -interface ddeHTMLTrackElement extends HTMLTrackElement{ append: ddeAppend; } -interface ddeHTMLUListElement extends HTMLUListElement{ append: ddeAppend; } -interface ddeHTMLVideoElement extends HTMLVideoElement{ append: ddeAppend; } -interface ddeSVGAElement extends SVGAElement{ append: ddeAppend; } -interface ddeSVGAnimateElement extends SVGAnimateElement{ append: ddeAppend; } -interface ddeSVGAnimateMotionElement extends SVGAnimateMotionElement{ append: ddeAppend; } -interface ddeSVGAnimateTransformElement extends SVGAnimateTransformElement{ append: ddeAppend; } -interface ddeSVGCircleElement extends SVGCircleElement{ append: ddeAppend; } -interface ddeSVGClipPathElement extends SVGClipPathElement{ append: ddeAppend; } -interface ddeSVGDefsElement extends SVGDefsElement{ append: ddeAppend; } -interface ddeSVGDescElement extends SVGDescElement{ append: ddeAppend; } -interface ddeSVGEllipseElement extends SVGEllipseElement{ append: ddeAppend; } -interface ddeSVGFEBlendElement extends SVGFEBlendElement{ append: ddeAppend; } -interface ddeSVGFEColorMatrixElement extends SVGFEColorMatrixElement{ append: ddeAppend; } -interface ddeSVGFEComponentTransferElement extends SVGFEComponentTransferElement{ append: ddeAppend; } -interface ddeSVGFECompositeElement extends SVGFECompositeElement{ append: ddeAppend; } -interface ddeSVGFEConvolveMatrixElement extends SVGFEConvolveMatrixElement{ append: ddeAppend; } -interface ddeSVGFEDiffuseLightingElement extends SVGFEDiffuseLightingElement{ append: ddeAppend; } -interface ddeSVGFEDisplacementMapElement extends SVGFEDisplacementMapElement{ append: ddeAppend; } -interface ddeSVGFEDistantLightElement extends SVGFEDistantLightElement{ append: ddeAppend; } -interface ddeSVGFEDropShadowElement extends SVGFEDropShadowElement{ append: ddeAppend; } -interface ddeSVGFEFloodElement extends SVGFEFloodElement{ append: ddeAppend; } -interface ddeSVGFEFuncAElement extends SVGFEFuncAElement{ append: ddeAppend; } -interface ddeSVGFEFuncBElement extends SVGFEFuncBElement{ append: ddeAppend; } -interface ddeSVGFEFuncGElement extends SVGFEFuncGElement{ append: ddeAppend; } -interface ddeSVGFEFuncRElement extends SVGFEFuncRElement{ append: ddeAppend; } -interface ddeSVGFEGaussianBlurElement extends SVGFEGaussianBlurElement{ append: ddeAppend; } -interface ddeSVGFEImageElement extends SVGFEImageElement{ append: ddeAppend; } -interface ddeSVGFEMergeElement extends SVGFEMergeElement{ append: ddeAppend; } -interface ddeSVGFEMergeNodeElement extends SVGFEMergeNodeElement{ append: ddeAppend; } -interface ddeSVGFEMorphologyElement extends SVGFEMorphologyElement{ append: ddeAppend; } -interface ddeSVGFEOffsetElement extends SVGFEOffsetElement{ append: ddeAppend; } -interface ddeSVGFEPointLightElement extends SVGFEPointLightElement{ append: ddeAppend; } -interface ddeSVGFESpecularLightingElement extends SVGFESpecularLightingElement{ append: ddeAppend; } -interface ddeSVGFESpotLightElement extends SVGFESpotLightElement{ append: ddeAppend; } -interface ddeSVGFETileElement extends SVGFETileElement{ append: ddeAppend; } -interface ddeSVGFETurbulenceElement extends SVGFETurbulenceElement{ append: ddeAppend; } -interface ddeSVGFilterElement extends SVGFilterElement{ append: ddeAppend; } -interface ddeSVGForeignObjectElement extends SVGForeignObjectElement{ append: ddeAppend; } -interface ddeSVGGElement extends SVGGElement{ append: ddeAppend; } -interface ddeSVGImageElement extends SVGImageElement{ append: ddeAppend; } -interface ddeSVGLineElement extends SVGLineElement{ append: ddeAppend; } -interface ddeSVGLinearGradientElement extends SVGLinearGradientElement{ append: ddeAppend; } -interface ddeSVGMarkerElement extends SVGMarkerElement{ append: ddeAppend; } -interface ddeSVGMaskElement extends SVGMaskElement{ append: ddeAppend; } -interface ddeSVGMetadataElement extends SVGMetadataElement{ append: ddeAppend; } -interface ddeSVGMPathElement extends SVGMPathElement{ append: ddeAppend; } -interface ddeSVGPathElement extends SVGPathElement{ append: ddeAppend; } -interface ddeSVGPatternElement extends SVGPatternElement{ append: ddeAppend; } -interface ddeSVGPolygonElement extends SVGPolygonElement{ append: ddeAppend; } -interface ddeSVGPolylineElement extends SVGPolylineElement{ append: ddeAppend; } -interface ddeSVGRadialGradientElement extends SVGRadialGradientElement{ append: ddeAppend; } -interface ddeSVGRectElement extends SVGRectElement{ append: ddeAppend; } -interface ddeSVGScriptElement extends SVGScriptElement{ append: ddeAppend; } -interface ddeSVGSetElement extends SVGSetElement{ append: ddeAppend; } -interface ddeSVGStopElement extends SVGStopElement{ append: ddeAppend; } -interface ddeSVGStyleElement extends SVGStyleElement{ append: ddeAppend; } -interface ddeSVGSVGElement extends SVGSVGElement{ append: ddeAppend; } -interface ddeSVGSwitchElement extends SVGSwitchElement{ append: ddeAppend; } -interface ddeSVGSymbolElement extends SVGSymbolElement{ append: ddeAppend; } -interface ddeSVGTextElement extends SVGTextElement{ append: ddeAppend; } -interface ddeSVGTextPathElement extends SVGTextPathElement{ append: ddeAppend; } -interface ddeSVGTitleElement extends SVGTitleElement{ append: ddeAppend; } -interface ddeSVGTSpanElement extends SVGTSpanElement{ append: ddeAppend; } -interface ddeSVGUseElement extends SVGUseElement{ append: ddeAppend; } -interface ddeSVGViewElement extends SVGViewElement{ append: ddeAppend; } -// editorconfig-checker-enable \ No newline at end of file diff --git a/dist/esm.d.ts b/dist/esm.d.ts index 556e227..f736075 100644 --- a/dist/esm.d.ts +++ b/dist/esm.d.ts @@ -4,7 +4,7 @@ export interface Signal { /** The current value of the signal */ get(): V; /** Set new value of the signal */ - set(value: V): V; + set(value: V, force?: boolean): V; toJSON(): V; valueOf(): V; } @@ -172,17 +172,30 @@ declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options? declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host): (data?: any) => void; export interface On { /** Listens to the DOM event. See {@link Document.addEventListener} */ - = ddeElementAddon>(type: Event, listener: (this: EE extends ddeElementAddon ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE; + (type: Event, listener: (this: EL, ev: DocumentEventMap[Event] & { + target: EL; + }) => any, options?: AddEventListenerOptions): ddeElementAddon; = ddeElementAddon>(type: string, listener: (this: EE extends ddeElementAddon ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; /** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - connected, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent) => any, options?: AddEventListenerOptions): EE; + connected(listener: (this: EL, event: CustomEvent>) => any, options?: AddEventListenerOptions): ddeElementAddon; /** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - disconnected, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent) => any, options?: AddEventListenerOptions): EE; - /** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - attributeChanged, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent<[ - string, - string - ]>) => any, options?: AddEventListenerOptions): EE; + disconnected(listener: (this: EL, event: CustomEvent) => any, options?: AddEventListenerOptions): ddeElementAddon; + /** + * Fires after the next tick of the Javascript event loop. + * This is handy for example to apply some property depending on the element content: + * ```js + * const selected= "Z"; + * //... + * return el("form").append( + * el("select", null, on.defer(e=> e.value=selected)).append( + * el("option", { value: "A", textContent: "A" }), + * //... + * el("option", { value: "Z", textContent: "Z" }), + * ), + * ); + * ``` + * */ + defer(listener: (element: EL) => any): ddeElementAddon; } export const on: On; export type Scope = { diff --git a/dist/esm.js b/dist/esm.js index fd33681..b3a6df8 100644 --- a/dist/esm.js +++ b/dist/esm.js @@ -26,38 +26,7 @@ function onAbort(signal, listener) { }; } -// src/signals-lib/common.js -var signals_global = { - /** - * Checks if a value is a signal - * @param {any} attributes - Value to check - * @returns {boolean} Whether the value is a signal - */ - isSignal(attributes) { - return false; - }, - /** - * Processes an attribute that might be reactive - * @param {Element} obj - Element that owns the attribute - * @param {string} key - Attribute name - * @param {any} attr - Attribute value - * @param {Function} set - Function to set the attribute - * @returns {any} Processed attribute value - */ - processReactiveAttribute(obj, key, attr, set) { - return attr; - } -}; -function registerReactivity(def, global = true) { - if (global) return oAssign(signals_global, def); - Object.setPrototypeOf(def, signals_global); - return def; -} -function signals(_this) { - return isProtoFrom(_this, signals_global) && _this !== signals_global ? _this : signals_global; -} - -// src/dom-common.js +// src/dom-lib/common.js var enviroment = { setDeleteAttr, ssr: "", @@ -83,7 +52,7 @@ var evc = "dde:connected"; var evd = "dde:disconnected"; var eva = "dde:attributeChanged"; -// src/events-observer.js +// src/dom-lib/events-observer.js var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { get() { return () => { @@ -247,7 +216,7 @@ function connectionsChangesObserverConstructor() { } } -// src/events.js +// src/dom-lib/events.js function dispatchEvent(name, options, host) { if (typeof options === "function") { host = options; @@ -269,6 +238,7 @@ function on(event, listener, options) { return element; }; } +on.defer = (fn) => setTimeout.bind(null, fn, 0); var lifeOptions = (obj) => oAssign({}, typeof obj === "object" ? obj : null, { once: true }); on.connected = function(listener, options) { options = lifeOptions(options); @@ -292,10 +262,7 @@ on.disconnected = function(listener, options) { }; }; -// src/dom.js -function queue(promise) { - return enviroment.q(promise); -} +// src/dom-lib/scopes.js var scopes = [{ get scope() { return enviroment.D.body; @@ -370,6 +337,60 @@ var scope = { return scopes.pop(); } }; + +// src/signals-lib/common.js +var signals_global = { + /** + * Checks if a value is a signal + * @param {any} attributes - Value to check + * @returns {boolean} Whether the value is a signal + */ + isSignal(attributes) { + return false; + }, + /** + * Processes an attribute that might be reactive + * @param {Element} obj - Element that owns the attribute + * @param {string} key - Attribute name + * @param {any} attr - Attribute value + * @param {Function} set - Function to set the attribute + * @returns {any} Processed attribute value + */ + processReactiveAttribute(obj, key, attr, set) { + return attr; + } +}; +function registerReactivity(def, global = true) { + if (global) return oAssign(signals_global, def); + Object.setPrototypeOf(def, signals_global); + return def; +} +function signals(_this) { + return isProtoFrom(_this, signals_global) && _this !== signals_global ? _this : signals_global; +} + +// src/dom-lib/helpers.js +function setRemove(obj, prop, key, val) { + return obj[(isUndef(val) ? "remove" : "set") + prop](key, val); +} +function setRemoveNS(obj, prop, key, val, ns = null) { + return obj[(isUndef(val) ? "remove" : "set") + prop + "NS"](ns, key, val); +} +function setDelete(obj, key, val) { + Reflect.set(obj, key, val); + if (!isUndef(val)) return; + return Reflect.deleteProperty(obj, key); +} +function elementAttribute(element, op, key, value) { + if (isInstance(element, enviroment.H)) + return element[op + "Attribute"](key, value); + return element[op + "AttributeNS"](null, key, value); +} + +// src/dom-lib/el.js +function queue(promise) { + return enviroment.q(promise); +} function append(...els) { this.appendOriginal(...els); return this; @@ -385,7 +406,8 @@ function createElement(tag, attributes, ...addons) { const s = signals(this); let scoped = 0; let el, el_host; - if (Object(attributes) !== attributes || s.isSignal(attributes)) + const att_type = typeof attributes; + if (att_type === "string" || att_type === "number" || s.isSignal(attributes)) attributes = { textContent: attributes }; switch (true) { case typeof tag === "function": { @@ -439,38 +461,6 @@ function createElementNS(ns) { return el; }; } -function simulateSlots(element, root = element) { - const mark_e = "\xB9\u2070", mark_s = "\u2713"; - const slots = Object.fromEntries( - Array.from(root.querySelectorAll("slot")).filter((s) => !s.name.endsWith(mark_e)).map((s) => [s.name += mark_e, s]) - ); - element.append = new Proxy(element.append, { - apply(orig, _, els) { - if (els[0] === root) return orig.apply(element, els); - for (const el of els) { - const name = (el.slot || "") + mark_e; - try { - elementAttribute(el, "remove", "slot"); - } catch (_error) { - } - const slot = slots[name]; - if (!slot) return; - if (!slot.name.startsWith(mark_s)) { - slot.childNodes.forEach((c) => c.remove()); - slot.name = mark_s + name; - } - slot.append(el); - } - element.append = orig; - return element; - } - }); - if (element !== root) { - const els = Array.from(element.childNodes); - element.append(...els); - } - return root; -} var assign_context = /* @__PURE__ */ new WeakMap(); var { setDeleteAttr: setDeleteAttr2 } = enviroment; function assign(element, ...attributes) { @@ -533,11 +523,6 @@ function classListDeclarative(element, toggle) { ); return element; } -function elementAttribute(element, op, key, value) { - if (isInstance(element, enviroment.H)) - return element[op + "Attribute"](key, value); - return element[op + "AttributeNS"](null, key, value); -} function isPropSetter(el, key) { if (!(key in el)) return false; const des = getPropDescriptor(el, key); @@ -561,19 +546,40 @@ function forEachEntries(s, target, element, obj, cb) { cb(key, val); }); } -function setRemove(obj, prop, key, val) { - return obj[(isUndef(val) ? "remove" : "set") + prop](key, val); -} -function setRemoveNS(obj, prop, key, val, ns = null) { - return obj[(isUndef(val) ? "remove" : "set") + prop + "NS"](ns, key, val); -} -function setDelete(obj, key, val) { - Reflect.set(obj, key, val); - if (!isUndef(val)) return; - return Reflect.deleteProperty(obj, key); -} -// src/customElement.js +// src/dom-lib/customElement.js +function simulateSlots(element, root = element) { + const mark_e = "\xB9\u2070", mark_s = "\u2713"; + const slots = Object.fromEntries( + Array.from(root.querySelectorAll("slot")).filter((s) => !s.name.endsWith(mark_e)).map((s) => [s.name += mark_e, s]) + ); + element.append = new Proxy(element.append, { + apply(orig, _, els) { + if (els[0] === root) return orig.apply(element, els); + for (const el of els) { + const name = (el.slot || "") + mark_e; + try { + elementAttribute(el, "remove", "slot"); + } catch (_error) { + } + const slot = slots[name]; + if (!slot) return; + if (!slot.name.startsWith(mark_s)) { + slot.childNodes.forEach((c) => c.remove()); + slot.name = mark_s + name; + } + slot.append(el); + } + element.append = orig; + return element; + } + }); + if (element !== root) { + const els = Array.from(element.childNodes); + element.append(...els); + } + return root; +} function customElementRender(target, render, props = {}) { const custom_element = target.host || target; scope.push({ @@ -662,7 +668,6 @@ export { dispatchEvent, createElement as el, createElementNS as elNS, - elementAttribute, lifecyclesToEvents, memo, on, diff --git a/dist/esm.min.d.ts b/dist/esm.min.d.ts index 556e227..f736075 100644 --- a/dist/esm.min.d.ts +++ b/dist/esm.min.d.ts @@ -4,7 +4,7 @@ export interface Signal { /** The current value of the signal */ get(): V; /** Set new value of the signal */ - set(value: V): V; + set(value: V, force?: boolean): V; toJSON(): V; valueOf(): V; } @@ -172,17 +172,30 @@ declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options? declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host): (data?: any) => void; export interface On { /** Listens to the DOM event. See {@link Document.addEventListener} */ - = ddeElementAddon>(type: Event, listener: (this: EE extends ddeElementAddon ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE; + (type: Event, listener: (this: EL, ev: DocumentEventMap[Event] & { + target: EL; + }) => any, options?: AddEventListenerOptions): ddeElementAddon; = ddeElementAddon>(type: string, listener: (this: EE extends ddeElementAddon ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; /** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - connected, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent) => any, options?: AddEventListenerOptions): EE; + connected(listener: (this: EL, event: CustomEvent>) => any, options?: AddEventListenerOptions): ddeElementAddon; /** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - disconnected, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent) => any, options?: AddEventListenerOptions): EE; - /** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - attributeChanged, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent<[ - string, - string - ]>) => any, options?: AddEventListenerOptions): EE; + disconnected(listener: (this: EL, event: CustomEvent) => any, options?: AddEventListenerOptions): ddeElementAddon; + /** + * Fires after the next tick of the Javascript event loop. + * This is handy for example to apply some property depending on the element content: + * ```js + * const selected= "Z"; + * //... + * return el("form").append( + * el("select", null, on.defer(e=> e.value=selected)).append( + * el("option", { value: "A", textContent: "A" }), + * //... + * el("option", { value: "Z", textContent: "Z" }), + * ), + * ); + * ``` + * */ + defer(listener: (element: EL) => any): ddeElementAddon; } export const on: On; export type Scope = { diff --git a/dist/esm.min.js b/dist/esm.min.js index 8ae4fd8..f3aa4a7 100644 --- a/dist/esm.min.js +++ b/dist/esm.min.js @@ -1 +1 @@ -var $=(...t)=>Object.prototype.hasOwnProperty.call(...t);function _(t){return typeof t>"u"}function b(t,e){return t instanceof e}function U(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function D(t=null,e={}){return Object.create(t,e)}function g(...t){return Object.assign(...t)}function j(t,e){if(!t||!b(t,AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}var A={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function Y(t,e=!0){return e?g(A,t):(Object.setPrototypeOf(t,A),t)}function L(t){return U(t,A)&&t!==A?t:A}var a={setDeleteAttr:tt,ssr:"",D:globalThis.document,N:globalThis.Node,F:globalThis.DocumentFragment,H:globalThis.HTMLElement,S:globalThis.SVGElement,M:globalThis.MutationObserver,q:t=>t||Promise.resolve()};function tt(t,e,n){if(Reflect.set(t,e,n),!!_(n)){if(Reflect.deleteProperty(t,e),b(t,a.H)&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var C="__dde_lifecyclesToEvents",v="dde:connected",w="dde:disconnected",H="dde:attributeChanged";var O=a.M?et():new Proxy({},{get(){return()=>{}}});function et(){let t=new Map,e=!1,n=s=>function(u){for(let i of u)if(i.type==="childList"){if(l(i.addedNodes,!0)){s();continue}E(i.removedNodes,!0)&&s()}},r=new a.M(n(f));return{observe(s){let u=new a.M(n(()=>{}));return u.observe(s,{childList:!0,subtree:!0}),()=>u.disconnect()},onConnected(s,u){d();let i=c(s);i.connected.has(u)||(i.connected.add(u),i.length_c+=1)},offConnected(s,u){if(!t.has(s))return;let i=t.get(s);i.connected.has(u)&&(i.connected.delete(u),i.length_c-=1,o(s,i))},onDisconnected(s,u){d();let i=c(s);i.disconnected.has(u)||(i.disconnected.add(u),i.length_d+=1)},offDisconnected(s,u){if(!t.has(s))return;let i=t.get(s);i.disconnected.delete(u),i.length_d-=1,o(s,i)}};function o(s,u){u.length_c||u.length_d||(t.delete(s),f())}function c(s){if(t.has(s))return t.get(s);let u={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(s,u),u}function d(){e||(e=!0,r.observe(a.D.body,{childList:!0,subtree:!0}))}function f(){!e||t.size||(e=!1,r.disconnect())}function p(){return new Promise(function(s){(requestIdleCallback||requestAnimationFrame)(s)})}async function h(s){t.size>30&&await p();let u=[];if(!b(s,a.N))return u;for(let i of t.keys())i===s||!b(i,a.N)||s.contains(i)&&u.push(i);return u}function l(s,u){let i=!1;for(let m of s){if(u&&h(m).then(l),!t.has(m))continue;let y=t.get(m);y.length_c&&(m.dispatchEvent(new Event(v)),y.connected=new WeakSet,y.length_c=0,y.length_d||t.delete(m),i=!0)}return i}function E(s,u){let i=!1;for(let m of s)u&&h(m).then(E),!(!t.has(m)||!t.get(m).length_d)&&((globalThis.queueMicrotask||setTimeout)(X(m)),i=!0);return i}function X(s){return()=>{s.isConnected||(s.dispatchEvent(new Event(w)),t.delete(s))}}}function xt(t,e,n){return typeof e=="function"&&(n=e,e=null),e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let d=c.length?new CustomEvent(t,g({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(d)}}function N(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var z=t=>g({},typeof t=="object"?t:null,{once:!0});N.connected=function(t,e){return e=z(e),function(r){return r.addEventListener(v,t,e),r[C]?r:r.isConnected?(r.dispatchEvent(new Event(v)),r):(j(e.signal,()=>O.offConnected(r,t))&&O.onConnected(r,t),r)}};N.disconnected=function(t,e){return e=z(e),function(r){return r.addEventListener(w,t,e),r[C]||j(e.signal,()=>O.offDisconnected(r,t))&&O.onDisconnected(r,t),r}};function At(t){return a.q(t)}var x=[{get scope(){return a.D.body},host:t=>t?t(a.D.body):a.D.body,prevent:!0}],q=new WeakMap,S={get current(){return x[x.length-1]},get host(){return this.current.host},get signal(){let{host:t}=this;if(q.has(t))return q.get(t);let e=new AbortController;return q.set(t,e),t(N.disconnected(()=>e.abort())),e.signal},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...x]},push(t={}){return x.push(g({},this.current,{prevent:!1},t))},pushRoot(){return x.push(x[0])},pop(){if(x.length!==1)return x.pop()}};function B(...t){return this.appendOriginal(...t),this}function nt(t){return t.append===B||(t.appendOriginal=t.append,t.append=B),t}var T;function k(t,e,...n){let r=L(this),o=0,c,d;switch((Object(e)!==e||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let f=(...l)=>l.length?(o===1?n.unshift(...l):l.forEach(E=>E(d)),void 0):d;S.push({scope:t,host:f}),c=t(e||void 0);let p=b(c,a.F);if(c.nodeName==="#comment")break;let h=k.mark({type:"component",name:t.name,host:p?"this":"parentElement"});c.prepend(h),p&&(d=h);break}case t==="#text":c=R.call(this,a.D.createTextNode(""),e);break;case(t==="<>"||!t):c=R.call(this,a.D.createDocumentFragment(),e);break;case!!T:c=R.call(this,a.D.createElementNS(T,t),e);break;case!c:c=R.call(this,a.D.createElement(t),e)}return nt(c),d||(d=c),n.forEach(f=>f(d)),o&&S.pop(),o=2,c}k.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=a.D.createComment(``);return e&&(r.end=a.D.createComment("")),r};function St(t){let e=this;return function(...r){T=t;let o=k.call(e,...r);return T=void 0,o}}function Dt(t,e=t){let n="\xB9\u2070",r="\u2713",o=Object.fromEntries(Array.from(e.querySelectorAll("slot")).filter(c=>!c.name.endsWith(n)).map(c=>[c.name+=n,c]));if(t.append=new Proxy(t.append,{apply(c,d,f){if(f[0]===e)return c.apply(t,f);for(let p of f){let h=(p.slot||"")+n;try{ot(p,"remove","slot")}catch{}let l=o[h];if(!l)return;l.name.startsWith(r)||(l.childNodes.forEach(E=>E.remove()),l.name=r+h),l.append(p)}return t.append=c,t}}),t!==e){let c=Array.from(t.childNodes);t.append(...c)}return e}var P=new WeakMap,{setDeleteAttr:Z}=a;function R(t,...e){if(!e.length)return t;P.set(t,V(t,this));for(let[n,r]of Object.entries(g({},...e)))J.call(this,t,n,r);return P.delete(t),t}function J(t,e,n){let{setRemoveAttr:r,s:o}=V(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(f,p)=>J.call(c,t,f,p));let[d]=e;if(d==="=")return r(e.slice(1),n);if(d===".")return G(t,e.slice(1),n);if(/(aria|data)([A-Z])/.test(e))return e=e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),r(e,n);switch(e==="className"&&(e="class"),e){case"xlink:href":return r(e,n,"http://www.w3.org/1999/xlink");case"textContent":return Z(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return W(o,e,t,n,G.bind(null,t[e]));case"ariaset":return W(o,e,t,n,(f,p)=>r("aria-"+f,p));case"classList":return rt.call(c,t,n)}return ct(t,e)?Z(t,e,n):r(e,n)}function V(t,e){if(P.has(t))return P.get(t);let r=(b(t,a.S)?it:st).bind(null,t,"Attribute"),o=L(e);return{setRemoveAttr:r,s:o}}function rt(t,e){let n=L(this);return W(n,"classList",t,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function ot(t,e,n,r){return b(t,a.H)?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function ct(t,e){if(!(e in t))return!1;let n=K(t,e);return!_(n.set)}function K(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||K(t,e)}function W(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([f,p]){f&&(f=new c(f),f.target=e,p=t.processReactiveAttribute(n,f,p,o),o(f,p))})}function st(t,e,n,r){return t[(_(r)?"remove":"set")+e](n,r)}function it(t,e,n,r,o=null){return t[(_(r)?"remove":"set")+e+"NS"](o,n,r)}function G(t,e,n){if(Reflect.set(t,e,n),!!_(n))return Reflect.deleteProperty(t,e)}function Pt(t,e,n={}){let r=t.host||t;S.push({scope:r,host:(...d)=>d.length?d.forEach(f=>f(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[C];o||ut(r);let c=e.call(r,n);return o||r.dispatchEvent(new Event(v)),t.nodeType===11&&typeof t.mode=="string"&&r.addEventListener(w,O.observe(t),{once:!0}),S.pop(),t.append(c)}function ut(t){return F(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(v))}),F(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(w)))}),F(t.prototype,"attributeChangedCallback",function(e,n,r){let[o,,c]=r;n.dispatchEvent(new CustomEvent(H,{detail:[o,c]})),e.apply(n,r)}),t.prototype[C]=!0,t}function F(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}var Q="__dde_memo",M=[];function I(t,e){if(!M.length)return e(t);let n=typeof t=="object"?JSON.stringify(t):t,[{cache:r,after:o}]=M;return o(n,$(r,n)?r[n]:e(t))}I.isScope=function(t){return t[Q]};I.scope=function(e,{signal:n,onlyLast:r}={}){let o=D();function c(...d){if(n&&n.aborted)return e.apply(this,d);let f=r?o:D();M.unshift({cache:o,after(h,l){return f[h]=l}});let p=e.apply(this,d);return M.shift(),o=f,p}return c[Q]=!0,c.clear=()=>o=D(),n&&n.addEventListener("abort",c.clear),c};export{R as assign,J as assignAttribute,nt as chainableAppend,rt as classListDeclarative,k as createElement,St as createElementNS,Pt as customElementRender,ut as customElementWithDDE,xt as dispatchEvent,k as el,St as elNS,ot as elementAttribute,ut as lifecyclesToEvents,I as memo,N as on,At as queue,Y as registerReactivity,S as scope,Dt as simulateSlots}; +var H=(...t)=>Object.prototype.hasOwnProperty.call(...t);function x(t){return typeof t>"u"}function h(t,e){return t instanceof e}function z(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function R(t=null,e={}){return Object.create(t,e)}function v(...t){return Object.assign(...t)}function q(t,e){if(!t||!h(t,AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}var f={setDeleteAttr:nt,ssr:"",D:globalThis.document,N:globalThis.Node,F:globalThis.DocumentFragment,H:globalThis.HTMLElement,S:globalThis.SVGElement,M:globalThis.MutationObserver,q:t=>t||Promise.resolve()};function nt(t,e,n){if(Reflect.set(t,e,n),!!x(n)){if(Reflect.deleteProperty(t,e),h(t,f.H)&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var O="__dde_lifecyclesToEvents",E="dde:connected",w="dde:disconnected",B="dde:attributeChanged";var y=f.M?rt():new Proxy({},{get(){return()=>{}}});function rt(){let t=new Map,e=!1,n=s=>function(u){for(let i of u)if(i.type==="childList"){if(l(i.addedNodes,!0)){s();continue}g(i.removedNodes,!0)&&s()}},r=new f.M(n(a));return{observe(s){let u=new f.M(n(()=>{}));return u.observe(s,{childList:!0,subtree:!0}),()=>u.disconnect()},onConnected(s,u){p();let i=c(s);i.connected.has(u)||(i.connected.add(u),i.length_c+=1)},offConnected(s,u){if(!t.has(s))return;let i=t.get(s);i.connected.has(u)&&(i.connected.delete(u),i.length_c-=1,o(s,i))},onDisconnected(s,u){p();let i=c(s);i.disconnected.has(u)||(i.disconnected.add(u),i.length_d+=1)},offDisconnected(s,u){if(!t.has(s))return;let i=t.get(s);i.disconnected.delete(u),i.length_d-=1,o(s,i)}};function o(s,u){u.length_c||u.length_d||(t.delete(s),a())}function c(s){if(t.has(s))return t.get(s);let u={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(s,u),u}function p(){e||(e=!0,r.observe(f.D.body,{childList:!0,subtree:!0}))}function a(){!e||t.size||(e=!1,r.disconnect())}function d(){return new Promise(function(s){(requestIdleCallback||requestAnimationFrame)(s)})}async function m(s){t.size>30&&await d();let u=[];if(!h(s,f.N))return u;for(let i of t.keys())i===s||!h(i,f.N)||s.contains(i)&&u.push(i);return u}function l(s,u){let i=!1;for(let b of s){if(u&&m(b).then(l),!t.has(b))continue;let C=t.get(b);C.length_c&&(b.dispatchEvent(new Event(E)),C.connected=new WeakSet,C.length_c=0,C.length_d||t.delete(b),i=!0)}return i}function g(s,u){let i=!1;for(let b of s)u&&m(b).then(g),!(!t.has(b)||!t.get(b).length_d)&&((globalThis.queueMicrotask||setTimeout)(j(b)),i=!0);return i}function j(s){return()=>{s.isConnected||(s.dispatchEvent(new Event(w)),t.delete(s))}}}function gt(t,e,n){return typeof e=="function"&&(n=e,e=null),e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let p=c.length?new CustomEvent(t,v({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(p)}}function S(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}S.defer=t=>setTimeout.bind(null,t,0);var Z=t=>v({},typeof t=="object"?t:null,{once:!0});S.connected=function(t,e){return e=Z(e),function(r){return r.addEventListener(E,t,e),r[O]?r:r.isConnected?(r.dispatchEvent(new Event(E)),r):(q(e.signal,()=>y.offConnected(r,t))&&y.onConnected(r,t),r)}};S.disconnected=function(t,e){return e=Z(e),function(r){return r.addEventListener(w,t,e),r[O]||q(e.signal,()=>y.offDisconnected(r,t))&&y.onDisconnected(r,t),r}};var _=[{get scope(){return f.D.body},host:t=>t?t(f.D.body):f.D.body,prevent:!0}],W=new WeakMap,A={get current(){return _[_.length-1]},get host(){return this.current.host},get signal(){let{host:t}=this;if(W.has(t))return W.get(t);let e=new AbortController;return W.set(t,e),t(S.disconnected(()=>e.abort())),e.signal},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[..._]},push(t={}){return _.push(v({},this.current,{prevent:!1},t))},pushRoot(){return _.push(_[0])},pop(){if(_.length!==1)return _.pop()}};var D={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function ot(t,e=!0){return e?v(D,t):(Object.setPrototypeOf(t,D),t)}function L(t){return z(t,D)&&t!==D?t:D}function G(t,e,n,r){return t[(x(r)?"remove":"set")+e](n,r)}function J(t,e,n,r,o=null){return t[(x(r)?"remove":"set")+e+"NS"](o,n,r)}function k(t,e,n){if(Reflect.set(t,e,n),!!x(n))return Reflect.deleteProperty(t,e)}function V(t,e,n,r){return h(t,f.H)?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function Tt(t){return f.q(t)}function K(...t){return this.appendOriginal(...t),this}function ct(t){return t.append===K||(t.appendOriginal=t.append,t.append=K),t}var T;function F(t,e,...n){let r=L(this),o=0,c,p,a=typeof e;switch((a==="string"||a==="number"||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let d=(...g)=>g.length?(o===1?n.unshift(...g):g.forEach(j=>j(p)),void 0):p;A.push({scope:t,host:d}),c=t(e||void 0);let m=h(c,f.F);if(c.nodeName==="#comment")break;let l=F.mark({type:"component",name:t.name,host:m?"this":"parentElement"});c.prepend(l),m&&(p=l);break}case t==="#text":c=N.call(this,f.D.createTextNode(""),e);break;case(t==="<>"||!t):c=N.call(this,f.D.createDocumentFragment(),e);break;case!!T:c=N.call(this,f.D.createElementNS(T,t),e);break;case!c:c=N.call(this,f.D.createElement(t),e)}return ct(c),p||(p=c),n.forEach(d=>d(p)),o&&A.pop(),o=2,c}F.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=f.D.createComment(``);return e&&(r.end=f.D.createComment("")),r};function Mt(t){let e=this;return function(...r){T=t;let o=F.call(e,...r);return T=void 0,o}}var P=new WeakMap,{setDeleteAttr:Q}=f;function N(t,...e){if(!e.length)return t;P.set(t,Y(t,this));for(let[n,r]of Object.entries(v({},...e)))X.call(this,t,n,r);return P.delete(t),t}function X(t,e,n){let{setRemoveAttr:r,s:o}=Y(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(a,d)=>X.call(c,t,a,d));let[p]=e;if(p==="=")return r(e.slice(1),n);if(p===".")return k(t,e.slice(1),n);if(/(aria|data)([A-Z])/.test(e))return e=e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),r(e,n);switch(e==="className"&&(e="class"),e){case"xlink:href":return r(e,n,"http://www.w3.org/1999/xlink");case"textContent":return Q(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return I(o,e,t,n,k.bind(null,t[e]));case"ariaset":return I(o,e,t,n,(a,d)=>r("aria-"+a,d));case"classList":return st.call(c,t,n)}return it(t,e)?Q(t,e,n):r(e,n)}function Y(t,e){if(P.has(t))return P.get(t);let r=(h(t,f.S)?J:G).bind(null,t,"Attribute"),o=L(e);return{setRemoveAttr:r,s:o}}function st(t,e){let n=L(this);return I(n,"classList",t,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function it(t,e){if(!(e in t))return!1;let n=tt(t,e);return!x(n.set)}function tt(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||tt(t,e)}function I(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([a,d]){a&&(a=new c(a),a.target=e,d=t.processReactiveAttribute(n,a,d,o),o(a,d))})}function $t(t,e=t){let n="\xB9\u2070",r="\u2713",o=Object.fromEntries(Array.from(e.querySelectorAll("slot")).filter(c=>!c.name.endsWith(n)).map(c=>[c.name+=n,c]));if(t.append=new Proxy(t.append,{apply(c,p,a){if(a[0]===e)return c.apply(t,a);for(let d of a){let m=(d.slot||"")+n;try{V(d,"remove","slot")}catch{}let l=o[m];if(!l)return;l.name.startsWith(r)||(l.childNodes.forEach(g=>g.remove()),l.name=r+m),l.append(d)}return t.append=c,t}}),t!==e){let c=Array.from(t.childNodes);t.append(...c)}return e}function Ht(t,e,n={}){let r=t.host||t;A.push({scope:r,host:(...p)=>p.length?p.forEach(a=>a(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[O];o||ut(r);let c=e.call(r,n);return o||r.dispatchEvent(new Event(E)),t.nodeType===11&&typeof t.mode=="string"&&r.addEventListener(w,y.observe(t),{once:!0}),A.pop(),t.append(c)}function ut(t){return U(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(E))}),U(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(w)))}),U(t.prototype,"attributeChangedCallback",function(e,n,r){let[o,,c]=r;n.dispatchEvent(new CustomEvent(B,{detail:[o,c]})),e.apply(n,r)}),t.prototype[O]=!0,t}function U(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}var et="__dde_memo",M=[];function $(t,e){if(!M.length)return e(t);let n=typeof t=="object"?JSON.stringify(t):t,[{cache:r,after:o}]=M;return o(n,H(r,n)?r[n]:e(t))}$.isScope=function(t){return t[et]};$.scope=function(e,{signal:n,onlyLast:r}={}){let o=R();function c(...p){if(n&&n.aborted)return e.apply(this,p);let a=r?o:R();M.unshift({cache:o,after(m,l){return a[m]=l}});let d=e.apply(this,p);return M.shift(),o=a,d}return c[et]=!0,c.clear=()=>o=R(),n&&n.addEventListener("abort",c.clear),c};export{N as assign,X as assignAttribute,ct as chainableAppend,st as classListDeclarative,F as createElement,Mt as createElementNS,Ht as customElementRender,ut as customElementWithDDE,gt as dispatchEvent,F as el,Mt as elNS,ut as lifecyclesToEvents,$ as memo,S as on,Tt as queue,ot as registerReactivity,A as scope,$t as simulateSlots}; diff --git a/dist/iife-with-signals.d.ts b/dist/iife-with-signals.d.ts index ec30620..61211f3 100644 --- a/dist/iife-with-signals.d.ts +++ b/dist/iife-with-signals.d.ts @@ -4,7 +4,7 @@ export interface Signal { /** The current value of the signal */ get(): V; /** Set new value of the signal */ - set(value: V): V; + set(value: V, force?: boolean): V; toJSON(): V; valueOf(): V; } @@ -173,17 +173,30 @@ declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options? declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host): (data?: any) => void; export interface On { /** Listens to the DOM event. See {@link Document.addEventListener} */ - = ddeElementAddon>(type: Event, listener: (this: EE extends ddeElementAddon ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE; + (type: Event, listener: (this: EL, ev: DocumentEventMap[Event] & { + target: EL; + }) => any, options?: AddEventListenerOptions): ddeElementAddon; = ddeElementAddon>(type: string, listener: (this: EE extends ddeElementAddon ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; /** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - connected, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent) => any, options?: AddEventListenerOptions): EE; + connected(listener: (this: EL, event: CustomEvent>) => any, options?: AddEventListenerOptions): ddeElementAddon; /** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - disconnected, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent) => any, options?: AddEventListenerOptions): EE; - /** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - attributeChanged, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent<[ - string, - string - ]>) => any, options?: AddEventListenerOptions): EE; + disconnected(listener: (this: EL, event: CustomEvent) => any, options?: AddEventListenerOptions): ddeElementAddon; + /** + * Fires after the next tick of the Javascript event loop. + * This is handy for example to apply some property depending on the element content: + * ```js + * const selected= "Z"; + * //... + * return el("form").append( + * el("select", null, on.defer(e=> e.value=selected)).append( + * el("option", { value: "A", textContent: "A" }), + * //... + * el("option", { value: "Z", textContent: "Z" }), + * ), + * ); + * ``` + * */ + defer(listener: (element: EL) => any): ddeElementAddon; } export const on: On; export type Scope = { diff --git a/dist/iife-with-signals.js b/dist/iife-with-signals.js index c77ab02..3aca9c7 100644 --- a/dist/iife-with-signals.js +++ b/dist/iife-with-signals.js @@ -32,7 +32,6 @@ var DDE = (() => { dispatchEvent: () => dispatchEvent, el: () => createElement, elNS: () => createElementNS, - elementAttribute: () => elementAttribute, isSignal: () => isSignal, lifecyclesToEvents: () => lifecyclesToEvents, memo: () => memo, @@ -101,38 +100,7 @@ var DDE = (() => { } }; - // src/signals-lib/common.js - var signals_global = { - /** - * Checks if a value is a signal - * @param {any} attributes - Value to check - * @returns {boolean} Whether the value is a signal - */ - isSignal(attributes) { - return false; - }, - /** - * Processes an attribute that might be reactive - * @param {Element} obj - Element that owns the attribute - * @param {string} key - Attribute name - * @param {any} attr - Attribute value - * @param {Function} set - Function to set the attribute - * @returns {any} Processed attribute value - */ - processReactiveAttribute(obj, key, attr, set) { - return attr; - } - }; - function registerReactivity(def, global = true) { - if (global) return oAssign(signals_global, def); - Object.setPrototypeOf(def, signals_global); - return def; - } - function signals(_this) { - return isProtoFrom(_this, signals_global) && _this !== signals_global ? _this : signals_global; - } - - // src/dom-common.js + // src/dom-lib/common.js var enviroment = { setDeleteAttr, ssr: "", @@ -158,7 +126,7 @@ var DDE = (() => { var evd = "dde:disconnected"; var eva = "dde:attributeChanged"; - // src/events-observer.js + // src/dom-lib/events-observer.js var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { get() { return () => { @@ -322,7 +290,7 @@ var DDE = (() => { } } - // src/events.js + // src/dom-lib/events.js function dispatchEvent(name, options, host) { if (typeof options === "function") { host = options; @@ -344,6 +312,7 @@ var DDE = (() => { return element; }; } + on.defer = (fn) => setTimeout.bind(null, fn, 0); var lifeOptions = (obj) => oAssign({}, typeof obj === "object" ? obj : null, { once: true }); on.connected = function(listener, options) { options = lifeOptions(options); @@ -367,10 +336,7 @@ var DDE = (() => { }; }; - // src/dom.js - function queue(promise) { - return enviroment.q(promise); - } + // src/dom-lib/scopes.js var scopes = [{ get scope() { return enviroment.D.body; @@ -445,6 +411,60 @@ var DDE = (() => { return scopes.pop(); } }; + + // src/signals-lib/common.js + var signals_global = { + /** + * Checks if a value is a signal + * @param {any} attributes - Value to check + * @returns {boolean} Whether the value is a signal + */ + isSignal(attributes) { + return false; + }, + /** + * Processes an attribute that might be reactive + * @param {Element} obj - Element that owns the attribute + * @param {string} key - Attribute name + * @param {any} attr - Attribute value + * @param {Function} set - Function to set the attribute + * @returns {any} Processed attribute value + */ + processReactiveAttribute(obj, key, attr, set) { + return attr; + } + }; + function registerReactivity(def, global = true) { + if (global) return oAssign(signals_global, def); + Object.setPrototypeOf(def, signals_global); + return def; + } + function signals(_this) { + return isProtoFrom(_this, signals_global) && _this !== signals_global ? _this : signals_global; + } + + // src/dom-lib/helpers.js + function setRemove(obj, prop, key, val) { + return obj[(isUndef(val) ? "remove" : "set") + prop](key, val); + } + function setRemoveNS(obj, prop, key, val, ns = null) { + return obj[(isUndef(val) ? "remove" : "set") + prop + "NS"](ns, key, val); + } + function setDelete(obj, key, val) { + Reflect.set(obj, key, val); + if (!isUndef(val)) return; + return Reflect.deleteProperty(obj, key); + } + function elementAttribute(element, op, key, value) { + if (isInstance(element, enviroment.H)) + return element[op + "Attribute"](key, value); + return element[op + "AttributeNS"](null, key, value); + } + + // src/dom-lib/el.js + function queue(promise) { + return enviroment.q(promise); + } function append(...els) { this.appendOriginal(...els); return this; @@ -460,7 +480,8 @@ var DDE = (() => { const s = signals(this); let scoped = 0; let el, el_host; - if (Object(attributes) !== attributes || s.isSignal(attributes)) + const att_type = typeof attributes; + if (att_type === "string" || att_type === "number" || s.isSignal(attributes)) attributes = { textContent: attributes }; switch (true) { case typeof tag === "function": { @@ -514,38 +535,6 @@ var DDE = (() => { return el; }; } - function simulateSlots(element, root = element) { - const mark_e = "\xB9\u2070", mark_s = "\u2713"; - const slots = Object.fromEntries( - Array.from(root.querySelectorAll("slot")).filter((s) => !s.name.endsWith(mark_e)).map((s) => [s.name += mark_e, s]) - ); - element.append = new Proxy(element.append, { - apply(orig, _, els) { - if (els[0] === root) return orig.apply(element, els); - for (const el of els) { - const name = (el.slot || "") + mark_e; - try { - elementAttribute(el, "remove", "slot"); - } catch (_error) { - } - const slot = slots[name]; - if (!slot) return; - if (!slot.name.startsWith(mark_s)) { - slot.childNodes.forEach((c) => c.remove()); - slot.name = mark_s + name; - } - slot.append(el); - } - element.append = orig; - return element; - } - }); - if (element !== root) { - const els = Array.from(element.childNodes); - element.append(...els); - } - return root; - } var assign_context = /* @__PURE__ */ new WeakMap(); var { setDeleteAttr: setDeleteAttr2 } = enviroment; function assign(element, ...attributes) { @@ -608,11 +597,6 @@ var DDE = (() => { ); return element; } - function elementAttribute(element, op, key, value) { - if (isInstance(element, enviroment.H)) - return element[op + "Attribute"](key, value); - return element[op + "AttributeNS"](null, key, value); - } function isPropSetter(el, key) { if (!(key in el)) return false; const des = getPropDescriptor(el, key); @@ -636,19 +620,40 @@ var DDE = (() => { cb(key, val); }); } - function setRemove(obj, prop, key, val) { - return obj[(isUndef(val) ? "remove" : "set") + prop](key, val); - } - function setRemoveNS(obj, prop, key, val, ns = null) { - return obj[(isUndef(val) ? "remove" : "set") + prop + "NS"](ns, key, val); - } - function setDelete(obj, key, val) { - Reflect.set(obj, key, val); - if (!isUndef(val)) return; - return Reflect.deleteProperty(obj, key); - } - // src/customElement.js + // src/dom-lib/customElement.js + function simulateSlots(element, root = element) { + const mark_e = "\xB9\u2070", mark_s = "\u2713"; + const slots = Object.fromEntries( + Array.from(root.querySelectorAll("slot")).filter((s) => !s.name.endsWith(mark_e)).map((s) => [s.name += mark_e, s]) + ); + element.append = new Proxy(element.append, { + apply(orig, _, els) { + if (els[0] === root) return orig.apply(element, els); + for (const el of els) { + const name = (el.slot || "") + mark_e; + try { + elementAttribute(el, "remove", "slot"); + } catch (_error) { + } + const slot = slots[name]; + if (!slot) return; + if (!slot.name.startsWith(mark_s)) { + slot.childNodes.forEach((c) => c.remove()); + slot.name = mark_s + name; + } + slot.append(el); + } + element.append = orig; + return element; + } + }); + if (element !== root) { + const els = Array.from(element.childNodes); + element.append(...els); + } + return root; + } function customElementRender(target, render, props = {}) { const custom_element = target.host || target; scope.push({ @@ -729,19 +734,19 @@ var DDE = (() => { // src/signals-lib/helpers.js var mark = "__dde_signal"; var queueSignalWrite = /* @__PURE__ */ (() => { - let pendingSignals = /* @__PURE__ */ new Set(); + let pendingSignals = /* @__PURE__ */ new Map(); let scheduled = false; function flushSignals() { scheduled = false; const todo = pendingSignals; - pendingSignals = /* @__PURE__ */ new Set(); - for (const signal2 of todo) { + pendingSignals = /* @__PURE__ */ new Map(); + for (const [signal2, force] of todo) { const M = signal2[mark]; - if (M) M.listeners.forEach((l) => l(M.value)); + if (M) M.listeners.forEach((l) => l(M.value, force)); } } - return function(s) { - pendingSignals.add(s); + return function(s, force = false) { + pendingSignals.set(s, pendingSignals.get(s) || force); if (scheduled) return; scheduled = true; queueMicrotask(flushSignals); @@ -778,11 +783,11 @@ var DDE = (() => { return create(false, value, actions); if (isSignal(value)) return value; const out = create(true); - function contextReWatch() { + function contextReWatch(_, force) { const [origin, ...deps_old] = deps.get(contextReWatch); deps.set(contextReWatch, /* @__PURE__ */ new Set([origin])); stack_watch.push(contextReWatch); - write(out, value()); + write(out, value(), force); stack_watch.pop(); if (!deps_old.length) return; const deps_curr = deps.get(contextReWatch); @@ -804,7 +809,7 @@ var DDE = (() => { throw new Error(`Action "${name}" not defined. See ${mark}.actions.`); actions[name].apply(M, a); if (M.skip) return delete M.skip; - queueSignalWrite(s); + queueSignalWrite(s, true); }; signal.on = function on2(s, listener, options = {}) { const { signal: as } = options; @@ -1013,7 +1018,7 @@ var DDE = (() => { const M = s[mark]; if (!M || !force && M.value === value) return; M.value = value; - queueSignalWrite(s); + queueSignalWrite(s, force); return value; } function addSignalListener(s, listener) { diff --git a/dist/iife-with-signals.min.d.ts b/dist/iife-with-signals.min.d.ts index ec30620..61211f3 100644 --- a/dist/iife-with-signals.min.d.ts +++ b/dist/iife-with-signals.min.d.ts @@ -4,7 +4,7 @@ export interface Signal { /** The current value of the signal */ get(): V; /** Set new value of the signal */ - set(value: V): V; + set(value: V, force?: boolean): V; toJSON(): V; valueOf(): V; } @@ -173,17 +173,30 @@ declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options? declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host): (data?: any) => void; export interface On { /** Listens to the DOM event. See {@link Document.addEventListener} */ - = ddeElementAddon>(type: Event, listener: (this: EE extends ddeElementAddon ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE; + (type: Event, listener: (this: EL, ev: DocumentEventMap[Event] & { + target: EL; + }) => any, options?: AddEventListenerOptions): ddeElementAddon; = ddeElementAddon>(type: string, listener: (this: EE extends ddeElementAddon ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; /** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - connected, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent) => any, options?: AddEventListenerOptions): EE; + connected(listener: (this: EL, event: CustomEvent>) => any, options?: AddEventListenerOptions): ddeElementAddon; /** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - disconnected, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent) => any, options?: AddEventListenerOptions): EE; - /** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - attributeChanged, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent<[ - string, - string - ]>) => any, options?: AddEventListenerOptions): EE; + disconnected(listener: (this: EL, event: CustomEvent) => any, options?: AddEventListenerOptions): ddeElementAddon; + /** + * Fires after the next tick of the Javascript event loop. + * This is handy for example to apply some property depending on the element content: + * ```js + * const selected= "Z"; + * //... + * return el("form").append( + * el("select", null, on.defer(e=> e.value=selected)).append( + * el("option", { value: "A", textContent: "A" }), + * //... + * el("option", { value: "Z", textContent: "Z" }), + * ), + * ); + * ``` + * */ + defer(listener: (element: EL) => any): ddeElementAddon; } export const on: On; export type Scope = { diff --git a/dist/iife-with-signals.min.js b/dist/iife-with-signals.min.js index 89e4a86..c73e3bf 100644 --- a/dist/iife-with-signals.min.js +++ b/dist/iife-with-signals.min.js @@ -1,4 +1,4 @@ -var DDE=(()=>{var G=Object.defineProperty;var At=Object.getOwnPropertyDescriptor;var Ot=Object.getOwnPropertyNames;var Ct=Object.prototype.hasOwnProperty;var Dt=(t,e)=>{for(var n in e)G(t,n,{get:e[n],enumerable:!0})},Rt=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Ot(e))!Ct.call(t,o)&&o!==n&&G(t,o,{get:()=>e[o],enumerable:!(r=At(e,o))||r.enumerable});return t};var Lt=t=>Rt(G({},"__esModule",{value:!0}),t);var Vt={};Dt(Vt,{S:()=>m,assign:()=>W,assignAttribute:()=>X,chainableAppend:()=>dt,classListDeclarative:()=>pt,createElement:()=>M,createElementNS:()=>jt,customElementRender:()=>$t,customElementWithDDE:()=>mt,dispatchEvent:()=>Mt,el:()=>M,elNS:()=>jt,elementAttribute:()=>ht,isSignal:()=>F,lifecyclesToEvents:()=>mt,memo:()=>L,on:()=>w,queue:()=>Pt,registerReactivity:()=>$,scope:()=>b,signal:()=>m,simulateSlots:()=>qt});var I=(...t)=>Object.prototype.hasOwnProperty.call(...t);function C(t){return typeof t>"u"}function ot(t){let e=typeof t;return e!=="object"?e:t===null?"null":Object.prototype.toString.call(t)}function S(t,e){return t instanceof e}function ct(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function x(t=null,e={}){return Object.create(t,e)}function E(...t){return Object.assign(...t)}function V(t,e){if(!t||!S(t,AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}function st(t,e){let{observedAttributes:n=[]}=t.constructor;return n.reduce(function(r,o){return r[Nt(o)]=e(t,o),r},{})}function Nt(t){return t.replace(/-./g,e=>e[1].toUpperCase())}var j=class extends Error{constructor(){super();let[e,...n]=this.stack.split(` -`),r=e.slice(e.indexOf("@"),e.indexOf(".js:")+4),o=r.includes("src/helpers.js")?"src/":r;this.stack=n.find(c=>!c.includes(o))||e}get compact(){let{stack:e}=this;return e.slice(0,e.indexOf("@")+1)+"\u2026"+e.slice(e.lastIndexOf("/"))}};var q={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function $(t,e=!0){return e?E(q,t):(Object.setPrototypeOf(t,q),t)}function U(t){return ct(t,q)&&t!==q?t:q}var l={setDeleteAttr:kt,ssr:"",D:globalThis.document,N:globalThis.Node,F:globalThis.DocumentFragment,H:globalThis.HTMLElement,S:globalThis.SVGElement,M:globalThis.MutationObserver,q:t=>t||Promise.resolve()};function kt(t,e,n){if(Reflect.set(t,e,n),!!C(n)){if(Reflect.deleteProperty(t,e),S(t,l.H)&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var T="__dde_lifecyclesToEvents",y="dde:connected",D="dde:disconnected",z="dde:attributeChanged";var R=l.M?Tt():new Proxy({},{get(){return()=>{}}});function Tt(){let t=new Map,e=!1,n=u=>function(a){for(let f of a)if(f.type==="childList"){if(h(f.addedNodes,!0)){u();continue}O(f.removedNodes,!0)&&u()}},r=new l.M(n(i));return{observe(u){let a=new l.M(n(()=>{}));return a.observe(u,{childList:!0,subtree:!0}),()=>a.disconnect()},onConnected(u,a){s();let f=c(u);f.connected.has(a)||(f.connected.add(a),f.length_c+=1)},offConnected(u,a){if(!t.has(u))return;let f=t.get(u);f.connected.has(a)&&(f.connected.delete(a),f.length_c-=1,o(u,f))},onDisconnected(u,a){s();let f=c(u);f.disconnected.has(a)||(f.disconnected.add(a),f.length_d+=1)},offDisconnected(u,a){if(!t.has(u))return;let f=t.get(u);f.disconnected.delete(a),f.length_d-=1,o(u,f)}};function o(u,a){a.length_c||a.length_d||(t.delete(u),i())}function c(u){if(t.has(u))return t.get(u);let a={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(u,a),a}function s(){e||(e=!0,r.observe(l.D.body,{childList:!0,subtree:!0}))}function i(){!e||t.size||(e=!1,r.disconnect())}function d(){return new Promise(function(u){(requestIdleCallback||requestAnimationFrame)(u)})}async function g(u){t.size>30&&await d();let a=[];if(!S(u,l.N))return a;for(let f of t.keys())f===u||!S(f,l.N)||u.contains(f)&&a.push(f);return a}function h(u,a){let f=!1;for(let _ of u){if(a&&g(_).then(h),!t.has(_))continue;let P=t.get(_);P.length_c&&(_.dispatchEvent(new Event(y)),P.connected=new WeakSet,P.length_c=0,P.length_d||t.delete(_),f=!0)}return f}function O(u,a){let f=!1;for(let _ of u)a&&g(_).then(O),!(!t.has(_)||!t.get(_).length_d)&&((globalThis.queueMicrotask||setTimeout)(yt(_)),f=!0);return f}function yt(u){return()=>{u.isConnected||(u.dispatchEvent(new Event(D)),t.delete(u))}}}function Mt(t,e,n){return typeof e=="function"&&(n=e,e=null),e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let s=c.length?new CustomEvent(t,E({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(s)}}function w(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var it=t=>E({},typeof t=="object"?t:null,{once:!0});w.connected=function(t,e){return e=it(e),function(r){return r.addEventListener(y,t,e),r[T]?r:r.isConnected?(r.dispatchEvent(new Event(y)),r):(V(e.signal,()=>R.offConnected(r,t))&&R.onConnected(r,t),r)}};w.disconnected=function(t,e){return e=it(e),function(r){return r.addEventListener(D,t,e),r[T]||V(e.signal,()=>R.offDisconnected(r,t))&&R.onDisconnected(r,t),r}};function Pt(t){return l.q(t)}var A=[{get scope(){return l.D.body},host:t=>t?t(l.D.body):l.D.body,prevent:!0}],K=new WeakMap,b={get current(){return A[A.length-1]},get host(){return this.current.host},get signal(){let{host:t}=this;if(K.has(t))return K.get(t);let e=new AbortController;return K.set(t,e),t(w.disconnected(()=>e.abort())),e.signal},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...A]},push(t={}){return A.push(E({},this.current,{prevent:!1},t))},pushRoot(){return A.push(A[0])},pop(){if(A.length!==1)return A.pop()}};function ut(...t){return this.appendOriginal(...t),this}function dt(t){return t.append===ut||(t.appendOriginal=t.append,t.append=ut),t}var H;function M(t,e,...n){let r=U(this),o=0,c,s;switch((Object(e)!==e||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let i=(...h)=>h.length?(o===1?n.unshift(...h):h.forEach(O=>O(s)),void 0):s;b.push({scope:t,host:i}),c=t(e||void 0);let d=S(c,l.F);if(c.nodeName==="#comment")break;let g=M.mark({type:"component",name:t.name,host:d?"this":"parentElement"});c.prepend(g),d&&(s=g);break}case t==="#text":c=W.call(this,l.D.createTextNode(""),e);break;case(t==="<>"||!t):c=W.call(this,l.D.createDocumentFragment(),e);break;case!!H:c=W.call(this,l.D.createElementNS(H,t),e);break;case!c:c=W.call(this,l.D.createElement(t),e)}return dt(c),s||(s=c),n.forEach(i=>i(s)),o&&b.pop(),o=2,c}M.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=l.D.createComment(``);return e&&(r.end=l.D.createComment("")),r};function jt(t){let e=this;return function(...r){H=t;let o=M.call(e,...r);return H=void 0,o}}function qt(t,e=t){let n="\xB9\u2070",r="\u2713",o=Object.fromEntries(Array.from(e.querySelectorAll("slot")).filter(c=>!c.name.endsWith(n)).map(c=>[c.name+=n,c]));if(t.append=new Proxy(t.append,{apply(c,s,i){if(i[0]===e)return c.apply(t,i);for(let d of i){let g=(d.slot||"")+n;try{ht(d,"remove","slot")}catch{}let h=o[g];if(!h)return;h.name.startsWith(r)||(h.childNodes.forEach(O=>O.remove()),h.name=r+g),h.append(d)}return t.append=c,t}}),t!==e){let c=Array.from(t.childNodes);t.append(...c)}return e}var J=new WeakMap,{setDeleteAttr:ft}=l;function W(t,...e){if(!e.length)return t;J.set(t,lt(t,this));for(let[n,r]of Object.entries(E({},...e)))X.call(this,t,n,r);return J.delete(t),t}function X(t,e,n){let{setRemoveAttr:r,s:o}=lt(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(i,d)=>X.call(c,t,i,d));let[s]=e;if(s==="=")return r(e.slice(1),n);if(s===".")return at(t,e.slice(1),n);if(/(aria|data)([A-Z])/.test(e))return e=e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),r(e,n);switch(e==="className"&&(e="class"),e){case"xlink:href":return r(e,n,"http://www.w3.org/1999/xlink");case"textContent":return ft(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return Q(o,e,t,n,at.bind(null,t[e]));case"ariaset":return Q(o,e,t,n,(i,d)=>r("aria-"+i,d));case"classList":return pt.call(c,t,n)}return Wt(t,e)?ft(t,e,n):r(e,n)}function lt(t,e){if(J.has(t))return J.get(t);let r=(S(t,l.S)?It:Ft).bind(null,t,"Attribute"),o=U(e);return{setRemoveAttr:r,s:o}}function pt(t,e){let n=U(this);return Q(n,"classList",t,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function ht(t,e,n,r){return S(t,l.H)?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function Wt(t,e){if(!(e in t))return!1;let n=gt(t,e);return!C(n.set)}function gt(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||gt(t,e)}function Q(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([i,d]){i&&(i=new c(i),i.target=e,d=t.processReactiveAttribute(n,i,d,o),o(i,d))})}function Ft(t,e,n,r){return t[(C(r)?"remove":"set")+e](n,r)}function It(t,e,n,r,o=null){return t[(C(r)?"remove":"set")+e+"NS"](o,n,r)}function at(t,e,n){if(Reflect.set(t,e,n),!!C(n))return Reflect.deleteProperty(t,e)}function $t(t,e,n={}){let r=t.host||t;b.push({scope:r,host:(...s)=>s.length?s.forEach(i=>i(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[T];o||mt(r);let c=e.call(r,n);return o||r.dispatchEvent(new Event(y)),t.nodeType===11&&typeof t.mode=="string"&&r.addEventListener(D,R.observe(t),{once:!0}),b.pop(),t.append(c)}function mt(t){return Y(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(y))}),Y(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(D)))}),Y(t.prototype,"attributeChangedCallback",function(e,n,r){let[o,,c]=r;n.dispatchEvent(new CustomEvent(z,{detail:[o,c]})),e.apply(n,r)}),t.prototype[T]=!0,t}function Y(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}var bt="__dde_memo",B=[];function L(t,e){if(!B.length)return e(t);let n=typeof t=="object"?JSON.stringify(t):t,[{cache:r,after:o}]=B;return o(n,I(r,n)?r[n]:e(t))}L.isScope=function(t){return t[bt]};L.scope=function(e,{signal:n,onlyLast:r}={}){let o=x();function c(...s){if(n&&n.aborted)return e.apply(this,s);let i=r?o:x();B.unshift({cache:o,after(g,h){return i[g]=h}});let d=e.apply(this,s);return B.shift(),o=i,d}return c[bt]=!0,c.clear=()=>o=x(),n&&n.addEventListener("abort",c.clear),c};var p="__dde_signal",tt=(()=>{let t=new Set,e=!1;function n(){e=!1;let r=t;t=new Set;for(let o of r){let c=o[p];c&&c.listeners.forEach(s=>s(c.value))}}return function(r){t.add(r),!e&&(e=!0,queueMicrotask(n))}})();var nt=x(null,{get:{value(){return xt(this)}},set:{value(...t){return wt(this,...t)}},toJSON:{value(){return xt(this)}},valueOf:{value(){return this[p]&&this[p].value}}}),Ut=x(nt,{set:{value(){}}});function F(t){return t&&t[p]}var Z=[],v=new WeakMap;function m(t,e){if(typeof t!="function")return vt(!1,t,e);if(F(t))return t;let n=vt(!0);function r(){let[o,...c]=v.get(r);if(v.set(r,new Set([o])),Z.push(r),wt(n,t()),Z.pop(),!c.length)return;let s=v.get(r);for(let i of c)s.has(i)||k(i,r)}return v.set(n[p],r),v.set(r,new Set([n])),r(),n}m.action=function(t,e,...n){let r=t[p];if(!r)return;let{actions:o}=r;if(!o||!I(o,e))throw new Error(`Action "${e}" not defined. See ${p}.actions.`);if(o[e].apply(r,n),r.skip)return delete r.skip;tt(t)};m.on=function t(e,n,r={}){let{signal:o}=r;if(!(o&&o.aborted)){if(Array.isArray(e))return e.forEach(c=>t(c,n,r));rt(e,n),o&&o.addEventListener("abort",()=>k(e,n))}};m.symbols={onclear:Symbol.for("Signal.onclear")};m.clear=function(...t){for(let n of t){let r=n[p];r&&(delete n.toJSON,r.onclear.forEach(o=>o.call(r)),e(n,r),delete n[p])}function e(n,r){r.listeners.forEach(o=>{if(r.listeners.delete(o),!v.has(o))return;let c=v.get(o);c.delete(n),!(c.size>1)&&(n.clear(...c),v.delete(o))})}};var N="__dde_reactive";m.el=function(t,e){e=L.isScope(e)?e:L.scope(e,{onlyLast:!0});let n=M.mark({type:"reactive",source:new j().compact},!0),r=n.end,o=l.D.createDocumentFragment();o.append(n,r);let{current:c}=b,s=i=>{if(!n.parentNode||!r.parentNode)return k(t,s);b.push(c);let d=e(i);b.pop(),Array.isArray(d)||(d=[d]);let g=document.createComment("");d.push(g),n.after(...d);let h;for(;(h=g.nextSibling)&&h!==r;)h.remove();g.remove(),n.isConnected&&zt(c.host())};return rt(t,s),_t(t,s,n,e),s(t.get()),c.host(w.disconnected(()=>e.clear())),o};function zt(t){!t||!t[N]||(requestIdleCallback||setTimeout)(function(){t[N]=t[N].filter(([e,n])=>n.isConnected?!0:(k(...e),!1))})}var Ht={_set(t){this.value=t}};function Jt(t){return function(e,n){let r=x(nt,{set:{value(...c){return e.setAttribute(n,...c)}}}),o=St(r,e.getAttribute(n),Ht);return t[n]=o,o}}var et="__dde_attributes";m.observedAttributes=function(t){let e=t[et]={},n=st(t,Jt(e));return w(z,function({detail:o}){/*! This maps attributes to signals (`S.observedAttributes`). - Investigate `__dde_attributes` key of the element. */let[c,s]=o,i=this[et][c];if(i)return m.action(i,"_set",s)})(t),w.disconnected(function(){/*! This removes all signals mapped to attributes (`S.observedAttributes`). - Investigate `__dde_attributes` key of the element. */m.clear(...Object.values(this[et]))})(t),n};var Et={isSignal:F,processReactiveAttribute(t,e,n,r){if(!F(n))return n;let o=c=>{if(!t.isConnected)return k(n,o);r(e,c)};return rt(n,o),_t(n,o,t,e),n.get()}};function _t(t,e,...n){let{current:r}=b;r.host(function(o){if(o[N])return o[N].push([[t,e],...n]);o[N]=[],!r.prevent&&w.disconnected(()=>o[N].forEach(([[c,s]])=>k(c,s,c[p]&&c[p].host&&c[p].host()===o)))(o)})}var Bt=new FinalizationRegistry(function(t){m.clear({[p]:t})});function vt(t,e,n){let r=x(t?Ut:nt),o=St(r,e,n,t);return Bt.register(o,o[p]),o}var Zt=E(x(),{stopPropagation(){this.skip=!0}});function St(t,e,n,r=!1){let o=[];ot(n)!=="[object Object]"&&(n={});let{onclear:c}=m.symbols;n[c]&&(o.push(n[c]),delete n[c]);let{host:s}=b;return Reflect.defineProperty(t,p,{value:E(x(Zt),{value:e,actions:n,onclear:o,host:s,listeners:new Set,defined:new j().stack,readonly:r}),enumerable:!1,writable:!1,configurable:!0}),t}function Gt(){return Z[Z.length-1]}function xt(t){if(!t[p])return;let{value:e,listeners:n}=t[p],r=Gt();return r&&n.add(r),v.has(r)&&v.get(r).add(t),e}function wt(t,e,n){let r=t[p];if(!(!r||!n&&r.value===e))return r.value=e,tt(t),e}function rt(t,e){if(t[p])return t[p].listeners.add(e)}function k(t,e,n){let r=t[p];if(!r)return;let{listeners:o}=r,c=o.delete(e);if(!c||!n||o.size)return c;m.clear(t);let s=v.get(r);if(!s)return c;let i=v.get(s);if(!i)return c;for(let d of i)k(d,s,!0);return c}$(Et);return Lt(Vt);})(); +var DDE=(()=>{var V=Object.defineProperty;var Ot=Object.getOwnPropertyDescriptor;var Rt=Object.getOwnPropertyNames;var Dt=Object.prototype.hasOwnProperty;var Lt=(t,e)=>{for(var n in e)V(t,n,{get:e[n],enumerable:!0})},Nt=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Rt(e))!Dt.call(t,o)&&o!==n&&V(t,o,{get:()=>e[o],enumerable:!(r=Ot(e,o))||r.enumerable});return t};var kt=t=>Nt(V({},"__esModule",{value:!0}),t);var Vt={};Lt(Vt,{S:()=>g,assign:()=>W,assignAttribute:()=>tt,chainableAppend:()=>mt,classListDeclarative:()=>vt,createElement:()=>T,createElementNS:()=>Wt,customElementRender:()=>Ut,customElementWithDDE:()=>xt,dispatchEvent:()=>qt,el:()=>T,elNS:()=>Wt,isSignal:()=>F,lifecyclesToEvents:()=>xt,memo:()=>L,on:()=>S,queue:()=>jt,registerReactivity:()=>$,scope:()=>v,signal:()=>g,simulateSlots:()=>It});var I=(...t)=>Object.prototype.hasOwnProperty.call(...t);function A(t){return typeof t>"u"}function st(t){let e=typeof t;return e!=="object"?e:t===null?"null":Object.prototype.toString.call(t)}function E(t,e){return t instanceof e}function it(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function _(t=null,e={}){return Object.create(t,e)}function b(...t){return Object.assign(...t)}function K(t,e){if(!t||!E(t,AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}function ut(t,e){let{observedAttributes:n=[]}=t.constructor;return n.reduce(function(r,o){return r[Mt(o)]=e(t,o),r},{})}function Mt(t){return t.replace(/-./g,e=>e[1].toUpperCase())}var q=class extends Error{constructor(){super();let[e,...n]=this.stack.split(` +`),r=e.slice(e.indexOf("@"),e.indexOf(".js:")+4),o=r.includes("src/helpers.js")?"src/":r;this.stack=n.find(c=>!c.includes(o))||e}get compact(){let{stack:e}=this;return e.slice(0,e.indexOf("@")+1)+"\u2026"+e.slice(e.lastIndexOf("/"))}};var d={setDeleteAttr:Tt,ssr:"",D:globalThis.document,N:globalThis.Node,F:globalThis.DocumentFragment,H:globalThis.HTMLElement,S:globalThis.SVGElement,M:globalThis.MutationObserver,q:t=>t||Promise.resolve()};function Tt(t,e,n){if(Reflect.set(t,e,n),!!A(n)){if(Reflect.deleteProperty(t,e),E(t,d.H)&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var M="__dde_lifecyclesToEvents",C="dde:connected",R="dde:disconnected",U="dde:attributeChanged";var D=d.M?Pt():new Proxy({},{get(){return()=>{}}});function Pt(){let t=new Map,e=!1,n=u=>function(p){for(let f of p)if(f.type==="childList"){if(m(f.addedNodes,!0)){u();continue}y(f.removedNodes,!0)&&u()}},r=new d.M(n(i));return{observe(u){let p=new d.M(n(()=>{}));return p.observe(u,{childList:!0,subtree:!0}),()=>p.disconnect()},onConnected(u,p){s();let f=c(u);f.connected.has(p)||(f.connected.add(p),f.length_c+=1)},offConnected(u,p){if(!t.has(u))return;let f=t.get(u);f.connected.has(p)&&(f.connected.delete(p),f.length_c-=1,o(u,f))},onDisconnected(u,p){s();let f=c(u);f.disconnected.has(p)||(f.disconnected.add(p),f.length_d+=1)},offDisconnected(u,p){if(!t.has(u))return;let f=t.get(u);f.disconnected.delete(p),f.length_d-=1,o(u,f)}};function o(u,p){p.length_c||p.length_d||(t.delete(u),i())}function c(u){if(t.has(u))return t.get(u);let p={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(u,p),p}function s(){e||(e=!0,r.observe(d.D.body,{childList:!0,subtree:!0}))}function i(){!e||t.size||(e=!1,r.disconnect())}function a(){return new Promise(function(u){(requestIdleCallback||requestAnimationFrame)(u)})}async function h(u){t.size>30&&await a();let p=[];if(!E(u,d.N))return p;for(let f of t.keys())f===u||!E(f,d.N)||u.contains(f)&&p.push(f);return p}function m(u,p){let f=!1;for(let w of u){if(p&&h(w).then(m),!t.has(w))continue;let P=t.get(w);P.length_c&&(w.dispatchEvent(new Event(C)),P.connected=new WeakSet,P.length_c=0,P.length_d||t.delete(w),f=!0)}return f}function y(u,p){let f=!1;for(let w of u)p&&h(w).then(y),!(!t.has(w)||!t.get(w).length_d)&&((globalThis.queueMicrotask||setTimeout)(G(w)),f=!0);return f}function G(u){return()=>{u.isConnected||(u.dispatchEvent(new Event(R)),t.delete(u))}}}function qt(t,e,n){return typeof e=="function"&&(n=e,e=null),e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let s=c.length?new CustomEvent(t,b({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(s)}}function S(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}S.defer=t=>setTimeout.bind(null,t,0);var ft=t=>b({},typeof t=="object"?t:null,{once:!0});S.connected=function(t,e){return e=ft(e),function(r){return r.addEventListener(C,t,e),r[M]?r:r.isConnected?(r.dispatchEvent(new Event(C)),r):(K(e.signal,()=>D.offConnected(r,t))&&D.onConnected(r,t),r)}};S.disconnected=function(t,e){return e=ft(e),function(r){return r.addEventListener(R,t,e),r[M]||K(e.signal,()=>D.offDisconnected(r,t))&&D.onDisconnected(r,t),r}};var O=[{get scope(){return d.D.body},host:t=>t?t(d.D.body):d.D.body,prevent:!0}],Q=new WeakMap,v={get current(){return O[O.length-1]},get host(){return this.current.host},get signal(){let{host:t}=this;if(Q.has(t))return Q.get(t);let e=new AbortController;return Q.set(t,e),t(S.disconnected(()=>e.abort())),e.signal},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...O]},push(t={}){return O.push(b({},this.current,{prevent:!1},t))},pushRoot(){return O.push(O[0])},pop(){if(O.length!==1)return O.pop()}};var j={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function $(t,e=!0){return e?b(j,t):(Object.setPrototypeOf(t,j),t)}function z(t){return it(t,j)&&t!==j?t:j}function at(t,e,n,r){return t[(A(r)?"remove":"set")+e](n,r)}function pt(t,e,n,r,o=null){return t[(A(r)?"remove":"set")+e+"NS"](o,n,r)}function X(t,e,n){if(Reflect.set(t,e,n),!!A(n))return Reflect.deleteProperty(t,e)}function dt(t,e,n,r){return E(t,d.H)?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function jt(t){return d.q(t)}function lt(...t){return this.appendOriginal(...t),this}function mt(t){return t.append===lt||(t.appendOriginal=t.append,t.append=lt),t}var H;function T(t,e,...n){let r=z(this),o=0,c,s,i=typeof e;switch((i==="string"||i==="number"||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let a=(...y)=>y.length?(o===1?n.unshift(...y):y.forEach(G=>G(s)),void 0):s;v.push({scope:t,host:a}),c=t(e||void 0);let h=E(c,d.F);if(c.nodeName==="#comment")break;let m=T.mark({type:"component",name:t.name,host:h?"this":"parentElement"});c.prepend(m),h&&(s=m);break}case t==="#text":c=W.call(this,d.D.createTextNode(""),e);break;case(t==="<>"||!t):c=W.call(this,d.D.createDocumentFragment(),e);break;case!!H:c=W.call(this,d.D.createElementNS(H,t),e);break;case!c:c=W.call(this,d.D.createElement(t),e)}return mt(c),s||(s=c),n.forEach(a=>a(s)),o&&v.pop(),o=2,c}T.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=d.D.createComment(``);return e&&(r.end=d.D.createComment("")),r};function Wt(t){let e=this;return function(...r){H=t;let o=T.call(e,...r);return H=void 0,o}}var J=new WeakMap,{setDeleteAttr:ht}=d;function W(t,...e){if(!e.length)return t;J.set(t,gt(t,this));for(let[n,r]of Object.entries(b({},...e)))tt.call(this,t,n,r);return J.delete(t),t}function tt(t,e,n){let{setRemoveAttr:r,s:o}=gt(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(i,a)=>tt.call(c,t,i,a));let[s]=e;if(s==="=")return r(e.slice(1),n);if(s===".")return X(t,e.slice(1),n);if(/(aria|data)([A-Z])/.test(e))return e=e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),r(e,n);switch(e==="className"&&(e="class"),e){case"xlink:href":return r(e,n,"http://www.w3.org/1999/xlink");case"textContent":return ht(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return Y(o,e,t,n,X.bind(null,t[e]));case"ariaset":return Y(o,e,t,n,(i,a)=>r("aria-"+i,a));case"classList":return vt.call(c,t,n)}return Ft(t,e)?ht(t,e,n):r(e,n)}function gt(t,e){if(J.has(t))return J.get(t);let r=(E(t,d.S)?pt:at).bind(null,t,"Attribute"),o=z(e);return{setRemoveAttr:r,s:o}}function vt(t,e){let n=z(this);return Y(n,"classList",t,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function Ft(t,e){if(!(e in t))return!1;let n=bt(t,e);return!A(n.set)}function bt(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||bt(t,e)}function Y(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([i,a]){i&&(i=new c(i),i.target=e,a=t.processReactiveAttribute(n,i,a,o),o(i,a))})}function It(t,e=t){let n="\xB9\u2070",r="\u2713",o=Object.fromEntries(Array.from(e.querySelectorAll("slot")).filter(c=>!c.name.endsWith(n)).map(c=>[c.name+=n,c]));if(t.append=new Proxy(t.append,{apply(c,s,i){if(i[0]===e)return c.apply(t,i);for(let a of i){let h=(a.slot||"")+n;try{dt(a,"remove","slot")}catch{}let m=o[h];if(!m)return;m.name.startsWith(r)||(m.childNodes.forEach(y=>y.remove()),m.name=r+h),m.append(a)}return t.append=c,t}}),t!==e){let c=Array.from(t.childNodes);t.append(...c)}return e}function Ut(t,e,n={}){let r=t.host||t;v.push({scope:r,host:(...s)=>s.length?s.forEach(i=>i(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[M];o||xt(r);let c=e.call(r,n);return o||r.dispatchEvent(new Event(C)),t.nodeType===11&&typeof t.mode=="string"&&r.addEventListener(R,D.observe(t),{once:!0}),v.pop(),t.append(c)}function xt(t){return et(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(C))}),et(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(R)))}),et(t.prototype,"attributeChangedCallback",function(e,n,r){let[o,,c]=r;n.dispatchEvent(new CustomEvent(U,{detail:[o,c]})),e.apply(n,r)}),t.prototype[M]=!0,t}function et(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}var Et="__dde_memo",B=[];function L(t,e){if(!B.length)return e(t);let n=typeof t=="object"?JSON.stringify(t):t,[{cache:r,after:o}]=B;return o(n,I(r,n)?r[n]:e(t))}L.isScope=function(t){return t[Et]};L.scope=function(e,{signal:n,onlyLast:r}={}){let o=_();function c(...s){if(n&&n.aborted)return e.apply(this,s);let i=r?o:_();B.unshift({cache:o,after(h,m){return i[h]=m}});let a=e.apply(this,s);return B.shift(),o=i,a}return c[Et]=!0,c.clear=()=>o=_(),n&&n.addEventListener("abort",c.clear),c};var l="__dde_signal",nt=(()=>{let t=new Map,e=!1;function n(){e=!1;let r=t;t=new Map;for(let[o,c]of r){let s=o[l];s&&s.listeners.forEach(i=>i(s.value,c))}}return function(r,o=!1){t.set(r,t.get(r)||o),!e&&(e=!0,queueMicrotask(n))}})();var ot=_(null,{get:{value(){return St(this)}},set:{value(...t){return Ct(this,...t)}},toJSON:{value(){return St(this)}},valueOf:{value(){return this[l]&&this[l].value}}}),$t=_(ot,{set:{value(){}}});function F(t){return t&&t[l]}var Z=[],x=new WeakMap;function g(t,e){if(typeof t!="function")return _t(!1,t,e);if(F(t))return t;let n=_t(!0);function r(o,c){let[s,...i]=x.get(r);if(x.set(r,new Set([s])),Z.push(r),Ct(n,t(),c),Z.pop(),!i.length)return;let a=x.get(r);for(let h of i)a.has(h)||k(h,r)}return x.set(n[l],r),x.set(r,new Set([n])),r(),n}g.action=function(t,e,...n){let r=t[l];if(!r)return;let{actions:o}=r;if(!o||!I(o,e))throw new Error(`Action "${e}" not defined. See ${l}.actions.`);if(o[e].apply(r,n),r.skip)return delete r.skip;nt(t,!0)};g.on=function t(e,n,r={}){let{signal:o}=r;if(!(o&&o.aborted)){if(Array.isArray(e))return e.forEach(c=>t(c,n,r));ct(e,n),o&&o.addEventListener("abort",()=>k(e,n))}};g.symbols={onclear:Symbol.for("Signal.onclear")};g.clear=function(...t){for(let n of t){let r=n[l];r&&(delete n.toJSON,r.onclear.forEach(o=>o.call(r)),e(n,r),delete n[l])}function e(n,r){r.listeners.forEach(o=>{if(r.listeners.delete(o),!x.has(o))return;let c=x.get(o);c.delete(n),!(c.size>1)&&(n.clear(...c),x.delete(o))})}};var N="__dde_reactive";g.el=function(t,e){e=L.isScope(e)?e:L.scope(e,{onlyLast:!0});let n=T.mark({type:"reactive",source:new q().compact},!0),r=n.end,o=d.D.createDocumentFragment();o.append(n,r);let{current:c}=v,s=i=>{if(!n.parentNode||!r.parentNode)return k(t,s);v.push(c);let a=e(i);v.pop(),Array.isArray(a)||(a=[a]);let h=document.createComment("");a.push(h),n.after(...a);let m;for(;(m=h.nextSibling)&&m!==r;)m.remove();h.remove(),n.isConnected&&zt(c.host())};return ct(t,s),yt(t,s,n,e),s(t.get()),c.host(S.disconnected(()=>e.clear())),o};function zt(t){!t||!t[N]||(requestIdleCallback||setTimeout)(function(){t[N]=t[N].filter(([e,n])=>n.isConnected?!0:(k(...e),!1))})}var Ht={_set(t){this.value=t}};function Jt(t){return function(e,n){let r=_(ot,{set:{value(...c){return e.setAttribute(n,...c)}}}),o=At(r,e.getAttribute(n),Ht);return t[n]=o,o}}var rt="__dde_attributes";g.observedAttributes=function(t){let e=t[rt]={},n=ut(t,Jt(e));return S(U,function({detail:o}){/*! This maps attributes to signals (`S.observedAttributes`). + Investigate `__dde_attributes` key of the element. */let[c,s]=o,i=this[rt][c];if(i)return g.action(i,"_set",s)})(t),S.disconnected(function(){/*! This removes all signals mapped to attributes (`S.observedAttributes`). + Investigate `__dde_attributes` key of the element. */g.clear(...Object.values(this[rt]))})(t),n};var wt={isSignal:F,processReactiveAttribute(t,e,n,r){if(!F(n))return n;let o=c=>{if(!t.isConnected)return k(n,o);r(e,c)};return ct(n,o),yt(n,o,t,e),n.get()}};function yt(t,e,...n){let{current:r}=v;r.host(function(o){if(o[N])return o[N].push([[t,e],...n]);o[N]=[],!r.prevent&&S.disconnected(()=>o[N].forEach(([[c,s]])=>k(c,s,c[l]&&c[l].host&&c[l].host()===o)))(o)})}var Bt=new FinalizationRegistry(function(t){g.clear({[l]:t})});function _t(t,e,n){let r=_(t?$t:ot),o=At(r,e,n,t);return Bt.register(o,o[l]),o}var Zt=b(_(),{stopPropagation(){this.skip=!0}});function At(t,e,n,r=!1){let o=[];st(n)!=="[object Object]"&&(n={});let{onclear:c}=g.symbols;n[c]&&(o.push(n[c]),delete n[c]);let{host:s}=v;return Reflect.defineProperty(t,l,{value:b(_(Zt),{value:e,actions:n,onclear:o,host:s,listeners:new Set,defined:new q().stack,readonly:r}),enumerable:!1,writable:!1,configurable:!0}),t}function Gt(){return Z[Z.length-1]}function St(t){if(!t[l])return;let{value:e,listeners:n}=t[l],r=Gt();return r&&n.add(r),x.has(r)&&x.get(r).add(t),e}function Ct(t,e,n){let r=t[l];if(!(!r||!n&&r.value===e))return r.value=e,nt(t,n),e}function ct(t,e){if(t[l])return t[l].listeners.add(e)}function k(t,e,n){let r=t[l];if(!r)return;let{listeners:o}=r,c=o.delete(e);if(!c||!n||o.size)return c;g.clear(t);let s=x.get(r);if(!s)return c;let i=x.get(s);if(!i)return c;for(let a of i)k(a,s,!0);return c}$(wt);return kt(Vt);})(); diff --git a/dist/iife.d.ts b/dist/iife.d.ts index df4075e..831ad80 100644 --- a/dist/iife.d.ts +++ b/dist/iife.d.ts @@ -4,7 +4,7 @@ export interface Signal { /** The current value of the signal */ get(): V; /** Set new value of the signal */ - set(value: V): V; + set(value: V, force?: boolean): V; toJSON(): V; valueOf(): V; } @@ -172,17 +172,30 @@ declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options? declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host): (data?: any) => void; export interface On { /** Listens to the DOM event. See {@link Document.addEventListener} */ - = ddeElementAddon>(type: Event, listener: (this: EE extends ddeElementAddon ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE; + (type: Event, listener: (this: EL, ev: DocumentEventMap[Event] & { + target: EL; + }) => any, options?: AddEventListenerOptions): ddeElementAddon; = ddeElementAddon>(type: string, listener: (this: EE extends ddeElementAddon ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; /** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - connected, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent) => any, options?: AddEventListenerOptions): EE; + connected(listener: (this: EL, event: CustomEvent>) => any, options?: AddEventListenerOptions): ddeElementAddon; /** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - disconnected, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent) => any, options?: AddEventListenerOptions): EE; - /** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - attributeChanged, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent<[ - string, - string - ]>) => any, options?: AddEventListenerOptions): EE; + disconnected(listener: (this: EL, event: CustomEvent) => any, options?: AddEventListenerOptions): ddeElementAddon; + /** + * Fires after the next tick of the Javascript event loop. + * This is handy for example to apply some property depending on the element content: + * ```js + * const selected= "Z"; + * //... + * return el("form").append( + * el("select", null, on.defer(e=> e.value=selected)).append( + * el("option", { value: "A", textContent: "A" }), + * //... + * el("option", { value: "Z", textContent: "Z" }), + * ), + * ); + * ``` + * */ + defer(listener: (element: EL) => any): ddeElementAddon; } export const on: On; export type Scope = { diff --git a/dist/iife.js b/dist/iife.js index a1a2081..cc35cdd 100644 --- a/dist/iife.js +++ b/dist/iife.js @@ -31,7 +31,6 @@ var DDE = (() => { dispatchEvent: () => dispatchEvent, el: () => createElement, elNS: () => createElementNS, - elementAttribute: () => elementAttribute, lifecyclesToEvents: () => lifecyclesToEvents, memo: () => memo, on: () => on, @@ -69,38 +68,7 @@ var DDE = (() => { }; } - // src/signals-lib/common.js - var signals_global = { - /** - * Checks if a value is a signal - * @param {any} attributes - Value to check - * @returns {boolean} Whether the value is a signal - */ - isSignal(attributes) { - return false; - }, - /** - * Processes an attribute that might be reactive - * @param {Element} obj - Element that owns the attribute - * @param {string} key - Attribute name - * @param {any} attr - Attribute value - * @param {Function} set - Function to set the attribute - * @returns {any} Processed attribute value - */ - processReactiveAttribute(obj, key, attr, set) { - return attr; - } - }; - function registerReactivity(def, global = true) { - if (global) return oAssign(signals_global, def); - Object.setPrototypeOf(def, signals_global); - return def; - } - function signals(_this) { - return isProtoFrom(_this, signals_global) && _this !== signals_global ? _this : signals_global; - } - - // src/dom-common.js + // src/dom-lib/common.js var enviroment = { setDeleteAttr, ssr: "", @@ -126,7 +94,7 @@ var DDE = (() => { var evd = "dde:disconnected"; var eva = "dde:attributeChanged"; - // src/events-observer.js + // src/dom-lib/events-observer.js var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { get() { return () => { @@ -290,7 +258,7 @@ var DDE = (() => { } } - // src/events.js + // src/dom-lib/events.js function dispatchEvent(name, options, host) { if (typeof options === "function") { host = options; @@ -312,6 +280,7 @@ var DDE = (() => { return element; }; } + on.defer = (fn) => setTimeout.bind(null, fn, 0); var lifeOptions = (obj) => oAssign({}, typeof obj === "object" ? obj : null, { once: true }); on.connected = function(listener, options) { options = lifeOptions(options); @@ -335,10 +304,7 @@ var DDE = (() => { }; }; - // src/dom.js - function queue(promise) { - return enviroment.q(promise); - } + // src/dom-lib/scopes.js var scopes = [{ get scope() { return enviroment.D.body; @@ -413,6 +379,60 @@ var DDE = (() => { return scopes.pop(); } }; + + // src/signals-lib/common.js + var signals_global = { + /** + * Checks if a value is a signal + * @param {any} attributes - Value to check + * @returns {boolean} Whether the value is a signal + */ + isSignal(attributes) { + return false; + }, + /** + * Processes an attribute that might be reactive + * @param {Element} obj - Element that owns the attribute + * @param {string} key - Attribute name + * @param {any} attr - Attribute value + * @param {Function} set - Function to set the attribute + * @returns {any} Processed attribute value + */ + processReactiveAttribute(obj, key, attr, set) { + return attr; + } + }; + function registerReactivity(def, global = true) { + if (global) return oAssign(signals_global, def); + Object.setPrototypeOf(def, signals_global); + return def; + } + function signals(_this) { + return isProtoFrom(_this, signals_global) && _this !== signals_global ? _this : signals_global; + } + + // src/dom-lib/helpers.js + function setRemove(obj, prop, key, val) { + return obj[(isUndef(val) ? "remove" : "set") + prop](key, val); + } + function setRemoveNS(obj, prop, key, val, ns = null) { + return obj[(isUndef(val) ? "remove" : "set") + prop + "NS"](ns, key, val); + } + function setDelete(obj, key, val) { + Reflect.set(obj, key, val); + if (!isUndef(val)) return; + return Reflect.deleteProperty(obj, key); + } + function elementAttribute(element, op, key, value) { + if (isInstance(element, enviroment.H)) + return element[op + "Attribute"](key, value); + return element[op + "AttributeNS"](null, key, value); + } + + // src/dom-lib/el.js + function queue(promise) { + return enviroment.q(promise); + } function append(...els) { this.appendOriginal(...els); return this; @@ -428,7 +448,8 @@ var DDE = (() => { const s = signals(this); let scoped = 0; let el, el_host; - if (Object(attributes) !== attributes || s.isSignal(attributes)) + const att_type = typeof attributes; + if (att_type === "string" || att_type === "number" || s.isSignal(attributes)) attributes = { textContent: attributes }; switch (true) { case typeof tag === "function": { @@ -482,38 +503,6 @@ var DDE = (() => { return el; }; } - function simulateSlots(element, root = element) { - const mark_e = "\xB9\u2070", mark_s = "\u2713"; - const slots = Object.fromEntries( - Array.from(root.querySelectorAll("slot")).filter((s) => !s.name.endsWith(mark_e)).map((s) => [s.name += mark_e, s]) - ); - element.append = new Proxy(element.append, { - apply(orig, _, els) { - if (els[0] === root) return orig.apply(element, els); - for (const el of els) { - const name = (el.slot || "") + mark_e; - try { - elementAttribute(el, "remove", "slot"); - } catch (_error) { - } - const slot = slots[name]; - if (!slot) return; - if (!slot.name.startsWith(mark_s)) { - slot.childNodes.forEach((c) => c.remove()); - slot.name = mark_s + name; - } - slot.append(el); - } - element.append = orig; - return element; - } - }); - if (element !== root) { - const els = Array.from(element.childNodes); - element.append(...els); - } - return root; - } var assign_context = /* @__PURE__ */ new WeakMap(); var { setDeleteAttr: setDeleteAttr2 } = enviroment; function assign(element, ...attributes) { @@ -576,11 +565,6 @@ var DDE = (() => { ); return element; } - function elementAttribute(element, op, key, value) { - if (isInstance(element, enviroment.H)) - return element[op + "Attribute"](key, value); - return element[op + "AttributeNS"](null, key, value); - } function isPropSetter(el, key) { if (!(key in el)) return false; const des = getPropDescriptor(el, key); @@ -604,19 +588,40 @@ var DDE = (() => { cb(key, val); }); } - function setRemove(obj, prop, key, val) { - return obj[(isUndef(val) ? "remove" : "set") + prop](key, val); - } - function setRemoveNS(obj, prop, key, val, ns = null) { - return obj[(isUndef(val) ? "remove" : "set") + prop + "NS"](ns, key, val); - } - function setDelete(obj, key, val) { - Reflect.set(obj, key, val); - if (!isUndef(val)) return; - return Reflect.deleteProperty(obj, key); - } - // src/customElement.js + // src/dom-lib/customElement.js + function simulateSlots(element, root = element) { + const mark_e = "\xB9\u2070", mark_s = "\u2713"; + const slots = Object.fromEntries( + Array.from(root.querySelectorAll("slot")).filter((s) => !s.name.endsWith(mark_e)).map((s) => [s.name += mark_e, s]) + ); + element.append = new Proxy(element.append, { + apply(orig, _, els) { + if (els[0] === root) return orig.apply(element, els); + for (const el of els) { + const name = (el.slot || "") + mark_e; + try { + elementAttribute(el, "remove", "slot"); + } catch (_error) { + } + const slot = slots[name]; + if (!slot) return; + if (!slot.name.startsWith(mark_s)) { + slot.childNodes.forEach((c) => c.remove()); + slot.name = mark_s + name; + } + slot.append(el); + } + element.append = orig; + return element; + } + }); + if (element !== root) { + const els = Array.from(element.childNodes); + element.append(...els); + } + return root; + } function customElementRender(target, render, props = {}) { const custom_element = target.host || target; scope.push({ diff --git a/dist/iife.min.d.ts b/dist/iife.min.d.ts index df4075e..831ad80 100644 --- a/dist/iife.min.d.ts +++ b/dist/iife.min.d.ts @@ -4,7 +4,7 @@ export interface Signal { /** The current value of the signal */ get(): V; /** Set new value of the signal */ - set(value: V): V; + set(value: V, force?: boolean): V; toJSON(): V; valueOf(): V; } @@ -172,17 +172,30 @@ declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options? declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, host: Host): (data?: any) => void; export interface On { /** Listens to the DOM event. See {@link Document.addEventListener} */ - = ddeElementAddon>(type: Event, listener: (this: EE extends ddeElementAddon ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE; + (type: Event, listener: (this: EL, ev: DocumentEventMap[Event] & { + target: EL; + }) => any, options?: AddEventListenerOptions): ddeElementAddon; = ddeElementAddon>(type: string, listener: (this: EE extends ddeElementAddon ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE; /** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - connected, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent) => any, options?: AddEventListenerOptions): EE; + connected(listener: (this: EL, event: CustomEvent>) => any, options?: AddEventListenerOptions): ddeElementAddon; /** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - disconnected, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent) => any, options?: AddEventListenerOptions): EE; - /** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line - attributeChanged, El extends (EE extends ddeElementAddon ? El : never)>(listener: (this: El, event: CustomEvent<[ - string, - string - ]>) => any, options?: AddEventListenerOptions): EE; + disconnected(listener: (this: EL, event: CustomEvent) => any, options?: AddEventListenerOptions): ddeElementAddon; + /** + * Fires after the next tick of the Javascript event loop. + * This is handy for example to apply some property depending on the element content: + * ```js + * const selected= "Z"; + * //... + * return el("form").append( + * el("select", null, on.defer(e=> e.value=selected)).append( + * el("option", { value: "A", textContent: "A" }), + * //... + * el("option", { value: "Z", textContent: "Z" }), + * ), + * ); + * ``` + * */ + defer(listener: (element: EL) => any): ddeElementAddon; } export const on: On; export type Scope = { diff --git a/dist/iife.min.js b/dist/iife.min.js index fa81502..17a64b8 100644 --- a/dist/iife.min.js +++ b/dist/iife.min.js @@ -1 +1 @@ -var DDE=(()=>{var W=Object.defineProperty;var ct=Object.getOwnPropertyDescriptor;var st=Object.getOwnPropertyNames;var it=Object.prototype.hasOwnProperty;var ut=(t,e)=>{for(var n in e)W(t,n,{get:e[n],enumerable:!0})},ft=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of st(e))!it.call(t,o)&&o!==n&&W(t,o,{get:()=>e[o],enumerable:!(r=ct(e,o))||r.enumerable});return t};var at=t=>ft(W({},"__esModule",{value:!0}),t);var _t={};ut(_t,{assign:()=>L,assignAttribute:()=>$,chainableAppend:()=>Q,classListDeclarative:()=>Y,createElement:()=>M,createElementNS:()=>mt,customElementRender:()=>Et,customElementWithDDE:()=>nt,dispatchEvent:()=>lt,el:()=>M,elNS:()=>mt,elementAttribute:()=>tt,lifecyclesToEvents:()=>nt,memo:()=>q,on:()=>D,queue:()=>ht,registerReactivity:()=>B,scope:()=>y,simulateSlots:()=>bt});var H=(...t)=>Object.prototype.hasOwnProperty.call(...t);function _(t){return typeof t>"u"}function b(t,e){return t instanceof e}function z(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function N(t=null,e={}){return Object.create(t,e)}function g(...t){return Object.assign(...t)}function k(t,e){if(!t||!b(t,AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}var S={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function B(t,e=!0){return e?g(S,t):(Object.setPrototypeOf(t,S),t)}function R(t){return z(t,S)&&t!==S?t:S}var a={setDeleteAttr:dt,ssr:"",D:globalThis.document,N:globalThis.Node,F:globalThis.DocumentFragment,H:globalThis.HTMLElement,S:globalThis.SVGElement,M:globalThis.MutationObserver,q:t=>t||Promise.resolve()};function dt(t,e,n){if(Reflect.set(t,e,n),!!_(n)){if(Reflect.deleteProperty(t,e),b(t,a.H)&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var C="__dde_lifecyclesToEvents",v="dde:connected",w="dde:disconnected",Z="dde:attributeChanged";var O=a.M?pt():new Proxy({},{get(){return()=>{}}});function pt(){let t=new Map,e=!1,n=s=>function(u){for(let i of u)if(i.type==="childList"){if(l(i.addedNodes,!0)){s();continue}E(i.removedNodes,!0)&&s()}},r=new a.M(n(f));return{observe(s){let u=new a.M(n(()=>{}));return u.observe(s,{childList:!0,subtree:!0}),()=>u.disconnect()},onConnected(s,u){d();let i=c(s);i.connected.has(u)||(i.connected.add(u),i.length_c+=1)},offConnected(s,u){if(!t.has(s))return;let i=t.get(s);i.connected.has(u)&&(i.connected.delete(u),i.length_c-=1,o(s,i))},onDisconnected(s,u){d();let i=c(s);i.disconnected.has(u)||(i.disconnected.add(u),i.length_d+=1)},offDisconnected(s,u){if(!t.has(s))return;let i=t.get(s);i.disconnected.delete(u),i.length_d-=1,o(s,i)}};function o(s,u){u.length_c||u.length_d||(t.delete(s),f())}function c(s){if(t.has(s))return t.get(s);let u={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(s,u),u}function d(){e||(e=!0,r.observe(a.D.body,{childList:!0,subtree:!0}))}function f(){!e||t.size||(e=!1,r.disconnect())}function p(){return new Promise(function(s){(requestIdleCallback||requestAnimationFrame)(s)})}async function h(s){t.size>30&&await p();let u=[];if(!b(s,a.N))return u;for(let i of t.keys())i===s||!b(i,a.N)||s.contains(i)&&u.push(i);return u}function l(s,u){let i=!1;for(let m of s){if(u&&h(m).then(l),!t.has(m))continue;let A=t.get(m);A.length_c&&(m.dispatchEvent(new Event(v)),A.connected=new WeakSet,A.length_c=0,A.length_d||t.delete(m),i=!0)}return i}function E(s,u){let i=!1;for(let m of s)u&&h(m).then(E),!(!t.has(m)||!t.get(m).length_d)&&((globalThis.queueMicrotask||setTimeout)(ot(m)),i=!0);return i}function ot(s){return()=>{s.isConnected||(s.dispatchEvent(new Event(w)),t.delete(s))}}}function lt(t,e,n){return typeof e=="function"&&(n=e,e=null),e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let d=c.length?new CustomEvent(t,g({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(d)}}function D(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var G=t=>g({},typeof t=="object"?t:null,{once:!0});D.connected=function(t,e){return e=G(e),function(r){return r.addEventListener(v,t,e),r[C]?r:r.isConnected?(r.dispatchEvent(new Event(v)),r):(k(e.signal,()=>O.offConnected(r,t))&&O.onConnected(r,t),r)}};D.disconnected=function(t,e){return e=G(e),function(r){return r.addEventListener(w,t,e),r[C]||k(e.signal,()=>O.offDisconnected(r,t))&&O.onDisconnected(r,t),r}};function ht(t){return a.q(t)}var x=[{get scope(){return a.D.body},host:t=>t?t(a.D.body):a.D.body,prevent:!0}],F=new WeakMap,y={get current(){return x[x.length-1]},get host(){return this.current.host},get signal(){let{host:t}=this;if(F.has(t))return F.get(t);let e=new AbortController;return F.set(t,e),t(D.disconnected(()=>e.abort())),e.signal},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...x]},push(t={}){return x.push(g({},this.current,{prevent:!1},t))},pushRoot(){return x.push(x[0])},pop(){if(x.length!==1)return x.pop()}};function J(...t){return this.appendOriginal(...t),this}function Q(t){return t.append===J||(t.appendOriginal=t.append,t.append=J),t}var T;function M(t,e,...n){let r=R(this),o=0,c,d;switch((Object(e)!==e||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let f=(...l)=>l.length?(o===1?n.unshift(...l):l.forEach(E=>E(d)),void 0):d;y.push({scope:t,host:f}),c=t(e||void 0);let p=b(c,a.F);if(c.nodeName==="#comment")break;let h=M.mark({type:"component",name:t.name,host:p?"this":"parentElement"});c.prepend(h),p&&(d=h);break}case t==="#text":c=L.call(this,a.D.createTextNode(""),e);break;case(t==="<>"||!t):c=L.call(this,a.D.createDocumentFragment(),e);break;case!!T:c=L.call(this,a.D.createElementNS(T,t),e);break;case!c:c=L.call(this,a.D.createElement(t),e)}return Q(c),d||(d=c),n.forEach(f=>f(d)),o&&y.pop(),o=2,c}M.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=a.D.createComment(``);return e&&(r.end=a.D.createComment("")),r};function mt(t){let e=this;return function(...r){T=t;let o=M.call(e,...r);return T=void 0,o}}function bt(t,e=t){let n="\xB9\u2070",r="\u2713",o=Object.fromEntries(Array.from(e.querySelectorAll("slot")).filter(c=>!c.name.endsWith(n)).map(c=>[c.name+=n,c]));if(t.append=new Proxy(t.append,{apply(c,d,f){if(f[0]===e)return c.apply(t,f);for(let p of f){let h=(p.slot||"")+n;try{tt(p,"remove","slot")}catch{}let l=o[h];if(!l)return;l.name.startsWith(r)||(l.childNodes.forEach(E=>E.remove()),l.name=r+h),l.append(p)}return t.append=c,t}}),t!==e){let c=Array.from(t.childNodes);t.append(...c)}return e}var P=new WeakMap,{setDeleteAttr:V}=a;function L(t,...e){if(!e.length)return t;P.set(t,X(t,this));for(let[n,r]of Object.entries(g({},...e)))$.call(this,t,n,r);return P.delete(t),t}function $(t,e,n){let{setRemoveAttr:r,s:o}=X(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(f,p)=>$.call(c,t,f,p));let[d]=e;if(d==="=")return r(e.slice(1),n);if(d===".")return K(t,e.slice(1),n);if(/(aria|data)([A-Z])/.test(e))return e=e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),r(e,n);switch(e==="className"&&(e="class"),e){case"xlink:href":return r(e,n,"http://www.w3.org/1999/xlink");case"textContent":return V(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return I(o,e,t,n,K.bind(null,t[e]));case"ariaset":return I(o,e,t,n,(f,p)=>r("aria-"+f,p));case"classList":return Y.call(c,t,n)}return gt(t,e)?V(t,e,n):r(e,n)}function X(t,e){if(P.has(t))return P.get(t);let r=(b(t,a.S)?xt:vt).bind(null,t,"Attribute"),o=R(e);return{setRemoveAttr:r,s:o}}function Y(t,e){let n=R(this);return I(n,"classList",t,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function tt(t,e,n,r){return b(t,a.H)?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function gt(t,e){if(!(e in t))return!1;let n=et(t,e);return!_(n.set)}function et(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||et(t,e)}function I(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([f,p]){f&&(f=new c(f),f.target=e,p=t.processReactiveAttribute(n,f,p,o),o(f,p))})}function vt(t,e,n,r){return t[(_(r)?"remove":"set")+e](n,r)}function xt(t,e,n,r,o=null){return t[(_(r)?"remove":"set")+e+"NS"](o,n,r)}function K(t,e,n){if(Reflect.set(t,e,n),!!_(n))return Reflect.deleteProperty(t,e)}function Et(t,e,n={}){let r=t.host||t;y.push({scope:r,host:(...d)=>d.length?d.forEach(f=>f(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[C];o||nt(r);let c=e.call(r,n);return o||r.dispatchEvent(new Event(v)),t.nodeType===11&&typeof t.mode=="string"&&r.addEventListener(w,O.observe(t),{once:!0}),y.pop(),t.append(c)}function nt(t){return U(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(v))}),U(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(w)))}),U(t.prototype,"attributeChangedCallback",function(e,n,r){let[o,,c]=r;n.dispatchEvent(new CustomEvent(Z,{detail:[o,c]})),e.apply(n,r)}),t.prototype[C]=!0,t}function U(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}var rt="__dde_memo",j=[];function q(t,e){if(!j.length)return e(t);let n=typeof t=="object"?JSON.stringify(t):t,[{cache:r,after:o}]=j;return o(n,H(r,n)?r[n]:e(t))}q.isScope=function(t){return t[rt]};q.scope=function(e,{signal:n,onlyLast:r}={}){let o=N();function c(...d){if(n&&n.aborted)return e.apply(this,d);let f=r?o:N();j.unshift({cache:o,after(h,l){return f[h]=l}});let p=e.apply(this,d);return j.shift(),o=f,p}return c[rt]=!0,c.clear=()=>o=N(),n&&n.addEventListener("abort",c.clear),c};return at(_t);})(); +var DDE=(()=>{var k=Object.defineProperty;var it=Object.getOwnPropertyDescriptor;var ut=Object.getOwnPropertyNames;var ft=Object.prototype.hasOwnProperty;var at=(t,e)=>{for(var n in e)k(t,n,{get:e[n],enumerable:!0})},pt=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of ut(e))!ft.call(t,o)&&o!==n&&k(t,o,{get:()=>e[o],enumerable:!(r=it(e,o))||r.enumerable});return t};var dt=t=>pt(k({},"__esModule",{value:!0}),t);var _t={};at(_t,{assign:()=>R,assignAttribute:()=>H,chainableAppend:()=>et,classListDeclarative:()=>rt,createElement:()=>M,createElementNS:()=>gt,customElementRender:()=>Et,customElementWithDDE:()=>ct,dispatchEvent:()=>mt,el:()=>M,elNS:()=>gt,lifecyclesToEvents:()=>ct,memo:()=>q,on:()=>C,queue:()=>bt,registerReactivity:()=>V,scope:()=>O,simulateSlots:()=>xt});var B=(...t)=>Object.prototype.hasOwnProperty.call(...t);function x(t){return typeof t>"u"}function h(t,e){return t instanceof e}function Z(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function L(t=null,e={}){return Object.create(t,e)}function v(...t){return Object.assign(...t)}function I(t,e){if(!t||!h(t,AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}var f={setDeleteAttr:lt,ssr:"",D:globalThis.document,N:globalThis.Node,F:globalThis.DocumentFragment,H:globalThis.HTMLElement,S:globalThis.SVGElement,M:globalThis.MutationObserver,q:t=>t||Promise.resolve()};function lt(t,e,n){if(Reflect.set(t,e,n),!!x(n)){if(Reflect.deleteProperty(t,e),h(t,f.H)&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var A="__dde_lifecyclesToEvents",E="dde:connected",w="dde:disconnected",G="dde:attributeChanged";var y=f.M?ht():new Proxy({},{get(){return()=>{}}});function ht(){let t=new Map,e=!1,n=s=>function(u){for(let i of u)if(i.type==="childList"){if(l(i.addedNodes,!0)){s();continue}g(i.removedNodes,!0)&&s()}},r=new f.M(n(a));return{observe(s){let u=new f.M(n(()=>{}));return u.observe(s,{childList:!0,subtree:!0}),()=>u.disconnect()},onConnected(s,u){p();let i=c(s);i.connected.has(u)||(i.connected.add(u),i.length_c+=1)},offConnected(s,u){if(!t.has(s))return;let i=t.get(s);i.connected.has(u)&&(i.connected.delete(u),i.length_c-=1,o(s,i))},onDisconnected(s,u){p();let i=c(s);i.disconnected.has(u)||(i.disconnected.add(u),i.length_d+=1)},offDisconnected(s,u){if(!t.has(s))return;let i=t.get(s);i.disconnected.delete(u),i.length_d-=1,o(s,i)}};function o(s,u){u.length_c||u.length_d||(t.delete(s),a())}function c(s){if(t.has(s))return t.get(s);let u={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(s,u),u}function p(){e||(e=!0,r.observe(f.D.body,{childList:!0,subtree:!0}))}function a(){!e||t.size||(e=!1,r.disconnect())}function d(){return new Promise(function(s){(requestIdleCallback||requestAnimationFrame)(s)})}async function m(s){t.size>30&&await d();let u=[];if(!h(s,f.N))return u;for(let i of t.keys())i===s||!h(i,f.N)||s.contains(i)&&u.push(i);return u}function l(s,u){let i=!1;for(let b of s){if(u&&m(b).then(l),!t.has(b))continue;let S=t.get(b);S.length_c&&(b.dispatchEvent(new Event(E)),S.connected=new WeakSet,S.length_c=0,S.length_d||t.delete(b),i=!0)}return i}function g(s,u){let i=!1;for(let b of s)u&&m(b).then(g),!(!t.has(b)||!t.get(b).length_d)&&((globalThis.queueMicrotask||setTimeout)(W(b)),i=!0);return i}function W(s){return()=>{s.isConnected||(s.dispatchEvent(new Event(w)),t.delete(s))}}}function mt(t,e,n){return typeof e=="function"&&(n=e,e=null),e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let p=c.length?new CustomEvent(t,v({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(p)}}function C(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}C.defer=t=>setTimeout.bind(null,t,0);var J=t=>v({},typeof t=="object"?t:null,{once:!0});C.connected=function(t,e){return e=J(e),function(r){return r.addEventListener(E,t,e),r[A]?r:r.isConnected?(r.dispatchEvent(new Event(E)),r):(I(e.signal,()=>y.offConnected(r,t))&&y.onConnected(r,t),r)}};C.disconnected=function(t,e){return e=J(e),function(r){return r.addEventListener(w,t,e),r[A]||I(e.signal,()=>y.offDisconnected(r,t))&&y.onDisconnected(r,t),r}};var _=[{get scope(){return f.D.body},host:t=>t?t(f.D.body):f.D.body,prevent:!0}],F=new WeakMap,O={get current(){return _[_.length-1]},get host(){return this.current.host},get signal(){let{host:t}=this;if(F.has(t))return F.get(t);let e=new AbortController;return F.set(t,e),t(C.disconnected(()=>e.abort())),e.signal},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[..._]},push(t={}){return _.push(v({},this.current,{prevent:!1},t))},pushRoot(){return _.push(_[0])},pop(){if(_.length!==1)return _.pop()}};var D={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function V(t,e=!0){return e?v(D,t):(Object.setPrototypeOf(t,D),t)}function N(t){return Z(t,D)&&t!==D?t:D}function K(t,e,n,r){return t[(x(r)?"remove":"set")+e](n,r)}function Q(t,e,n,r,o=null){return t[(x(r)?"remove":"set")+e+"NS"](o,n,r)}function U(t,e,n){if(Reflect.set(t,e,n),!!x(n))return Reflect.deleteProperty(t,e)}function X(t,e,n,r){return h(t,f.H)?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function bt(t){return f.q(t)}function Y(...t){return this.appendOriginal(...t),this}function et(t){return t.append===Y||(t.appendOriginal=t.append,t.append=Y),t}var T;function M(t,e,...n){let r=N(this),o=0,c,p,a=typeof e;switch((a==="string"||a==="number"||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let d=(...g)=>g.length?(o===1?n.unshift(...g):g.forEach(W=>W(p)),void 0):p;O.push({scope:t,host:d}),c=t(e||void 0);let m=h(c,f.F);if(c.nodeName==="#comment")break;let l=M.mark({type:"component",name:t.name,host:m?"this":"parentElement"});c.prepend(l),m&&(p=l);break}case t==="#text":c=R.call(this,f.D.createTextNode(""),e);break;case(t==="<>"||!t):c=R.call(this,f.D.createDocumentFragment(),e);break;case!!T:c=R.call(this,f.D.createElementNS(T,t),e);break;case!c:c=R.call(this,f.D.createElement(t),e)}return et(c),p||(p=c),n.forEach(d=>d(p)),o&&O.pop(),o=2,c}M.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=f.D.createComment(``);return e&&(r.end=f.D.createComment("")),r};function gt(t){let e=this;return function(...r){T=t;let o=M.call(e,...r);return T=void 0,o}}var P=new WeakMap,{setDeleteAttr:tt}=f;function R(t,...e){if(!e.length)return t;P.set(t,nt(t,this));for(let[n,r]of Object.entries(v({},...e)))H.call(this,t,n,r);return P.delete(t),t}function H(t,e,n){let{setRemoveAttr:r,s:o}=nt(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(a,d)=>H.call(c,t,a,d));let[p]=e;if(p==="=")return r(e.slice(1),n);if(p===".")return U(t,e.slice(1),n);if(/(aria|data)([A-Z])/.test(e))return e=e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),r(e,n);switch(e==="className"&&(e="class"),e){case"xlink:href":return r(e,n,"http://www.w3.org/1999/xlink");case"textContent":return tt(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return $(o,e,t,n,U.bind(null,t[e]));case"ariaset":return $(o,e,t,n,(a,d)=>r("aria-"+a,d));case"classList":return rt.call(c,t,n)}return vt(t,e)?tt(t,e,n):r(e,n)}function nt(t,e){if(P.has(t))return P.get(t);let r=(h(t,f.S)?Q:K).bind(null,t,"Attribute"),o=N(e);return{setRemoveAttr:r,s:o}}function rt(t,e){let n=N(this);return $(n,"classList",t,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function vt(t,e){if(!(e in t))return!1;let n=ot(t,e);return!x(n.set)}function ot(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||ot(t,e)}function $(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([a,d]){a&&(a=new c(a),a.target=e,d=t.processReactiveAttribute(n,a,d,o),o(a,d))})}function xt(t,e=t){let n="\xB9\u2070",r="\u2713",o=Object.fromEntries(Array.from(e.querySelectorAll("slot")).filter(c=>!c.name.endsWith(n)).map(c=>[c.name+=n,c]));if(t.append=new Proxy(t.append,{apply(c,p,a){if(a[0]===e)return c.apply(t,a);for(let d of a){let m=(d.slot||"")+n;try{X(d,"remove","slot")}catch{}let l=o[m];if(!l)return;l.name.startsWith(r)||(l.childNodes.forEach(g=>g.remove()),l.name=r+m),l.append(d)}return t.append=c,t}}),t!==e){let c=Array.from(t.childNodes);t.append(...c)}return e}function Et(t,e,n={}){let r=t.host||t;O.push({scope:r,host:(...p)=>p.length?p.forEach(a=>a(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[A];o||ct(r);let c=e.call(r,n);return o||r.dispatchEvent(new Event(E)),t.nodeType===11&&typeof t.mode=="string"&&r.addEventListener(w,y.observe(t),{once:!0}),O.pop(),t.append(c)}function ct(t){return z(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(E))}),z(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(w)))}),z(t.prototype,"attributeChangedCallback",function(e,n,r){let[o,,c]=r;n.dispatchEvent(new CustomEvent(G,{detail:[o,c]})),e.apply(n,r)}),t.prototype[A]=!0,t}function z(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}var st="__dde_memo",j=[];function q(t,e){if(!j.length)return e(t);let n=typeof t=="object"?JSON.stringify(t):t,[{cache:r,after:o}]=j;return o(n,B(r,n)?r[n]:e(t))}q.isScope=function(t){return t[st]};q.scope=function(e,{signal:n,onlyLast:r}={}){let o=L();function c(...p){if(n&&n.aborted)return e.apply(this,p);let a=r?o:L();j.unshift({cache:o,after(m,l){return a[m]=l}});let d=e.apply(this,p);return j.shift(),o=a,d}return c[st]=!0,c.clear=()=>o=L(),n&&n.addEventListener("abort",c.clear),c};return dt(_t);})(); diff --git a/docs/assets/devtools.png b/docs/assets/devtools.png new file mode 100644 index 0000000000000000000000000000000000000000..6a2f8242bfcdb9d3efe876a8cd5e920cb58845e1 GIT binary patch literal 148296 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 +}, +{ + name: "Navigation", + html: `` +}, +{ + name: "Form", + html: `
+
+ + +
+
+ + +
+
+ + +
+ +
` +} +]; + +// Convert HTML to dd code +function convertHTMLtoDDE(html, options = {}) { + + try { + const parsed = parse(html); + const content = parsed.children[0] || parsed.childNodes[0]; + return !content ? "" : nodeToDDE(content, options); + } catch (error) { + console.error("Parsing error:", error); + return `// Error parsing HTML: ${error.message}`; + } +} + +// Node types based on standard DOM nodeType values +const NODE_TYPE = { + ELEMENT: 1, // Standard element node (equivalent to node.type === "element") + TEXT: 3, // Text node (equivalent to node.type === "text") + COMMENT: 8 // Comment node (equivalent to node.type === "comment") +}; + +// Convert a parsed node to dd code +function nodeToDDE(node, options = {}, level = 0) { + const tab= options.indent === "-1" ? "\t" : " ".repeat(options.indent); + const indent = tab.repeat(level); + const nextIndent = tab.repeat(level + 1); + + const { nodeType } = node; + // Handle text nodes + if (nodeType === NODE_TYPE.TEXT) { + const text = el("i", { innerText: node.nodeValue }).textContent; + if (!text.trim()) return null; + + // Return as plain text or template string for longer text + return text.includes("\n") || text.includes('"') + ? `\`${text}\`` + : `"${text}"`; + } + + // Handle comment nodes + if (nodeType === NODE_TYPE.COMMENT) { + const text = node.nodeValue; + if (!text.trim()) return null; + return text.includes("\n") + ? [ "/*", ...text.trim().split("\n").map(l=> tab+l), "*/" ] + : [ `// ${text}` ]; + } + + // For element nodes + if (nodeType === NODE_TYPE.ELEMENT) { + // Special case for SVG elements + const isNS = node.tagName === "svg"; + const elFunction = isNS ? "elNS" : "el"; + + // Get tag name + let tagStr = `"${node.tagName}"`; + + // Process attributes + const attrs = []; + const sets = { + aria: {}, + data: {}, + } + + for (const { name: key, value } of node.attributes) { + // Handle class attribute + if (key === "class") { + attrs.push(`className: "${value}"`); + continue; + } + + // Handle style attribute + if (key === "style") { + if (options.styleAsObject) { + // Convert inline style to object + const styleObj = {}; + value.split(";").forEach(part => { + const [propRaw, valueRaw] = part.split(":"); + if (propRaw && valueRaw) { + const prop = propRaw.trim(); + const propCamel = prop.replace(/-([a-z])/g, (_, c) => c.toUpperCase()); + styleObj[propCamel] = valueRaw.trim(); + } + }); + + if (Object.keys(styleObj).length > 0) { + const styleStr = JSON.stringify(styleObj).replace(/"([^"]+)":/g, "$1:"); + attrs.push(`style: ${styleStr}`); + } + } else { + // Keep as string + attrs.push(`style: "${value}"`); + } + continue; + } + + // Handle boolean attributes + if (value === "" || value === key) { + attrs.push(`${key}: true`); + continue; + } + + // Handle data/aria attributes + if (key.startsWith("data-") || key.startsWith("aria-")) { + const keyName = key.startsWith("aria-") ? "aria" : "data"; + const keyCamel = key.slice(keyName.length + 1).replace(/-([a-z])/g, (_, c) => c.toUpperCase()); + sets[keyName][keyCamel] = value; + continue; + } + + // Regular attributes + const keyRegular = key==="for" + ? "htmlFor" + : key.startsWith("on") + ? `"=${key}"` + : key.replace(/-([a-z])/g, (_, c) => c.toUpperCase()); + attrs.push(`${keyRegular}: "${value}"`); + } + + // Process sets + for (const [name, set] of Object.entries(sets)) { + if(options.dataAttrsAsCamel) + for (const [key, value] of Object.entries(set)) + attrs.push(`${name}${key[0].toUpperCase() + key.substring(1)}: "${value}"`); + else { + const setStr= Object.entries(set).map(([key, value]) => `${key}: "${value}"`).join(","); + if (setStr !== "") + attrs.push(`${name}set: { ${setStr} }`); + } + } + + // Process children + const children = []; + for (const child of node.childNodes) { + const childCode = nodeToDDE(child, options, level + 1); + if (!childCode) continue; + + children.push(childCode); + } + if(node.childNodes.length===1 && node.childNodes[0].nodeType===NODE_TYPE.TEXT){ + const textContent= children.pop().slice(1, -1); + attrs.unshift(`textContent: "${textContent}"`); + } + + // Build the element creation code + let result = `${elFunction}("${node.tagName.toLowerCase()}"`; + + // Add attributes if any + if (attrs.length > 0) { + const tooLong= attrs.join(``).length+result.length > 55; + if(options.expaned || tooLong || attrs.length > 3) + result += `, {\n${nextIndent}${attrs.join(`,\n${nextIndent}`)},\n${indent}}`; + else + result += `, { ${attrs.join(", ")} }`; + } + + // Add children if any + if (children.length > 0) { + const chs= children.map(ch=> + Array.isArray(ch) ? ch.map(l=> nextIndent + l).join("\n") : + nextIndent + ch + ","); + result += `).append(\n${chs.join("\n")}\n${indent})`; + } else { + result += ")"; + } + + return result; + } + + return null; +} + +export function converter() { + // State for the converter + const htmlInput = S(examples[0].html); + const error = S(""); + + const status = S(""); + const showStatus= msg => { + status.set(msg); + // Clear status after 3 seconds + setTimeout(() => status.set(""), 3000); + }; + + // Options state + const options = { + styleAsObject: { + title: "Convert style to object", + value: S(true), + }, + dataAttrsAsCamel: { + title: "dataKey/ariaKey (or dataset/ariaset)", + value: S(true), + }, + indent: { + title: "Indentation (-1 for tabs)", + value: S("-1"), + type: "number", + }, + expaned: { + title: "Force multiline", + value: S(false), + } + }; + const getOptions = ()=> Object.fromEntries(Object.entries(options) + .map(([key, option]) => ([ + key, + option.value.get() + ])) + ); + + // Update the dd output when input or options change + const ddeOutput = S(() => { + try { + const result = convertHTMLtoDDE(htmlInput.get(), getOptions()); + error.set(""); + return result; + } catch (err) { + error.set(`Error: ${err.message}`); + return ""; + } + }); + + // Event handlers + const onConvert = on("submit", e => { + e.preventDefault(); + htmlInput.set(htmlInput.get(), true); + showStatus("Converted!"); + }); + + const onCopy = on("click", async () => { + if (!ddeOutput.get()) return; + + try { + await navigator.clipboard.writeText(ddeOutput.get()); + showStatus("Copied to clipboard!"); + } catch (err) { + error.set(`Could not copy: ${err.message}`); + } + }); + const onClear = on("click", () => { + htmlInput.set(""); + showStatus("Input cleared"); + }); + const onExampleLoad = (example) => on("click", () => { + htmlInput.set(example.html); + showStatus(`Loaded "${example.name}" example`); + }); + + const optionsElements = () => Object.entries(options) + .map(([key, option]) => + el("label", { className: "option-group" }).append( + option.type==="number" + ? el("input", { + type: option.type || "checkbox", + name: key, + value: option.value.get(), + max: 10, + }, on("change", e => option.value.set(e.target.value))) + : el("input", { + type: option.type || "checkbox", + name: key, + checked: option.value.get(), + }, on("change", e => option.value.set(e.target.checked))), + option.title, + ) + ); + const exampleButtons = examples.map(example => + el("button", { + type: "button", + className: "secondary example-button" + }, onExampleLoad(example)).append(example.name) + ); + + return el("div", { id: "html-to-dde-converter" }).append( + el("h3", "HTML to dd Converter"), + el("p", { className: "description" }).append( + "Convert HTML markup to dd JavaScript code. Paste your HTML below or choose from an example." + ), + + el("form", { className: "converter-form" }, onConvert).append( + el("div", { className: "options" }).append(...optionsElements()), + + el("div", { className: "examples-list" }).append( + el("label", "Examples: "), + ...exampleButtons + ), + + el("div", { className: "editor-container" }).append( + el("div", { className: "input-group" }).append( + el("label", { htmlFor: "html-input" }).append( + "HTML Input", + el("div", { className: "button-group" }).append( + el("button", { + type: "button", + className: "secondary", + title: "Clear input" + }, onClear).append("Clear") + ) + ), + el("textarea", { + id: "html-input", + spellcheck: false, + value: htmlInput, + placeholder: "Paste your HTML here or choose an example", + oninput: e => htmlInput.set(e.target.value) + }) + ), + + el("div", { className: "output-group" }).append( + el("label", { htmlFor: "dde-output" }).append( + "dd Output", + el("div", { className: "button-group" }).append( + el("button", { + textContent: "Copy", + type: "button", + className: "copy-button", + title: "Copy to clipboard", + disabled: S(() => !ddeOutput.get()) + }, onCopy) + ) + ), + el("textarea", { + id: "dde-output", + readonly: true, + spellcheck: false, + placeholder: "The converted dd code will appear here", + value: S(() => ddeOutput.get() || "// Convert HTML to see results here") + }) + ) + ), + + el("div", { className: "button-group" }).append( + S.el(error, error => !error ? el() : el("div", { className: "error" }).append(error)), + el("div", { className: "status", textContent: status }), + el("button", { type: "submit" }).append("Convert") + ) + ) + ); +} diff --git a/docs/components/example.html.js b/docs/components/example.html.js index 53948f3..64d1f72 100644 --- a/docs/components/example.html.js +++ b/docs/components/example.html.js @@ -3,7 +3,6 @@ const host= "."+example.name; styles.css` ${host} { grid-column: full-main; - width: calc(100% - .75em); height: calc(4/6 * var(--body-max-width)); border-radius: var(--border-radius); box-shadow: var(--shadow); @@ -84,7 +83,6 @@ html[data-theme="light"] .cm-s-material .cm-error { color: #f44336 !important; } @media (max-width: 767px) { ${host} { height: 50vh; - max-width: 100%; } ${host} main { flex-grow: 1; @@ -97,7 +95,7 @@ html[data-theme="light"] .cm-s-material .cm-error { color: #f44336 !important; } } } ${host}[data-variant=big]{ - height: 100vh; + height: 150vh; main { flex-flow: column nowrap; diff --git a/docs/components/examples/case-studies/data-dashboard.js b/docs/components/examples/case-studies/data-dashboard.js new file mode 100644 index 0000000..b588485 --- /dev/null +++ b/docs/components/examples/case-studies/data-dashboard.js @@ -0,0 +1,394 @@ +/** + * Case Study: Data Dashboard with Charts + * + * This example demonstrates: + * - Integration with a third-party charting library + * - Data fetching and state management + * - Responsive layout design + * - Multiple interactive components working together + */ + +import { el, on } from "deka-dom-el"; +import { S } from "deka-dom-el/signals"; + +/** + * Data Dashboard Component with Chart Integration + * @returns {HTMLElement} Dashboard element + */ +export function DataDashboard() { + // Mock data for demonstration + const DATA = { + sales: [42, 58, 65, 49, 72, 85, 63, 70, 78, 89, 95, 86], + visitors: [1420, 1620, 1750, 1850, 2100, 2400, 2250, 2500, 2750, 2900, 3100, 3200], + conversion: [2.9, 3.5, 3.7, 2.6, 3.4, 3.5, 2.8, 2.8, 2.8, 3.1, 3.0, 2.7], + months: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + }; + + // Application state + const selectedYear = S(2024); + const selectedDataType = S(/** @type {'sales' | 'visitors' | 'conversion'} */ ('sales')); + const isLoading = S(false); + const error = S(null); + + // Filter options + const years = [2022, 2023, 2024]; + const dataTypes = [ + { id: 'sales', label: 'Sales', unit: 'K' }, + { id: 'visitors', label: 'Visitors', unit: '' }, + { id: 'conversion', label: 'Conversion Rate', unit: '%' } + ]; + + // Computed values + const selectedData = S(() => { + return DATA[selectedDataType.get()]; + }); + + const currentDataType = S(() => { + return dataTypes.find(type => type.id === selectedDataType.get()); + }); + + const totalValue = S(() => { + const data = selectedData.get(); + return data.reduce((sum, value) => sum + value, 0); + }); + + const averageValue = S(() => { + const data = selectedData.get(); + return data.reduce((sum, value) => sum + value, 0) / data.length; + }); + + const highestValue = S(() => { + return Math.max(...selectedData.get()); + }); + + // Event handlers + const onYearChange = on("change", e => { + selectedYear.set(parseInt(/** @type {HTMLSelectElement} */(e.target).value)); + loadData(); + }); + + const onDataTypeChange = on("click", e => { + const type = /** @type {'sales' | 'visitors' | 'conversion'} */( + /** @type {HTMLButtonElement} */(e.currentTarget).dataset.type); + selectedDataType.set(type); + }); + + // Simulate data loading + function loadData() { + isLoading.set(true); + error.set(null); + + // Simulate API call + setTimeout(() => { + if (Math.random() > 0.9) { + // Simulate occasional error + error.set('Failed to load data. Please try again.'); + } + isLoading.set(false); + }, 800); + } + + // Reactive chart rendering + const chart = S(()=> { + const chart= el("canvas", { id: "chart-canvas", width: 800, height: 400 }); + const ctx = chart.getContext('2d'); + const data = selectedData.get(); + const months = DATA.months; + const width = chart.width; + const height = chart.height; + const maxValue = Math.max(...data) * 1.1; + const barWidth = width / data.length - 10; + + // Clear canvas + ctx.clearRect(0, 0, width, height); + + // Draw background grid + ctx.beginPath(); + ctx.strokeStyle = '#f0f0f0'; + ctx.lineWidth = 1; + for(let i = 0; i < 5; i++) { + const y = height - (height * (i / 5)) - 30; + ctx.moveTo(50, y); + ctx.lineTo(width - 20, y); + + // Draw grid labels + ctx.fillStyle = '#999'; + ctx.font = '12px Arial'; + ctx.fillText(Math.round(maxValue * (i / 5)), 20, y + 5); + } + ctx.stroke(); + + // Draw bars + data.forEach((value, index) => { + const x = index * (barWidth + 10) + 60; + const barHeight = (value / maxValue) * (height - 60); + + // Bar + ctx.fillStyle = '#4a90e2'; + ctx.fillRect(x, height - barHeight - 30, barWidth, barHeight); + + // Month label + ctx.fillStyle = '#666'; + ctx.font = '12px Arial'; + ctx.fillText(months[index], x + barWidth/2 - 10, height - 10); + }); + + // Chart title + ctx.fillStyle = '#333'; + ctx.font = 'bold 14px Arial'; + ctx.fillText(`${currentDataType.get().label} (${selectedYear.get()})`, width/2 - 80, 20); + return chart; + }); + + return el("div", { className: "dashboard" }).append( + el("header", { className: "dashboard-header" }).append( + el("h1", "Sales Performance Dashboard"), + el("div", { className: "year-filter" }).append( + el("label", { htmlFor: "yearSelect", textContent: "Select Year:" }), + el("select", { id: "yearSelect" }, + on.defer(el=> el.value = selectedYear.get().toString()), + onYearChange + ).append( + ...years.map(year => el("option", { value: year, textContent: year })) + ) + ) + ), + + // Error message (only shown when there's an error) + S.el(error, errorMsg => !errorMsg + ? el() + : el("div", { className: "error-message" }).append( + el("p", errorMsg), + el("button", { textContent: "Retry", type: "button" }, on("click", loadData)), + ), + ), + + // Loading indicator + S.el(isLoading, loading => !loading + ? el() + : el("div", { className: "loading-spinner" }) + ), + + // Main dashboard content + el("div", { className: "dashboard-content" }).append( + // Metrics cards + el("div", { className: "metrics-container" }).append( + el("div", { className: "metric-card" }).append( + el("h3", "Total"), + el("#text", S(() => `${totalValue.get().toLocaleString()}${currentDataType.get().unit}`)), + ), + el("div", { className: "metric-card" }).append( + el("h3", "Average"), + el("#text", S(() => `${averageValue.get().toFixed(1)}${currentDataType.get().unit}`)), + ), + el("div", { className: "metric-card" }).append( + el("h3", "Highest"), + el("#text", S(() => `${highestValue.get()}${currentDataType.get().unit}`)), + ), + ), + + // Data type selection tabs + el("div", { className: "data-type-tabs" }).append( + ...dataTypes.map(type => + el("button", { + type: "button", + className: S(() => selectedDataType.get() === type.id ? 'active' : ''), + dataType: type.id, + textContent: type.label + }, onDataTypeChange) + ) + ), + + // Chart container + el("div", { className: "chart-container" }).append( + S.el(chart, chart => chart) + ) + ), + ); +} + +// Render the component +document.body.append( + el("div", { style: "padding: 20px; background: #f5f5f5; min-height: 100vh;" }).append( + el(DataDashboard) + ), + el("style", ` + .dashboard { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + max-width: 1000px; + margin: 0 auto; + padding: 1rem; + background: #fff; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + border-radius: 8px; + } + + .dashboard-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1.5rem; + padding-bottom: 1rem; + border-bottom: 1px solid #eee; + } + + .dashboard-header h1 { + font-size: 1.5rem; + margin: 0; + color: #333; + } + + .year-filter { + display: flex; + align-items: center; + gap: 0.5rem; + } + + .year-filter select { + padding: 0.5rem; + border: 1px solid #ddd; + border-radius: 4px; + font-size: 1rem; + } + + .metrics-container { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1rem; + margin-bottom: 1.5rem; + } + + .metric-card { + background: #f9f9f9; + border-radius: 8px; + padding: 1rem; + text-align: center; + transition: transform 0.2s ease; + } + + .metric-card:hover { + transform: translateY(-5px); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05); + } + + .metric-card h3 { + margin-top: 0; + color: #666; + font-size: 0.9rem; + margin-bottom: 0.5rem; + } + + .metric-card p { + font-size: 1.5rem; + font-weight: bold; + color: #333; + margin: 0; + } + + .data-type-tabs { + display: flex; + border-bottom: 1px solid #eee; + margin-bottom: 1.5rem; + } + + .data-type-tabs button { + background: none; + border: none; + padding: 0.75rem 1.5rem; + font-size: 1rem; + cursor: pointer; + color: #666; + position: relative; + } + + .data-type-tabs button.active { + color: #4a90e2; + font-weight: 500; + } + + .data-type-tabs button.active::after { + content: ''; + position: absolute; + bottom: -1px; + left: 0; + width: 100%; + height: 3px; + background: #4a90e2; + border-radius: 3px 3px 0 0; + } + + .chart-container { + background: #fff; + border-radius: 8px; + padding: 1rem; + margin-bottom: 1.5rem; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); + } + + .loading-spinner { + display: flex; + justify-content: center; + align-items: center; + height: 100px; + } + + .loading-spinner::before { + content: ''; + width: 40px; + height: 40px; + border: 4px solid #f3f3f3; + border-top: 4px solid #4a90e2; + border-radius: 50%; + animation: spin 1s linear infinite; + } + + @keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } + } + + .error-message { + background: #ffecec; + color: #e74c3c; + padding: 1rem; + border-radius: 4px; + margin-bottom: 1.5rem; + display: flex; + justify-content: space-between; + align-items: center; + } + + .error-message p { + margin: 0; + } + + .error-message button { + background: #e74c3c; + color: white; + border: none; + border-radius: 4px; + padding: 0.5rem 1rem; + cursor: pointer; + } + + @media (max-width: 768px) { + .metrics-container { + grid-template-columns: 1fr; + } + + .dashboard-header { + flex-direction: column; + align-items: flex-start; + gap: 1rem; + } + + .year-filter { + width: 100%; + } + + .year-filter select { + flex-grow: 1; + } + } + `) +); diff --git a/docs/components/examples/case-studies/image-gallery.js b/docs/components/examples/case-studies/image-gallery.js new file mode 100644 index 0000000..e4dcec7 --- /dev/null +++ b/docs/components/examples/case-studies/image-gallery.js @@ -0,0 +1,417 @@ +/** + * Case Study: Interactive Image Gallery + * + * This example demonstrates: + * - Dynamic loading of content + * - Lightbox functionality + * - Animation handling + * - Keyboard and gesture navigation + */ + +import { el, memo, on } from "deka-dom-el"; +import { S } from "deka-dom-el/signals"; + +// Sample image data +const imagesSample = (url=> [ + { id: 1, src: url+'nature', alt: 'Nature', title: 'Beautiful Landscape' }, + { id: 2, src: url+'places', alt: 'City', title: 'Urban Architecture' }, + { id: 3, src: url+'people', alt: 'People', title: 'Street Photography' }, + { id: 4, src: url+'food', alt: 'Food', title: 'Culinary Delights' }, + { id: 5, src: url+'animals', alt: 'Animals', title: 'Wildlife' }, + { id: 6, src: url+'travel', alt: 'Travel', title: 'Adventure Awaits' }, + { id: 7, src: url+'computer', alt: 'Technology', title: 'Modern Tech' }, + { id: 8, src: url+'music', alt: 'Art', title: 'Creative Expression' }, +])('https://api.algobook.info/v1/randomimage?category='); +/** + * Interactive Image Gallery Component + * @returns {HTMLElement} Gallery element + */ +export function ImageGallery(images= imagesSample) { + + // Application state + const selectedImageId = S(null); + const filterTag = S('all'); + const imagesToDisplay = S(() => { + const tag = filterTag.get(); + if (tag === 'all') return images; + else return images.filter(img => img.alt.toLowerCase() === tag); + }) + + // Derived state + const selectedImage = S(() => { + const id = selectedImageId.get(); + return id ? images.find(img => img.id === id) : null; + }); + + const isLightboxOpen = S(() => selectedImage.get() !== null); + + // Event handlers + const onImageClick = id => on("click", () => { + selectedImageId.set(id); + document.body.style.overflow = 'hidden'; // Prevent scrolling when lightbox is open + + // Add keyboard event listeners when lightbox opens + document.addEventListener('keydown', handleKeyDown); + }); + const closeLightbox = () => { + selectedImageId.set(null); + document.body.style.overflow = ''; // Restore scrolling + + // Remove keyboard event listeners when lightbox closes + document.removeEventListener('keydown', handleKeyDown); + }; + const onPrevImage = e => { + e.stopPropagation(); // Prevent closing the lightbox + const images = imagesToDisplay.get(); + const currentId = selectedImageId.get(); + const currentIndex = images.findIndex(img => img.id === currentId); + const prevIndex = (currentIndex - 1 + images.length) % images.length; + selectedImageId.set(images[prevIndex].id); + }; + const onNextImage = e => { + e.stopPropagation(); // Prevent closing the lightbox + const images = imagesToDisplay.get(); + const currentId = selectedImageId.get(); + const currentIndex = images.findIndex(img => img.id === currentId); + const nextIndex = (currentIndex + 1) % images.length; + selectedImageId.set(images[nextIndex].id); + }; + const onFilterChange = tag => on("click", () => { + filterTag.set(tag); + }); + + // Keyboard navigation handler + function handleKeyDown(e) { + switch(e.key) { + case 'Escape': + closeLightbox(); + break; + case 'ArrowLeft': + document.querySelector('.lightbox-prev-btn').click(); + break; + case 'ArrowRight': + document.querySelector('.lightbox-next-btn').click(); + break; + } + } + + // Build the gallery UI + return el("div", { className: "gallery-container" }).append( + // Gallery header + el("header", { className: "gallery-header" }).append( + el("h1", "Interactive Image Gallery"), + el("p", "Click on any image to view it in the lightbox. Use arrow keys for navigation.") + ), + + // Filter options + el("div", { className: "gallery-filters" }).append( + el("button", { + classList: { active: S(() => filterTag.get() === 'all') }, + textContent: "All" + }, onFilterChange('all')), + el("button", { + classList: { active: S(() => filterTag.get() === 'nature') }, + textContent: "Nature" + }, onFilterChange('nature')), + el("button", { + classList: { active: S(() => filterTag.get() === 'urban') }, + textContent: "Urban" + }, onFilterChange('urban')), + el("button", { + classList: { active: S(() => filterTag.get() === 'people') }, + textContent: "People" + }, onFilterChange('people')) + ), + + // Image grid + el("div", { className: "gallery-grid" }).append( + S.el(imagesToDisplay, images => + images.map(image => + memo(image.id, ()=> + el("div", { + className: "gallery-item", + dataTag: image.alt.toLowerCase() + }).append( + el("img", { + src: image.src, + alt: image.alt, + loading: "lazy" + }, onImageClick(image.id)), + el("div", { className: "gallery-item-caption" }).append( + el("h3", image.title), + el("p", image.alt) + ) + ) + ) + ) + ) + ), + + // Lightbox (only shown when an image is selected) + S.el(isLightboxOpen, open => !open + ? el() + : el("div", { className: "lightbox-overlay" }, on("click", closeLightbox)).append( + el("div", { + className: "lightbox-content", + onClick: e => e.stopPropagation() // Prevent closing when clicking inside + }).append( + el("button", { + className: "lightbox-close-btn", + "aria-label": "Close lightbox" + }, on("click", closeLightbox)).append("×"), + + el("button", { + className: "lightbox-prev-btn", + "aria-label": "Previous image" + }, on("click", onPrevImage)).append("❮"), + + el("button", { + className: "lightbox-next-btn", + "aria-label": "Next image" + }, on("click", onNextImage)).append("❯"), + + S.el(selectedImage, img => !img + ? el() + : el("div", { className: "lightbox-image-container" }).append( + el("img", { + src: img.src, + alt: img.alt, + className: "lightbox-image" + }), + el("div", { className: "lightbox-caption" }).append( + el("h2", img.title), + el("p", img.alt) + ) + ) + ) + ) + ) + ), + ); +} + +// Render the component +document.body.append( + el("div", { style: "padding: 20px; background: #f5f5f5; min-height: 100vh;" }).append( + el(ImageGallery) + ), + el("style", ` + .gallery-container { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + max-width: 1200px; + margin: 0 auto; + padding: 2rem; + } + + .gallery-header { + text-align: center; + margin-bottom: 2rem; + } + + .gallery-header h1 { + margin-bottom: 0.5rem; + color: #333; + } + + .gallery-header p { + color: #666; + } + + .gallery-filters { + display: flex; + justify-content: center; + margin-bottom: 2rem; + flex-wrap: wrap; + } + + .gallery-filters button { + background: none; + border: none; + padding: 0.5rem 1.5rem; + margin: 0 0.5rem; + font-size: 1rem; + cursor: pointer; + border-radius: 30px; + transition: all 0.3s ease; + color: #555; + } + + .gallery-filters button:hover { + background: #f0f0f0; + } + + .gallery-filters button.active { + background: #4a90e2; + color: white; + } + + .gallery-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); + gap: 1.5rem; + } + + .gallery-item { + position: relative; + border-radius: 8px; + overflow: hidden; + box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1); + transition: transform 0.3s ease, box-shadow 0.3s ease; + cursor: pointer; + } + + .gallery-item:hover { + transform: translateY(-5px); + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15); + } + + .gallery-item img { + width: 100%; + height: 200px; + object-fit: cover; + display: block; + transition: transform 0.5s ease; + } + + .gallery-item:hover img { + transform: scale(1.05); + } + + .gallery-item-caption { + position: absolute; + bottom: 0; + left: 0; + right: 0; + background: linear-gradient(to top, rgba(0, 0, 0, 0.7), transparent); + color: white; + padding: 1rem; + transform: translateY(100%); + transition: transform 0.3s ease; + } + + .gallery-item:hover .gallery-item-caption { + transform: translateY(0); + } + + .gallery-item-caption h3 { + margin: 0 0 0.5rem; + font-size: 1.2rem; + } + + .gallery-item-caption p { + margin: 0; + font-size: 0.9rem; + opacity: 0.8; + } + + /* Lightbox styles */ + .lightbox-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.9); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; + padding: 2rem; + } + + .lightbox-content { + position: relative; + max-width: 90%; + max-height: 90%; + } + + .lightbox-image-container { + overflow: hidden; + border-radius: 4px; + box-shadow: 0 0 30px rgba(0, 0, 0, 0.5); + background: #000; + } + + .lightbox-image { + max-width: 100%; + max-height: 80vh; + display: block; + margin: 0 auto; + } + + .lightbox-caption { + background: #222; + color: white; + padding: 1rem; + text-align: center; + } + + .lightbox-caption h2 { + margin: 0 0 0.5rem; + } + + .lightbox-caption p { + margin: 0; + opacity: 0.8; + } + + .lightbox-close-btn, + .lightbox-prev-btn, + .lightbox-next-btn { + background: rgba(0, 0, 0, 0.5); + color: white; + border: none; + font-size: 1.5rem; + width: 50px; + height: 50px; + border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + transition: background 0.3s ease; + position: absolute; + } + + .lightbox-close-btn:hover, + .lightbox-prev-btn:hover, + .lightbox-next-btn:hover { + background: rgba(0, 0, 0, 0.8); + } + + .lightbox-close-btn { + top: -25px; + right: -25px; + } + + .lightbox-prev-btn { + left: -25px; + top: 50%; + transform: translateY(-50%); + } + + .lightbox-next-btn { + right: -25px; + top: 50%; + transform: translateY(-50%); + } + + @media (max-width: 768px) { + .gallery-container { + padding: 1rem; + } + + .gallery-grid { + grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); + gap: 1rem; + } + + .lightbox-prev-btn, + .lightbox-next-btn { + width: 40px; + height: 40px; + font-size: 1.2rem; + } + } + `) +); diff --git a/docs/components/examples/case-studies/interactive-form.js b/docs/components/examples/case-studies/interactive-form.js new file mode 100644 index 0000000..42b3ce1 --- /dev/null +++ b/docs/components/examples/case-studies/interactive-form.js @@ -0,0 +1,342 @@ +/** + * Case Study: Interactive Form with Validation + * + * This example demonstrates: + * - Form handling with real-time validation + * - Reactive UI updates based on input state + * - Complex form state management + * - Clean separation of concerns (data, validation, UI) + */ + +import { dispatchEvent, el, on, scope } from "deka-dom-el"; +import { S } from "deka-dom-el/signals"; + +/** + * @typedef {Object} FormState + * @property {string} name + * @property {string} email + * @property {string} password + * @property {string} confirmPassword + * @property {boolean} agreedToTerms + * */ +/** + * Interactive Form with Validation Component + * @returns {HTMLElement} Form element + */ +export function InteractiveForm() { + const submitted = S(false); + /** @type {FormState|null} */ + let formState = null; + /** @param {CustomEvent} event */ + const onSubmit = ({ detail }) => { + submitted.set(true); + formState = detail; + }; + const onAnotherAccount = () => { + submitted.set(false) + formState = null; + }; + + return el("div", { className: "form-container" }).append( + S.el(submitted, s => s + ? el("div", { className: "success-message" }).append( + el("h3", "Thank you for registering!"), + el("p", `Welcome, ${formState.name}! Your account has been created successfully.`), + el("button", { textContent: "Register another account", type: "button" }, + on("click", onAnotherAccount) + ), + ) + : el(Form, { initial: formState }, on("form:submit", onSubmit)) + ) + ); +} +/** + * Form Component + * @type {(props: { initial: FormState | null }) => HTMLElement} + * */ +export function Form({ initial }) { + const { host }= scope; + // Form state management + const formState = S(initial || { + name: '', + email: '', + password: '', + confirmPassword: '', + agreedToTerms: false + }, { + /** + * @template {keyof FormState} K + * @param {K} key + * @param {FormState[K]} value + * */ + update(key, value) { + this.value[key] = value; + } + }); + + // Derived signals for validation + const nameValid = S(() => formState.get().name.length >= 3); + const emailValid = S(() => { + const email = formState.get().email; + return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); + }); + const passwordValid = S(() => { + const password = formState.get().password; + return password.length >= 8 && /[A-Z]/.test(password) && /[0-9]/.test(password); + }); + const passwordsMatch = S(() => { + const { password, confirmPassword } = formState.get(); + return password === confirmPassword && confirmPassword !== ''; + }); + const termsAgreed = S(() => formState.get().agreedToTerms); + + // Overall form validity + const formValid = S(() => + nameValid.get() && + emailValid.get() && + passwordValid.get() && + passwordsMatch.get() && + termsAgreed.get() + ); + + // Event handlers + /** + * Event handler for input events + * @param {"value"|"checked"} prop + * @returns {(ev: Event) => void} + * */ + const onChange= prop => ev => { + const input = /** @type {HTMLInputElement} */(ev.target); + S.action(formState, "update", /** @type {keyof FormState} */(input.id), input[prop]); + }; + const dispatcSubmit = dispatchEvent("form:submit", host); + const onSubmit = on("submit", e => { + e.preventDefault(); + if (!formValid.get()) { + return; + } + + dispatcSubmit(formState.get()); + }); + + // Component UI + return el("form", { className: "registration-form" }, onSubmit).append( + el("h2", "Create an Account"), + + // Name field + el("div", { classList: { + "form-group": true, + valid: nameValid, + invalid: S(()=> !nameValid.get() && formState.get().name) + }}).append( + el("label", { htmlFor: "name", textContent: "Full Name" }), + el("input", { + id: "name", + type: "text", + value: formState.get().name, + placeholder: "Enter your full name" + }, on("input", onChange("value"))), + el("div", { className: "validation-message", textContent: "Name must be at least 3 characters long" }), + ), + + // Email field + el("div", { classList: { + "form-group": true, + valid: emailValid, + invalid: S(()=> !emailValid.get() && formState.get().email) + }}).append( + el("label", { htmlFor: "email", textContent: "Email Address" }), + el("input", { + id: "email", + type: "email", + value: formState.get().email, + placeholder: "Enter your email address" + }, on("input", onChange("value"))), + el("div", { className: "validation-message", textContent: "Please enter a valid email address" }) + ), + + // Password field + el("div", { classList: { + "form-group": true, + valid: passwordValid, + invalid: S(()=> !passwordValid.get() && formState.get().password) + }}).append( + el("label", { htmlFor: "password", textContent: "Password" }), + el("input", { + id: "password", + type: "password", + value: formState.get().password, + placeholder: "Create a password" + }, on("input", onChange("value"))), + el("div", { + className: "validation-message", + textContent: "Password must be at least 8 characters with at least one uppercase letter and one number", + }), + ), + + // Confirm password field + el("div", { classList: { + "form-group": true, + valid: passwordsMatch, + invalid: S(()=> !passwordsMatch.get() && formState.get().confirmPassword) + }}).append( + el("label", { htmlFor: "confirmPassword", textContent: "Confirm Password" }), + el("input", { + id: "confirmPassword", + type: "password", + value: formState.get().confirmPassword, + placeholder: "Confirm your password" + }, on("input", onChange("value"))), + el("div", { className: "validation-message", textContent: "Passwords must match" }), + ), + + // Terms agreement + el("div", { className: "form-group checkbox-group" }).append( + el("input", { + id: "agreedToTerms", + type: "checkbox", + checked: formState.get().agreedToTerms + }, on("change", onChange("checked"))), + el("label", { htmlFor: "agreedToTerms", textContent: "I agree to the Terms and Conditions" }), + ), + + // Submit button + el("button", { + textContent: "Create Account", + type: "submit", + className: "submit-button", + disabled: S(() => !formValid.get()) + }), + ); +} + +// Render the component +document.body.append( + el("div", { style: "padding: 20px; background: #f5f5f5; min-height: 100vh;" }).append( + el(InteractiveForm) + ), + el("style", ` + .form-container { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + max-width: 500px; + margin: 0 auto; + padding: 2rem; + border-radius: 8px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + background: #fff; + } + + h2 { + margin-top: 0; + color: #333; + margin-bottom: 1.5rem; + } + + .form-group { + margin-bottom: 1.5rem; + position: relative; + transition: all 0.3s ease; + } + + label { + display: block; + margin-bottom: 0.5rem; + color: #555; + font-weight: 500; + } + + input[type="text"], + input[type="email"], + input[type="password"] { + width: 100%; + padding: 0.75rem; + border: 1px solid #ddd; + border-radius: 4px; + font-size: 1rem; + transition: border-color 0.3s ease; + } + + input:focus { + outline: none; + border-color: #4a90e2; + box-shadow: 0 0 0 2px rgba(74, 144, 226, 0.2); + } + + .checkbox-group { + display: flex; + align-items: center; + } + + .checkbox-group label { + margin: 0 0 0 0.5rem; + } + + .validation-message { + font-size: 0.85rem; + color: #e74c3c; + margin-top: 0.5rem; + height: 0; + overflow: hidden; + opacity: 0; + transition: all 0.3s ease; + } + + .form-group.invalid .validation-message { + height: auto; + opacity: 1; + } + + .form-group.valid input { + border-color: #2ecc71; + } + + .form-group.invalid input { + border-color: #e74c3c; + } + + .submit-button { + background-color: #4a90e2; + color: white; + border: none; + border-radius: 4px; + padding: 0.75rem 1.5rem; + font-size: 1rem; + cursor: pointer; + transition: background-color 0.3s ease; + width: 100%; + } + + .submit-button:hover:not(:disabled) { + background-color: #3a7bc8; + } + + .submit-button:disabled { + background-color: #b5b5b5; + cursor: not-allowed; + } + + .success-message { + text-align: center; + color: #2ecc71; + } + + .success-message h3 { + margin-top: 0; + } + + .success-message button { + background-color: #2ecc71; + color: white; + border: none; + border-radius: 4px; + padding: 0.75rem 1.5rem; + font-size: 1rem; + cursor: pointer; + margin-top: 1rem; + } + + .success-message button:hover { + background-color: #27ae60; + } + `), +); diff --git a/docs/components/examples/case-studies/task-manager.js b/docs/components/examples/case-studies/task-manager.js new file mode 100644 index 0000000..b6d24b2 --- /dev/null +++ b/docs/components/examples/case-studies/task-manager.js @@ -0,0 +1,715 @@ +/** + * Case Study: Task Manager Application + * + * This example demonstrates: + * - Complex state management with signals + * - Drag and drop functionality + * - Local storage persistence + * - Responsive design for different devices + */ + +import { el, on, dispatchEvent, scope } from "deka-dom-el"; +import { S } from "deka-dom-el/signals"; + +/** @typedef {{ id: number, title: string, description: string, priority: string, status: string }} Task */ +/** + * Task Manager Component + * @returns {HTMLElement} Task manager UI + */ +export function TaskManager() { + // + const STORAGE_KEY = 'dde-task-manager'; + const STATUSES = { + TODO: 'todo', + IN_PROGRESS: 'in-progress', + DONE: 'done' + }; + /** @type {Task[]} */ + let initialTasks = []; + try { + const saved = localStorage.getItem(STORAGE_KEY); + if (saved) { + initialTasks = JSON.parse(saved); + } + } catch (e) { + console.error('Failed to load tasks from localStorage', e); + } + if (!initialTasks.length) { + initialTasks = [ + { id: 1, title: 'Create project structure', description: 'Set up folders and initial files', + status: STATUSES.DONE, priority: 'high' }, + { id: 2, title: 'Design UI components', description: 'Create mockups for main views', + status: STATUSES.IN_PROGRESS, priority: 'medium' }, + { id: 3, title: 'Implement authentication', description: 'Set up user login and registration', + status: STATUSES.TODO, priority: 'high' }, + { id: 4, title: 'Write documentation', description: 'Document API endpoints and usage examples', + status: STATUSES.TODO, priority: 'low' }, + ]; + } + const tasks = S(initialTasks, { + add(task) { this.value.push(task); }, + remove(id) { this.value = this.value.filter(task => task.id !== id); }, + update(id, task) { + const current= this.value.find(t => t.id === id); + if (current) Object.assign(current, task); + } + }); + S.on(tasks, value => { + try { + localStorage.setItem(STORAGE_KEY, JSON.stringify(value)); + } catch (e) { + console.error('Failed to save tasks to localStorage', e); + } + }); + // + + const filterPriority = S('all'); + const searchQuery = S(''); + // Filtered tasks based on priority and search query + const filteredTasks = S(() => { + let filtered = tasks.get(); + + // Filter by priority + if (filterPriority.get() !== 'all') { + filtered = filtered.filter(task => task.priority === filterPriority.get()); + } + + // Filter by search query + const query = searchQuery.get().toLowerCase(); + if (query) { + filtered = filtered.filter(task => + task.title.toLowerCase().includes(query) || + task.description.toLowerCase().includes(query) + ); + } + + return filtered; + }); + /** Tasks grouped by status for display in columns */ + const tasksByStatus = S(() => { + const filtered = filteredTasks.get(); + return { + [STATUSES.TODO]: filtered.filter(t => t.status === STATUSES.TODO), + [STATUSES.IN_PROGRESS]: filtered.filter(t => t.status === STATUSES.IN_PROGRESS), + [STATUSES.DONE]: filtered.filter(t => t.status === STATUSES.DONE) + }; + }); + + // signals and handlers for adding new tasks + const newTask = { title: '', description: '', priority: 'medium' }; + const onAddTask = e => { + e.preventDefault(); + if (!newTask.title) return; + + S.action(tasks, "add", { + id: Date.now(), + status: STATUSES.TODO, + ...newTask + }); + e.target.reset(); + }; + // + const onCardEdit= on("card:edit", /** @param {CardEditEvent} ev */({ detail: [ id, task ] })=> + S.action(tasks, "update", id, task)); + const onCardDelete= on("card:delete", /** @param {CardDeleteEvent} ev */({ detail: id })=> + S.action(tasks, "remove", id)); + + const { onDragable, onDragArea }= moveElementAddon( + (id, status) => S.action(tasks, "update", id, { status }) + ); + + // Build the task manager UI + return el("div", { className: "task-manager" }).append( + el("header", { className: "app-header" }).append( + el("h1", "DDE Task Manager"), + el("div", { className: "app-controls" }).append( + el("input", { + type: "text", + placeholder: "Search tasks...", + value: searchQuery.get() + }, on("input", e => searchQuery.set(e.target.value))), + el("select", null, + on.defer(el=> el.value= filterPriority.get()), + on("change", e => filterPriority.set(e.target.value)) + ).append( + el("option", { value: "all", textContent: "All Priorities" }), + el("option", { value: "low", textContent: "Low Priority" }), + el("option", { value: "medium", textContent: "Medium Priority" }), + el("option", { value: "high", textContent: "High Priority" }) + ) + ) + ), + + // Add new task form + el("form", { className: "new-task-form" }, on("submit", onAddTask)).append( + el("div", { className: "form-row" }).append( + el("input", { + type: "text", + placeholder: "New task title", + value: newTask.title, + required: true + }, on("input", e => newTask.title= e.target.value.trim())), + el("select", null, + on.defer(el=> el.value= newTask.priority), + on("change", e => newTask.priority= e.target.value) + ).append( + el("option", { value: "low", textContent: "Low" }), + el("option", { value: "medium", textContent: "Medium" }), + el("option", { value: "high", textContent: "High" }) + ), + el("button", { type: "submit", className: "add-btn" }).append("Add Task") + ), + el("textarea", { + placeholder: "Task description (optional)", + value: newTask.description + }, on("input", e => newTask.description= e.target.value.trim())) + ), + + // Task board with columns + el("div", { className: "task-board" }).append( + // Todo column + el("div", { + id: `column-${STATUSES.TODO}`, + className: "task-column" + }, onDragArea(STATUSES.TODO)).append( + el("h2", { className: "column-header" }).append( + "To Do ", + el("span", { + textContent: S(() => tasksByStatus.get()[STATUSES.TODO].length), + className: "task-count" + }), + ), + S.el(S(() => tasksByStatus.get()[STATUSES.TODO]), tasks => + el("div", { className: "column-tasks" }).append( + ...tasks.map(task=> el(TaskCard, { task, onDragable }, onCardEdit, onCardDelete)) + ) + ) + ), + + // In Progress column + el("div", { + id: `column-${STATUSES.IN_PROGRESS}`, + className: "task-column" + }, onDragArea(STATUSES.IN_PROGRESS)).append( + el("h2", { className: "column-header" }).append( + "In Progress ", + el("span", { + textContent: S(() => tasksByStatus.get()[STATUSES.IN_PROGRESS].length), + className: "task-count", + }), + ), + S.el(S(() => tasksByStatus.get()[STATUSES.IN_PROGRESS]), tasks => + el("div", { className: "column-tasks" }).append( + ...tasks.map(task=> el(TaskCard, { task, onDragable }, onCardEdit, onCardDelete)) + ) + ) + ), + + // Done column + el("div", { + id: `column-${STATUSES.DONE}`, + className: "task-column" + }, onDragArea(STATUSES.DONE)).append( + el("h2", { className: "column-header" }).append( + "Done ", + el("span", { + textContent: S(() => tasksByStatus.get()[STATUSES.DONE].length), + className: "task-count", + }), + ), + S.el(S(() => tasksByStatus.get()[STATUSES.DONE]), tasks => + el("div", { className: "column-tasks" }).append( + ...tasks.map(task=> el(TaskCard, { task, onDragable }, onCardEdit, onCardDelete)) + ) + ) + ) + ), + ); +} +/** @typedef {CustomEvent<[ string, Task ]>} CardEditEvent */ +/** @typedef {CustomEvent} CardDeleteEvent */ +/** + * Task Card Component + * @type {(props: { task: Task, onDragable: (id: number) => ddeElementAddon }) => HTMLElement} + * @fires {CardEditEvent} card:edit + * @fires {CardDeleteEvent} card:delete + * */ +function TaskCard({ task, onDragable }){ + const { host }= scope; + const isEditing = S(false); + const onEditStart = () => isEditing.set(true); + + const dispatchEdit= dispatchEvent("card:edit", host); + const dispatchDelete= dispatchEvent("card:delete", host).bind(null, task.id); + + return el("div", { + id: `task-${task.id}`, + className: `task-card priority-${task.priority}`, + draggable: true + }, onDragable(task.id)).append( + S.el(isEditing, editing => editing + ? el(EditMode) + : el().append( + el("div", { className: "task-header" }).append( + el("h3", { className: "task-title", textContent: task.title }), + el("div", { className: "task-actions" }).append( + el("button", { + textContent: "✎", + className: "edit-btn", + ariaLabel: "Edit task" + }, on("click", onEditStart)), + el("button", { + textContent: "✕", + className: "delete-btn", + ariaLabel: "Delete task" + }, on("click", dispatchDelete)) + ) + ), + !task.description + ? el() + : el("p", { className: "task-description", textContent: task.description }), + el("div", { className: "task-meta" }).append( + el("span", { + className: `priority-badge priority-${task.priority}`, + textContent: task.priority.charAt(0).toUpperCase() + task.priority.slice(1) + }) + ) + ) + ) + ); + function EditMode(){ + const onSubmit = on("submit", e => { + e.preventDefault(); + const formData = new FormData(/** @type {HTMLFormElement} */(e.target)); + const title = formData.get("title"); + const description = formData.get("description"); + const priority = formData.get("priority"); + isEditing.set(false); + dispatchEdit([ task.id, { title, description, priority } ]); + }) + const onEditCancel = () => isEditing.set(false); + + return el("form", { className: "task-edit-form" }, onSubmit).append( + el("input", { + name: "title", + className: "task-title-input", + defaultValue: task.title, + placeholder: "Task title", + required: true, + autoFocus: true + }), + el("textarea", { + name: "description", + className: "task-desc-input", + defaultValue: task.description, + placeholder: "Description (optional)" + }), + el("select", { + name: "priority", + }, on.defer(el=> el.value = task.priority)).append( + el("option", { value: "low", textContent: "Low Priority" }), + el("option", { value: "medium", textContent: "Medium Priority" }), + el("option", { value: "high", textContent: "High Priority" }) + ), + el("div", { className: "task-edit-actions" }).append( + el("button", { + textContent: "Cancel", + type: "button", + className: "cancel-btn" + }, on("click", onEditCancel)), + el("button", { + textContent: "Save", + type: "submit", + className: "save-btn" + }) + ) + ); + } +} + +/** + * Helper function to handle move an element + * @param {(id: string, status: string) => void} onMoved + * */ +function moveElementAddon(onMoved){ + let draggedTaskId = null; + function onDragable(id) { + return element => { + on("dragstart", e => { + draggedTaskId= id; + e.dataTransfer.effectAllowed = 'move'; + + // Add some styling to the element being dragged + setTimeout(() => { + const el = document.getElementById(`task-${id}`); + if (el) el.classList.add('dragging'); + }, 0); + })(element); + + on("dragend", () => { + draggedTaskId= null; + + // Remove the styling + const el = document.getElementById(`task-${id}`); + if (el) el.classList.remove('dragging'); + })(element); + }; + } + function onDragArea(status) { + return element => { + on("dragover", e => { + e.preventDefault(); + e.dataTransfer.dropEffect = 'move'; + + // Add a visual indicator for the drop target + const column = document.getElementById(`column-${status}`); + if (column) column.classList.add('drag-over'); + })(element); + + on("dragleave", () => { + // Remove the visual indicator + const column = document.getElementById(`column-${status}`); + if (column) column.classList.remove('drag-over'); + })(element); + + on("drop", e => { + e.preventDefault(); + const id = draggedTaskId; + if (id) onMoved(id, status); + // Remove the visual indicator + const column = document.getElementById(`column-${status}`); + if (column) column.classList.remove('drag-over'); + })(element); + }; + } + return { onDragable, onDragArea }; +} + +// Render the component +document.body.append( + el("div", { style: "padding: 20px; background: #f5f5f5; min-height: 100vh;" }).append( + el(TaskManager) + ), + el("style", ` + .task-manager { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + max-width: 1200px; + margin: 0 auto; + padding: 1rem; + color: #333; + } + + .app-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1.5rem; + flex-wrap: wrap; + gap: 1rem; + } + + .app-header h1 { + margin: 0; + color: #2d3748; + } + + .app-controls { + display: flex; + gap: 1rem; + } + + .app-controls input, + .app-controls select { + padding: 0.5rem; + border: 1px solid #e2e8f0; + border-radius: 4px; + font-size: 0.9rem; + } + + .new-task-form { + background: white; + padding: 1.5rem; + border-radius: 8px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); + margin-bottom: 2rem; + } + + .form-row { + display: flex; + gap: 1rem; + margin-bottom: 1rem; + } + + .form-row input { + flex-grow: 1; + padding: 0.75rem; + border: 1px solid #e2e8f0; + border-radius: 4px; + font-size: 1rem; + } + + .form-row select { + width: 100px; + padding: 0.75rem; + border: 1px solid #e2e8f0; + border-radius: 4px; + font-size: 1rem; + } + + .add-btn { + background: #4a90e2; + color: white; + border: none; + border-radius: 4px; + padding: 0.75rem 1.5rem; + font-size: 1rem; + cursor: pointer; + transition: background 0.2s ease; + } + + .add-btn:hover { + background: #3a7bc8; + } + + .new-task-form textarea { + width: 100%; + padding: 0.75rem; + border: 1px solid #e2e8f0; + border-radius: 4px; + font-size: 1rem; + resize: vertical; + min-height: 80px; + } + + .task-board { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 1.5rem; + } + + .task-column { + background: #f7fafc; + border-radius: 8px; + padding: 1rem; + min-height: 400px; + transition: background 0.2s ease; + } + + .column-header { + margin-top: 0; + padding-bottom: 0.75rem; + border-bottom: 2px solid #e2e8f0; + font-size: 1.25rem; + color: #2d3748; + display: flex; + align-items: center; + } + + .task-count { + display: inline-flex; + justify-content: center; + align-items: center; + background: #e2e8f0; + color: #4a5568; + border-radius: 50%; + width: 25px; + height: 25px; + font-size: 0.875rem; + margin-left: 0.5rem; + } + + .column-tasks { + margin-top: 1rem; + display: flex; + flex-direction: column; + gap: 1rem; + min-height: 200px; + } + + .task-card { + background: white; + border-radius: 6px; + padding: 1rem; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05); + cursor: grab; + transition: transform 0.2s ease, box-shadow 0.2s ease; + position: relative; + border-left: 4px solid #ccc; + } + + .task-card:hover { + transform: translateY(-3px); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1); + } + + .task-card.dragging { + opacity: 0.5; + cursor: grabbing; + } + + .task-card.priority-low { + border-left-color: #38b2ac; + } + + .task-card.priority-medium { + border-left-color: #ecc94b; + } + + .task-card.priority-high { + border-left-color: #e53e3e; + } + + .task-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 0.5rem; + } + + .task-title { + margin: 0; + font-size: 1.1rem; + color: #2d3748; + word-break: break-word; + } + + .task-description { + margin: 0.5rem 0; + font-size: 0.9rem; + color: #4a5568; + word-break: break-word; + } + + .task-actions { + display: flex; + gap: 0.5rem; + } + + .edit-btn, + .delete-btn { + background: none; + border: none; + font-size: 1rem; + cursor: pointer; + width: 24px; + height: 24px; + display: inline-flex; + justify-content: center; + align-items: center; + border-radius: 50%; + color: #718096; + transition: background 0.2s ease, color 0.2s ease; + } + + .edit-btn:hover { + background: #edf2f7; + color: #4a5568; + } + + .delete-btn:hover { + background: #fed7d7; + color: #e53e3e; + } + + .task-meta { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 0.75rem; + } + + .priority-badge { + font-size: 0.75rem; + padding: 0.2rem 0.5rem; + border-radius: 4px; + font-weight: 500; + } + + .priority-badge.priority-low { + background: #e6fffa; + color: #2c7a7b; + } + + .priority-badge.priority-medium { + background: #fefcbf; + color: #975a16; + } + + .priority-badge.priority-high { + background: #fed7d7; + color: #c53030; + } + + .drag-over { + background: #f0f9ff; + border: 2px dashed #4a90e2; + } + + .task-edit-form { + display: flex; + flex-direction: column; + gap: 0.75rem; + } + + .task-title-input, + .task-desc-input { + width: 100%; + padding: 0.5rem; + border: 1px solid #e2e8f0; + border-radius: 4px; + font-size: 0.9rem; + } + + .task-desc-input { + min-height: 60px; + resize: vertical; + } + + .task-edit-actions { + display: flex; + justify-content: flex-end; + gap: 0.5rem; + margin-top: 0.5rem; + } + + .cancel-btn, + .save-btn { + padding: 0.4rem 0.75rem; + border-radius: 4px; + font-size: 0.9rem; + cursor: pointer; + } + + .cancel-btn { + background: #edf2f7; + color: #4a5568; + border: 1px solid #e2e8f0; + } + + .save-btn { + background: #4a90e2; + color: white; + border: none; + } + + @media (max-width: 768px) { + .app-header { + flex-direction: column; + align-items: flex-start; + } + + .app-controls { + width: 100%; + flex-direction: column; + } + + .form-row { + flex-direction: column; + } + + .task-board { + grid-template-columns: 1fr; + } + } + `) +); diff --git a/docs/components/examples/debugging/debouncing.js b/docs/components/examples/debugging/debouncing.js index ccbb618..9ceaae3 100644 --- a/docs/components/examples/debugging/debouncing.js +++ b/docs/components/examples/debugging/debouncing.js @@ -1,5 +1,6 @@ import { S } from "deka-dom-el/signals"; -// Debouncing signal updates + +// ===== Approach 1: Traditional debouncing with utility function ===== function debounce(func, wait) { let timeout; return (...args)=> { @@ -8,8 +9,59 @@ function debounce(func, wait) { }; } -const inputSignal= S(""); -const debouncedSet= debounce(value => inputSignal.set(value), 300); +const inputSignal = S(""); +const debouncedSet = debounce(value => inputSignal.set(value), 300); // In your input handler -inputElement.addEventListener("input", e=> debouncedSet(e.target.value)); +inputElement.addEventListener("input", e => debouncedSet(e.target.value)); + +// ===== Approach 2: Signal debouncing utility ===== +/** + * Creates a debounced signal that only updates after delay + * @param {any} initialValue Initial signal value + * @param {number} delay Debounce delay in ms + */ +function createDebouncedSignal(initialValue, delay = 300) { + // Create two signals: one for immediate updates, one for debounced values + const immediateSignal = S(initialValue); + const debouncedSignal = S(initialValue); + + // Keep track of the timeout + let timeout = null; + + // Set up a listener on the immediate signal + S.on(immediateSignal, value => { + // Clear any existing timeout + if (timeout) clearTimeout(timeout); + + // Set a new timeout to update the debounced signal + timeout = setTimeout(() => { + debouncedSignal.set(value); + }, delay); + }); + + // Return an object with both signals and a setter function + return { + // The raw signal that updates immediately + raw: immediateSignal, + // The debounced signal that only updates after delay + debounced: debouncedSignal, + // Setter function to update the immediate signal + set: value => immediateSignal.set(value) + }; +} + +// Usage example +const searchInput = createDebouncedSignal("", 300); + +// Log immediate changes for demonstration +S.on(searchInput.raw, value => console.log("Input changed to:", value)); + +// Only perform expensive operations on the debounced value +S.on(searchInput.debounced, value => { + console.log("Performing search with:", value); + // Expensive operation would go here +}); + +// In your input handler +searchElement.addEventListener("input", e => searchInput.set(e.target.value)); diff --git a/docs/components/examples/events/live-cycle.js b/docs/components/examples/events/live-cycle.js index e24a9c8..ff01944 100644 --- a/docs/components/examples/events/live-cycle.js +++ b/docs/components/examples/events/live-cycle.js @@ -1,15 +1,28 @@ import { el, on } from "deka-dom-el"; -const paragraph= el("p", "See lifecycle events in console.", - el=> log({ type: "dde:created", detail: el }), - on.connected(log), - on.disconnected(log), -); +function allLifecycleEvents(){ + return el("form", null, + el=> log({ type: "dde:created", detail: el }), + on.connected(log), + on.disconnected(log), + ).append( + el("select", { id: "country" }, on.defer(select => { + // This runs when the select is ready with all its options + select.value = "cz"; // Pre-select Czechia + log({ type: "dde:on.defer", detail: select }); + })).append( + el("option", { value: "au", textContent: "Australia" }), + el("option", { value: "ca", textContent: "Canada" }), + el("option", { value: "cz", textContent: "Czechia" }), + ), + el("p", "See lifecycle events in console."), + ); +} document.body.append( - paragraph, - el("button", "Update attribute", on("click", ()=> paragraph.setAttribute("test", Math.random().toString()))), - " ", - el("button", "Remove", on("click", ()=> paragraph.remove())) + el(allLifecycleEvents), + el("button", "Remove Element", on("click", function(){ + this.previousSibling.remove(); + })) ); /** @param {Partial} event */ diff --git a/docs/components/examples/introducing/helloWorld.js b/docs/components/examples/introducing/helloWorld.js index 774dc44..560192a 100644 --- a/docs/components/examples/introducing/helloWorld.js +++ b/docs/components/examples/introducing/helloWorld.js @@ -7,20 +7,20 @@ function HelloWorld({ emoji = "🚀" }) { const clicks = S(0); return el().append( - // PART 2: Bind state to UI elements - el("p", { - className: "greeting", - // This paragraph automatically updates when clicks changes - textContent: S(() => `Hello World ${emoji.repeat(clicks.get())}`) - }), + // PART 2: Bind state to UI elements + el("p", { + className: "greeting", + // This paragraph automatically updates when clicks changes + textContent: S(() => `Hello World ${emoji.repeat(clicks.get())}`) + }), - // PART 3: Update state in response to events - el("button", { - type: "button", - textContent: "Add emoji", - // When clicked, update the state - onclick: () => clicks.set(clicks.get() + 1) - }) + // PART 3: Update state in response to events + el("button", { + type: "button", + textContent: "Add emoji", + // When clicked, update the state + onclick: () => clicks.set(clicks.get() + 1) + }) ); } diff --git a/docs/components/examples/ireland-test/counter.js b/docs/components/examples/ireland-test/counter.js index 9832883..4b995d5 100644 --- a/docs/components/examples/ireland-test/counter.js +++ b/docs/components/examples/ireland-test/counter.js @@ -9,7 +9,7 @@ document.body.append( padding: 1em; margin: 1em; } - `.trim()) +`.trim()) ); export function CounterStandard() { diff --git a/docs/components/examples/reallife/todomvc.js b/docs/components/examples/reallife/todomvc.js index daa56b3..b2c0985 100644 --- a/docs/components/examples/reallife/todomvc.js +++ b/docs/components/examples/reallife/todomvc.js @@ -13,41 +13,38 @@ import { S } from "deka-dom-el/signals"; * @returns {HTMLElement} The root TodoMVC application element */ function Todos(){ - const pageS = routerSignal(S); + const { signal } = scope; + const pageS = routerSignal(S, signal); const todosS = todosSignal(); /** Derived signal that filters todos based on current route */ - const filteredTodosS = S(()=> { + const todosFilteredS = S(()=> { const todos = todosS.get(); const filter = pageS.get(); + if (filter === "all") return todos; return todos.filter(todo => { if (filter === "active") return !todo.completed; if (filter === "completed") return todo.completed; - return true; // "all" }); }); - - // Setup hash change listener - window.addEventListener("hashchange", () => { - const hash = location.hash.replace("#", "") || "all"; - S.action(pageS, "set", /** @type {"all"|"active"|"completed"} */(hash)); - }); + const todosRemainingS = S(()=> todosS.get().filter(todo => !todo.completed).length); /** @type {ddeElementAddon} */ const onToggleAll = on("change", event => { const checked = /** @type {HTMLInputElement} */ (event.target).checked; S.action(todosS, "completeAll", checked); }); + const formNewTodo = "newTodo"; /** @type {ddeElementAddon} */ const onSubmitNewTodo = on("submit", event => { event.preventDefault(); const input = /** @type {HTMLInputElement} */( - /** @type {HTMLFormElement} */(event.target).elements.namedItem("newTodo") + /** @type {HTMLFormElement} */(event.target).elements.namedItem(formNewTodo) ); const title = input.value.trim(); - if (title) { - S.action(todosS, "add", title); - input.value = ""; - } + if (!title) return; + + S.action(todosS, "add", title); + input.value = ""; }); const onClearCompleted = on("click", () => S.action(todosS, "clearCompleted")); const onDelete = on("todo:delete", ev => @@ -61,15 +58,16 @@ function Todos(){ el("form", null, onSubmitNewTodo).append( el("input", { className: "new-todo", - name: "newTodo", + name: formNewTodo, placeholder: "What needs to be done?", autocomplete: "off", autofocus: true }) ) ), - S.el(todosS, todos => todos.length - ? el("main", { className: "main" }).append( + S.el(todosS, todos => !todos.length + ? el() + : el("main", { className: "main" }).append( el("input", { id: "toggle-all", className: "toggle-all", @@ -77,55 +75,48 @@ function Todos(){ }, onToggleAll), el("label", { htmlFor: "toggle-all", title: "Mark all as complete" }), el("ul", { className: "todo-list" }).append( - S.el(filteredTodosS, filteredTodos => filteredTodos.map(todo => + S.el(todosFilteredS, filteredTodos => filteredTodos.map(todo => memo(todo.id, ()=> el(TodoItem, todo, onDelete, onEdit))) ) ) ) - : el() ), - S.el(todosS, todos => memo(todos.length, length=> length - ? el("footer", { className: "footer" }).append( + S.el(todosS, todos => !todos.length + ? el() + : el("footer", { className: "footer" }).append( el("span", { className: "todo-count" }).append( - S.el(S(() => todosS.get().filter(todo => !todo.completed).length), - length=> el("strong").append( - length + " ", - length === 1 ? "item left" : "items left" + noOfLeft() + ), + memo("filters", ()=> + el("ul", { className: "filters" }).append( + ...[ "All", "Active", "Completed" ].map(textContent => + el("li").append( + el("a", { + textContent, + classList: { selected: S(()=> pageS.get() === textContent.toLowerCase()) }, + href: `#${textContent.toLowerCase()}` + }) + ) ) - ) - ), - el("ul", { className: "filters" }).append( - el("li").append( - el("a", { - textContent: "All", - className: S(()=> pageS.get() === "all" ? "selected" : ""), - href: "#" - }), ), - el("li").append( - el("a", { - textContent: "Active", - className: S(()=> pageS.get() === "active" ? "selected" : ""), - href: "#active" - }), - ), - el("li").append( - el("a", { - textContent: "Completed", - className: S(()=> pageS.get() === "completed" ? "selected" : ""), - href: "#completed" - }), - ) ), - S.el(S(() => todosS.get().some(todo => todo.completed)), - hasTodosCompleted=> hasTodosCompleted - ? el("button", { textContent: "Clear completed", className: "clear-completed" }, onClearCompleted) - : el() - ) + todos.length - todosRemainingS.get() === 0 + ? el() + : memo("delete", () => + el("button", + { textContent: "Clear completed", className: "clear-completed" }, + onClearCompleted) + ) ) - : el() - )) + ) ); + function noOfLeft(){ + const length = todosRemainingS.get(); + return el("strong").append( + length + " ", + length === 1 ? "item left" : "items left" + ) + } } /** @@ -177,10 +168,11 @@ function TodoItem({ id, title, completed }) { } isEditing.set(false); }); + const formEdit = "edit"; /** @type {ddeElementAddon} */ const onSubmitEdit = on("submit", event => { event.preventDefault(); - const input = /** @type {HTMLFormElement} */(event.target).elements.namedItem("edit"); + const input = /** @type {HTMLFormElement} */(event.target).elements.namedItem(formEdit); const value = /** @type {HTMLInputElement} */(input).value.trim(); if (value) { dispatchEdit({ id, title: value }); @@ -207,18 +199,17 @@ function TodoItem({ id, title, completed }) { checked: completed }, onToggleCompleted), el("label", { textContent: title }, onStartEdit), - el("button", { className: "destroy" }, onDelete) + el("button", { ariaLabel: "Delete todo", className: "destroy" }, onDelete) ), - S.el(isEditing, editing => editing - ? el("form", null, onSubmitEdit).append( + S.el(isEditing, editing => !editing + ? el() + : el("form", null, onSubmitEdit).append( el("input", { className: "edit", - name: "edit", + name: formEdit, value: title, - "data-id": id }, onBlurEdit, onKeyDown, addFocus) ) - : el() ) ); } @@ -342,6 +333,7 @@ function todosSignal(){ localStorage.setItem(store_key, JSON.stringify(value)); } catch (e) { console.error("Failed to save todos to localStorage", e); + // Optionally, provide user feedback } }); return out; @@ -350,20 +342,30 @@ function todosSignal(){ /** * Creates a signal for managing route state * - * @param {typeof S} signal - The signal constructor + * @param {typeof S} signal - The signal constructor from a library + * @param {AbortSignal} abortSignal */ -function routerSignal(signal){ +function routerSignal(signal, abortSignal){ const initial = location.hash.replace("#", "") || "all"; - return signal(initial, { + const out = signal(initial, { /** * Set the current route * @param {"all"|"active"|"completed"} hash - The route to set */ set(hash){ location.hash = hash; - this.value = hash; - } + //this.value = hash; + }, }); + + // Setup hash change listener + window.addEventListener("hashchange", () => { + const hash = location.hash.replace("#", "") || "all"; + //S.action(out, "set", /** @type {"all"|"active"|"completed"} */(hash)); + out.set(hash); + }, { signal: abortSignal }); + + return out; } /** diff --git a/docs/components/examples/signals/actions-todos.js b/docs/components/examples/signals/actions-todos.js index 9a15932..a69f824 100644 --- a/docs/components/examples/signals/actions-todos.js +++ b/docs/components/examples/signals/actions-todos.js @@ -7,7 +7,7 @@ const todos= S([], { const removed= this.value.pop(); if(removed) S.clear(removed); }, - [S.symbols.onclear](){ // this covers `O.clear(todos)` + [S.symbols.onclear](){ // this covers `S.clear(todos)` S.clear(...this.value); } }); diff --git a/docs/components/getLibraryUrl.html.js b/docs/components/getLibraryUrl.html.js new file mode 100644 index 0000000..9f02992 --- /dev/null +++ b/docs/components/getLibraryUrl.html.js @@ -0,0 +1,83 @@ +import { styles } from "../ssr.js"; + +styles.css` +#library-url-form { + display: flex; + flex-flow: column nowrap; + gap: 1rem; + padding: 1.5rem; + border-radius: var(--border-radius); + background-color: var(--bg-sidebar); + box-shadow: var(--shadow); + border: 1px solid var(--border); + margin: 1.5rem 0; +} + +#library-url-form .selectors { + display: flex; + flex-flow: row wrap; + gap: 0.75rem; +} + +#library-url-form output { + display: flex; + flex-flow: column nowrap; + gap: 0.75rem; + margin-top: 0.5rem; +} + +#library-url-form output p { + font-weight: 500; + margin: 0.25rem 0; + color: var(--text-light); +} + +#library-url-form .url-title { + display: flex; + align-items: center; + gap: 0.5rem; + margin-bottom: -0.25rem; +} + +#library-url-form .url-title strong { + font-family: var(--font-mono); + font-size: 0.95rem; +} + +#library-url-form .url-title span { + color: var(--text-light); + font-size: 0.9rem; +} + +#library-url-form .code { + margin-bottom: 1rem; +} + +#library-url-form .info-text { + font-size: 0.9rem; + font-style: italic; + margin-top: 1rem; + color: var(--text-light); +} + +@media (max-width: 768px) { + #library-url-form .selectors { + flex-direction: column; + } + + #library-url-form select { + width: 100%; + } +} +`; + +import { el } from "deka-dom-el"; +import { ireland } from "./ireland.html.js"; + +export function getLibraryUrl({ page_id }){ + return el(ireland, { + src: new URL("./getLibraryUrl.js.js", import.meta.url), + exportName: "getLibraryUrl", + page_id, + }); +} diff --git a/docs/components/getLibraryUrl.js.js b/docs/components/getLibraryUrl.js.js new file mode 100644 index 0000000..786ed3c --- /dev/null +++ b/docs/components/getLibraryUrl.js.js @@ -0,0 +1,92 @@ +import { el, on } from "deka-dom-el"; +import { S } from "deka-dom-el/signals"; + +const url_base= { + jsdeka: "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/", +}; + +export function getLibraryUrl(){ + const lib= S([ "esm", "-with-signals", ".min" ]); + const url= S(()=> url_base.jsdeka+lib.get().join("")); + const urlLabel= S(() => { + const [format, signalsPart, minified] = lib.get(); + const formatText = format === "esm" ? "ES Module" : "IIFE"; + const signalsText = signalsPart ? " with signals" : ""; + const minText = minified ? " (minified)" : ""; + return `${formatText}${signalsText}${minText}`; + }) + const onSubmit= on("submit", ev => { + ev.preventDefault(); + const form= new FormData(/** @type {HTMLFormElement} */ (ev.target)); + lib.set([ + "module", + "what", + "minified", + ].map(name => /** @type {string} */(form.get(name)))); + }); + const onChangeSubmit= on("change", + ev=> /** @type {HTMLSelectElement} */(ev.target).form.requestSubmit() + ); + + return el("form", { id: "library-url-form" }, onSubmit).append( + el("h4", "Select your preferred library format:"), + el("div", { className: "selectors" }).append( + el("select", { name: "module" }, onChangeSubmit, + on.defer(select => select.value = lib.get()[0]), + ).append( + el("option", { value: "esm", textContent: "ESM — modern JavaScript module" }), + el("option", { value: "iife", textContent: "IIFE — legacy JavaScript with DDE global variable" }), + ), + el("select", { name: "what" }, onChangeSubmit, + on.defer(select => select.value = lib.get()[1]), + ).append( + el("option", { value: "", textContent: "DOM part only" }), + el("option", { value: "-with-signals", textContent: "DOM + signals" }), + ), + el("select", { name: "minified" }, onChangeSubmit, + on.defer(select => select.value = lib.get()[2]), + ).append( + el("option", { value: "", textContent: "Unminified" }), + el("option", { value: ".min", textContent: "Minified" }), + ), + ), + el("output").append( + el("div", { className: "url-title" }).append( + el("strong", "JavaScript:"), + el("span", urlLabel), + ), + el(code, { value: S(()=> url.get()+".js") }), + el("div", { className: "url-title" }).append( + el("strong", "TypeScript definition:") + ), + el(code, { value: S(()=> url.get()+".d.ts") }), + el("p", { className: "info-text", + textContent: "Use the CDN URL in your HTML or import it in your JavaScript files." + }) + ) + ) +} +/** @param {{ value: ddeSignal }} props */ +function code({ value }){ + /** @type {ddeSignal<"Copy"|"Copied!">} */ + const textContent= S("Copy"); + const onCopy= on("click", () => { + navigator.clipboard.writeText(value.get()); + + textContent.set("Copied!"); + setTimeout(() => { + textContent.set("Copy"); + }, 1500); + }); + return el("div", { className: "code", dataJs: "done", tabIndex: 0 }).append( + el("code").append( + el("pre", value), + ), + el("button", { + className: "copy-button", + textContent, + ariaLabel: "Copy code to clipboard", + }, onCopy) + ) + ; +} diff --git a/docs/components/ireland.html.js b/docs/components/ireland.html.js index 8387664..15b42e2 100644 --- a/docs/components/ireland.html.js +++ b/docs/components/ireland.html.js @@ -1,3 +1,33 @@ +import { styles } from "../ssr.js"; +styles.css` +[data-dde-mark] { + opacity: .5; + filter: grayscale(); + + @media (prefers-reduced-motion: no-preference) { + animation: fadein 2s infinite ease forwards;; + } + + position: relative; + &::after { + content: "Loading Ireland…"; + background-color: rgba(0, 0, 0, .5); + color: white; + font-weight: bold; + border-radius: 5px; + padding: 5px 10px; + position: absolute; + top: 3%; + left: 50%; + transform: translateX(-50%); + } +} +@keyframes fadein { + from { opacity: .5; } + to { opacity: .85; } +} +`; + import { el, queue } from "deka-dom-el"; import { addEventListener, registerClientFile } from "../ssr.js"; import { relative } from "node:path"; @@ -21,10 +51,17 @@ export function ireland({ src, exportName = "default", props = {} }) { const path= "./"+relative(dir, src.pathname); const id = "ireland-" + generateComponentId(src); const element = el.mark({ type: "later", name: ireland.name }); - queue(import(path).then(module => { - const component = module[exportName]; - element.replaceWith(el(component, props, mark(id))); - })); + queue( + import(path) + .then(module => { + const component = module[exportName]; + const content= el(component, props, mark(id)); + element.replaceWith(content); + content.querySelectorAll("input, textarea, button") + .forEach(el=> el.disabled= true); + }) + .catch(console.error) + ); if(!componentsRegistry.size) addEventListener("oneachrender", registerClientPart); diff --git a/docs/components/mnemonic/signals-init.js b/docs/components/mnemonic/signals-init.js index 2e29529..6e4429e 100644 --- a/docs/components/mnemonic/signals-init.js +++ b/docs/components/mnemonic/signals-init.js @@ -14,10 +14,6 @@ export function mnemonic(){ el("code", "S.on(, [, ])"), " — listen to the signal value changes", ), - el("li").append( - el("code", "S.clear(...)"), - " — off and clear signals", - ), el("li").append( el("code", "S(, )"), " — signal: pattern to create complex reactive objects/arrays", @@ -29,6 +25,11 @@ export function mnemonic(){ el("li").append( el("code", "S.el(, )"), " — render partial dom structure (template) based on the current signal value", - ) + ), + el("li").append( + el("code", "S.clear(...)"), + " — off and clear signals (most of the time it is not needed as reactive ", + "attributes and elements are cleared automatically)", + ), ); } diff --git a/docs/components/scrollTop.css.js b/docs/components/scrollTop.html.js similarity index 75% rename from docs/components/scrollTop.css.js rename to docs/components/scrollTop.html.js index da37671..152b851 100644 --- a/docs/components/scrollTop.css.js +++ b/docs/components/scrollTop.html.js @@ -37,3 +37,14 @@ styles.css` } } `; + +import { el } from "deka-dom-el"; +import { ireland } from "./ireland.html.js"; + +export function scrollTop(){ + return el(ireland, { + src: new URL("./scrollTop.js.js", import.meta.url), + exportName: "scrollTop", + page_id: "*", + }); +} diff --git a/docs/global.css.js b/docs/global.css.js index eca1342..11241cd 100644 --- a/docs/global.css.js +++ b/docs/global.css.js @@ -86,7 +86,7 @@ html { } :focus-visible { - outline: 3px solid hsl(231, 48%, 70%); + outline: 3px solid var(--primary-light); outline-offset: 2px; } @@ -193,6 +193,34 @@ pre code { background-color: transparent; padding: 0; } +figure { + width: 100%; + text-align: center; + color: var(--text-light); + border: 1px dashed var(--border); + border-radius: var(--border-radius); + + img { + object-fit: contain; + border-radius: var(--border-radius); + box-shadow: var(--shadow); + max-width: 100%; + } +} +select { + padding: 0.5rem 0.75rem; + border-radius: var(--border-radius); + border: 1px solid var(--border); + background-color: var(--bg); + color: var(--text); + cursor: pointer; + font-size: 0.95rem; + font-family: var(--font-main); +} + +select:hover { + border-color: var(--primary); +} /* Layout */ body { @@ -234,7 +262,7 @@ body > main { } body > main > *, body > main slot > * { width: 100%; - max-width: 100%; + max-width: calc(var(--body-max-width) * 5/3); margin-inline: auto; grid-column: main; } @@ -267,9 +295,8 @@ body > main h3, body > main h4 { /* Boxes */ .illustration{ grid-column: full-main; - width: calc(100% - .75em); } -.illustration:not(:has( .comparison)){ +.illustration:not(:has( .comparison)):not(:has( .tabs)) { grid-column: main; pre { diff --git a/docs/index.html.js b/docs/index.html.js index bfcf6a8..b0bec30 100644 --- a/docs/index.html.js +++ b/docs/index.html.js @@ -1,3 +1,4 @@ +import "./components/getLibraryUrl.html.js"; import { t, T } from "./utils/index.js"; export const info= { href: "./", @@ -11,6 +12,7 @@ import { simplePage } from "./layout/simplePage.html.js"; import { h3 } from "./components/pageUtils.html.js"; import { example } from "./components/example.html.js"; import { code } from "./components/code.html.js"; +import { getLibraryUrl } from "./components/getLibraryUrl.html.js"; /** @param {string} url */ const fileURL= url=> new URL(url, import.meta.url); const references= { @@ -27,13 +29,13 @@ const references= { export function page({ pkg, info }){ const page_id= info.id; return el(simplePage, { info, pkg }).append( - el("p").append(...T` + el("p").append(T` Welcome to Deka DOM Elements (dd or DDE) — a lightweight library for building dynamic UIs with a declarative syntax that stays close to the native DOM API. dd gives you powerful reactive tools without the complexity and overhead of larger frameworks. `), el("div", { className: "callout" }).append( - el("h4", t`What Makes dd Special`), + el("h4", t`Key Benefits of dd`), el("ul").append( el("li", t`No build step required — use directly in the browser`), el("li", t`Lightweight core (~10–15kB minified) without unnecessary dependencies (0 at now 😇)`), @@ -44,8 +46,8 @@ export function page({ pkg, info }){ ), 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("p").append(...T` + el(h3, { textContent: t`The 3PS Pattern: Simplified architecture pattern`, id: "h-3ps" }), + el("p").append(T` At the heart of dd 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 to reason about. @@ -62,67 +64,98 @@ export function page({ pkg, info }){ ) ) ), - el("p").append(...T` + el("p").append(T` The 3PS pattern separates your code into three clear parts: `), el("ol").append( - el("li").append(...T` + el("li").append(T` ${el("strong", "Create State")}: Define your application’s reactive data using signals `), - el("li").append(...T` - ${el("strong", "Bind to Elements")}: Define how UI elements react to state changes + el("li").append(T` + ${el("strong", "React to Changes")}: Define how UI elements and other parts of your app 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("p").append(...T` + el("p").append(T` 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", - ...references.w_mvv })} and ${el("a", { textContent: "MVC", ...references.w_mvc })}, but with less - overhead and complexity. + approach ${el("strong", "is not")} something new and/or special to dd. It’s based on ${el("a", { + textContent: "MVC", ...references.w_mvc })} (${el("a", { textContent: "MVVM", ...references.w_mvv })}), + but is there presented in simpler form. `), 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 reusable pieces of UI with encapsulated state and behavior. You’ll learn more about this in the following sections. + `), + el("p").append(T` + The 3PS pattern isn’t required to use with dd but it is good practice to follow it or some similar + software architecture. `) ), + el(h3, t`Getting Started`), + el("p").append(T` + There are multiple ways to include dd in your project. You can use npm for a full development setup, + or directly include it from a CDN for quick prototyping. + `), + el("h4", "npm installation"), + el(code, { content: "npm install deka-dom-el # Coming soon", language: "shell", page_id }), + el("h4", "CDN / Direct Script Usage"), + el("p").append(T` + Use the interactive selector below to choose your preferred format: + `), + el(getLibraryUrl, { page_id }), + el("div", { className: "note" }).append( + el("p").append(T` + Based on your selection, you can use dd in your project like this: + `), + el(code, { content: ` + // ESM format (modern JavaScript with import/export) + import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.min.js"; + + // Or with IIFE format (creates a global DDE object) + // + const { el, on } = DDE; + `, language: "js", page_id }), + ), + el(h3, t`How to Use This Documentation`), - el("p").append(...T` + el("p").append(T` This guide will take you through dd’s features step by step: `), 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`), - 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`), - 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`), - 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`), - 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`), - 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`), - 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`), - 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`), - 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`), - 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("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`), - 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`), ), - el("p").append(...T` + el("p").append(T` Each section builds on the previous ones, so we recommend following them in order. Let’s get started with the basics of creating elements! `), diff --git a/docs/layout/simplePage.html.js b/docs/layout/simplePage.html.js index 1a603b0..328d469 100644 --- a/docs/layout/simplePage.html.js +++ b/docs/layout/simplePage.html.js @@ -3,10 +3,7 @@ import { el, simulateSlots } from "deka-dom-el"; import { header } from "./head.html.js"; import { prevNext } from "../components/pageUtils.html.js"; -import { ireland } from "../components/ireland.html.js"; -import "../components/scrollTop.css.js"; -/** @param {string} url */ -const fileURL= url=> new URL(url, import.meta.url); +import { scrollTop } from "../components/scrollTop.html.js"; /** @param {Pick} attrs */ export function simplePage({ pkg, info }){ @@ -33,6 +30,6 @@ export function simplePage({ pkg, info }){ ), // Scroll to top button - el(ireland, { src: fileURL("../components/scrollTop.js.js"), exportName: "scrollTop" }) + el(scrollTop), )); } diff --git a/docs/p02-elements.html.js b/docs/p02-elements.html.js index ab7b0cc..bda75bf 100644 --- a/docs/p02-elements.html.js +++ b/docs/p02-elements.html.js @@ -49,7 +49,7 @@ const references= { export function page({ pkg, info }){ const page_id= info.id; 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. dd provides a simple yet powerful approach to element creation that is declarative, chainable, 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(h3, t`Creating Elements: Native vs dd`), - el("p").append(...T` + el("p").append(T` In standard JavaScript, you create DOM elements using the ${el("a", references.mdn_create).append(el("code", "document.createElement()"))} method 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")} with enhanced property assignment. `), el(example, { src: fileURL("./components/examples/elements/dekaCreateElement.js"), page_id }), el(h3, t`Advanced Property Assignment`), - el("p").append(...T` + el("p").append(T` The ${el("code", "assign")} function is the heart of dd’s element property handling. It is internally 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 })} @@ -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("dt", t`Data and ARIA Attributes`), - el("dd").append(...T`Both ${el("code", "dataset")}.* and ${el("code", "data-")}* syntaxes supported - (same for ${el("em", "ARIA")})`), + el("dd").append(T`Both ${el("code", "dataset.keyName")} and ${el("code", "dataKeyName")} syntaxes are + supported (same for ${el("code", "aria")}/${el("code", "ariaset")})`), 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("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")}) and ${el("code", "classList")} object for toggling classes`), 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`), 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("div", { className: "note" }).append( - el("p").append(...T` + el("p").append(T` You can explore standard HTML element properties in the MDN documentation for ${el("a", { textContent: "HTMLElement", ...references.mdn_el })} (base class) 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("p").append(...T` + el("p").append(T` One of the most powerful features of dd is its approach to building element trees. Unlike the native DOM API which doesn’t return the parent after ${el("code", "append()")}, dd’s ${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. 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(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. This lets you refactor complex UI trees into reusable pieces: `), 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. This makes it easy to pass data down to components and create reusable UI fragments. `), el("div", { className: "tip" }).append( - el("p").append(...T` + el("p").append(T` It’s 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. `), - el("p").append(...T` + el("p").append(T` 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: ${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("p").append(...T` + el("p").append(T` For non-HTML elements like SVG, MathML, or custom namespaces, dd provides the ${el("code", "elNS")} function which corresponds to the native ${el("a", references.mdn_ns).append(el("code", "document.createElementNS"))}: `), 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 using the same consistent interface. `), el(h3, t`Best Practices for Declarative DOM Creation`), el("ol").append( - el("li").append(...T` + el("li").append(T` ${el("strong", "Use component functions for reusable UI fragments:")} Extract common UI patterns into reusable functions that return elements. `), - el("li").append(...T` + el("li").append(T` ${el("strong", "Leverage destructuring for cleaner component code:")} Use ${el("a", { textContent: "destructuring", ...references.mdn_destruct })} to extract properties 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("code", ".append()")} to build complex DOM trees for better performance and cleaner code. `), diff --git a/docs/p03-events.html.js b/docs/p03-events.html.js index 3e59a22..acbd302 100644 --- a/docs/p03-events.html.js +++ b/docs/p03-events.html.js @@ -41,7 +41,7 @@ const references= { export function page({ pkg, info }){ const page_id= info.id; return el(simplePage, { info, pkg }).append( - el("p").append(...T` + el("p").append(T` Events are at the core of interactive web applications. dd provides a clean, declarative approach to handling DOM events and extends this pattern with a powerful Addon system to incorporate additional 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(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 ${el("a", references.mdn_listen).append(el("code", "element.addEventListener(type, listener, options)"))}. dd 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’s approach is that it works as an Addon (see below), making it easy to integrate directly into element declarations. `), @@ -86,15 +86,15 @@ export function page({ pkg, info }){ el(h3, t`Removing Event Listeners`), el("div", { className: "note" }).append( - el("p").append(...T` - Unlike the native addEventListener/removeEventListener pattern, dd uses the ${el("a", { - textContent: "AbortSignal", ...references.mdn_abortListener })} for declarative approach for removal: + el("p").append(T` + Unlike the native addEventListener/removeEventListener pattern, dd uses ${el("strong", "only")} + ${el("a", { textContent: "AbortSignal", ...references.mdn_abortListener })} for declarative removal: `) ), 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 ( - see scopes and extensions section). + see scopes and extensions section — mainly ${el("code", "scope.signal")}). `), el(h3, t`Three Ways to Handle Events`), @@ -102,7 +102,7 @@ export function page({ pkg, info }){ el("div", { className: "tab", dataTab: "html-attr" }).append( el("h4", t`HTML Attribute Style`), 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 ${el("code", ``)}. This can be particularly 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").append(...T` + el("p").append(T` For a deeper comparison of these approaches, see ${el("a", { textContent: "WebReflection’s detailed analysis", ...references.web_events })}. `), el(h3, t`Understanding Addons`), - el("p").append(...T` + el("p").append(T` Addons are a powerful pattern in dd that extends beyond just event handling. An Addon is any function that accepts an HTML element as its first parameter. `), @@ -139,24 +139,24 @@ export function page({ pkg, info }){ 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 extend your templates with additional functionality: `), 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 ${el("code", "ddeElementAddon")}. Notice how Addons can also be used to get element references. `), el(h3, t`Lifecycle Events`), - el("p").append(...T` + el("p").append(T` Addons are called immediately when an element is created, even before it’s 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 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 and component patterns: `), el("div", { className: "function-table" }).append( el("dl").append( @@ -170,7 +170,7 @@ export function page({ pkg, info }){ el(example, { src: fileURL("./components/examples/events/live-cycle.js"), page_id }), el("div", { className: "note" }).append( - el("p").append(...T` + el("p").append(T` For regular elements (non-custom elements), dd uses ${el("a", references.mdn_mutation).append(el("code", "MutationObserver"), " | MDN")} internally to track lifecycle events. @@ -179,28 +179,41 @@ export function page({ pkg, info }){ el("div", { className: "warning" }).append( el("ul").append( - el("li").append(...T` + el("li").append(T` 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 names prefixed with ${el("code", "dde:")}. `), - el("li").append(...T` + el("li").append(T` 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 `), - el("li").append(...T` + el("li").append(T` …see section later in documentation regarding hosts elements `), - el("li").append(...T` + el("li").append(T` dd ensures that connected/disconnected events fire only once for better predictability `) ) ), + el(h3, t`Utility Helpers`), + el("p").append(T` + You can use the ${el("code", "on.defer")} helper to defer execution to the next event loop. + This is useful for example when you wan to set some element properties based on the current element + body (typically the ${el("code", "

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 ZaJ&ln@Md5Z({F@FQjk%WE`Mhj^j{1EJIeq7 literal 0 HcmV?d00001 diff --git a/docs/components/code.html.js b/docs/components/code.html.js index 7d2736f..6425412 100644 --- a/docs/components/code.html.js +++ b/docs/components/code.html.js @@ -184,7 +184,7 @@ import { el } from "deka-dom-el"; * @param {string} [attrs.className] * @param {URL} [attrs.src] Example code file path * @param {string} [attrs.content] Example code - * @param {"js"|"ts"|"html"|"css"} [attrs.language="js"] Language of the code + * @param {"js"|"ts"|"html"|"css"|"shell"} [attrs.language="js"] Language of the code * @param {string} [attrs.page_id] ID of the page, if setted it registers shiki * */ export function code({ id, src, content, language= "js", className= host.slice(1), page_id }){ diff --git a/docs/components/converter.html.js b/docs/components/converter.html.js new file mode 100644 index 0000000..fc9db56 --- /dev/null +++ b/docs/components/converter.html.js @@ -0,0 +1,176 @@ +import { styles } from "../ssr.js"; + +styles.css` +#html-to-dde-converter { + grid-column: full-main; + display: flex; + flex-direction: column; + gap: 1.5rem; + padding: 1.5rem; + border-radius: var(--border-radius); + background-color: var(--bg-sidebar); + box-shadow: var(--shadow); + border: 1px solid var(--border); +} + +#html-to-dde-converter h3 { + margin-top: 0; + color: var(--primary); +} + +#html-to-dde-converter .description { + color: var(--text-light); + font-size: 0.95rem; + margin-top: -1rem; +} + +#html-to-dde-converter .converter-form { + display: flex; + flex-direction: column; + gap: 1rem; +} + +#html-to-dde-converter .input-group, +#html-to-dde-converter .output-group { + display: flex; + flex-direction: column; + gap: 0.5rem; +} +#html-to-dde-converter [type="number"]{ + width: 3em; + font-variant-numeric: tabular-nums; + font-size: 1rem; +} + +#html-to-dde-converter label { + font-weight: 500; + display: flex; + justify-content: space-between; +} + +#html-to-dde-converter .options { + display: flex; + flex-wrap: wrap; + gap: 1rem; + margin-bottom: 0.5rem; +} + +#html-to-dde-converter .option-group { + display: flex; + align-items: center; + gap: 0.5rem; +} + +#html-to-dde-converter textarea { + font-family: var(--font-mono); + font-size: 0.9rem; + padding: 1rem; + border-radius: var(--border-radius); + border: 1px solid var(--border); + background-color: var(--bg); + color: var(--text); + min-height: 200px; + height: 25em; + resize: vertical; +} + +#html-to-dde-converter textarea:focus { + outline: 2px solid var(--primary-light); + outline-offset: 1px; +} + +#html-to-dde-converter .button-group { + display: flex; + gap: 0.5rem; + justify-content: space-between; + align-items: center; +} + +#html-to-dde-converter button { + padding: 0.5rem 1rem; + border-radius: var(--border-radius); + border: none; + background-color: var(--primary); + color: var(--button-text); + font-weight: 500; + cursor: pointer; + transition: background-color 0.2s ease; +} + +#html-to-dde-converter button:hover { + background-color: var(--primary-dark); +} + +#html-to-dde-converter button.secondary { + background-color: transparent; + border: 1px solid var(--border); + color: var(--text); +} + +#html-to-dde-converter button.secondary:hover { + background-color: var(--bg); + border-color: var(--primary); +} + +#html-to-dde-converter .copy-button { + background-color: var(--secondary); +} + +#html-to-dde-converter .copy-button:hover { + background-color: var(--secondary-dark); +} + +#html-to-dde-converter .status { + font-size: 0.9rem; + color: var(--text-light); +} + +#html-to-dde-converter .error { + color: hsl(0, 100%, 60%); + font-size: 0.9rem; + margin-top: 0.5rem; +} + +/* Sample HTML examples list */ +#html-to-dde-converter .examples-list { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + margin-top: 0.5rem; +} + +#html-to-dde-converter .example-button { + font-size: 0.85rem; + padding: 0.25rem 0.5rem; +} +`; + +import { ireland } from "./ireland.html.js"; +import { el } from "deka-dom-el"; +const fileURL= url=> new URL(url, import.meta.url); + +export function converter({ page_id }){ + registerClientPart(page_id); + return el(ireland, { + src: fileURL("./converter.js.js"), + exportName: "converter", + page_id, + }); +} + +let is_registered= {}; +/** @param {string} page_id */ +function registerClientPart(page_id){ + if(is_registered[page_id]) return; + + document.head.append( + el("script", { + // src: "https://unpkg.com/@beforesemicolon/html-parser/dist/client.js", + src: "https://cdn.jsdelivr.net/npm/@beforesemicolon/html-parser/dist/client.js", + type: "text/javascript", + charset: "utf-8", + defer: true + }), + ); + is_registered[page_id]= true; +} diff --git a/docs/components/converter.js.js b/docs/components/converter.js.js new file mode 100644 index 0000000..f99fca7 --- /dev/null +++ b/docs/components/converter.js.js @@ -0,0 +1,384 @@ +import { el, on } from "deka-dom-el"; +import { S } from "deka-dom-el/signals"; +const { parse }= globalThis.BFS || { parse(){ return { children: [ "not implemented" ] } } }; +// Example HTML snippets +const examples = [ +{ + name: "Simple Component", + html: `