@elenajs/core 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/bundle.js +2 -0
- package/dist/bundle.js.map +1 -0
- package/dist/common/events.d.ts +8 -0
- package/dist/common/events.d.ts.map +1 -0
- package/dist/common/props.d.ts +36 -0
- package/dist/common/props.d.ts.map +1 -0
- package/dist/common/render.d.ts +27 -0
- package/dist/common/render.d.ts.map +1 -0
- package/dist/common/utils.d.ts +28 -0
- package/dist/common/utils.d.ts.map +1 -0
- package/dist/elena.d.ts +59 -0
- package/dist/elena.d.ts.map +1 -0
- package/dist/elena.js +2 -0
- package/dist/elena.js.map +1 -0
- package/dist/events.js +2 -0
- package/dist/events.js.map +1 -0
- package/dist/props.js +2 -0
- package/dist/props.js.map +1 -0
- package/dist/render.js +2 -0
- package/dist/render.js.map +1 -0
- package/dist/utils.js +2 -0
- package/dist/utils.js.map +1 -0
- package/package.json +34 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ariel Salminen https://arielsalminen.com
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/bundle.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function e(e,t,n){if(t="boolean"===e&&"boolean"!=typeof t?null!==t:t,!n)return t;if("toAttribute"===n)switch(e){case"object":case"array":return null===t?null:JSON.stringify(t);case"boolean":return t?"":null;case"number":return null===t?null:t;default:return t}else switch(e){case"object":case"array":return t&&JSON.parse(t);case"boolean":default:return t;case"number":return null!==t?+t:t}}function t(e,t,n){e?null===n?e.removeAttribute(t):e.setAttribute(t,n):console.warn("░█ [ELENA]: Cannot sync attributes to a null element.")}class n extends Event{constructor(e,t){super(e,{bubbles:!0,composed:!0,...t})}}function r(e,t){"undefined"!=typeof window&&"customElements"in window&&(window.customElements.get(e)||window.customElements.define(e,t))}function s(e){const t={"&":"&","<":"<",">":">",'"':""","'":"'"};return String(e).replace(/[&<>"']/g,e=>t[e])}function i(e,...t){const n=e.reduce((e,n,r)=>e+n+s(String(t[r]??"")),"");return{__raw:!0,toString:()=>n}}function o(e,t,n){(function(e,t,n){if(e._tplStrings!==t||!e._tplParts)return!1;let r=!1;for(let t=0;t<n.length;t++){const i=n[t],o=i&&i.__raw,l=o?String(i):s(String(i??""));if(l!==e._tplValues[t])if(e._tplValues[t]=l,o)r=!0;else{const n=e._tplParts[t];n?n.textContent=String(i??""):r=!0}}return!r})(e,t,n)||function(e,t,n){const r=n.map(e=>e&&e.__raw?String(e):s(String(e??""))),i=t.reduce((e,t,n)=>e+t.replace(/\n\s*/g," ")+(r[n]??""),"").replace(/>\s+</g,"><").replace(/>\s+/g,">").replace(/\s+</g,"<").trim();(function(e,t){if(!e)return void console.warn("░█ [ELENA]: Cannot render to a null element.");e.replaceChildren((l??=document.createRange()).createContextualFragment(t))})(e,i),e._tplStrings=t,e._tplValues=r,e._tplParts=function(e,t){const n=new Array(t.length),r=document.createTreeWalker(e,NodeFilter.SHOW_TEXT);let s,i=0;for(;(s=r.nextNode())&&i<t.length;)s.textContent===t[i]&&(n[i]=s,i++);return n}(e,r)}(e,t,n)}let l;function a(r,s){const i=s&&s.element?/^[a-z][a-z0-9-]*$/i.test(s.element)?e=>e.getElementsByClassName(s.element)[0]:e=>e.querySelector(s.element):e=>e.firstElementChild;class l extends r{element=null;attributeChangedCallback(t,n,r){!function(t,n,r,s){if(r!==s){const r=e(typeof t[n],s,"toProp");t[n]=r}}(this,t,n,r),this.element&&n!==r&&this.render()}static get observedAttributes(){return s&&s.props?s.props:[]}render(){}template(e,...t){o(this,e,t)}connectedCallback(){if(this.render(),this.element||(this.element=i(this),this.element||(console.warn("░█ [ELENA]: No element found, using firstElementChild as fallback."),this.element=this.firstElementChild)),this._props)for(const[n,r]of this._props){const s=e(typeof r,r,"toAttribute");"string"==typeof r&&""===r?(this.removeAttribute(n),this.element.removeAttribute(n)):(t(this,n,s),t(this.element,n,s))}!this._events&&s&&s.events&&(this._events=!0,s.events?.forEach(e=>{this.element.addEventListener(e,this),this[e]=(...t)=>this.element[e](...t)})),this.updated()}updated(){this._hydrated||(this._hydrated=!0,this.classList.add("elena-hydrated"))}disconnectedCallback(){this._events&&(this._events=!1,s.events?.forEach(e=>{this.element?.removeEventListener(e,this)}))}handleEvent(e){s.events?.includes(e.type)&&(e.stopPropagation(),this.dispatchEvent(new n(e.type,{cancelable:!0})))}}return s&&s.props?.length&&function(n,r){for(const s of r)Object.defineProperty(n,s,{configurable:!0,enumerable:!0,get(){return this._props?this._props.get(s):void 0},set(n){if(this._props||(this._props=new Map),n===this._props.get(s))return;if(this._props.set(s,n),!this.isConnected)return;const r=e(typeof n,n,"toAttribute");t(this,s,r),this.element&&t(this.element,s,r)}})}(l.prototype,s.props),l}export{a as Elena,r as defineElement,i as html};
|
|
2
|
+
//# sourceMappingURL=bundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle.js","sources":["../src/common/props.js","../src/common/events.js","../src/common/utils.js","../src/common/render.js","../src/elena.js"],"sourcesContent":["/**\n * Get the value of the Elena Custom Element prop.\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;\n }\n } else {\n switch (type) {\n case \"object\":\n case \"array\":\n return value && JSON.parse(value);\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 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 attributes to a null element.\");\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[]} properties - Prop names to define\n */\nexport function setProps(proto, properties) {\n for (const prop of properties) {\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 const attrValue = getPropValue(typeof value, value, \"toAttribute\");\n syncAttribute(this, prop, attrValue);\n if (this.element) {\n syncAttribute(this.element, prop, attrValue);\n }\n },\n });\n }\n}\n\n/**\n * We need to update the internals of our component\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 const newAttr = getPropValue(type, newValue, \"toProp\");\n context[name] = newAttr;\n }\n}\n","/**\n * A base class for events which defaults to\n * bubbling and composed.\n */\nexport class ElenaEvent extends Event {\n constructor(type, eventInitDict) {\n super(type, {\n bubbles: true,\n composed: true,\n ...eventInitDict,\n });\n }\n}\n","/**\n * Register the Elena custom element if the\n * 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 */\nexport function escapeHtml(str) {\n const Escape = { \"&\": \"&\", \"<\": \"<\", \">\": \">\", '\"': \""\", \"'\": \"'\" };\n return String(str).replace(/[&<>\"']/g, c => Escape[c]);\n}\n\n/**\n * Tagged template for trusted HTML fragments with auto-escaped interpolations.\n * Use inside `this.template` for conditional HTML blocks.\n *\n * @param {TemplateStringsArray} strings\n * @param {...*} values\n * @returns {{ __raw: true, toString(): string }}\n */\nexport function html(strings, ...values) {\n const result = strings.reduce(\n (acc, str, i) => acc + str + escapeHtml(String(values[i] ?? \"\")),\n \"\"\n );\n return { __raw: true, toString: () => result };\n}\n","import { escapeHtml } from \"./utils.js\";\n\n/**\n * Render a tagged template into an element with DOM diffing.\n *\n * On first render, builds the full HTML markup and render.\n * On re-renders, patches only the text nodes whose values changed,\n * avoiding a full DOM rebuild.\n *\n * Cache state is stored on the element instance:\n * _tplStrings — reference to the template's static strings array\n * _tplValues — array of escaped values from the last render\n * _tplParts — array mapping each value index to its DOM text node\n *\n * @param {HTMLElement} element\n * @param {TemplateStringsArray} strings - Static parts of the tagged template\n * @param {Array} values - Dynamic interpolated values\n */\nexport function renderTemplate(element, strings, values) {\n if (patchTextNodes(element, strings, values)) {\n return;\n }\n fullRender(element, strings, values);\n}\n\n/**\n * Fast path: patch only the text nodes whose values changed.\n * Returns true if all changes were handled (no full render needed).\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 let needsFullRender = false;\n\n for (let i = 0; i < values.length; i++) {\n const v = values[i];\n const isRaw = v && v.__raw;\n const newRendered = isRaw ? String(v) : escapeHtml(String(v ?? \"\"));\n const oldRendered = element._tplValues[i];\n\n if (newRendered === oldRendered) {\n continue;\n }\n\n element._tplValues[i] = newRendered;\n\n // Raw HTML values or attribute-position values require a full render\n if (isRaw) {\n needsFullRender = true;\n } else {\n const textNode = element._tplParts[i];\n if (textNode) {\n // Value is in a text position — update the DOM node directly\n textNode.textContent = String(v ?? \"\");\n } else {\n // Value is in an attribute position — can't patch, need full render\n needsFullRender = true;\n }\n }\n }\n\n return !needsFullRender;\n}\n\n/**\n * Cold path: build full HTML markup, render it via DocumentFragment,\n * and map each interpolated value to its corresponding DOM text node\n * for future fast-path patching.\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 const renderedValues = values.map(v => (v && v.__raw ? String(v) : escapeHtml(String(v ?? \"\"))));\n\n // Build the complete HTML string, stripping template indentation.\n // 1. Replace newlines + indentation with a single space (preserves attribute separation)\n // 2. Clean up: remove whitespace between/around tags and trim\n const markup = strings\n .reduce((out, str, i) => out + str.replace(/\\n\\s*/g, \" \") + (renderedValues[i] ?? \"\"), \"\")\n .replace(/>\\s+</g, \"><\")\n .replace(/>\\s+/g, \">\")\n .replace(/\\s+</g, \"<\")\n .trim();\n\n renderHtml(element, markup);\n\n // Cache template identity and rendered values\n element._tplStrings = strings;\n element._tplValues = renderedValues;\n\n // Walk text nodes to map each value index to its DOM node\n element._tplParts = mapTextNodes(element, renderedValues);\n}\n\n/**\n * Walk the element's text nodes and map each escaped value\n * to its corresponding DOM text node. Values in attribute\n * positions won't have a matching text node and will be null.\n *\n * @param {HTMLElement} element - The host element to walk\n * @param {string[]} escapedValues - HTML-escaped interpolated values\n * @returns {Array<Text | undefined>} Array mapping each value index to its text node\n */\nfunction mapTextNodes(element, escapedValues) {\n const parts = new Array(escapedValues.length);\n const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);\n\n let valueIndex = 0;\n let node;\n\n while ((node = walker.nextNode()) && valueIndex < escapedValues.length) {\n if (node.textContent === escapedValues[valueIndex]) {\n parts[valueIndex] = node;\n valueIndex++;\n }\n }\n\n return parts;\n}\n\n/**\n * Lazily-created Range reused across renders as a createContextualFragment\n * factory. Deferred so the module can be imported in non-browser environments.\n *\n * @type {Range | undefined}\n */\nlet _range;\n\n/**\n * Render an HTML string into an element by parsing it into a\n * DocumentFragment via createContextualFragment and swapping\n * the element's children in a single replaceChildren call.\n *\n * @param {HTMLElement} element\n * @param {string} markup\n */\nexport function renderHtml(element, markup) {\n if (!element) {\n console.warn(\"░█ [ELENA]: Cannot render to a null element.\");\n return;\n }\n element.replaceChildren((_range ??= document.createRange()).createContextualFragment(markup));\n}\n","import { setProps, getProps, getPropValue, syncAttribute } from \"./common/props.js\";\nimport { ElenaEvent } from \"./common/events.js\";\nimport { defineElement, html } from \"./common/utils.js\";\nimport { renderTemplate } from \"./common/render.js\";\n\nexport { defineElement, html };\n\n/**\n * ██████████ ████\n * ░░███░░░░░█░░███\n * ░███ █ ░ ░███ ██████ ████████ ██████\n * ░██████ ░███ ███░░███░░███░░███ ░░░░░███\n * ░███░░█ ░███ ░███████ ░███ ░███ ███████\n * ░███ ░ █ ░███ ░███░░░ ░███ ░███ ███░░███\n * ██████████ █████░░██████ ████ █████░░████████\n * ░░░░░░░░░░ ░░░░░ ░░░░░░ ░░░░ ░░░░░ ░░░░░░░░\n *\n * Elena Custom Elements\n * https://elenajs.com\n *\n * @constructor\n * @param {ElenaConstructor} superClass - Class constructor to extend.\n * @param {ElenaOptions} options - Configuration options for Elena.\n * @returns {CustomElementConstructor}\n */\nexport function Elena(superClass, options) {\n /**\n * Pre-compile element resolver once at class definition\n * time to improve performance:\n *\n * 1. no selector: firstElementChild (property access)\n * 2. className: getElementsByClassName (skips full selector parser)\n * 3. any other: querySelector (full parser, only when needed)\n */\n const resolveElement = !(options && options.element)\n ? host => host.firstElementChild\n : /^[a-z][a-z0-9-]*$/i.test(options.element)\n ? host => host.getElementsByClassName(options.element)[0]\n : host => host.querySelector(options.element);\n\n /**\n * Set up the initial state and default\n * values for the Elena Custom Element.\n */\n class ElenaElement extends superClass {\n /**\n * Reference to the base element in the provided template.\n *\n * @type {Object}\n */\n element = null;\n\n /**\n * This method is called when the Elena Element’s\n * props are changed, added, removed or replaced.\n *\n * @param {string} prop\n * @param {string} oldValue\n * @param {string} newValue\n */\n attributeChangedCallback(prop, oldValue, newValue) {\n getProps(this, prop, oldValue, newValue);\n\n // Re-render when attributes change (after initial render)\n if (this.element && oldValue !== newValue) {\n this.render();\n }\n }\n\n /**\n * This static method returns an array containing the\n * names of the props we want to observe.\n */\n static get observedAttributes() {\n return options && options.props ? options.props : [];\n }\n\n /**\n * Override in subclasses to define the element's HTML structure.\n * No-op by default — elements without a render method connect safely.\n */\n render() {}\n\n /**\n * Render a tagged template literal with auto-escaping and DOM diffing.\n * Usage: this.template`<span>${this.label}</span>`\n *\n * @param {TemplateStringsArray} strings\n * @param {...*} values\n */\n template(strings, ...values) {\n renderTemplate(this, strings, values);\n }\n\n /**\n * This method is called each time the Elena\n * Custom Element is added to the document.\n */\n connectedCallback() {\n this.render();\n\n if (!this.element) {\n this.element = resolveElement(this);\n\n if (!this.element) {\n console.warn(\"░█ [ELENA]: No element found, using firstElementChild as fallback.\");\n this.element = this.firstElementChild;\n }\n }\n\n // Flush props set before connection to host and inner element attributes\n if (this._props) {\n for (const [prop, value] of this._props) {\n const attrValue = getPropValue(typeof value, value, \"toAttribute\");\n if (typeof value === \"string\" && value === \"\") {\n this.removeAttribute(prop);\n this.element.removeAttribute(prop);\n } else {\n syncAttribute(this, prop, attrValue);\n syncAttribute(this.element, prop, attrValue);\n }\n }\n }\n\n if (!this._events && options && options.events) {\n this._events = true;\n options.events?.forEach(e => {\n this.element.addEventListener(e, this);\n this[e] = (...args) => this.element[e](...args);\n });\n }\n\n this.updated();\n }\n\n /**\n * Perform post-update after each render().\n *\n * @internal\n */\n updated() {\n if (!this._hydrated) {\n this._hydrated = true;\n this.classList.add(\"elena-hydrated\");\n }\n }\n\n /**\n * This method is called each time the Elena Custom\n * Element is removed from the document.\n */\n disconnectedCallback() {\n if (this._events) {\n this._events = false;\n options.events?.forEach(e => {\n this.element?.removeEventListener(e, this);\n });\n }\n }\n\n /**\n * Handles events on the custom element.\n *\n * @internal\n */\n handleEvent(event) {\n if (options.events?.includes(event.type)) {\n event.stopPropagation();\n /** @internal */\n this.dispatchEvent(new ElenaEvent(event.type, { cancelable: true }));\n }\n }\n }\n\n if (options && options.props?.length) {\n setProps(ElenaElement.prototype, options.props);\n }\n\n return ElenaElement;\n}\n\n/**\n * @typedef {Object} ElenaOptions\n * @property {string[]} [props] - Props observed and synced as attributes.\n * @property {string[]} [events] - Events to delegate from the inner element.\n * @property {string} [element] - CSS selector for the inner element.\n */\n\n/**\n * @typedef {new (...args: any[]) => HTMLElement} ElenaConstructor\n */\n"],"names":["getPropValue","type","value","transform","JSON","stringify","parse","syncAttribute","element","name","removeAttribute","setAttribute","console","warn","ElenaEvent","Event","constructor","eventInitDict","super","bubbles","composed","defineElement","tagName","Element","window","customElements","get","define","escapeHtml","str","Escape","String","replace","c","html","strings","values","result","reduce","acc","i","__raw","toString","renderTemplate","_tplStrings","_tplParts","needsFullRender","length","v","isRaw","newRendered","_tplValues","textNode","textContent","patchTextNodes","renderedValues","map","markup","out","trim","replaceChildren","_range","document","createRange","createContextualFragment","renderHtml","escapedValues","parts","Array","walker","createTreeWalker","NodeFilter","SHOW_TEXT","node","valueIndex","nextNode","mapTextNodes","fullRender","Elena","superClass","options","resolveElement","test","host","getElementsByClassName","querySelector","firstElementChild","ElenaElement","attributeChangedCallback","prop","oldValue","newValue","context","newAttr","getProps","this","render","observedAttributes","props","template","connectedCallback","_props","attrValue","_events","events","forEach","e","addEventListener","args","updated","_hydrated","classList","add","disconnectedCallback","removeEventListener","handleEvent","event","includes","stopPropagation","dispatchEvent","cancelable","proto","properties","Object","defineProperty","configurable","enumerable","undefined","set","Map","isConnected","setProps","prototype"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/common/events.js"],"names":[],"mappings":"AAAA;;;GAGG;AACH;IACE,2CAMC;CACF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get the value of the Elena Custom Element prop.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} type
|
|
5
|
+
* @param {any} value
|
|
6
|
+
* @param {"toAttribute" | "toProp"} [transform]
|
|
7
|
+
*/
|
|
8
|
+
export function getPropValue(type: string, value: any, transform?: "toAttribute" | "toProp"): any;
|
|
9
|
+
/**
|
|
10
|
+
* Set or remove an attribute on an element.
|
|
11
|
+
*
|
|
12
|
+
* @param {Element} element - Target element
|
|
13
|
+
* @param {string} name - Attribute name
|
|
14
|
+
* @param {string | null} value - Attribute value, or null to remove
|
|
15
|
+
*/
|
|
16
|
+
export function syncAttribute(element: Element, name: string, value: string | null): void;
|
|
17
|
+
/**
|
|
18
|
+
* Define prop getters/setters on the prototype once
|
|
19
|
+
* at class-creation time. Values are stored per-instance
|
|
20
|
+
* via a `_props` Map that is lazily created.
|
|
21
|
+
*
|
|
22
|
+
* @param {Function} proto - The class prototype
|
|
23
|
+
* @param {string[]} properties - Prop names to define
|
|
24
|
+
*/
|
|
25
|
+
export function setProps(proto: Function, properties: string[]): void;
|
|
26
|
+
/**
|
|
27
|
+
* We need to update the internals of our component
|
|
28
|
+
* when props on the host element are changed.
|
|
29
|
+
*
|
|
30
|
+
* @param {object} context
|
|
31
|
+
* @param {string} name
|
|
32
|
+
* @param {any} oldValue
|
|
33
|
+
* @param {any} newValue
|
|
34
|
+
*/
|
|
35
|
+
export function getProps(context: object, name: string, oldValue: any, newValue: any): void;
|
|
36
|
+
//# sourceMappingURL=props.d.ts.map
|
|
@@ -0,0 +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,OAgClC;AAED;;;;;;GAMG;AACH,uCAJW,OAAO,QACP,MAAM,SACN,MAAM,GAAG,IAAI,QAYvB;AAED;;;;;;;GAOG;AACH,sDAFW,MAAM,EAAE,QA+BlB;AAED;;;;;;;;GAQG;AACH,kCALW,MAAM,QACN,MAAM,YACN,GAAG,YACH,GAAG,QAQb"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render a tagged template into an element with DOM diffing.
|
|
3
|
+
*
|
|
4
|
+
* On first render, builds the full HTML markup and render.
|
|
5
|
+
* On re-renders, patches only the text nodes whose values changed,
|
|
6
|
+
* avoiding a full DOM rebuild.
|
|
7
|
+
*
|
|
8
|
+
* Cache state is stored on the element instance:
|
|
9
|
+
* _tplStrings — reference to the template's static strings array
|
|
10
|
+
* _tplValues — array of escaped values from the last render
|
|
11
|
+
* _tplParts — array mapping each value index to its DOM text node
|
|
12
|
+
*
|
|
13
|
+
* @param {HTMLElement} element
|
|
14
|
+
* @param {TemplateStringsArray} strings - Static parts of the tagged template
|
|
15
|
+
* @param {Array} values - Dynamic interpolated values
|
|
16
|
+
*/
|
|
17
|
+
export function renderTemplate(element: HTMLElement, strings: TemplateStringsArray, values: any[]): void;
|
|
18
|
+
/**
|
|
19
|
+
* Render an HTML string into an element by parsing it into a
|
|
20
|
+
* DocumentFragment via createContextualFragment and swapping
|
|
21
|
+
* the element's children in a single replaceChildren call.
|
|
22
|
+
*
|
|
23
|
+
* @param {HTMLElement} element
|
|
24
|
+
* @param {string} markup
|
|
25
|
+
*/
|
|
26
|
+
export function renderHtml(element: HTMLElement, markup: string): void;
|
|
27
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/common/render.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AACH,wCAJW,WAAW,WACX,oBAAoB,uBAQ9B;AAmHD;;;;;;;GAOG;AACH,oCAHW,WAAW,UACX,MAAM,QAQhB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register the Elena custom element if the
|
|
3
|
+
* browser supports it.
|
|
4
|
+
*
|
|
5
|
+
* @param {string} tagName
|
|
6
|
+
* @param {Function} Element
|
|
7
|
+
*/
|
|
8
|
+
export function defineElement(tagName: string, Element: Function): void;
|
|
9
|
+
/**
|
|
10
|
+
* Escape a string for safe insertion into HTML.
|
|
11
|
+
*
|
|
12
|
+
* @param {string} str
|
|
13
|
+
* @returns {string}
|
|
14
|
+
*/
|
|
15
|
+
export function escapeHtml(str: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Tagged template for trusted HTML fragments with auto-escaped interpolations.
|
|
18
|
+
* Use inside `this.template` for conditional HTML blocks.
|
|
19
|
+
*
|
|
20
|
+
* @param {TemplateStringsArray} strings
|
|
21
|
+
* @param {...*} values
|
|
22
|
+
* @returns {{ __raw: true, toString(): string }}
|
|
23
|
+
*/
|
|
24
|
+
export function html(strings: TemplateStringsArray, ...values: any[]): {
|
|
25
|
+
__raw: true;
|
|
26
|
+
toString(): string;
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/common/utils.js"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,uCAHW,MAAM,2BAShB;AAED;;;;;GAKG;AACH,gCAHW,MAAM,GACJ,MAAM,CAKlB;AAED;;;;;;;GAOG;AACH,8BAJW,oBAAoB,aACjB,GAAC,EAAA,GACF;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,IAAI,MAAM,CAAA;CAAE,CAQ/C"}
|
package/dist/elena.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ██████████ ████
|
|
3
|
+
* ░░███░░░░░█░░███
|
|
4
|
+
* ░███ █ ░ ░███ ██████ ████████ ██████
|
|
5
|
+
* ░██████ ░███ ███░░███░░███░░███ ░░░░░███
|
|
6
|
+
* ░███░░█ ░███ ░███████ ░███ ░███ ███████
|
|
7
|
+
* ░███ ░ █ ░███ ░███░░░ ░███ ░███ ███░░███
|
|
8
|
+
* ██████████ █████░░██████ ████ █████░░████████
|
|
9
|
+
* ░░░░░░░░░░ ░░░░░ ░░░░░░ ░░░░ ░░░░░ ░░░░░░░░
|
|
10
|
+
*
|
|
11
|
+
* Elena Custom Elements
|
|
12
|
+
* https://elenajs.com
|
|
13
|
+
*
|
|
14
|
+
* @constructor
|
|
15
|
+
* @param {ElenaConstructor} superClass - Class constructor to extend.
|
|
16
|
+
* @param {ElenaOptions} options - Configuration options for Elena.
|
|
17
|
+
* @returns {CustomElementConstructor}
|
|
18
|
+
*/
|
|
19
|
+
export function Elena(superClass: ElenaConstructor, options: ElenaOptions): CustomElementConstructor;
|
|
20
|
+
export class Elena {
|
|
21
|
+
/**
|
|
22
|
+
* ██████████ ████
|
|
23
|
+
* ░░███░░░░░█░░███
|
|
24
|
+
* ░███ █ ░ ░███ ██████ ████████ ██████
|
|
25
|
+
* ░██████ ░███ ███░░███░░███░░███ ░░░░░███
|
|
26
|
+
* ░███░░█ ░███ ░███████ ░███ ░███ ███████
|
|
27
|
+
* ░███ ░ █ ░███ ░███░░░ ░███ ░███ ███░░███
|
|
28
|
+
* ██████████ █████░░██████ ████ █████░░████████
|
|
29
|
+
* ░░░░░░░░░░ ░░░░░ ░░░░░░ ░░░░ ░░░░░ ░░░░░░░░
|
|
30
|
+
*
|
|
31
|
+
* Elena Custom Elements
|
|
32
|
+
* https://elenajs.com
|
|
33
|
+
*
|
|
34
|
+
* @constructor
|
|
35
|
+
* @param {ElenaConstructor} superClass - Class constructor to extend.
|
|
36
|
+
* @param {ElenaOptions} options - Configuration options for Elena.
|
|
37
|
+
* @returns {CustomElementConstructor}
|
|
38
|
+
*/
|
|
39
|
+
constructor(superClass: ElenaConstructor, options: ElenaOptions);
|
|
40
|
+
}
|
|
41
|
+
export type ElenaOptions = {
|
|
42
|
+
/**
|
|
43
|
+
* - Props observed and synced as attributes.
|
|
44
|
+
*/
|
|
45
|
+
props?: string[];
|
|
46
|
+
/**
|
|
47
|
+
* - Events to delegate from the inner element.
|
|
48
|
+
*/
|
|
49
|
+
events?: string[];
|
|
50
|
+
/**
|
|
51
|
+
* - CSS selector for the inner element.
|
|
52
|
+
*/
|
|
53
|
+
element?: string;
|
|
54
|
+
};
|
|
55
|
+
export type ElenaConstructor = new (...args: any[]) => HTMLElement;
|
|
56
|
+
import { defineElement } from "./common/utils.js";
|
|
57
|
+
import { html } from "./common/utils.js";
|
|
58
|
+
export { defineElement, html };
|
|
59
|
+
//# sourceMappingURL=elena.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elena.d.ts","sourceRoot":"","sources":["../src/elena.js"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;GAiBG;AACH,kCAJW,gBAAgB,WAChB,YAAY,GACV,wBAAwB,CA4JpC;;IA5KD;;;;;;;;;;;;;;;;;OAiBG;IACH,wBAJW,gBAAgB,WAChB,YAAY,EA6JtB;;;;;;YAIa,MAAM,EAAE;;;;aACR,MAAM,EAAE;;;;cACR,MAAM;;+BAIP,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,WAAW;8BA3LZ,mBAAmB;qBAAnB,mBAAmB"}
|
package/dist/elena.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{setProps as e,getProps as t,getPropValue as s,syncAttribute as n}from"./props.js";import{ElenaEvent as i}from"./events.js";export{defineElement,html}from"./utils.js";import{renderTemplate as r}from"./render.js";function l(l,h){const o=h&&h.element?/^[a-z][a-z0-9-]*$/i.test(h.element)?e=>e.getElementsByClassName(h.element)[0]:e=>e.querySelector(h.element):e=>e.firstElementChild;class a extends l{element=null;attributeChangedCallback(e,s,n){t(this,e,s,n),this.element&&s!==n&&this.render()}static get observedAttributes(){return h&&h.props?h.props:[]}render(){}template(e,...t){r(this,e,t)}connectedCallback(){if(this.render(),this.element||(this.element=o(this),this.element||(console.warn("░█ [ELENA]: No element found, using firstElementChild as fallback."),this.element=this.firstElementChild)),this._props)for(const[e,t]of this._props){const i=s(typeof t,t,"toAttribute");"string"==typeof t&&""===t?(this.removeAttribute(e),this.element.removeAttribute(e)):(n(this,e,i),n(this.element,e,i))}!this._events&&h&&h.events&&(this._events=!0,h.events?.forEach(e=>{this.element.addEventListener(e,this),this[e]=(...t)=>this.element[e](...t)})),this.updated()}updated(){this._hydrated||(this._hydrated=!0,this.classList.add("elena-hydrated"))}disconnectedCallback(){this._events&&(this._events=!1,h.events?.forEach(e=>{this.element?.removeEventListener(e,this)}))}handleEvent(e){h.events?.includes(e.type)&&(e.stopPropagation(),this.dispatchEvent(new i(e.type,{cancelable:!0})))}}return h&&h.props?.length&&e(a.prototype,h.props),a}export{l as Elena};
|
|
2
|
+
//# sourceMappingURL=elena.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elena.js","sources":["../src/elena.js"],"sourcesContent":["import { setProps, getProps, getPropValue, syncAttribute } from \"./common/props.js\";\nimport { ElenaEvent } from \"./common/events.js\";\nimport { defineElement, html } from \"./common/utils.js\";\nimport { renderTemplate } from \"./common/render.js\";\n\nexport { defineElement, html };\n\n/**\n * ██████████ ████\n * ░░███░░░░░█░░███\n * ░███ █ ░ ░███ ██████ ████████ ██████\n * ░██████ ░███ ███░░███░░███░░███ ░░░░░███\n * ░███░░█ ░███ ░███████ ░███ ░███ ███████\n * ░███ ░ █ ░███ ░███░░░ ░███ ░███ ███░░███\n * ██████████ █████░░██████ ████ █████░░████████\n * ░░░░░░░░░░ ░░░░░ ░░░░░░ ░░░░ ░░░░░ ░░░░░░░░\n *\n * Elena Custom Elements\n * https://elenajs.com\n *\n * @constructor\n * @param {ElenaConstructor} superClass - Class constructor to extend.\n * @param {ElenaOptions} options - Configuration options for Elena.\n * @returns {CustomElementConstructor}\n */\nexport function Elena(superClass, options) {\n /**\n * Pre-compile element resolver once at class definition\n * time to improve performance:\n *\n * 1. no selector: firstElementChild (property access)\n * 2. className: getElementsByClassName (skips full selector parser)\n * 3. any other: querySelector (full parser, only when needed)\n */\n const resolveElement = !(options && options.element)\n ? host => host.firstElementChild\n : /^[a-z][a-z0-9-]*$/i.test(options.element)\n ? host => host.getElementsByClassName(options.element)[0]\n : host => host.querySelector(options.element);\n\n /**\n * Set up the initial state and default\n * values for the Elena Custom Element.\n */\n class ElenaElement extends superClass {\n /**\n * Reference to the base element in the provided template.\n *\n * @type {Object}\n */\n element = null;\n\n /**\n * This method is called when the Elena Element’s\n * props are changed, added, removed or replaced.\n *\n * @param {string} prop\n * @param {string} oldValue\n * @param {string} newValue\n */\n attributeChangedCallback(prop, oldValue, newValue) {\n getProps(this, prop, oldValue, newValue);\n\n // Re-render when attributes change (after initial render)\n if (this.element && oldValue !== newValue) {\n this.render();\n }\n }\n\n /**\n * This static method returns an array containing the\n * names of the props we want to observe.\n */\n static get observedAttributes() {\n return options && options.props ? options.props : [];\n }\n\n /**\n * Override in subclasses to define the element's HTML structure.\n * No-op by default — elements without a render method connect safely.\n */\n render() {}\n\n /**\n * Render a tagged template literal with auto-escaping and DOM diffing.\n * Usage: this.template`<span>${this.label}</span>`\n *\n * @param {TemplateStringsArray} strings\n * @param {...*} values\n */\n template(strings, ...values) {\n renderTemplate(this, strings, values);\n }\n\n /**\n * This method is called each time the Elena\n * Custom Element is added to the document.\n */\n connectedCallback() {\n this.render();\n\n if (!this.element) {\n this.element = resolveElement(this);\n\n if (!this.element) {\n console.warn(\"░█ [ELENA]: No element found, using firstElementChild as fallback.\");\n this.element = this.firstElementChild;\n }\n }\n\n // Flush props set before connection to host and inner element attributes\n if (this._props) {\n for (const [prop, value] of this._props) {\n const attrValue = getPropValue(typeof value, value, \"toAttribute\");\n if (typeof value === \"string\" && value === \"\") {\n this.removeAttribute(prop);\n this.element.removeAttribute(prop);\n } else {\n syncAttribute(this, prop, attrValue);\n syncAttribute(this.element, prop, attrValue);\n }\n }\n }\n\n if (!this._events && options && options.events) {\n this._events = true;\n options.events?.forEach(e => {\n this.element.addEventListener(e, this);\n this[e] = (...args) => this.element[e](...args);\n });\n }\n\n this.updated();\n }\n\n /**\n * Perform post-update after each render().\n *\n * @internal\n */\n updated() {\n if (!this._hydrated) {\n this._hydrated = true;\n this.classList.add(\"elena-hydrated\");\n }\n }\n\n /**\n * This method is called each time the Elena Custom\n * Element is removed from the document.\n */\n disconnectedCallback() {\n if (this._events) {\n this._events = false;\n options.events?.forEach(e => {\n this.element?.removeEventListener(e, this);\n });\n }\n }\n\n /**\n * Handles events on the custom element.\n *\n * @internal\n */\n handleEvent(event) {\n if (options.events?.includes(event.type)) {\n event.stopPropagation();\n /** @internal */\n this.dispatchEvent(new ElenaEvent(event.type, { cancelable: true }));\n }\n }\n }\n\n if (options && options.props?.length) {\n setProps(ElenaElement.prototype, options.props);\n }\n\n return ElenaElement;\n}\n\n/**\n * @typedef {Object} ElenaOptions\n * @property {string[]} [props] - Props observed and synced as attributes.\n * @property {string[]} [events] - Events to delegate from the inner element.\n * @property {string} [element] - CSS selector for the inner element.\n */\n\n/**\n * @typedef {new (...args: any[]) => HTMLElement} ElenaConstructor\n */\n"],"names":["Elena","superClass","options","resolveElement","element","test","host","getElementsByClassName","querySelector","firstElementChild","ElenaElement","attributeChangedCallback","prop","oldValue","newValue","getProps","this","render","observedAttributes","props","template","strings","values","renderTemplate","connectedCallback","console","warn","_props","value","attrValue","getPropValue","removeAttribute","syncAttribute","_events","events","forEach","e","addEventListener","args","updated","_hydrated","classList","add","disconnectedCallback","removeEventListener","handleEvent","event","includes","type","stopPropagation","dispatchEvent","ElenaEvent","cancelable","length","setProps","prototype"],"mappings":"0NAyBO,SAASA,EAAMC,EAAYC,GAShC,MAAMC,EAAmBD,GAAWA,EAAQE,QAExC,qBAAqBC,KAAKH,EAAQE,SAChCE,GAAQA,EAAKC,uBAAuBL,EAAQE,SAAS,GACrDE,GAAQA,EAAKE,cAAcN,EAAQE,SAHrCE,GAAQA,EAAKG,kBASjB,MAAMC,UAAqBT,EAMzBG,QAAU,KAUV,wBAAAO,CAAyBC,EAAMC,EAAUC,GACvCC,EAASC,KAAMJ,EAAMC,EAAUC,GAG3BE,KAAKZ,SAAWS,IAAaC,GAC/BE,KAAKC,QAET,CAMA,6BAAWC,GACT,OAAOhB,GAAWA,EAAQiB,MAAQjB,EAAQiB,MAAQ,EACpD,CAMA,MAAAF,GAAU,CASV,QAAAG,CAASC,KAAYC,GACnBC,EAAeP,KAAMK,EAASC,EAChC,CAMA,iBAAAE,GAaE,GAZAR,KAAKC,SAEAD,KAAKZ,UACRY,KAAKZ,QAAUD,EAAea,MAEzBA,KAAKZ,UACRqB,QAAQC,KAAK,sEACbV,KAAKZ,QAAUY,KAAKP,oBAKpBO,KAAKW,OACP,IAAK,MAAOf,EAAMgB,KAAUZ,KAAKW,OAAQ,CACvC,MAAME,EAAYC,SAAoBF,EAAOA,EAAO,eAC/B,iBAAVA,GAAgC,KAAVA,GAC/BZ,KAAKe,gBAAgBnB,GACrBI,KAAKZ,QAAQ2B,gBAAgBnB,KAE7BoB,EAAchB,KAAMJ,EAAMiB,GAC1BG,EAAchB,KAAKZ,QAASQ,EAAMiB,GAEtC,EAGGb,KAAKiB,SAAW/B,GAAWA,EAAQgC,SACtClB,KAAKiB,SAAU,EACf/B,EAAQgC,QAAQC,QAAQC,IACtBpB,KAAKZ,QAAQiC,iBAAiBD,EAAGpB,MACjCA,KAAKoB,GAAK,IAAIE,IAAStB,KAAKZ,QAAQgC,MAAME,MAI9CtB,KAAKuB,SACP,CAOA,OAAAA,GACOvB,KAAKwB,YACRxB,KAAKwB,WAAY,EACjBxB,KAAKyB,UAAUC,IAAI,kBAEvB,CAMA,oBAAAC,GACM3B,KAAKiB,UACPjB,KAAKiB,SAAU,EACf/B,EAAQgC,QAAQC,QAAQC,IACtBpB,KAAKZ,SAASwC,oBAAoBR,EAAGpB,QAG3C,CAOA,WAAA6B,CAAYC,GACN5C,EAAQgC,QAAQa,SAASD,EAAME,QACjCF,EAAMG,kBAENjC,KAAKkC,cAAc,IAAIC,EAAWL,EAAME,KAAM,CAAEI,YAAY,KAEhE,EAOF,OAJIlD,GAAWA,EAAQiB,OAAOkC,QAC5BC,EAAS5C,EAAa6C,UAAWrD,EAAQiB,OAGpCT,CACT"}
|
package/dist/events.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sources":["../src/common/events.js"],"sourcesContent":["/**\n * A base class for events which defaults to\n * bubbling and composed.\n */\nexport class ElenaEvent extends Event {\n constructor(type, eventInitDict) {\n super(type, {\n bubbles: true,\n composed: true,\n ...eventInitDict,\n });\n }\n}\n"],"names":["ElenaEvent","Event","constructor","type","eventInitDict","super","bubbles","composed"],"mappings":"AAIO,MAAMA,UAAmBC,MAC9B,WAAAC,CAAYC,EAAMC,GAChBC,MAAMF,EAAM,CACVG,SAAS,EACTC,UAAU,KACPH,GAEP"}
|
package/dist/props.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
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}else switch(t){case"object":case"array":return e&&JSON.parse(e);case"boolean":default:return e;case"number":return null!==e?+e:e}}function e(t,e,n){t?null===n?t.removeAttribute(e):t.setAttribute(e,n):console.warn("░█ [ELENA]: Cannot sync attributes to a null element.")}function n(n,r){for(const o of r)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))return;if(this._props.set(o,n),!this.isConnected)return;const r=t(typeof n,n,"toAttribute");e(this,o,r),this.element&&e(this.element,o,r)}})}function r(e,n,r,o){if(r!==o){const r=t(typeof e[n],o,"toProp");e[n]=r}}export{t as getPropValue,r as getProps,n as setProps,e as syncAttribute};
|
|
2
|
+
//# sourceMappingURL=props.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"props.js","sources":["../src/common/props.js"],"sourcesContent":["/**\n * Get the value of the Elena Custom Element prop.\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;\n }\n } else {\n switch (type) {\n case \"object\":\n case \"array\":\n return value && JSON.parse(value);\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 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 attributes to a null element.\");\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[]} properties - Prop names to define\n */\nexport function setProps(proto, properties) {\n for (const prop of properties) {\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 const attrValue = getPropValue(typeof value, value, \"toAttribute\");\n syncAttribute(this, prop, attrValue);\n if (this.element) {\n syncAttribute(this.element, prop, attrValue);\n }\n },\n });\n }\n}\n\n/**\n * We need to update the internals of our component\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 const newAttr = getPropValue(type, newValue, \"toProp\");\n context[name] = newAttr;\n }\n}\n"],"names":["getPropValue","type","value","transform","JSON","stringify","parse","syncAttribute","element","name","removeAttribute","setAttribute","console","warn","setProps","proto","properties","prop","Object","defineProperty","configurable","enumerable","get","this","_props","undefined","set","Map","isConnected","attrValue","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,OAAOA,OAGX,OAAQD,GACN,IAAK,SACL,IAAK,QACH,OAAOC,GAASE,KAAKE,MAAMJ,GAC7B,IAAK,UAIL,QACE,OAAOA,EAHT,IAAK,SACH,OAAiB,OAAVA,GAAkBA,EAAQA,EAKzC,CASO,SAASK,EAAcC,EAASC,EAAMP,GACtCM,EAIS,OAAVN,EACFM,EAAQE,gBAAgBD,GAExBD,EAAQG,aAAaF,EAAMP,GAN3BU,QAAQC,KAAK,wDAQjB,CAUO,SAASC,EAASC,EAAOC,GAC9B,IAAK,MAAMC,KAAQD,EACjBE,OAAOC,eAAeJ,EAAOE,EAAM,CACjCG,cAAc,EACdC,YAAY,EACZ,GAAAC,GACE,OAAOC,KAAKC,OAASD,KAAKC,OAAOF,IAAIL,QAAQQ,CAC/C,EACA,GAAAC,CAAIxB,GAIF,GAHKqB,KAAKC,SACRD,KAAKC,OAAS,IAAIG,KAEhBzB,IAAUqB,KAAKC,OAAOF,IAAIL,GAC5B,OAIF,GADAM,KAAKC,OAAOE,IAAIT,EAAMf,IACjBqB,KAAKK,YACR,OAGF,MAAMC,EAAY7B,SAAoBE,EAAOA,EAAO,eACpDK,EAAcgB,KAAMN,EAAMY,GACtBN,KAAKf,SACPD,EAAcgB,KAAKf,QAASS,EAAMY,EAEtC,GAGN,CAWO,SAASC,EAASC,EAAStB,EAAMuB,EAAUC,GAChD,GAAID,IAAaC,EAAU,CACzB,MACMC,EAAUlC,SADI+B,EAAQtB,GACOwB,EAAU,UAC7CF,EAAQtB,GAAQyB,CAClB,CACF"}
|
package/dist/render.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{escapeHtml as t}from"./utils.js";function e(e,n,l){(function(e,n,r){if(e._tplStrings!==n||!e._tplParts)return!1;let l=!1;for(let n=0;n<r.length;n++){const a=r[n],o=a&&a.__raw,c=o?String(a):t(String(a??""));if(c!==e._tplValues[n])if(e._tplValues[n]=c,o)l=!0;else{const t=e._tplParts[n];t?t.textContent=String(a??""):l=!0}}return!l})(e,n,l)||function(e,n,l){const a=l.map(e=>e&&e.__raw?String(e):t(String(e??""))),o=n.reduce((t,e,n)=>t+e.replace(/\n\s*/g," ")+(a[n]??""),"").replace(/>\s+</g,"><").replace(/>\s+/g,">").replace(/\s+</g,"<").trim();r(e,o),e._tplStrings=n,e._tplValues=a,e._tplParts=function(t,e){const n=new Array(e.length),r=document.createTreeWalker(t,NodeFilter.SHOW_TEXT);let l,a=0;for(;(l=r.nextNode())&&a<e.length;)l.textContent===e[a]&&(n[a]=l,a++);return n}(e,a)}(e,n,l)}let n;function r(t,e){t?t.replaceChildren((n??=document.createRange()).createContextualFragment(e)):console.warn("░█ [ELENA]: Cannot render to a null element.")}export{r as renderHtml,e as renderTemplate};
|
|
2
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sources":["../src/common/render.js"],"sourcesContent":["import { escapeHtml } from \"./utils.js\";\n\n/**\n * Render a tagged template into an element with DOM diffing.\n *\n * On first render, builds the full HTML markup and render.\n * On re-renders, patches only the text nodes whose values changed,\n * avoiding a full DOM rebuild.\n *\n * Cache state is stored on the element instance:\n * _tplStrings — reference to the template's static strings array\n * _tplValues — array of escaped values from the last render\n * _tplParts — array mapping each value index to its DOM text node\n *\n * @param {HTMLElement} element\n * @param {TemplateStringsArray} strings - Static parts of the tagged template\n * @param {Array} values - Dynamic interpolated values\n */\nexport function renderTemplate(element, strings, values) {\n if (patchTextNodes(element, strings, values)) {\n return;\n }\n fullRender(element, strings, values);\n}\n\n/**\n * Fast path: patch only the text nodes whose values changed.\n * Returns true if all changes were handled (no full render needed).\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 let needsFullRender = false;\n\n for (let i = 0; i < values.length; i++) {\n const v = values[i];\n const isRaw = v && v.__raw;\n const newRendered = isRaw ? String(v) : escapeHtml(String(v ?? \"\"));\n const oldRendered = element._tplValues[i];\n\n if (newRendered === oldRendered) {\n continue;\n }\n\n element._tplValues[i] = newRendered;\n\n // Raw HTML values or attribute-position values require a full render\n if (isRaw) {\n needsFullRender = true;\n } else {\n const textNode = element._tplParts[i];\n if (textNode) {\n // Value is in a text position — update the DOM node directly\n textNode.textContent = String(v ?? \"\");\n } else {\n // Value is in an attribute position — can't patch, need full render\n needsFullRender = true;\n }\n }\n }\n\n return !needsFullRender;\n}\n\n/**\n * Cold path: build full HTML markup, render it via DocumentFragment,\n * and map each interpolated value to its corresponding DOM text node\n * for future fast-path patching.\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 const renderedValues = values.map(v => (v && v.__raw ? String(v) : escapeHtml(String(v ?? \"\"))));\n\n // Build the complete HTML string, stripping template indentation.\n // 1. Replace newlines + indentation with a single space (preserves attribute separation)\n // 2. Clean up: remove whitespace between/around tags and trim\n const markup = strings\n .reduce((out, str, i) => out + str.replace(/\\n\\s*/g, \" \") + (renderedValues[i] ?? \"\"), \"\")\n .replace(/>\\s+</g, \"><\")\n .replace(/>\\s+/g, \">\")\n .replace(/\\s+</g, \"<\")\n .trim();\n\n renderHtml(element, markup);\n\n // Cache template identity and rendered values\n element._tplStrings = strings;\n element._tplValues = renderedValues;\n\n // Walk text nodes to map each value index to its DOM node\n element._tplParts = mapTextNodes(element, renderedValues);\n}\n\n/**\n * Walk the element's text nodes and map each escaped value\n * to its corresponding DOM text node. Values in attribute\n * positions won't have a matching text node and will be null.\n *\n * @param {HTMLElement} element - The host element to walk\n * @param {string[]} escapedValues - HTML-escaped interpolated values\n * @returns {Array<Text | undefined>} Array mapping each value index to its text node\n */\nfunction mapTextNodes(element, escapedValues) {\n const parts = new Array(escapedValues.length);\n const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);\n\n let valueIndex = 0;\n let node;\n\n while ((node = walker.nextNode()) && valueIndex < escapedValues.length) {\n if (node.textContent === escapedValues[valueIndex]) {\n parts[valueIndex] = node;\n valueIndex++;\n }\n }\n\n return parts;\n}\n\n/**\n * Lazily-created Range reused across renders as a createContextualFragment\n * factory. Deferred so the module can be imported in non-browser environments.\n *\n * @type {Range | undefined}\n */\nlet _range;\n\n/**\n * Render an HTML string into an element by parsing it into a\n * DocumentFragment via createContextualFragment and swapping\n * the element's children in a single replaceChildren call.\n *\n * @param {HTMLElement} element\n * @param {string} markup\n */\nexport function renderHtml(element, markup) {\n if (!element) {\n console.warn(\"░█ [ELENA]: Cannot render to a null element.\");\n return;\n }\n element.replaceChildren((_range ??= document.createRange()).createContextualFragment(markup));\n}\n"],"names":["renderTemplate","element","strings","values","_tplStrings","_tplParts","needsFullRender","i","length","v","isRaw","__raw","newRendered","String","escapeHtml","_tplValues","textNode","textContent","patchTextNodes","renderedValues","map","markup","reduce","out","str","replace","trim","renderHtml","escapedValues","parts","Array","walker","document","createTreeWalker","NodeFilter","SHOW_TEXT","node","valueIndex","nextNode","mapTextNodes","fullRender","_range","replaceChildren","createRange","createContextualFragment","console","warn"],"mappings":"wCAkBO,SAASA,EAAeC,EAASC,EAASC,IAgBjD,SAAwBF,EAASC,EAASC,GAExC,GAAIF,EAAQG,cAAgBF,IAAYD,EAAQI,UAC9C,OAAO,EAGT,IAAIC,GAAkB,EAEtB,IAAK,IAAIC,EAAI,EAAGA,EAAIJ,EAAOK,OAAQD,IAAK,CACtC,MAAME,EAAIN,EAAOI,GACXG,EAAQD,GAAKA,EAAEE,MACfC,EAAcF,EAAQG,OAAOJ,GAAKK,EAAWD,OAAOJ,GAAK,KAG/D,GAAIG,IAFgBX,EAAQc,WAAWR,GASvC,GAHAN,EAAQc,WAAWR,GAAKK,EAGpBF,EACFJ,GAAkB,MACb,CACL,MAAMU,EAAWf,EAAQI,UAAUE,GAC/BS,EAEFA,EAASC,YAAcJ,OAAOJ,GAAK,IAGnCH,GAAkB,CAEtB,CACF,CAEA,OAAQA,CACV,EAnDMY,CAAejB,EAASC,EAASC,IA8DvC,SAAoBF,EAASC,EAASC,GACpC,MAAMgB,EAAiBhB,EAAOiB,IAAIX,GAAMA,GAAKA,EAAEE,MAAQE,OAAOJ,GAAKK,EAAWD,OAAOJ,GAAK,MAKpFY,EAASnB,EACZoB,OAAO,CAACC,EAAKC,EAAKjB,IAAMgB,EAAMC,EAAIC,QAAQ,SAAU,MAAQN,EAAeZ,IAAM,IAAK,IACtFkB,QAAQ,SAAU,MAClBA,QAAQ,QAAS,KACjBA,QAAQ,QAAS,KACjBC,OAEHC,EAAW1B,EAASoB,GAGpBpB,EAAQG,YAAcF,EACtBD,EAAQc,WAAaI,EAGrBlB,EAAQI,UAYV,SAAsBJ,EAAS2B,GAC7B,MAAMC,EAAQ,IAAIC,MAAMF,EAAcpB,QAChCuB,EAASC,SAASC,iBAAiBhC,EAASiC,WAAWC,WAE7D,IACIC,EADAC,EAAa,EAGjB,MAAQD,EAAOL,EAAOO,aAAeD,EAAaT,EAAcpB,QAC1D4B,EAAKnB,cAAgBW,EAAcS,KACrCR,EAAMQ,GAAcD,EACpBC,KAIJ,OAAOR,CACT,CA3BsBU,CAAatC,EAASkB,EAC5C,CAhFEqB,CAAWvC,EAASC,EAASC,EAC/B,CAiHA,IAAIsC,EAUG,SAASd,EAAW1B,EAASoB,GAC7BpB,EAILA,EAAQyC,iBAAiBD,IAAWT,SAASW,eAAeC,yBAAyBvB,IAHnFwB,QAAQC,KAAK,+CAIjB"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function n(n,t){"undefined"!=typeof window&&"customElements"in window&&(window.customElements.get(n)||window.customElements.define(n,t))}function t(n){const t={"&":"&","<":"<",">":">",'"':""","'":"'"};return String(n).replace(/[&<>"']/g,n=>t[n])}function e(n,...e){const o=n.reduce((n,o,i)=>n+o+t(String(e[i]??"")),"");return{__raw:!0,toString:()=>o}}export{n as defineElement,t as escapeHtml,e as html};
|
|
2
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../src/common/utils.js"],"sourcesContent":["/**\n * Register the Elena custom element if the\n * 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 */\nexport function escapeHtml(str) {\n const Escape = { \"&\": \"&\", \"<\": \"<\", \">\": \">\", '\"': \""\", \"'\": \"'\" };\n return String(str).replace(/[&<>\"']/g, c => Escape[c]);\n}\n\n/**\n * Tagged template for trusted HTML fragments with auto-escaped interpolations.\n * Use inside `this.template` for conditional HTML blocks.\n *\n * @param {TemplateStringsArray} strings\n * @param {...*} values\n * @returns {{ __raw: true, toString(): string }}\n */\nexport function html(strings, ...values) {\n const result = strings.reduce(\n (acc, str, i) => acc + str + escapeHtml(String(values[i] ?? \"\")),\n \"\"\n );\n return { __raw: true, toString: () => result };\n}\n"],"names":["defineElement","tagName","Element","window","customElements","get","define","escapeHtml","str","Escape","String","replace","c","html","strings","values","result","reduce","acc","i","__raw","toString"],"mappings":"AAOO,SAASA,EAAcC,EAASC,GACf,oBAAXC,QAA0B,mBAAoBA,SAClDA,OAAOC,eAAeC,IAAIJ,IAC7BE,OAAOC,eAAeE,OAAOL,EAASC,GAG5C,CAQO,SAASK,EAAWC,GACzB,MAAMC,EAAS,CAAE,IAAK,QAAS,IAAK,OAAQ,IAAK,OAAQ,IAAK,SAAU,IAAK,SAC7E,OAAOC,OAAOF,GAAKG,QAAQ,WAAYC,GAAKH,EAAOG,GACrD,CAUO,SAASC,EAAKC,KAAYC,GAC/B,MAAMC,EAASF,EAAQG,OACrB,CAACC,EAAKV,EAAKW,IAAMD,EAAMV,EAAMD,EAAWG,OAAOK,EAAOI,IAAM,KAC5D,IAEF,MAAO,CAAEC,OAAO,EAAMC,SAAU,IAAML,EACxC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@elenajs/core",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Elena is a lightweight, opinionated library for building blazing fast progressive custom elements and web components.",
|
|
5
|
+
"author": "Ariel Salminen <info@arielsalminen.com>",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/elena.js",
|
|
10
|
+
"types": "./dist/elena.d.ts",
|
|
11
|
+
"type": "module",
|
|
12
|
+
"files": [
|
|
13
|
+
"dist"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"prebuild": "npm run -s clean",
|
|
17
|
+
"start": "rollup -c --watch",
|
|
18
|
+
"build": "NODE_OPTIONS='--no-warnings' rollup -c",
|
|
19
|
+
"postbuild": "npx -p typescript tsc",
|
|
20
|
+
"test": "vitest run --coverage",
|
|
21
|
+
"bench": "vitest bench",
|
|
22
|
+
"clean": "rm -rf dist/"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@rollup/plugin-terser": "0.4.4",
|
|
26
|
+
"@vitest/coverage-v8": "4.0.18",
|
|
27
|
+
"happy-dom": "20.5.0",
|
|
28
|
+
"rollup": "4.57.1",
|
|
29
|
+
"rollup-plugin-summary": "3.0.1",
|
|
30
|
+
"typescript": "5.9.3",
|
|
31
|
+
"vitest": "4.0.18"
|
|
32
|
+
},
|
|
33
|
+
"gitHead": "794f273398cf73d6c9e0950af0847b507cb9352a"
|
|
34
|
+
}
|