From 58b73dcbc7da166442d850e3946e504a0fdfbaa9 Mon Sep 17 00:00:00 2001 From: Jan Andrle Date: Fri, 24 Nov 2023 20:41:04 +0100 Subject: [PATCH] :boom: rename signals to observables --- README.md | 6 +- bs/build.js | 2 +- dist/dde-with-observables.js | 27 +++ dist/dde-with-signals.js | 26 --- dist/dde.js | 4 +- ...signals.d.ts => esm-with-observables.d.ts} | 53 +++--- dist/esm-with-observables.js | 4 + dist/esm-with-signals.js | 4 - dist/esm.d.ts | 4 +- dist/esm.js | 2 +- docs/index.html | 6 +- docs/p02-elements.html | 18 +- docs/p03-events.html | 14 +- docs/p04-observables.html | 35 ++++ docs_src/components/example.html.js | 2 +- docs_src/components/examples/helloWorld.js | 2 +- .../observables/computations-abort.js | 16 ++ .../{signals => observables}/intro.js | 6 +- .../examples/observables/observables.js | 8 + .../examples/signals/computations-abort.js | 16 -- .../components/examples/signals/signals.js | 8 - docs_src/index.html.js | 4 +- docs_src/p02-elements.html.js | 2 +- ...ignals.html.js => p04-observables.html.js} | 38 ++--- docs_src/ssr.js | 2 +- examples/components/fullNameComponent.js | 6 +- examples/components/todosComponent.js | 22 +-- examples/components/webComponent.js | 6 +- examples/exports.js | 8 +- index-with-observables.d.ts | 2 + index-with-observables.js | 2 + index-with-signals.d.ts | 2 - index-with-signals.js | 2 - index.d.ts | 4 +- observables.d.ts | 64 ++++++++ observables.js | 4 + package.json | 14 +- signals.d.ts | 63 ------- signals.js | 4 - src/dom.js | 10 +- src/events.js | 2 +- src/observables-common.js | 13 ++ src/{signals-lib.js => observables-lib.js} | 155 +++++++++--------- src/signals-common.js | 13 -- 44 files changed, 372 insertions(+), 333 deletions(-) create mode 100644 dist/dde-with-observables.js delete mode 100644 dist/dde-with-signals.js rename dist/{esm-with-signals.d.ts => esm-with-observables.d.ts} (94%) create mode 100644 dist/esm-with-observables.js delete mode 100644 dist/esm-with-signals.js create mode 100644 docs/p04-observables.html create mode 100644 docs_src/components/examples/observables/computations-abort.js rename docs_src/components/examples/{signals => observables}/intro.js (57%) create mode 100644 docs_src/components/examples/observables/observables.js delete mode 100644 docs_src/components/examples/signals/computations-abort.js delete mode 100644 docs_src/components/examples/signals/signals.js rename docs_src/{p04-signals.html.js => p04-observables.html.js} (57%) create mode 100644 index-with-observables.d.ts create mode 100644 index-with-observables.js delete mode 100644 index-with-signals.d.ts delete mode 100644 index-with-signals.js create mode 100644 observables.d.ts create mode 100644 observables.js delete mode 100644 signals.d.ts delete mode 100644 signals.js create mode 100644 src/observables-common.js rename src/{signals-lib.js => observables-lib.js} (53%) delete mode 100644 src/signals-common.js diff --git a/README.md b/README.md index 9cc3856..bc46e75 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,8 @@ function component({ textContent, className }){ } ``` # Deka DOM Elements -Creating reactive elements, components and Web components using [IDL](https://developer.mozilla.org/en-US/docs/Glossary/IDL)/JavaScript DOM API and signals -([Signals — whats going on behind the scenes | by Ryan Hoffnan | ITNEXT](https://itnext.io/signals-whats-going-on-behind-the-scenes-ec858589ea63) or [The Evolution of Signals in JavaScript - DEV Community](https://dev.to/this-is-learning/the-evolution-of-signals-in-javascript-8ob)). +Creating reactive elements, components and Web components using [IDL](https://developer.mozilla.org/en-US/docs/Glossary/IDL)/JavaScript DOM API and signals/observables +([Signals — whats going on behind the scenes | by Ryan Hoffnan | ITNEXT](https://itnext.io/signals-whats-going-on-behind-the-scenes-ec858589ea63), [The Evolution of Signals in JavaScript - DEV Community](https://dev.to/this-is-learning/the-evolution-of-signals-in-javascript-8ob) or [Observer pattern - Wikipedia](https://en.wikipedia.org/wiki/Observer_pattern)). ## Inspiration and suggested alternatives - my previous library (mostly used internaly): [jaandrle/dollar_dom_component: Functional DOM components without JSX and virtual DOM.](https://github.com/jaandrle/dollar_dom_component) @@ -59,7 +59,7 @@ hopefully, help in integrating the library into existing projects. To balance these requirements, numerous compromises have been made. To summarize: - [ ] Library size: 10–15kB minified (the original goal was a maximum of 10kB) -- [x] Optional use of *signals* with the ability to register *your own signals implementation* +- [x] Optional use of *observables* with the ability to register *your own signals/observables implementation* - [x] *No build step required* - [x] Preference for a *declarative/functional* approach - [x] Focus on zero/minimal dependencies diff --git a/bs/build.js b/bs/build.js index a0d756b..7fa087f 100755 --- a/bs/build.js +++ b/bs/build.js @@ -1,6 +1,6 @@ #!/usr/bin/env -S npx nodejsscript import { bundle as bundleDTS } from "dts-bundler"; -const files= [ "index", "index-with-signals" ]; +const files= [ "index", "index-with-observables" ]; const filesOut= (file, mark= "esm")=> "dist/"+file.replace("index", mark); const css= echo.css` .info{ color: gray; } diff --git a/dist/dde-with-observables.js b/dist/dde-with-observables.js new file mode 100644 index 0000000..24a3f75 --- /dev/null +++ b/dist/dde-with-observables.js @@ -0,0 +1,27 @@ +//deka-dom-el library is available via global namespace `dde` +(()=> { +var A={isObservable(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function T(t,e=!0){return e?Object.assign(A,t):(Object.setPrototypeOf(t,A),t)}function C(t){return A.isPrototypeOf(t)&&t!==A?t:A}function x(t){return typeof t>"u"}function B(t){let e=typeof t;return e!=="object"?e:t===null?"null":Object.prototype.toString.call(t)}function N(t,e){if(!t||!(t instanceof AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}var $={setDeleteAttr:tt,ssr:""};function tt(t,e,n){if(Reflect.set(t,e,n),!!x(n)){if(Reflect.deleteProperty(t,e),t instanceof HTMLElement&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var E=[{scope:document.body,host:t=>t?t(document.body):document.body,custom_element:!1,prevent:!0}],g={get current(){return E[E.length-1]},get host(){return this.current.host},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...E]},push(t={}){return E.push(Object.assign({},this.current,{prevent:!1},t))},pushRoot(){return E.push(E[0])},pop(){if(E.length!==1)return E.pop()}};function H(...t){return this.appendOriginal(...t),this}function et(t){return t.append===H||(t.appendOriginal=t.append,t.append=H),t}var j;function y(t,e,...n){let r=C(this),o=0,c,s;switch((Object(e)!==e||r.isObservable(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1,g.push({scope:t,host:(...l)=>l.length?(o===1?n.unshift(...l):l.forEach(m=>m(s)),void 0):s}),c=t(e||void 0);let d=c instanceof DocumentFragment;if(c.nodeName==="#comment")break;let u=y.mark({type:"component",name:t.name,host:d?"this":"parentElement"});c.prepend(u),d&&(s=u);break}case t==="#text":c=P.call(this,document.createTextNode(""),e);break;case(t==="<>"||!t):c=P.call(this,document.createDocumentFragment(),e);break;case!!j:c=P.call(this,document.createElementNS(j,t),e);break;case!c:c=P.call(this,document.createElement(t),e)}return et(c),s||(s=c),n.forEach(d=>d(s)),o&&g.pop(),o=2,c}function vt(t){let e=Symbol.for("default"),n=Array.from(t.querySelectorAll("slot")).reduce((o,c)=>Reflect.set(o,c.name||e,c)&&o,{}),r=Reflect.has(n,e);return t.append=new Proxy(t.append,{apply(o,c,s){if(!s.length)return t;let d=document.createDocumentFragment();for(let u of s){if(!u||!u.slot){r&&d.appendChild(u);continue}let l=u.slot,m=n[l];O(u,"remove","slot"),m&&(m.replaceWith(u),Reflect.deleteProperty(n,l))}return r&&(n[e].replaceWith(d),Reflect.deleteProperty(n,e)),Object.values(n).forEach(u=>u.replaceWith(y().append(...Array.from(u.childNodes)))),t}}),t}y.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=document.createComment(``);return e||(r.end=document.createComment("")),r};function Et(t){let e=this;return function(...r){j=t;let o=y.call(e,...r);return j=void 0,o}}var{setDeleteAttr:I}=$,L=new WeakMap;function P(t,...e){if(!e.length)return t;L.set(t,G(t,this));for(let[n,r]of Object.entries(Object.assign({},...e)))Z.call(this,t,n,r);return L.delete(t),t}function Z(t,e,n){let{setRemoveAttr:r,s:o}=G(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(d,u)=>Z.call(c,t,d,u));let[s]=e;if(s==="=")return r(e.slice(1),n);if(s===".")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 I(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return F(o,n,J.bind(null,t[e]));case"ariaset":return F(o,n,(d,u)=>r("aria-"+d,u));case"classList":return nt.call(c,t,n)}return rt(t,e)?I(t,e,n):r(e,n)}function G(t,e){if(L.has(t))return L.get(t);let r=(t instanceof SVGElement?ct:ot).bind(null,t,"Attribute"),o=C(e);return{setRemoveAttr:r,s:o}}function nt(t,e){let n=C(this);return F(n,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function xt(t){return Array.from(t.children).forEach(e=>e.remove()),t}function O(t,e,n,r){return t instanceof HTMLElement?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function rt(t,e){if(!Reflect.has(t,e))return!1;let n=V(t,e);return!x(n.set)}function V(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||V(t,e)}function F(t,e,n){if(!(typeof e!="object"||e===null))return Object.entries(e).forEach(function([o,c]){o&&(c=t.processReactiveAttribute(e,o,c,n),n(o,c))})}function K(t){return Array.isArray(t)?t.filter(Boolean).join(" "):t}function ot(t,e,n,r){return t[(x(r)?"remove":"set")+e](n,K(r))}function ct(t,e,n,r,o=null){return t[(x(r)?"remove":"set")+e+"NS"](o,n,K(r))}function J(t,e,n){if(Reflect.set(t,e,n),!!x(n))return Reflect.deleteProperty(t,e)}function wt(t,e,n){return e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let s=c.length?new CustomEvent(t,Object.assign({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(s)}}function v(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var D=it(),st=new WeakSet;v.connected=function(t,e){let{custom_element:n}=g.current,r="connected";return typeof e!="object"&&(e={}),e.once=!0,function(c){n&&(c=n);let s="dde:"+r;return c.addEventListener(s,t,e),c.__dde_lifecycleToEvents?c:c.isConnected?(c.dispatchEvent(new Event(s)),c):(N(e.signal,()=>D.offConnected(c,t))&&D.onConnected(c,t),c)}};v.disconnected=function(t,e){let{custom_element:n}=g.current,r="disconnected";return typeof e!="object"&&(e={}),e.once=!0,function(c){n&&(c=n);let s="dde:"+r;return c.addEventListener(s,t,e),c.__dde_lifecycleToEvents||N(e.signal,()=>D.offDisconnected(c,t))&&D.onDisconnected(c,t),c}};var z=new WeakMap;v.disconnectedAsAbort=function(t){if(z.has(t))return z.get(t);let e=new AbortController;return z.set(t,e),t(v.disconnected(()=>e.abort())),e};v.attributeChanged=function(t,e){let n="attributeChanged";return typeof e!="object"&&(e={}),function(o){let c="dde:"+n;if(o.addEventListener(c,t,e),o.__dde_lifecycleToEvents||st.has(o))return o;let s=new MutationObserver(function(u){for(let{attributeName:l,target:m}of u)m.dispatchEvent(new CustomEvent(c,{detail:[l,m.getAttribute(l)]}))});return N(e.signal,()=>s.disconnect())&&s.observe(o,{attributes:!0}),o}};function it(){let t=new Map,e=!1,n=new MutationObserver(function(i){for(let f of i)if(f.type==="childList"){if(l(f.addedNodes,!0)){s();continue}m(f.removedNodes,!0)&&s()}});return{onConnected(i,f){c();let a=o(i);a.connected.has(f)||(a.connected.add(f),a.length_c+=1)},offConnected(i,f){if(!t.has(i))return;let a=t.get(i);a.connected.has(f)&&(a.connected.delete(f),a.length_c-=1,r(i,a))},onDisconnected(i,f){c();let a=o(i);a.disconnected.has(f)||(a.disconnected.add(f),a.length_d+=1)},offDisconnected(i,f){if(!t.has(i))return;let a=t.get(i);a.disconnected.has(f)&&(a.disconnected.delete(f),a.length_d-=1,r(i,a))}};function r(i,f){f.length_c||f.length_d||(t.delete(i),s())}function o(i){if(t.has(i))return t.get(i);let f={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(i,f),f}function c(){e||(e=!0,n.observe(document.body,{childList:!0,subtree:!0}))}function s(){!e||t.size||(e=!1,n.disconnect())}function d(){return new Promise(function(i){(requestIdleCallback||requestAnimationFrame)(i)})}async function u(i){t.size>30&&await d();let f=[];if(!(i instanceof Node))return f;for(let a of t.keys())a===i||!(a instanceof Node)||i.contains(a)&&f.push(a);return f}function l(i,f){let a=!1;for(let b of i){if(f&&u(b).then(l),!t.has(b))continue;let w=t.get(b);w.length_c&&(b.dispatchEvent(new Event("dde:connected")),w.connected=new WeakSet,w.length_c=0,w.length_d||t.delete(b),a=!0)}return a}function m(i,f){let a=!1;for(let b of i)f&&u(b).then(m),!(!t.has(b)||!t.get(b).length_d)&&(b.dispatchEvent(new Event("dde:disconnected")),t.delete(b),a=!0);return a}}var p=Symbol.for("observable");function W(t){try{return Reflect.has(t,p)}catch{return!1}}var M=[],h=new WeakMap;function _(t,e){if(typeof t!="function")return Q(t,e);if(W(t))return t;let n=Q(),r=function(){let[o,...c]=h.get(r);if(h.set(r,new Set([o])),M.push(r),n(t()),M.pop(),!c.length)return;let s=h.get(r);for(let d of c)s.has(d)||S(d,r)};return h.set(n[p],r),h.set(r,new Set([n])),r(),n}_.action=function(t,e,...n){let r=t[p],{actions:o}=r;if(!o||!Reflect.has(o,e))throw new Error(`'${t}' has no action with name '${e}'!`);if(o[e].apply(r,n),r.skip)return Reflect.deleteProperty(r,"skip");r.listeners.forEach(c=>c(r.value))};_.on=function t(e,n,r={}){let{observable:o}=r;if(!(o&&o.aborted)){if(Array.isArray(e))return e.forEach(c=>t(c,n,r));U(e,n),o&&o.addEventListener("abort",()=>S(e,n))}};_.symbols={observable:p,onclear:Symbol.for("Observable.onclear")};_.clear=function(...t){for(let n of t){Reflect.deleteProperty(n,"toJSON");let r=n[p];r.onclear.forEach(o=>o.call(r)),e(n,r),Reflect.deleteProperty(n,p)}function e(n,r){r.listeners.forEach(o=>{if(r.listeners.delete(o),!h.has(o))return;let c=h.get(o);c.delete(n),!(c.size>1)&&(n.clear(...c),h.delete(o))})}};var k="__dde_reactive";_.el=function(t,e){let n=y.mark({type:"reactive"},!1),r=n.end,o=document.createDocumentFragment();o.append(n,r);let{current:c}=g,s=d=>{if(!n.parentNode||!r.parentNode)return S(t,s);g.push(c);let u=e(d);g.pop(),Array.isArray(u)||(u=[u]);let l=n;for(;(l=n.nextSibling)!==r;)l.remove();n.after(...u)};return U(t,s),Y(t,s,n,e),s(t()),o};var R="__dde_attributes";_.attribute=function(t,e=null){let n=_(e),r;return g.host(o=>{if(r=o,O(r,"has",t)?n(O(r,"get",t)):e!==null&&O(r,"set",t,e),o[R]){o[R][t]=n;return}r[R]={[t]:n},v.attributeChanged(function({detail:s}){/*! This maps attributes to observables (`S.attribute`). +* Investigate `__dde_attributes` key of the element.*/let[d,u]=s,l=r[R][d];if(l)return l(u)})(r),v.disconnected(function(){/*! This removes all observables mapped to attributes (`S.attribute`). +* Investigate `__dde_attributes` key of the element.*/_.clear(...Object.values(r[R]))})(r)}),new Proxy(n,{apply(o,c,s){if(!s.length)return o();let d=s[0];return O(r,"set",t,d)}})};var X={isObservable:W,processReactiveAttribute(t,e,n,r){if(!W(n))return n;let o=c=>r(e,c);return U(n,o),Y(n,o,t,e),n()}};function Y(t,e,...n){let{current:r}=g;r.prevent||r.host(function(o){o[k]||(o[k]=[],v.disconnected(()=>o[k].forEach(([[c,s]])=>S(c,s,c[p]?.host()===o)))(o)),o[k].push([[t,e],...n])})}function Q(t,e){let n=(...r)=>r.length?lt(n,...r):dt(n);return ut(n,t,e)}var ft=Object.assign(Object.create(null),{stopPropagation(){this.skip=!0}}),q=class extends Error{constructor(){super();let[e,...n]=this.stack.split(` +`),r=e.slice(e.indexOf("@"),e.indexOf(".js:")+4);this.stack=n.find(o=>!o.includes(r))}};function ut(t,e,n){let r=[];B(n)!=="[object Object]"&&(n={});let{onclear:o}=t.symbols;n[o]&&(r.push(n[o]),Reflect.deleteProperty(n,o));let{host:c}=g;return Reflect.defineProperty(t,p,{value:{value:e,actions:n,onclear:r,host:c,listeners:new Set,defined:new q},enumerable:!1,writable:!1,configurable:!0}),t.toJSON=()=>t(),Object.setPrototypeOf(t[p],ft),t}function at(){return M[M.length-1]}function dt(t){if(!t[p])return;let{value:e,listeners:n}=t[p],r=at();return r&&n.add(r),h.has(r)&&h.get(r).add(t),e}function lt(t,e,n){if(!t[p])return;let r=t[p];if(!(!n&&r.value===e))return r.value=e,r.listeners.forEach(o=>o(e)),e}function U(t,e){if(t[p])return t[p].listeners.add(e)}function S(t,e,n){let r=t[p];if(!r)return;let o=r.listeners.delete(e);if(n&&!r.listeners.size){if(t.clear(t),!h.has(r))return o;let c=h.get(r);if(!h.has(c))return o;h.get(c).forEach(s=>S(s,c,!0))}return o}T(X); +globalThis.dde= {O: _, +assign: P, +assignAttribute: Z, +chainableAppend: et, +classListDeclarative: nt, +createElement: y, +createElementNS: Et, +dispatchEvent: wt, +el: y, +elNS: Et, +elementAttribute: O, +empty: xt, +isObservable: W, +observable: _, +on: v, +registerReactivity: T, +scope: g, +simulateSlots: vt +}; + +})(); \ No newline at end of file diff --git a/dist/dde-with-signals.js b/dist/dde-with-signals.js deleted file mode 100644 index f91dae9..0000000 --- a/dist/dde-with-signals.js +++ /dev/null @@ -1,26 +0,0 @@ -//deka-dom-el library is available via global namespace `dde` -(()=> { -var A={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function T(t,e=!0){return e?Object.assign(A,t):(Object.setPrototypeOf(t,A),t)}function C(t){return A.isPrototypeOf(t)&&t!==A?t:A}function x(t){return typeof t>"u"}function B(t){let e=typeof t;return e!=="object"?e:t===null?"null":Object.prototype.toString.call(t)}function N(t,e){if(!t||!(t instanceof AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}var $={setDeleteAttr:tt,ssr:""};function tt(t,e,n){if(Reflect.set(t,e,n),!!x(n)){if(Reflect.deleteProperty(t,e),t instanceof HTMLElement&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var v=[{scope:document.body,host:t=>t?t(document.body):document.body,custom_element:!1,prevent:!0}],g={get current(){return v[v.length-1]},get host(){return this.current.host},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...v]},push(t={}){return v.push(Object.assign({},this.current,{prevent:!1},t))},pushRoot(){return v.push(v[0])},pop(){if(v.length!==1)return v.pop()}};function H(...t){return this.appendOriginal(...t),this}function et(t){return t.append===H||(t.appendOriginal=t.append,t.append=H),t}var j;function y(t,e,...n){let r=C(this),o=0,c,s;switch((Object(e)!==e||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1,g.push({scope:t,host:(...l)=>l.length?(o===1?n.unshift(...l):l.forEach(_=>_(s)),void 0):s}),c=t(e||void 0);let d=c instanceof DocumentFragment;if(c.nodeName==="#comment")break;let u=y.mark({type:"component",name:t.name,host:d?"this":"parentElement"});c.prepend(u),d&&(s=u);break}case t==="#text":c=P.call(this,document.createTextNode(""),e);break;case(t==="<>"||!t):c=P.call(this,document.createDocumentFragment(),e);break;case!!j:c=P.call(this,document.createElementNS(j,t),e);break;case!c:c=P.call(this,document.createElement(t),e)}return et(c),s||(s=c),n.forEach(d=>d(s)),o&&g.pop(),o=2,c}function Et(t){let e=Symbol.for("default"),n=Array.from(t.querySelectorAll("slot")).reduce((o,c)=>Reflect.set(o,c.name||e,c)&&o,{}),r=Reflect.has(n,e);return t.append=new Proxy(t.append,{apply(o,c,s){if(!s.length)return t;let d=document.createDocumentFragment();for(let u of s){if(!u||!u.slot){r&&d.appendChild(u);continue}let l=u.slot,_=n[l];S(u,"remove","slot"),_&&(_.replaceWith(u),Reflect.deleteProperty(n,l))}return r&&(n[e].replaceWith(d),Reflect.deleteProperty(n,e)),Object.values(n).forEach(u=>u.replaceWith(y().append(...Array.from(u.childNodes)))),t}}),t}y.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=document.createComment(``);return e||(r.end=document.createComment("")),r};function vt(t){let e=this;return function(...r){j=t;let o=y.call(e,...r);return j=void 0,o}}var{setDeleteAttr:I}=$,L=new WeakMap;function P(t,...e){if(!e.length)return t;L.set(t,G(t,this));for(let[n,r]of Object.entries(Object.assign({},...e)))Z.call(this,t,n,r);return L.delete(t),t}function Z(t,e,n){let{setRemoveAttr:r,s:o}=G(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(d,u)=>Z.call(c,t,d,u));let[s]=e;if(s==="=")return r(e.slice(1),n);if(s===".")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 I(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return F(o,n,J.bind(null,t[e]));case"ariaset":return F(o,n,(d,u)=>r("aria-"+d,u));case"classList":return nt.call(c,t,n)}return rt(t,e)?I(t,e,n):r(e,n)}function G(t,e){if(L.has(t))return L.get(t);let r=(t instanceof SVGElement?ct:ot).bind(null,t,"Attribute"),o=C(e);return{setRemoveAttr:r,s:o}}function nt(t,e){let n=C(this);return F(n,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function xt(t){return Array.from(t.children).forEach(e=>e.remove()),t}function S(t,e,n,r){return t instanceof HTMLElement?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function rt(t,e){if(!Reflect.has(t,e))return!1;let n=V(t,e);return!x(n.set)}function V(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||V(t,e)}function F(t,e,n){if(!(typeof e!="object"||e===null))return Object.entries(e).forEach(function([o,c]){o&&(c=t.processReactiveAttribute(e,o,c,n),n(o,c))})}function K(t){return Array.isArray(t)?t.filter(Boolean).join(" "):t}function ot(t,e,n,r){return t[(x(r)?"remove":"set")+e](n,K(r))}function ct(t,e,n,r,o=null){return t[(x(r)?"remove":"set")+e+"NS"](o,n,K(r))}function J(t,e,n){if(Reflect.set(t,e,n),!!x(n))return Reflect.deleteProperty(t,e)}function wt(t,e,n){return e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let s=c.length?new CustomEvent(t,Object.assign({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(s)}}function E(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var D=it(),st=new WeakSet;E.connected=function(t,e){let{custom_element:n}=g.current,r="connected";return typeof e!="object"&&(e={}),e.once=!0,function(c){n&&(c=n);let s="dde:"+r;return c.addEventListener(s,t,e),c.__dde_lifecycleToEvents?c:c.isConnected?(c.dispatchEvent(new Event(s)),c):(N(e.signal,()=>D.offConnected(c,t))&&D.onConnected(c,t),c)}};E.disconnected=function(t,e){let{custom_element:n}=g.current,r="disconnected";return typeof e!="object"&&(e={}),e.once=!0,function(c){n&&(c=n);let s="dde:"+r;return c.addEventListener(s,t,e),c.__dde_lifecycleToEvents||N(e.signal,()=>D.offDisconnected(c,t))&&D.onDisconnected(c,t),c}};var z=new WeakMap;E.disconnectedAsAbort=function(t){if(z.has(t))return z.get(t);let e=new AbortController;return z.set(t,e),t(E.disconnected(()=>e.abort())),e};E.attributeChanged=function(t,e){let n="attributeChanged";return typeof e!="object"&&(e={}),function(o){let c="dde:"+n;if(o.addEventListener(c,t,e),o.__dde_lifecycleToEvents||st.has(o))return o;let s=new MutationObserver(function(u){for(let{attributeName:l,target:_}of u)_.dispatchEvent(new CustomEvent(c,{detail:[l,_.getAttribute(l)]}))});return N(e.signal,()=>s.disconnect())&&s.observe(o,{attributes:!0}),o}};function it(){let t=new Map,e=!1,n=new MutationObserver(function(i){for(let f of i)if(f.type==="childList"){if(l(f.addedNodes,!0)){s();continue}_(f.removedNodes,!0)&&s()}});return{onConnected(i,f){c();let a=o(i);a.connected.has(f)||(a.connected.add(f),a.length_c+=1)},offConnected(i,f){if(!t.has(i))return;let a=t.get(i);a.connected.has(f)&&(a.connected.delete(f),a.length_c-=1,r(i,a))},onDisconnected(i,f){c();let a=o(i);a.disconnected.has(f)||(a.disconnected.add(f),a.length_d+=1)},offDisconnected(i,f){if(!t.has(i))return;let a=t.get(i);a.disconnected.has(f)&&(a.disconnected.delete(f),a.length_d-=1,r(i,a))}};function r(i,f){f.length_c||f.length_d||(t.delete(i),s())}function o(i){if(t.has(i))return t.get(i);let f={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(i,f),f}function c(){e||(e=!0,n.observe(document.body,{childList:!0,subtree:!0}))}function s(){!e||t.size||(e=!1,n.disconnect())}function d(){return new Promise(function(i){(requestIdleCallback||requestAnimationFrame)(i)})}async function u(i){t.size>30&&await d();let f=[];if(!(i instanceof Node))return f;for(let a of t.keys())a===i||!(a instanceof Node)||i.contains(a)&&f.push(a);return f}function l(i,f){let a=!1;for(let m of i){if(f&&u(m).then(l),!t.has(m))continue;let w=t.get(m);w.length_c&&(m.dispatchEvent(new Event("dde:connected")),w.connected=new WeakSet,w.length_c=0,w.length_d||t.delete(m),a=!0)}return a}function _(i,f){let a=!1;for(let m of i)f&&u(m).then(_),!(!t.has(m)||!t.get(m).length_d)&&(m.dispatchEvent(new Event("dde:disconnected")),t.delete(m),a=!0);return a}}var p=Symbol.for("Signal");function W(t){try{return Reflect.has(t,p)}catch{return!1}}var M=[],h=new WeakMap;function b(t,e){if(typeof t!="function")return Q(t,e);if(W(t))return t;let n=Q(),r=function(){let[o,...c]=h.get(r);if(h.set(r,new Set([o])),M.push(r),n(t()),M.pop(),!c.length)return;let s=h.get(r);for(let d of c)s.has(d)||R(d,r)};return h.set(n[p],r),h.set(r,new Set([n])),r(),n}b.action=function(t,e,...n){let r=t[p],{actions:o}=r;if(!o||!Reflect.has(o,e))throw new Error(`'${t}' has no action with name '${e}'!`);if(o[e].apply(r,n),r.skip)return Reflect.deleteProperty(r,"skip");r.listeners.forEach(c=>c(r.value))};b.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));U(e,n),o&&o.addEventListener("abort",()=>R(e,n))}};b.symbols={signal:p,onclear:Symbol.for("Signal.onclear")};b.clear=function(...t){for(let n of t){Reflect.deleteProperty(n,"toJSON");let r=n[p];r.onclear.forEach(o=>o.call(r)),e(n,r),Reflect.deleteProperty(n,p)}function e(n,r){r.listeners.forEach(o=>{if(r.listeners.delete(o),!h.has(o))return;let c=h.get(o);c.delete(n),!(c.size>1)&&(b.clear(...c),h.delete(o))})}};var k="__dde_reactive";b.el=function(t,e){let n=y.mark({type:"reactive"},!1),r=n.end,o=document.createDocumentFragment();o.append(n,r);let{current:c}=g,s=d=>{if(!n.parentNode||!r.parentNode)return R(t,s);g.push(c);let u=e(d);g.pop(),Array.isArray(u)||(u=[u]);let l=n;for(;(l=n.nextSibling)!==r;)l.remove();n.after(...u)};return U(t,s),Y(t,s,n,e),s(t()),o};var O="__dde_attributes";b.attribute=function(t,e=null){let n=b(e),r;return g.host(o=>{if(r=o,S(r,"has",t)?n(S(r,"get",t)):e!==null&&S(r,"set",t,e),o[O]){o[O][t]=n;return}r[O]={[t]:n},E.attributeChanged(function({detail:s}){/*! This maps attributes to signals (`S.attribute`). -* Investigate `__dde_attributes` key of the element.*/let[d,u]=s,l=r[O][d];if(l)return l(u)})(r),E.disconnected(function(){/*! This removes all signals mapped to attributes (`S.attribute`). -* Investigate `__dde_attributes` key of the element.*/b.clear(...Object.values(r[O]))})(r)}),new Proxy(n,{apply(o,c,s){if(!s.length)return o();let d=s[0];return S(r,"set",t,d)}})};var X={isSignal:W,processReactiveAttribute(t,e,n,r){if(!W(n))return n;let o=c=>r(e,c);return U(n,o),Y(n,o,t,e),n()}};function Y(t,e,...n){let{current:r}=g;r.prevent||r.host(function(o){o[k]||(o[k]=[],E.disconnected(()=>o[k].forEach(([[c,s]])=>R(c,s,c[p]?.host()===o)))(o)),o[k].push([[t,e],...n])})}function Q(t,e){let n=(...r)=>r.length?lt(n,...r):dt(n);return ut(n,t,e)}var ft=Object.assign(Object.create(null),{stopPropagation(){this.skip=!0}}),q=class extends Error{constructor(){super();let[e,...n]=this.stack.split(` -`),r=e.slice(e.indexOf("@"),e.indexOf(".js:")+4);this.stack=n.find(o=>!o.includes(r))}};function ut(t,e,n){let r=[];B(n)!=="[object Object]"&&(n={});let{onclear:o}=b.symbols;n[o]&&(r.push(n[o]),Reflect.deleteProperty(n,o));let{host:c}=g;return Reflect.defineProperty(t,p,{value:{value:e,actions:n,onclear:r,host:c,listeners:new Set,defined:new q},enumerable:!1,writable:!1,configurable:!0}),t.toJSON=()=>t(),Object.setPrototypeOf(t[p],ft),t}function at(){return M[M.length-1]}function dt(t){if(!t[p])return;let{value:e,listeners:n}=t[p],r=at();return r&&n.add(r),h.has(r)&&h.get(r).add(t),e}function lt(t,e,n){if(!t[p])return;let r=t[p];if(!(!n&&r.value===e))return r.value=e,r.listeners.forEach(o=>o(e)),e}function U(t,e){if(t[p])return t[p].listeners.add(e)}function R(t,e,n){let r=t[p];if(!r)return;let o=r.listeners.delete(e);if(n&&!r.listeners.size){if(b.clear(t),!h.has(r))return o;let c=h.get(r);if(!h.has(c))return o;h.get(c).forEach(s=>R(s,c,!0))}return o}T(X); -globalThis.dde= {S: b, -assign: P, -assignAttribute: Z, -chainableAppend: et, -classListDeclarative: nt, -createElement: y, -createElementNS: vt, -dispatchEvent: wt, -el: y, -elNS: vt, -elementAttribute: S, -empty: xt, -isSignal: W, -on: E, -registerReactivity: T, -scope: g, -simulateSlots: Et -}; - -})(); \ No newline at end of file diff --git a/dist/dde.js b/dist/dde.js index 785b65a..1286bc5 100644 --- a/dist/dde.js +++ b/dist/dde.js @@ -1,6 +1,6 @@ //deka-dom-el library is available via global namespace `dde` (()=> { -var E={isSignal(t){return!1},processReactiveAttribute(t,e,n,c){return n}};function q(t,e=!0){return e?Object.assign(E,t):(Object.setPrototypeOf(t,E),t)}function x(t){return E.isPrototypeOf(t)&&t!==E?t:E}function b(t){return typeof t>"u"}function A(t,e){if(!t||!(t instanceof AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}var S={setDeleteAttr:F,ssr:""};function F(t,e,n){if(Reflect.set(t,e,n),!!b(n)){if(Reflect.deleteProperty(t,e),t instanceof HTMLElement&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var g=[{scope:document.body,host:t=>t?t(document.body):document.body,custom_element:!1,prevent:!0}],v={get current(){return g[g.length-1]},get host(){return this.current.host},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...g]},push(t={}){return g.push(Object.assign({},this.current,{prevent:!1},t))},pushRoot(){return g.push(g[0])},pop(){if(g.length!==1)return g.pop()}};function L(...t){return this.appendOriginal(...t),this}function U(t){return t.append===L||(t.appendOriginal=t.append,t.append=L),t}var O;function C(t,e,...n){let c=x(this),o=0,r,f;switch((Object(e)!==e||c.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1,v.push({scope:t,host:(...l)=>l.length?(o===1?n.unshift(...l):l.forEach(h=>h(f)),void 0):f}),r=t(e||void 0);let d=r instanceof DocumentFragment;if(r.nodeName==="#comment")break;let a=C.mark({type:"component",name:t.name,host:d?"this":"parentElement"});r.prepend(a),d&&(f=a);break}case t==="#text":r=w.call(this,document.createTextNode(""),e);break;case(t==="<>"||!t):r=w.call(this,document.createDocumentFragment(),e);break;case!!O:r=w.call(this,document.createElementNS(O,t),e);break;case!r:r=w.call(this,document.createElement(t),e)}return U(r),f||(f=r),n.forEach(d=>d(f)),o&&v.pop(),o=2,r}function tt(t){let e=Symbol.for("default"),n=Array.from(t.querySelectorAll("slot")).reduce((o,r)=>Reflect.set(o,r.name||e,r)&&o,{}),c=Reflect.has(n,e);return t.append=new Proxy(t.append,{apply(o,r,f){if(!f.length)return t;let d=document.createDocumentFragment();for(let a of f){if(!a||!a.slot){c&&d.appendChild(a);continue}let l=a.slot,h=n[l];B(a,"remove","slot"),h&&(h.replaceWith(a),Reflect.deleteProperty(n,l))}return c&&(n[e].replaceWith(d),Reflect.deleteProperty(n,e)),Object.values(n).forEach(a=>a.replaceWith(C().append(...Array.from(a.childNodes)))),t}}),t}C.mark=function(t,e=!1){t=Object.entries(t).map(([o,r])=>o+`="${r}"`).join(" ");let n=e?"":"/",c=document.createComment(``);return e||(c.end=document.createComment("")),c};function et(t){let e=this;return function(...c){O=t;let o=C.call(e,...c);return O=void 0,o}}var{setDeleteAttr:j}=S,y=new WeakMap;function w(t,...e){if(!e.length)return t;y.set(t,M(t,this));for(let[n,c]of Object.entries(Object.assign({},...e)))W.call(this,t,n,c);return y.delete(t),t}function W(t,e,n){let{setRemoveAttr:c,s:o}=M(t,this),r=this;n=o.processReactiveAttribute(t,e,n,(d,a)=>W.call(r,t,d,a));let[f]=e;if(f==="=")return c(e.slice(1),n);if(f===".")return P(t,e.slice(1),n);if(/(aria|data)([A-Z])/.test(e))return e=e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),c(e,n);switch(e==="className"&&(e="class"),e){case"xlink:href":return c(e,n,"http://www.w3.org/1999/xlink");case"textContent":return j(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return N(o,n,P.bind(null,t[e]));case"ariaset":return N(o,n,(d,a)=>c("aria-"+d,a));case"classList":return z.call(r,t,n)}return k(t,e)?j(t,e,n):c(e,n)}function M(t,e){if(y.has(t))return y.get(t);let c=(t instanceof SVGElement?I:H).bind(null,t,"Attribute"),o=x(e);return{setRemoveAttr:c,s:o}}function z(t,e){let n=x(this);return N(n,e,(c,o)=>t.classList.toggle(c,o===-1?void 0:!!o)),t}function nt(t){return Array.from(t.children).forEach(e=>e.remove()),t}function B(t,e,n,c){return t instanceof HTMLElement?t[e+"Attribute"](n,c):t[e+"AttributeNS"](null,n,c)}function k(t,e){if(!Reflect.has(t,e))return!1;let n=T(t,e);return!b(n.set)}function T(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||T(t,e)}function N(t,e,n){if(!(typeof e!="object"||e===null))return Object.entries(e).forEach(function([o,r]){o&&(r=t.processReactiveAttribute(e,o,r,n),n(o,r))})}function $(t){return Array.isArray(t)?t.filter(Boolean).join(" "):t}function H(t,e,n,c){return t[(b(c)?"remove":"set")+e](n,$(c))}function I(t,e,n,c,o=null){return t[(b(c)?"remove":"set")+e+"NS"](o,n,$(c))}function P(t,e,n){if(Reflect.set(t,e,n),!!b(n))return Reflect.deleteProperty(t,e)}function ct(t,e,n){return e||(e={}),function(o,...r){n&&(r.unshift(o),o=typeof n=="function"?n():n);let f=r.length?new CustomEvent(t,Object.assign({detail:r[0]},e)):new Event(t,e);return o.dispatchEvent(f)}}function _(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var R=G(),Z=new WeakSet;_.connected=function(t,e){let{custom_element:n}=v.current,c="connected";return typeof e!="object"&&(e={}),e.once=!0,function(r){n&&(r=n);let f="dde:"+c;return r.addEventListener(f,t,e),r.__dde_lifecycleToEvents?r:r.isConnected?(r.dispatchEvent(new Event(f)),r):(A(e.signal,()=>R.offConnected(r,t))&&R.onConnected(r,t),r)}};_.disconnected=function(t,e){let{custom_element:n}=v.current,c="disconnected";return typeof e!="object"&&(e={}),e.once=!0,function(r){n&&(r=n);let f="dde:"+c;return r.addEventListener(f,t,e),r.__dde_lifecycleToEvents||A(e.signal,()=>R.offDisconnected(r,t))&&R.onDisconnected(r,t),r}};var D=new WeakMap;_.disconnectedAsAbort=function(t){if(D.has(t))return D.get(t);let e=new AbortController;return D.set(t,e),t(_.disconnected(()=>e.abort())),e};_.attributeChanged=function(t,e){let n="attributeChanged";return typeof e!="object"&&(e={}),function(o){let r="dde:"+n;if(o.addEventListener(r,t,e),o.__dde_lifecycleToEvents||Z.has(o))return o;let f=new MutationObserver(function(a){for(let{attributeName:l,target:h}of a)h.dispatchEvent(new CustomEvent(r,{detail:[l,h.getAttribute(l)]}))});return A(e.signal,()=>f.disconnect())&&f.observe(o,{attributes:!0}),o}};function G(){let t=new Map,e=!1,n=new MutationObserver(function(s){for(let i of s)if(i.type==="childList"){if(l(i.addedNodes,!0)){f();continue}h(i.removedNodes,!0)&&f()}});return{onConnected(s,i){r();let u=o(s);u.connected.has(i)||(u.connected.add(i),u.length_c+=1)},offConnected(s,i){if(!t.has(s))return;let u=t.get(s);u.connected.has(i)&&(u.connected.delete(i),u.length_c-=1,c(s,u))},onDisconnected(s,i){r();let u=o(s);u.disconnected.has(i)||(u.disconnected.add(i),u.length_d+=1)},offDisconnected(s,i){if(!t.has(s))return;let u=t.get(s);u.disconnected.has(i)&&(u.disconnected.delete(i),u.length_d-=1,c(s,u))}};function c(s,i){i.length_c||i.length_d||(t.delete(s),f())}function o(s){if(t.has(s))return t.get(s);let i={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(s,i),i}function r(){e||(e=!0,n.observe(document.body,{childList:!0,subtree:!0}))}function f(){!e||t.size||(e=!1,n.disconnect())}function d(){return new Promise(function(s){(requestIdleCallback||requestAnimationFrame)(s)})}async function a(s){t.size>30&&await d();let i=[];if(!(s instanceof Node))return i;for(let u of t.keys())u===s||!(u instanceof Node)||s.contains(u)&&i.push(u);return i}function l(s,i){let u=!1;for(let p of s){if(i&&a(p).then(l),!t.has(p))continue;let m=t.get(p);m.length_c&&(p.dispatchEvent(new Event("dde:connected")),m.connected=new WeakSet,m.length_c=0,m.length_d||t.delete(p),u=!0)}return u}function h(s,i){let u=!1;for(let p of s)i&&a(p).then(h),!(!t.has(p)||!t.get(p).length_d)&&(p.dispatchEvent(new Event("dde:disconnected")),t.delete(p),u=!0);return u}} +var v={isObservable(t){return!1},processReactiveAttribute(t,e,n,c){return n}};function q(t,e=!0){return e?Object.assign(v,t):(Object.setPrototypeOf(t,v),t)}function x(t){return v.isPrototypeOf(t)&&t!==v?t:v}function g(t){return typeof t>"u"}function A(t,e){if(!t||!(t instanceof AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}var S={setDeleteAttr:F,ssr:""};function F(t,e,n){if(Reflect.set(t,e,n),!!g(n)){if(Reflect.deleteProperty(t,e),t instanceof HTMLElement&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var b=[{scope:document.body,host:t=>t?t(document.body):document.body,custom_element:!1,prevent:!0}],E={get current(){return b[b.length-1]},get host(){return this.current.host},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...b]},push(t={}){return b.push(Object.assign({},this.current,{prevent:!1},t))},pushRoot(){return b.push(b[0])},pop(){if(b.length!==1)return b.pop()}};function L(...t){return this.appendOriginal(...t),this}function U(t){return t.append===L||(t.appendOriginal=t.append,t.append=L),t}var O;function C(t,e,...n){let c=x(this),o=0,r,f;switch((Object(e)!==e||c.isObservable(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1,E.push({scope:t,host:(...l)=>l.length?(o===1?n.unshift(...l):l.forEach(h=>h(f)),void 0):f}),r=t(e||void 0);let d=r instanceof DocumentFragment;if(r.nodeName==="#comment")break;let a=C.mark({type:"component",name:t.name,host:d?"this":"parentElement"});r.prepend(a),d&&(f=a);break}case t==="#text":r=w.call(this,document.createTextNode(""),e);break;case(t==="<>"||!t):r=w.call(this,document.createDocumentFragment(),e);break;case!!O:r=w.call(this,document.createElementNS(O,t),e);break;case!r:r=w.call(this,document.createElement(t),e)}return U(r),f||(f=r),n.forEach(d=>d(f)),o&&E.pop(),o=2,r}function tt(t){let e=Symbol.for("default"),n=Array.from(t.querySelectorAll("slot")).reduce((o,r)=>Reflect.set(o,r.name||e,r)&&o,{}),c=Reflect.has(n,e);return t.append=new Proxy(t.append,{apply(o,r,f){if(!f.length)return t;let d=document.createDocumentFragment();for(let a of f){if(!a||!a.slot){c&&d.appendChild(a);continue}let l=a.slot,h=n[l];B(a,"remove","slot"),h&&(h.replaceWith(a),Reflect.deleteProperty(n,l))}return c&&(n[e].replaceWith(d),Reflect.deleteProperty(n,e)),Object.values(n).forEach(a=>a.replaceWith(C().append(...Array.from(a.childNodes)))),t}}),t}C.mark=function(t,e=!1){t=Object.entries(t).map(([o,r])=>o+`="${r}"`).join(" ");let n=e?"":"/",c=document.createComment(``);return e||(c.end=document.createComment("")),c};function et(t){let e=this;return function(...c){O=t;let o=C.call(e,...c);return O=void 0,o}}var{setDeleteAttr:j}=S,y=new WeakMap;function w(t,...e){if(!e.length)return t;y.set(t,M(t,this));for(let[n,c]of Object.entries(Object.assign({},...e)))W.call(this,t,n,c);return y.delete(t),t}function W(t,e,n){let{setRemoveAttr:c,s:o}=M(t,this),r=this;n=o.processReactiveAttribute(t,e,n,(d,a)=>W.call(r,t,d,a));let[f]=e;if(f==="=")return c(e.slice(1),n);if(f===".")return P(t,e.slice(1),n);if(/(aria|data)([A-Z])/.test(e))return e=e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),c(e,n);switch(e==="className"&&(e="class"),e){case"xlink:href":return c(e,n,"http://www.w3.org/1999/xlink");case"textContent":return j(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return N(o,n,P.bind(null,t[e]));case"ariaset":return N(o,n,(d,a)=>c("aria-"+d,a));case"classList":return z.call(r,t,n)}return k(t,e)?j(t,e,n):c(e,n)}function M(t,e){if(y.has(t))return y.get(t);let c=(t instanceof SVGElement?I:H).bind(null,t,"Attribute"),o=x(e);return{setRemoveAttr:c,s:o}}function z(t,e){let n=x(this);return N(n,e,(c,o)=>t.classList.toggle(c,o===-1?void 0:!!o)),t}function nt(t){return Array.from(t.children).forEach(e=>e.remove()),t}function B(t,e,n,c){return t instanceof HTMLElement?t[e+"Attribute"](n,c):t[e+"AttributeNS"](null,n,c)}function k(t,e){if(!Reflect.has(t,e))return!1;let n=T(t,e);return!g(n.set)}function T(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||T(t,e)}function N(t,e,n){if(!(typeof e!="object"||e===null))return Object.entries(e).forEach(function([o,r]){o&&(r=t.processReactiveAttribute(e,o,r,n),n(o,r))})}function $(t){return Array.isArray(t)?t.filter(Boolean).join(" "):t}function H(t,e,n,c){return t[(g(c)?"remove":"set")+e](n,$(c))}function I(t,e,n,c,o=null){return t[(g(c)?"remove":"set")+e+"NS"](o,n,$(c))}function P(t,e,n){if(Reflect.set(t,e,n),!!g(n))return Reflect.deleteProperty(t,e)}function ct(t,e,n){return e||(e={}),function(o,...r){n&&(r.unshift(o),o=typeof n=="function"?n():n);let f=r.length?new CustomEvent(t,Object.assign({detail:r[0]},e)):new Event(t,e);return o.dispatchEvent(f)}}function _(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var R=G(),Z=new WeakSet;_.connected=function(t,e){let{custom_element:n}=E.current,c="connected";return typeof e!="object"&&(e={}),e.once=!0,function(r){n&&(r=n);let f="dde:"+c;return r.addEventListener(f,t,e),r.__dde_lifecycleToEvents?r:r.isConnected?(r.dispatchEvent(new Event(f)),r):(A(e.signal,()=>R.offConnected(r,t))&&R.onConnected(r,t),r)}};_.disconnected=function(t,e){let{custom_element:n}=E.current,c="disconnected";return typeof e!="object"&&(e={}),e.once=!0,function(r){n&&(r=n);let f="dde:"+c;return r.addEventListener(f,t,e),r.__dde_lifecycleToEvents||A(e.signal,()=>R.offDisconnected(r,t))&&R.onDisconnected(r,t),r}};var D=new WeakMap;_.disconnectedAsAbort=function(t){if(D.has(t))return D.get(t);let e=new AbortController;return D.set(t,e),t(_.disconnected(()=>e.abort())),e};_.attributeChanged=function(t,e){let n="attributeChanged";return typeof e!="object"&&(e={}),function(o){let r="dde:"+n;if(o.addEventListener(r,t,e),o.__dde_lifecycleToEvents||Z.has(o))return o;let f=new MutationObserver(function(a){for(let{attributeName:l,target:h}of a)h.dispatchEvent(new CustomEvent(r,{detail:[l,h.getAttribute(l)]}))});return A(e.signal,()=>f.disconnect())&&f.observe(o,{attributes:!0}),o}};function G(){let t=new Map,e=!1,n=new MutationObserver(function(s){for(let i of s)if(i.type==="childList"){if(l(i.addedNodes,!0)){f();continue}h(i.removedNodes,!0)&&f()}});return{onConnected(s,i){r();let u=o(s);u.connected.has(i)||(u.connected.add(i),u.length_c+=1)},offConnected(s,i){if(!t.has(s))return;let u=t.get(s);u.connected.has(i)&&(u.connected.delete(i),u.length_c-=1,c(s,u))},onDisconnected(s,i){r();let u=o(s);u.disconnected.has(i)||(u.disconnected.add(i),u.length_d+=1)},offDisconnected(s,i){if(!t.has(s))return;let u=t.get(s);u.disconnected.has(i)&&(u.disconnected.delete(i),u.length_d-=1,c(s,u))}};function c(s,i){i.length_c||i.length_d||(t.delete(s),f())}function o(s){if(t.has(s))return t.get(s);let i={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(s,i),i}function r(){e||(e=!0,n.observe(document.body,{childList:!0,subtree:!0}))}function f(){!e||t.size||(e=!1,n.disconnect())}function d(){return new Promise(function(s){(requestIdleCallback||requestAnimationFrame)(s)})}async function a(s){t.size>30&&await d();let i=[];if(!(s instanceof Node))return i;for(let u of t.keys())u===s||!(u instanceof Node)||s.contains(u)&&i.push(u);return i}function l(s,i){let u=!1;for(let p of s){if(i&&a(p).then(l),!t.has(p))continue;let m=t.get(p);m.length_c&&(p.dispatchEvent(new Event("dde:connected")),m.connected=new WeakSet,m.length_c=0,m.length_d||t.delete(p),u=!0)}return u}function h(s,i){let u=!1;for(let p of s)i&&a(p).then(h),!(!t.has(p)||!t.get(p).length_d)&&(p.dispatchEvent(new Event("dde:disconnected")),t.delete(p),u=!0);return u}} globalThis.dde= {assign: w, assignAttribute: W, chainableAppend: U, @@ -14,7 +14,7 @@ elementAttribute: B, empty: nt, on: _, registerReactivity: q, -scope: v, +scope: E, simulateSlots: tt }; diff --git a/dist/esm-with-signals.d.ts b/dist/esm-with-observables.d.ts similarity index 94% rename from dist/esm-with-signals.d.ts rename to dist/esm-with-observables.d.ts index 7e6c53e..4c2f71d 100644 --- a/dist/esm-with-signals.d.ts +++ b/dist/esm-with-observables.d.ts @@ -153,10 +153,10 @@ export const scope: { preventDefault(prevent: T): T, /** * This represents reference to the current host element — `scope.host()`. - * It can be also used to register Addon (function to be called when component is initized) + * It can be also used to register Addon(s) (functions to be called when component is initized) * — `scope.host(on.connected(console.log))`. * */ - host: ddeElementAddon, + host: (...addons: ddeElementAddon[])=> HTMLElement, state: Scope[], /** Adds new child scope. All attributes are inherited by default. */ @@ -444,19 +444,19 @@ declare global{ interface ddeSVGUseElement extends SVGUseElement{ append: ddeAppend; } interface ddeSVGViewElement extends SVGViewElement{ append: ddeAppend; } } -export type Signal= (set?: V)=> V & A; -type Action= (this: { value: V }, ...a: any[])=> typeof S._ | void; +export type Observable= (set?: V)=> V & A; +type Action= (this: { value: V }, ...a: any[])=> typeof observable._ | void; type SymbolOnclear= Symbol; -type SymbolSignal= Symbol; +type SymbolObservable= Symbol; type Actions= Record>; -interface S { +interface observable{ _: Symbol /** * Simple example: * ```js - * const hello= S("Hello Signal"); + * const hello= S("Hello Observable"); * ``` - * …simple todo signal: + * …simple todo observable: * ```js * const todos= S([], { * add(v){ this.value.push(S(v)); }, @@ -464,46 +464,47 @@ interface S { * [S.symbols.onclear](){ S.clear(...this.value); }, * }); * ``` - * …computed signal: + * …computed observable: * ```js * const name= S("Jan"); * const surname= S("Andrle"); * const fullname= S(()=> name()+" "+surname()); * ``` - * @param value Initial signal value. Or function computing value from other signals. - * @param actions Use to define actions on the signal. Such as add item to the array. - * There is also a reserved function `S.symbol.onclear` which is called when the signal is cleared + * @param value Initial observable value. Or function computing value from other observables. + * @param actions Use to define actions on the observable. Such as add item to the array. + * There is also a reserved function `S.symbol.onclear` which is called when the observable is cleared * by `S.clear`. * */ - >(value: V, actions?: A): Signal; + >(value: V, actions?: A): Observable; /** - * Computations signal. This creates a signal which is computed from other signals. + * Computations observable. This creates a observable which is computed from other observables. * */ - (computation: ()=> V): Signal - action>, A extends (S extends Signal ? A : never), N extends keyof A>( - signal: S, + (computation: ()=> V): Observable + action>, A extends (S extends Observable ? A : never), N extends keyof A>( + observable: S, name: N, ...params: A[N] extends (...args: infer P)=> any ? P : never ): void; - clear(...signals: Signal[]): void; - on(signal: Signal, onchange: (a: T)=> void, options?: AddEventListenerOptions): void; + clear(...observables: Observable[]): void; + on(observable: Observable, onchange: (a: T)=> void, options?: AddEventListenerOptions): void; symbols: { - signal: SymbolSignal; + observable: SymbolObservable; onclear: SymbolOnclear; } /** - * Reactive element, which is rendered based on the given signal. + * Reactive element, which is rendered based on the given observable. * ```js - * S.el(signal, value=> value ? el("b", "True") : el("i", "False")); + * S.el(observable, value=> value ? el("b", "True") : el("i", "False")); * S.el(listS, list=> list.map(li=> el("li", li))); * ``` * */ - el(signal: Signal, el: (v: S)=> Element | Element[]): DocumentFragment; + el(observable: Observable, el: (v: S)=> Element | Element[]): DocumentFragment; - attribute(name: string, initial?: string): Signal; + attribute(name: string, initial?: string): Observable; } -export const S: S; +export const observable: observable; +export const O: observable; declare global { - type ddeSignal= Signal; + type ddeObservable= Observable; type ddeActions= Actions } \ No newline at end of file diff --git a/dist/esm-with-observables.js b/dist/esm-with-observables.js new file mode 100644 index 0000000..a6e8724 --- /dev/null +++ b/dist/esm-with-observables.js @@ -0,0 +1,4 @@ +var A={isObservable(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function T(t,e=!0){return e?Object.assign(A,t):(Object.setPrototypeOf(t,A),t)}function C(t){return A.isPrototypeOf(t)&&t!==A?t:A}function x(t){return typeof t>"u"}function B(t){let e=typeof t;return e!=="object"?e:t===null?"null":Object.prototype.toString.call(t)}function N(t,e){if(!t||!(t instanceof AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}var $={setDeleteAttr:tt,ssr:""};function tt(t,e,n){if(Reflect.set(t,e,n),!!x(n)){if(Reflect.deleteProperty(t,e),t instanceof HTMLElement&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var E=[{scope:document.body,host:t=>t?t(document.body):document.body,custom_element:!1,prevent:!0}],g={get current(){return E[E.length-1]},get host(){return this.current.host},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...E]},push(t={}){return E.push(Object.assign({},this.current,{prevent:!1},t))},pushRoot(){return E.push(E[0])},pop(){if(E.length!==1)return E.pop()}};function H(...t){return this.appendOriginal(...t),this}function et(t){return t.append===H||(t.appendOriginal=t.append,t.append=H),t}var j;function y(t,e,...n){let r=C(this),o=0,c,s;switch((Object(e)!==e||r.isObservable(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1,g.push({scope:t,host:(...l)=>l.length?(o===1?n.unshift(...l):l.forEach(m=>m(s)),void 0):s}),c=t(e||void 0);let d=c instanceof DocumentFragment;if(c.nodeName==="#comment")break;let u=y.mark({type:"component",name:t.name,host:d?"this":"parentElement"});c.prepend(u),d&&(s=u);break}case t==="#text":c=P.call(this,document.createTextNode(""),e);break;case(t==="<>"||!t):c=P.call(this,document.createDocumentFragment(),e);break;case!!j:c=P.call(this,document.createElementNS(j,t),e);break;case!c:c=P.call(this,document.createElement(t),e)}return et(c),s||(s=c),n.forEach(d=>d(s)),o&&g.pop(),o=2,c}function vt(t){let e=Symbol.for("default"),n=Array.from(t.querySelectorAll("slot")).reduce((o,c)=>Reflect.set(o,c.name||e,c)&&o,{}),r=Reflect.has(n,e);return t.append=new Proxy(t.append,{apply(o,c,s){if(!s.length)return t;let d=document.createDocumentFragment();for(let u of s){if(!u||!u.slot){r&&d.appendChild(u);continue}let l=u.slot,m=n[l];O(u,"remove","slot"),m&&(m.replaceWith(u),Reflect.deleteProperty(n,l))}return r&&(n[e].replaceWith(d),Reflect.deleteProperty(n,e)),Object.values(n).forEach(u=>u.replaceWith(y().append(...Array.from(u.childNodes)))),t}}),t}y.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=document.createComment(``);return e||(r.end=document.createComment("")),r};function Et(t){let e=this;return function(...r){j=t;let o=y.call(e,...r);return j=void 0,o}}var{setDeleteAttr:I}=$,L=new WeakMap;function P(t,...e){if(!e.length)return t;L.set(t,G(t,this));for(let[n,r]of Object.entries(Object.assign({},...e)))Z.call(this,t,n,r);return L.delete(t),t}function Z(t,e,n){let{setRemoveAttr:r,s:o}=G(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(d,u)=>Z.call(c,t,d,u));let[s]=e;if(s==="=")return r(e.slice(1),n);if(s===".")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 I(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return F(o,n,J.bind(null,t[e]));case"ariaset":return F(o,n,(d,u)=>r("aria-"+d,u));case"classList":return nt.call(c,t,n)}return rt(t,e)?I(t,e,n):r(e,n)}function G(t,e){if(L.has(t))return L.get(t);let r=(t instanceof SVGElement?ct:ot).bind(null,t,"Attribute"),o=C(e);return{setRemoveAttr:r,s:o}}function nt(t,e){let n=C(this);return F(n,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function xt(t){return Array.from(t.children).forEach(e=>e.remove()),t}function O(t,e,n,r){return t instanceof HTMLElement?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function rt(t,e){if(!Reflect.has(t,e))return!1;let n=V(t,e);return!x(n.set)}function V(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||V(t,e)}function F(t,e,n){if(!(typeof e!="object"||e===null))return Object.entries(e).forEach(function([o,c]){o&&(c=t.processReactiveAttribute(e,o,c,n),n(o,c))})}function K(t){return Array.isArray(t)?t.filter(Boolean).join(" "):t}function ot(t,e,n,r){return t[(x(r)?"remove":"set")+e](n,K(r))}function ct(t,e,n,r,o=null){return t[(x(r)?"remove":"set")+e+"NS"](o,n,K(r))}function J(t,e,n){if(Reflect.set(t,e,n),!!x(n))return Reflect.deleteProperty(t,e)}function wt(t,e,n){return e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let s=c.length?new CustomEvent(t,Object.assign({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(s)}}function v(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var D=it(),st=new WeakSet;v.connected=function(t,e){let{custom_element:n}=g.current,r="connected";return typeof e!="object"&&(e={}),e.once=!0,function(c){n&&(c=n);let s="dde:"+r;return c.addEventListener(s,t,e),c.__dde_lifecycleToEvents?c:c.isConnected?(c.dispatchEvent(new Event(s)),c):(N(e.signal,()=>D.offConnected(c,t))&&D.onConnected(c,t),c)}};v.disconnected=function(t,e){let{custom_element:n}=g.current,r="disconnected";return typeof e!="object"&&(e={}),e.once=!0,function(c){n&&(c=n);let s="dde:"+r;return c.addEventListener(s,t,e),c.__dde_lifecycleToEvents||N(e.signal,()=>D.offDisconnected(c,t))&&D.onDisconnected(c,t),c}};var z=new WeakMap;v.disconnectedAsAbort=function(t){if(z.has(t))return z.get(t);let e=new AbortController;return z.set(t,e),t(v.disconnected(()=>e.abort())),e};v.attributeChanged=function(t,e){let n="attributeChanged";return typeof e!="object"&&(e={}),function(o){let c="dde:"+n;if(o.addEventListener(c,t,e),o.__dde_lifecycleToEvents||st.has(o))return o;let s=new MutationObserver(function(u){for(let{attributeName:l,target:m}of u)m.dispatchEvent(new CustomEvent(c,{detail:[l,m.getAttribute(l)]}))});return N(e.signal,()=>s.disconnect())&&s.observe(o,{attributes:!0}),o}};function it(){let t=new Map,e=!1,n=new MutationObserver(function(i){for(let f of i)if(f.type==="childList"){if(l(f.addedNodes,!0)){s();continue}m(f.removedNodes,!0)&&s()}});return{onConnected(i,f){c();let a=o(i);a.connected.has(f)||(a.connected.add(f),a.length_c+=1)},offConnected(i,f){if(!t.has(i))return;let a=t.get(i);a.connected.has(f)&&(a.connected.delete(f),a.length_c-=1,r(i,a))},onDisconnected(i,f){c();let a=o(i);a.disconnected.has(f)||(a.disconnected.add(f),a.length_d+=1)},offDisconnected(i,f){if(!t.has(i))return;let a=t.get(i);a.disconnected.has(f)&&(a.disconnected.delete(f),a.length_d-=1,r(i,a))}};function r(i,f){f.length_c||f.length_d||(t.delete(i),s())}function o(i){if(t.has(i))return t.get(i);let f={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(i,f),f}function c(){e||(e=!0,n.observe(document.body,{childList:!0,subtree:!0}))}function s(){!e||t.size||(e=!1,n.disconnect())}function d(){return new Promise(function(i){(requestIdleCallback||requestAnimationFrame)(i)})}async function u(i){t.size>30&&await d();let f=[];if(!(i instanceof Node))return f;for(let a of t.keys())a===i||!(a instanceof Node)||i.contains(a)&&f.push(a);return f}function l(i,f){let a=!1;for(let b of i){if(f&&u(b).then(l),!t.has(b))continue;let w=t.get(b);w.length_c&&(b.dispatchEvent(new Event("dde:connected")),w.connected=new WeakSet,w.length_c=0,w.length_d||t.delete(b),a=!0)}return a}function m(i,f){let a=!1;for(let b of i)f&&u(b).then(m),!(!t.has(b)||!t.get(b).length_d)&&(b.dispatchEvent(new Event("dde:disconnected")),t.delete(b),a=!0);return a}}var p=Symbol.for("observable");function W(t){try{return Reflect.has(t,p)}catch{return!1}}var M=[],h=new WeakMap;function _(t,e){if(typeof t!="function")return Q(t,e);if(W(t))return t;let n=Q(),r=function(){let[o,...c]=h.get(r);if(h.set(r,new Set([o])),M.push(r),n(t()),M.pop(),!c.length)return;let s=h.get(r);for(let d of c)s.has(d)||S(d,r)};return h.set(n[p],r),h.set(r,new Set([n])),r(),n}_.action=function(t,e,...n){let r=t[p],{actions:o}=r;if(!o||!Reflect.has(o,e))throw new Error(`'${t}' has no action with name '${e}'!`);if(o[e].apply(r,n),r.skip)return Reflect.deleteProperty(r,"skip");r.listeners.forEach(c=>c(r.value))};_.on=function t(e,n,r={}){let{observable:o}=r;if(!(o&&o.aborted)){if(Array.isArray(e))return e.forEach(c=>t(c,n,r));U(e,n),o&&o.addEventListener("abort",()=>S(e,n))}};_.symbols={observable:p,onclear:Symbol.for("Observable.onclear")};_.clear=function(...t){for(let n of t){Reflect.deleteProperty(n,"toJSON");let r=n[p];r.onclear.forEach(o=>o.call(r)),e(n,r),Reflect.deleteProperty(n,p)}function e(n,r){r.listeners.forEach(o=>{if(r.listeners.delete(o),!h.has(o))return;let c=h.get(o);c.delete(n),!(c.size>1)&&(n.clear(...c),h.delete(o))})}};var k="__dde_reactive";_.el=function(t,e){let n=y.mark({type:"reactive"},!1),r=n.end,o=document.createDocumentFragment();o.append(n,r);let{current:c}=g,s=d=>{if(!n.parentNode||!r.parentNode)return S(t,s);g.push(c);let u=e(d);g.pop(),Array.isArray(u)||(u=[u]);let l=n;for(;(l=n.nextSibling)!==r;)l.remove();n.after(...u)};return U(t,s),Y(t,s,n,e),s(t()),o};var R="__dde_attributes";_.attribute=function(t,e=null){let n=_(e),r;return g.host(o=>{if(r=o,O(r,"has",t)?n(O(r,"get",t)):e!==null&&O(r,"set",t,e),o[R]){o[R][t]=n;return}r[R]={[t]:n},v.attributeChanged(function({detail:s}){/*! This maps attributes to observables (`S.attribute`). +* Investigate `__dde_attributes` key of the element.*/let[d,u]=s,l=r[R][d];if(l)return l(u)})(r),v.disconnected(function(){/*! This removes all observables mapped to attributes (`S.attribute`). +* Investigate `__dde_attributes` key of the element.*/_.clear(...Object.values(r[R]))})(r)}),new Proxy(n,{apply(o,c,s){if(!s.length)return o();let d=s[0];return O(r,"set",t,d)}})};var X={isObservable:W,processReactiveAttribute(t,e,n,r){if(!W(n))return n;let o=c=>r(e,c);return U(n,o),Y(n,o,t,e),n()}};function Y(t,e,...n){let{current:r}=g;r.prevent||r.host(function(o){o[k]||(o[k]=[],v.disconnected(()=>o[k].forEach(([[c,s]])=>S(c,s,c[p]?.host()===o)))(o)),o[k].push([[t,e],...n])})}function Q(t,e){let n=(...r)=>r.length?lt(n,...r):dt(n);return ut(n,t,e)}var ft=Object.assign(Object.create(null),{stopPropagation(){this.skip=!0}}),q=class extends Error{constructor(){super();let[e,...n]=this.stack.split(` +`),r=e.slice(e.indexOf("@"),e.indexOf(".js:")+4);this.stack=n.find(o=>!o.includes(r))}};function ut(t,e,n){let r=[];B(n)!=="[object Object]"&&(n={});let{onclear:o}=t.symbols;n[o]&&(r.push(n[o]),Reflect.deleteProperty(n,o));let{host:c}=g;return Reflect.defineProperty(t,p,{value:{value:e,actions:n,onclear:r,host:c,listeners:new Set,defined:new q},enumerable:!1,writable:!1,configurable:!0}),t.toJSON=()=>t(),Object.setPrototypeOf(t[p],ft),t}function at(){return M[M.length-1]}function dt(t){if(!t[p])return;let{value:e,listeners:n}=t[p],r=at();return r&&n.add(r),h.has(r)&&h.get(r).add(t),e}function lt(t,e,n){if(!t[p])return;let r=t[p];if(!(!n&&r.value===e))return r.value=e,r.listeners.forEach(o=>o(e)),e}function U(t,e){if(t[p])return t[p].listeners.add(e)}function S(t,e,n){let r=t[p];if(!r)return;let o=r.listeners.delete(e);if(n&&!r.listeners.size){if(t.clear(t),!h.has(r))return o;let c=h.get(r);if(!h.has(c))return o;h.get(c).forEach(s=>S(s,c,!0))}return o}T(X);export{_ as O,P as assign,Z as assignAttribute,et as chainableAppend,nt as classListDeclarative,y as createElement,Et as createElementNS,wt as dispatchEvent,y as el,Et as elNS,O as elementAttribute,xt as empty,W as isObservable,_ as observable,v as on,T as registerReactivity,g as scope,vt as simulateSlots}; diff --git a/dist/esm-with-signals.js b/dist/esm-with-signals.js deleted file mode 100644 index 79f0493..0000000 --- a/dist/esm-with-signals.js +++ /dev/null @@ -1,4 +0,0 @@ -var A={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function T(t,e=!0){return e?Object.assign(A,t):(Object.setPrototypeOf(t,A),t)}function C(t){return A.isPrototypeOf(t)&&t!==A?t:A}function x(t){return typeof t>"u"}function B(t){let e=typeof t;return e!=="object"?e:t===null?"null":Object.prototype.toString.call(t)}function N(t,e){if(!t||!(t instanceof AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}var $={setDeleteAttr:tt,ssr:""};function tt(t,e,n){if(Reflect.set(t,e,n),!!x(n)){if(Reflect.deleteProperty(t,e),t instanceof HTMLElement&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var v=[{scope:document.body,host:t=>t?t(document.body):document.body,custom_element:!1,prevent:!0}],g={get current(){return v[v.length-1]},get host(){return this.current.host},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...v]},push(t={}){return v.push(Object.assign({},this.current,{prevent:!1},t))},pushRoot(){return v.push(v[0])},pop(){if(v.length!==1)return v.pop()}};function H(...t){return this.appendOriginal(...t),this}function et(t){return t.append===H||(t.appendOriginal=t.append,t.append=H),t}var j;function y(t,e,...n){let r=C(this),o=0,c,s;switch((Object(e)!==e||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1,g.push({scope:t,host:(...l)=>l.length?(o===1?n.unshift(...l):l.forEach(_=>_(s)),void 0):s}),c=t(e||void 0);let d=c instanceof DocumentFragment;if(c.nodeName==="#comment")break;let u=y.mark({type:"component",name:t.name,host:d?"this":"parentElement"});c.prepend(u),d&&(s=u);break}case t==="#text":c=P.call(this,document.createTextNode(""),e);break;case(t==="<>"||!t):c=P.call(this,document.createDocumentFragment(),e);break;case!!j:c=P.call(this,document.createElementNS(j,t),e);break;case!c:c=P.call(this,document.createElement(t),e)}return et(c),s||(s=c),n.forEach(d=>d(s)),o&&g.pop(),o=2,c}function Et(t){let e=Symbol.for("default"),n=Array.from(t.querySelectorAll("slot")).reduce((o,c)=>Reflect.set(o,c.name||e,c)&&o,{}),r=Reflect.has(n,e);return t.append=new Proxy(t.append,{apply(o,c,s){if(!s.length)return t;let d=document.createDocumentFragment();for(let u of s){if(!u||!u.slot){r&&d.appendChild(u);continue}let l=u.slot,_=n[l];S(u,"remove","slot"),_&&(_.replaceWith(u),Reflect.deleteProperty(n,l))}return r&&(n[e].replaceWith(d),Reflect.deleteProperty(n,e)),Object.values(n).forEach(u=>u.replaceWith(y().append(...Array.from(u.childNodes)))),t}}),t}y.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=document.createComment(``);return e||(r.end=document.createComment("")),r};function vt(t){let e=this;return function(...r){j=t;let o=y.call(e,...r);return j=void 0,o}}var{setDeleteAttr:I}=$,L=new WeakMap;function P(t,...e){if(!e.length)return t;L.set(t,G(t,this));for(let[n,r]of Object.entries(Object.assign({},...e)))Z.call(this,t,n,r);return L.delete(t),t}function Z(t,e,n){let{setRemoveAttr:r,s:o}=G(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(d,u)=>Z.call(c,t,d,u));let[s]=e;if(s==="=")return r(e.slice(1),n);if(s===".")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 I(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return F(o,n,J.bind(null,t[e]));case"ariaset":return F(o,n,(d,u)=>r("aria-"+d,u));case"classList":return nt.call(c,t,n)}return rt(t,e)?I(t,e,n):r(e,n)}function G(t,e){if(L.has(t))return L.get(t);let r=(t instanceof SVGElement?ct:ot).bind(null,t,"Attribute"),o=C(e);return{setRemoveAttr:r,s:o}}function nt(t,e){let n=C(this);return F(n,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function xt(t){return Array.from(t.children).forEach(e=>e.remove()),t}function S(t,e,n,r){return t instanceof HTMLElement?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function rt(t,e){if(!Reflect.has(t,e))return!1;let n=V(t,e);return!x(n.set)}function V(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||V(t,e)}function F(t,e,n){if(!(typeof e!="object"||e===null))return Object.entries(e).forEach(function([o,c]){o&&(c=t.processReactiveAttribute(e,o,c,n),n(o,c))})}function K(t){return Array.isArray(t)?t.filter(Boolean).join(" "):t}function ot(t,e,n,r){return t[(x(r)?"remove":"set")+e](n,K(r))}function ct(t,e,n,r,o=null){return t[(x(r)?"remove":"set")+e+"NS"](o,n,K(r))}function J(t,e,n){if(Reflect.set(t,e,n),!!x(n))return Reflect.deleteProperty(t,e)}function wt(t,e,n){return e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let s=c.length?new CustomEvent(t,Object.assign({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(s)}}function E(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var D=it(),st=new WeakSet;E.connected=function(t,e){let{custom_element:n}=g.current,r="connected";return typeof e!="object"&&(e={}),e.once=!0,function(c){n&&(c=n);let s="dde:"+r;return c.addEventListener(s,t,e),c.__dde_lifecycleToEvents?c:c.isConnected?(c.dispatchEvent(new Event(s)),c):(N(e.signal,()=>D.offConnected(c,t))&&D.onConnected(c,t),c)}};E.disconnected=function(t,e){let{custom_element:n}=g.current,r="disconnected";return typeof e!="object"&&(e={}),e.once=!0,function(c){n&&(c=n);let s="dde:"+r;return c.addEventListener(s,t,e),c.__dde_lifecycleToEvents||N(e.signal,()=>D.offDisconnected(c,t))&&D.onDisconnected(c,t),c}};var z=new WeakMap;E.disconnectedAsAbort=function(t){if(z.has(t))return z.get(t);let e=new AbortController;return z.set(t,e),t(E.disconnected(()=>e.abort())),e};E.attributeChanged=function(t,e){let n="attributeChanged";return typeof e!="object"&&(e={}),function(o){let c="dde:"+n;if(o.addEventListener(c,t,e),o.__dde_lifecycleToEvents||st.has(o))return o;let s=new MutationObserver(function(u){for(let{attributeName:l,target:_}of u)_.dispatchEvent(new CustomEvent(c,{detail:[l,_.getAttribute(l)]}))});return N(e.signal,()=>s.disconnect())&&s.observe(o,{attributes:!0}),o}};function it(){let t=new Map,e=!1,n=new MutationObserver(function(i){for(let f of i)if(f.type==="childList"){if(l(f.addedNodes,!0)){s();continue}_(f.removedNodes,!0)&&s()}});return{onConnected(i,f){c();let a=o(i);a.connected.has(f)||(a.connected.add(f),a.length_c+=1)},offConnected(i,f){if(!t.has(i))return;let a=t.get(i);a.connected.has(f)&&(a.connected.delete(f),a.length_c-=1,r(i,a))},onDisconnected(i,f){c();let a=o(i);a.disconnected.has(f)||(a.disconnected.add(f),a.length_d+=1)},offDisconnected(i,f){if(!t.has(i))return;let a=t.get(i);a.disconnected.has(f)&&(a.disconnected.delete(f),a.length_d-=1,r(i,a))}};function r(i,f){f.length_c||f.length_d||(t.delete(i),s())}function o(i){if(t.has(i))return t.get(i);let f={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(i,f),f}function c(){e||(e=!0,n.observe(document.body,{childList:!0,subtree:!0}))}function s(){!e||t.size||(e=!1,n.disconnect())}function d(){return new Promise(function(i){(requestIdleCallback||requestAnimationFrame)(i)})}async function u(i){t.size>30&&await d();let f=[];if(!(i instanceof Node))return f;for(let a of t.keys())a===i||!(a instanceof Node)||i.contains(a)&&f.push(a);return f}function l(i,f){let a=!1;for(let m of i){if(f&&u(m).then(l),!t.has(m))continue;let w=t.get(m);w.length_c&&(m.dispatchEvent(new Event("dde:connected")),w.connected=new WeakSet,w.length_c=0,w.length_d||t.delete(m),a=!0)}return a}function _(i,f){let a=!1;for(let m of i)f&&u(m).then(_),!(!t.has(m)||!t.get(m).length_d)&&(m.dispatchEvent(new Event("dde:disconnected")),t.delete(m),a=!0);return a}}var p=Symbol.for("Signal");function W(t){try{return Reflect.has(t,p)}catch{return!1}}var M=[],h=new WeakMap;function b(t,e){if(typeof t!="function")return Q(t,e);if(W(t))return t;let n=Q(),r=function(){let[o,...c]=h.get(r);if(h.set(r,new Set([o])),M.push(r),n(t()),M.pop(),!c.length)return;let s=h.get(r);for(let d of c)s.has(d)||R(d,r)};return h.set(n[p],r),h.set(r,new Set([n])),r(),n}b.action=function(t,e,...n){let r=t[p],{actions:o}=r;if(!o||!Reflect.has(o,e))throw new Error(`'${t}' has no action with name '${e}'!`);if(o[e].apply(r,n),r.skip)return Reflect.deleteProperty(r,"skip");r.listeners.forEach(c=>c(r.value))};b.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));U(e,n),o&&o.addEventListener("abort",()=>R(e,n))}};b.symbols={signal:p,onclear:Symbol.for("Signal.onclear")};b.clear=function(...t){for(let n of t){Reflect.deleteProperty(n,"toJSON");let r=n[p];r.onclear.forEach(o=>o.call(r)),e(n,r),Reflect.deleteProperty(n,p)}function e(n,r){r.listeners.forEach(o=>{if(r.listeners.delete(o),!h.has(o))return;let c=h.get(o);c.delete(n),!(c.size>1)&&(b.clear(...c),h.delete(o))})}};var k="__dde_reactive";b.el=function(t,e){let n=y.mark({type:"reactive"},!1),r=n.end,o=document.createDocumentFragment();o.append(n,r);let{current:c}=g,s=d=>{if(!n.parentNode||!r.parentNode)return R(t,s);g.push(c);let u=e(d);g.pop(),Array.isArray(u)||(u=[u]);let l=n;for(;(l=n.nextSibling)!==r;)l.remove();n.after(...u)};return U(t,s),Y(t,s,n,e),s(t()),o};var O="__dde_attributes";b.attribute=function(t,e=null){let n=b(e),r;return g.host(o=>{if(r=o,S(r,"has",t)?n(S(r,"get",t)):e!==null&&S(r,"set",t,e),o[O]){o[O][t]=n;return}r[O]={[t]:n},E.attributeChanged(function({detail:s}){/*! This maps attributes to signals (`S.attribute`). -* Investigate `__dde_attributes` key of the element.*/let[d,u]=s,l=r[O][d];if(l)return l(u)})(r),E.disconnected(function(){/*! This removes all signals mapped to attributes (`S.attribute`). -* Investigate `__dde_attributes` key of the element.*/b.clear(...Object.values(r[O]))})(r)}),new Proxy(n,{apply(o,c,s){if(!s.length)return o();let d=s[0];return S(r,"set",t,d)}})};var X={isSignal:W,processReactiveAttribute(t,e,n,r){if(!W(n))return n;let o=c=>r(e,c);return U(n,o),Y(n,o,t,e),n()}};function Y(t,e,...n){let{current:r}=g;r.prevent||r.host(function(o){o[k]||(o[k]=[],E.disconnected(()=>o[k].forEach(([[c,s]])=>R(c,s,c[p]?.host()===o)))(o)),o[k].push([[t,e],...n])})}function Q(t,e){let n=(...r)=>r.length?lt(n,...r):dt(n);return ut(n,t,e)}var ft=Object.assign(Object.create(null),{stopPropagation(){this.skip=!0}}),q=class extends Error{constructor(){super();let[e,...n]=this.stack.split(` -`),r=e.slice(e.indexOf("@"),e.indexOf(".js:")+4);this.stack=n.find(o=>!o.includes(r))}};function ut(t,e,n){let r=[];B(n)!=="[object Object]"&&(n={});let{onclear:o}=b.symbols;n[o]&&(r.push(n[o]),Reflect.deleteProperty(n,o));let{host:c}=g;return Reflect.defineProperty(t,p,{value:{value:e,actions:n,onclear:r,host:c,listeners:new Set,defined:new q},enumerable:!1,writable:!1,configurable:!0}),t.toJSON=()=>t(),Object.setPrototypeOf(t[p],ft),t}function at(){return M[M.length-1]}function dt(t){if(!t[p])return;let{value:e,listeners:n}=t[p],r=at();return r&&n.add(r),h.has(r)&&h.get(r).add(t),e}function lt(t,e,n){if(!t[p])return;let r=t[p];if(!(!n&&r.value===e))return r.value=e,r.listeners.forEach(o=>o(e)),e}function U(t,e){if(t[p])return t[p].listeners.add(e)}function R(t,e,n){let r=t[p];if(!r)return;let o=r.listeners.delete(e);if(n&&!r.listeners.size){if(b.clear(t),!h.has(r))return o;let c=h.get(r);if(!h.has(c))return o;h.get(c).forEach(s=>R(s,c,!0))}return o}T(X);export{b as S,P as assign,Z as assignAttribute,et as chainableAppend,nt as classListDeclarative,y as createElement,vt as createElementNS,wt as dispatchEvent,y as el,vt as elNS,S as elementAttribute,xt as empty,W as isSignal,E as on,T as registerReactivity,g as scope,Et as simulateSlots}; diff --git a/dist/esm.d.ts b/dist/esm.d.ts index eab54d6..b5a43b8 100644 --- a/dist/esm.d.ts +++ b/dist/esm.d.ts @@ -153,10 +153,10 @@ export const scope: { preventDefault(prevent: T): T, /** * This represents reference to the current host element — `scope.host()`. - * It can be also used to register Addon (function to be called when component is initized) + * It can be also used to register Addon(s) (functions to be called when component is initized) * — `scope.host(on.connected(console.log))`. * */ - host: ddeElementAddon, + host: (...addons: ddeElementAddon[])=> HTMLElement, state: Scope[], /** Adds new child scope. All attributes are inherited by default. */ diff --git a/dist/esm.js b/dist/esm.js index 7062b14..f2cd11e 100644 --- a/dist/esm.js +++ b/dist/esm.js @@ -1 +1 @@ -var E={isSignal(t){return!1},processReactiveAttribute(t,e,n,c){return n}};function q(t,e=!0){return e?Object.assign(E,t):(Object.setPrototypeOf(t,E),t)}function x(t){return E.isPrototypeOf(t)&&t!==E?t:E}function b(t){return typeof t>"u"}function A(t,e){if(!t||!(t instanceof AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}var S={setDeleteAttr:F,ssr:""};function F(t,e,n){if(Reflect.set(t,e,n),!!b(n)){if(Reflect.deleteProperty(t,e),t instanceof HTMLElement&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var g=[{scope:document.body,host:t=>t?t(document.body):document.body,custom_element:!1,prevent:!0}],v={get current(){return g[g.length-1]},get host(){return this.current.host},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...g]},push(t={}){return g.push(Object.assign({},this.current,{prevent:!1},t))},pushRoot(){return g.push(g[0])},pop(){if(g.length!==1)return g.pop()}};function L(...t){return this.appendOriginal(...t),this}function U(t){return t.append===L||(t.appendOriginal=t.append,t.append=L),t}var O;function C(t,e,...n){let c=x(this),o=0,r,f;switch((Object(e)!==e||c.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1,v.push({scope:t,host:(...l)=>l.length?(o===1?n.unshift(...l):l.forEach(h=>h(f)),void 0):f}),r=t(e||void 0);let d=r instanceof DocumentFragment;if(r.nodeName==="#comment")break;let a=C.mark({type:"component",name:t.name,host:d?"this":"parentElement"});r.prepend(a),d&&(f=a);break}case t==="#text":r=w.call(this,document.createTextNode(""),e);break;case(t==="<>"||!t):r=w.call(this,document.createDocumentFragment(),e);break;case!!O:r=w.call(this,document.createElementNS(O,t),e);break;case!r:r=w.call(this,document.createElement(t),e)}return U(r),f||(f=r),n.forEach(d=>d(f)),o&&v.pop(),o=2,r}function tt(t){let e=Symbol.for("default"),n=Array.from(t.querySelectorAll("slot")).reduce((o,r)=>Reflect.set(o,r.name||e,r)&&o,{}),c=Reflect.has(n,e);return t.append=new Proxy(t.append,{apply(o,r,f){if(!f.length)return t;let d=document.createDocumentFragment();for(let a of f){if(!a||!a.slot){c&&d.appendChild(a);continue}let l=a.slot,h=n[l];B(a,"remove","slot"),h&&(h.replaceWith(a),Reflect.deleteProperty(n,l))}return c&&(n[e].replaceWith(d),Reflect.deleteProperty(n,e)),Object.values(n).forEach(a=>a.replaceWith(C().append(...Array.from(a.childNodes)))),t}}),t}C.mark=function(t,e=!1){t=Object.entries(t).map(([o,r])=>o+`="${r}"`).join(" ");let n=e?"":"/",c=document.createComment(``);return e||(c.end=document.createComment("")),c};function et(t){let e=this;return function(...c){O=t;let o=C.call(e,...c);return O=void 0,o}}var{setDeleteAttr:j}=S,y=new WeakMap;function w(t,...e){if(!e.length)return t;y.set(t,M(t,this));for(let[n,c]of Object.entries(Object.assign({},...e)))W.call(this,t,n,c);return y.delete(t),t}function W(t,e,n){let{setRemoveAttr:c,s:o}=M(t,this),r=this;n=o.processReactiveAttribute(t,e,n,(d,a)=>W.call(r,t,d,a));let[f]=e;if(f==="=")return c(e.slice(1),n);if(f===".")return P(t,e.slice(1),n);if(/(aria|data)([A-Z])/.test(e))return e=e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),c(e,n);switch(e==="className"&&(e="class"),e){case"xlink:href":return c(e,n,"http://www.w3.org/1999/xlink");case"textContent":return j(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return N(o,n,P.bind(null,t[e]));case"ariaset":return N(o,n,(d,a)=>c("aria-"+d,a));case"classList":return z.call(r,t,n)}return k(t,e)?j(t,e,n):c(e,n)}function M(t,e){if(y.has(t))return y.get(t);let c=(t instanceof SVGElement?I:H).bind(null,t,"Attribute"),o=x(e);return{setRemoveAttr:c,s:o}}function z(t,e){let n=x(this);return N(n,e,(c,o)=>t.classList.toggle(c,o===-1?void 0:!!o)),t}function nt(t){return Array.from(t.children).forEach(e=>e.remove()),t}function B(t,e,n,c){return t instanceof HTMLElement?t[e+"Attribute"](n,c):t[e+"AttributeNS"](null,n,c)}function k(t,e){if(!Reflect.has(t,e))return!1;let n=T(t,e);return!b(n.set)}function T(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||T(t,e)}function N(t,e,n){if(!(typeof e!="object"||e===null))return Object.entries(e).forEach(function([o,r]){o&&(r=t.processReactiveAttribute(e,o,r,n),n(o,r))})}function $(t){return Array.isArray(t)?t.filter(Boolean).join(" "):t}function H(t,e,n,c){return t[(b(c)?"remove":"set")+e](n,$(c))}function I(t,e,n,c,o=null){return t[(b(c)?"remove":"set")+e+"NS"](o,n,$(c))}function P(t,e,n){if(Reflect.set(t,e,n),!!b(n))return Reflect.deleteProperty(t,e)}function ct(t,e,n){return e||(e={}),function(o,...r){n&&(r.unshift(o),o=typeof n=="function"?n():n);let f=r.length?new CustomEvent(t,Object.assign({detail:r[0]},e)):new Event(t,e);return o.dispatchEvent(f)}}function _(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var R=G(),Z=new WeakSet;_.connected=function(t,e){let{custom_element:n}=v.current,c="connected";return typeof e!="object"&&(e={}),e.once=!0,function(r){n&&(r=n);let f="dde:"+c;return r.addEventListener(f,t,e),r.__dde_lifecycleToEvents?r:r.isConnected?(r.dispatchEvent(new Event(f)),r):(A(e.signal,()=>R.offConnected(r,t))&&R.onConnected(r,t),r)}};_.disconnected=function(t,e){let{custom_element:n}=v.current,c="disconnected";return typeof e!="object"&&(e={}),e.once=!0,function(r){n&&(r=n);let f="dde:"+c;return r.addEventListener(f,t,e),r.__dde_lifecycleToEvents||A(e.signal,()=>R.offDisconnected(r,t))&&R.onDisconnected(r,t),r}};var D=new WeakMap;_.disconnectedAsAbort=function(t){if(D.has(t))return D.get(t);let e=new AbortController;return D.set(t,e),t(_.disconnected(()=>e.abort())),e};_.attributeChanged=function(t,e){let n="attributeChanged";return typeof e!="object"&&(e={}),function(o){let r="dde:"+n;if(o.addEventListener(r,t,e),o.__dde_lifecycleToEvents||Z.has(o))return o;let f=new MutationObserver(function(a){for(let{attributeName:l,target:h}of a)h.dispatchEvent(new CustomEvent(r,{detail:[l,h.getAttribute(l)]}))});return A(e.signal,()=>f.disconnect())&&f.observe(o,{attributes:!0}),o}};function G(){let t=new Map,e=!1,n=new MutationObserver(function(s){for(let i of s)if(i.type==="childList"){if(l(i.addedNodes,!0)){f();continue}h(i.removedNodes,!0)&&f()}});return{onConnected(s,i){r();let u=o(s);u.connected.has(i)||(u.connected.add(i),u.length_c+=1)},offConnected(s,i){if(!t.has(s))return;let u=t.get(s);u.connected.has(i)&&(u.connected.delete(i),u.length_c-=1,c(s,u))},onDisconnected(s,i){r();let u=o(s);u.disconnected.has(i)||(u.disconnected.add(i),u.length_d+=1)},offDisconnected(s,i){if(!t.has(s))return;let u=t.get(s);u.disconnected.has(i)&&(u.disconnected.delete(i),u.length_d-=1,c(s,u))}};function c(s,i){i.length_c||i.length_d||(t.delete(s),f())}function o(s){if(t.has(s))return t.get(s);let i={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(s,i),i}function r(){e||(e=!0,n.observe(document.body,{childList:!0,subtree:!0}))}function f(){!e||t.size||(e=!1,n.disconnect())}function d(){return new Promise(function(s){(requestIdleCallback||requestAnimationFrame)(s)})}async function a(s){t.size>30&&await d();let i=[];if(!(s instanceof Node))return i;for(let u of t.keys())u===s||!(u instanceof Node)||s.contains(u)&&i.push(u);return i}function l(s,i){let u=!1;for(let p of s){if(i&&a(p).then(l),!t.has(p))continue;let m=t.get(p);m.length_c&&(p.dispatchEvent(new Event("dde:connected")),m.connected=new WeakSet,m.length_c=0,m.length_d||t.delete(p),u=!0)}return u}function h(s,i){let u=!1;for(let p of s)i&&a(p).then(h),!(!t.has(p)||!t.get(p).length_d)&&(p.dispatchEvent(new Event("dde:disconnected")),t.delete(p),u=!0);return u}}export{w as assign,W as assignAttribute,U as chainableAppend,z as classListDeclarative,C as createElement,et as createElementNS,ct as dispatchEvent,C as el,et as elNS,B as elementAttribute,nt as empty,_ as on,q as registerReactivity,v as scope,tt as simulateSlots}; +var v={isObservable(t){return!1},processReactiveAttribute(t,e,n,c){return n}};function q(t,e=!0){return e?Object.assign(v,t):(Object.setPrototypeOf(t,v),t)}function x(t){return v.isPrototypeOf(t)&&t!==v?t:v}function g(t){return typeof t>"u"}function A(t,e){if(!t||!(t instanceof AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}var S={setDeleteAttr:F,ssr:""};function F(t,e,n){if(Reflect.set(t,e,n),!!g(n)){if(Reflect.deleteProperty(t,e),t instanceof HTMLElement&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var b=[{scope:document.body,host:t=>t?t(document.body):document.body,custom_element:!1,prevent:!0}],E={get current(){return b[b.length-1]},get host(){return this.current.host},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...b]},push(t={}){return b.push(Object.assign({},this.current,{prevent:!1},t))},pushRoot(){return b.push(b[0])},pop(){if(b.length!==1)return b.pop()}};function L(...t){return this.appendOriginal(...t),this}function U(t){return t.append===L||(t.appendOriginal=t.append,t.append=L),t}var O;function C(t,e,...n){let c=x(this),o=0,r,f;switch((Object(e)!==e||c.isObservable(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1,E.push({scope:t,host:(...l)=>l.length?(o===1?n.unshift(...l):l.forEach(h=>h(f)),void 0):f}),r=t(e||void 0);let d=r instanceof DocumentFragment;if(r.nodeName==="#comment")break;let a=C.mark({type:"component",name:t.name,host:d?"this":"parentElement"});r.prepend(a),d&&(f=a);break}case t==="#text":r=w.call(this,document.createTextNode(""),e);break;case(t==="<>"||!t):r=w.call(this,document.createDocumentFragment(),e);break;case!!O:r=w.call(this,document.createElementNS(O,t),e);break;case!r:r=w.call(this,document.createElement(t),e)}return U(r),f||(f=r),n.forEach(d=>d(f)),o&&E.pop(),o=2,r}function tt(t){let e=Symbol.for("default"),n=Array.from(t.querySelectorAll("slot")).reduce((o,r)=>Reflect.set(o,r.name||e,r)&&o,{}),c=Reflect.has(n,e);return t.append=new Proxy(t.append,{apply(o,r,f){if(!f.length)return t;let d=document.createDocumentFragment();for(let a of f){if(!a||!a.slot){c&&d.appendChild(a);continue}let l=a.slot,h=n[l];B(a,"remove","slot"),h&&(h.replaceWith(a),Reflect.deleteProperty(n,l))}return c&&(n[e].replaceWith(d),Reflect.deleteProperty(n,e)),Object.values(n).forEach(a=>a.replaceWith(C().append(...Array.from(a.childNodes)))),t}}),t}C.mark=function(t,e=!1){t=Object.entries(t).map(([o,r])=>o+`="${r}"`).join(" ");let n=e?"":"/",c=document.createComment(``);return e||(c.end=document.createComment("")),c};function et(t){let e=this;return function(...c){O=t;let o=C.call(e,...c);return O=void 0,o}}var{setDeleteAttr:j}=S,y=new WeakMap;function w(t,...e){if(!e.length)return t;y.set(t,M(t,this));for(let[n,c]of Object.entries(Object.assign({},...e)))W.call(this,t,n,c);return y.delete(t),t}function W(t,e,n){let{setRemoveAttr:c,s:o}=M(t,this),r=this;n=o.processReactiveAttribute(t,e,n,(d,a)=>W.call(r,t,d,a));let[f]=e;if(f==="=")return c(e.slice(1),n);if(f===".")return P(t,e.slice(1),n);if(/(aria|data)([A-Z])/.test(e))return e=e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),c(e,n);switch(e==="className"&&(e="class"),e){case"xlink:href":return c(e,n,"http://www.w3.org/1999/xlink");case"textContent":return j(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return N(o,n,P.bind(null,t[e]));case"ariaset":return N(o,n,(d,a)=>c("aria-"+d,a));case"classList":return z.call(r,t,n)}return k(t,e)?j(t,e,n):c(e,n)}function M(t,e){if(y.has(t))return y.get(t);let c=(t instanceof SVGElement?I:H).bind(null,t,"Attribute"),o=x(e);return{setRemoveAttr:c,s:o}}function z(t,e){let n=x(this);return N(n,e,(c,o)=>t.classList.toggle(c,o===-1?void 0:!!o)),t}function nt(t){return Array.from(t.children).forEach(e=>e.remove()),t}function B(t,e,n,c){return t instanceof HTMLElement?t[e+"Attribute"](n,c):t[e+"AttributeNS"](null,n,c)}function k(t,e){if(!Reflect.has(t,e))return!1;let n=T(t,e);return!g(n.set)}function T(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||T(t,e)}function N(t,e,n){if(!(typeof e!="object"||e===null))return Object.entries(e).forEach(function([o,r]){o&&(r=t.processReactiveAttribute(e,o,r,n),n(o,r))})}function $(t){return Array.isArray(t)?t.filter(Boolean).join(" "):t}function H(t,e,n,c){return t[(g(c)?"remove":"set")+e](n,$(c))}function I(t,e,n,c,o=null){return t[(g(c)?"remove":"set")+e+"NS"](o,n,$(c))}function P(t,e,n){if(Reflect.set(t,e,n),!!g(n))return Reflect.deleteProperty(t,e)}function ct(t,e,n){return e||(e={}),function(o,...r){n&&(r.unshift(o),o=typeof n=="function"?n():n);let f=r.length?new CustomEvent(t,Object.assign({detail:r[0]},e)):new Event(t,e);return o.dispatchEvent(f)}}function _(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var R=G(),Z=new WeakSet;_.connected=function(t,e){let{custom_element:n}=E.current,c="connected";return typeof e!="object"&&(e={}),e.once=!0,function(r){n&&(r=n);let f="dde:"+c;return r.addEventListener(f,t,e),r.__dde_lifecycleToEvents?r:r.isConnected?(r.dispatchEvent(new Event(f)),r):(A(e.signal,()=>R.offConnected(r,t))&&R.onConnected(r,t),r)}};_.disconnected=function(t,e){let{custom_element:n}=E.current,c="disconnected";return typeof e!="object"&&(e={}),e.once=!0,function(r){n&&(r=n);let f="dde:"+c;return r.addEventListener(f,t,e),r.__dde_lifecycleToEvents||A(e.signal,()=>R.offDisconnected(r,t))&&R.onDisconnected(r,t),r}};var D=new WeakMap;_.disconnectedAsAbort=function(t){if(D.has(t))return D.get(t);let e=new AbortController;return D.set(t,e),t(_.disconnected(()=>e.abort())),e};_.attributeChanged=function(t,e){let n="attributeChanged";return typeof e!="object"&&(e={}),function(o){let r="dde:"+n;if(o.addEventListener(r,t,e),o.__dde_lifecycleToEvents||Z.has(o))return o;let f=new MutationObserver(function(a){for(let{attributeName:l,target:h}of a)h.dispatchEvent(new CustomEvent(r,{detail:[l,h.getAttribute(l)]}))});return A(e.signal,()=>f.disconnect())&&f.observe(o,{attributes:!0}),o}};function G(){let t=new Map,e=!1,n=new MutationObserver(function(s){for(let i of s)if(i.type==="childList"){if(l(i.addedNodes,!0)){f();continue}h(i.removedNodes,!0)&&f()}});return{onConnected(s,i){r();let u=o(s);u.connected.has(i)||(u.connected.add(i),u.length_c+=1)},offConnected(s,i){if(!t.has(s))return;let u=t.get(s);u.connected.has(i)&&(u.connected.delete(i),u.length_c-=1,c(s,u))},onDisconnected(s,i){r();let u=o(s);u.disconnected.has(i)||(u.disconnected.add(i),u.length_d+=1)},offDisconnected(s,i){if(!t.has(s))return;let u=t.get(s);u.disconnected.has(i)&&(u.disconnected.delete(i),u.length_d-=1,c(s,u))}};function c(s,i){i.length_c||i.length_d||(t.delete(s),f())}function o(s){if(t.has(s))return t.get(s);let i={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(s,i),i}function r(){e||(e=!0,n.observe(document.body,{childList:!0,subtree:!0}))}function f(){!e||t.size||(e=!1,n.disconnect())}function d(){return new Promise(function(s){(requestIdleCallback||requestAnimationFrame)(s)})}async function a(s){t.size>30&&await d();let i=[];if(!(s instanceof Node))return i;for(let u of t.keys())u===s||!(u instanceof Node)||s.contains(u)&&i.push(u);return i}function l(s,i){let u=!1;for(let p of s){if(i&&a(p).then(l),!t.has(p))continue;let m=t.get(p);m.length_c&&(p.dispatchEvent(new Event("dde:connected")),m.connected=new WeakSet,m.length_c=0,m.length_d||t.delete(p),u=!0)}return u}function h(s,i){let u=!1;for(let p of s)i&&a(p).then(h),!(!t.has(p)||!t.get(p).length_d)&&(p.dispatchEvent(new Event("dde:disconnected")),t.delete(p),u=!0);return u}}export{w as assign,W as assignAttribute,U as chainableAppend,z as classListDeclarative,C as createElement,et as createElementNS,ct as dispatchEvent,C as el,et as elNS,B as elementAttribute,nt as empty,_ as on,q as registerReactivity,E as scope,tt as simulateSlots}; diff --git a/docs/index.html b/docs/index.html index a6b8772..0c1020e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,5 +1,5 @@ -`deka-dom-el` — Introduction

