lego-dom 2.1.3 → 2.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lego.min.js +2 -2
- package/dist/lego.mjs +2 -2
- package/package.json +1 -1
- package/src/index.js +208 -45
package/dist/lego.min.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
(()=>{var
|
|
1
|
+
(()=>{var y={},I=new WeakMap,D=new WeakMap,C=new WeakMap,X=new WeakMap,_=new Set,q=new Set,R=new Map,Q=new Map;var M=e=>(D.has(e)||D.set(e,{snapped:!1,bindings:null,bound:!1,rendering:!1,anchor:null}),D.get(e));var N={},he=e=>{N=e};var m={onError:(e,r,o)=>{console.error(`[Lego Error] [${r}]`,e,o)},metrics:{},debug:!1,syntax:"brackets"},P=(e,r)=>{!e||!r||Object.getOwnPropertyNames(e).forEach(o=>{let s=Object.getOwnPropertyDescriptor(e,o);Object.defineProperty(r,o,s)})},U=()=>m.syntax==="brackets"?["[[","]]"]:["{{","}}"],ne=new Map,j=()=>{let[e,r]=U(),o=e+r;if(ne.has(o))return ne.get(o);let s=e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),t=r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),a=new RegExp(`${s}(.*?)${t}`,"g");return ne.set(o,a),a},be=e=>{let o=e.split("/").pop().replace(/\.lego$/,"").replace(/_/g,"-").replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase();if(!o.includes("-"))throw new Error(`[Lego] Invalid block definition: "${e}". Block names must contain a hyphen (e.g. user-card.lego or UserCard.lego).`);return o},B=(e,r)=>{if(!e)return"";let o=e.trim().split("."),s=r;for(let t of o){if(s==null)return"";s=s[t]}return s??""},ae=e=>typeof Node<"u"&&e instanceof Node,O=(e,r,o)=>{if(r.nodeType!==Node.ELEMENT_NODE)return;let s=[...r.attributes].find(a=>a.name===e||a.name.startsWith(`${e}.`));if(!s)return;let t={};return o&&(t=o(s,r)),{type:e,node:r,expr:s.value,modifiers:s.name.split(".").slice(1),...t}};var Z=class{constructor(r=1e3){this.limit=r,this.cache=new Map}get(r){if(!this.cache.has(r))return;let o=this.cache.get(r);return this.cache.delete(r),this.cache.set(r,o),o}set(r,o){if(this.cache.has(r))this.cache.delete(r);else if(this.cache.size>=this.limit){let s=this.cache.keys().next().value;this.cache.delete(s)}this.cache.set(r,o)}get size(){return this.cache.size}clear(){this.cache.clear()}};var F=(e,r)=>{if(!e)return;let o=e.parentElement||(e.getRootNode?e.getRootNode().host:null);for(;o;){let s=o.tagName?o.tagName.toLowerCase():"";if(s&&(r==="*"&&y[s]||s===r.toLowerCase()))return o;o=o.parentElement||o.getRootNode&&o.getRootNode().host}},ye=(e,r)=>{if(typeof e=="function"){let s=Array.from(document.querySelectorAll("*")).filter(t=>t.tagName.includes("-"));return[].concat(e(s))}if(e.startsWith("#")){let s=document.getElementById(e.slice(1));return s?[s]:[]}let o=r?.querySelectorAll(e)||[];return o.length>0?[...o]:[...document.querySelectorAll(e)]},Y=(e,r)=>{if(e.type==="checkbox")e.checked!==!!r&&(e.checked=!!r);else{let o=r==null?"":String(r);e.value!==o&&(e.value=o)}};var ie=null,Ee=e=>{ie=e},K=[],ce=e=>{let r=K.find(t=>t.regex.test(e));if(!r)return null;let o=e.match(r.regex).slice(1),s=r.paramNames?Object.fromEntries(r.paramNames.map((t,a)=>[t,o[a]])):{};return{match:r,params:s}},ee=async(e=null,r=null)=>{if(typeof window>"u")return;let o=window.location.pathname,s=ce(o);if(m.debug&&console.log("[Lego Trace] Matching route",o,s?.match),!s)return;let{match:t,params:a}=s;if(t.middleware&&!await t.middleware({path:o,params:a}))return;let i=e&&e.length?e:["lego-router"],n=r||document;t.tagName&&i.flatMap(l=>ye(l,n)).forEach(l=>{l&&(l.innerHTML=`<${t.tagName}></${t.tagName}>`,ie&&ie(l.firstElementChild))})},te=(e,...r)=>o=>{let s=async(t,a=null,i=!0,n={})=>{if(i&&typeof history<"u"){let l={legoTargets:r.filter(d=>typeof d=="string"),method:t,body:a};history.pushState(l,"",e)}await ee(r.length?r:null,o)};return{get:(t=!0,a={})=>s("GET",null,t,a),post:(t,a=!0,i={})=>s("POST",t,a,i),put:(t,a=!0,i={})=>s("PUT",t,a,i),patch:(t,a=!0,i={})=>s("PATCH",t,a,i),delete:(t=!0,a={})=>s("DELETE",null,t,a)}};var we=new Z(1e3),x=(e,r,o=!0)=>{if(/\b(function|eval|import|class|module|deploy|constructor|__proto__)\b/.test(e)){console.warn(`[Lego] Security Warning: Blocked dangerous expression "${e}"`);return}try{let s=r.state||{},t=we.get(e);t||(t=new Function("global","self","event","helpers",`
|
|
2
2
|
with(this) {
|
|
3
3
|
with(helpers) {
|
|
4
4
|
return ${e}
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
|
-
`),we.set(e,s));let n={$ancestors:a=>F(r.self,a),$registry:a=>Z.get(a.toLowerCase()),$element:r.self,$route:x.$route,$go:(a,...c)=>re(a,...c)(r.self),$db:x.$db,$emit:(a,c)=>{r.self.dispatchEvent(new CustomEvent(a,{detail:c,bubbles:!0,composed:!0}))}},i=s.call(o,r.global,r.self,r.event,n);return typeof i=="function"?i.call(o,r.event):i}catch(o){if(t)throw o;f.onError(o,"render-error",r.self);return}},le=(e,r={})=>{if(!e||e.trim()==="{}")return{};let t=o=>new Function("scope","global",`with(global) { with(scope) { return (${o}); } }`)(r,x);try{return t(e)}catch(o){let s=e.trim();if(!s.startsWith("{")&&s.includes(":"))try{return t(`{${e}}`)}catch{}return console.error(`[Lego] Error parsing b-logic: "${e.length>80?e.slice(0,80)+"...":e}"`,o),{}}};var Ne={name:"b-if",scan:(e,{checkGlobal:r,getPrivateData:t})=>k("b-if",e,(o,s)=>{r(o.value);let n=document.createComment(`b-if: ${o.value}`),i=t(s);return i.anchor=n,{anchor:n}}),execute({binding:e,state:r,global:t}){let{node:o,anchor:s,expr:n}=e,i=!!N(n,{state:r,global:t,self:o}),a=!!o.parentNode;i&&!a?s.parentNode&&s.parentNode.replaceChild(o,s):!i&&a&&o.parentNode.replaceChild(s,o)}};var xe={name:"b-show",scan(e,{checkGlobal:r}){if(e.nodeType===Node.ELEMENT_NODE&&e.hasAttribute("b-show")){let t=e.getAttribute("b-show");return r(t),{type:"b-show",node:e,expr:t}}},execute({binding:e,state:r,global:t}){let{node:o,expr:s}=e;o.style.display=N(s,{state:r,global:t,self:o})?"":"none"}};var ve={name:"b-text",scan(e){if(e.nodeType===Node.ELEMENT_NODE&&e.hasAttribute("b-text"))return{type:"b-text",node:e,path:e.getAttribute("b-text")}},execute({binding:e,state:r}){let{node:t,path:o}=e;t.textContent=C(o,r)}};var Se={name:"b-html",scan:e=>k("b-html",e),execute:({binding:e,state:r,global:t})=>{let{node:o,expr:s}=e;o.innerHTML=N(s,{state:r,global:t,self:o})||""}};var Le={name:"b-sync",scan(e){if(e.nodeType===Node.ELEMENT_NODE&&e.hasAttribute("b-sync"))return{type:"b-sync",node:e}},execute({binding:e,state:r}){let{node:t}=e;ee(t,C(t.getAttribute("b-sync"),r))}};var $e={name:"b-for",scan(e,{checkGlobal:r,pendingOperations:t}){if(e.nodeType!==Node.ELEMENT_NODE)return;let o=e.getAttribute("b-for")?.match(/^\s*(\w+)\s+in\s+([\s\S]+?)\s*$/);if(o){r(o[2]);let s=document.createComment(`b-for: ${o[1]} in ${o[2].trim()}`);return t.push(()=>{e.parentNode&&(e.parentNode.insertBefore(s,e),e.remove())}),{type:"b-for",anchor:s,itemName:o[1],listName:o[2].trim(),keyPath:e.getAttribute("b-key")||null,template:e.cloneNode(!0)}}},execute({binding:e,state:r,global:t,helpers:o}){let{bind:s,updateNodeBindings:n}=o;if(!s||!n){console.error("[Lego] b-for directive missing required helpers: bind, updateNodeBindings");return}let{anchor:i,listName:a,itemName:c,keyPath:l,template:m}=e,{contextEl:g}=o,d=N(a,{state:r,global:t,self:g})||[];M.has(i)||M.set(i,new Map);let p=M.get(i),b=new Set,h=[];d.forEach((u,v)=>{let y;l?(y=C(l,u),y===void 0&&console.warn(`[Lego] b-key="${l}" resolved to undefined for item at index ${v}. Check for typos.`)):u&&typeof u=="object"?(y=u.id||u._id||u.uuid||u.key,y===void 0&&(Q.has(u)||Q.set(u,Math.random()),y=Q.get(u))):y=`${v}-${u}`,b.add(y);let A=p.get(y);A||(A=m.cloneNode(!0),A.removeAttribute("b-for"),A.removeAttribute("b-key"),p.set(y,A),s(A,g,{name:c,listName:a,index:v}));let Ie=Object.assign(Object.create(r),{[c]:u,$index:v});n(A,Ie),A.querySelectorAll("[b-sync]").forEach(me=>{let ge=me.getAttribute("b-sync");if(ge.startsWith(`${c}.`)){let qe=N(a,{state:r,global:t,self:g});ee(me,C(ge.split(".").slice(1).join("."),qe[v]))}}),h.push(A)});let E=i.nextSibling;h.forEach(u=>{u!==E?i.parentNode.insertBefore(u,E):E=E.nextSibling});for(let[u,v]of p.entries())b.has(u)||(v.remove(),p.delete(u))}};var _e={scan:e=>{if(e.hasAttribute("b-init"))return{type:"b-init",node:e,expr:e.getAttribute("b-init")}},execute:({binding:e,state:r})=>{e.initialized||(e.initialized=!0,N(e.expr,{state:r}))}};var Te={name:"b-enter",scan:e=>k("b-enter",e,(r,t)=>({modifiers:r.name.split(".").slice(1)})),execute:({binding:e,state:r})=>{if(e.observer||e.done)return;let t=new IntersectionObserver((o,s)=>{o[0].isIntersecting&&(N(e.expr,{state:r}),e.modifiers.includes("once")&&(s.disconnect(),e.observer=null,e.done=!0))});t.observe(e.node),e.observer=t},destroy:({binding:e})=>{e.observer&&(e.observer.disconnect(),e.observer=null)}};var Ae={scan:e=>k("b-leave",e),execute:({binding:e,state:r})=>{if(e.observer||e.done)return;let t=new IntersectionObserver((o,s)=>{let n=o[0];n.isIntersecting&&(e.activated=!0),!n.isIntersecting&&e.activated&&(N(e.expr,{state:r}),e.modifiers.includes("once")&&(s.disconnect(),e.observer=null,e.done=!0))});t.observe(e.node),e.observer=t},destroy:({binding:e})=>{e.observer&&(e.observer.disconnect(),e.observer=null)}};var J={"b-if":Ne,"b-show":xe,"b-text":ve,"b-html":Se,"b-sync":Le,"b-for":$e,"b-init":_e,"b-enter":Te,"b-leave":Ae};var Ke=(e=null)=>{let r=!1,t=new Set,o=!1,s=e,n=new Set,i=null,a=new Set,c=d=>{s=d},l=()=>{i&&clearTimeout(i),i=setTimeout(()=>{a.forEach(d=>{let p=d._studs;if(p&&typeof p.updated=="function")try{p.updated.call(p)}catch(b){console.error("[Lego] Error in updated hook:",b)}}),a.clear(),i=null},50)},m=()=>{n.size>0&&(n.forEach(d=>t.add(d)),n.clear(),!r&&t.size>0&&(r=!0,requestAnimationFrame(g)))},g=()=>{o=!0;let d=Array.from(t);t.clear(),r=!1,d.forEach(p=>{p.isConnected&&s&&s(p)}),d.forEach(p=>a.add(p)),l(),o=!1,m()};return{add:d=>{if(d){if(o){n.add(d);return}t.add(d),!r&&(r=!0,requestAnimationFrame(g))}},setHandler:c}},oe=Ke();var $=new Map,se=new Map,V=new WeakMap,X=new Map,Ue=e=>{let r=Array.from(X.entries()).filter(([s])=>s.startsWith("lego:")).sort((s,n)=>s[1].timestamp-n[1].timestamp),t=0,o=[];for(let[s,n]of r){if(t>=e)break;try{localStorage.removeItem(s),t+=n.size,o.push(s),X.delete(s)}catch(i){console.error(`[Lego] Failed to evict ${s}:`,i)}}return o},Me=(e,r,t)=>{f.debug&&console.log("[Lego Trace] scheduleSave",e,r,t),se.has(e)&&clearTimeout(se.get(e));let o=()=>{try{let s=JSON.stringify(r),n=new Blob([s]).size;localStorage.setItem(e,s);let i=e.startsWith("lego:")?e:`lego:${e}`;X.set(i,{timestamp:Date.now(),size:n}),se.delete(e)}catch(s){if(s.name==="QuotaExceededError"){console.warn(`[Lego] Storage quota exceeded for key: ${e}`);try{let n=JSON.stringify(r),i=new Blob([n]).size,a=Ue(i*2);if(a.length>0){f.debug&&console.log(`[Lego] Evicted ${a.length} old keys, retrying save`),localStorage.setItem(e,n);let c=e.startsWith("lego:")?e:`lego:${e}`;X.set(c,{timestamp:Date.now(),size:i})}else f.onError(new Error("Storage quota exceeded and no keys available for eviction"),"quota",e)}catch{f.onError(new Error(`Critical: Could not save ${e} even after eviction`),"quota-critical",e)}}else console.error(`[Lego] Storage Error (${e}):`,s)}};t>0?se.set(e,setTimeout(o,t)):o()},ue=e=>({__type:"lego-db",key:e,_default:void 0,_debounce:0,default(t){return this._default=t,this},debounce(t){return this._debounce=t,this},set(t,o=0){return Me(e,t,o),$.has(e)&&$.get(e).forEach(({target:s,prop:n,el:i,batcher:a})=>{s[n]=t,i&&a&&a.add(i)}),t},get(){try{let t=localStorage.getItem(e);return t!==null?JSON.parse(t):null}catch(t){return console.warn(`[Lego] Failed to get localStorage value for key "${e}":`,t),null}},delete(){try{return localStorage.removeItem(e),X.delete(e.startsWith("lego:")?e:`lego:${e}`),$.has(e)&&$.get(e).forEach(({target:t,prop:o,el:s,batcher:n})=>{t[o]=null,s&&n&&n.add(s)}),!0}catch(t){return console.error(`[Lego] Failed to delete localStorage key "${e}":`,t),!1}}}),ke=e=>e&&e.__type==="lego-db",Ce=(e,r,t,o,s)=>{f.debug&&console.log("[Lego Trace] Reactive DB Init:",r,t);let n=t._default;try{let i=localStorage.getItem(t.key);i!==null&&(n=JSON.parse(i))}catch(i){console.warn(`[Lego] Failed to parse localStorage value for key "${t.key}":`,i)}e[r]=n,V.has(e)||V.set(e,{}),V.get(e)[r]={key:t.key,debounce:t._debounce},f.debug&&console.log("[Lego Trace] DB Metadata Set:",r,V.get(e)[r]),$.has(t.key)||$.set(t.key,new Set),$.get(t.key).add({target:e,prop:r,el:o,batcher:s})},Oe=(e,r,t)=>{let o=V.get(e);if(o&&o[r]){let s=o[r].key;Me(s,t,o[r].debounce),$.has(s)&&$.get(s).forEach(({target:n,prop:i,el:a,batcher:c})=>{n!==e&&(n[i]=t,a&&c&&c.add(a))})}},De=()=>{typeof window<"u"&&window.addEventListener("storage",e=>{if(!(!e.key||!$.has(e.key)))try{let r=JSON.parse(e.newValue);$.get(e.key).forEach(({target:t,prop:o,el:s,batcher:n})=>{t[o]=r,s&&n&&n.add(s)})}catch(r){console.warn("[Lego] Cross-tab sync error:",r)}})};var z=(e,r,t=oe)=>{if(e===null||typeof e!="object"||ae(e))return e;if(q.has(e))return q.get(e);for(let n in e){let i=Object.getOwnPropertyDescriptor(e,n);if(i&&i.get)continue;let a=e[n];ke(a)&&Ce(e,n,a,r,t)}let o={get:(n,i)=>{let a=Reflect.get(n,i);return a!==null&&typeof a=="object"&&!ae(a)?z(a,r,t):a},set:(n,i,a,c)=>{let l=n[i];f.debug&&l!==a&&console.log("[Lego Trace] Reactive SET:",i,"Old:",l,"New:",a,"Target:",n);let m=Reflect.set(n,i,a,c);return c===q.get(n)&&l!==a&&(t.add(r),Oe(n,i,a)),m},deleteProperty:(n,i)=>{let a=Reflect.deleteProperty(n,i);return t.add(r),a}},s=new Proxy(e,o);return q.set(e,s),s};var je=e=>{let r=e;for(;r;){let t=r.getAttribute&&r.getAttribute("b-error");if(t)return{errorTag:t,targetElement:r};let o=r.tagName?r.tagName.toLowerCase():"",s=w[o];if(s){let n=s.getAttribute("b-error");if(n)return{errorTag:n,targetElement:r}}r=r.parentElement||r.getRootNode&&r.getRootNode().host}return null},de=null,fe=null,Be=(e,r)=>{de=e,fe=r},Ge=(e,r,t)=>{if(!de||!fe){console.error("[Lego] Error boundary dependencies not loaded",t);return}try{r.shadowRoot?r.shadowRoot.innerHTML="":r.innerHTML="";let o=document.createElement(e);(r.shadowRoot||r).appendChild(o),de(o),o._studs&&(o._studs.$error={message:t.message,stack:t.stack,component:r.tagName.toLowerCase()},fe(o))}catch(o){console.error("[Lego] Error boundary failed to render:",o),console.error("[Lego] Original error:",t)}},W=(e,r,t)=>{let o=je(r);o?Ge(o.errorTag,o.targetElement,e):f.onError(e,t,r)};var H=(e,r,t=null)=>{let o=r._studs,s=a=>{let c=_(a);if(!c.bound){if(a.hasAttributes()){let l=a.attributes;for(let m=0;m<l.length;m++){let g=l[m];if(g.name.startsWith("@")){let d=g.name.slice(1).split("."),p=d[0],b=d.slice(1);a.addEventListener(p,h=>{if(b.includes("prevent")&&h.preventDefault(),b.includes("stop")&&h.stopPropagation(),!(b.includes("self")&&h.target!==h.currentTarget)){if(typeof KeyboardEvent<"u"&&h instanceof KeyboardEvent){if(b.includes("ctrl")&&!h.ctrlKey||b.includes("alt")&&!h.altKey||b.includes("shift")&&!h.shiftKey||b.includes("meta")&&!h.metaKey)return;let E=b.filter(u=>!["prevent","stop","self","ctrl","alt","shift","meta","capture","once","passive"].includes(u));if(E.length>0){let u=h.key.toLowerCase();if(!E.some(y=>y==="enter"?u==="enter":y==="esc"||y==="escape"?u==="escape":y==="space"?u===" ":y==="tab"?u==="tab":y==="delete"?u==="delete":y==="backspace"?u==="backspace":y==="up"?u==="arrowup":y==="down"?u==="arrowdown":y==="left"?u==="arrowleft":y==="right"?u==="arrowright":y==="alpha"?/^[a-z]$/.test(u):y==="numbers"?/^[0-9]$/.test(u):y===u))return}}try{let E=o;if(t){let v=N(t.listName,{state:o,global:x,self:r})[t.index];E=Object.assign(Object.create(o),{[t.name]:v})}N(g.value,{state:E,global:x,self:a,event:h,$event:h},!0)}catch(E){W(E,r,"event-handler")}}})}}if(a.hasAttribute("b-sync")){let m=a.getAttribute("b-sync"),g=()=>{try{let d,p;if(t&&m.startsWith(`${t.name}.`)){let E=N(t.listName,{state:o,global:x,self:r})[t.index];if(!E)return;let u=m.split(".").slice(1);p=u.pop(),d=u.reduce((v,y)=>v[y],E)}else{let h=m.split(".");p=h.pop(),d=h.reduce((E,u)=>E[u],o)}let b=a.type==="checkbox"?a.checked:a.value;d&&d[p]!==b&&(d[p]=b)}catch(d){f.onError(d,"sync-update",a)}};a.addEventListener("input",g),a.addEventListener("change",g)}if(a.hasAttribute("b-var")){let m=a.getAttribute("b-var");o.$vars&&(o.$vars[m]=a)}}c.bound=!0}};e instanceof Element&&s(e);let n=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT),i;for(;i=n.nextNode();)s(i)},Je=e=>{let r=[],t=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT),o,s=[];for(;o=t.nextNode();){let n=o;if((c=>{let l=c.parentNode;for(;l&&l!==e;){if(l.hasAttribute&&l.hasAttribute("b-for"))return!0;l=l.parentNode}return!1})(o))continue;let a=c=>{if(/\bglobal\b/.test(c)){let l=e.host||e;K.add(l)}};if(o.nodeType===Node.ELEMENT_NODE){for(let[l,m]of Object.entries(J))if(m.scan){let g=m.scan(o,{checkGlobal:a,getPrivateData:_,pendingOperations:s,current:n});g&&r.push(g)}let[c]=U();[...o.attributes].forEach(l=>{l.value.includes(c)&&(a(l.value),r.push({type:"attr",node:o,attrName:l.name,template:l.value}))})}else if(o.nodeType===Node.TEXT_NODE){let[c]=U();o.textContent.includes(c)&&(a(o.textContent),r.push({type:"text",node:o,template:o.textContent}))}}return s.forEach(n=>n()),r},Ve=(e,r)=>{let t=n=>{if(n.nodeType===Node.TEXT_NODE){n._tpl===void 0&&(n._tpl=n.textContent);let i=n._tpl.replace(j(),(a,c)=>N(c.trim(),{state:r,global:x,self:n})??"");n.textContent!==i&&(n.textContent=i)}else if(n.nodeType===Node.ELEMENT_NODE){let[i]=U();[...n.attributes].forEach(a=>{if(a._tpl===void 0&&(a._tpl=a.value),a._tpl.includes(i)){let c=a._tpl.replace(j(),(l,m)=>N(m.trim(),{state:r,global:x,self:n})??"");a.value!==c&&(a.value=c,a.name==="class"&&(n.className=c))}})}};t(e);let o=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT),s;for(;s=o.nextNode();)t(s)},O=e=>{f.debug&&console.log("[Lego Trace] render() called for:",e.tagName);let r=e._studs;if(!r)return;let t=_(e);if(!t.rendering){t.rendering=!0,f.metrics&&f.metrics.onRenderStart&&f.metrics.onRenderStart(e);try{let o=e.shadowRoot||e;t.bindings||(t.bindings=Je(o)),t.bindings.forEach(s=>{let n=J[s.type];if(n){n.execute({binding:s,state:r,global:x,helpers:{bind:H,updateNodeBindings:Ve,contextEl:e}});return}if(s.type==="text"){let i=s.template.replace(j(),(a,c)=>N(c.trim(),{state:r,global:x,self:s.node})??"");s.node.textContent!==i&&(s.node.textContent=i)}if(s.type==="attr"){let i=s.template.replace(j(),(a,c)=>N(c.trim(),{state:r,global:x,self:s.node})??"");s.node.getAttribute(s.attrName)!==i&&(s.node.setAttribute(s.attrName,i),s.attrName==="class"&&(s.node.className=i))}}),r===x&&K.forEach(s=>O(s))}catch(o){W(o,e,"render")}finally{f.metrics&&f.metrics.onRenderEnd&&f.metrics.onRenderEnd(e),t.rendering=!1}}};var Re=new Map,Pe={},Fe=e=>{Pe=e},ze=async()=>{let e=Object.entries(Pe).map(async([r,t])=>{let o=await Promise.all(t.map(async s=>{try{if(s instanceof CSSStyleSheet)return s;let n=await fetch(s);if(!n.ok)throw new Error(`Status ${n.status}`);let i=await n.text(),a=new CSSStyleSheet;return await a.replace(i),a}catch(n){return console.error(`[Lego] Failed to load stylesheet: ${s}`,n),null}}));Re.set(r,o.filter(s=>s!==null))});await Promise.all(e),f.debug&&console.log("[Lego Debug] Re-applying stylesheets to",L.size,"blocks"),L.forEach(r=>{pe(r)})},pe=e=>{if(!e.shadowRoot&&!e._legoShadow)return;let r=e.shadowRoot||e._legoShadow,t=e.tagName.toLowerCase(),o=w[t],s=(o&&o.getAttribute("b-stylesheets")||"").split(/\s+/).filter(Boolean),n=(e.getAttribute("b-stylesheets")||"").split(/\s+/).filter(Boolean),i=[],a=e.parentElement||(e.getRootNode?e.getRootNode().host:null);for(;a;){let g=(a.getAttribute("b-cascade")||"").split(/\s+/).filter(Boolean);g.length&&i.push(...g);let d=a.tagName?a.tagName.toLowerCase():"";if(w[d]){let p=(w[d].getAttribute("b-cascade")||"").split(/\s+/).filter(Boolean);p.length&&i.push(...p)}a=a.parentElement||a.getRootNode&&a.getRootNode().host}let c=[...new Set([...s,...n])],l=[...new Set(i)],m=[...new Set([...l,...c])];if(m.length>0){let g=m.flatMap(d=>Re.get(d)||[]);g.length>0&&f.debug&&console.log("[Lego Debug] Applying styles to",e.tagName,"- Names:",m,"- Sheets:",g.length),g.length>0&&(r.adoptedStyleSheets=[...g])}e._studsMeta={stylesheets:{explicit:c,inherited:l,applied:m}}};var S=e=>{if(f.debug&&console.log("[Lego Trace] snap() called for:",e.tagName),!e||e.nodeType!==Node.ELEMENT_NODE)return;let r=_(e),t=e.tagName.toLowerCase(),o=w[t];if(o&&!r.snapped){r.snapped=!0;let n=o.content.cloneNode(!0),i=e.shadowRoot;i?i.innerHTML="":i=e.attachShadow({mode:"open"}),pe(e);let a=F(e,"*")||F(e.getRootNode().host,"*"),c=a&&a.state?a.state:{},l=R.get(t)||{},m=le(o.getAttribute("b-logic")||"{}"),g=le(e.getAttribute("b-logic")||"{}",c),d={$vars:{},$element:e,get $parent(){return F(e,"*")},$emit:(h,E)=>{e.dispatchEvent(new CustomEvent(h,{detail:E,bubbles:!0,composed:!0}))},get $route(){return x.$route},get $go(){return x.$go}};P(l,d),P(m,d),P(g,d),e._studs=z(d,e),Object.defineProperty(e,"state",{get(){return this._studs},set(h){Object.assign(this._studs,h)},configurable:!0,enumerable:!1}),i.appendChild(n);let p=i.querySelector("style");p&&(p.textContent=p.textContent.replace(/\bself\b/g,":host")),H(i,e),L.add(e),O(e),e.setAttribute("b-id",t);let b=i.querySelectorAll("*");if(f.debug&&console.log("[Lego Debug] Nested scan in",e.tagName,"- Found elements:",b.length),b.forEach(h=>{let E=h.tagName.toLowerCase(),u=!!w[E];u&&f.debug&&console.log("[Lego Debug] Checking",E,"- Registered:",u),u&&S(h)}),e._legoShadow||(e._legoShadow=i),typeof e._studs.mounted=="function")try{e._studs.mounted.call(e._studs)}catch(h){W(h,e,"mounted")}}let s=e.parentElement;for(;s&&!s._studs;)s=s.parentElement;s&&s._studs&&H(e,s),[...e.children].forEach(S)},I=e=>{if(e._studs&&typeof e._studs.unmounted=="function")try{e._studs.unmounted.call(e._studs)}catch(t){W(t,e,"unmounted")}e.shadowRoot&&[...e.shadowRoot.children].forEach(I),L.delete(e),K.delete(e),e._studs&&(e._studs.$element=null,e._studs.$vars&&(Object.keys(e._studs.$vars).forEach(t=>{e._studs.$vars[t]=null}),e._studs.$vars=null),e._studs.$emit&&(e._studs.$emit=null),delete e._studs.$parent,delete e._studs.$route,delete e._studs.$go,e._studs=null),e.hasOwnProperty("state")&&delete e.state;let r=B.get(e);if(r&&(r.bindings&&(r.bindings.forEach(t=>{let o=J[t.type];if(o&&o.destroy)try{o.destroy({binding:t})}catch(s){console.error(`[Lego] Error in directive cleanup (${t.type}):`,s)}t.node=null,t.anchor=null}),r.bindings=null),r.anchor=null,B.delete(e)),M.has(e)){let t=M.get(e);t.forEach((o,s)=>{o&&o._studs&&(o._studs=null)}),t.clear(),M.delete(e)}[...e.children].forEach(I)};function We(e,r="block.lego"){let t={template:"",script:"",style:"",stylesAttr:"",cascadeAttr:"",errorAttr:"",blockName:be(r)},o=e,s=/<(template|script|style)\b((?:\s+(?:[^>"']|"[^"]*"|'[^']*')*)*)>/i;for(;o;){let n=o.match(s);if(!n)break;let i=n[1].toLowerCase(),a=n[2],c=n[0],l=n.index,m=`</${i}>`,g=l+c.length,d=o.indexOf(m,g);if(d===-1){console.warn(`[Lego] Unclosed <${i}> tag in ${r}`);break}let p=o.slice(g,d);if(i==="template"){t.template=p.trim();let b=a.match(/b-stylesheets=["']([^"']+)["']/);b&&(t.stylesAttr=b[1]);let h=a.match(/b-cascade=["']([^"']+)["']/);h&&(t.cascadeAttr=h[1]);let E=a.match(/b-error=["']([^"']+)["']/);E&&(t.errorAttr=E[1])}else if(i==="script"){t.script=p.trim();let b=a.match(/lang=["']([^"']+)["']/);b&&(t.scriptLang=b[1])}else i==="style"&&(t.style=p.trim());o=o.slice(d+m.length)}return t}var He=(e,r,t="block.lego")=>{let o=We(r,t),{blockName:s,template:n,script:i,style:a,stylesAttr:c,cascadeAttr:l,errorAttr:m}=o,g={};if(i)try{let p=i.trim(),b=p.match(/export\s+default\s+({[\s\S]*})/),h=b?b[1]:p;g=new Function("Lego","$db",`return ${h}`)(e,e.globals.$db)}catch(p){f.onError(p,"script",s)}let d=n;a&&(d=`<style>${a}</style>`+d),w[s]=document.createElement("template"),w[s].innerHTML=d,c&&w[s].setAttribute("b-stylesheets",c),l&&w[s].setAttribute("b-cascade",l),m&&w[s].setAttribute("b-error",m),R.set(s,g),document.querySelectorAll(s).forEach(p=>!_(p).snapped&&S(p))};oe.setHandler(O);Be(S,O);Ee(S);var Xe={url:typeof window<"u"?window.location.pathname:"/",route:"",params:{},query:{},method:"GET",body:null},T=z({$route:Xe,$go:(e,...r)=>re(e,...r)(document.body),$db:ue},typeof document<"u"?document.body:null);he(T);var D={db:ue,snap:S,unsnap:I,defineLegoFile:(e,r)=>He(D,e,r),block:(e,r,t={},o="",s="",n="")=>{let i=document.createElement("template");i.setAttribute("b-id",e),i.setAttribute("b-stylesheets",o),s&&i.setAttribute("b-cascade",s),n&&i.setAttribute("b-error",n),i.innerHTML=r,w[e]=i,R.set(e,t);try{let a={};P(t,a),Z.set(e.toLowerCase(),z(a,document.body))}catch(a){f.onError(a,"define",e)}document.querySelectorAll(e).forEach(S),[...L].forEach(a=>{a.tagName.toLowerCase()===e.toLowerCase()&&(f.debug&&console.log("[Lego HMR] Reloading",e),I(a),S(a))}),L.forEach(a=>{a._legoShadow&&a._legoShadow.querySelectorAll(e).forEach(c=>{_(c).snapped||(f.debug&&console.log("[Lego Debug] Lazy-initializing",e,"in",a.tagName),S(c))})})},getActiveBlocksCount:()=>L.size,getLegos:()=>Object.keys(w),config:f,globals:T,route:(e,r,t=null)=>{let o=[],s=e==="*"?".*":e;s=s.replace(/:([^\/]+)/g,(n,i)=>(o.push(i),"([^/]+)")),G.push({path:e,regex:new RegExp(`^${s}$`),tagName:r,paramNames:o,middleware:t})},debug:{stylesheets:e=>!e||!e._studsMeta?null:e._studsMeta.stylesheets},init:async(e=document.body,r={})=>{if((!e||typeof e.nodeType!="number")&&(e=document.body),Fe(r.styles||{}),f.loader=r.loader,f.debug=r.debug===!0,await ze(),G.length>0){let n=window.location.pathname,i=window.location.search,a=ce(n);if(a){let{match:c,params:l}=a,m=Object.fromEntries(new URLSearchParams(i));T.$route.url=n+i,T.$route.route=c.path,T.$route.params=l,T.$route.query=m,T.$route.method="GET",T.$route.body=null}}document.querySelectorAll("template[b-id]").forEach(n=>{w[n.getAttribute("b-id")]=n});let t=n=>{if(n.nodeType!==Node.ELEMENT_NODE)return;S(n);let i=n.tagName.toLowerCase();if(i.includes("-")&&!w[i]&&f.loader&&!L.has(n)){let a=f.loader(i);if(a){let c=typeof a=="string"?fetch(a).then(l=>l.text()):a;Promise.resolve(c).then(l=>D.defineLegoFile(l,`${i}.lego`)).catch(l=>console.error(`[Lego] Failed to load ${i}:`,l))}}};new MutationObserver(n=>n.forEach(i=>{i.addedNodes.forEach(t),i.removedNodes.forEach(a=>a.nodeType===Node.ELEMENT_NODE&&I(a))})).observe(e,{childList:!0,subtree:!0});let s=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT);for(t(e);s.nextNode();)t(s.currentNode);if(e._studs=T,H(e,e),O(e),r.studio){if(!w["lego-studio"]){let n=document.createElement("script");n.src="https://unpkg.com/@legodom/studio@0.0.2/dist/lego-studio.js",n.onerror=()=>console.warn("[Lego] Failed to load Studio from CDN"),document.head.appendChild(n)}D.route("/_/studio","lego-studio"),D.route("/_/studio/:block","lego-studio")}G.length>0&&(window.addEventListener("popstate",n=>{let i=n.state?.legoTargets||null;te(i)}),document.addEventListener("submit",n=>{n.preventDefault()}),document.addEventListener("click",n=>{let a=n.composedPath().find(c=>c.tagName==="A"&&(c.hasAttribute("b-target")||c.hasAttribute("b-link")));if(a){n.preventDefault();let c=a.getAttribute("href"),l=a.getAttribute("b-target"),m=l?l.split(/\s+/).filter(Boolean):[],g=a.getAttribute("b-link")!=="false";T.$go(c,...m).get(g)}}),te()),De()}};typeof window<"u"?window.Lego=D:typeof global<"u"&&(global.Lego=D);var go=D;})();
|
|
7
|
+
`),we.set(e,t));let a={$ancestors:n=>F(r.self,n),$registry:n=>Q.get(n.toLowerCase()),$element:r.self,$route:N.$route,$go:(n,...c)=>te(n,...c)(r.self),$db:N.$db,$emit:(n,c)=>{r.self.dispatchEvent(new CustomEvent(n,{detail:c,bubbles:!0,composed:!0}))}},i=t.call(s,r.global,r.self,r.event,a);return typeof i=="function"?i.call(s,r.event):i}catch(s){if(o)throw s;m.onError(s,"render-error",r.self);return}},le=(e,r={})=>{if(!e||e.trim()==="{}")return{};let o=s=>new Function("scope","global",`with(global) { with(scope) { return (${s}); } }`)(r,N);try{return o(e)}catch(s){let t=e.trim();if(!t.startsWith("{")&&t.includes(":"))try{return o(`{${e}}`)}catch{}return console.error(`[Lego] Error parsing b-logic: "${e.length>80?e.slice(0,80)+"...":e}"`,s),{}}};var xe={name:"b-if",scan:(e,{checkGlobal:r,getPrivateData:o})=>O("b-if",e,(s,t)=>{r(s.value);let a=document.createComment(`b-if: ${s.value}`),i=o(t);return i.anchor=a,{anchor:a}}),execute({binding:e,state:r,global:o}){let{node:s,anchor:t,expr:a}=e,i=!!x(a,{state:r,global:o,self:s}),n=!!s.parentNode;i&&!n?t.parentNode&&t.parentNode.replaceChild(s,t):!i&&n&&s.parentNode.replaceChild(t,s)}};var ve={name:"b-show",scan(e,{checkGlobal:r}){if(e.nodeType===Node.ELEMENT_NODE&&e.hasAttribute("b-show")){let o=e.getAttribute("b-show");return r(o),{type:"b-show",node:e,expr:o}}},execute({binding:e,state:r,global:o}){let{node:s,expr:t}=e;s.style.display=x(t,{state:r,global:o,self:s})?"":"none"}};var Ne={name:"b-text",scan(e){if(e.nodeType===Node.ELEMENT_NODE&&e.hasAttribute("b-text"))return{type:"b-text",node:e,path:e.getAttribute("b-text")}},execute({binding:e,state:r}){let{node:o,path:s}=e;o.textContent=B(s,r)}};var Se={name:"b-html",scan:e=>O("b-html",e),execute:({binding:e,state:r,global:o})=>{let{node:s,expr:t}=e;s.innerHTML=x(t,{state:r,global:o,self:s})||""}};var $e={name:"b-sync",scan(e){if(e.nodeType===Node.ELEMENT_NODE&&e.hasAttribute("b-sync"))return{type:"b-sync",node:e}},execute({binding:e,state:r}){let{node:o}=e;Y(o,B(o.getAttribute("b-sync"),r))}};var Le={name:"b-for",scan(e,{checkGlobal:r,pendingOperations:o}){if(e.nodeType!==Node.ELEMENT_NODE)return;let s=e.getAttribute("b-for")?.match(/^\s*(\w+)\s+in\s+([\s\S]+?)\s*$/);if(s){r(s[2]);let t=document.createComment(`b-for: ${s[1]} in ${s[2].trim()}`);return o.push(()=>{e.parentNode&&(e.parentNode.insertBefore(t,e),e.remove())}),{type:"b-for",anchor:t,itemName:s[1],listName:s[2].trim(),keyPath:e.getAttribute("b-key")||null,template:e.cloneNode(!0)}}},execute({binding:e,state:r,global:o,helpers:s}){let{bind:t,updateNodeBindings:a}=s;if(!t||!a){console.error("[Lego] b-for directive missing required helpers: bind, updateNodeBindings");return}let{anchor:i,listName:n,itemName:c,keyPath:l,template:d}=e,{contextEl:u}=s,f=x(n,{state:r,global:o,self:u})||[];C.has(i)||C.set(i,new Map);let g=C.get(i),b=new Set,h=[];f.forEach((p,$)=>{let E;l?(E=B(l,p),E===void 0&&console.warn(`[Lego] b-key="${l}" resolved to undefined for item at index ${$}. Check for typos.`)):p&&typeof p=="object"?(E=p.id||p._id||p.uuid||p.key,E===void 0&&(X.has(p)||X.set(p,Math.random()),E=X.get(p))):E=`${$}-${p}`,b.add(E);let T=g.get(E);T||(T=d.cloneNode(!0),T.removeAttribute("b-for"),T.removeAttribute("b-key"),g.set(E,T),t(T,u,{name:c,listName:n,index:$}));let Ie=Object.assign(Object.create(r),{[c]:p,$index:$});a(T,Ie),T.querySelectorAll("[b-sync]").forEach(me=>{let ge=me.getAttribute("b-sync");if(ge.startsWith(`${c}.`)){let qe=x(n,{state:r,global:o,self:u});Y(me,B(ge.split(".").slice(1).join("."),qe[$]))}}),h.push(T)});let w=i.nextSibling;h.forEach(p=>{p!==w?i.parentNode.insertBefore(p,w):w=w.nextSibling});for(let[p,$]of g.entries())b.has(p)||($.remove(),g.delete(p))}};var _e={scan:e=>{if(e.hasAttribute("b-init"))return{type:"b-init",node:e,expr:e.getAttribute("b-init")}},execute:({binding:e,state:r})=>{e.initialized||(e.initialized=!0,x(e.expr,{state:r}))}};var Te={name:"b-enter",scan:e=>O("b-enter",e,(r,o)=>({modifiers:r.name.split(".").slice(1)})),execute:({binding:e,state:r})=>{if(e.observer||e.done)return;let o=new IntersectionObserver((s,t)=>{s[0].isIntersecting&&(x(e.expr,{state:r}),e.modifiers.includes("once")&&(t.disconnect(),e.observer=null,e.done=!0))});o.observe(e.node),e.observer=o},destroy:({binding:e})=>{e.observer&&(e.observer.disconnect(),e.observer=null)}};var Ae={scan:e=>O("b-leave",e),execute:({binding:e,state:r})=>{if(e.observer||e.done)return;let o=new IntersectionObserver((s,t)=>{let a=s[0];a.isIntersecting&&(e.activated=!0),!a.isIntersecting&&e.activated&&(x(e.expr,{state:r}),e.modifiers.includes("once")&&(t.disconnect(),e.observer=null,e.done=!0))});o.observe(e.node),e.observer=o},destroy:({binding:e})=>{e.observer&&(e.observer.disconnect(),e.observer=null)}};var G={"b-if":xe,"b-show":ve,"b-text":Ne,"b-html":Se,"b-sync":$e,"b-for":Le,"b-init":_e,"b-enter":Te,"b-leave":Ae};var Ue=(e=null)=>{let r=!1,o=new Set,s=!1,t=e,a=new Set,i=null,n=new Set,c=f=>{t=f},l=()=>{i&&clearTimeout(i),i=setTimeout(()=>{n.forEach(f=>{let g=f._studs;if(g&&typeof g.updated=="function")try{g.updated.call(g)}catch(b){console.error("[Lego] Error in updated hook:",b)}}),n.clear(),i=null},50)},d=()=>{a.size>0&&(a.forEach(f=>o.add(f)),a.clear(),!r&&o.size>0&&(r=!0,requestAnimationFrame(u)))},u=()=>{s=!0;let f=Array.from(o);o.clear(),r=!1,f.forEach(g=>{g.isConnected&&t&&t(g)}),f.forEach(g=>n.add(g)),l(),s=!1,d()};return{add:f=>{if(f){if(s){a.add(f);return}o.add(f),!r&&(r=!0,requestAnimationFrame(u))}},setHandler:c}},re=Ue();var L=new Map,oe=new Map,J=new WeakMap,V=new Map,je=e=>{let r=Array.from(V.entries()).filter(([t])=>t.startsWith("lego:")).sort((t,a)=>t[1].timestamp-a[1].timestamp),o=0,s=[];for(let[t,a]of r){if(o>=e)break;try{localStorage.removeItem(t),o+=a.size,s.push(t),V.delete(t)}catch(i){console.error(`[Lego] Failed to evict ${t}:`,i)}}return s},ke=(e,r,o)=>{m.debug&&console.log("[Lego Trace] scheduleSave",e,r,o),oe.has(e)&&clearTimeout(oe.get(e));let s=()=>{try{let t=JSON.stringify(r),a=new Blob([t]).size;localStorage.setItem(e,t);let i=e.startsWith("lego:")?e:`lego:${e}`;V.set(i,{timestamp:Date.now(),size:a}),oe.delete(e)}catch(t){if(t.name==="QuotaExceededError"){console.warn(`[Lego] Storage quota exceeded for key: ${e}`);try{let a=JSON.stringify(r),i=new Blob([a]).size,n=je(i*2);if(n.length>0){m.debug&&console.log(`[Lego] Evicted ${n.length} old keys, retrying save`),localStorage.setItem(e,a);let c=e.startsWith("lego:")?e:`lego:${e}`;V.set(c,{timestamp:Date.now(),size:i})}else m.onError(new Error("Storage quota exceeded and no keys available for eviction"),"quota",e)}catch{m.onError(new Error(`Critical: Could not save ${e} even after eviction`),"quota-critical",e)}}else console.error(`[Lego] Storage Error (${e}):`,t)}};o>0?oe.set(e,setTimeout(s,o)):s()},fe=e=>({__type:"lego-db",key:e,_default:void 0,_debounce:0,default(o){return this._default=o,this},debounce(o){return this._debounce=o,this},set(o,s=0){return ke(e,o,s),L.has(e)&&L.get(e).forEach(({target:t,prop:a,el:i,batcher:n})=>{t[a]=o,i&&n&&n.add(i)}),o},get(){try{let o=localStorage.getItem(e);return o!==null?JSON.parse(o):null}catch(o){return console.warn(`[Lego] Failed to get localStorage value for key "${e}":`,o),null}},delete(){try{return localStorage.removeItem(e),V.delete(e.startsWith("lego:")?e:`lego:${e}`),L.has(e)&&L.get(e).forEach(({target:o,prop:s,el:t,batcher:a})=>{o[s]=null,t&&a&&a.add(t)}),!0}catch(o){return console.error(`[Lego] Failed to delete localStorage key "${e}":`,o),!1}}}),Ce=e=>e&&e.__type==="lego-db",Me=(e,r,o,s,t)=>{m.debug&&console.log("[Lego Trace] Reactive DB Init:",r,o);let a=o._default;try{let i=localStorage.getItem(o.key);i!==null&&(a=JSON.parse(i))}catch(i){console.warn(`[Lego] Failed to parse localStorage value for key "${o.key}":`,i)}e[r]=a,J.has(e)||J.set(e,{}),J.get(e)[r]={key:o.key,debounce:o._debounce},m.debug&&console.log("[Lego Trace] DB Metadata Set:",r,J.get(e)[r]),L.has(o.key)||L.set(o.key,new Set),L.get(o.key).add({target:e,prop:r,el:s,batcher:t})},Oe=(e,r,o)=>{let s=J.get(e);if(s&&s[r]){let t=s[r].key;ke(t,o,s[r].debounce),L.has(t)&&L.get(t).forEach(({target:a,prop:i,el:n,batcher:c})=>{a!==e&&(a[i]=o,n&&c&&c.add(n))})}},Be=()=>{typeof window<"u"&&window.addEventListener("storage",e=>{if(!(!e.key||!L.has(e.key)))try{let r=JSON.parse(e.newValue);L.get(e.key).forEach(({target:o,prop:s,el:t,batcher:a})=>{o[s]=r,t&&a&&a.add(t)})}catch(r){console.warn("[Lego] Cross-tab sync error:",r)}})};var z=(e,r,o=re)=>{if(e===null||typeof e!="object"||ae(e))return e;if(I.has(e))return I.get(e);for(let a in e){let i=Object.getOwnPropertyDescriptor(e,a);if(i&&i.get)continue;let n=e[a];Ce(n)&&Me(e,a,n,r,o)}let s={get:(a,i)=>{let n=Reflect.get(a,i);return n!==null&&typeof n=="object"&&!ae(n)?z(n,r,o):n},set:(a,i,n,c)=>{let l=a[i];m.debug&&l!==n&&console.log("[Lego Trace] Reactive SET:",i,"Old:",l,"New:",n,"Target:",a);let d=Reflect.set(a,i,n,c);return c===I.get(a)&&l!==n&&(o.add(r),Oe(a,i,n)),d},deleteProperty:(a,i)=>{let n=Reflect.deleteProperty(a,i);return o.add(r),n}},t=new Proxy(e,s);return I.set(e,t),t};var Ke=e=>{let r=e;for(;r;){let o=r.getAttribute&&r.getAttribute("b-error");if(o)return{errorTag:o,targetElement:r};let s=r.tagName?r.tagName.toLowerCase():"",t=y[s];if(t){let a=t.getAttribute("b-error");if(a)return{errorTag:a,targetElement:r}}r=r.parentElement||r.getRootNode&&r.getRootNode().host}return null},de=null,ue=null,De=(e,r)=>{de=e,ue=r},Ge=(e,r,o)=>{if(!de||!ue){console.error("[Lego] Error boundary dependencies not loaded",o);return}try{r.shadowRoot?r.shadowRoot.innerHTML="":r.innerHTML="";let s=document.createElement(e);(r.shadowRoot||r).appendChild(s),de(s),s._studs&&(s._studs.$error={message:o.message,stack:o.stack,component:r.tagName.toLowerCase()},ue(s))}catch(s){console.error("[Lego] Error boundary failed to render:",s),console.error("[Lego] Original error:",o)}},W=(e,r,o)=>{let s=Ke(r);s?Ge(s.errorTag,s.targetElement,e):m.onError(e,o,r)};var se=(e,r,o=null)=>{let s=r._studs,t=n=>{let c=M(n);if(!c.bound){if(n.hasAttributes()){let l=n.attributes;for(let d=0;d<l.length;d++){let u=l[d];if(u.name.startsWith("@")){let f=u.name.slice(1).split("."),g=f[0],b=f.slice(1);n.addEventListener(g,h=>{if(b.includes("prevent")&&h.preventDefault(),b.includes("stop")&&h.stopPropagation(),!(b.includes("self")&&h.target!==h.currentTarget)){if(typeof KeyboardEvent<"u"&&h instanceof KeyboardEvent){if(b.includes("ctrl")&&!h.ctrlKey||b.includes("alt")&&!h.altKey||b.includes("shift")&&!h.shiftKey||b.includes("meta")&&!h.metaKey)return;let w=b.filter(p=>!["prevent","stop","self","ctrl","alt","shift","meta","capture","once","passive"].includes(p));if(w.length>0){let p=h.key.toLowerCase();if(!w.some(E=>E==="enter"?p==="enter":E==="esc"||E==="escape"?p==="escape":E==="space"?p===" ":E==="tab"?p==="tab":E==="delete"?p==="delete":E==="backspace"?p==="backspace":E==="up"?p==="arrowup":E==="down"?p==="arrowdown":E==="left"?p==="arrowleft":E==="right"?p==="arrowright":E==="alpha"?/^[a-z]$/.test(p):E==="numbers"?/^[0-9]$/.test(p):E===p))return}}try{let w=s;if(o){let $=x(o.listName,{state:s,global:N,self:r})[o.index];w=Object.assign(Object.create(s),{[o.name]:$})}x(u.value,{state:w,global:N,self:n,event:h,$event:h},!0)}catch(w){W(w,r,"event-handler")}}})}}if(n.hasAttribute("b-sync")){let d=n.getAttribute("b-sync"),u=()=>{try{let f,g;if(o&&d.startsWith(`${o.name}.`)){let w=x(o.listName,{state:s,global:N,self:r})[o.index];if(!w)return;let p=d.split(".").slice(1);g=p.pop(),f=p.reduce(($,E)=>$[E],w)}else{let h=d.split(".");g=h.pop(),f=h.reduce((w,p)=>w[p],s)}let b=n.type==="checkbox"?n.checked:n.value;f&&f[g]!==b&&(f[g]=b)}catch(f){m.onError(f,"sync-update",n)}};n.addEventListener("input",u),n.addEventListener("change",u)}if(n.hasAttribute("b-var")){let d=n.getAttribute("b-var");s.$vars&&(s.$vars[d]=n)}}c.bound=!0}};e instanceof Element&&t(e);let a=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT),i;for(;i=a.nextNode();)t(i)},Je=e=>{let r=[],o=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT),s,t=[];for(;s=o.nextNode();){let a=s;if((c=>{let l=c.parentNode;for(;l&&l!==e;){if(l.hasAttribute&&l.hasAttribute("b-for"))return!0;l=l.parentNode}return!1})(s))continue;let n=c=>{if(/\bglobal\b/.test(c)){let l=e.host||e;q.add(l)}};if(s.nodeType===Node.ELEMENT_NODE){for(let[l,d]of Object.entries(G))if(d.scan){let u=d.scan(s,{checkGlobal:n,getPrivateData:M,pendingOperations:t,current:a});u&&r.push(u)}let[c]=U();[...s.attributes].forEach(l=>{l.value.includes(c)&&(n(l.value),r.push({type:"attr",node:s,attrName:l.name,template:l.value}))})}else if(s.nodeType===Node.TEXT_NODE){let[c]=U();s.textContent.includes(c)&&(n(s.textContent),r.push({type:"text",node:s,template:s.textContent}))}}return t.forEach(a=>a()),r},Ve=(e,r)=>{let o=a=>{if(a.nodeType===Node.TEXT_NODE){a._tpl===void 0&&(a._tpl=a.textContent);let i=a._tpl.replace(j(),(n,c)=>x(c.trim(),{state:r,global:N,self:a})??"");a.textContent!==i&&(a.textContent=i)}else if(a.nodeType===Node.ELEMENT_NODE){let[i]=U();[...a.attributes].forEach(n=>{if(n._tpl===void 0&&(n._tpl=n.value),n._tpl.includes(i)){let c=n._tpl.replace(j(),(l,d)=>x(d.trim(),{state:r,global:N,self:a})??"");n.value!==c&&(n.value=c,n.name==="class"&&(a.className=c))}})}};o(e);let s=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT),t;for(;t=s.nextNode();)o(t)},H=e=>{m.debug&&console.log("[Lego Trace] render() called for:",e.tagName);let r=e._studs;if(!r)return;let o=M(e);if(!o.rendering){o.rendering=!0,m.metrics&&m.metrics.onRenderStart&&m.metrics.onRenderStart(e);try{let s=e.shadowRoot||e;o.bindings||(o.bindings=Je(s)),o.bindings.forEach(t=>{let a=G[t.type];if(a){a.execute({binding:t,state:r,global:N,helpers:{bind:se,updateNodeBindings:Ve,contextEl:e}});return}if(t.type==="text"){let i=t.template.replace(j(),(n,c)=>x(c.trim(),{state:r,global:N,self:t.node})??"");t.node.textContent!==i&&(t.node.textContent=i)}if(t.type==="attr"){let i=t.template.replace(j(),(n,c)=>x(c.trim(),{state:r,global:N,self:t.node})??"");t.node.getAttribute(t.attrName)!==i&&(t.node.setAttribute(t.attrName,i),t.attrName==="class"&&(t.node.className=i))}}),r===N&&q.forEach(t=>H(t))}catch(s){W(s,e,"render")}finally{m.metrics&&m.metrics.onRenderEnd&&m.metrics.onRenderEnd(e),o.rendering=!1}}};var Re=new Map,Pe={},Fe=e=>{Pe=e},ze=async()=>{let e=Object.entries(Pe).map(async([r,o])=>{let s=await Promise.all(o.map(async t=>{try{if(t instanceof CSSStyleSheet)return t;let a=await fetch(t);if(!a.ok)throw new Error(`Status ${a.status}`);let i=await a.text(),n=new CSSStyleSheet;return await n.replace(i),n}catch(a){return console.error(`[Lego] Failed to load stylesheet: ${t}`,a),null}}));Re.set(r,s.filter(t=>t!==null))});await Promise.all(e),m.debug&&console.log("[Lego Debug] Re-applying stylesheets to",_.size,"blocks"),_.forEach(r=>{pe(r)})},pe=e=>{if(!e.shadowRoot&&!e._legoShadow)return;let r=e.shadowRoot||e._legoShadow,o=e.tagName.toLowerCase(),s=y[o],t=(s&&s.getAttribute("b-stylesheets")||"").split(/\s+/).filter(Boolean),a=(e.getAttribute("b-stylesheets")||"").split(/\s+/).filter(Boolean),i=[],n=e.parentElement||(e.getRootNode?e.getRootNode().host:null);for(;n;){let u=(n.getAttribute("b-cascade")||"").split(/\s+/).filter(Boolean);u.length&&i.push(...u);let f=n.tagName?n.tagName.toLowerCase():"";if(y[f]){let g=(y[f].getAttribute("b-cascade")||"").split(/\s+/).filter(Boolean);g.length&&i.push(...g)}n=n.parentElement||n.getRootNode&&n.getRootNode().host}let c=[...new Set([...t,...a])],l=[...new Set(i)],d=[...new Set([...l,...c])];if(d.length>0){let u=d.flatMap(f=>Re.get(f)||[]);u.length>0&&m.debug&&console.log("[Lego Debug] Applying styles to",e.tagName,"- Names:",d,"- Sheets:",u.length),u.length>0&&(r.adoptedStyleSheets=[...u])}e._studsMeta={stylesheets:{explicit:c,inherited:l,applied:d}}};var S=e=>{if(m.debug&&console.log("[Lego Trace] snap() called for:",e.tagName),!e||e.nodeType!==Node.ELEMENT_NODE)return;let r=M(e),o=e.tagName.toLowerCase(),s=y[o];if(s&&!r.snapped){r.snapped=!0;let a=s.content.cloneNode(!0),i=e.shadowRoot;i?i.innerHTML="":i=e.attachShadow({mode:"open"}),pe(e);let n=F(e,"*")||F(e.getRootNode().host,"*"),c=n&&n.state?n.state:{},l=R.get(o)||{},d=le(s.getAttribute("b-logic")||"{}"),u=le(e.getAttribute("b-logic")||"{}",c),f={$vars:{},$element:e,get $parent(){return F(e,"*")},$emit:(h,w)=>{e.dispatchEvent(new CustomEvent(h,{detail:w,bubbles:!0,composed:!0}))},get $route(){return N.$route},get $go(){return N.$go}};P(l,f),P(d,f),P(u,f),e._studs=z(f,e),Object.defineProperty(e,"state",{get(){return this._studs},set(h){Object.assign(this._studs,h)},configurable:!0,enumerable:!1}),i.appendChild(a);let g=i.querySelector("style");g&&(g.textContent=g.textContent.replace(/\bself\b/g,":host")),se(i,e),_.add(e),H(e),e.setAttribute("b-id",o);let b=i.querySelectorAll("*");if(m.debug&&console.log("[Lego Debug] Nested scan in",e.tagName,"- Found elements:",b.length),b.forEach(h=>{let w=h.tagName.toLowerCase(),p=!!y[w];p&&m.debug&&console.log("[Lego Debug] Checking",w,"- Registered:",p),p&&S(h)}),e._legoShadow||(e._legoShadow=i),typeof e._studs.mounted=="function")try{e._studs.mounted.call(e._studs)}catch(h){W(h,e,"mounted")}}let t=e.parentElement;for(;t&&!t._studs;)t=t.parentElement;t&&t._studs&&se(e,t),[...e.children].forEach(S)},A=e=>{if(e._studs&&typeof e._studs.unmounted=="function")try{e._studs.unmounted.call(e._studs)}catch(o){W(o,e,"unmounted")}e.shadowRoot&&[...e.shadowRoot.children].forEach(A),_.delete(e),q.delete(e),e._studs&&(e._studs.$element=null,e._studs.$vars&&(Object.keys(e._studs.$vars).forEach(o=>{e._studs.$vars[o]=null}),e._studs.$vars=null),e._studs.$emit&&(e._studs.$emit=null),delete e._studs.$parent,delete e._studs.$route,delete e._studs.$go,e._studs=null),e.hasOwnProperty("state")&&delete e.state;let r=D.get(e);if(r&&(r.bindings&&(r.bindings.forEach(o=>{let s=G[o.type];if(s&&s.destroy)try{s.destroy({binding:o})}catch(t){console.error(`[Lego] Error in directive cleanup (${o.type}):`,t)}o.node=null,o.anchor=null}),r.bindings=null),r.anchor=null,D.delete(e)),C.has(e)){let o=C.get(e);o.forEach((s,t)=>{s&&s._studs&&(s._studs=null)}),o.clear(),C.delete(e)}[...e.children].forEach(A)};function We(e,r="block.lego"){let o={template:"",script:"",style:"",stylesAttr:"",cascadeAttr:"",errorAttr:"",blockName:be(r)},s=e,t=/<(template|script|style)\b((?:\s+(?:[^>"']|"[^"]*"|'[^']*')*)*)>/i;for(;s;){let a=s.match(t);if(!a)break;let i=a[1].toLowerCase(),n=a[2],c=a[0],l=a.index,d=`</${i}>`,u=l+c.length,f=s.indexOf(d,u);if(f===-1){console.warn(`[Lego] Unclosed <${i}> tag in ${r}`);break}let g=s.slice(u,f);if(i==="template"){o.template=g.trim();let b=n.match(/b-stylesheets=["']([^"']+)["']/);b&&(o.stylesAttr=b[1]);let h=n.match(/b-cascade=["']([^"']+)["']/);h&&(o.cascadeAttr=h[1]);let w=n.match(/b-error=["']([^"']+)["']/);w&&(o.errorAttr=w[1])}else if(i==="script"){o.script=g.trim();let b=n.match(/lang=["']([^"']+)["']/);b&&(o.scriptLang=b[1])}else i==="style"&&(o.style=g.trim());s=s.slice(f+d.length)}return o}var He=(e,r,o="block.lego")=>{let s=We(r,o),{blockName:t,template:a,script:i,style:n,stylesAttr:c,cascadeAttr:l,errorAttr:d}=s,u={};if(i)try{let g=i.trim(),b=g.match(/export\s+default\s+({[\s\S]*})/),h=b?b[1]:g;u=new Function("Lego","$db",`return ${h}`)(e,e.globals.$db)}catch(g){m.onError(g,"script",t)}let f=a;n&&(f=`<style>${n}</style>`+f),y[t]=document.createElement("template"),y[t].innerHTML=f,c&&y[t].setAttribute("b-stylesheets",c),l&&y[t].setAttribute("b-cascade",l),d&&y[t].setAttribute("b-error",d),R.set(t,u),document.querySelectorAll(t).forEach(g=>!M(g).snapped&&S(g))};re.setHandler(H);De(S,H);Ee(S);var Xe={url:typeof window<"u"?window.location.pathname:"/",route:"",params:{},query:{},method:"GET",body:null},k=z({$route:Xe,$go:(e,...r)=>te(e,...r)(document.body),$db:fe},typeof document<"u"?document.body:null);he(k);var v={db:fe,snap:S,unsnap:A,defineLegoFile:(e,r)=>He(v,e,r),block:(e,r,o={},s="",t="",a="")=>{let i=document.createElement("template");i.setAttribute("b-id",e),i.setAttribute("b-stylesheets",s),t&&i.setAttribute("b-cascade",t),a&&i.setAttribute("b-error",a),i.innerHTML=r,y[e]=i,R.set(e,o);try{let n={};P(o,n),Q.set(e.toLowerCase(),z(n,document.body))}catch(n){m.onError(n,"define",e)}if(customElements.get(e))document.querySelectorAll(e).forEach(n=>{A(n),S(n)}),_.forEach(n=>{n._legoShadow&&n._legoShadow.querySelectorAll(e).forEach(c=>{A(c),S(c)})});else try{customElements.define(e,class extends HTMLElement{connectedCallback(){y[e]&&S(this)}disconnectedCallback(){A(this)}})}catch(n){console.warn(`[Lego] Failed to register web component ${e}:`,n)}},getActiveBlocksCount:()=>_.size,getLegos:()=>Object.keys(y),config:m,globals:k,route:(e,r,o=null)=>{let s=[],t=e==="*"?".*":e;t=t.replace(/:([^\/]+)/g,(a,i)=>(s.push(i),"([^/]+)")),K.push({path:e,regex:new RegExp(`^${t}$`),tagName:r,paramNames:s,middleware:o})},debug:{stylesheets:e=>!e||!e._studsMeta?null:e._studsMeta.stylesheets},init:async(e=document.body,r={})=>{if((!e||typeof e.nodeType!="number")&&(e=document.body),Fe(r.styles||{}),m.loader=r.loader,m.debug=r.debug===!0,await ze(),K.length>0){let t=window.location.pathname,a=window.location.search,i=ce(t);if(i){let{match:n,params:c}=i,l=Object.fromEntries(new URLSearchParams(a));k.$route.url=t+a,k.$route.route=n.path,k.$route.params=c,k.$route.query=l,k.$route.method="GET",k.$route.body=null}}document.querySelectorAll("template[b-id]").forEach(t=>{let a=t.getAttribute("b-id");y[a]=t,customElements.get(a)||customElements.define(a,class extends HTMLElement{connectedCallback(){y[a]&&S(this)}disconnectedCallback(){A(this)}})});let o=t=>{if(!t)return{};let a={};return Object.entries(t).forEach(([i,n])=>{if(typeof n=="function")a[i]=n();else if(typeof n=="string"&&n.startsWith("$db.")){let c=n.slice(4);a[i]=v.db(c).get()}else if(typeof n=="string"&&n.startsWith("$globals.")){let c=n.slice(9);a[i]=N[c]}else a[i]=n}),a},s=(t,a,i={})=>{customElements.get(t)||customElements.define(t,class extends HTMLElement{async connectedCallback(){if(y[t]){S(this);return}if(v._fetching||(v._fetching=new Set),!v._fetching.has(t)){v._fetching.add(t);try{let n=a.startsWith("POST:")?"POST":"GET",c=a.replace(/^POST:/,""),l=o(i.headers),d={method:n,headers:l,credentials:i.credentials},f=await(await fetch(c,d)).text();v.defineLegoFile(f,`${t}.lego`),y[t]&&S(this)}catch(n){console.error(`[Lego] Failed to load manifest block ${t}:`,n)}finally{v._fetching.delete(t)}}}disconnectedCallback(){A(this)}})};if(r.manifest){let t=r.manifest;if(t.url&&typeof t.url=="string")try{let i=o(t.headers);t=await(await fetch(t.url,{headers:i,credentials:t.credentials})).json()}catch(i){console.error("[Lego] Failed to load manifest:",i),t=[]}else if(typeof t=="string")try{t=await(await fetch(t)).json()}catch(i){console.error("[Lego] Failed to load manifest:",i),t=[]}let a=Array.isArray(t)?t:[t];for(let i of a){let n=i.base||"",c=i.suffix===!0?".lego":i.suffix||"",l={headers:i.headers||{},credentials:i.credentials};i.legos&&i.legos.forEach(d=>{s(d,`${n}${d}${c}`,l)}),i.map&&Object.entries(i.map).forEach(([d,u])=>{let f=u.match(/^https?:|^\//)?u:`${n}${u}`;s(d,f,l)})}}if(m.loader){let t=n=>{if(n.nodeType!==Node.ELEMENT_NODE)return;let c=n.tagName.toLowerCase();if(c.includes("-")&&!y[c]&&!_.has(n)){if(v._fetching&&v._fetching.has(c))return;v._fetching||(v._fetching=new Set),v._fetching.add(c);let l=m.loader(c);if(l){let d=typeof l=="string"?fetch(l).then(u=>u.text()):l;Promise.resolve(d).then(u=>{v.defineLegoFile(u,`${c}.lego`),v._fetching.delete(c)}).catch(u=>{console.error(`[Lego] Failed to load ${c}:`,u),v._fetching.delete(c)})}}if(n.children.length>0){let l=n.firstElementChild;for(;l;)t(l),l=l.nextElementSibling}};new MutationObserver(n=>n.forEach(c=>{c.addedNodes.forEach(t)})).observe(e,{childList:!0,subtree:!0});let i=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT);for(;i.nextNode();)t(i.currentNode)}if(r.studio){if(!y["lego-studio"]){let t=document.createElement("script");t.src="https://unpkg.com/@legodom/studio@0.0.2/dist/lego-studio.js",t.onerror=()=>console.warn("[Lego] Failed to load Studio from CDN"),document.head.appendChild(t)}v.route("/_/studio","lego-studio"),v.route("/_/studio/:block","lego-studio")}K.length>0&&(window.addEventListener("popstate",t=>{let a=t.state?.legoTargets||null;ee(a)}),document.addEventListener("submit",t=>{t.preventDefault()}),document.addEventListener("click",t=>{let i=t.composedPath().find(n=>n.tagName==="A"&&(n.hasAttribute("b-target")||n.hasAttribute("b-link")));if(i){t.preventDefault();let n=i.getAttribute("href"),c=i.getAttribute("b-target"),l=c?c.split(/\s+/).filter(Boolean):[],d=i.getAttribute("b-link")!=="false";k.$go(n,...l).get(d)}}),ee()),Be()}};typeof window<"u"?window.Lego=v:typeof global<"u"&&(global.Lego=v);var ho=v;})();
|
package/dist/lego.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
var
|
|
1
|
+
var y={},I=new WeakMap,D=new WeakMap,C=new WeakMap,X=new WeakMap,_=new Set,q=new Set,R=new Map,Q=new Map;var M=e=>(D.has(e)||D.set(e,{snapped:!1,bindings:null,bound:!1,rendering:!1,anchor:null}),D.get(e));var N={},he=e=>{N=e};var m={onError:(e,r,o)=>{console.error(`[Lego Error] [${r}]`,e,o)},metrics:{},debug:!1,syntax:"brackets"},P=(e,r)=>{!e||!r||Object.getOwnPropertyNames(e).forEach(o=>{let s=Object.getOwnPropertyDescriptor(e,o);Object.defineProperty(r,o,s)})},U=()=>m.syntax==="brackets"?["[[","]]"]:["{{","}}"],ne=new Map,j=()=>{let[e,r]=U(),o=e+r;if(ne.has(o))return ne.get(o);let s=e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),t=r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),a=new RegExp(`${s}(.*?)${t}`,"g");return ne.set(o,a),a},be=e=>{let o=e.split("/").pop().replace(/\.lego$/,"").replace(/_/g,"-").replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase();if(!o.includes("-"))throw new Error(`[Lego] Invalid block definition: "${e}". Block names must contain a hyphen (e.g. user-card.lego or UserCard.lego).`);return o},B=(e,r)=>{if(!e)return"";let o=e.trim().split("."),s=r;for(let t of o){if(s==null)return"";s=s[t]}return s??""},ae=e=>typeof Node<"u"&&e instanceof Node,O=(e,r,o)=>{if(r.nodeType!==Node.ELEMENT_NODE)return;let s=[...r.attributes].find(a=>a.name===e||a.name.startsWith(`${e}.`));if(!s)return;let t={};return o&&(t=o(s,r)),{type:e,node:r,expr:s.value,modifiers:s.name.split(".").slice(1),...t}};var Z=class{constructor(r=1e3){this.limit=r,this.cache=new Map}get(r){if(!this.cache.has(r))return;let o=this.cache.get(r);return this.cache.delete(r),this.cache.set(r,o),o}set(r,o){if(this.cache.has(r))this.cache.delete(r);else if(this.cache.size>=this.limit){let s=this.cache.keys().next().value;this.cache.delete(s)}this.cache.set(r,o)}get size(){return this.cache.size}clear(){this.cache.clear()}};var F=(e,r)=>{if(!e)return;let o=e.parentElement||(e.getRootNode?e.getRootNode().host:null);for(;o;){let s=o.tagName?o.tagName.toLowerCase():"";if(s&&(r==="*"&&y[s]||s===r.toLowerCase()))return o;o=o.parentElement||o.getRootNode&&o.getRootNode().host}},ye=(e,r)=>{if(typeof e=="function"){let s=Array.from(document.querySelectorAll("*")).filter(t=>t.tagName.includes("-"));return[].concat(e(s))}if(e.startsWith("#")){let s=document.getElementById(e.slice(1));return s?[s]:[]}let o=r?.querySelectorAll(e)||[];return o.length>0?[...o]:[...document.querySelectorAll(e)]},Y=(e,r)=>{if(e.type==="checkbox")e.checked!==!!r&&(e.checked=!!r);else{let o=r==null?"":String(r);e.value!==o&&(e.value=o)}};var ie=null,Ee=e=>{ie=e},K=[],ce=e=>{let r=K.find(t=>t.regex.test(e));if(!r)return null;let o=e.match(r.regex).slice(1),s=r.paramNames?Object.fromEntries(r.paramNames.map((t,a)=>[t,o[a]])):{};return{match:r,params:s}},ee=async(e=null,r=null)=>{if(typeof window>"u")return;let o=window.location.pathname,s=ce(o);if(m.debug&&console.log("[Lego Trace] Matching route",o,s?.match),!s)return;let{match:t,params:a}=s;if(t.middleware&&!await t.middleware({path:o,params:a}))return;let i=e&&e.length?e:["lego-router"],n=r||document;t.tagName&&i.flatMap(l=>ye(l,n)).forEach(l=>{l&&(l.innerHTML=`<${t.tagName}></${t.tagName}>`,ie&&ie(l.firstElementChild))})},te=(e,...r)=>o=>{let s=async(t,a=null,i=!0,n={})=>{if(i&&typeof history<"u"){let l={legoTargets:r.filter(d=>typeof d=="string"),method:t,body:a};history.pushState(l,"",e)}await ee(r.length?r:null,o)};return{get:(t=!0,a={})=>s("GET",null,t,a),post:(t,a=!0,i={})=>s("POST",t,a,i),put:(t,a=!0,i={})=>s("PUT",t,a,i),patch:(t,a=!0,i={})=>s("PATCH",t,a,i),delete:(t=!0,a={})=>s("DELETE",null,t,a)}};var we=new Z(1e3),x=(e,r,o=!0)=>{if(/\b(function|eval|import|class|module|deploy|constructor|__proto__)\b/.test(e)){console.warn(`[Lego] Security Warning: Blocked dangerous expression "${e}"`);return}try{let s=r.state||{},t=we.get(e);t||(t=new Function("global","self","event","helpers",`
|
|
2
2
|
with(this) {
|
|
3
3
|
with(helpers) {
|
|
4
4
|
return ${e}
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
|
-
`),we.set(e,s));let n={$ancestors:a=>F(r.self,a),$registry:a=>Z.get(a.toLowerCase()),$element:r.self,$route:x.$route,$go:(a,...c)=>re(a,...c)(r.self),$db:x.$db,$emit:(a,c)=>{r.self.dispatchEvent(new CustomEvent(a,{detail:c,bubbles:!0,composed:!0}))}},i=s.call(o,r.global,r.self,r.event,n);return typeof i=="function"?i.call(o,r.event):i}catch(o){if(t)throw o;f.onError(o,"render-error",r.self);return}},le=(e,r={})=>{if(!e||e.trim()==="{}")return{};let t=o=>new Function("scope","global",`with(global) { with(scope) { return (${o}); } }`)(r,x);try{return t(e)}catch(o){let s=e.trim();if(!s.startsWith("{")&&s.includes(":"))try{return t(`{${e}}`)}catch{}return console.error(`[Lego] Error parsing b-logic: "${e.length>80?e.slice(0,80)+"...":e}"`,o),{}}};var Ne={name:"b-if",scan:(e,{checkGlobal:r,getPrivateData:t})=>k("b-if",e,(o,s)=>{r(o.value);let n=document.createComment(`b-if: ${o.value}`),i=t(s);return i.anchor=n,{anchor:n}}),execute({binding:e,state:r,global:t}){let{node:o,anchor:s,expr:n}=e,i=!!N(n,{state:r,global:t,self:o}),a=!!o.parentNode;i&&!a?s.parentNode&&s.parentNode.replaceChild(o,s):!i&&a&&o.parentNode.replaceChild(s,o)}};var xe={name:"b-show",scan(e,{checkGlobal:r}){if(e.nodeType===Node.ELEMENT_NODE&&e.hasAttribute("b-show")){let t=e.getAttribute("b-show");return r(t),{type:"b-show",node:e,expr:t}}},execute({binding:e,state:r,global:t}){let{node:o,expr:s}=e;o.style.display=N(s,{state:r,global:t,self:o})?"":"none"}};var ve={name:"b-text",scan(e){if(e.nodeType===Node.ELEMENT_NODE&&e.hasAttribute("b-text"))return{type:"b-text",node:e,path:e.getAttribute("b-text")}},execute({binding:e,state:r}){let{node:t,path:o}=e;t.textContent=C(o,r)}};var Se={name:"b-html",scan:e=>k("b-html",e),execute:({binding:e,state:r,global:t})=>{let{node:o,expr:s}=e;o.innerHTML=N(s,{state:r,global:t,self:o})||""}};var Le={name:"b-sync",scan(e){if(e.nodeType===Node.ELEMENT_NODE&&e.hasAttribute("b-sync"))return{type:"b-sync",node:e}},execute({binding:e,state:r}){let{node:t}=e;ee(t,C(t.getAttribute("b-sync"),r))}};var $e={name:"b-for",scan(e,{checkGlobal:r,pendingOperations:t}){if(e.nodeType!==Node.ELEMENT_NODE)return;let o=e.getAttribute("b-for")?.match(/^\s*(\w+)\s+in\s+([\s\S]+?)\s*$/);if(o){r(o[2]);let s=document.createComment(`b-for: ${o[1]} in ${o[2].trim()}`);return t.push(()=>{e.parentNode&&(e.parentNode.insertBefore(s,e),e.remove())}),{type:"b-for",anchor:s,itemName:o[1],listName:o[2].trim(),keyPath:e.getAttribute("b-key")||null,template:e.cloneNode(!0)}}},execute({binding:e,state:r,global:t,helpers:o}){let{bind:s,updateNodeBindings:n}=o;if(!s||!n){console.error("[Lego] b-for directive missing required helpers: bind, updateNodeBindings");return}let{anchor:i,listName:a,itemName:c,keyPath:l,template:m}=e,{contextEl:g}=o,d=N(a,{state:r,global:t,self:g})||[];M.has(i)||M.set(i,new Map);let p=M.get(i),b=new Set,h=[];d.forEach((u,v)=>{let y;l?(y=C(l,u),y===void 0&&console.warn(`[Lego] b-key="${l}" resolved to undefined for item at index ${v}. Check for typos.`)):u&&typeof u=="object"?(y=u.id||u._id||u.uuid||u.key,y===void 0&&(Q.has(u)||Q.set(u,Math.random()),y=Q.get(u))):y=`${v}-${u}`,b.add(y);let A=p.get(y);A||(A=m.cloneNode(!0),A.removeAttribute("b-for"),A.removeAttribute("b-key"),p.set(y,A),s(A,g,{name:c,listName:a,index:v}));let Ie=Object.assign(Object.create(r),{[c]:u,$index:v});n(A,Ie),A.querySelectorAll("[b-sync]").forEach(me=>{let ge=me.getAttribute("b-sync");if(ge.startsWith(`${c}.`)){let qe=N(a,{state:r,global:t,self:g});ee(me,C(ge.split(".").slice(1).join("."),qe[v]))}}),h.push(A)});let E=i.nextSibling;h.forEach(u=>{u!==E?i.parentNode.insertBefore(u,E):E=E.nextSibling});for(let[u,v]of p.entries())b.has(u)||(v.remove(),p.delete(u))}};var _e={scan:e=>{if(e.hasAttribute("b-init"))return{type:"b-init",node:e,expr:e.getAttribute("b-init")}},execute:({binding:e,state:r})=>{e.initialized||(e.initialized=!0,N(e.expr,{state:r}))}};var Te={name:"b-enter",scan:e=>k("b-enter",e,(r,t)=>({modifiers:r.name.split(".").slice(1)})),execute:({binding:e,state:r})=>{if(e.observer||e.done)return;let t=new IntersectionObserver((o,s)=>{o[0].isIntersecting&&(N(e.expr,{state:r}),e.modifiers.includes("once")&&(s.disconnect(),e.observer=null,e.done=!0))});t.observe(e.node),e.observer=t},destroy:({binding:e})=>{e.observer&&(e.observer.disconnect(),e.observer=null)}};var Ae={scan:e=>k("b-leave",e),execute:({binding:e,state:r})=>{if(e.observer||e.done)return;let t=new IntersectionObserver((o,s)=>{let n=o[0];n.isIntersecting&&(e.activated=!0),!n.isIntersecting&&e.activated&&(N(e.expr,{state:r}),e.modifiers.includes("once")&&(s.disconnect(),e.observer=null,e.done=!0))});t.observe(e.node),e.observer=t},destroy:({binding:e})=>{e.observer&&(e.observer.disconnect(),e.observer=null)}};var J={"b-if":Ne,"b-show":xe,"b-text":ve,"b-html":Se,"b-sync":Le,"b-for":$e,"b-init":_e,"b-enter":Te,"b-leave":Ae};var Ke=(e=null)=>{let r=!1,t=new Set,o=!1,s=e,n=new Set,i=null,a=new Set,c=d=>{s=d},l=()=>{i&&clearTimeout(i),i=setTimeout(()=>{a.forEach(d=>{let p=d._studs;if(p&&typeof p.updated=="function")try{p.updated.call(p)}catch(b){console.error("[Lego] Error in updated hook:",b)}}),a.clear(),i=null},50)},m=()=>{n.size>0&&(n.forEach(d=>t.add(d)),n.clear(),!r&&t.size>0&&(r=!0,requestAnimationFrame(g)))},g=()=>{o=!0;let d=Array.from(t);t.clear(),r=!1,d.forEach(p=>{p.isConnected&&s&&s(p)}),d.forEach(p=>a.add(p)),l(),o=!1,m()};return{add:d=>{if(d){if(o){n.add(d);return}t.add(d),!r&&(r=!0,requestAnimationFrame(g))}},setHandler:c}},oe=Ke();var $=new Map,se=new Map,V=new WeakMap,X=new Map,Ue=e=>{let r=Array.from(X.entries()).filter(([s])=>s.startsWith("lego:")).sort((s,n)=>s[1].timestamp-n[1].timestamp),t=0,o=[];for(let[s,n]of r){if(t>=e)break;try{localStorage.removeItem(s),t+=n.size,o.push(s),X.delete(s)}catch(i){console.error(`[Lego] Failed to evict ${s}:`,i)}}return o},Me=(e,r,t)=>{f.debug&&console.log("[Lego Trace] scheduleSave",e,r,t),se.has(e)&&clearTimeout(se.get(e));let o=()=>{try{let s=JSON.stringify(r),n=new Blob([s]).size;localStorage.setItem(e,s);let i=e.startsWith("lego:")?e:`lego:${e}`;X.set(i,{timestamp:Date.now(),size:n}),se.delete(e)}catch(s){if(s.name==="QuotaExceededError"){console.warn(`[Lego] Storage quota exceeded for key: ${e}`);try{let n=JSON.stringify(r),i=new Blob([n]).size,a=Ue(i*2);if(a.length>0){f.debug&&console.log(`[Lego] Evicted ${a.length} old keys, retrying save`),localStorage.setItem(e,n);let c=e.startsWith("lego:")?e:`lego:${e}`;X.set(c,{timestamp:Date.now(),size:i})}else f.onError(new Error("Storage quota exceeded and no keys available for eviction"),"quota",e)}catch{f.onError(new Error(`Critical: Could not save ${e} even after eviction`),"quota-critical",e)}}else console.error(`[Lego] Storage Error (${e}):`,s)}};t>0?se.set(e,setTimeout(o,t)):o()},ue=e=>({__type:"lego-db",key:e,_default:void 0,_debounce:0,default(t){return this._default=t,this},debounce(t){return this._debounce=t,this},set(t,o=0){return Me(e,t,o),$.has(e)&&$.get(e).forEach(({target:s,prop:n,el:i,batcher:a})=>{s[n]=t,i&&a&&a.add(i)}),t},get(){try{let t=localStorage.getItem(e);return t!==null?JSON.parse(t):null}catch(t){return console.warn(`[Lego] Failed to get localStorage value for key "${e}":`,t),null}},delete(){try{return localStorage.removeItem(e),X.delete(e.startsWith("lego:")?e:`lego:${e}`),$.has(e)&&$.get(e).forEach(({target:t,prop:o,el:s,batcher:n})=>{t[o]=null,s&&n&&n.add(s)}),!0}catch(t){return console.error(`[Lego] Failed to delete localStorage key "${e}":`,t),!1}}}),ke=e=>e&&e.__type==="lego-db",Ce=(e,r,t,o,s)=>{f.debug&&console.log("[Lego Trace] Reactive DB Init:",r,t);let n=t._default;try{let i=localStorage.getItem(t.key);i!==null&&(n=JSON.parse(i))}catch(i){console.warn(`[Lego] Failed to parse localStorage value for key "${t.key}":`,i)}e[r]=n,V.has(e)||V.set(e,{}),V.get(e)[r]={key:t.key,debounce:t._debounce},f.debug&&console.log("[Lego Trace] DB Metadata Set:",r,V.get(e)[r]),$.has(t.key)||$.set(t.key,new Set),$.get(t.key).add({target:e,prop:r,el:o,batcher:s})},Oe=(e,r,t)=>{let o=V.get(e);if(o&&o[r]){let s=o[r].key;Me(s,t,o[r].debounce),$.has(s)&&$.get(s).forEach(({target:n,prop:i,el:a,batcher:c})=>{n!==e&&(n[i]=t,a&&c&&c.add(a))})}},De=()=>{typeof window<"u"&&window.addEventListener("storage",e=>{if(!(!e.key||!$.has(e.key)))try{let r=JSON.parse(e.newValue);$.get(e.key).forEach(({target:t,prop:o,el:s,batcher:n})=>{t[o]=r,s&&n&&n.add(s)})}catch(r){console.warn("[Lego] Cross-tab sync error:",r)}})};var z=(e,r,t=oe)=>{if(e===null||typeof e!="object"||ae(e))return e;if(q.has(e))return q.get(e);for(let n in e){let i=Object.getOwnPropertyDescriptor(e,n);if(i&&i.get)continue;let a=e[n];ke(a)&&Ce(e,n,a,r,t)}let o={get:(n,i)=>{let a=Reflect.get(n,i);return a!==null&&typeof a=="object"&&!ae(a)?z(a,r,t):a},set:(n,i,a,c)=>{let l=n[i];f.debug&&l!==a&&console.log("[Lego Trace] Reactive SET:",i,"Old:",l,"New:",a,"Target:",n);let m=Reflect.set(n,i,a,c);return c===q.get(n)&&l!==a&&(t.add(r),Oe(n,i,a)),m},deleteProperty:(n,i)=>{let a=Reflect.deleteProperty(n,i);return t.add(r),a}},s=new Proxy(e,o);return q.set(e,s),s};var je=e=>{let r=e;for(;r;){let t=r.getAttribute&&r.getAttribute("b-error");if(t)return{errorTag:t,targetElement:r};let o=r.tagName?r.tagName.toLowerCase():"",s=w[o];if(s){let n=s.getAttribute("b-error");if(n)return{errorTag:n,targetElement:r}}r=r.parentElement||r.getRootNode&&r.getRootNode().host}return null},de=null,fe=null,Be=(e,r)=>{de=e,fe=r},Ge=(e,r,t)=>{if(!de||!fe){console.error("[Lego] Error boundary dependencies not loaded",t);return}try{r.shadowRoot?r.shadowRoot.innerHTML="":r.innerHTML="";let o=document.createElement(e);(r.shadowRoot||r).appendChild(o),de(o),o._studs&&(o._studs.$error={message:t.message,stack:t.stack,component:r.tagName.toLowerCase()},fe(o))}catch(o){console.error("[Lego] Error boundary failed to render:",o),console.error("[Lego] Original error:",t)}},W=(e,r,t)=>{let o=je(r);o?Ge(o.errorTag,o.targetElement,e):f.onError(e,t,r)};var H=(e,r,t=null)=>{let o=r._studs,s=a=>{let c=_(a);if(!c.bound){if(a.hasAttributes()){let l=a.attributes;for(let m=0;m<l.length;m++){let g=l[m];if(g.name.startsWith("@")){let d=g.name.slice(1).split("."),p=d[0],b=d.slice(1);a.addEventListener(p,h=>{if(b.includes("prevent")&&h.preventDefault(),b.includes("stop")&&h.stopPropagation(),!(b.includes("self")&&h.target!==h.currentTarget)){if(typeof KeyboardEvent<"u"&&h instanceof KeyboardEvent){if(b.includes("ctrl")&&!h.ctrlKey||b.includes("alt")&&!h.altKey||b.includes("shift")&&!h.shiftKey||b.includes("meta")&&!h.metaKey)return;let E=b.filter(u=>!["prevent","stop","self","ctrl","alt","shift","meta","capture","once","passive"].includes(u));if(E.length>0){let u=h.key.toLowerCase();if(!E.some(y=>y==="enter"?u==="enter":y==="esc"||y==="escape"?u==="escape":y==="space"?u===" ":y==="tab"?u==="tab":y==="delete"?u==="delete":y==="backspace"?u==="backspace":y==="up"?u==="arrowup":y==="down"?u==="arrowdown":y==="left"?u==="arrowleft":y==="right"?u==="arrowright":y==="alpha"?/^[a-z]$/.test(u):y==="numbers"?/^[0-9]$/.test(u):y===u))return}}try{let E=o;if(t){let v=N(t.listName,{state:o,global:x,self:r})[t.index];E=Object.assign(Object.create(o),{[t.name]:v})}N(g.value,{state:E,global:x,self:a,event:h,$event:h},!0)}catch(E){W(E,r,"event-handler")}}})}}if(a.hasAttribute("b-sync")){let m=a.getAttribute("b-sync"),g=()=>{try{let d,p;if(t&&m.startsWith(`${t.name}.`)){let E=N(t.listName,{state:o,global:x,self:r})[t.index];if(!E)return;let u=m.split(".").slice(1);p=u.pop(),d=u.reduce((v,y)=>v[y],E)}else{let h=m.split(".");p=h.pop(),d=h.reduce((E,u)=>E[u],o)}let b=a.type==="checkbox"?a.checked:a.value;d&&d[p]!==b&&(d[p]=b)}catch(d){f.onError(d,"sync-update",a)}};a.addEventListener("input",g),a.addEventListener("change",g)}if(a.hasAttribute("b-var")){let m=a.getAttribute("b-var");o.$vars&&(o.$vars[m]=a)}}c.bound=!0}};e instanceof Element&&s(e);let n=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT),i;for(;i=n.nextNode();)s(i)},Je=e=>{let r=[],t=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT),o,s=[];for(;o=t.nextNode();){let n=o;if((c=>{let l=c.parentNode;for(;l&&l!==e;){if(l.hasAttribute&&l.hasAttribute("b-for"))return!0;l=l.parentNode}return!1})(o))continue;let a=c=>{if(/\bglobal\b/.test(c)){let l=e.host||e;K.add(l)}};if(o.nodeType===Node.ELEMENT_NODE){for(let[l,m]of Object.entries(J))if(m.scan){let g=m.scan(o,{checkGlobal:a,getPrivateData:_,pendingOperations:s,current:n});g&&r.push(g)}let[c]=U();[...o.attributes].forEach(l=>{l.value.includes(c)&&(a(l.value),r.push({type:"attr",node:o,attrName:l.name,template:l.value}))})}else if(o.nodeType===Node.TEXT_NODE){let[c]=U();o.textContent.includes(c)&&(a(o.textContent),r.push({type:"text",node:o,template:o.textContent}))}}return s.forEach(n=>n()),r},Ve=(e,r)=>{let t=n=>{if(n.nodeType===Node.TEXT_NODE){n._tpl===void 0&&(n._tpl=n.textContent);let i=n._tpl.replace(j(),(a,c)=>N(c.trim(),{state:r,global:x,self:n})??"");n.textContent!==i&&(n.textContent=i)}else if(n.nodeType===Node.ELEMENT_NODE){let[i]=U();[...n.attributes].forEach(a=>{if(a._tpl===void 0&&(a._tpl=a.value),a._tpl.includes(i)){let c=a._tpl.replace(j(),(l,m)=>N(m.trim(),{state:r,global:x,self:n})??"");a.value!==c&&(a.value=c,a.name==="class"&&(n.className=c))}})}};t(e);let o=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT),s;for(;s=o.nextNode();)t(s)},O=e=>{f.debug&&console.log("[Lego Trace] render() called for:",e.tagName);let r=e._studs;if(!r)return;let t=_(e);if(!t.rendering){t.rendering=!0,f.metrics&&f.metrics.onRenderStart&&f.metrics.onRenderStart(e);try{let o=e.shadowRoot||e;t.bindings||(t.bindings=Je(o)),t.bindings.forEach(s=>{let n=J[s.type];if(n){n.execute({binding:s,state:r,global:x,helpers:{bind:H,updateNodeBindings:Ve,contextEl:e}});return}if(s.type==="text"){let i=s.template.replace(j(),(a,c)=>N(c.trim(),{state:r,global:x,self:s.node})??"");s.node.textContent!==i&&(s.node.textContent=i)}if(s.type==="attr"){let i=s.template.replace(j(),(a,c)=>N(c.trim(),{state:r,global:x,self:s.node})??"");s.node.getAttribute(s.attrName)!==i&&(s.node.setAttribute(s.attrName,i),s.attrName==="class"&&(s.node.className=i))}}),r===x&&K.forEach(s=>O(s))}catch(o){W(o,e,"render")}finally{f.metrics&&f.metrics.onRenderEnd&&f.metrics.onRenderEnd(e),t.rendering=!1}}};var Re=new Map,Pe={},Fe=e=>{Pe=e},ze=async()=>{let e=Object.entries(Pe).map(async([r,t])=>{let o=await Promise.all(t.map(async s=>{try{if(s instanceof CSSStyleSheet)return s;let n=await fetch(s);if(!n.ok)throw new Error(`Status ${n.status}`);let i=await n.text(),a=new CSSStyleSheet;return await a.replace(i),a}catch(n){return console.error(`[Lego] Failed to load stylesheet: ${s}`,n),null}}));Re.set(r,o.filter(s=>s!==null))});await Promise.all(e),f.debug&&console.log("[Lego Debug] Re-applying stylesheets to",L.size,"blocks"),L.forEach(r=>{pe(r)})},pe=e=>{if(!e.shadowRoot&&!e._legoShadow)return;let r=e.shadowRoot||e._legoShadow,t=e.tagName.toLowerCase(),o=w[t],s=(o&&o.getAttribute("b-stylesheets")||"").split(/\s+/).filter(Boolean),n=(e.getAttribute("b-stylesheets")||"").split(/\s+/).filter(Boolean),i=[],a=e.parentElement||(e.getRootNode?e.getRootNode().host:null);for(;a;){let g=(a.getAttribute("b-cascade")||"").split(/\s+/).filter(Boolean);g.length&&i.push(...g);let d=a.tagName?a.tagName.toLowerCase():"";if(w[d]){let p=(w[d].getAttribute("b-cascade")||"").split(/\s+/).filter(Boolean);p.length&&i.push(...p)}a=a.parentElement||a.getRootNode&&a.getRootNode().host}let c=[...new Set([...s,...n])],l=[...new Set(i)],m=[...new Set([...l,...c])];if(m.length>0){let g=m.flatMap(d=>Re.get(d)||[]);g.length>0&&f.debug&&console.log("[Lego Debug] Applying styles to",e.tagName,"- Names:",m,"- Sheets:",g.length),g.length>0&&(r.adoptedStyleSheets=[...g])}e._studsMeta={stylesheets:{explicit:c,inherited:l,applied:m}}};var S=e=>{if(f.debug&&console.log("[Lego Trace] snap() called for:",e.tagName),!e||e.nodeType!==Node.ELEMENT_NODE)return;let r=_(e),t=e.tagName.toLowerCase(),o=w[t];if(o&&!r.snapped){r.snapped=!0;let n=o.content.cloneNode(!0),i=e.shadowRoot;i?i.innerHTML="":i=e.attachShadow({mode:"open"}),pe(e);let a=F(e,"*")||F(e.getRootNode().host,"*"),c=a&&a.state?a.state:{},l=R.get(t)||{},m=le(o.getAttribute("b-logic")||"{}"),g=le(e.getAttribute("b-logic")||"{}",c),d={$vars:{},$element:e,get $parent(){return F(e,"*")},$emit:(h,E)=>{e.dispatchEvent(new CustomEvent(h,{detail:E,bubbles:!0,composed:!0}))},get $route(){return x.$route},get $go(){return x.$go}};P(l,d),P(m,d),P(g,d),e._studs=z(d,e),Object.defineProperty(e,"state",{get(){return this._studs},set(h){Object.assign(this._studs,h)},configurable:!0,enumerable:!1}),i.appendChild(n);let p=i.querySelector("style");p&&(p.textContent=p.textContent.replace(/\bself\b/g,":host")),H(i,e),L.add(e),O(e),e.setAttribute("b-id",t);let b=i.querySelectorAll("*");if(f.debug&&console.log("[Lego Debug] Nested scan in",e.tagName,"- Found elements:",b.length),b.forEach(h=>{let E=h.tagName.toLowerCase(),u=!!w[E];u&&f.debug&&console.log("[Lego Debug] Checking",E,"- Registered:",u),u&&S(h)}),e._legoShadow||(e._legoShadow=i),typeof e._studs.mounted=="function")try{e._studs.mounted.call(e._studs)}catch(h){W(h,e,"mounted")}}let s=e.parentElement;for(;s&&!s._studs;)s=s.parentElement;s&&s._studs&&H(e,s),[...e.children].forEach(S)},I=e=>{if(e._studs&&typeof e._studs.unmounted=="function")try{e._studs.unmounted.call(e._studs)}catch(t){W(t,e,"unmounted")}e.shadowRoot&&[...e.shadowRoot.children].forEach(I),L.delete(e),K.delete(e),e._studs&&(e._studs.$element=null,e._studs.$vars&&(Object.keys(e._studs.$vars).forEach(t=>{e._studs.$vars[t]=null}),e._studs.$vars=null),e._studs.$emit&&(e._studs.$emit=null),delete e._studs.$parent,delete e._studs.$route,delete e._studs.$go,e._studs=null),e.hasOwnProperty("state")&&delete e.state;let r=B.get(e);if(r&&(r.bindings&&(r.bindings.forEach(t=>{let o=J[t.type];if(o&&o.destroy)try{o.destroy({binding:t})}catch(s){console.error(`[Lego] Error in directive cleanup (${t.type}):`,s)}t.node=null,t.anchor=null}),r.bindings=null),r.anchor=null,B.delete(e)),M.has(e)){let t=M.get(e);t.forEach((o,s)=>{o&&o._studs&&(o._studs=null)}),t.clear(),M.delete(e)}[...e.children].forEach(I)};function We(e,r="block.lego"){let t={template:"",script:"",style:"",stylesAttr:"",cascadeAttr:"",errorAttr:"",blockName:be(r)},o=e,s=/<(template|script|style)\b((?:\s+(?:[^>"']|"[^"]*"|'[^']*')*)*)>/i;for(;o;){let n=o.match(s);if(!n)break;let i=n[1].toLowerCase(),a=n[2],c=n[0],l=n.index,m=`</${i}>`,g=l+c.length,d=o.indexOf(m,g);if(d===-1){console.warn(`[Lego] Unclosed <${i}> tag in ${r}`);break}let p=o.slice(g,d);if(i==="template"){t.template=p.trim();let b=a.match(/b-stylesheets=["']([^"']+)["']/);b&&(t.stylesAttr=b[1]);let h=a.match(/b-cascade=["']([^"']+)["']/);h&&(t.cascadeAttr=h[1]);let E=a.match(/b-error=["']([^"']+)["']/);E&&(t.errorAttr=E[1])}else if(i==="script"){t.script=p.trim();let b=a.match(/lang=["']([^"']+)["']/);b&&(t.scriptLang=b[1])}else i==="style"&&(t.style=p.trim());o=o.slice(d+m.length)}return t}var He=(e,r,t="block.lego")=>{let o=We(r,t),{blockName:s,template:n,script:i,style:a,stylesAttr:c,cascadeAttr:l,errorAttr:m}=o,g={};if(i)try{let p=i.trim(),b=p.match(/export\s+default\s+({[\s\S]*})/),h=b?b[1]:p;g=new Function("Lego","$db",`return ${h}`)(e,e.globals.$db)}catch(p){f.onError(p,"script",s)}let d=n;a&&(d=`<style>${a}</style>`+d),w[s]=document.createElement("template"),w[s].innerHTML=d,c&&w[s].setAttribute("b-stylesheets",c),l&&w[s].setAttribute("b-cascade",l),m&&w[s].setAttribute("b-error",m),R.set(s,g),document.querySelectorAll(s).forEach(p=>!_(p).snapped&&S(p))};oe.setHandler(O);Be(S,O);Ee(S);var Xe={url:typeof window<"u"?window.location.pathname:"/",route:"",params:{},query:{},method:"GET",body:null},T=z({$route:Xe,$go:(e,...r)=>re(e,...r)(document.body),$db:ue},typeof document<"u"?document.body:null);he(T);var D={db:ue,snap:S,unsnap:I,defineLegoFile:(e,r)=>He(D,e,r),block:(e,r,t={},o="",s="",n="")=>{let i=document.createElement("template");i.setAttribute("b-id",e),i.setAttribute("b-stylesheets",o),s&&i.setAttribute("b-cascade",s),n&&i.setAttribute("b-error",n),i.innerHTML=r,w[e]=i,R.set(e,t);try{let a={};P(t,a),Z.set(e.toLowerCase(),z(a,document.body))}catch(a){f.onError(a,"define",e)}document.querySelectorAll(e).forEach(S),[...L].forEach(a=>{a.tagName.toLowerCase()===e.toLowerCase()&&(f.debug&&console.log("[Lego HMR] Reloading",e),I(a),S(a))}),L.forEach(a=>{a._legoShadow&&a._legoShadow.querySelectorAll(e).forEach(c=>{_(c).snapped||(f.debug&&console.log("[Lego Debug] Lazy-initializing",e,"in",a.tagName),S(c))})})},getActiveBlocksCount:()=>L.size,getLegos:()=>Object.keys(w),config:f,globals:T,route:(e,r,t=null)=>{let o=[],s=e==="*"?".*":e;s=s.replace(/:([^\/]+)/g,(n,i)=>(o.push(i),"([^/]+)")),G.push({path:e,regex:new RegExp(`^${s}$`),tagName:r,paramNames:o,middleware:t})},debug:{stylesheets:e=>!e||!e._studsMeta?null:e._studsMeta.stylesheets},init:async(e=document.body,r={})=>{if((!e||typeof e.nodeType!="number")&&(e=document.body),Fe(r.styles||{}),f.loader=r.loader,f.debug=r.debug===!0,await ze(),G.length>0){let n=window.location.pathname,i=window.location.search,a=ce(n);if(a){let{match:c,params:l}=a,m=Object.fromEntries(new URLSearchParams(i));T.$route.url=n+i,T.$route.route=c.path,T.$route.params=l,T.$route.query=m,T.$route.method="GET",T.$route.body=null}}document.querySelectorAll("template[b-id]").forEach(n=>{w[n.getAttribute("b-id")]=n});let t=n=>{if(n.nodeType!==Node.ELEMENT_NODE)return;S(n);let i=n.tagName.toLowerCase();if(i.includes("-")&&!w[i]&&f.loader&&!L.has(n)){let a=f.loader(i);if(a){let c=typeof a=="string"?fetch(a).then(l=>l.text()):a;Promise.resolve(c).then(l=>D.defineLegoFile(l,`${i}.lego`)).catch(l=>console.error(`[Lego] Failed to load ${i}:`,l))}}};new MutationObserver(n=>n.forEach(i=>{i.addedNodes.forEach(t),i.removedNodes.forEach(a=>a.nodeType===Node.ELEMENT_NODE&&I(a))})).observe(e,{childList:!0,subtree:!0});let s=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT);for(t(e);s.nextNode();)t(s.currentNode);if(e._studs=T,H(e,e),O(e),r.studio){if(!w["lego-studio"]){let n=document.createElement("script");n.src="https://unpkg.com/@legodom/studio@0.0.2/dist/lego-studio.js",n.onerror=()=>console.warn("[Lego] Failed to load Studio from CDN"),document.head.appendChild(n)}D.route("/_/studio","lego-studio"),D.route("/_/studio/:block","lego-studio")}G.length>0&&(window.addEventListener("popstate",n=>{let i=n.state?.legoTargets||null;te(i)}),document.addEventListener("submit",n=>{n.preventDefault()}),document.addEventListener("click",n=>{let a=n.composedPath().find(c=>c.tagName==="A"&&(c.hasAttribute("b-target")||c.hasAttribute("b-link")));if(a){n.preventDefault();let c=a.getAttribute("href"),l=a.getAttribute("b-target"),m=l?l.split(/\s+/).filter(Boolean):[],g=a.getAttribute("b-link")!=="false";T.$go(c,...m).get(g)}}),te()),De()}};typeof window<"u"?window.Lego=D:typeof global<"u"&&(global.Lego=D);var go=D;export{D as Lego,go as default};
|
|
7
|
+
`),we.set(e,t));let a={$ancestors:n=>F(r.self,n),$registry:n=>Q.get(n.toLowerCase()),$element:r.self,$route:N.$route,$go:(n,...c)=>te(n,...c)(r.self),$db:N.$db,$emit:(n,c)=>{r.self.dispatchEvent(new CustomEvent(n,{detail:c,bubbles:!0,composed:!0}))}},i=t.call(s,r.global,r.self,r.event,a);return typeof i=="function"?i.call(s,r.event):i}catch(s){if(o)throw s;m.onError(s,"render-error",r.self);return}},le=(e,r={})=>{if(!e||e.trim()==="{}")return{};let o=s=>new Function("scope","global",`with(global) { with(scope) { return (${s}); } }`)(r,N);try{return o(e)}catch(s){let t=e.trim();if(!t.startsWith("{")&&t.includes(":"))try{return o(`{${e}}`)}catch{}return console.error(`[Lego] Error parsing b-logic: "${e.length>80?e.slice(0,80)+"...":e}"`,s),{}}};var xe={name:"b-if",scan:(e,{checkGlobal:r,getPrivateData:o})=>O("b-if",e,(s,t)=>{r(s.value);let a=document.createComment(`b-if: ${s.value}`),i=o(t);return i.anchor=a,{anchor:a}}),execute({binding:e,state:r,global:o}){let{node:s,anchor:t,expr:a}=e,i=!!x(a,{state:r,global:o,self:s}),n=!!s.parentNode;i&&!n?t.parentNode&&t.parentNode.replaceChild(s,t):!i&&n&&s.parentNode.replaceChild(t,s)}};var ve={name:"b-show",scan(e,{checkGlobal:r}){if(e.nodeType===Node.ELEMENT_NODE&&e.hasAttribute("b-show")){let o=e.getAttribute("b-show");return r(o),{type:"b-show",node:e,expr:o}}},execute({binding:e,state:r,global:o}){let{node:s,expr:t}=e;s.style.display=x(t,{state:r,global:o,self:s})?"":"none"}};var Ne={name:"b-text",scan(e){if(e.nodeType===Node.ELEMENT_NODE&&e.hasAttribute("b-text"))return{type:"b-text",node:e,path:e.getAttribute("b-text")}},execute({binding:e,state:r}){let{node:o,path:s}=e;o.textContent=B(s,r)}};var Se={name:"b-html",scan:e=>O("b-html",e),execute:({binding:e,state:r,global:o})=>{let{node:s,expr:t}=e;s.innerHTML=x(t,{state:r,global:o,self:s})||""}};var $e={name:"b-sync",scan(e){if(e.nodeType===Node.ELEMENT_NODE&&e.hasAttribute("b-sync"))return{type:"b-sync",node:e}},execute({binding:e,state:r}){let{node:o}=e;Y(o,B(o.getAttribute("b-sync"),r))}};var Le={name:"b-for",scan(e,{checkGlobal:r,pendingOperations:o}){if(e.nodeType!==Node.ELEMENT_NODE)return;let s=e.getAttribute("b-for")?.match(/^\s*(\w+)\s+in\s+([\s\S]+?)\s*$/);if(s){r(s[2]);let t=document.createComment(`b-for: ${s[1]} in ${s[2].trim()}`);return o.push(()=>{e.parentNode&&(e.parentNode.insertBefore(t,e),e.remove())}),{type:"b-for",anchor:t,itemName:s[1],listName:s[2].trim(),keyPath:e.getAttribute("b-key")||null,template:e.cloneNode(!0)}}},execute({binding:e,state:r,global:o,helpers:s}){let{bind:t,updateNodeBindings:a}=s;if(!t||!a){console.error("[Lego] b-for directive missing required helpers: bind, updateNodeBindings");return}let{anchor:i,listName:n,itemName:c,keyPath:l,template:d}=e,{contextEl:u}=s,f=x(n,{state:r,global:o,self:u})||[];C.has(i)||C.set(i,new Map);let g=C.get(i),b=new Set,h=[];f.forEach((p,$)=>{let E;l?(E=B(l,p),E===void 0&&console.warn(`[Lego] b-key="${l}" resolved to undefined for item at index ${$}. Check for typos.`)):p&&typeof p=="object"?(E=p.id||p._id||p.uuid||p.key,E===void 0&&(X.has(p)||X.set(p,Math.random()),E=X.get(p))):E=`${$}-${p}`,b.add(E);let T=g.get(E);T||(T=d.cloneNode(!0),T.removeAttribute("b-for"),T.removeAttribute("b-key"),g.set(E,T),t(T,u,{name:c,listName:n,index:$}));let Ie=Object.assign(Object.create(r),{[c]:p,$index:$});a(T,Ie),T.querySelectorAll("[b-sync]").forEach(me=>{let ge=me.getAttribute("b-sync");if(ge.startsWith(`${c}.`)){let qe=x(n,{state:r,global:o,self:u});Y(me,B(ge.split(".").slice(1).join("."),qe[$]))}}),h.push(T)});let w=i.nextSibling;h.forEach(p=>{p!==w?i.parentNode.insertBefore(p,w):w=w.nextSibling});for(let[p,$]of g.entries())b.has(p)||($.remove(),g.delete(p))}};var _e={scan:e=>{if(e.hasAttribute("b-init"))return{type:"b-init",node:e,expr:e.getAttribute("b-init")}},execute:({binding:e,state:r})=>{e.initialized||(e.initialized=!0,x(e.expr,{state:r}))}};var Te={name:"b-enter",scan:e=>O("b-enter",e,(r,o)=>({modifiers:r.name.split(".").slice(1)})),execute:({binding:e,state:r})=>{if(e.observer||e.done)return;let o=new IntersectionObserver((s,t)=>{s[0].isIntersecting&&(x(e.expr,{state:r}),e.modifiers.includes("once")&&(t.disconnect(),e.observer=null,e.done=!0))});o.observe(e.node),e.observer=o},destroy:({binding:e})=>{e.observer&&(e.observer.disconnect(),e.observer=null)}};var Ae={scan:e=>O("b-leave",e),execute:({binding:e,state:r})=>{if(e.observer||e.done)return;let o=new IntersectionObserver((s,t)=>{let a=s[0];a.isIntersecting&&(e.activated=!0),!a.isIntersecting&&e.activated&&(x(e.expr,{state:r}),e.modifiers.includes("once")&&(t.disconnect(),e.observer=null,e.done=!0))});o.observe(e.node),e.observer=o},destroy:({binding:e})=>{e.observer&&(e.observer.disconnect(),e.observer=null)}};var G={"b-if":xe,"b-show":ve,"b-text":Ne,"b-html":Se,"b-sync":$e,"b-for":Le,"b-init":_e,"b-enter":Te,"b-leave":Ae};var Ue=(e=null)=>{let r=!1,o=new Set,s=!1,t=e,a=new Set,i=null,n=new Set,c=f=>{t=f},l=()=>{i&&clearTimeout(i),i=setTimeout(()=>{n.forEach(f=>{let g=f._studs;if(g&&typeof g.updated=="function")try{g.updated.call(g)}catch(b){console.error("[Lego] Error in updated hook:",b)}}),n.clear(),i=null},50)},d=()=>{a.size>0&&(a.forEach(f=>o.add(f)),a.clear(),!r&&o.size>0&&(r=!0,requestAnimationFrame(u)))},u=()=>{s=!0;let f=Array.from(o);o.clear(),r=!1,f.forEach(g=>{g.isConnected&&t&&t(g)}),f.forEach(g=>n.add(g)),l(),s=!1,d()};return{add:f=>{if(f){if(s){a.add(f);return}o.add(f),!r&&(r=!0,requestAnimationFrame(u))}},setHandler:c}},re=Ue();var L=new Map,oe=new Map,J=new WeakMap,V=new Map,je=e=>{let r=Array.from(V.entries()).filter(([t])=>t.startsWith("lego:")).sort((t,a)=>t[1].timestamp-a[1].timestamp),o=0,s=[];for(let[t,a]of r){if(o>=e)break;try{localStorage.removeItem(t),o+=a.size,s.push(t),V.delete(t)}catch(i){console.error(`[Lego] Failed to evict ${t}:`,i)}}return s},ke=(e,r,o)=>{m.debug&&console.log("[Lego Trace] scheduleSave",e,r,o),oe.has(e)&&clearTimeout(oe.get(e));let s=()=>{try{let t=JSON.stringify(r),a=new Blob([t]).size;localStorage.setItem(e,t);let i=e.startsWith("lego:")?e:`lego:${e}`;V.set(i,{timestamp:Date.now(),size:a}),oe.delete(e)}catch(t){if(t.name==="QuotaExceededError"){console.warn(`[Lego] Storage quota exceeded for key: ${e}`);try{let a=JSON.stringify(r),i=new Blob([a]).size,n=je(i*2);if(n.length>0){m.debug&&console.log(`[Lego] Evicted ${n.length} old keys, retrying save`),localStorage.setItem(e,a);let c=e.startsWith("lego:")?e:`lego:${e}`;V.set(c,{timestamp:Date.now(),size:i})}else m.onError(new Error("Storage quota exceeded and no keys available for eviction"),"quota",e)}catch{m.onError(new Error(`Critical: Could not save ${e} even after eviction`),"quota-critical",e)}}else console.error(`[Lego] Storage Error (${e}):`,t)}};o>0?oe.set(e,setTimeout(s,o)):s()},fe=e=>({__type:"lego-db",key:e,_default:void 0,_debounce:0,default(o){return this._default=o,this},debounce(o){return this._debounce=o,this},set(o,s=0){return ke(e,o,s),L.has(e)&&L.get(e).forEach(({target:t,prop:a,el:i,batcher:n})=>{t[a]=o,i&&n&&n.add(i)}),o},get(){try{let o=localStorage.getItem(e);return o!==null?JSON.parse(o):null}catch(o){return console.warn(`[Lego] Failed to get localStorage value for key "${e}":`,o),null}},delete(){try{return localStorage.removeItem(e),V.delete(e.startsWith("lego:")?e:`lego:${e}`),L.has(e)&&L.get(e).forEach(({target:o,prop:s,el:t,batcher:a})=>{o[s]=null,t&&a&&a.add(t)}),!0}catch(o){return console.error(`[Lego] Failed to delete localStorage key "${e}":`,o),!1}}}),Ce=e=>e&&e.__type==="lego-db",Me=(e,r,o,s,t)=>{m.debug&&console.log("[Lego Trace] Reactive DB Init:",r,o);let a=o._default;try{let i=localStorage.getItem(o.key);i!==null&&(a=JSON.parse(i))}catch(i){console.warn(`[Lego] Failed to parse localStorage value for key "${o.key}":`,i)}e[r]=a,J.has(e)||J.set(e,{}),J.get(e)[r]={key:o.key,debounce:o._debounce},m.debug&&console.log("[Lego Trace] DB Metadata Set:",r,J.get(e)[r]),L.has(o.key)||L.set(o.key,new Set),L.get(o.key).add({target:e,prop:r,el:s,batcher:t})},Oe=(e,r,o)=>{let s=J.get(e);if(s&&s[r]){let t=s[r].key;ke(t,o,s[r].debounce),L.has(t)&&L.get(t).forEach(({target:a,prop:i,el:n,batcher:c})=>{a!==e&&(a[i]=o,n&&c&&c.add(n))})}},Be=()=>{typeof window<"u"&&window.addEventListener("storage",e=>{if(!(!e.key||!L.has(e.key)))try{let r=JSON.parse(e.newValue);L.get(e.key).forEach(({target:o,prop:s,el:t,batcher:a})=>{o[s]=r,t&&a&&a.add(t)})}catch(r){console.warn("[Lego] Cross-tab sync error:",r)}})};var z=(e,r,o=re)=>{if(e===null||typeof e!="object"||ae(e))return e;if(I.has(e))return I.get(e);for(let a in e){let i=Object.getOwnPropertyDescriptor(e,a);if(i&&i.get)continue;let n=e[a];Ce(n)&&Me(e,a,n,r,o)}let s={get:(a,i)=>{let n=Reflect.get(a,i);return n!==null&&typeof n=="object"&&!ae(n)?z(n,r,o):n},set:(a,i,n,c)=>{let l=a[i];m.debug&&l!==n&&console.log("[Lego Trace] Reactive SET:",i,"Old:",l,"New:",n,"Target:",a);let d=Reflect.set(a,i,n,c);return c===I.get(a)&&l!==n&&(o.add(r),Oe(a,i,n)),d},deleteProperty:(a,i)=>{let n=Reflect.deleteProperty(a,i);return o.add(r),n}},t=new Proxy(e,s);return I.set(e,t),t};var Ke=e=>{let r=e;for(;r;){let o=r.getAttribute&&r.getAttribute("b-error");if(o)return{errorTag:o,targetElement:r};let s=r.tagName?r.tagName.toLowerCase():"",t=y[s];if(t){let a=t.getAttribute("b-error");if(a)return{errorTag:a,targetElement:r}}r=r.parentElement||r.getRootNode&&r.getRootNode().host}return null},de=null,ue=null,De=(e,r)=>{de=e,ue=r},Ge=(e,r,o)=>{if(!de||!ue){console.error("[Lego] Error boundary dependencies not loaded",o);return}try{r.shadowRoot?r.shadowRoot.innerHTML="":r.innerHTML="";let s=document.createElement(e);(r.shadowRoot||r).appendChild(s),de(s),s._studs&&(s._studs.$error={message:o.message,stack:o.stack,component:r.tagName.toLowerCase()},ue(s))}catch(s){console.error("[Lego] Error boundary failed to render:",s),console.error("[Lego] Original error:",o)}},W=(e,r,o)=>{let s=Ke(r);s?Ge(s.errorTag,s.targetElement,e):m.onError(e,o,r)};var se=(e,r,o=null)=>{let s=r._studs,t=n=>{let c=M(n);if(!c.bound){if(n.hasAttributes()){let l=n.attributes;for(let d=0;d<l.length;d++){let u=l[d];if(u.name.startsWith("@")){let f=u.name.slice(1).split("."),g=f[0],b=f.slice(1);n.addEventListener(g,h=>{if(b.includes("prevent")&&h.preventDefault(),b.includes("stop")&&h.stopPropagation(),!(b.includes("self")&&h.target!==h.currentTarget)){if(typeof KeyboardEvent<"u"&&h instanceof KeyboardEvent){if(b.includes("ctrl")&&!h.ctrlKey||b.includes("alt")&&!h.altKey||b.includes("shift")&&!h.shiftKey||b.includes("meta")&&!h.metaKey)return;let w=b.filter(p=>!["prevent","stop","self","ctrl","alt","shift","meta","capture","once","passive"].includes(p));if(w.length>0){let p=h.key.toLowerCase();if(!w.some(E=>E==="enter"?p==="enter":E==="esc"||E==="escape"?p==="escape":E==="space"?p===" ":E==="tab"?p==="tab":E==="delete"?p==="delete":E==="backspace"?p==="backspace":E==="up"?p==="arrowup":E==="down"?p==="arrowdown":E==="left"?p==="arrowleft":E==="right"?p==="arrowright":E==="alpha"?/^[a-z]$/.test(p):E==="numbers"?/^[0-9]$/.test(p):E===p))return}}try{let w=s;if(o){let $=x(o.listName,{state:s,global:N,self:r})[o.index];w=Object.assign(Object.create(s),{[o.name]:$})}x(u.value,{state:w,global:N,self:n,event:h,$event:h},!0)}catch(w){W(w,r,"event-handler")}}})}}if(n.hasAttribute("b-sync")){let d=n.getAttribute("b-sync"),u=()=>{try{let f,g;if(o&&d.startsWith(`${o.name}.`)){let w=x(o.listName,{state:s,global:N,self:r})[o.index];if(!w)return;let p=d.split(".").slice(1);g=p.pop(),f=p.reduce(($,E)=>$[E],w)}else{let h=d.split(".");g=h.pop(),f=h.reduce((w,p)=>w[p],s)}let b=n.type==="checkbox"?n.checked:n.value;f&&f[g]!==b&&(f[g]=b)}catch(f){m.onError(f,"sync-update",n)}};n.addEventListener("input",u),n.addEventListener("change",u)}if(n.hasAttribute("b-var")){let d=n.getAttribute("b-var");s.$vars&&(s.$vars[d]=n)}}c.bound=!0}};e instanceof Element&&t(e);let a=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT),i;for(;i=a.nextNode();)t(i)},Je=e=>{let r=[],o=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT),s,t=[];for(;s=o.nextNode();){let a=s;if((c=>{let l=c.parentNode;for(;l&&l!==e;){if(l.hasAttribute&&l.hasAttribute("b-for"))return!0;l=l.parentNode}return!1})(s))continue;let n=c=>{if(/\bglobal\b/.test(c)){let l=e.host||e;q.add(l)}};if(s.nodeType===Node.ELEMENT_NODE){for(let[l,d]of Object.entries(G))if(d.scan){let u=d.scan(s,{checkGlobal:n,getPrivateData:M,pendingOperations:t,current:a});u&&r.push(u)}let[c]=U();[...s.attributes].forEach(l=>{l.value.includes(c)&&(n(l.value),r.push({type:"attr",node:s,attrName:l.name,template:l.value}))})}else if(s.nodeType===Node.TEXT_NODE){let[c]=U();s.textContent.includes(c)&&(n(s.textContent),r.push({type:"text",node:s,template:s.textContent}))}}return t.forEach(a=>a()),r},Ve=(e,r)=>{let o=a=>{if(a.nodeType===Node.TEXT_NODE){a._tpl===void 0&&(a._tpl=a.textContent);let i=a._tpl.replace(j(),(n,c)=>x(c.trim(),{state:r,global:N,self:a})??"");a.textContent!==i&&(a.textContent=i)}else if(a.nodeType===Node.ELEMENT_NODE){let[i]=U();[...a.attributes].forEach(n=>{if(n._tpl===void 0&&(n._tpl=n.value),n._tpl.includes(i)){let c=n._tpl.replace(j(),(l,d)=>x(d.trim(),{state:r,global:N,self:a})??"");n.value!==c&&(n.value=c,n.name==="class"&&(a.className=c))}})}};o(e);let s=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT),t;for(;t=s.nextNode();)o(t)},H=e=>{m.debug&&console.log("[Lego Trace] render() called for:",e.tagName);let r=e._studs;if(!r)return;let o=M(e);if(!o.rendering){o.rendering=!0,m.metrics&&m.metrics.onRenderStart&&m.metrics.onRenderStart(e);try{let s=e.shadowRoot||e;o.bindings||(o.bindings=Je(s)),o.bindings.forEach(t=>{let a=G[t.type];if(a){a.execute({binding:t,state:r,global:N,helpers:{bind:se,updateNodeBindings:Ve,contextEl:e}});return}if(t.type==="text"){let i=t.template.replace(j(),(n,c)=>x(c.trim(),{state:r,global:N,self:t.node})??"");t.node.textContent!==i&&(t.node.textContent=i)}if(t.type==="attr"){let i=t.template.replace(j(),(n,c)=>x(c.trim(),{state:r,global:N,self:t.node})??"");t.node.getAttribute(t.attrName)!==i&&(t.node.setAttribute(t.attrName,i),t.attrName==="class"&&(t.node.className=i))}}),r===N&&q.forEach(t=>H(t))}catch(s){W(s,e,"render")}finally{m.metrics&&m.metrics.onRenderEnd&&m.metrics.onRenderEnd(e),o.rendering=!1}}};var Re=new Map,Pe={},Fe=e=>{Pe=e},ze=async()=>{let e=Object.entries(Pe).map(async([r,o])=>{let s=await Promise.all(o.map(async t=>{try{if(t instanceof CSSStyleSheet)return t;let a=await fetch(t);if(!a.ok)throw new Error(`Status ${a.status}`);let i=await a.text(),n=new CSSStyleSheet;return await n.replace(i),n}catch(a){return console.error(`[Lego] Failed to load stylesheet: ${t}`,a),null}}));Re.set(r,s.filter(t=>t!==null))});await Promise.all(e),m.debug&&console.log("[Lego Debug] Re-applying stylesheets to",_.size,"blocks"),_.forEach(r=>{pe(r)})},pe=e=>{if(!e.shadowRoot&&!e._legoShadow)return;let r=e.shadowRoot||e._legoShadow,o=e.tagName.toLowerCase(),s=y[o],t=(s&&s.getAttribute("b-stylesheets")||"").split(/\s+/).filter(Boolean),a=(e.getAttribute("b-stylesheets")||"").split(/\s+/).filter(Boolean),i=[],n=e.parentElement||(e.getRootNode?e.getRootNode().host:null);for(;n;){let u=(n.getAttribute("b-cascade")||"").split(/\s+/).filter(Boolean);u.length&&i.push(...u);let f=n.tagName?n.tagName.toLowerCase():"";if(y[f]){let g=(y[f].getAttribute("b-cascade")||"").split(/\s+/).filter(Boolean);g.length&&i.push(...g)}n=n.parentElement||n.getRootNode&&n.getRootNode().host}let c=[...new Set([...t,...a])],l=[...new Set(i)],d=[...new Set([...l,...c])];if(d.length>0){let u=d.flatMap(f=>Re.get(f)||[]);u.length>0&&m.debug&&console.log("[Lego Debug] Applying styles to",e.tagName,"- Names:",d,"- Sheets:",u.length),u.length>0&&(r.adoptedStyleSheets=[...u])}e._studsMeta={stylesheets:{explicit:c,inherited:l,applied:d}}};var S=e=>{if(m.debug&&console.log("[Lego Trace] snap() called for:",e.tagName),!e||e.nodeType!==Node.ELEMENT_NODE)return;let r=M(e),o=e.tagName.toLowerCase(),s=y[o];if(s&&!r.snapped){r.snapped=!0;let a=s.content.cloneNode(!0),i=e.shadowRoot;i?i.innerHTML="":i=e.attachShadow({mode:"open"}),pe(e);let n=F(e,"*")||F(e.getRootNode().host,"*"),c=n&&n.state?n.state:{},l=R.get(o)||{},d=le(s.getAttribute("b-logic")||"{}"),u=le(e.getAttribute("b-logic")||"{}",c),f={$vars:{},$element:e,get $parent(){return F(e,"*")},$emit:(h,w)=>{e.dispatchEvent(new CustomEvent(h,{detail:w,bubbles:!0,composed:!0}))},get $route(){return N.$route},get $go(){return N.$go}};P(l,f),P(d,f),P(u,f),e._studs=z(f,e),Object.defineProperty(e,"state",{get(){return this._studs},set(h){Object.assign(this._studs,h)},configurable:!0,enumerable:!1}),i.appendChild(a);let g=i.querySelector("style");g&&(g.textContent=g.textContent.replace(/\bself\b/g,":host")),se(i,e),_.add(e),H(e),e.setAttribute("b-id",o);let b=i.querySelectorAll("*");if(m.debug&&console.log("[Lego Debug] Nested scan in",e.tagName,"- Found elements:",b.length),b.forEach(h=>{let w=h.tagName.toLowerCase(),p=!!y[w];p&&m.debug&&console.log("[Lego Debug] Checking",w,"- Registered:",p),p&&S(h)}),e._legoShadow||(e._legoShadow=i),typeof e._studs.mounted=="function")try{e._studs.mounted.call(e._studs)}catch(h){W(h,e,"mounted")}}let t=e.parentElement;for(;t&&!t._studs;)t=t.parentElement;t&&t._studs&&se(e,t),[...e.children].forEach(S)},A=e=>{if(e._studs&&typeof e._studs.unmounted=="function")try{e._studs.unmounted.call(e._studs)}catch(o){W(o,e,"unmounted")}e.shadowRoot&&[...e.shadowRoot.children].forEach(A),_.delete(e),q.delete(e),e._studs&&(e._studs.$element=null,e._studs.$vars&&(Object.keys(e._studs.$vars).forEach(o=>{e._studs.$vars[o]=null}),e._studs.$vars=null),e._studs.$emit&&(e._studs.$emit=null),delete e._studs.$parent,delete e._studs.$route,delete e._studs.$go,e._studs=null),e.hasOwnProperty("state")&&delete e.state;let r=D.get(e);if(r&&(r.bindings&&(r.bindings.forEach(o=>{let s=G[o.type];if(s&&s.destroy)try{s.destroy({binding:o})}catch(t){console.error(`[Lego] Error in directive cleanup (${o.type}):`,t)}o.node=null,o.anchor=null}),r.bindings=null),r.anchor=null,D.delete(e)),C.has(e)){let o=C.get(e);o.forEach((s,t)=>{s&&s._studs&&(s._studs=null)}),o.clear(),C.delete(e)}[...e.children].forEach(A)};function We(e,r="block.lego"){let o={template:"",script:"",style:"",stylesAttr:"",cascadeAttr:"",errorAttr:"",blockName:be(r)},s=e,t=/<(template|script|style)\b((?:\s+(?:[^>"']|"[^"]*"|'[^']*')*)*)>/i;for(;s;){let a=s.match(t);if(!a)break;let i=a[1].toLowerCase(),n=a[2],c=a[0],l=a.index,d=`</${i}>`,u=l+c.length,f=s.indexOf(d,u);if(f===-1){console.warn(`[Lego] Unclosed <${i}> tag in ${r}`);break}let g=s.slice(u,f);if(i==="template"){o.template=g.trim();let b=n.match(/b-stylesheets=["']([^"']+)["']/);b&&(o.stylesAttr=b[1]);let h=n.match(/b-cascade=["']([^"']+)["']/);h&&(o.cascadeAttr=h[1]);let w=n.match(/b-error=["']([^"']+)["']/);w&&(o.errorAttr=w[1])}else if(i==="script"){o.script=g.trim();let b=n.match(/lang=["']([^"']+)["']/);b&&(o.scriptLang=b[1])}else i==="style"&&(o.style=g.trim());s=s.slice(f+d.length)}return o}var He=(e,r,o="block.lego")=>{let s=We(r,o),{blockName:t,template:a,script:i,style:n,stylesAttr:c,cascadeAttr:l,errorAttr:d}=s,u={};if(i)try{let g=i.trim(),b=g.match(/export\s+default\s+({[\s\S]*})/),h=b?b[1]:g;u=new Function("Lego","$db",`return ${h}`)(e,e.globals.$db)}catch(g){m.onError(g,"script",t)}let f=a;n&&(f=`<style>${n}</style>`+f),y[t]=document.createElement("template"),y[t].innerHTML=f,c&&y[t].setAttribute("b-stylesheets",c),l&&y[t].setAttribute("b-cascade",l),d&&y[t].setAttribute("b-error",d),R.set(t,u),document.querySelectorAll(t).forEach(g=>!M(g).snapped&&S(g))};re.setHandler(H);De(S,H);Ee(S);var Xe={url:typeof window<"u"?window.location.pathname:"/",route:"",params:{},query:{},method:"GET",body:null},k=z({$route:Xe,$go:(e,...r)=>te(e,...r)(document.body),$db:fe},typeof document<"u"?document.body:null);he(k);var v={db:fe,snap:S,unsnap:A,defineLegoFile:(e,r)=>He(v,e,r),block:(e,r,o={},s="",t="",a="")=>{let i=document.createElement("template");i.setAttribute("b-id",e),i.setAttribute("b-stylesheets",s),t&&i.setAttribute("b-cascade",t),a&&i.setAttribute("b-error",a),i.innerHTML=r,y[e]=i,R.set(e,o);try{let n={};P(o,n),Q.set(e.toLowerCase(),z(n,document.body))}catch(n){m.onError(n,"define",e)}if(customElements.get(e))document.querySelectorAll(e).forEach(n=>{A(n),S(n)}),_.forEach(n=>{n._legoShadow&&n._legoShadow.querySelectorAll(e).forEach(c=>{A(c),S(c)})});else try{customElements.define(e,class extends HTMLElement{connectedCallback(){y[e]&&S(this)}disconnectedCallback(){A(this)}})}catch(n){console.warn(`[Lego] Failed to register web component ${e}:`,n)}},getActiveBlocksCount:()=>_.size,getLegos:()=>Object.keys(y),config:m,globals:k,route:(e,r,o=null)=>{let s=[],t=e==="*"?".*":e;t=t.replace(/:([^\/]+)/g,(a,i)=>(s.push(i),"([^/]+)")),K.push({path:e,regex:new RegExp(`^${t}$`),tagName:r,paramNames:s,middleware:o})},debug:{stylesheets:e=>!e||!e._studsMeta?null:e._studsMeta.stylesheets},init:async(e=document.body,r={})=>{if((!e||typeof e.nodeType!="number")&&(e=document.body),Fe(r.styles||{}),m.loader=r.loader,m.debug=r.debug===!0,await ze(),K.length>0){let t=window.location.pathname,a=window.location.search,i=ce(t);if(i){let{match:n,params:c}=i,l=Object.fromEntries(new URLSearchParams(a));k.$route.url=t+a,k.$route.route=n.path,k.$route.params=c,k.$route.query=l,k.$route.method="GET",k.$route.body=null}}document.querySelectorAll("template[b-id]").forEach(t=>{let a=t.getAttribute("b-id");y[a]=t,customElements.get(a)||customElements.define(a,class extends HTMLElement{connectedCallback(){y[a]&&S(this)}disconnectedCallback(){A(this)}})});let o=t=>{if(!t)return{};let a={};return Object.entries(t).forEach(([i,n])=>{if(typeof n=="function")a[i]=n();else if(typeof n=="string"&&n.startsWith("$db.")){let c=n.slice(4);a[i]=v.db(c).get()}else if(typeof n=="string"&&n.startsWith("$globals.")){let c=n.slice(9);a[i]=N[c]}else a[i]=n}),a},s=(t,a,i={})=>{customElements.get(t)||customElements.define(t,class extends HTMLElement{async connectedCallback(){if(y[t]){S(this);return}if(v._fetching||(v._fetching=new Set),!v._fetching.has(t)){v._fetching.add(t);try{let n=a.startsWith("POST:")?"POST":"GET",c=a.replace(/^POST:/,""),l=o(i.headers),d={method:n,headers:l,credentials:i.credentials},f=await(await fetch(c,d)).text();v.defineLegoFile(f,`${t}.lego`),y[t]&&S(this)}catch(n){console.error(`[Lego] Failed to load manifest block ${t}:`,n)}finally{v._fetching.delete(t)}}}disconnectedCallback(){A(this)}})};if(r.manifest){let t=r.manifest;if(t.url&&typeof t.url=="string")try{let i=o(t.headers);t=await(await fetch(t.url,{headers:i,credentials:t.credentials})).json()}catch(i){console.error("[Lego] Failed to load manifest:",i),t=[]}else if(typeof t=="string")try{t=await(await fetch(t)).json()}catch(i){console.error("[Lego] Failed to load manifest:",i),t=[]}let a=Array.isArray(t)?t:[t];for(let i of a){let n=i.base||"",c=i.suffix===!0?".lego":i.suffix||"",l={headers:i.headers||{},credentials:i.credentials};i.legos&&i.legos.forEach(d=>{s(d,`${n}${d}${c}`,l)}),i.map&&Object.entries(i.map).forEach(([d,u])=>{let f=u.match(/^https?:|^\//)?u:`${n}${u}`;s(d,f,l)})}}if(m.loader){let t=n=>{if(n.nodeType!==Node.ELEMENT_NODE)return;let c=n.tagName.toLowerCase();if(c.includes("-")&&!y[c]&&!_.has(n)){if(v._fetching&&v._fetching.has(c))return;v._fetching||(v._fetching=new Set),v._fetching.add(c);let l=m.loader(c);if(l){let d=typeof l=="string"?fetch(l).then(u=>u.text()):l;Promise.resolve(d).then(u=>{v.defineLegoFile(u,`${c}.lego`),v._fetching.delete(c)}).catch(u=>{console.error(`[Lego] Failed to load ${c}:`,u),v._fetching.delete(c)})}}if(n.children.length>0){let l=n.firstElementChild;for(;l;)t(l),l=l.nextElementSibling}};new MutationObserver(n=>n.forEach(c=>{c.addedNodes.forEach(t)})).observe(e,{childList:!0,subtree:!0});let i=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT);for(;i.nextNode();)t(i.currentNode)}if(r.studio){if(!y["lego-studio"]){let t=document.createElement("script");t.src="https://unpkg.com/@legodom/studio@0.0.2/dist/lego-studio.js",t.onerror=()=>console.warn("[Lego] Failed to load Studio from CDN"),document.head.appendChild(t)}v.route("/_/studio","lego-studio"),v.route("/_/studio/:block","lego-studio")}K.length>0&&(window.addEventListener("popstate",t=>{let a=t.state?.legoTargets||null;ee(a)}),document.addEventListener("submit",t=>{t.preventDefault()}),document.addEventListener("click",t=>{let i=t.composedPath().find(n=>n.tagName==="A"&&(n.hasAttribute("b-target")||n.hasAttribute("b-link")));if(i){t.preventDefault();let n=i.getAttribute("href"),c=i.getAttribute("b-target"),l=c?c.split(/\s+/).filter(Boolean):[],d=i.getAttribute("b-link")!=="false";k.$go(n,...l).get(d)}}),ee()),Be()}};typeof window<"u"?window.Lego=v:typeof global<"u"&&(global.Lego=v);var ho=v;export{v as Lego,ho as default};
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -60,27 +60,36 @@ const Lego = {
|
|
|
60
60
|
config.onError(e, 'define', tagName);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
activeBlocks.forEach(block => {
|
|
75
|
-
if (block._legoShadow) {
|
|
76
|
-
block._legoShadow.querySelectorAll(tagName).forEach(instance => {
|
|
77
|
-
if (!getPrivateData(instance).snapped) {
|
|
78
|
-
if (config.debug) console.log('[Lego Debug] Lazy-initializing', tagName, 'in', block.tagName);
|
|
79
|
-
snap(instance);
|
|
63
|
+
if (!customElements.get(tagName)) {
|
|
64
|
+
try {
|
|
65
|
+
customElements.define(tagName, class extends HTMLElement {
|
|
66
|
+
connectedCallback() {
|
|
67
|
+
// Defer if not yet registered (shouldn't happen via Lego.block, but good safety)
|
|
68
|
+
if (registry[tagName]) snap(this);
|
|
69
|
+
}
|
|
70
|
+
disconnectedCallback() {
|
|
71
|
+
unsnap(this);
|
|
80
72
|
}
|
|
81
73
|
});
|
|
74
|
+
} catch (e) {
|
|
75
|
+
console.warn(`[Lego] Failed to register web component ${tagName}:`, e);
|
|
82
76
|
}
|
|
83
|
-
}
|
|
77
|
+
} else {
|
|
78
|
+
// HMR or Re-definition: manually upgrade existing instances
|
|
79
|
+
document.querySelectorAll(tagName).forEach(el => {
|
|
80
|
+
unsnap(el);
|
|
81
|
+
snap(el);
|
|
82
|
+
});
|
|
83
|
+
// Also catch instances in shadow roots
|
|
84
|
+
activeBlocks.forEach(block => {
|
|
85
|
+
if (block._legoShadow) {
|
|
86
|
+
block._legoShadow.querySelectorAll(tagName).forEach(instance => {
|
|
87
|
+
unsnap(instance);
|
|
88
|
+
snap(instance);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
84
93
|
},
|
|
85
94
|
getActiveBlocksCount: () => activeBlocks.size,
|
|
86
95
|
getLegos: () => Object.keys(registry),
|
|
@@ -127,41 +136,195 @@ const Lego = {
|
|
|
127
136
|
}
|
|
128
137
|
}
|
|
129
138
|
|
|
139
|
+
// 5. Register inline templates
|
|
130
140
|
document.querySelectorAll('template[b-id]').forEach(t => {
|
|
131
|
-
|
|
141
|
+
const tagName = t.getAttribute('b-id');
|
|
142
|
+
registry[tagName] = t;
|
|
143
|
+
|
|
144
|
+
if (!customElements.get(tagName)) {
|
|
145
|
+
customElements.define(tagName, class extends HTMLElement {
|
|
146
|
+
connectedCallback() {
|
|
147
|
+
if (registry[tagName]) snap(this);
|
|
148
|
+
}
|
|
149
|
+
disconnectedCallback() {
|
|
150
|
+
unsnap(this);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
132
154
|
});
|
|
133
155
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
156
|
+
// 6. Process Manifest (Pre-registration for Shadow DOM support)
|
|
157
|
+
const resolveHeaders = (headers) => {
|
|
158
|
+
if (!headers) return {};
|
|
159
|
+
const resolved = {};
|
|
160
|
+
Object.entries(headers).forEach(([key, val]) => {
|
|
161
|
+
if (typeof val === 'function') {
|
|
162
|
+
resolved[key] = val();
|
|
163
|
+
} else if (typeof val === 'string' && val.startsWith('$db.')) {
|
|
164
|
+
// $db.auth.token
|
|
165
|
+
const path = val.slice(4);
|
|
166
|
+
// Simple get from persistence layer
|
|
167
|
+
resolved[key] = Lego.db(path).get();
|
|
168
|
+
} else if (typeof val === 'string' && val.startsWith('$globals.')) {
|
|
169
|
+
// $globals.user.token
|
|
170
|
+
const keyPath = val.slice(9);
|
|
171
|
+
resolved[key] = globalsTarget[keyPath];
|
|
172
|
+
} else {
|
|
173
|
+
resolved[key] = val;
|
|
148
174
|
}
|
|
149
|
-
}
|
|
175
|
+
});
|
|
176
|
+
return resolved;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const registerLazy = (tagName, url, config = {}) => {
|
|
180
|
+
if (customElements.get(tagName)) return;
|
|
181
|
+
|
|
182
|
+
customElements.define(tagName, class extends HTMLElement {
|
|
183
|
+
async connectedCallback() {
|
|
184
|
+
if (registry[tagName]) {
|
|
185
|
+
snap(this);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (!Lego._fetching) Lego._fetching = new Set();
|
|
190
|
+
if (Lego._fetching.has(tagName)) return;
|
|
191
|
+
Lego._fetching.add(tagName);
|
|
192
|
+
|
|
193
|
+
try {
|
|
194
|
+
const method = url.startsWith('POST:') ? 'POST' : 'GET';
|
|
195
|
+
const cleanUrl = url.replace(/^POST:/, '');
|
|
196
|
+
|
|
197
|
+
// Resolve headers at runtime (just-in-time)
|
|
198
|
+
const headers = resolveHeaders(config.headers);
|
|
199
|
+
|
|
200
|
+
const fetchOpts = {
|
|
201
|
+
method,
|
|
202
|
+
headers,
|
|
203
|
+
credentials: config.credentials
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const req = await fetch(cleanUrl, fetchOpts);
|
|
207
|
+
const content = await req.text();
|
|
208
|
+
|
|
209
|
+
Lego.defineLegoFile(content, `${tagName}.lego`);
|
|
210
|
+
|
|
211
|
+
if (registry[tagName]) snap(this);
|
|
212
|
+
} catch (e) {
|
|
213
|
+
console.error(`[Lego] Failed to load manifest block ${tagName}:`, e);
|
|
214
|
+
} finally {
|
|
215
|
+
Lego._fetching.delete(tagName);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
disconnectedCallback() {
|
|
219
|
+
unsnap(this);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
150
222
|
};
|
|
151
223
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
224
|
+
if (options.manifest) {
|
|
225
|
+
let m = options.manifest;
|
|
226
|
+
|
|
227
|
+
// 1. Check for Object with URL (Auth Manifest)
|
|
228
|
+
if (m.url && typeof m.url === 'string') {
|
|
229
|
+
try {
|
|
230
|
+
const headers = resolveHeaders(m.headers);
|
|
231
|
+
const r = await fetch(m.url, { headers, credentials: m.credentials });
|
|
232
|
+
m = await r.json();
|
|
233
|
+
} catch (e) {
|
|
234
|
+
console.error('[Lego] Failed to load manifest:', e);
|
|
235
|
+
m = [];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// 2. Check for String URL (Public Manifest)
|
|
239
|
+
else if (typeof m === 'string') {
|
|
240
|
+
try {
|
|
241
|
+
const r = await fetch(m);
|
|
242
|
+
m = await r.json();
|
|
243
|
+
} catch (e) {
|
|
244
|
+
console.error('[Lego] Failed to load manifest:', e);
|
|
245
|
+
m = [];
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Normalize to array
|
|
250
|
+
const groups = Array.isArray(m) ? m : [m];
|
|
251
|
+
|
|
252
|
+
for (const group of groups) {
|
|
253
|
+
const base = group.base || '';
|
|
254
|
+
const suffix = group.suffix === true ? '.lego' : (group.suffix || '');
|
|
255
|
+
|
|
256
|
+
const config = {
|
|
257
|
+
headers: group.headers || {},
|
|
258
|
+
credentials: group.credentials
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
// 1. Array style: legos: ['name']
|
|
262
|
+
if (group.legos) {
|
|
263
|
+
group.legos.forEach(name => {
|
|
264
|
+
registerLazy(name, `${base}${name}${suffix}`, config);
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
// 2. Map style: map: { 'name': 'url' }
|
|
268
|
+
if (group.map) {
|
|
269
|
+
Object.entries(group.map).forEach(([name, url]) => {
|
|
270
|
+
const fullUrl = url.match(/^https?:|^\//) ? url : `${base}${url}`;
|
|
271
|
+
registerLazy(name, fullUrl, config);
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Auto-Discovery: Watch for unknown tags to lazy-load (HTMX-style / Server Blocks)
|
|
278
|
+
if (config.loader) {
|
|
279
|
+
const discover = (n) => {
|
|
280
|
+
if (n.nodeType !== Node.ELEMENT_NODE) return;
|
|
281
|
+
const tagName = n.tagName.toLowerCase();
|
|
282
|
+
if (tagName.includes('-') && !registry[tagName] && !activeBlocks.has(n)) {
|
|
283
|
+
// Check if we are already fetching this tag to avoid dupes
|
|
284
|
+
if (Lego._fetching && Lego._fetching.has(tagName)) return;
|
|
285
|
+
|
|
286
|
+
if (!Lego._fetching) Lego._fetching = new Set();
|
|
287
|
+
Lego._fetching.add(tagName);
|
|
288
|
+
|
|
289
|
+
const result = config.loader(tagName);
|
|
290
|
+
if (result) {
|
|
291
|
+
const promise = (typeof result === 'string')
|
|
292
|
+
? fetch(result).then(r => r.text())
|
|
293
|
+
: result;
|
|
157
294
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
295
|
+
Promise.resolve(promise)
|
|
296
|
+
.then(legoFile => {
|
|
297
|
+
Lego.defineLegoFile(legoFile, `${tagName}.lego`);
|
|
298
|
+
Lego._fetching.delete(tagName);
|
|
299
|
+
})
|
|
300
|
+
.catch(e => {
|
|
301
|
+
console.error(`[Lego] Failed to load ${tagName}:`, e);
|
|
302
|
+
Lego._fetching.delete(tagName);
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
// Recursively check children for other unknown blocks
|
|
307
|
+
if (n.children.length > 0) {
|
|
308
|
+
// Use lightweight iteration
|
|
309
|
+
let child = n.firstElementChild;
|
|
310
|
+
while (child) {
|
|
311
|
+
discover(child);
|
|
312
|
+
child = child.nextElementSibling;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
};
|
|
161
316
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
317
|
+
const discoveryObserver = new MutationObserver(m => m.forEach(r => {
|
|
318
|
+
r.addedNodes.forEach(discover);
|
|
319
|
+
}));
|
|
320
|
+
|
|
321
|
+
// Observe with subtree to catch deep injections
|
|
322
|
+
discoveryObserver.observe(root, { childList: true, subtree: true });
|
|
323
|
+
|
|
324
|
+
// Initial scan
|
|
325
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
|
326
|
+
while (walker.nextNode()) discover(walker.currentNode);
|
|
327
|
+
}
|
|
165
328
|
|
|
166
329
|
if (options.studio) {
|
|
167
330
|
if (!registry['lego-studio']) {
|