ilha 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,2133 @@
1
- import{computed as e,effect as t,endBatch as n,setActiveSub as r,signal as i,startBatch as a}from"alien-signals";function o(e,t){if(t>32)return!0;if(typeof e!=`object`||!e)return!1;if(Array.isArray(e)){for(let n of e)if(o(n,t+1))return!0;return!1}for(let n in e)if(Object.prototype.hasOwnProperty.call(e,n)&&o(e[n],t+1))return!0;return!1}const s=new Set([`__proto__`,`constructor`,`prototype`]);function c(e){if(!(typeof e!=`object`||!e)){if(Array.isArray(e)){for(let t of e)c(t);return}for(let t of Object.getOwnPropertyNames(e))s.has(t)?delete e[t]:c(e[t])}}function l(e,t){if(e.length>262144){`${t}`;return}let n;try{n=JSON.parse(e)}catch{`${t}`;return}if(o(n,1)){`${t}`;return}if(typeof n!=`object`||!n||Array.isArray(n)){`${t}`;return}return c(n),n}function u(e,t){if(Object.is(e,t))return!0;if(typeof e!=`object`||!e||typeof t!=`object`||!t)return!1;let n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(let r of n)if(!Object.prototype.hasOwnProperty.call(t,r)||!Object.is(e[r],t[r]))return!1;return!0}function d(e){let t=document.createElement(`template`);return t.innerHTML=e,t.content}function f(e){let t=[];for(let n of e.querySelectorAll(`[data-ilha-slot]`)){if(!(n instanceof Element))continue;let r=n.parentElement??n.parentNode,i=!1;for(;r&&r!==e;){if(r instanceof Element&&r.hasAttribute(`data-ilha-slot`)){i=!0;break}r=r instanceof Element?r.parentElement??r.parentNode:r.parentNode}i||t.push(n.getAttribute(`data-ilha-slot`))}return t}function p(e,t){for(let n of e.querySelectorAll(`[${A}]`))if(n.getAttribute(A)===t)return n.getAttribute(j)??``;return null}const m=/^[a-z][a-z0-9-]*$/i;function h(e){let t=e.trim();if(t.length===0)throw Error(`island.as() requires a non-empty HTML tag name.`);if(!m.test(t))throw Error(`island.as() tag must be a valid HTML element name (got "${e}"). Use names like "span", "div", or "li".`);return t.toLowerCase()}function g(e){let t=e[k];return typeof t==`string`&&t.length>0?t:`div`}function _(e,t,n,r){return`<${e} ${A}="${w(t)}"${n}>${r}</${e}>`}function ee(e,t,n){if(typeof document>`u`)return!1;let r=d(e),i=d(t),a=f(r),o=f(i);if(a.length!==o.length||a.some((e,t)=>e!==o[t]))return!1;for(let e of n){let t=p(r,e),n=p(i,e);if(t===null||n===null||t!==n)return!1}return!0}function te(e){return e===void 0?``:JSON.stringify(e)}const v=new Set([`data-checked`,`data-unchecked`,`data-indeterminate`,`aria-checked`,`data-open`,`data-closed`,`data-state`,`aria-expanded`,`aria-hidden`,`data-selected`,`data-panel-open`]);function y(e,t){return e.matches(`[data-slot]`)&&v.has(t)}function b(e,t){for(let{name:n,value:r}of t.attributes)y(e,n)||e.getAttribute(n)!==r&&e.setAttribute(n,r);for(let{name:n}of Array.from(e.attributes))y(e,n)||t.hasAttribute(n)||e.removeAttribute(n)}function x(e,t){let n=Array.from(t.childNodes),r=null;for(let t of e.children){let e=t.getAttribute(`data-key`);e!==null&&!(r??=new Map).has(e)&&r.set(e,t)}let i=null;if(r!==null){i=new Set;for(let e of t.children){let t=e.getAttribute(`data-key`);t!==null&&i.add(t)}}for(let t=0;t<n.length;t++){let a=n[t],o=e.childNodes[t];if(r!==null&&a.nodeType===1){let t=a.getAttribute(`data-key`);if(t!==null){let n=r.get(t);if(n)n!==o&&(e.insertBefore(n,o??null),o=n);else if(o instanceof Element){let t=o.getAttribute(`data-key`);if(t!==null&&i.has(t)){e.insertBefore(a.cloneNode(!0),o);continue}}}}if(!o){e.appendChild(a.cloneNode(!0));continue}if(o.nodeType!==a.nodeType){e.replaceChild(a.cloneNode(!0),o);continue}if(o.nodeType===3||o.nodeType===8){o.nodeValue!==a.nodeValue&&(o.nodeValue=a.nodeValue);continue}if(o.nodeType===1){let t=o,n=a;if(t.localName!==n.localName||t.namespaceURI!==n.namespaceURI){e.replaceChild(n.cloneNode(!0),t);continue}if(t.localName===`input`&&t.type!==n.type){e.replaceChild(n.cloneNode(!0),t);continue}if(b(t,n),t.localName===`textarea`){let e=n.textContent??``;t.textContent!==e&&(t.textContent=e,t.value=e)}else x(t,n)}}for(;e.childNodes.length>n.length;)e.lastChild.remove()}function ne(e,t){if(e.localName!==t.localName||e.namespaceURI!==t.namespaceURI)throw Error(`[ilha] morph: elements must match`);x(e,t)}function S(e){if(typeof e!=`object`||!e)return!1;let t=e[`~standard`];return t!=null&&typeof t.validate==`function`&&t.version===1}function re(e,t){let n=e[`~standard`].validate(t);if(n instanceof Promise)throw Error(`[ilha] Async schemas are not supported.`);if(n.issues)throw Error(`[ilha] Validation failed:\n${n.issues.map(e=>` - ${e.message}`).join(`
2
- `)}`);return n.value}const C={"&":`&amp;`,"<":`&lt;`,">":`&gt;`,'"':`&quot;`,"'":`&#39;`};function w(e){return String(e).replace(/[&<>"']/g,e=>C[e])}function T(e){if(e.length===0||e[0]!==`
3
- `)return e;let t=e.split(`
4
- `);for(;t.length&&t[0].trim()===``;)t.shift();for(;t.length&&t[t.length-1].trim()===``;)t.pop();if(!t.length)return``;let n=Math.min(...t.filter(e=>e.trim()!==``).map(e=>e.match(/^(\s*)/)[1].length));return t.map(e=>e.slice(n)).join(`
5
- `)}const E=Symbol.for(`ilha.raw`),D=Symbol.for(`ilha.signalAccessor`),ie=Symbol.for(`ilha.island`),O=Symbol.for(`ilha.islandCall`),ae=Symbol.for(`ilha.islandMountInternal`),k=Symbol.for(`ilha.islandSlotTag`),A=`data-ilha-slot`,j=`data-ilha-props`,oe=`data-ilha-state`;function M(e){return`<style data-ilha-css>@scope (:scope) to ([data-ilha]){${e.replace(/<\/style/gi,`<\\/style`)}}</style>`}const N=[];function se(e,t){let n={slots:new Map,positional:0,liveHost:e,pending:t?new Map:void 0,binds:[]};return N.push(n),n}function P(){N.pop()}function F(){return N[N.length-1]}function I(e){return typeof e==`function`&&ie in e}function L(e){return e==null||typeof e!=`object`&&typeof e!=`function`?!1:O in e?!0:typeof e==`object`&&`island`in e&&I(e.island)}function R(e,t,n){let r=F(),i;i=n===void 0?r?`p:${r.positional++}`:`p:0`:`k:${n}`,r&&r.slots.set(i,{island:e,props:t});let a=g(e),o=t?` ${j}='${w(JSON.stringify(t))}'`:``;if(r?.liveHost)return _(a,i,o,``);if(r?.pending){P();try{let n=e(t);return n instanceof Promise?(r.pending.set(i,n.then(String)),_(a,i,o,z(i))):_(a,i,o,String(n))}finally{N.push(r)}}let s=e.toString(t);return _(a,i,o,s)}function z(e){return`<!--ilha-async:${w(e)}-->`}async function ce(e,t){for(let[n,r]of t){let t=await r;e=e.split(z(n)).join(t)}return e}function B(e){e[D]=!0;let t=e;return t.select=e=>K(t,e),t}function V(e){return typeof e==`function`&&D in e}function H(e,t){let n=e;for(let e of t){if(n==null)return;n=n[e]}return n}function U(e,t,n){if(t.length===0)return n;let[r,...i]=t;if(Array.isArray(e)){let t=r;if(t<0||t>=e.length)return e;let a=e[t],o=i.length===0?n:U(a,i,n);if(Object.is(a,o))return e;let s=e.slice();return s[t]=o,s}if(typeof e==`object`&&e){let t=e,a=String(r),o=t[a],s=i.length===0?n:U(o,i,n);if(i.length===0){if(Object.is(o,n))return e}else if(Object.is(o,s))return e;return{...t,[a]:s}}return i.length===0?n:U(void 0,i,n)}function W(e){return typeof e==`symbol`||e===`length`?null:/^\d+$/.test(e)?Number(e):e}function G(e,t){let n=[],r=e=>e===null||typeof e!=`object`&&typeof e!=`function`?e:new Proxy(e,{get(e,t,i){let a=W(t);a!=null&&n.push(a);let o=Reflect.get(e,t,i);return a!=null&&typeof o==`object`&&o?r(o):o}});return t(r(e)),n}function K(e,t){let n=G(e(),t),r=t(e()),i=n.length===0?e():H(e(),n);if(!Object.is(r,i))throw Error(`select(): selector must only traverse nested properties or array indexes — derived or transformed values are not supported.`);return B((...r)=>{if(r.length===0)return n.length===0?t(e()):H(e(),n);let i=n.length===0?r[0]:U(e(),n,r[0]);Object.is(e(),i)||e(i)})}function q(e){return{[E]:!0,value:e}}function J(e,...t){if(typeof e==`string`)return e;let n=``;for(let r=0;r<e.length;r++)n+=e[r],r<t.length&&(n+=String(t[r]));return n}function Y(e){if(e==null||e===!0||e===!1)return``;if(Array.isArray(e))return e.map(Y).join(``);if(me(e))return e.value;if(L(e)){let t=typeof e==`function`?e():e;return R(t.island,t.props,t.key)}return I(e)?R(e,void 0,void 0):V(e)||typeof e==`function`?w(e()):w(e)}const le=new Set([`value`,`checked`,`valueAsNumber`,`valueAsDate`,`files`,`open`,`group`,`this`]),X=/\bbind:([a-zA-Z]+)\s*=\s*("|')?$/;function ue(e,t){let n=t;for(let t=0;t<e.length;t++){let r=e[t];if(n!==null)r===n&&(n=null);else if(r===`"`||r===`'`)n=r;else if(r===`>`)return{index:t,quote:n}}return{index:-1,quote:n}}function de(e){if(e instanceof Date){if(isNaN(e.getTime()))return``;let t=e=>String(e).padStart(2,`0`);return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}`}return``}function Z(e){let t=e.lastIndexOf(`<`);if(t===-1)return null;let n=e.slice(t);if(n.includes(`>`))return null;let r=n.match(/\bvalue\s*=\s*("([^"]*)"|'([^']*)'|([^\s>]+))/);return r?r[2]??r[3]??r[4]??null:null}function fe(e,t,n,r){let i=`${e}:${t}`,a;try{a=n()}catch{a=void 0}switch(e){case`value`:return[` value="${w(a??``)}"`,i];case`valueAsNumber`:return[` value="${w(a==null?``:String(a))}"`,i];case`valueAsDate`:return[` value="${w(de(a))}"`,i];case`checked`:return[a?` checked`:``,i];case`open`:return[a?` open`:``,i];case`files`:return[``,i];case`this`:return[``,i];case`group`:{let e=Z(r);return e==null?[``,i]:[(Array.isArray(a)?a.map(String).includes(e):a!=null&&String(a)===e)?` checked`:``,i]}}}function pe(e,...t){let n=``,r=null,i=``,a=null,o=F();for(let s=0;s<e.length;s++){let c=e[s];if(r!==null&&(c.startsWith(r)&&(c=c.slice(1)),r=null),i!==``){let{index:e,quote:t}=ue(c,a);e===-1?a=t:(c=c.slice(0,e).replace(/\s*\/\s*$/,``)+` data-ilha-bind="${i}">`+c.slice(e+1),i=``,a=null)}if(s>=t.length){n+=c;continue}let l=t[s],u=c.match(X);if(u&&V(l)){let e=u[1],t=u[2]??null;if(!le.has(e)){n+=c+Y(l);continue}if(!o){let i=c.slice(0,c.length-u[0].length),a=t??`"`;n+=i+e+`=`+a+Y(l)+a,t&&(r=t);continue}let a=c.length-u[0].length,s=c.slice(0,a).replace(/\s+$/,``),d=o.binds.length;o.binds.push({kind:e,accessor:l});let[f,p]=fe(e,d,l,s);n+=s+f,i+=(i?`,`:``)+p,t&&(r=t);continue}n+=c+Y(l)}return i!==``&&(n+=` data-ilha-bind="${i}"`),{[E]:!0,value:T(n)}}function me(e){return typeof e!=`object`||!e?!1:E in e&&typeof e.value==`string`}function he(e){return me(e)?e.value:e}const Q=new Map;function ge(e,t){if(Q.has(e))return Q.get(e);let n=i(t),r=(...e)=>{if(e.length===0)return n();n(e[0])};return Q.set(e,r),r}const _e=Object.assign(ge,{delete(e){return Q.delete(e)},clear(){Q.clear()}});function ve(e){let t=i(e);return B((...e)=>{if(e.length===0)return t();t(e[0])})}function ye(t){let n=e(t);return B((...e)=>{if(!(e.length>0))return n()})}function be(e){let r,i=()=>{if(typeof r==`function`){try{r()}catch(e){console.error(e)}r=void 0}},o=t(()=>{i(),a();try{r=e()}catch(e){console.error(e)}finally{n()}});return()=>{o(),i()}}function xe(e){let t=r(void 0);try{return e()}finally{r(t)}}function Se(e){a();try{return e()}finally{n()}}function Ce(e,t){let n=B((...n)=>{if(n.length>0){t&&t(n[0]);return}return e().value});return new Proxy(n,{get(t,n,r){return n===`loading`||n===`value`||n===`error`?e()[n]:Reflect.get(t,n,r)}})}function we(){return Ce(()=>({loading:!1,value:void 0,error:void 0}))}function Te(e){let t=new Map;for(let[n,r]of Object.entries(e))t.set(n,Ce(()=>r,e=>{r.loading=!1,r.value=e,r.error=void 0}));return new Proxy({},{get(e,n){if(typeof n==`string`)return t.get(n)??we()}})}function Ee(e,n,a,o){let s=new Map;for(let t of e){let e;if(o!=null&&t.key in o)e={...o[t.key]};else if(t.fn.constructor.name===`AsyncFunction`||t.fn.constructor.name===`AsyncGeneratorFunction`)e={loading:!0,value:void 0,error:void 0};else{let r=new AbortController;try{let i=t.fn({state:n,input:a,signal:r.signal});i instanceof Promise?(e={loading:!0,value:void 0,error:void 0},i.catch(()=>{})):e={loading:!1,value:i,error:void 0}}catch(t){e={loading:!1,value:void 0,error:t instanceof Error?t:Error(String(t))}}finally{r.abort()}}let r=i(e);s.set(t.key,r)}let c=new Map;for(let t of e){let e=s.get(t.key);c.set(t.key,Ce(()=>e(),t=>{let n=r(void 0);e({loading:!1,value:t,error:void 0}),r(n)}))}return{proxy:new Proxy({},{get(e,t){if(typeof t==`string`)return c.get(t)??we()}}),setup:()=>{let i=[];for(let c of e){let e=s.get(c.key),l=new AbortController,u=o!=null&&c.key in o,d=t(()=>{l.abort(),l=new AbortController;let t=l,i;try{i=c.fn({state:n,input:a,signal:t.signal})}catch(t){if(u){u=!1;return}let n=r(void 0);e({loading:!1,value:void 0,error:t instanceof Error?t:Error(String(t))}),r(n);return}if(u){u=!1,i instanceof Promise&&i.catch(()=>{});return}if(!(i instanceof Promise)){let t=r(void 0);e({loading:!1,value:i,error:void 0}),r(t);return}let o=r(void 0);e({loading:!0,value:e().value,error:void 0}),r(o),i.then(n=>{t.signal.aborted||e({loading:!1,value:n,error:void 0})}).catch(n=>{t.signal.aborted||e({loading:!1,value:void 0,error:n instanceof Error?n:Error(String(n))})})});i.push(()=>{d(),l.abort()})}return()=>i.forEach(e=>e())}}}const De=`data-ilha-bind`;function Oe(e){let t=[];for(let n of e.split(`,`)){let[e,r]=n.split(`:`);if(!e||!r)continue;let i=Number(r);!Number.isInteger(i)||i<0||t.push({kind:e,index:i})}return t}function ke(e,t){let n=e;switch(t){case`value`:return{event:e.tagName===`SELECT`?`change`:`input`,read:e=>e.value,write:(e,t)=>e.value=t==null?``:String(t)};case`valueAsNumber`:return{event:`input`,read:e=>{let t=e.valueAsNumber;return Number.isNaN(t)?null:t},write:(e,t)=>e.value=t==null||Number.isNaN(t)?``:String(t)};case`valueAsDate`:return{event:`input`,read:e=>e.valueAsDate,write:(e,t)=>{e.value=de(t)}};case`checked`:return{event:`change`,read:e=>e.checked,write:(e,t)=>e.checked=!!t};case`files`:return{event:`change`,read:e=>e.files,write:()=>{}};case`open`:return{event:`toggle`,read:e=>e.open,write:(e,t)=>e.open=!!t};case`this`:return{event:null,read:()=>void 0,write:()=>{}};case`group`:{let e=n.type===`checkbox`;return{event:`change`,read:t=>{let n=t;return e?{__ilhaGroup:!0,value:n.value,checked:n.checked}:n.checked?n.value:void 0},write:(t,n)=>{let r=t;e?r.checked=(Array.isArray(n)?n.map(String):[]).includes(r.value):r.checked=n!=null&&String(n)===r.value}}}}}function Ae(e,t){if(t.length===0)return()=>{};let n=[],r=[];e.hasAttribute(De)&&r.push(e);for(let t of e.querySelectorAll(`[${De}]`))r.push(t);for(let e of r){let r=Oe(e.getAttribute(De));for(let i of r){let r=t[i.index];if(!r||r.kind!==i.kind)continue;let{event:a,read:o,write:s}=ke(e,i.kind),c=r.accessor;if(i.kind===`this`){c(e),n.push(()=>c(null));continue}try{s(e,c())}catch{}if(a===null)continue;let l=()=>{let t=o(e);if(i.kind===`group`){let e=t;if(e===void 0)return;if(typeof e==`object`&&e.__ilhaGroup){let t=c(),n=Array.isArray(t)?[...t]:[],r=n.findIndex(t=>String(t)===e.value);if(e.checked&&r===-1){let r=e.value,i=Array.isArray(t)&&t.length>0?t[0]:void 0;if(i!==void 0)if(typeof i==`number`){let e=Number(r);r=Number.isNaN(e)?r:e}else typeof i==`boolean`&&(r=!!r);n.push(r)}else!e.checked&&r!==-1&&n.splice(r,1);c(n);return}let n=c(),r=e;if(typeof n==`number`&&typeof e==`string`){let t=Number(e);r=Number.isNaN(t)?0:t}else typeof n==`boolean`&&(r=!!e);c(r);return}let n=c(),r=t;if(typeof n==`number`&&typeof t==`string`){let e=Number(t);r=Number.isNaN(e)?0:e}else typeof n==`boolean`&&(r=!!t);c(r)};e.addEventListener(a,l),n.push(()=>e.removeEventListener(a,l))}}return()=>n.forEach(e=>e())}function je(e){let t=e.lastIndexOf(`@`),n=t===-1?``:e.slice(0,t),r=(t===-1?e:e.slice(t+1)).split(`:`),i=r[0],a=new Set(r.slice(1));return{selector:n,eventType:i,options:{once:a.has(`once`),capture:a.has(`capture`),passive:a.has(`passive`)},abortable:a.has(`abortable`)}}function Me(e){if(typeof AbortSignal.any==`function`)return AbortSignal.any(e);let t=new AbortController,n=[];for(let r of e){if(r.aborted)return t.abort(r.reason),n.forEach(e=>e()),t.signal;let e=()=>t.abort(r.reason);r.addEventListener(`abort`,e,{once:!0}),n.push(()=>r.removeEventListener(`abort`,e))}return t.signal.aborted||t.signal.addEventListener(`abort`,()=>{n.forEach(e=>e())}),t.signal}const $=new Set;function Ne(e,t){if($.size===0)return!1;for(let n of $)try{n(e,t)}catch(e){console.error(e)}return!0}function Pe(e){return $.add(e),()=>{$.delete(e)}}var Fe=class e{_cfg;constructor(e){this._cfg=e}input(t){let n=null,r=null;return t!==void 0&&(S(t)?n=t:r=t),new e({schema:n,defaultInput:r,states:[],deriveds:[],ons:[],effects:[],onMounts:[],onErrors:[],transition:null,css:null,as:null})}as(t){return new e({...this._cfg,as:h(t)})}state(t,n){let r=this._cfg;return new e({...r,states:[...r.states,{key:t,init:n}]})}derived(t,n){let r=this._cfg;return new e({...r,deriveds:[...r.deriveds,{key:t,fn:n}]})}on(t,n){let r=je(t);return new e({...this._cfg,ons:[...this._cfg.ons,{selector:r.selector,event:r.eventType,options:r.options,abortable:r.abortable,handler:n}]})}effect(t){return new e({...this._cfg,effects:[...this._cfg.effects,{fn:t}]})}onMount(t){return new e({...this._cfg,onMounts:[...this._cfg.onMounts,{fn:t}]})}onError(t){return new e({...this._cfg,onErrors:[...this._cfg.onErrors,{fn:t}]})}transition(t){return new e({...this._cfg,transition:t})}css(t,...n){let r;if(typeof t==`string`)r=t;else{let e=``;for(let r=0;r<t.length;r++)e+=t[r],r<n.length&&(e+=String(n[r]));r=e}return new e({...this._cfg,css:r})}render(e){let{schema:o,defaultInput:s,states:c,deriveds:d,ons:f,effects:p,onMounts:m,onErrors:g,transition:_,css:v,as:y}=this._cfg,b=v==null?``:M(v),x=y??`div`;function S(e){let t={...s??{},...e??{}};return o?re(o,t):t}function C(e,t,n){let r=se(t,n);try{let t=he(e()),n=r.slots,i=r.binds;if(r.pending&&r.pending.size>0){let e=r.pending;return(async()=>({html:await ce(t,e),slots:n,binds:i}))()}return{html:t,slots:n,binds:i}}finally{P()}}function T(e){let t={};for(let n of c){let r=typeof n.init==`function`?n.init(e):n.init,i=B((...e)=>{if(e.length===0)return r});t[n.key]=i}return t}function E(e,t){let n={};for(let r of c){let a=i(t&&r.key in t?t[r.key]:typeof r.init==`function`?r.init(e):r.init),o=B((...e)=>{if(e.length===0)return a();a(e[0])});n[r.key]=o}return n}function D(){if(typeof document<`u`)return document.createElement(`div`);let e={matches:()=>!1,querySelector:()=>null,querySelectorAll:()=>[],setAttribute:()=>{},getAttribute:()=>null,removeAttribute:()=>{},appendChild:()=>e};return e}function N(e,t,n){if(m.length===0||F())return;let i=D(),a=[];for(let o of m){let s=r(void 0),c;try{c=o.fn({state:t,derived:n,input:e,host:i,hydrated:!1})}catch(r){let a=r instanceof Error?r:Error(String(r));if(g.length===0)Ne(a,`mount`)||console.error(a);else for(let r of g)try{r.fn({error:a,source:`mount`,state:t,derived:n,input:e,host:i})}catch(e){console.error(e)}}finally{r(s)}typeof c==`function`&&a.push(c)}for(let e of a.reverse())try{e()}catch(e){let t=e instanceof Error?e:Error(String(e));g.length===0&&(Ne(t,`mount`)||console.error(t))}}function I(t,n=!1){let i=S(t),a=E(i),o=d.map(e=>{let t=r(void 0);try{return{key:e.key,result:e.fn({state:a,input:i,signal:new AbortController().signal})}}catch(t){return{key:e.key,result:Promise.reject(t)}}finally{r(t)}});if(!o.some(e=>e.result instanceof Promise)||n){let t={};for(let e of o)e.result instanceof Promise?t[e.key]={loading:!0,value:void 0,error:void 0}:t[e.key]={loading:!1,value:e.result,error:void 0};let n=Te(t);F()||N(i,a,n);let s=r(void 0);try{let{html:t}=C(()=>e({state:a,derived:n,input:i}));return b+t}finally{r(s)}}return Promise.all(o.map(async e=>{try{return{key:e.key,envelope:{loading:!1,value:await Promise.resolve(e.result),error:void 0}}}catch(t){return{key:e.key,envelope:{loading:!1,value:void 0,error:t instanceof Error?t:Error(String(t))}}}})).then(async t=>{let n={};for(let e of t)n[e.key]=e.envelope;let o=Te(n);F()||N(i,a,o);let s=r(void 0);try{let{html:t}=await C(()=>e({state:a,derived:o,input:i}),void 0,!0);return b+t}finally{r(s)}})}function L(e,t){return R(e,t).unmount}function R(o,s){if(s===void 0){let e=o.getAttribute(j);if(e){let t=l(e,j);t!==void 0&&(s=t)}}let c=i(S(s)),h=new Proxy({},{get(e,t){return c()[t]},has(e,t){return t in c()},ownKeys(){let e=r(void 0);try{return Reflect.ownKeys(c())}finally{r(e)}},getOwnPropertyDescriptor(e,t){let n=r(void 0);try{return Reflect.getOwnPropertyDescriptor(c(),t)}finally{r(n)}}}),v,y=o.getAttribute(oe);if(y){let e=l(y,oe);e!==void 0&&(v=e)}let x=v?Object.fromEntries(Object.entries(v).filter(([e])=>e!==`_derived`&&e!==`_skipOnMount`)):void 0,re=v?._derived,w;if(re){w={};for(let[e,t]of Object.entries(re))t.error&&!(t.error instanceof Error)?w[e]={...t,error:Error(String(t.error))}:w[e]=t}let T=v!=null,D=x!=null&&Object.keys(x).length>0,ie=T&&v?._skipOnMount===!0&&D,O=E(h,x),k=[],M=new AbortController;k.push(()=>M.abort());let{proxy:N,setup:se}=Ee(d,O,h,w),P=()=>{};function F(e,t){let n=e instanceof Error?e:Error(String(e));if(g.length===0){Ne(n,t)||console.error(n);return}for(let e of g)try{e.fn({error:n,source:t,state:O,derived:N,input:h,host:o})}catch(e){console.error(e)}}if(_?.enter)try{let e=_.enter(o);e instanceof Promise&&e.catch(e=>F(e,`transition`))}catch(e){F(e,`transition`)}let I=new Map,L=new Map;function R(e,t){I.delete(e);let n=Symbol(),r=t.unmount(),i=t=>{let r=L.get(e);!r||r.token!==n||(r.el.remove(),t?.remove(),L.delete(e))};if(r instanceof Promise)return L.set(e,{el:t.el,token:n}),r.finally(()=>i());t.el.remove()}function z(e){let t=e;for(;t&&t!==o;){if(t.hasAttribute(`data-ilha`))return!1;t=t.parentElement}return t===o}function ce(){let e=new Set([...L.values()].map(e=>e.el)),t=new Map;for(let n of o.querySelectorAll(`[${A}]`)){if(e.has(n))continue;let r=n.getAttribute(A);r===null||t.has(r)||z(n)&&t.set(r,n)}return t}function B(e){for(let[t,n]of I)e.has(t)||R(t,n);for(let[t,n]of I){let r=e.get(t);r&&r.island!==n.island&&R(t,n)}let t=null;for(let[n,{island:i,props:a}]of e){let e=I.get(n);if(e){e.updateProps(a);continue}t===null&&(t=ce());let o=t.get(n)??null;if(!o)continue;let s=a;if(s===void 0){let e=o.getAttribute(j)??o.getAttribute(`data-props`);if(e){let t=l(e,`props on [${A}="${n}"]`);t!==void 0&&(s=t)}}let c=r(void 0),u;try{let e=i[ae];u=e?e(o,s):{unmount:i.mount(o,s),updateProps:()=>{}}}finally{r(c)}I.set(n,{el:o,island:i,...u})}}let V=[],H=new Set,U=new WeakMap;function W(){for(let e of f)e.options.once&&H.has(e)||(e.selector===``?[o]:Array.from(o.querySelectorAll(e.selector))).forEach(t=>{let r=r=>{if(e.options.once){H.add(e);for(let t of V.filter(t=>t.entry===e))t.target.removeEventListener(t.type,t.fn,t.options);V.splice(0,V.length,...V.filter(t=>t.entry!==e))}let i=r.target instanceof Element?r.target:t,s=e.selector===``?i:t,c;if(e.abortable){let n=U.get(e);n||(n=new WeakMap,U.set(e,n));let r=n.get(t);r&&r.abort();let i=new AbortController;n.set(t,i),c=Me([M.signal,i.signal])}else c=M.signal;let l;a();try{l=e.handler({state:O,derived:N,input:h,host:o,target:s,event:r,signal:c})}catch(e){F(e,`on`),n();return}n(),l instanceof Promise&&l.catch(e=>{e&&e.name===`AbortError`||F(e,`on`)})},i={...e.options,once:!1};t.addEventListener(e.event,r,i),V.push({target:t,type:e.event,fn:r,options:i,entry:e})})}function G(){for(let e of V)e.target.removeEventListener(e.type,e.fn,e.options);V.length=0}function K(){for(let e of m){let t=r(void 0),n;try{n=e.fn({state:O,derived:N,input:h,host:o,hydrated:T})}catch(e){F(e,`mount`)}finally{r(t)}if(n){let e=n;k.push(()=>{try{e()}catch(e){F(e,`mount`)}})}}}let q=T&&o.childNodes.length>0;T&&m.length>0&&!ie&&K();let J=C(()=>e({state:O,derived:N,input:h}),q?o:void 0);q||(o.innerHTML=b+J.html);let Y=Ae(o,J.binds);k.push(()=>Y()),B(J.slots),k.push(()=>I.forEach(e=>e.unmount())),W(),!T&&m.length>0&&K();for(let e of p){let r,i=null,s=t(()=>{if(r){try{r()}catch(e){F(e,`effect`)}r=void 0}i&&i.abort(),i=new AbortController;let t=Me([M.signal,i.signal]);a();try{r=e.fn({state:O,derived:N,input:h,host:o,signal:t})}catch(e){F(e,`effect`)}finally{n()}});k.push(()=>{if(s(),r)try{r()}catch(e){F(e,`effect`)}i&&i.abort()})}P=se(),k.push(P);let le=!1,X=J.html,ue=0,de=t(()=>{let t=++ue,{html:n,slots:r,binds:i}=C(()=>e({state:O,derived:N,input:h}),o),a=b+n;if(!le){if(le=!0,q){for(let[e,t]of I){let n=r.get(e);n&&t.updateProps(n.props)}if(n===X)return}if(n===X||I.size>0&&I.size===r.size&&[...r.keys()].every(e=>I.has(e))&&ee(X,n,r.keys()))return}G(),Y();let s=I.size,c=[];for(let[e,t]of I)if(!r.has(e)){let n=R(e,t);n instanceof Promise&&c.push(n)}for(let[e,t]of I){let n=r.get(e);if(n&&n.island!==t.island){let n=R(e,t);n instanceof Promise&&c.push(n)}}let l=()=>{if(t!==ue)return;let e=new Map,n=r.size<s;for(let[t,i]of I){if(!r.has(t)||!i.el.isConnected)continue;if(n&&t.startsWith(`p:`)){R(t,i);continue}let a=i.el.tagName.toLowerCase(),o=document.createElement(a);o.setAttribute(A,t);let s=te(r.get(t)?.props);s!==``&&o.setAttribute(j,s),i.el.replaceWith(o),e.set(t,i.el)}let c=document.createElement(`template`),l=o.tagName.toLowerCase();if(c.innerHTML=`<${l}>${a}</${l}>`,ne(o,c.content.firstElementChild),e.size>0){let t=ce();for(let[n,r]of e){let e=t.get(n);e&&e.replaceWith(r)}}W(),Y=Ae(o,i),B(r)};c.length>0?Promise.allSettled(c).then(e=>{for(let t of e)t.status===`rejected`&&console.error(t.reason);l()}):l()}),Z=!1;return{unmount:()=>{if(Z)return;Z=!0,de(),G();let e=[];for(let[,t]of I){let n=t.unmount();n instanceof Promise&&e.push(n)}if(_?.leave)try{let t=_.leave(o);t instanceof Promise&&e.push(t)}catch(e){F(e,`transition`)}let t=()=>{for(let e of k)e()};if(e.length>0)return Promise.all(e).then(t).catch(e=>{F(e,`transition`),t()});t()},updateProps:e=>{if(Z)return;let t=S(e);u(c(),t)||c(t)}}}let z=function(e){return F()?{[O]:!0,island:z,props:e,key:void 0}:I(e)};return z.toString=e=>I(e,!0),z.mount=(e,t)=>L(e,t),z[ae]=(e,t)=>R(e,t),z[k]=x,z.key=e=>{if(typeof e!=`string`||e.trim().length===0)throw Error(`island.key() requires a non-empty string.`);if(e.includes(`:`))throw Error(`island.key() key cannot contain the slot separator ":" (got "${e}").`);let t=(t=>({[O]:!0,island:z,props:t,key:e}));return t[O]=!0,t},z[ie]=!0,z.define=(e,t)=>{if(typeof customElements>`u`||typeof HTMLElement>`u`){`${e}`;return}let n=new Set([`annotation-xml`,`color-profile`,`font-face`,`font-face-src`,`font-face-uri`,`font-face-format`,`font-face-name`,`missing-glyph`]);if(typeof e!=`string`||!/^[a-z][a-z0-9._-]*-[a-z0-9._-]*$/.test(e)||n.has(e)){`${e}`;return}if(customElements.get(e)){`${e}`;return}let r=t?.observe??[];class i extends HTMLElement{static observedAttributes=r;_handle=null;_props;_unmounting=!1;_reconnect=!1;get props(){return this._props}set props(e){this._props=e,this._handle&&!this._unmounting&&this._handle.updateProps(this._mergedProps())}_mergedProps(){let e={},t=!1;for(let n of r){let r=this.getAttribute(n);r!==null&&(e[n]=r,t=!0)}if(!(!t&&this._props===void 0))return{...e,...this._props??{}}}connectedCallback(){if(this._unmounting){this._reconnect=!0;return}this._handle||=R(this,this._mergedProps())}disconnectedCallback(){!this._handle||this._unmounting||(this._unmounting=!0,this._reconnect=!1,Promise.resolve(this._handle.unmount()).finally(()=>{this._handle=null,this._unmounting=!1,this._reconnect&&(this._reconnect=!1,this.isConnected&&(this._handle=R(this,this._mergedProps())))}))}attributeChangedCallback(){this._handle&&!this._unmounting&&this._handle.updateProps(this._mergedProps())}}customElements.define(e,i)},z.hydratable=async(e,t)=>{let{name:n,as:i=`div`,snapshot:a=!1,skipOnMount:o}=t,s=h(i),l=e??{},u=await I(l),f=w(JSON.stringify(l)),p=``;if(a!==!1){let e=a===!0||a.state!==!1,t=a===!0||a.derived!==!1,n=o??(e||t),i={},s=S(l),u=T(s);if(e)for(let e of c)i[e.key]=u[e.key]();if(t){let e={};for(let t of d){let n=r(void 0),i,a,o=!1;try{i=t.fn({state:u,input:s,signal:new AbortController().signal})}catch(e){o=!0,a=e}finally{r(n)}if(o){e[t.key]={loading:!1,value:void 0,error:a instanceof Error?a.message:String(a)};continue}try{let n=await Promise.resolve(i);e[t.key]={loading:!1,value:n,error:void 0}}catch(n){e[t.key]={loading:!1,value:void 0,error:n instanceof Error?n.message:String(n)}}}i._derived=e}n&&(i._skipOnMount=!0),p=` ${oe}='${w(JSON.stringify(i))}'`}return`<${s} data-ilha="${w(n)}" ${j}='${f}'${p}>${u}</${s}>`},z}};function Ie(e,t,n){let r=typeof e==`string`?document.querySelector(e):e;return r?t.mount(r,n):(console.warn(`[ilha] from(): element not found: ${e}`),null)}function Le(e,t={}){let n=t.root??document.body,r=t.lazy??!1,i=[];function a(t){let n=t.getAttribute(`data-ilha`);if(!n)return;let r=e[n];if(!r){`${n}${Object.keys(e).join(`, `)}`;return}let a={},o=t.getAttribute(j);if(o){let e=l(o,`${j} on [data-ilha="${n}"]`);e!==void 0&&(a=e)}i.push(r.mount(t,a))}let o=Array.from(n.querySelectorAll(`[data-ilha]`));if(r&&typeof IntersectionObserver<`u`){let e=!1,t=new IntersectionObserver(n=>{if(!e)for(let e of n)e.isIntersecting&&(a(e.target),t.unobserve(e.target))});o.forEach(e=>t.observe(e)),i.push(()=>{e=!0,t.disconnect()})}else o.forEach(a);return{unmount:()=>{let e=[];for(let t of i){let n=t();n instanceof Promise&&e.push(n)}if(e.length>0)return Promise.all(e).then(()=>{})}}}const Re=new Fe({schema:null,defaultInput:null,states:[],deriveds:[],ons:[],effects:[],onMounts:[],onErrors:[],transition:null,css:null,as:null}),ze=Object.assign(Re,{html:pe,raw:q,mount:Le,from:Ie,context:_e,signal:ve,computed:ye,batch:Se,untrack:xe,onUncaughtError:Pe});function Be(e,t,n){return q(R(e,t,n))}const Ve=pe,He=q,Ue=J,We=Le,Ge=Ie,Ke=_e;export{ae as ISLAND_MOUNT_INTERNAL,Be as __ilhaJsxSlot,Se as batch,ye as computed,Ke as context,Ue as css,ze as default,be as effect,Ge as from,Ve as html,ve as ilhaSignal,ve as signal,We as mount,Pe as onUncaughtError,He as raw,xe as untrack};
1
+ import { computed, effect, endBatch, setActiveSub, signal, startBatch } from "alien-signals";
2
+
3
+ //#region src/index.ts
4
+ const MAX_SNAPSHOT_CHARS = 256 * 1024;
5
+ const MAX_SNAPSHOT_DEPTH = 32;
6
+ function exceedsMaxDepth(value, depth) {
7
+ if (depth > MAX_SNAPSHOT_DEPTH) return true;
8
+ if (value === null || typeof value !== "object") return false;
9
+ if (Array.isArray(value)) {
10
+ for (const item of value) if (exceedsMaxDepth(item, depth + 1)) return true;
11
+ return false;
12
+ }
13
+ for (const key in value) {
14
+ if (!Object.prototype.hasOwnProperty.call(value, key)) continue;
15
+ if (exceedsMaxDepth(value[key], depth + 1)) return true;
16
+ }
17
+ return false;
18
+ }
19
+ const UNSAFE_SNAPSHOT_KEYS = /* @__PURE__ */ new Set([
20
+ "__proto__",
21
+ "constructor",
22
+ "prototype"
23
+ ]);
24
+ function stripUnsafeKeys(value) {
25
+ if (value === null || typeof value !== "object") return;
26
+ if (Array.isArray(value)) {
27
+ for (const item of value) stripUnsafeKeys(item);
28
+ return;
29
+ }
30
+ for (const key of Object.getOwnPropertyNames(value)) if (UNSAFE_SNAPSHOT_KEYS.has(key)) delete value[key];
31
+ else stripUnsafeKeys(value[key]);
32
+ }
33
+ function safeParseSnapshot(raw, label) {
34
+ if (raw.length > MAX_SNAPSHOT_CHARS) {
35
+ `${label}`;
36
+ return;
37
+ }
38
+ let parsed;
39
+ try {
40
+ parsed = JSON.parse(raw);
41
+ } catch {
42
+ `${label}`;
43
+ return;
44
+ }
45
+ if (exceedsMaxDepth(parsed, 1)) {
46
+ `${label}`;
47
+ return;
48
+ }
49
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
50
+ `${label}`;
51
+ return;
52
+ }
53
+ stripUnsafeKeys(parsed);
54
+ return parsed;
55
+ }
56
+ function shallowEqualInput(a, b) {
57
+ if (Object.is(a, b)) return true;
58
+ if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) return false;
59
+ const ak = Object.keys(a);
60
+ const bk = Object.keys(b);
61
+ if (ak.length !== bk.length) return false;
62
+ for (const k of ak) {
63
+ if (!Object.prototype.hasOwnProperty.call(b, k)) return false;
64
+ if (!Object.is(a[k], b[k])) return false;
65
+ }
66
+ return true;
67
+ }
68
+ function parseHtmlFragment(html) {
69
+ const tpl = document.createElement("template");
70
+ tpl.innerHTML = html;
71
+ return tpl.content;
72
+ }
73
+ function extractDirectChildSlotIdsInOrder(root) {
74
+ const ids = [];
75
+ for (const el of root.querySelectorAll("[data-ilha-slot]")) {
76
+ if (!(el instanceof Element)) continue;
77
+ let parent = el.parentElement ?? el.parentNode;
78
+ let nested = false;
79
+ while (parent && parent !== root) {
80
+ if (parent instanceof Element && parent.hasAttribute("data-ilha-slot")) {
81
+ nested = true;
82
+ break;
83
+ }
84
+ parent = parent instanceof Element ? parent.parentElement ?? parent.parentNode : parent.parentNode;
85
+ }
86
+ if (!nested) ids.push(el.getAttribute("data-ilha-slot"));
87
+ }
88
+ return ids;
89
+ }
90
+ function extractSlotPropsAttr(root, slotId) {
91
+ for (const el of root.querySelectorAll(`[${SLOT_ATTR}]`)) if (el.getAttribute(SLOT_ATTR) === slotId) return el.getAttribute(PROPS_ATTR) ?? "";
92
+ return null;
93
+ }
94
+ const SLOT_TAG_NAME_RE = /^[a-z][a-z0-9-]*$/i;
95
+ function assertValidSlotTagName(tag) {
96
+ const trimmed = tag.trim();
97
+ if (trimmed.length === 0) throw new Error("island.as() requires a non-empty HTML tag name.");
98
+ if (!SLOT_TAG_NAME_RE.test(trimmed)) throw new Error(`island.as() tag must be a valid HTML element name (got "${tag}"). Use names like "span", "div", or "li".`);
99
+ return trimmed.toLowerCase();
100
+ }
101
+ function getIslandSlotTag(island) {
102
+ const tag = island[ISLAND_SLOT_TAG];
103
+ if (typeof tag === "string" && tag.length > 0) return tag;
104
+ return "div";
105
+ }
106
+ function wrapIslandSlotHtml(tag, id, propsAttr, inner) {
107
+ return `<${tag} ${SLOT_ATTR}="${escapeHtml(id)}"${propsAttr}>${inner}</${tag}>`;
108
+ }
109
+ function isStableInlineSlotMount(initialHtml, renderedHtml, slotIds) {
110
+ if (typeof document === "undefined") return false;
111
+ const initialRoot = parseHtmlFragment(initialHtml);
112
+ const renderedRoot = parseHtmlFragment(renderedHtml);
113
+ const initialOrder = extractDirectChildSlotIdsInOrder(initialRoot);
114
+ const renderedOrder = extractDirectChildSlotIdsInOrder(renderedRoot);
115
+ if (initialOrder.length !== renderedOrder.length || initialOrder.some((id, i) => id !== renderedOrder[i])) return false;
116
+ for (const id of slotIds) {
117
+ const initialProps = extractSlotPropsAttr(initialRoot, id);
118
+ const renderedProps = extractSlotPropsAttr(renderedRoot, id);
119
+ if (initialProps === null || renderedProps === null) return false;
120
+ if (initialProps !== renderedProps) return false;
121
+ }
122
+ return true;
123
+ }
124
+ function serializeSlotProps(props) {
125
+ return props === void 0 ? "" : JSON.stringify(props);
126
+ }
127
+ const MORPH_CONTROLLER_SLOT_SELECTOR = "[data-slot]";
128
+ const MORPH_CONTROLLER_ATTRS = /* @__PURE__ */ new Set([
129
+ "data-checked",
130
+ "data-unchecked",
131
+ "data-indeterminate",
132
+ "aria-checked",
133
+ "data-open",
134
+ "data-closed",
135
+ "data-state",
136
+ "aria-expanded",
137
+ "aria-hidden",
138
+ "data-selected",
139
+ "data-panel-open"
140
+ ]);
141
+ function shouldPreserveMorphAttr(el, name) {
142
+ return el.matches(MORPH_CONTROLLER_SLOT_SELECTOR) && MORPH_CONTROLLER_ATTRS.has(name);
143
+ }
144
+ function syncAttributes(from, to) {
145
+ for (const { name, value } of to.attributes) {
146
+ if (shouldPreserveMorphAttr(from, name)) continue;
147
+ if (from.getAttribute(name) !== value) from.setAttribute(name, value);
148
+ }
149
+ for (const { name } of Array.from(from.attributes)) {
150
+ if (shouldPreserveMorphAttr(from, name)) continue;
151
+ if (!to.hasAttribute(name)) from.removeAttribute(name);
152
+ }
153
+ }
154
+ function morphChildren(fromParent, toParent) {
155
+ const toNodes = Array.from(toParent.childNodes);
156
+ let fromKeyed = null;
157
+ for (const child of fromParent.children) {
158
+ const k = child.getAttribute("data-key");
159
+ if (k !== null && !(fromKeyed ??= /* @__PURE__ */ new Map()).has(k)) fromKeyed.set(k, child);
160
+ }
161
+ let toKeys = null;
162
+ if (fromKeyed !== null) {
163
+ toKeys = /* @__PURE__ */ new Set();
164
+ for (const child of toParent.children) {
165
+ const k = child.getAttribute("data-key");
166
+ if (k !== null) toKeys.add(k);
167
+ }
168
+ }
169
+ for (let i = 0; i < toNodes.length; i++) {
170
+ const toNode = toNodes[i];
171
+ let fromNode = fromParent.childNodes[i];
172
+ if (fromKeyed !== null) {
173
+ const toKey = toNode.nodeType === 1 ? toNode.getAttribute("data-key") : null;
174
+ if (toKey !== null) {
175
+ const match = fromKeyed.get(toKey);
176
+ if (match) {
177
+ fromKeyed.delete(toKey);
178
+ if (match !== fromNode) {
179
+ fromParent.insertBefore(match, fromNode ?? null);
180
+ fromNode = match;
181
+ }
182
+ }
183
+ }
184
+ if (fromNode instanceof Element) {
185
+ const fromKey = fromNode.getAttribute("data-key");
186
+ if (fromKey !== null && fromKey !== toKey && toKeys.has(fromKey)) {
187
+ fromParent.insertBefore(toNode.cloneNode(true), fromNode);
188
+ continue;
189
+ }
190
+ }
191
+ }
192
+ if (!fromNode) {
193
+ fromParent.appendChild(toNode.cloneNode(true));
194
+ continue;
195
+ }
196
+ if (fromNode.nodeType !== toNode.nodeType) {
197
+ fromParent.replaceChild(toNode.cloneNode(true), fromNode);
198
+ continue;
199
+ }
200
+ if (fromNode.nodeType === 3 || fromNode.nodeType === 8) {
201
+ if (fromNode.nodeValue !== toNode.nodeValue) fromNode.nodeValue = toNode.nodeValue;
202
+ continue;
203
+ }
204
+ if (fromNode.nodeType === 1) {
205
+ const fromEl = fromNode;
206
+ const toEl = toNode;
207
+ if (fromEl.localName !== toEl.localName || fromEl.namespaceURI !== toEl.namespaceURI) {
208
+ fromParent.replaceChild(toEl.cloneNode(true), fromEl);
209
+ continue;
210
+ }
211
+ if (fromEl.localName === "input" && fromEl.type !== toEl.type) {
212
+ fromParent.replaceChild(toEl.cloneNode(true), fromEl);
213
+ continue;
214
+ }
215
+ if (fromEl.localName === "input") {
216
+ const hadChecked = fromEl.hasAttribute("checked");
217
+ const hadValue = fromEl.getAttribute("value");
218
+ syncAttributes(fromEl, toEl);
219
+ const hasChecked = toEl.hasAttribute("checked");
220
+ if (hasChecked !== hadChecked) fromEl.checked = hasChecked;
221
+ const newValue = toEl.getAttribute("value");
222
+ if (newValue !== hadValue) fromEl.value = newValue ?? "";
223
+ continue;
224
+ }
225
+ syncAttributes(fromEl, toEl);
226
+ if (fromEl.localName === "textarea") {
227
+ const newText = toEl.textContent ?? "";
228
+ if (fromEl.textContent !== newText) {
229
+ fromEl.textContent = newText;
230
+ fromEl.value = newText;
231
+ }
232
+ } else morphChildren(fromEl, toEl);
233
+ }
234
+ }
235
+ while (fromParent.childNodes.length > toNodes.length) fromParent.lastChild.remove();
236
+ }
237
+ function morphInner(from, to) {
238
+ if (from.localName !== to.localName || from.namespaceURI !== to.namespaceURI) throw new Error("[ilha] morph: elements must match");
239
+ morphChildren(from, to);
240
+ }
241
+ function isStandardSchema(value) {
242
+ if (value == null || typeof value !== "object") return false;
243
+ const std = value["~standard"];
244
+ return std != null && typeof std.validate === "function" && std.version === 1;
245
+ }
246
+ function validateSchema(schema, value) {
247
+ const result = schema["~standard"].validate(value);
248
+ if (result instanceof Promise) throw new Error("[ilha] Async schemas are not supported.");
249
+ if (result.issues) throw new Error(`[ilha] Validation failed:\n${result.issues.map((i) => ` - ${i.message}`).join("\n")}`);
250
+ return result.value;
251
+ }
252
+ const ESC = {
253
+ "&": "&amp;",
254
+ "<": "&lt;",
255
+ ">": "&gt;",
256
+ "\"": "&quot;",
257
+ "'": "&#39;"
258
+ };
259
+ function escapeHtml(value) {
260
+ return String(value).replace(/[&<>"']/g, (c) => ESC[c]);
261
+ }
262
+ function dedentString(str) {
263
+ if (str.length === 0 || str[0] !== "\n") return str;
264
+ const lines = str.split("\n");
265
+ while (lines.length && lines[0].trim() === "") lines.shift();
266
+ while (lines.length && lines[lines.length - 1].trim() === "") lines.pop();
267
+ if (!lines.length) return "";
268
+ const indent = Math.min(...lines.filter((l) => l.trim() !== "").map((l) => l.match(/^(\s*)/)[1].length));
269
+ return lines.map((l) => l.slice(indent)).join("\n");
270
+ }
271
+ const RAW = Symbol.for("ilha.raw");
272
+ const SIGNAL_ACCESSOR = Symbol.for("ilha.signalAccessor");
273
+ const ISLAND = Symbol.for("ilha.island");
274
+ const ISLAND_CALL = Symbol.for("ilha.islandCall");
275
+ /** @internal Internal hook used by a parent's mountSlots to mount a child island and
276
+ * retain a handle to push updated props into it on subsequent parent
277
+ * re-renders. Not part of the public surface. */
278
+ const ISLAND_MOUNT_INTERNAL = Symbol.for("ilha.islandMountInternal");
279
+ const ISLAND_SLOT_TAG = Symbol.for("ilha.islandSlotTag");
280
+ const SLOT_ATTR = "data-ilha-slot";
281
+ const PROPS_ATTR = "data-ilha-props";
282
+ const STATE_ATTR = "data-ilha-state";
283
+ const CSS_ATTR = "data-ilha-css";
284
+ function buildScopedStyle(css) {
285
+ return `<style ${CSS_ATTR}>@scope (:scope) to ([data-ilha]){${css.replace(/<\/style/gi, "<\\/style")}}</style>`;
286
+ }
287
+ const renderCtxStack = [];
288
+ function pushRenderCtx(liveHost, asyncChildren) {
289
+ const ctx = {
290
+ slots: /* @__PURE__ */ new Map(),
291
+ positional: 0,
292
+ liveHost,
293
+ pending: asyncChildren ? /* @__PURE__ */ new Map() : void 0,
294
+ binds: []
295
+ };
296
+ renderCtxStack.push(ctx);
297
+ return ctx;
298
+ }
299
+ function popRenderCtx() {
300
+ renderCtxStack.pop();
301
+ }
302
+ function currentRenderCtx() {
303
+ return renderCtxStack[renderCtxStack.length - 1];
304
+ }
305
+ function isIsland(v) {
306
+ return typeof v === "function" && ISLAND in v;
307
+ }
308
+ function isIslandCall(v) {
309
+ if (v == null || typeof v !== "object" && typeof v !== "function") return false;
310
+ if (ISLAND_CALL in v) return true;
311
+ return typeof v === "object" && "island" in v && isIsland(v.island);
312
+ }
313
+ function emitIslandSlot(island, props, key) {
314
+ const ctx = currentRenderCtx();
315
+ let id;
316
+ if (key !== void 0) id = `k:${key}`;
317
+ else id = ctx ? `p:${ctx.positional++}` : "p:0";
318
+ if (ctx) ctx.slots.set(id, {
319
+ island,
320
+ props
321
+ });
322
+ const slotTag = getIslandSlotTag(island);
323
+ const propsAttr = props ? ` ${PROPS_ATTR}='${escapeHtml(JSON.stringify(props))}'` : "";
324
+ if (ctx?.liveHost) return wrapIslandSlotHtml(slotTag, id, propsAttr, "");
325
+ if (ctx?.pending) {
326
+ popRenderCtx();
327
+ try {
328
+ const result = island(props);
329
+ if (result instanceof Promise) {
330
+ ctx.pending.set(id, result.then(String));
331
+ return wrapIslandSlotHtml(slotTag, id, propsAttr, asyncSlotMarker(id));
332
+ }
333
+ return wrapIslandSlotHtml(slotTag, id, propsAttr, String(result));
334
+ } finally {
335
+ renderCtxStack.push(ctx);
336
+ }
337
+ }
338
+ const inner = island.toString(props);
339
+ return wrapIslandSlotHtml(slotTag, id, propsAttr, inner);
340
+ }
341
+ function asyncSlotMarker(id) {
342
+ return `<!--ilha-async:${escapeHtml(id)}-->`;
343
+ }
344
+ async function resolveAsyncChildren(html, pending) {
345
+ for (const [id, promise] of pending) {
346
+ const inner = await promise;
347
+ html = html.split(asyncSlotMarker(id)).join(inner);
348
+ }
349
+ return html;
350
+ }
351
+ function markSignalAccessor(fn) {
352
+ fn[SIGNAL_ACCESSOR] = true;
353
+ const accessor = fn;
354
+ accessor.select = (selector) => createSelectAccessor(accessor, selector);
355
+ return accessor;
356
+ }
357
+ function isSignalAccessor(v) {
358
+ return typeof v === "function" && SIGNAL_ACCESSOR in v;
359
+ }
360
+ function getAtPath(obj, path) {
361
+ let cur = obj;
362
+ for (const seg of path) {
363
+ if (cur == null) return void 0;
364
+ cur = cur[seg];
365
+ }
366
+ return cur;
367
+ }
368
+ function setAtPath(obj, path, value) {
369
+ if (path.length === 0) return value;
370
+ const [head, ...rest] = path;
371
+ if (Array.isArray(obj)) {
372
+ const idx = head;
373
+ if (idx < 0 || idx >= obj.length) return obj;
374
+ const next = obj[idx];
375
+ const updated = rest.length === 0 ? value : setAtPath(next, rest, value);
376
+ if (Object.is(next, updated)) return obj;
377
+ const copy = obj.slice();
378
+ copy[idx] = updated;
379
+ return copy;
380
+ }
381
+ if (obj !== null && typeof obj === "object") {
382
+ const record = obj;
383
+ const key = String(head);
384
+ const next = record[key];
385
+ const updated = rest.length === 0 ? value : setAtPath(next, rest, value);
386
+ if (rest.length === 0) {
387
+ if (Object.is(next, value)) return obj;
388
+ } else if (Object.is(next, updated)) return obj;
389
+ return {
390
+ ...record,
391
+ [key]: updated
392
+ };
393
+ }
394
+ return rest.length === 0 ? value : setAtPath(void 0, rest, value);
395
+ }
396
+ function toPathSegment(prop) {
397
+ if (typeof prop === "symbol") return null;
398
+ if (prop === "length") return null;
399
+ if (/^\d+$/.test(prop)) return Number(prop);
400
+ return prop;
401
+ }
402
+ function trackSelectPath(rootState, selector) {
403
+ const path = [];
404
+ const track = (value) => {
405
+ if (value === null || typeof value !== "object" && typeof value !== "function") return value;
406
+ return new Proxy(value, { get(target, prop, receiver) {
407
+ const seg = toPathSegment(prop);
408
+ if (seg != null) path.push(seg);
409
+ const next = Reflect.get(target, prop, receiver);
410
+ return seg != null && next !== null && typeof next === "object" ? track(next) : next;
411
+ } });
412
+ };
413
+ selector(track(rootState));
414
+ return path;
415
+ }
416
+ function createSelectAccessor(root, selector) {
417
+ const path = trackSelectPath(root(), selector);
418
+ const selected = selector(root());
419
+ const resolved = path.length === 0 ? root() : getAtPath(root(), path);
420
+ if (!Object.is(selected, resolved)) throw new Error("select(): selector must only traverse nested properties or array indexes — derived or transformed values are not supported.");
421
+ return markSignalAccessor((...args) => {
422
+ if (args.length === 0) return path.length === 0 ? selector(root()) : getAtPath(root(), path);
423
+ const next = path.length === 0 ? args[0] : setAtPath(root(), path, args[0]);
424
+ if (!Object.is(root(), next)) root(next);
425
+ });
426
+ }
427
+ function ilhaRaw(value) {
428
+ return {
429
+ [RAW]: true,
430
+ value
431
+ };
432
+ }
433
+ function ilhaCss(strings, ...values) {
434
+ if (typeof strings === "string") return strings;
435
+ let result = "";
436
+ for (let i = 0; i < strings.length; i++) {
437
+ result += strings[i];
438
+ if (i < values.length) result += String(values[i]);
439
+ }
440
+ return result;
441
+ }
442
+ function interpolateValue(v) {
443
+ if (v == null || v === true || v === false) return "";
444
+ if (Array.isArray(v)) return v.map(interpolateValue).join("");
445
+ if (isRawHtml(v)) return v.value;
446
+ if (isIslandCall(v)) {
447
+ const call = typeof v === "function" ? v() : v;
448
+ return emitIslandSlot(call.island, call.props, call.key);
449
+ }
450
+ if (isIsland(v)) return emitIslandSlot(v, void 0, void 0);
451
+ if (isSignalAccessor(v)) return escapeHtml(v());
452
+ if (typeof v === "function") return escapeHtml(v());
453
+ return escapeHtml(v);
454
+ }
455
+ const BIND_VALID_KINDS = /* @__PURE__ */ new Set([
456
+ "value",
457
+ "checked",
458
+ "valueAsNumber",
459
+ "valueAsDate",
460
+ "files",
461
+ "open",
462
+ "group",
463
+ "this"
464
+ ]);
465
+ const BIND_PREFIX_RE = /\bbind:([a-zA-Z]+)\s*=\s*("|')?$/;
466
+ function findTagCloseIndex(chunk, initialQuote) {
467
+ let quote = initialQuote;
468
+ for (let i = 0; i < chunk.length; i++) {
469
+ const ch = chunk[i];
470
+ if (quote !== null) {
471
+ if (ch === quote) quote = null;
472
+ } else if (ch === "\"" || ch === "'") quote = ch;
473
+ else if (ch === ">") return {
474
+ index: i,
475
+ quote
476
+ };
477
+ }
478
+ return {
479
+ index: -1,
480
+ quote
481
+ };
482
+ }
483
+ function formatDateForInput(d) {
484
+ if (d instanceof Date) {
485
+ if (isNaN(d.getTime())) return "";
486
+ const pad = (n) => String(n).padStart(2, "0");
487
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
488
+ }
489
+ return "";
490
+ }
491
+ function extractElementStaticValue(prefix) {
492
+ const lastOpen = prefix.lastIndexOf("<");
493
+ if (lastOpen === -1) return null;
494
+ const tagPrefix = prefix.slice(lastOpen);
495
+ if (tagPrefix.includes(">")) return null;
496
+ const m = tagPrefix.match(/\bvalue\s*=\s*("([^"]*)"|'([^']*)'|([^\s>]+))/);
497
+ if (!m) return null;
498
+ return m[2] ?? m[3] ?? m[4] ?? null;
499
+ }
500
+ function emitBindSSR(kind, index, accessor, prefixForStaticPeek) {
501
+ const spec = `${kind}:${index}`;
502
+ let v;
503
+ try {
504
+ v = accessor();
505
+ } catch {
506
+ v = void 0;
507
+ }
508
+ switch (kind) {
509
+ case "value": return [` value="${escapeHtml(v ?? "")}"`, spec];
510
+ case "valueAsNumber": return [` value="${escapeHtml(v == null ? "" : String(v))}"`, spec];
511
+ case "valueAsDate": return [` value="${escapeHtml(formatDateForInput(v))}"`, spec];
512
+ case "checked": return [v ? ` checked` : ``, spec];
513
+ case "open": return [v ? ` open` : ``, spec];
514
+ case "files": return [``, spec];
515
+ case "this": return [``, spec];
516
+ case "group": {
517
+ const optionValue = extractElementStaticValue(prefixForStaticPeek);
518
+ if (optionValue == null) return [``, spec];
519
+ return [(Array.isArray(v) ? v.map(String).includes(optionValue) : v != null && String(v) === optionValue) ? ` checked` : ``, spec];
520
+ }
521
+ }
522
+ }
523
+ function ilhaHtml(strings, ...values) {
524
+ let result = "";
525
+ let stripLeadingQuote = null;
526
+ let pendingBindSpecs = "";
527
+ let pendingQuote = null;
528
+ const ctx = currentRenderCtx();
529
+ for (let i = 0; i < strings.length; i++) {
530
+ let chunk = strings[i];
531
+ if (stripLeadingQuote !== null) {
532
+ if (chunk.startsWith(stripLeadingQuote)) chunk = chunk.slice(1);
533
+ stripLeadingQuote = null;
534
+ }
535
+ if (pendingBindSpecs !== "") {
536
+ const { index: gtIdx, quote } = findTagCloseIndex(chunk, pendingQuote);
537
+ if (gtIdx !== -1) {
538
+ chunk = chunk.slice(0, gtIdx).replace(/\s*\/\s*$/, "") + ` data-ilha-bind="${pendingBindSpecs}">` + chunk.slice(gtIdx + 1);
539
+ pendingBindSpecs = "";
540
+ pendingQuote = null;
541
+ } else pendingQuote = quote;
542
+ }
543
+ if (i >= values.length) {
544
+ result += chunk;
545
+ continue;
546
+ }
547
+ const value = values[i];
548
+ const m = chunk.match(BIND_PREFIX_RE);
549
+ if (m && isSignalAccessor(value)) {
550
+ const name = m[1];
551
+ const openQuote = m[2] ?? null;
552
+ if (!BIND_VALID_KINDS.has(name)) {
553
+ result += chunk + interpolateValue(value);
554
+ continue;
555
+ }
556
+ if (!ctx) {
557
+ const stripped = chunk.slice(0, chunk.length - m[0].length);
558
+ const quote = openQuote ?? "\"";
559
+ result += stripped + name + "=" + quote + interpolateValue(value) + quote;
560
+ if (openQuote) stripLeadingQuote = openQuote;
561
+ continue;
562
+ }
563
+ const matchStart = chunk.length - m[0].length;
564
+ const cleanPrefix = chunk.slice(0, matchStart).replace(/\s+$/, "");
565
+ const index = ctx.binds.length;
566
+ ctx.binds.push({
567
+ kind: name,
568
+ accessor: value
569
+ });
570
+ const [valueAttrs, spec] = emitBindSSR(name, index, value, cleanPrefix);
571
+ result += cleanPrefix + valueAttrs;
572
+ pendingBindSpecs += (pendingBindSpecs ? "," : "") + spec;
573
+ if (openQuote) stripLeadingQuote = openQuote;
574
+ continue;
575
+ }
576
+ result += chunk + interpolateValue(value);
577
+ }
578
+ if (pendingBindSpecs !== "") result += ` data-ilha-bind="${pendingBindSpecs}"`;
579
+ return {
580
+ [RAW]: true,
581
+ value: dedentString(result)
582
+ };
583
+ }
584
+ function isRawHtml(v) {
585
+ if (typeof v !== "object" || v === null) return false;
586
+ return RAW in v && typeof v.value === "string";
587
+ }
588
+ function unwrapHtml(v) {
589
+ return isRawHtml(v) ? v.value : v;
590
+ }
591
+ const contextRegistry = /* @__PURE__ */ new Map();
592
+ function ilhaContextFn(key, initial) {
593
+ if (contextRegistry.has(key)) return contextRegistry.get(key);
594
+ const s = signal(initial);
595
+ const accessor = (...args) => {
596
+ if (args.length === 0) return s();
597
+ s(args[0]);
598
+ };
599
+ contextRegistry.set(key, accessor);
600
+ return accessor;
601
+ }
602
+ const ilhaContext = Object.assign(ilhaContextFn, {
603
+ /** Remove a context signal from the registry. Returns true if it existed. */
604
+ delete(key) {
605
+ return contextRegistry.delete(key);
606
+ },
607
+ /** Remove all context signals from the registry (e.g. between tests). */
608
+ clear() {
609
+ contextRegistry.clear();
610
+ }
611
+ });
612
+ /**
613
+ * Create a free-standing reactive signal that lives outside any island.
614
+ * Useful for sharing state across islands without prop drilling, or for
615
+ * binding form inputs to module-level state via the `bind:value=${signal}`
616
+ * template syntax.
617
+ *
618
+ * The returned accessor is a getter when called with no arguments and a
619
+ * setter when called with one. Reading it inside a `.derived()`, `.effect()`,
620
+ * or `.render()` automatically subscribes the surrounding reactive scope —
621
+ * so when the signal changes, dependents re-run as if it were local state.
622
+ */
623
+ function ilhaSignal(initial) {
624
+ const s = signal(initial);
625
+ return markSignalAccessor((...args) => {
626
+ if (args.length === 0) return s();
627
+ s(args[0]);
628
+ });
629
+ }
630
+ /**
631
+ * Create a free-standing read-only reactive value derived from other signals.
632
+ * The computation is lazy and cached: `fn` re-runs only when a signal it read
633
+ * changed and the computed is read again. Reading it inside a `.derived()`,
634
+ * `.effect()`, `.render()`, or top-level `effect()` subscribes that scope —
635
+ * dependents re-run when the computed's value changes.
636
+ *
637
+ * ```ts
638
+ * const items = ilha.signal([1, 2, 3]);
639
+ * const total = ilha.computed(() => items().reduce((a, b) => a + b, 0));
640
+ * ```
641
+ */
642
+ function ilhaComputed(fn) {
643
+ const c = computed(fn);
644
+ return markSignalAccessor((...args) => {
645
+ if (args.length > 0) return;
646
+ return c();
647
+ });
648
+ }
649
+ /**
650
+ * Run a free-standing reactive effect outside any island. `fn` runs once
651
+ * immediately and again whenever a signal it read changes. It may return a
652
+ * cleanup function, invoked before each re-run and on stop. Signal writes
653
+ * inside the effect are batched. Returns a stop function that disposes the
654
+ * effect and runs the final cleanup.
655
+ *
656
+ * ```ts
657
+ * const stop = effect(() => {
658
+ * document.title = `${cart.count()} items`;
659
+ * });
660
+ * ```
661
+ */
662
+ function ilhaEffect(fn) {
663
+ let cleanup;
664
+ const runCleanup = () => {
665
+ if (typeof cleanup === "function") {
666
+ try {
667
+ cleanup();
668
+ } catch (err) {
669
+ console.error(err);
670
+ }
671
+ cleanup = void 0;
672
+ }
673
+ };
674
+ const stop = effect(() => {
675
+ runCleanup();
676
+ startBatch();
677
+ try {
678
+ cleanup = fn();
679
+ } catch (err) {
680
+ console.error(err);
681
+ } finally {
682
+ endBatch();
683
+ }
684
+ });
685
+ return () => {
686
+ stop();
687
+ runCleanup();
688
+ };
689
+ }
690
+ /**
691
+ * Run `fn` with reactive tracking suspended. Reading signals inside `fn`
692
+ * returns their current value without subscribing the surrounding scope.
693
+ * Use this in effects/deriveds when you want to peek at state without
694
+ * causing a re-run on its changes.
695
+ */
696
+ function untrack(fn) {
697
+ const prev = setActiveSub(void 0);
698
+ try {
699
+ return fn();
700
+ } finally {
701
+ setActiveSub(prev);
702
+ }
703
+ }
704
+ /**
705
+ * Run `fn` as an atomic batch — multiple signal writes inside the callback
706
+ * produce a single propagation pass, so dependents (effects, deriveds,
707
+ * island re-renders) see the final state and run once instead of once per
708
+ * write. Returns whatever `fn` returns.
709
+ *
710
+ * Note: `.on()` handlers and `.effect()` runs are batched implicitly, so
711
+ * you only need this when triggering multiple writes from outside an
712
+ * island (e.g. from a top-level event listener or async callback).
713
+ */
714
+ function batch(fn) {
715
+ startBatch();
716
+ try {
717
+ return fn();
718
+ } finally {
719
+ endBatch();
720
+ }
721
+ }
722
+ function createDerivedAccessor(read, write) {
723
+ const accessor = markSignalAccessor((...args) => {
724
+ if (args.length > 0) {
725
+ if (write) write(args[0]);
726
+ return;
727
+ }
728
+ return read().value;
729
+ });
730
+ return new Proxy(accessor, { get(target, prop, receiver) {
731
+ if (prop === "loading" || prop === "value" || prop === "error") return read()[prop];
732
+ return Reflect.get(target, prop, receiver);
733
+ } });
734
+ }
735
+ function defaultDerivedAccessor() {
736
+ return createDerivedAccessor(() => ({
737
+ loading: false,
738
+ value: void 0,
739
+ error: void 0
740
+ }));
741
+ }
742
+ function buildDerivedAccessors(envelopes) {
743
+ const accessors = /* @__PURE__ */ new Map();
744
+ for (const [key, envelope] of Object.entries(envelopes)) accessors.set(key, createDerivedAccessor(() => envelope, (value) => {
745
+ envelope.loading = false;
746
+ envelope.value = value;
747
+ envelope.error = void 0;
748
+ }));
749
+ return new Proxy({}, { get(_, key) {
750
+ if (typeof key !== "string") return void 0;
751
+ return accessors.get(key) ?? defaultDerivedAccessor();
752
+ } });
753
+ }
754
+ function createDerivedProxy(entries, state, input, derivedSnapshot) {
755
+ const envelopes = /* @__PURE__ */ new Map();
756
+ for (const entry of entries) {
757
+ let initialEnvelope;
758
+ if (derivedSnapshot != null && entry.key in derivedSnapshot) initialEnvelope = { ...derivedSnapshot[entry.key] };
759
+ else if (!(entry.fn.constructor.name === "AsyncFunction" || entry.fn.constructor.name === "AsyncGeneratorFunction")) {
760
+ const ac = new AbortController();
761
+ try {
762
+ const result = entry.fn({
763
+ state,
764
+ input,
765
+ signal: ac.signal
766
+ });
767
+ if (!(result instanceof Promise)) initialEnvelope = {
768
+ loading: false,
769
+ value: result,
770
+ error: void 0
771
+ };
772
+ else {
773
+ initialEnvelope = {
774
+ loading: true,
775
+ value: void 0,
776
+ error: void 0
777
+ };
778
+ result.catch(() => {});
779
+ }
780
+ } catch (err) {
781
+ initialEnvelope = {
782
+ loading: false,
783
+ value: void 0,
784
+ error: err instanceof Error ? err : new Error(String(err))
785
+ };
786
+ } finally {
787
+ ac.abort();
788
+ }
789
+ } else initialEnvelope = {
790
+ loading: true,
791
+ value: void 0,
792
+ error: void 0
793
+ };
794
+ const env = signal(initialEnvelope);
795
+ envelopes.set(entry.key, env);
796
+ }
797
+ const accessors = /* @__PURE__ */ new Map();
798
+ for (const entry of entries) {
799
+ const env = envelopes.get(entry.key);
800
+ accessors.set(entry.key, createDerivedAccessor(() => env(), (value) => {
801
+ const prevSub = setActiveSub(void 0);
802
+ env({
803
+ loading: false,
804
+ value,
805
+ error: void 0
806
+ });
807
+ setActiveSub(prevSub);
808
+ }));
809
+ }
810
+ const proxy = new Proxy({}, { get(_, key) {
811
+ if (typeof key !== "string") return void 0;
812
+ return accessors.get(key) ?? defaultDerivedAccessor();
813
+ } });
814
+ const setup = () => {
815
+ const stops = [];
816
+ for (const entry of entries) {
817
+ const env = envelopes.get(entry.key);
818
+ let ac = new AbortController();
819
+ let skipFirst = derivedSnapshot != null && entry.key in derivedSnapshot;
820
+ const stopEffect = effect(() => {
821
+ ac.abort();
822
+ ac = new AbortController();
823
+ const currentAc = ac;
824
+ let result;
825
+ try {
826
+ result = entry.fn({
827
+ state,
828
+ input,
829
+ signal: currentAc.signal
830
+ });
831
+ } catch (err) {
832
+ if (skipFirst) {
833
+ skipFirst = false;
834
+ return;
835
+ }
836
+ const prevSub = setActiveSub(void 0);
837
+ env({
838
+ loading: false,
839
+ value: void 0,
840
+ error: err instanceof Error ? err : new Error(String(err))
841
+ });
842
+ setActiveSub(prevSub);
843
+ return;
844
+ }
845
+ if (skipFirst) {
846
+ skipFirst = false;
847
+ if (result instanceof Promise) result.catch(() => {});
848
+ return;
849
+ }
850
+ if (!(result instanceof Promise)) {
851
+ const prevSub = setActiveSub(void 0);
852
+ env({
853
+ loading: false,
854
+ value: result,
855
+ error: void 0
856
+ });
857
+ setActiveSub(prevSub);
858
+ return;
859
+ }
860
+ const prevSub = setActiveSub(void 0);
861
+ env({
862
+ loading: true,
863
+ value: env().value,
864
+ error: void 0
865
+ });
866
+ setActiveSub(prevSub);
867
+ result.then((value) => {
868
+ if (currentAc.signal.aborted) return;
869
+ env({
870
+ loading: false,
871
+ value,
872
+ error: void 0
873
+ });
874
+ }).catch((err) => {
875
+ if (currentAc.signal.aborted) return;
876
+ env({
877
+ loading: false,
878
+ value: void 0,
879
+ error: err instanceof Error ? err : new Error(String(err))
880
+ });
881
+ });
882
+ });
883
+ stops.push(() => {
884
+ stopEffect();
885
+ ac.abort();
886
+ });
887
+ }
888
+ return () => stops.forEach((s) => s());
889
+ };
890
+ return {
891
+ proxy,
892
+ setup
893
+ };
894
+ }
895
+ const BIND_SENTINEL_ATTR = "data-ilha-bind";
896
+ function parseBindSentinel(value) {
897
+ const out = [];
898
+ for (const part of value.split(",")) {
899
+ const [kind, idx] = part.split(":");
900
+ if (!kind || !idx) continue;
901
+ const i = Number(idx);
902
+ if (!Number.isInteger(i) || i < 0) continue;
903
+ out.push({
904
+ kind,
905
+ index: i
906
+ });
907
+ }
908
+ return out;
909
+ }
910
+ function resolveBindOps(el, kind) {
911
+ const input = el;
912
+ switch (kind) {
913
+ case "value": return {
914
+ event: el.tagName === "SELECT" ? "change" : "input",
915
+ read: (el) => el.value,
916
+ write: (el, v) => el.value = v == null ? "" : String(v)
917
+ };
918
+ case "valueAsNumber": return {
919
+ event: "input",
920
+ read: (el) => {
921
+ const n = el.valueAsNumber;
922
+ return Number.isNaN(n) ? null : n;
923
+ },
924
+ write: (el, v) => el.value = v == null || Number.isNaN(v) ? "" : String(v)
925
+ };
926
+ case "valueAsDate": return {
927
+ event: "input",
928
+ read: (el) => el.valueAsDate,
929
+ write: (el, v) => {
930
+ el.value = formatDateForInput(v);
931
+ }
932
+ };
933
+ case "checked": return {
934
+ event: "change",
935
+ read: (el) => el.checked,
936
+ write: (el, v) => el.checked = Boolean(v)
937
+ };
938
+ case "files": return {
939
+ event: "change",
940
+ read: (el) => el.files,
941
+ write: () => {}
942
+ };
943
+ case "open": return {
944
+ event: "toggle",
945
+ read: (el) => el.open,
946
+ write: (el, v) => el.open = Boolean(v)
947
+ };
948
+ case "this": return {
949
+ event: null,
950
+ read: () => void 0,
951
+ write: () => {}
952
+ };
953
+ case "group": {
954
+ const isCheckbox = input.type === "checkbox";
955
+ return {
956
+ event: "change",
957
+ read: (el) => {
958
+ const i = el;
959
+ if (isCheckbox) return {
960
+ __ilhaGroup: true,
961
+ value: i.value,
962
+ checked: i.checked
963
+ };
964
+ return i.checked ? i.value : void 0;
965
+ },
966
+ write: (el, v) => {
967
+ const i = el;
968
+ if (isCheckbox) i.checked = (Array.isArray(v) ? v.map(String) : []).includes(i.value);
969
+ else i.checked = v != null && String(v) === i.value;
970
+ }
971
+ };
972
+ }
973
+ }
974
+ }
975
+ function applyTemplateBindings(host, binds) {
976
+ if (binds.length === 0) return () => {};
977
+ const cleanups = [];
978
+ const elements = [];
979
+ if (host.hasAttribute(BIND_SENTINEL_ATTR)) elements.push(host);
980
+ for (const el of host.querySelectorAll(`[${BIND_SENTINEL_ATTR}]`)) elements.push(el);
981
+ for (const el of elements) {
982
+ const specs = parseBindSentinel(el.getAttribute(BIND_SENTINEL_ATTR));
983
+ for (const spec of specs) {
984
+ const record = binds[spec.index];
985
+ if (!record) continue;
986
+ if (record.kind !== spec.kind) continue;
987
+ const { event, read, write } = resolveBindOps(el, spec.kind);
988
+ const accessor = record.accessor;
989
+ if (spec.kind === "this") {
990
+ accessor(el);
991
+ cleanups.push(() => accessor(null));
992
+ continue;
993
+ }
994
+ try {
995
+ write(el, accessor());
996
+ } catch (err) {}
997
+ if (event === null) continue;
998
+ const listener = () => {
999
+ const raw = read(el);
1000
+ if (spec.kind === "group") {
1001
+ const groupRead = raw;
1002
+ if (groupRead === void 0) return;
1003
+ if (typeof groupRead === "object" && groupRead.__ilhaGroup) {
1004
+ const currentArr = accessor();
1005
+ const arr = Array.isArray(currentArr) ? [...currentArr] : [];
1006
+ const idx = arr.findIndex((x) => String(x) === groupRead.value);
1007
+ if (groupRead.checked && idx === -1) {
1008
+ let coercedVal = groupRead.value;
1009
+ const templateVal = Array.isArray(currentArr) && currentArr.length > 0 ? currentArr[0] : void 0;
1010
+ if (templateVal !== void 0) {
1011
+ if (typeof templateVal === "number") {
1012
+ const n = Number(coercedVal);
1013
+ coercedVal = Number.isNaN(n) ? coercedVal : n;
1014
+ } else if (typeof templateVal === "boolean") coercedVal = Boolean(coercedVal);
1015
+ }
1016
+ arr.push(coercedVal);
1017
+ } else if (!groupRead.checked && idx !== -1) arr.splice(idx, 1);
1018
+ accessor(arr);
1019
+ return;
1020
+ }
1021
+ const currentVal = accessor();
1022
+ let coerced = groupRead;
1023
+ if (typeof currentVal === "number" && typeof groupRead === "string") {
1024
+ const n = Number(groupRead);
1025
+ coerced = Number.isNaN(n) ? 0 : n;
1026
+ } else if (typeof currentVal === "boolean") coerced = Boolean(groupRead);
1027
+ accessor(coerced);
1028
+ return;
1029
+ }
1030
+ const currentVal = accessor();
1031
+ let value = raw;
1032
+ if (typeof currentVal === "number" && typeof raw === "string") {
1033
+ const n = Number(raw);
1034
+ value = Number.isNaN(n) ? 0 : n;
1035
+ } else if (typeof currentVal === "boolean") value = Boolean(raw);
1036
+ accessor(value);
1037
+ };
1038
+ el.addEventListener(event, listener);
1039
+ cleanups.push(() => el.removeEventListener(event, listener));
1040
+ }
1041
+ }
1042
+ return () => cleanups.forEach((c) => c());
1043
+ }
1044
+ function parseOnArgs(selectorOrCombined) {
1045
+ const atIdx = selectorOrCombined.lastIndexOf("@");
1046
+ const selector = atIdx === -1 ? "" : selectorOrCombined.slice(0, atIdx);
1047
+ const parts = (atIdx === -1 ? selectorOrCombined : selectorOrCombined.slice(atIdx + 1)).split(":");
1048
+ const eventType = parts[0];
1049
+ const modifiers = new Set(parts.slice(1));
1050
+ return {
1051
+ selector,
1052
+ eventType,
1053
+ options: {
1054
+ once: modifiers.has("once"),
1055
+ capture: modifiers.has("capture"),
1056
+ passive: modifiers.has("passive")
1057
+ },
1058
+ abortable: modifiers.has("abortable")
1059
+ };
1060
+ }
1061
+ /**
1062
+ * Combine multiple AbortSignals into one that aborts when any input aborts.
1063
+ * Uses native AbortSignal.any when available, falls back to a manual chain
1064
+ * otherwise (for older runtimes).
1065
+ */
1066
+ function anySignal(signals) {
1067
+ if (typeof AbortSignal.any === "function") return AbortSignal.any(signals);
1068
+ const controller = new AbortController();
1069
+ const cleanups = [];
1070
+ for (const s of signals) {
1071
+ if (s.aborted) {
1072
+ controller.abort(s.reason);
1073
+ cleanups.forEach((c) => c());
1074
+ return controller.signal;
1075
+ }
1076
+ const handler = () => controller.abort(s.reason);
1077
+ s.addEventListener("abort", handler, { once: true });
1078
+ cleanups.push(() => s.removeEventListener("abort", handler));
1079
+ }
1080
+ if (!controller.signal.aborted) controller.signal.addEventListener("abort", () => {
1081
+ cleanups.forEach((c) => c());
1082
+ });
1083
+ return controller.signal;
1084
+ }
1085
+ const globalErrorHandlers = /* @__PURE__ */ new Set();
1086
+ function reportToGlobal(error, source) {
1087
+ if (globalErrorHandlers.size === 0) return false;
1088
+ for (const handler of globalErrorHandlers) try {
1089
+ handler(error, source);
1090
+ } catch (handlerErr) {
1091
+ console.error(handlerErr);
1092
+ }
1093
+ return true;
1094
+ }
1095
+ /**
1096
+ * Register a global error handler invoked when any island reports an error
1097
+ * (from .on, .effect, .onMount, or transitions) and has no local .onError()
1098
+ * handler. Returns an unsubscribe function. Islands with their own .onError()
1099
+ * are handled locally and do not reach the global sink.
1100
+ */
1101
+ function onUncaughtError(fn) {
1102
+ globalErrorHandlers.add(fn);
1103
+ return () => {
1104
+ globalErrorHandlers.delete(fn);
1105
+ };
1106
+ }
1107
+ var IlhaBuilder = class IlhaBuilder {
1108
+ _cfg;
1109
+ constructor(cfg) {
1110
+ this._cfg = cfg;
1111
+ }
1112
+ input(initialOrSchema) {
1113
+ let schema = null;
1114
+ let defaultInput = null;
1115
+ if (initialOrSchema !== void 0) if (isStandardSchema(initialOrSchema)) schema = initialOrSchema;
1116
+ else defaultInput = initialOrSchema;
1117
+ return new IlhaBuilder({
1118
+ schema,
1119
+ defaultInput,
1120
+ states: [],
1121
+ deriveds: [],
1122
+ ons: [],
1123
+ effects: [],
1124
+ onMounts: [],
1125
+ onErrors: [],
1126
+ transition: null,
1127
+ css: null,
1128
+ as: null
1129
+ });
1130
+ }
1131
+ as(tag) {
1132
+ return new IlhaBuilder({
1133
+ ...this._cfg,
1134
+ as: assertValidSlotTagName(tag)
1135
+ });
1136
+ }
1137
+ state(key, init) {
1138
+ const cfg = this._cfg;
1139
+ return new IlhaBuilder({
1140
+ ...cfg,
1141
+ states: [...cfg.states, {
1142
+ key,
1143
+ init
1144
+ }]
1145
+ });
1146
+ }
1147
+ derived(key, fn) {
1148
+ const cfg = this._cfg;
1149
+ return new IlhaBuilder({
1150
+ ...cfg,
1151
+ deriveds: [...cfg.deriveds, {
1152
+ key,
1153
+ fn
1154
+ }]
1155
+ });
1156
+ }
1157
+ on(selectorOrCombined, handler) {
1158
+ const parsed = parseOnArgs(selectorOrCombined);
1159
+ return new IlhaBuilder({
1160
+ ...this._cfg,
1161
+ ons: [...this._cfg.ons, {
1162
+ selector: parsed.selector,
1163
+ event: parsed.eventType,
1164
+ options: parsed.options,
1165
+ abortable: parsed.abortable,
1166
+ handler
1167
+ }]
1168
+ });
1169
+ }
1170
+ effect(fn) {
1171
+ return new IlhaBuilder({
1172
+ ...this._cfg,
1173
+ effects: [...this._cfg.effects, { fn }]
1174
+ });
1175
+ }
1176
+ onMount(fn) {
1177
+ return new IlhaBuilder({
1178
+ ...this._cfg,
1179
+ onMounts: [...this._cfg.onMounts, { fn }]
1180
+ });
1181
+ }
1182
+ onError(fn) {
1183
+ return new IlhaBuilder({
1184
+ ...this._cfg,
1185
+ onErrors: [...this._cfg.onErrors, { fn }]
1186
+ });
1187
+ }
1188
+ transition(opts) {
1189
+ return new IlhaBuilder({
1190
+ ...this._cfg,
1191
+ transition: opts
1192
+ });
1193
+ }
1194
+ css(strings, ...values) {
1195
+ let source;
1196
+ if (typeof strings === "string") source = strings;
1197
+ else {
1198
+ let result = "";
1199
+ for (let i = 0; i < strings.length; i++) {
1200
+ result += strings[i];
1201
+ if (i < values.length) result += String(values[i]);
1202
+ }
1203
+ source = result;
1204
+ }
1205
+ return new IlhaBuilder({
1206
+ ...this._cfg,
1207
+ css: source
1208
+ });
1209
+ }
1210
+ render(fn) {
1211
+ const { schema, defaultInput, states, deriveds, ons, effects, onMounts, onErrors, transition, css: cssSource, as: slotAs } = this._cfg;
1212
+ const stylePrefix = cssSource != null ? buildScopedStyle(cssSource) : "";
1213
+ const configuredSlotTag = slotAs ?? "div";
1214
+ function resolveInput(props) {
1215
+ const merged = {
1216
+ ...defaultInput ?? {},
1217
+ ...props ?? {}
1218
+ };
1219
+ if (!schema) return merged;
1220
+ return validateSchema(schema, merged);
1221
+ }
1222
+ function renderWithCtx(fn, liveHost, asyncChildren) {
1223
+ const ctx = pushRenderCtx(liveHost, asyncChildren);
1224
+ try {
1225
+ const html = unwrapHtml(fn());
1226
+ const slots = ctx.slots;
1227
+ const binds = ctx.binds;
1228
+ if (ctx.pending && ctx.pending.size > 0) {
1229
+ const pending = ctx.pending;
1230
+ return (async () => {
1231
+ return {
1232
+ html: await resolveAsyncChildren(html, pending),
1233
+ slots,
1234
+ binds
1235
+ };
1236
+ })();
1237
+ }
1238
+ return {
1239
+ html,
1240
+ slots,
1241
+ binds
1242
+ };
1243
+ } finally {
1244
+ popRenderCtx();
1245
+ }
1246
+ }
1247
+ function buildPlainState(input) {
1248
+ const state = {};
1249
+ for (const entry of states) {
1250
+ const value = typeof entry.init === "function" ? entry.init(input) : entry.init;
1251
+ const accessor = markSignalAccessor((...args) => {
1252
+ if (args.length === 0) return value;
1253
+ });
1254
+ state[entry.key] = accessor;
1255
+ }
1256
+ return state;
1257
+ }
1258
+ function buildSignalState(input, snapshot) {
1259
+ const state = {};
1260
+ for (const entry of states) {
1261
+ const s = signal(snapshot && entry.key in snapshot ? snapshot[entry.key] : typeof entry.init === "function" ? entry.init(input) : entry.init);
1262
+ const accessor = markSignalAccessor((...args) => {
1263
+ if (args.length === 0) return s();
1264
+ s(args[0]);
1265
+ });
1266
+ state[entry.key] = accessor;
1267
+ }
1268
+ return state;
1269
+ }
1270
+ /** Detached host for SSR setup hooks; must not be `{}` (Areia/components call host.matches). */
1271
+ function createSsrOnMountHost() {
1272
+ if (typeof document !== "undefined") return document.createElement("div");
1273
+ const stub = {
1274
+ matches: () => false,
1275
+ querySelector: () => null,
1276
+ querySelectorAll: () => [],
1277
+ setAttribute: () => {},
1278
+ getAttribute: () => null,
1279
+ removeAttribute: () => {},
1280
+ appendChild: () => stub
1281
+ };
1282
+ return stub;
1283
+ }
1284
+ /** Run .onMount() before top-level SSR only (seed module/external state from `input`). */
1285
+ function runOnMountForRender(input, state, derived) {
1286
+ if (onMounts.length === 0) return;
1287
+ if (currentRenderCtx()) return;
1288
+ const host = createSsrOnMountHost();
1289
+ const ssrCleanups = [];
1290
+ for (const entry of onMounts) {
1291
+ const prevSub = setActiveSub(void 0);
1292
+ let userCleanup = void 0;
1293
+ try {
1294
+ userCleanup = entry.fn({
1295
+ state,
1296
+ derived,
1297
+ input,
1298
+ host,
1299
+ hydrated: false
1300
+ });
1301
+ } catch (err) {
1302
+ const error = err instanceof Error ? err : new Error(String(err));
1303
+ if (onErrors.length === 0) {
1304
+ if (!reportToGlobal(error, "mount")) console.error(error);
1305
+ } else for (const oe of onErrors) try {
1306
+ oe.fn({
1307
+ error,
1308
+ source: "mount",
1309
+ state,
1310
+ derived,
1311
+ input,
1312
+ host
1313
+ });
1314
+ } catch (handlerErr) {
1315
+ console.error(handlerErr);
1316
+ }
1317
+ } finally {
1318
+ setActiveSub(prevSub);
1319
+ }
1320
+ if (typeof userCleanup === "function") ssrCleanups.push(userCleanup);
1321
+ }
1322
+ for (const teardown of ssrCleanups.reverse()) try {
1323
+ teardown();
1324
+ } catch (err) {
1325
+ const error = err instanceof Error ? err : new Error(String(err));
1326
+ if (onErrors.length === 0) {
1327
+ if (!reportToGlobal(error, "mount")) console.error(error);
1328
+ }
1329
+ }
1330
+ }
1331
+ function renderToString(props, sync = false) {
1332
+ const input = resolveInput(props);
1333
+ const state = buildSignalState(input);
1334
+ const results = deriveds.map((entry) => {
1335
+ const prevSub = setActiveSub(void 0);
1336
+ try {
1337
+ return {
1338
+ key: entry.key,
1339
+ result: entry.fn({
1340
+ state,
1341
+ input,
1342
+ signal: new AbortController().signal
1343
+ })
1344
+ };
1345
+ } catch (err) {
1346
+ return {
1347
+ key: entry.key,
1348
+ result: Promise.reject(err)
1349
+ };
1350
+ } finally {
1351
+ setActiveSub(prevSub);
1352
+ }
1353
+ });
1354
+ if (!results.some((r) => r.result instanceof Promise) || sync) {
1355
+ const envelopes = {};
1356
+ for (const r of results) if (r.result instanceof Promise) envelopes[r.key] = {
1357
+ loading: true,
1358
+ value: void 0,
1359
+ error: void 0
1360
+ };
1361
+ else envelopes[r.key] = {
1362
+ loading: false,
1363
+ value: r.result,
1364
+ error: void 0
1365
+ };
1366
+ const derived = buildDerivedAccessors(envelopes);
1367
+ if (!currentRenderCtx()) runOnMountForRender(input, state, derived);
1368
+ const prevSub = setActiveSub(void 0);
1369
+ try {
1370
+ const { html } = renderWithCtx(() => fn({
1371
+ state,
1372
+ derived,
1373
+ input
1374
+ }));
1375
+ return stylePrefix + html;
1376
+ } finally {
1377
+ setActiveSub(prevSub);
1378
+ }
1379
+ }
1380
+ return Promise.all(results.map(async (r) => {
1381
+ try {
1382
+ return {
1383
+ key: r.key,
1384
+ envelope: {
1385
+ loading: false,
1386
+ value: await Promise.resolve(r.result),
1387
+ error: void 0
1388
+ }
1389
+ };
1390
+ } catch (err) {
1391
+ return {
1392
+ key: r.key,
1393
+ envelope: {
1394
+ loading: false,
1395
+ value: void 0,
1396
+ error: err instanceof Error ? err : new Error(String(err))
1397
+ }
1398
+ };
1399
+ }
1400
+ })).then(async (resolved) => {
1401
+ const envelopes = {};
1402
+ for (const r of resolved) envelopes[r.key] = r.envelope;
1403
+ const derived = buildDerivedAccessors(envelopes);
1404
+ if (!currentRenderCtx()) runOnMountForRender(input, state, derived);
1405
+ const prevSub = setActiveSub(void 0);
1406
+ try {
1407
+ const { html } = await renderWithCtx(() => fn({
1408
+ state,
1409
+ derived,
1410
+ input
1411
+ }), void 0, true);
1412
+ return stylePrefix + html;
1413
+ } finally {
1414
+ setActiveSub(prevSub);
1415
+ }
1416
+ });
1417
+ }
1418
+ function mountIsland(host, props) {
1419
+ return mountIslandInternal(host, props).unmount;
1420
+ }
1421
+ function mountIslandInternal(host, props) {
1422
+ if (props === void 0) {
1423
+ const rawProps = host.getAttribute(PROPS_ATTR);
1424
+ if (rawProps) {
1425
+ const parsed = safeParseSnapshot(rawProps, PROPS_ATTR);
1426
+ if (parsed !== void 0) props = parsed;
1427
+ }
1428
+ }
1429
+ const inputSignal = signal(resolveInput(props));
1430
+ const input = new Proxy({}, {
1431
+ get(_t, key) {
1432
+ return inputSignal()[key];
1433
+ },
1434
+ has(_t, key) {
1435
+ return key in inputSignal();
1436
+ },
1437
+ ownKeys() {
1438
+ const prevSub = setActiveSub(void 0);
1439
+ try {
1440
+ return Reflect.ownKeys(inputSignal());
1441
+ } finally {
1442
+ setActiveSub(prevSub);
1443
+ }
1444
+ },
1445
+ getOwnPropertyDescriptor(_t, key) {
1446
+ const prevSub = setActiveSub(void 0);
1447
+ try {
1448
+ return Reflect.getOwnPropertyDescriptor(inputSignal(), key);
1449
+ } finally {
1450
+ setActiveSub(prevSub);
1451
+ }
1452
+ }
1453
+ });
1454
+ let snapshotRaw;
1455
+ const rawState = host.getAttribute(STATE_ATTR);
1456
+ if (rawState) {
1457
+ const parsed = safeParseSnapshot(rawState, STATE_ATTR);
1458
+ if (parsed !== void 0) snapshotRaw = parsed;
1459
+ }
1460
+ const stateSnapshot = snapshotRaw ? Object.fromEntries(Object.entries(snapshotRaw).filter(([k]) => k !== "_derived" && k !== "_skipOnMount")) : void 0;
1461
+ const derivedSnapshotRaw = snapshotRaw?._derived;
1462
+ let derivedSnapshot;
1463
+ if (derivedSnapshotRaw) {
1464
+ derivedSnapshot = {};
1465
+ for (const [k, v] of Object.entries(derivedSnapshotRaw)) if (v.error && !(v.error instanceof Error)) derivedSnapshot[k] = {
1466
+ ...v,
1467
+ error: new Error(String(v.error))
1468
+ };
1469
+ else derivedSnapshot[k] = v;
1470
+ }
1471
+ const hydrated = snapshotRaw != null;
1472
+ const snapshotHasIslandState = stateSnapshot != null && Object.keys(stateSnapshot).length > 0;
1473
+ const shouldSkipOnMount = hydrated && snapshotRaw?.["_skipOnMount"] === true && snapshotHasIslandState;
1474
+ const state = buildSignalState(input, stateSnapshot);
1475
+ const cleanups = [];
1476
+ const unmountController = new AbortController();
1477
+ cleanups.push(() => unmountController.abort());
1478
+ const { proxy: derived, setup: setupDerived } = createDerivedProxy(deriveds, state, input, derivedSnapshot);
1479
+ let stopDerived = () => {};
1480
+ function reportError(err, source) {
1481
+ const error = err instanceof Error ? err : new Error(String(err));
1482
+ if (onErrors.length === 0) {
1483
+ if (!reportToGlobal(error, source)) console.error(error);
1484
+ return;
1485
+ }
1486
+ for (const entry of onErrors) try {
1487
+ entry.fn({
1488
+ error,
1489
+ source,
1490
+ state,
1491
+ derived,
1492
+ input,
1493
+ host
1494
+ });
1495
+ } catch (handlerErr) {
1496
+ console.error(handlerErr);
1497
+ }
1498
+ }
1499
+ if (transition?.enter) try {
1500
+ const result = transition.enter(host);
1501
+ if (result instanceof Promise) result.catch((err) => reportError(err, "transition"));
1502
+ } catch (err) {
1503
+ reportError(err, "transition");
1504
+ }
1505
+ const mountedSlots = /* @__PURE__ */ new Map();
1506
+ const leavingSlots = /* @__PURE__ */ new Map();
1507
+ function teardownMountedSlot(id, entry) {
1508
+ mountedSlots.delete(id);
1509
+ const token = Symbol();
1510
+ const result = entry.unmount();
1511
+ const remove = (stub) => {
1512
+ const leaving = leavingSlots.get(id);
1513
+ if (!leaving || leaving.token !== token) return;
1514
+ leaving.el.remove();
1515
+ stub?.remove();
1516
+ leavingSlots.delete(id);
1517
+ };
1518
+ if (result instanceof Promise) {
1519
+ leavingSlots.set(id, {
1520
+ el: entry.el,
1521
+ token
1522
+ });
1523
+ return result.finally(() => remove());
1524
+ }
1525
+ entry.el.remove();
1526
+ }
1527
+ function slotBelongsToHost(candidate) {
1528
+ let el = candidate;
1529
+ while (el && el !== host) {
1530
+ if (el.hasAttribute("data-ilha")) return false;
1531
+ el = el.parentElement;
1532
+ }
1533
+ return el === host;
1534
+ }
1535
+ function buildSlotIndex() {
1536
+ const leavingEls = new Set([...leavingSlots.values()].map((l) => l.el));
1537
+ const index = /* @__PURE__ */ new Map();
1538
+ for (const candidate of host.querySelectorAll(`[${SLOT_ATTR}]`)) {
1539
+ if (leavingEls.has(candidate)) continue;
1540
+ const id = candidate.getAttribute(SLOT_ATTR);
1541
+ if (id === null || index.has(id)) continue;
1542
+ if (slotBelongsToHost(candidate)) index.set(id, candidate);
1543
+ }
1544
+ return index;
1545
+ }
1546
+ function mountSlots(slotMap) {
1547
+ for (const [id, entry] of mountedSlots) if (!slotMap.has(id)) teardownMountedSlot(id, entry);
1548
+ for (const [id, entry] of mountedSlots) {
1549
+ const next = slotMap.get(id);
1550
+ if (next && next.island !== entry.island) teardownMountedSlot(id, entry);
1551
+ }
1552
+ let slotIndex = null;
1553
+ for (const [id, { island: childIsland, props }] of slotMap) {
1554
+ const existing = mountedSlots.get(id);
1555
+ if (existing) {
1556
+ existing.updateProps(props);
1557
+ continue;
1558
+ }
1559
+ if (slotIndex === null) slotIndex = buildSlotIndex();
1560
+ const slotEl = slotIndex.get(id) ?? null;
1561
+ if (!slotEl) continue;
1562
+ let slotProps = props;
1563
+ if (slotProps === void 0) {
1564
+ const rawProps = slotEl.getAttribute(PROPS_ATTR) ?? slotEl.getAttribute("data-props");
1565
+ if (rawProps) {
1566
+ const parsed = safeParseSnapshot(rawProps, `props on [${SLOT_ATTR}="${id}"]`);
1567
+ if (parsed !== void 0) slotProps = parsed;
1568
+ }
1569
+ }
1570
+ const prevSub = setActiveSub(void 0);
1571
+ let handle;
1572
+ try {
1573
+ const internal = childIsland[ISLAND_MOUNT_INTERNAL];
1574
+ handle = internal ? internal(slotEl, slotProps) : {
1575
+ unmount: childIsland.mount(slotEl, slotProps),
1576
+ updateProps: () => {}
1577
+ };
1578
+ } finally {
1579
+ setActiveSub(prevSub);
1580
+ }
1581
+ mountedSlots.set(id, {
1582
+ el: slotEl,
1583
+ island: childIsland,
1584
+ ...handle
1585
+ });
1586
+ }
1587
+ }
1588
+ const listeners = [];
1589
+ const firedOnce = /* @__PURE__ */ new Set();
1590
+ const invocationControllers = /* @__PURE__ */ new WeakMap();
1591
+ function attachListeners() {
1592
+ for (const entry of ons) {
1593
+ if (entry.options.once && firedOnce.has(entry)) continue;
1594
+ (entry.selector === "" ? [host] : Array.from(host.querySelectorAll(entry.selector))).forEach((listenerTarget) => {
1595
+ const listener = (event) => {
1596
+ if (entry.options.once) {
1597
+ firedOnce.add(entry);
1598
+ for (const l of listeners.filter((l) => l.entry === entry)) l.target.removeEventListener(l.type, l.fn, l.options);
1599
+ listeners.splice(0, listeners.length, ...listeners.filter((l) => l.entry !== entry));
1600
+ }
1601
+ const eventTarget = event.target instanceof Element ? event.target : listenerTarget;
1602
+ const handlerTarget = entry.selector === "" ? eventTarget : listenerTarget;
1603
+ let handlerSignal;
1604
+ if (entry.abortable) {
1605
+ let entryMap = invocationControllers.get(entry);
1606
+ if (!entryMap) {
1607
+ entryMap = /* @__PURE__ */ new WeakMap();
1608
+ invocationControllers.set(entry, entryMap);
1609
+ }
1610
+ const prev = entryMap.get(listenerTarget);
1611
+ if (prev) prev.abort();
1612
+ const invocationController = new AbortController();
1613
+ entryMap.set(listenerTarget, invocationController);
1614
+ handlerSignal = anySignal([unmountController.signal, invocationController.signal]);
1615
+ } else handlerSignal = unmountController.signal;
1616
+ let result;
1617
+ startBatch();
1618
+ try {
1619
+ result = entry.handler({
1620
+ state,
1621
+ derived,
1622
+ input,
1623
+ host,
1624
+ target: handlerTarget,
1625
+ event,
1626
+ signal: handlerSignal
1627
+ });
1628
+ } catch (err) {
1629
+ reportError(err, "on");
1630
+ endBatch();
1631
+ return;
1632
+ }
1633
+ endBatch();
1634
+ if (result instanceof Promise) result.catch((err) => {
1635
+ if (err && err.name === "AbortError") return;
1636
+ reportError(err, "on");
1637
+ });
1638
+ };
1639
+ const opts = {
1640
+ ...entry.options,
1641
+ once: false
1642
+ };
1643
+ listenerTarget.addEventListener(entry.event, listener, opts);
1644
+ listeners.push({
1645
+ target: listenerTarget,
1646
+ type: entry.event,
1647
+ fn: listener,
1648
+ options: opts,
1649
+ entry
1650
+ });
1651
+ });
1652
+ }
1653
+ }
1654
+ function detachListeners() {
1655
+ for (const l of listeners) l.target.removeEventListener(l.type, l.fn, l.options);
1656
+ listeners.length = 0;
1657
+ }
1658
+ function invokeOnMounts() {
1659
+ for (const entry of onMounts) {
1660
+ const prevSub = setActiveSub(void 0);
1661
+ let userCleanup = void 0;
1662
+ try {
1663
+ userCleanup = entry.fn({
1664
+ state,
1665
+ derived,
1666
+ input,
1667
+ host,
1668
+ hydrated
1669
+ });
1670
+ } catch (err) {
1671
+ reportError(err, "mount");
1672
+ } finally {
1673
+ setActiveSub(prevSub);
1674
+ }
1675
+ if (userCleanup) {
1676
+ const teardown = userCleanup;
1677
+ cleanups.push(() => {
1678
+ try {
1679
+ teardown();
1680
+ } catch (err) {
1681
+ reportError(err, "mount");
1682
+ }
1683
+ });
1684
+ }
1685
+ }
1686
+ }
1687
+ const preserveSSRDom = hydrated && host.childNodes.length > 0;
1688
+ if (hydrated && onMounts.length > 0 && !shouldSkipOnMount) invokeOnMounts();
1689
+ const initial = renderWithCtx(() => fn({
1690
+ state,
1691
+ derived,
1692
+ input
1693
+ }), preserveSSRDom ? host : void 0);
1694
+ if (!preserveSSRDom) host.innerHTML = stylePrefix + initial.html;
1695
+ let stopBindings = applyTemplateBindings(host, initial.binds);
1696
+ cleanups.push(() => stopBindings());
1697
+ mountSlots(initial.slots);
1698
+ cleanups.push(() => mountedSlots.forEach((entry) => entry.unmount()));
1699
+ attachListeners();
1700
+ if (!hydrated && onMounts.length > 0) invokeOnMounts();
1701
+ for (const entry of effects) {
1702
+ let userCleanup;
1703
+ let runController = null;
1704
+ const stopEffect = effect(() => {
1705
+ if (userCleanup) {
1706
+ try {
1707
+ userCleanup();
1708
+ } catch (err) {
1709
+ reportError(err, "effect");
1710
+ }
1711
+ userCleanup = void 0;
1712
+ }
1713
+ if (runController) runController.abort();
1714
+ runController = new AbortController();
1715
+ const runSignal = anySignal([unmountController.signal, runController.signal]);
1716
+ startBatch();
1717
+ try {
1718
+ userCleanup = entry.fn({
1719
+ state,
1720
+ derived,
1721
+ input,
1722
+ host,
1723
+ signal: runSignal
1724
+ });
1725
+ } catch (err) {
1726
+ reportError(err, "effect");
1727
+ } finally {
1728
+ endBatch();
1729
+ }
1730
+ });
1731
+ cleanups.push(() => {
1732
+ stopEffect();
1733
+ if (userCleanup) try {
1734
+ userCleanup();
1735
+ } catch (err) {
1736
+ reportError(err, "effect");
1737
+ }
1738
+ if (runController) runController.abort();
1739
+ });
1740
+ }
1741
+ stopDerived = setupDerived();
1742
+ cleanups.push(stopDerived);
1743
+ let initialized = false;
1744
+ const initialRenderedHtml = initial.html;
1745
+ let renderEpoch = 0;
1746
+ const stopRender = effect(() => {
1747
+ const epoch = ++renderEpoch;
1748
+ const { html: rendered, slots: newSlotMap, binds: newBinds } = renderWithCtx(() => fn({
1749
+ state,
1750
+ derived,
1751
+ input
1752
+ }), host);
1753
+ const html = stylePrefix + rendered;
1754
+ if (!initialized) {
1755
+ initialized = true;
1756
+ if (preserveSSRDom) {
1757
+ for (const [id, entry] of mountedSlots) {
1758
+ const next = newSlotMap.get(id);
1759
+ if (next) entry.updateProps(next.props);
1760
+ }
1761
+ if (rendered === initialRenderedHtml) return;
1762
+ }
1763
+ if (rendered === initialRenderedHtml) return;
1764
+ if (mountedSlots.size > 0 && mountedSlots.size === newSlotMap.size && [...newSlotMap.keys()].every((id) => mountedSlots.has(id)) && isStableInlineSlotMount(initialRenderedHtml, rendered, newSlotMap.keys())) return;
1765
+ }
1766
+ detachListeners();
1767
+ stopBindings();
1768
+ const prevMountedCount = mountedSlots.size;
1769
+ const leavingPromises = [];
1770
+ for (const [id, entry] of mountedSlots) if (!newSlotMap.has(id)) {
1771
+ const r = teardownMountedSlot(id, entry);
1772
+ if (r instanceof Promise) leavingPromises.push(r);
1773
+ }
1774
+ for (const [id, entry] of mountedSlots) {
1775
+ const next = newSlotMap.get(id);
1776
+ if (next && next.island !== entry.island) {
1777
+ const r = teardownMountedSlot(id, entry);
1778
+ if (r instanceof Promise) leavingPromises.push(r);
1779
+ }
1780
+ }
1781
+ const applyMorph = () => {
1782
+ if (epoch !== renderEpoch) return;
1783
+ const preserved = /* @__PURE__ */ new Map();
1784
+ const listShrunk = newSlotMap.size < prevMountedCount;
1785
+ for (const [id, entry] of mountedSlots) {
1786
+ if (!newSlotMap.has(id)) continue;
1787
+ if (!entry.el.isConnected) continue;
1788
+ if (listShrunk && id.startsWith("p:")) {
1789
+ teardownMountedSlot(id, entry);
1790
+ continue;
1791
+ }
1792
+ const stubTag = entry.el.tagName.toLowerCase();
1793
+ const stub = document.createElement(stubTag);
1794
+ stub.setAttribute(SLOT_ATTR, id);
1795
+ const incomingProps = serializeSlotProps(newSlotMap.get(id)?.props);
1796
+ if (incomingProps !== "") stub.setAttribute(PROPS_ATTR, incomingProps);
1797
+ entry.el.replaceWith(stub);
1798
+ preserved.set(id, entry.el);
1799
+ }
1800
+ const tpl = document.createElement("template");
1801
+ const morphRootTag = host.tagName.toLowerCase();
1802
+ tpl.innerHTML = `<${morphRootTag}>${html}</${morphRootTag}>`;
1803
+ morphInner(host, tpl.content.firstElementChild);
1804
+ if (preserved.size > 0) {
1805
+ const rehomeIndex = buildSlotIndex();
1806
+ for (const [id, liveEl] of preserved) {
1807
+ const stub = rehomeIndex.get(id);
1808
+ if (!stub) continue;
1809
+ stub.replaceWith(liveEl);
1810
+ }
1811
+ }
1812
+ attachListeners();
1813
+ stopBindings = applyTemplateBindings(host, newBinds);
1814
+ mountSlots(newSlotMap);
1815
+ };
1816
+ if (leavingPromises.length > 0) Promise.allSettled(leavingPromises).then((results) => {
1817
+ for (const r of results) if (r.status === "rejected") console.error(r.reason);
1818
+ applyMorph();
1819
+ });
1820
+ else applyMorph();
1821
+ });
1822
+ let tornDown = false;
1823
+ const unmount = () => {
1824
+ if (tornDown) return;
1825
+ tornDown = true;
1826
+ stopRender();
1827
+ detachListeners();
1828
+ const pending = [];
1829
+ for (const [, entry] of mountedSlots) {
1830
+ const result = entry.unmount();
1831
+ if (result instanceof Promise) pending.push(result);
1832
+ }
1833
+ if (transition?.leave) try {
1834
+ const result = transition.leave(host);
1835
+ if (result instanceof Promise) pending.push(result);
1836
+ } catch (err) {
1837
+ reportError(err, "transition");
1838
+ }
1839
+ const finish = () => {
1840
+ for (const c of cleanups) c();
1841
+ };
1842
+ if (pending.length > 0) return Promise.all(pending).then(finish).catch((err) => {
1843
+ reportError(err, "transition");
1844
+ finish();
1845
+ });
1846
+ finish();
1847
+ };
1848
+ const updateProps = (nextProps) => {
1849
+ if (tornDown) return;
1850
+ const next = resolveInput(nextProps);
1851
+ if (shallowEqualInput(inputSignal(), next)) return;
1852
+ inputSignal(next);
1853
+ };
1854
+ return {
1855
+ unmount,
1856
+ updateProps
1857
+ };
1858
+ }
1859
+ /**
1860
+ * Dual-mode island invocation:
1861
+ * - When called inside an `html` interpolation (i.e. {@link currentRenderCtx}
1862
+ * is active), returns an {@link IslandCall} carrying props to be emitted
1863
+ * as a child slot marker; {@link interpolateValue} consumes this marker.
1864
+ * - When called at the top level with no active render context, returns
1865
+ * SSR HTML via {@link renderToString} (backward-compatible public API).
1866
+ *
1867
+ * The declared return type omits {@link IslandCall} because TypeScript
1868
+ * cannot narrow based on runtime stack state.
1869
+ */
1870
+ const island = function(props) {
1871
+ if (currentRenderCtx()) return {
1872
+ [ISLAND_CALL]: true,
1873
+ island,
1874
+ props,
1875
+ key: void 0
1876
+ };
1877
+ return renderToString(props);
1878
+ };
1879
+ island.toString = (props) => renderToString(props, true);
1880
+ island.mount = (host, props) => mountIsland(host, props);
1881
+ island[ISLAND_MOUNT_INTERNAL] = (host, props) => mountIslandInternal(host, props);
1882
+ island[ISLAND_SLOT_TAG] = configuredSlotTag;
1883
+ island.key = (key) => {
1884
+ if (typeof key !== "string" || key.trim().length === 0) throw new Error("island.key() requires a non-empty string.");
1885
+ if (key.includes(":")) throw new Error(`island.key() key cannot contain the slot separator ":" (got "${key}").`);
1886
+ const keyed = ((props) => ({
1887
+ [ISLAND_CALL]: true,
1888
+ island,
1889
+ props,
1890
+ key
1891
+ }));
1892
+ keyed[ISLAND_CALL] = true;
1893
+ return keyed;
1894
+ };
1895
+ island[ISLAND] = true;
1896
+ island.define = (tagName, options) => {
1897
+ if (typeof customElements === "undefined" || typeof HTMLElement === "undefined") {
1898
+ `${tagName}`;
1899
+ return;
1900
+ }
1901
+ const CE_RESERVED = /* @__PURE__ */ new Set([
1902
+ "annotation-xml",
1903
+ "color-profile",
1904
+ "font-face",
1905
+ "font-face-src",
1906
+ "font-face-uri",
1907
+ "font-face-format",
1908
+ "font-face-name",
1909
+ "missing-glyph"
1910
+ ]);
1911
+ if (typeof tagName !== "string" || !/^[a-z][a-z0-9._-]*-[a-z0-9._-]*$/.test(tagName) || CE_RESERVED.has(tagName)) {
1912
+ `${tagName}`;
1913
+ return;
1914
+ }
1915
+ if (customElements.get(tagName)) {
1916
+ `${tagName}`;
1917
+ return;
1918
+ }
1919
+ const observe = options?.observe ?? [];
1920
+ class IlhaIslandElement extends HTMLElement {
1921
+ static observedAttributes = observe;
1922
+ _handle = null;
1923
+ _props;
1924
+ _unmounting = false;
1925
+ _reconnect = false;
1926
+ get props() {
1927
+ return this._props;
1928
+ }
1929
+ set props(p) {
1930
+ this._props = p;
1931
+ if (this._handle && !this._unmounting) this._handle.updateProps(this._mergedProps());
1932
+ }
1933
+ _mergedProps() {
1934
+ const attrProps = {};
1935
+ let hasAttrs = false;
1936
+ for (const name of observe) {
1937
+ const v = this.getAttribute(name);
1938
+ if (v !== null) {
1939
+ attrProps[name] = v;
1940
+ hasAttrs = true;
1941
+ }
1942
+ }
1943
+ if (!hasAttrs && this._props === void 0) return void 0;
1944
+ return {
1945
+ ...attrProps,
1946
+ ...this._props ?? {}
1947
+ };
1948
+ }
1949
+ connectedCallback() {
1950
+ if (this._unmounting) {
1951
+ this._reconnect = true;
1952
+ return;
1953
+ }
1954
+ if (this._handle) return;
1955
+ this._handle = mountIslandInternal(this, this._mergedProps());
1956
+ }
1957
+ disconnectedCallback() {
1958
+ if (!this._handle || this._unmounting) return;
1959
+ this._unmounting = true;
1960
+ this._reconnect = false;
1961
+ Promise.resolve(this._handle.unmount()).finally(() => {
1962
+ this._handle = null;
1963
+ this._unmounting = false;
1964
+ if (this._reconnect) {
1965
+ this._reconnect = false;
1966
+ if (this.isConnected) this._handle = mountIslandInternal(this, this._mergedProps());
1967
+ }
1968
+ });
1969
+ }
1970
+ attributeChangedCallback() {
1971
+ if (this._handle && !this._unmounting) this._handle.updateProps(this._mergedProps());
1972
+ }
1973
+ }
1974
+ customElements.define(tagName, IlhaIslandElement);
1975
+ };
1976
+ island.hydratable = async (props, opts) => {
1977
+ const { name, as: rawTag = "div", snapshot = false, skipOnMount: explicitSkipOnMount } = opts;
1978
+ const tag = assertValidSlotTagName(rawTag);
1979
+ const resolvedProps = props ?? {};
1980
+ const inner = await renderToString(resolvedProps);
1981
+ const encodedProps = escapeHtml(JSON.stringify(resolvedProps));
1982
+ let stateAttr = "";
1983
+ if (snapshot !== false) {
1984
+ const doState = snapshot === true || snapshot.state !== false;
1985
+ const doDerived = snapshot === true || snapshot.derived !== false;
1986
+ const doSkipOnMount = explicitSkipOnMount ?? (doState || doDerived);
1987
+ const snapshotData = {};
1988
+ const input = resolveInput(resolvedProps);
1989
+ const plainState = buildPlainState(input);
1990
+ if (doState) for (const entry of states) snapshotData[entry.key] = plainState[entry.key]();
1991
+ if (doDerived) {
1992
+ const derivedResults = {};
1993
+ for (const entry of deriveds) {
1994
+ const prevSub = setActiveSub(void 0);
1995
+ let resultPromise;
1996
+ let syncError;
1997
+ let threw = false;
1998
+ try {
1999
+ resultPromise = entry.fn({
2000
+ state: plainState,
2001
+ input,
2002
+ signal: new AbortController().signal
2003
+ });
2004
+ } catch (err) {
2005
+ threw = true;
2006
+ syncError = err;
2007
+ } finally {
2008
+ setActiveSub(prevSub);
2009
+ }
2010
+ if (threw) {
2011
+ derivedResults[entry.key] = {
2012
+ loading: false,
2013
+ value: void 0,
2014
+ error: syncError instanceof Error ? syncError.message : String(syncError)
2015
+ };
2016
+ continue;
2017
+ }
2018
+ try {
2019
+ const result = await Promise.resolve(resultPromise);
2020
+ derivedResults[entry.key] = {
2021
+ loading: false,
2022
+ value: result,
2023
+ error: void 0
2024
+ };
2025
+ } catch (err) {
2026
+ derivedResults[entry.key] = {
2027
+ loading: false,
2028
+ value: void 0,
2029
+ error: err instanceof Error ? err.message : String(err)
2030
+ };
2031
+ }
2032
+ }
2033
+ snapshotData["_derived"] = derivedResults;
2034
+ }
2035
+ if (doSkipOnMount) snapshotData["_skipOnMount"] = true;
2036
+ stateAttr = ` ${STATE_ATTR}='${escapeHtml(JSON.stringify(snapshotData))}'`;
2037
+ }
2038
+ return `<${tag} data-ilha="${escapeHtml(name)}" ${PROPS_ATTR}='${encodedProps}'${stateAttr}>${inner}</${tag}>`;
2039
+ };
2040
+ return island;
2041
+ }
2042
+ };
2043
+ function ilhaFrom(selector, island, props) {
2044
+ const host = typeof selector === "string" ? document.querySelector(selector) : selector;
2045
+ if (!host) {
2046
+ console.warn(`[ilha] from(): element not found: ${selector}`);
2047
+ return null;
2048
+ }
2049
+ return island.mount(host, props);
2050
+ }
2051
+ function mountAll(registry, options = {}) {
2052
+ const root = options.root ?? document.body;
2053
+ const lazy = options.lazy ?? false;
2054
+ const unmounts = [];
2055
+ function activateEl(host) {
2056
+ const name = host.getAttribute("data-ilha");
2057
+ if (!name) return;
2058
+ const island = registry[name];
2059
+ if (!island) {
2060
+ `${name}${Object.keys(registry).join(", ")}`;
2061
+ return;
2062
+ }
2063
+ let props = {};
2064
+ const rawProps = host.getAttribute(PROPS_ATTR);
2065
+ if (rawProps) {
2066
+ const parsed = safeParseSnapshot(rawProps, `${PROPS_ATTR} on [data-ilha="${name}"]`);
2067
+ if (parsed !== void 0) props = parsed;
2068
+ }
2069
+ unmounts.push(island.mount(host, props));
2070
+ }
2071
+ const els = Array.from(root.querySelectorAll("[data-ilha]"));
2072
+ if (lazy && typeof IntersectionObserver !== "undefined") {
2073
+ let disposed = false;
2074
+ const io = new IntersectionObserver((entries) => {
2075
+ if (disposed) return;
2076
+ for (const entry of entries) if (entry.isIntersecting) {
2077
+ activateEl(entry.target);
2078
+ io.unobserve(entry.target);
2079
+ }
2080
+ });
2081
+ els.forEach((el) => io.observe(el));
2082
+ unmounts.push(() => {
2083
+ disposed = true;
2084
+ io.disconnect();
2085
+ });
2086
+ } else els.forEach(activateEl);
2087
+ return { unmount: () => {
2088
+ const pending = [];
2089
+ for (const u of unmounts) {
2090
+ const result = u();
2091
+ if (result instanceof Promise) pending.push(result);
2092
+ }
2093
+ if (pending.length > 0) return Promise.all(pending).then(() => {});
2094
+ } };
2095
+ }
2096
+ const rootBuilder = new IlhaBuilder({
2097
+ schema: null,
2098
+ defaultInput: null,
2099
+ states: [],
2100
+ deriveds: [],
2101
+ ons: [],
2102
+ effects: [],
2103
+ onMounts: [],
2104
+ onErrors: [],
2105
+ transition: null,
2106
+ css: null,
2107
+ as: null
2108
+ });
2109
+ const ilha = Object.assign(rootBuilder, {
2110
+ html: ilhaHtml,
2111
+ raw: ilhaRaw,
2112
+ mount: mountAll,
2113
+ from: ilhaFrom,
2114
+ context: ilhaContext,
2115
+ signal: ilhaSignal,
2116
+ computed: ilhaComputed,
2117
+ batch,
2118
+ untrack,
2119
+ onUncaughtError
2120
+ });
2121
+ /** @internal Used by the separate JSX runtime entry to preserve island slot composition. */
2122
+ function __ilhaJsxSlot(island, props, key) {
2123
+ return ilhaRaw(emitIslandSlot(island, props, key));
2124
+ }
2125
+ const html = ilhaHtml;
2126
+ const raw = ilhaRaw;
2127
+ const css = ilhaCss;
2128
+ const mount = mountAll;
2129
+ const from = ilhaFrom;
2130
+ const context = ilhaContext;
2131
+
2132
+ //#endregion
2133
+ export { ISLAND_MOUNT_INTERNAL, __ilhaJsxSlot, batch, ilhaComputed as computed, context, css, ilha as default, ilhaEffect as effect, from, html, ilhaSignal, ilhaSignal as signal, mount, onUncaughtError, raw, untrack };