eleva 1.0.1 → 1.1.0

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.
Files changed (97) hide show
  1. package/README.md +21 -10
  2. package/dist/{eleva-plugins.cjs.js → eleva-plugins.cjs} +1002 -292
  3. package/dist/eleva-plugins.cjs.map +1 -0
  4. package/dist/eleva-plugins.d.cts +1352 -0
  5. package/dist/eleva-plugins.d.cts.map +1 -0
  6. package/dist/eleva-plugins.d.ts +1352 -0
  7. package/dist/eleva-plugins.d.ts.map +1 -0
  8. package/dist/{eleva-plugins.esm.js → eleva-plugins.js} +1002 -292
  9. package/dist/eleva-plugins.js.map +1 -0
  10. package/dist/eleva-plugins.umd.js +1001 -291
  11. package/dist/eleva-plugins.umd.js.map +1 -1
  12. package/dist/eleva-plugins.umd.min.js +1 -1
  13. package/dist/eleva-plugins.umd.min.js.map +1 -1
  14. package/dist/{eleva.cjs.js → eleva.cjs} +421 -191
  15. package/dist/eleva.cjs.map +1 -0
  16. package/dist/eleva.d.cts +1329 -0
  17. package/dist/eleva.d.cts.map +1 -0
  18. package/dist/eleva.d.ts +473 -226
  19. package/dist/eleva.d.ts.map +1 -0
  20. package/dist/{eleva.esm.js → eleva.js} +422 -192
  21. package/dist/eleva.js.map +1 -0
  22. package/dist/eleva.umd.js +420 -190
  23. package/dist/eleva.umd.js.map +1 -1
  24. package/dist/eleva.umd.min.js +1 -1
  25. package/dist/eleva.umd.min.js.map +1 -1
  26. package/dist/plugins/attr.cjs +279 -0
  27. package/dist/plugins/attr.cjs.map +1 -0
  28. package/dist/plugins/attr.d.cts +101 -0
  29. package/dist/plugins/attr.d.cts.map +1 -0
  30. package/dist/plugins/attr.d.ts +101 -0
  31. package/dist/plugins/attr.d.ts.map +1 -0
  32. package/dist/plugins/attr.js +276 -0
  33. package/dist/plugins/attr.js.map +1 -0
  34. package/dist/plugins/attr.umd.js +111 -22
  35. package/dist/plugins/attr.umd.js.map +1 -1
  36. package/dist/plugins/attr.umd.min.js +1 -1
  37. package/dist/plugins/attr.umd.min.js.map +1 -1
  38. package/dist/plugins/router.cjs +1873 -0
  39. package/dist/plugins/router.cjs.map +1 -0
  40. package/dist/plugins/router.d.cts +1296 -0
  41. package/dist/plugins/router.d.cts.map +1 -0
  42. package/dist/plugins/router.d.ts +1296 -0
  43. package/dist/plugins/router.d.ts.map +1 -0
  44. package/dist/plugins/router.js +1870 -0
  45. package/dist/plugins/router.js.map +1 -0
  46. package/dist/plugins/router.umd.js +482 -186
  47. package/dist/plugins/router.umd.js.map +1 -1
  48. package/dist/plugins/router.umd.min.js +1 -1
  49. package/dist/plugins/router.umd.min.js.map +1 -1
  50. package/dist/plugins/store.cjs +920 -0
  51. package/dist/plugins/store.cjs.map +1 -0
  52. package/dist/plugins/store.d.cts +266 -0
  53. package/dist/plugins/store.d.cts.map +1 -0
  54. package/dist/plugins/store.d.ts +266 -0
  55. package/dist/plugins/store.d.ts.map +1 -0
  56. package/dist/plugins/store.js +917 -0
  57. package/dist/plugins/store.js.map +1 -0
  58. package/dist/plugins/store.umd.js +410 -85
  59. package/dist/plugins/store.umd.js.map +1 -1
  60. package/dist/plugins/store.umd.min.js +1 -1
  61. package/dist/plugins/store.umd.min.js.map +1 -1
  62. package/package.json +112 -68
  63. package/src/core/Eleva.js +195 -115
  64. package/src/index.cjs +10 -0
  65. package/src/index.js +11 -0
  66. package/src/modules/Emitter.js +68 -20
  67. package/src/modules/Renderer.js +82 -20
  68. package/src/modules/Signal.js +43 -15
  69. package/src/modules/TemplateEngine.js +50 -9
  70. package/src/plugins/Attr.js +121 -19
  71. package/src/plugins/Router.js +526 -181
  72. package/src/plugins/Store.js +448 -69
  73. package/src/plugins/index.js +1 -0
  74. package/types/core/Eleva.d.ts +263 -169
  75. package/types/core/Eleva.d.ts.map +1 -1
  76. package/types/index.d.cts +3 -0
  77. package/types/index.d.cts.map +1 -0
  78. package/types/index.d.ts +5 -0
  79. package/types/index.d.ts.map +1 -1
  80. package/types/modules/Emitter.d.ts +73 -30
  81. package/types/modules/Emitter.d.ts.map +1 -1
  82. package/types/modules/Renderer.d.ts +48 -18
  83. package/types/modules/Renderer.d.ts.map +1 -1
  84. package/types/modules/Signal.d.ts +44 -16
  85. package/types/modules/Signal.d.ts.map +1 -1
  86. package/types/modules/TemplateEngine.d.ts +46 -11
  87. package/types/modules/TemplateEngine.d.ts.map +1 -1
  88. package/types/plugins/Attr.d.ts +83 -16
  89. package/types/plugins/Attr.d.ts.map +1 -1
  90. package/types/plugins/Router.d.ts +498 -207
  91. package/types/plugins/Router.d.ts.map +1 -1
  92. package/types/plugins/Store.d.ts +211 -37
  93. package/types/plugins/Store.d.ts.map +1 -1
  94. package/dist/eleva-plugins.cjs.js.map +0 -1
  95. package/dist/eleva-plugins.esm.js.map +0 -1
  96. package/dist/eleva.cjs.js.map +0 -1
  97. package/dist/eleva.esm.js.map +0 -1