`deka-dom-el` — Introduction

Introducing a library.

The library tries to provide pure JavaScript tool(s) to create reactive interfaces.

We start with creating and modifying a static elements and end up with UI templates. From document.createElement to el. Then we go through the native events system and the way to include it declaratively in UI templates. From element.addEventListener to on.

Next step is providing interactivity not only for our UI templates. We introduce signals (S) and how them incorporate to UI templates.

Now we will clarify how the signals are incorporated into our templates with regard to application performance. This is not the only reason the library uses scopes. We will look at how they work in components represented in JavaScript by functions.

import { el } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; -import { S } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; +`deka-dom-el` — Introduction

`deka-dom-el` — Introduction

Introducing a library.

The library tries to provide pure JavaScript tool(s) to create reactive interfaces.

We start with creating and modifying a static elements and end up with UI templates. From document.createElement to el. Then we go through the native events system and the way to include it declaratively in UI templates. From element.addEventListener to on.

Next step is providing interactivity not only for our UI templates. We introduce observables (O) and how them incorporate to UI templates.

Now we will clarify how the observables are incorporated into our templates with regard to application performance. This is not the only reason the library uses scopes. We will look at how they work in components represented in JavaScript by functions.

import { el } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js"; +import { S } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js"; const clicks= S(0); document.body.append( el().append( @@ -13,4 +13,4 @@ document.body.append( }) ) ); -
\ No newline at end of file +
\ No newline at end of file diff --git a/docs/p02-elements.html b/docs/p02-elements.html index 4c882e2..4662d87 100644 --- a/docs/p02-elements.html +++ b/docs/p02-elements.html @@ -1,4 +1,4 @@ -`deka-dom-el` — Elements

