{"version":3,"file":"attr.cjs","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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"}