@@ -0,0 +1,276 @@
1
+ /*! Eleva Attr Plugin v1.1.0 | MIT License | https://elevajs.com */
2
+ /**
3
+ * @module eleva/plugins/attr
4
+ * @fileoverview Attribute plugin providing ARIA, data, boolean, and dynamic attribute handling.
5
+ */ // ============================================================================
6
+ // TYPE DEFINITIONS
7
+ // ============================================================================
8
+ // -----------------------------------------------------------------------------
9
+ // External Type Imports
10
+ // -----------------------------------------------------------------------------
11
+ /**
12
+ * Type imports from the Eleva core library.
13
+ * @typedef {import('eleva').Eleva} Eleva
14
+ */ // -----------------------------------------------------------------------------
15
+ // Attr Type Definitions
16
+ // -----------------------------------------------------------------------------
17
+ /**
18
+ * Configuration options for the AttrPlugin.
19
+ * @typedef {Object} AttrPluginOptions
20
+ * @property {boolean} [enableAria=true]
21
+ * Enable ARIA attribute handling.
22
+ * @property {boolean} [enableData=true]
23
+ * Enable data attribute handling.
24
+ * @property {boolean} [enableBoolean=true]
25
+ * Enable boolean attribute handling.
26
+ * @property {boolean} [enableDynamic=true]
27
+ * Enable dynamic property detection.
28
+ * @description Configuration options passed to AttrPlugin.install().
29
+ */ /**
30
+ * Function signature for attribute update operations.
31
+ * @typedef {(oldEl: HTMLElement, newEl: HTMLElement) => void} AttributeUpdateFunction
32
+ * @description Updates attributes on oldEl to match newEl's attributes.
33
+ */ /**
34
+ * A regular expression to match hyphenated lowercase letters.
35
+ * @private
36
+ * @type {RegExp}
37
+ */ const CAMEL_RE = /-([a-z])/g;
38
+ /**
39
+ * @class 🎯 AttrPlugin
40
+ * @classdesc A plugin that provides advanced attribute handling for Eleva components.
41
+ * This plugin extends the renderer with sophisticated attribute processing including:
42
+ * - ARIA attribute handling with proper property mapping
43
+ * - Data attribute management
44
+ * - Boolean attribute processing
45
+ * - Dynamic property detection and mapping
46
+ * - Attribute cleanup and removal
47
+ *
48
+ * @example
49
+ * // Install the plugin
50
+ * const app = new Eleva("myApp");
51
+ * app.use(AttrPlugin);
52
+ *
53
+ * // Use advanced attributes in components
54
+ * app.component("myComponent", {
55
+ * template: (ctx) => `
56
+ * <button
57
+ * aria-expanded="${ctx.isExpanded.value}"
58
+ * data-user-id="${ctx.userId.value}"
59
+ * disabled="${ctx.isLoading.value}"
60
+ * class="btn ${ctx.variant.value}"
61
+ * >
62
+ * ${ctx.text.value}
63
+ * </button>
64
+ * `
65
+ * });
66
+ */ const AttrPlugin = {
67
+ /**
68
+ * Unique identifier for the plugin
69
+ * @type {string}
70
+ */ name: "attr",
71
+ /**
72
+ * Plugin version
73
+ * @type {string}
74
+ */ version: "1.1.0",
75
+ /**
76
+ * Plugin description
77
+ * @type {string}
78
+ */ description: "Advanced attribute handling for Eleva components",
79
+ /**
80
+ * Installs the plugin into the Eleva instance.
81
+ *
82
+ * @public
83
+ * Method wrapping behavior:
84
+ * - Stores original `_patchNode` in `renderer._originalPatchNode`
85
+ * - Overrides `renderer._patchNode` to use enhanced attribute handling
86
+ * - Adds `renderer.updateAttributes` and `eleva.updateElementAttributes` helpers
87
+ * - Call `uninstall()` to restore original behavior
88
+ *
89
+ * @param {Eleva} eleva - The Eleva instance to enhance.
90
+ * @param {AttrPluginOptions} options - Plugin configuration options.
91
+ * @param {boolean} [options.enableAria=true] - Enable ARIA attribute handling.
92
+ * Maps aria-* attributes to DOM properties (e.g., aria-expanded → ariaExpanded).
93
+ * @param {boolean} [options.enableData=true] - Enable data attribute handling.
94
+ * Syncs data-* attributes with element.dataset for consistent access.
95
+ * @param {boolean} [options.enableBoolean=true] - Enable boolean attribute handling.
96
+ * Treats empty strings and attribute names as true, "false" string as false.
97
+ * @param {boolean} [options.enableDynamic=true] - Enable dynamic property detection.
98
+ * Searches element prototype chain for property matches (useful for custom elements).
99
+ * @returns {void}
100
+ * @example
101
+ * // Basic installation with defaults
102
+ * app.use(AttrPlugin);
103
+ *
104
+ * @example
105
+ * // Custom configuration
106
+ * app.use(AttrPlugin, {
107
+ * enableAria: true,
108
+ * enableData: true,
109
+ * enableBoolean: true,
110
+ * enableDynamic: false // Disable for performance
111
+ * });
112
+ *
113
+ * @example
114
+ * // Using ARIA attributes in templates
115
+ * template: (ctx) => `
116
+ * <div role="dialog" aria-modal="true" aria-labelledby="title">
117
+ * <h2 id="title">Modal Title</h2>
118
+ * <button aria-expanded="${ctx.isOpen.value}">Toggle</button>
119
+ * </div>
120
+ * `
121
+ * @see uninstall - Remove the plugin and restore original behavior.
122
+ */ install (eleva, options = {}) {
123
+ const { enableAria = true, enableData = true, enableBoolean = true, enableDynamic = true } = options;
124
+ /**
125
+ * Updates the attributes of an element to match a new element's attributes.
126
+ *
127
+ * Processing order:
128
+ * 1. Skip event attributes (@click, @input) - handled by Eleva's event system
129
+ * 2. Skip unchanged attributes - optimization
130
+ * 3. ARIA attributes (aria-*): Map to DOM properties (aria-expanded → ariaExpanded)
131
+ * 4. Data attributes (data-*): Update both dataset and attribute
132
+ * 5. Boolean attributes: Handle empty string as true, "false" as false
133
+ * 6. Other attributes: Map to properties with dynamic detection for custom elements
134
+ * 7. Remove old attributes not present in new element
135
+ *
136
+ * Dynamic property detection (when enableDynamic=true):
137
+ * - Checks if property exists directly on element
138
+ * - Searches element's prototype chain for case-insensitive matches
139
+ * - Enables compatibility with custom elements and Web Components
140
+ *
141
+ * @inner
142
+ * @param {HTMLElement} oldEl - The original element to update (modified in-place).
143
+ * @param {HTMLElement} newEl - The reference element with desired attributes.
144
+ * @returns {void}
145
+ */ const updateAttributes = (oldEl, newEl)=>{
146
+ const oldAttrs = oldEl.attributes;
147
+ const newAttrs = newEl.attributes;
148
+ // Process new attributes
149
+ for(let i = 0; i < newAttrs.length; i++){
150
+ const { name, value } = newAttrs[i];
151
+ // Skip event attributes (handled by event system)
152
+ if (name.startsWith("@")) continue;
153
+ // Skip if attribute hasn't changed
154
+ if (oldEl.getAttribute(name) === value) continue;
155
+ // Handle ARIA attributes
156
+ if (enableAria && name.startsWith("aria-")) {
157
+ const prop = "aria" + name.slice(5).replace(CAMEL_RE, (_, l)=>l.toUpperCase());
158
+ oldEl[prop] = value;
159
+ oldEl.setAttribute(name, value);
160
+ } else if (enableData && name.startsWith("data-")) {
161
+ oldEl.dataset[name.slice(5)] = value;
162
+ oldEl.setAttribute(name, value);
163
+ } else {
164
+ let prop = name.replace(CAMEL_RE, (_, l)=>l.toUpperCase());
165
+ // Dynamic property detection
166
+ if (enableDynamic && !(prop in oldEl) && !Object.getOwnPropertyDescriptor(Object.getPrototypeOf(oldEl), prop)) {
167
+ const elementProps = Object.getOwnPropertyNames(Object.getPrototypeOf(oldEl));
168
+ const matchingProp = elementProps.find((p)=>p.toLowerCase() === name.toLowerCase() || p.toLowerCase().includes(name.toLowerCase()) || name.toLowerCase().includes(p.toLowerCase()));
169
+ if (matchingProp) {
170
+ prop = matchingProp;
171
+ }
172
+ }
173
+ const descriptor = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(oldEl), prop);
174
+ const hasProperty = prop in oldEl || descriptor;
175
+ if (hasProperty) {
176
+ // Boolean attribute handling
177
+ if (enableBoolean) {
178
+ const isBoolean = typeof oldEl[prop] === "boolean" || descriptor?.get && typeof descriptor.get.call(oldEl) === "boolean";
179
+ if (isBoolean) {
180
+ const boolValue = value !== "false" && (value === "" || value === prop || value === "true");
181
+ oldEl[prop] = boolValue;
182
+ if (boolValue) {
183
+ oldEl.setAttribute(name, "");
184
+ } else {
185
+ oldEl.removeAttribute(name);
186
+ }
187
+ } else {
188
+ oldEl[prop] = value;
189
+ oldEl.setAttribute(name, value);
190
+ }
191
+ } else {
192
+ oldEl[prop] = value;
193
+ oldEl.setAttribute(name, value);
194
+ }
195
+ } else {
196
+ oldEl.setAttribute(name, value);
197
+ }
198
+ }
199
+ }
200
+ // Remove old attributes that are no longer present
201
+ for(let i = oldAttrs.length - 1; i >= 0; i--){
202
+ const name = oldAttrs[i].name;
203
+ if (!newEl.hasAttribute(name)) {
204
+ oldEl.removeAttribute(name);
205
+ }
206
+ }
207
+ };
208
+ // Extend the renderer with the advanced attribute handler
209
+ if (eleva.renderer) {
210
+ eleva.renderer.updateAttributes = updateAttributes;
211
+ // Store the original _patchNode method
212
+ const originalPatchNode = eleva.renderer._patchNode;
213
+ eleva.renderer._originalPatchNode = originalPatchNode;
214
+ /**
215
+ * Overridden _patchNode method that uses enhanced attribute handling.
216
+ * Delegates to `updateAttributes` instead of the basic `_updateAttributes`.
217
+ *
218
+ * @param {Node} oldNode - The original DOM node to update.
219
+ * @param {Node} newNode - The new DOM node with desired state.
220
+ * @returns {void}
221
+ */ eleva.renderer._patchNode = function(oldNode, newNode) {
222
+ if (oldNode?._eleva_instance) return;
223
+ if (oldNode.nodeType === Node.TEXT_NODE) {
224
+ if (oldNode.nodeValue !== newNode.nodeValue) {
225
+ oldNode.nodeValue = newNode.nodeValue;
226
+ }
227
+ } else if (oldNode.nodeType === Node.ELEMENT_NODE) {
228
+ // Use advanced attribute handler instead of basic _updateAttributes
229
+ updateAttributes(oldNode, newNode);
230
+ this._diff(oldNode, newNode);
231
+ }
232
+ };
233
+ }
234
+ // Add plugin metadata to the Eleva instance
235
+ if (!eleva.plugins) {
236
+ eleva.plugins = new Map();
237
+ }
238
+ eleva.plugins.set(this.name, {
239
+ name: this.name,
240
+ version: this.version,
241
+ description: this.description,
242
+ options
243
+ });
244
+ // Add utility methods for manual attribute updates
245
+ /** @type {AttributeUpdateFunction} */ eleva.updateElementAttributes = updateAttributes;
246
+ },
247
+ /**
248
+ * Uninstalls the plugin from the Eleva instance.
249
+ *
250
+ * @public
251
+ * @param {Eleva} eleva - The Eleva instance.
252
+ * @returns {void}
253
+ * @description
254
+ * Restores the original renderer patching behavior and removes
255
+ * `eleva.updateElementAttributes`.
256
+ * @example
257
+ * // Uninstall the plugin
258
+ * AttrPlugin.uninstall(app);
259
+ * @see install - Install the plugin.
260
+ */ uninstall (eleva) {
261
+ // Restore original _patchNode method if it exists
262
+ if (eleva.renderer && eleva.renderer._originalPatchNode) {
263
+ eleva.renderer._patchNode = eleva.renderer._originalPatchNode;
264
+ delete eleva.renderer._originalPatchNode;
265
+ }
266
+ // Remove plugin metadata
267
+ if (eleva.plugins) {
268
+ eleva.plugins.delete(this.name);
269
+ }
270
+ // Remove utility methods
271
+ delete eleva.updateElementAttributes;
272
+ }
273
+ };
274
+
275
+ export { AttrPlugin as Attr, AttrPlugin };
276
+ //# sourceMappingURL=attr.js.map
@@ -0,0 +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,4 +1,4 @@
1
- /*! Eleva Attr Plugin v1.0.0 | MIT License | https://elevajs.com */
1
+ /*! Eleva Attr Plugin v1.1.0 | 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) :
@@ -6,6 +6,37 @@
6
6
  })(this, (function (exports) { 'use strict';
7
7
 
8
8
  /**
9
+ * @module eleva/plugins/attr
10
+ * @fileoverview Attribute plugin providing ARIA, data, boolean, and dynamic attribute handling.
11
+ */ // ============================================================================
12
+ // TYPE DEFINITIONS
13
+ // ============================================================================
14
+ // -----------------------------------------------------------------------------
15
+ // External Type Imports
16
+ // -----------------------------------------------------------------------------
17
+ /**
18
+ * Type imports from the Eleva core library.
19
+ * @typedef {import('eleva').Eleva} Eleva
20
+ */ // -----------------------------------------------------------------------------
21
+ // Attr Type Definitions
22
+ // -----------------------------------------------------------------------------
23
+ /**
24
+ * Configuration options for the AttrPlugin.
25
+ * @typedef {Object} AttrPluginOptions
26
+ * @property {boolean} [enableAria=true]
27
+ * Enable ARIA attribute handling.
28
+ * @property {boolean} [enableData=true]
29
+ * Enable data attribute handling.
30
+ * @property {boolean} [enableBoolean=true]
31
+ * Enable boolean attribute handling.
32
+ * @property {boolean} [enableDynamic=true]
33
+ * Enable dynamic property detection.
34
+ * @description Configuration options passed to AttrPlugin.install().
35
+ */ /**
36
+ * Function signature for attribute update operations.
37
+ * @typedef {(oldEl: HTMLElement, newEl: HTMLElement) => void} AttributeUpdateFunction
38
+ * @description Updates attributes on oldEl to match newEl's attributes.
39
+ */ /**
9
40
  * A regular expression to match hyphenated lowercase letters.
10
41
  * @private
11
42
  * @type {RegExp}
@@ -46,33 +77,76 @@
46
77
  /**
47
78
  * Plugin version
48
79
  * @type {string}
49
- */ version: "1.0.0",
80
+ */ version: "1.1.0",
50
81
  /**
51
82
  * Plugin description
52
83
  * @type {string}
53
84
  */ description: "Advanced attribute handling for Eleva components",