`deka-dom-el` — Elements

Basic concepts of elements modifications and creations.

Native JavaScript DOM elements creations

Let’s go through all patterns we would like to use and what needs to be improved for better experience.

// when NPM +`deka-dom-el` — Elements

`deka-dom-el` — Elements

Basic concepts of elements modifications and creations.

Native JavaScript DOM elements creations

Let’s go through all patterns we would like to use and what needs to be improved for better experience.

// when NPM import { assign, el, elNS } from "deka-dom-el"; // https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm.js @@ -22,7 +22,7 @@ document.body.append( { textContent: "Element’s text content.", style: "color: coral;" } ) ); -

To make this easier, you can use the el function. Internally in basic examples, it is wrapper around assign(document.createElement(…), { … }).

import { el, assign } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; +

To make this easier, you can use the el function. Internally in basic examples, it is wrapper around assign(document.createElement(…), { … }).

import { el, assign } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js"; const color= "lightcoral"; document.body.append( el("p", { textContent: "Hello (first time)", style: { color } }) @@ -33,7 +33,7 @@ document.body.append( { textContent: "Hello (second time)", style: { color } } ) ); -

The assign function provides improved behaviour of Object.assign(). You can declaratively sets any IDL and attribute of the given element. Function prefers IDL and fallback to the element.setAttribute if there is no writable property in the element prototype.

