@elenajs/core 1.0.0-rc.6 → 1.0.0-rc.8

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/bundle.js CHANGED
@@ -1,2 +1,6 @@
1
- function t(t,s,e){if(s="boolean"===t&&"boolean"!=typeof s?null!==s:s,!e)return s;if("toAttribute"===e)switch(t){case"object":case"array":return null===s?null:JSON.stringify(s);case"boolean":return s?"":null;case"number":return null===s?null:s;default:return""===s?null:s}else switch(t){case"object":case"array":if(!s)return s;try{return JSON.parse(s)}catch{return console.warn("░█ [ELENA]: Invalid JSON: "+s),null}case"boolean":return s;case"number":return null!==s?+s:s;default:return s??""}}function s(t,s,e){t?null===e?t.removeAttribute(s):t.setAttribute(s,e):console.warn("░█ [ELENA]: Cannot sync attrs.")}const e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};function i(t){return Array.isArray(t)?t.map(t=>n(t)).join(""):n(t)}function n(t){return t?.t?String(t):(s=String(t??""),String(s).replace(/[&<>"']/g,t=>e[t]));var s}function o(t,...s){let e;return{t:!0,strings:t,values:s,toString:()=>(void 0===e&&(e=t.reduce((t,e,n)=>t+e+i(s[n]),"")),e)}}function r(t){return{t:!0,toString:()=>t??""}}const h=Object.freeze({t:!0,toString:()=>""}),c=t=>Array.isArray(t)?t.some(t=>t?.t):t?.t,u=t=>Array.isArray(t)?t.map(t=>String(t??"")).join(""):String(t??"");function l(t){return t.replace(/>\n\s*/g,">").replace(/\n\s*</g,"<").replace(/\n\s*/g," ").replace(/>\s+</g,"><")}const a=new WeakMap,f="e"+Math.random().toString(36).slice(2,6);function d(t,s,e){return!function(t,s,e){if(t.i!==s||!t.o)return!1;for(let s=0;s<e.length;s++){const i=e[s],n=Array.isArray(i)?u(i):i;if(n!==t.h[s]){if(c(i)||!t.o[s])return!1;t.h[s]=n,t.o[s].textContent=u(i)}}return!0}(t,s,e)&&(function(t,s,e){let n=a.get(s);if(!n){const t=Array.from(s,l);n={processedStrings:t,template:e.length>0?p(t,e.length):null},a.set(s,n)}if(n.template)t.o=function(t,s,e){const n=s.content.cloneNode(!0),o=document.createTreeWalker(n,NodeFilter.SHOW_COMMENT),r=new Array(e.length),h=[];let l;for(;l=o.nextNode();)l.data===f&&h.push(l);for(let t=0;t<h.length;t++){const s=e[t];if(c(s)){const e=document.createElement("template");e.innerHTML=i(s),h[t].parentNode.replaceChild(e.content,h[t])}else{const e=document.createTextNode(u(s));h[t].parentNode.replaceChild(e,h[t]),r[t]=e}}return t.replaceChildren(n),r}(t,n.template,e);else{const s=e.map(t=>i(t)),o=n.processedStrings.reduce((t,e,i)=>t+e+(s[i]??""),"").replace(/>\s+</g,"><").trim(),r=document.createElement("template");r.innerHTML=o,y(t,r.content.childNodes),t.o=null}t.i=s,t.h=e.map(t=>Array.isArray(t)?u(t):t)}(t,s,e),!0)}function p(t,s){const e=`\x3c!--${f}--\x3e`,i=t.reduce((t,i,n)=>t+i+(n<s?e:""),"").trim(),n=document.createElement("template");n.innerHTML=i;const o=document.createTreeWalker(n.content,NodeFilter.SHOW_COMMENT);let r=0;for(;o.nextNode();)o.currentNode.data===f&&r++;return r===s?n:null}function y(t,s){const e=Array.from(t.childNodes),i=Array.from(s),n=Math.max(e.length,i.length);for(let s=0;s<n;s++){const n=e[s],o=i[s];n?o?n.nodeType!==o.nodeType||n.nodeType===Node.ELEMENT_NODE&&n.tagName!==o.tagName?t.replaceChild(o,n):n.nodeType===Node.TEXT_NODE?n.textContent!==o.textContent&&(n.textContent=o.textContent):n.nodeType===Node.ELEMENT_NODE&&(g(n,o),y(n,o.childNodes)):t.removeChild(n):t.appendChild(o)}}function g(t,s){for(let e=t.attributes.length-1;e>=0;e--){const{name:i}=t.attributes[e];s.hasAttribute(i)||t.removeAttribute(i)}for(let e=0;e<s.attributes.length;e++){const{name:i,value:n}=s.attributes[e];t.getAttribute(i)!==n&&t.setAttribute(i,n)}}const b=new WeakSet;function m(e){return class extends e{element=null;attributeChangedCallback(s,e,i){super.attributeChangedCallback?.(s,e,i),"text"!==s?(this.u=!0,function(s,e,i,n){if(i!==n){const i=typeof s[e];"undefined"===i&&console.warn(`░█ [ELENA]: Prop "${e}" has no default.`);const o=t(i,n,"toProp");s[e]=o}}(this,s,e,i),this.u=!1,this.l&&e!==i&&!this.p&&this.m()):this.text=i??""}static get observedAttributes(){if(this.A)return this.A;const t=(this.props||[]).map(t=>"string"==typeof t?t:t.name);return this.A=[...t,"text"],this.A}connectedCallback(){super.connectedCallback?.(),this.S(),this.N(),this._(),this.v(),this.willUpdate(),this.C(),this.L(),this.k(),this.l||(this.l=!0,this.setAttribute("hydrated",""),this.firstUpdated()),this.updated()}S(){const e=this.constructor;if(b.has(e))return;const i=new Set,n=[];if(e.props){for(const t of e.props)"string"==typeof t?n.push(t):(n.push(t.name),!1===t.reflect&&i.add(t.name));n.includes("text")&&console.warn('░█ [ELENA]: "text" is reserved.'),function(e,i,n){for(const o of i){const i=!n||!n.has(o);Object.defineProperty(e,o,{configurable:!0,enumerable:!0,get(){return this.O?this.O.get(o):void 0},set(e){if(this.O||(this.O=new Map),e!==this.O.get(o)&&(this.O.set(o,e),this.isConnected))if(i){if(!this.u){const i=t(typeof e,e,"toAttribute");s(this,o,i)}}else this.l&&!this.p&&this.m()}})}}(e.prototype,n,i)}if(e.j=n,e.P=i,e.M=e.events||null,e.M)for(const t of e.M)Object.prototype.hasOwnProperty.call(e.prototype,t)||(e.prototype[t]=function(...s){return this.element[t](...s)});var o;e.U=(o=e.element)?t=>t.querySelector(o):t=>t.firstElementChild,b.add(e)}N(){this.u=!0;for(const t of this.constructor.j)if(Object.prototype.hasOwnProperty.call(this,t)){const s=this[t];delete this[t],this[t]=s}this.u=!1}_(){this.l||void 0!==this.q||(this.text=this.textContent.trim())}get F(){return this.J??this.shadowRoot??this}v(){const t=this.constructor;if(!t.shadow)return;this.J||this.shadowRoot||(this.J=this.attachShadow({mode:t.shadow}));const s=this.J??this.shadowRoot;if(t.styles){if(!t.R){const s=Array.isArray(t.styles)?t.styles:[t.styles];t.R=s.map(t=>{if("string"==typeof t){const s=new CSSStyleSheet;return s.replaceSync(t),s}return t})}s.adoptedStyleSheets=t.R}}C(){const t=this.render();if(t&&t.strings){const s=this.F;if(d(s,t.strings,t.values)){const t=this.element;if(this.element=this.constructor.U(s),this.W&&t&&this.element!==t){const s=this.constructor.M;for(const e of s)t.removeEventListener(e,this),this.element.addEventListener(e,this)}}}if(!this.element){const t=this.F;this.element=this.constructor.U(t),this.element||(this.constructor.element&&console.warn("░█ [ELENA]: Element not found."),this.element=t.firstElementChild)}}L(){if(this.O){const e=this.constructor.P;for(const[i,n]of this.O){if(e.has(i))continue;const o=t(typeof n,n,"toAttribute");(null!==o||this.hasAttribute(i))&&s(this,i,o)}}}k(){const t=this.constructor.M;if(!this.W&&t?.length)if(this.element){this.W=!0;for(const s of t)this.element.addEventListener(s,this)}else console.warn("░█ [ELENA]: Cannot add events.")}render(){}willUpdate(){}firstUpdated(){}updated(){}adoptedCallback(){super.adoptedCallback?.()}disconnectedCallback(){if(super.disconnectedCallback?.(),this.W){this.W=!1;for(const t of this.constructor.M)this.element?.removeEventListener(t,this)}}handleEvent(t){this.constructor.M?.includes(t.type)&&(t.bubbles&&(t.composed||this.F===this)||this.dispatchEvent(new Event(t.type,{bubbles:t.bubbles})))}get text(){return this.q??""}set text(t){const s=this.q;this.q=t,this.l&&s!==t&&!this.p&&this.m()}static define(){var t,s;this.tagName?(t=this.tagName,s=this,"undefined"!=typeof window&&"customElements"in window&&(window.customElements.get(t)||window.customElements.define(t,s))):console.warn("░█ [ELENA]: define() without a tagName.")}m(){this.p||this.$||(this.$=!0,this.D=new Promise(t=>{this.I=t}),queueMicrotask(()=>{try{this.T()}catch(t){console.error("░█ [ELENA]:",t)}}))}T(){this.$=!1;const t=this.I;this.I=null;try{try{this.willUpdate(),this.p=!0,this.C()}finally{this.p=!1}this.updated()}finally{this.D=null,t()}}get updateComplete(){return this.D?this.D:Promise.resolve()}requestUpdate(){this.l&&!this.p&&this.m()}}}export{m as Elena,o as html,h as nothing,r as unsafeHTML};
2
- //# sourceMappingURL=bundle.js.map
1
+ /**
2
+ * @elenajs/core v1.0.0-rc.8
3
+ * (c) 2025-present Ariel Salminen and Elena contributors
4
+ * @license MIT
5
+ */
6
+ const t="░█ [ELENA]: ",s=Array.isArray,i=s=>console.warn(t+s),e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};function n(t){return s(t)?t.map(o).join(""):o(t)}function o(t){return t?.t?String(t):String(t??"").replace(/[&<>"']/g,t=>e[t])}function r(t,...s){let i;return{t:!0,strings:t,values:s,toString:()=>(null==i&&(i=t.reduce((t,i,e)=>t+i+n(s[e]),"")),i)}}function h(t){return{t:!0,toString:()=>t??""}}const c={t:!0,toString:()=>""},u=t=>s(t)?t.some(t=>t?.t):t?.t,f=t=>s(t)?t.join(""):String(t??"");function l(t){return t.replace(/(>)\n\s*|\n\s*(<)/g,"$1$2").replace(/\n\s*/g," ").replace(/>\s+</g,"><")}function a(t,s,e){if(s="boolean"===t&&"boolean"!=typeof s?null!==s:s,!e)return s;if("toAttribute"===e)switch(t){case"object":case"array":return s&&JSON.stringify(s);case"boolean":return s?"":null;default:return""===s?null:s}else switch(t){case"object":case"array":if(!s)return s;try{return JSON.parse(s)}catch{return i("Invalid JSON: "+s),null}case"number":return null!==s?+s:s;default:return s??""}}function d(t,s,e){t?null===e?t.removeAttribute(s):t.setAttribute(s,e):i("Cannot sync attrs.")}const p=new WeakMap,g="e"+(1e5*Math.random()|0),b=()=>document.createElement("template"),y=t=>document.createTreeWalker(t,128);function m(t,i,e){return!function(t,i,e){if(t.i!==i||!t.o)return!1;for(let i=0;i<e.length;i++){const n=e[i],o=s(n)?f(n):n;if(o!==t.h[i]){if(u(n)||!t.o[i])return!1;t.h[i]=o,t.o[i].textContent=f(n)}}return!0}(t,i,e)&&(function(t,i,e){let o=p.get(i);if(!o){const t=i.map(l);o={u:t,l:e.length>0?S(t,e.length):null},p.set(i,o)}if(o.l)t.o=function(t,s,i){const e=s.content.cloneNode(!0),o=y(e),r=Array(i.length),h=[];let c;for(;c=o.nextNode();)c.data===g&&h.push(c);for(let t=0;t<h.length;t++){const s=i[t];if(u(s)){const i=b();i.innerHTML=n(s),h[t].parentNode.replaceChild(i.content,h[t])}else{const i=document.createTextNode(f(s));h[t].parentNode.replaceChild(i,h[t]),r[t]=i}}return t.replaceChildren(e),r}(t,o.l,e);else{const s=e.map(n),i=o.u.reduce((t,i,e)=>t+i+(s[e]??""),"").replace(/>\s+</g,"><").trim(),r=b();r.innerHTML=i,_(t,r.content.childNodes),t.o=null}t.i=i,t.h=e.map(t=>s(t)?f(t):t)}(t,i,e),!0)}function S(t,s){const i=`\x3c!--${g}--\x3e`,e=t.reduce((t,e,n)=>t+e+(n<s?i:""),"").trim(),n=b();n.innerHTML=e;const o=y(n.content);let r=0;for(;o.nextNode();)o.currentNode.data===g&&r++;return r===s?n:null}function _(t,s){const i=Array.from(t.childNodes),e=Array.from(s),n=Math.max(i.length,e.length);for(let s=0;s<n;s++){const n=i[s],o=e[s];n?o?n.nodeType!==o.nodeType||1===n.nodeType&&n.tagName!==o.tagName?t.replaceChild(o,n):3===n.nodeType?n.textContent!==o.textContent&&(n.textContent=o.textContent):1===n.nodeType&&(w(n,o),_(n,o.childNodes)):t.removeChild(n):t.appendChild(o)}}function w(t,s){for(let i=t.attributes.length-1;i>=0;i--){const{name:e}=t.attributes[i];s.hasAttribute(e)||t.removeAttribute(e)}for(let i=0;i<s.attributes.length;i++){const{name:e,value:n}=s.attributes[i];t.getAttribute(e)!==n&&t.setAttribute(e,n)}}const v=new WeakSet,x=(t,s)=>Object.prototype.hasOwnProperty.call(t,s);function C(s){return class extends s{element=null;attributeChangedCallback(t,s,e){super.attributeChangedCallback?.(t,s,e),"text"!==t?(this.p=!0,function(t,s,e,n){if(e!==n){const e=typeof t[s];"undefined"===e&&i(`Prop "${s}" has no default.`);const o=a(e,n,"toProp");t[s]=o}}(this,t,s,e),this.p=!1,this.m&&s!==e&&!this.S&&this._()):this.text=e??""}static get observedAttributes(){if(this.v)return this.v;const t=(this.props||[]).map(t=>"string"==typeof t?t:t.name);return this.v=[...t,"text"],this.v}connectedCallback(){super.connectedCallback?.(),this.C(),this.A(),this.m||void 0!==this.k||(this.text=this.textContent.trim()),this.P(),this.willUpdate(),this.M(),this.N(),this.O(),this.m||(this.m=!0,this.setAttribute("hydrated",""),this.firstUpdated()),this.updated()}C(){const t=this.constructor;if(v.has(t))return;const s=new Set,e=[];if(t.props){for(const i of t.props)"string"==typeof i?e.push(i):(e.push(i.name),!1===i.reflect&&s.add(i.name));e.includes("text")&&i('"text" is reserved.'),function(t,s,i){for(const e of s){const s=!i||!i.has(e);Object.defineProperty(t,e,{configurable:!0,enumerable:!0,get(){return this.j?.get(e)},set(t){if(this.j||(this.j=new Map),t!==this.j.get(e)&&(this.j.set(e,t),this.isConnected))if(s){if(!this.p){const s=a(typeof t,t,"toAttribute");d(this,e,s)}}else this.m&&!this.S&&this._()}})}}(t.prototype,e,s)}if(t.U=e,t.$=s,t.q=t.events||null,t.q)for(const s of t.q)x(t.prototype,s)||(t.prototype[s]=function(...t){return this.element[s](...t)});var n;t.J=(n=t.element)?t=>t.querySelector(n):t=>t.firstElementChild,v.add(t)}A(){this.p=!0;for(const t of this.constructor.U)if(x(this,t)){const s=this[t];delete this[t],this[t]=s}this.p=!1}get R(){return this.W??this.shadowRoot??this}P(){const t=this.constructor;if(!t.shadow)return;this.W||this.shadowRoot||(this.W=this.attachShadow({mode:t.shadow}));const s=this.W??this.shadowRoot;if(t.styles){if(!t.D){const s=[t.styles].flat();t.D=s.map(t=>{if("string"==typeof t){const s=new CSSStyleSheet;return s.replaceSync(t),s}return t})}s.adoptedStyleSheets=t.D}}M(){const t=this.constructor,s=this.R,e=this.render();if(e&&e.strings&&m(s,e.strings,e.values)){const i=this.element;if(this.element=t.J(s),this.F&&i&&this.element!==i){const s=t.q;for(const t of s)i.removeEventListener(t,this),this.element.addEventListener(t,this)}}this.element||(this.element=t.J(s),this.element||(t.element&&i("Element not found."),this.element=s.firstElementChild))}N(){if(this.j){const t=this.constructor.$;for(const[s,i]of this.j){if(t.has(s))continue;const e=a(typeof i,i,"toAttribute");(null!==e||this.hasAttribute(s))&&d(this,s,e)}}}O(){const t=this.constructor.q;if(!this.F&&t?.length)if(this.element){this.F=!0;for(const s of t)this.element.addEventListener(s,this)}else i("Cannot add events.")}render(){}willUpdate(){}firstUpdated(){}updated(){}adoptedCallback(){super.adoptedCallback?.()}disconnectedCallback(){if(super.disconnectedCallback?.(),this.F){this.F=!1;for(const t of this.constructor.q)this.element?.removeEventListener(t,this)}}handleEvent(t){this.constructor.q?.includes(t.type)&&(t.bubbles&&(t.composed||this.R===this)||this.dispatchEvent(new Event(t.type,{bubbles:t.bubbles})))}get text(){return this.k??""}set text(t){const s=this.k;this.k=t,this.m&&s!==t&&!this.S&&this._()}static define(){const t=this.tagName;t?function(t,s){const i=globalThis.customElements;i?.get(t)||i?.define(t,s)}(t,this):i("define() without a tagName.")}_(){this.S||this.I||(this.I=!0,this.L=new Promise(t=>{this.T=t}),queueMicrotask(()=>{try{this.B()}catch(s){console.error(t,s)}}))}B(){this.I=!1;const t=this.T;this.T=null;try{try{this.willUpdate(),this.S=!0,this.M()}finally{this.S=!1}this.updated()}finally{this.L=null,t()}}get updateComplete(){return this.L||Promise.resolve()}requestUpdate(){this.m&&!this.S&&this._()}}}export{C as Elena,r as html,c as nothing,h as unsafeHTML};
@@ -1 +1 @@
1
- {"version":3,"file":"props.d.ts","sourceRoot":"","sources":["../../src/common/props.js"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,mCAJW,MAAM,SACN,GAAG,cACH,aAAa,GAAG,QAAQ,OAwClC;AAED;;;;;;GAMG;AACH,uCAJW,OAAO,QACP,MAAM,SACN,MAAM,GAAG,IAAI,QAYvB;AAED;;;;;;;;GAQG;AACH,qDAHW,MAAM,EAAE,cACR,GAAG,CAAC,MAAM,CAAC,QAsCrB;AAED;;;;;;;;GAQG;AACH,kCALW,MAAM,QACN,MAAM,YACN,GAAG,YACH,GAAG,QAWb"}
1
+ {"version":3,"file":"props.d.ts","sourceRoot":"","sources":["../../src/common/props.js"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,mCAJW,MAAM,SACN,GAAG,cACH,aAAa,GAAG,QAAQ,OAqClC;AAED;;;;;;GAMG;AACH,uCAJW,OAAO,QACP,MAAM,SACN,MAAM,GAAG,IAAI,QAYvB;AAED;;;;;;;;GAQG;AACH,qDAHW,MAAM,EAAE,cACR,GAAG,CAAC,MAAM,CAAC,QAsCrB;AAED;;;;;;;;GAQG;AACH,kCALW,MAAM,QACN,MAAM,YACN,GAAG,YACH,GAAG,QAWb"}
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/common/render.js"],"names":[],"mappings":"AAKA;;;;;;;;;GASG;AACH,wCALW,WAAW,WACX,oBAAoB,kBAElB,OAAO,CAQnB"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/common/render.js"],"names":[],"mappings":"AAWA;;;;;;;;;GASG;AACH,wCALW,WAAW,WACX,oBAAoB,kBAElB,OAAO,CAQnB"}
@@ -45,6 +45,7 @@ export function unsafeHTML(str: string): {
45
45
  * @returns {string}
46
46
  */
47
47
  export function collapseWhitespace(string: string): string;
48
+ export function warn(msg: string): void;
48
49
  /**
49
50
  * A placeholder you can return from a conditional expression
50
51
  * inside a template to render nothing.
@@ -57,4 +58,6 @@ export const nothing: {
57
58
  };
58
59
  export function isRaw(value: any): boolean;
59
60
  export function toPlainText(value: any): string;
61
+ export const prefix: "\u2591\u2588 [ELENA]: ";
62
+ export const isArray: (arg: any) => arg is any[];
60
63
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/common/utils.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,uCAHW,MAAM,2BAShB;AASD,6CAEC;AAED;;;;;;GAMG;AACH,oCAHW,GAAC,GACC,MAAM,CAOlB;AAaD;;;;;;;GAOG;AACH,8BAJW,oBAAoB,aACjB,GAAC,EAAA,GACF;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,oBAAoB,CAAC;IAAC,MAAM,QAAQ;IAAC,QAAQ,IAAI,MAAM,CAAA;CAAE,CAiB7F;AAED;;;;;GAKG;AACH,gCAHW,MAAM,GACJ;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,IAAI,MAAM,CAAA;CAAE,CAI/C;AA4BD;;;;;GAKG;AACH,2CAHW,MAAM,GACJ,MAAM,CAQlB;AAtCD;;;;;GAKG;AACH,sBAFU;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,IAAI,MAAM,CAAA;CAAE,CAE6B;AAQnE,6BAHI,GAAC,GACC,OAAO,CAGmD;AAQhE,mCAHI,GAAC,GACC,MAAM,CAG0E"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/common/utils.js"],"names":[],"mappings":"AAUA;;;;;GAKG;AACH,uCAHW,MAAM,2BAMhB;AASD,6CAEC;AAED;;;;;;GAMG;AACH,oCAHW,GAAC,GACC,MAAM,CAOlB;AAaD;;;;;;;GAOG;AACH,8BAJW,oBAAoB,aACjB,GAAC,EAAA,GACF;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,oBAAoB,CAAC;IAAC,MAAM,QAAQ;IAAC,QAAQ,IAAI,MAAM,CAAA;CAAE,CAiB7F;AAED;;;;;GAKG;AACH,gCAHW,MAAM,GACJ;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,IAAI,MAAM,CAAA;CAAE,CAI/C;AA0BD;;;;;GAKG;AACH,2CAHW,MAAM,GACJ,MAAM,CAOlB;AAxHM,0BAHI,MAAM,QAGoC;AAqFrD;;;;;GAKG;AACH,sBAFU;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,IAAI,MAAM,CAAA;CAAE,CAEc;AAQpD,6BAHI,GAAC,GACC,OAAO,CAE2E;AAQxF,mCAHI,GAAC,GACC,MAAM,CAEwE;AAlH3F,qBAAe,wBAAc,CAAC;AAC9B,iDAA8B"}
@@ -1 +1 @@
1
- {"version":3,"file":"elena.d.ts","sourceRoot":"","sources":["../src/elena.js"],"names":[],"mappings":"AAiEA;;;;;;;;;GASG;AACH,kCAHW,gBAAgB,GACd,uBAAuB,CAwenC;+BA3gBY,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,WAAW;mCAInC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAAC,MAAM,IAAI,IAAI,CAAC;IAAC,UAAU,IAAI,IAAI,CAAC;IAAC,YAAY,IAAI,IAAI,CAAC;IAAC,OAAO,IAAI,IAAI,CAAC;IAAC,iBAAiB,IAAI,IAAI,CAAC;IAAC,oBAAoB,IAAI,IAAI,CAAA;CAAE;8BAIjL;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE;sCAInC,CAAC,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,WAAW,GAAG,oBAAoB,CAAC,GAAG;IACvE,MAAM,IAAI,IAAI,CAAC;IACnB,QAAY,CAAC,kBAAkB,EAAE,MAAM,EAAE,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,CAAC,MAAM,GAAG,eAAe,CAAC,EAAE,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC3B,MAAM,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,CAAC,aAAa,GAAG,MAAM,CAAC,EAAE,CAAC;CAC9D;qBA5CqD,mBAAmB;2BAAnB,mBAAmB;wBAAnB,mBAAmB"}
1
+ {"version":3,"file":"elena.d.ts","sourceRoot":"","sources":["../src/elena.js"],"names":[],"mappings":"AAkEA;;;;;;;;;GASG;AACH,kCAHW,gBAAgB,GACd,uBAAuB,CA6dnC;+BAjgBY,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,WAAW;mCAInC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAAC,MAAM,IAAI,IAAI,CAAC;IAAC,UAAU,IAAI,IAAI,CAAC;IAAC,YAAY,IAAI,IAAI,CAAC;IAAC,OAAO,IAAI,IAAI,CAAC;IAAC,iBAAiB,IAAI,IAAI,CAAC;IAAC,oBAAoB,IAAI,IAAI,CAAA;CAAE;8BAIjL;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE;sCAInC,CAAC,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,WAAW,GAAG,oBAAoB,CAAC,GAAG;IACvE,MAAM,IAAI,IAAI,CAAC;IACnB,QAAY,CAAC,kBAAkB,EAAE,MAAM,EAAE,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,CAAC,MAAM,GAAG,eAAe,CAAC,EAAE,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC3B,MAAM,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,CAAC,aAAa,GAAG,MAAM,CAAC,EAAE,CAAC;CAC9D;qBA5CmE,mBAAmB;2BAAnB,mBAAmB;wBAAnB,mBAAmB"}
package/dist/elena.js CHANGED
@@ -1,2 +1,6 @@
1
- import{getProps as t,setProps as e,getPropValue as s,syncAttribute as n}from"./props.js";import{defineElement as i}from"./utils.js";export{html,nothing,unsafeHTML}from"./utils.js";import{renderTemplate as r}from"./render.js";const o=new WeakSet;function h(h){return class extends h{element=null;attributeChangedCallback(e,s,n){super.attributeChangedCallback?.(e,s,n),"text"!==e?(this._syncing=!0,t(this,e,s,n),this._syncing=!1,this._hydrated&&s!==n&&!this._isRendering&&this._safeRender()):this.text=n??""}static get observedAttributes(){if(this._observedAttrs)return this._observedAttrs;const t=(this.props||[]).map(t=>"string"==typeof t?t:t.name);return this._observedAttrs=[...t,"text"],this._observedAttrs}connectedCallback(){super.connectedCallback?.(),this._setupStaticProps(),this._captureClassFieldDefaults(),this._captureText(),this._attachShadow(),this.willUpdate(),this._applyRender(),this._syncProps(),this._delegateEvents(),this._hydrated||(this._hydrated=!0,this.setAttribute("hydrated",""),this.firstUpdated()),this.updated()}_setupStaticProps(){const t=this.constructor;if(o.has(t))return;const s=new Set,n=[];if(t.props){for(const e of t.props)"string"==typeof e?n.push(e):(n.push(e.name),!1===e.reflect&&s.add(e.name));n.includes("text")&&console.warn('░█ [ELENA]: "text" is reserved.'),e(t.prototype,n,s)}if(t._propNames=n,t._noReflect=s,t._elenaEvents=t.events||null,t._elenaEvents)for(const e of t._elenaEvents)Object.prototype.hasOwnProperty.call(t.prototype,e)||(t.prototype[e]=function(...t){return this.element[e](...t)});var i;t._resolver=(i=t.element)?t=>t.querySelector(i):t=>t.firstElementChild,o.add(t)}_captureClassFieldDefaults(){this._syncing=!0;for(const t of this.constructor._propNames)if(Object.prototype.hasOwnProperty.call(this,t)){const e=this[t];delete this[t],this[t]=e}this._syncing=!1}_captureText(){this._hydrated||void 0!==this._text||(this.text=this.textContent.trim())}get _renderRoot(){return this._shadow??this.shadowRoot??this}_attachShadow(){const t=this.constructor;if(!t.shadow)return;this._shadow||this.shadowRoot||(this._shadow=this.attachShadow({mode:t.shadow}));const e=this._shadow??this.shadowRoot;if(t.styles){if(!t._adoptedSheets){const e=Array.isArray(t.styles)?t.styles:[t.styles];t._adoptedSheets=e.map(t=>{if("string"==typeof t){const e=new CSSStyleSheet;return e.replaceSync(t),e}return t})}e.adoptedStyleSheets=t._adoptedSheets}}_applyRender(){const t=this.render();if(t&&t.strings){const e=this._renderRoot;if(r(e,t.strings,t.values)){const t=this.element;if(this.element=this.constructor._resolver(e),this._events&&t&&this.element!==t){const e=this.constructor._elenaEvents;for(const s of e)t.removeEventListener(s,this),this.element.addEventListener(s,this)}}}if(!this.element){const t=this._renderRoot;this.element=this.constructor._resolver(t),this.element||(this.constructor.element&&console.warn("░█ [ELENA]: Element not found."),this.element=t.firstElementChild)}}_syncProps(){if(this._props){const t=this.constructor._noReflect;for(const[e,i]of this._props){if(t.has(e))continue;const r=s(typeof i,i,"toAttribute");(null!==r||this.hasAttribute(e))&&n(this,e,r)}}}_delegateEvents(){const t=this.constructor._elenaEvents;if(!this._events&&t?.length)if(this.element){this._events=!0;for(const e of t)this.element.addEventListener(e,this)}else console.warn("░█ [ELENA]: Cannot add events.")}render(){}willUpdate(){}firstUpdated(){}updated(){}adoptedCallback(){super.adoptedCallback?.()}disconnectedCallback(){if(super.disconnectedCallback?.(),this._events){this._events=!1;for(const t of this.constructor._elenaEvents)this.element?.removeEventListener(t,this)}}handleEvent(t){this.constructor._elenaEvents?.includes(t.type)&&(t.bubbles&&(t.composed||this._renderRoot===this)||this.dispatchEvent(new Event(t.type,{bubbles:t.bubbles})))}get text(){return this._text??""}set text(t){const e=this._text;this._text=t,this._hydrated&&e!==t&&!this._isRendering&&this._safeRender()}static define(){this.tagName?i(this.tagName,this):console.warn("░█ [ELENA]: define() without a tagName.")}_safeRender(){this._isRendering||this._renderPending||(this._renderPending=!0,this._updateComplete=new Promise(t=>{this._resolveUpdate=t}),queueMicrotask(()=>{try{this._performUpdate()}catch(t){console.error("░█ [ELENA]:",t)}}))}_performUpdate(){this._renderPending=!1;const t=this._resolveUpdate;this._resolveUpdate=null;try{try{this.willUpdate(),this._isRendering=!0,this._applyRender()}finally{this._isRendering=!1}this.updated()}finally{this._updateComplete=null,t()}}get updateComplete(){return this._updateComplete?this._updateComplete:Promise.resolve()}requestUpdate(){this._hydrated&&!this._isRendering&&this._safeRender()}}}export{h as Elena};
2
- //# sourceMappingURL=elena.js.map
1
+ /**
2
+ * @elenajs/core v1.0.0-rc.8
3
+ * (c) 2025-present Ariel Salminen and Elena contributors
4
+ * @license MIT
5
+ */
6
+ import{getProps as t,setProps as e,getPropValue as s,syncAttribute as i}from"./props.js";import{warn as n,defineElement as r,prefix as o}from"./utils.js";export{html,nothing,unsafeHTML}from"./utils.js";import{renderTemplate as h}from"./render.js";const a=new WeakSet,d=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);function l(l){return class extends l{element=null;attributeChangedCallback(e,s,i){super.attributeChangedCallback?.(e,s,i),"text"!==e?(this._syncing=!0,t(this,e,s,i),this._syncing=!1,this._hydrated&&s!==i&&!this._isRendering&&this._safeRender()):this.text=i??""}static get observedAttributes(){if(this._observedAttrs)return this._observedAttrs;const t=(this.props||[]).map(t=>"string"==typeof t?t:t.name);return this._observedAttrs=[...t,"text"],this._observedAttrs}connectedCallback(){super.connectedCallback?.(),this._setupStaticProps(),this._captureClassFieldDefaults(),this._hydrated||void 0!==this._text||(this.text=this.textContent.trim()),this._attachShadow(),this.willUpdate(),this._applyRender(),this._syncProps(),this._delegateEvents(),this._hydrated||(this._hydrated=!0,this.setAttribute("hydrated",""),this.firstUpdated()),this.updated()}_setupStaticProps(){const t=this.constructor;if(a.has(t))return;const s=new Set,i=[];if(t.props){for(const e of t.props)"string"==typeof e?i.push(e):(i.push(e.name),!1===e.reflect&&s.add(e.name));i.includes("text")&&n('"text" is reserved.'),e(t.prototype,i,s)}if(t._propNames=i,t._noReflect=s,t._elenaEvents=t.events||null,t._elenaEvents)for(const e of t._elenaEvents)d(t.prototype,e)||(t.prototype[e]=function(...t){return this.element[e](...t)});var r;t._resolver=(r=t.element)?t=>t.querySelector(r):t=>t.firstElementChild,a.add(t)}_captureClassFieldDefaults(){this._syncing=!0;for(const t of this.constructor._propNames)if(d(this,t)){const e=this[t];delete this[t],this[t]=e}this._syncing=!1}get _renderRoot(){return this._shadow??this.shadowRoot??this}_attachShadow(){const t=this.constructor;if(!t.shadow)return;this._shadow||this.shadowRoot||(this._shadow=this.attachShadow({mode:t.shadow}));const e=this._shadow??this.shadowRoot;if(t.styles){if(!t._adoptedSheets){const e=[t.styles].flat();t._adoptedSheets=e.map(t=>{if("string"==typeof t){const e=new CSSStyleSheet;return e.replaceSync(t),e}return t})}e.adoptedStyleSheets=t._adoptedSheets}}_applyRender(){const t=this.constructor,e=this._renderRoot,s=this.render();if(s&&s.strings&&h(e,s.strings,s.values)){const s=this.element;if(this.element=t._resolver(e),this._events&&s&&this.element!==s){const e=t._elenaEvents;for(const t of e)s.removeEventListener(t,this),this.element.addEventListener(t,this)}}this.element||(this.element=t._resolver(e),this.element||(t.element&&n("Element not found."),this.element=e.firstElementChild))}_syncProps(){if(this._props){const t=this.constructor._noReflect;for(const[e,n]of this._props){if(t.has(e))continue;const r=s(typeof n,n,"toAttribute");(null!==r||this.hasAttribute(e))&&i(this,e,r)}}}_delegateEvents(){const t=this.constructor._elenaEvents;if(!this._events&&t?.length)if(this.element){this._events=!0;for(const e of t)this.element.addEventListener(e,this)}else n("Cannot add events.")}render(){}willUpdate(){}firstUpdated(){}updated(){}adoptedCallback(){super.adoptedCallback?.()}disconnectedCallback(){if(super.disconnectedCallback?.(),this._events){this._events=!1;for(const t of this.constructor._elenaEvents)this.element?.removeEventListener(t,this)}}handleEvent(t){this.constructor._elenaEvents?.includes(t.type)&&(t.bubbles&&(t.composed||this._renderRoot===this)||this.dispatchEvent(new Event(t.type,{bubbles:t.bubbles})))}get text(){return this._text??""}set text(t){const e=this._text;this._text=t,this._hydrated&&e!==t&&!this._isRendering&&this._safeRender()}static define(){const t=this.tagName;t?r(t,this):n("define() without a tagName.")}_safeRender(){this._isRendering||this._renderPending||(this._renderPending=!0,this._updateComplete=new Promise(t=>{this._resolveUpdate=t}),queueMicrotask(()=>{try{this._performUpdate()}catch(t){console.error(o,t)}}))}_performUpdate(){this._renderPending=!1;const t=this._resolveUpdate;this._resolveUpdate=null;try{try{this.willUpdate(),this._isRendering=!0,this._applyRender()}finally{this._isRendering=!1}this.updated()}finally{this._updateComplete=null,t()}}get updateComplete(){return this._updateComplete||Promise.resolve()}requestUpdate(){this._hydrated&&!this._isRendering&&this._safeRender()}}}export{l as Elena};
package/dist/props.js CHANGED
@@ -1,2 +1 @@
1
- function t(t,e,n){if(e="boolean"===t&&"boolean"!=typeof e?null!==e:e,!n)return e;if("toAttribute"===n)switch(t){case"object":case"array":return null===e?null:JSON.stringify(e);case"boolean":return e?"":null;case"number":return null===e?null:e;default:return""===e?null:e}else switch(t){case"object":case"array":if(!e)return e;try{return JSON.parse(e)}catch{return console.warn("░█ [ELENA]: Invalid JSON: "+e),null}case"boolean":return e;case"number":return null!==e?+e:e;default:return e??""}}function e(t,e,n){t?null===n?t.removeAttribute(e):t.setAttribute(e,n):console.warn("░█ [ELENA]: Cannot sync attrs.")}function n(n,r,s){for(const o of r){const r=!s||!s.has(o);Object.defineProperty(n,o,{configurable:!0,enumerable:!0,get(){return this._props?this._props.get(o):void 0},set(n){if(this._props||(this._props=new Map),n!==this._props.get(o)&&(this._props.set(o,n),this.isConnected))if(r){if(!this._syncing){const r=t(typeof n,n,"toAttribute");e(this,o,r)}}else this._hydrated&&!this._isRendering&&this._safeRender()}})}}function r(e,n,r,s){if(r!==s){const r=typeof e[n];"undefined"===r&&console.warn(`░█ [ELENA]: Prop "${n}" has no default.`);const o=t(r,s,"toProp");e[n]=o}}export{t as getPropValue,r as getProps,n as setProps,e as syncAttribute};
2
- //# sourceMappingURL=props.js.map
1
+ import{warn as t}from"./utils.js";function e(e,n,r){if(n="boolean"===e&&"boolean"!=typeof n?null!==n:n,!r)return n;if("toAttribute"===r)switch(e){case"object":case"array":return n&&JSON.stringify(n);case"boolean":return n?"":null;default:return""===n?null:n}else switch(e){case"object":case"array":if(!n)return n;try{return JSON.parse(n)}catch{return t("Invalid JSON: "+n),null}case"number":return null!==n?+n:n;default:return n??""}}function n(e,n,r){e?null===r?e.removeAttribute(n):e.setAttribute(n,r):t("Cannot sync attrs.")}function r(t,r,s){for(const o of r){const r=!s||!s.has(o);Object.defineProperty(t,o,{configurable:!0,enumerable:!0,get(){return this._props?.get(o)},set(t){if(this._props||(this._props=new Map),t!==this._props.get(o)&&(this._props.set(o,t),this.isConnected))if(r){if(!this._syncing){const r=e(typeof t,t,"toAttribute");n(this,o,r)}}else this._hydrated&&!this._isRendering&&this._safeRender()}})}}function s(n,r,s,o){if(s!==o){const s=typeof n[r];"undefined"===s&&t(`Prop "${r}" has no default.`);const i=e(s,o,"toProp");n[r]=i}}export{e as getPropValue,s as getProps,r as setProps,n as syncAttribute};
package/dist/render.js CHANGED
@@ -1,2 +1 @@
1
- import{toPlainText as e,isRaw as t,collapseWhitespace as n,resolveValue as r}from"./utils.js";const o=new WeakMap,l="e"+Math.random().toString(36).slice(2,6);function a(a,i,d){return!function(n,r,o){if(n._tplStrings!==r||!n._tplParts)return!1;for(let r=0;r<o.length;r++){const l=o[r],a=Array.isArray(l)?e(l):l;if(a!==n._tplValues[r]){if(t(l)||!n._tplParts[r])return!1;n._tplValues[r]=a,n._tplParts[r].textContent=e(l)}}return!0}(a,i,d)&&(function(a,i,d){let u=o.get(i);if(!u){const e=Array.from(i,n);u={processedStrings:e,template:d.length>0?c(e,d.length):null},o.set(i,u)}if(u.template)a._tplParts=function(n,o,a){const c=o.content.cloneNode(!0),s=document.createTreeWalker(c,NodeFilter.SHOW_COMMENT),i=new Array(a.length),d=[];let u;for(;u=s.nextNode();)u.data===l&&d.push(u);for(let n=0;n<d.length;n++){const o=a[n];if(t(o)){const e=document.createElement("template");e.innerHTML=r(o),d[n].parentNode.replaceChild(e.content,d[n])}else{const t=document.createTextNode(e(o));d[n].parentNode.replaceChild(t,d[n]),i[n]=t}}return n.replaceChildren(c),i}(a,u.template,d);else{const e=d.map(e=>r(e)),t=u.processedStrings.reduce((t,n,r)=>t+n+(e[r]??""),"").replace(/>\s+</g,"><").trim(),n=document.createElement("template");n.innerHTML=t,s(a,n.content.childNodes),a._tplParts=null}a._tplStrings=i,a._tplValues=d.map(t=>Array.isArray(t)?e(t):t)}(a,i,d),!0)}function c(e,t){const n=`\x3c!--${l}--\x3e`,r=e.reduce((e,r,o)=>e+r+(o<t?n:""),"").trim(),o=document.createElement("template");o.innerHTML=r;const a=document.createTreeWalker(o.content,NodeFilter.SHOW_COMMENT);let c=0;for(;a.nextNode();)a.currentNode.data===l&&c++;return c===t?o:null}function s(e,t){const n=Array.from(e.childNodes),r=Array.from(t),o=Math.max(n.length,r.length);for(let t=0;t<o;t++){const o=n[t],l=r[t];o?l?o.nodeType!==l.nodeType||o.nodeType===Node.ELEMENT_NODE&&o.tagName!==l.tagName?e.replaceChild(l,o):o.nodeType===Node.TEXT_NODE?o.textContent!==l.textContent&&(o.textContent=l.textContent):o.nodeType===Node.ELEMENT_NODE&&(i(o,l),s(o,l.childNodes)):e.removeChild(o):e.appendChild(l)}}function i(e,t){for(let n=e.attributes.length-1;n>=0;n--){const{name:r}=e.attributes[n];t.hasAttribute(r)||e.removeAttribute(r)}for(let n=0;n<t.attributes.length;n++){const{name:r,value:o}=t.attributes[n];e.getAttribute(r)!==o&&e.setAttribute(r,o)}}export{a as renderTemplate};
2
- //# sourceMappingURL=render.js.map
1
+ import{isArray as t,toPlainText as e,isRaw as n,collapseWhitespace as r,resolveValue as o}from"./utils.js";const a=new WeakMap,l="e"+(1e5*Math.random()|0),c=()=>document.createElement("template"),s=t=>document.createTreeWalker(t,128);function i(i,p,d){return!function(r,o,a){if(r._templateStrings!==o||!r._templateParts)return!1;for(let o=0;o<a.length;o++){const l=a[o],c=t(l)?e(l):l;if(c!==r._templateValues[o]){if(n(l)||!r._templateParts[o])return!1;r._templateValues[o]=c,r._templateParts[o].textContent=e(l)}}return!0}(i,p,d)&&(function(i,p,d){let f=a.get(p);if(!f){const t=p.map(r);f={_strings:t,_template:d.length>0?u(t,d.length):null},a.set(p,f)}if(f._template)i._templateParts=function(t,r,a){const i=r.content.cloneNode(!0),u=s(i),m=Array(a.length),p=[];let d;for(;d=u.nextNode();)d.data===l&&p.push(d);for(let t=0;t<p.length;t++){const r=a[t];if(n(r)){const e=c();e.innerHTML=o(r),p[t].parentNode.replaceChild(e.content,p[t])}else{const n=document.createTextNode(e(r));p[t].parentNode.replaceChild(n,p[t]),m[t]=n}}return t.replaceChildren(i),m}(i,f._template,d);else{const t=d.map(o),e=f._strings.reduce((e,n,r)=>e+n+(t[r]??""),"").replace(/>\s+</g,"><").trim(),n=c();n.innerHTML=e,m(i,n.content.childNodes),i._templateParts=null}i._templateStrings=p,i._templateValues=d.map(n=>t(n)?e(n):n)}(i,p,d),!0)}function u(t,e){const n=`\x3c!--${l}--\x3e`,r=t.reduce((t,r,o)=>t+r+(o<e?n:""),"").trim(),o=c();o.innerHTML=r;const a=s(o.content);let i=0;for(;a.nextNode();)a.currentNode.data===l&&i++;return i===e?o:null}function m(t,e){const n=Array.from(t.childNodes),r=Array.from(e),o=Math.max(n.length,r.length);for(let e=0;e<o;e++){const o=n[e],a=r[e];o?a?o.nodeType!==a.nodeType||1===o.nodeType&&o.tagName!==a.tagName?t.replaceChild(a,o):3===o.nodeType?o.textContent!==a.textContent&&(o.textContent=a.textContent):1===o.nodeType&&(p(o,a),m(o,a.childNodes)):t.removeChild(o):t.appendChild(a)}}function p(t,e){for(let n=t.attributes.length-1;n>=0;n--){const{name:r}=t.attributes[n];e.hasAttribute(r)||t.removeAttribute(r)}for(let n=0;n<e.attributes.length;n++){const{name:r,value:o}=e.attributes[n];t.getAttribute(r)!==o&&t.setAttribute(r,o)}}export{i as renderTemplate};
package/dist/utils.js CHANGED
@@ -1,2 +1 @@
1
- function n(n,r){"undefined"!=typeof window&&"customElements"in window&&(window.customElements.get(n)||window.customElements.define(n,r))}const r={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};function t(n){return String(n).replace(/[&<>"']/g,n=>r[n])}function e(n){return Array.isArray(n)?n.map(n=>i(n)).join(""):i(n)}function i(n){return n?.__raw?String(n):t(String(n??""))}function o(n,...r){let t;return{__raw:!0,strings:n,values:r,toString:()=>(void 0===t&&(t=n.reduce((n,t,i)=>n+t+e(r[i]),"")),t)}}function a(n){return{__raw:!0,toString:()=>n??""}}const u=Object.freeze({__raw:!0,toString:()=>""}),c=n=>Array.isArray(n)?n.some(n=>n?.__raw):n?.__raw,s=n=>Array.isArray(n)?n.map(n=>String(n??"")).join(""):String(n??"");function g(n){return n.replace(/>\n\s*/g,">").replace(/\n\s*</g,"<").replace(/\n\s*/g," ").replace(/>\s+</g,"><")}export{g as collapseWhitespace,n as defineElement,t as escapeHtml,o as html,c as isRaw,u as nothing,e as resolveValue,s as toPlainText,a as unsafeHTML};
2
- //# sourceMappingURL=utils.js.map
1
+ const n="░█ [ELENA]: ",r=Array.isArray,t=r=>console.warn(n+r);function e(n,r){const t=globalThis.customElements;t?.get(n)||t?.define(n,r)}const o={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};function i(n){return String(n).replace(/[&<>"']/g,n=>o[n])}function c(n){return r(n)?n.map(u).join(""):u(n)}function u(n){return n?.__raw?String(n):i(n??"")}function a(n,...r){let t;return{__raw:!0,strings:n,values:r,toString:()=>(null==t&&(t=n.reduce((n,t,e)=>n+t+c(r[e]),"")),t)}}function s(n){return{__raw:!0,toString:()=>n??""}}const g={__raw:!0,toString:()=>""},l=n=>r(n)?n.some(n=>n?.__raw):n?.__raw,_=n=>r(n)?n.join(""):String(n??"");function f(n){return n.replace(/(>)\n\s*|\n\s*(<)/g,"$1$2").replace(/\n\s*/g," ").replace(/>\s+</g,"><")}export{f as collapseWhitespace,e as defineElement,i as escapeHtml,a as html,r as isArray,l as isRaw,g as nothing,n as prefix,c as resolveValue,_ as toPlainText,s as unsafeHTML,t as warn};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elenajs/core",
3
- "version": "1.0.0-rc.6",
3
+ "version": "1.0.0-rc.8",
4
4
  "description": "Elena is a simple, tiny library for building Progressive Web Components.",
5
5
  "author": "Elena <hi@elenajs.com>",
6
6
  "homepage": "https://elenajs.com/",
@@ -56,5 +56,5 @@
56
56
  "typescript": "5.9.3",
57
57
  "vitest": "4.1.0"
58
58
  },
59
- "gitHead": "92b3eb5194bc1855201915d896fa37a88b6dd190"
59
+ "gitHead": "1ed3381ee856296e0fa92ff863447843e8a51957"
60
60
  }
@@ -1,3 +1,5 @@
1
+ import { warn } from "./utils.js";
2
+
1
3
  /**
2
4
  * Get the value of the Elena Element property.
3
5
  *
@@ -14,11 +16,10 @@ export function getPropValue(type, value, transform) {
14
16
  switch (type) {
15
17
  case "object":
16
18
  case "array":
17
- return value === null ? null : JSON.stringify(value);
19
+ return value && JSON.stringify(value);
18
20
  case "boolean":
19
21
  return value ? "" : null;
20
- case "number":
21
- return value === null ? null : value;
22
+ // number, string:
22
23
  default:
23
24
  return value === "" ? null : value;
24
25
  }
@@ -32,11 +33,9 @@ export function getPropValue(type, value, transform) {
32
33
  try {
33
34
  return JSON.parse(value);
34
35
  } catch {
35
- console.warn("░█ [ELENA]: Invalid JSON: " + value);
36
+ warn("Invalid JSON: " + value);
36
37
  return null;
37
38
  }
38
- case "boolean":
39
- return value; // conversion already handled above
40
39
  case "number":
41
40
  return value !== null ? +value : value;
42
41
  default:
@@ -54,7 +53,7 @@ export function getPropValue(type, value, transform) {
54
53
  */
55
54
  export function syncAttribute(element, name, value) {
56
55
  if (!element) {
57
- console.warn("░█ [ELENA]: Cannot sync attrs.");
56
+ warn("Cannot sync attrs.");
58
57
  return;
59
58
  }
60
59
  if (value === null) {
@@ -80,7 +79,7 @@ export function setProps(proto, propNames, noReflect) {
80
79
  configurable: true,
81
80
  enumerable: true,
82
81
  get() {
83
- return this._props ? this._props.get(prop) : undefined;
82
+ return this._props?.get(prop);
84
83
  },
85
84
  set(value) {
86
85
  if (!this._props) {
@@ -124,7 +123,7 @@ export function getProps(context, name, oldValue, newValue) {
124
123
  if (oldValue !== newValue) {
125
124
  const type = typeof context[name];
126
125
  if (type === "undefined") {
127
- console.warn(`░█ [ELENA]: Prop "${name}" has no default.`);
126
+ warn(`Prop "${name}" has no default.`);
128
127
  }
129
128
  const newAttr = getPropValue(type, newValue, "toProp");
130
129
  context[name] = newAttr;
@@ -1,7 +1,13 @@
1
- import { collapseWhitespace, isRaw, resolveValue, toPlainText } from "./utils.js";
1
+ import { collapseWhitespace, isArray, isRaw, resolveValue, toPlainText } from "./utils.js";
2
2
 
3
3
  const stringsCache = new WeakMap();
4
- const markerKey = "e" + Math.random().toString(36).slice(2, 6);
4
+ const markerKey = "e" + ((Math.random() * 1e5) | 0);
5
+ const SHOW_COMMENT = 128;
6
+ const ELEMENT_NODE = 1;
7
+ const TEXT_NODE = 3;
8
+
9
+ const newTemplate = () => document.createElement("template");
10
+ const treeWalker = node => document.createTreeWalker(node, SHOW_COMMENT);
5
11
 
6
12
  /**
7
13
  * Render a tagged template into an Elena Element with DOM diffing.
@@ -31,24 +37,24 @@ export function renderTemplate(element, strings, values) {
31
37
  */
32
38
  function patchTextNodes(element, strings, values) {
33
39
  // Only works when re-rendering the same template shape
34
- if (element._tplStrings !== strings || !element._tplParts) {
40
+ if (element._templateStrings !== strings || !element._templateParts) {
35
41
  return false;
36
42
  }
37
43
 
38
44
  for (let i = 0; i < values.length; i++) {
39
45
  const v = values[i];
40
- const comparable = Array.isArray(v) ? toPlainText(v) : v;
46
+ const comparable = isArray(v) ? toPlainText(v) : v;
41
47
 
42
- if (comparable === element._tplValues[i]) {
48
+ if (comparable === element._templateValues[i]) {
43
49
  continue;
44
50
  }
45
51
 
46
- if (isRaw(v) || !element._tplParts[i]) {
52
+ if (isRaw(v) || !element._templateParts[i]) {
47
53
  return false;
48
54
  }
49
55
 
50
- element._tplValues[i] = comparable;
51
- element._tplParts[i].textContent = toPlainText(v);
56
+ element._templateValues[i] = comparable;
57
+ element._templateParts[i].textContent = toPlainText(v);
52
58
  }
53
59
 
54
60
  return true;
@@ -65,54 +71,54 @@ function fullRender(element, strings, values) {
65
71
  let entry = stringsCache.get(strings);
66
72
 
67
73
  if (!entry) {
68
- const processedStrings = Array.from(strings, collapseWhitespace);
74
+ const _strings = strings.map(collapseWhitespace);
69
75
  entry = {
70
- processedStrings,
71
- template: values.length > 0 ? createTemplate(processedStrings, values.length) : null,
76
+ _strings,
77
+ _template: values.length > 0 ? createTemplate(_strings, values.length) : null,
72
78
  };
73
79
  stringsCache.set(strings, entry);
74
80
  }
75
81
 
76
- if (entry.template) {
77
- element._tplParts = cloneAndPatch(element, entry.template, values);
82
+ if (entry._template) {
83
+ element._templateParts = cloneAndPatch(element, entry._template, values);
78
84
  } else {
79
85
  // Fallback for attribute-position values or static templates.
80
86
  // White space collapsing here protects against Vue SSR mismatches.
81
- const renderedValues = values.map(value => resolveValue(value));
82
- const markup = entry.processedStrings
87
+ const renderedValues = values.map(resolveValue);
88
+ const markup = entry._strings
83
89
  .reduce((out, str, i) => out + str + (renderedValues[i] ?? ""), "")
84
90
  .replace(/>\s+</g, "><")
85
91
  .trim();
86
92
 
87
93
  // Morph existing DOM to match new markup instead of replacing it.
88
- const tpl = document.createElement("template");
89
- tpl.innerHTML = markup;
90
- morphContent(element, tpl.content.childNodes);
91
- element._tplParts = null;
94
+ const template = newTemplate();
95
+ template.innerHTML = markup;
96
+ morphContent(element, template.content.childNodes);
97
+ element._templateParts = null;
92
98
  }
93
99
 
94
- element._tplStrings = strings;
95
- element._tplValues = values.map(v => (Array.isArray(v) ? toPlainText(v) : v));
100
+ element._templateStrings = strings;
101
+ element._templateValues = values.map(v => (isArray(v) ? toPlainText(v) : v));
96
102
  }
97
103
 
98
104
  /**
99
105
  * Build a <template> element with comment markers.
100
106
  *
101
- * @param {string[]} processedStrings - Whitespace-collapsed static parts
107
+ * @param {string[]} _strings - Whitespace-collapsed static parts
102
108
  * @param {number} valueCount - Number of dynamic values
103
109
  * @returns {HTMLTemplateElement | null}
104
110
  */
105
- function createTemplate(processedStrings, valueCount) {
111
+ function createTemplate(_strings, valueCount) {
106
112
  const marker = `<!--${markerKey}-->`;
107
- const markup = processedStrings
113
+ const markup = _strings
108
114
  .reduce((out, str, i) => out + str + (i < valueCount ? marker : ""), "")
109
115
  .trim();
110
116
 
111
- const tpl = document.createElement("template");
112
- tpl.innerHTML = markup;
117
+ const template = newTemplate();
118
+ template.innerHTML = markup;
113
119
 
114
120
  // Mismatch means this template shape cannot use the clone path.
115
- const walker = document.createTreeWalker(tpl.content, NodeFilter.SHOW_COMMENT);
121
+ const walker = treeWalker(template.content);
116
122
  let count = 0;
117
123
 
118
124
  while (walker.nextNode()) {
@@ -121,7 +127,7 @@ function createTemplate(processedStrings, valueCount) {
121
127
  }
122
128
  }
123
129
 
124
- return count === valueCount ? tpl : null;
130
+ return count === valueCount ? template : null;
125
131
  }
126
132
 
127
133
  /**
@@ -135,8 +141,8 @@ function createTemplate(processedStrings, valueCount) {
135
141
  */
136
142
  function cloneAndPatch(element, template, values) {
137
143
  const clone = template.content.cloneNode(true);
138
- const walker = document.createTreeWalker(clone, NodeFilter.SHOW_COMMENT);
139
- const parts = new Array(values.length);
144
+ const walker = treeWalker(clone);
145
+ const parts = Array(values.length);
140
146
  const markers = [];
141
147
  let node;
142
148
 
@@ -152,7 +158,7 @@ function cloneAndPatch(element, template, values) {
152
158
 
153
159
  if (isRaw(value)) {
154
160
  // Raw HTML: parse and insert as fragment
155
- const tmp = document.createElement("template");
161
+ const tmp = newTemplate();
156
162
  tmp.innerHTML = resolveValue(value);
157
163
  markers[i].parentNode.replaceChild(tmp.content, markers[i]);
158
164
 
@@ -191,14 +197,14 @@ function morphContent(parent, nextNodes) {
191
197
  parent.removeChild(cur);
192
198
  } else if (
193
199
  cur.nodeType !== nxt.nodeType ||
194
- (cur.nodeType === Node.ELEMENT_NODE && cur.tagName !== nxt.tagName)
200
+ (cur.nodeType === ELEMENT_NODE && cur.tagName !== nxt.tagName)
195
201
  ) {
196
202
  parent.replaceChild(nxt, cur);
197
- } else if (cur.nodeType === Node.TEXT_NODE) {
203
+ } else if (cur.nodeType === TEXT_NODE) {
198
204
  if (cur.textContent !== nxt.textContent) {
199
205
  cur.textContent = nxt.textContent;
200
206
  }
201
- } else if (cur.nodeType === Node.ELEMENT_NODE) {
207
+ } else if (cur.nodeType === ELEMENT_NODE) {
202
208
  morphAttributes(cur, nxt);
203
209
  morphContent(cur, nxt.childNodes);
204
210
  }
@@ -1,3 +1,13 @@
1
+ const prefix = "░█ [ELENA]: ";
2
+ const isArray = Array.isArray;
3
+
4
+ /**
5
+ * @param {string} msg
6
+ * @internal
7
+ */
8
+ export const warn = msg => console.warn(prefix + msg);
9
+ export { prefix, isArray };
10
+
1
11
  /**
2
12
  * Register the Elena Element if the browser supports it.
3
13
  *
@@ -5,11 +15,8 @@
5
15
  * @param {Function} Element
6
16
  */
7
17
  export function defineElement(tagName, Element) {
8
- if (typeof window !== "undefined" && "customElements" in window) {
9
- if (!window.customElements.get(tagName)) {
10
- window.customElements.define(tagName, Element);
11
- }
12
- }
18
+ const customElements = globalThis.customElements;
19
+ customElements?.get(tagName) || customElements?.define(tagName, Element);
13
20
  }
14
21
 
15
22
  /**
@@ -31,8 +38,8 @@ export function escapeHtml(str) {
31
38
  * @returns {string}
32
39
  */
33
40
  export function resolveValue(value) {
34
- if (Array.isArray(value)) {
35
- return value.map(item => resolveItem(item)).join("");
41
+ if (isArray(value)) {
42
+ return value.map(resolveItem).join("");
36
43
  }
37
44
  return resolveItem(value);
38
45
  }
@@ -45,7 +52,7 @@ export function resolveValue(value) {
45
52
  * @returns {string}
46
53
  */
47
54
  function resolveItem(value) {
48
- return value?.__raw ? String(value) : escapeHtml(String(value ?? ""));
55
+ return value?.__raw ? String(value) : escapeHtml(value ?? "");
49
56
  }
50
57
 
51
58
  /**
@@ -63,7 +70,7 @@ export function html(strings, ...values) {
63
70
  strings,
64
71
  values,
65
72
  toString: () => {
66
- if (str === undefined) {
73
+ if (str == null) {
67
74
  str = strings.reduce((acc, s, i) => {
68
75
  return acc + s + resolveValue(values[i]);
69
76
  }, "");
@@ -89,7 +96,7 @@ export function unsafeHTML(str) {
89
96
  *
90
97
  * @type {{ __raw: true, toString(): string }}
91
98
  */
92
- export const nothing = Object.freeze({ __raw: true, toString: () => "" });
99
+ export const nothing = { __raw: true, toString: () => "" };
93
100
 
94
101
  /**
95
102
  * Check if a value contains trusted HTML fragments.
@@ -97,8 +104,7 @@ export const nothing = Object.freeze({ __raw: true, toString: () => "" });
97
104
  * @param {*} value
98
105
  * @returns {boolean}
99
106
  */
100
- export const isRaw = value =>
101
- Array.isArray(value) ? value.some(item => item?.__raw) : value?.__raw;
107
+ export const isRaw = value => (isArray(value) ? value.some(item => item?.__raw) : value?.__raw);
102
108
 
103
109
  /**
104
110
  * Convert a value to its plain text string.
@@ -106,8 +112,7 @@ export const isRaw = value =>
106
112
  * @param {*} value
107
113
  * @returns {string}
108
114
  */
109
- export const toPlainText = value =>
110
- Array.isArray(value) ? value.map(item => String(item ?? "")).join("") : String(value ?? "");
115
+ export const toPlainText = value => (isArray(value) ? value.join("") : String(value ?? ""));
111
116
 
112
117
  /**
113
118
  * Collapse whitespace from a static string part.
@@ -117,8 +122,7 @@ export const toPlainText = value =>
117
122
  */
118
123
  export function collapseWhitespace(string) {
119
124
  return string
120
- .replace(/>\n\s*/g, ">") // newline after tag close
121
- .replace(/\n\s*</g, "<") // newline before tag open
125
+ .replace(/(>)\n\s*|\n\s*(<)/g, "$1$2") // newlines adjacent to tags
122
126
  .replace(/\n\s*/g, " ") // newline in text content, preserve word boundary
123
127
  .replace(/>\s+</g, "><"); // whitespace between tags
124
128
  }
package/src/elena.js CHANGED
@@ -13,7 +13,7 @@
13
13
  */
14
14
 
15
15
  import { setProps, getProps, getPropValue, syncAttribute } from "./common/props.js";
16
- import { defineElement, html, unsafeHTML, nothing } from "./common/utils.js";
16
+ import { defineElement, html, unsafeHTML, nothing, warn, prefix } from "./common/utils.js";
17
17
  import { renderTemplate } from "./common/render.js";
18
18
 
19
19
  export { html, unsafeHTML, nothing };
@@ -62,6 +62,7 @@ function elementResolver(selector) {
62
62
 
63
63
  // Tracks which component classes have already been set up.
64
64
  const setupRegistry = new WeakSet();
65
+ const hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key);
65
66
 
66
67
  /**
67
68
  * Creates an Elena component class by extending `superClass`.
@@ -136,7 +137,9 @@ export function Elena(superClass) {
136
137
  super.connectedCallback?.();
137
138
  this._setupStaticProps();
138
139
  this._captureClassFieldDefaults();
139
- this._captureText();
140
+ if (!this._hydrated && this._text === undefined) {
141
+ this.text = this.textContent.trim();
142
+ }
140
143
  this._attachShadow();
141
144
  this.willUpdate();
142
145
  this._applyRender();
@@ -181,7 +184,7 @@ export function Elena(superClass) {
181
184
  }
182
185
 
183
186
  if (names.includes("text")) {
184
- console.warn('░█ [ELENA]: "text" is reserved.');
187
+ warn('"text" is reserved.');
185
188
  }
186
189
 
187
190
  setProps(component.prototype, names, noRef);
@@ -193,7 +196,7 @@ export function Elena(superClass) {
193
196
 
194
197
  if (component._elenaEvents) {
195
198
  for (const e of component._elenaEvents) {
196
- if (!Object.prototype.hasOwnProperty.call(component.prototype, e)) {
199
+ if (!hasOwn(component.prototype, e)) {
197
200
  component.prototype[e] = function (...args) {
198
201
  return this.element[e](...args);
199
202
  };
@@ -215,7 +218,7 @@ export function Elena(superClass) {
215
218
  this._syncing = true;
216
219
 
217
220
  for (const name of this.constructor._propNames) {
218
- if (Object.prototype.hasOwnProperty.call(this, name)) {
221
+ if (hasOwn(this, name)) {
219
222
  const value = this[name];
220
223
  delete this[name];
221
224
  this[name] = value;
@@ -225,17 +228,6 @@ export function Elena(superClass) {
225
228
  this._syncing = false;
226
229
  }
227
230
 
228
- /**
229
- * Saves any text inside the element before the first render.
230
- *
231
- * @internal
232
- */
233
- _captureText() {
234
- if (!this._hydrated && this._text === undefined) {
235
- this.text = this.textContent.trim();
236
- }
237
- }
238
-
239
231
  /**
240
232
  * The root node to render into. Returns the shadow root when shadow mode
241
233
  * is enabled, otherwise the host element itself.
@@ -275,7 +267,7 @@ export function Elena(superClass) {
275
267
  // Normalize to array and cache converted CSSStyleSheet instances on the class.
276
268
  // Avoids re-parsing CSS strings on every element instance.
277
269
  if (!component._adoptedSheets) {
278
- const stylesList = Array.isArray(component.styles) ? component.styles : [component.styles];
270
+ const stylesList = [component.styles].flat();
279
271
 
280
272
  component._adoptedSheets = stylesList.map(s => {
281
273
  if (typeof s === "string") {
@@ -297,10 +289,11 @@ export function Elena(superClass) {
297
289
  * @internal
298
290
  */
299
291
  _applyRender() {
292
+ const constructor = this.constructor;
293
+ const root = this._renderRoot;
300
294
  const result = this.render();
301
295
 
302
296
  if (result && result.strings) {
303
- const root = this._renderRoot;
304
297
  const rebuilt = renderTemplate(root, result.strings, result.values);
305
298
 
306
299
  // Re-resolve element ref when the DOM was fully rebuilt.
@@ -308,11 +301,11 @@ export function Elena(superClass) {
308
301
  // so the existing ref is still valid.
309
302
  if (rebuilt) {
310
303
  const oldElement = this.element;
311
- this.element = this.constructor._resolver(root);
304
+ this.element = constructor._resolver(root);
312
305
 
313
306
  // Re-bind event listeners when the inner element was replaced.
314
307
  if (this._events && oldElement && this.element !== oldElement) {
315
- const events = this.constructor._elenaEvents;
308
+ const events = constructor._elenaEvents;
316
309
 
317
310
  for (const e of events) {
318
311
  oldElement.removeEventListener(e, this);
@@ -324,12 +317,11 @@ export function Elena(superClass) {
324
317
 
325
318
  // Resolve inner element on first render
326
319
  if (!this.element) {
327
- const root = this._renderRoot;
328
- this.element = this.constructor._resolver(root);
320
+ this.element = constructor._resolver(root);
329
321
 
330
322
  if (!this.element) {
331
- if (this.constructor.element) {
332
- console.warn("░█ [ELENA]: Element not found.");
323
+ if (constructor.element) {
324
+ warn("Element not found.");
333
325
  }
334
326
  this.element = root.firstElementChild;
335
327
  }
@@ -373,7 +365,7 @@ export function Elena(superClass) {
373
365
 
374
366
  if (!this._events && events?.length) {
375
367
  if (!this.element) {
376
- console.warn("░█ [ELENA]: Cannot add events.");
368
+ warn("Cannot add events.");
377
369
  } else {
378
370
  this._events = true;
379
371
 
@@ -477,10 +469,11 @@ export function Elena(superClass) {
477
469
  * not on the Elena mixin itself.
478
470
  */
479
471
  static define() {
480
- if (this.tagName) {
481
- defineElement(this.tagName, this);
472
+ const tag = this.tagName;
473
+ if (tag) {
474
+ defineElement(tag, this);
482
475
  } else {
483
- console.warn("░█ [ELENA]: define() without a tagName.");
476
+ warn("define() without a tagName.");
484
477
  }
485
478
  }
486
479
 
@@ -503,7 +496,7 @@ export function Elena(superClass) {
503
496
  try {
504
497
  this._performUpdate();
505
498
  } catch (e) {
506
- console.error("░█ [ELENA]:", e);
499
+ console.error(prefix, e);
507
500
  }
508
501
  });
509
502
  }
@@ -541,10 +534,7 @@ export function Elena(superClass) {
541
534
  * @type {Promise<void>}
542
535
  */
543
536
  get updateComplete() {
544
- if (this._updateComplete) {
545
- return this._updateComplete;
546
- }
547
- return Promise.resolve();
537
+ return this._updateComplete || Promise.resolve();
548
538
  }
549
539
 
550
540
  /**
@@ -1 +0,0 @@
1
- {"version":3,"file":"bundle.js","sources":["../src/common/props.js","../src/common/utils.js","../src/common/render.js","../src/elena.js"],"sourcesContent":["/**\n * Get the value of the Elena Element property.\n *\n * @param {string} type\n * @param {any} value\n * @param {\"toAttribute\" | \"toProp\"} [transform]\n */\nexport function getPropValue(type, value, transform) {\n value = type === \"boolean\" && typeof value !== \"boolean\" ? value !== null : value;\n\n if (!transform) {\n return value;\n } else if (transform === \"toAttribute\") {\n switch (type) {\n case \"object\":\n case \"array\":\n return value === null ? null : JSON.stringify(value);\n case \"boolean\":\n return value ? \"\" : null;\n case \"number\":\n return value === null ? null : value;\n default:\n return value === \"\" ? null : value;\n }\n } else {\n switch (type) {\n case \"object\":\n case \"array\":\n if (!value) {\n return value;\n }\n try {\n return JSON.parse(value);\n } catch {\n console.warn(\"░█ [ELENA]: Invalid JSON: \" + value);\n return null;\n }\n case \"boolean\":\n return value; // conversion already handled above\n case \"number\":\n return value !== null ? +value : value;\n default:\n return value ?? \"\";\n }\n }\n}\n\n/**\n * Set or remove an attribute on an Elena Element.\n *\n * @param {Element} element - Target element\n * @param {string} name - Attribute name\n * @param {string | null} value - Attribute value, or null to remove\n */\nexport function syncAttribute(element, name, value) {\n if (!element) {\n console.warn(\"░█ [ELENA]: Cannot sync attrs.\");\n return;\n }\n if (value === null) {\n element.removeAttribute(name);\n } else {\n element.setAttribute(name, value);\n }\n}\n\n/**\n * Define prop getters/setters on the prototype once\n * at class-creation time. Values are stored per-instance\n * via a `_props` Map that is lazily created.\n *\n * @param {Function} proto - The class prototype\n * @param {string[]} propNames - Prop names to define\n * @param {Set<string>} [noReflect] - Props that should not reflect to attributes\n */\nexport function setProps(proto, propNames, noReflect) {\n for (const prop of propNames) {\n const reflects = !noReflect || !noReflect.has(prop);\n Object.defineProperty(proto, prop, {\n configurable: true,\n enumerable: true,\n get() {\n return this._props ? this._props.get(prop) : undefined;\n },\n set(value) {\n if (!this._props) {\n this._props = new Map();\n }\n if (value === this._props.get(prop)) {\n return;\n }\n\n this._props.set(prop, value);\n if (!this.isConnected) {\n return;\n }\n\n if (reflects) {\n // Skip reflection when called from attributeChangedCallback. The\n // attribute is already at the new value, setting it again is redundant\n // and would fire an extra attributeChangedCallback with identical values.\n if (!this._syncing) {\n const attrValue = getPropValue(typeof value, value, \"toAttribute\");\n syncAttribute(this, prop, attrValue);\n }\n } else if (this._hydrated && !this._isRendering) {\n this._safeRender();\n }\n },\n });\n }\n}\n\n/**\n * We need to update the internals of the Elena Element\n * when props on the host element are changed.\n *\n * @param {object} context\n * @param {string} name\n * @param {any} oldValue\n * @param {any} newValue\n */\nexport function getProps(context, name, oldValue, newValue) {\n if (oldValue !== newValue) {\n const type = typeof context[name];\n if (type === \"undefined\") {\n console.warn(`░█ [ELENA]: Prop \"${name}\" has no default.`);\n }\n const newAttr = getPropValue(type, newValue, \"toProp\");\n context[name] = newAttr;\n }\n}\n","/**\n * Register the Elena Element if the browser supports it.\n *\n * @param {string} tagName\n * @param {Function} Element\n */\nexport function defineElement(tagName, Element) {\n if (typeof window !== \"undefined\" && \"customElements\" in window) {\n if (!window.customElements.get(tagName)) {\n window.customElements.define(tagName, Element);\n }\n }\n}\n\n/**\n * Escape a string for safe insertion into HTML.\n *\n * @param {string} str\n * @returns {string}\n */\nconst Escape = { \"&\": \"&amp;\", \"<\": \"&lt;\", \">\": \"&gt;\", '\"': \"&quot;\", \"'\": \"&#39;\" };\nexport function escapeHtml(str) {\n return String(str).replace(/[&<>\"']/g, c => Escape[c]);\n}\n\n/**\n * Resolve an interpolated template value to its\n * HTML string representation.\n *\n * @param {*} value\n * @returns {string}\n */\nexport function resolveValue(value) {\n if (Array.isArray(value)) {\n return value.map(item => resolveItem(item)).join(\"\");\n }\n return resolveItem(value);\n}\n\n/**\n * Resolve a single value to its HTML string\n * representation.\n *\n * @param {*} value\n * @returns {string}\n */\nfunction resolveItem(value) {\n return value?.__raw ? String(value) : escapeHtml(String(value ?? \"\"));\n}\n\n/**\n * Tagged template for trusted HTML. Use as the return value\n * of render(), or for sub-fragments inside render methods.\n *\n * @param {TemplateStringsArray} strings\n * @param {...*} values\n * @returns {{ __raw: true, strings: TemplateStringsArray, values: Array, toString(): string }}\n */\nexport function html(strings, ...values) {\n let str;\n return {\n __raw: true,\n strings,\n values,\n toString: () => {\n if (str === undefined) {\n str = strings.reduce((acc, s, i) => {\n return acc + s + resolveValue(values[i]);\n }, \"\");\n }\n return str;\n },\n };\n}\n\n/**\n * Renders a string as HTML rather than text.\n *\n * @param {string} str - The raw HTML string to trust.\n * @returns {{ __raw: true, toString(): string }}\n */\nexport function unsafeHTML(str) {\n return { __raw: true, toString: () => str ?? \"\" };\n}\n\n/**\n * A placeholder you can return from a conditional expression\n * inside a template to render nothing.\n *\n * @type {{ __raw: true, toString(): string }}\n */\nexport const nothing = Object.freeze({ __raw: true, toString: () => \"\" });\n\n/**\n * Check if a value contains trusted HTML fragments.\n *\n * @param {*} value\n * @returns {boolean}\n */\nexport const isRaw = value =>\n Array.isArray(value) ? value.some(item => item?.__raw) : value?.__raw;\n\n/**\n * Convert a value to its plain text string.\n *\n * @param {*} value\n * @returns {string}\n */\nexport const toPlainText = value =>\n Array.isArray(value) ? value.map(item => String(item ?? \"\")).join(\"\") : String(value ?? \"\");\n\n/**\n * Collapse whitespace from a static string part.\n *\n * @param {string} string\n * @returns {string}\n */\nexport function collapseWhitespace(string) {\n return string\n .replace(/>\\n\\s*/g, \">\") // newline after tag close\n .replace(/\\n\\s*</g, \"<\") // newline before tag open\n .replace(/\\n\\s*/g, \" \") // newline in text content, preserve word boundary\n .replace(/>\\s+</g, \"><\"); // whitespace between tags\n}\n","import { collapseWhitespace, isRaw, resolveValue, toPlainText } from \"./utils.js\";\n\nconst stringsCache = new WeakMap();\nconst markerKey = \"e\" + Math.random().toString(36).slice(2, 6);\n\n/**\n * Render a tagged template into an Elena Element with DOM diffing.\n * Returns true if the DOM was fully rebuilt, false if only text\n * nodes were patched in place.\n *\n * @param {HTMLElement} element\n * @param {TemplateStringsArray} strings - Static parts of the tagged template\n * @param {Array} values - Dynamic interpolated values\n * @returns {boolean}\n */\nexport function renderTemplate(element, strings, values) {\n if (patchTextNodes(element, strings, values)) {\n return false;\n }\n fullRender(element, strings, values);\n return true;\n}\n\n/**\n * Fast path: patch only the text nodes whose values changed.\n *\n * @param {HTMLElement} element - The host element with cached template state\n * @param {TemplateStringsArray} strings - Static parts of the tagged template\n * @param {Array} values - Dynamic interpolated values\n * @returns {boolean} Whether patching was sufficient (false = full render)\n */\nfunction patchTextNodes(element, strings, values) {\n // Only works when re-rendering the same template shape\n if (element._tplStrings !== strings || !element._tplParts) {\n return false;\n }\n\n for (let i = 0; i < values.length; i++) {\n const v = values[i];\n const comparable = Array.isArray(v) ? toPlainText(v) : v;\n\n if (comparable === element._tplValues[i]) {\n continue;\n }\n\n if (isRaw(v) || !element._tplParts[i]) {\n return false;\n }\n\n element._tplValues[i] = comparable;\n element._tplParts[i].textContent = toPlainText(v);\n }\n\n return true;\n}\n\n/**\n * Cold path: clone a cached <template> and patch in values.\n *\n * @param {HTMLElement} element - The host element to render into\n * @param {TemplateStringsArray} strings - Static parts of the tagged template\n * @param {Array} values - Dynamic interpolated values\n */\nfunction fullRender(element, strings, values) {\n let entry = stringsCache.get(strings);\n\n if (!entry) {\n const processedStrings = Array.from(strings, collapseWhitespace);\n entry = {\n processedStrings,\n template: values.length > 0 ? createTemplate(processedStrings, values.length) : null,\n };\n stringsCache.set(strings, entry);\n }\n\n if (entry.template) {\n element._tplParts = cloneAndPatch(element, entry.template, values);\n } else {\n // Fallback for attribute-position values or static templates.\n // White space collapsing here protects against Vue SSR mismatches.\n const renderedValues = values.map(value => resolveValue(value));\n const markup = entry.processedStrings\n .reduce((out, str, i) => out + str + (renderedValues[i] ?? \"\"), \"\")\n .replace(/>\\s+</g, \"><\")\n .trim();\n\n // Morph existing DOM to match new markup instead of replacing it.\n const tpl = document.createElement(\"template\");\n tpl.innerHTML = markup;\n morphContent(element, tpl.content.childNodes);\n element._tplParts = null;\n }\n\n element._tplStrings = strings;\n element._tplValues = values.map(v => (Array.isArray(v) ? toPlainText(v) : v));\n}\n\n/**\n * Build a <template> element with comment markers.\n *\n * @param {string[]} processedStrings - Whitespace-collapsed static parts\n * @param {number} valueCount - Number of dynamic values\n * @returns {HTMLTemplateElement | null}\n */\nfunction createTemplate(processedStrings, valueCount) {\n const marker = `<!--${markerKey}-->`;\n const markup = processedStrings\n .reduce((out, str, i) => out + str + (i < valueCount ? marker : \"\"), \"\")\n .trim();\n\n const tpl = document.createElement(\"template\");\n tpl.innerHTML = markup;\n\n // Mismatch means this template shape cannot use the clone path.\n const walker = document.createTreeWalker(tpl.content, NodeFilter.SHOW_COMMENT);\n let count = 0;\n\n while (walker.nextNode()) {\n if (walker.currentNode.data === markerKey) {\n count++;\n }\n }\n\n return count === valueCount ? tpl : null;\n}\n\n/**\n * Clone a cached template and replace comment markers\n * with actual content.\n *\n * @param {HTMLElement} element - The host element to render into\n * @param {HTMLTemplateElement} template - Cached template with markers\n * @param {Array} values - Raw interpolated values\n * @returns {Array<Text | undefined>} Text node map for fast-path patching\n */\nfunction cloneAndPatch(element, template, values) {\n const clone = template.content.cloneNode(true);\n const walker = document.createTreeWalker(clone, NodeFilter.SHOW_COMMENT);\n const parts = new Array(values.length);\n const markers = [];\n let node;\n\n // Collect markers before modifying the tree\n while ((node = walker.nextNode())) {\n if (node.data === markerKey) {\n markers.push(node);\n }\n }\n\n for (let i = 0; i < markers.length; i++) {\n const value = values[i];\n\n if (isRaw(value)) {\n // Raw HTML: parse and insert as fragment\n const tmp = document.createElement(\"template\");\n tmp.innerHTML = resolveValue(value);\n markers[i].parentNode.replaceChild(tmp.content, markers[i]);\n\n // Raw values can't be fast-patched; leave parts undefined\n } else {\n // Create text node with unescaped content\n const textNode = document.createTextNode(toPlainText(value));\n markers[i].parentNode.replaceChild(textNode, markers[i]);\n parts[i] = textNode;\n }\n }\n\n element.replaceChildren(clone);\n return parts;\n}\n\n/**\n * Patches attributes and text content in-place when structure is stable,\n * preserving element identity and focus state across re-renders.\n *\n * @param {Node} parent\n * @param {NodeList} nextNodes - The desired child nodes from the new render\n */\nfunction morphContent(parent, nextNodes) {\n const current = Array.from(parent.childNodes);\n const next = Array.from(nextNodes);\n const len = Math.max(current.length, next.length);\n\n for (let i = 0; i < len; i++) {\n const cur = current[i];\n const nxt = next[i];\n\n if (!cur) {\n parent.appendChild(nxt);\n } else if (!nxt) {\n parent.removeChild(cur);\n } else if (\n cur.nodeType !== nxt.nodeType ||\n (cur.nodeType === Node.ELEMENT_NODE && cur.tagName !== nxt.tagName)\n ) {\n parent.replaceChild(nxt, cur);\n } else if (cur.nodeType === Node.TEXT_NODE) {\n if (cur.textContent !== nxt.textContent) {\n cur.textContent = nxt.textContent;\n }\n } else if (cur.nodeType === Node.ELEMENT_NODE) {\n morphAttributes(cur, nxt);\n morphContent(cur, nxt.childNodes);\n }\n }\n}\n\n/**\n * Morhp element’s attributes without rebuilding the DOM.\n *\n * @param {Element} current - The current existing DOM element\n * @param {Element} next - The desired element from the new render\n */\nfunction morphAttributes(current, next) {\n for (let i = current.attributes.length - 1; i >= 0; i--) {\n const { name } = current.attributes[i];\n\n if (!next.hasAttribute(name)) {\n current.removeAttribute(name);\n }\n }\n\n for (let i = 0; i < next.attributes.length; i++) {\n const { name, value } = next.attributes[i];\n\n if (current.getAttribute(name) !== value) {\n current.setAttribute(name, value);\n }\n }\n}\n","/**\n * ██████████ ████\n * ░░███░░░░░█░░███\n * ░███ █ ░ ░███ ██████ ████████ ██████\n * ░██████ ░███ ███░░███░░███░░███ ░░░░░███\n * ░███░░█ ░███ ░███████ ░███ ░███ ███████\n * ░███ ░ █ ░███ ░███░░░ ░███ ░███ ███░░███\n * ██████████ █████░░██████ ████ █████░░████████\n * ░░░░░░░░░░ ░░░░░ ░░░░░░ ░░░░ ░░░░░ ░░░░░░░░\n *\n * Elena Progressive Web Components\n * https://elenajs.com\n */\n\nimport { setProps, getProps, getPropValue, syncAttribute } from \"./common/props.js\";\nimport { defineElement, html, unsafeHTML, nothing } from \"./common/utils.js\";\nimport { renderTemplate } from \"./common/render.js\";\n\nexport { html, unsafeHTML, nothing };\n\n/**\n * Returns a function that finds the inner element using the given selector.\n * Built once per component class to avoid repeated work.\n *\n * - No selector: uses firstElementChild\n * - Any string: uses querySelector\n *\n * @param {string | undefined} selector\n * @returns {(host: HTMLElement) => HTMLElement | null}\n */\nfunction elementResolver(selector) {\n if (!selector) {\n return host => host.firstElementChild;\n }\n return host => host.querySelector(selector);\n}\n\n/**\n * @typedef {new (...args: any[]) => HTMLElement} ElenaConstructor\n */\n\n/**\n * @typedef {{ text: string, element: HTMLElement | null, render(): void, willUpdate(): void, firstUpdated(): void, updated(): void, connectedCallback(): void, disconnectedCallback(): void }} ElenaInstanceMembers\n */\n\n/**\n * @typedef {{ name: string, reflect?: boolean }} ElenaPropObject\n */\n\n/**\n * @typedef {(new (...args: any[]) => HTMLElement & ElenaInstanceMembers) & {\n * define(): void,\n * readonly observedAttributes: string[],\n * tagName?: string,\n * props?: (string | ElenaPropObject)[],\n * events?: string[],\n * element?: string,\n * shadow?: \"open\" | \"closed\",\n * styles?: CSSStyleSheet | string | (CSSStyleSheet | string)[],\n * }} ElenaElementConstructor\n */\n\n// Tracks which component classes have already been set up.\nconst setupRegistry = new WeakSet();\n\n/**\n * Creates an Elena component class by extending `superClass`.\n *\n * Adds rendering, props, and event handling to your component.\n * Configure it using static class fields: `static tagName`,\n * `static props`, `static events`, and `static element`.\n *\n * @param {ElenaConstructor} superClass - The base class to extend (usually `HTMLElement`).\n * @returns {ElenaElementConstructor} A class ready to be defined as a custom element.\n */\nexport function Elena(superClass) {\n /**\n * The base Elena element class with all built-in behavior.\n */\n class ElenaElement extends superClass {\n /**\n * The inner element rendered by this component.\n *\n * @type {HTMLElement | null}\n */\n element = null;\n\n /**\n * Called by the browser when an observed attribute changes.\n * Updates the matching prop and re-renders if needed.\n *\n * @param {string} prop\n * @param {string} oldValue\n * @param {string} newValue\n */\n attributeChangedCallback(prop, oldValue, newValue) {\n super.attributeChangedCallback?.(prop, oldValue, newValue);\n\n if (prop === \"text\") {\n this.text = newValue ?? \"\";\n return;\n }\n\n // Set flag so the property setter skips redundant attribute reflection:\n // the attribute is already at the new value, no need to set it again.\n this._syncing = true;\n getProps(this, prop, oldValue, newValue);\n this._syncing = false;\n\n // Re-render when attributes change (after initial render).\n // Guard against re-entrant renders: if render() itself mutates an observed\n // attribute, skip the recursive call to prevent an infinite loop.\n if (this._hydrated && oldValue !== newValue && !this._isRendering) {\n this._safeRender();\n }\n }\n\n /**\n * Lists the attributes Elena watches for changes.\n * Reads from the subclass’s `static props` field.\n */\n static get observedAttributes() {\n if (this._observedAttrs) {\n return this._observedAttrs;\n }\n\n const propNames = (this.props || []).map(p => (typeof p === \"string\" ? p : p.name));\n this._observedAttrs = [...propNames, \"text\"];\n return this._observedAttrs;\n }\n\n /**\n * Called by the browser each time the element is added to the page.\n */\n connectedCallback() {\n super.connectedCallback?.();\n this._setupStaticProps();\n this._captureClassFieldDefaults();\n this._captureText();\n this._attachShadow();\n this.willUpdate();\n this._applyRender();\n this._syncProps();\n this._delegateEvents();\n if (!this._hydrated) {\n this._hydrated = true;\n this.setAttribute(\"hydrated\", \"\");\n this.firstUpdated();\n }\n this.updated();\n }\n\n /**\n * Sets up props, events, and the element selector once per component class.\n * Runs the first time an instance of a given class connects to the page.\n *\n * @internal\n */\n _setupStaticProps() {\n const component = this.constructor;\n\n if (setupRegistry.has(component)) {\n return;\n }\n\n // Props with reflect: false\n const noRef = new Set();\n const names = [];\n\n if (component.props) {\n for (const p of component.props) {\n if (typeof p === \"string\") {\n names.push(p);\n } else {\n names.push(p.name);\n\n if (p.reflect === false) {\n noRef.add(p.name);\n }\n }\n }\n\n if (names.includes(\"text\")) {\n console.warn('░█ [ELENA]: \"text\" is reserved.');\n }\n\n setProps(component.prototype, names, noRef);\n }\n\n component._propNames = names;\n component._noReflect = noRef;\n component._elenaEvents = component.events || null;\n\n if (component._elenaEvents) {\n for (const e of component._elenaEvents) {\n if (!Object.prototype.hasOwnProperty.call(component.prototype, e)) {\n component.prototype[e] = function (...args) {\n return this.element[e](...args);\n };\n }\n }\n }\n\n component._resolver = elementResolver(component.element);\n setupRegistry.add(component);\n }\n\n /**\n * Moves class field defaults into Elena’s internal props store\n * so that getters and setters work correctly.\n *\n * @internal\n */\n _captureClassFieldDefaults() {\n this._syncing = true;\n\n for (const name of this.constructor._propNames) {\n if (Object.prototype.hasOwnProperty.call(this, name)) {\n const value = this[name];\n delete this[name];\n this[name] = value;\n }\n }\n\n this._syncing = false;\n }\n\n /**\n * Saves any text inside the element before the first render.\n *\n * @internal\n */\n _captureText() {\n if (!this._hydrated && this._text === undefined) {\n this.text = this.textContent.trim();\n }\n }\n\n /**\n * The root node to render into. Returns the shadow root when shadow mode\n * is enabled, otherwise the host element itself.\n *\n * @type {ShadowRoot | HTMLElement}\n */\n get _renderRoot() {\n return this._shadow ?? this.shadowRoot ?? this;\n }\n\n /**\n * Attaches a shadow root and adopts styles on first connect.\n * Only runs when `static shadow` is set on the component class.\n *\n * @internal\n */\n _attachShadow() {\n const component = this.constructor;\n\n if (!component.shadow) {\n return;\n }\n\n // A shadow root may already exist if Declarative Shadow DOM was used.\n // In that case skip attachShadow() but still adopt styles below.\n // Store the reference so closed shadow roots remain accessible.\n if (!this._shadow && !this.shadowRoot) {\n this._shadow = this.attachShadow({ mode: component.shadow });\n }\n\n const shadowRoot = this._shadow ?? this.shadowRoot;\n\n if (!component.styles) {\n return;\n }\n\n // Normalize to array and cache converted CSSStyleSheet instances on the class.\n // Avoids re-parsing CSS strings on every element instance.\n if (!component._adoptedSheets) {\n const stylesList = Array.isArray(component.styles) ? component.styles : [component.styles];\n\n component._adoptedSheets = stylesList.map(s => {\n if (typeof s === \"string\") {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(s);\n return sheet;\n }\n return s;\n });\n }\n\n shadowRoot.adoptedStyleSheets = component._adoptedSheets;\n }\n\n /**\n * Calls render() and updates the DOM with the result.\n * Also resolves the inner element reference.\n *\n * @internal\n */\n _applyRender() {\n const result = this.render();\n\n if (result && result.strings) {\n const root = this._renderRoot;\n const rebuilt = renderTemplate(root, result.strings, result.values);\n\n // Re-resolve element ref when the DOM was fully rebuilt.\n // Fast-path text node patching leaves the DOM structure intact,\n // so the existing ref is still valid.\n if (rebuilt) {\n const oldElement = this.element;\n this.element = this.constructor._resolver(root);\n\n // Re-bind event listeners when the inner element was replaced.\n if (this._events && oldElement && this.element !== oldElement) {\n const events = this.constructor._elenaEvents;\n\n for (const e of events) {\n oldElement.removeEventListener(e, this);\n this.element.addEventListener(e, this);\n }\n }\n }\n }\n\n // Resolve inner element on first render\n if (!this.element) {\n const root = this._renderRoot;\n this.element = this.constructor._resolver(root);\n\n if (!this.element) {\n if (this.constructor.element) {\n console.warn(\"░█ [ELENA]: Element not found.\");\n }\n this.element = root.firstElementChild;\n }\n }\n }\n\n /**\n * Syncs any props that were set before the element\n * connected to the page.\n *\n * @internal\n */\n _syncProps() {\n if (this._props) {\n const noReflect = this.constructor._noReflect;\n\n for (const [prop, value] of this._props) {\n if (noReflect.has(prop)) {\n continue;\n }\n\n const attrValue = getPropValue(typeof value, value, \"toAttribute\");\n\n if (attrValue === null && !this.hasAttribute(prop)) {\n continue;\n }\n\n syncAttribute(this, prop, attrValue);\n }\n }\n }\n\n /**\n * Forwards events from the inner element\n * up to the host element.\n *\n * @internal\n */\n _delegateEvents() {\n const events = this.constructor._elenaEvents;\n\n if (!this._events && events?.length) {\n if (!this.element) {\n console.warn(\"░█ [ELENA]: Cannot add events.\");\n } else {\n this._events = true;\n\n for (const e of events) {\n this.element.addEventListener(e, this);\n }\n }\n }\n }\n\n /**\n * Define the element’s HTML here. Return an `html`\n * tagged template. If not overridden, the element connects\n * to the page without rendering anything.\n */\n render() {}\n\n /**\n * Called before every render.\n * Override to prepare state before the template runs.\n */\n willUpdate() {}\n\n /**\n * Called once after the element’s first render.\n * Override to run setup that needs the DOM.\n */\n firstUpdated() {}\n\n /**\n * Called after every render.\n * Override to react to changes.\n */\n updated() {}\n\n /**\n * Called by the browser when the element is moved\n * to a new document via `adoptNode()`.\n */\n adoptedCallback() {\n super.adoptedCallback?.();\n }\n\n /**\n * Called by the browser each time the element\n * is removed from the page.\n */\n disconnectedCallback() {\n super.disconnectedCallback?.();\n if (this._events) {\n this._events = false;\n\n for (const e of this.constructor._elenaEvents) {\n this.element?.removeEventListener(e, this);\n }\n }\n }\n\n /**\n * Forwards events that cannot reach the host naturally:\n * non-bubbling events (focus, blur) and non-composed\n * events in Shadow DOM (change, submit, reset).\n * Composed bubbling events (click, input) pass through on their own.\n *\n * @internal\n */\n handleEvent(event) {\n if (!this.constructor._elenaEvents?.includes(event.type)) {\n return;\n }\n\n if (!event.bubbles || (!event.composed && this._renderRoot !== this)) {\n /** @internal */\n this.dispatchEvent(new Event(event.type, { bubbles: event.bubbles }));\n }\n }\n\n /**\n * The text content of the element. Elena reads this\n * from the element’s children before the first render.\n * Updating it triggers a re-render.\n *\n * @type {string}\n */\n get text() {\n return this._text ?? \"\";\n }\n\n set text(value) {\n const old = this._text;\n this._text = value;\n\n if (this._hydrated && old !== value && !this._isRendering) {\n this._safeRender();\n }\n }\n\n /**\n * Registers the component as a custom element using `static tagName`.\n * Call this on your component class after the class body is defined,\n * not on the Elena mixin itself.\n */\n static define() {\n if (this.tagName) {\n defineElement(this.tagName, this);\n } else {\n console.warn(\"░█ [ELENA]: define() without a tagName.\");\n }\n }\n\n /**\n * Schedules a re-render via microtask. If called multiple times\n * before the microtask fires, only one render runs.\n *\n * @internal\n */\n _safeRender() {\n if (this._isRendering) {\n return;\n }\n if (!this._renderPending) {\n this._renderPending = true;\n this._updateComplete = new Promise(resolve => {\n this._resolveUpdate = resolve;\n });\n queueMicrotask(() => {\n try {\n this._performUpdate();\n } catch (e) {\n console.error(\"░█ [ELENA]:\", e);\n }\n });\n }\n }\n\n /**\n * Runs the batched update cycle.\n * Called by the microtask in _safeRender().\n *\n * @internal\n */\n _performUpdate() {\n this._renderPending = false;\n const resolve = this._resolveUpdate;\n this._resolveUpdate = null;\n try {\n try {\n this.willUpdate();\n this._isRendering = true;\n this._applyRender();\n } finally {\n this._isRendering = false;\n }\n this.updated();\n } finally {\n this._updateComplete = null;\n resolve();\n }\n }\n\n /**\n * A Promise that resolves after the render completes.\n * Resolves immediately if no render is scheduled.\n *\n * @type {Promise<void>}\n */\n get updateComplete() {\n if (this._updateComplete) {\n return this._updateComplete;\n }\n return Promise.resolve();\n }\n\n /**\n * Schedules a re-render. Use this to manually trigger an\n * update when Elena cannot detect the change automatically.\n */\n requestUpdate() {\n if (this._hydrated && !this._isRendering) {\n this._safeRender();\n }\n }\n }\n\n return ElenaElement;\n}\n"],"names":["getPropValue","type","value","transform","JSON","stringify","parse","console","warn","syncAttribute","element","name","removeAttribute","setAttribute","Escape","resolveValue","Array","isArray","map","item","resolveItem","join","__raw","String","str","replace","c","html","strings","values","toString","undefined","reduce","acc","s","i","unsafeHTML","nothing","Object","freeze","isRaw","some","toPlainText","collapseWhitespace","string","stringsCache","WeakMap","markerKey","Math","random","slice","renderTemplate","_tplStrings","_tplParts","length","v","comparable","_tplValues","textContent","patchTextNodes","entry","get","processedStrings","from","template","createTemplate","set","clone","content","cloneNode","walker","document","createTreeWalker","NodeFilter","SHOW_COMMENT","parts","markers","node","nextNode","data","push","tmp","createElement","innerHTML","parentNode","replaceChild","textNode","createTextNode","replaceChildren","cloneAndPatch","renderedValues","markup","out","trim","tpl","morphContent","childNodes","fullRender","valueCount","marker","count","currentNode","parent","nextNodes","current","next","len","max","cur","nxt","nodeType","Node","ELEMENT_NODE","tagName","TEXT_NODE","morphAttributes","removeChild","appendChild","attributes","hasAttribute","getAttribute","setupRegistry","WeakSet","Elena","superClass","attributeChangedCallback","prop","oldValue","newValue","super","this","_syncing","context","newAttr","getProps","_hydrated","_isRendering","_safeRender","text","observedAttributes","_observedAttrs","propNames","props","p","connectedCallback","_setupStaticProps","_captureClassFieldDefaults","_captureText","_attachShadow","willUpdate","_applyRender","_syncProps","_delegateEvents","firstUpdated","updated","component","constructor","has","noRef","Set","names","reflect","add","includes","proto","noReflect","reflects","defineProperty","configurable","enumerable","_props","Map","isConnected","attrValue","setProps","prototype","_propNames","_noReflect","_elenaEvents","events","e","hasOwnProperty","call","args","selector","_resolver","host","querySelector","firstElementChild","_text","_renderRoot","_shadow","shadowRoot","shadow","attachShadow","mode","styles","_adoptedSheets","stylesList","sheet","CSSStyleSheet","replaceSync","adoptedStyleSheets","result","render","root","oldElement","_events","removeEventListener","addEventListener","adoptedCallback","disconnectedCallback","handleEvent","event","bubbles","composed","dispatchEvent","Event","old","define","Element","window","customElements","_renderPending","_updateComplete","Promise","resolve","_resolveUpdate","queueMicrotask","_performUpdate","error","updateComplete","requestUpdate"],"mappings":"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"}
package/dist/elena.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"elena.js","sources":["../src/elena.js"],"sourcesContent":["/**\n * ██████████ ████\n * ░░███░░░░░█░░███\n * ░███ █ ░ ░███ ██████ ████████ ██████\n * ░██████ ░███ ███░░███░░███░░███ ░░░░░███\n * ░███░░█ ░███ ░███████ ░███ ░███ ███████\n * ░███ ░ █ ░███ ░███░░░ ░███ ░███ ███░░███\n * ██████████ █████░░██████ ████ █████░░████████\n * ░░░░░░░░░░ ░░░░░ ░░░░░░ ░░░░ ░░░░░ ░░░░░░░░\n *\n * Elena Progressive Web Components\n * https://elenajs.com\n */\n\nimport { setProps, getProps, getPropValue, syncAttribute } from \"./common/props.js\";\nimport { defineElement, html, unsafeHTML, nothing } from \"./common/utils.js\";\nimport { renderTemplate } from \"./common/render.js\";\n\nexport { html, unsafeHTML, nothing };\n\n/**\n * Returns a function that finds the inner element using the given selector.\n * Built once per component class to avoid repeated work.\n *\n * - No selector: uses firstElementChild\n * - Any string: uses querySelector\n *\n * @param {string | undefined} selector\n * @returns {(host: HTMLElement) => HTMLElement | null}\n */\nfunction elementResolver(selector) {\n if (!selector) {\n return host => host.firstElementChild;\n }\n return host => host.querySelector(selector);\n}\n\n/**\n * @typedef {new (...args: any[]) => HTMLElement} ElenaConstructor\n */\n\n/**\n * @typedef {{ text: string, element: HTMLElement | null, render(): void, willUpdate(): void, firstUpdated(): void, updated(): void, connectedCallback(): void, disconnectedCallback(): void }} ElenaInstanceMembers\n */\n\n/**\n * @typedef {{ name: string, reflect?: boolean }} ElenaPropObject\n */\n\n/**\n * @typedef {(new (...args: any[]) => HTMLElement & ElenaInstanceMembers) & {\n * define(): void,\n * readonly observedAttributes: string[],\n * tagName?: string,\n * props?: (string | ElenaPropObject)[],\n * events?: string[],\n * element?: string,\n * shadow?: \"open\" | \"closed\",\n * styles?: CSSStyleSheet | string | (CSSStyleSheet | string)[],\n * }} ElenaElementConstructor\n */\n\n// Tracks which component classes have already been set up.\nconst setupRegistry = new WeakSet();\n\n/**\n * Creates an Elena component class by extending `superClass`.\n *\n * Adds rendering, props, and event handling to your component.\n * Configure it using static class fields: `static tagName`,\n * `static props`, `static events`, and `static element`.\n *\n * @param {ElenaConstructor} superClass - The base class to extend (usually `HTMLElement`).\n * @returns {ElenaElementConstructor} A class ready to be defined as a custom element.\n */\nexport function Elena(superClass) {\n /**\n * The base Elena element class with all built-in behavior.\n */\n class ElenaElement extends superClass {\n /**\n * The inner element rendered by this component.\n *\n * @type {HTMLElement | null}\n */\n element = null;\n\n /**\n * Called by the browser when an observed attribute changes.\n * Updates the matching prop and re-renders if needed.\n *\n * @param {string} prop\n * @param {string} oldValue\n * @param {string} newValue\n */\n attributeChangedCallback(prop, oldValue, newValue) {\n super.attributeChangedCallback?.(prop, oldValue, newValue);\n\n if (prop === \"text\") {\n this.text = newValue ?? \"\";\n return;\n }\n\n // Set flag so the property setter skips redundant attribute reflection:\n // the attribute is already at the new value, no need to set it again.\n this._syncing = true;\n getProps(this, prop, oldValue, newValue);\n this._syncing = false;\n\n // Re-render when attributes change (after initial render).\n // Guard against re-entrant renders: if render() itself mutates an observed\n // attribute, skip the recursive call to prevent an infinite loop.\n if (this._hydrated && oldValue !== newValue && !this._isRendering) {\n this._safeRender();\n }\n }\n\n /**\n * Lists the attributes Elena watches for changes.\n * Reads from the subclass’s `static props` field.\n */\n static get observedAttributes() {\n if (this._observedAttrs) {\n return this._observedAttrs;\n }\n\n const propNames = (this.props || []).map(p => (typeof p === \"string\" ? p : p.name));\n this._observedAttrs = [...propNames, \"text\"];\n return this._observedAttrs;\n }\n\n /**\n * Called by the browser each time the element is added to the page.\n */\n connectedCallback() {\n super.connectedCallback?.();\n this._setupStaticProps();\n this._captureClassFieldDefaults();\n this._captureText();\n this._attachShadow();\n this.willUpdate();\n this._applyRender();\n this._syncProps();\n this._delegateEvents();\n if (!this._hydrated) {\n this._hydrated = true;\n this.setAttribute(\"hydrated\", \"\");\n this.firstUpdated();\n }\n this.updated();\n }\n\n /**\n * Sets up props, events, and the element selector once per component class.\n * Runs the first time an instance of a given class connects to the page.\n *\n * @internal\n */\n _setupStaticProps() {\n const component = this.constructor;\n\n if (setupRegistry.has(component)) {\n return;\n }\n\n // Props with reflect: false\n const noRef = new Set();\n const names = [];\n\n if (component.props) {\n for (const p of component.props) {\n if (typeof p === \"string\") {\n names.push(p);\n } else {\n names.push(p.name);\n\n if (p.reflect === false) {\n noRef.add(p.name);\n }\n }\n }\n\n if (names.includes(\"text\")) {\n console.warn('░█ [ELENA]: \"text\" is reserved.');\n }\n\n setProps(component.prototype, names, noRef);\n }\n\n component._propNames = names;\n component._noReflect = noRef;\n component._elenaEvents = component.events || null;\n\n if (component._elenaEvents) {\n for (const e of component._elenaEvents) {\n if (!Object.prototype.hasOwnProperty.call(component.prototype, e)) {\n component.prototype[e] = function (...args) {\n return this.element[e](...args);\n };\n }\n }\n }\n\n component._resolver = elementResolver(component.element);\n setupRegistry.add(component);\n }\n\n /**\n * Moves class field defaults into Elena’s internal props store\n * so that getters and setters work correctly.\n *\n * @internal\n */\n _captureClassFieldDefaults() {\n this._syncing = true;\n\n for (const name of this.constructor._propNames) {\n if (Object.prototype.hasOwnProperty.call(this, name)) {\n const value = this[name];\n delete this[name];\n this[name] = value;\n }\n }\n\n this._syncing = false;\n }\n\n /**\n * Saves any text inside the element before the first render.\n *\n * @internal\n */\n _captureText() {\n if (!this._hydrated && this._text === undefined) {\n this.text = this.textContent.trim();\n }\n }\n\n /**\n * The root node to render into. Returns the shadow root when shadow mode\n * is enabled, otherwise the host element itself.\n *\n * @type {ShadowRoot | HTMLElement}\n */\n get _renderRoot() {\n return this._shadow ?? this.shadowRoot ?? this;\n }\n\n /**\n * Attaches a shadow root and adopts styles on first connect.\n * Only runs when `static shadow` is set on the component class.\n *\n * @internal\n */\n _attachShadow() {\n const component = this.constructor;\n\n if (!component.shadow) {\n return;\n }\n\n // A shadow root may already exist if Declarative Shadow DOM was used.\n // In that case skip attachShadow() but still adopt styles below.\n // Store the reference so closed shadow roots remain accessible.\n if (!this._shadow && !this.shadowRoot) {\n this._shadow = this.attachShadow({ mode: component.shadow });\n }\n\n const shadowRoot = this._shadow ?? this.shadowRoot;\n\n if (!component.styles) {\n return;\n }\n\n // Normalize to array and cache converted CSSStyleSheet instances on the class.\n // Avoids re-parsing CSS strings on every element instance.\n if (!component._adoptedSheets) {\n const stylesList = Array.isArray(component.styles) ? component.styles : [component.styles];\n\n component._adoptedSheets = stylesList.map(s => {\n if (typeof s === \"string\") {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(s);\n return sheet;\n }\n return s;\n });\n }\n\n shadowRoot.adoptedStyleSheets = component._adoptedSheets;\n }\n\n /**\n * Calls render() and updates the DOM with the result.\n * Also resolves the inner element reference.\n *\n * @internal\n */\n _applyRender() {\n const result = this.render();\n\n if (result && result.strings) {\n const root = this._renderRoot;\n const rebuilt = renderTemplate(root, result.strings, result.values);\n\n // Re-resolve element ref when the DOM was fully rebuilt.\n // Fast-path text node patching leaves the DOM structure intact,\n // so the existing ref is still valid.\n if (rebuilt) {\n const oldElement = this.element;\n this.element = this.constructor._resolver(root);\n\n // Re-bind event listeners when the inner element was replaced.\n if (this._events && oldElement && this.element !== oldElement) {\n const events = this.constructor._elenaEvents;\n\n for (const e of events) {\n oldElement.removeEventListener(e, this);\n this.element.addEventListener(e, this);\n }\n }\n }\n }\n\n // Resolve inner element on first render\n if (!this.element) {\n const root = this._renderRoot;\n this.element = this.constructor._resolver(root);\n\n if (!this.element) {\n if (this.constructor.element) {\n console.warn(\"░█ [ELENA]: Element not found.\");\n }\n this.element = root.firstElementChild;\n }\n }\n }\n\n /**\n * Syncs any props that were set before the element\n * connected to the page.\n *\n * @internal\n */\n _syncProps() {\n if (this._props) {\n const noReflect = this.constructor._noReflect;\n\n for (const [prop, value] of this._props) {\n if (noReflect.has(prop)) {\n continue;\n }\n\n const attrValue = getPropValue(typeof value, value, \"toAttribute\");\n\n if (attrValue === null && !this.hasAttribute(prop)) {\n continue;\n }\n\n syncAttribute(this, prop, attrValue);\n }\n }\n }\n\n /**\n * Forwards events from the inner element\n * up to the host element.\n *\n * @internal\n */\n _delegateEvents() {\n const events = this.constructor._elenaEvents;\n\n if (!this._events && events?.length) {\n if (!this.element) {\n console.warn(\"░█ [ELENA]: Cannot add events.\");\n } else {\n this._events = true;\n\n for (const e of events) {\n this.element.addEventListener(e, this);\n }\n }\n }\n }\n\n /**\n * Define the element’s HTML here. Return an `html`\n * tagged template. If not overridden, the element connects\n * to the page without rendering anything.\n */\n render() {}\n\n /**\n * Called before every render.\n * Override to prepare state before the template runs.\n */\n willUpdate() {}\n\n /**\n * Called once after the element’s first render.\n * Override to run setup that needs the DOM.\n */\n firstUpdated() {}\n\n /**\n * Called after every render.\n * Override to react to changes.\n */\n updated() {}\n\n /**\n * Called by the browser when the element is moved\n * to a new document via `adoptNode()`.\n */\n adoptedCallback() {\n super.adoptedCallback?.();\n }\n\n /**\n * Called by the browser each time the element\n * is removed from the page.\n */\n disconnectedCallback() {\n super.disconnectedCallback?.();\n if (this._events) {\n this._events = false;\n\n for (const e of this.constructor._elenaEvents) {\n this.element?.removeEventListener(e, this);\n }\n }\n }\n\n /**\n * Forwards events that cannot reach the host naturally:\n * non-bubbling events (focus, blur) and non-composed\n * events in Shadow DOM (change, submit, reset).\n * Composed bubbling events (click, input) pass through on their own.\n *\n * @internal\n */\n handleEvent(event) {\n if (!this.constructor._elenaEvents?.includes(event.type)) {\n return;\n }\n\n if (!event.bubbles || (!event.composed && this._renderRoot !== this)) {\n /** @internal */\n this.dispatchEvent(new Event(event.type, { bubbles: event.bubbles }));\n }\n }\n\n /**\n * The text content of the element. Elena reads this\n * from the element’s children before the first render.\n * Updating it triggers a re-render.\n *\n * @type {string}\n */\n get text() {\n return this._text ?? \"\";\n }\n\n set text(value) {\n const old = this._text;\n this._text = value;\n\n if (this._hydrated && old !== value && !this._isRendering) {\n this._safeRender();\n }\n }\n\n /**\n * Registers the component as a custom element using `static tagName`.\n * Call this on your component class after the class body is defined,\n * not on the Elena mixin itself.\n */\n static define() {\n if (this.tagName) {\n defineElement(this.tagName, this);\n } else {\n console.warn(\"░█ [ELENA]: define() without a tagName.\");\n }\n }\n\n /**\n * Schedules a re-render via microtask. If called multiple times\n * before the microtask fires, only one render runs.\n *\n * @internal\n */\n _safeRender() {\n if (this._isRendering) {\n return;\n }\n if (!this._renderPending) {\n this._renderPending = true;\n this._updateComplete = new Promise(resolve => {\n this._resolveUpdate = resolve;\n });\n queueMicrotask(() => {\n try {\n this._performUpdate();\n } catch (e) {\n console.error(\"░█ [ELENA]:\", e);\n }\n });\n }\n }\n\n /**\n * Runs the batched update cycle.\n * Called by the microtask in _safeRender().\n *\n * @internal\n */\n _performUpdate() {\n this._renderPending = false;\n const resolve = this._resolveUpdate;\n this._resolveUpdate = null;\n try {\n try {\n this.willUpdate();\n this._isRendering = true;\n this._applyRender();\n } finally {\n this._isRendering = false;\n }\n this.updated();\n } finally {\n this._updateComplete = null;\n resolve();\n }\n }\n\n /**\n * A Promise that resolves after the render completes.\n * Resolves immediately if no render is scheduled.\n *\n * @type {Promise<void>}\n */\n get updateComplete() {\n if (this._updateComplete) {\n return this._updateComplete;\n }\n return Promise.resolve();\n }\n\n /**\n * Schedules a re-render. Use this to manually trigger an\n * update when Elena cannot detect the change automatically.\n */\n requestUpdate() {\n if (this._hydrated && !this._isRendering) {\n this._safeRender();\n }\n }\n }\n\n return ElenaElement;\n}\n"],"names":["setupRegistry","WeakSet","Elena","superClass","element","attributeChangedCallback","prop","oldValue","newValue","super","this","_syncing","getProps","_hydrated","_isRendering","_safeRender","text","observedAttributes","_observedAttrs","propNames","props","map","p","name","connectedCallback","_setupStaticProps","_captureClassFieldDefaults","_captureText","_attachShadow","willUpdate","_applyRender","_syncProps","_delegateEvents","setAttribute","firstUpdated","updated","component","constructor","has","noRef","Set","names","push","reflect","add","includes","console","warn","setProps","prototype","_propNames","_noReflect","_elenaEvents","events","e","Object","hasOwnProperty","call","args","selector","_resolver","host","querySelector","firstElementChild","value","undefined","_text","textContent","trim","_renderRoot","_shadow","shadowRoot","shadow","attachShadow","mode","styles","_adoptedSheets","stylesList","Array","isArray","s","sheet","CSSStyleSheet","replaceSync","adoptedStyleSheets","result","render","strings","root","renderTemplate","values","oldElement","_events","removeEventListener","addEventListener","_props","noReflect","attrValue","getPropValue","hasAttribute","syncAttribute","length","adoptedCallback","disconnectedCallback","handleEvent","event","type","bubbles","composed","dispatchEvent","Event","old","define","tagName","defineElement","_renderPending","_updateComplete","Promise","resolve","_resolveUpdate","queueMicrotask","_performUpdate","error","updateComplete","requestUpdate"],"mappings":"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"}
package/dist/props.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"props.js","sources":["../src/common/props.js"],"sourcesContent":["/**\n * Get the value of the Elena Element property.\n *\n * @param {string} type\n * @param {any} value\n * @param {\"toAttribute\" | \"toProp\"} [transform]\n */\nexport function getPropValue(type, value, transform) {\n value = type === \"boolean\" && typeof value !== \"boolean\" ? value !== null : value;\n\n if (!transform) {\n return value;\n } else if (transform === \"toAttribute\") {\n switch (type) {\n case \"object\":\n case \"array\":\n return value === null ? null : JSON.stringify(value);\n case \"boolean\":\n return value ? \"\" : null;\n case \"number\":\n return value === null ? null : value;\n default:\n return value === \"\" ? null : value;\n }\n } else {\n switch (type) {\n case \"object\":\n case \"array\":\n if (!value) {\n return value;\n }\n try {\n return JSON.parse(value);\n } catch {\n console.warn(\"░█ [ELENA]: Invalid JSON: \" + value);\n return null;\n }\n case \"boolean\":\n return value; // conversion already handled above\n case \"number\":\n return value !== null ? +value : value;\n default:\n return value ?? \"\";\n }\n }\n}\n\n/**\n * Set or remove an attribute on an Elena Element.\n *\n * @param {Element} element - Target element\n * @param {string} name - Attribute name\n * @param {string | null} value - Attribute value, or null to remove\n */\nexport function syncAttribute(element, name, value) {\n if (!element) {\n console.warn(\"░█ [ELENA]: Cannot sync attrs.\");\n return;\n }\n if (value === null) {\n element.removeAttribute(name);\n } else {\n element.setAttribute(name, value);\n }\n}\n\n/**\n * Define prop getters/setters on the prototype once\n * at class-creation time. Values are stored per-instance\n * via a `_props` Map that is lazily created.\n *\n * @param {Function} proto - The class prototype\n * @param {string[]} propNames - Prop names to define\n * @param {Set<string>} [noReflect] - Props that should not reflect to attributes\n */\nexport function setProps(proto, propNames, noReflect) {\n for (const prop of propNames) {\n const reflects = !noReflect || !noReflect.has(prop);\n Object.defineProperty(proto, prop, {\n configurable: true,\n enumerable: true,\n get() {\n return this._props ? this._props.get(prop) : undefined;\n },\n set(value) {\n if (!this._props) {\n this._props = new Map();\n }\n if (value === this._props.get(prop)) {\n return;\n }\n\n this._props.set(prop, value);\n if (!this.isConnected) {\n return;\n }\n\n if (reflects) {\n // Skip reflection when called from attributeChangedCallback. The\n // attribute is already at the new value, setting it again is redundant\n // and would fire an extra attributeChangedCallback with identical values.\n if (!this._syncing) {\n const attrValue = getPropValue(typeof value, value, \"toAttribute\");\n syncAttribute(this, prop, attrValue);\n }\n } else if (this._hydrated && !this._isRendering) {\n this._safeRender();\n }\n },\n });\n }\n}\n\n/**\n * We need to update the internals of the Elena Element\n * when props on the host element are changed.\n *\n * @param {object} context\n * @param {string} name\n * @param {any} oldValue\n * @param {any} newValue\n */\nexport function getProps(context, name, oldValue, newValue) {\n if (oldValue !== newValue) {\n const type = typeof context[name];\n if (type === \"undefined\") {\n console.warn(`░█ [ELENA]: Prop \"${name}\" has no default.`);\n }\n const newAttr = getPropValue(type, newValue, \"toProp\");\n context[name] = newAttr;\n }\n}\n"],"names":["getPropValue","type","value","transform","JSON","stringify","parse","console","warn","syncAttribute","element","name","removeAttribute","setAttribute","setProps","proto","propNames","noReflect","prop","reflects","has","Object","defineProperty","configurable","enumerable","get","this","_props","undefined","set","Map","isConnected","_syncing","attrValue","_hydrated","_isRendering","_safeRender","getProps","context","oldValue","newValue","newAttr"],"mappings":"AAOO,SAASA,EAAaC,EAAMC,EAAOC,GAGxC,GAFAD,EAAiB,YAATD,GAAuC,kBAAVC,EAAgC,OAAVA,EAAiBA,GAEvEC,EACH,OAAOD,EACF,GAAkB,gBAAdC,EACT,OAAQF,GACN,IAAK,SACL,IAAK,QACH,OAAiB,OAAVC,EAAiB,KAAOE,KAAKC,UAAUH,GAChD,IAAK,UACH,OAAOA,EAAQ,GAAK,KACtB,IAAK,SACH,OAAiB,OAAVA,EAAiB,KAAOA,EACjC,QACE,MAAiB,KAAVA,EAAe,KAAOA,OAGjC,OAAQD,GACN,IAAK,SACL,IAAK,QACH,IAAKC,EACH,OAAOA,EAET,IACE,OAAOE,KAAKE,MAAMJ,EACpB,CAAE,MAEA,OADAK,QAAQC,KAAK,6BAA+BN,GACrC,IACT,CACF,IAAK,UACH,OAAOA,EACT,IAAK,SACH,OAAiB,OAAVA,GAAkBA,EAAQA,EACnC,QACE,OAAOA,GAAS,GAGxB,CASO,SAASO,EAAcC,EAASC,EAAMT,GACtCQ,EAIS,OAAVR,EACFQ,EAAQE,gBAAgBD,GAExBD,EAAQG,aAAaF,EAAMT,GAN3BK,QAAQC,KAAK,iCAQjB,CAWO,SAASM,EAASC,EAAOC,EAAWC,GACzC,IAAK,MAAMC,KAAQF,EAAW,CAC5B,MAAMG,GAAYF,IAAcA,EAAUG,IAAIF,GAC9CG,OAAOC,eAAeP,EAAOG,EAAM,CACjCK,cAAc,EACdC,YAAY,EACZ,GAAAC,GACE,OAAOC,KAAKC,OAASD,KAAKC,OAAOF,IAAIP,QAAQU,CAC/C,EACA,GAAAC,CAAI3B,GAIF,GAHKwB,KAAKC,SACRD,KAAKC,OAAS,IAAIG,KAEhB5B,IAAUwB,KAAKC,OAAOF,IAAIP,KAI9BQ,KAAKC,OAAOE,IAAIX,EAAMhB,GACjBwB,KAAKK,aAIV,GAAIZ,GAIF,IAAKO,KAAKM,SAAU,CAClB,MAAMC,EAAYjC,SAAoBE,EAAOA,EAAO,eACpDO,EAAciB,KAAMR,EAAMe,EAC5B,OACSP,KAAKQ,YAAcR,KAAKS,cACjCT,KAAKU,aAET,GAEJ,CACF,CAWO,SAASC,EAASC,EAAS3B,EAAM4B,EAAUC,GAChD,GAAID,IAAaC,EAAU,CACzB,MAAMvC,SAAcqC,EAAQ3B,GACf,cAATV,GACFM,QAAQC,KAAK,qBAAqBG,sBAEpC,MAAM8B,EAAUzC,EAAaC,EAAMuC,EAAU,UAC7CF,EAAQ3B,GAAQ8B,CAClB,CACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"render.js","sources":["../src/common/render.js"],"sourcesContent":["import { collapseWhitespace, isRaw, resolveValue, toPlainText } from \"./utils.js\";\n\nconst stringsCache = new WeakMap();\nconst markerKey = \"e\" + Math.random().toString(36).slice(2, 6);\n\n/**\n * Render a tagged template into an Elena Element with DOM diffing.\n * Returns true if the DOM was fully rebuilt, false if only text\n * nodes were patched in place.\n *\n * @param {HTMLElement} element\n * @param {TemplateStringsArray} strings - Static parts of the tagged template\n * @param {Array} values - Dynamic interpolated values\n * @returns {boolean}\n */\nexport function renderTemplate(element, strings, values) {\n if (patchTextNodes(element, strings, values)) {\n return false;\n }\n fullRender(element, strings, values);\n return true;\n}\n\n/**\n * Fast path: patch only the text nodes whose values changed.\n *\n * @param {HTMLElement} element - The host element with cached template state\n * @param {TemplateStringsArray} strings - Static parts of the tagged template\n * @param {Array} values - Dynamic interpolated values\n * @returns {boolean} Whether patching was sufficient (false = full render)\n */\nfunction patchTextNodes(element, strings, values) {\n // Only works when re-rendering the same template shape\n if (element._tplStrings !== strings || !element._tplParts) {\n return false;\n }\n\n for (let i = 0; i < values.length; i++) {\n const v = values[i];\n const comparable = Array.isArray(v) ? toPlainText(v) : v;\n\n if (comparable === element._tplValues[i]) {\n continue;\n }\n\n if (isRaw(v) || !element._tplParts[i]) {\n return false;\n }\n\n element._tplValues[i] = comparable;\n element._tplParts[i].textContent = toPlainText(v);\n }\n\n return true;\n}\n\n/**\n * Cold path: clone a cached <template> and patch in values.\n *\n * @param {HTMLElement} element - The host element to render into\n * @param {TemplateStringsArray} strings - Static parts of the tagged template\n * @param {Array} values - Dynamic interpolated values\n */\nfunction fullRender(element, strings, values) {\n let entry = stringsCache.get(strings);\n\n if (!entry) {\n const processedStrings = Array.from(strings, collapseWhitespace);\n entry = {\n processedStrings,\n template: values.length > 0 ? createTemplate(processedStrings, values.length) : null,\n };\n stringsCache.set(strings, entry);\n }\n\n if (entry.template) {\n element._tplParts = cloneAndPatch(element, entry.template, values);\n } else {\n // Fallback for attribute-position values or static templates.\n // White space collapsing here protects against Vue SSR mismatches.\n const renderedValues = values.map(value => resolveValue(value));\n const markup = entry.processedStrings\n .reduce((out, str, i) => out + str + (renderedValues[i] ?? \"\"), \"\")\n .replace(/>\\s+</g, \"><\")\n .trim();\n\n // Morph existing DOM to match new markup instead of replacing it.\n const tpl = document.createElement(\"template\");\n tpl.innerHTML = markup;\n morphContent(element, tpl.content.childNodes);\n element._tplParts = null;\n }\n\n element._tplStrings = strings;\n element._tplValues = values.map(v => (Array.isArray(v) ? toPlainText(v) : v));\n}\n\n/**\n * Build a <template> element with comment markers.\n *\n * @param {string[]} processedStrings - Whitespace-collapsed static parts\n * @param {number} valueCount - Number of dynamic values\n * @returns {HTMLTemplateElement | null}\n */\nfunction createTemplate(processedStrings, valueCount) {\n const marker = `<!--${markerKey}-->`;\n const markup = processedStrings\n .reduce((out, str, i) => out + str + (i < valueCount ? marker : \"\"), \"\")\n .trim();\n\n const tpl = document.createElement(\"template\");\n tpl.innerHTML = markup;\n\n // Mismatch means this template shape cannot use the clone path.\n const walker = document.createTreeWalker(tpl.content, NodeFilter.SHOW_COMMENT);\n let count = 0;\n\n while (walker.nextNode()) {\n if (walker.currentNode.data === markerKey) {\n count++;\n }\n }\n\n return count === valueCount ? tpl : null;\n}\n\n/**\n * Clone a cached template and replace comment markers\n * with actual content.\n *\n * @param {HTMLElement} element - The host element to render into\n * @param {HTMLTemplateElement} template - Cached template with markers\n * @param {Array} values - Raw interpolated values\n * @returns {Array<Text | undefined>} Text node map for fast-path patching\n */\nfunction cloneAndPatch(element, template, values) {\n const clone = template.content.cloneNode(true);\n const walker = document.createTreeWalker(clone, NodeFilter.SHOW_COMMENT);\n const parts = new Array(values.length);\n const markers = [];\n let node;\n\n // Collect markers before modifying the tree\n while ((node = walker.nextNode())) {\n if (node.data === markerKey) {\n markers.push(node);\n }\n }\n\n for (let i = 0; i < markers.length; i++) {\n const value = values[i];\n\n if (isRaw(value)) {\n // Raw HTML: parse and insert as fragment\n const tmp = document.createElement(\"template\");\n tmp.innerHTML = resolveValue(value);\n markers[i].parentNode.replaceChild(tmp.content, markers[i]);\n\n // Raw values can't be fast-patched; leave parts undefined\n } else {\n // Create text node with unescaped content\n const textNode = document.createTextNode(toPlainText(value));\n markers[i].parentNode.replaceChild(textNode, markers[i]);\n parts[i] = textNode;\n }\n }\n\n element.replaceChildren(clone);\n return parts;\n}\n\n/**\n * Patches attributes and text content in-place when structure is stable,\n * preserving element identity and focus state across re-renders.\n *\n * @param {Node} parent\n * @param {NodeList} nextNodes - The desired child nodes from the new render\n */\nfunction morphContent(parent, nextNodes) {\n const current = Array.from(parent.childNodes);\n const next = Array.from(nextNodes);\n const len = Math.max(current.length, next.length);\n\n for (let i = 0; i < len; i++) {\n const cur = current[i];\n const nxt = next[i];\n\n if (!cur) {\n parent.appendChild(nxt);\n } else if (!nxt) {\n parent.removeChild(cur);\n } else if (\n cur.nodeType !== nxt.nodeType ||\n (cur.nodeType === Node.ELEMENT_NODE && cur.tagName !== nxt.tagName)\n ) {\n parent.replaceChild(nxt, cur);\n } else if (cur.nodeType === Node.TEXT_NODE) {\n if (cur.textContent !== nxt.textContent) {\n cur.textContent = nxt.textContent;\n }\n } else if (cur.nodeType === Node.ELEMENT_NODE) {\n morphAttributes(cur, nxt);\n morphContent(cur, nxt.childNodes);\n }\n }\n}\n\n/**\n * Morhp element’s attributes without rebuilding the DOM.\n *\n * @param {Element} current - The current existing DOM element\n * @param {Element} next - The desired element from the new render\n */\nfunction morphAttributes(current, next) {\n for (let i = current.attributes.length - 1; i >= 0; i--) {\n const { name } = current.attributes[i];\n\n if (!next.hasAttribute(name)) {\n current.removeAttribute(name);\n }\n }\n\n for (let i = 0; i < next.attributes.length; i++) {\n const { name, value } = next.attributes[i];\n\n if (current.getAttribute(name) !== value) {\n current.setAttribute(name, value);\n }\n }\n}\n"],"names":["stringsCache","WeakMap","markerKey","Math","random","toString","slice","renderTemplate","element","strings","values","_tplStrings","_tplParts","i","length","v","comparable","Array","isArray","toPlainText","_tplValues","isRaw","textContent","patchTextNodes","entry","get","processedStrings","from","collapseWhitespace","template","createTemplate","set","clone","content","cloneNode","walker","document","createTreeWalker","NodeFilter","SHOW_COMMENT","parts","markers","node","nextNode","data","push","value","tmp","createElement","innerHTML","resolveValue","parentNode","replaceChild","textNode","createTextNode","replaceChildren","cloneAndPatch","renderedValues","map","markup","reduce","out","str","replace","trim","tpl","morphContent","childNodes","fullRender","valueCount","marker","count","currentNode","parent","nextNodes","current","next","len","max","cur","nxt","nodeType","Node","ELEMENT_NODE","tagName","TEXT_NODE","morphAttributes","removeChild","appendChild","attributes","name","hasAttribute","removeAttribute","getAttribute","setAttribute"],"mappings":"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"}
package/dist/utils.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.js","sources":["../src/common/utils.js"],"sourcesContent":["/**\n * Register the Elena Element if the browser supports it.\n *\n * @param {string} tagName\n * @param {Function} Element\n */\nexport function defineElement(tagName, Element) {\n if (typeof window !== \"undefined\" && \"customElements\" in window) {\n if (!window.customElements.get(tagName)) {\n window.customElements.define(tagName, Element);\n }\n }\n}\n\n/**\n * Escape a string for safe insertion into HTML.\n *\n * @param {string} str\n * @returns {string}\n */\nconst Escape = { \"&\": \"&amp;\", \"<\": \"&lt;\", \">\": \"&gt;\", '\"': \"&quot;\", \"'\": \"&#39;\" };\nexport function escapeHtml(str) {\n return String(str).replace(/[&<>\"']/g, c => Escape[c]);\n}\n\n/**\n * Resolve an interpolated template value to its\n * HTML string representation.\n *\n * @param {*} value\n * @returns {string}\n */\nexport function resolveValue(value) {\n if (Array.isArray(value)) {\n return value.map(item => resolveItem(item)).join(\"\");\n }\n return resolveItem(value);\n}\n\n/**\n * Resolve a single value to its HTML string\n * representation.\n *\n * @param {*} value\n * @returns {string}\n */\nfunction resolveItem(value) {\n return value?.__raw ? String(value) : escapeHtml(String(value ?? \"\"));\n}\n\n/**\n * Tagged template for trusted HTML. Use as the return value\n * of render(), or for sub-fragments inside render methods.\n *\n * @param {TemplateStringsArray} strings\n * @param {...*} values\n * @returns {{ __raw: true, strings: TemplateStringsArray, values: Array, toString(): string }}\n */\nexport function html(strings, ...values) {\n let str;\n return {\n __raw: true,\n strings,\n values,\n toString: () => {\n if (str === undefined) {\n str = strings.reduce((acc, s, i) => {\n return acc + s + resolveValue(values[i]);\n }, \"\");\n }\n return str;\n },\n };\n}\n\n/**\n * Renders a string as HTML rather than text.\n *\n * @param {string} str - The raw HTML string to trust.\n * @returns {{ __raw: true, toString(): string }}\n */\nexport function unsafeHTML(str) {\n return { __raw: true, toString: () => str ?? \"\" };\n}\n\n/**\n * A placeholder you can return from a conditional expression\n * inside a template to render nothing.\n *\n * @type {{ __raw: true, toString(): string }}\n */\nexport const nothing = Object.freeze({ __raw: true, toString: () => \"\" });\n\n/**\n * Check if a value contains trusted HTML fragments.\n *\n * @param {*} value\n * @returns {boolean}\n */\nexport const isRaw = value =>\n Array.isArray(value) ? value.some(item => item?.__raw) : value?.__raw;\n\n/**\n * Convert a value to its plain text string.\n *\n * @param {*} value\n * @returns {string}\n */\nexport const toPlainText = value =>\n Array.isArray(value) ? value.map(item => String(item ?? \"\")).join(\"\") : String(value ?? \"\");\n\n/**\n * Collapse whitespace from a static string part.\n *\n * @param {string} string\n * @returns {string}\n */\nexport function collapseWhitespace(string) {\n return string\n .replace(/>\\n\\s*/g, \">\") // newline after tag close\n .replace(/\\n\\s*</g, \"<\") // newline before tag open\n .replace(/\\n\\s*/g, \" \") // newline in text content, preserve word boundary\n .replace(/>\\s+</g, \"><\"); // whitespace between tags\n}\n"],"names":["defineElement","tagName","Element","window","customElements","get","define","Escape","escapeHtml","str","String","replace","c","resolveValue","value","Array","isArray","map","item","resolveItem","join","__raw","html","strings","values","toString","undefined","reduce","acc","s","i","unsafeHTML","nothing","Object","freeze","isRaw","some","toPlainText","collapseWhitespace","string"],"mappings":"AAMO,SAASA,EAAcC,EAASC,GACf,oBAAXC,QAA0B,mBAAoBA,SAClDA,OAAOC,eAAeC,IAAIJ,IAC7BE,OAAOC,eAAeE,OAAOL,EAASC,GAG5C,CAQA,MAAMK,EAAS,CAAE,IAAK,QAAS,IAAK,OAAQ,IAAK,OAAQ,IAAK,SAAU,IAAK,SACtE,SAASC,EAAWC,GACzB,OAAOC,OAAOD,GAAKE,QAAQ,WAAYC,GAAKL,EAAOK,GACrD,CASO,SAASC,EAAaC,GAC3B,OAAIC,MAAMC,QAAQF,GACTA,EAAMG,IAAIC,GAAQC,EAAYD,IAAOE,KAAK,IAE5CD,EAAYL,EACrB,CASA,SAASK,EAAYL,GACnB,OAAOA,GAAOO,MAAQX,OAAOI,GAASN,EAAWE,OAAOI,GAAS,IACnE,CAUO,SAASQ,EAAKC,KAAYC,GAC/B,IAAIf,EACJ,MAAO,CACLY,OAAO,EACPE,UACAC,SACAC,SAAU,UACIC,IAARjB,IACFA,EAAMc,EAAQI,OAAO,CAACC,EAAKC,EAAGC,IACrBF,EAAMC,EAAIhB,EAAaW,EAAOM,IACpC,KAEErB,GAGb,CAQO,SAASsB,EAAWtB,GACzB,MAAO,CAAEY,OAAO,EAAMI,SAAU,IAAMhB,GAAO,GAC/C,CAQY,MAACuB,EAAUC,OAAOC,OAAO,CAAEb,OAAO,EAAMI,SAAU,IAAM,KAQvDU,EAAQrB,GACnBC,MAAMC,QAAQF,GAASA,EAAMsB,KAAKlB,GAAQA,GAAMG,OAASP,GAAOO,MAQrDgB,EAAcvB,GACzBC,MAAMC,QAAQF,GAASA,EAAMG,IAAIC,GAAQR,OAAOQ,GAAQ,KAAKE,KAAK,IAAMV,OAAOI,GAAS,IAQnF,SAASwB,EAAmBC,GACjC,OAAOA,EACJ5B,QAAQ,UAAW,KACnBA,QAAQ,UAAW,KACnBA,QAAQ,SAAU,KAClBA,QAAQ,SAAU,KACvB"}