eleva 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/eleva-plugins.cjs +25 -21
- package/dist/eleva-plugins.cjs.map +1 -1
- package/dist/eleva-plugins.js +25 -21
- package/dist/eleva-plugins.js.map +1 -1
- package/dist/eleva-plugins.umd.js +25 -21
- package/dist/eleva-plugins.umd.js.map +1 -1
- package/dist/eleva-plugins.umd.min.js +1 -1
- package/dist/eleva-plugins.umd.min.js.map +1 -1
- package/dist/eleva.cjs +9 -13
- package/dist/eleva.cjs.map +1 -1
- package/dist/eleva.d.cts +4 -15
- package/dist/eleva.d.cts.map +1 -1
- package/dist/eleva.d.ts +4 -15
- package/dist/eleva.d.ts.map +1 -1
- package/dist/eleva.js +9 -13
- package/dist/eleva.js.map +1 -1
- package/dist/eleva.umd.js +9 -13
- package/dist/eleva.umd.js.map +1 -1
- package/dist/eleva.umd.min.js +1 -1
- package/dist/eleva.umd.min.js.map +1 -1
- package/dist/plugins/attr.cjs +2 -2
- package/dist/plugins/attr.cjs.map +1 -1
- package/dist/plugins/attr.js +2 -2
- package/dist/plugins/attr.js.map +1 -1
- package/dist/plugins/attr.umd.js +2 -2
- package/dist/plugins/attr.umd.js.map +1 -1
- package/dist/plugins/attr.umd.min.js +1 -1
- package/dist/plugins/attr.umd.min.js.map +1 -1
- package/dist/plugins/router.cjs +23 -19
- package/dist/plugins/router.cjs.map +1 -1
- package/dist/plugins/router.js +23 -19
- package/dist/plugins/router.js.map +1 -1
- package/dist/plugins/router.umd.js +23 -19
- package/dist/plugins/router.umd.js.map +1 -1
- package/dist/plugins/router.umd.min.js +1 -1
- package/dist/plugins/router.umd.min.js.map +1 -1
- package/dist/plugins/store.cjs +2 -2
- package/dist/plugins/store.cjs.map +1 -1
- package/dist/plugins/store.js +2 -2
- package/dist/plugins/store.js.map +1 -1
- package/dist/plugins/store.umd.js +2 -2
- package/dist/plugins/store.umd.js.map +1 -1
- package/dist/plugins/store.umd.min.js +1 -1
- package/dist/plugins/store.umd.min.js.map +1 -1
- package/package.json +5 -5
- package/src/core/Eleva.js +4 -11
- package/src/modules/TemplateEngine.js +3 -3
- package/src/plugins/Attr.js +1 -1
- package/src/plugins/Router.js +24 -21
- package/src/plugins/Store.js +1 -1
- package/types/core/Eleva.d.ts +2 -13
- package/types/core/Eleva.d.ts.map +1 -1
- package/types/modules/TemplateEngine.d.ts +1 -1
- package/types/modules/TemplateEngine.d.ts.map +1 -1
- package/types/plugins/Router.d.ts.map +1 -1
package/dist/plugins/attr.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attr.js","sources":["../../src/plugins/Attr.js"],"sourcesContent":["\"use strict\";\n\n/**\n * @module eleva/plugins/attr\n * @fileoverview Attribute plugin providing ARIA, data, boolean, and dynamic attribute handling.\n */\n\n// ============================================================================\n// TYPE DEFINITIONS\n// ============================================================================\n\n// -----------------------------------------------------------------------------\n// External Type Imports\n// -----------------------------------------------------------------------------\n\n/**\n * Type imports from the Eleva core library.\n * @typedef {import('eleva').Eleva} Eleva\n */\n\n// -----------------------------------------------------------------------------\n// Attr Type Definitions\n// -----------------------------------------------------------------------------\n\n/**\n * Configuration options for the AttrPlugin.\n * @typedef {Object} AttrPluginOptions\n * @property {boolean} [enableAria=true]\n * Enable ARIA attribute handling.\n * @property {boolean} [enableData=true]\n * Enable data attribute handling.\n * @property {boolean} [enableBoolean=true]\n * Enable boolean attribute handling.\n * @property {boolean} [enableDynamic=true]\n * Enable dynamic property detection.\n * @description Configuration options passed to AttrPlugin.install().\n */\n\n/**\n * Function signature for attribute update operations.\n * @typedef {(oldEl: HTMLElement, newEl: HTMLElement) => void} AttributeUpdateFunction\n * @description Updates attributes on oldEl to match newEl's attributes.\n */\n\n/**\n * A regular expression to match hyphenated lowercase letters.\n * @private\n * @type {RegExp}\n */\nconst CAMEL_RE = /-([a-z])/g;\n\n/**\n * @class 🎯 AttrPlugin\n * @classdesc A plugin that provides advanced attribute handling for Eleva components.\n * This plugin extends the renderer with sophisticated attribute processing including:\n * - ARIA attribute handling with proper property mapping\n * - Data attribute management\n * - Boolean attribute processing\n * - Dynamic property detection and mapping\n * - Attribute cleanup and removal\n *\n * @example\n * // Install the plugin\n * const app = new Eleva(\"myApp\");\n * app.use(AttrPlugin);\n *\n * // Use advanced attributes in components\n * app.component(\"myComponent\", {\n * template: (ctx) => `\n * <button\n * aria-expanded=\"${ctx.isExpanded.value}\"\n * data-user-id=\"${ctx.userId.value}\"\n * disabled=\"${ctx.isLoading.value}\"\n * class=\"btn ${ctx.variant.value}\"\n * >\n * ${ctx.text.value}\n * </button>\n * `\n * });\n */\nexport const AttrPlugin = {\n /**\n * Unique identifier for the plugin\n * @type {string}\n */\n name: \"attr\",\n\n /**\n * Plugin version\n * @type {string}\n */\n version: \"1.1.0\",\n\n /**\n * Plugin description\n * @type {string}\n */\n description: \"Advanced attribute handling for Eleva components\",\n\n /**\n * Installs the plugin into the Eleva instance.\n *\n * @public\n * Method wrapping behavior:\n * - Stores original `_patchNode` in `renderer._originalPatchNode`\n * - Overrides `renderer._patchNode` to use enhanced attribute handling\n * - Adds `renderer.updateAttributes` and `eleva.updateElementAttributes` helpers\n * - Call `uninstall()` to restore original behavior\n *\n * @param {Eleva} eleva - The Eleva instance to enhance.\n * @param {AttrPluginOptions} options - Plugin configuration options.\n * @param {boolean} [options.enableAria=true] - Enable ARIA attribute handling.\n * Maps aria-* attributes to DOM properties (e.g., aria-expanded → ariaExpanded).\n * @param {boolean} [options.enableData=true] - Enable data attribute handling.\n * Syncs data-* attributes with element.dataset for consistent access.\n * @param {boolean} [options.enableBoolean=true] - Enable boolean attribute handling.\n * Treats empty strings and attribute names as true, \"false\" string as false.\n * @param {boolean} [options.enableDynamic=true] - Enable dynamic property detection.\n * Searches element prototype chain for property matches (useful for custom elements).\n * @returns {void}\n * @example\n * // Basic installation with defaults\n * app.use(AttrPlugin);\n *\n * @example\n * // Custom configuration\n * app.use(AttrPlugin, {\n * enableAria: true,\n * enableData: true,\n * enableBoolean: true,\n * enableDynamic: false // Disable for performance\n * });\n *\n * @example\n * // Using ARIA attributes in templates\n * template: (ctx) => `\n * <div role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"title\">\n * <h2 id=\"title\">Modal Title</h2>\n * <button aria-expanded=\"${ctx.isOpen.value}\">Toggle</button>\n * </div>\n * `\n * @see uninstall - Remove the plugin and restore original behavior.\n */\n install(eleva, options = {}) {\n const {\n enableAria = true,\n enableData = true,\n enableBoolean = true,\n enableDynamic = true,\n } = options;\n\n /**\n * Updates the attributes of an element to match a new element's attributes.\n *\n * Processing order:\n * 1. Skip event attributes (@click, @input) - handled by Eleva's event system\n * 2. Skip unchanged attributes - optimization\n * 3. ARIA attributes (aria-*): Map to DOM properties (aria-expanded → ariaExpanded)\n * 4. Data attributes (data-*): Update both dataset and attribute\n * 5. Boolean attributes: Handle empty string as true, \"false\" as false\n * 6. Other attributes: Map to properties with dynamic detection for custom elements\n * 7. Remove old attributes not present in new element\n *\n * Dynamic property detection (when enableDynamic=true):\n * - Checks if property exists directly on element\n * - Searches element's prototype chain for case-insensitive matches\n * - Enables compatibility with custom elements and Web Components\n *\n * @inner\n * @param {HTMLElement} oldEl - The original element to update (modified in-place).\n * @param {HTMLElement} newEl - The reference element with desired attributes.\n * @returns {void}\n */\n const updateAttributes = (oldEl, newEl) => {\n const oldAttrs = oldEl.attributes;\n const newAttrs = newEl.attributes;\n\n // Process new attributes\n for (let i = 0; i < newAttrs.length; i++) {\n const { name, value } = newAttrs[i];\n\n // Skip event attributes (handled by event system)\n if (name.startsWith(\"@\")) continue;\n\n // Skip if attribute hasn't changed\n if (oldEl.getAttribute(name) === value) continue;\n\n // Handle ARIA attributes\n if (enableAria && name.startsWith(\"aria-\")) {\n const prop =\n \"aria\" + name.slice(5).replace(CAMEL_RE, (_, l) => l.toUpperCase());\n oldEl[prop] = value;\n oldEl.setAttribute(name, value);\n }\n // Handle data attributes\n else if (enableData && name.startsWith(\"data-\")) {\n oldEl.dataset[name.slice(5)] = value;\n oldEl.setAttribute(name, value);\n }\n // Handle other attributes\n else {\n let prop = name.replace(CAMEL_RE, (_, l) => l.toUpperCase());\n\n // Dynamic property detection\n if (\n enableDynamic &&\n !(prop in oldEl) &&\n !Object.getOwnPropertyDescriptor(Object.getPrototypeOf(oldEl), prop)\n ) {\n const elementProps = Object.getOwnPropertyNames(\n Object.getPrototypeOf(oldEl)\n );\n const matchingProp = elementProps.find(\n (p) =>\n p.toLowerCase() === name.toLowerCase() ||\n p.toLowerCase().includes(name.toLowerCase()) ||\n name.toLowerCase().includes(p.toLowerCase())\n );\n\n if (matchingProp) {\n prop = matchingProp;\n }\n }\n\n const descriptor = Object.getOwnPropertyDescriptor(\n Object.getPrototypeOf(oldEl),\n prop\n );\n const hasProperty = prop in oldEl || descriptor;\n\n if (hasProperty) {\n // Boolean attribute handling\n if (enableBoolean) {\n const isBoolean =\n typeof oldEl[prop] === \"boolean\" ||\n (descriptor?.get &&\n typeof descriptor.get.call(oldEl) === \"boolean\");\n\n if (isBoolean) {\n const boolValue =\n value !== \"false\" &&\n (value === \"\" || value === prop || value === \"true\");\n oldEl[prop] = boolValue;\n\n if (boolValue) {\n oldEl.setAttribute(name, \"\");\n } else {\n oldEl.removeAttribute(name);\n }\n } else {\n oldEl[prop] = value;\n oldEl.setAttribute(name, value);\n }\n } else {\n oldEl[prop] = value;\n oldEl.setAttribute(name, value);\n }\n } else {\n oldEl.setAttribute(name, value);\n }\n }\n }\n\n // Remove old attributes that are no longer present\n for (let i = oldAttrs.length - 1; i >= 0; i--) {\n const name = oldAttrs[i].name;\n if (!newEl.hasAttribute(name)) {\n oldEl.removeAttribute(name);\n }\n }\n };\n\n // Extend the renderer with the advanced attribute handler\n if (eleva.renderer) {\n eleva.renderer.updateAttributes = updateAttributes;\n\n // Store the original _patchNode method\n const originalPatchNode = eleva.renderer._patchNode;\n eleva.renderer._originalPatchNode = originalPatchNode;\n\n /**\n * Overridden _patchNode method that uses enhanced attribute handling.\n * Delegates to `updateAttributes` instead of the basic `_updateAttributes`.\n *\n * @param {Node} oldNode - The original DOM node to update.\n * @param {Node} newNode - The new DOM node with desired state.\n * @returns {void}\n */\n eleva.renderer._patchNode = function (oldNode, newNode) {\n if (oldNode?._eleva_instance) return;\n\n if (oldNode.nodeType === Node.TEXT_NODE) {\n if (oldNode.nodeValue !== newNode.nodeValue) {\n oldNode.nodeValue = newNode.nodeValue;\n }\n } else if (oldNode.nodeType === Node.ELEMENT_NODE) {\n // Use advanced attribute handler instead of basic _updateAttributes\n updateAttributes(oldNode, newNode);\n this._diff(oldNode, newNode);\n }\n };\n }\n\n // Add plugin metadata to the Eleva instance\n if (!eleva.plugins) {\n eleva.plugins = new Map();\n }\n eleva.plugins.set(this.name, {\n name: this.name,\n version: this.version,\n description: this.description,\n options,\n });\n\n // Add utility methods for manual attribute updates\n /** @type {AttributeUpdateFunction} */\n eleva.updateElementAttributes = updateAttributes;\n },\n\n /**\n * Uninstalls the plugin from the Eleva instance.\n *\n * @public\n * @param {Eleva} eleva - The Eleva instance.\n * @returns {void}\n * @description\n * Restores the original renderer patching behavior and removes\n * `eleva.updateElementAttributes`.\n * @example\n * // Uninstall the plugin\n * AttrPlugin.uninstall(app);\n * @see install - Install the plugin.\n */\n uninstall(eleva) {\n // Restore original _patchNode method if it exists\n if (eleva.renderer && eleva.renderer._originalPatchNode) {\n eleva.renderer._patchNode = eleva.renderer._originalPatchNode;\n delete eleva.renderer._originalPatchNode;\n }\n\n // Remove plugin metadata\n if (eleva.plugins) {\n eleva.plugins.delete(this.name);\n }\n\n // Remove utility methods\n delete eleva.updateElementAttributes;\n },\n};\n\n// Short name export for convenience\nexport { AttrPlugin as Attr };\n"],"names":["CAMEL_RE","AttrPlugin","name","version","description","install","eleva","options","enableAria","enableData","enableBoolean","enableDynamic","updateAttributes","oldEl","newEl","oldAttrs","attributes","newAttrs","i","length","value","startsWith","getAttribute","prop","slice","replace","_","l","toUpperCase","setAttribute","dataset","Object","getOwnPropertyDescriptor","getPrototypeOf","elementProps","getOwnPropertyNames","matchingProp","find","p","toLowerCase","includes","descriptor","hasProperty","isBoolean","get","call","boolValue","removeAttribute","hasAttribute","renderer","originalPatchNode","_patchNode","_originalPatchNode","oldNode","newNode","_eleva_instance","nodeType","Node","TEXT_NODE","nodeValue","ELEMENT_NODE","_diff","plugins","Map","set","updateElementAttributes","uninstall","delete"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"attr.js","sources":["../../src/plugins/Attr.js"],"sourcesContent":["\"use strict\";\n\n/**\n * @module eleva/plugins/attr\n * @fileoverview Attribute plugin providing ARIA, data, boolean, and dynamic attribute handling.\n */\n\n// ============================================================================\n// TYPE DEFINITIONS\n// ============================================================================\n\n// -----------------------------------------------------------------------------\n// External Type Imports\n// -----------------------------------------------------------------------------\n\n/**\n * Type imports from the Eleva core library.\n * @typedef {import('eleva').Eleva} Eleva\n */\n\n// -----------------------------------------------------------------------------\n// Attr Type Definitions\n// -----------------------------------------------------------------------------\n\n/**\n * Configuration options for the AttrPlugin.\n * @typedef {Object} AttrPluginOptions\n * @property {boolean} [enableAria=true]\n * Enable ARIA attribute handling.\n * @property {boolean} [enableData=true]\n * Enable data attribute handling.\n * @property {boolean} [enableBoolean=true]\n * Enable boolean attribute handling.\n * @property {boolean} [enableDynamic=true]\n * Enable dynamic property detection.\n * @description Configuration options passed to AttrPlugin.install().\n */\n\n/**\n * Function signature for attribute update operations.\n * @typedef {(oldEl: HTMLElement, newEl: HTMLElement) => void} AttributeUpdateFunction\n * @description Updates attributes on oldEl to match newEl's attributes.\n */\n\n/**\n * A regular expression to match hyphenated lowercase letters.\n * @private\n * @type {RegExp}\n */\nconst CAMEL_RE = /-([a-z])/g;\n\n/**\n * @class 🎯 AttrPlugin\n * @classdesc A plugin that provides advanced attribute handling for Eleva components.\n * This plugin extends the renderer with sophisticated attribute processing including:\n * - ARIA attribute handling with proper property mapping\n * - Data attribute management\n * - Boolean attribute processing\n * - Dynamic property detection and mapping\n * - Attribute cleanup and removal\n *\n * @example\n * // Install the plugin\n * const app = new Eleva(\"myApp\");\n * app.use(AttrPlugin);\n *\n * // Use advanced attributes in components\n * app.component(\"myComponent\", {\n * template: (ctx) => `\n * <button\n * aria-expanded=\"${ctx.isExpanded.value}\"\n * data-user-id=\"${ctx.userId.value}\"\n * disabled=\"${ctx.isLoading.value}\"\n * class=\"btn ${ctx.variant.value}\"\n * >\n * ${ctx.text.value}\n * </button>\n * `\n * });\n */\nexport const AttrPlugin = {\n /**\n * Unique identifier for the plugin\n * @type {string}\n */\n name: \"attr\",\n\n /**\n * Plugin version\n * @type {string}\n */\n version: \"1.1.1\",\n\n /**\n * Plugin description\n * @type {string}\n */\n description: \"Advanced attribute handling for Eleva components\",\n\n /**\n * Installs the plugin into the Eleva instance.\n *\n * @public\n * Method wrapping behavior:\n * - Stores original `_patchNode` in `renderer._originalPatchNode`\n * - Overrides `renderer._patchNode` to use enhanced attribute handling\n * - Adds `renderer.updateAttributes` and `eleva.updateElementAttributes` helpers\n * - Call `uninstall()` to restore original behavior\n *\n * @param {Eleva} eleva - The Eleva instance to enhance.\n * @param {AttrPluginOptions} options - Plugin configuration options.\n * @param {boolean} [options.enableAria=true] - Enable ARIA attribute handling.\n * Maps aria-* attributes to DOM properties (e.g., aria-expanded → ariaExpanded).\n * @param {boolean} [options.enableData=true] - Enable data attribute handling.\n * Syncs data-* attributes with element.dataset for consistent access.\n * @param {boolean} [options.enableBoolean=true] - Enable boolean attribute handling.\n * Treats empty strings and attribute names as true, \"false\" string as false.\n * @param {boolean} [options.enableDynamic=true] - Enable dynamic property detection.\n * Searches element prototype chain for property matches (useful for custom elements).\n * @returns {void}\n * @example\n * // Basic installation with defaults\n * app.use(AttrPlugin);\n *\n * @example\n * // Custom configuration\n * app.use(AttrPlugin, {\n * enableAria: true,\n * enableData: true,\n * enableBoolean: true,\n * enableDynamic: false // Disable for performance\n * });\n *\n * @example\n * // Using ARIA attributes in templates\n * template: (ctx) => `\n * <div role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"title\">\n * <h2 id=\"title\">Modal Title</h2>\n * <button aria-expanded=\"${ctx.isOpen.value}\">Toggle</button>\n * </div>\n * `\n * @see uninstall - Remove the plugin and restore original behavior.\n */\n install(eleva, options = {}) {\n const {\n enableAria = true,\n enableData = true,\n enableBoolean = true,\n enableDynamic = true,\n } = options;\n\n /**\n * Updates the attributes of an element to match a new element's attributes.\n *\n * Processing order:\n * 1. Skip event attributes (@click, @input) - handled by Eleva's event system\n * 2. Skip unchanged attributes - optimization\n * 3. ARIA attributes (aria-*): Map to DOM properties (aria-expanded → ariaExpanded)\n * 4. Data attributes (data-*): Update both dataset and attribute\n * 5. Boolean attributes: Handle empty string as true, \"false\" as false\n * 6. Other attributes: Map to properties with dynamic detection for custom elements\n * 7. Remove old attributes not present in new element\n *\n * Dynamic property detection (when enableDynamic=true):\n * - Checks if property exists directly on element\n * - Searches element's prototype chain for case-insensitive matches\n * - Enables compatibility with custom elements and Web Components\n *\n * @inner\n * @param {HTMLElement} oldEl - The original element to update (modified in-place).\n * @param {HTMLElement} newEl - The reference element with desired attributes.\n * @returns {void}\n */\n const updateAttributes = (oldEl, newEl) => {\n const oldAttrs = oldEl.attributes;\n const newAttrs = newEl.attributes;\n\n // Process new attributes\n for (let i = 0; i < newAttrs.length; i++) {\n const { name, value } = newAttrs[i];\n\n // Skip event attributes (handled by event system)\n if (name.startsWith(\"@\")) continue;\n\n // Skip if attribute hasn't changed\n if (oldEl.getAttribute(name) === value) continue;\n\n // Handle ARIA attributes\n if (enableAria && name.startsWith(\"aria-\")) {\n const prop =\n \"aria\" + name.slice(5).replace(CAMEL_RE, (_, l) => l.toUpperCase());\n oldEl[prop] = value;\n oldEl.setAttribute(name, value);\n }\n // Handle data attributes\n else if (enableData && name.startsWith(\"data-\")) {\n oldEl.dataset[name.slice(5)] = value;\n oldEl.setAttribute(name, value);\n }\n // Handle other attributes\n else {\n let prop = name.replace(CAMEL_RE, (_, l) => l.toUpperCase());\n\n // Dynamic property detection\n if (\n enableDynamic &&\n !(prop in oldEl) &&\n !Object.getOwnPropertyDescriptor(Object.getPrototypeOf(oldEl), prop)\n ) {\n const elementProps = Object.getOwnPropertyNames(\n Object.getPrototypeOf(oldEl)\n );\n const matchingProp = elementProps.find(\n (p) =>\n p.toLowerCase() === name.toLowerCase() ||\n p.toLowerCase().includes(name.toLowerCase()) ||\n name.toLowerCase().includes(p.toLowerCase())\n );\n\n if (matchingProp) {\n prop = matchingProp;\n }\n }\n\n const descriptor = Object.getOwnPropertyDescriptor(\n Object.getPrototypeOf(oldEl),\n prop\n );\n const hasProperty = prop in oldEl || descriptor;\n\n if (hasProperty) {\n // Boolean attribute handling\n if (enableBoolean) {\n const isBoolean =\n typeof oldEl[prop] === \"boolean\" ||\n (descriptor?.get &&\n typeof descriptor.get.call(oldEl) === \"boolean\");\n\n if (isBoolean) {\n const boolValue =\n value !== \"false\" &&\n (value === \"\" || value === prop || value === \"true\");\n oldEl[prop] = boolValue;\n\n if (boolValue) {\n oldEl.setAttribute(name, \"\");\n } else {\n oldEl.removeAttribute(name);\n }\n } else {\n oldEl[prop] = value;\n oldEl.setAttribute(name, value);\n }\n } else {\n oldEl[prop] = value;\n oldEl.setAttribute(name, value);\n }\n } else {\n oldEl.setAttribute(name, value);\n }\n }\n }\n\n // Remove old attributes that are no longer present\n for (let i = oldAttrs.length - 1; i >= 0; i--) {\n const name = oldAttrs[i].name;\n if (!newEl.hasAttribute(name)) {\n oldEl.removeAttribute(name);\n }\n }\n };\n\n // Extend the renderer with the advanced attribute handler\n if (eleva.renderer) {\n eleva.renderer.updateAttributes = updateAttributes;\n\n // Store the original _patchNode method\n const originalPatchNode = eleva.renderer._patchNode;\n eleva.renderer._originalPatchNode = originalPatchNode;\n\n /**\n * Overridden _patchNode method that uses enhanced attribute handling.\n * Delegates to `updateAttributes` instead of the basic `_updateAttributes`.\n *\n * @param {Node} oldNode - The original DOM node to update.\n * @param {Node} newNode - The new DOM node with desired state.\n * @returns {void}\n */\n eleva.renderer._patchNode = function (oldNode, newNode) {\n if (oldNode?._eleva_instance) return;\n\n if (oldNode.nodeType === Node.TEXT_NODE) {\n if (oldNode.nodeValue !== newNode.nodeValue) {\n oldNode.nodeValue = newNode.nodeValue;\n }\n } else if (oldNode.nodeType === Node.ELEMENT_NODE) {\n // Use advanced attribute handler instead of basic _updateAttributes\n updateAttributes(oldNode, newNode);\n this._diff(oldNode, newNode);\n }\n };\n }\n\n // Add plugin metadata to the Eleva instance\n if (!eleva.plugins) {\n eleva.plugins = new Map();\n }\n eleva.plugins.set(this.name, {\n name: this.name,\n version: this.version,\n description: this.description,\n options,\n });\n\n // Add utility methods for manual attribute updates\n /** @type {AttributeUpdateFunction} */\n eleva.updateElementAttributes = updateAttributes;\n },\n\n /**\n * Uninstalls the plugin from the Eleva instance.\n *\n * @public\n * @param {Eleva} eleva - The Eleva instance.\n * @returns {void}\n * @description\n * Restores the original renderer patching behavior and removes\n * `eleva.updateElementAttributes`.\n * @example\n * // Uninstall the plugin\n * AttrPlugin.uninstall(app);\n * @see install - Install the plugin.\n */\n uninstall(eleva) {\n // Restore original _patchNode method if it exists\n if (eleva.renderer && eleva.renderer._originalPatchNode) {\n eleva.renderer._patchNode = eleva.renderer._originalPatchNode;\n delete eleva.renderer._originalPatchNode;\n }\n\n // Remove plugin metadata\n if (eleva.plugins) {\n eleva.plugins.delete(this.name);\n }\n\n // Remove utility methods\n delete eleva.updateElementAttributes;\n },\n};\n\n// Short name export for convenience\nexport { AttrPlugin as Attr };\n"],"names":["CAMEL_RE","AttrPlugin","name","version","description","install","eleva","options","enableAria","enableData","enableBoolean","enableDynamic","updateAttributes","oldEl","newEl","oldAttrs","attributes","newAttrs","i","length","value","startsWith","getAttribute","prop","slice","replace","_","l","toUpperCase","setAttribute","dataset","Object","getOwnPropertyDescriptor","getPrototypeOf","elementProps","getOwnPropertyNames","matchingProp","find","p","toLowerCase","includes","descriptor","hasProperty","isBoolean","get","call","boolValue","removeAttribute","hasAttribute","renderer","originalPatchNode","_patchNode","_originalPatchNode","oldNode","newNode","_eleva_instance","nodeType","Node","TEXT_NODE","nodeValue","ELEMENT_NODE","_diff","plugins","Map","set","updateElementAttributes","uninstall","delete"],"mappings":";AAEA;;;AAGC;AAGD;AACA;AAEA;AACA;AACA;AAEA;;;AAGC;AAGD;AACA;AAEA;;;;;;;;;;;;;;;;;;;;AAwBC,IACD,MAAMA,QAAAA,GAAW,WAAA;AAEjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA6BaC,UAAAA,GAAa;AACxB;;;AAGC,MACDC,IAAAA,EAAM,MAAA;AAEN;;;AAGC,MACDC,OAAAA,EAAS,OAAA;AAET;;;AAGC,MACDC,WAAAA,EAAa,kDAAA;AAEb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CC,MACDC,OAAAA,CAAAA,CAAQC,KAAK,EAAEC,OAAAA,GAAU,EAAE,EAAA;AACzB,QAAA,MAAM,EACJC,UAAAA,GAAa,IAAI,EACjBC,UAAAA,GAAa,IAAI,EACjBC,aAAAA,GAAgB,IAAI,EACpBC,aAAAA,GAAgB,IAAI,EACrB,GAAGJ,OAAAA;AAEJ;;;;;;;;;;;;;;;;;;;;;QAsBA,MAAMK,gBAAAA,GAAmB,CAACC,KAAAA,EAAOC,KAAAA,GAAAA;YAC/B,MAAMC,QAAAA,GAAWF,MAAMG,UAAU;YACjC,MAAMC,QAAAA,GAAWH,MAAME,UAAU;;AAGjC,YAAA,IAAK,IAAIE,CAAAA,GAAI,CAAA,EAAGA,IAAID,QAAAA,CAASE,MAAM,EAAED,CAAAA,EAAAA,CAAK;gBACxC,MAAM,EAAEhB,IAAI,EAAEkB,KAAK,EAAE,GAAGH,QAAQ,CAACC,CAAAA,CAAE;;gBAGnC,IAAIhB,IAAAA,CAAKmB,UAAU,CAAC,GAAA,CAAA,EAAM;;AAG1B,gBAAA,IAAIR,KAAAA,CAAMS,YAAY,CAACpB,IAAAA,CAAAA,KAAUkB,KAAAA,EAAO;;AAGxC,gBAAA,IAAIZ,UAAAA,IAAcN,IAAAA,CAAKmB,UAAU,CAAC,OAAA,CAAA,EAAU;AAC1C,oBAAA,MAAME,IAAAA,GACJ,MAAA,GAASrB,IAAAA,CAAKsB,KAAK,CAAC,CAAA,CAAA,CAAGC,OAAO,CAACzB,QAAAA,EAAU,CAAC0B,CAAAA,EAAGC,CAAAA,GAAMA,EAAEC,WAAW,EAAA,CAAA;oBAClEf,KAAK,CAACU,KAAK,GAAGH,KAAAA;oBACdP,KAAAA,CAAMgB,YAAY,CAAC3B,IAAAA,EAAMkB,KAAAA,CAAAA;AAC3B,gBAAA,CAAA,MAEK,IAAIX,UAAAA,IAAcP,IAAAA,CAAKmB,UAAU,CAAC,OAAA,CAAA,EAAU;AAC/CR,oBAAAA,KAAAA,CAAMiB,OAAO,CAAC5B,IAAAA,CAAKsB,KAAK,CAAC,GAAG,GAAGJ,KAAAA;oBAC/BP,KAAAA,CAAMgB,YAAY,CAAC3B,IAAAA,EAAMkB,KAAAA,CAAAA;gBAC3B,CAAA,MAEK;oBACH,IAAIG,IAAAA,GAAOrB,KAAKuB,OAAO,CAACzB,UAAU,CAAC0B,CAAAA,EAAGC,CAAAA,GAAMA,CAAAA,CAAEC,WAAW,EAAA,CAAA;;AAGzD,oBAAA,IACEjB,aAAAA,IACA,EAAEY,IAAAA,IAAQV,KAAI,CAAA,IACd,CAACkB,MAAAA,CAAOC,wBAAwB,CAACD,MAAAA,CAAOE,cAAc,CAACpB,QAAQU,IAAAA,CAAAA,EAC/D;AACA,wBAAA,MAAMW,eAAeH,MAAAA,CAAOI,mBAAmB,CAC7CJ,MAAAA,CAAOE,cAAc,CAACpB,KAAAA,CAAAA,CAAAA;wBAExB,MAAMuB,YAAAA,GAAeF,YAAAA,CAAaG,IAAI,CACpC,CAACC,CAAAA,GACCA,CAAAA,CAAEC,WAAW,EAAA,KAAOrC,IAAAA,CAAKqC,WAAW,EAAA,IACpCD,CAAAA,CAAEC,WAAW,EAAA,CAAGC,QAAQ,CAACtC,IAAAA,CAAKqC,WAAW,EAAA,CAAA,IACzCrC,IAAAA,CAAKqC,WAAW,EAAA,CAAGC,QAAQ,CAACF,CAAAA,CAAEC,WAAW,EAAA,CAAA,CAAA;AAG7C,wBAAA,IAAIH,YAAAA,EAAc;4BAChBb,IAAAA,GAAOa,YAAAA;AACT,wBAAA;AACF,oBAAA;AAEA,oBAAA,MAAMK,aAAaV,MAAAA,CAAOC,wBAAwB,CAChDD,MAAAA,CAAOE,cAAc,CAACpB,KAAAA,CAAAA,EACtBU,IAAAA,CAAAA;oBAEF,MAAMmB,WAAAA,GAAcnB,QAAQV,KAAAA,IAAS4B,UAAAA;AAErC,oBAAA,IAAIC,WAAAA,EAAa;;AAEf,wBAAA,IAAIhC,aAAAA,EAAe;AACjB,4BAAA,MAAMiC,SAAAA,GACJ,OAAO9B,KAAK,CAACU,KAAK,KAAK,SAAA,IACtBkB,UAAAA,EAAYG,GAAAA,IACX,OAAOH,UAAAA,CAAWG,GAAG,CAACC,IAAI,CAAChC,KAAAA,CAAAA,KAAW,SAAA;AAE1C,4BAAA,IAAI8B,SAAAA,EAAW;gCACb,MAAMG,SAAAA,GACJ1B,UAAU,OAAA,KACTA,UAAU,EAAA,IAAMA,KAAAA,KAAUG,IAAAA,IAAQH,KAAAA,KAAU,MAAK,CAAA;gCACpDP,KAAK,CAACU,KAAK,GAAGuB,SAAAA;AAEd,gCAAA,IAAIA,SAAAA,EAAW;oCACbjC,KAAAA,CAAMgB,YAAY,CAAC3B,IAAAA,EAAM,EAAA,CAAA;gCAC3B,CAAA,MAAO;AACLW,oCAAAA,KAAAA,CAAMkC,eAAe,CAAC7C,IAAAA,CAAAA;AACxB,gCAAA;4BACF,CAAA,MAAO;gCACLW,KAAK,CAACU,KAAK,GAAGH,KAAAA;gCACdP,KAAAA,CAAMgB,YAAY,CAAC3B,IAAAA,EAAMkB,KAAAA,CAAAA;AAC3B,4BAAA;wBACF,CAAA,MAAO;4BACLP,KAAK,CAACU,KAAK,GAAGH,KAAAA;4BACdP,KAAAA,CAAMgB,YAAY,CAAC3B,IAAAA,EAAMkB,KAAAA,CAAAA;AAC3B,wBAAA;oBACF,CAAA,MAAO;wBACLP,KAAAA,CAAMgB,YAAY,CAAC3B,IAAAA,EAAMkB,KAAAA,CAAAA;AAC3B,oBAAA;AACF,gBAAA;AACF,YAAA;;YAGA,IAAK,IAAIF,IAAIH,QAAAA,CAASI,MAAM,GAAG,CAAA,EAAGD,CAAAA,IAAK,GAAGA,CAAAA,EAAAA,CAAK;AAC7C,gBAAA,MAAMhB,IAAAA,GAAOa,QAAQ,CAACG,CAAAA,CAAE,CAAChB,IAAI;AAC7B,gBAAA,IAAI,CAACY,KAAAA,CAAMkC,YAAY,CAAC9C,IAAAA,CAAAA,EAAO;AAC7BW,oBAAAA,KAAAA,CAAMkC,eAAe,CAAC7C,IAAAA,CAAAA;AACxB,gBAAA;AACF,YAAA;AACF,QAAA,CAAA;;QAGA,IAAII,KAAAA,CAAM2C,QAAQ,EAAE;YAClB3C,KAAAA,CAAM2C,QAAQ,CAACrC,gBAAgB,GAAGA,gBAAAA;;AAGlC,YAAA,MAAMsC,iBAAAA,GAAoB5C,KAAAA,CAAM2C,QAAQ,CAACE,UAAU;YACnD7C,KAAAA,CAAM2C,QAAQ,CAACG,kBAAkB,GAAGF,iBAAAA;AAEpC;;;;;;;UAQA5C,KAAAA,CAAM2C,QAAQ,CAACE,UAAU,GAAG,SAAUE,OAAO,EAAEC,OAAO,EAAA;AACpD,gBAAA,IAAID,SAASE,eAAAA,EAAiB;AAE9B,gBAAA,IAAIF,OAAAA,CAAQG,QAAQ,KAAKC,IAAAA,CAAKC,SAAS,EAAE;AACvC,oBAAA,IAAIL,OAAAA,CAAQM,SAAS,KAAKL,OAAAA,CAAQK,SAAS,EAAE;wBAC3CN,OAAAA,CAAQM,SAAS,GAAGL,OAAAA,CAAQK,SAAS;AACvC,oBAAA;AACF,gBAAA,CAAA,MAAO,IAAIN,OAAAA,CAAQG,QAAQ,KAAKC,IAAAA,CAAKG,YAAY,EAAE;;AAEjDhD,oBAAAA,gBAAAA,CAAiByC,OAAAA,EAASC,OAAAA,CAAAA;oBAC1B,IAAI,CAACO,KAAK,CAACR,OAAAA,EAASC,OAAAA,CAAAA;AACtB,gBAAA;AACF,YAAA,CAAA;AACF,QAAA;;QAGA,IAAI,CAAChD,KAAAA,CAAMwD,OAAO,EAAE;YAClBxD,KAAAA,CAAMwD,OAAO,GAAG,IAAIC,GAAAA,EAAAA;AACtB,QAAA;AACAzD,QAAAA,KAAAA,CAAMwD,OAAO,CAACE,GAAG,CAAC,IAAI,CAAC9D,IAAI,EAAE;YAC3BA,IAAAA,EAAM,IAAI,CAACA,IAAI;YACfC,OAAAA,EAAS,IAAI,CAACA,OAAO;YACrBC,WAAAA,EAAa,IAAI,CAACA,WAAW;AAC7BG,YAAAA;AACF,SAAA,CAAA;;+CAIAD,KAAAA,CAAM2D,uBAAuB,GAAGrD,gBAAAA;AAClC,IAAA,CAAA;AAEA;;;;;;;;;;;;;AAaC,MACDsD,WAAU5D,KAAK,EAAA;;AAEb,QAAA,IAAIA,MAAM2C,QAAQ,IAAI3C,MAAM2C,QAAQ,CAACG,kBAAkB,EAAE;AACvD9C,YAAAA,KAAAA,CAAM2C,QAAQ,CAACE,UAAU,GAAG7C,KAAAA,CAAM2C,QAAQ,CAACG,kBAAkB;YAC7D,OAAO9C,KAAAA,CAAM2C,QAAQ,CAACG,kBAAkB;AAC1C,QAAA;;QAGA,IAAI9C,KAAAA,CAAMwD,OAAO,EAAE;AACjBxD,YAAAA,KAAAA,CAAMwD,OAAO,CAACK,MAAM,CAAC,IAAI,CAACjE,IAAI,CAAA;AAChC,QAAA;;AAGA,QAAA,OAAOI,MAAM2D,uBAAuB;AACtC,IAAA;AACF;;;;"}
|
package/dist/plugins/attr.umd.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! Eleva Attr Plugin v1.1.
|
|
1
|
+
/*! Eleva Attr Plugin v1.1.1 | MIT License | https://elevajs.com */
|
|
2
2
|
(function (global, factory) {
|
|
3
3
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
4
4
|
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
/**
|
|
78
78
|
* Plugin version
|
|
79
79
|
* @type {string}
|
|
80
|
-
*/ version: "1.1.
|
|
80
|
+
*/ version: "1.1.1",
|
|
81
81
|
/**
|
|
82
82
|
* Plugin description
|
|
83
83
|
* @type {string}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attr.umd.js","sources":["../../src/plugins/Attr.js"],"sourcesContent":["\"use strict\";\n\n/**\n * @module eleva/plugins/attr\n * @fileoverview Attribute plugin providing ARIA, data, boolean, and dynamic attribute handling.\n */\n\n// ============================================================================\n// TYPE DEFINITIONS\n// ============================================================================\n\n// -----------------------------------------------------------------------------\n// External Type Imports\n// -----------------------------------------------------------------------------\n\n/**\n * Type imports from the Eleva core library.\n * @typedef {import('eleva').Eleva} Eleva\n */\n\n// -----------------------------------------------------------------------------\n// Attr Type Definitions\n// -----------------------------------------------------------------------------\n\n/**\n * Configuration options for the AttrPlugin.\n * @typedef {Object} AttrPluginOptions\n * @property {boolean} [enableAria=true]\n * Enable ARIA attribute handling.\n * @property {boolean} [enableData=true]\n * Enable data attribute handling.\n * @property {boolean} [enableBoolean=true]\n * Enable boolean attribute handling.\n * @property {boolean} [enableDynamic=true]\n * Enable dynamic property detection.\n * @description Configuration options passed to AttrPlugin.install().\n */\n\n/**\n * Function signature for attribute update operations.\n * @typedef {(oldEl: HTMLElement, newEl: HTMLElement) => void} AttributeUpdateFunction\n * @description Updates attributes on oldEl to match newEl's attributes.\n */\n\n/**\n * A regular expression to match hyphenated lowercase letters.\n * @private\n * @type {RegExp}\n */\nconst CAMEL_RE = /-([a-z])/g;\n\n/**\n * @class 🎯 AttrPlugin\n * @classdesc A plugin that provides advanced attribute handling for Eleva components.\n * This plugin extends the renderer with sophisticated attribute processing including:\n * - ARIA attribute handling with proper property mapping\n * - Data attribute management\n * - Boolean attribute processing\n * - Dynamic property detection and mapping\n * - Attribute cleanup and removal\n *\n * @example\n * // Install the plugin\n * const app = new Eleva(\"myApp\");\n * app.use(AttrPlugin);\n *\n * // Use advanced attributes in components\n * app.component(\"myComponent\", {\n * template: (ctx) => `\n * <button\n * aria-expanded=\"${ctx.isExpanded.value}\"\n * data-user-id=\"${ctx.userId.value}\"\n * disabled=\"${ctx.isLoading.value}\"\n * class=\"btn ${ctx.variant.value}\"\n * >\n * ${ctx.text.value}\n * </button>\n * `\n * });\n */\nexport const AttrPlugin = {\n /**\n * Unique identifier for the plugin\n * @type {string}\n */\n name: \"attr\",\n\n /**\n * Plugin version\n * @type {string}\n */\n version: \"1.1.0\",\n\n /**\n * Plugin description\n * @type {string}\n */\n description: \"Advanced attribute handling for Eleva components\",\n\n /**\n * Installs the plugin into the Eleva instance.\n *\n * @public\n * Method wrapping behavior:\n * - Stores original `_patchNode` in `renderer._originalPatchNode`\n * - Overrides `renderer._patchNode` to use enhanced attribute handling\n * - Adds `renderer.updateAttributes` and `eleva.updateElementAttributes` helpers\n * - Call `uninstall()` to restore original behavior\n *\n * @param {Eleva} eleva - The Eleva instance to enhance.\n * @param {AttrPluginOptions} options - Plugin configuration options.\n * @param {boolean} [options.enableAria=true] - Enable ARIA attribute handling.\n * Maps aria-* attributes to DOM properties (e.g., aria-expanded → ariaExpanded).\n * @param {boolean} [options.enableData=true] - Enable data attribute handling.\n * Syncs data-* attributes with element.dataset for consistent access.\n * @param {boolean} [options.enableBoolean=true] - Enable boolean attribute handling.\n * Treats empty strings and attribute names as true, \"false\" string as false.\n * @param {boolean} [options.enableDynamic=true] - Enable dynamic property detection.\n * Searches element prototype chain for property matches (useful for custom elements).\n * @returns {void}\n * @example\n * // Basic installation with defaults\n * app.use(AttrPlugin);\n *\n * @example\n * // Custom configuration\n * app.use(AttrPlugin, {\n * enableAria: true,\n * enableData: true,\n * enableBoolean: true,\n * enableDynamic: false // Disable for performance\n * });\n *\n * @example\n * // Using ARIA attributes in templates\n * template: (ctx) => `\n * <div role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"title\">\n * <h2 id=\"title\">Modal Title</h2>\n * <button aria-expanded=\"${ctx.isOpen.value}\">Toggle</button>\n * </div>\n * `\n * @see uninstall - Remove the plugin and restore original behavior.\n */\n install(eleva, options = {}) {\n const {\n enableAria = true,\n enableData = true,\n enableBoolean = true,\n enableDynamic = true,\n } = options;\n\n /**\n * Updates the attributes of an element to match a new element's attributes.\n *\n * Processing order:\n * 1. Skip event attributes (@click, @input) - handled by Eleva's event system\n * 2. Skip unchanged attributes - optimization\n * 3. ARIA attributes (aria-*): Map to DOM properties (aria-expanded → ariaExpanded)\n * 4. Data attributes (data-*): Update both dataset and attribute\n * 5. Boolean attributes: Handle empty string as true, \"false\" as false\n * 6. Other attributes: Map to properties with dynamic detection for custom elements\n * 7. Remove old attributes not present in new element\n *\n * Dynamic property detection (when enableDynamic=true):\n * - Checks if property exists directly on element\n * - Searches element's prototype chain for case-insensitive matches\n * - Enables compatibility with custom elements and Web Components\n *\n * @inner\n * @param {HTMLElement} oldEl - The original element to update (modified in-place).\n * @param {HTMLElement} newEl - The reference element with desired attributes.\n * @returns {void}\n */\n const updateAttributes = (oldEl, newEl) => {\n const oldAttrs = oldEl.attributes;\n const newAttrs = newEl.attributes;\n\n // Process new attributes\n for (let i = 0; i < newAttrs.length; i++) {\n const { name, value } = newAttrs[i];\n\n // Skip event attributes (handled by event system)\n if (name.startsWith(\"@\")) continue;\n\n // Skip if attribute hasn't changed\n if (oldEl.getAttribute(name) === value) continue;\n\n // Handle ARIA attributes\n if (enableAria && name.startsWith(\"aria-\")) {\n const prop =\n \"aria\" + name.slice(5).replace(CAMEL_RE, (_, l) => l.toUpperCase());\n oldEl[prop] = value;\n oldEl.setAttribute(name, value);\n }\n // Handle data attributes\n else if (enableData && name.startsWith(\"data-\")) {\n oldEl.dataset[name.slice(5)] = value;\n oldEl.setAttribute(name, value);\n }\n // Handle other attributes\n else {\n let prop = name.replace(CAMEL_RE, (_, l) => l.toUpperCase());\n\n // Dynamic property detection\n if (\n enableDynamic &&\n !(prop in oldEl) &&\n !Object.getOwnPropertyDescriptor(Object.getPrototypeOf(oldEl), prop)\n ) {\n const elementProps = Object.getOwnPropertyNames(\n Object.getPrototypeOf(oldEl)\n );\n const matchingProp = elementProps.find(\n (p) =>\n p.toLowerCase() === name.toLowerCase() ||\n p.toLowerCase().includes(name.toLowerCase()) ||\n name.toLowerCase().includes(p.toLowerCase())\n );\n\n if (matchingProp) {\n prop = matchingProp;\n }\n }\n\n const descriptor = Object.getOwnPropertyDescriptor(\n Object.getPrototypeOf(oldEl),\n prop\n );\n const hasProperty = prop in oldEl || descriptor;\n\n if (hasProperty) {\n // Boolean attribute handling\n if (enableBoolean) {\n const isBoolean =\n typeof oldEl[prop] === \"boolean\" ||\n (descriptor?.get &&\n typeof descriptor.get.call(oldEl) === \"boolean\");\n\n if (isBoolean) {\n const boolValue =\n value !== \"false\" &&\n (value === \"\" || value === prop || value === \"true\");\n oldEl[prop] = boolValue;\n\n if (boolValue) {\n oldEl.setAttribute(name, \"\");\n } else {\n oldEl.removeAttribute(name);\n }\n } else {\n oldEl[prop] = value;\n oldEl.setAttribute(name, value);\n }\n } else {\n oldEl[prop] = value;\n oldEl.setAttribute(name, value);\n }\n } else {\n oldEl.setAttribute(name, value);\n }\n }\n }\n\n // Remove old attributes that are no longer present\n for (let i = oldAttrs.length - 1; i >= 0; i--) {\n const name = oldAttrs[i].name;\n if (!newEl.hasAttribute(name)) {\n oldEl.removeAttribute(name);\n }\n }\n };\n\n // Extend the renderer with the advanced attribute handler\n if (eleva.renderer) {\n eleva.renderer.updateAttributes = updateAttributes;\n\n // Store the original _patchNode method\n const originalPatchNode = eleva.renderer._patchNode;\n eleva.renderer._originalPatchNode = originalPatchNode;\n\n /**\n * Overridden _patchNode method that uses enhanced attribute handling.\n * Delegates to `updateAttributes` instead of the basic `_updateAttributes`.\n *\n * @param {Node} oldNode - The original DOM node to update.\n * @param {Node} newNode - The new DOM node with desired state.\n * @returns {void}\n */\n eleva.renderer._patchNode = function (oldNode, newNode) {\n if (oldNode?._eleva_instance) return;\n\n if (oldNode.nodeType === Node.TEXT_NODE) {\n if (oldNode.nodeValue !== newNode.nodeValue) {\n oldNode.nodeValue = newNode.nodeValue;\n }\n } else if (oldNode.nodeType === Node.ELEMENT_NODE) {\n // Use advanced attribute handler instead of basic _updateAttributes\n updateAttributes(oldNode, newNode);\n this._diff(oldNode, newNode);\n }\n };\n }\n\n // Add plugin metadata to the Eleva instance\n if (!eleva.plugins) {\n eleva.plugins = new Map();\n }\n eleva.plugins.set(this.name, {\n name: this.name,\n version: this.version,\n description: this.description,\n options,\n });\n\n // Add utility methods for manual attribute updates\n /** @type {AttributeUpdateFunction} */\n eleva.updateElementAttributes = updateAttributes;\n },\n\n /**\n * Uninstalls the plugin from the Eleva instance.\n *\n * @public\n * @param {Eleva} eleva - The Eleva instance.\n * @returns {void}\n * @description\n * Restores the original renderer patching behavior and removes\n * `eleva.updateElementAttributes`.\n * @example\n * // Uninstall the plugin\n * AttrPlugin.uninstall(app);\n * @see install - Install the plugin.\n */\n uninstall(eleva) {\n // Restore original _patchNode method if it exists\n if (eleva.renderer && eleva.renderer._originalPatchNode) {\n eleva.renderer._patchNode = eleva.renderer._originalPatchNode;\n delete eleva.renderer._originalPatchNode;\n }\n\n // Remove plugin metadata\n if (eleva.plugins) {\n eleva.plugins.delete(this.name);\n }\n\n // Remove utility methods\n delete eleva.updateElementAttributes;\n },\n};\n\n// Short name export for convenience\nexport { AttrPlugin as Attr };\n"],"names":["CAMEL_RE","AttrPlugin","name","version","description","install","eleva","options","enableAria","enableData","enableBoolean","enableDynamic","updateAttributes","oldEl","newEl","oldAttrs","attributes","newAttrs","i","length","value","startsWith","getAttribute","prop","slice","replace","_","l","toUpperCase","setAttribute","dataset","Object","getOwnPropertyDescriptor","getPrototypeOf","elementProps","getOwnPropertyNames","matchingProp","find","p","toLowerCase","includes","descriptor","hasProperty","isBoolean","get","call","boolValue","removeAttribute","hasAttribute","renderer","originalPatchNode","_patchNode","_originalPatchNode","oldNode","newNode","_eleva_instance","nodeType","Node","TEXT_NODE","nodeValue","ELEMENT_NODE","_diff","plugins","Map","set","updateElementAttributes","uninstall","delete"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"attr.umd.js","sources":["../../src/plugins/Attr.js"],"sourcesContent":["\"use strict\";\n\n/**\n * @module eleva/plugins/attr\n * @fileoverview Attribute plugin providing ARIA, data, boolean, and dynamic attribute handling.\n */\n\n// ============================================================================\n// TYPE DEFINITIONS\n// ============================================================================\n\n// -----------------------------------------------------------------------------\n// External Type Imports\n// -----------------------------------------------------------------------------\n\n/**\n * Type imports from the Eleva core library.\n * @typedef {import('eleva').Eleva} Eleva\n */\n\n// -----------------------------------------------------------------------------\n// Attr Type Definitions\n// -----------------------------------------------------------------------------\n\n/**\n * Configuration options for the AttrPlugin.\n * @typedef {Object} AttrPluginOptions\n * @property {boolean} [enableAria=true]\n * Enable ARIA attribute handling.\n * @property {boolean} [enableData=true]\n * Enable data attribute handling.\n * @property {boolean} [enableBoolean=true]\n * Enable boolean attribute handling.\n * @property {boolean} [enableDynamic=true]\n * Enable dynamic property detection.\n * @description Configuration options passed to AttrPlugin.install().\n */\n\n/**\n * Function signature for attribute update operations.\n * @typedef {(oldEl: HTMLElement, newEl: HTMLElement) => void} AttributeUpdateFunction\n * @description Updates attributes on oldEl to match newEl's attributes.\n */\n\n/**\n * A regular expression to match hyphenated lowercase letters.\n * @private\n * @type {RegExp}\n */\nconst CAMEL_RE = /-([a-z])/g;\n\n/**\n * @class 🎯 AttrPlugin\n * @classdesc A plugin that provides advanced attribute handling for Eleva components.\n * This plugin extends the renderer with sophisticated attribute processing including:\n * - ARIA attribute handling with proper property mapping\n * - Data attribute management\n * - Boolean attribute processing\n * - Dynamic property detection and mapping\n * - Attribute cleanup and removal\n *\n * @example\n * // Install the plugin\n * const app = new Eleva(\"myApp\");\n * app.use(AttrPlugin);\n *\n * // Use advanced attributes in components\n * app.component(\"myComponent\", {\n * template: (ctx) => `\n * <button\n * aria-expanded=\"${ctx.isExpanded.value}\"\n * data-user-id=\"${ctx.userId.value}\"\n * disabled=\"${ctx.isLoading.value}\"\n * class=\"btn ${ctx.variant.value}\"\n * >\n * ${ctx.text.value}\n * </button>\n * `\n * });\n */\nexport const AttrPlugin = {\n /**\n * Unique identifier for the plugin\n * @type {string}\n */\n name: \"attr\",\n\n /**\n * Plugin version\n * @type {string}\n */\n version: \"1.1.1\",\n\n /**\n * Plugin description\n * @type {string}\n */\n description: \"Advanced attribute handling for Eleva components\",\n\n /**\n * Installs the plugin into the Eleva instance.\n *\n * @public\n * Method wrapping behavior:\n * - Stores original `_patchNode` in `renderer._originalPatchNode`\n * - Overrides `renderer._patchNode` to use enhanced attribute handling\n * - Adds `renderer.updateAttributes` and `eleva.updateElementAttributes` helpers\n * - Call `uninstall()` to restore original behavior\n *\n * @param {Eleva} eleva - The Eleva instance to enhance.\n * @param {AttrPluginOptions} options - Plugin configuration options.\n * @param {boolean} [options.enableAria=true] - Enable ARIA attribute handling.\n * Maps aria-* attributes to DOM properties (e.g., aria-expanded → ariaExpanded).\n * @param {boolean} [options.enableData=true] - Enable data attribute handling.\n * Syncs data-* attributes with element.dataset for consistent access.\n * @param {boolean} [options.enableBoolean=true] - Enable boolean attribute handling.\n * Treats empty strings and attribute names as true, \"false\" string as false.\n * @param {boolean} [options.enableDynamic=true] - Enable dynamic property detection.\n * Searches element prototype chain for property matches (useful for custom elements).\n * @returns {void}\n * @example\n * // Basic installation with defaults\n * app.use(AttrPlugin);\n *\n * @example\n * // Custom configuration\n * app.use(AttrPlugin, {\n * enableAria: true,\n * enableData: true,\n * enableBoolean: true,\n * enableDynamic: false // Disable for performance\n * });\n *\n * @example\n * // Using ARIA attributes in templates\n * template: (ctx) => `\n * <div role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"title\">\n * <h2 id=\"title\">Modal Title</h2>\n * <button aria-expanded=\"${ctx.isOpen.value}\">Toggle</button>\n * </div>\n * `\n * @see uninstall - Remove the plugin and restore original behavior.\n */\n install(eleva, options = {}) {\n const {\n enableAria = true,\n enableData = true,\n enableBoolean = true,\n enableDynamic = true,\n } = options;\n\n /**\n * Updates the attributes of an element to match a new element's attributes.\n *\n * Processing order:\n * 1. Skip event attributes (@click, @input) - handled by Eleva's event system\n * 2. Skip unchanged attributes - optimization\n * 3. ARIA attributes (aria-*): Map to DOM properties (aria-expanded → ariaExpanded)\n * 4. Data attributes (data-*): Update both dataset and attribute\n * 5. Boolean attributes: Handle empty string as true, \"false\" as false\n * 6. Other attributes: Map to properties with dynamic detection for custom elements\n * 7. Remove old attributes not present in new element\n *\n * Dynamic property detection (when enableDynamic=true):\n * - Checks if property exists directly on element\n * - Searches element's prototype chain for case-insensitive matches\n * - Enables compatibility with custom elements and Web Components\n *\n * @inner\n * @param {HTMLElement} oldEl - The original element to update (modified in-place).\n * @param {HTMLElement} newEl - The reference element with desired attributes.\n * @returns {void}\n */\n const updateAttributes = (oldEl, newEl) => {\n const oldAttrs = oldEl.attributes;\n const newAttrs = newEl.attributes;\n\n // Process new attributes\n for (let i = 0; i < newAttrs.length; i++) {\n const { name, value } = newAttrs[i];\n\n // Skip event attributes (handled by event system)\n if (name.startsWith(\"@\")) continue;\n\n // Skip if attribute hasn't changed\n if (oldEl.getAttribute(name) === value) continue;\n\n // Handle ARIA attributes\n if (enableAria && name.startsWith(\"aria-\")) {\n const prop =\n \"aria\" + name.slice(5).replace(CAMEL_RE, (_, l) => l.toUpperCase());\n oldEl[prop] = value;\n oldEl.setAttribute(name, value);\n }\n // Handle data attributes\n else if (enableData && name.startsWith(\"data-\")) {\n oldEl.dataset[name.slice(5)] = value;\n oldEl.setAttribute(name, value);\n }\n // Handle other attributes\n else {\n let prop = name.replace(CAMEL_RE, (_, l) => l.toUpperCase());\n\n // Dynamic property detection\n if (\n enableDynamic &&\n !(prop in oldEl) &&\n !Object.getOwnPropertyDescriptor(Object.getPrototypeOf(oldEl), prop)\n ) {\n const elementProps = Object.getOwnPropertyNames(\n Object.getPrototypeOf(oldEl)\n );\n const matchingProp = elementProps.find(\n (p) =>\n p.toLowerCase() === name.toLowerCase() ||\n p.toLowerCase().includes(name.toLowerCase()) ||\n name.toLowerCase().includes(p.toLowerCase())\n );\n\n if (matchingProp) {\n prop = matchingProp;\n }\n }\n\n const descriptor = Object.getOwnPropertyDescriptor(\n Object.getPrototypeOf(oldEl),\n prop\n );\n const hasProperty = prop in oldEl || descriptor;\n\n if (hasProperty) {\n // Boolean attribute handling\n if (enableBoolean) {\n const isBoolean =\n typeof oldEl[prop] === \"boolean\" ||\n (descriptor?.get &&\n typeof descriptor.get.call(oldEl) === \"boolean\");\n\n if (isBoolean) {\n const boolValue =\n value !== \"false\" &&\n (value === \"\" || value === prop || value === \"true\");\n oldEl[prop] = boolValue;\n\n if (boolValue) {\n oldEl.setAttribute(name, \"\");\n } else {\n oldEl.removeAttribute(name);\n }\n } else {\n oldEl[prop] = value;\n oldEl.setAttribute(name, value);\n }\n } else {\n oldEl[prop] = value;\n oldEl.setAttribute(name, value);\n }\n } else {\n oldEl.setAttribute(name, value);\n }\n }\n }\n\n // Remove old attributes that are no longer present\n for (let i = oldAttrs.length - 1; i >= 0; i--) {\n const name = oldAttrs[i].name;\n if (!newEl.hasAttribute(name)) {\n oldEl.removeAttribute(name);\n }\n }\n };\n\n // Extend the renderer with the advanced attribute handler\n if (eleva.renderer) {\n eleva.renderer.updateAttributes = updateAttributes;\n\n // Store the original _patchNode method\n const originalPatchNode = eleva.renderer._patchNode;\n eleva.renderer._originalPatchNode = originalPatchNode;\n\n /**\n * Overridden _patchNode method that uses enhanced attribute handling.\n * Delegates to `updateAttributes` instead of the basic `_updateAttributes`.\n *\n * @param {Node} oldNode - The original DOM node to update.\n * @param {Node} newNode - The new DOM node with desired state.\n * @returns {void}\n */\n eleva.renderer._patchNode = function (oldNode, newNode) {\n if (oldNode?._eleva_instance) return;\n\n if (oldNode.nodeType === Node.TEXT_NODE) {\n if (oldNode.nodeValue !== newNode.nodeValue) {\n oldNode.nodeValue = newNode.nodeValue;\n }\n } else if (oldNode.nodeType === Node.ELEMENT_NODE) {\n // Use advanced attribute handler instead of basic _updateAttributes\n updateAttributes(oldNode, newNode);\n this._diff(oldNode, newNode);\n }\n };\n }\n\n // Add plugin metadata to the Eleva instance\n if (!eleva.plugins) {\n eleva.plugins = new Map();\n }\n eleva.plugins.set(this.name, {\n name: this.name,\n version: this.version,\n description: this.description,\n options,\n });\n\n // Add utility methods for manual attribute updates\n /** @type {AttributeUpdateFunction} */\n eleva.updateElementAttributes = updateAttributes;\n },\n\n /**\n * Uninstalls the plugin from the Eleva instance.\n *\n * @public\n * @param {Eleva} eleva - The Eleva instance.\n * @returns {void}\n * @description\n * Restores the original renderer patching behavior and removes\n * `eleva.updateElementAttributes`.\n * @example\n * // Uninstall the plugin\n * AttrPlugin.uninstall(app);\n * @see install - Install the plugin.\n */\n uninstall(eleva) {\n // Restore original _patchNode method if it exists\n if (eleva.renderer && eleva.renderer._originalPatchNode) {\n eleva.renderer._patchNode = eleva.renderer._originalPatchNode;\n delete eleva.renderer._originalPatchNode;\n }\n\n // Remove plugin metadata\n if (eleva.plugins) {\n eleva.plugins.delete(this.name);\n }\n\n // Remove utility methods\n delete eleva.updateElementAttributes;\n },\n};\n\n// Short name export for convenience\nexport { AttrPlugin as Attr };\n"],"names":["CAMEL_RE","AttrPlugin","name","version","description","install","eleva","options","enableAria","enableData","enableBoolean","enableDynamic","updateAttributes","oldEl","newEl","oldAttrs","attributes","newAttrs","i","length","value","startsWith","getAttribute","prop","slice","replace","_","l","toUpperCase","setAttribute","dataset","Object","getOwnPropertyDescriptor","getPrototypeOf","elementProps","getOwnPropertyNames","matchingProp","find","p","toLowerCase","includes","descriptor","hasProperty","isBoolean","get","call","boolValue","removeAttribute","hasAttribute","renderer","originalPatchNode","_patchNode","_originalPatchNode","oldNode","newNode","_eleva_instance","nodeType","Node","TEXT_NODE","nodeValue","ELEMENT_NODE","_diff","plugins","Map","set","updateElementAttributes","uninstall","delete"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e,t;e=this,t=function(e){"use strict";let t=/-([a-z])/g,r={name:"attr",version:"1.1.
|
|
1
|
+
var e,t;e=this,t=function(e){"use strict";let t=/-([a-z])/g,r={name:"attr",version:"1.1.1",description:"Advanced attribute handling for Eleva components",install(e,r={}){let{enableAria:i=!0,enableData:o=!0,enableBoolean:n=!0,enableDynamic:s=!0}=r,a=(e,r)=>{let a=e.attributes,l=r.attributes;for(let r=0;r<l.length;r++){let{name:a,value:d}=l[r];if(!a.startsWith("@")&&e.getAttribute(a)!==d)if(i&&a.startsWith("aria-"))e["aria"+a.slice(5).replace(t,(e,t)=>t.toUpperCase())]=d,e.setAttribute(a,d);else if(o&&a.startsWith("data-"))e.dataset[a.slice(5)]=d,e.setAttribute(a,d);else{let r=a.replace(t,(e,t)=>t.toUpperCase());if(s&&!(r in e)&&!Object.getOwnPropertyDescriptor(Object.getPrototypeOf(e),r)){let t=Object.getOwnPropertyNames(Object.getPrototypeOf(e)).find(e=>e.toLowerCase()===a.toLowerCase()||e.toLowerCase().includes(a.toLowerCase())||a.toLowerCase().includes(e.toLowerCase()));t&&(r=t)}let i=Object.getOwnPropertyDescriptor(Object.getPrototypeOf(e),r);if(r in e||i)if(n)if("boolean"==typeof e[r]||i?.get&&"boolean"==typeof i.get.call(e)){let t="false"!==d&&(""===d||d===r||"true"===d);e[r]=t,t?e.setAttribute(a,""):e.removeAttribute(a)}else e[r]=d,e.setAttribute(a,d);else e[r]=d,e.setAttribute(a,d);else e.setAttribute(a,d)}}for(let t=a.length-1;t>=0;t--){let i=a[t].name;r.hasAttribute(i)||e.removeAttribute(i)}};if(e.renderer){e.renderer.updateAttributes=a;let t=e.renderer._patchNode;e.renderer._originalPatchNode=t,e.renderer._patchNode=function(e,t){e?._eleva_instance||(e.nodeType===Node.TEXT_NODE?e.nodeValue!==t.nodeValue&&(e.nodeValue=t.nodeValue):e.nodeType===Node.ELEMENT_NODE&&(a(e,t),this._diff(e,t)))}}e.plugins||(e.plugins=new Map),e.plugins.set(this.name,{name:this.name,version:this.version,description:this.description,options:r}),e.updateElementAttributes=a},uninstall(e){e.renderer&&e.renderer._originalPatchNode&&(e.renderer._patchNode=e.renderer._originalPatchNode,delete e.renderer._originalPatchNode),e.plugins&&e.plugins.delete(this.name),delete e.updateElementAttributes}};e.Attr=r,e.AttrPlugin=r},"object"==typeof exports&&"u">typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="u">typeof globalThis?globalThis:e||self).ElevaAttrPlugin={});
|
|
2
2
|
//# sourceMappingURL=attr.umd.min.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attr.umd.min.js","sources":["../../src/plugins/Attr.js"],"sourcesContent":["\"use strict\";\n\n/**\n * @module eleva/plugins/attr\n * @fileoverview Attribute plugin providing ARIA, data, boolean, and dynamic attribute handling.\n */\n\n// ============================================================================\n// TYPE DEFINITIONS\n// ============================================================================\n\n// -----------------------------------------------------------------------------\n// External Type Imports\n// -----------------------------------------------------------------------------\n\n/**\n * Type imports from the Eleva core library.\n * @typedef {import('eleva').Eleva} Eleva\n */\n\n// -----------------------------------------------------------------------------\n// Attr Type Definitions\n// -----------------------------------------------------------------------------\n\n/**\n * Configuration options for the AttrPlugin.\n * @typedef {Object} AttrPluginOptions\n * @property {boolean} [enableAria=true]\n * Enable ARIA attribute handling.\n * @property {boolean} [enableData=true]\n * Enable data attribute handling.\n * @property {boolean} [enableBoolean=true]\n * Enable boolean attribute handling.\n * @property {boolean} [enableDynamic=true]\n * Enable dynamic property detection.\n * @description Configuration options passed to AttrPlugin.install().\n */\n\n/**\n * Function signature for attribute update operations.\n * @typedef {(oldEl: HTMLElement, newEl: HTMLElement) => void} AttributeUpdateFunction\n * @description Updates attributes on oldEl to match newEl's attributes.\n */\n\n/**\n * A regular expression to match hyphenated lowercase letters.\n * @private\n * @type {RegExp}\n */\nconst CAMEL_RE = /-([a-z])/g;\n\n/**\n * @class 🎯 AttrPlugin\n * @classdesc A plugin that provides advanced attribute handling for Eleva components.\n * This plugin extends the renderer with sophisticated attribute processing including:\n * - ARIA attribute handling with proper property mapping\n * - Data attribute management\n * - Boolean attribute processing\n * - Dynamic property detection and mapping\n * - Attribute cleanup and removal\n *\n * @example\n * // Install the plugin\n * const app = new Eleva(\"myApp\");\n * app.use(AttrPlugin);\n *\n * // Use advanced attributes in components\n * app.component(\"myComponent\", {\n * template: (ctx) => `\n * <button\n * aria-expanded=\"${ctx.isExpanded.value}\"\n * data-user-id=\"${ctx.userId.value}\"\n * disabled=\"${ctx.isLoading.value}\"\n * class=\"btn ${ctx.variant.value}\"\n * >\n * ${ctx.text.value}\n * </button>\n * `\n * });\n */\nexport const AttrPlugin = {\n /**\n * Unique identifier for the plugin\n * @type {string}\n */\n name: \"attr\",\n\n /**\n * Plugin version\n * @type {string}\n */\n version: \"1.1.0\",\n\n /**\n * Plugin description\n * @type {string}\n */\n description: \"Advanced attribute handling for Eleva components\",\n\n /**\n * Installs the plugin into the Eleva instance.\n *\n * @public\n * Method wrapping behavior:\n * - Stores original `_patchNode` in `renderer._originalPatchNode`\n * - Overrides `renderer._patchNode` to use enhanced attribute handling\n * - Adds `renderer.updateAttributes` and `eleva.updateElementAttributes` helpers\n * - Call `uninstall()` to restore original behavior\n *\n * @param {Eleva} eleva - The Eleva instance to enhance.\n * @param {AttrPluginOptions} options - Plugin configuration options.\n * @param {boolean} [options.enableAria=true] - Enable ARIA attribute handling.\n * Maps aria-* attributes to DOM properties (e.g., aria-expanded → ariaExpanded).\n * @param {boolean} [options.enableData=true] - Enable data attribute handling.\n * Syncs data-* attributes with element.dataset for consistent access.\n * @param {boolean} [options.enableBoolean=true] - Enable boolean attribute handling.\n * Treats empty strings and attribute names as true, \"false\" string as false.\n * @param {boolean} [options.enableDynamic=true] - Enable dynamic property detection.\n * Searches element prototype chain for property matches (useful for custom elements).\n * @returns {void}\n * @example\n * // Basic installation with defaults\n * app.use(AttrPlugin);\n *\n * @example\n * // Custom configuration\n * app.use(AttrPlugin, {\n * enableAria: true,\n * enableData: true,\n * enableBoolean: true,\n * enableDynamic: false // Disable for performance\n * });\n *\n * @example\n * // Using ARIA attributes in templates\n * template: (ctx) => `\n * <div role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"title\">\n * <h2 id=\"title\">Modal Title</h2>\n * <button aria-expanded=\"${ctx.isOpen.value}\">Toggle</button>\n * </div>\n * `\n * @see uninstall - Remove the plugin and restore original behavior.\n */\n install(eleva, options = {}) {\n const {\n enableAria = true,\n enableData = true,\n enableBoolean = true,\n enableDynamic = true,\n } = options;\n\n /**\n * Updates the attributes of an element to match a new element's attributes.\n *\n * Processing order:\n * 1. Skip event attributes (@click, @input) - handled by Eleva's event system\n * 2. Skip unchanged attributes - optimization\n * 3. ARIA attributes (aria-*): Map to DOM properties (aria-expanded → ariaExpanded)\n * 4. Data attributes (data-*): Update both dataset and attribute\n * 5. Boolean attributes: Handle empty string as true, \"false\" as false\n * 6. Other attributes: Map to properties with dynamic detection for custom elements\n * 7. Remove old attributes not present in new element\n *\n * Dynamic property detection (when enableDynamic=true):\n * - Checks if property exists directly on element\n * - Searches element's prototype chain for case-insensitive matches\n * - Enables compatibility with custom elements and Web Components\n *\n * @inner\n * @param {HTMLElement} oldEl - The original element to update (modified in-place).\n * @param {HTMLElement} newEl - The reference element with desired attributes.\n * @returns {void}\n */\n const updateAttributes = (oldEl, newEl) => {\n const oldAttrs = oldEl.attributes;\n const newAttrs = newEl.attributes;\n\n // Process new attributes\n for (let i = 0; i < newAttrs.length; i++) {\n const { name, value } = newAttrs[i];\n\n // Skip event attributes (handled by event system)\n if (name.startsWith(\"@\")) continue;\n\n // Skip if attribute hasn't changed\n if (oldEl.getAttribute(name) === value) continue;\n\n // Handle ARIA attributes\n if (enableAria && name.startsWith(\"aria-\")) {\n const prop =\n \"aria\" + name.slice(5).replace(CAMEL_RE, (_, l) => l.toUpperCase());\n oldEl[prop] = value;\n oldEl.setAttribute(name, value);\n }\n // Handle data attributes\n else if (enableData && name.startsWith(\"data-\")) {\n oldEl.dataset[name.slice(5)] = value;\n oldEl.setAttribute(name, value);\n }\n // Handle other attributes\n else {\n let prop = name.replace(CAMEL_RE, (_, l) => l.toUpperCase());\n\n // Dynamic property detection\n if (\n enableDynamic &&\n !(prop in oldEl) &&\n !Object.getOwnPropertyDescriptor(Object.getPrototypeOf(oldEl), prop)\n ) {\n const elementProps = Object.getOwnPropertyNames(\n Object.getPrototypeOf(oldEl)\n );\n const matchingProp = elementProps.find(\n (p) =>\n p.toLowerCase() === name.toLowerCase() ||\n p.toLowerCase().includes(name.toLowerCase()) ||\n name.toLowerCase().includes(p.toLowerCase())\n );\n\n if (matchingProp) {\n prop = matchingProp;\n }\n }\n\n const descriptor = Object.getOwnPropertyDescriptor(\n Object.getPrototypeOf(oldEl),\n prop\n );\n const hasProperty = prop in oldEl || descriptor;\n\n if (hasProperty) {\n // Boolean attribute handling\n if (enableBoolean) {\n const isBoolean =\n typeof oldEl[prop] === \"boolean\" ||\n (descriptor?.get &&\n typeof descriptor.get.call(oldEl) === \"boolean\");\n\n if (isBoolean) {\n const boolValue =\n value !== \"false\" &&\n (value === \"\" || value === prop || value === \"true\");\n oldEl[prop] = boolValue;\n\n if (boolValue) {\n oldEl.setAttribute(name, \"\");\n } else {\n oldEl.removeAttribute(name);\n }\n } else {\n oldEl[prop] = value;\n oldEl.setAttribute(name, value);\n }\n } else {\n oldEl[prop] = value;\n oldEl.setAttribute(name, value);\n }\n } else {\n oldEl.setAttribute(name, value);\n }\n }\n }\n\n // Remove old attributes that are no longer present\n for (let i = oldAttrs.length - 1; i >= 0; i--) {\n const name = oldAttrs[i].name;\n if (!newEl.hasAttribute(name)) {\n oldEl.removeAttribute(name);\n }\n }\n };\n\n // Extend the renderer with the advanced attribute handler\n if (eleva.renderer) {\n eleva.renderer.updateAttributes = updateAttributes;\n\n // Store the original _patchNode method\n const originalPatchNode = eleva.renderer._patchNode;\n eleva.renderer._originalPatchNode = originalPatchNode;\n\n /**\n * Overridden _patchNode method that uses enhanced attribute handling.\n * Delegates to `updateAttributes` instead of the basic `_updateAttributes`.\n *\n * @param {Node} oldNode - The original DOM node to update.\n * @param {Node} newNode - The new DOM node with desired state.\n * @returns {void}\n */\n eleva.renderer._patchNode = function (oldNode, newNode) {\n if (oldNode?._eleva_instance) return;\n\n if (oldNode.nodeType === Node.TEXT_NODE) {\n if (oldNode.nodeValue !== newNode.nodeValue) {\n oldNode.nodeValue = newNode.nodeValue;\n }\n } else if (oldNode.nodeType === Node.ELEMENT_NODE) {\n // Use advanced attribute handler instead of basic _updateAttributes\n updateAttributes(oldNode, newNode);\n this._diff(oldNode, newNode);\n }\n };\n }\n\n // Add plugin metadata to the Eleva instance\n if (!eleva.plugins) {\n eleva.plugins = new Map();\n }\n eleva.plugins.set(this.name, {\n name: this.name,\n version: this.version,\n description: this.description,\n options,\n });\n\n // Add utility methods for manual attribute updates\n /** @type {AttributeUpdateFunction} */\n eleva.updateElementAttributes = updateAttributes;\n },\n\n /**\n * Uninstalls the plugin from the Eleva instance.\n *\n * @public\n * @param {Eleva} eleva - The Eleva instance.\n * @returns {void}\n * @description\n * Restores the original renderer patching behavior and removes\n * `eleva.updateElementAttributes`.\n * @example\n * // Uninstall the plugin\n * AttrPlugin.uninstall(app);\n * @see install - Install the plugin.\n */\n uninstall(eleva) {\n // Restore original _patchNode method if it exists\n if (eleva.renderer && eleva.renderer._originalPatchNode) {\n eleva.renderer._patchNode = eleva.renderer._originalPatchNode;\n delete eleva.renderer._originalPatchNode;\n }\n\n // Remove plugin metadata\n if (eleva.plugins) {\n eleva.plugins.delete(this.name);\n }\n\n // Remove utility methods\n delete eleva.updateElementAttributes;\n },\n};\n\n// Short name export for convenience\nexport { AttrPlugin as Attr };\n"],"names":["CAMEL_RE","AttrPlugin","name","version","description","install","eleva","options","enableAria","enableData","enableBoolean","enableDynamic","updateAttributes","oldEl","newEl","oldAttrs","attributes","newAttrs","i","length","value","startsWith","getAttribute","slice","replace","_","l","toUpperCase","setAttribute","dataset","prop","Object","getOwnPropertyDescriptor","getPrototypeOf","matchingProp","elementProps","getOwnPropertyNames","find","p","toLowerCase","includes","descriptor","get","call","boolValue","removeAttribute","hasAttribute","renderer","originalPatchNode","_patchNode","_originalPatchNode","oldNode","newNode","_eleva_instance","nodeType","Node","TEXT_NODE","nodeValue","ELEMENT_NODE","_diff","plugins","Map","set","updateElementAttributes","uninstall","delete"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"attr.umd.min.js","sources":["../../src/plugins/Attr.js"],"sourcesContent":["\"use strict\";\n\n/**\n * @module eleva/plugins/attr\n * @fileoverview Attribute plugin providing ARIA, data, boolean, and dynamic attribute handling.\n */\n\n// ============================================================================\n// TYPE DEFINITIONS\n// ============================================================================\n\n// -----------------------------------------------------------------------------\n// External Type Imports\n// -----------------------------------------------------------------------------\n\n/**\n * Type imports from the Eleva core library.\n * @typedef {import('eleva').Eleva} Eleva\n */\n\n// -----------------------------------------------------------------------------\n// Attr Type Definitions\n// -----------------------------------------------------------------------------\n\n/**\n * Configuration options for the AttrPlugin.\n * @typedef {Object} AttrPluginOptions\n * @property {boolean} [enableAria=true]\n * Enable ARIA attribute handling.\n * @property {boolean} [enableData=true]\n * Enable data attribute handling.\n * @property {boolean} [enableBoolean=true]\n * Enable boolean attribute handling.\n * @property {boolean} [enableDynamic=true]\n * Enable dynamic property detection.\n * @description Configuration options passed to AttrPlugin.install().\n */\n\n/**\n * Function signature for attribute update operations.\n * @typedef {(oldEl: HTMLElement, newEl: HTMLElement) => void} AttributeUpdateFunction\n * @description Updates attributes on oldEl to match newEl's attributes.\n */\n\n/**\n * A regular expression to match hyphenated lowercase letters.\n * @private\n * @type {RegExp}\n */\nconst CAMEL_RE = /-([a-z])/g;\n\n/**\n * @class 🎯 AttrPlugin\n * @classdesc A plugin that provides advanced attribute handling for Eleva components.\n * This plugin extends the renderer with sophisticated attribute processing including:\n * - ARIA attribute handling with proper property mapping\n * - Data attribute management\n * - Boolean attribute processing\n * - Dynamic property detection and mapping\n * - Attribute cleanup and removal\n *\n * @example\n * // Install the plugin\n * const app = new Eleva(\"myApp\");\n * app.use(AttrPlugin);\n *\n * // Use advanced attributes in components\n * app.component(\"myComponent\", {\n * template: (ctx) => `\n * <button\n * aria-expanded=\"${ctx.isExpanded.value}\"\n * data-user-id=\"${ctx.userId.value}\"\n * disabled=\"${ctx.isLoading.value}\"\n * class=\"btn ${ctx.variant.value}\"\n * >\n * ${ctx.text.value}\n * </button>\n * `\n * });\n */\nexport const AttrPlugin = {\n /**\n * Unique identifier for the plugin\n * @type {string}\n */\n name: \"attr\",\n\n /**\n * Plugin version\n * @type {string}\n */\n version: \"1.1.1\",\n\n /**\n * Plugin description\n * @type {string}\n */\n description: \"Advanced attribute handling for Eleva components\",\n\n /**\n * Installs the plugin into the Eleva instance.\n *\n * @public\n * Method wrapping behavior:\n * - Stores original `_patchNode` in `renderer._originalPatchNode`\n * - Overrides `renderer._patchNode` to use enhanced attribute handling\n * - Adds `renderer.updateAttributes` and `eleva.updateElementAttributes` helpers\n * - Call `uninstall()` to restore original behavior\n *\n * @param {Eleva} eleva - The Eleva instance to enhance.\n * @param {AttrPluginOptions} options - Plugin configuration options.\n * @param {boolean} [options.enableAria=true] - Enable ARIA attribute handling.\n * Maps aria-* attributes to DOM properties (e.g., aria-expanded → ariaExpanded).\n * @param {boolean} [options.enableData=true] - Enable data attribute handling.\n * Syncs data-* attributes with element.dataset for consistent access.\n * @param {boolean} [options.enableBoolean=true] - Enable boolean attribute handling.\n * Treats empty strings and attribute names as true, \"false\" string as false.\n * @param {boolean} [options.enableDynamic=true] - Enable dynamic property detection.\n * Searches element prototype chain for property matches (useful for custom elements).\n * @returns {void}\n * @example\n * // Basic installation with defaults\n * app.use(AttrPlugin);\n *\n * @example\n * // Custom configuration\n * app.use(AttrPlugin, {\n * enableAria: true,\n * enableData: true,\n * enableBoolean: true,\n * enableDynamic: false // Disable for performance\n * });\n *\n * @example\n * // Using ARIA attributes in templates\n * template: (ctx) => `\n * <div role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"title\">\n * <h2 id=\"title\">Modal Title</h2>\n * <button aria-expanded=\"${ctx.isOpen.value}\">Toggle</button>\n * </div>\n * `\n * @see uninstall - Remove the plugin and restore original behavior.\n */\n install(eleva, options = {}) {\n const {\n enableAria = true,\n enableData = true,\n enableBoolean = true,\n enableDynamic = true,\n } = options;\n\n /**\n * Updates the attributes of an element to match a new element's attributes.\n *\n * Processing order:\n * 1. Skip event attributes (@click, @input) - handled by Eleva's event system\n * 2. Skip unchanged attributes - optimization\n * 3. ARIA attributes (aria-*): Map to DOM properties (aria-expanded → ariaExpanded)\n * 4. Data attributes (data-*): Update both dataset and attribute\n * 5. Boolean attributes: Handle empty string as true, \"false\" as false\n * 6. Other attributes: Map to properties with dynamic detection for custom elements\n * 7. Remove old attributes not present in new element\n *\n * Dynamic property detection (when enableDynamic=true):\n * - Checks if property exists directly on element\n * - Searches element's prototype chain for case-insensitive matches\n * - Enables compatibility with custom elements and Web Components\n *\n * @inner\n * @param {HTMLElement} oldEl - The original element to update (modified in-place).\n * @param {HTMLElement} newEl - The reference element with desired attributes.\n * @returns {void}\n */\n const updateAttributes = (oldEl, newEl) => {\n const oldAttrs = oldEl.attributes;\n const newAttrs = newEl.attributes;\n\n // Process new attributes\n for (let i = 0; i < newAttrs.length; i++) {\n const { name, value } = newAttrs[i];\n\n // Skip event attributes (handled by event system)\n if (name.startsWith(\"@\")) continue;\n\n // Skip if attribute hasn't changed\n if (oldEl.getAttribute(name) === value) continue;\n\n // Handle ARIA attributes\n if (enableAria && name.startsWith(\"aria-\")) {\n const prop =\n \"aria\" + name.slice(5).replace(CAMEL_RE, (_, l) => l.toUpperCase());\n oldEl[prop] = value;\n oldEl.setAttribute(name, value);\n }\n // Handle data attributes\n else if (enableData && name.startsWith(\"data-\")) {\n oldEl.dataset[name.slice(5)] = value;\n oldEl.setAttribute(name, value);\n }\n // Handle other attributes\n else {\n let prop = name.replace(CAMEL_RE, (_, l) => l.toUpperCase());\n\n // Dynamic property detection\n if (\n enableDynamic &&\n !(prop in oldEl) &&\n !Object.getOwnPropertyDescriptor(Object.getPrototypeOf(oldEl), prop)\n ) {\n const elementProps = Object.getOwnPropertyNames(\n Object.getPrototypeOf(oldEl)\n );\n const matchingProp = elementProps.find(\n (p) =>\n p.toLowerCase() === name.toLowerCase() ||\n p.toLowerCase().includes(name.toLowerCase()) ||\n name.toLowerCase().includes(p.toLowerCase())\n );\n\n if (matchingProp) {\n prop = matchingProp;\n }\n }\n\n const descriptor = Object.getOwnPropertyDescriptor(\n Object.getPrototypeOf(oldEl),\n prop\n );\n const hasProperty = prop in oldEl || descriptor;\n\n if (hasProperty) {\n // Boolean attribute handling\n if (enableBoolean) {\n const isBoolean =\n typeof oldEl[prop] === \"boolean\" ||\n (descriptor?.get &&\n typeof descriptor.get.call(oldEl) === \"boolean\");\n\n if (isBoolean) {\n const boolValue =\n value !== \"false\" &&\n (value === \"\" || value === prop || value === \"true\");\n oldEl[prop] = boolValue;\n\n if (boolValue) {\n oldEl.setAttribute(name, \"\");\n } else {\n oldEl.removeAttribute(name);\n }\n } else {\n oldEl[prop] = value;\n oldEl.setAttribute(name, value);\n }\n } else {\n oldEl[prop] = value;\n oldEl.setAttribute(name, value);\n }\n } else {\n oldEl.setAttribute(name, value);\n }\n }\n }\n\n // Remove old attributes that are no longer present\n for (let i = oldAttrs.length - 1; i >= 0; i--) {\n const name = oldAttrs[i].name;\n if (!newEl.hasAttribute(name)) {\n oldEl.removeAttribute(name);\n }\n }\n };\n\n // Extend the renderer with the advanced attribute handler\n if (eleva.renderer) {\n eleva.renderer.updateAttributes = updateAttributes;\n\n // Store the original _patchNode method\n const originalPatchNode = eleva.renderer._patchNode;\n eleva.renderer._originalPatchNode = originalPatchNode;\n\n /**\n * Overridden _patchNode method that uses enhanced attribute handling.\n * Delegates to `updateAttributes` instead of the basic `_updateAttributes`.\n *\n * @param {Node} oldNode - The original DOM node to update.\n * @param {Node} newNode - The new DOM node with desired state.\n * @returns {void}\n */\n eleva.renderer._patchNode = function (oldNode, newNode) {\n if (oldNode?._eleva_instance) return;\n\n if (oldNode.nodeType === Node.TEXT_NODE) {\n if (oldNode.nodeValue !== newNode.nodeValue) {\n oldNode.nodeValue = newNode.nodeValue;\n }\n } else if (oldNode.nodeType === Node.ELEMENT_NODE) {\n // Use advanced attribute handler instead of basic _updateAttributes\n updateAttributes(oldNode, newNode);\n this._diff(oldNode, newNode);\n }\n };\n }\n\n // Add plugin metadata to the Eleva instance\n if (!eleva.plugins) {\n eleva.plugins = new Map();\n }\n eleva.plugins.set(this.name, {\n name: this.name,\n version: this.version,\n description: this.description,\n options,\n });\n\n // Add utility methods for manual attribute updates\n /** @type {AttributeUpdateFunction} */\n eleva.updateElementAttributes = updateAttributes;\n },\n\n /**\n * Uninstalls the plugin from the Eleva instance.\n *\n * @public\n * @param {Eleva} eleva - The Eleva instance.\n * @returns {void}\n * @description\n * Restores the original renderer patching behavior and removes\n * `eleva.updateElementAttributes`.\n * @example\n * // Uninstall the plugin\n * AttrPlugin.uninstall(app);\n * @see install - Install the plugin.\n */\n uninstall(eleva) {\n // Restore original _patchNode method if it exists\n if (eleva.renderer && eleva.renderer._originalPatchNode) {\n eleva.renderer._patchNode = eleva.renderer._originalPatchNode;\n delete eleva.renderer._originalPatchNode;\n }\n\n // Remove plugin metadata\n if (eleva.plugins) {\n eleva.plugins.delete(this.name);\n }\n\n // Remove utility methods\n delete eleva.updateElementAttributes;\n },\n};\n\n// Short name export for convenience\nexport { AttrPlugin as Attr };\n"],"names":["CAMEL_RE","AttrPlugin","name","version","description","install","eleva","options","enableAria","enableData","enableBoolean","enableDynamic","updateAttributes","oldEl","newEl","oldAttrs","attributes","newAttrs","i","length","value","startsWith","getAttribute","slice","replace","_","l","toUpperCase","setAttribute","dataset","prop","Object","getOwnPropertyDescriptor","getPrototypeOf","matchingProp","elementProps","getOwnPropertyNames","find","p","toLowerCase","includes","descriptor","get","call","boolValue","removeAttribute","hasAttribute","renderer","originalPatchNode","_patchNode","_originalPatchNode","oldNode","newNode","_eleva_instance","nodeType","Node","TEXT_NODE","nodeValue","ELEMENT_NODE","_diff","plugins","Map","set","updateElementAttributes","uninstall","delete"],"mappings":"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"}
|
package/dist/plugins/router.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! Eleva Router Plugin v1.1.
|
|
1
|
+
/*! Eleva Router Plugin v1.1.1 | MIT License | https://elevajs.com */
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -800,26 +800,30 @@
|
|
|
800
800
|
// Increment navigation ID and capture it for this navigation
|
|
801
801
|
const currentNavId = ++this._navigationId;
|
|
802
802
|
this._isNavigating = true;
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
if (
|
|
808
|
-
|
|
809
|
-
|
|
803
|
+
try {
|
|
804
|
+
const state = target.state || {};
|
|
805
|
+
const replace = target.replace || false;
|
|
806
|
+
const historyMethod = replace ? "replaceState" : "pushState";
|
|
807
|
+
if (this.options.mode === "hash") {
|
|
808
|
+
if (replace) {
|
|
809
|
+
const newUrl = `${window.location.pathname}${window.location.search}#${path}`;
|
|
810
|
+
window.history.replaceState(state, "", newUrl);
|
|
811
|
+
} else {
|
|
812
|
+
window.location.hash = path;
|
|
813
|
+
}
|
|
810
814
|
} else {
|
|
811
|
-
|
|
815
|
+
const url = this.options.mode === "query" ? this._buildQueryUrl(path) : path;
|
|
816
|
+
history[historyMethod](state, "", url);
|
|
812
817
|
}
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
|
|
818
|
+
} finally{
|
|
819
|
+
// Always reset the flag via microtask, even if history manipulation throws
|
|
820
|
+
// Only reset if no newer navigation has started
|
|
821
|
+
queueMicrotask(()=>{
|
|
822
|
+
if (this._navigationId === currentNavId) {
|
|
823
|
+
this._isNavigating = false;
|
|
824
|
+
}
|
|
825
|
+
});
|
|
816
826
|
}
|
|
817
|
-
// Only reset the flag if no newer navigation has started
|
|
818
|
-
queueMicrotask(()=>{
|
|
819
|
-
if (this._navigationId === currentNavId) {
|
|
820
|
-
this._isNavigating = false;
|
|
821
|
-
}
|
|
822
|
-
});
|
|
823
827
|
}
|
|
824
828
|
return navigationSuccessful;
|
|
825
829
|
} catch (error) {
|
|
@@ -1737,7 +1741,7 @@
|
|
|
1737
1741
|
/**
|
|
1738
1742
|
* Plugin version
|
|
1739
1743
|
* @type {string}
|
|
1740
|
-
*/ version: "1.1.
|
|
1744
|
+
*/ version: "1.1.1",
|
|
1741
1745
|
/**
|
|
1742
1746
|
* Plugin description
|
|
1743
1747
|
* @type {string}
|