From afd09a25dbf84435edd4764d78d9a9e6f762013c Mon Sep 17 00:00:00 2001 From: Jan Andrle Date: Mon, 10 Mar 2025 11:32:21 +0100 Subject: [PATCH] :zap: scope.signal --- dist/esm-with-signals.d.ts | 4 + dist/esm-with-signals.js | 438 ++++++++++++------------ dist/esm-with-signals.min.d.ts | 4 + dist/esm-with-signals.min.js | 6 +- dist/esm.d.ts | 4 + dist/esm.js | 438 ++++++++++++------------ dist/esm.min.d.ts | 4 + dist/esm.min.js | 2 +- dist/iife-with-signals.d.ts | 4 + dist/iife-with-signals.js | 438 ++++++++++++------------ dist/iife-with-signals.min.d.ts | 4 + dist/iife-with-signals.min.js | 8 +- dist/iife.d.ts | 4 + dist/iife.js | 438 ++++++++++++------------ dist/iife.min.d.ts | 4 + dist/iife.min.js | 2 +- docs/components/mnemonic/scopes-init.js | 4 + docs/p08-extensions.html.js | 7 +- index.d.ts | 5 + src/dom.js | 16 + src/events.js | 18 - 21 files changed, 953 insertions(+), 899 deletions(-) diff --git a/dist/esm-with-signals.d.ts b/dist/esm-with-signals.d.ts index cf835a7..9e91b86 100644 --- a/dist/esm-with-signals.d.ts +++ b/dist/esm-with-signals.d.ts @@ -203,6 +203,10 @@ export const scope: { * — `scope.host(on.connected(console.log))`. * */ host: (...addons: ddeElementAddon[]) => HTMLElement; + /** + * Creates/gets an AbortController that triggers when the element disconnects + * */ + signal: AbortSignal; state: Scope[]; /** Adds new child scope. All attributes are inherited by default. */ push(scope?: Partial): ReturnType["push"]>; diff --git a/dist/esm-with-signals.js b/dist/esm-with-signals.js index 53e4de3..4f12834 100644 --- a/dist/esm-with-signals.js +++ b/dist/esm-with-signals.js @@ -111,6 +111,215 @@ var evc = "dde:connected"; var evd = "dde:disconnected"; var eva = "dde:attributeChanged"; +// src/events-observer.js +var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { + get() { + return () => { + }; + } +}); +function connectionsChangesObserverConstructor() { + const store = /* @__PURE__ */ new Map(); + let is_observing = false; + const observerListener = (stop2) => function(mutations) { + for (const mutation of mutations) { + if (mutation.type !== "childList") continue; + if (observerAdded(mutation.addedNodes, true)) { + stop2(); + continue; + } + if (observerRemoved(mutation.removedNodes, true)) + stop2(); + } + }; + const observer = new enviroment.M(observerListener(stop)); + return { + /** + * Creates an observer for a specific element + * @param {Element} element - Element to observe + * @returns {Function} Cleanup function + */ + observe(element) { + const o = new enviroment.M(observerListener(() => { + })); + o.observe(element, { childList: true, subtree: true }); + return () => o.disconnect(); + }, + /** + * Register a connection listener for an element + * @param {Element} element - Element to watch + * @param {Function} listener - Callback for connection event + */ + onConnected(element, listener) { + start(); + const listeners = getElementStore(element); + if (listeners.connected.has(listener)) return; + listeners.connected.add(listener); + listeners.length_c += 1; + }, + /** + * Unregister a connection listener + * @param {Element} element - Element being watched + * @param {Function} listener - Callback to remove + */ + offConnected(element, listener) { + if (!store.has(element)) return; + const ls = store.get(element); + if (!ls.connected.has(listener)) return; + ls.connected.delete(listener); + ls.length_c -= 1; + cleanWhenOff(element, ls); + }, + /** + * Register a disconnection listener for an element + * @param {Element} element - Element to watch + * @param {Function} listener - Callback for disconnection event + */ + onDisconnected(element, listener) { + start(); + const listeners = getElementStore(element); + if (listeners.disconnected.has(listener)) return; + listeners.disconnected.add(listener); + listeners.length_d += 1; + }, + /** + * Unregister a disconnection listener + * @param {Element} element - Element being watched + * @param {Function} listener - Callback to remove + */ + offDisconnected(element, listener) { + if (!store.has(element)) return; + const ls = store.get(element); + ls.disconnected.delete(listener); + ls.length_d -= 1; + cleanWhenOff(element, ls); + } + }; + function cleanWhenOff(element, ls) { + if (ls.length_c || ls.length_d) + return; + store.delete(element); + stop(); + } + function getElementStore(element) { + if (store.has(element)) return store.get(element); + const out = { + connected: /* @__PURE__ */ new WeakSet(), + length_c: 0, + disconnected: /* @__PURE__ */ new WeakSet(), + length_d: 0 + }; + store.set(element, out); + return out; + } + function start() { + if (is_observing) return; + is_observing = true; + observer.observe(enviroment.D.body, { childList: true, subtree: true }); + } + function stop() { + if (!is_observing || store.size) return; + is_observing = false; + observer.disconnect(); + } + function requestIdle() { + return new Promise(function(resolve) { + (requestIdleCallback || requestAnimationFrame)(resolve); + }); + } + async function collectChildren(element) { + if (store.size > 30) + await requestIdle(); + const out = []; + if (!isInstance(element, Node)) return out; + for (const el of store.keys()) { + if (el === element || !isInstance(el, Node)) continue; + if (element.contains(el)) + out.push(el); + } + return out; + } + function observerAdded(addedNodes, is_root) { + let out = false; + for (const element of addedNodes) { + if (is_root) collectChildren(element).then(observerAdded); + if (!store.has(element)) continue; + const ls = store.get(element); + if (!ls.length_c) continue; + element.dispatchEvent(new Event(evc)); + ls.connected = /* @__PURE__ */ new WeakSet(); + ls.length_c = 0; + if (!ls.length_d) store.delete(element); + out = true; + } + return out; + } + function observerRemoved(removedNodes, is_root) { + let out = false; + for (const element of removedNodes) { + if (is_root) collectChildren(element).then(observerRemoved); + if (!store.has(element)) continue; + const ls = store.get(element); + if (!ls.length_d) continue; + (globalThis.queueMicrotask || setTimeout)(dispatchRemove(element)); + out = true; + } + return out; + } + function dispatchRemove(element) { + return () => { + if (element.isConnected) return; + element.dispatchEvent(new Event(evd)); + store.delete(element); + }; + } +} + +// src/events.js +function dispatchEvent(name, options, host) { + if (typeof options === "function") { + host = options; + options = null; + } + if (!options) options = {}; + return function dispatch(element, ...d) { + if (host) { + d.unshift(element); + element = typeof host === "function" ? host() : host; + } + const event = d.length ? new CustomEvent(name, oAssign({ detail: d[0] }, options)) : new Event(name, options); + return element.dispatchEvent(event); + }; +} +function on(event, listener, options) { + return function registerElement(element) { + element.addEventListener(event, listener, options); + return element; + }; +} +var lifeOptions = (obj) => oAssign({}, typeof obj === "object" ? obj : null, { once: true }); +on.connected = function(listener, options) { + options = lifeOptions(options); + return function registerElement(element) { + element.addEventListener(evc, listener, options); + if (element[keyLTE]) return element; + if (element.isConnected) return element.dispatchEvent(new Event(evc)), element; + const c = onAbort(options.signal, () => c_ch_o.offConnected(element, listener)); + if (c) c_ch_o.onConnected(element, listener); + return element; + }; +}; +on.disconnected = function(listener, options) { + options = lifeOptions(options); + return function registerElement(element) { + element.addEventListener(evd, listener, options); + if (element[keyLTE]) return element; + const c = onAbort(options.signal, () => c_ch_o.offDisconnected(element, listener)); + if (c) c_ch_o.onDisconnected(element, listener); + return element; + }; +}; + // src/dom.js function queue(promise) { return enviroment.q(promise); @@ -122,6 +331,7 @@ var scopes = [{ host: (c) => c ? c(enviroment.D.body) : enviroment.D.body, prevent: true }]; +var store_abort = /* @__PURE__ */ new WeakMap(); var scope = { /** * Gets the current scope @@ -138,6 +348,17 @@ var scope = { return this.current.host; }, /** + * Creates/gets an AbortController that triggers when the element disconnects + * */ + get signal() { + const { host } = this; + if (store_abort.has(host)) return store_abort.get(host); + const a = new AbortController(); + store_abort.set(host, a); + host(on.disconnected(() => a.abort())); + return a.signal; + }, + /** * Prevents default behavior in the current scope * @returns {Object} Current scope context */ @@ -380,170 +601,6 @@ function setDelete(obj, key, val) { return Reflect.deleteProperty(obj, key); } -// src/events-observer.js -var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { - get() { - return () => { - }; - } -}); -function connectionsChangesObserverConstructor() { - const store = /* @__PURE__ */ new Map(); - let is_observing = false; - const observerListener = (stop2) => function(mutations) { - for (const mutation of mutations) { - if (mutation.type !== "childList") continue; - if (observerAdded(mutation.addedNodes, true)) { - stop2(); - continue; - } - if (observerRemoved(mutation.removedNodes, true)) - stop2(); - } - }; - const observer = new enviroment.M(observerListener(stop)); - return { - /** - * Creates an observer for a specific element - * @param {Element} element - Element to observe - * @returns {Function} Cleanup function - */ - observe(element) { - const o = new enviroment.M(observerListener(() => { - })); - o.observe(element, { childList: true, subtree: true }); - return () => o.disconnect(); - }, - /** - * Register a connection listener for an element - * @param {Element} element - Element to watch - * @param {Function} listener - Callback for connection event - */ - onConnected(element, listener) { - start(); - const listeners = getElementStore(element); - if (listeners.connected.has(listener)) return; - listeners.connected.add(listener); - listeners.length_c += 1; - }, - /** - * Unregister a connection listener - * @param {Element} element - Element being watched - * @param {Function} listener - Callback to remove - */ - offConnected(element, listener) { - if (!store.has(element)) return; - const ls = store.get(element); - if (!ls.connected.has(listener)) return; - ls.connected.delete(listener); - ls.length_c -= 1; - cleanWhenOff(element, ls); - }, - /** - * Register a disconnection listener for an element - * @param {Element} element - Element to watch - * @param {Function} listener - Callback for disconnection event - */ - onDisconnected(element, listener) { - start(); - const listeners = getElementStore(element); - if (listeners.disconnected.has(listener)) return; - listeners.disconnected.add(listener); - listeners.length_d += 1; - }, - /** - * Unregister a disconnection listener - * @param {Element} element - Element being watched - * @param {Function} listener - Callback to remove - */ - offDisconnected(element, listener) { - if (!store.has(element)) return; - const ls = store.get(element); - ls.disconnected.delete(listener); - ls.length_d -= 1; - cleanWhenOff(element, ls); - } - }; - function cleanWhenOff(element, ls) { - if (ls.length_c || ls.length_d) - return; - store.delete(element); - stop(); - } - function getElementStore(element) { - if (store.has(element)) return store.get(element); - const out = { - connected: /* @__PURE__ */ new WeakSet(), - length_c: 0, - disconnected: /* @__PURE__ */ new WeakSet(), - length_d: 0 - }; - store.set(element, out); - return out; - } - function start() { - if (is_observing) return; - is_observing = true; - observer.observe(enviroment.D.body, { childList: true, subtree: true }); - } - function stop() { - if (!is_observing || store.size) return; - is_observing = false; - observer.disconnect(); - } - function requestIdle() { - return new Promise(function(resolve) { - (requestIdleCallback || requestAnimationFrame)(resolve); - }); - } - async function collectChildren(element) { - if (store.size > 30) - await requestIdle(); - const out = []; - if (!isInstance(element, Node)) return out; - for (const el of store.keys()) { - if (el === element || !isInstance(el, Node)) continue; - if (element.contains(el)) - out.push(el); - } - return out; - } - function observerAdded(addedNodes, is_root) { - let out = false; - for (const element of addedNodes) { - if (is_root) collectChildren(element).then(observerAdded); - if (!store.has(element)) continue; - const ls = store.get(element); - if (!ls.length_c) continue; - element.dispatchEvent(new Event(evc)); - ls.connected = /* @__PURE__ */ new WeakSet(); - ls.length_c = 0; - if (!ls.length_d) store.delete(element); - out = true; - } - return out; - } - function observerRemoved(removedNodes, is_root) { - let out = false; - for (const element of removedNodes) { - if (is_root) collectChildren(element).then(observerRemoved); - if (!store.has(element)) continue; - const ls = store.get(element); - if (!ls.length_d) continue; - (globalThis.queueMicrotask || setTimeout)(dispatchRemove(element)); - out = true; - } - return out; - } - function dispatchRemove(element) { - return () => { - if (element.isConnected) return; - element.dispatchEvent(new Event(evd)); - store.delete(element); - }; - } -} - // src/customElement.js function customElementRender(target, render, props = {}) { const custom_element = target.host || target; @@ -587,59 +644,6 @@ function wrapMethod(obj, method, apply) { }), { apply }); } -// src/events.js -function dispatchEvent(name, options, host) { - if (typeof options === "function") { - host = options; - options = null; - } - if (!options) options = {}; - return function dispatch(element, ...d) { - if (host) { - d.unshift(element); - element = typeof host === "function" ? host() : host; - } - const event = d.length ? new CustomEvent(name, oAssign({ detail: d[0] }, options)) : new Event(name, options); - return element.dispatchEvent(event); - }; -} -function on(event, listener, options) { - return function registerElement(element) { - element.addEventListener(event, listener, options); - return element; - }; -} -var lifeOptions = (obj) => oAssign({}, typeof obj === "object" ? obj : null, { once: true }); -on.connected = function(listener, options) { - options = lifeOptions(options); - return function registerElement(element) { - element.addEventListener(evc, listener, options); - if (element[keyLTE]) return element; - if (element.isConnected) return element.dispatchEvent(new Event(evc)), element; - const c = onAbort(options.signal, () => c_ch_o.offConnected(element, listener)); - if (c) c_ch_o.onConnected(element, listener); - return element; - }; -}; -on.disconnected = function(listener, options) { - options = lifeOptions(options); - return function registerElement(element) { - element.addEventListener(evd, listener, options); - if (element[keyLTE]) return element; - const c = onAbort(options.signal, () => c_ch_o.offDisconnected(element, listener)); - if (c) c_ch_o.onDisconnected(element, listener); - return element; - }; -}; -var store_abort = /* @__PURE__ */ new WeakMap(); -on.disconnectedAsAbort = function(host) { - if (store_abort.has(host)) return store_abort.get(host); - const a = new AbortController(); - store_abort.set(host, a); - host(on.disconnected(() => a.abort())); - return a.signal; -}; - // src/signals-lib/helpers.js var mark = "__dde_signal"; var queueSignalWrite = /* @__PURE__ */ (() => { diff --git a/dist/esm-with-signals.min.d.ts b/dist/esm-with-signals.min.d.ts index cf835a7..9e91b86 100644 --- a/dist/esm-with-signals.min.d.ts +++ b/dist/esm-with-signals.min.d.ts @@ -203,6 +203,10 @@ export const scope: { * — `scope.host(on.connected(console.log))`. * */ host: (...addons: ddeElementAddon[]) => HTMLElement; + /** + * Creates/gets an AbortController that triggers when the element disconnects + * */ + signal: AbortSignal; state: Scope[]; /** Adds new child scope. All attributes are inherited by default. */ push(scope?: Partial): ReturnType["push"]>; diff --git a/dist/esm-with-signals.min.js b/dist/esm-with-signals.min.js index 9def1af..676ca71 100644 --- a/dist/esm-with-signals.min.js +++ b/dist/esm-with-signals.min.js @@ -1,4 +1,4 @@ var B=(...t)=>Object.prototype.hasOwnProperty.call(...t);function O(t){return typeof t>"u"}function et(t){let e=typeof t;return e!=="object"?e:t===null?"null":Object.prototype.toString.call(t)}function S(t,e){return t instanceof e}function nt(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function w(t=null,e={}){return Object.create(t,e)}function b(...t){return Object.assign(...t)}function J(t,e){if(!t||!S(t,AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}function rt(t,e){let{observedAttributes:n=[]}=t.constructor;return n.reduce(function(r,o){return r[vt(o)]=e(t,o),r},{})}function vt(t){return t.replace(/-./g,e=>e[1].toUpperCase())}var P=class extends Error{constructor(){super();let[e,...n]=this.stack.split(` -`),r=e.slice(e.indexOf("@"),e.indexOf(".js:")+4),o=r.includes("src/helpers.js")?"src/":r;this.stack=n.find(c=>!c.includes(o))||e}get compact(){let{stack:e}=this;return e.slice(0,e.indexOf("@")+1)+"\u2026"+e.slice(e.lastIndexOf("/"))}};var q={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function Z(t,e=!0){return e?b(q,t):(Object.setPrototypeOf(t,q),t)}function W(t){return nt(t,q)&&t!==q?t:q}var d={setDeleteAttr:bt,ssr:"",D:globalThis.document,F:globalThis.DocumentFragment,H:globalThis.HTMLElement,S:globalThis.SVGElement,M:globalThis.MutationObserver,q:t=>t||Promise.resolve()};function bt(t,e,n){if(Reflect.set(t,e,n),!!O(n)){if(Reflect.deleteProperty(t,e),S(t,d.H)&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var N="__dde_lifecyclesToEvents",y="dde:connected",D="dde:disconnected",F="dde:attributeChanged";function zt(t){return d.q(t)}var C=[{get scope(){return d.D.body},host:t=>t?t(d.D.body):d.D.body,prevent:!0}],x={get current(){return C[C.length-1]},get host(){return this.current.host},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...C]},push(t={}){return C.push(b({},this.current,{prevent:!1},t))},pushRoot(){return C.push(C[0])},pop(){if(C.length!==1)return C.pop()}};function ot(...t){return this.appendOriginal(...t),this}function xt(t){return t.append===ot||(t.appendOriginal=t.append,t.append=ot),t}var $;function j(t,e,...n){let r=W(this),o=0,c,s;switch((Object(e)!==e||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let i=(...h)=>h.length?(o===1?n.unshift(...h):h.forEach(v=>v(s)),void 0):s;x.push({scope:t,host:i}),c=t(e||void 0);let p=S(c,d.F);if(c.nodeName==="#comment")break;let E=j.mark({type:"component",name:t.name,host:p?"this":"parentElement"});c.prepend(E),p&&(s=E);break}case t==="#text":c=I.call(this,d.D.createTextNode(""),e);break;case(t==="<>"||!t):c=I.call(this,d.D.createDocumentFragment(),e);break;case!!$:c=I.call(this,d.D.createElementNS($,t),e);break;case!c:c=I.call(this,d.D.createElement(t),e)}return xt(c),s||(s=c),n.forEach(i=>i(s)),o&&x.pop(),o=2,c}j.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=d.D.createComment(``);return e&&(r.end=d.D.createComment("")),r};function Ht(t){let e=this;return function(...r){$=t;let o=j.call(e,...r);return $=void 0,o}}function Bt(t,e=t){let n="\xB9\u2070",r="\u2713",o=Object.fromEntries(Array.from(e.querySelectorAll("slot")).filter(c=>!c.name.endsWith(n)).map(c=>[c.name+=n,c]));if(t.append=new Proxy(t.append,{apply(c,s,i){if(i[0]===e)return c.apply(t,i);for(let p of i){let E=(p.slot||"")+n;try{_t(p,"remove","slot")}catch{}let h=o[E];if(!h)return;h.name.startsWith(r)||(h.childNodes.forEach(v=>v.remove()),h.name=r+E),h.append(p)}return t.append=c,t}}),t!==e){let c=Array.from(t.childNodes);t.append(...c)}return e}var U=new WeakMap,{setDeleteAttr:ct}=d;function I(t,...e){if(!e.length)return t;U.set(t,ut(t,this));for(let[n,r]of Object.entries(b({},...e)))it.call(this,t,n,r);return U.delete(t),t}function it(t,e,n){let{setRemoveAttr:r,s:o}=ut(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(i,p)=>it.call(c,t,i,p));let[s]=e;if(s==="=")return r(e.slice(1),n);if(s===".")return st(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 ct(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return G(o,e,t,n,st.bind(null,t[e]));case"ariaset":return G(o,e,t,n,(i,p)=>r("aria-"+i,p));case"classList":return Et.call(c,t,n)}return St(t,e)?ct(t,e,n):r(e,n)}function ut(t,e){if(U.has(t))return U.get(t);let r=(S(t,d.S)?At:wt).bind(null,t,"Attribute"),o=W(e);return{setRemoveAttr:r,s:o}}function Et(t,e){let n=W(this);return G(n,"classList",t,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function _t(t,e,n,r){return S(t,d.H)?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function St(t,e){if(!(e in t))return!1;let n=ft(t,e);return!O(n.set)}function ft(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||ft(t,e)}function G(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([i,p]){i&&(i=new c(i),i.target=e,p=t.processReactiveAttribute(n,i,p,o),o(i,p))})}function wt(t,e,n,r){return t[(O(r)?"remove":"set")+e](n,r)}function At(t,e,n,r,o=null){return t[(O(r)?"remove":"set")+e+"NS"](o,n,r)}function st(t,e,n){if(Reflect.set(t,e,n),!!O(n))return Reflect.deleteProperty(t,e)}var R=d.M?yt():new Proxy({},{get(){return()=>{}}});function yt(){let t=new Map,e=!1,n=u=>function(a){for(let f of a)if(f.type==="childList"){if(h(f.addedNodes,!0)){u();continue}v(f.removedNodes,!0)&&u()}},r=new d.M(n(i));return{observe(u){let a=new d.M(n(()=>{}));return a.observe(u,{childList:!0,subtree:!0}),()=>a.disconnect()},onConnected(u,a){s();let f=c(u);f.connected.has(a)||(f.connected.add(a),f.length_c+=1)},offConnected(u,a){if(!t.has(u))return;let f=t.get(u);f.connected.has(a)&&(f.connected.delete(a),f.length_c-=1,o(u,f))},onDisconnected(u,a){s();let f=c(u);f.disconnected.has(a)||(f.disconnected.add(a),f.length_d+=1)},offDisconnected(u,a){if(!t.has(u))return;let f=t.get(u);f.disconnected.delete(a),f.length_d-=1,o(u,f)}};function o(u,a){a.length_c||a.length_d||(t.delete(u),i())}function c(u){if(t.has(u))return t.get(u);let a={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(u,a),a}function s(){e||(e=!0,r.observe(d.D.body,{childList:!0,subtree:!0}))}function i(){!e||t.size||(e=!1,r.disconnect())}function p(){return new Promise(function(u){(requestIdleCallback||requestAnimationFrame)(u)})}async function E(u){t.size>30&&await p();let a=[];if(!S(u,Node))return a;for(let f of t.keys())f===u||!S(f,Node)||u.contains(f)&&a.push(f);return a}function h(u,a){let f=!1;for(let _ of u){if(a&&E(_).then(h),!t.has(_))continue;let M=t.get(_);M.length_c&&(_.dispatchEvent(new Event(y)),M.connected=new WeakSet,M.length_c=0,M.length_d||t.delete(_),f=!0)}return f}function v(u,a){let f=!1;for(let _ of u)a&&E(_).then(v),!(!t.has(_)||!t.get(_).length_d)&&((globalThis.queueMicrotask||setTimeout)(T(_)),f=!0);return f}function T(u){return()=>{u.isConnected||(u.dispatchEvent(new Event(D)),t.delete(u))}}}function Yt(t,e,n={}){let r=t.host||t;x.push({scope:r,host:(...s)=>s.length?s.forEach(i=>i(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[N];o||Ct(r);let c=e.call(r,n);return o||r.dispatchEvent(new Event(y)),t.nodeType===11&&typeof t.mode=="string"&&r.addEventListener(D,R.observe(t),{once:!0}),x.pop(),t.append(c)}function Ct(t){return V(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(y))}),V(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(D)))}),V(t.prototype,"attributeChangedCallback",function(e,n,r){let[o,,c]=r;n.dispatchEvent(new CustomEvent(F,{detail:[o,c]})),e.apply(n,r)}),t.prototype[N]=!0,t}function V(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}function re(t,e,n){return typeof e=="function"&&(n=e,e=null),e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let s=c.length?new CustomEvent(t,b({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(s)}}function A(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var at=t=>b({},typeof t=="object"?t:null,{once:!0});A.connected=function(t,e){return e=at(e),function(r){return r.addEventListener(y,t,e),r[N]?r:r.isConnected?(r.dispatchEvent(new Event(y)),r):(J(e.signal,()=>R.offConnected(r,t))&&R.onConnected(r,t),r)}};A.disconnected=function(t,e){return e=at(e),function(r){return r.addEventListener(D,t,e),r[N]||J(e.signal,()=>R.offDisconnected(r,t))&&R.onDisconnected(r,t),r}};var K=new WeakMap;A.disconnectedAsAbort=function(t){if(K.has(t))return K.get(t);let e=new AbortController;return K.set(t,e),t(A.disconnected(()=>e.abort())),e.signal};var l="__dde_signal",Q=(()=>{let t=new Set,e=!1;function n(){e=!1;let r=t;t=new Set;for(let o of r){let c=o[l];c&&c.listeners.forEach(s=>s(c.value))}}return function(r){t.add(r),!e&&(e=!0,queueMicrotask(n))}})();var Y=w(null,{get:{value(){return lt(this)}},set:{value(...t){return mt(this,...t)}},toJSON:{value(){return lt(this)}},valueOf:{value(){return this[l]&&this[l].value}}}),Ot=w(Y,{set:{value(){}}});function z(t){return t&&t[l]}var H=[],m=new WeakMap;function g(t,e){if(typeof t!="function")return dt(!1,t,e);if(z(t))return t;let n=dt(!0);function r(){let[o,...c]=m.get(r);if(m.set(r,new Set([o])),H.push(r),mt(n,t()),H.pop(),!c.length)return;let s=m.get(r);for(let i of c)s.has(i)||k(i,r)}return m.set(n[l],r),m.set(r,new Set([n])),r(),n}g.action=function(t,e,...n){let r=t[l];if(!r)return;let{actions:o}=r;if(!o||!B(o,e))throw new Error(`Action "${e}" not defined. See ${l}.actions.`);if(o[e].apply(r,n),r.skip)return delete r.skip;Q(t)};g.on=function t(e,n,r={}){let{signal:o}=r;if(!(o&&o.aborted)){if(Array.isArray(e))return e.forEach(c=>t(c,n,r));tt(e,n),o&&o.addEventListener("abort",()=>k(e,n))}};g.symbols={onclear:Symbol.for("Signal.onclear")};g.clear=function(...t){for(let n of t){let r=n[l];r&&(delete n.toJSON,r.onclear.forEach(o=>o.call(r)),e(n,r),delete n[l])}function e(n,r){r.listeners.forEach(o=>{if(r.listeners.delete(o),!m.has(o))return;let c=m.get(o);c.delete(n),!(c.size>1)&&(n.clear(...c),m.delete(o))})}};var L="__dde_reactive";function Dt(t=w()){return(e,n)=>B(t,e)?t[e]:t[e]=n()}g.el=function(t,e){let n=j.mark({type:"reactive",source:new P().compact},!0),r=n.end,o=d.D.createDocumentFragment();o.append(n,r);let{current:c}=x,s=w(),i=p=>{if(!n.parentNode||!r.parentNode)return k(t,i);let E=Dt(s);s=w(),x.push(c);let h=e(p,function(a,f){return s[a]=E(a,f)});x.pop(),Array.isArray(h)||(h=[h]);let v=document.createComment("");h.push(v),n.after(...h);let T;for(;(T=v.nextSibling)&&T!==r;)T.remove();v.remove(),n.isConnected&&Rt(c.host())};return tt(t,i),ht(t,i,n,e),i(t.get()),c.host(A.disconnected(()=>s={})),o};function Rt(t){!t||!t[L]||(requestIdleCallback||setTimeout)(function(){t[L]=t[L].filter(([e,n])=>n.isConnected?!0:(k(...e),!1))})}var Lt={_set(t){this.value=t}};function kt(t){return function(e,n){let r=w(Y,{set:{value(...c){return e.setAttribute(n,...c)}}}),o=gt(r,e.getAttribute(n),Lt);return t[n]=o,o}}var X="__dde_attributes";g.observedAttributes=function(t){let e=t[X]={},n=rt(t,kt(e));return A(F,function({detail:o}){/*! This maps attributes to signals (`S.observedAttributes`). - Investigate `__dde_attributes` key of the element. */let[c,s]=o,i=this[X][c];if(i)return g.action(i,"_set",s)})(t),A.disconnected(function(){/*! This removes all signals mapped to attributes (`S.observedAttributes`). - Investigate `__dde_attributes` key of the element. */g.clear(...Object.values(this[X]))})(t),n};var pt={isSignal:z,processReactiveAttribute(t,e,n,r){if(!z(n))return n;let o=c=>{if(!t.isConnected)return k(n,o);r(e,c)};return tt(n,o),ht(n,o,t,e),n.get()}};function ht(t,e,...n){let{current:r}=x;r.host(function(o){if(o[L])return o[L].push([[t,e],...n]);o[L]=[],!r.prevent&&A.disconnected(()=>o[L].forEach(([[c,s]])=>k(c,s,c[l]&&c[l].host&&c[l].host()===o)))(o)})}var Nt=new FinalizationRegistry(function(t){g.clear({[l]:t})});function dt(t,e,n){let r=w(t?Ot:Y),o=gt(r,e,n,t);return Nt.register(o,o[l]),o}var Tt=b(w(),{stopPropagation(){this.skip=!0}});function gt(t,e,n,r=!1){let o=[];et(n)!=="[object Object]"&&(n={});let{onclear:c}=g.symbols;n[c]&&(o.push(n[c]),delete n[c]);let{host:s}=x;return Reflect.defineProperty(t,l,{value:b(w(Tt),{value:e,actions:n,onclear:o,host:s,listeners:new Set,defined:new P().stack,readonly:r}),enumerable:!1,writable:!1,configurable:!0}),t}function Mt(){return H[H.length-1]}function lt(t){if(!t[l])return;let{value:e,listeners:n}=t[l],r=Mt();return r&&n.add(r),m.has(r)&&m.get(r).add(t),e}function mt(t,e,n){let r=t[l];if(!(!r||!n&&r.value===e))return r.value=e,Q(t),e}function tt(t,e){if(t[l])return t[l].listeners.add(e)}function k(t,e,n){let r=t[l];if(!r)return;let{listeners:o}=r,c=o.delete(e);if(!c||!n||o.size)return c;g.clear(t);let s=m.get(r);if(!s)return c;let i=m.get(s);if(!i)return c;for(let p of i)k(p,s,!0);return c}Z(pt);export{g as S,I as assign,it as assignAttribute,xt as chainableAppend,Et as classListDeclarative,j as createElement,Ht as createElementNS,Yt as customElementRender,Ct as customElementWithDDE,re as dispatchEvent,j as el,Ht as elNS,_t as elementAttribute,z as isSignal,Ct as lifecyclesToEvents,A as on,zt as queue,Z as registerReactivity,x as scope,g as signal,Bt as simulateSlots}; +`),r=e.slice(e.indexOf("@"),e.indexOf(".js:")+4),o=r.includes("src/helpers.js")?"src/":r;this.stack=n.find(c=>!c.includes(o))||e}get compact(){let{stack:e}=this;return e.slice(0,e.indexOf("@")+1)+"\u2026"+e.slice(e.lastIndexOf("/"))}};var q={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function Z(t,e=!0){return e?b(q,t):(Object.setPrototypeOf(t,q),t)}function W(t){return nt(t,q)&&t!==q?t:q}var d={setDeleteAttr:bt,ssr:"",D:globalThis.document,F:globalThis.DocumentFragment,H:globalThis.HTMLElement,S:globalThis.SVGElement,M:globalThis.MutationObserver,q:t=>t||Promise.resolve()};function bt(t,e,n){if(Reflect.set(t,e,n),!!O(n)){if(Reflect.deleteProperty(t,e),S(t,d.H)&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var N="__dde_lifecyclesToEvents",A="dde:connected",D="dde:disconnected",F="dde:attributeChanged";var R=d.M?xt():new Proxy({},{get(){return()=>{}}});function xt(){let t=new Map,e=!1,n=u=>function(a){for(let f of a)if(f.type==="childList"){if(h(f.addedNodes,!0)){u();continue}v(f.removedNodes,!0)&&u()}},r=new d.M(n(i));return{observe(u){let a=new d.M(n(()=>{}));return a.observe(u,{childList:!0,subtree:!0}),()=>a.disconnect()},onConnected(u,a){s();let f=c(u);f.connected.has(a)||(f.connected.add(a),f.length_c+=1)},offConnected(u,a){if(!t.has(u))return;let f=t.get(u);f.connected.has(a)&&(f.connected.delete(a),f.length_c-=1,o(u,f))},onDisconnected(u,a){s();let f=c(u);f.disconnected.has(a)||(f.disconnected.add(a),f.length_d+=1)},offDisconnected(u,a){if(!t.has(u))return;let f=t.get(u);f.disconnected.delete(a),f.length_d-=1,o(u,f)}};function o(u,a){a.length_c||a.length_d||(t.delete(u),i())}function c(u){if(t.has(u))return t.get(u);let a={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(u,a),a}function s(){e||(e=!0,r.observe(d.D.body,{childList:!0,subtree:!0}))}function i(){!e||t.size||(e=!1,r.disconnect())}function p(){return new Promise(function(u){(requestIdleCallback||requestAnimationFrame)(u)})}async function E(u){t.size>30&&await p();let a=[];if(!S(u,Node))return a;for(let f of t.keys())f===u||!S(f,Node)||u.contains(f)&&a.push(f);return a}function h(u,a){let f=!1;for(let _ of u){if(a&&E(_).then(h),!t.has(_))continue;let M=t.get(_);M.length_c&&(_.dispatchEvent(new Event(A)),M.connected=new WeakSet,M.length_c=0,M.length_d||t.delete(_),f=!0)}return f}function v(u,a){let f=!1;for(let _ of u)a&&E(_).then(v),!(!t.has(_)||!t.get(_).length_d)&&((globalThis.queueMicrotask||setTimeout)(T(_)),f=!0);return f}function T(u){return()=>{u.isConnected||(u.dispatchEvent(new Event(D)),t.delete(u))}}}function Bt(t,e,n){return typeof e=="function"&&(n=e,e=null),e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let s=c.length?new CustomEvent(t,b({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(s)}}function y(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var ot=t=>b({},typeof t=="object"?t:null,{once:!0});y.connected=function(t,e){return e=ot(e),function(r){return r.addEventListener(A,t,e),r[N]?r:r.isConnected?(r.dispatchEvent(new Event(A)),r):(J(e.signal,()=>R.offConnected(r,t))&&R.onConnected(r,t),r)}};y.disconnected=function(t,e){return e=ot(e),function(r){return r.addEventListener(D,t,e),r[N]||J(e.signal,()=>R.offDisconnected(r,t))&&R.onDisconnected(r,t),r}};function Yt(t){return d.q(t)}var C=[{get scope(){return d.D.body},host:t=>t?t(d.D.body):d.D.body,prevent:!0}],G=new WeakMap,x={get current(){return C[C.length-1]},get host(){return this.current.host},get signal(){let{host:t}=this;if(G.has(t))return G.get(t);let e=new AbortController;return G.set(t,e),t(y.disconnected(()=>e.abort())),e.signal},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...C]},push(t={}){return C.push(b({},this.current,{prevent:!1},t))},pushRoot(){return C.push(C[0])},pop(){if(C.length!==1)return C.pop()}};function ct(...t){return this.appendOriginal(...t),this}function Et(t){return t.append===ct||(t.appendOriginal=t.append,t.append=ct),t}var $;function j(t,e,...n){let r=W(this),o=0,c,s;switch((Object(e)!==e||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let i=(...h)=>h.length?(o===1?n.unshift(...h):h.forEach(v=>v(s)),void 0):s;x.push({scope:t,host:i}),c=t(e||void 0);let p=S(c,d.F);if(c.nodeName==="#comment")break;let E=j.mark({type:"component",name:t.name,host:p?"this":"parentElement"});c.prepend(E),p&&(s=E);break}case t==="#text":c=I.call(this,d.D.createTextNode(""),e);break;case(t==="<>"||!t):c=I.call(this,d.D.createDocumentFragment(),e);break;case!!$:c=I.call(this,d.D.createElementNS($,t),e);break;case!c:c=I.call(this,d.D.createElement(t),e)}return Et(c),s||(s=c),n.forEach(i=>i(s)),o&&x.pop(),o=2,c}j.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=d.D.createComment(``);return e&&(r.end=d.D.createComment("")),r};function te(t){let e=this;return function(...r){$=t;let o=j.call(e,...r);return $=void 0,o}}function ee(t,e=t){let n="\xB9\u2070",r="\u2713",o=Object.fromEntries(Array.from(e.querySelectorAll("slot")).filter(c=>!c.name.endsWith(n)).map(c=>[c.name+=n,c]));if(t.append=new Proxy(t.append,{apply(c,s,i){if(i[0]===e)return c.apply(t,i);for(let p of i){let E=(p.slot||"")+n;try{St(p,"remove","slot")}catch{}let h=o[E];if(!h)return;h.name.startsWith(r)||(h.childNodes.forEach(v=>v.remove()),h.name=r+E),h.append(p)}return t.append=c,t}}),t!==e){let c=Array.from(t.childNodes);t.append(...c)}return e}var U=new WeakMap,{setDeleteAttr:st}=d;function I(t,...e){if(!e.length)return t;U.set(t,ft(t,this));for(let[n,r]of Object.entries(b({},...e)))ut.call(this,t,n,r);return U.delete(t),t}function ut(t,e,n){let{setRemoveAttr:r,s:o}=ft(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(i,p)=>ut.call(c,t,i,p));let[s]=e;if(s==="=")return r(e.slice(1),n);if(s===".")return it(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 st(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return V(o,e,t,n,it.bind(null,t[e]));case"ariaset":return V(o,e,t,n,(i,p)=>r("aria-"+i,p));case"classList":return _t.call(c,t,n)}return wt(t,e)?st(t,e,n):r(e,n)}function ft(t,e){if(U.has(t))return U.get(t);let r=(S(t,d.S)?At:yt).bind(null,t,"Attribute"),o=W(e);return{setRemoveAttr:r,s:o}}function _t(t,e){let n=W(this);return V(n,"classList",t,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function St(t,e,n,r){return S(t,d.H)?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function wt(t,e){if(!(e in t))return!1;let n=at(t,e);return!O(n.set)}function at(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||at(t,e)}function V(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([i,p]){i&&(i=new c(i),i.target=e,p=t.processReactiveAttribute(n,i,p,o),o(i,p))})}function yt(t,e,n,r){return t[(O(r)?"remove":"set")+e](n,r)}function At(t,e,n,r,o=null){return t[(O(r)?"remove":"set")+e+"NS"](o,n,r)}function it(t,e,n){if(Reflect.set(t,e,n),!!O(n))return Reflect.deleteProperty(t,e)}function se(t,e,n={}){let r=t.host||t;x.push({scope:r,host:(...s)=>s.length?s.forEach(i=>i(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[N];o||Ct(r);let c=e.call(r,n);return o||r.dispatchEvent(new Event(A)),t.nodeType===11&&typeof t.mode=="string"&&r.addEventListener(D,R.observe(t),{once:!0}),x.pop(),t.append(c)}function Ct(t){return K(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(A))}),K(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(D)))}),K(t.prototype,"attributeChangedCallback",function(e,n,r){let[o,,c]=r;n.dispatchEvent(new CustomEvent(F,{detail:[o,c]})),e.apply(n,r)}),t.prototype[N]=!0,t}function K(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}var l="__dde_signal",Q=(()=>{let t=new Set,e=!1;function n(){e=!1;let r=t;t=new Set;for(let o of r){let c=o[l];c&&c.listeners.forEach(s=>s(c.value))}}return function(r){t.add(r),!e&&(e=!0,queueMicrotask(n))}})();var Y=w(null,{get:{value(){return lt(this)}},set:{value(...t){return mt(this,...t)}},toJSON:{value(){return lt(this)}},valueOf:{value(){return this[l]&&this[l].value}}}),Ot=w(Y,{set:{value(){}}});function z(t){return t&&t[l]}var H=[],m=new WeakMap;function g(t,e){if(typeof t!="function")return dt(!1,t,e);if(z(t))return t;let n=dt(!0);function r(){let[o,...c]=m.get(r);if(m.set(r,new Set([o])),H.push(r),mt(n,t()),H.pop(),!c.length)return;let s=m.get(r);for(let i of c)s.has(i)||k(i,r)}return m.set(n[l],r),m.set(r,new Set([n])),r(),n}g.action=function(t,e,...n){let r=t[l];if(!r)return;let{actions:o}=r;if(!o||!B(o,e))throw new Error(`Action "${e}" not defined. See ${l}.actions.`);if(o[e].apply(r,n),r.skip)return delete r.skip;Q(t)};g.on=function t(e,n,r={}){let{signal:o}=r;if(!(o&&o.aborted)){if(Array.isArray(e))return e.forEach(c=>t(c,n,r));tt(e,n),o&&o.addEventListener("abort",()=>k(e,n))}};g.symbols={onclear:Symbol.for("Signal.onclear")};g.clear=function(...t){for(let n of t){let r=n[l];r&&(delete n.toJSON,r.onclear.forEach(o=>o.call(r)),e(n,r),delete n[l])}function e(n,r){r.listeners.forEach(o=>{if(r.listeners.delete(o),!m.has(o))return;let c=m.get(o);c.delete(n),!(c.size>1)&&(n.clear(...c),m.delete(o))})}};var L="__dde_reactive";function Dt(t=w()){return(e,n)=>B(t,e)?t[e]:t[e]=n()}g.el=function(t,e){let n=j.mark({type:"reactive",source:new P().compact},!0),r=n.end,o=d.D.createDocumentFragment();o.append(n,r);let{current:c}=x,s=w(),i=p=>{if(!n.parentNode||!r.parentNode)return k(t,i);let E=Dt(s);s=w(),x.push(c);let h=e(p,function(a,f){return s[a]=E(a,f)});x.pop(),Array.isArray(h)||(h=[h]);let v=document.createComment("");h.push(v),n.after(...h);let T;for(;(T=v.nextSibling)&&T!==r;)T.remove();v.remove(),n.isConnected&&Rt(c.host())};return tt(t,i),ht(t,i,n,e),i(t.get()),c.host(y.disconnected(()=>s={})),o};function Rt(t){!t||!t[L]||(requestIdleCallback||setTimeout)(function(){t[L]=t[L].filter(([e,n])=>n.isConnected?!0:(k(...e),!1))})}var Lt={_set(t){this.value=t}};function kt(t){return function(e,n){let r=w(Y,{set:{value(...c){return e.setAttribute(n,...c)}}}),o=gt(r,e.getAttribute(n),Lt);return t[n]=o,o}}var X="__dde_attributes";g.observedAttributes=function(t){let e=t[X]={},n=rt(t,kt(e));return y(F,function({detail:o}){/*! This maps attributes to signals (`S.observedAttributes`). + Investigate `__dde_attributes` key of the element. */let[c,s]=o,i=this[X][c];if(i)return g.action(i,"_set",s)})(t),y.disconnected(function(){/*! This removes all signals mapped to attributes (`S.observedAttributes`). + Investigate `__dde_attributes` key of the element. */g.clear(...Object.values(this[X]))})(t),n};var pt={isSignal:z,processReactiveAttribute(t,e,n,r){if(!z(n))return n;let o=c=>{if(!t.isConnected)return k(n,o);r(e,c)};return tt(n,o),ht(n,o,t,e),n.get()}};function ht(t,e,...n){let{current:r}=x;r.host(function(o){if(o[L])return o[L].push([[t,e],...n]);o[L]=[],!r.prevent&&y.disconnected(()=>o[L].forEach(([[c,s]])=>k(c,s,c[l]&&c[l].host&&c[l].host()===o)))(o)})}var Nt=new FinalizationRegistry(function(t){g.clear({[l]:t})});function dt(t,e,n){let r=w(t?Ot:Y),o=gt(r,e,n,t);return Nt.register(o,o[l]),o}var Tt=b(w(),{stopPropagation(){this.skip=!0}});function gt(t,e,n,r=!1){let o=[];et(n)!=="[object Object]"&&(n={});let{onclear:c}=g.symbols;n[c]&&(o.push(n[c]),delete n[c]);let{host:s}=x;return Reflect.defineProperty(t,l,{value:b(w(Tt),{value:e,actions:n,onclear:o,host:s,listeners:new Set,defined:new P().stack,readonly:r}),enumerable:!1,writable:!1,configurable:!0}),t}function Mt(){return H[H.length-1]}function lt(t){if(!t[l])return;let{value:e,listeners:n}=t[l],r=Mt();return r&&n.add(r),m.has(r)&&m.get(r).add(t),e}function mt(t,e,n){let r=t[l];if(!(!r||!n&&r.value===e))return r.value=e,Q(t),e}function tt(t,e){if(t[l])return t[l].listeners.add(e)}function k(t,e,n){let r=t[l];if(!r)return;let{listeners:o}=r,c=o.delete(e);if(!c||!n||o.size)return c;g.clear(t);let s=m.get(r);if(!s)return c;let i=m.get(s);if(!i)return c;for(let p of i)k(p,s,!0);return c}Z(pt);export{g as S,I as assign,ut as assignAttribute,Et as chainableAppend,_t as classListDeclarative,j as createElement,te as createElementNS,se as customElementRender,Ct as customElementWithDDE,Bt as dispatchEvent,j as el,te as elNS,St as elementAttribute,z as isSignal,Ct as lifecyclesToEvents,y as on,Yt as queue,Z as registerReactivity,x as scope,g as signal,ee as simulateSlots}; diff --git a/dist/esm.d.ts b/dist/esm.d.ts index cdb2000..09e90e7 100644 --- a/dist/esm.d.ts +++ b/dist/esm.d.ts @@ -202,6 +202,10 @@ export const scope: { * — `scope.host(on.connected(console.log))`. * */ host: (...addons: ddeElementAddon[]) => HTMLElement; + /** + * Creates/gets an AbortController that triggers when the element disconnects + * */ + signal: AbortSignal; state: Scope[]; /** Adds new child scope. All attributes are inherited by default. */ push(scope?: Partial): ReturnType["push"]>; diff --git a/dist/esm.js b/dist/esm.js index 857673a..df77eb0 100644 --- a/dist/esm.js +++ b/dist/esm.js @@ -78,6 +78,215 @@ var evc = "dde:connected"; var evd = "dde:disconnected"; var eva = "dde:attributeChanged"; +// src/events-observer.js +var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { + get() { + return () => { + }; + } +}); +function connectionsChangesObserverConstructor() { + const store = /* @__PURE__ */ new Map(); + let is_observing = false; + const observerListener = (stop2) => function(mutations) { + for (const mutation of mutations) { + if (mutation.type !== "childList") continue; + if (observerAdded(mutation.addedNodes, true)) { + stop2(); + continue; + } + if (observerRemoved(mutation.removedNodes, true)) + stop2(); + } + }; + const observer = new enviroment.M(observerListener(stop)); + return { + /** + * Creates an observer for a specific element + * @param {Element} element - Element to observe + * @returns {Function} Cleanup function + */ + observe(element) { + const o = new enviroment.M(observerListener(() => { + })); + o.observe(element, { childList: true, subtree: true }); + return () => o.disconnect(); + }, + /** + * Register a connection listener for an element + * @param {Element} element - Element to watch + * @param {Function} listener - Callback for connection event + */ + onConnected(element, listener) { + start(); + const listeners = getElementStore(element); + if (listeners.connected.has(listener)) return; + listeners.connected.add(listener); + listeners.length_c += 1; + }, + /** + * Unregister a connection listener + * @param {Element} element - Element being watched + * @param {Function} listener - Callback to remove + */ + offConnected(element, listener) { + if (!store.has(element)) return; + const ls = store.get(element); + if (!ls.connected.has(listener)) return; + ls.connected.delete(listener); + ls.length_c -= 1; + cleanWhenOff(element, ls); + }, + /** + * Register a disconnection listener for an element + * @param {Element} element - Element to watch + * @param {Function} listener - Callback for disconnection event + */ + onDisconnected(element, listener) { + start(); + const listeners = getElementStore(element); + if (listeners.disconnected.has(listener)) return; + listeners.disconnected.add(listener); + listeners.length_d += 1; + }, + /** + * Unregister a disconnection listener + * @param {Element} element - Element being watched + * @param {Function} listener - Callback to remove + */ + offDisconnected(element, listener) { + if (!store.has(element)) return; + const ls = store.get(element); + ls.disconnected.delete(listener); + ls.length_d -= 1; + cleanWhenOff(element, ls); + } + }; + function cleanWhenOff(element, ls) { + if (ls.length_c || ls.length_d) + return; + store.delete(element); + stop(); + } + function getElementStore(element) { + if (store.has(element)) return store.get(element); + const out = { + connected: /* @__PURE__ */ new WeakSet(), + length_c: 0, + disconnected: /* @__PURE__ */ new WeakSet(), + length_d: 0 + }; + store.set(element, out); + return out; + } + function start() { + if (is_observing) return; + is_observing = true; + observer.observe(enviroment.D.body, { childList: true, subtree: true }); + } + function stop() { + if (!is_observing || store.size) return; + is_observing = false; + observer.disconnect(); + } + function requestIdle() { + return new Promise(function(resolve) { + (requestIdleCallback || requestAnimationFrame)(resolve); + }); + } + async function collectChildren(element) { + if (store.size > 30) + await requestIdle(); + const out = []; + if (!isInstance(element, Node)) return out; + for (const el of store.keys()) { + if (el === element || !isInstance(el, Node)) continue; + if (element.contains(el)) + out.push(el); + } + return out; + } + function observerAdded(addedNodes, is_root) { + let out = false; + for (const element of addedNodes) { + if (is_root) collectChildren(element).then(observerAdded); + if (!store.has(element)) continue; + const ls = store.get(element); + if (!ls.length_c) continue; + element.dispatchEvent(new Event(evc)); + ls.connected = /* @__PURE__ */ new WeakSet(); + ls.length_c = 0; + if (!ls.length_d) store.delete(element); + out = true; + } + return out; + } + function observerRemoved(removedNodes, is_root) { + let out = false; + for (const element of removedNodes) { + if (is_root) collectChildren(element).then(observerRemoved); + if (!store.has(element)) continue; + const ls = store.get(element); + if (!ls.length_d) continue; + (globalThis.queueMicrotask || setTimeout)(dispatchRemove(element)); + out = true; + } + return out; + } + function dispatchRemove(element) { + return () => { + if (element.isConnected) return; + element.dispatchEvent(new Event(evd)); + store.delete(element); + }; + } +} + +// src/events.js +function dispatchEvent(name, options, host) { + if (typeof options === "function") { + host = options; + options = null; + } + if (!options) options = {}; + return function dispatch(element, ...d) { + if (host) { + d.unshift(element); + element = typeof host === "function" ? host() : host; + } + const event = d.length ? new CustomEvent(name, oAssign({ detail: d[0] }, options)) : new Event(name, options); + return element.dispatchEvent(event); + }; +} +function on(event, listener, options) { + return function registerElement(element) { + element.addEventListener(event, listener, options); + return element; + }; +} +var lifeOptions = (obj) => oAssign({}, typeof obj === "object" ? obj : null, { once: true }); +on.connected = function(listener, options) { + options = lifeOptions(options); + return function registerElement(element) { + element.addEventListener(evc, listener, options); + if (element[keyLTE]) return element; + if (element.isConnected) return element.dispatchEvent(new Event(evc)), element; + const c = onAbort(options.signal, () => c_ch_o.offConnected(element, listener)); + if (c) c_ch_o.onConnected(element, listener); + return element; + }; +}; +on.disconnected = function(listener, options) { + options = lifeOptions(options); + return function registerElement(element) { + element.addEventListener(evd, listener, options); + if (element[keyLTE]) return element; + const c = onAbort(options.signal, () => c_ch_o.offDisconnected(element, listener)); + if (c) c_ch_o.onDisconnected(element, listener); + return element; + }; +}; + // src/dom.js function queue(promise) { return enviroment.q(promise); @@ -89,6 +298,7 @@ var scopes = [{ host: (c) => c ? c(enviroment.D.body) : enviroment.D.body, prevent: true }]; +var store_abort = /* @__PURE__ */ new WeakMap(); var scope = { /** * Gets the current scope @@ -105,6 +315,17 @@ var scope = { return this.current.host; }, /** + * Creates/gets an AbortController that triggers when the element disconnects + * */ + get signal() { + const { host } = this; + if (store_abort.has(host)) return store_abort.get(host); + const a = new AbortController(); + store_abort.set(host, a); + host(on.disconnected(() => a.abort())); + return a.signal; + }, + /** * Prevents default behavior in the current scope * @returns {Object} Current scope context */ @@ -347,170 +568,6 @@ function setDelete(obj, key, val) { return Reflect.deleteProperty(obj, key); } -// src/events-observer.js -var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { - get() { - return () => { - }; - } -}); -function connectionsChangesObserverConstructor() { - const store = /* @__PURE__ */ new Map(); - let is_observing = false; - const observerListener = (stop2) => function(mutations) { - for (const mutation of mutations) { - if (mutation.type !== "childList") continue; - if (observerAdded(mutation.addedNodes, true)) { - stop2(); - continue; - } - if (observerRemoved(mutation.removedNodes, true)) - stop2(); - } - }; - const observer = new enviroment.M(observerListener(stop)); - return { - /** - * Creates an observer for a specific element - * @param {Element} element - Element to observe - * @returns {Function} Cleanup function - */ - observe(element) { - const o = new enviroment.M(observerListener(() => { - })); - o.observe(element, { childList: true, subtree: true }); - return () => o.disconnect(); - }, - /** - * Register a connection listener for an element - * @param {Element} element - Element to watch - * @param {Function} listener - Callback for connection event - */ - onConnected(element, listener) { - start(); - const listeners = getElementStore(element); - if (listeners.connected.has(listener)) return; - listeners.connected.add(listener); - listeners.length_c += 1; - }, - /** - * Unregister a connection listener - * @param {Element} element - Element being watched - * @param {Function} listener - Callback to remove - */ - offConnected(element, listener) { - if (!store.has(element)) return; - const ls = store.get(element); - if (!ls.connected.has(listener)) return; - ls.connected.delete(listener); - ls.length_c -= 1; - cleanWhenOff(element, ls); - }, - /** - * Register a disconnection listener for an element - * @param {Element} element - Element to watch - * @param {Function} listener - Callback for disconnection event - */ - onDisconnected(element, listener) { - start(); - const listeners = getElementStore(element); - if (listeners.disconnected.has(listener)) return; - listeners.disconnected.add(listener); - listeners.length_d += 1; - }, - /** - * Unregister a disconnection listener - * @param {Element} element - Element being watched - * @param {Function} listener - Callback to remove - */ - offDisconnected(element, listener) { - if (!store.has(element)) return; - const ls = store.get(element); - ls.disconnected.delete(listener); - ls.length_d -= 1; - cleanWhenOff(element, ls); - } - }; - function cleanWhenOff(element, ls) { - if (ls.length_c || ls.length_d) - return; - store.delete(element); - stop(); - } - function getElementStore(element) { - if (store.has(element)) return store.get(element); - const out = { - connected: /* @__PURE__ */ new WeakSet(), - length_c: 0, - disconnected: /* @__PURE__ */ new WeakSet(), - length_d: 0 - }; - store.set(element, out); - return out; - } - function start() { - if (is_observing) return; - is_observing = true; - observer.observe(enviroment.D.body, { childList: true, subtree: true }); - } - function stop() { - if (!is_observing || store.size) return; - is_observing = false; - observer.disconnect(); - } - function requestIdle() { - return new Promise(function(resolve) { - (requestIdleCallback || requestAnimationFrame)(resolve); - }); - } - async function collectChildren(element) { - if (store.size > 30) - await requestIdle(); - const out = []; - if (!isInstance(element, Node)) return out; - for (const el of store.keys()) { - if (el === element || !isInstance(el, Node)) continue; - if (element.contains(el)) - out.push(el); - } - return out; - } - function observerAdded(addedNodes, is_root) { - let out = false; - for (const element of addedNodes) { - if (is_root) collectChildren(element).then(observerAdded); - if (!store.has(element)) continue; - const ls = store.get(element); - if (!ls.length_c) continue; - element.dispatchEvent(new Event(evc)); - ls.connected = /* @__PURE__ */ new WeakSet(); - ls.length_c = 0; - if (!ls.length_d) store.delete(element); - out = true; - } - return out; - } - function observerRemoved(removedNodes, is_root) { - let out = false; - for (const element of removedNodes) { - if (is_root) collectChildren(element).then(observerRemoved); - if (!store.has(element)) continue; - const ls = store.get(element); - if (!ls.length_d) continue; - (globalThis.queueMicrotask || setTimeout)(dispatchRemove(element)); - out = true; - } - return out; - } - function dispatchRemove(element) { - return () => { - if (element.isConnected) return; - element.dispatchEvent(new Event(evd)); - store.delete(element); - }; - } -} - // src/customElement.js function customElementRender(target, render, props = {}) { const custom_element = target.host || target; @@ -553,59 +610,6 @@ function wrapMethod(obj, method, apply) { obj[method] = new Proxy(obj[method] || (() => { }), { apply }); } - -// src/events.js -function dispatchEvent(name, options, host) { - if (typeof options === "function") { - host = options; - options = null; - } - if (!options) options = {}; - return function dispatch(element, ...d) { - if (host) { - d.unshift(element); - element = typeof host === "function" ? host() : host; - } - const event = d.length ? new CustomEvent(name, oAssign({ detail: d[0] }, options)) : new Event(name, options); - return element.dispatchEvent(event); - }; -} -function on(event, listener, options) { - return function registerElement(element) { - element.addEventListener(event, listener, options); - return element; - }; -} -var lifeOptions = (obj) => oAssign({}, typeof obj === "object" ? obj : null, { once: true }); -on.connected = function(listener, options) { - options = lifeOptions(options); - return function registerElement(element) { - element.addEventListener(evc, listener, options); - if (element[keyLTE]) return element; - if (element.isConnected) return element.dispatchEvent(new Event(evc)), element; - const c = onAbort(options.signal, () => c_ch_o.offConnected(element, listener)); - if (c) c_ch_o.onConnected(element, listener); - return element; - }; -}; -on.disconnected = function(listener, options) { - options = lifeOptions(options); - return function registerElement(element) { - element.addEventListener(evd, listener, options); - if (element[keyLTE]) return element; - const c = onAbort(options.signal, () => c_ch_o.offDisconnected(element, listener)); - if (c) c_ch_o.onDisconnected(element, listener); - return element; - }; -}; -var store_abort = /* @__PURE__ */ new WeakMap(); -on.disconnectedAsAbort = function(host) { - if (store_abort.has(host)) return store_abort.get(host); - const a = new AbortController(); - store_abort.set(host, a); - host(on.disconnected(() => a.abort())); - return a.signal; -}; export { assign, assignAttribute, diff --git a/dist/esm.min.d.ts b/dist/esm.min.d.ts index cdb2000..09e90e7 100644 --- a/dist/esm.min.d.ts +++ b/dist/esm.min.d.ts @@ -202,6 +202,10 @@ export const scope: { * — `scope.host(on.connected(console.log))`. * */ host: (...addons: ddeElementAddon[]) => HTMLElement; + /** + * Creates/gets an AbortController that triggers when the element disconnects + * */ + signal: AbortSignal; state: Scope[]; /** Adds new child scope. All attributes are inherited by default. */ push(scope?: Partial): ReturnType["push"]>; diff --git a/dist/esm.min.js b/dist/esm.min.js index 1b2080a..690face 100644 --- a/dist/esm.min.js +++ b/dist/esm.min.js @@ -1 +1 @@ -function w(t){return typeof t>"u"}function g(t,e){return t instanceof e}function W(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function v(...t){return Object.assign(...t)}function P(t,e){if(!t||!g(t,AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}var C={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function V(t,e=!0){return e?v(C,t):(Object.setPrototypeOf(t,C),t)}function S(t){return W(t,C)&&t!==C?t:C}var a={setDeleteAttr:J,ssr:"",D:globalThis.document,F:globalThis.DocumentFragment,H:globalThis.HTMLElement,S:globalThis.SVGElement,M:globalThis.MutationObserver,q:t=>t||Promise.resolve()};function J(t,e,n){if(Reflect.set(t,e,n),!!w(n)){if(Reflect.deleteProperty(t,e),g(t,a.H)&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var O="__dde_lifecyclesToEvents",m="dde:connected",_="dde:disconnected",F="dde:attributeChanged";function pt(t){return a.q(t)}var x=[{get scope(){return a.D.body},host:t=>t?t(a.D.body):a.D.body,prevent:!0}],D={get current(){return x[x.length-1]},get host(){return this.current.host},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...x]},push(t={}){return x.push(v({},this.current,{prevent:!1},t))},pushRoot(){return x.push(x[0])},pop(){if(x.length!==1)return x.pop()}};function I(...t){return this.appendOriginal(...t),this}function K(t){return t.append===I||(t.appendOriginal=t.append,t.append=I),t}var R;function j(t,e,...n){let r=S(this),o=0,c,d;switch((Object(e)!==e||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let f=(...l)=>l.length?(o===1?n.unshift(...l):l.forEach(E=>E(d)),void 0):d;D.push({scope:t,host:f}),c=t(e||void 0);let p=g(c,a.F);if(c.nodeName==="#comment")break;let b=j.mark({type:"component",name:t.name,host:p?"this":"parentElement"});c.prepend(b),p&&(d=b);break}case t==="#text":c=L.call(this,a.D.createTextNode(""),e);break;case(t==="<>"||!t):c=L.call(this,a.D.createDocumentFragment(),e);break;case!!R:c=L.call(this,a.D.createElementNS(R,t),e);break;case!c:c=L.call(this,a.D.createElement(t),e)}return K(c),d||(d=c),n.forEach(f=>f(d)),o&&D.pop(),o=2,c}j.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=a.D.createComment(``);return e&&(r.end=a.D.createComment("")),r};function lt(t){let e=this;return function(...r){R=t;let o=j.call(e,...r);return R=void 0,o}}function ht(t,e=t){let n="\xB9\u2070",r="\u2713",o=Object.fromEntries(Array.from(e.querySelectorAll("slot")).filter(c=>!c.name.endsWith(n)).map(c=>[c.name+=n,c]));if(t.append=new Proxy(t.append,{apply(c,d,f){if(f[0]===e)return c.apply(t,f);for(let p of f){let b=(p.slot||"")+n;try{X(p,"remove","slot")}catch{}let l=o[b];if(!l)return;l.name.startsWith(r)||(l.childNodes.forEach(E=>E.remove()),l.name=r+b),l.append(p)}return t.append=c,t}}),t!==e){let c=Array.from(t.childNodes);t.append(...c)}return e}var T=new WeakMap,{setDeleteAttr:$}=a;function L(t,...e){if(!e.length)return t;T.set(t,z(t,this));for(let[n,r]of Object.entries(v({},...e)))H.call(this,t,n,r);return T.delete(t),t}function H(t,e,n){let{setRemoveAttr:r,s:o}=z(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(f,p)=>H.call(c,t,f,p));let[d]=e;if(d==="=")return r(e.slice(1),n);if(d===".")return U(t,e.slice(1),n);if(/(aria|data)([A-Z])/.test(e))return e=e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),r(e,n);switch(e==="className"&&(e="class"),e){case"xlink:href":return r(e,n,"http://www.w3.org/1999/xlink");case"textContent":return $(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return M(o,e,t,n,U.bind(null,t[e]));case"ariaset":return M(o,e,t,n,(f,p)=>r("aria-"+f,p));case"classList":return Q.call(c,t,n)}return Y(t,e)?$(t,e,n):r(e,n)}function z(t,e){if(T.has(t))return T.get(t);let r=(g(t,a.S)?et:tt).bind(null,t,"Attribute"),o=S(e);return{setRemoveAttr:r,s:o}}function Q(t,e){let n=S(this);return M(n,"classList",t,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function X(t,e,n,r){return g(t,a.H)?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function Y(t,e){if(!(e in t))return!1;let n=B(t,e);return!w(n.set)}function B(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||B(t,e)}function M(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([f,p]){f&&(f=new c(f),f.target=e,p=t.processReactiveAttribute(n,f,p,o),o(f,p))})}function tt(t,e,n,r){return t[(w(r)?"remove":"set")+e](n,r)}function et(t,e,n,r,o=null){return t[(w(r)?"remove":"set")+e+"NS"](o,n,r)}function U(t,e,n){if(Reflect.set(t,e,n),!!w(n))return Reflect.deleteProperty(t,e)}var A=a.M?nt():new Proxy({},{get(){return()=>{}}});function nt(){let t=new Map,e=!1,n=s=>function(u){for(let i of u)if(i.type==="childList"){if(l(i.addedNodes,!0)){s();continue}E(i.removedNodes,!0)&&s()}},r=new a.M(n(f));return{observe(s){let u=new a.M(n(()=>{}));return u.observe(s,{childList:!0,subtree:!0}),()=>u.disconnect()},onConnected(s,u){d();let i=c(s);i.connected.has(u)||(i.connected.add(u),i.length_c+=1)},offConnected(s,u){if(!t.has(s))return;let i=t.get(s);i.connected.has(u)&&(i.connected.delete(u),i.length_c-=1,o(s,i))},onDisconnected(s,u){d();let i=c(s);i.disconnected.has(u)||(i.disconnected.add(u),i.length_d+=1)},offDisconnected(s,u){if(!t.has(s))return;let i=t.get(s);i.disconnected.delete(u),i.length_d-=1,o(s,i)}};function o(s,u){u.length_c||u.length_d||(t.delete(s),f())}function c(s){if(t.has(s))return t.get(s);let u={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(s,u),u}function d(){e||(e=!0,r.observe(a.D.body,{childList:!0,subtree:!0}))}function f(){!e||t.size||(e=!1,r.disconnect())}function p(){return new Promise(function(s){(requestIdleCallback||requestAnimationFrame)(s)})}async function b(s){t.size>30&&await p();let u=[];if(!g(s,Node))return u;for(let i of t.keys())i===s||!g(i,Node)||s.contains(i)&&u.push(i);return u}function l(s,u){let i=!1;for(let h of s){if(u&&b(h).then(l),!t.has(h))continue;let y=t.get(h);y.length_c&&(h.dispatchEvent(new Event(m)),y.connected=new WeakSet,y.length_c=0,y.length_d||t.delete(h),i=!0)}return i}function E(s,u){let i=!1;for(let h of s)u&&b(h).then(E),!(!t.has(h)||!t.get(h).length_d)&&((globalThis.queueMicrotask||setTimeout)(G(h)),i=!0);return i}function G(s){return()=>{s.isConnected||(s.dispatchEvent(new Event(_)),t.delete(s))}}}function _t(t,e,n={}){let r=t.host||t;D.push({scope:r,host:(...d)=>d.length?d.forEach(f=>f(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[O];o||rt(r);let c=e.call(r,n);return o||r.dispatchEvent(new Event(m)),t.nodeType===11&&typeof t.mode=="string"&&r.addEventListener(_,A.observe(t),{once:!0}),D.pop(),t.append(c)}function rt(t){return k(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(m))}),k(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(_)))}),k(t.prototype,"attributeChangedCallback",function(e,n,r){let[o,,c]=r;n.dispatchEvent(new CustomEvent(F,{detail:[o,c]})),e.apply(n,r)}),t.prototype[O]=!0,t}function k(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}function Ct(t,e,n){return typeof e=="function"&&(n=e,e=null),e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let d=c.length?new CustomEvent(t,v({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(d)}}function N(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var Z=t=>v({},typeof t=="object"?t:null,{once:!0});N.connected=function(t,e){return e=Z(e),function(r){return r.addEventListener(m,t,e),r[O]?r:r.isConnected?(r.dispatchEvent(new Event(m)),r):(P(e.signal,()=>A.offConnected(r,t))&&A.onConnected(r,t),r)}};N.disconnected=function(t,e){return e=Z(e),function(r){return r.addEventListener(_,t,e),r[O]||P(e.signal,()=>A.offDisconnected(r,t))&&A.onDisconnected(r,t),r}};var q=new WeakMap;N.disconnectedAsAbort=function(t){if(q.has(t))return q.get(t);let e=new AbortController;return q.set(t,e),t(N.disconnected(()=>e.abort())),e.signal};export{L as assign,H as assignAttribute,K as chainableAppend,Q as classListDeclarative,j as createElement,lt as createElementNS,_t as customElementRender,rt as customElementWithDDE,Ct as dispatchEvent,j as el,lt as elNS,X as elementAttribute,rt as lifecyclesToEvents,N as on,pt as queue,V as registerReactivity,D as scope,ht as simulateSlots}; +function w(t){return typeof t>"u"}function g(t,e){return t instanceof e}function W(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function v(...t){return Object.assign(...t)}function P(t,e){if(!t||!g(t,AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}var A={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function V(t,e=!0){return e?v(A,t):(Object.setPrototypeOf(t,A),t)}function S(t){return W(t,A)&&t!==A?t:A}var a={setDeleteAttr:J,ssr:"",D:globalThis.document,F:globalThis.DocumentFragment,H:globalThis.HTMLElement,S:globalThis.SVGElement,M:globalThis.MutationObserver,q:t=>t||Promise.resolve()};function J(t,e,n){if(Reflect.set(t,e,n),!!w(n)){if(Reflect.deleteProperty(t,e),g(t,a.H)&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var y="__dde_lifecyclesToEvents",m="dde:connected",_="dde:disconnected",F="dde:attributeChanged";var O=a.M?K():new Proxy({},{get(){return()=>{}}});function K(){let t=new Map,e=!1,n=s=>function(u){for(let i of u)if(i.type==="childList"){if(l(i.addedNodes,!0)){s();continue}E(i.removedNodes,!0)&&s()}},r=new a.M(n(f));return{observe(s){let u=new a.M(n(()=>{}));return u.observe(s,{childList:!0,subtree:!0}),()=>u.disconnect()},onConnected(s,u){d();let i=c(s);i.connected.has(u)||(i.connected.add(u),i.length_c+=1)},offConnected(s,u){if(!t.has(s))return;let i=t.get(s);i.connected.has(u)&&(i.connected.delete(u),i.length_c-=1,o(s,i))},onDisconnected(s,u){d();let i=c(s);i.disconnected.has(u)||(i.disconnected.add(u),i.length_d+=1)},offDisconnected(s,u){if(!t.has(s))return;let i=t.get(s);i.disconnected.delete(u),i.length_d-=1,o(s,i)}};function o(s,u){u.length_c||u.length_d||(t.delete(s),f())}function c(s){if(t.has(s))return t.get(s);let u={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(s,u),u}function d(){e||(e=!0,r.observe(a.D.body,{childList:!0,subtree:!0}))}function f(){!e||t.size||(e=!1,r.disconnect())}function p(){return new Promise(function(s){(requestIdleCallback||requestAnimationFrame)(s)})}async function b(s){t.size>30&&await p();let u=[];if(!g(s,Node))return u;for(let i of t.keys())i===s||!g(i,Node)||s.contains(i)&&u.push(i);return u}function l(s,u){let i=!1;for(let h of s){if(u&&b(h).then(l),!t.has(h))continue;let C=t.get(h);C.length_c&&(h.dispatchEvent(new Event(m)),C.connected=new WeakSet,C.length_c=0,C.length_d||t.delete(h),i=!0)}return i}function E(s,u){let i=!1;for(let h of s)u&&b(h).then(E),!(!t.has(h)||!t.get(h).length_d)&&((globalThis.queueMicrotask||setTimeout)(G(h)),i=!0);return i}function G(s){return()=>{s.isConnected||(s.dispatchEvent(new Event(_)),t.delete(s))}}}function ht(t,e,n){return typeof e=="function"&&(n=e,e=null),e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let d=c.length?new CustomEvent(t,v({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(d)}}function L(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var I=t=>v({},typeof t=="object"?t:null,{once:!0});L.connected=function(t,e){return e=I(e),function(r){return r.addEventListener(m,t,e),r[y]?r:r.isConnected?(r.dispatchEvent(new Event(m)),r):(P(e.signal,()=>O.offConnected(r,t))&&O.onConnected(r,t),r)}};L.disconnected=function(t,e){return e=I(e),function(r){return r.addEventListener(_,t,e),r[y]||P(e.signal,()=>O.offDisconnected(r,t))&&O.onDisconnected(r,t),r}};function _t(t){return a.q(t)}var x=[{get scope(){return a.D.body},host:t=>t?t(a.D.body):a.D.body,prevent:!0}],M=new WeakMap,D={get current(){return x[x.length-1]},get host(){return this.current.host},get signal(){let{host:t}=this;if(M.has(t))return M.get(t);let e=new AbortController;return M.set(t,e),t(L.disconnected(()=>e.abort())),e.signal},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...x]},push(t={}){return x.push(v({},this.current,{prevent:!1},t))},pushRoot(){return x.push(x[0])},pop(){if(x.length!==1)return x.pop()}};function $(...t){return this.appendOriginal(...t),this}function Q(t){return t.append===$||(t.appendOriginal=t.append,t.append=$),t}var T;function k(t,e,...n){let r=S(this),o=0,c,d;switch((Object(e)!==e||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let f=(...l)=>l.length?(o===1?n.unshift(...l):l.forEach(E=>E(d)),void 0):d;D.push({scope:t,host:f}),c=t(e||void 0);let p=g(c,a.F);if(c.nodeName==="#comment")break;let b=k.mark({type:"component",name:t.name,host:p?"this":"parentElement"});c.prepend(b),p&&(d=b);break}case t==="#text":c=R.call(this,a.D.createTextNode(""),e);break;case(t==="<>"||!t):c=R.call(this,a.D.createDocumentFragment(),e);break;case!!T:c=R.call(this,a.D.createElementNS(T,t),e);break;case!c:c=R.call(this,a.D.createElement(t),e)}return Q(c),d||(d=c),n.forEach(f=>f(d)),o&&D.pop(),o=2,c}k.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=a.D.createComment(``);return e&&(r.end=a.D.createComment("")),r};function Ot(t){let e=this;return function(...r){T=t;let o=k.call(e,...r);return T=void 0,o}}function yt(t,e=t){let n="\xB9\u2070",r="\u2713",o=Object.fromEntries(Array.from(e.querySelectorAll("slot")).filter(c=>!c.name.endsWith(n)).map(c=>[c.name+=n,c]));if(t.append=new Proxy(t.append,{apply(c,d,f){if(f[0]===e)return c.apply(t,f);for(let p of f){let b=(p.slot||"")+n;try{Y(p,"remove","slot")}catch{}let l=o[b];if(!l)return;l.name.startsWith(r)||(l.childNodes.forEach(E=>E.remove()),l.name=r+b),l.append(p)}return t.append=c,t}}),t!==e){let c=Array.from(t.childNodes);t.append(...c)}return e}var N=new WeakMap,{setDeleteAttr:U}=a;function R(t,...e){if(!e.length)return t;N.set(t,B(t,this));for(let[n,r]of Object.entries(v({},...e)))z.call(this,t,n,r);return N.delete(t),t}function z(t,e,n){let{setRemoveAttr:r,s:o}=B(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(f,p)=>z.call(c,t,f,p));let[d]=e;if(d==="=")return r(e.slice(1),n);if(d===".")return H(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 U(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return j(o,e,t,n,H.bind(null,t[e]));case"ariaset":return j(o,e,t,n,(f,p)=>r("aria-"+f,p));case"classList":return X.call(c,t,n)}return tt(t,e)?U(t,e,n):r(e,n)}function B(t,e){if(N.has(t))return N.get(t);let r=(g(t,a.S)?nt:et).bind(null,t,"Attribute"),o=S(e);return{setRemoveAttr:r,s:o}}function X(t,e){let n=S(this);return j(n,"classList",t,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function Y(t,e,n,r){return g(t,a.H)?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function tt(t,e){if(!(e in t))return!1;let n=Z(t,e);return!w(n.set)}function Z(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||Z(t,e)}function j(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([f,p]){f&&(f=new c(f),f.target=e,p=t.processReactiveAttribute(n,f,p,o),o(f,p))})}function et(t,e,n,r){return t[(w(r)?"remove":"set")+e](n,r)}function nt(t,e,n,r,o=null){return t[(w(r)?"remove":"set")+e+"NS"](o,n,r)}function H(t,e,n){if(Reflect.set(t,e,n),!!w(n))return Reflect.deleteProperty(t,e)}function Lt(t,e,n={}){let r=t.host||t;D.push({scope:r,host:(...d)=>d.length?d.forEach(f=>f(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[y];o||rt(r);let c=e.call(r,n);return o||r.dispatchEvent(new Event(m)),t.nodeType===11&&typeof t.mode=="string"&&r.addEventListener(_,O.observe(t),{once:!0}),D.pop(),t.append(c)}function rt(t){return q(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(m))}),q(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(_)))}),q(t.prototype,"attributeChangedCallback",function(e,n,r){let[o,,c]=r;n.dispatchEvent(new CustomEvent(F,{detail:[o,c]})),e.apply(n,r)}),t.prototype[y]=!0,t}function q(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}export{R as assign,z as assignAttribute,Q as chainableAppend,X as classListDeclarative,k as createElement,Ot as createElementNS,Lt as customElementRender,rt as customElementWithDDE,ht as dispatchEvent,k as el,Ot as elNS,Y as elementAttribute,rt as lifecyclesToEvents,L as on,_t as queue,V as registerReactivity,D as scope,yt as simulateSlots}; diff --git a/dist/iife-with-signals.d.ts b/dist/iife-with-signals.d.ts index b461bd9..2621a11 100644 --- a/dist/iife-with-signals.d.ts +++ b/dist/iife-with-signals.d.ts @@ -203,6 +203,10 @@ export const scope: { * — `scope.host(on.connected(console.log))`. * */ host: (...addons: ddeElementAddon[]) => HTMLElement; + /** + * Creates/gets an AbortController that triggers when the element disconnects + * */ + signal: AbortSignal; state: Scope[]; /** Adds new child scope. All attributes are inherited by default. */ push(scope?: Partial): ReturnType["push"]>; diff --git a/dist/iife-with-signals.js b/dist/iife-with-signals.js index 09a63b5..97552ee 100644 --- a/dist/iife-with-signals.js +++ b/dist/iife-with-signals.js @@ -156,6 +156,215 @@ var DDE = (() => { var evd = "dde:disconnected"; var eva = "dde:attributeChanged"; + // src/events-observer.js + var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { + get() { + return () => { + }; + } + }); + function connectionsChangesObserverConstructor() { + const store = /* @__PURE__ */ new Map(); + let is_observing = false; + const observerListener = (stop2) => function(mutations) { + for (const mutation of mutations) { + if (mutation.type !== "childList") continue; + if (observerAdded(mutation.addedNodes, true)) { + stop2(); + continue; + } + if (observerRemoved(mutation.removedNodes, true)) + stop2(); + } + }; + const observer = new enviroment.M(observerListener(stop)); + return { + /** + * Creates an observer for a specific element + * @param {Element} element - Element to observe + * @returns {Function} Cleanup function + */ + observe(element) { + const o = new enviroment.M(observerListener(() => { + })); + o.observe(element, { childList: true, subtree: true }); + return () => o.disconnect(); + }, + /** + * Register a connection listener for an element + * @param {Element} element - Element to watch + * @param {Function} listener - Callback for connection event + */ + onConnected(element, listener) { + start(); + const listeners = getElementStore(element); + if (listeners.connected.has(listener)) return; + listeners.connected.add(listener); + listeners.length_c += 1; + }, + /** + * Unregister a connection listener + * @param {Element} element - Element being watched + * @param {Function} listener - Callback to remove + */ + offConnected(element, listener) { + if (!store.has(element)) return; + const ls = store.get(element); + if (!ls.connected.has(listener)) return; + ls.connected.delete(listener); + ls.length_c -= 1; + cleanWhenOff(element, ls); + }, + /** + * Register a disconnection listener for an element + * @param {Element} element - Element to watch + * @param {Function} listener - Callback for disconnection event + */ + onDisconnected(element, listener) { + start(); + const listeners = getElementStore(element); + if (listeners.disconnected.has(listener)) return; + listeners.disconnected.add(listener); + listeners.length_d += 1; + }, + /** + * Unregister a disconnection listener + * @param {Element} element - Element being watched + * @param {Function} listener - Callback to remove + */ + offDisconnected(element, listener) { + if (!store.has(element)) return; + const ls = store.get(element); + ls.disconnected.delete(listener); + ls.length_d -= 1; + cleanWhenOff(element, ls); + } + }; + function cleanWhenOff(element, ls) { + if (ls.length_c || ls.length_d) + return; + store.delete(element); + stop(); + } + function getElementStore(element) { + if (store.has(element)) return store.get(element); + const out = { + connected: /* @__PURE__ */ new WeakSet(), + length_c: 0, + disconnected: /* @__PURE__ */ new WeakSet(), + length_d: 0 + }; + store.set(element, out); + return out; + } + function start() { + if (is_observing) return; + is_observing = true; + observer.observe(enviroment.D.body, { childList: true, subtree: true }); + } + function stop() { + if (!is_observing || store.size) return; + is_observing = false; + observer.disconnect(); + } + function requestIdle() { + return new Promise(function(resolve) { + (requestIdleCallback || requestAnimationFrame)(resolve); + }); + } + async function collectChildren(element) { + if (store.size > 30) + await requestIdle(); + const out = []; + if (!isInstance(element, Node)) return out; + for (const el of store.keys()) { + if (el === element || !isInstance(el, Node)) continue; + if (element.contains(el)) + out.push(el); + } + return out; + } + function observerAdded(addedNodes, is_root) { + let out = false; + for (const element of addedNodes) { + if (is_root) collectChildren(element).then(observerAdded); + if (!store.has(element)) continue; + const ls = store.get(element); + if (!ls.length_c) continue; + element.dispatchEvent(new Event(evc)); + ls.connected = /* @__PURE__ */ new WeakSet(); + ls.length_c = 0; + if (!ls.length_d) store.delete(element); + out = true; + } + return out; + } + function observerRemoved(removedNodes, is_root) { + let out = false; + for (const element of removedNodes) { + if (is_root) collectChildren(element).then(observerRemoved); + if (!store.has(element)) continue; + const ls = store.get(element); + if (!ls.length_d) continue; + (globalThis.queueMicrotask || setTimeout)(dispatchRemove(element)); + out = true; + } + return out; + } + function dispatchRemove(element) { + return () => { + if (element.isConnected) return; + element.dispatchEvent(new Event(evd)); + store.delete(element); + }; + } + } + + // src/events.js + function dispatchEvent(name, options, host) { + if (typeof options === "function") { + host = options; + options = null; + } + if (!options) options = {}; + return function dispatch(element, ...d) { + if (host) { + d.unshift(element); + element = typeof host === "function" ? host() : host; + } + const event = d.length ? new CustomEvent(name, oAssign({ detail: d[0] }, options)) : new Event(name, options); + return element.dispatchEvent(event); + }; + } + function on(event, listener, options) { + return function registerElement(element) { + element.addEventListener(event, listener, options); + return element; + }; + } + var lifeOptions = (obj) => oAssign({}, typeof obj === "object" ? obj : null, { once: true }); + on.connected = function(listener, options) { + options = lifeOptions(options); + return function registerElement(element) { + element.addEventListener(evc, listener, options); + if (element[keyLTE]) return element; + if (element.isConnected) return element.dispatchEvent(new Event(evc)), element; + const c = onAbort(options.signal, () => c_ch_o.offConnected(element, listener)); + if (c) c_ch_o.onConnected(element, listener); + return element; + }; + }; + on.disconnected = function(listener, options) { + options = lifeOptions(options); + return function registerElement(element) { + element.addEventListener(evd, listener, options); + if (element[keyLTE]) return element; + const c = onAbort(options.signal, () => c_ch_o.offDisconnected(element, listener)); + if (c) c_ch_o.onDisconnected(element, listener); + return element; + }; + }; + // src/dom.js function queue(promise) { return enviroment.q(promise); @@ -167,6 +376,7 @@ var DDE = (() => { host: (c) => c ? c(enviroment.D.body) : enviroment.D.body, prevent: true }]; + var store_abort = /* @__PURE__ */ new WeakMap(); var scope = { /** * Gets the current scope @@ -183,6 +393,17 @@ var DDE = (() => { return this.current.host; }, /** + * Creates/gets an AbortController that triggers when the element disconnects + * */ + get signal() { + const { host } = this; + if (store_abort.has(host)) return store_abort.get(host); + const a = new AbortController(); + store_abort.set(host, a); + host(on.disconnected(() => a.abort())); + return a.signal; + }, + /** * Prevents default behavior in the current scope * @returns {Object} Current scope context */ @@ -425,170 +646,6 @@ var DDE = (() => { return Reflect.deleteProperty(obj, key); } - // src/events-observer.js - var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { - get() { - return () => { - }; - } - }); - function connectionsChangesObserverConstructor() { - const store = /* @__PURE__ */ new Map(); - let is_observing = false; - const observerListener = (stop2) => function(mutations) { - for (const mutation of mutations) { - if (mutation.type !== "childList") continue; - if (observerAdded(mutation.addedNodes, true)) { - stop2(); - continue; - } - if (observerRemoved(mutation.removedNodes, true)) - stop2(); - } - }; - const observer = new enviroment.M(observerListener(stop)); - return { - /** - * Creates an observer for a specific element - * @param {Element} element - Element to observe - * @returns {Function} Cleanup function - */ - observe(element) { - const o = new enviroment.M(observerListener(() => { - })); - o.observe(element, { childList: true, subtree: true }); - return () => o.disconnect(); - }, - /** - * Register a connection listener for an element - * @param {Element} element - Element to watch - * @param {Function} listener - Callback for connection event - */ - onConnected(element, listener) { - start(); - const listeners = getElementStore(element); - if (listeners.connected.has(listener)) return; - listeners.connected.add(listener); - listeners.length_c += 1; - }, - /** - * Unregister a connection listener - * @param {Element} element - Element being watched - * @param {Function} listener - Callback to remove - */ - offConnected(element, listener) { - if (!store.has(element)) return; - const ls = store.get(element); - if (!ls.connected.has(listener)) return; - ls.connected.delete(listener); - ls.length_c -= 1; - cleanWhenOff(element, ls); - }, - /** - * Register a disconnection listener for an element - * @param {Element} element - Element to watch - * @param {Function} listener - Callback for disconnection event - */ - onDisconnected(element, listener) { - start(); - const listeners = getElementStore(element); - if (listeners.disconnected.has(listener)) return; - listeners.disconnected.add(listener); - listeners.length_d += 1; - }, - /** - * Unregister a disconnection listener - * @param {Element} element - Element being watched - * @param {Function} listener - Callback to remove - */ - offDisconnected(element, listener) { - if (!store.has(element)) return; - const ls = store.get(element); - ls.disconnected.delete(listener); - ls.length_d -= 1; - cleanWhenOff(element, ls); - } - }; - function cleanWhenOff(element, ls) { - if (ls.length_c || ls.length_d) - return; - store.delete(element); - stop(); - } - function getElementStore(element) { - if (store.has(element)) return store.get(element); - const out = { - connected: /* @__PURE__ */ new WeakSet(), - length_c: 0, - disconnected: /* @__PURE__ */ new WeakSet(), - length_d: 0 - }; - store.set(element, out); - return out; - } - function start() { - if (is_observing) return; - is_observing = true; - observer.observe(enviroment.D.body, { childList: true, subtree: true }); - } - function stop() { - if (!is_observing || store.size) return; - is_observing = false; - observer.disconnect(); - } - function requestIdle() { - return new Promise(function(resolve) { - (requestIdleCallback || requestAnimationFrame)(resolve); - }); - } - async function collectChildren(element) { - if (store.size > 30) - await requestIdle(); - const out = []; - if (!isInstance(element, Node)) return out; - for (const el of store.keys()) { - if (el === element || !isInstance(el, Node)) continue; - if (element.contains(el)) - out.push(el); - } - return out; - } - function observerAdded(addedNodes, is_root) { - let out = false; - for (const element of addedNodes) { - if (is_root) collectChildren(element).then(observerAdded); - if (!store.has(element)) continue; - const ls = store.get(element); - if (!ls.length_c) continue; - element.dispatchEvent(new Event(evc)); - ls.connected = /* @__PURE__ */ new WeakSet(); - ls.length_c = 0; - if (!ls.length_d) store.delete(element); - out = true; - } - return out; - } - function observerRemoved(removedNodes, is_root) { - let out = false; - for (const element of removedNodes) { - if (is_root) collectChildren(element).then(observerRemoved); - if (!store.has(element)) continue; - const ls = store.get(element); - if (!ls.length_d) continue; - (globalThis.queueMicrotask || setTimeout)(dispatchRemove(element)); - out = true; - } - return out; - } - function dispatchRemove(element) { - return () => { - if (element.isConnected) return; - element.dispatchEvent(new Event(evd)); - store.delete(element); - }; - } - } - // src/customElement.js function customElementRender(target, render, props = {}) { const custom_element = target.host || target; @@ -632,59 +689,6 @@ var DDE = (() => { }), { apply }); } - // src/events.js - function dispatchEvent(name, options, host) { - if (typeof options === "function") { - host = options; - options = null; - } - if (!options) options = {}; - return function dispatch(element, ...d) { - if (host) { - d.unshift(element); - element = typeof host === "function" ? host() : host; - } - const event = d.length ? new CustomEvent(name, oAssign({ detail: d[0] }, options)) : new Event(name, options); - return element.dispatchEvent(event); - }; - } - function on(event, listener, options) { - return function registerElement(element) { - element.addEventListener(event, listener, options); - return element; - }; - } - var lifeOptions = (obj) => oAssign({}, typeof obj === "object" ? obj : null, { once: true }); - on.connected = function(listener, options) { - options = lifeOptions(options); - return function registerElement(element) { - element.addEventListener(evc, listener, options); - if (element[keyLTE]) return element; - if (element.isConnected) return element.dispatchEvent(new Event(evc)), element; - const c = onAbort(options.signal, () => c_ch_o.offConnected(element, listener)); - if (c) c_ch_o.onConnected(element, listener); - return element; - }; - }; - on.disconnected = function(listener, options) { - options = lifeOptions(options); - return function registerElement(element) { - element.addEventListener(evd, listener, options); - if (element[keyLTE]) return element; - const c = onAbort(options.signal, () => c_ch_o.offDisconnected(element, listener)); - if (c) c_ch_o.onDisconnected(element, listener); - return element; - }; - }; - var store_abort = /* @__PURE__ */ new WeakMap(); - on.disconnectedAsAbort = function(host) { - if (store_abort.has(host)) return store_abort.get(host); - const a = new AbortController(); - store_abort.set(host, a); - host(on.disconnected(() => a.abort())); - return a.signal; - }; - // src/signals-lib/helpers.js var mark = "__dde_signal"; var queueSignalWrite = /* @__PURE__ */ (() => { diff --git a/dist/iife-with-signals.min.d.ts b/dist/iife-with-signals.min.d.ts index b461bd9..2621a11 100644 --- a/dist/iife-with-signals.min.d.ts +++ b/dist/iife-with-signals.min.d.ts @@ -203,6 +203,10 @@ export const scope: { * — `scope.host(on.connected(console.log))`. * */ host: (...addons: ddeElementAddon[]) => HTMLElement; + /** + * Creates/gets an AbortController that triggers when the element disconnects + * */ + signal: AbortSignal; state: Scope[]; /** Adds new child scope. All attributes are inherited by default. */ push(scope?: Partial): ReturnType["push"]>; diff --git a/dist/iife-with-signals.min.js b/dist/iife-with-signals.min.js index 50074dc..422eb9b 100644 --- a/dist/iife-with-signals.min.js +++ b/dist/iife-with-signals.min.js @@ -1,4 +1,4 @@ -var DDE=(()=>{var J=Object.defineProperty;var St=Object.getOwnPropertyDescriptor;var wt=Object.getOwnPropertyNames;var At=Object.prototype.hasOwnProperty;var yt=(t,e)=>{for(var n in e)J(t,n,{get:e[n],enumerable:!0})},Ct=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of wt(e))!At.call(t,o)&&o!==n&&J(t,o,{get:()=>e[o],enumerable:!(r=St(e,o))||r.enumerable});return t};var Ot=t=>Ct(J({},"__esModule",{value:!0}),t);var Zt={};yt(Zt,{S:()=>g,assign:()=>W,assignAttribute:()=>K,chainableAppend:()=>ft,classListDeclarative:()=>dt,createElement:()=>T,createElementNS:()=>kt,customElementRender:()=>jt,customElementWithDDE:()=>ht,dispatchEvent:()=>Wt,el:()=>T,elNS:()=>kt,elementAttribute:()=>lt,isSignal:()=>F,lifecyclesToEvents:()=>ht,on:()=>A,queue:()=>Lt,registerReactivity:()=>I,scope:()=>m,signal:()=>g,simulateSlots:()=>Nt});var Z=(...t)=>Object.prototype.hasOwnProperty.call(...t);function O(t){return typeof t>"u"}function rt(t){let e=typeof t;return e!=="object"?e:t===null?"null":Object.prototype.toString.call(t)}function S(t,e){return t instanceof e}function ot(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function w(t=null,e={}){return Object.create(t,e)}function x(...t){return Object.assign(...t)}function G(t,e){if(!t||!S(t,AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}function ct(t,e){let{observedAttributes:n=[]}=t.constructor;return n.reduce(function(r,o){return r[Dt(o)]=e(t,o),r},{})}function Dt(t){return t.replace(/-./g,e=>e[1].toUpperCase())}var q=class extends Error{constructor(){super();let[e,...n]=this.stack.split(` -`),r=e.slice(e.indexOf("@"),e.indexOf(".js:")+4),o=r.includes("src/helpers.js")?"src/":r;this.stack=n.find(c=>!c.includes(o))||e}get compact(){let{stack:e}=this;return e.slice(0,e.indexOf("@")+1)+"\u2026"+e.slice(e.lastIndexOf("/"))}};var j={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function I(t,e=!0){return e?x(j,t):(Object.setPrototypeOf(t,j),t)}function $(t){return ot(t,j)&&t!==j?t:j}var d={setDeleteAttr:Rt,ssr:"",D:globalThis.document,F:globalThis.DocumentFragment,H:globalThis.HTMLElement,S:globalThis.SVGElement,M:globalThis.MutationObserver,q:t=>t||Promise.resolve()};function Rt(t,e,n){if(Reflect.set(t,e,n),!!O(n)){if(Reflect.deleteProperty(t,e),S(t,d.H)&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var N="__dde_lifecyclesToEvents",y="dde:connected",D="dde:disconnected",U="dde:attributeChanged";function Lt(t){return d.q(t)}var C=[{get scope(){return d.D.body},host:t=>t?t(d.D.body):d.D.body,prevent:!0}],m={get current(){return C[C.length-1]},get host(){return this.current.host},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...C]},push(t={}){return C.push(x({},this.current,{prevent:!1},t))},pushRoot(){return C.push(C[0])},pop(){if(C.length!==1)return C.pop()}};function st(...t){return this.appendOriginal(...t),this}function ft(t){return t.append===st||(t.appendOriginal=t.append,t.append=st),t}var z;function T(t,e,...n){let r=$(this),o=0,c,s;switch((Object(e)!==e||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let i=(...h)=>h.length?(o===1?n.unshift(...h):h.forEach(b=>b(s)),void 0):s;m.push({scope:t,host:i}),c=t(e||void 0);let p=S(c,d.F);if(c.nodeName==="#comment")break;let E=T.mark({type:"component",name:t.name,host:p?"this":"parentElement"});c.prepend(E),p&&(s=E);break}case t==="#text":c=W.call(this,d.D.createTextNode(""),e);break;case(t==="<>"||!t):c=W.call(this,d.D.createDocumentFragment(),e);break;case!!z:c=W.call(this,d.D.createElementNS(z,t),e);break;case!c:c=W.call(this,d.D.createElement(t),e)}return ft(c),s||(s=c),n.forEach(i=>i(s)),o&&m.pop(),o=2,c}T.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=d.D.createComment(``);return e&&(r.end=d.D.createComment("")),r};function kt(t){let e=this;return function(...r){z=t;let o=T.call(e,...r);return z=void 0,o}}function Nt(t,e=t){let n="\xB9\u2070",r="\u2713",o=Object.fromEntries(Array.from(e.querySelectorAll("slot")).filter(c=>!c.name.endsWith(n)).map(c=>[c.name+=n,c]));if(t.append=new Proxy(t.append,{apply(c,s,i){if(i[0]===e)return c.apply(t,i);for(let p of i){let E=(p.slot||"")+n;try{lt(p,"remove","slot")}catch{}let h=o[E];if(!h)return;h.name.startsWith(r)||(h.childNodes.forEach(b=>b.remove()),h.name=r+E),h.append(p)}return t.append=c,t}}),t!==e){let c=Array.from(t.childNodes);t.append(...c)}return e}var H=new WeakMap,{setDeleteAttr:it}=d;function W(t,...e){if(!e.length)return t;H.set(t,at(t,this));for(let[n,r]of Object.entries(x({},...e)))K.call(this,t,n,r);return H.delete(t),t}function K(t,e,n){let{setRemoveAttr:r,s:o}=at(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(i,p)=>K.call(c,t,i,p));let[s]=e;if(s==="=")return r(e.slice(1),n);if(s===".")return ut(t,e.slice(1),n);if(/(aria|data)([A-Z])/.test(e))return e=e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),r(e,n);switch(e==="className"&&(e="class"),e){case"xlink:href":return r(e,n,"http://www.w3.org/1999/xlink");case"textContent":return it(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return V(o,e,t,n,ut.bind(null,t[e]));case"ariaset":return V(o,e,t,n,(i,p)=>r("aria-"+i,p));case"classList":return dt.call(c,t,n)}return Tt(t,e)?it(t,e,n):r(e,n)}function at(t,e){if(H.has(t))return H.get(t);let r=(S(t,d.S)?Pt:Mt).bind(null,t,"Attribute"),o=$(e);return{setRemoveAttr:r,s:o}}function dt(t,e){let n=$(this);return V(n,"classList",t,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function lt(t,e,n,r){return S(t,d.H)?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function Tt(t,e){if(!(e in t))return!1;let n=pt(t,e);return!O(n.set)}function pt(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||pt(t,e)}function V(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([i,p]){i&&(i=new c(i),i.target=e,p=t.processReactiveAttribute(n,i,p,o),o(i,p))})}function Mt(t,e,n,r){return t[(O(r)?"remove":"set")+e](n,r)}function Pt(t,e,n,r,o=null){return t[(O(r)?"remove":"set")+e+"NS"](o,n,r)}function ut(t,e,n){if(Reflect.set(t,e,n),!!O(n))return Reflect.deleteProperty(t,e)}var R=d.M?qt():new Proxy({},{get(){return()=>{}}});function qt(){let t=new Map,e=!1,n=u=>function(a){for(let f of a)if(f.type==="childList"){if(h(f.addedNodes,!0)){u();continue}b(f.removedNodes,!0)&&u()}},r=new d.M(n(i));return{observe(u){let a=new d.M(n(()=>{}));return a.observe(u,{childList:!0,subtree:!0}),()=>a.disconnect()},onConnected(u,a){s();let f=c(u);f.connected.has(a)||(f.connected.add(a),f.length_c+=1)},offConnected(u,a){if(!t.has(u))return;let f=t.get(u);f.connected.has(a)&&(f.connected.delete(a),f.length_c-=1,o(u,f))},onDisconnected(u,a){s();let f=c(u);f.disconnected.has(a)||(f.disconnected.add(a),f.length_d+=1)},offDisconnected(u,a){if(!t.has(u))return;let f=t.get(u);f.disconnected.delete(a),f.length_d-=1,o(u,f)}};function o(u,a){a.length_c||a.length_d||(t.delete(u),i())}function c(u){if(t.has(u))return t.get(u);let a={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(u,a),a}function s(){e||(e=!0,r.observe(d.D.body,{childList:!0,subtree:!0}))}function i(){!e||t.size||(e=!1,r.disconnect())}function p(){return new Promise(function(u){(requestIdleCallback||requestAnimationFrame)(u)})}async function E(u){t.size>30&&await p();let a=[];if(!S(u,Node))return a;for(let f of t.keys())f===u||!S(f,Node)||u.contains(f)&&a.push(f);return a}function h(u,a){let f=!1;for(let _ of u){if(a&&E(_).then(h),!t.has(_))continue;let P=t.get(_);P.length_c&&(_.dispatchEvent(new Event(y)),P.connected=new WeakSet,P.length_c=0,P.length_d||t.delete(_),f=!0)}return f}function b(u,a){let f=!1;for(let _ of u)a&&E(_).then(b),!(!t.has(_)||!t.get(_).length_d)&&((globalThis.queueMicrotask||setTimeout)(M(_)),f=!0);return f}function M(u){return()=>{u.isConnected||(u.dispatchEvent(new Event(D)),t.delete(u))}}}function jt(t,e,n={}){let r=t.host||t;m.push({scope:r,host:(...s)=>s.length?s.forEach(i=>i(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[N];o||ht(r);let c=e.call(r,n);return o||r.dispatchEvent(new Event(y)),t.nodeType===11&&typeof t.mode=="string"&&r.addEventListener(D,R.observe(t),{once:!0}),m.pop(),t.append(c)}function ht(t){return Q(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(y))}),Q(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(D)))}),Q(t.prototype,"attributeChangedCallback",function(e,n,r){let[o,,c]=r;n.dispatchEvent(new CustomEvent(U,{detail:[o,c]})),e.apply(n,r)}),t.prototype[N]=!0,t}function Q(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}function Wt(t,e,n){return typeof e=="function"&&(n=e,e=null),e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let s=c.length?new CustomEvent(t,x({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(s)}}function A(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var gt=t=>x({},typeof t=="object"?t:null,{once:!0});A.connected=function(t,e){return e=gt(e),function(r){return r.addEventListener(y,t,e),r[N]?r:r.isConnected?(r.dispatchEvent(new Event(y)),r):(G(e.signal,()=>R.offConnected(r,t))&&R.onConnected(r,t),r)}};A.disconnected=function(t,e){return e=gt(e),function(r){return r.addEventListener(D,t,e),r[N]||G(e.signal,()=>R.offDisconnected(r,t))&&R.onDisconnected(r,t),r}};var X=new WeakMap;A.disconnectedAsAbort=function(t){if(X.has(t))return X.get(t);let e=new AbortController;return X.set(t,e),t(A.disconnected(()=>e.abort())),e.signal};var l="__dde_signal",Y=(()=>{let t=new Set,e=!1;function n(){e=!1;let r=t;t=new Set;for(let o of r){let c=o[l];c&&c.listeners.forEach(s=>s(c.value))}}return function(r){t.add(r),!e&&(e=!0,queueMicrotask(n))}})();var et=w(null,{get:{value(){return vt(this)}},set:{value(...t){return _t(this,...t)}},toJSON:{value(){return vt(this)}},valueOf:{value(){return this[l]&&this[l].value}}}),Ft=w(et,{set:{value(){}}});function F(t){return t&&t[l]}var B=[],v=new WeakMap;function g(t,e){if(typeof t!="function")return mt(!1,t,e);if(F(t))return t;let n=mt(!0);function r(){let[o,...c]=v.get(r);if(v.set(r,new Set([o])),B.push(r),_t(n,t()),B.pop(),!c.length)return;let s=v.get(r);for(let i of c)s.has(i)||k(i,r)}return v.set(n[l],r),v.set(r,new Set([n])),r(),n}g.action=function(t,e,...n){let r=t[l];if(!r)return;let{actions:o}=r;if(!o||!Z(o,e))throw new Error(`Action "${e}" not defined. See ${l}.actions.`);if(o[e].apply(r,n),r.skip)return delete r.skip;Y(t)};g.on=function t(e,n,r={}){let{signal:o}=r;if(!(o&&o.aborted)){if(Array.isArray(e))return e.forEach(c=>t(c,n,r));nt(e,n),o&&o.addEventListener("abort",()=>k(e,n))}};g.symbols={onclear:Symbol.for("Signal.onclear")};g.clear=function(...t){for(let n of t){let r=n[l];r&&(delete n.toJSON,r.onclear.forEach(o=>o.call(r)),e(n,r),delete n[l])}function e(n,r){r.listeners.forEach(o=>{if(r.listeners.delete(o),!v.has(o))return;let c=v.get(o);c.delete(n),!(c.size>1)&&(n.clear(...c),v.delete(o))})}};var L="__dde_reactive";function It(t=w()){return(e,n)=>Z(t,e)?t[e]:t[e]=n()}g.el=function(t,e){let n=T.mark({type:"reactive",source:new q().compact},!0),r=n.end,o=d.D.createDocumentFragment();o.append(n,r);let{current:c}=m,s=w(),i=p=>{if(!n.parentNode||!r.parentNode)return k(t,i);let E=It(s);s=w(),m.push(c);let h=e(p,function(a,f){return s[a]=E(a,f)});m.pop(),Array.isArray(h)||(h=[h]);let b=document.createComment("");h.push(b),n.after(...h);let M;for(;(M=b.nextSibling)&&M!==r;)M.remove();b.remove(),n.isConnected&&$t(c.host())};return nt(t,i),xt(t,i,n,e),i(t.get()),c.host(A.disconnected(()=>s={})),o};function $t(t){!t||!t[L]||(requestIdleCallback||setTimeout)(function(){t[L]=t[L].filter(([e,n])=>n.isConnected?!0:(k(...e),!1))})}var Ut={_set(t){this.value=t}};function zt(t){return function(e,n){let r=w(et,{set:{value(...c){return e.setAttribute(n,...c)}}}),o=Et(r,e.getAttribute(n),Ut);return t[n]=o,o}}var tt="__dde_attributes";g.observedAttributes=function(t){let e=t[tt]={},n=ct(t,zt(e));return A(U,function({detail:o}){/*! This maps attributes to signals (`S.observedAttributes`). - Investigate `__dde_attributes` key of the element. */let[c,s]=o,i=this[tt][c];if(i)return g.action(i,"_set",s)})(t),A.disconnected(function(){/*! This removes all signals mapped to attributes (`S.observedAttributes`). - Investigate `__dde_attributes` key of the element. */g.clear(...Object.values(this[tt]))})(t),n};var bt={isSignal:F,processReactiveAttribute(t,e,n,r){if(!F(n))return n;let o=c=>{if(!t.isConnected)return k(n,o);r(e,c)};return nt(n,o),xt(n,o,t,e),n.get()}};function xt(t,e,...n){let{current:r}=m;r.host(function(o){if(o[L])return o[L].push([[t,e],...n]);o[L]=[],!r.prevent&&A.disconnected(()=>o[L].forEach(([[c,s]])=>k(c,s,c[l]&&c[l].host&&c[l].host()===o)))(o)})}var Ht=new FinalizationRegistry(function(t){g.clear({[l]:t})});function mt(t,e,n){let r=w(t?Ft:et),o=Et(r,e,n,t);return Ht.register(o,o[l]),o}var Bt=x(w(),{stopPropagation(){this.skip=!0}});function Et(t,e,n,r=!1){let o=[];rt(n)!=="[object Object]"&&(n={});let{onclear:c}=g.symbols;n[c]&&(o.push(n[c]),delete n[c]);let{host:s}=m;return Reflect.defineProperty(t,l,{value:x(w(Bt),{value:e,actions:n,onclear:o,host:s,listeners:new Set,defined:new q().stack,readonly:r}),enumerable:!1,writable:!1,configurable:!0}),t}function Jt(){return B[B.length-1]}function vt(t){if(!t[l])return;let{value:e,listeners:n}=t[l],r=Jt();return r&&n.add(r),v.has(r)&&v.get(r).add(t),e}function _t(t,e,n){let r=t[l];if(!(!r||!n&&r.value===e))return r.value=e,Y(t),e}function nt(t,e){if(t[l])return t[l].listeners.add(e)}function k(t,e,n){let r=t[l];if(!r)return;let{listeners:o}=r,c=o.delete(e);if(!c||!n||o.size)return c;g.clear(t);let s=v.get(r);if(!s)return c;let i=v.get(s);if(!i)return c;for(let p of i)k(p,s,!0);return c}I(bt);return Ot(Zt);})(); +var DDE=(()=>{var J=Object.defineProperty;var St=Object.getOwnPropertyDescriptor;var wt=Object.getOwnPropertyNames;var yt=Object.prototype.hasOwnProperty;var At=(t,e)=>{for(var n in e)J(t,n,{get:e[n],enumerable:!0})},Ct=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of wt(e))!yt.call(t,o)&&o!==n&&J(t,o,{get:()=>e[o],enumerable:!(r=St(e,o))||r.enumerable});return t};var Ot=t=>Ct(J({},"__esModule",{value:!0}),t);var Zt={};At(Zt,{S:()=>g,assign:()=>W,assignAttribute:()=>Q,chainableAppend:()=>at,classListDeclarative:()=>lt,createElement:()=>T,createElementNS:()=>Tt,customElementRender:()=>Wt,customElementWithDDE:()=>gt,dispatchEvent:()=>kt,el:()=>T,elNS:()=>Tt,elementAttribute:()=>pt,isSignal:()=>F,lifecyclesToEvents:()=>gt,on:()=>y,queue:()=>Nt,registerReactivity:()=>I,scope:()=>m,signal:()=>g,simulateSlots:()=>Mt});var Z=(...t)=>Object.prototype.hasOwnProperty.call(...t);function O(t){return typeof t>"u"}function rt(t){let e=typeof t;return e!=="object"?e:t===null?"null":Object.prototype.toString.call(t)}function S(t,e){return t instanceof e}function ot(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function w(t=null,e={}){return Object.create(t,e)}function x(...t){return Object.assign(...t)}function G(t,e){if(!t||!S(t,AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}function ct(t,e){let{observedAttributes:n=[]}=t.constructor;return n.reduce(function(r,o){return r[Dt(o)]=e(t,o),r},{})}function Dt(t){return t.replace(/-./g,e=>e[1].toUpperCase())}var q=class extends Error{constructor(){super();let[e,...n]=this.stack.split(` +`),r=e.slice(e.indexOf("@"),e.indexOf(".js:")+4),o=r.includes("src/helpers.js")?"src/":r;this.stack=n.find(c=>!c.includes(o))||e}get compact(){let{stack:e}=this;return e.slice(0,e.indexOf("@")+1)+"\u2026"+e.slice(e.lastIndexOf("/"))}};var j={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function I(t,e=!0){return e?x(j,t):(Object.setPrototypeOf(t,j),t)}function $(t){return ot(t,j)&&t!==j?t:j}var d={setDeleteAttr:Rt,ssr:"",D:globalThis.document,F:globalThis.DocumentFragment,H:globalThis.HTMLElement,S:globalThis.SVGElement,M:globalThis.MutationObserver,q:t=>t||Promise.resolve()};function Rt(t,e,n){if(Reflect.set(t,e,n),!!O(n)){if(Reflect.deleteProperty(t,e),S(t,d.H)&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var N="__dde_lifecyclesToEvents",A="dde:connected",D="dde:disconnected",U="dde:attributeChanged";var R=d.M?Lt():new Proxy({},{get(){return()=>{}}});function Lt(){let t=new Map,e=!1,n=u=>function(a){for(let f of a)if(f.type==="childList"){if(h(f.addedNodes,!0)){u();continue}b(f.removedNodes,!0)&&u()}},r=new d.M(n(i));return{observe(u){let a=new d.M(n(()=>{}));return a.observe(u,{childList:!0,subtree:!0}),()=>a.disconnect()},onConnected(u,a){s();let f=c(u);f.connected.has(a)||(f.connected.add(a),f.length_c+=1)},offConnected(u,a){if(!t.has(u))return;let f=t.get(u);f.connected.has(a)&&(f.connected.delete(a),f.length_c-=1,o(u,f))},onDisconnected(u,a){s();let f=c(u);f.disconnected.has(a)||(f.disconnected.add(a),f.length_d+=1)},offDisconnected(u,a){if(!t.has(u))return;let f=t.get(u);f.disconnected.delete(a),f.length_d-=1,o(u,f)}};function o(u,a){a.length_c||a.length_d||(t.delete(u),i())}function c(u){if(t.has(u))return t.get(u);let a={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(u,a),a}function s(){e||(e=!0,r.observe(d.D.body,{childList:!0,subtree:!0}))}function i(){!e||t.size||(e=!1,r.disconnect())}function p(){return new Promise(function(u){(requestIdleCallback||requestAnimationFrame)(u)})}async function E(u){t.size>30&&await p();let a=[];if(!S(u,Node))return a;for(let f of t.keys())f===u||!S(f,Node)||u.contains(f)&&a.push(f);return a}function h(u,a){let f=!1;for(let _ of u){if(a&&E(_).then(h),!t.has(_))continue;let P=t.get(_);P.length_c&&(_.dispatchEvent(new Event(A)),P.connected=new WeakSet,P.length_c=0,P.length_d||t.delete(_),f=!0)}return f}function b(u,a){let f=!1;for(let _ of u)a&&E(_).then(b),!(!t.has(_)||!t.get(_).length_d)&&((globalThis.queueMicrotask||setTimeout)(M(_)),f=!0);return f}function M(u){return()=>{u.isConnected||(u.dispatchEvent(new Event(D)),t.delete(u))}}}function kt(t,e,n){return typeof e=="function"&&(n=e,e=null),e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let s=c.length?new CustomEvent(t,x({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(s)}}function y(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var st=t=>x({},typeof t=="object"?t:null,{once:!0});y.connected=function(t,e){return e=st(e),function(r){return r.addEventListener(A,t,e),r[N]?r:r.isConnected?(r.dispatchEvent(new Event(A)),r):(G(e.signal,()=>R.offConnected(r,t))&&R.onConnected(r,t),r)}};y.disconnected=function(t,e){return e=st(e),function(r){return r.addEventListener(D,t,e),r[N]||G(e.signal,()=>R.offDisconnected(r,t))&&R.onDisconnected(r,t),r}};function Nt(t){return d.q(t)}var C=[{get scope(){return d.D.body},host:t=>t?t(d.D.body):d.D.body,prevent:!0}],V=new WeakMap,m={get current(){return C[C.length-1]},get host(){return this.current.host},get signal(){let{host:t}=this;if(V.has(t))return V.get(t);let e=new AbortController;return V.set(t,e),t(y.disconnected(()=>e.abort())),e.signal},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...C]},push(t={}){return C.push(x({},this.current,{prevent:!1},t))},pushRoot(){return C.push(C[0])},pop(){if(C.length!==1)return C.pop()}};function it(...t){return this.appendOriginal(...t),this}function at(t){return t.append===it||(t.appendOriginal=t.append,t.append=it),t}var z;function T(t,e,...n){let r=$(this),o=0,c,s;switch((Object(e)!==e||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let i=(...h)=>h.length?(o===1?n.unshift(...h):h.forEach(b=>b(s)),void 0):s;m.push({scope:t,host:i}),c=t(e||void 0);let p=S(c,d.F);if(c.nodeName==="#comment")break;let E=T.mark({type:"component",name:t.name,host:p?"this":"parentElement"});c.prepend(E),p&&(s=E);break}case t==="#text":c=W.call(this,d.D.createTextNode(""),e);break;case(t==="<>"||!t):c=W.call(this,d.D.createDocumentFragment(),e);break;case!!z:c=W.call(this,d.D.createElementNS(z,t),e);break;case!c:c=W.call(this,d.D.createElement(t),e)}return at(c),s||(s=c),n.forEach(i=>i(s)),o&&m.pop(),o=2,c}T.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=d.D.createComment(``);return e&&(r.end=d.D.createComment("")),r};function Tt(t){let e=this;return function(...r){z=t;let o=T.call(e,...r);return z=void 0,o}}function Mt(t,e=t){let n="\xB9\u2070",r="\u2713",o=Object.fromEntries(Array.from(e.querySelectorAll("slot")).filter(c=>!c.name.endsWith(n)).map(c=>[c.name+=n,c]));if(t.append=new Proxy(t.append,{apply(c,s,i){if(i[0]===e)return c.apply(t,i);for(let p of i){let E=(p.slot||"")+n;try{pt(p,"remove","slot")}catch{}let h=o[E];if(!h)return;h.name.startsWith(r)||(h.childNodes.forEach(b=>b.remove()),h.name=r+E),h.append(p)}return t.append=c,t}}),t!==e){let c=Array.from(t.childNodes);t.append(...c)}return e}var H=new WeakMap,{setDeleteAttr:ut}=d;function W(t,...e){if(!e.length)return t;H.set(t,dt(t,this));for(let[n,r]of Object.entries(x({},...e)))Q.call(this,t,n,r);return H.delete(t),t}function Q(t,e,n){let{setRemoveAttr:r,s:o}=dt(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(i,p)=>Q.call(c,t,i,p));let[s]=e;if(s==="=")return r(e.slice(1),n);if(s===".")return ft(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 ut(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return K(o,e,t,n,ft.bind(null,t[e]));case"ariaset":return K(o,e,t,n,(i,p)=>r("aria-"+i,p));case"classList":return lt.call(c,t,n)}return Pt(t,e)?ut(t,e,n):r(e,n)}function dt(t,e){if(H.has(t))return H.get(t);let r=(S(t,d.S)?jt:qt).bind(null,t,"Attribute"),o=$(e);return{setRemoveAttr:r,s:o}}function lt(t,e){let n=$(this);return K(n,"classList",t,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function pt(t,e,n,r){return S(t,d.H)?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function Pt(t,e){if(!(e in t))return!1;let n=ht(t,e);return!O(n.set)}function ht(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||ht(t,e)}function K(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([i,p]){i&&(i=new c(i),i.target=e,p=t.processReactiveAttribute(n,i,p,o),o(i,p))})}function qt(t,e,n,r){return t[(O(r)?"remove":"set")+e](n,r)}function jt(t,e,n,r,o=null){return t[(O(r)?"remove":"set")+e+"NS"](o,n,r)}function ft(t,e,n){if(Reflect.set(t,e,n),!!O(n))return Reflect.deleteProperty(t,e)}function Wt(t,e,n={}){let r=t.host||t;m.push({scope:r,host:(...s)=>s.length?s.forEach(i=>i(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[N];o||gt(r);let c=e.call(r,n);return o||r.dispatchEvent(new Event(A)),t.nodeType===11&&typeof t.mode=="string"&&r.addEventListener(D,R.observe(t),{once:!0}),m.pop(),t.append(c)}function gt(t){return X(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(A))}),X(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(D)))}),X(t.prototype,"attributeChangedCallback",function(e,n,r){let[o,,c]=r;n.dispatchEvent(new CustomEvent(U,{detail:[o,c]})),e.apply(n,r)}),t.prototype[N]=!0,t}function X(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}var l="__dde_signal",Y=(()=>{let t=new Set,e=!1;function n(){e=!1;let r=t;t=new Set;for(let o of r){let c=o[l];c&&c.listeners.forEach(s=>s(c.value))}}return function(r){t.add(r),!e&&(e=!0,queueMicrotask(n))}})();var et=w(null,{get:{value(){return vt(this)}},set:{value(...t){return _t(this,...t)}},toJSON:{value(){return vt(this)}},valueOf:{value(){return this[l]&&this[l].value}}}),Ft=w(et,{set:{value(){}}});function F(t){return t&&t[l]}var B=[],v=new WeakMap;function g(t,e){if(typeof t!="function")return mt(!1,t,e);if(F(t))return t;let n=mt(!0);function r(){let[o,...c]=v.get(r);if(v.set(r,new Set([o])),B.push(r),_t(n,t()),B.pop(),!c.length)return;let s=v.get(r);for(let i of c)s.has(i)||k(i,r)}return v.set(n[l],r),v.set(r,new Set([n])),r(),n}g.action=function(t,e,...n){let r=t[l];if(!r)return;let{actions:o}=r;if(!o||!Z(o,e))throw new Error(`Action "${e}" not defined. See ${l}.actions.`);if(o[e].apply(r,n),r.skip)return delete r.skip;Y(t)};g.on=function t(e,n,r={}){let{signal:o}=r;if(!(o&&o.aborted)){if(Array.isArray(e))return e.forEach(c=>t(c,n,r));nt(e,n),o&&o.addEventListener("abort",()=>k(e,n))}};g.symbols={onclear:Symbol.for("Signal.onclear")};g.clear=function(...t){for(let n of t){let r=n[l];r&&(delete n.toJSON,r.onclear.forEach(o=>o.call(r)),e(n,r),delete n[l])}function e(n,r){r.listeners.forEach(o=>{if(r.listeners.delete(o),!v.has(o))return;let c=v.get(o);c.delete(n),!(c.size>1)&&(n.clear(...c),v.delete(o))})}};var L="__dde_reactive";function It(t=w()){return(e,n)=>Z(t,e)?t[e]:t[e]=n()}g.el=function(t,e){let n=T.mark({type:"reactive",source:new q().compact},!0),r=n.end,o=d.D.createDocumentFragment();o.append(n,r);let{current:c}=m,s=w(),i=p=>{if(!n.parentNode||!r.parentNode)return k(t,i);let E=It(s);s=w(),m.push(c);let h=e(p,function(a,f){return s[a]=E(a,f)});m.pop(),Array.isArray(h)||(h=[h]);let b=document.createComment("");h.push(b),n.after(...h);let M;for(;(M=b.nextSibling)&&M!==r;)M.remove();b.remove(),n.isConnected&&$t(c.host())};return nt(t,i),xt(t,i,n,e),i(t.get()),c.host(y.disconnected(()=>s={})),o};function $t(t){!t||!t[L]||(requestIdleCallback||setTimeout)(function(){t[L]=t[L].filter(([e,n])=>n.isConnected?!0:(k(...e),!1))})}var Ut={_set(t){this.value=t}};function zt(t){return function(e,n){let r=w(et,{set:{value(...c){return e.setAttribute(n,...c)}}}),o=Et(r,e.getAttribute(n),Ut);return t[n]=o,o}}var tt="__dde_attributes";g.observedAttributes=function(t){let e=t[tt]={},n=ct(t,zt(e));return y(U,function({detail:o}){/*! This maps attributes to signals (`S.observedAttributes`). + Investigate `__dde_attributes` key of the element. */let[c,s]=o,i=this[tt][c];if(i)return g.action(i,"_set",s)})(t),y.disconnected(function(){/*! This removes all signals mapped to attributes (`S.observedAttributes`). + Investigate `__dde_attributes` key of the element. */g.clear(...Object.values(this[tt]))})(t),n};var bt={isSignal:F,processReactiveAttribute(t,e,n,r){if(!F(n))return n;let o=c=>{if(!t.isConnected)return k(n,o);r(e,c)};return nt(n,o),xt(n,o,t,e),n.get()}};function xt(t,e,...n){let{current:r}=m;r.host(function(o){if(o[L])return o[L].push([[t,e],...n]);o[L]=[],!r.prevent&&y.disconnected(()=>o[L].forEach(([[c,s]])=>k(c,s,c[l]&&c[l].host&&c[l].host()===o)))(o)})}var Ht=new FinalizationRegistry(function(t){g.clear({[l]:t})});function mt(t,e,n){let r=w(t?Ft:et),o=Et(r,e,n,t);return Ht.register(o,o[l]),o}var Bt=x(w(),{stopPropagation(){this.skip=!0}});function Et(t,e,n,r=!1){let o=[];rt(n)!=="[object Object]"&&(n={});let{onclear:c}=g.symbols;n[c]&&(o.push(n[c]),delete n[c]);let{host:s}=m;return Reflect.defineProperty(t,l,{value:x(w(Bt),{value:e,actions:n,onclear:o,host:s,listeners:new Set,defined:new q().stack,readonly:r}),enumerable:!1,writable:!1,configurable:!0}),t}function Jt(){return B[B.length-1]}function vt(t){if(!t[l])return;let{value:e,listeners:n}=t[l],r=Jt();return r&&n.add(r),v.has(r)&&v.get(r).add(t),e}function _t(t,e,n){let r=t[l];if(!(!r||!n&&r.value===e))return r.value=e,Y(t),e}function nt(t,e){if(t[l])return t[l].listeners.add(e)}function k(t,e,n){let r=t[l];if(!r)return;let{listeners:o}=r,c=o.delete(e);if(!c||!n||o.size)return c;g.clear(t);let s=v.get(r);if(!s)return c;let i=v.get(s);if(!i)return c;for(let p of i)k(p,s,!0);return c}I(bt);return Ot(Zt);})(); diff --git a/dist/iife.d.ts b/dist/iife.d.ts index 90eed40..7af3916 100644 --- a/dist/iife.d.ts +++ b/dist/iife.d.ts @@ -202,6 +202,10 @@ export const scope: { * — `scope.host(on.connected(console.log))`. * */ host: (...addons: ddeElementAddon[]) => HTMLElement; + /** + * Creates/gets an AbortController that triggers when the element disconnects + * */ + signal: AbortSignal; state: Scope[]; /** Adds new child scope. All attributes are inherited by default. */ push(scope?: Partial): ReturnType["push"]>; diff --git a/dist/iife.js b/dist/iife.js index bc8ad95..5f70394 100644 --- a/dist/iife.js +++ b/dist/iife.js @@ -120,6 +120,215 @@ var DDE = (() => { var evd = "dde:disconnected"; var eva = "dde:attributeChanged"; + // src/events-observer.js + var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { + get() { + return () => { + }; + } + }); + function connectionsChangesObserverConstructor() { + const store = /* @__PURE__ */ new Map(); + let is_observing = false; + const observerListener = (stop2) => function(mutations) { + for (const mutation of mutations) { + if (mutation.type !== "childList") continue; + if (observerAdded(mutation.addedNodes, true)) { + stop2(); + continue; + } + if (observerRemoved(mutation.removedNodes, true)) + stop2(); + } + }; + const observer = new enviroment.M(observerListener(stop)); + return { + /** + * Creates an observer for a specific element + * @param {Element} element - Element to observe + * @returns {Function} Cleanup function + */ + observe(element) { + const o = new enviroment.M(observerListener(() => { + })); + o.observe(element, { childList: true, subtree: true }); + return () => o.disconnect(); + }, + /** + * Register a connection listener for an element + * @param {Element} element - Element to watch + * @param {Function} listener - Callback for connection event + */ + onConnected(element, listener) { + start(); + const listeners = getElementStore(element); + if (listeners.connected.has(listener)) return; + listeners.connected.add(listener); + listeners.length_c += 1; + }, + /** + * Unregister a connection listener + * @param {Element} element - Element being watched + * @param {Function} listener - Callback to remove + */ + offConnected(element, listener) { + if (!store.has(element)) return; + const ls = store.get(element); + if (!ls.connected.has(listener)) return; + ls.connected.delete(listener); + ls.length_c -= 1; + cleanWhenOff(element, ls); + }, + /** + * Register a disconnection listener for an element + * @param {Element} element - Element to watch + * @param {Function} listener - Callback for disconnection event + */ + onDisconnected(element, listener) { + start(); + const listeners = getElementStore(element); + if (listeners.disconnected.has(listener)) return; + listeners.disconnected.add(listener); + listeners.length_d += 1; + }, + /** + * Unregister a disconnection listener + * @param {Element} element - Element being watched + * @param {Function} listener - Callback to remove + */ + offDisconnected(element, listener) { + if (!store.has(element)) return; + const ls = store.get(element); + ls.disconnected.delete(listener); + ls.length_d -= 1; + cleanWhenOff(element, ls); + } + }; + function cleanWhenOff(element, ls) { + if (ls.length_c || ls.length_d) + return; + store.delete(element); + stop(); + } + function getElementStore(element) { + if (store.has(element)) return store.get(element); + const out = { + connected: /* @__PURE__ */ new WeakSet(), + length_c: 0, + disconnected: /* @__PURE__ */ new WeakSet(), + length_d: 0 + }; + store.set(element, out); + return out; + } + function start() { + if (is_observing) return; + is_observing = true; + observer.observe(enviroment.D.body, { childList: true, subtree: true }); + } + function stop() { + if (!is_observing || store.size) return; + is_observing = false; + observer.disconnect(); + } + function requestIdle() { + return new Promise(function(resolve) { + (requestIdleCallback || requestAnimationFrame)(resolve); + }); + } + async function collectChildren(element) { + if (store.size > 30) + await requestIdle(); + const out = []; + if (!isInstance(element, Node)) return out; + for (const el of store.keys()) { + if (el === element || !isInstance(el, Node)) continue; + if (element.contains(el)) + out.push(el); + } + return out; + } + function observerAdded(addedNodes, is_root) { + let out = false; + for (const element of addedNodes) { + if (is_root) collectChildren(element).then(observerAdded); + if (!store.has(element)) continue; + const ls = store.get(element); + if (!ls.length_c) continue; + element.dispatchEvent(new Event(evc)); + ls.connected = /* @__PURE__ */ new WeakSet(); + ls.length_c = 0; + if (!ls.length_d) store.delete(element); + out = true; + } + return out; + } + function observerRemoved(removedNodes, is_root) { + let out = false; + for (const element of removedNodes) { + if (is_root) collectChildren(element).then(observerRemoved); + if (!store.has(element)) continue; + const ls = store.get(element); + if (!ls.length_d) continue; + (globalThis.queueMicrotask || setTimeout)(dispatchRemove(element)); + out = true; + } + return out; + } + function dispatchRemove(element) { + return () => { + if (element.isConnected) return; + element.dispatchEvent(new Event(evd)); + store.delete(element); + }; + } + } + + // src/events.js + function dispatchEvent(name, options, host) { + if (typeof options === "function") { + host = options; + options = null; + } + if (!options) options = {}; + return function dispatch(element, ...d) { + if (host) { + d.unshift(element); + element = typeof host === "function" ? host() : host; + } + const event = d.length ? new CustomEvent(name, oAssign({ detail: d[0] }, options)) : new Event(name, options); + return element.dispatchEvent(event); + }; + } + function on(event, listener, options) { + return function registerElement(element) { + element.addEventListener(event, listener, options); + return element; + }; + } + var lifeOptions = (obj) => oAssign({}, typeof obj === "object" ? obj : null, { once: true }); + on.connected = function(listener, options) { + options = lifeOptions(options); + return function registerElement(element) { + element.addEventListener(evc, listener, options); + if (element[keyLTE]) return element; + if (element.isConnected) return element.dispatchEvent(new Event(evc)), element; + const c = onAbort(options.signal, () => c_ch_o.offConnected(element, listener)); + if (c) c_ch_o.onConnected(element, listener); + return element; + }; + }; + on.disconnected = function(listener, options) { + options = lifeOptions(options); + return function registerElement(element) { + element.addEventListener(evd, listener, options); + if (element[keyLTE]) return element; + const c = onAbort(options.signal, () => c_ch_o.offDisconnected(element, listener)); + if (c) c_ch_o.onDisconnected(element, listener); + return element; + }; + }; + // src/dom.js function queue(promise) { return enviroment.q(promise); @@ -131,6 +340,7 @@ var DDE = (() => { host: (c) => c ? c(enviroment.D.body) : enviroment.D.body, prevent: true }]; + var store_abort = /* @__PURE__ */ new WeakMap(); var scope = { /** * Gets the current scope @@ -147,6 +357,17 @@ var DDE = (() => { return this.current.host; }, /** + * Creates/gets an AbortController that triggers when the element disconnects + * */ + get signal() { + const { host } = this; + if (store_abort.has(host)) return store_abort.get(host); + const a = new AbortController(); + store_abort.set(host, a); + host(on.disconnected(() => a.abort())); + return a.signal; + }, + /** * Prevents default behavior in the current scope * @returns {Object} Current scope context */ @@ -389,170 +610,6 @@ var DDE = (() => { return Reflect.deleteProperty(obj, key); } - // src/events-observer.js - var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, { - get() { - return () => { - }; - } - }); - function connectionsChangesObserverConstructor() { - const store = /* @__PURE__ */ new Map(); - let is_observing = false; - const observerListener = (stop2) => function(mutations) { - for (const mutation of mutations) { - if (mutation.type !== "childList") continue; - if (observerAdded(mutation.addedNodes, true)) { - stop2(); - continue; - } - if (observerRemoved(mutation.removedNodes, true)) - stop2(); - } - }; - const observer = new enviroment.M(observerListener(stop)); - return { - /** - * Creates an observer for a specific element - * @param {Element} element - Element to observe - * @returns {Function} Cleanup function - */ - observe(element) { - const o = new enviroment.M(observerListener(() => { - })); - o.observe(element, { childList: true, subtree: true }); - return () => o.disconnect(); - }, - /** - * Register a connection listener for an element - * @param {Element} element - Element to watch - * @param {Function} listener - Callback for connection event - */ - onConnected(element, listener) { - start(); - const listeners = getElementStore(element); - if (listeners.connected.has(listener)) return; - listeners.connected.add(listener); - listeners.length_c += 1; - }, - /** - * Unregister a connection listener - * @param {Element} element - Element being watched - * @param {Function} listener - Callback to remove - */ - offConnected(element, listener) { - if (!store.has(element)) return; - const ls = store.get(element); - if (!ls.connected.has(listener)) return; - ls.connected.delete(listener); - ls.length_c -= 1; - cleanWhenOff(element, ls); - }, - /** - * Register a disconnection listener for an element - * @param {Element} element - Element to watch - * @param {Function} listener - Callback for disconnection event - */ - onDisconnected(element, listener) { - start(); - const listeners = getElementStore(element); - if (listeners.disconnected.has(listener)) return; - listeners.disconnected.add(listener); - listeners.length_d += 1; - }, - /** - * Unregister a disconnection listener - * @param {Element} element - Element being watched - * @param {Function} listener - Callback to remove - */ - offDisconnected(element, listener) { - if (!store.has(element)) return; - const ls = store.get(element); - ls.disconnected.delete(listener); - ls.length_d -= 1; - cleanWhenOff(element, ls); - } - }; - function cleanWhenOff(element, ls) { - if (ls.length_c || ls.length_d) - return; - store.delete(element); - stop(); - } - function getElementStore(element) { - if (store.has(element)) return store.get(element); - const out = { - connected: /* @__PURE__ */ new WeakSet(), - length_c: 0, - disconnected: /* @__PURE__ */ new WeakSet(), - length_d: 0 - }; - store.set(element, out); - return out; - } - function start() { - if (is_observing) return; - is_observing = true; - observer.observe(enviroment.D.body, { childList: true, subtree: true }); - } - function stop() { - if (!is_observing || store.size) return; - is_observing = false; - observer.disconnect(); - } - function requestIdle() { - return new Promise(function(resolve) { - (requestIdleCallback || requestAnimationFrame)(resolve); - }); - } - async function collectChildren(element) { - if (store.size > 30) - await requestIdle(); - const out = []; - if (!isInstance(element, Node)) return out; - for (const el of store.keys()) { - if (el === element || !isInstance(el, Node)) continue; - if (element.contains(el)) - out.push(el); - } - return out; - } - function observerAdded(addedNodes, is_root) { - let out = false; - for (const element of addedNodes) { - if (is_root) collectChildren(element).then(observerAdded); - if (!store.has(element)) continue; - const ls = store.get(element); - if (!ls.length_c) continue; - element.dispatchEvent(new Event(evc)); - ls.connected = /* @__PURE__ */ new WeakSet(); - ls.length_c = 0; - if (!ls.length_d) store.delete(element); - out = true; - } - return out; - } - function observerRemoved(removedNodes, is_root) { - let out = false; - for (const element of removedNodes) { - if (is_root) collectChildren(element).then(observerRemoved); - if (!store.has(element)) continue; - const ls = store.get(element); - if (!ls.length_d) continue; - (globalThis.queueMicrotask || setTimeout)(dispatchRemove(element)); - out = true; - } - return out; - } - function dispatchRemove(element) { - return () => { - if (element.isConnected) return; - element.dispatchEvent(new Event(evd)); - store.delete(element); - }; - } - } - // src/customElement.js function customElementRender(target, render, props = {}) { const custom_element = target.host || target; @@ -595,58 +652,5 @@ var DDE = (() => { obj[method] = new Proxy(obj[method] || (() => { }), { apply }); } - - // src/events.js - function dispatchEvent(name, options, host) { - if (typeof options === "function") { - host = options; - options = null; - } - if (!options) options = {}; - return function dispatch(element, ...d) { - if (host) { - d.unshift(element); - element = typeof host === "function" ? host() : host; - } - const event = d.length ? new CustomEvent(name, oAssign({ detail: d[0] }, options)) : new Event(name, options); - return element.dispatchEvent(event); - }; - } - function on(event, listener, options) { - return function registerElement(element) { - element.addEventListener(event, listener, options); - return element; - }; - } - var lifeOptions = (obj) => oAssign({}, typeof obj === "object" ? obj : null, { once: true }); - on.connected = function(listener, options) { - options = lifeOptions(options); - return function registerElement(element) { - element.addEventListener(evc, listener, options); - if (element[keyLTE]) return element; - if (element.isConnected) return element.dispatchEvent(new Event(evc)), element; - const c = onAbort(options.signal, () => c_ch_o.offConnected(element, listener)); - if (c) c_ch_o.onConnected(element, listener); - return element; - }; - }; - on.disconnected = function(listener, options) { - options = lifeOptions(options); - return function registerElement(element) { - element.addEventListener(evd, listener, options); - if (element[keyLTE]) return element; - const c = onAbort(options.signal, () => c_ch_o.offDisconnected(element, listener)); - if (c) c_ch_o.onDisconnected(element, listener); - return element; - }; - }; - var store_abort = /* @__PURE__ */ new WeakMap(); - on.disconnectedAsAbort = function(host) { - if (store_abort.has(host)) return store_abort.get(host); - const a = new AbortController(); - store_abort.set(host, a); - host(on.disconnected(() => a.abort())); - return a.signal; - }; return __toCommonJS(index_exports); })(); diff --git a/dist/iife.min.d.ts b/dist/iife.min.d.ts index 90eed40..7af3916 100644 --- a/dist/iife.min.d.ts +++ b/dist/iife.min.d.ts @@ -202,6 +202,10 @@ export const scope: { * — `scope.host(on.connected(console.log))`. * */ host: (...addons: ddeElementAddon[]) => HTMLElement; + /** + * Creates/gets an AbortController that triggers when the element disconnects + * */ + signal: AbortSignal; state: Scope[]; /** Adds new child scope. All attributes are inherited by default. */ push(scope?: Partial): ReturnType["push"]>; diff --git a/dist/iife.min.js b/dist/iife.min.js index cc3c822..a9832cc 100644 --- a/dist/iife.min.js +++ b/dist/iife.min.js @@ -1 +1 @@ -var DDE=(()=>{var M=Object.defineProperty;var tt=Object.getOwnPropertyDescriptor;var et=Object.getOwnPropertyNames;var nt=Object.prototype.hasOwnProperty;var rt=(t,e)=>{for(var n in e)M(t,n,{get:e[n],enumerable:!0})},ot=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of et(e))!nt.call(t,o)&&o!==n&&M(t,o,{get:()=>e[o],enumerable:!(r=tt(e,o))||r.enumerable});return t};var ct=t=>ot(M({},"__esModule",{value:!0}),t);var bt={};rt(bt,{assign:()=>S,assignAttribute:()=>q,chainableAppend:()=>Z,classListDeclarative:()=>V,createElement:()=>P,createElementNS:()=>ut,customElementRender:()=>ht,customElementWithDDE:()=>Q,dispatchEvent:()=>gt,el:()=>P,elNS:()=>ut,elementAttribute:()=>J,lifecyclesToEvents:()=>Q,on:()=>L,queue:()=>it,registerReactivity:()=>$,scope:()=>y,simulateSlots:()=>ft});function w(t){return typeof t>"u"}function g(t,e){return t instanceof e}function I(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function v(...t){return Object.assign(...t)}function j(t,e){if(!t||!g(t,AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}var D={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function $(t,e=!0){return e?v(D,t):(Object.setPrototypeOf(t,D),t)}function R(t){return I(t,D)&&t!==D?t:D}var a={setDeleteAttr:st,ssr:"",D:globalThis.document,F:globalThis.DocumentFragment,H:globalThis.HTMLElement,S:globalThis.SVGElement,M:globalThis.MutationObserver,q:t=>t||Promise.resolve()};function st(t,e,n){if(Reflect.set(t,e,n),!!w(n)){if(Reflect.deleteProperty(t,e),g(t,a.H)&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var O="__dde_lifecyclesToEvents",m="dde:connected",_="dde:disconnected",U="dde:attributeChanged";function it(t){return a.q(t)}var x=[{get scope(){return a.D.body},host:t=>t?t(a.D.body):a.D.body,prevent:!0}],y={get current(){return x[x.length-1]},get host(){return this.current.host},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...x]},push(t={}){return x.push(v({},this.current,{prevent:!1},t))},pushRoot(){return x.push(x[0])},pop(){if(x.length!==1)return x.pop()}};function H(...t){return this.appendOriginal(...t),this}function Z(t){return t.append===H||(t.appendOriginal=t.append,t.append=H),t}var T;function P(t,e,...n){let r=R(this),o=0,c,d;switch((Object(e)!==e||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let f=(...l)=>l.length?(o===1?n.unshift(...l):l.forEach(E=>E(d)),void 0):d;y.push({scope:t,host:f}),c=t(e||void 0);let p=g(c,a.F);if(c.nodeName==="#comment")break;let b=P.mark({type:"component",name:t.name,host:p?"this":"parentElement"});c.prepend(b),p&&(d=b);break}case t==="#text":c=S.call(this,a.D.createTextNode(""),e);break;case(t==="<>"||!t):c=S.call(this,a.D.createDocumentFragment(),e);break;case!!T:c=S.call(this,a.D.createElementNS(T,t),e);break;case!c:c=S.call(this,a.D.createElement(t),e)}return Z(c),d||(d=c),n.forEach(f=>f(d)),o&&y.pop(),o=2,c}P.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=a.D.createComment(``);return e&&(r.end=a.D.createComment("")),r};function ut(t){let e=this;return function(...r){T=t;let o=P.call(e,...r);return T=void 0,o}}function ft(t,e=t){let n="\xB9\u2070",r="\u2713",o=Object.fromEntries(Array.from(e.querySelectorAll("slot")).filter(c=>!c.name.endsWith(n)).map(c=>[c.name+=n,c]));if(t.append=new Proxy(t.append,{apply(c,d,f){if(f[0]===e)return c.apply(t,f);for(let p of f){let b=(p.slot||"")+n;try{J(p,"remove","slot")}catch{}let l=o[b];if(!l)return;l.name.startsWith(r)||(l.childNodes.forEach(E=>E.remove()),l.name=r+b),l.append(p)}return t.append=c,t}}),t!==e){let c=Array.from(t.childNodes);t.append(...c)}return e}var N=new WeakMap,{setDeleteAttr:z}=a;function S(t,...e){if(!e.length)return t;N.set(t,G(t,this));for(let[n,r]of Object.entries(v({},...e)))q.call(this,t,n,r);return N.delete(t),t}function q(t,e,n){let{setRemoveAttr:r,s:o}=G(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(f,p)=>q.call(c,t,f,p));let[d]=e;if(d==="=")return r(e.slice(1),n);if(d===".")return B(t,e.slice(1),n);if(/(aria|data)([A-Z])/.test(e))return e=e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),r(e,n);switch(e==="className"&&(e="class"),e){case"xlink:href":return r(e,n,"http://www.w3.org/1999/xlink");case"textContent":return z(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return k(o,e,t,n,B.bind(null,t[e]));case"ariaset":return k(o,e,t,n,(f,p)=>r("aria-"+f,p));case"classList":return V.call(c,t,n)}return at(t,e)?z(t,e,n):r(e,n)}function G(t,e){if(N.has(t))return N.get(t);let r=(g(t,a.S)?pt:dt).bind(null,t,"Attribute"),o=R(e);return{setRemoveAttr:r,s:o}}function V(t,e){let n=R(this);return k(n,"classList",t,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function J(t,e,n,r){return g(t,a.H)?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function at(t,e){if(!(e in t))return!1;let n=K(t,e);return!w(n.set)}function K(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||K(t,e)}function k(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([f,p]){f&&(f=new c(f),f.target=e,p=t.processReactiveAttribute(n,f,p,o),o(f,p))})}function dt(t,e,n,r){return t[(w(r)?"remove":"set")+e](n,r)}function pt(t,e,n,r,o=null){return t[(w(r)?"remove":"set")+e+"NS"](o,n,r)}function B(t,e,n){if(Reflect.set(t,e,n),!!w(n))return Reflect.deleteProperty(t,e)}var A=a.M?lt():new Proxy({},{get(){return()=>{}}});function lt(){let t=new Map,e=!1,n=s=>function(u){for(let i of u)if(i.type==="childList"){if(l(i.addedNodes,!0)){s();continue}E(i.removedNodes,!0)&&s()}},r=new a.M(n(f));return{observe(s){let u=new a.M(n(()=>{}));return u.observe(s,{childList:!0,subtree:!0}),()=>u.disconnect()},onConnected(s,u){d();let i=c(s);i.connected.has(u)||(i.connected.add(u),i.length_c+=1)},offConnected(s,u){if(!t.has(s))return;let i=t.get(s);i.connected.has(u)&&(i.connected.delete(u),i.length_c-=1,o(s,i))},onDisconnected(s,u){d();let i=c(s);i.disconnected.has(u)||(i.disconnected.add(u),i.length_d+=1)},offDisconnected(s,u){if(!t.has(s))return;let i=t.get(s);i.disconnected.delete(u),i.length_d-=1,o(s,i)}};function o(s,u){u.length_c||u.length_d||(t.delete(s),f())}function c(s){if(t.has(s))return t.get(s);let u={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(s,u),u}function d(){e||(e=!0,r.observe(a.D.body,{childList:!0,subtree:!0}))}function f(){!e||t.size||(e=!1,r.disconnect())}function p(){return new Promise(function(s){(requestIdleCallback||requestAnimationFrame)(s)})}async function b(s){t.size>30&&await p();let u=[];if(!g(s,Node))return u;for(let i of t.keys())i===s||!g(i,Node)||s.contains(i)&&u.push(i);return u}function l(s,u){let i=!1;for(let h of s){if(u&&b(h).then(l),!t.has(h))continue;let C=t.get(h);C.length_c&&(h.dispatchEvent(new Event(m)),C.connected=new WeakSet,C.length_c=0,C.length_d||t.delete(h),i=!0)}return i}function E(s,u){let i=!1;for(let h of s)u&&b(h).then(E),!(!t.has(h)||!t.get(h).length_d)&&((globalThis.queueMicrotask||setTimeout)(Y(h)),i=!0);return i}function Y(s){return()=>{s.isConnected||(s.dispatchEvent(new Event(_)),t.delete(s))}}}function ht(t,e,n={}){let r=t.host||t;y.push({scope:r,host:(...d)=>d.length?d.forEach(f=>f(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[O];o||Q(r);let c=e.call(r,n);return o||r.dispatchEvent(new Event(m)),t.nodeType===11&&typeof t.mode=="string"&&r.addEventListener(_,A.observe(t),{once:!0}),y.pop(),t.append(c)}function Q(t){return W(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(m))}),W(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(_)))}),W(t.prototype,"attributeChangedCallback",function(e,n,r){let[o,,c]=r;n.dispatchEvent(new CustomEvent(U,{detail:[o,c]})),e.apply(n,r)}),t.prototype[O]=!0,t}function W(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}function gt(t,e,n){return typeof e=="function"&&(n=e,e=null),e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let d=c.length?new CustomEvent(t,v({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(d)}}function L(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var X=t=>v({},typeof t=="object"?t:null,{once:!0});L.connected=function(t,e){return e=X(e),function(r){return r.addEventListener(m,t,e),r[O]?r:r.isConnected?(r.dispatchEvent(new Event(m)),r):(j(e.signal,()=>A.offConnected(r,t))&&A.onConnected(r,t),r)}};L.disconnected=function(t,e){return e=X(e),function(r){return r.addEventListener(_,t,e),r[O]||j(e.signal,()=>A.offDisconnected(r,t))&&A.onDisconnected(r,t),r}};var F=new WeakMap;L.disconnectedAsAbort=function(t){if(F.has(t))return F.get(t);let e=new AbortController;return F.set(t,e),t(L.disconnected(()=>e.abort())),e.signal};return ct(bt);})(); +var DDE=(()=>{var M=Object.defineProperty;var tt=Object.getOwnPropertyDescriptor;var et=Object.getOwnPropertyNames;var nt=Object.prototype.hasOwnProperty;var rt=(t,e)=>{for(var n in e)M(t,n,{get:e[n],enumerable:!0})},ot=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of et(e))!nt.call(t,o)&&o!==n&&M(t,o,{get:()=>e[o],enumerable:!(r=tt(e,o))||r.enumerable});return t};var ct=t=>ot(M({},"__esModule",{value:!0}),t);var bt={};rt(bt,{assign:()=>L,assignAttribute:()=>W,chainableAppend:()=>G,classListDeclarative:()=>J,createElement:()=>P,createElementNS:()=>at,customElementRender:()=>gt,customElementWithDDE:()=>X,dispatchEvent:()=>ut,el:()=>P,elNS:()=>at,elementAttribute:()=>K,lifecyclesToEvents:()=>X,on:()=>S,queue:()=>ft,registerReactivity:()=>$,scope:()=>C,simulateSlots:()=>dt});function w(t){return typeof t>"u"}function g(t,e){return t instanceof e}function I(t,e){return Object.prototype.isPrototypeOf.call(e,t)}function v(...t){return Object.assign(...t)}function j(t,e){if(!t||!g(t,AbortSignal))return!0;if(!t.aborted)return t.addEventListener("abort",e),function(){t.removeEventListener("abort",e)}}var D={isSignal(t){return!1},processReactiveAttribute(t,e,n,r){return n}};function $(t,e=!0){return e?v(D,t):(Object.setPrototypeOf(t,D),t)}function R(t){return I(t,D)&&t!==D?t:D}var a={setDeleteAttr:st,ssr:"",D:globalThis.document,F:globalThis.DocumentFragment,H:globalThis.HTMLElement,S:globalThis.SVGElement,M:globalThis.MutationObserver,q:t=>t||Promise.resolve()};function st(t,e,n){if(Reflect.set(t,e,n),!!w(n)){if(Reflect.deleteProperty(t,e),g(t,a.H)&&t.getAttribute(e)==="undefined")return t.removeAttribute(e);if(Reflect.get(t,e)==="undefined")return Reflect.set(t,e,"")}}var y="__dde_lifecyclesToEvents",m="dde:connected",_="dde:disconnected",U="dde:attributeChanged";var O=a.M?it():new Proxy({},{get(){return()=>{}}});function it(){let t=new Map,e=!1,n=s=>function(u){for(let i of u)if(i.type==="childList"){if(l(i.addedNodes,!0)){s();continue}E(i.removedNodes,!0)&&s()}},r=new a.M(n(f));return{observe(s){let u=new a.M(n(()=>{}));return u.observe(s,{childList:!0,subtree:!0}),()=>u.disconnect()},onConnected(s,u){d();let i=c(s);i.connected.has(u)||(i.connected.add(u),i.length_c+=1)},offConnected(s,u){if(!t.has(s))return;let i=t.get(s);i.connected.has(u)&&(i.connected.delete(u),i.length_c-=1,o(s,i))},onDisconnected(s,u){d();let i=c(s);i.disconnected.has(u)||(i.disconnected.add(u),i.length_d+=1)},offDisconnected(s,u){if(!t.has(s))return;let i=t.get(s);i.disconnected.delete(u),i.length_d-=1,o(s,i)}};function o(s,u){u.length_c||u.length_d||(t.delete(s),f())}function c(s){if(t.has(s))return t.get(s);let u={connected:new WeakSet,length_c:0,disconnected:new WeakSet,length_d:0};return t.set(s,u),u}function d(){e||(e=!0,r.observe(a.D.body,{childList:!0,subtree:!0}))}function f(){!e||t.size||(e=!1,r.disconnect())}function p(){return new Promise(function(s){(requestIdleCallback||requestAnimationFrame)(s)})}async function b(s){t.size>30&&await p();let u=[];if(!g(s,Node))return u;for(let i of t.keys())i===s||!g(i,Node)||s.contains(i)&&u.push(i);return u}function l(s,u){let i=!1;for(let h of s){if(u&&b(h).then(l),!t.has(h))continue;let A=t.get(h);A.length_c&&(h.dispatchEvent(new Event(m)),A.connected=new WeakSet,A.length_c=0,A.length_d||t.delete(h),i=!0)}return i}function E(s,u){let i=!1;for(let h of s)u&&b(h).then(E),!(!t.has(h)||!t.get(h).length_d)&&((globalThis.queueMicrotask||setTimeout)(Y(h)),i=!0);return i}function Y(s){return()=>{s.isConnected||(s.dispatchEvent(new Event(_)),t.delete(s))}}}function ut(t,e,n){return typeof e=="function"&&(n=e,e=null),e||(e={}),function(o,...c){n&&(c.unshift(o),o=typeof n=="function"?n():n);let d=c.length?new CustomEvent(t,v({detail:c[0]},e)):new Event(t,e);return o.dispatchEvent(d)}}function S(t,e,n){return function(o){return o.addEventListener(t,e,n),o}}var H=t=>v({},typeof t=="object"?t:null,{once:!0});S.connected=function(t,e){return e=H(e),function(r){return r.addEventListener(m,t,e),r[y]?r:r.isConnected?(r.dispatchEvent(new Event(m)),r):(j(e.signal,()=>O.offConnected(r,t))&&O.onConnected(r,t),r)}};S.disconnected=function(t,e){return e=H(e),function(r){return r.addEventListener(_,t,e),r[y]||j(e.signal,()=>O.offDisconnected(r,t))&&O.onDisconnected(r,t),r}};function ft(t){return a.q(t)}var x=[{get scope(){return a.D.body},host:t=>t?t(a.D.body):a.D.body,prevent:!0}],k=new WeakMap,C={get current(){return x[x.length-1]},get host(){return this.current.host},get signal(){let{host:t}=this;if(k.has(t))return k.get(t);let e=new AbortController;return k.set(t,e),t(S.disconnected(()=>e.abort())),e.signal},preventDefault(){let{current:t}=this;return t.prevent=!0,t},get state(){return[...x]},push(t={}){return x.push(v({},this.current,{prevent:!1},t))},pushRoot(){return x.push(x[0])},pop(){if(x.length!==1)return x.pop()}};function z(...t){return this.appendOriginal(...t),this}function G(t){return t.append===z||(t.appendOriginal=t.append,t.append=z),t}var T;function P(t,e,...n){let r=R(this),o=0,c,d;switch((Object(e)!==e||r.isSignal(e))&&(e={textContent:e}),!0){case typeof t=="function":{o=1;let f=(...l)=>l.length?(o===1?n.unshift(...l):l.forEach(E=>E(d)),void 0):d;C.push({scope:t,host:f}),c=t(e||void 0);let p=g(c,a.F);if(c.nodeName==="#comment")break;let b=P.mark({type:"component",name:t.name,host:p?"this":"parentElement"});c.prepend(b),p&&(d=b);break}case t==="#text":c=L.call(this,a.D.createTextNode(""),e);break;case(t==="<>"||!t):c=L.call(this,a.D.createDocumentFragment(),e);break;case!!T:c=L.call(this,a.D.createElementNS(T,t),e);break;case!c:c=L.call(this,a.D.createElement(t),e)}return G(c),d||(d=c),n.forEach(f=>f(d)),o&&C.pop(),o=2,c}P.mark=function(t,e=!1){t=Object.entries(t).map(([o,c])=>o+`="${c}"`).join(" ");let n=e?"":"/",r=a.D.createComment(``);return e&&(r.end=a.D.createComment("")),r};function at(t){let e=this;return function(...r){T=t;let o=P.call(e,...r);return T=void 0,o}}function dt(t,e=t){let n="\xB9\u2070",r="\u2713",o=Object.fromEntries(Array.from(e.querySelectorAll("slot")).filter(c=>!c.name.endsWith(n)).map(c=>[c.name+=n,c]));if(t.append=new Proxy(t.append,{apply(c,d,f){if(f[0]===e)return c.apply(t,f);for(let p of f){let b=(p.slot||"")+n;try{K(p,"remove","slot")}catch{}let l=o[b];if(!l)return;l.name.startsWith(r)||(l.childNodes.forEach(E=>E.remove()),l.name=r+b),l.append(p)}return t.append=c,t}}),t!==e){let c=Array.from(t.childNodes);t.append(...c)}return e}var N=new WeakMap,{setDeleteAttr:B}=a;function L(t,...e){if(!e.length)return t;N.set(t,V(t,this));for(let[n,r]of Object.entries(v({},...e)))W.call(this,t,n,r);return N.delete(t),t}function W(t,e,n){let{setRemoveAttr:r,s:o}=V(t,this),c=this;n=o.processReactiveAttribute(t,e,n,(f,p)=>W.call(c,t,f,p));let[d]=e;if(d==="=")return r(e.slice(1),n);if(d===".")return Z(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 B(t,e,n);case"style":if(typeof n!="object")break;case"dataset":return q(o,e,t,n,Z.bind(null,t[e]));case"ariaset":return q(o,e,t,n,(f,p)=>r("aria-"+f,p));case"classList":return J.call(c,t,n)}return pt(t,e)?B(t,e,n):r(e,n)}function V(t,e){if(N.has(t))return N.get(t);let r=(g(t,a.S)?ht:lt).bind(null,t,"Attribute"),o=R(e);return{setRemoveAttr:r,s:o}}function J(t,e){let n=R(this);return q(n,"classList",t,e,(r,o)=>t.classList.toggle(r,o===-1?void 0:!!o)),t}function K(t,e,n,r){return g(t,a.H)?t[e+"Attribute"](n,r):t[e+"AttributeNS"](null,n,r)}function pt(t,e){if(!(e in t))return!1;let n=Q(t,e);return!w(n.set)}function Q(t,e){if(t=Object.getPrototypeOf(t),!t)return{};let n=Object.getOwnPropertyDescriptor(t,e);return n||Q(t,e)}function q(t,e,n,r,o){let c=String;if(!(typeof r!="object"||r===null))return Object.entries(r).forEach(function([f,p]){f&&(f=new c(f),f.target=e,p=t.processReactiveAttribute(n,f,p,o),o(f,p))})}function lt(t,e,n,r){return t[(w(r)?"remove":"set")+e](n,r)}function ht(t,e,n,r,o=null){return t[(w(r)?"remove":"set")+e+"NS"](o,n,r)}function Z(t,e,n){if(Reflect.set(t,e,n),!!w(n))return Reflect.deleteProperty(t,e)}function gt(t,e,n={}){let r=t.host||t;C.push({scope:r,host:(...d)=>d.length?d.forEach(f=>f(r)):r}),typeof n=="function"&&(n=n.call(r,r));let o=r[y];o||X(r);let c=e.call(r,n);return o||r.dispatchEvent(new Event(m)),t.nodeType===11&&typeof t.mode=="string"&&r.addEventListener(_,O.observe(t),{once:!0}),C.pop(),t.append(c)}function X(t){return F(t.prototype,"connectedCallback",function(e,n,r){e.apply(n,r),n.dispatchEvent(new Event(m))}),F(t.prototype,"disconnectedCallback",function(e,n,r){e.apply(n,r),(globalThis.queueMicrotask||setTimeout)(()=>!n.isConnected&&n.dispatchEvent(new Event(_)))}),F(t.prototype,"attributeChangedCallback",function(e,n,r){let[o,,c]=r;n.dispatchEvent(new CustomEvent(U,{detail:[o,c]})),e.apply(n,r)}),t.prototype[y]=!0,t}function F(t,e,n){t[e]=new Proxy(t[e]||(()=>{}),{apply:n})}return ct(bt);})(); diff --git a/docs/components/mnemonic/scopes-init.js b/docs/components/mnemonic/scopes-init.js index 62dd70d..8b1c446 100644 --- a/docs/components/mnemonic/scopes-init.js +++ b/docs/components/mnemonic/scopes-init.js @@ -14,6 +14,10 @@ export function mnemonic(){ el("li").append( el("code", "scope.host(...)"), " — use addons to current component", + ), + el("li").append( + el("code", "scope.signal"), + " — get AbortSignal that triggers when the element disconnects", ) ); } diff --git a/docs/p08-extensions.html.js b/docs/p08-extensions.html.js index 194e0b6..46ad1a4 100644 --- a/docs/p08-extensions.html.js +++ b/docs/p08-extensions.html.js @@ -59,7 +59,7 @@ el("div", { id: "example" }, myAddon({ option: "value" })); `), el("div", { className: "tip" }).append( el("p").append(...T` - The ${el("code", "on.disconnectedAsAbort")} utility creates an AbortSignal that automatically + The ${el("code", "scope.signal")} property creates an AbortSignal that automatically triggers when an element is disconnected from the DOM, making cleanup much easier to manage. `) ), @@ -80,8 +80,7 @@ function externalLibraryAddon(config, signal) { } // dde component function Component(){ - const { host }= scope; - const signal= on.disconnectedAsAbort(host); + const { signal }= scope; return el("div", null, externalLibraryAddon({ option: "value" }, signal)); } `.trim(), page_id }), @@ -213,7 +212,7 @@ console.log(doubled.get()); // 10`, page_id }), el("ol").append( el("li").append(...T` ${el("strong", "Use AbortSignals for cleanup:")} Always implement proper resource cleanup with - ${el("code", "on.disconnectedAsAbort")} or similar mechanisms + ${el("code", "scope.signal")} or similar mechanisms `), el("li").append(...T` ${el("strong", "Separate core logic from library adaptation:")} Make your core functionality work diff --git a/index.d.ts b/index.d.ts index 1a94076..f9e5d47 100644 --- a/index.d.ts +++ b/index.d.ts @@ -243,6 +243,11 @@ export const scope: { * */ host: (...addons: ddeElementAddon[])=> HTMLElement, + /** + * Creates/gets an AbortController that triggers when the element disconnects + * */ + signal: AbortSignal, + state: Scope[], /** Adds new child scope. All attributes are inherited by default. */ push(scope?: Partial): ReturnType["push"]>, diff --git a/src/dom.js b/src/dom.js index dc3da60..8859e52 100644 --- a/src/dom.js +++ b/src/dom.js @@ -1,6 +1,7 @@ import { signals } from "./signals-lib/common.js"; import { enviroment as env } from './dom-common.js'; import { isInstance, isUndef, oAssign } from "./helpers.js"; +import { on } from "./events.js"; /** * Queues a promise, this is helpful for crossplatform components (on server side we can wait for all registered @@ -19,6 +20,8 @@ const scopes= [ { host: c=> c ? c(env.D.body) : env.D.body, prevent: true, } ]; +/** Store for disconnect abort controllers */ +const store_abort= new WeakMap(); /** * Scope management utility for tracking component hierarchies */ @@ -35,6 +38,19 @@ export const scope= { */ get host(){ return this.current.host; }, + /** + * Creates/gets an AbortController that triggers when the element disconnects + * */ + get signal(){ + const { host }= this; + if(store_abort.has(host)) return store_abort.get(host); + + const a= new AbortController(); + store_abort.set(host, a); + host(on.disconnected(()=> a.abort())); + return a.signal; + }, + /** * Prevents default behavior in the current scope * @returns {Object} Current scope context diff --git a/src/events.js b/src/events.js index 5c55b94..5fbaf95 100644 --- a/src/events.js +++ b/src/events.js @@ -88,21 +88,3 @@ on.disconnected= function(listener, options){ return element; }; }; - -/** Store for disconnect abort controllers */ -const store_abort= new WeakMap(); - -/** - * Creates an AbortController that triggers when the element disconnects - * - * @param {Function} host - Host element or function taking an element - * @returns {AbortSignal} AbortSignal that aborts on disconnect - */ -on.disconnectedAsAbort= function(host){ - if(store_abort.has(host)) return store_abort.get(host); - - const a= new AbortController(); - store_abort.set(host, a); - host(on.disconnected(()=> a.abort())); - return a.signal; -};