You can study all JavaScript elements interfaces to the corresponding HTML elements. All HTML elements inherits from HTMLElement. To see all available IDLs for example for paragraphs, see HTMLParagraphElement. Moreover, the assign provides a way to sets declaratively some convenient properties:

  • It is possible to sets data-*/aria-* attributes using object notation.
  • In opposite, it is also possible to sets data-*/aria-* attribute using camelCase notation.
  • You can use string or object as a value for style property.
  • className (IDL – preffered)/class are ways to add CSS class to the element. You can use string (similarly to class="…" syntax in HTML) or array of strings. This is handy to concat conditional classes.
  • Use classList to toggle specific classes. This will be handy later when the reactivity via signals is beeing introduced.
  • The assign also accepts the undefined as a value for any property to remove it from the element declaratively. Also for some IDL the corresponding attribute is removed as it can be confusing. For example, natievly the element’s id is removed by setting the IDL to an empty string.
  • You can use = or . to force processing given key as attribute/property of the element.

For processing, the assign internally uses assignAttribute and classListDeclarative.

import { assign, assignAttribute, classListDeclarative } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; +

The assign function provides improved behaviour of Object.assign(). You can declaratively sets any IDL and attribute of the given element. Function prefers IDL and fallback to the element.setAttribute if there is no writable property in the element prototype.

