From 4c450ae76359167d851cac1fa7364391c73818dd Mon Sep 17 00:00:00 2001 From: Jan Andrle Date: Wed, 19 Mar 2025 17:10:43 +0100 Subject: [PATCH] :zap: :bug: :abc: v0.9.4-alpha (#42) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :bug: fixes #41 * :zap: adjust package size limits * :abc: * :tv: requestIdleCallback doesn need to be global * :abc: corrects irland page headers * :tv: version * :zap: Signal ← SignalReadonly * :bug: ensures only one disconncetd listener …for cleanup * :zap: :abc: Better build and improve texting * :bug: logo alignemt (due to gh) * :abc: md enhancements * :abc: :zap: products --- CONTRIBUTING.md | 9 +- README.md | 61 +-- bs/docs.js | 3 +- dist/esm-with-signals.js | 35 +- dist/esm-with-signals.min.js | 6 +- dist/esm.js | 10 +- dist/esm.min.js | 2 +- dist/iife-with-signals.js | 35 +- dist/iife-with-signals.min.js | 4 +- dist/iife.js | 10 +- dist/iife.min.js | 2 +- docs/components/code.html.js | 22 +- docs/components/converter.html.js | 5 +- docs/components/example.html.js | 5 +- .../examples/case-studies/data-dashboard.js | 1 + .../examples/case-studies/products.js | 501 ++++++++++++++++++ .../examples/case-studies/task-manager.js | 2 +- .../examples/elements/dde-dom-create.js | 4 +- .../examples/elements/dde-dom-tree.js | 4 +- docs/components/examples/reallife/todomvc.js | 13 +- docs/components/getLibraryUrl.html.js | 4 +- docs/components/ireland.html.js | 1 - docs/components/mnemonic/events-init.js | 4 + docs/index.html.js | 39 +- docs/p02-elements.html.js | 27 +- docs/p03-events.html.js | 31 +- docs/p04-signals.html.js | 43 +- docs/p05-scopes.html.js | 17 +- docs/p06-customElement.html.js | 15 +- docs/p07-debugging.html.js | 19 +- docs/p08-extensions.html.js | 15 +- docs/p09-optimization.html.js | 19 +- docs/p10-todomvc.html.js | 83 +-- docs/p11-ssr.html.js | 15 +- docs/p12-ireland.html.js | 22 +- docs/p13-appendix.html.js | 3 +- docs/p14-converter.html.js | 3 +- docs/p15-examples.html.js | 32 +- docs/ssr.js | 4 + package-lock.json | 4 +- package.json | 13 +- src/dom-lib/events-observer.js | 11 +- src/helpers.js | 9 + src/signals-lib/signals-lib.js | 26 +- 44 files changed, 854 insertions(+), 339 deletions(-) create mode 100644 docs/components/examples/case-studies/products.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0247d8c..46b2d55 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -75,11 +75,14 @@ where everyone feels comfortable participating. …see [BS folder](./bs/README.md) for more info. +## Categorizing [![git3moji](https://img.shields.io/badge/git3moji%E2%80%93v1-%E2%9A%A1%EF%B8%8F%F0%9F%90%9B%F0%9F%93%BA%F0%9F%91%AE%F0%9F%94%A4-fffad8.svg?style=flat-square)](https://robinpokorny.github.io/git3moji/) +We use [git3moji](https://git3moji.netlify.app/) for commit messages, issue titles, pull request titles and in other +areas. To make categorizing quick and consistent. + ## Commit Guidelines -We use -[![git3moji](https://img.shields.io/badge/git3moji%E2%80%93v1-%E2%9A%A1%EF%B8%8F%F0%9F%90%9B%F0%9F%93%BA%F0%9F%91%AE%F0%9F%94%A4-fffad8.svg?style=flat-square)](https://robinpokorny.github.io/git3moji/) -for commit messages. This helps keep the commit history clear and consistent. +We use [git3moji](https://git3moji.netlify.app/) for commit messages. This helps keep the commit history clear and +consistent. ``` :emoji: Short summary of the change diff --git a/README.md b/README.md index a9b94f2..6ac927c 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,11 @@ **Alpha** -| [source code on GitHub](https://github.com/jaandrle/deka-dom-el) -| [*mirrored* on Gitea](https://gitea.jaandrle.cz/jaandrle/deka-dom-el) -| [![git3moji](https://img.shields.io/badge/git3moji%E2%80%93v1-%E2%9A%A1%EF%B8%8F%F0%9F%90%9B%F0%9F%93%BA%F0%9F%91%AE%F0%9F%94%A4-fffad8.svg?style=flat-square)](https://robinpokorny.github.io/git3moji/) - -

- Deka DOM Elements Logo -

- -# Deka DOM Elements (dd\ or DDE) +| [Docs](https://jaandrle.github.io/deka-dom-el "Official documentation and guide site") +| [NPM](https://www.npmjs.com/package/deka-dom-el "Official NPM package page") +| [GitHub](https://github.com/jaandrle/deka-dom-el "Official GitHub repository") +([*Gitea*](https://gitea.jaandrle.cz/jaandrle/deka-dom-el "GitHub repository mirror on my own Gitea instance")) ***Vanilla for flavouring — a full-fledged feast for large projects*** -*…use simple DOM API by default and library tools and logic when you need them* - ```javascript // 🌟 Reactive component with clear separation of concerns document.body.append( @@ -20,28 +13,23 @@ document.body.append( ); function EmojiCounter({ initial }) { - // ✨ State - Define reactive data + // ✨ - Define reactive data const count = S(0); const emoji = S(initial); + const textContent = S(() => `Hello World ${emoji.get().repeat(count.get())}`); - /** @param {HTMLOptionElement} el */ - const isSelected= el=> (el.selected= el.value===initial); - - // 🔄 View - UI updates automatically when signals change + // 🔄 - UI updates automatically when signals change return el().append( - el("p", { - className: "output", - textContent: S(() => - `Hello World ${emoji.get().repeat(count.get())}`), - }), + el("p", { textContent, className: "output" }), - // 🎮 Controls - Update state on events + // 🎮 - Update state on events el("button", { textContent: "Add Emoji" }, - on("click", () => count.set(count.get() + 1)) + on("click", () => count.set(count.get() + 1)), ), - el("select", null, on.defer(el=> el.value= initial), - on("change", e => emoji.set(e.target.value)) + el("select", null, + on.defer(el=> el.value= initial), + on("change", e => emoji.set(e.target.value)), ).append( el(Option, "🎉"), el(Option, "🚀"), @@ -53,6 +41,13 @@ function Option({ textContent }){ return el("option", { value: textContent, textContent }); } ``` +*…use simple DOM API by default and library tools and logic when you need them* + +

+ Deka DOM Elements Logo +

+ +# Deka DOM Elements (dd\ or DDE) Creating reactive elements, components, and Web Components using the native [IDL](https://developer.mozilla.org/en-US/docs/Glossary/IDL)/JavaScript DOM API enhanced with @@ -64,19 +59,21 @@ Creating reactive elements, components, and Web Components using the native - ☑️ **Lightweight** — ~10-15kB minified (original goal 10kB) with **zero**/minimal dependencies - ✅ **Declarative & functional approach** for clean, maintainable code - ✅ **Signals and events** for reactive UI +- ✅ **Auto-releasing resources** for memory management but nice development experience - ✅ **Memoization for performance** — optimize rendering with intelligent caching -- ✅ **Optional build-in signals** with support for custom reactive implementations (#39) -- ✅ **Server-side rendering** support via [jsdom](https://github.com/jsdom/jsdom) +- ☑️ **Optional build-in signals** with support for custom reactive implementations (#39) +- ☑️ **Server-side rendering** support via [jsdom](https://github.com/jsdom/jsdom) - ✅ **TypeScript support** -- ☑️ **Support for debugging with browser DevTools** without extensions +- ✅ **Support for debugging with browser DevTools** without extensions - ☑️ **Enhanced Web Components** support ## Getting Started -### Documentation +### Quick Links - [**Documentation and Guide**](https://jaandrle.github.io/deka-dom-el) - [**Examples**](https://jaandrle.github.io/deka-dom-el/p15-examples.html) +- [**Changelog**](https://github.com/jaandrle/deka-dom-el/releases) ### Installation @@ -87,7 +84,7 @@ npm install deka-dom-el --save …or via 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. +format selector](https://jaandrle.github.io/deka-dom-el/#h-getting-started) on the documentation site. ```html @@ -141,9 +138,9 @@ get started, coding standards, commit guidelines, and the pull request process. 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 - [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 +- [jaandrle/dollar_dom_component](https://github.com/jaandrle/dollar_dom_component) — + Functional DOM components without JSX/virtual DOM (my old library) diff --git a/bs/docs.js b/bs/docs.js index 76d6501..1e34dd6 100755 --- a/bs/docs.js +++ b/bs/docs.js @@ -2,7 +2,7 @@ /* jshint esversion: 11,-W097, -W040, module: true, node: true, expr: true, undef: true *//* global echo, $, pipe, s, fetch, cyclicLoop */// editorconfig-checker-disable-line echo("Building static documentation files…"); echo("Preparing…"); -import { path_target, pages as pages_registered, styles, dispatchEvent, t } from "../docs/ssr.js"; +import { path_target, pages as pages_registered, styles, currentPageId, dispatchEvent, t } from "../docs/ssr.js"; import { createHTMl } from "./docs/jsdom.js"; import { register, queue } from "../jsdom.js"; const pkg= s.cat("package.json").xargs(JSON.parse); @@ -28,6 +28,7 @@ for(const { id, info } of pages){ ); const { el }= await register(serverDOM.dom); const { page }= await import(`../docs/${id}.html.js`); + currentPageId(id) serverDOM.document.body.append( el(page, { pkg, info }), ); diff --git a/dist/esm-with-signals.js b/dist/esm-with-signals.js index 75f5c8e..8516977 100644 --- a/dist/esm-with-signals.js +++ b/dist/esm-with-signals.js @@ -41,6 +41,11 @@ function observedAttributes(instance, observedAttribute2) { function kebabToCamel(name) { return name.replace(/-./g, (x) => x[1].toUpperCase()); } +function requestIdle() { + return new Promise(function(resolve) { + (globalThis.requestIdleCallback || requestAnimationFrame)(resolve); + }); +} // src/dom-lib/common.js var enviroment = { @@ -179,11 +184,6 @@ function connectionsChangesObserverConstructor() { is_observing = false; observer.disconnect(); } - function requestIdle() { - return new Promise(function(resolve) { - (requestIdleCallback || requestAnimationFrame)(resolve); - }); - } async function collectChildren(element) { if (store.size > 30) await requestIdle(); @@ -696,13 +696,10 @@ var queueSignalWrite = /* @__PURE__ */ (() => { })(); // src/signals-lib/signals-lib.js -var Signal = oCreate(null, { +var SignalReadOnly = oCreate(null, { get: { value() { return read(this); } }, - set: { value(...v) { - return write(this, ...v); - } }, toJSON: { value() { return read(this); } }, @@ -710,9 +707,9 @@ var Signal = oCreate(null, { return this[mark] && this[mark].value; } } }); -var SignalReadOnly = oCreate(Signal, { - set: { value() { - return; +var Signal = oCreate(SignalReadOnly, { + set: { value(...v) { + return write(this, ...v); } } }); function isSignal(candidate) { @@ -824,7 +821,7 @@ signal.el = function(s, map) { }; function requestCleanUpReactives(host) { if (!host || !host[key_reactive]) return; - (requestIdleCallback || setTimeout)(function() { + requestIdle().then(function() { host[key_reactive] = host[key_reactive].filter(([s, el]) => el.isConnected ? true : (removeSignalListener(...s), false)); }); } @@ -889,9 +886,10 @@ var signals_config = { function removeSignalsFromElements(s, listener, ...notes) { const { current } = scope; current.host(function(element) { - if (!element[key_reactive]) element[key_reactive] = []; + const is_first = !element[key_reactive]; + if (is_first) element[key_reactive] = []; element[key_reactive].push([[s, listener], ...notes]); - if (current.prevent) return; + if (!is_first || current.prevent) return; on.disconnected( () => ( /*! Clears all Signals listeners added in the current scope/host (`S.el`, `assign`, …?). @@ -906,7 +904,7 @@ var cleanUpRegistry = new FinalizationRegistry(function(s) { }); function create(is_readonly, value, actions) { const varS = oCreate(is_readonly ? SignalReadOnly : Signal); - const SI = toSignal(varS, value, actions, is_readonly); + const SI = toSignal(varS, value, actions); cleanUpRegistry.register(SI, SI[mark]); return SI; } @@ -918,7 +916,7 @@ var protoSigal = oAssign(oCreate(), { this.skip = true; } }); -function toSignal(s, value, actions, readonly = false) { +function toSignal(s, value, actions) { const onclear = []; if (typeOf(actions) !== "[object Object]") actions = {}; @@ -934,8 +932,7 @@ function toSignal(s, value, actions, readonly = false) { actions, onclear, host, - listeners: /* @__PURE__ */ new Set(), - readonly + listeners: /* @__PURE__ */ new Set() }), enumerable: false, writable: false, diff --git a/dist/esm-with-signals.min.js b/dist/esm-with-signals.min.js index adcf83e..3161436 100644 --- a/dist/esm-with-signals.min.js +++ b/dist/esm-with-signals.min.js @@ -1,3 +1,3 @@ -var j=(...t)=>Object.prototype.hasOwnProperty.call(...t);function A(t){return typeof t>"u"}function rt(t){let e=typeof t;return e!=="object"?e:t===null?"null":Object.prototype.toString.call(t)}function _(t,e){return t instanceof e}function ot(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function S(t=null,e={}){return Object.create(t,e)}function b(...t){return Object.assign(...t)}function Z(t,e){if(!t||!_(t,AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}function ct(t,e){let{observedAttributes:n=[]}=t.constructor;return n.reduce(function(r,o){return r[St(o)]=e(t,o),r},{})}function St(t){return t.replace(/-./g,e=>e[1].toUpperCase())}var d={setDeleteAttr:wt,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 wt(t,e,n){if(Reflect.set(t,e,n),!!A(n)){if(Reflect.deleteProperty(t,e),_(t,d.H)&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var T="__dde_lifecyclesToEvents",C="dde:connected",D="dde:disconnected",F="dde:attributeChanged";var L=d.M?yt():new Proxy({},{get(){return()=>{}}});function yt(){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}g(f.removedNodes,!0)&&u()}},r=new d.M(n(s));return{observe(u){let a=new d.M(n(()=>{}));return a.observe(u,{childList:!0,subtree:!0}),()=>a.disconnect()},onConnected(u,a){i();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){i();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),s())}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 i(){e||(e=!0,r.observe(d.D.body,{childList:!0,subtree:!0}))}function s(){!e||t.size||(e=!1,r.disconnect())}function p(){return new Promise(function(u){(requestIdleCallback||requestAnimationFrame)(u)})}async function m(u){t.size>30&&await p();let a=[];if(!_(u,d.N))return a;for(let f of t.keys())f===u||!_(f,d.N)||u.contains(f)&&a.push(f);return a}function h(u,a){let f=!1;for(let w of u){if(a&&m(w).then(h),!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 g(u,a){let f=!1;for(let w of u)a&&m(w).then(g),!(!t.has(w)||!t.get(w).length_d)&&((globalThis.queueMicrotask||setTimeout)(R(w)),f=!0);return f}function R(u){return()=>{u.isConnected||(u.dispatchEvent(new Event(D)),t.delete(u))}}}function Ht(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 i=c.length?new CustomEvent(t,b({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(i)}}function y(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}y.defer=t=>setTimeout.bind(null,t,0);var it=t=>b({},typeof t=="object"?t:null,{once:!0});y.connected=function(t,e){return e=it(e),function(r){return r.addEventListener(C,t,e),r[T]?r:r.isConnected?(r.dispatchEvent(new Event(C)),r):(Z(e.signal,()=>L.offConnected(r,t))&&L.onConnected(r,t),r)}};y.disconnected=function(t,e){return e=it(e),function(r){return r.addEventListener(D,t,e),r[T]||Z(e.signal,()=>L.offDisconnected(r,t))&&L.onDisconnected(r,t),r}};var O=[{get scope(){return d.D.body},host:t=>t?t(d.D.body):d.D.body,prevent:!0}],G=new WeakMap,x={get current(){return O[O.length-1]},get host(){return this.current.host},get signal(){let{host:t}=this;if(G.has(t))return G.get(t);let e=new AbortController;return G.set(t,e),t(y.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 q={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function V(t,e=!0){return e?b(q,t):(Object.setPrototypeOf(t,q),t)}function I(t){return ot(t,q)&&t!==q?t:q}function st(t,e,n,r){return t[(A(r)?"remove":"set")+e](n,r)}function ut(t,e,n,r,o=null){return t[(A(r)?"remove":"set")+e+"NS"](o,n,r)}function K(t,e,n){if(Reflect.set(t,e,n),!!A(n))return Reflect.deleteProperty(t,e)}function ft(t,e,n,r){return _(t,d.H)?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function ce(t){return d.q(t)}function at(...t){return this.appendOriginal(...t),this}function At(t){return t.append===at||(t.appendOriginal=t.append,t.append=at),t}var $;function W(t,e,...n){let r=I(this),o=0,c,i,s=typeof e;switch((s==="string"||s==="number"||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let p=(...g)=>g.length?(o===1?n.unshift(...g):g.forEach(R=>R(i)),void 0):i;x.push({scope:t,host:p}),c=t(e||void 0);let m=_(c,d.F);if(c.nodeName==="#comment")break;let h=W.mark({type:"component",name:t.name,host:m?"this":"parentElement"});c.prepend(h),m&&(i=h);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 At(c),i||(i=c),n.forEach(p=>p(i)),o&&x.pop(),o=2,c}W.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 se(t){let e=this;return function(...r){$=t;let o=W.call(e,...r);return $=void 0,o}}var z=new WeakMap,{setDeleteAttr:pt}=d;function U(t,...e){if(!e.length)return t;z.set(t,lt(t,this));for(let[n,r]of Object.entries(b({},...e)))dt.call(this,t,n,r);return z.delete(t),t}function dt(t,e,n){let{setRemoveAttr:r,s:o}=lt(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(s,p)=>dt.call(c,t,s,p));let[i]=e;if(i==="=")return r(e.slice(1),n);if(i===".")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 pt(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return Q(o,e,t,n,K.bind(null,t[e]));case"ariaset":return Q(o,e,t,n,(s,p)=>r("aria-"+s,p));case"classList":return Ct.call(c,t,n)}return Ot(t,e)?pt(t,e,n):r(e,n)}function lt(t,e){if(z.has(t))return z.get(t);let r=(_(t,d.S)?ut:st).bind(null,t,"Attribute"),o=I(e);return{setRemoveAttr:r,s:o}}function Ct(t,e){let n=I(this);return Q(n,"classList",t,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function Ot(t,e){if(!(e in t))return!1;let n=ht(t,e);return!A(n.set)}function ht(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||ht(t,e)}function Q(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([s,p]){s&&(s=new c(s),s.target=e,p=t.processReactiveAttribute(n,s,p,o),o(s,p))})}function me(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,i,s){if(s[0]===e)return c.apply(t,s);for(let p of s){let m=(p.slot||"")+n;try{ft(p,"remove","slot")}catch{}let h=o[m];if(!h)return;h.name.startsWith(r)||(h.childNodes.forEach(g=>g.remove()),h.name=r+m),h.append(p)}return t.append=c,t}}),t!==e){let c=Array.from(t.childNodes);t.append(...c)}return e}function ge(t,e,n={}){let r=t.host||t;x.push({scope:r,host:(...i)=>i.length?i.forEach(s=>s(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[T];o||Rt(r);let c=e.call(r,n);return o||r.dispatchEvent(new Event(C)),t.nodeType===11&&typeof t.mode=="string"&&r.addEventListener(D,L.observe(t),{once:!0}),x.pop(),t.append(c)}function Rt(t){return X(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(C))}),X(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(D)))}),X(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[T]=!0,t}function X(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}var mt="__dde_memo",H=[];function k(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,j(r,n)?r[n]:e(t))}k.isScope=function(t){return t[mt]};k.scope=function(e,{signal:n,onlyLast:r}={}){let o=S();function c(...i){if(n&&n.aborted)return e.apply(this,i);let s=r?o:S();H.unshift({cache:o,after(m,h){return s[m]=h}});let p=e.apply(this,i);return H.shift(),o=s,p}return c[mt]=!0,c.clear=()=>o=S(),n&&n.addEventListener("abort",c.clear),c};var l="__dde_signal",Y=(()=>{let t=new Map,e=!1;function n(){e=!1;let r=t;t=new Map;for(let[o,c]of r){let i=o[l];i&&i.listeners.forEach(s=>s(i.value,c))}}return function(r,o=!1){t.set(r,t.get(r)||o),!e&&(e=!0,queueMicrotask(n))}})();var et=S(null,{get:{value(){return vt(this)}},set:{value(...t){return _t(this,...t)}},toJSON:{value(){return vt(this)}},valueOf:{value(){return this[l]&&this[l].value}}}),Dt=S(et,{set:{value(){}}});function J(t){return t&&t[l]}var B=[],E=new WeakMap;function v(t,e){if(typeof t!="function")return gt(!1,t,e);if(J(t))return t;let n=gt(!0);function r(o,c){let[i,...s]=E.get(r);if(E.set(r,new Set([i])),B.push(r),_t(n,t(),c),B.pop(),!s.length)return;let p=E.get(r);for(let m of s)p.has(m)||M(m,r)}return E.set(n[l],r),E.set(r,new Set([n])),r(),n}v.action=function(t,e,...n){let r=t[l];if(!r)return;let{actions:o}=r;if(!o||!j(o,e))throw new Error(`Action "${e}" not defined. See ${l}.actions.`);if(o[e].apply(r,n),r.skip)return delete r.skip;Y(t,!0)};v.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));nt(e,n),o&&o.addEventListener("abort",()=>M(e,n))}};v.symbols={onclear:Symbol.for("Signal.onclear")};v.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),!E.has(o))return;let c=E.get(o);c.delete(n),!(c.size>1)&&(n.clear(...c),E.delete(o))})}};var N="__dde_reactive";v.el=function(t,e){let n=k.isScope(e)?e:k.scope(e,{onlyLast:!0}),{current:r}=x,{scope:o}=r,c=W.mark({type:"reactive",component:o&&o.name||""},!0),i=c.end,s=d.D.createDocumentFragment();s.append(c,i);let p=m=>{if(!c.parentNode||!i.parentNode)return M(t,p);x.push(r);let h=n(m);x.pop(),Array.isArray(h)||(h=[h]);let g=document.createComment("");h.push(g),c.after(...h);let R;for(;(R=g.nextSibling)&&R!==i;)R.remove();g.remove(),c.isConnected&&Lt(r.host())};return nt(t,p),xt(t,p,c,e),p(t.get()),r.host(y.disconnected(()=>n.clear())),s};function Lt(t){!t||!t[N]||(requestIdleCallback||setTimeout)(function(){t[N]=t[N].filter(([e,n])=>n.isConnected?!0:(M(...e),!1))})}var Nt={_set(t){this.value=t}};function Mt(t){return function(e,n){let r=S(et,{set:{value(...c){return e.setAttribute(n,...c)}}}),o=Et(r,e.getAttribute(n),Nt);return t[n]=o,o}}var tt="__dde_attributes";v.observedAttributes=function(t){let e=t[tt]={},n=ct(t,Mt(e));return y(F,function({detail:o}){/*! This maps attributes to signals (`S.observedAttributes`). - Investigate `__dde_attributes` key of the element. */let[c,i]=o,s=this[tt][c];if(s)return v.action(s,"_set",i)})(t),y.disconnected(function(){/*! This removes all signals mapped to attributes (`S.observedAttributes`). - Investigate `__dde_attributes` key of the element. */v.clear(...Object.values(this[tt]))})(t),n};var bt={isSignal:J,processReactiveAttribute(t,e,n,r){if(!J(n))return n;let o=c=>{if(!t.isConnected)return M(n,o);r(e,c)};return nt(n,o),xt(n,o,t,e),n.get()}};function xt(t,e,...n){let{current:r}=x;r.host(function(o){o[N]||(o[N]=[]),o[N].push([[t,e],...n]),!r.prevent&&y.disconnected(()=>o[N].forEach(([[c,i]])=>M(c,i,c[l]&&c[l].host&&c[l].host()===o)))(o)})}var Tt=new FinalizationRegistry(function(t){v.clear({[l]:t})});function gt(t,e,n){let r=S(t?Dt:et),o=Et(r,e,n,t);return Tt.register(o,o[l]),o}var kt=b(S(),{stopPropagation(){this.skip=!0}});function Et(t,e,n,r=!1){let o=[];rt(n)!=="[object Object]"&&(n={});let{onclear:c}=v.symbols;n[c]&&(o.push(n[c]),delete n[c]);let{host:i}=x;return Reflect.defineProperty(t,l,{value:b(S(kt),{value:e,actions:n,onclear:o,host:i,listeners:new Set,readonly:r}),enumerable:!1,writable:!1,configurable:!0}),t}function Pt(){return B[B.length-1]}function vt(t){if(!t[l])return;let{value:e,listeners:n}=t[l],r=Pt();return r&&n.add(r),E.has(r)&&E.get(r).add(t),e}function _t(t,e,n){let r=t[l];if(!(!r||!n&&r.value===e))return r.value=e,Y(t,n),e}function nt(t,e){if(t[l])return t[l].listeners.add(e)}function M(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;v.clear(t);let i=E.get(r);if(!i)return c;let s=E.get(i);if(!s)return c;for(let p of s)M(p,i,!0);return c}V(bt);export{v as S,U as assign,dt as assignAttribute,At as chainableAppend,Ct as classListDeclarative,W as createElement,se as createElementNS,ge as customElementRender,Rt as customElementWithDDE,Ht as dispatchEvent,W as el,se as elNS,J as isSignal,Rt as lifecyclesToEvents,k as memo,y as on,ce as queue,V as registerReactivity,x as scope,v as signal,me as simulateSlots}; +var W=(...t)=>Object.prototype.hasOwnProperty.call(...t);function A(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 E(t,e){return t instanceof e}function rt(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function S(t=null,e={}){return Object.create(t,e)}function b(...t){return Object.assign(...t)}function Z(t,e){if(!t||!E(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[wt(o)]=e(t,o),r},{})}function wt(t){return t.replace(/-./g,e=>e[1].toUpperCase())}function j(){return new Promise(function(t){(globalThis.requestIdleCallback||requestAnimationFrame)(t)})}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 M="__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}h(f.removedNodes,!0)&&u()}},r=new d.M(n(s));return{observe(u){let p=new d.M(n(()=>{}));return p.observe(u,{childList:!0,subtree:!0}),()=>p.disconnect()},onConnected(u,p){i();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){i();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),s())}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 i(){e||(e=!0,r.observe(d.D.body,{childList:!0,subtree:!0}))}function s(){!e||t.size||(e=!1,r.disconnect())}async function a(u){t.size>30&&await j();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&&a(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 h(u,p){let f=!1;for(let w of u)p&&a(w).then(h),!(!t.has(w)||!t.get(w).length_d)&&((globalThis.queueMicrotask||setTimeout)(v(w)),f=!0);return f}function v(u){return()=>{u.isConnected||(u.dispatchEvent(new Event(R)),t.delete(u))}}}function Ht(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 i=c.length?new CustomEvent(t,b({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(i)}}function y(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}y.defer=t=>setTimeout.bind(null,t,0);var ct=t=>b({},typeof t=="object"?t:null,{once:!0});y.connected=function(t,e){return e=ct(e),function(r){return r.addEventListener(C,t,e),r[M]?r:r.isConnected?(r.dispatchEvent(new Event(C)),r):(Z(e.signal,()=>D.offConnected(r,t))&&D.onConnected(r,t),r)}};y.disconnected=function(t,e){return e=ct(e),function(r){return r.addEventListener(R,t,e),r[M]||Z(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}],G=new WeakMap,x={get current(){return O[O.length-1]},get host(){return this.current.host},get signal(){let{host:t}=this;if(G.has(t))return G.get(t);let e=new AbortController;return G.set(t,e),t(y.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 k={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function V(t,e=!0){return e?b(k,t):(Object.setPrototypeOf(t,k),t)}function I(t){return rt(t,k)&&t!==k?t:k}function it(t,e,n,r){return t[(A(r)?"remove":"set")+e](n,r)}function st(t,e,n,r,o=null){return t[(A(r)?"remove":"set")+e+"NS"](o,n,r)}function K(t,e,n){if(Reflect.set(t,e,n),!!A(n))return Reflect.deleteProperty(t,e)}function ut(t,e,n,r){return E(t,d.H)?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function ce(t){return d.q(t)}function ft(...t){return this.appendOriginal(...t),this}function Ct(t){return t.append===ft||(t.appendOriginal=t.append,t.append=ft),t}var $;function q(t,e,...n){let r=I(this),o=0,c,i,s=typeof e;switch((s==="string"||s==="number"||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let a=(...v)=>v.length?(o===1?n.unshift(...v):v.forEach(u=>u(i)),void 0):i;x.push({scope:t,host:a}),c=t(e||void 0);let m=E(c,d.F);if(c.nodeName==="#comment")break;let h=q.mark({type:"component",name:t.name,host:m?"this":"parentElement"});c.prepend(h),m&&(i=h);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),i||(i=c),n.forEach(a=>a(i)),o&&x.pop(),o=2,c}q.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 se(t){let e=this;return function(...r){$=t;let o=q.call(e,...r);return $=void 0,o}}var z=new WeakMap,{setDeleteAttr:at}=d;function U(t,...e){if(!e.length)return t;z.set(t,dt(t,this));for(let[n,r]of Object.entries(b({},...e)))pt.call(this,t,n,r);return z.delete(t),t}function pt(t,e,n){let{setRemoveAttr:r,s:o}=dt(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(s,a)=>pt.call(c,t,s,a));let[i]=e;if(i==="=")return r(e.slice(1),n);if(i===".")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 at(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return Q(o,e,t,n,K.bind(null,t[e]));case"ariaset":return Q(o,e,t,n,(s,a)=>r("aria-"+s,a));case"classList":return Ot.call(c,t,n)}return Rt(t,e)?at(t,e,n):r(e,n)}function dt(t,e){if(z.has(t))return z.get(t);let r=(E(t,d.S)?st:it).bind(null,t,"Attribute"),o=I(e);return{setRemoveAttr:r,s:o}}function Ot(t,e){let n=I(this);return Q(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=lt(t,e);return!A(n.set)}function lt(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||lt(t,e)}function Q(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([s,a]){s&&(s=new c(s),s.target=e,a=t.processReactiveAttribute(n,s,a,o),o(s,a))})}function me(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,i,s){if(s[0]===e)return c.apply(t,s);for(let a of s){let m=(a.slot||"")+n;try{ut(a,"remove","slot")}catch{}let h=o[m];if(!h)return;h.name.startsWith(r)||(h.childNodes.forEach(v=>v.remove()),h.name=r+m),h.append(a)}return t.append=c,t}}),t!==e){let c=Array.from(t.childNodes);t.append(...c)}return e}function ge(t,e,n={}){let r=t.host||t;x.push({scope:r,host:(...i)=>i.length?i.forEach(s=>s(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[M];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}),x.pop(),t.append(c)}function Dt(t){return X(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(C))}),X(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(R)))}),X(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[M]=!0,t}function X(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}var ht="__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[ht]};T.scope=function(e,{signal:n,onlyLast:r}={}){let o=S();function c(...i){if(n&&n.aborted)return e.apply(this,i);let s=r?o:S();H.unshift({cache:o,after(m,h){return s[m]=h}});let a=e.apply(this,i);return H.shift(),o=s,a}return c[ht]=!0,c.clear=()=>o=S(),n&&n.addEventListener("abort",c.clear),c};var l="__dde_signal",Y=(()=>{let t=new Map,e=!1;function n(){e=!1;let r=t;t=new Map;for(let[o,c]of r){let i=o[l];i&&i.listeners.forEach(s=>s(i.value,c))}}return function(r,o=!1){t.set(r,t.get(r)||o),!e&&(e=!0,queueMicrotask(n))}})();var vt=S(null,{get:{value(){return gt(this)}},toJSON:{value(){return gt(this)}},valueOf:{value(){return this[l]&&this[l].value}}}),bt=S(vt,{set:{value(...t){return St(this,...t)}}});function J(t){return t&&t[l]}var B=[],_=new WeakMap;function g(t,e){if(typeof t!="function")return mt(!1,t,e);if(J(t))return t;let n=mt(!0);function r(o,c){let[i,...s]=_.get(r);if(_.set(r,new Set([i])),B.push(r),St(n,t(),c),B.pop(),!s.length)return;let a=_.get(r);for(let m of s)a.has(m)||N(m,r)}return _.set(n[l],r),_.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;Y(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));et(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),!_.has(o))return;let c=_.get(o);c.delete(n),!(c.size>1)&&(n.clear(...c),_.delete(o))})}};var L="__dde_reactive";g.el=function(t,e){let n=T.isScope(e)?e:T.scope(e,{onlyLast:!0}),{current:r}=x,{scope:o}=r,c=q.mark({type:"reactive",component:o&&o.name||""},!0),i=c.end,s=d.D.createDocumentFragment();s.append(c,i);let a=m=>{if(!c.parentNode||!i.parentNode)return N(t,a);x.push(r);let h=n(m);x.pop(),Array.isArray(h)||(h=[h]);let v=document.createComment("");h.push(v),c.after(...h);let u;for(;(u=v.nextSibling)&&u!==i;)u.remove();v.remove(),c.isConnected&&Lt(r.host())};return et(t,a),_t(t,a,c,e),a(t.get()),r.host(y.disconnected(()=>n.clear())),s};function Lt(t){!t||!t[L]||j().then(function(){t[L]=t[L].filter(([e,n])=>n.isConnected?!0:(N(...e),!1))})}var Nt={_set(t){this.value=t}};function Mt(t){return function(e,n){let r=S(bt,{set:{value(...c){return e.setAttribute(n,...c)}}}),o=Et(r,e.getAttribute(n),Nt);return t[n]=o,o}}var tt="__dde_attributes";g.observedAttributes=function(t){let e=t[tt]={},n=ot(t,Mt(e));return y(F,function({detail:o}){/*! This maps attributes to signals (`S.observedAttributes`). + Investigate `__dde_attributes` key of the element. */let[c,i]=o,s=this[tt][c];if(s)return g.action(s,"_set",i)})(t),y.disconnected(function(){/*! This removes all signals mapped to attributes (`S.observedAttributes`). + Investigate `__dde_attributes` key of the element. */g.clear(...Object.values(this[tt]))})(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 et(n,o),_t(n,o,t,e),n.get()}};function _t(t,e,...n){let{current:r}=x;r.host(function(o){let c=!o[L];c&&(o[L]=[]),o[L].push([[t,e],...n]),!(!c||r.prevent)&&y.disconnected(()=>o[L].forEach(([[i,s]])=>N(i,s,i[l]&&i[l].host&&i[l].host()===o)))(o)})}var Tt=new FinalizationRegistry(function(t){g.clear({[l]:t})});function mt(t,e,n){let r=S(t?vt:bt),o=Et(r,e,n);return Tt.register(o,o[l]),o}var Pt=b(S(),{stopPropagation(){this.skip=!0}});function Et(t,e,n){let r=[];nt(n)!=="[object Object]"&&(n={});let{onclear:o}=g.symbols;n[o]&&(r.push(n[o]),delete n[o]);let{host:c}=x;return Reflect.defineProperty(t,l,{value:b(S(Pt),{value:e,actions:n,onclear:r,host:c,listeners:new Set}),enumerable:!1,writable:!1,configurable:!0}),t}function kt(){return B[B.length-1]}function gt(t){if(!t[l])return;let{value:e,listeners:n}=t[l],r=kt();return r&&n.add(r),_.has(r)&&_.get(r).add(t),e}function St(t,e,n){let r=t[l];if(!(!r||!n&&r.value===e))return r.value=e,Y(t,n),e}function et(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 i=_.get(r);if(!i)return c;let s=_.get(i);if(!s)return c;for(let a of s)N(a,i,!0);return c}V(xt);export{g as S,U as assign,pt as assignAttribute,Ct as chainableAppend,Ot as classListDeclarative,q as createElement,se as createElementNS,ge as customElementRender,Dt as customElementWithDDE,Ht as dispatchEvent,q as el,se as elNS,J as isSignal,Dt as lifecyclesToEvents,T as memo,y as on,ce as queue,V as registerReactivity,x as scope,g as signal,me as simulateSlots}; diff --git a/dist/esm.js b/dist/esm.js index 53df0cf..3033b4b 100644 --- a/dist/esm.js +++ b/dist/esm.js @@ -25,6 +25,11 @@ function onAbort(signal, listener) { signal.removeEventListener("abort", listener); }; } +function requestIdle() { + return new Promise(function(resolve) { + (globalThis.requestIdleCallback || requestAnimationFrame)(resolve); + }); +} // src/dom-lib/common.js var enviroment = { @@ -163,11 +168,6 @@ function connectionsChangesObserverConstructor() { is_observing = false; observer.disconnect(); } - function requestIdle() { - return new Promise(function(resolve) { - (requestIdleCallback || requestAnimationFrame)(resolve); - }); - } async function collectChildren(element) { if (store.size > 30) await requestIdle(); diff --git a/dist/esm.min.js b/dist/esm.min.js index 13eaba1..363bcb8 100644 --- a/dist/esm.min.js +++ b/dist/esm.min.js @@ -1 +1 @@ -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 g(...t){return Object.assign(...t)}function W(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 C="__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}v(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 v(s,u){let i=!1;for(let b of s)u&&m(b).then(v),!(!t.has(b)||!t.get(b).length_d)&&((globalThis.queueMicrotask||setTimeout)(q(b)),i=!0);return i}function q(s){return()=>{s.isConnected||(s.dispatchEvent(new Event(w)),t.delete(s))}}}function vt(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,g({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(p)}}function D(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}D.defer=t=>setTimeout.bind(null,t,0);var Z=t=>g({},typeof t=="object"?t:null,{once:!0});D.connected=function(t,e){return e=Z(e),function(r){return r.addEventListener(E,t,e),r[C]?r:r.isConnected?(r.dispatchEvent(new Event(E)),r):(W(e.signal,()=>y.offConnected(r,t))&&y.onConnected(r,t),r)}};D.disconnected=function(t,e){return e=Z(e),function(r){return r.addEventListener(w,t,e),r[C]||W(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}],j=new WeakMap,A={get current(){return _[_.length-1]},get host(){return this.current.host},get signal(){let{host:t}=this;if(j.has(t))return j.get(t);let e=new AbortController;return j.set(t,e),t(D.disconnected(()=>e.abort())),e.signal},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[..._]},push(t={}){return _.push(g({},this.current,{prevent:!1},t))},pushRoot(){return _.push(_[0])},pop(){if(_.length!==1)return _.pop()}};var O={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function ot(t,e=!0){return e?g(O,t):(Object.setPrototypeOf(t,O),t)}function L(t){return z(t,O)&&t!==O?t:O}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 F(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 U(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=(...v)=>v.length?(o===1?n.unshift(...v):v.forEach(q=>q(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=U.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}U.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=U.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(g({},...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 F(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,F.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 kt(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(v=>v.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[C];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 $(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(E))}),$(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(w)))}),$(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[C]=!0,t}function $(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}var et="__dde_memo",M=[];function k(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))}k.isScope=function(t){return t[et]};k.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,U as createElement,Mt as createElementNS,Ht as customElementRender,ut as customElementWithDDE,vt as dispatchEvent,U as el,Mt as elNS,ut as lifecyclesToEvents,k as memo,D as on,Tt as queue,ot as registerReactivity,A as scope,kt as simulateSlots}; +var k=(...t)=>Object.prototype.hasOwnProperty.call(...t);function x(t){return typeof t>"u"}function h(t,e){return t instanceof e}function H(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function R(t=null,e={}){return Object.create(t,e)}function g(...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)}}function z(){return new Promise(function(t){(globalThis.requestIdleCallback||requestAnimationFrame)(t)})}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 C="__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(m(i.addedNodes,!0)){s();continue}l(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())}async function d(s){t.size>30&&await z();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 m(s,u){let i=!1;for(let b of s){if(u&&d(b).then(m),!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 l(s,u){let i=!1;for(let b of s)u&&d(b).then(l),!(!t.has(b)||!t.get(b).length_d)&&((globalThis.queueMicrotask||setTimeout)(v(b)),i=!0);return i}function v(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,g({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(p)}}function D(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}D.defer=t=>setTimeout.bind(null,t,0);var Z=t=>g({},typeof t=="object"?t:null,{once:!0});D.connected=function(t,e){return e=Z(e),function(r){return r.addEventListener(E,t,e),r[C]?r:r.isConnected?(r.dispatchEvent(new Event(E)),r):(q(e.signal,()=>y.offConnected(r,t))&&y.onConnected(r,t),r)}};D.disconnected=function(t,e){return e=Z(e),function(r){return r.addEventListener(w,t,e),r[C]||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(D.disconnected(()=>e.abort())),e.signal},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[..._]},push(t={}){return _.push(g({},this.current,{prevent:!1},t))},pushRoot(){return _.push(_[0])},pop(){if(_.length!==1)return _.pop()}};var O={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function ot(t,e=!0){return e?g(O,t):(Object.setPrototypeOf(t,O),t)}function T(t){return H(t,O)&&t!==O?t:O}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 j(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 Nt(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 N;function F(t,e,...n){let r=T(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=(...v)=>v.length?(o===1?n.unshift(...v):v.forEach(s=>s(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=L.call(this,f.D.createTextNode(""),e);break;case(t==="<>"||!t):c=L.call(this,f.D.createDocumentFragment(),e);break;case!!N:c=L.call(this,f.D.createElementNS(N,t),e);break;case!c:c=L.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){N=t;let o=F.call(e,...r);return N=void 0,o}}var P=new WeakMap,{setDeleteAttr:Q}=f;function L(t,...e){if(!e.length)return t;P.set(t,Y(t,this));for(let[n,r]of Object.entries(g({},...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 j(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,j.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=T(e);return{setRemoveAttr:r,s:o}}function st(t,e){let n=T(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 kt(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(v=>v.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[C];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[C]=!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,k(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{L 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,D as on,Nt as queue,ot as registerReactivity,A as scope,kt as simulateSlots}; diff --git a/dist/iife-with-signals.js b/dist/iife-with-signals.js index c530964..2bceb59 100644 --- a/dist/iife-with-signals.js +++ b/dist/iife-with-signals.js @@ -86,6 +86,11 @@ var DDE = (() => { function kebabToCamel(name) { return name.replace(/-./g, (x) => x[1].toUpperCase()); } + function requestIdle() { + return new Promise(function(resolve) { + (globalThis.requestIdleCallback || requestAnimationFrame)(resolve); + }); + } // src/dom-lib/common.js var enviroment = { @@ -224,11 +229,6 @@ var DDE = (() => { is_observing = false; observer.disconnect(); } - function requestIdle() { - return new Promise(function(resolve) { - (requestIdleCallback || requestAnimationFrame)(resolve); - }); - } async function collectChildren(element) { if (store.size > 30) await requestIdle(); @@ -741,13 +741,10 @@ var DDE = (() => { })(); // src/signals-lib/signals-lib.js - var Signal = oCreate(null, { + var SignalReadOnly = oCreate(null, { get: { value() { return read(this); } }, - set: { value(...v) { - return write(this, ...v); - } }, toJSON: { value() { return read(this); } }, @@ -755,9 +752,9 @@ var DDE = (() => { return this[mark] && this[mark].value; } } }); - var SignalReadOnly = oCreate(Signal, { - set: { value() { - return; + var Signal = oCreate(SignalReadOnly, { + set: { value(...v) { + return write(this, ...v); } } }); function isSignal(candidate) { @@ -869,7 +866,7 @@ var DDE = (() => { }; function requestCleanUpReactives(host) { if (!host || !host[key_reactive]) return; - (requestIdleCallback || setTimeout)(function() { + requestIdle().then(function() { host[key_reactive] = host[key_reactive].filter(([s, el]) => el.isConnected ? true : (removeSignalListener(...s), false)); }); } @@ -934,9 +931,10 @@ var DDE = (() => { function removeSignalsFromElements(s, listener, ...notes) { const { current } = scope; current.host(function(element) { - if (!element[key_reactive]) element[key_reactive] = []; + const is_first = !element[key_reactive]; + if (is_first) element[key_reactive] = []; element[key_reactive].push([[s, listener], ...notes]); - if (current.prevent) return; + if (!is_first || current.prevent) return; on.disconnected( () => ( /*! Clears all Signals listeners added in the current scope/host (`S.el`, `assign`, …?). @@ -951,7 +949,7 @@ var DDE = (() => { }); function create(is_readonly, value, actions) { const varS = oCreate(is_readonly ? SignalReadOnly : Signal); - const SI = toSignal(varS, value, actions, is_readonly); + const SI = toSignal(varS, value, actions); cleanUpRegistry.register(SI, SI[mark]); return SI; } @@ -963,7 +961,7 @@ var DDE = (() => { this.skip = true; } }); - function toSignal(s, value, actions, readonly = false) { + function toSignal(s, value, actions) { const onclear = []; if (typeOf(actions) !== "[object Object]") actions = {}; @@ -979,8 +977,7 @@ var DDE = (() => { actions, onclear, host, - listeners: /* @__PURE__ */ new Set(), - readonly + listeners: /* @__PURE__ */ new Set() }), enumerable: false, writable: false, diff --git a/dist/iife-with-signals.min.js b/dist/iife-with-signals.min.js index 2214989..5e23a9e 100644 --- a/dist/iife-with-signals.min.js +++ b/dist/iife-with-signals.min.js @@ -1,3 +1,3 @@ -var DDE=(()=>{var G=Object.defineProperty;var Ct=Object.getOwnPropertyDescriptor;var Ot=Object.getOwnPropertyNames;var Rt=Object.prototype.hasOwnProperty;var Dt=(t,e)=>{for(var n in e)G(t,n,{get:e[n],enumerable:!0})},Lt=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Ot(e))!Rt.call(t,o)&&o!==n&&G(t,o,{get:()=>e[o],enumerable:!(r=Ct(e,o))||r.enumerable});return t};var Nt=t=>Lt(G({},"__esModule",{value:!0}),t);var Gt={};Dt(Gt,{S:()=>g,assign:()=>j,assignAttribute:()=>Y,chainableAppend:()=>ht,classListDeclarative:()=>gt,createElement:()=>P,createElementNS:()=>Wt,customElementRender:()=>It,customElementWithDDE:()=>bt,dispatchEvent:()=>Pt,el:()=>P,elNS:()=>Wt,isSignal:()=>F,lifecyclesToEvents:()=>bt,memo:()=>N,on:()=>w,queue:()=>qt,registerReactivity:()=>$,scope:()=>b,signal:()=>g,simulateSlots:()=>Ft});var I=(...t)=>Object.prototype.hasOwnProperty.call(...t);function A(t){return typeof t>"u"}function ct(t){let e=typeof t;return e!=="object"?e:t===null?"null":Object.prototype.toString.call(t)}function _(t,e){return t instanceof e}function it(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function S(t=null,e={}){return Object.create(t,e)}function x(...t){return Object.assign(...t)}function V(t,e){if(!t||!_(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[Mt(o)]=e(t,o),r},{})}function Mt(t){return t.replace(/-./g,e=>e[1].toUpperCase())}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),_(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",D="dde:disconnected",U="dde:attributeChanged";var L=d.M?kt():new Proxy({},{get(){return()=>{}}});function kt(){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}v(f.removedNodes,!0)&&u()}},r=new d.M(n(s));return{observe(u){let a=new d.M(n(()=>{}));return a.observe(u,{childList:!0,subtree:!0}),()=>a.disconnect()},onConnected(u,a){i();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){i();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),s())}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 i(){e||(e=!0,r.observe(d.D.body,{childList:!0,subtree:!0}))}function s(){!e||t.size||(e=!1,r.disconnect())}function p(){return new Promise(function(u){(requestIdleCallback||requestAnimationFrame)(u)})}async function m(u){t.size>30&&await p();let a=[];if(!_(u,d.N))return a;for(let f of t.keys())f===u||!_(f,d.N)||u.contains(f)&&a.push(f);return a}function h(u,a){let f=!1;for(let y of u){if(a&&m(y).then(h),!t.has(y))continue;let q=t.get(y);q.length_c&&(y.dispatchEvent(new Event(C)),q.connected=new WeakSet,q.length_c=0,q.length_d||t.delete(y),f=!0)}return f}function v(u,a){let f=!1;for(let y of u)a&&m(y).then(v),!(!t.has(y)||!t.get(y).length_d)&&((globalThis.queueMicrotask||setTimeout)(R(y)),f=!0);return f}function R(u){return()=>{u.isConnected||(u.dispatchEvent(new Event(D)),t.delete(u))}}}function Pt(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 i=c.length?new CustomEvent(t,x({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(i)}}function w(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}w.defer=t=>setTimeout.bind(null,t,0);var ut=t=>x({},typeof t=="object"?t:null,{once:!0});w.connected=function(t,e){return e=ut(e),function(r){return r.addEventListener(C,t,e),r[k]?r:r.isConnected?(r.dispatchEvent(new Event(C)),r):(V(e.signal,()=>L.offConnected(r,t))&&L.onConnected(r,t),r)}};w.disconnected=function(t,e){return e=ut(e),function(r){return r.addEventListener(D,t,e),r[k]||V(e.signal,()=>L.offDisconnected(r,t))&&L.onDisconnected(r,t),r}};var O=[{get scope(){return d.D.body},host:t=>t?t(d.D.body):d.D.body,prevent:!0}],K=new WeakMap,b={get current(){return O[O.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[...O]},push(t={}){return O.push(x({},this.current,{prevent:!1},t))},pushRoot(){return O.push(O[0])},pop(){if(O.length!==1)return O.pop()}};var W={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function $(t,e=!0){return e?x(W,t):(Object.setPrototypeOf(t,W),t)}function z(t){return it(t,W)&&t!==W?t:W}function ft(t,e,n,r){return t[(A(r)?"remove":"set")+e](n,r)}function at(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 pt(t,e,n,r){return _(t,d.H)?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function qt(t){return d.q(t)}function dt(...t){return this.appendOriginal(...t),this}function ht(t){return t.append===dt||(t.appendOriginal=t.append,t.append=dt),t}var H;function P(t,e,...n){let r=z(this),o=0,c,i,s=typeof e;switch((s==="string"||s==="number"||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let p=(...v)=>v.length?(o===1?n.unshift(...v):v.forEach(R=>R(i)),void 0):i;b.push({scope:t,host:p}),c=t(e||void 0);let m=_(c,d.F);if(c.nodeName==="#comment")break;let h=P.mark({type:"component",name:t.name,host:m?"this":"parentElement"});c.prepend(h),m&&(i=h);break}case t==="#text":c=j.call(this,d.D.createTextNode(""),e);break;case(t==="<>"||!t):c=j.call(this,d.D.createDocumentFragment(),e);break;case!!H:c=j.call(this,d.D.createElementNS(H,t),e);break;case!c:c=j.call(this,d.D.createElement(t),e)}return ht(c),i||(i=c),n.forEach(p=>p(i)),o&&b.pop(),o=2,c}P.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=P.call(e,...r);return H=void 0,o}}var J=new WeakMap,{setDeleteAttr:lt}=d;function j(t,...e){if(!e.length)return t;J.set(t,mt(t,this));for(let[n,r]of Object.entries(x({},...e)))Y.call(this,t,n,r);return J.delete(t),t}function Y(t,e,n){let{setRemoveAttr:r,s:o}=mt(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(s,p)=>Y.call(c,t,s,p));let[i]=e;if(i==="=")return r(e.slice(1),n);if(i===".")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 lt(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,(s,p)=>r("aria-"+s,p));case"classList":return gt.call(c,t,n)}return jt(t,e)?lt(t,e,n):r(e,n)}function mt(t,e){if(J.has(t))return J.get(t);let r=(_(t,d.S)?at:ft).bind(null,t,"Attribute"),o=z(e);return{setRemoveAttr:r,s:o}}function gt(t,e){let n=z(this);return X(n,"classList",t,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function jt(t,e){if(!(e in t))return!1;let n=vt(t,e);return!A(n.set)}function vt(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||vt(t,e)}function X(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([s,p]){s&&(s=new c(s),s.target=e,p=t.processReactiveAttribute(n,s,p,o),o(s,p))})}function Ft(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,i,s){if(s[0]===e)return c.apply(t,s);for(let p of s){let m=(p.slot||"")+n;try{pt(p,"remove","slot")}catch{}let h=o[m];if(!h)return;h.name.startsWith(r)||(h.childNodes.forEach(v=>v.remove()),h.name=r+m),h.append(p)}return t.append=c,t}}),t!==e){let c=Array.from(t.childNodes);t.append(...c)}return e}function It(t,e,n={}){let r=t.host||t;b.push({scope:r,host:(...i)=>i.length?i.forEach(s=>s(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[k];o||bt(r);let c=e.call(r,n);return o||r.dispatchEvent(new Event(C)),t.nodeType===11&&typeof t.mode=="string"&&r.addEventListener(D,L.observe(t),{once:!0}),b.pop(),t.append(c)}function bt(t){return tt(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(C))}),tt(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(D)))}),tt(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[k]=!0,t}function tt(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}var xt="__dde_memo",B=[];function N(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))}N.isScope=function(t){return t[xt]};N.scope=function(e,{signal:n,onlyLast:r}={}){let o=S();function c(...i){if(n&&n.aborted)return e.apply(this,i);let s=r?o:S();B.unshift({cache:o,after(m,h){return s[m]=h}});let p=e.apply(this,i);return B.shift(),o=s,p}return c[xt]=!0,c.clear=()=>o=S(),n&&n.addEventListener("abort",c.clear),c};var l="__dde_signal",et=(()=>{let t=new Map,e=!1;function n(){e=!1;let r=t;t=new Map;for(let[o,c]of r){let i=o[l];i&&i.listeners.forEach(s=>s(i.value,c))}}return function(r,o=!1){t.set(r,t.get(r)||o),!e&&(e=!0,queueMicrotask(n))}})();var rt=S(null,{get:{value(){return _t(this)}},set:{value(...t){return At(this,...t)}},toJSON:{value(){return _t(this)}},valueOf:{value(){return this[l]&&this[l].value}}}),Ut=S(rt,{set:{value(){}}});function F(t){return t&&t[l]}var Z=[],E=new WeakMap;function g(t,e){if(typeof t!="function")return Et(!1,t,e);if(F(t))return t;let n=Et(!0);function r(o,c){let[i,...s]=E.get(r);if(E.set(r,new Set([i])),Z.push(r),At(n,t(),c),Z.pop(),!s.length)return;let p=E.get(r);for(let m of s)p.has(m)||T(m,r)}return E.set(n[l],r),E.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;et(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));ot(e,n),o&&o.addEventListener("abort",()=>T(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),!E.has(o))return;let c=E.get(o);c.delete(n),!(c.size>1)&&(n.clear(...c),E.delete(o))})}};var M="__dde_reactive";g.el=function(t,e){let n=N.isScope(e)?e:N.scope(e,{onlyLast:!0}),{current:r}=b,{scope:o}=r,c=P.mark({type:"reactive",component:o&&o.name||""},!0),i=c.end,s=d.D.createDocumentFragment();s.append(c,i);let p=m=>{if(!c.parentNode||!i.parentNode)return T(t,p);b.push(r);let h=n(m);b.pop(),Array.isArray(h)||(h=[h]);let v=document.createComment("");h.push(v),c.after(...h);let R;for(;(R=v.nextSibling)&&R!==i;)R.remove();v.remove(),c.isConnected&&$t(r.host())};return ot(t,p),wt(t,p,c,e),p(t.get()),r.host(w.disconnected(()=>n.clear())),s};function $t(t){!t||!t[M]||(requestIdleCallback||setTimeout)(function(){t[M]=t[M].filter(([e,n])=>n.isConnected?!0:(T(...e),!1))})}var zt={_set(t){this.value=t}};function Ht(t){return function(e,n){let r=S(rt,{set:{value(...c){return e.setAttribute(n,...c)}}}),o=yt(r,e.getAttribute(n),zt);return t[n]=o,o}}var nt="__dde_attributes";g.observedAttributes=function(t){let e=t[nt]={},n=st(t,Ht(e));return w(U,function({detail:o}){/*! This maps attributes to signals (`S.observedAttributes`). +var DDE=(()=>{var G=Object.defineProperty;var Ot=Object.getOwnPropertyDescriptor;var Rt=Object.getOwnPropertyNames;var Dt=Object.prototype.hasOwnProperty;var Lt=(t,e)=>{for(var n in e)G(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&&G(t,o,{get:()=>e[o],enumerable:!(r=Ot(e,o))||r.enumerable});return t};var Mt=t=>Nt(G({},"__esModule",{value:!0}),t);var Gt={};Lt(Gt,{S:()=>g,assign:()=>W,assignAttribute:()=>Y,chainableAppend:()=>lt,classListDeclarative:()=>mt,createElement:()=>P,createElementNS:()=>jt,customElementRender:()=>Ut,customElementWithDDE:()=>vt,dispatchEvent:()=>qt,el:()=>P,elNS:()=>jt,isSignal:()=>j,lifecyclesToEvents:()=>vt,memo:()=>L,on:()=>w,queue:()=>Wt,registerReactivity:()=>$,scope:()=>v,signal:()=>g,simulateSlots:()=>It});var F=(...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 S(t=null,e={}){return Object.create(t,e)}function x(...t){return Object.assign(...t)}function V(t,e){if(!t||!E(t,AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}function it(t,e){let{observedAttributes:n=[]}=t.constructor;return n.reduce(function(r,o){return r[Tt(o)]=e(t,o),r},{})}function Tt(t){return t.replace(/-./g,e=>e[1].toUpperCase())}function I(){return new Promise(function(t){(globalThis.requestIdleCallback||requestAnimationFrame)(t)})}var d={setDeleteAttr:Pt,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 Pt(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 T="__dde_lifecyclesToEvents",C="dde:connected",R="dde:disconnected",U="dde:attributeChanged";var D=d.M?kt():new Proxy({},{get(){return()=>{}}});function kt(){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}h(f.removedNodes,!0)&&u()}},r=new d.M(n(s));return{observe(u){let p=new d.M(n(()=>{}));return p.observe(u,{childList:!0,subtree:!0}),()=>p.disconnect()},onConnected(u,p){i();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){i();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),s())}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 i(){e||(e=!0,r.observe(d.D.body,{childList:!0,subtree:!0}))}function s(){!e||t.size||(e=!1,r.disconnect())}async function a(u){t.size>30&&await I();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 y of u){if(p&&a(y).then(m),!t.has(y))continue;let k=t.get(y);k.length_c&&(y.dispatchEvent(new Event(C)),k.connected=new WeakSet,k.length_c=0,k.length_d||t.delete(y),f=!0)}return f}function h(u,p){let f=!1;for(let y of u)p&&a(y).then(h),!(!t.has(y)||!t.get(y).length_d)&&((globalThis.queueMicrotask||setTimeout)(b(y)),f=!0);return f}function b(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 i=c.length?new CustomEvent(t,x({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(i)}}function w(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}w.defer=t=>setTimeout.bind(null,t,0);var st=t=>x({},typeof t=="object"?t:null,{once:!0});w.connected=function(t,e){return e=st(e),function(r){return r.addEventListener(C,t,e),r[T]?r:r.isConnected?(r.dispatchEvent(new Event(C)),r):(V(e.signal,()=>D.offConnected(r,t))&&D.onConnected(r,t),r)}};w.disconnected=function(t,e){return e=st(e),function(r){return r.addEventListener(R,t,e),r[T]||V(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}],K=new WeakMap,v={get current(){return O[O.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[...O]},push(t={}){return O.push(x({},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 $(t,e=!0){return e?x(q,t):(Object.setPrototypeOf(t,q),t)}function z(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 Wt(t){return d.q(t)}function pt(...t){return this.appendOriginal(...t),this}function lt(t){return t.append===pt||(t.appendOriginal=t.append,t.append=pt),t}var H;function P(t,e,...n){let r=z(this),o=0,c,i,s=typeof e;switch((s==="string"||s==="number"||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let a=(...b)=>b.length?(o===1?n.unshift(...b):b.forEach(u=>u(i)),void 0):i;v.push({scope:t,host:a}),c=t(e||void 0);let m=E(c,d.F);if(c.nodeName==="#comment")break;let h=P.mark({type:"component",name:t.name,host:m?"this":"parentElement"});c.prepend(h),m&&(i=h);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 lt(c),i||(i=c),n.forEach(a=>a(i)),o&&v.pop(),o=2,c}P.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 jt(t){let e=this;return function(...r){H=t;let o=P.call(e,...r);return H=void 0,o}}var J=new WeakMap,{setDeleteAttr:dt}=d;function W(t,...e){if(!e.length)return t;J.set(t,ht(t,this));for(let[n,r]of Object.entries(x({},...e)))Y.call(this,t,n,r);return J.delete(t),t}function Y(t,e,n){let{setRemoveAttr:r,s:o}=ht(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(s,a)=>Y.call(c,t,s,a));let[i]=e;if(i==="=")return r(e.slice(1),n);if(i===".")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,(s,a)=>r("aria-"+s,a));case"classList":return mt.call(c,t,n)}return Ft(t,e)?dt(t,e,n):r(e,n)}function ht(t,e){if(J.has(t))return J.get(t);let r=(E(t,d.S)?ft:ut).bind(null,t,"Attribute"),o=z(e);return{setRemoveAttr:r,s:o}}function mt(t,e){let n=z(this);return X(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=gt(t,e);return!A(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 X(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([s,a]){s&&(s=new c(s),s.target=e,a=t.processReactiveAttribute(n,s,a,o),o(s,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,i,s){if(s[0]===e)return c.apply(t,s);for(let a of s){let m=(a.slot||"")+n;try{at(a,"remove","slot")}catch{}let h=o[m];if(!h)return;h.name.startsWith(r)||(h.childNodes.forEach(b=>b.remove()),h.name=r+m),h.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:(...i)=>i.length?i.forEach(s=>s(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[T];o||vt(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 vt(t){return tt(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(C))}),tt(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(R)))}),tt(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[T]=!0,t}function tt(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,F(r,n)?r[n]:e(t))}L.isScope=function(t){return t[bt]};L.scope=function(e,{signal:n,onlyLast:r}={}){let o=S();function c(...i){if(n&&n.aborted)return e.apply(this,i);let s=r?o:S();B.unshift({cache:o,after(m,h){return s[m]=h}});let a=e.apply(this,i);return B.shift(),o=s,a}return c[bt]=!0,c.clear=()=>o=S(),n&&n.addEventListener("abort",c.clear),c};var l="__dde_signal",et=(()=>{let t=new Map,e=!1;function n(){e=!1;let r=t;t=new Map;for(let[o,c]of r){let i=o[l];i&&i.listeners.forEach(s=>s(i.value,c))}}return function(r,o=!1){t.set(r,t.get(r)||o),!e&&(e=!0,queueMicrotask(n))}})();var Et=S(null,{get:{value(){return _t(this)}},toJSON:{value(){return _t(this)}},valueOf:{value(){return this[l]&&this[l].value}}}),St=S(Et,{set:{value(...t){return Ct(this,...t)}}});function j(t){return t&&t[l]}var Z=[],_=new WeakMap;function g(t,e){if(typeof t!="function")return xt(!1,t,e);if(j(t))return t;let n=xt(!0);function r(o,c){let[i,...s]=_.get(r);if(_.set(r,new Set([i])),Z.push(r),Ct(n,t(),c),Z.pop(),!s.length)return;let a=_.get(r);for(let m of s)a.has(m)||M(m,r)}return _.set(n[l],r),_.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||!F(o,e))throw new Error(`Action "${e}" not defined. See ${l}.actions.`);if(o[e].apply(r,n),r.skip)return delete r.skip;et(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",()=>M(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),!_.has(o))return;let c=_.get(o);c.delete(n),!(c.size>1)&&(n.clear(...c),_.delete(o))})}};var N="__dde_reactive";g.el=function(t,e){let n=L.isScope(e)?e:L.scope(e,{onlyLast:!0}),{current:r}=v,{scope:o}=r,c=P.mark({type:"reactive",component:o&&o.name||""},!0),i=c.end,s=d.D.createDocumentFragment();s.append(c,i);let a=m=>{if(!c.parentNode||!i.parentNode)return M(t,a);v.push(r);let h=n(m);v.pop(),Array.isArray(h)||(h=[h]);let b=document.createComment("");h.push(b),c.after(...h);let u;for(;(u=b.nextSibling)&&u!==i;)u.remove();b.remove(),c.isConnected&&$t(r.host())};return rt(t,a),yt(t,a,c,e),a(t.get()),r.host(w.disconnected(()=>n.clear())),s};function $t(t){!t||!t[N]||I().then(function(){t[N]=t[N].filter(([e,n])=>n.isConnected?!0:(M(...e),!1))})}var zt={_set(t){this.value=t}};function Ht(t){return function(e,n){let r=S(St,{set:{value(...c){return e.setAttribute(n,...c)}}}),o=At(r,e.getAttribute(n),zt);return t[n]=o,o}}var nt="__dde_attributes";g.observedAttributes=function(t){let e=t[nt]={},n=it(t,Ht(e));return w(U,function({detail:o}){/*! This maps attributes to signals (`S.observedAttributes`). Investigate `__dde_attributes` key of the element. */let[c,i]=o,s=this[nt][c];if(s)return g.action(s,"_set",i)})(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[nt]))})(t),n};var St={isSignal:F,processReactiveAttribute(t,e,n,r){if(!F(n))return n;let o=c=>{if(!t.isConnected)return T(n,o);r(e,c)};return ot(n,o),wt(n,o,t,e),n.get()}};function wt(t,e,...n){let{current:r}=b;r.host(function(o){o[M]||(o[M]=[]),o[M].push([[t,e],...n]),!r.prevent&&w.disconnected(()=>o[M].forEach(([[c,i]])=>T(c,i,c[l]&&c[l].host&&c[l].host()===o)))(o)})}var Jt=new FinalizationRegistry(function(t){g.clear({[l]:t})});function Et(t,e,n){let r=S(t?Ut:rt),o=yt(r,e,n,t);return Jt.register(o,o[l]),o}var Bt=x(S(),{stopPropagation(){this.skip=!0}});function yt(t,e,n,r=!1){let o=[];ct(n)!=="[object Object]"&&(n={});let{onclear:c}=g.symbols;n[c]&&(o.push(n[c]),delete n[c]);let{host:i}=b;return Reflect.defineProperty(t,l,{value:x(S(Bt),{value:e,actions:n,onclear:o,host:i,listeners:new Set,readonly:r}),enumerable:!1,writable:!1,configurable:!0}),t}function Zt(){return Z[Z.length-1]}function _t(t){if(!t[l])return;let{value:e,listeners:n}=t[l],r=Zt();return r&&n.add(r),E.has(r)&&E.get(r).add(t),e}function At(t,e,n){let r=t[l];if(!(!r||!n&&r.value===e))return r.value=e,et(t,n),e}function ot(t,e){if(t[l])return t[l].listeners.add(e)}function T(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 i=E.get(r);if(!i)return c;let s=E.get(i);if(!s)return c;for(let p of s)T(p,i,!0);return c}$(St);return Nt(Gt);})(); + Investigate `__dde_attributes` key of the element. */g.clear(...Object.values(this[nt]))})(t),n};var wt={isSignal:j,processReactiveAttribute(t,e,n,r){if(!j(n))return n;let o=c=>{if(!t.isConnected)return M(n,o);r(e,c)};return rt(n,o),yt(n,o,t,e),n.get()}};function yt(t,e,...n){let{current:r}=v;r.host(function(o){let c=!o[N];c&&(o[N]=[]),o[N].push([[t,e],...n]),!(!c||r.prevent)&&w.disconnected(()=>o[N].forEach(([[i,s]])=>M(i,s,i[l]&&i[l].host&&i[l].host()===o)))(o)})}var Jt=new FinalizationRegistry(function(t){g.clear({[l]:t})});function xt(t,e,n){let r=S(t?Et:St),o=At(r,e,n);return Jt.register(o,o[l]),o}var Bt=x(S(),{stopPropagation(){this.skip=!0}});function At(t,e,n){let r=[];ot(n)!=="[object Object]"&&(n={});let{onclear:o}=g.symbols;n[o]&&(r.push(n[o]),delete n[o]);let{host:c}=v;return Reflect.defineProperty(t,l,{value:x(S(Bt),{value:e,actions:n,onclear:r,host:c,listeners:new Set}),enumerable:!1,writable:!1,configurable:!0}),t}function Zt(){return Z[Z.length-1]}function _t(t){if(!t[l])return;let{value:e,listeners:n}=t[l],r=Zt();return r&&n.add(r),_.has(r)&&_.get(r).add(t),e}function Ct(t,e,n){let r=t[l];if(!(!r||!n&&r.value===e))return r.value=e,et(t,n),e}function rt(t,e){if(t[l])return t[l].listeners.add(e)}function M(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 i=_.get(r);if(!i)return c;let s=_.get(i);if(!s)return c;for(let a of s)M(a,i,!0);return c}$(wt);return Mt(Gt);})(); diff --git a/dist/iife.js b/dist/iife.js index 15fa790..5c70716 100644 --- a/dist/iife.js +++ b/dist/iife.js @@ -67,6 +67,11 @@ var DDE = (() => { signal.removeEventListener("abort", listener); }; } + function requestIdle() { + return new Promise(function(resolve) { + (globalThis.requestIdleCallback || requestAnimationFrame)(resolve); + }); + } // src/dom-lib/common.js var enviroment = { @@ -205,11 +210,6 @@ var DDE = (() => { is_observing = false; observer.disconnect(); } - function requestIdle() { - return new Promise(function(resolve) { - (requestIdleCallback || requestAnimationFrame)(resolve); - }); - } async function collectChildren(element) { if (store.size > 30) await requestIdle(); diff --git a/dist/iife.min.js b/dist/iife.min.js index 12e6a97..a6e927a 100644 --- a/dist/iife.min.js +++ b/dist/iife.min.js @@ -1 +1 @@ -var DDE=(()=>{var F=Object.defineProperty;var it=Object.getOwnPropertyDescriptor;var ut=Object.getOwnPropertyNames;var ft=Object.prototype.hasOwnProperty;var at=(t,e)=>{for(var n in e)F(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&&F(t,o,{get:()=>e[o],enumerable:!(r=it(e,o))||r.enumerable});return t};var dt=t=>pt(F({},"__esModule",{value:!0}),t);var _t={};at(_t,{assign:()=>R,assignAttribute:()=>H,chainableAppend:()=>et,classListDeclarative:()=>rt,createElement:()=>M,createElementNS:()=>vt,customElementRender:()=>Et,customElementWithDDE:()=>ct,dispatchEvent:()=>mt,el:()=>M,elNS:()=>vt,lifecyclesToEvents:()=>ct,memo:()=>W,on:()=>S,queue:()=>bt,registerReactivity:()=>V,scope:()=>C,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 g(...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}v(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 D=t.get(b);D.length_c&&(b.dispatchEvent(new Event(E)),D.connected=new WeakSet,D.length_c=0,D.length_d||t.delete(b),i=!0)}return i}function v(s,u){let i=!1;for(let b of s)u&&m(b).then(v),!(!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 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,g({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 J=t=>g({},typeof t=="object"?t:null,{once:!0});S.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)}};S.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}],U=new WeakMap,C={get current(){return _[_.length-1]},get host(){return this.current.host},get signal(){let{host:t}=this;if(U.has(t))return U.get(t);let e=new AbortController;return U.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(g({},this.current,{prevent:!1},t))},pushRoot(){return _.push(_[0])},pop(){if(_.length!==1)return _.pop()}};var O={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function V(t,e=!0){return e?g(O,t):(Object.setPrototypeOf(t,O),t)}function N(t){return Z(t,O)&&t!==O?t:O}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 $(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=(...v)=>v.length?(o===1?n.unshift(...v):v.forEach(j=>j(p)),void 0):p;C.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&&C.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 vt(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(g({},...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 $(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 k(o,e,t,n,$.bind(null,t[e]));case"ariaset":return k(o,e,t,n,(a,d)=>r("aria-"+a,d));case"classList":return rt.call(c,t,n)}return gt(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 k(n,"classList",t,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function gt(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 k(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(v=>v.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;C.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}),C.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",q=[];function W(t,e){if(!q.length)return e(t);let n=typeof t=="object"?JSON.stringify(t):t,[{cache:r,after:o}]=q;return o(n,B(r,n)?r[n]:e(t))}W.isScope=function(t){return t[st]};W.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();q.unshift({cache:o,after(m,l){return a[m]=l}});let d=e.apply(this,p);return q.shift(),o=a,d}return c[st]=!0,c.clear=()=>o=L(),n&&n.addEventListener("abort",c.clear),c};return dt(_t);})(); +var DDE=(()=>{var j=Object.defineProperty;var it=Object.getOwnPropertyDescriptor;var ut=Object.getOwnPropertyNames;var ft=Object.prototype.hasOwnProperty;var at=(t,e)=>{for(var n in e)j(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&&j(t,o,{get:()=>e[o],enumerable:!(r=it(e,o))||r.enumerable});return t};var dt=t=>pt(j({},"__esModule",{value:!0}),t);var _t={};at(_t,{assign:()=>R,assignAttribute:()=>k,chainableAppend:()=>et,classListDeclarative:()=>rt,createElement:()=>M,createElementNS:()=>gt,customElementRender:()=>Et,customElementWithDDE:()=>ct,dispatchEvent:()=>mt,el:()=>M,elNS:()=>gt,lifecyclesToEvents:()=>ct,memo:()=>W,on:()=>S,queue:()=>bt,registerReactivity:()=>V,scope:()=>C,simulateSlots:()=>xt});var z=(...t)=>Object.prototype.hasOwnProperty.call(...t);function x(t){return typeof t>"u"}function h(t,e){return t instanceof e}function B(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function T(t=null,e={}){return Object.create(t,e)}function g(...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)}}function Z(){return new Promise(function(t){(globalThis.requestIdleCallback||requestAnimationFrame)(t)})}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(m(i.addedNodes,!0)){s();continue}l(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())}async function d(s){t.size>30&&await Z();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 m(s,u){let i=!1;for(let b of s){if(u&&d(b).then(m),!t.has(b))continue;let D=t.get(b);D.length_c&&(b.dispatchEvent(new Event(E)),D.connected=new WeakSet,D.length_c=0,D.length_d||t.delete(b),i=!0)}return i}function l(s,u){let i=!1;for(let b of s)u&&d(b).then(l),!(!t.has(b)||!t.get(b).length_d)&&((globalThis.queueMicrotask||setTimeout)(v(b)),i=!0);return i}function v(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,g({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 J=t=>g({},typeof t=="object"?t:null,{once:!0});S.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)}};S.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,C={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(S.disconnected(()=>e.abort())),e.signal},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[..._]},push(t={}){return _.push(g({},this.current,{prevent:!1},t))},pushRoot(){return _.push(_[0])},pop(){if(_.length!==1)return _.pop()}};var O={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function V(t,e=!0){return e?g(O,t):(Object.setPrototypeOf(t,O),t)}function L(t){return B(t,O)&&t!==O?t:O}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 N;function M(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=(...v)=>v.length?(o===1?n.unshift(...v):v.forEach(s=>s(p)),void 0):p;C.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!!N:c=R.call(this,f.D.createElementNS(N,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&&C.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){N=t;let o=M.call(e,...r);return N=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(g({},...e)))k.call(this,t,n,r);return P.delete(t),t}function k(t,e,n){let{setRemoveAttr:r,s:o}=nt(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(a,d)=>k.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=L(e);return{setRemoveAttr:r,s:o}}function rt(t,e){let n=L(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(v=>v.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;C.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}),C.pop(),t.append(c)}function ct(t){return H(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(E))}),H(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(w)))}),H(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 H(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}var st="__dde_memo",q=[];function W(t,e){if(!q.length)return e(t);let n=typeof t=="object"?JSON.stringify(t):t,[{cache:r,after:o}]=q;return o(n,z(r,n)?r[n]:e(t))}W.isScope=function(t){return t[st]};W.scope=function(e,{signal:n,onlyLast:r}={}){let o=T();function c(...p){if(n&&n.aborted)return e.apply(this,p);let a=r?o:T();q.unshift({cache:o,after(m,l){return a[m]=l}});let d=e.apply(this,p);return q.shift(),o=a,d}return c[st]=!0,c.clear=()=>o=T(),n&&n.addEventListener("abort",c.clear),c};return dt(_t);})(); diff --git a/docs/components/code.html.js b/docs/components/code.html.js index 6425412..3179ea6 100644 --- a/docs/components/code.html.js +++ b/docs/components/code.html.js @@ -1,4 +1,4 @@ -import { registerClientFile, styles } from "../ssr.js"; +import { page_id, registerClientFile, styles } from "../ssr.js"; const host= "."+code.name; styles.css` /* Code block styling */ @@ -177,6 +177,9 @@ ${host}:hover .copy-button { } `; import { el } from "deka-dom-el"; +/** + * @typedef {"js"|"ts"|"html"|"css"|"shell"|"-"} Language + * */ /** * Prints code to the page and registers flems to make it interactive. * @param {object} attrs @@ -184,15 +187,17 @@ 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"|"shell"} [attrs.language="js"] Language of the code - * @param {string} [attrs.page_id] ID of the page, if setted it registers shiki + * @param {Language} [attrs.language="-s"] Language of the code * */ -export function code({ id, src, content, language= "js", className= host.slice(1), page_id }){ - if(src) content= s.cat(src); +export function code({ id, src, content, language= "-", className= host.slice(1) }){ + if(src){ + content= s.cat(src); + if(language=== "-") language= /** @type {Language} */(src.pathname.split(".").pop()); + } content= normalizeIndentation(content); let dataJS; - if(page_id){ - registerClientPart(page_id); + if(language!== "-"){ + registerClientPart(); dataJS= "todo"; } return el("div", { id, className, dataJS, tabIndex: 0 }).append( @@ -204,8 +209,7 @@ export function pre({ content }){ return el("pre").append(el("code", content.trim())); } let is_registered= {}; -/** @param {string} page_id */ -function registerClientPart(page_id){ +function registerClientPart(){ if(is_registered[page_id]) return; // Add Shiki with a more reliable loading method diff --git a/docs/components/converter.html.js b/docs/components/converter.html.js index fc9db56..139e960 100644 --- a/docs/components/converter.html.js +++ b/docs/components/converter.html.js @@ -1,4 +1,4 @@ -import { styles } from "../ssr.js"; +import { page_id, styles } from "../ssr.js"; styles.css` #html-to-dde-converter { @@ -149,12 +149,11 @@ 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 }){ +export function converter(){ registerClientPart(page_id); return el(ireland, { src: fileURL("./converter.js.js"), exportName: "converter", - page_id, }); } diff --git a/docs/components/example.html.js b/docs/components/example.html.js index 64d1f72..47d6118 100644 --- a/docs/components/example.html.js +++ b/docs/components/example.html.js @@ -1,4 +1,4 @@ -import { styles } from "../ssr.js"; +import { page_id, styles } from "../ssr.js"; const host= "."+example.name; styles.css` ${host} { @@ -119,9 +119,8 @@ import { relative } from "node:path"; * @param {URL} attrs.src Example code file path * @param {"js"|"ts"|"html"|"css"} [attrs.language="js"] Language of the code * @param {"normal"|"big"} [attrs.variant="normal"] Size of the example - * @param {string} attrs.page_id ID of the page * */ -export function example({ src, language= "js", variant= "normal", page_id }){ +export function example({ src, language= "js", variant= "normal" }){ registerClientPart(page_id); const content= s.cat(src).toString() .replaceAll(/ from "deka-dom-el(\/signals)?";/g, ' from "./esm-with-signals.js";'); diff --git a/docs/components/examples/case-studies/data-dashboard.js b/docs/components/examples/case-studies/data-dashboard.js index 9aa78e9..6ed125a 100644 --- a/docs/components/examples/case-studies/data-dashboard.js +++ b/docs/components/examples/case-studies/data-dashboard.js @@ -303,6 +303,7 @@ document.body.append( padding: 1rem; margin-bottom: 1.5rem; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); + overflow: auto; } .loading-spinner { diff --git a/docs/components/examples/case-studies/products.js b/docs/components/examples/case-studies/products.js new file mode 100644 index 0000000..91fa2c2 --- /dev/null +++ b/docs/components/examples/case-studies/products.js @@ -0,0 +1,501 @@ +import { el, on } from "deka-dom-el"; +import { S } from "deka-dom-el/signals"; + +export function ProductCatalog() { + const itemsPerPage = 5; + const products = asyncSignal(S, fetchProducts, { initial: [], keepLast: true }); + const searchTerm = S(""); + const handleSearch = (e) => searchTerm.set(e.target.value); + const sortOrder = S("default"); + const handleSort = (e) => sortOrder.set(e.target.value); + const page = S(1); + const handlePageChange = (newPage) => page.set(newPage); + const resetFilters = () => { + searchTerm.set(""); + sortOrder.set("default"); + page.set(1); + }; + + const filteredProducts = S(() => { + if (products.status.get() !== "resolved") return []; + + const results = products.result.get().filter(product => + product.title.toLowerCase().includes(searchTerm.get().toLowerCase()) || + product.description.toLowerCase().includes(searchTerm.get().toLowerCase()) + ); + + return [...results].sort((a, b) => { + const order = sortOrder.get(); + if (order === "price-asc") return a.price - b.price; + if (order === "price-desc") return b.price - a.price; + if (order === "rating") return b.rating - a.rating; + return 0; // default: no sorting + }); + }); + const totalPages = S(() => Math.ceil(filteredProducts.get().length / itemsPerPage)); + const paginatedProducts = S(() => { + const currentPage = page.get(); + const filtered = filteredProducts.get(); + const start = (currentPage - 1) * itemsPerPage; + return filtered.slice(start, start + itemsPerPage); + }); + + // Component structure + return el("div", { className: "product-catalog" }).append( + el("header", { className: "catalog-header" }).append( + el("h2", "Product Catalog"), + el("div", { className: "toolbar" }).append( + el("button", { + className: "refresh-btn", + textContent: "Refresh Products", + type: "button", + onclick: () => products.invoke(), + }), + el("button", { + className: "reset-btn", + textContent: "Reset Filters", + type: "button", + onclick: resetFilters, + }) + ) + ), + + // Search and filter controls + el("div", { className: "controls" }).append( + el("div", { className: "search-box" }).append( + el("input", { + type: "search", + placeholder: "Search products...", + value: searchTerm, + oninput: handleSearch, + }) + ), + el("div", { className: "sort-options" }).append( + el("label", "Sort by: "), + el("select", { onchange: handleSort }, on.defer(el => el.value = sortOrder.get())).append( + el("option", { value: "default", textContent: "Default" }), + el("option", { value: "price-asc", textContent: "Price: Low to High" }), + el("option", { value: "price-desc", textContent: "Price: High to Low" }), + el("option", { value: "rating", textContent: "Top Rated" }) + ) + ) + ), + + // Status indicators + el("div", { className: "status-container" }).append( + S.el(products.status, status => + status === "pending" ? + el("div", { className: "loader" }).append( + el("div", { className: "spinner" }), + el("p", "Loading products...") + ) + : status === "rejected" ? + el("div", { className: "error-message" }).append( + el("p", products.error.get().message), + el("button", { + textContent: "Try Again", + onclick: () => products.invoke() + }) + ) + : el() + ) + ), + + // Results count + S.el(S(()=> [filteredProducts.get(), searchTerm.get()]), ([filtered, term]) => + products.status.get() === "resolved" + ? el("div", { + className: "results-info", + textContent: term ? + `Found ${filtered.length} products matching "${term}"` + : `Showing all ${filtered.length} products` + }) + : el() + ), + + // Products grid + el("div", { className: "products-grid" }).append( + S.el(paginatedProducts, paginatedItems => + products.status.get() === "resolved" && paginatedItems.length > 0 ? + paginatedItems.map(product => el(ProductCard, { product })) + : products.status.get() === "resolved" && paginatedItems.length === 0 ? + el("p", { className: "no-results", textContent: "No products found matching your criteria." }) + : el() + ) + ), + + // Pagination + S.el(S(()=> [totalPages.get(), page.get()]), ([total, current]) => + products.status.get() === "resolved" && total > 1 ? + el("div", { className: "pagination" }).append( + el("button", { + textContent: "Previous", + disabled: current === 1, + onclick: () => handlePageChange(current - 1) + }), + ...Array.from({ length: total }, (_, i) => i + 1).map(num => + el("button", { + className: num === current ? "current-page" : "", + textContent: num, + onclick: () => handlePageChange(num) + }) + ), + el("button", { + textContent: "Next", + disabled: current === total, + onclick: () => handlePageChange(current + 1) + }) + ) + : el() + ) + ); +} + +// Product card component +function ProductCard({ product }) { + const showDetails = S(false); + + return el("div", { className: "product-card" }).append( + el("div", { className: "product-image" }).append( + el("img", { src: product.thumbnail, alt: product.title }) + ), + el("div", { className: "product-info" }).append( + el("h3", { className: "product-title", textContent: product.title }), + el("div", { className: "product-price-rating" }).append( + el("span", { className: "product-price", textContent: `$${product.price.toFixed(2)}` }), + el("span", { className: "product-rating" }).append( + el("span", { className: "stars", textContent: "★".repeat(Math.round(product.rating)) }), + el("span", { className: "rating-value", textContent: `(${product.rating})` }), + ) + ), + el("p", { className: "product-category", textContent: `Category: ${product.category}` }), + S.el(showDetails, details => + details ? + el("div", { className: "product-details" }).append( + el("p", { className: "product-description", textContent: product.description }), + el("div", { className: "product-meta" }).append( + el("p", `Brand: ${product.brand}`), + el("p", `Stock: ${product.stock} units`), + el("p", `Discount: ${product.discountPercentage}%`) + ) + ) + : el() + ), + el("div", { className: "product-actions" }).append( + el("button", { + className: "details-btn", + textContent: S(() => showDetails.get() ? "Hide Details" : "Show Details"), + onclick: () => showDetails.set(!showDetails.get()) + }), + el("button", { + className: "add-to-cart-btn", + textContent: "Add to Cart" + }) + ) + ) + ); +} + +// Data fetching function +async function fetchProducts({ signal }) { + await simulateNetworkDelay(); + // Simulate random errors for demonstration + if (Math.random() > 0.9) throw new Error("Failed to load products. Network error."); + + const response = await fetch("https://dummyjson.com/products", { signal }); + if (!response.ok) throw new Error(`API error: ${response.status}`); + + const data = await response.json(); + return data.products.slice(0, 20); // Limit to 20 products for the demo +} + +// Utility for simulating network latency +function simulateNetworkDelay(min = 300, max = 1200) { + const delay = Math.floor(Math.random() * (max - min + 1)) + min; + return new Promise(resolve => setTimeout(resolve, delay)); +} + +/** + * Custom hook for async data fetching with signals + * @template T + * @param {typeof S} S - Signal constructor + * @param {(params: { signal: AbortSignal }) => Promise} invoker - Async function to execute + * @param {{ initial?: T, keepLast?: boolean }} options - Configuration options + * @returns {Object} Status signals and control methods + */ +export function asyncSignal(S, invoker, { initial, keepLast } = {}) { + // Status tracking signals + const status = S("pending"); + const result = S(initial); + const error = S(null); + let controller = null; + + // Function to trigger data fetching + async function invoke() { + // Cancel any in-flight request + if (controller) controller.abort(); + controller = new AbortController(); + + status.set("pending"); + error.set(null); + if (!keepLast) result.set(initial); + + try { + const data = await invoker({ + signal: controller.signal, + }); + if (!controller.signal.aborted) { + status.set("resolved"); + result.set(data); + } + } catch (e) { + if (e.name !== "AbortError") { + error.set(e); + status.set("rejected"); + } + } + } + + // Initial data fetch + invoke(); + + return { status, result, error, invoke }; +} + +// Initialize the component +document.body.append( + el(ProductCatalog), + el("style", ` + .product-catalog { + font-family: system-ui, -apple-system, sans-serif; + max-width: 1200px; + margin: 0 auto; + padding: 20px; + } + + .catalog-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; + } + + .toolbar button { + margin-left: 10px; + padding: 8px 12px; + border-radius: 4px; + border: none; + background: #4a6cf7; + color: white; + cursor: pointer; + } + + .controls { + display: flex; + justify-content: space-between; + margin-bottom: 20px; + gap: 15px; + flex-wrap: wrap; + } + + .search-box input { + padding: 8px 12px; + border: 1px solid #ddd; + border-radius: 4px; + width: 300px; + max-width: 100%; + } + + .sort-options select { + padding: 8px 12px; + border: 1px solid #ddd; + border-radius: 4px; + } + + .loader { + text-align: center; + padding: 40px 0; + } + + .spinner { + display: inline-block; + width: 40px; + height: 40px; + border: 4px solid rgba(0, 0, 0, 0.1); + border-left-color: #4a6cf7; + border-radius: 50%; + animation: spin 1s linear infinite; + } + + @keyframes spin { + to { transform: rotate(360deg); } + } + + .error-message { + background: #ffebee; + color: #c62828; + padding: 15px; + border-radius: 4px; + margin: 20px 0; + text-align: center; + } + + .results-info { + margin-bottom: 15px; + color: #666; + } + + .products-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 20px; + margin-bottom: 30px; + } + + .product-card { + border: 1px solid #eee; + border-radius: 8px; + overflow: hidden; + transition: transform 0.2s, box-shadow 0.2s; + } + + .product-card:hover { + transform: translateY(-5px); + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); + } + + .product-image img { + width: 100%; + height: 180px; + object-fit: cover; + display: block; + } + + .product-info { + padding: 15px; + } + + .product-title { + margin: 0 0 10px; + font-size: 1.1rem; + height: 2.4rem; + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + } + + .product-price-rating { + display: flex; + justify-content: space-between; + margin-bottom: 10px; + } + + .product-price { + font-weight: bold; + color: #4a6cf7; + font-size: 1.2rem; + } + + .stars { + color: gold; + margin-right: 5px; + } + + .product-category { + color: #666; + font-size: 0.9rem; + margin-bottom: 15px; + } + + .product-details { + margin: 15px 0; + font-size: 0.9rem; + } + + .product-description { + line-height: 1.5; + margin-bottom: 10px; + color: #444; + } + + .product-meta { + display: flex; + flex-wrap: wrap; + gap: 10px; + color: #666; + font-size: 0.85rem; + } + + .product-actions { + display: flex; + gap: 10px; + margin-top: 15px; + } + + .product-actions button { + flex: 1; + padding: 8px 0; + border: none; + border-radius: 4px; + cursor: pointer; + } + + .details-btn { + background: #eee; + color: #333; + } + + .add-to-cart-btn { + background: #4a6cf7; + color: white; + } + + .pagination { + display: flex; + justify-content: center; + gap: 5px; + margin-top: 30px; + } + + .pagination button { + padding: 8px 12px; + border: 1px solid #ddd; + background: white; + border-radius: 4px; + cursor: pointer; + } + + .pagination button.current-page { + background: #4a6cf7; + color: white; + border-color: #4a6cf7; + } + + .pagination button:disabled { + opacity: 0.5; + cursor: not-allowed; + } + + .no-results { + grid-column: 1 / -1; + text-align: center; + padding: 40px; + color: #666; + } + + @media (max-width: 768px) { + .controls { + flex-direction: column; + } + + .search-box input { + width: 100%; + } + + .products-grid { + grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); + } + } + `), +); diff --git a/docs/components/examples/case-studies/task-manager.js b/docs/components/examples/case-studies/task-manager.js index b6d24b2..d501b1c 100644 --- a/docs/components/examples/case-studies/task-manager.js +++ b/docs/components/examples/case-studies/task-manager.js @@ -483,7 +483,7 @@ document.body.append( .task-board { display: grid; - grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1.5rem; } diff --git a/docs/components/examples/elements/dde-dom-create.js b/docs/components/examples/elements/dde-dom-create.js index b9edb55..7806369 100644 --- a/docs/components/examples/elements/dde-dom-create.js +++ b/docs/components/examples/elements/dde-dom-create.js @@ -4,11 +4,11 @@ import { el } from "deka-dom-el"; const button = el("button", { textContent: "Click me", className: "primary", - disabled: true + disabled: true, }); // Shorter and more expressive // than the native approach // Add to DOM -document.body.append(button); \ No newline at end of file +document.body.append(button); diff --git a/docs/components/examples/elements/dde-dom-tree.js b/docs/components/examples/elements/dde-dom-tree.js index 4cf01b0..5865f55 100644 --- a/docs/components/examples/elements/dde-dom-tree.js +++ b/docs/components/examples/elements/dde-dom-tree.js @@ -6,6 +6,6 @@ import { el } from "deka-dom-el"; document.body.append( el("div").append( el("h1", "Title"), - el("p", "Paragraph") - ) + el("p", "Paragraph"), + ), ); diff --git a/docs/components/examples/reallife/todomvc.js b/docs/components/examples/reallife/todomvc.js index b2c0985..09ef0af 100644 --- a/docs/components/examples/reallife/todomvc.js +++ b/docs/components/examples/reallife/todomvc.js @@ -81,11 +81,11 @@ function Todos(){ ) ) ), - S.el(todosS, todos => !todos.length + S.el(todosS, ({ length }) => !length ? el() : el("footer", { className: "footer" }).append( el("span", { className: "todo-count" }).append( - noOfLeft() + el("strong", length + " " + (length === 1 ? "item" : "items")), ), memo("filters", ()=> el("ul", { className: "filters" }).append( @@ -100,7 +100,7 @@ function Todos(){ ) ), ), - todos.length - todosRemainingS.get() === 0 + length - todosRemainingS.get() === 0 ? el() : memo("delete", () => el("button", @@ -110,13 +110,6 @@ function Todos(){ ) ) ); - function noOfLeft(){ - const length = todosRemainingS.get(); - return el("strong").append( - length + " ", - length === 1 ? "item left" : "items left" - ) - } } /** diff --git a/docs/components/getLibraryUrl.html.js b/docs/components/getLibraryUrl.html.js index 9f02992..d1fa163 100644 --- a/docs/components/getLibraryUrl.html.js +++ b/docs/components/getLibraryUrl.html.js @@ -1,4 +1,4 @@ -import { styles } from "../ssr.js"; +import { styles, page_id } from "../ssr.js"; styles.css` #library-url-form { @@ -74,7 +74,7 @@ styles.css` import { el } from "deka-dom-el"; import { ireland } from "./ireland.html.js"; -export function getLibraryUrl({ page_id }){ +export function getLibraryUrl(){ return el(ireland, { src: new URL("./getLibraryUrl.js.js", import.meta.url), exportName: "getLibraryUrl", diff --git a/docs/components/ireland.html.js b/docs/components/ireland.html.js index 15b42e2..6422b77 100644 --- a/docs/components/ireland.html.js +++ b/docs/components/ireland.html.js @@ -43,7 +43,6 @@ const componentsRegistry = new Map(); * @param {object} attrs * @param {URL} attrs.src - Path to the file containing the component * @param {string} [attrs.exportName="default"] - Name of the export to use - * @param {string} attrs.page_id - ID of the current page * @param {object} [attrs.props={}] - Props to pass to the component */ export function ireland({ src, exportName = "default", props = {} }) { diff --git a/docs/components/mnemonic/events-init.js b/docs/components/mnemonic/events-init.js index 22ace4c..a0f7bc1 100644 --- a/docs/components/mnemonic/events-init.js +++ b/docs/components/mnemonic/events-init.js @@ -12,6 +12,10 @@ export function mnemonic(){ " — corresponds to custom elemnets callbacks ", el("code", "Callback(...){...}"), ". To connect to custom element see following page, else it is simulated by MutationObserver." ), + el("li").append( + el("code", "on.defer(=> )()"), + " — calls callback later", + ), el("li").append( el("code", "dispatchEvent([, ])(element)"), " — just ", el("code", ".dispatchEvent(new Event([, ]))") diff --git a/docs/index.html.js b/docs/index.html.js index 3982987..bb1a051 100644 --- a/docs/index.html.js +++ b/docs/index.html.js @@ -3,8 +3,8 @@ import { t, T } from "./utils/index.js"; export const info= { href: "./", title: t`Introduction`, - fullTitle: t`Vanilla for flavouring — a full-fledged feast for large projects`, - description: t`A lightweight, reactive DOM library for creating dynamic UIs with a declarative syntax`, + fullTitle: t`Vanilla for flavouring — a full-fledged feast for large projects`, + description: t`Reactive DOM library for creating dynamic UIs with a declarative syntax`, }; import { el } from "deka-dom-el"; @@ -16,7 +16,11 @@ import { getLibraryUrl } from "./components/getLibraryUrl.html.js"; /** @param {string} url */ const fileURL= url=> new URL(url, import.meta.url); const references= { - w_mvv:{ + npm: { + title: t`NPM package page for dd`, + href: "https://www.npmjs.com/package/deka-dom-el", + }, + w_mvv: { title: t`Wikipedia: Model–view–viewmodel`, href: "https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel", }, @@ -27,10 +31,9 @@ const references= { }; /** @param {import("./types.d.ts").PageAttrs} attrs */ export function page({ pkg, info }){ - const page_id= info.id; return el(simplePage, { info, pkg }).append( el("p").append(T` - Welcome to Deka DOM Elements (dd or DDE) — a lightweight library for building dynamic UIs with + Welcome to Deka DOM Elements (dd or DDE) — a 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. `), @@ -40,11 +43,11 @@ export function page({ pkg, info }){ 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 😇)`), el("li", t`Natural DOM API — work with real DOM nodes, not abstractions`), - el("li", t`Built-in reactivity with simplified but powerful signals system`), + el("li", t`Built-in (but optional) reactivity with simplified but powerful signals system`), el("li", t`Clean code organization with the 3PS pattern`) ) ), - el(example, { src: fileURL("./components/examples/introducing/helloWorld.js"), page_id }), + el(example, { src: fileURL("./components/examples/introducing/helloWorld.js") }), el(h3, { textContent: t`The 3PS Pattern: Simplified architecture pattern`, id: "h-3ps" }), el("p").append(T` @@ -56,11 +59,11 @@ export function page({ pkg, info }){ el("div", { className: "tabs" }).append( el("div", { className: "tab" }).append( el("h5", t`Traditional DOM Manipulation`), - el(code, { src: fileURL("./components/examples/introducing/3ps-before.js"), page_id }), + el(code, { src: fileURL("./components/examples/introducing/3ps-before.js") }), ), el("div", { className: "tab" }).append( el("h5", t`dd's 3PS Pattern`), - el(code, { src: fileURL("./components/examples/introducing/3ps.js"), page_id }), + el(code, { src: fileURL("./components/examples/introducing/3ps.js") }), ) ) ), @@ -101,16 +104,20 @@ export function page({ pkg, info }){ 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. + 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 --save", language: "shell", page_id }), + el(code, { content: "npm install deka-dom-el --save", language: "shell" }), + el("p").append(T` + …see ${el("a", { textContent: "package page", ...references.npm, target: "_blank" })}. + `), + 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(getLibraryUrl), el("div", { className: "note" }).append( el("p").append(T` Based on your selection, you can use dd in your project like this: @@ -119,10 +126,10 @@ export function page({ pkg, info }){ // 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) + // Or with IIFE format (creates a global DDE object) // const { el, on } = DDE; - `, language: "js", page_id }), + `, language: "js" }), ), el(h3, t`How to Use This Documentation`), @@ -146,7 +153,7 @@ export function page({ pkg, info }){ Integrating third-party functionalities`), 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 rendering with dd`), diff --git a/docs/p02-elements.html.js b/docs/p02-elements.html.js index ff47db2..0834bb6 100644 --- a/docs/p02-elements.html.js +++ b/docs/p02-elements.html.js @@ -47,12 +47,11 @@ const references= { }; /** @param {import("./types.d.ts").PageAttrs} attrs */ export function page({ pkg, info }){ - const page_id= info.id; return el(simplePage, { info, pkg }).append( el("p").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. + dd provides a simple yet powerful approach to element creation that is declarative, chainable, + and maintains a clean syntax close to HTML structure. `), el("div", { className: "callout" }).append( el("h4", t`dd Elements: Key Benefits`), @@ -65,7 +64,7 @@ export function page({ pkg, info }){ ) ), - el(code, { src: fileURL("./components/examples/elements/intro.js"), page_id }), + el(code, { src: fileURL("./components/examples/elements/intro.js") }), el(h3, t`Creating Elements: Native vs dd`), el("p").append(T` @@ -77,11 +76,11 @@ export function page({ pkg, info }){ el("div", { className: "comparison" }).append( el("div").append( el("h5", t`Native DOM API`), - el(code, { src: fileURL("./components/examples/elements/native-dom-create.js"), page_id }) + el(code, { src: fileURL("./components/examples/elements/native-dom-create.js") }) ), el("div").append( el("h5", t`dd Approach`), - el(code, { src: fileURL("./components/examples/elements/dde-dom-create.js"), page_id }) + el(code, { src: fileURL("./components/examples/elements/dde-dom-create.js") }) ) ) ), @@ -89,7 +88,7 @@ export function page({ pkg, info }){ 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(example, { src: fileURL("./components/examples/elements/dekaCreateElement.js") }), el(h3, t`Advanced Property Assignment`), el("p").append(T` @@ -122,7 +121,7 @@ export function page({ pkg, info }){ el("dd").append(T`Pass ${el("code", "undefined")} to remove a property or attribute`) ) ), - el(example, { src: fileURL("./components/examples/elements/dekaAssign.js"), page_id }), + el(example, { src: fileURL("./components/examples/elements/dekaAssign.js") }), el("div", { className: "note" }).append( el("p").append(T` @@ -142,11 +141,11 @@ export function page({ pkg, info }){ el("div", { className: "comparison" }).append( el("div", { className: "bad-practice" }).append( el("h5", t`❌ Native DOM API`), - el(code, { src: fileURL("./components/examples/elements/native-dom-tree.js"), page_id }) + el(code, { src: fileURL("./components/examples/elements/native-dom-tree.js") }) ), el("div", { className: "good-practice" }).append( el("h5", t`✅ dd Approach`), - el(code, { src: fileURL("./components/examples/elements/dde-dom-tree.js"), page_id }) + el(code, { src: fileURL("./components/examples/elements/dde-dom-tree.js") }) ) ) ), @@ -154,14 +153,14 @@ export function page({ pkg, info }){ 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(example, { src: fileURL("./components/examples/elements/dekaAppend.js") }), el(h3, t`Using Components to Build UI Fragments`), 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(example, { src: fileURL("./components/examples/elements/dekaBasicComponent.js") }), 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. @@ -185,9 +184,9 @@ export function page({ pkg, info }){ 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(example, { src: fileURL("./components/examples/elements/dekaElNS.js") }), el("p").append(T` - This function returns a namespace-specific element creator, allowing you to work with any element type + This function returns a namespace-specific element creator, allowing you to work with any element type using the same consistent interface. `), diff --git a/docs/p03-events.html.js b/docs/p03-events.html.js index 9e1605b..e975337 100644 --- a/docs/p03-events.html.js +++ b/docs/p03-events.html.js @@ -39,7 +39,6 @@ const references= { }; /** @param {import("./types.d.ts").PageAttrs} attrs */ export function page({ pkg, info }){ - const page_id= info.id; return el(simplePage, { info, pkg }).append( el("p").append(T` Events are at the core of interactive web applications. dd provides a clean, declarative approach to @@ -57,7 +56,7 @@ export function page({ pkg, info }){ ) ), - el(code, { src: fileURL("./components/examples/events/intro.js"), page_id }), + el(code, { src: fileURL("./components/examples/events/intro.js") }), el(h3, t`Events and Listeners: Two Approaches`), el("p").append(T` @@ -70,11 +69,11 @@ export function page({ pkg, info }){ el("div", { className: "tabs" }).append( el("div", { className: "tab" }).append( el("h5", t`Native DOM API`), - el(code, { content: `element.addEventListener("click", callback, options);`, page_id }) + el(code, { content: `element.addEventListener("click", callback, options);`, language: "js" }) ), el("div", { className: "tab" }).append( el("h5", t`dd Approach`), - el(code, { content: `on("click", callback, options)(element);`, page_id }) + el(code, { content: `on("click", callback, options)(element);`, language: "js" }) ) ) ), @@ -82,7 +81,7 @@ export function page({ pkg, info }){ 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. `), - el(example, { src: fileURL("./components/examples/events/compare.js"), page_id }), + el(example, { src: fileURL("./components/examples/events/compare.js") }), el(h3, t`Removing Event Listeners`), el("div", { className: "note" }).append( @@ -91,7 +90,7 @@ export function page({ pkg, info }){ ${el("a", { textContent: "AbortSignal", ...references.mdn_abortListener })} for declarative removal: `) ), - el(example, { src: fileURL("./components/examples/events/abortSignal.js"), page_id }), + el(example, { src: fileURL("./components/examples/events/abortSignal.js") }), 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 — mainly ${el("code", "scope.signal")}). @@ -101,26 +100,26 @@ export function page({ pkg, info }){ el("div", { className: "tabs" }).append( 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(code, { src: fileURL("./components/examples/events/attribute-event.js") }), el("p").append(T` - Forces usage as an HTML attribute. Corresponds to + Forces usage as an HTML attribute. Corresponds to ${el("code", ``)}. This can be particularly useful for SSR scenarios. `) ), el("div", { className: "tab", dataTab: "property" }).append( el("h4", t`Property Assignment`), - el(code, { src: fileURL("./components/examples/events/property-event.js"), page_id }), + el(code, { src: fileURL("./components/examples/events/property-event.js") }), el("p", t`Assigns the event handler directly to the element’s property.`) ), el("div", { className: "tab", dataTab: "addon" }).append( el("h4", t`Addon Approach`), - el(code, { src: fileURL("./components/examples/events/chain-event.js"), page_id }), + el(code, { src: fileURL("./components/examples/events/chain-event.js") }), el("p", t`Uses the addon pattern (so adds the event listener to the element), see above.`) ) ), el("p").append(T` - For a deeper comparison of these approaches, see + For a deeper comparison of these approaches, see ${el("a", { textContent: "WebReflection’s detailed analysis", ...references.web_events })}. `), @@ -143,7 +142,7 @@ export function page({ pkg, info }){ 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(example, { src: fileURL("./components/examples/events/templateWithListeners.js") }), 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. @@ -167,7 +166,7 @@ export function page({ pkg, info }){ el("dd", t`Fires when the element is removed from the DOM`), ) ), - el(example, { src: fileURL("./components/examples/events/live-cycle.js"), page_id }), + el(example, { src: fileURL("./components/examples/events/live-cycle.js") }), el("div", { className: "note" }).append( el("p").append(T` @@ -217,8 +216,8 @@ export function page({ pkg, info }){ This makes it easy to implement component communication through events, following standard web platform patterns. The curried approach allows for easy reuse of event dispatchers throughout your application. `), - el(example, { src: fileURL("./components/examples/events/compareDispatch.js"), page_id }), - el(code, { src: fileURL("./components/examples/events/dispatch.js"), page_id }), + el(example, { src: fileURL("./components/examples/events/compareDispatch.js") }), + el(code, { src: fileURL("./components/examples/events/dispatch.js") }), el(h3, t`Best Practices`), el("ol").append( @@ -251,6 +250,6 @@ export function page({ pkg, info }){ ) ), - el(mnemonic) + el(mnemonic), ); } diff --git a/docs/p04-signals.html.js b/docs/p04-signals.html.js index 06560e9..805eee2 100644 --- a/docs/p04-signals.html.js +++ b/docs/p04-signals.html.js @@ -42,7 +42,6 @@ const references= { }; /** @param {import("./types.d.ts").PageAttrs} attrs */ export function page({ pkg, info }){ - const page_id= info.id; return el(simplePage, { info, pkg }).append( el("p").append(T` Signals provide a simple yet powerful way to create reactive applications with dd. They handle the @@ -58,7 +57,7 @@ export function page({ pkg, info }){ el("li").append(T`${el("strong", "In future")} no dependencies or framework lock-in`) ) ), - el(code, { src: fileURL("./components/examples/signals/intro.js"), page_id }), + el(code, { src: fileURL("./components/examples/signals/intro.js") }), el(h3, t`The 3-Part Structure of Signals`), el("p").append(T` @@ -68,21 +67,21 @@ export function page({ pkg, info }){ el("div", { className: "signal-diagram" }).append( el("div", { className: "signal-part" }).append( el("h4", t`PART 1: Create Signal`), - el(code, { content: "const count = S(0);", page_id }), + el(code, { content: "const count = S(0);", language: "js" }), el("p", t`Define a reactive value that can be observed and changed`) ), el("div", { className: "signal-part" }).append( el("h4", t`PART 2: React to Changes`), - el(code, { content: "S.on(count, value => updateUI(value));", page_id }), + el(code, { content: "S.on(count, value => updateUI(value));", language: "js" }), el("p", t`Subscribe to signal changes with callbacks or effects`) ), el("div", { className: "signal-part" }).append( el("h4", t`PART 3: Update Signal`), - el(code, { content: "count.set(count.get() + 1);", page_id }), + el(code, { content: "count.set(count.get() + 1);", language: "js" }), el("p", t`Modify the signal value, which automatically triggers updates`) ) ), - el(example, { src: fileURL("./components/examples/signals/signals.js"), page_id }), + el(example, { src: fileURL("./components/examples/signals/signals.js") }), el("div", { className: "note" }).append( el("p").append(T` @@ -125,12 +124,12 @@ export function page({ pkg, info }){ Computed values (also called derived signals) automatically update when their dependencies change. Create them by passing ${el("strong", "a function")} to ${el("code", "S()")}: `), - el(example, { src: fileURL("./components/examples/signals/derived.js"), page_id }), + el(example, { src: fileURL("./components/examples/signals/derived.js") }), el("p").append(T` Derived signals are read-only - you can’t call ${el("code", ".set()")} on them. Their value is always computed from their dependencies. They’re perfect for transforming or combining data from other signals. `), - el(example, { src: fileURL("./components/examples/signals/computations-abort.js"), page_id }), + el(example, { src: fileURL("./components/examples/signals/computations-abort.js") }), el(h3, t`Signal Actions: For Complex State`), el("p").append(T` @@ -151,7 +150,7 @@ export function page({ pkg, info }){ }); // Use the action S.action(todos, "add", "New todo"); - `, page_id }) + `, language: "js" }) ), el("div", { className: "bad-practice" }).append( el("h5", t`❌ Without Actions`), @@ -161,7 +160,7 @@ export function page({ pkg, info }){ const items = todos.get(); items.push("New todo"); // This WON’T trigger updates! - `, page_id })) + `, language: "js" })) ), ), el("p").append(T` @@ -172,7 +171,7 @@ export function page({ pkg, info }){ ${el("code", "this.stopPropagation()")} in the method representing the given action. As it can be seen in examples, the “store” value is available also in the function for given action (${el("code", "this.value")}). `), - el(example, { src: fileURL("./components/examples/signals/actions-demo.js"), page_id }), + el(example, { src: fileURL("./components/examples/signals/actions-demo.js") }), el("p").append(T` Actions provide these benefits: @@ -186,7 +185,7 @@ export function page({ pkg, info }){ el("p").append(T` Here’s a more complete example of a todo list using signal actions: `), - el(example, { src: fileURL("./components/examples/signals/actions-todos.js"), page_id }), + el(example, { src: fileURL("./components/examples/signals/actions-todos.js") }), el("div", { className: "tip" }).append( el("p").append(T` @@ -223,7 +222,7 @@ export function page({ pkg, info }){ // Later: color.set("red"); // UI updates automatically - `, page_id }), + `, language: "js" }), ), el("div", { className: "tab", dataTab: "elements" }).append( el("h4", t`Reactive Elements`), @@ -241,7 +240,7 @@ export function page({ pkg, info }){ // Later: S.action(items, "push", "Dragonfruit"); // List updates automatically - `, page_id }), + `, language: "js" }), ) ), @@ -250,12 +249,12 @@ export function page({ pkg, info }){ You can use special properties like ${el("code", "dataset")}, ${el("code", "ariaset")}, and ${el("code", "classList")} for fine-grained control over specific attribute types. `), - el(example, { src: fileURL("./components/examples/signals/dom-attrs.js"), page_id }), + el(example, { src: fileURL("./components/examples/signals/dom-attrs.js") }), el("p").append(T` ${el("code", "S.el()")} is especially powerful for conditional rendering and lists: `), - el(example, { src: fileURL("./components/examples/signals/dom-el.js"), page_id }), + el(example, { src: fileURL("./components/examples/signals/dom-el.js") }), el(h3, t`Best Practices for Signals`), el("p").append(T` @@ -289,7 +288,7 @@ export function page({ pkg, info }){ el("h4", t`We can process form events without signals`), el("p", t`This can be used when the form data doesn’t need to be reactive and we just waiting for results.`), - el(code, { page_id, content: ` + el(code, { content: ` const onFormSubmit = on("submit", e => { e.preventDefault(); const formData = new FormData(e.currentTarget); @@ -301,13 +300,13 @@ export function page({ pkg, info }){ return el("form", null, onFormSubmit).append( // … ); - ` }) + `, language: "js" }) ), el("div", { className: "tab", dataTab: "variables" }).append( el("h4", t`We can use variables without signals`), el("p", t`We use this when we dont’t need to reflect changes in the elsewhere (UI).`), - el(code, { page_id, content: ` + el(code, { content: ` let canSubmit = false; const onFormSubmit = on("submit", e => { @@ -318,14 +317,14 @@ export function page({ pkg, info }){ const onAllowSubmit = on("click", e => { canSubmit = true; }); - `}), + `, language: "js" }), ), el("div", { className: "tab", dataTab: "state" }).append( el("h4", t`Using signals`), el("p", t`We use this when we need to reflect changes for example in the UI (e.g. enable/disable buttons).`), - el(code, { page_id, content: ` + el(code, { content: ` const canSubmit = S(false); const onFormSubmit = on("submit", e => { @@ -341,7 +340,7 @@ export function page({ pkg, info }){ el("button", { textContent: "Allow Submit", type: "button" }, onAllowSubmit), el("button", { disabled: S(()=> !canSubmit), textContent: "Submit" }) ); - `}), + `, language: "js" }), ), ), diff --git a/docs/p05-scopes.html.js b/docs/p05-scopes.html.js index 418933e..8b93e5d 100644 --- a/docs/p05-scopes.html.js +++ b/docs/p05-scopes.html.js @@ -27,14 +27,13 @@ const references= { }; /** @param {import("./types.d.ts").PageAttrs} attrs */ export function page({ pkg, info }){ - const page_id= info.id; return el(simplePage, { info, pkg }).append( el("p").append(T` For state-less components we can use functions as UI components (see “Elements” page). But in real life, we may need to handle the component’s life-cycle and provide JavaScript the way to properly use the ${el("a", { textContent: t`Garbage collection`, ...references.garbage_collection })}. `), - el(code, { src: fileURL("./components/examples/scopes/intro.js"), page_id }), + el(code, { src: fileURL("./components/examples/scopes/intro.js") }), el("p").append(T`The library therefore uses ${el("em", t`scopes`)} to provide these functionalities.`), el(h3, t`Understanding Host Elements and Scopes`), @@ -83,7 +82,7 @@ export function page({ pkg, info }){ el("dd", t`Applies the addons to the host element (and returns the host element)`) ) ), - el(example, { src: fileURL("./components/examples/scopes/scopes-and-hosts.js"), page_id }), + el(example, { src: fileURL("./components/examples/scopes/scopes-and-hosts.js") }), el("div", { className: "tip" }).append( el("p").append(T` @@ -95,7 +94,7 @@ export function page({ pkg, info }){ If you are interested in the implementation details, see Class-Based Components section. `) ), - el(code, { src: fileURL("./components/examples/scopes/good-practise.js"), page_id }), + el(code, { src: fileURL("./components/examples/scopes/good-practise.js") }), el(h3, t`Class-Based Components`), el("p").append(T` @@ -103,7 +102,7 @@ export function page({ pkg, info }){ For this, we implement function ${el("code", "elClass")} and use it to demonstrate implementation details for better understanding of the scope logic. `), - el(example, { src: fileURL("./components/examples/scopes/class-component.js"), page_id }), + el(example, { src: fileURL("./components/examples/scopes/class-component.js") }), el(h3, t`Automatic Cleanup with Scopes`), el("p").append(T` @@ -123,7 +122,7 @@ export function page({ pkg, info }){ - Custom cleanup code (dd and user) ` }) ), - el(example, { src: fileURL("./components/examples/scopes/cleaning.js"), page_id }), + el(example, { src: fileURL("./components/examples/scopes/cleaning.js") }), el("div", { className: "note" }).append( el("p").append(T` @@ -149,17 +148,17 @@ export function page({ pkg, info }){ el("div", { className: "tab", dataTab: "declarative" }).append( el("h4", t`✅ Declarative Approach`), el("p", t`Define what your UI should look like based on state:`), - el(code, { src: fileURL("./components/examples/scopes/declarative.js"), page_id }) + el(code, { src: fileURL("./components/examples/scopes/declarative.js") }) ), el("div", { className: "tab", dataTab: "imperative" }).append( el("h4", t`⚠️ Imperative Approach`), el("p", t`Manually update the DOM in response to events:`), - el(code, { src: fileURL("./components/examples/scopes/imperative.js"), page_id }) + el(code, { src: fileURL("./components/examples/scopes/imperative.js") }) ), el("div", { className: "tab", dataTab: "mixed" }).append( el("h4", t`❌ Mixed Approach`), el("p", t`This approach should be avoided:`), - el(code, { src: fileURL("./components/examples/scopes/mixed.js"), page_id }) + el(code, { src: fileURL("./components/examples/scopes/mixed.js") }) ) ), diff --git a/docs/p06-customElement.html.js b/docs/p06-customElement.html.js index 89dd4d7..7bb22f7 100644 --- a/docs/p06-customElement.html.js +++ b/docs/p06-customElement.html.js @@ -57,7 +57,6 @@ const references= { }; /** @param {import("./types.d.ts").PageAttrs} attrs */ export function page({ pkg, info }){ - const page_id= info.id; return el(simplePage, { info, pkg }).append( el("p").append(T` dd pairs powerfully with ${el("a", references.mdn_web_components).append(el("strong", t`Web @@ -73,7 +72,7 @@ export function page({ pkg, info }){ el("li", t`Clean component lifecycle management`), ), ), - el(code, { src: fileURL("./components/examples/customElement/intro.js"), page_id }), + el(code, { src: fileURL("./components/examples/customElement/intro.js") }), el(h3, t`Getting Started: Web Components Basics`), el("p").append(T` @@ -95,7 +94,7 @@ export function page({ pkg, info }){ el("p").append(T` Let’s start with a basic Custom Element example without dd to establish the foundation: `), - el(code, { src: fileURL("./components/examples/customElement/native-basic.js"), page_id }), + el(code, { src: fileURL("./components/examples/customElement/native-basic.js") }), el("div", { className: "note" }).append( el("p").append(T` @@ -124,7 +123,7 @@ export function page({ pkg, info }){ el("dd", t`Allows using on.connected(), on.disconnected() or S.observedAttributes().`) ) ), - el(example, { src: fileURL("./components/examples/customElement/customElementWithDDE.js"), page_id }), + el(example, { src: fileURL("./components/examples/customElement/customElementWithDDE.js") }), el("div", { className: "tip" }).append( el("p").append(T` @@ -156,7 +155,7 @@ export function page({ pkg, info }){ el("dd", t`The rendered DOM tree`) ) ), - el(example, { src: fileURL("./components/examples/customElement/dde.js"), page_id }), + el(example, { src: fileURL("./components/examples/customElement/dde.js") }), el("div", { className: "note" }).append( el("p").append(T` @@ -188,7 +187,7 @@ export function page({ pkg, info }){ Using the ${el("code", "S.observedAttributes")} creates a reactive connection between your element’s attributes and its internal rendering. When attributes change, your component automatically updates! `), - el(example, { src: fileURL("./components/examples/customElement/observedAttributes.js"), page_id }), + el(example, { src: fileURL("./components/examples/customElement/observedAttributes.js") }), el("div", { className: "callout" }).append( el("h4", t`How S.observedAttributes Works`), @@ -221,7 +220,7 @@ export function page({ pkg, info }){

Content

` }) ), - el(example, { src: fileURL("./components/examples/customElement/shadowRoot.js"), page_id }), + el(example, { src: fileURL("./components/examples/customElement/shadowRoot.js") }), el("p").append(T` For more information on Shadow DOM, see @@ -234,7 +233,7 @@ export function page({ pkg, info }){ Besides the encapsulation, the Shadow DOM allows for using the ${el("a", references.mdn_shadow_dom_slot).append( el("strong", t``), t` element(s)`)}. You can simulate this feature using ${el("code", "simulateSlots")}: `), - el(example, { src: fileURL("./components/examples/customElement/simulateSlots.js"), page_id }), + el(example, { src: fileURL("./components/examples/customElement/simulateSlots.js") }), el("div", { className: "function-table" }).append( el("h4", t`simulateSlots`), el("dl").append( diff --git a/docs/p07-debugging.html.js b/docs/p07-debugging.html.js index 9344821..e916eb4 100644 --- a/docs/p07-debugging.html.js +++ b/docs/p07-debugging.html.js @@ -15,7 +15,6 @@ const fileURL= url=> new URL(url, import.meta.url); /** @param {import("./types.d.ts").PageAttrs} attrs */ export function page({ pkg, info }){ - const page_id= info.id; return el(simplePage, { info, pkg }).append( el("p").append(T` Debugging is an essential part of application development. This guide provides techniques @@ -36,7 +35,7 @@ export function page({ pkg, info }){ el(code, { content: ` const signal = S(0); console.log('Current value:', signal.valueOf()); - `, page_id }), + `, language: "js" }), el("div", { className: "warning" }).append( el("p").append(T` ${el("code", "signal.get")} is OK, but in some situations may lead to unexpected results: @@ -49,7 +48,7 @@ export function page({ pkg, info }){ // but typically this is fine ↓ return signal.get() + 1; }); - ` }) + `, language: "js" }) ), el("p").append(T` You can also monitor signal changes by adding a listener: @@ -57,7 +56,7 @@ export function page({ pkg, info }){ el(code, { content: ` // Log every time the signal changes S.on(signal, value => console.log('Signal changed:', value)); - `, page_id }), + `, language: "js" }), el("h4", t`Debugging derived signals`), el("p").append(T` @@ -69,7 +68,7 @@ export function page({ pkg, info }){ el("li", t`Add logging/debugger inside the computation function to see when it runs`), el("li", t`Verify that the computation function actually accesses the signal values with .get()`) ), - el(example, { src: fileURL("./components/examples/debugging/consoleLog.js"), page_id }), + el(example, { src: fileURL("./components/examples/debugging/consoleLog.js") }), el("h4", t`Examining signal via DevTools`), el("p").append(T` @@ -77,11 +76,11 @@ export function page({ pkg, info }){ signal objects. It contains the following information: `), el("ul").append( + // TODO: value? el("li", t`listeners: A Set of functions called when the signal value changes`), el("li", t`actions: Custom actions that can be performed on the signal`), el("li", t`onclear: Functions to run when the signal is cleared`), el("li", t`host: Reference to the host element/scope in which the signal was created`), - el("li", t`readonly: Boolean flag indicating if the signal is read-only`) ), el("p").append(T` …to determine the current value of the signal, call ${el("code", "signal.valueOf()")}. Don’t hesitate to @@ -121,7 +120,7 @@ export function page({ pkg, info }){ "S.el(S(()=> count.get() % 2), odd=> …)")}). `), ), - el(code, { src: fileURL("./components/examples/debugging/mutations.js"), page_id }), + el(code, { src: fileURL("./components/examples/debugging/mutations.js") }), el("h4", t`Memory leaks with signal listeners`), el("p").append(T` @@ -137,7 +136,7 @@ export function page({ pkg, info }){ el("li", t`Make sure derived signals don’t perform expensive calculations unnecessarily`), el("li", t`Keep signal computations focused and minimal`) ), - el(code, { src: fileURL("./components/examples/debugging/debouncing.js"), page_id }), + el(code, { src: fileURL("./components/examples/debugging/debouncing.js") }), el(h3, t`Browser DevTools tips for components and reactivity`), el("p").append(T` @@ -150,7 +149,7 @@ export function page({ pkg, info }){ that are automatically updated when signal values change. These elements are wrapped in special comment nodes for debugging (to be true they are also used internally, so please do not edit them by hand): `), - el(code, { src: fileURL("./components/examples/debugging/dom-reactive-mark.html"), page_id }), + el(code, { src: fileURL("./components/examples/debugging/dom-reactive-mark.html") }), el("p").append(T` This is particularly useful when debugging why a reactive section isn’t updating as expected. You can inspect the elements between the comment nodes to see their current state and the @@ -187,7 +186,7 @@ export function page({ pkg, info }){ so you can see the element and property that changes in the console right away. These properties make it easier to understand the reactive structure of your application when inspecting elements. `), - el(example, { src: fileURL("./components/examples/signals/debugging-dom.js"), page_id }), + el(example, { src: fileURL("./components/examples/signals/debugging-dom.js") }), el("p", { className: "note" }).append(T` ${el("code", ".__dde_reactive")} - An array property on DOM elements that tracks signal-to-element diff --git a/docs/p08-extensions.html.js b/docs/p08-extensions.html.js index d37df79..ed95b1f 100644 --- a/docs/p08-extensions.html.js +++ b/docs/p08-extensions.html.js @@ -14,7 +14,6 @@ const fileURL= url=> new URL(url, import.meta.url); /** @param {import("./types.js").PageAttrs} attrs */ export function page({ pkg, info }){ - const page_id= info.id; return el(simplePage, { info, pkg }).append( el("p").append(T` dd is designed with extensibility in mind. This page covers how to separate @@ -49,7 +48,7 @@ export function page({ pkg, info }){ // Using an addon el("div", { id: "example" }, myAddon({ option: "value" })); - `, page_id }), + `, language: "js" }), el(h3, t`Resource Cleanup with Abort Signals`), el("p").append(T` @@ -83,7 +82,7 @@ export function page({ pkg, info }){ const { signal }= scope; return el("div", null, externalLibraryAddon({ option: "value" }, signal)); } - `, page_id }), + `, language: "js" }), el(h3, t`Building Library-Independent Extensions`), el("p").append(T` @@ -104,7 +103,7 @@ export function page({ pkg, info }){ }); }; } - `, page_id }) + `, language: "js" }) ), el("div", { className: "tab" }).append( el("h5", t`⚠️ Library-Dependent`), @@ -118,7 +117,7 @@ export function page({ pkg, info }){ })(element); }; } - `, page_id }) + `, language: "js" }) ) ) ), @@ -177,7 +176,7 @@ export function page({ pkg, info }){ textContent: "All" }) ); - `, page_id }), + `, language: "js" }), el("div", { className: "callout" }).append( el("h4", t`Benefits of Signal Factories`), @@ -217,7 +216,7 @@ export function page({ pkg, info }){ const counter = createEnhancedSignal(0); el("button", { textContent: "Increment", onclick: () => counter.increment() }); el("div", S.text\`Count: \${counter}\`); - `, page_id }), + `, language: "js" }), el("div", { className: "tip" }).append( el("p").append(T` @@ -259,7 +258,7 @@ export function page({ pkg, info }){ // Update signal value count.set(5); // Logs: 5 console.log(doubled.get()); // 10 - `, page_id }), + `, language: "js" }), el("p").append(T` The independent signals API includes all core functionality (${el("code", "S()")}, ${el("code", "S.on()")}, ${el("code", "S.action()")}). diff --git a/docs/p09-optimization.html.js b/docs/p09-optimization.html.js index 3bd5c58..0c58da4 100644 --- a/docs/p09-optimization.html.js +++ b/docs/p09-optimization.html.js @@ -43,7 +43,6 @@ const references= { /** @param {import("./types.d.ts").PageAttrs} attrs */ export function page({ pkg, info }){ - const page_id= info.id; return el(simplePage, { info, pkg }).append( el("p").append(T` As your applications grow, performance becomes increasingly important. dd provides several @@ -60,7 +59,7 @@ export function page({ pkg, info }){ el("li", t`Simple debugging for performance bottlenecks`) ) ), - el(code, { src: fileURL("./components/examples/optimization/intro.js"), page_id }), + el(code, { src: fileURL("./components/examples/optimization/intro.js") }), el(h3, t`Memoization with memo: Native vs dd`), el("p").append(T` @@ -84,7 +83,7 @@ export function page({ pkg, info }){ )) ); } - `, page_id }) + `, language: "js" }) ), el("div").append( el("h5", t`With dd's memo`), @@ -102,7 +101,7 @@ export function page({ pkg, info }){ ))) ); } - `, page_id }) + `, language: "js" }) ) ) ), @@ -134,7 +133,7 @@ export function page({ pkg, info }){ memo(todo.id, () => el(TodoItem, todo) )))) - `, page_id }), + `, language: "js" }), el("p").append(T` The ${el("code", "memo")} function in this context: @@ -146,7 +145,7 @@ export function page({ pkg, info }){ el("li", t`Only calls the generator function when rendering an item with a new key`) ), - el(example, { src: fileURL("./components/examples/optimization/memo.js"), page_id }), + el(example, { src: fileURL("./components/examples/optimization/memo.js") }), el(h3, t`Creating Memoization Scopes`), el("p").append(T` @@ -171,7 +170,7 @@ export function page({ pkg, info }){ const container = el("div").append( ...items.map(item => renderItem(item)) ); - `, page_id }), + `, language: "js" }), el("p").append(T` The scope function accepts options to customize its behavior: @@ -188,7 +187,7 @@ export function page({ pkg, info }){ // Clear cache when signal is aborted signal: controller.signal }); - `, page_id }), + `, language: "js" }), el("p").append(T` You can use custom memo scope as function in (e. g. ${el("code", "S.el(signal, renderList)")}) and as (Abort) signal use ${el("code", "scope.signal")}. @@ -317,7 +316,7 @@ export function page({ pkg, info }){ // On subsequent renders, the cached fragment is empty! container.append(memoizedFragment); // Nothing gets appended - `, page_id }), + `, language: "js" }), el("p").append(T` This happens because a DocumentFragment is emptied when it's appended to the DOM. When the fragment @@ -338,7 +337,7 @@ export function page({ pkg, info }){ S.el(itemsSignal, items => items.map(item => el("div", item))) ) ); - `, page_id }) + `, language: "js" }) ), el("p").append(T` diff --git a/docs/p10-todomvc.html.js b/docs/p10-todomvc.html.js index d3f1854..ce8b482 100644 --- a/docs/p10-todomvc.html.js +++ b/docs/p10-todomvc.html.js @@ -43,7 +43,6 @@ const references= { /** @param {import("./types.d.ts").PageAttrs} attrs */ export function page({ pkg, info }){ - const page_id= info.id; return el(simplePage, { info, pkg }).append( el("p").append(T` ${el("a", references.todomvc).append("TodoMVC")} is a project that helps developers compare different @@ -69,7 +68,7 @@ export function page({ pkg, info }){ challenges in a clean, maintainable way. `), - el(example, { src: fileURL("./components/examples/reallife/todomvc.js"), variant: "big", page_id }), + el(example, { src: fileURL("./components/examples/reallife/todomvc.js"), variant: "big" }), el(h3, t`Application Architecture Overview`), el("p").append(T` @@ -118,7 +117,7 @@ export function page({ pkg, info }){ }); }); const todosRemainingS = S(()=> todosS.get().filter(todo => !todo.completed).length); - `, page_id }), + `, language: "js" }), el("p").append(T` The ${el("code", "todosSignal")} function creates a custom signal with actions for manipulating the todos: @@ -207,7 +206,7 @@ export function page({ pkg, info }){ }); return out; } - `, page_id }), + `, language: "js" }), el("div", { className: "note" }).append( el("p").append(T` @@ -241,7 +240,7 @@ export function page({ pkg, info }){ memo(todo.id, ()=> el(TodoItem, todo, onDelete, onEdit))) ) ) - `, page_id }), + `, language: "js" }), el("p").append(T` The derived signal automatically recalculates whenever either the todos list or the current filter changes, @@ -263,7 +262,7 @@ export function page({ pkg, info }){ type: "checkbox" }, onToggleAll), el("label", { htmlFor: "toggle-all", title: "Mark all as complete" }), - `, page_id }), + `, language: "js" }), el("p").append(T` The "toggle all" checkbox allows users to mark all todos as completed or active. When the checkbox @@ -300,7 +299,7 @@ export function page({ pkg, info }){ // Component content... ); } - `, page_id }), + `, language: "js" }), el("p").append(T` The TodoItem component maintains its own local UI state with signals, providing immediate @@ -311,16 +310,16 @@ export function page({ pkg, info }){ el(code, { content: ` // Dynamic class attributes el("a", { - textContent: "All", - className: S(()=> pageS.get() === "all" ? "selected" : ""), - href: "#" + textContent, + classList: { selected: S(()=> pageS.get() === textContent.toLowerCase()) }, + href: \`#\${textContent.toLowerCase()}\` }) // Reactive classList el("li", { classList: { completed: isCompleted, editing: isEditing } }) - `, page_id }), + `, language: "js" }), el("div", { className: "tip" }).append( el("p").append(T` @@ -341,7 +340,7 @@ export function page({ pkg, info }){ memo(todo.id, ()=> el(TodoItem, todo, onDelete, onEdit))) ) ) - `, page_id }), + `, language: "js" }), el("p").append(T` This approach ensures that: @@ -355,18 +354,25 @@ export function page({ pkg, info }){ el("h4", t`Memoizing UI Sections`), el(code, { content: ` - S.el(todosS, todos => memo(todos.length, length=> length - ? el("footer", { className: "footer" }).append( - // Footer content... + S.el(todosS, ({ length }) => !length + ? el() + : el("footer", { className: "footer" }).append( + // … + memo("filters", ()=> + // … + el("a", { + textContent, + classList: { selected: S(()=> pageS.get() === textContent.toLowerCase()) }, + href: \`#\${textContent.toLowerCase()}\` + }) + // … ) - : el() )) - `, page_id }), + `, language: "js" }), el("p").append(T` - By memoizing based on the todos length, the entire footer component is only re-rendered - when todos are added or removed, not when their properties change. This improves performance - by avoiding unnecessary DOM operations. + We memoize the UI section and uses derived signal for the classList. Re-rendering this part is therefore + unnecessary when the number of todos changes. `), el("div", { className: "tip" }).append( @@ -389,9 +395,11 @@ export function page({ pkg, info }){ `), el(code, { content: ` // Event handlers in the main component - const onDelete = on("todo:delete", ev => S.action(todosS, "delete", ev.detail)); - const onEdit = on("todo:edit", ev => S.action(todosS, "edit", ev.detail)); - `, page_id }), + const onDelete = on("todo:delete", ev => + S.action(todosS, "delete", /** @type {{ detail: Todo["id"] }} */(ev).detail)); + const onEdit = on("todo:edit", ev => + S.action(todosS, "edit", /** @type {{ detail: Partial & { id: Todo["id"] } }} */(ev).detail)); + `, language: "js" }), el("h4", t`2. The TodoItem Component with Scopes and Local State`), el("p").append(T` @@ -434,7 +442,7 @@ export function page({ pkg, info }){ // Component implementation... } - `, page_id }), + `, language: "js" }), el("div", { className: "tip" }).append( el("p").append(T` @@ -455,7 +463,7 @@ export function page({ pkg, info }){ }).append( // Component content... ); - `, page_id }), + `, language: "js" }), el("p").append(T` Benefits of using ${el("code", "classList")}: @@ -494,7 +502,7 @@ export function page({ pkg, info }){ value: title, "data-id": id }, onBlurEdit, onKeyDown, addFocus) - `, page_id }), + `, language: "js" }), el("p").append(T` This approach offers several advantages: @@ -522,27 +530,26 @@ export function page({ pkg, info }){ el("h4", t`Conditional Todo List`), el(code, { content: ` S.el(todosS, todos => todos.length - ? el("main", { className: "main" }).append( + ? el() + : el("main", { className: "main" }).append( // Main content with toggle all and todo list ) - : el() ) - `, page_id }), + `, language: "js" }), el("h4", t`Conditional Edit Form`), el(code, { content: ` - 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() ) - `, page_id }), + `, language: "js" }), el("h4", t`Conditional Clear Completed Button`), el(code, { content: ` @@ -553,7 +560,7 @@ export function page({ pkg, info }){ { textContent: "Clear completed", className: "clear-completed" }, onClearCompleted) ) - `, page_id }), + `, language: "js" }), el("div", { className: "note" }).append( el("p").append(T` @@ -599,7 +606,7 @@ export function page({ pkg, info }){ if (event.key !== "Escape") return; isEditing.set(false); }); - `, page_id }), + `, language: "js" }), el("div", { className: "tip" }).append( el("p").append(T` @@ -630,7 +637,7 @@ export function page({ pkg, info }){ ${el("strong", "Declarative Class Management:")} Using the classList property for cleaner class handling `), el("li").append(T` - ${el("strong", "Focus Management:")} Reliable input focus with setTimeout + ${el("strong", "Focus Management:")} Reliable input focus with requestAnimationFrame `), el("li").append(T` ${el("strong", "Persistent Storage:")} Automatically saving application state with signal listeners diff --git a/docs/p11-ssr.html.js b/docs/p11-ssr.html.js index 53b7822..2bf5cf7 100644 --- a/docs/p11-ssr.html.js +++ b/docs/p11-ssr.html.js @@ -14,7 +14,6 @@ const fileURL= url=> new URL(url, import.meta.url); /** @param {import("./types.js").PageAttrs} attrs */ export function page({ pkg, info }){ - const page_id= info.id; return el(simplePage, { info, pkg }).append( el("div", { className: "warning" }).append( el("p").append(T` @@ -45,7 +44,7 @@ export function page({ pkg, info }){ than jsdom `), ), - el(code, { src: fileURL("./components/examples/ssr/intro.js"), page_id }), + el(code, { src: fileURL("./components/examples/ssr/intro.js") }), el(h3, t`Why Server-Side Rendering?`), el("p").append(T` @@ -71,27 +70,27 @@ export function page({ pkg, info }){ el("li", t`Provides a promise queue system for managing async operations during rendering`), el("li", t`Handles DOM property/attribute mapping differences between browsers and jsdom`) ), - el(code, { src: fileURL("./components/examples/ssr/start.js"), page_id }), + el(code, { src: fileURL("./components/examples/ssr/start.js") }), el(h3, t`Basic SSR Example`), el("p").append(T` Here’s a simple example of how to use dd for server-side rendering in a Node.js script: `), - el(code, { src: fileURL("./components/examples/ssr/basic-example.js"), page_id }), + el(code, { src: fileURL("./components/examples/ssr/basic-example.js") }), el(h3, t`Building a Static Site Generator`), el("p").append(T` You can build a complete static site generator with dd. In fact, this documentation site is built using dd for server-side rendering! Here’s how the documentation build process works: `), - el(code, { src: fileURL("./components/examples/ssr/static-site-generator.js"), page_id }), + el(code, { src: fileURL("./components/examples/ssr/static-site-generator.js") }), el(h3, t`Working with Async Content in SSR`), el("p").append(T` The jsdom export includes a queue system to handle asynchronous operations during rendering. This is crucial for components that fetch data or perform other async tasks. `), - el(code, { src: fileURL("./components/examples/ssr/async-data.js"), page_id }), + el(code, { src: fileURL("./components/examples/ssr/async-data.js") }), el(h3, t`Working with Dynamic Imports for SSR`), el("p").append(T` @@ -119,7 +118,7 @@ export function page({ pkg, info }){ el("p").append(T` Follow this pattern when creating server-side rendered pages: `), - el(code, { src: fileURL("./components/examples/ssr/pages.js"), page_id }), + el(code, { src: fileURL("./components/examples/ssr/pages.js") }), el(h3, t`SSR Considerations and Limitations`), el("p").append(T` @@ -141,7 +140,7 @@ export function page({ pkg, info }){ This documentation site itself is built using dd’s SSR capabilities. The build process collects all page components, renders them with jsdom, and outputs static HTML files. `), - el(code, { src: fileURL("./components/examples/ssr/static-site-generator.js"), page_id }), + el(code, { src: fileURL("./components/examples/ssr/static-site-generator.js") }), el("p").append(T` The resulting static files can be deployed to any static hosting service, diff --git a/docs/p12-ireland.html.js b/docs/p12-ireland.html.js index 385edc6..46eb35d 100644 --- a/docs/p12-ireland.html.js +++ b/docs/p12-ireland.html.js @@ -1,9 +1,8 @@ import { T, t } from "./utils/index.js"; export const info= { title: t`Ireland Components`, - fullTitle: t`Interactive Demo Components with Server-Side Pre-Rendering`, - description: t`Creating live, interactive component examples in documentation with server-side - rendering and client-side hydration.`, + fullTitle: t`Server-Side Pre-Rendering and Client-Side Rehydration`, + description: t`Using Ireland components for server-side pre-rendering and client-side rehydration`, }; import { el } from "deka-dom-el"; @@ -16,7 +15,6 @@ const fileURL= url=> new URL(url, import.meta.url); /** @param {import("./types.js").PageAttrs} attrs */ export function page({ pkg, info }){ - const page_id= info.id; return el(simplePage, { info, pkg }).append( el("div", { className: "warning" }).append( el("p").append(T` @@ -67,7 +65,7 @@ export function page({ pkg, info }){ src: fileURL("./components/examples/path/to/component.js"), exportName: "NamedExport", // optional, defaults to "default", }) - `, page_id }), + `, language: "js" }), el("p").append(T` During the build process (${el("code", "bs/docs.js")}), the following happens: @@ -119,7 +117,7 @@ export function page({ pkg, info }){ // Final build step - trigger SSR end event dispatchEvent("onssrend"); - `, page_id }), + `, language: "js" }), el("h4", t`File Registration`), el(code, { content: ` // From docs/ssr.js - File registration system @@ -145,7 +143,7 @@ export function page({ pkg, info }){ head[head instanceof HTMLScriptElement ? "src" : "href"] = file_name; document.head.append(head); } - `, page_id }), + `, language: "js" }), el("h4", t`Server-Side Rendering`), el(code, { content: ` // From docs/components/ireland.html.js - Server-side component implementation @@ -226,7 +224,7 @@ export function page({ pkg, info }){ \`.trim()) ); } - `, page_id }), + `, language: "js" }), el("h4", t`Client-Side Hydration`), el(code, { content: ` // From docs/components/ireland.js.js - Client-side hydration @@ -250,7 +248,7 @@ export function page({ pkg, info }){ }); }); } - `, page_id }), + `, language: "js" }), el(h3, t`Live Example`), el("p").append(T` @@ -259,14 +257,10 @@ export function page({ pkg, info }){ rendered with the Ireland component system: `), - el(code, { - src: fileURL("./components/examples/ireland-test/counter.js"), - page_id - }), + el(code, { src: fileURL("./components/examples/ireland-test/counter.js") }), el(ireland, { src: fileURL("./components/examples/ireland-test/counter.js"), exportName: "CounterStandard", - page_id }), el("p").append(T` diff --git a/docs/p13-appendix.html.js b/docs/p13-appendix.html.js index 5841fbe..6f9d8f8 100644 --- a/docs/p13-appendix.html.js +++ b/docs/p13-appendix.html.js @@ -40,7 +40,6 @@ const references= { /** @param {import("./types.d.ts").PageAttrs} attrs */ export function page({ pkg, info }){ - const page_id= info.id; return el(simplePage, { info, pkg }).append( el("p").append(T` This reference guide provides a comprehensive summary of dd’s key concepts, best practices, @@ -166,7 +165,7 @@ export function page({ pkg, info }){ className: S(() => countS.get() > 10 ? 'warning' : '') }) ); - `, page_id }), + `, language: "js" }), el(h3, t`Key Concepts Reference`), diff --git a/docs/p14-converter.html.js b/docs/p14-converter.html.js index e4b96cd..bd7c64c 100644 --- a/docs/p14-converter.html.js +++ b/docs/p14-converter.html.js @@ -13,7 +13,6 @@ import { converter } from "./components/converter.html.js"; /** @param {import("./types.d.ts").PageAttrs} attrs */ export function page({ pkg, info }){ - const page_id= info.id; return el(simplePage, { info, pkg }).append( el("p").append(T` Transitioning from HTML to dd is simple with our interactive converter. This tool helps you quickly @@ -28,7 +27,7 @@ export function page({ pkg, info }){ ), // The actual converter component - el(converter, { page_id }), + el(converter), el(h3, t`Next Steps`), el("p").append(T` diff --git a/docs/p15-examples.html.js b/docs/p15-examples.html.js index 2e6e88f..c41acb1 100644 --- a/docs/p15-examples.html.js +++ b/docs/p15-examples.html.js @@ -14,7 +14,6 @@ const fileURL= url=> new URL(url, import.meta.url); /** @param {import("./types.d.ts").PageAttrs} attrs */ export function page({ pkg, info }){ - const page_id= info.id; return el(simplePage, { info, pkg }).append( el("p").append(T` Real-world application examples showcasing how to build complete, production-ready interfaces with dd: @@ -25,23 +24,21 @@ export function page({ pkg, info }){ third-party charting library, data fetching and state management, responsive layout design, and multiple interactive components working together. `), - el(example, { src: fileURL("./components/examples/case-studies/data-dashboard.js"), variant: "big", page_id }), + el(example, { src: fileURL("./components/examples/case-studies/data-dashboard.js"), variant: "big" }), el(h3, t`Interactive Form`), el("p").append(T` Complete form with real-time validation, conditional rendering, and responsive design. Form handling with real-time validation, reactive UI updates, complex form state management, and clean separation of concerns. `), - el(example, { src: fileURL("./components/examples/case-studies/interactive-form.js"), variant: "big", page_id }), - + el(example, { src: fileURL("./components/examples/case-studies/interactive-form.js"), variant: "big" }), el(h3, t`Interactive Image Gallery`), el("p").append(T` Responsive image gallery with lightbox, keyboard navigation, and filtering. Dynamic loading of content, lightbox functionality, animation handling, and keyboard and gesture navigation support. `), - el(example, { src: fileURL("./components/examples/case-studies/image-gallery.js"), variant: "big", page_id }), - + el(example, { src: fileURL("./components/examples/case-studies/image-gallery.js"), variant: "big" }), el(h3, t`Task Manager`), el("p").append(T` @@ -49,8 +46,29 @@ export function page({ pkg, info }){ with signals, drag and drop functionality, local storage persistence, and responsive design for different devices. `), - el(example, { src: fileURL("./components/examples/case-studies/task-manager.js"), variant: "big", page_id }), + el(example, { src: fileURL("./components/examples/case-studies/task-manager.js"), variant: "big" }), + el(h3, t`Product Catalog with asyncSignal`), + el("p").append(T` + Interactive product catalog with search, sorting, and pagination. Features include dynamic product filtering, + responsive UI with detailed view toggles, error handling with retry capability, and proper resource cleanup. + Demonstrates advanced signal usage, including derived signals, abortable async data fetching, and optimized + rendering patterns. + `), + el("div", { className: "callout" }).append( + el("h4", t`asyncSignal Utility`), + el("p").append(T` + This example showcases the asyncSignal utility, which is a powerful abstraction for handling async data + fetching with proper state management. It provides: + `), + el("ul").append( + el("li", t`Automatic tracking of loading, success, and error states`), + el("li", t`AbortController integration for request cancellation`), + el("li", t`Error handling and recovery`), + el("li", t`Options for caching previous data during loading states`) + ) + ), + el(example, { src: fileURL("./components/examples/case-studies/products.js"), variant: "big" }), el(h3, t`TodoMVC`), el("p").append(T` diff --git a/docs/ssr.js b/docs/ssr.js index 4d151b6..72d38c2 100644 --- a/docs/ssr.js +++ b/docs/ssr.js @@ -1,4 +1,8 @@ export { t } from "./utils/index.js"; +/** @type {string} */ +export let page_id; +/** @param {string} id */ +export function currentPageId(id){ page_id= id; } export const path_target= { root: "dist/docs/", css: "dist/docs/", diff --git a/package-lock.json b/package-lock.json index 24b04a2..0966adc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "deka-dom-el", - "version": "0.9.3-alpha", + "version": "0.9.4-alpha", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "deka-dom-el", - "version": "0.9.3-alpha", + "version": "0.9.4-alpha", "license": "MIT", "devDependencies": { "@size-limit/preset-small-lib": "~11.2", diff --git a/package.json b/package.json index 8e58f45..e45c75f 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "deka-dom-el", - "version": "0.9.3-alpha", + "version": "0.9.4-alpha", "description": "A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks.", "author": "Jan Andrle ", "license": "MIT", - "homepage": "https://github.com/jaandrle/deka-dom-el", + "homepage": "https://jaandrle.github.io/deka-dom-el/", "repository": { "type": "git", "url": "git+ssh://git@github.com/jaandrle/deka-dom-el.git" @@ -52,7 +52,6 @@ "maxdepth": 3, "maxcomplexity": 14, "globals": { - "requestIdleCallback": false, "AbortController": false, "AbortSignal": false, "FinalizationRegistry": false @@ -61,25 +60,25 @@ "size-limit": [ { "path": "./index.js", - "limit": "10.5 kB", + "limit": "10 kB", "gzip": false, "brotli": false }, { "path": "./signals.js", - "limit": "12.5 kB", + "limit": "12.2 kB", "gzip": false, "brotli": false }, { "path": "./index-with-signals.js", - "limit": "15 kB", + "limit": "14.75 kB", "gzip": false, "brotli": false }, { "path": "./index-with-signals.js", - "limit": "5.5 kB" + "limit": "5.25 kB" } ], "modifyEsbuildConfig": { diff --git a/src/dom-lib/events-observer.js b/src/dom-lib/events-observer.js index e09199b..9779970 100644 --- a/src/dom-lib/events-observer.js +++ b/src/dom-lib/events-observer.js @@ -1,5 +1,5 @@ import { enviroment as env, evc, evd } from './common.js'; -import { isInstance } from "../helpers.js"; +import { isInstance, requestIdle } from "../helpers.js"; /** * Connection changes observer for tracking element connection/disconnection @@ -149,15 +149,6 @@ function connectionsChangesObserverConstructor(){ observer.disconnect(); } - //TODO: remount support? - /** - * Schedule a task during browser idle time - * @returns {Promise} Promise that resolves when browser is idle - */ - function requestIdle(){ return new Promise(function(resolve){ - (requestIdleCallback || requestAnimationFrame)(resolve); - }); } - /** * Collects child elements from the store that are contained by the given element * @param {Element} element - Parent element diff --git a/src/helpers.js b/src/helpers.js index e3b1655..e7db626 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -68,3 +68,12 @@ export function observedAttributes(instance, observedAttribute){ * @returns {string} The camelCase string */ function kebabToCamel(name){ return name.replace(/-./g, x=> x[1].toUpperCase()); } + +/** + * Schedule a task during browser idle time + * @returns {Promise} Promise that resolves when browser is idle + */ +export function requestIdle(){ return new Promise(function(resolve){ + (globalThis.requestIdleCallback || requestAnimationFrame)(resolve); + }); +} diff --git a/src/signals-lib/signals-lib.js b/src/signals-lib/signals-lib.js index f02b949..21149ca 100644 --- a/src/signals-lib/signals-lib.js +++ b/src/signals-lib/signals-lib.js @@ -1,15 +1,14 @@ import { queueSignalWrite, mark } from "./helpers.js"; export { mark }; -import { hasOwn, oCreate, oAssign } from "../helpers.js"; +import { hasOwn, oCreate, oAssign, requestIdle } from "../helpers.js"; -const Signal = oCreate(null, { +const SignalReadOnly= oCreate(null, { get: { value(){ return read(this); } }, - set: { value(...v){ return write(this, ...v); } }, toJSON: { value(){ return read(this); } }, valueOf: { value(){ return this[mark] && this[mark].value; } } }); -const SignalReadOnly= oCreate(Signal, { - set: { value(){ return; } }, +const Signal = oCreate(SignalReadOnly, { + set: { value(...v){ return write(this, ...v); } }, }); /** * Checks if a value is a signal @@ -214,7 +213,7 @@ signal.el= function(s, map){ */ function requestCleanUpReactives(host){ if(!host || !host[key_reactive]) return; - (requestIdleCallback || setTimeout)(function(){ + requestIdle().then(function(){ host[key_reactive]= host[key_reactive] .filter(([ s, el ])=> el.isConnected ? true : (removeSignalListener(...s), false)); }); @@ -314,9 +313,14 @@ export const signals_config= { function removeSignalsFromElements(s, listener, ...notes){ const { current }= scope; current.host(function(element){ - if(!element[key_reactive]) element[key_reactive]= []; + const is_first= !element[key_reactive]; + if(is_first) element[key_reactive]= []; element[key_reactive].push([ [ s, listener ], ...notes ]); - if(current.prevent) return; // typically document.body, doenst need auto-remove as it should happen on page leave + if( + !is_first + // typically document.body, doenst need auto-remove as it should happen on page leave + || current.prevent + ) return; on.disconnected(()=> /*! Clears all Signals listeners added in the current scope/host (`S.el`, `assign`, …?). You can investigate the `__dde_reactive` key of the element. */ @@ -344,7 +348,7 @@ const cleanUpRegistry = new FinalizationRegistry(function(s){ */ function create(is_readonly, value, actions){ const varS = oCreate(is_readonly ? SignalReadOnly : Signal); - const SI= toSignal(varS, value, actions, is_readonly); + const SI= toSignal(varS, value, actions); cleanUpRegistry.register(SI, SI[mark]); return SI; } @@ -367,11 +371,10 @@ const protoSigal= oAssign(oCreate(), { * @param {Object} s - Object to transform * @param {any} value - Initial value * @param {Object} actions - Custom actions - * @param {boolean} [readonly=false] - Whether the signal is readonly * @returns {Object} Signal object with get() and set() methods * @private */ -function toSignal(s, value, actions, readonly= false){ +function toSignal(s, value, actions){ const onclear= []; if(typeOf(actions)!=="[object Object]") actions= {}; @@ -385,7 +388,6 @@ function toSignal(s, value, actions, readonly= false){ value: oAssign(oCreate(protoSigal), { value, actions, onclear, host, listeners: new Set(), - readonly }), enumerable: false, writable: false,