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