You can study all JavaScript elements interfaces to the corresponding HTML elements. All HTML elements inherits from HTMLElement. To see all available IDLs for example for paragraphs, see HTMLParagraphElement. Moreover, the assign provides a way to sets declaratively some convenient properties:

  • It is possible to sets data-*/aria-* attributes using object notation.
  • In opposite, it is also possible to sets data-*/aria-* attribute using camelCase notation.
  • You can use string or object as a value for style property.
  • className (IDL – preffered)/class are ways to add CSS class to the element. You can use string (similarly to class="…" syntax in HTML) or array of strings. This is handy to concat conditional classes.
  • Use classList to toggle specific classes. This will be handy later when the reactivity via observables is beeing introduced.
  • The assign also accepts the undefined as a value for any property to remove it from the element declaratively. Also for some IDL the corresponding attribute is removed as it can be confusing. For example, natievly the element’s id is removed by setting the IDL to an empty string.
  • You can use = or . to force processing given key as attribute/property of the element.

For processing, the assign internally uses assignAttribute and classListDeclarative.

import { assign, assignAttribute, classListDeclarative } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js"; const paragraph= document.createElement("p"); assignAttribute(paragraph, "textContent", "Hello, world!"); @@ -66,7 +66,7 @@ console.log("paragraph.something=", paragraph.something); document.body.append( paragraph ); -