54
85
  /**
55
- * Installs the plugin into the Eleva instance
86
+ * Installs the plugin into the Eleva instance.
87
+ *
88
+ * @public
89
+ * Method wrapping behavior:
90
+ * - Stores original `_patchNode` in `renderer._originalPatchNode`
91
+ * - Overrides `renderer._patchNode` to use enhanced attribute handling
92
+ * - Adds `renderer.updateAttributes` and `eleva.updateElementAttributes` helpers
93
+ * - Call `uninstall()` to restore original behavior
94
+ *
95
+ * @param {Eleva} eleva - The Eleva instance to enhance.
96
+ * @param {AttrPluginOptions} options - Plugin configuration options.
97
+ * @param {boolean} [options.enableAria=true] - Enable ARIA attribute handling.
98
+ * Maps aria-* attributes to DOM properties (e.g., aria-expanded → ariaExpanded).
99
+ * @param {boolean} [options.enableData=true] - Enable data attribute handling.
100
+ * Syncs data-* attributes with element.dataset for consistent access.
101
+ * @param {boolean} [options.enableBoolean=true] - Enable boolean attribute handling.
102
+ * Treats empty strings and attribute names as true, "false" string as false.
103
+ * @param {boolean} [options.enableDynamic=true] - Enable dynamic property detection.
104
+ * Searches element prototype chain for property matches (useful for custom elements).
105
+ * @returns {void}
106
+ * @example
107
+ * // Basic installation with defaults
108
+ * app.use(AttrPlugin);
56
109
  *
57
- * @param {Object} eleva - The Eleva instance
58
- * @param {Object} options - Plugin configuration options
59
- * @param {boolean} [options.enableAria=true] - Enable ARIA attribute handling
60
- * @param {boolean} [options.enableData=true] - Enable data attribute handling
61
- * @param {boolean} [options.enableBoolean=true] - Enable boolean attribute handling
62
- * @param {boolean} [options.enableDynamic=true] - Enable dynamic property detection
110
+ * @example
111
+ * // Custom configuration
112
+ * app.use(AttrPlugin, {
113
+ * enableAria: true,
114
+ * enableData: true,
115
+ * enableBoolean: true,
116
+ * enableDynamic: false // Disable for performance
117
+ * });
118
+ *
119
+ * @example
120
+ * // Using ARIA attributes in templates
121
+ * template: (ctx) => `
122
+ * <div role="dialog" aria-modal="true" aria-labelledby="title">
123
+ * <h2 id="title">Modal Title</h2>
124
+ * <button aria-expanded="${ctx.isOpen.value}">Toggle</button>
125
+ * </div>
126
+ * `
127
+ * @see uninstall - Remove the plugin and restore original behavior.
63
128
  */ install (eleva, options = {}) {
64
129
  const { enableAria = true, enableData = true, enableBoolean = true, enableDynamic = true } = options;
65
130
  /**
66
131
  * Updates the attributes of an element to match a new element's attributes.
67
- * This method provides sophisticated attribute processing including:
68
- * - ARIA attribute handling with proper property mapping
69
- * - Data attribute management
70
- * - Boolean attribute processing
71
- * - Dynamic property detection and mapping
72
- * - Attribute cleanup and removal
73
132
  *
74
- * @param {HTMLElement} oldEl - The original element to update
75
- * @param {HTMLElement} newEl - The new element to update
133
+ * Processing order:
134
+ * 1. Skip event attributes (@click, @input) - handled by Eleva's event system
135
+ * 2. Skip unchanged attributes - optimization
136
+ * 3. ARIA attributes (aria-*): Map to DOM properties (aria-expanded → ariaExpanded)
137
+ * 4. Data attributes (data-*): Update both dataset and attribute
138
+ * 5. Boolean attributes: Handle empty string as true, "false" as false
139
+ * 6. Other attributes: Map to properties with dynamic detection for custom elements
140
+ * 7. Remove old attributes not present in new element
141
+ *
142
+ * Dynamic property detection (when enableDynamic=true):
143
+ * - Checks if property exists directly on element
144
+ * - Searches element's prototype chain for case-insensitive matches
145
+ * - Enables compatibility with custom elements and Web Components
146
+ *
147
+ * @inner
148
+ * @param {HTMLElement} oldEl - The original element to update (modified in-place).
149
+ * @param {HTMLElement} newEl - The reference element with desired attributes.
76
150
  * @returns {void}
77
151
  */ const updateAttributes = (oldEl, newEl)=>{
78
152
  const oldAttrs = oldEl.attributes;
@@ -143,8 +217,14 @@
143
217
  // Store the original _patchNode method
144
218
  const originalPatchNode = eleva.renderer._patchNode;
145
219
  eleva.renderer._originalPatchNode = originalPatchNode;
146
- // Override the _patchNode method to use our attribute handler
147
- eleva.renderer._patchNode = function(oldNode, newNode) {
220
+ /**
221
+ * Overridden _patchNode method that uses enhanced attribute handling.
222
+ * Delegates to `updateAttributes` instead of the basic `_updateAttributes`.
223
+ *
224
+ * @param {Node} oldNode - The original DOM node to update.
225
+ * @param {Node} newNode - The new DOM node with desired state.
226
+ * @returns {void}
227
+ */ eleva.renderer._patchNode = function(oldNode, newNode) {
148
228
  if (oldNode?._eleva_instance) return;
149
229
  if (oldNode.nodeType === Node.TEXT_NODE) {
150
230
  if (oldNode.nodeValue !== newNode.nodeValue) {
@@ -168,12 +248,21 @@
168
248
  options
169
249
  });
170
250
  // Add utility methods for manual attribute updates
171
- eleva.updateElementAttributes = updateAttributes;
251
+ /** @type {AttributeUpdateFunction} */ eleva.updateElementAttributes = updateAttributes;
172
252
  },
173
253
  /**
174
- * Uninstalls the plugin from the Eleva instance
254
+ * Uninstalls the plugin from the Eleva instance.
175
255
  *
176
- * @param {Object} eleva - The Eleva instance
256
+ * @public
257
+ * @param {Eleva} eleva - The Eleva instance.
258
+ * @returns {void}
259
+ * @description
260
+ * Restores the original renderer patching behavior and removes
261
+ * `eleva.updateElementAttributes`.
262
+ * @example
263
+ * // Uninstall the plugin
264
+ * AttrPlugin.uninstall(app);
265
+ * @see install - Install the plugin.
177
266
  */ uninstall (eleva) {
178
267
  // Restore original _patchNode method if it exists
179
268
  if (eleva.renderer && eleva.renderer._originalPatchNode) {
@@ -1 +1 @@
1
- {"version":3,"file":"attr.umd.js","sources":["../../src/plugins/Attr.js"],"sourcesContent":["\"use strict\";\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.0.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 * @param {Object} eleva - The Eleva instance\n * @param {Object} options - Plugin configuration options\n * @param {boolean} [options.enableAria=true] - Enable ARIA attribute handling\n * @param {boolean} [options.enableData=true] - Enable data attribute handling\n * @param {boolean} [options.enableBoolean=true] - Enable boolean attribute handling\n * @param {boolean} [options.enableDynamic=true] - Enable dynamic property detection\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 * This method provides 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 * @param {HTMLElement} oldEl - The original element to update\n * @param {HTMLElement} newEl - The new element to update\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 // Override the _patchNode method to use our attribute handler\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 eleva.updateElementAttributes = updateAttributes;\n },\n\n /**\n * Uninstalls the plugin from the Eleva instance\n *\n * @param {Object} eleva - The Eleva instance\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.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,2 +1,2 @@
1
- var e,t;e=this,t=function(e){"use strict";let t=/-([a-z])/g,r={name:"attr",version:"1.0.0",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={});
1
+ var e,t;e=this,t=function(e){"use strict";let t=/-([a-z])/g,r={name:"attr",version:"1.1.0",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