hooktml
Version:
A reactive HTML component library with hooks-based lifecycle management
4 lines (3 loc) • 26.2 kB
JavaScript
(()=>{var E=e=>e===null||typeof e>"u",Q=e=>typeof e>"u",k=e=>!E(e),Ae=e=>typeof e=="string"&&e.trim()!==""&&!isNaN(Number(e)),v=e=>typeof e=="string",Z=e=>v(e)&&e.length>0,A=e=>v(e)&&e.length===0,N=e=>typeof e=="object"&&e!==null&&!Array.isArray(e)&&Object.keys(e).length>0,m=e=>typeof e=="function",R=e=>Array.isArray(e),x=e=>R(e)&&e.length===0,w=e=>R(e)&&e.length>0,g=e=>e instanceof HTMLElement,de=e=>!e||typeof e!="object"?!1:!!(e instanceof HTMLElement||e===document||"nodeType"in e&&e.nodeType===9&&"addEventListener"in e&&m(e.addEventListener)||e===window||"window"in e&&e.window===e&&"addEventListener"in e&&m(e.addEventListener)),$e=e=>w(e)&&e.every(de),D=e=>w(e)&&e.every(g),J=e=>typeof e=="object"&&e!==null&&!Array.isArray(e),T=e=>N(e)&&"value"in e&&"subscribe"in e&&m(e.subscribe);var Ne={componentPath:void 0,debug:!1,attributePrefix:"",formattedPrefix:""},Re={...Ne},nt=e=>E(e)||!v(e)||A(e)?"":e.endsWith("-")?e:`${e}-`,ze=(e={})=>{let t={...e};"attributePrefix"in t&&(t.formattedPrefix=nt(t.attributePrefix)),Re={...Ne,...t}},y=()=>({...Re});var Y=e=>`[HookTML] ${e}`,a={log:(e,...t)=>{let{debug:r}=y();r&&m(console.log)&&console.log(Y(e),...t)},info:(e,...t)=>{let{debug:r}=y();r&&m(console.info)&&console.info(Y(e),...t)},warn:(e,...t)=>{m(console.warn)&&console.warn(Y(e),...t)},error:(e,...t)=>{m(console.error)&&console.error(Y(e),...t)}};var Ie=e=>A(e)?!1:e.startsWith("use")&&e.length>3,X=new Map,he=new Map,ye=e=>{if(!m(e))return a.warn("Invalid hook: must be a function"),!1;let t=e.name;if(A(t))return a.warn("Invalid hook: must be a named function"),!1;if(!Ie(t))return a.warn(`Invalid hook name: "${t}". Hook names must start with "use"`),!1;let r=!X.has(t);return r&&(X.set(t,e),a.log(`Registered hook: ${t}`)),r},Ee=e=>{if(!m(e))return a.warn("Invalid chainable hook: must be a function"),!1;let t=e.name;if(A(t))return a.warn("Invalid chainable hook: must be a named function"),!1;if(!Ie(t))return a.warn(`Invalid chainable hook name: "${t}". Hook names must start with "use"`),!1;let r=!he.has(t);return r&&(he.set(t,e),a.log(`Registered chainable hook: ${t}`)),r};var De=e=>{if(v(e))return X.get(e)};var z=()=>new Map(X),ee=()=>new Map(he);var b=({fn:e,onError:t,onFinally:r})=>{try{return e()}catch(o){return t(o)}finally{k(r)&&r()}};var P=[],te=new WeakMap,re=new WeakMap,O=new WeakMap,j=new WeakMap,W=new WeakMap,st=e=>{let t={element:e,effectQueue:[],cleanups:[]},r=te.get(e)||[];return te.set(e,r),O.set(e,0),t},it=()=>P.length>0?P[P.length-1]:null,at=(e,t,r)=>{let o;return b({fn:()=>{let n=j.get(t);n||(n=new Map,j.set(t,n));let u=n.get(r);m(u)&&oe(u),o=e(),m(o)&&n.set(r,o);let i=W.get(t);i||(i=new Set,W.set(t,i)),i.add(r)},onError:n=>{a.error("Error in effect execution:",n)}}),o},ct=e=>{let{element:t,effectQueue:r}=e;if(x(r))return;a.log(`Executing ${r.length} effect(s) for element:`,t);let o=W.get(t);o||(o=new Set,W.set(t,o)),r.forEach((n,u)=>{o.has(u)||at(n,t,u)}),r.length=0,O.set(t,0)},ne=(e,t)=>{let r=st(e);return P.push(r),b({fn:()=>{let o=t();return ct(r),o},onError:o=>(a.error("Error in withHookContext:",o),null),onFinally:()=>{P.pop()}})},oe=e=>{m(e)&&b({fn:e,onError:t=>{a.error("Error in effect cleanup:",t)}})},H=(e,t)=>{let r=it();if(!r){a.warn("useEffect called outside component/directive context");return}if(E(t))throw new Error("[HookTML] useEffect requires a dependencies array. For one-time effects, use an empty array [].");if(!R(t))throw new Error("[HookTML] useEffect dependencies must be an array.");let{element:o}=r,n=O.get(o)||0;if(O.set(o,n+1),w(t)){let i=t.filter(c=>!T(c)&&!E(c));if(!x(i)){let{debug:c}=y(),p=l=>J(l)?JSON.stringify(l).slice(0,50):String(l),s=c?`
Non-reactive values: ${i.map(p).join(", ")}`:"";a.warn(`useEffect dependency array contains ${i.length} non-signal value(s) that won't trigger re-runs.
To make values reactive, convert them to signals with signal().${s}`)}}let u=()=>{let i=re.get(o);i||(i=new Map,re.set(o,i));let c=i.get(n);c||(c=new Set,i.set(n,c)),c.forEach(s=>s()),c.clear(),t.forEach(s=>{if(T(s)){let l=s.subscribe(()=>{p()});c.add(l)}});let p=()=>{let s=j.get(o);s||(s=new Map,j.set(o,s));let l=s.get(n);m(l)&&oe(l);let f=e();return m(f)&&s.set(n,f),f};return p()};r.effectQueue.push(u)},je=e=>{let t=te.get(e),r=!1;k(t)&&w(t)&&(t.forEach(u=>{oe(u)}),te.delete(e),r=!0);let o=re.get(e);o&&(o.forEach(u=>{u.forEach(i=>i()),u.clear()}),re.delete(e),r=!0);let n=j.get(e);return n&&(n.forEach(u=>{oe(u)}),j.delete(e),r=!0),O.delete(e),W.delete(e),r};var S=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase()),$=e=>e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),F=e=>/[^aeiou]y$/.test(e)?e.slice(0,-1)+"ies":/(s|x|z|ch|sh)$/.test(e)?e+"es":e+"s";var _=e=>{let t={current:e},r=new Set,o={get value(){return!Q(globalThis)&&globalThis.__HOOKTML_TRACK_SIGNAL__&&globalThis.__HOOKTML_TRACK_SIGNAL__(o),t.current},set value(n){t.current!==n&&(t.current=n,r.size>0&&r.forEach(u=>{b({fn:()=>u(n),onError:i=>{a.error("Error in signal subscriber:",i)}})}))},subscribe(n){if(!m(n))throw new Error("[HookTML] Signal subscribers must be functions");return r.add(n),()=>{r.delete(n)}},destroy(){r.clear()},toString(){return`Signal(${t.current})`}};return o};var se=new Map,ut=e=>A(e)?!1:/^[A-Z][A-Za-z0-9]*$/.test(e),we=e=>{if(!m(e))return a.warn("Invalid component: must be a function"),!1;let t=e.name;if(!ut(t))return a.warn(`Invalid component name: "${t}". Must be a non-empty PascalCase name`),!1;let r=!se.has(t);return r&&(se.set(t,e),a.log(`Registered component: ${t}`)),r},I=()=>Array.from(se.keys()),_e=e=>{if(v(e))return se.get(e)};var ie=class{constructor(){this.stateRegistry=new WeakMap}markInitialized(t){if(!g(t))throw new Error("[HookTML] markInitialized requires an HTMLElement");let r=this.getOrCreateState(t);r.initialized=!0}markDirectiveInitialized(t,r){if(!g(t))throw new Error("[HookTML] markDirectiveInitialized requires an HTMLElement");if(!r)throw new Error("[HookTML] directiveName is required");let o=this.getOrCreateState(t);o.initializedDirectives.includes(r)||o.initializedDirectives.push(r)}isInitialized(t){return g(t)?this.stateRegistry.get(t)?.initialized??!1:!1}isDirectiveInitialized(t,r){return!g(t)||!r?!1:this.stateRegistry.get(t)?.initializedDirectives.includes(r)??!1}getInitializedDirectives(t){return g(t)?this.stateRegistry.get(t)?.initializedDirectives??[]:[]}clearState(t){g(t)&&this.stateRegistry.delete(t)}getOrCreateState(t){let r=this.stateRegistry.get(t);return r||(r={initialized:!1,initializedDirectives:[]},this.stateRegistry.set(t,r)),r}};var ae=class{constructor(){this.teardownRegistry=new WeakMap,this.stateManager=new ie}registerComponent(t,r){if(!g(t))throw new Error("[HookTML] registerComponent requires an HTMLElement");if(!m(r))return!1;let o=this.teardownRegistry.get(t);return o||(o={component:void 0,directives:[]},this.teardownRegistry.set(t,o)),o.component=r,this.stateManager.markInitialized(t),!0}registerDirective(t,r,o){if(!g(t))throw new Error("[HookTML] registerDirective requires an HTMLElement");if(!m(r))return!1;if(!o)throw new Error("[HookTML] directiveName is required");let n=this.teardownRegistry.get(t);return n||(n={component:void 0,directives:[]},this.teardownRegistry.set(t,n)),n.directives.push(r),this.stateManager.markDirectiveInitialized(t,o),!0}getComponentTeardown(t){if(!g(t))throw new Error("[HookTML] getComponentTeardown requires an HTMLElement");return this.teardownRegistry.get(t)?.component}getDirectiveTeardowns(t){if(!g(t))throw new Error("[HookTML] getDirectiveTeardowns requires an HTMLElement");return this.teardownRegistry.get(t)?.directives??[]}getTeardowns(t){if(!g(t))throw new Error("[HookTML] getTeardowns requires an HTMLElement");return this.teardownRegistry.get(t)??{component:void 0,directives:[]}}hasRegistration(t){if(!g(t))return!1;let r=this.teardownRegistry.get(t);return k(r)&&(m(r.component)||w(r.directives))}executeComponentTeardown(t){if(!g(t))throw new Error("[HookTML] executeComponentTeardown requires an HTMLElement");let r=this.teardownRegistry.get(t);if(!r?.component)return{success:!0,error:void 0};let o=r.component;return b({fn:()=>(o(),r.component=void 0,{success:!0,error:void 0}),onError:n=>(a.error("Error in component teardown:",n),{success:!1,error:n})})}executeDirectiveTeardowns(t){if(!g(t))throw new Error("[HookTML] executeDirectiveTeardowns requires an HTMLElement");let r=this.teardownRegistry.get(t);if(!r?.directives.length)return[];let o=r.directives.map(n=>b({fn:()=>(n(),{success:!0,error:void 0}),onError:u=>(a.error("Error in directive teardown:",u),{success:!1,error:u})}));return r.directives=[],o}executeTeardowns(t){if(!g(t))throw new Error("[HookTML] executeTeardowns requires an HTMLElement");let r=this.executeComponentTeardown(t),o=this.executeDirectiveTeardowns(t);return this.teardownRegistry.delete(t),this.stateManager.clearState(t),{component:r,directives:o}}isInitialized(t){return this.stateManager.isInitialized(t)}isDirectiveInitialized(t,r){return this.stateManager.isDirectiveInitialized(t,r)}getInitializedDirectives(t){return this.stateManager.getInitializedDirectives(t)}markInitialized(t){this.stateManager.markInitialized(t)}clearState(t){this.stateManager.clearState(t)}};var L=new ae;var qe=e=>{g(e)&&L.markInitialized(e)};var ft=(e,t)=>{let{formattedPrefix:r}=y();return e.classList.contains(t)||g(e)&&e.getAttribute(`${r}use-component`)===t},lt=(e,t,r)=>{let o=F(t);o in e?R(e[o])&&e[o].push(r):e[o]=[e[t],r]},Pe=(e,t)=>{let{formattedPrefix:r}=y(),o=`${r}${$(t)}-`,n={};return Array.from(e.getElementsByTagName("*")).some(i=>ft(i,t)?!0:(Array.from(i.attributes).forEach(({name:c})=>{if(c.startsWith(o)){let p=S(c.slice(o.length));n[p]?lt(n,p,i):n[p]=i}}),!1)),n};var be=e=>e==="true"?!0:e==="false"?!1:e==="null"?null:Ae(e)?Number(e):e,Oe=(e,t)=>{let{formattedPrefix:r}=y(),o=`${r}${$(t)}-`,n={};Array.from(e.attributes).forEach(({name:i,value:c})=>{if(i.startsWith(o)){let p=S(i.slice(o.length));n[p]=be(c)}});let u=Pe(e,t);return Object.keys(u).length>0&&(n.children=u),n},We=(e,t,r)=>{let{formattedPrefix:o}=y(),n=t.startsWith("use")?$(t.slice(3)):$(t),u=`${o}${n}-`,i={};return Z(r)&&(i.value=be(r)),Array.from(e.attributes).forEach(({name:c,value:p})=>{if(c.startsWith(u)){let s=S(c.slice(u.length));i[s]=be(p)}}),i};var ce=e=>{if(!g(e))throw new Error("[HookTML] removeCloak requires an HTMLElement");e.removeAttribute("data-hooktml-cloak")};var Fe="__hooktml",pt="[data-hooktml-cloak] { visibility: hidden; }",mt=()=>{let e=document.getElementById(Fe);if(e instanceof HTMLStyleElement)return e;let t=document.createElement("style");return t.id=Fe,t.textContent=pt,document.head.appendChild(t),t},gt=e=>y().componentSelectorMode==="class"?`.${e.name}`:`[data-component="${e.name}"]`,dt=e=>e?e.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\s*([{};:,])\s*/g,"$1").replace(/\s+/g," ").trim():"",Ke=e=>dt(e),ht=e=>{let t=e.styles?.trim()??"";return`${gt(e)} { ${t} }`},yt=(e,t)=>{let r=Ke(t);return Array.from(e.cssRules).some(o=>Ke(o.cssText)===r)},Be=(e,t)=>{let{debug:r}=y();if(!g(t))throw new Error("[HookTML] injectComponentStyles requires an HTMLElement as second argument");if(k(e.styles)&&!v(e.styles)){r&&a.warn(`Component "${e.name}" has non-string styles property (type: ${typeof e.styles}). Styles must be a string.`,e),ce(t);return}if(E(e.styles)||A(e.styles)){ce(t);return}let n=mt().sheet,u=ht(e);k(n)&&(yt(n,u)?a.warn(`Duplicate style injection skipped for component "${e.name}". Styles already present in stylesheet.`,t):(n.insertRule(u,n.cssRules.length),a.log(`Injected styles for component "${e.name}"`))),ce(t)};var Et=e=>e.map(t=>`.${t}`).join(", "),wt=(e,t="")=>e.map(r=>`[${t}use-component="${r}"]`).join(", "),bt=(e,t,r="")=>{let n=Array.from(e.classList).find(i=>t.includes(i));if(k(n))return n;let u=e.getAttribute(`${r}use-component`);return k(u)&&t.includes(u)?u:null},ue=()=>{a.log("Scanning for components...");let e=I(),{formattedPrefix:t}=y();if(!e.length)return a.log("No components registered yet"),[];let r=Et(e),o=wt(e,t),n=`${r}, ${o}`;return a.log(`Scanning DOM with selector: "${n}"`),Array.from(document.querySelectorAll(n)).map(i=>{let c=bt(i,e,t);return k(c)?{element:i,componentName:c}:null}).filter(k)},fe=e=>{if(E(e)||x(e))return a.log("No components to initialize"),[];a.log(`Initializing ${e.length} component(s)...`);let t=e.map(({element:r,componentName:o})=>{if(L.isInitialized(r))return a.log(`Skipping already initialized component: ${o}`),null;let n=_e(o);return E(n)?(a.warn(`No registered function found for component: ${o}`),null):b({fn:()=>{a.log(`Initializing component: ${o}`);let u=Oe(r,o),i=ne(r,()=>n(r,u));return i===null?null:(m(i)?L.registerComponent(r,i):J(i)&&(k(i.context)&&Object.defineProperty(r,"component",{value:i.context,writable:!0,configurable:!0}),m(i.cleanup)&&L.registerComponent(r,i.cleanup)),Be(n,r),qe(r),{element:r,componentName:o,instance:i})},onError:u=>(a.error(`Error initializing component ${o}:`,u),null)})}).filter(k);return a.log(`Successfully initialized ${t.length} component(s)`),t};var le=new WeakMap,Ve=(e,t)=>{if(!g(e))return;let r=le.get(e);if(r)return r.get(t)},Ue=(e,t,r)=>{if(!g(e))return;let o=le.get(e);o||(o=new Map,le.set(e,o)),o.set(t,r),a.log(`Stored hook instance for "${t}" on element:`,e)},Ge=e=>{g(e)&&le.delete(e)};var kt=(e,t="")=>e.length?e.map(o=>`[${t}${$(o)}]`).join(", "):"",Tt=(e,t="")=>{let r=Array.from(e.attributes),o=`${t}use-`;return r.filter(n=>n.name.startsWith(o)).map(n=>({name:n.name.substring(t.length),originalName:n.name,value:n.value}))},ke=e=>{if(L.hasRegistration(e)){a.log("\u23ED\uFE0F Skipping already processed element",e);return}let{formattedPrefix:r}=y(),o=Tt(e,r);a.log(`Processing element with ${o.length} hook(s):`,e),o.forEach(({name:n,originalName:u,value:i})=>{let c=S(n);a.log(`Looking for hook "${c}" from attribute "${u}"`);let p=De(c);if(k(p)&&m(p)){if(a.log(`Found hook "${c}" for element:`,e),Ve(e,c)){a.log(`Using existing instance for hook "${c}"`);return}let l=We(e,c,i);k(i)&&a.log(`Passing props to hook "${c}":`,l);let f={current:void 0};if(b({fn:()=>{a.log(`Calling hook function for "${c}" with hook context`),f.current=ne(e,()=>{let d=p(e,l);return Ue(e,c,d),d}),a.log(`Hook "${c}" returned:`,f.current,typeof f.current)},onError:d=>{a.error(`Error applying hook "${c}":`,d)}}),m(f.current)){a.log(`Storing teardown function for hook "${c}" on element:`,e),L.registerDirective(e,f.current,c);let d=L.hasRegistration(e);a.log(`\u2705 Verified teardown is registered: ${d}`)}else a.log(`Hook "${c}" did not return a teardown function`)}else a.warn(`Unknown hook "${c}" requested on element:`,e)})},Qe=()=>{let e=z(),t=Array.from(e.keys()),{formattedPrefix:r}=y();if(x(t))return a.log("No hooks registered yet"),0;let o=kt(t,r);a.log(`Scanning DOM for hook directives with selector: "${o}"`);let n=Array.from(document.querySelectorAll(o)).filter(g);return a.log(`Found ${n.length} element(s) with hook directives`),n.forEach(u=>ke(u)),n.length};var Ze=e=>e.nodeType===Node.ELEMENT_NODE,Ct=(e,t)=>{let r=t.removedNodes||[],o=Array.from(r).filter(c=>g(c)&&Ze(c)).flatMap(c=>{let p=c,s=Array.from(p.getElementsByTagName("*")).filter(g);return[p,...s]});o.forEach(c=>{e.elements.has(c)&&(e.delegate.removeElement(c),e.elements.delete(c));let p=pe.get(c);p&&(p.forEach(s=>s()),pe.delete(c))});let n=t.addedNodes||[],u=Array.from(n).filter(c=>g(c)&&Ze(c)).flatMap(c=>{let p=c,s=Array.from(p.getElementsByTagName("*")).filter(g);return[p,...s]}),i=[...o,...u];w(i)&&Mt(i),Te(e)},Te=e=>{if(!e.started)return;let t=new Set(e.delegate.matchElements(e.root));Array.from(e.elements).filter(n=>!t.has(n)).forEach(n=>{e.delegate.removeElement(n),e.elements.delete(n)}),Array.from(t).filter(n=>!e.elements.has(n)).forEach(n=>{e.delegate.addElement(n),e.elements.add(n)})},xt=(e,t)=>{let r={root:e,delegate:t,elements:new Set,started:!1},o=new MutationObserver(s=>{r.started&&s.forEach(l=>Ct(r,l))}),n=()=>o.observe(e,{attributes:!0,childList:!0,subtree:!0}),u=()=>o.disconnect();return{start:()=>{r.started||(r.started=!0,n(),Te(r))},stop:()=>{r.started&&(o.takeRecords&&o.takeRecords(),u(),r.started=!1)},pause:s=>{r.started&&(u(),r.started=!1),s(),r.started||(n(),r.started=!0)},refresh:()=>Te(r)}},Je=(e,t="")=>e.length?e.map(o=>`[${t}${$(o)}]`).join(", "):"",Ye=(e,t="")=>{if(!e.length)return"";let r=e.map(n=>`.${n}`).join(", "),o=e.map(n=>`[${t}use-component="${n}"]`).join(", ");return`${r}, ${o}`},Ht=()=>({matchElements:o=>{let{formattedPrefix:n}=y(),u=z(),i=Array.from(u.keys()),c=I(),p=[];return w(i)&&p.push(Je(i,n)),w(c)&&p.push(Ye(c,n)),x(p)?[]:Array.from(o.querySelectorAll(p.join(", "))).filter(g)},addElement:o=>{b({fn:()=>{let{formattedPrefix:n}=y(),u=z(),i=Array.from(u.keys());if(w(i)){let p=Je(i,n);o.matches(p)&&ke(o)}let c=I();if(w(c)){let p=Ye(c,n);if(o.matches(p)){let s=ue().filter(l=>l.element===o);w(s)&&fe(s)}}},onError:n=>{y().debug&&a.error("Error processing element:",n)}})},removeElement:o=>{b({fn:()=>{L.executeTeardowns(o),je(o),Ge(o)},onError:n=>{y().debug&&a.error("Error removing element:",n)}})}}),Ce=new Set,pe=new WeakMap,Xe=(e,t,r)=>{let o={element:e,prefix:t,callback:r};Ce.add(o);let n=()=>{Ce.delete(o)},u=pe.get(e)||[];pe.set(e,[...u,n])},Mt=e=>{let t=new Set;e.forEach(r=>{Ce.forEach(o=>{(o.element===r||o.element.isConnected&&o.element.contains(r))&&(t.has(o)||(t.add(o),b({fn:o.callback,onError:n=>{y().debug&&a.error("Error in children watcher callback:",n)}})))})})},et=()=>{let e=Ht(),t=xt(document.documentElement,e);return{start:()=>{t.start(),a.log("DOM observation started")},stop:()=>{t.stop(),a.log("DOM Observer stopped")}}};var xe=(e,t,r={})=>{if(!g(e))throw new Error("[HookTML] useChildren requires an HTMLElement as first argument");if(E(t)||!Z(t))throw new Error("[HookTML] useChildren requires a non-empty string prefix as second argument");let{signals:o=[]}=r,n=`[use-${t}]`,u=`${t}-`,i={},c={},p=()=>{Object.keys(c).forEach(l=>{c[l]=[]});let s=e.getElementsByTagName("*");for(let l=0;l<s.length;l++){let f=s[l];if(!g(f))continue;let d=!1,h=[];for(let M=0;M<f.attributes.length;M++){let q=f.attributes[M];q.name.startsWith(u)&&(d=!0,h.push(q))}if(!d)continue;let C=f.closest(n);if(!(C&&C!==e))for(let M=0;M<h.length;M++){let ot=h[M].name.slice(u.length),ge=S(ot);R(c[ge])||(c[ge]=[]),c[ge].push(f)}}};return p(),Object.keys(c).forEach(s=>{let l=c[s],f=F(s);o.includes(s)?(i[s]=_(l[0]),i[f]=_(l)):(i[s]=l[0],i[f]=l)}),w(o)&&Xe(e,t,()=>{p(),Object.keys(c).forEach(s=>{let l=c[s],f=F(s);o.includes(s)&&(i[s]&&T(i[s])&&(i[s].value=w(l)?l[0]:null),i[f]&&T(i[f])&&(i[f].value=l))})}),i};var K=(e,t,r=[])=>{if(E(e))return a.info("[HookTML] useEvents called with null/undefined element, skipping event registration"),()=>{};if(x(e))return a.info("[HookTML] useEvents called with empty array, skipping event registration"),()=>{};let o=de(e),n=$e(e);if(!o&&!n)throw new Error("[HookTML] useEvents requires an EventTarget or array of EventTargets as first argument");let u=n?e:[e];if(!N(t))throw new Error("[HookTML] useEvents requires a non-empty object mapping event names to listeners");let c=Object.values(t).filter(T).concat(r),p=new Map,s=()=>{p.forEach((f,d)=>{u.forEach(h=>{h.removeEventListener(d,f)})}),p.clear();let l=Object.entries(t).filter(([f,d])=>{let h=T(d)?d.value:d;if(!m(h)){a.warn(`Event handler for '${f}' is not a function, skipping`);return}return[f,h]});u.forEach((f,d)=>{l.forEach(([h,C])=>{let M=q=>{m(C)&&C(q,d)};f.addEventListener(h,M),p.set(h,M)})})};return s(),w(c)&&H(()=>{s()},c),()=>{p.forEach((l,f)=>{u.forEach(d=>{d.removeEventListener(f,l)})}),p.clear()}};var B=(e,t,r=[])=>{if(E(e))return a.info("[HookTML] useClasses called with null/undefined element, skipping class application"),()=>{};if(x(e))return a.info("[HookTML] useClasses called with empty array, skipping class application"),()=>{};let o=D(e)?e:[e];if(o.some(s=>!g(s)))throw new Error("[HookTML] useClasses requires HTMLElement(s) as first argument");if(!N(t))throw new Error("[HookTML] useClasses requires a non-empty object mapping class names to boolean conditions");let u=Object.values(t).filter(T).concat(r),i=new WeakMap,c=(s,l,f)=>m(s)?!!s(l,f):T(s)?!!s.value:!!s,p=()=>{o.forEach((s,l)=>{let f=i.get(s);f||(f=new Set,i.set(s,f)),f.forEach(d=>{s.classList.remove(d)}),f.clear(),Object.entries(t).forEach(([d,h])=>{c(h,s,l)&&(s.classList.add(d),f.add(d))})})};return p(),w(u)&&H(()=>{p()},u),()=>{o.forEach(s=>{let l=i.get(s);l&&(l.forEach(f=>{s.classList.remove(f)}),l.clear())})}};var V=(e,t,r=[])=>{if(E(e))return a.info("[HookTML] useAttributes called with null/undefined element, skipping attribute setting"),()=>{};if(x(e))return a.info("[HookTML] useAttributes called with empty array, skipping attribute setting"),()=>{};let o=D(e)?e:[e];if(o.some(s=>!g(s)))throw new Error("[HookTML] useAttributes requires HTMLElement(s) as first argument");if(!N(t))throw new Error("[HookTML] useAttributes requires a non-empty object mapping attribute names to values");let n=Object.values(t).filter(T),u=n.concat(r),i=new WeakMap,c=(s,l,f)=>m(s)?s(l,f):T(s)?s.value:s,p=()=>{o.forEach((s,l)=>{let f=i.get(s);f||(f=new Map,i.set(s,f)),Object.entries(t).forEach(([d,h])=>{f.has(d)||f.set(d,s.hasAttribute(d)?s.getAttribute(d):null);let C=c(h,s,l);E(C)?s.removeAttribute(d):s.setAttribute(d,C)})})};return p(),w(u)&&b({fn:()=>{H(()=>{p()},u)},onError:s=>{a.error("Error in useAttributes:",s);let l=n.map(f=>T(f)?f.subscribe(()=>p()):null).filter(k);o.forEach(f=>{let d=i.get(f);if(d){let h=d.get("__cleanup");d.set("__cleanup",()=>{l.forEach(C=>C()),m(h)&&h()})}})}}),()=>{o.forEach(s=>{let l=i.get(s);if(l){let f=l.get("__cleanup");m(f)&&f(),l.forEach((d,h)=>{h!=="__cleanup"&&(E(d)?s.removeAttribute(h):s.setAttribute(h,d))}),l.clear()}})}};var U=(e,t,r=[])=>{if(E(e))return a.info("[HookTML] useStyles called with null/undefined element, skipping style application"),()=>{};if(x(e))return a.info("[HookTML] useStyles called with empty array, skipping style application"),()=>{};let o=D(e)?e:[e];if(o.some(s=>!g(s)))throw new Error("[HookTML] useStyles requires HTMLElement(s) as first argument");if(!N(t))throw new Error("[HookTML] useStyles requires a non-empty object mapping style properties to values");let n=Object.values(t).filter(T),u=n.concat(r),i=new WeakMap,c=(s,l,f)=>m(s)?s(l,f):T(s)?s.value:s,p=()=>{o.forEach((s,l)=>{let f=i.get(s);f||(f=new Map,i.set(s,f)),Object.entries(t).forEach(([d,h])=>{let C=d.includes("-")?S(d):d;f.has(C)||f.set(C,s.style[C]);let M=c(h,s,l);s.style[C]=M})})};return p(),w(u)&&b({fn:()=>{H(()=>{p()},u)},onError:s=>{a.error("Error in useStyles:",s);let l=n.map(f=>f.subscribe(()=>p()));o.forEach(f=>{let d=i.get(f);if(d){let h=d.get("__cleanup");d.set("__cleanup",()=>{l.forEach(C=>C()),m(h)&&h()})}})}}),()=>{o.forEach(s=>{let l=i.get(s);if(l){let f=l.get("__cleanup");m(f)&&f(),l.forEach((d,h)=>{h!=="__cleanup"&&(s.style[h]=d)}),l.clear()}})}};var G=(e,t,r=[])=>{if(E(e)){a.info("[HookTML] useText called with null/undefined element, skipping text updates");return}if(!g(e)){a.info("[HookTML] useText requires HTMLElement as first argument");return}if(!m(t)){a.info("[HookTML] useText requires a function as the second argument");return}H(()=>{e.textContent=t()},r)};var He=e=>{if(!g(e))throw new Error("[HookTML] with(el) requires an HTMLElement as argument");let t={useEvents:o=>(K(e,o),t),useClasses:o=>(B(e,o),t),useAttributes:o=>(V(e,o),t),useStyles:o=>(U(e,o),t),useText:o=>(G(e,o),t)};return ee().forEach((o,n)=>{m(o)&&!t[n]&&(t[n]=(...u)=>(o(e,...u),t))}),t};var Me=class e{static instance=null;constructor(){this.currentTracker=null,this.computingSignals=new Set}static getInstance(){return this.instance||(this.instance=new e),this.instance}trackDependency(t){this.currentTracker&&m(this.currentTracker)&&this.currentTracker(t)}startTracking(t){let r=this.currentTracker;return this.currentTracker=t,()=>{this.currentTracker=r}}isComputing(t){return this.computingSignals.has(t)}markAsComputing(t){this.computingSignals.add(t)}markAsComplete(t){this.computingSignals.delete(t)}},tt=Me.getInstance(),Se=e=>{tt.trackDependency(e)};Q(globalThis)||(globalThis.__HOOKTML_TRACK_SIGNAL__=Se);var Le=e=>{if(!m(e))throw new Error("[HookTML] computed() requires a function");let t={value:void 0,hasValue:!1,isStale:!0,isComputing:!1,dependencies:new Set,subscribers:new Set,notificationScheduled:!1},r=new Set,o=()=>{r.forEach(i=>i()),r.clear(),t.dependencies.clear()},n=()=>{t.notificationScheduled||t.subscribers.size===0||(t.notificationScheduled=!0,queueMicrotask(()=>{if(t.notificationScheduled=!1,t.subscribers.size>0){let i=u.value;t.subscribers.forEach(c=>{b({fn:()=>c(i),onError:p=>{console.error("[HookTML] Error in computed subscriber:",p)}})})}}))},u={get value(){if(!t.isStale&&t.hasValue)return Se(u),t.value;if(t.isComputing)throw new Error("[HookTML] Circular dependency detected in computed signal");o(),t.isComputing=!0;let i=new Set,c=tt.startTracking(s=>{if(T(s)&&!i.has(s)){i.add(s);let l=s.subscribe(()=>{let f=t.isStale;t.isStale=!0,!f&&t.hasValue&&n()});r.add(l)}}),p=e();return c(),t.isComputing=!1,t.dependencies=i,t.value=p,t.hasValue=!0,t.isStale=!1,Se(u),p},set value(i){throw new Error("[HookTML] Cannot assign to computed signal. Computed signals are read-only.")},subscribe(i){if(!m(i))throw new Error("[HookTML] Computed subscribers must be functions");return t.subscribers.add(i),()=>{t.subscribers.delete(i)}},destroy(){o(),t.subscribers.clear(),t.hasValue=!1,t.isStale=!0,t.notificationScheduled=!1},toString(){let i=t.dependencies.size,c=t.isStale?" (stale)":"";return`Computed(${t.hasValue?t.value:"uncomputed"}, ${i} deps${c})`}};return u};var ve={current:null},rt=e=>{ze(e),a.log("Initializing...");let{debug:t,attributePrefix:r}=y();return r&&a.log(`Using attribute prefix: "${r}"`),ve.current=et(),ve.current.start(),me(),a.log("Initialization complete"),{config:y(),scan:me,stop:()=>ve.current?.stop(),components:I,hooks:z,chainableHooks:ee}},me=()=>{a.log("Manual scan triggered");let e=ue(),t=fe(e);return Qe(),a.log(`Manual scan complete, initialized ${t.length} new component(s)`),t};Object.assign(window,{HookTML:{start:rt,scan:me,registerComponent:we,registerHook:ye,registerChainableHook:Ee,useEffect:H,useChildren:xe,useEvents:K,useClasses:B,useAttributes:V,useStyles:U,useText:G,with:He,signal:_,computed:Le,getConfig:y}});})();