# Native JavaScript templating

By default, the native JS has no good way to define HTML template using DOM API:

document.body.append( +

# Native JavaScript templating

By default, the native JS has no good way to define HTML template using DOM API:

document.body.append( document.createElement("div"), document.createElement("span"), document.createElement("main") @@ -77,7 +77,7 @@ const template= document.createElement("main").append( document.createElement("span"), ); console.log(typeof template==="undefined"); -

This library therefore overwrites the append method of created elements to always return parent element.

import { el } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; +

This library therefore overwrites the append method of created elements to always return parent element.

import { el } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js"; document.head.append( el("style").append( "tr, td{ border: 1px solid red; padding: 1em; }", @@ -102,7 +102,7 @@ document.body.append( ) ); -import { chainableAppend } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; +import { chainableAppend } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js"; /** @param {keyof HTMLElementTagNameMap} tag */ const createElement= tag=> chainableAppend(document.createElement(tag)); document.body.append( @@ -112,7 +112,7 @@ document.body.append( ) ) ); -

# Basic (state-less) components

You can use functions for encapsulation (repeating) logic. The el accepts function as first argument. In that case, the function should return dom elements and the second argument for el is argument for given element.

import { el } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; +

# Basic (state-less) components

You can use functions for encapsulation (repeating) logic. The el accepts function as first argument. In that case, the function should return dom elements and the second argument for el is argument for given element.

import { el } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js"; document.head.append( el("style").append( ".class1{ font-weight: bold; }", @@ -129,7 +129,7 @@ function component({ className, textContent }){ el("p", textContent) ); } -

As you can see, in case of state-less/basic components there is no difference between calling component function directly or using el function.

It is nice to use similar naming convention as native DOM API. This allows us to use the destructuring assignment syntax and keep track of the native API (things are best remembered through regular use).

# Creating non-HTML elements

Similarly to the native DOM API (document.createElementNS) for non-HTML elements we need to tell JavaScript which kind of the element to create. We can use the elNS function:

import { elNS, assign } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; +

As you can see, in case of state-less/basic components there is no difference between calling component function directly or using el function.

It is nice to use similar naming convention as native DOM API. This allows us to use the destructuring assignment syntax and keep track of the native API (things are best remembered through regular use).

# Creating non-HTML elements

Similarly to the native DOM API (document.createElementNS) for non-HTML elements we need to tell JavaScript which kind of the element to create. We can use the elNS function:

import { elNS, assign } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js"; const elSVG= elNS("http://www.w3.org/2000/svg"); const elMath= elNS("http://www.w3.org/1998/Math/MathML"); document.body.append( @@ -140,4 +140,4 @@ document.body.append( console.log( document.body.innerHTML.includes("<svg></svg><math></math>") ) -

# Mnemonic

  • assign(<element>, ...<idl-objects>): <element> — assign properties to the element
  • el(<tag-name>, <primitive>)[.append(...)]: <element-from-tag-name> — simple element containing only text
  • el(<tag-name>, <idl-object>)[.append(...)]: <element-from-tag-name> — element with more properties
  • el(<function>, <function-argument(s)>)[.append(...)]: <element-returned-by-function> — using component represented by function
  • el(<...>, <...>, ...<addons>) — see following page
  • elNS(<namespace>)(<as-el-see-above>)[.append(...)]: <element-based-on-arguments> — typically SVG elements
\ No newline at end of file +

# Mnemonic

  • assign(<element>, ...<idl-objects>): <element> — assign properties to the element
  • el(<tag-name>, <primitive>)[.append(...)]: <element-from-tag-name> — simple element containing only text
  • el(<tag-name>, <idl-object>)[.append(...)]: <element-from-tag-name> — element with more properties
  • el(<function>, <function-argument(s)>)[.append(...)]: <element-returned-by-function> — using component represented by function
  • el(<...>, <...>, ...<addons>) — see following page
  • elNS(<namespace>)(<as-el-see-above>)[.append(...)]: <element-based-on-arguments> — typically SVG elements
\ No newline at end of file diff --git a/docs/p03-events.html b/docs/p03-events.html index 693090e..8032733 100644 --- a/docs/p03-events.html +++ b/docs/p03-events.html @@ -1,11 +1,11 @@ -`deka-dom-el` — Events and Addons

`deka-dom-el` — Events and Addons

Using not only events in UI declaratively.

Listenning to the native DOM events and other Addons

We quickly introduce helper to listening to the native DOM events. And library syntax/pattern so-called Addon to incorporate not only this in UI templates declaratively.

// when NPM +`deka-dom-el` — Events and Addons

`deka-dom-el` — Events and Addons

Using not only events in UI declaratively.

Listenning to the native DOM events and other Addons

We quickly introduce helper to listening to the native DOM events. And library syntax/pattern so-called Addon to incorporate not only this in UI templates declaratively.

// when NPM import { on, dispatchEvent } from "deka-dom-el"; // https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm.js /** * @type {ddeElementAddon} * */ -

# Events and listenners

In JavaScript you can listen to the native DOM events of the given element by using element.addEventListener(type, listener, options). The library provides an alternative (on) accepting the differen order of the arguments:

import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; +

# Events and listenners

In JavaScript you can listen to the native DOM events of the given element by using element.addEventListener(type, listener, options). The library provides an alternative (on) accepting the differen order of the arguments:

import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js"; const log= mark=> console.log.bind(console, mark); const button= el("button", "Test click"); @@ -15,7 +15,7 @@ on("click", log("`on`"), { once: true })(button); document.body.append( button ); -

…this is actually one of the two differences. The another one is that on accepts only object as the options (but it is still optional).

The other difference is that there is no off function. You can remove listener declaratively using AbortSignal:

import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; +

…this is actually one of the two differences. The another one is that on accepts only object as the options (but it is still optional).

The other difference is that there is no off function. You can remove listener declaratively using AbortSignal:

import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js"; const log= mark=> console.log.bind(console, mark); const abort_controller= new AbortController(); @@ -28,7 +28,7 @@ on("click", log("`on`"), { signal })(button); document.body.append( button, " ", el("button", { textContent: "Off", onclick: ()=> abort_controller.abort() }) ); -

So, there are (typically) three ways to handle events. You can use:

  • el("button", { textContent: "click me", "=onclick": "console.log(event)" })
  • el("button", { textContent: "click me", onclick: console.log })
  • el("button", { textContent: "click me" }, on("click", console.log))

In the first example we force to use HTML attribute (it corresponds to <button onclick="console.log(event)">click me</button>). Side note: this can be useful in case of SSR. To study difference, you can read a nice summary here: GIST @WebReflection/web_events.md.

# Addons

From practical point of view, Addons are just functions that accept any html element as their first parameter. You can see that the on(…) fullfills this requirement.

You can use Addons as ≥3rd argument of el function. This way is possible to extends you templates by additional (3rd party) functionalities. But for now mainly, you can add events listeners:

import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; +

So, there are (typically) three ways to handle events. You can use:

  • el("button", { textContent: "click me", "=onclick": "console.log(event)" })
  • el("button", { textContent: "click me", onclick: console.log })
  • el("button", { textContent: "click me" }, on("click", console.log))

In the first example we force to use HTML attribute (it corresponds to <button onclick="console.log(event)">click me</button>). Side note: this can be useful in case of SSR. To study difference, you can read a nice summary here: GIST @WebReflection/web_events.md.

# Addons

From practical point of view, Addons are just functions that accept any html element as their first parameter. You can see that the on(…) fullfills this requirement.

You can use Addons as ≥3rd argument of el function. This way is possible to extends you templates by additional (3rd party) functionalities. But for now mainly, you can add events listeners:

import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js"; const abort_controller= new AbortController(); const { signal }= abort_controller; /** @type {ddeElementAddon<HTMLButtonElement>} */ @@ -52,7 +52,7 @@ function update(event){ "\n" ); } -

As the example shows, you can also provide types in JSDoc+TypeScript by using global type ddeElementAddon. Also notice, you can use Addons to get element reference.

# Life-cycle events

Addons are called immediately when the element is created, even it is not connected to live DOM yet. Therefore, you can understand the Addon to be “oncreate” event.

The library provide three additional live-cycle events corresponding to how they are named in a case of custom elements: on.connected, on.disconnected and on.attributeChanged.

import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; +

As the example shows, you can also provide types in JSDoc+TypeScript by using global type ddeElementAddon. Also notice, you can use Addons to get element reference.

# Life-cycle events

Addons are called immediately when the element is created, even it is not connected to live DOM yet. Therefore, you can understand the Addon to be “oncreate” event.

The library provide three additional live-cycle events corresponding to how they are named in a case of custom elements: on.connected, on.disconnected and on.attributeChanged.

import { el, on } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js"; const paragraph= el("p", "See live-cycle events in console.", el=> log({ type: "dde:created", detail: el }), on.connected(log), @@ -70,7 +70,7 @@ document.body.append( function log({ type, detail }){ console.log({ _this: this, type, detail }); } -

For Custom elements, we will later introduce a way to replace *Callback syntax with dde:* events. The on.* functions then listen to the appropriate Custom Elements events (see Custom element lifecycle callbacks | MDN).

But, in case of regular elemnets the MutationObserver | MDN is internaly used to track these events. Therefore, there are some drawbacks:

  • To proper listener registration, you need to use on.* not `on("dde:*", …)`!
  • Use sparingly! Internally, library must loop of all registered events and fires event properly. It is good practice to use the fact that if an element is removed, its children are also removed! In this spirit, we will introduce later the host syntax to register clean up procedures when the component is removed from the app.

# Final notes

The library also provides a method to dispatch the events.

import { el, on, dispatchEvent } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js"; +

For Custom elements, we will later introduce a way to replace *Callback syntax with dde:* events. The on.* functions then listen to the appropriate Custom Elements events (see Custom element lifecycle callbacks | MDN).

But, in case of regular elemnets the MutationObserver | MDN is internaly used to track these events. Therefore, there are some drawbacks:

  • To proper listener registration, you need to use on.* not `on("dde:*", …)`!
  • Use sparingly! Internally, library must loop of all registered events and fires event properly. It is good practice to use the fact that if an element is removed, its children are also removed! In this spirit, we will introduce later the host syntax to register clean up procedures when the component is removed from the app.

# Final notes

The library also provides a method to dispatch the events.

import { el, on, dispatchEvent } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js"; document.body.append( el("p", "Listenning to `test` event.", on("test", console.log)).append( el("br"), @@ -94,4 +94,4 @@ function dde(){ function ddeOptions(){ dispatchEvent("test", { bubbles: true })(this, "hi"); } -

# Mnemonic

  • on(<event>, <listener>[, <options>])(<element>) — just <element>.addEventListener(<event>, <listener>[, <options>])
  • on.<live-cycle>(<event>, <listener>[, <options>])(<element>) — corresponds to custom elemnets callbacks <live-cycle>Callback(...){...}. To connect to custom element see following page, else it is simulated by MutationObserver.
  • dispatchEvent(<event>[, <options>])(element) — just <element>.dispatchEvent(new Event(<event>[, <options>]))
  • dispatchEvent(<event>[, <options>])(element, detail) — just <element>.dispatchEvent(new CustomEvent(<event>, { detail, ...<options> }))
\ No newline at end of file +

# Mnemonic

  • on(<event>, <listener>[, <options>])(<element>) — just <element>.addEventListener(<event>, <listener>[, <options>])
  • on.<live-cycle>(<event>, <listener>[, <options>])(<element>) — corresponds to custom elemnets callbacks <live-cycle>Callback(...){...}. To connect to custom element see following page, else it is simulated by MutationObserver.
  • dispatchEvent(<event>[, <options>])(element) — just <element>.dispatchEvent(new Event(<event>[, <options>]))
  • dispatchEvent(<event>[, <options>])(element, detail) — just <element>.dispatchEvent(new CustomEvent(<event>, { detail, ...<options> }))
\ No newline at end of file diff --git a/docs/p04-observables.html b/docs/p04-observables.html new file mode 100644 index 0000000..7635786 --- /dev/null +++ b/docs/p04-observables.html @@ -0,0 +1,35 @@ +`deka-dom-el` — Observables and reactivity

`deka-dom-el` — Observables and reactivity

Handling reactivity in UI via observables.

Using observables to manage reactivity

How a program responds to variable data or user interactions is one of the fundamental problems of programming. If we desire to solve the issue in a declarative manner, observables may be a viable approach.

// when NPM +import { O } from "deka-dom-el/observables"; +// https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js + +/** + * @type {ddeObservable} + * */ +/** + * @type {ddeActions} + * */ +

# Introducing observables

Using observables, we split program logic into the three parts. Firstly (α), we create a variable (constant) representing reactive value. Somewhere later, we can register (β) a logic reacting to the observable value changes. Similarly, in a remaining part (γ), we can update the observable value.

import { O } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js"; +// α — `observable` represents a reactive value +const observable= O(0); +// β — just reacts on observable changes +O.on(observable, console.log); +// γ — just updates the value +observable(observable()+1); +setInterval(()=> observable(observable()+1), 5000); +

All this is just an example of Event-driven programming and Publish–subscribe pattern (compare for example with fpubsub library). All three parts can be in some manner independent and still connected to the same reactive entity.

Observables are implemented in the library as functions. To see current value of observable, just call it without any arguments console.log(observable()). To update the observable value, pass any argument observable('a new value'). For listenning the observable value changes, use O.on(observable, console.log).

Similarly to the on function to register DOM events listener. You can use AbortController/AbortSignal to off/stop listenning. For representing “live” piece of code computation pattern:

import { O } from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js"; +const observable= O(0); +// computation pattern +const double= O(()=> 2*observable()); + +const ac= new AbortController(); +O.on(observable, v=> console.log("observable", v), { signal: ac.signal }); +O.on(double, v=> console.log("double", v), { signal: ac.signal }); + +observable(observable()+1); +const interval= 5000; +const id= setInterval(()=> observable(observable()+1), interval); +ac.signal.addEventListener("abort", + ()=> setTimeout(()=> clearInterval(id), 2*interval)); + +setTimeout(()=> ac.abort(), 3*interval) +

# Mnemonic

  • O(<value>) — observable: reactive value
  • O(()=> <computation>) — observable: reactive value dependent on calculation using other observables
  • O.on(<observable>, <listener>[, <options>]) — listen to the observable value changes
  • O.clear(...<observables>) — off and clear observables
  • O(<value>, <actions>) — observable: pattern to create complex reactive objects/arrays
  • O.action(<observable>, <action-name>, ...<action-arguments>) — invoke an action for given observable
\ No newline at end of file diff --git a/docs_src/components/example.html.js b/docs_src/components/example.html.js index 8bc87f8..10c3c2b 100644 --- a/docs_src/components/example.html.js +++ b/docs_src/components/example.html.js @@ -26,7 +26,7 @@ import { relative } from "node:path"; export function example({ src, language= "js", page_id }){ registerClientPart(page_id); const content= s.cat(src).toString() - .replaceAll(/ from "deka-dom-el(\/signals)?";/g, ' from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js";'); + .replaceAll(/ from "deka-dom-el(\/observables)?";/g, ' from "https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js";'); const id= "code-example-"+generateCodeId(src); return el().append( el(code, { id, content, language, className: example.name }), diff --git a/docs_src/components/examples/helloWorld.js b/docs_src/components/examples/helloWorld.js index 37d13b1..c687f33 100644 --- a/docs_src/components/examples/helloWorld.js +++ b/docs_src/components/examples/helloWorld.js @@ -1,5 +1,5 @@ import { el } from "deka-dom-el"; -import { S } from "deka-dom-el/signals"; +import { S } from "deka-dom-el/observables"; const clicks= S(0); document.body.append( el().append( diff --git a/docs_src/components/examples/observables/computations-abort.js b/docs_src/components/examples/observables/computations-abort.js new file mode 100644 index 0000000..f504e7d --- /dev/null +++ b/docs_src/components/examples/observables/computations-abort.js @@ -0,0 +1,16 @@ +import { O } from "deka-dom-el/observables"; +const observable= O(0); +// computation pattern +const double= O(()=> 2*observable()); + +const ac= new AbortController(); +O.on(observable, v=> console.log("observable", v), { signal: ac.signal }); +O.on(double, v=> console.log("double", v), { signal: ac.signal }); + +observable(observable()+1); +const interval= 5000; +const id= setInterval(()=> observable(observable()+1), interval); +ac.signal.addEventListener("abort", + ()=> setTimeout(()=> clearInterval(id), 2*interval)); + +setTimeout(()=> ac.abort(), 3*interval) diff --git a/docs_src/components/examples/signals/intro.js b/docs_src/components/examples/observables/intro.js similarity index 57% rename from docs_src/components/examples/signals/intro.js rename to docs_src/components/examples/observables/intro.js index 32dc961..dd6bed6 100644 --- a/docs_src/components/examples/signals/intro.js +++ b/docs_src/components/examples/observables/intro.js @@ -1,9 +1,9 @@ // when NPM -import { S } from "deka-dom-el/signals"; -// https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js +import { O } from "deka-dom-el/observables"; +// https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-observables.js /** - * @type {ddeSignal} + * @type {ddeObservable} * */ /** * @type {ddeActions} diff --git a/docs_src/components/examples/observables/observables.js b/docs_src/components/examples/observables/observables.js new file mode 100644 index 0000000..c1e9d9c --- /dev/null +++ b/docs_src/components/examples/observables/observables.js @@ -0,0 +1,8 @@ +import { O } from "deka-dom-el/observables"; +// α — `observable` represents a reactive value +const observable= O(0); +// β — just reacts on observable changes +O.on(observable, console.log); +// γ — just updates the value +observable(observable()+1); +setInterval(()=> observable(observable()+1), 5000); diff --git a/docs_src/components/examples/signals/computations-abort.js b/docs_src/components/examples/signals/computations-abort.js deleted file mode 100644 index c7702c0..0000000 --- a/docs_src/components/examples/signals/computations-abort.js +++ /dev/null @@ -1,16 +0,0 @@ -import { S } from "deka-dom-el/signals"; -const signal= S(0); -// computation pattern -const double= S(()=> 2*signal()); - -const ac= new AbortController(); -S.on(signal, v=> console.log("signal", v), { signal: ac.signal }); -S.on(double, v=> console.log("double", v), { signal: ac.signal }); - -signal(signal()+1); -const interval= 5000; -const id= setInterval(()=> signal(signal()+1), interval); -ac.signal.addEventListener("abort", - ()=> setTimeout(()=> clearInterval(id), 2*interval)); - -setTimeout(()=> ac.abort(), 3*interval) diff --git a/docs_src/components/examples/signals/signals.js b/docs_src/components/examples/signals/signals.js deleted file mode 100644 index f9b6d52..0000000 --- a/docs_src/components/examples/signals/signals.js +++ /dev/null @@ -1,8 +0,0 @@ -import { S } from "deka-dom-el/signals"; -// α — `signal` represents a reactive value -const signal= S(0); -// β — just reacts on signal changes -S.on(signal, console.log); -// γ — just updates the value -signal(signal()+1); -setInterval(()=> signal(signal()+1), 5000); diff --git a/docs_src/index.html.js b/docs_src/index.html.js index 3b5422c..d3dd2e9 100644 --- a/docs_src/index.html.js +++ b/docs_src/index.html.js @@ -23,10 +23,10 @@ export function page({ pkg, info }){ el("p").append( "Next step is providing interactivity not only for our UI templates.", " ", - "We introduce signals (", el("code", "S"), ") and how them incorporate to UI templates.", + "We introduce observables (", el("code", "O"), ") and how them incorporate to UI templates.", ), el("p").append( - "Now we will clarify how the signals are incorporated into our templates with regard ", + "Now we will clarify how the observables are incorporated into our templates with regard ", "to application performance. This is not the only reason the library uses ", el("code", "scope"), "s. We will look at how they work in components represented ", "in JavaScript by functions." diff --git a/docs_src/p02-elements.html.js b/docs_src/p02-elements.html.js index 469f531..269a5b3 100644 --- a/docs_src/p02-elements.html.js +++ b/docs_src/p02-elements.html.js @@ -64,7 +64,7 @@ export function page({ pkg, info }){ "This is handy to concat conditional classes." ), el("li").append( - "Use ", el("code", "classList"), " to toggle specific classes. This will be handy later when the reactivity via signals is beeing introduced.", + "Use ", el("code", "classList"), " to toggle specific classes. This will be handy later when the reactivity via observables is beeing introduced.", ), el("li").append( "The ", el("code", "assign"), " also accepts the ", el("code", "undefined"), " as a value for any property to remove it from the element declaratively. ", diff --git a/docs_src/p04-signals.html.js b/docs_src/p04-observables.html.js similarity index 57% rename from docs_src/p04-signals.html.js rename to docs_src/p04-observables.html.js index afb943c..988eda5 100644 --- a/docs_src/p04-signals.html.js +++ b/docs_src/p04-observables.html.js @@ -12,24 +12,24 @@ const fileURL= url=> new URL(url, import.meta.url); export function page({ pkg, info }){ const page_id= info.id; return el(simplePage, { info, pkg }).append( - el("h2", "Using signals to manage reactivity"), + el("h2", "Using observables to manage reactivity"), el("p").append( "How a program responds to variable data or user", " interactions is one of the fundamental problems of programming.", " If we desire to solve the issue in a declarative manner,", - " signals may be a viable approach.", + " observables may be a viable approach.", ), - el(code, { src: fileURL("./components/examples/signals/intro.js"), page_id }), + el(code, { src: fileURL("./components/examples/observables/intro.js"), page_id }), - el(h3, "Introducing signals"), + el(h3, "Introducing observables"), el("p").append( - "Using signals, we split program logic into the three parts.", + "Using observables, we split program logic into the three parts.", " Firstly (α), we create a variable (constant) representing reactive", " value. Somewhere later, we can register (β) a logic reacting", - " to the signal value changes. Similarly, in a remaining part (γ), we", - " can update the signal value." + " to the observable value changes. Similarly, in a remaining part (γ), we", + " can update the observable value." ), - el(example, { src: fileURL("./components/examples/signals/signals.js"), page_id }), + el(example, { src: fileURL("./components/examples/observables/observables.js"), page_id }), el("p").append( "All this is just an example of ", el("a", { textContent: "Event-driven programming", href: "https://en.wikipedia.org/wiki/Event-driven_programming", title: "Wikipedia: Event-driven programming" }), @@ -40,35 +40,35 @@ export function page({ pkg, info }){ " to the same reactive entity." ), el("p").append( - "Signals are implemented in the library as functions. To see current value", - " of signal, just call it without any arguments ", el("code", "console.log(signal())"), ".", - " To update the signal value, pass any argument ", el("code", "signal('a new value')"), ".", - " For listenning the signal value changes, use ", el("code", "S.on(signal, console.log)"), "." + "Observables are implemented in the library as functions. To see current value", + " of observable, just call it without any arguments ", el("code", "console.log(observable())"), ".", + " To update the observable value, pass any argument ", el("code", "observable('a new value')"), ".", + " For listenning the observable value changes, use ", el("code", "O.on(observable, console.log)"), "." ), el("p").append( "Similarly to the ", el("code", "on"), " function to register DOM events listener.", " You can use ", el("code", "AbortController"), "/", el("code", "AbortSignal"), " to", " ", el("em", "off"), "/stop listenning. For representing “live” piece of code computation pattern:" ), - el(example, { src: fileURL("./components/examples/signals/computations-abort.js"), page_id }), + el(example, { src: fileURL("./components/examples/observables/computations-abort.js"), page_id }), el(mnemonicUl).append( el("li").append( - el("code", "S()"), " — signal: reactive value", + el("code", "O()"), " — observable: reactive value", ), el("li").append( - el("code", "S(()=> )"), " — signal: reactive value dependent on calculation using other signals", + el("code", "O(()=> )"), " — observable: reactive value dependent on calculation using other observables", ), el("li").append( - el("code", "S.on(, [, ])"), " — listen to the signal value changes", + el("code", "O.on(, [, ])"), " — listen to the observable value changes", ), el("li").append( - el("code", "S.clear(...)"), " — off and clear signals", + el("code", "O.clear(...)"), " — off and clear observables", ), el("li").append( - el("code", "S(, )"), " — signal: pattern to create complex reactive objects/arrays", + el("code", "O(, )"), " — observable: pattern to create complex reactive objects/arrays", ), el("li").append( - el("code", "S.action(, , ...)"), " — invoke an action for given signal" + el("code", "O.action(, , ...)"), " — invoke an action for given observable" ) ), ); diff --git a/docs_src/ssr.js b/docs_src/ssr.js index 8af2919..cb5278c 100644 --- a/docs_src/ssr.js +++ b/docs_src/ssr.js @@ -6,7 +6,7 @@ export const pages= [ { id: "index", href: "./", title: "Introduction", description: "Introducing a library." }, { id: "p02-elements", href: "p02-elements", title: "Elements", description: "Basic concepts of elements modifications and creations." }, { id: "p03-events", href: "p03-events", title: "Events and Addons", description: "Using not only events in UI declaratively." }, - { id: "p04-signals", href: "p04-signals", title: "Signals and reactivity", description: "Handling reactivity in UI via signals." }, + { id: "p04-observables", href: "p04-observables", title: "Observables and reactivity", description: "Handling reactivity in UI via observables." }, ]; /** * @typedef registerClientFile diff --git a/examples/components/fullNameComponent.js b/examples/components/fullNameComponent.js index 22defe7..ecbcfc2 100644 --- a/examples/components/fullNameComponent.js +++ b/examples/components/fullNameComponent.js @@ -1,4 +1,4 @@ -import { style, el, elNS, on, S, scope } from '../exports.js'; +import { style, el, elNS, on, O, scope } from '../exports.js'; const className= style.host(fullNameComponent).css` :host form{ display: flex; @@ -7,8 +7,8 @@ const className= style.host(fullNameComponent).css` `; export function fullNameComponent(){ const labels= [ "Name", "Surname" ]; - const name= labels.map(_=> S("")); - const full_name= S(()=> + const name= labels.map(_=> O("")); + const full_name= O(()=> name.map(l=> l()).filter(Boolean).join(" ") || "-"); scope.host( on.connected(()=> console.log(fullNameComponent)), diff --git a/examples/components/todosComponent.js b/examples/components/todosComponent.js index e6d9c13..55b1e86 100644 --- a/examples/components/todosComponent.js +++ b/examples/components/todosComponent.js @@ -1,4 +1,4 @@ -import { style, el, dispatchEvent, on, S, scope } from '../exports.js'; +import { style, el, dispatchEvent, on, O, scope } from '../exports.js'; const className= style.host(todosComponent).css` :host{ display: flex; @@ -16,23 +16,23 @@ const className= style.host(todosComponent).css` `; /** @param {{ todos: string[] }} */ export function todosComponent({ todos= [ "Task A" ] }= {}){ - const todosS= S(todos.map(t=> S(t)), { - add(v){ this.value.push(S(v)); }, - remove(i){ S.clear(this.value.splice(i, 1)[0]); } + const todosS= O(todos.map(t=> O(t)), { + add(v){ this.value.push(O(v)); }, + remove(i){ O.clear(this.value.splice(i, 1)[0]); } }); const name= "todoName"; const onsubmitAdd= on("submit", event=> { const el= event.target.elements[name]; event.preventDefault(); - S.action(todosS, "add", el.value); + O.action(todosS, "add", el.value); el.value= ""; }); const onremove= on("remove", event=> - S.action(todosS, "remove", event.detail)); + O.action(todosS, "remove", event.detail)); const ul_todos= el("ul").append( - S.el(todosS, ts=> ts + O.el(todosS, ts=> ts .map((textContent, value)=> el(todoComponent, { textContent, value, className }, onremove)) )); @@ -40,7 +40,7 @@ export function todosComponent({ todos= [ "Task A" ] }= {}){ el("div").append( el("h2", "Todos:"), el("h3", "List of todos:"), - S.el(todosS, ts=> !ts.length + O.el(todosS, ts=> !ts.length ? el("p", "No todos yet") : ul_todos), el("p", "Click to the text to edit it.") @@ -54,7 +54,7 @@ export function todosComponent({ todos= [ "Task A" ] }= {}){ ), el("div").append( el("h3", "Output (JSON):"), - el("output", S(()=> JSON.stringify(todosS, null, "\t"))) + el("output", O(()=> JSON.stringify(todosS, null, "\t"))) ) ) } @@ -69,13 +69,13 @@ function todoComponent({ textContent, value }){ event.stopPropagation(); dispatchEvent("remove")(host(), value); }); - const is_editable= S(false); + const is_editable= O(false); const onedited= on("change", ev=> { textContent(ev.target.value); is_editable(false); }); return el("li").append( - S.el(is_editable, is=> is + O.el(is_editable, is=> is ? el("input", { value: textContent(), type: "text" }, onedited) : el("span", { textContent, onclick: is_editable.bind(null, true) }), ), diff --git a/examples/components/webComponent.js b/examples/components/webComponent.js index 7491e39..36a0163 100644 --- a/examples/components/webComponent.js +++ b/examples/components/webComponent.js @@ -1,5 +1,5 @@ import { el, on, scope } from "../../index.js"; -import { S } from "../../signals.js"; +import { O } from "../../observables.js"; /** * Compatible with `npx -y web-component-analyzer examples/components/webComponent.js` @@ -24,8 +24,8 @@ export class CustomHTMLTestElement extends HTMLElement{ on.attributeChanged(e=> console.log(e)), on.disconnected(()=> console.log(CustomHTMLTestElement)) ); - const name= S.attribute("name"); - const preName= S.attribute("pre-name"); + const name= O.attribute("name"); + const preName= O.attribute("pre-name"); console.log({ name, test, preName}); return el("p").append( diff --git a/examples/exports.js b/examples/exports.js index 8c4928f..a05eeae 100644 --- a/examples/exports.js +++ b/examples/exports.js @@ -1,10 +1,10 @@ import * as dde_dom from "../index.js"; export * from "../index.js"; -import * as dde_s from "../signals.js"; -export * from "../signals.js"; +import * as dde_s from "../observables.js"; +export * from "../observables.js"; Object.assign(globalThis, dde_dom, dde_s); -//import * as dde_dom from "../dist/esm-with-signals.js"; -//export * from "../dist/esm-with-signals.js"; +//import * as dde_dom from "../dist/esm-with-observables.js"; +//export * from "../dist/esm-with-observables.js"; //Object.assign(globalThis, dde_dom); export const style= createStyle(); diff --git a/index-with-observables.d.ts b/index-with-observables.d.ts new file mode 100644 index 0000000..e563543 --- /dev/null +++ b/index-with-observables.d.ts @@ -0,0 +1,2 @@ +export * from "./index"; +export * from "./observables"; diff --git a/index-with-observables.js b/index-with-observables.js new file mode 100644 index 0000000..c64e169 --- /dev/null +++ b/index-with-observables.js @@ -0,0 +1,2 @@ +export * from "./index.js"; +export * from "./observables.js"; diff --git a/index-with-signals.d.ts b/index-with-signals.d.ts deleted file mode 100644 index eefb192..0000000 --- a/index-with-signals.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./index"; -export * from "./signals"; diff --git a/index-with-signals.js b/index-with-signals.js deleted file mode 100644 index e969ab0..0000000 --- a/index-with-signals.js +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./index.js"; -export * from "./signals.js"; diff --git a/index.d.ts b/index.d.ts index 14ae9f7..c6bbb02 100644 --- a/index.d.ts +++ b/index.d.ts @@ -152,10 +152,10 @@ export const scope: { preventDefault(prevent: T): T, /** * This represents reference to the current host element — `scope.host()`. - * It can be also used to register Addon (function to be called when component is initized) + * It can be also used to register Addon(s) (functions to be called when component is initized) * — `scope.host(on.connected(console.log))`. * */ - host: ddeElementAddon, + host: (...addons: ddeElementAddon[])=> HTMLElement, state: Scope[], /** Adds new child scope. All attributes are inherited by default. */ diff --git a/observables.d.ts b/observables.d.ts new file mode 100644 index 0000000..7925f4d --- /dev/null +++ b/observables.d.ts @@ -0,0 +1,64 @@ +export type Observable= (set?: V)=> V & A; +type Action= (this: { value: V }, ...a: any[])=> typeof observable._ | void; +type SymbolOnclear= Symbol; +type SymbolObservable= Symbol; +type Actions= Record>; +interface observable{ + _: Symbol + /** + * Simple example: + * ```js + * const hello= S("Hello Observable"); + * ``` + * …simple todo observable: + * ```js + * const todos= S([], { + * add(v){ this.value.push(S(v)); }, + * remove(i){ this.value.splice(i, 1); }, + * [S.symbols.onclear](){ S.clear(...this.value); }, + * }); + * ``` + * …computed observable: + * ```js + * const name= S("Jan"); + * const surname= S("Andrle"); + * const fullname= S(()=> name()+" "+surname()); + * ``` + * @param value Initial observable value. Or function computing value from other observables. + * @param actions Use to define actions on the observable. Such as add item to the array. + * There is also a reserved function `S.symbol.onclear` which is called when the observable is cleared + * by `S.clear`. + * */ + >(value: V, actions?: A): Observable; + /** + * Computations observable. This creates a observable which is computed from other observables. + * */ + (computation: ()=> V): Observable + action>, A extends (S extends Observable ? A : never), N extends keyof A>( + observable: S, + name: N, + ...params: A[N] extends (...args: infer P)=> any ? P : never + ): void; + clear(...observables: Observable[]): void; + on(observable: Observable, onchange: (a: T)=> void, options?: AddEventListenerOptions): void; + symbols: { + observable: SymbolObservable; + onclear: SymbolOnclear; + } + /** + * Reactive element, which is rendered based on the given observable. + * ```js + * S.el(observable, value=> value ? el("b", "True") : el("i", "False")); + * S.el(listS, list=> list.map(li=> el("li", li))); + * ``` + * */ + el(observable: Observable, el: (v: S)=> Element | Element[]): DocumentFragment; + + attribute(name: string, initial?: string): Observable; +} +export const observable: observable; +export const O: observable; +declare global { + type ddeObservable= Observable; + type ddeActions= Actions +} diff --git a/observables.js b/observables.js new file mode 100644 index 0000000..a17edaa --- /dev/null +++ b/observables.js @@ -0,0 +1,4 @@ +export { observable, O, isObservable } from "./src/observables-lib.js"; +import { observables_config } from "./src/observables-lib.js"; +import { registerReactivity } from "./src/observables-common.js"; +registerReactivity(observables_config); diff --git a/package.json b/package.json index bf1c578..8d12ad5 100644 --- a/package.json +++ b/package.json @@ -24,13 +24,13 @@ "import": "./jsdom.js", "types": "./jsdom.d.ts" }, - "./signals": { - "import": "./signals.js", - "types": "./signals.d.ts" + "./observables": { + "import": "./observables.js", + "types": "./observables.d.ts" }, - "./src/signals-lib": { - "import": "./src/signals-lib.js", - "types": "./src/signals.d.ts" + "./src/observables-lib": { + "import": "./src/observables-lib.js", + "types": "./src/observables.d.ts" } }, "files": [ @@ -62,7 +62,7 @@ "gzip": false }, { - "path": "./signals.js", + "path": "./observables.js", "limit": "11.5 kB", "gzip": false }, diff --git a/signals.d.ts b/signals.d.ts deleted file mode 100644 index f3893b8..0000000 --- a/signals.d.ts +++ /dev/null @@ -1,63 +0,0 @@ -export type Signal= (set?: V)=> V & A; -type Action= (this: { value: V }, ...a: any[])=> typeof S._ | void; -type SymbolOnclear= Symbol; -type SymbolSignal= Symbol; -type Actions= Record>; -interface S { - _: Symbol - /** - * Simple example: - * ```js - * const hello= S("Hello Signal"); - * ``` - * …simple todo signal: - * ```js - * const todos= S([], { - * add(v){ this.value.push(S(v)); }, - * remove(i){ this.value.splice(i, 1); }, - * [S.symbols.onclear](){ S.clear(...this.value); }, - * }); - * ``` - * …computed signal: - * ```js - * const name= S("Jan"); - * const surname= S("Andrle"); - * const fullname= S(()=> name()+" "+surname()); - * ``` - * @param value Initial signal value. Or function computing value from other signals. - * @param actions Use to define actions on the signal. Such as add item to the array. - * There is also a reserved function `S.symbol.onclear` which is called when the signal is cleared - * by `S.clear`. - * */ - >(value: V, actions?: A): Signal; - /** - * Computations signal. This creates a signal which is computed from other signals. - * */ - (computation: ()=> V): Signal - action>, A extends (S extends Signal ? A : never), N extends keyof A>( - signal: S, - name: N, - ...params: A[N] extends (...args: infer P)=> any ? P : never - ): void; - clear(...signals: Signal[]): void; - on(signal: Signal, onchange: (a: T)=> void, options?: AddEventListenerOptions): void; - symbols: { - signal: SymbolSignal; - onclear: SymbolOnclear; - } - /** - * Reactive element, which is rendered based on the given signal. - * ```js - * S.el(signal, value=> value ? el("b", "True") : el("i", "False")); - * S.el(listS, list=> list.map(li=> el("li", li))); - * ``` - * */ - el(signal: Signal, el: (v: S)=> Element | Element[]): DocumentFragment; - - attribute(name: string, initial?: string): Signal; -} -export const S: S; -declare global { - type ddeSignal= Signal; - type ddeActions= Actions -} diff --git a/signals.js b/signals.js deleted file mode 100644 index c28bcca..0000000 --- a/signals.js +++ /dev/null @@ -1,4 +0,0 @@ -export { S, isSignal } from "./src/signals-lib.js"; -import { signals_config } from "./src/signals-lib.js"; -import { registerReactivity } from "./src/signals-common.js"; -registerReactivity(signals_config); diff --git a/src/dom.js b/src/dom.js index 7ab5056..2048dac 100644 --- a/src/dom.js +++ b/src/dom.js @@ -1,4 +1,4 @@ -import { signals } from "./signals-common.js"; +import { observables } from "./observables-common.js"; import { enviroment } from './dom-common.js'; /** @type {{ scope: object, prevent: boolean, host: function }[]} */ @@ -32,11 +32,11 @@ export function chainableAppend(el){ if(el.append===append) return el; el.append let namespace; export function createElement(tag, attributes, ...addons){ /* jshint maxcomplexity: 15 */ - const s= signals(this); + const s= observables(this); let scoped= 0; let el, el_host; //TODO Array.isArray(tag) ⇒ set key (cache els) - if(Object(attributes)!==attributes || s.isSignal(attributes)) + if(Object(attributes)!==attributes || s.isObservable(attributes)) attributes= { textContent: attributes }; switch(true){ case typeof tag==="function": { @@ -168,11 +168,11 @@ function assignContext(element, _this){ if(assign_context.has(element)) return assign_context.get(element); const is_svg= element instanceof SVGElement; const setRemoveAttr= (is_svg ? setRemoveNS : setRemove).bind(null, element, "Attribute"); - const s= signals(_this); + const s= observables(_this); return { setRemoveAttr, s }; } export function classListDeclarative(element, toggle){ - const s= signals(this); + const s= observables(this); forEachEntries(s, toggle, (class_name, val)=> element.classList.toggle(class_name, val===-1 ? undefined : Boolean(val))); diff --git a/src/events.js b/src/events.js index 12a93eb..6f743e4 100644 --- a/src/events.js +++ b/src/events.js @@ -1,4 +1,4 @@ -export { registerReactivity } from './signals-common.js'; +export { registerReactivity } from './observables-common.js'; export function dispatchEvent(name, options, host){ if(!options) options= {}; diff --git a/src/observables-common.js b/src/observables-common.js new file mode 100644 index 0000000..e9b5260 --- /dev/null +++ b/src/observables-common.js @@ -0,0 +1,13 @@ +export const observables_global= { + isObservable(attributes){ return false; }, + processReactiveAttribute(obj, key, attr, set){ return attr; }, +}; +export function registerReactivity(def, global= true){ + if(global) return Object.assign(observables_global, def); + Object.setPrototypeOf(def, observables_global); + return def; +} +/** @param {unknown} _this @returns {typeof observables_global} */ +export function observables(_this){ + return observables_global.isPrototypeOf(_this) && _this!==observables_global ? _this : observables_global; +} diff --git a/src/signals-lib.js b/src/observables-lib.js similarity index 53% rename from src/signals-lib.js rename to src/observables-lib.js index 29888bf..02fef99 100644 --- a/src/signals-lib.js +++ b/src/observables-lib.js @@ -1,25 +1,25 @@ -export const mark= Symbol.for("Signal"); +export const mark= Symbol.for("observable"); -export function isSignal(candidate){ +export function isObservable(candidate){ try{ return Reflect.has(candidate, mark); } catch(e){ return false; } } /** @type {function[]} */ const stack_watch= []; /** - * ### `WeakMap>>` - * The `Set` is in the form of `[ source, ...depended signals (DSs) ]`. + * ### `WeakMap>>` + * The `Set` is in the form of `[ source, ...depended observables (DSs) ]`. * When the DS is cleaned (`S.clear`) it is removed from DSs, * if remains only one (`source`) it is cleared too. * ### `WeakMap` * This is used for revesed deps, the `function` is also key for `deps`. - * @type {WeakMap>|function>} + * @type {WeakMap>|function>} * */ const deps= new WeakMap(); -export function S(value, actions){ +export function observable(value, actions){ if(typeof value!=="function") return create(value, actions); - if(isSignal(value)) return value; + if(isObservable(value)) return value; const out= create(); const contextReWatch= function(){ @@ -32,9 +32,9 @@ export function S(value, actions){ if(!deps_old.length) return; const deps_curr= deps.get(contextReWatch); - for (const dep_signal of deps_old){ - if(deps_curr.has(dep_signal)) continue; - removeSignalListener(dep_signal, contextReWatch); + for (const dep_observable of deps_old){ + if(deps_curr.has(dep_observable)) continue; + removeObservableListener(dep_observable, contextReWatch); } }; deps.set(out[mark], contextReWatch); @@ -42,44 +42,45 @@ export function S(value, actions){ contextReWatch(); return out; } -S.action= function(signal, name, ...a){ - const s= signal[mark], { actions }= s; +export { observable as O }; +observable.action= function(observable, name, ...a){ + const s= observable[mark], { actions }= s; if(!actions || !Reflect.has(actions, name)) - throw new Error(`'${signal}' has no action with name '${name}'!`); + throw new Error(`'${observable}' has no action with name '${name}'!`); actions[name].apply(s, a); if(s.skip) return Reflect.deleteProperty(s, "skip"); s.listeners.forEach(l=> l(s.value)); }; -S.on= function on(signals, listener, options= {}){ - const { signal: as }= options; +observable.on= function on(observables, listener, options= {}){ + const { observable: as }= options; if(as && as.aborted) return; - if(Array.isArray(signals)) return signals.forEach(s=> on(s, listener, options)); - addSignalListener(signals, listener); - if(as) as.addEventListener("abort", ()=> removeSignalListener(signals, listener)); - //TODO cleanup when signal removed + if(Array.isArray(observables)) return observables.forEach(s=> on(s, listener, options)); + addObservableListener(observables, listener); + if(as) as.addEventListener("abort", ()=> removeObservableListener(observables, listener)); + //TODO cleanup when observable removed }; -S.symbols= { - signal: mark, - onclear: Symbol.for("Signal.onclear") +observable.symbols= { + observable: mark, + onclear: Symbol.for("Observable.onclear") }; -S.clear= function(...signals){ - for(const signal of signals){ - Reflect.deleteProperty(signal, "toJSON"); - const s= signal[mark]; +observable.clear= function(...observables){ + for(const observable of observables){ + Reflect.deleteProperty(observable, "toJSON"); + const s= observable[mark]; s.onclear.forEach(f=> f.call(s)); - clearListDeps(signal, s); - Reflect.deleteProperty(signal, mark); + clearListDeps(observable, s); + Reflect.deleteProperty(observable, mark); } - function clearListDeps(signal, s){ + function clearListDeps(observable, s){ s.listeners.forEach(l=> { s.listeners.delete(l); if(!deps.has(l)) return; const ls= deps.get(l); - ls.delete(signal); + ls.delete(observable); if(ls.size>1) return; - S.clear(...ls); + observable.clear(...ls); deps.delete(l); }); } @@ -87,7 +88,7 @@ S.clear= function(...signals){ const key_reactive= "__dde_reactive"; import { el, elementAttribute } from "./dom.js"; import { scope } from "./dom.js"; -S.el= function(signal, map){ +observable.el= function(observable, map){ const mark_start= el.mark({ type: "reactive" }, false); const mark_end= mark_start.end; const out= document.createDocumentFragment(); @@ -95,7 +96,7 @@ S.el= function(signal, map){ const { current }= scope; const reRenderReactiveElement= v=> { if(!mark_start.parentNode || !mark_end.parentNode) - return removeSignalListener(signal, reRenderReactiveElement); + return removeObservableListener(observable, reRenderReactiveElement); scope.push(current); let els= map(v); scope.pop(); @@ -106,16 +107,16 @@ S.el= function(signal, map){ el_r.remove(); mark_start.after(...els); }; - addSignalListener(signal, reRenderReactiveElement); - removeSignalsFromElements(signal, reRenderReactiveElement, mark_start, map); - reRenderReactiveElement(signal()); + addObservableListener(observable, reRenderReactiveElement); + removeObservablesFromElements(observable, reRenderReactiveElement, mark_start, map); + reRenderReactiveElement(observable()); return out; }; import { on } from "./events.js"; const key_attributes= "__dde_attributes"; -S.attribute= function(name, initial= null){ +observable.attribute= function(name, initial= null){ //TODO host=element & reuse existing - const out= S(initial); + const out= observable(initial); let element; scope.host(el=> { element= el; @@ -127,17 +128,17 @@ S.attribute= function(name, initial= null){ return; } element[key_attributes]= { [name]: out }; - on.attributeChanged(function attributeChangeToSignal({ detail }){ - /*! This maps attributes to signals (`S.attribute`). + on.attributeChanged(function attributeChangeToObservable({ detail }){ + /*! This maps attributes to observables (`S.attribute`). * Investigate `__dde_attributes` key of the element.*/ const [ name, value ]= detail; const curr= element[key_attributes][name]; if(curr) return curr(value); })(element); on.disconnected(function(){ - /*! This removes all signals mapped to attributes (`S.attribute`). + /*! This removes all observables mapped to attributes (`S.attribute`). * Investigate `__dde_attributes` key of the element.*/ - S.clear(...Object.values(element[key_attributes])); + observable.clear(...Object.values(element[key_attributes])); })(element); }); return new Proxy(out, { @@ -150,17 +151,17 @@ S.attribute= function(name, initial= null){ }; import { typeOf } from './helpers.js'; -export const signals_config= { - isSignal, +export const observables_config= { + isObservable, processReactiveAttribute(element, key, attrs, set){ - if(!isSignal(attrs)) return attrs; + if(!isObservable(attrs)) return attrs; const l= attr=> set(key, attr); - addSignalListener(attrs, l); - removeSignalsFromElements(attrs, l, element, key); + addObservableListener(attrs, l); + removeObservablesFromElements(attrs, l, element, key); return attrs(); } }; -function removeSignalsFromElements(signal, listener, ...notes){ +function removeObservablesFromElements(observable, listener, ...notes){ const { current }= scope; if(current.prevent) return; current.host(function(element){ @@ -168,28 +169,28 @@ function removeSignalsFromElements(signal, listener, ...notes){ element[key_reactive]= []; on.disconnected(()=> /*! - * Clears all signals listeners added in the current scope/host (`S.el`, `assign`, …?). + * Clears all Observables listeners added in the current scope/host (`S.el`, `assign`, …?). * You can investigate the `__dde_reactive` key of the element. * */ - element[key_reactive].forEach(([ [ signal, listener ] ])=> - removeSignalListener(signal, listener, signal[mark]?.host() === element)) + element[key_reactive].forEach(([ [ observable, listener ] ])=> + removeObservableListener(observable, listener, observable[mark]?.host() === element)) )(element); } - element[key_reactive].push([ [ signal, listener ], ...notes ]); + element[key_reactive].push([ [ observable, listener ], ...notes ]); }); } function create(value, actions){ - const signal= (...value)=> - value.length ? write(signal, ...value) : read(signal); - return toSignal(signal, value, actions); + const observable= (...value)=> + value.length ? write(observable, ...value) : read(observable); + return toObservable(observable, value, actions); } const protoSigal= Object.assign(Object.create(null), { stopPropagation(){ this.skip= true; } }); -class SignalDefined extends Error{ +class ObservableDefined extends Error{ constructor(){ super(); const [ curr, ...rest ]= this.stack.split("\n"); @@ -197,64 +198,64 @@ class SignalDefined extends Error{ this.stack= rest.find(l=> !l.includes(curr_file)); } } -function toSignal(signal, value, actions){ +function toObservable(observable, value, actions){ const onclear= []; if(typeOf(actions)!=="[object Object]") actions= {}; - const { onclear: ocs }= S.symbols; + const { onclear: ocs }= observable.symbols; if(actions[ocs]){ onclear.push(actions[ocs]); Reflect.deleteProperty(actions, ocs); } const { host }= scope; - Reflect.defineProperty(signal, mark, { + Reflect.defineProperty(observable, mark, { value: { value, actions, onclear, host, listeners: new Set(), - defined: new SignalDefined() + defined: new ObservableDefined() }, enumerable: false, writable: false, configurable: true }); - signal.toJSON= ()=> signal(); - Object.setPrototypeOf(signal[mark], protoSigal); - return signal; + observable.toJSON= ()=> observable(); + Object.setPrototypeOf(observable[mark], protoSigal); + return observable; } function currentContext(){ return stack_watch[stack_watch.length - 1]; } -function read(signal){ - if(!signal[mark]) return; - const { value, listeners }= signal[mark]; +function read(observable){ + if(!observable[mark]) return; + const { value, listeners }= observable[mark]; const context= currentContext(); if(context) listeners.add(context); - if(deps.has(context)) deps.get(context).add(signal); + if(deps.has(context)) deps.get(context).add(observable); return value; } -function write(signal, value, force){ - if(!signal[mark]) return; - const s= signal[mark]; +function write(observable, value, force){ + if(!observable[mark]) return; + const s= observable[mark]; if(!force && s.value===value) return; s.value= value; s.listeners.forEach(l=> l(value)); return value; } -function addSignalListener(signal, listener){ - if(!signal[mark]) return; - return signal[mark].listeners.add(listener); +function addObservableListener(observable, listener){ + if(!observable[mark]) return; + return observable[mark].listeners.add(listener); } -function removeSignalListener(signal, listener, clear_when_empty){ - const s= signal[mark]; +function removeObservableListener(observable, listener, clear_when_empty){ + const s= observable[mark]; if(!s) return; const out= s.listeners.delete(listener); if(clear_when_empty && !s.listeners.size){ - S.clear(signal); + observable.clear(observable); if(!deps.has(s)) return out; const c= deps.get(s); if(!deps.has(c)) return out; - deps.get(c).forEach(sig=> removeSignalListener(sig, c, true)); + deps.get(c).forEach(sig=> removeObservableListener(sig, c, true)); } return out; } diff --git a/src/signals-common.js b/src/signals-common.js deleted file mode 100644 index abe281a..0000000 --- a/src/signals-common.js +++ /dev/null @@ -1,13 +0,0 @@ -export const signals_global= { - isSignal(attributes){ return false; }, - processReactiveAttribute(obj, key, attr, set){ return attr; }, -}; -export function registerReactivity(def, global= true){ - if(global) return Object.assign(signals_global, def); - Object.setPrototypeOf(def, signals_global); - return def; -} -/** @param {unknown} _this @returns {typeof signals_global} */ -export function signals(_this){ - return signals_global.isPrototypeOf(_this) && _this!==signals_global ? _this : signals_global; -}