@vanduo-oss/framework 1.3.9 → 1.4.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 (119) hide show
  1. package/README.md +87 -42
  2. package/css/components/affix.css +1 -1
  3. package/css/components/alerts.css +40 -40
  4. package/css/components/avatar.css +33 -33
  5. package/css/components/badges.css +42 -42
  6. package/css/components/breadcrumbs.css +5 -5
  7. package/css/components/bubble.css +4 -4
  8. package/css/components/buttons.css +124 -124
  9. package/css/components/cards.css +10 -10
  10. package/css/components/chips.css +28 -28
  11. package/css/components/code-snippet.css +18 -18
  12. package/css/components/collapsible.css +20 -20
  13. package/css/components/collections.css +21 -21
  14. package/css/components/datepicker.css +13 -13
  15. package/css/components/doc-search.css +46 -53
  16. package/css/components/doc-tabs.css +10 -10
  17. package/css/components/draggable.css +34 -34
  18. package/css/components/dropdown.css +14 -14
  19. package/css/components/expanding-cards.css +1 -1
  20. package/css/components/fab.css +7 -7
  21. package/css/components/flow.css +3 -3
  22. package/css/components/footer.css +26 -26
  23. package/css/components/forms.css +95 -83
  24. package/css/components/image-box.css +13 -17
  25. package/css/components/modals.css +8 -8
  26. package/css/components/music-player.css +26 -26
  27. package/css/components/navbar.css +27 -27
  28. package/css/components/pagination.css +15 -15
  29. package/css/components/preloader.css +10 -10
  30. package/css/components/progress.css +8 -8
  31. package/css/components/rating.css +4 -4
  32. package/css/components/sidenav.css +14 -14
  33. package/css/components/skeleton.css +10 -9
  34. package/css/components/spinner.css +10 -10
  35. package/css/components/spotlight.css +7 -7
  36. package/css/components/stepper.css +13 -13
  37. package/css/components/suggest.css +10 -10
  38. package/css/components/tabs.css +22 -22
  39. package/css/components/theme-customizer.css +87 -87
  40. package/css/components/timeline.css +14 -14
  41. package/css/components/timepicker.css +7 -7
  42. package/css/components/toast.css +31 -31
  43. package/css/components/tooltips.css +11 -11
  44. package/css/components/transfer.css +12 -12
  45. package/css/components/tree.css +9 -9
  46. package/css/components/waypoint.css +3 -3
  47. package/css/core/colors.css +34 -34
  48. package/css/core/grid.css +1 -6
  49. package/css/core/helpers.css +11 -11
  50. package/css/core/tokens.css +113 -35
  51. package/css/core/typography.css +14 -12
  52. package/css/core/vd-aliases.css +100 -52
  53. package/css/effects/morph.css +5 -5
  54. package/css/utilities/media.css +2 -2
  55. package/css/utilities/table.css +34 -34
  56. package/css/utilities/transitions.css +22 -10
  57. package/css/vanduo.css +14 -34
  58. package/dist/build-info.json +3 -3
  59. package/dist/vanduo.cjs.js +929 -289
  60. package/dist/vanduo.cjs.js.map +3 -3
  61. package/dist/vanduo.cjs.min.js +7 -7
  62. package/dist/vanduo.cjs.min.js.map +3 -3
  63. package/dist/vanduo.css +7914 -7823
  64. package/dist/vanduo.css.map +1 -1
  65. package/dist/vanduo.esm.js +929 -289
  66. package/dist/vanduo.esm.js.map +3 -3
  67. package/dist/vanduo.esm.min.js +7 -7
  68. package/dist/vanduo.esm.min.js.map +3 -3
  69. package/dist/vanduo.js +929 -289
  70. package/dist/vanduo.js.map +3 -3
  71. package/dist/vanduo.min.css +2 -2
  72. package/dist/vanduo.min.css.map +1 -1
  73. package/dist/vanduo.min.js +7 -7
  74. package/dist/vanduo.min.js.map +3 -3
  75. package/js/components/affix.js +2 -2
  76. package/js/components/bubble.js +3 -3
  77. package/js/components/code-snippet.js +129 -5
  78. package/js/components/collapsible.js +2 -3
  79. package/js/components/datepicker.js +2 -2
  80. package/js/components/doc-search.js +69 -11
  81. package/js/components/draggable.js +4 -4
  82. package/js/components/dropdown.js +2 -3
  83. package/js/components/expanding-cards.js +2 -2
  84. package/js/components/flow.js +2 -2
  85. package/js/components/font-switcher.js +23 -13
  86. package/js/components/glass.js +2 -2
  87. package/js/components/grid.js +19 -8
  88. package/js/components/image-box.js +49 -10
  89. package/js/components/lazy-load.js +81 -9
  90. package/js/components/modals.js +28 -12
  91. package/js/components/morph.js +2 -2
  92. package/js/components/music-player.js +2 -2
  93. package/js/components/navbar.js +2 -2
  94. package/js/components/pagination.js +2 -3
  95. package/js/components/parallax.js +9 -10
  96. package/js/components/preloader.js +14 -5
  97. package/js/components/rating.js +2 -2
  98. package/js/components/ripple.js +2 -2
  99. package/js/components/select.js +2 -3
  100. package/js/components/sidenav.js +43 -14
  101. package/js/components/spotlight.js +2 -2
  102. package/js/components/stepper.js +2 -2
  103. package/js/components/suggest.js +9 -3
  104. package/js/components/tabs.js +2 -2
  105. package/js/components/theme-customizer.js +151 -21
  106. package/js/components/theme-switcher.js +27 -16
  107. package/js/components/timeline.js +41 -12
  108. package/js/components/timepicker.js +2 -2
  109. package/js/components/toast.js +1 -1
  110. package/js/components/tooltips.js +4 -4
  111. package/js/components/transfer.js +2 -2
  112. package/js/components/tree.js +2 -2
  113. package/js/components/validate.js +2 -2
  114. package/js/components/vd-hex.js +12 -6
  115. package/js/components/waypoint.js +2 -2
  116. package/js/utils/helpers.js +7 -4
  117. package/js/utils/lifecycle.js +158 -83
  118. package/js/vanduo.js +203 -34
  119. package/package.json +2 -1
@@ -1,4 +1,4 @@
1
- /*! Vanduo v1.3.9 | Built: 2026-05-10T18:54:59.798Z | git:2945a85 | development */
1
+ /*! Vanduo v1.4.0 | Built: 2026-05-20T14:51:00.085Z | git:46420b0 | development */
2
2
  var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -28,190 +28,398 @@ module.exports = __toCommonJS(index_exports);
28
28
  // js/utils/lifecycle.js
29
29
  (function() {
30
30
  "use strict";
31
+ function normalizeCallbacks(value) {
32
+ if (!value) return [];
33
+ if (Array.isArray(value)) {
34
+ return value.filter(function(fn) {
35
+ return typeof fn === "function";
36
+ });
37
+ }
38
+ return typeof value === "function" ? [value] : [];
39
+ }
40
+ function normalizeOptions(options) {
41
+ if (typeof options === "function") {
42
+ return { onDestroy: [options] };
43
+ }
44
+ return options || {};
45
+ }
46
+ function callSafely(label, fn) {
47
+ try {
48
+ fn();
49
+ } catch (error) {
50
+ console.warn("[Vanduo Lifecycle] " + label + " error:", error);
51
+ }
52
+ }
31
53
  const Lifecycle = {
32
- // Map of element -> { componentName, cleanupFunctions }
54
+ // Map<Element, Map<componentName, { cleanup, onDestroy, registeredAt }>>
33
55
  instances: /* @__PURE__ */ new Map(),
34
- /**
35
- * Register a component instance
36
- * @param {HTMLElement} element - The DOM element
37
- * @param {string} componentName - Name of the component
38
- * @param {Array<Function>} cleanupFns - Functions to call on destroy
39
- */
40
- register: function(element, componentName, cleanupFns = []) {
41
- if (this.instances.has(element)) {
42
- const existing = this.instances.get(element);
43
- existing.cleanup = existing.cleanup.concat(cleanupFns);
56
+ isRoot: function(root) {
57
+ return !!root && (root === document || root.nodeType === 1 || root.nodeType === 9 || root.nodeType === 11);
58
+ },
59
+ normalizeRoot: function(root) {
60
+ return this.isRoot(root) ? root : document;
61
+ },
62
+ isInRoot: function(root, element) {
63
+ const scope = this.normalizeRoot(root);
64
+ if (!(element instanceof Element)) return false;
65
+ if (scope === document) {
66
+ return document.documentElement ? document.documentElement.contains(element) : document.contains(element);
67
+ }
68
+ if (scope === element) return true;
69
+ return typeof scope.contains === "function" && scope.contains(element);
70
+ },
71
+ queryAll: function(root, selector) {
72
+ const scope = this.normalizeRoot(root);
73
+ const matches = [];
74
+ if (scope instanceof Element && typeof scope.matches === "function" && scope.matches(selector)) {
75
+ matches.push(scope);
76
+ }
77
+ if (typeof scope.querySelectorAll === "function") {
78
+ const descendants = scope.querySelectorAll(selector);
79
+ for (let i = 0; i < descendants.length; i++) {
80
+ matches.push(descendants[i]);
81
+ }
82
+ }
83
+ return matches;
84
+ },
85
+ queryOne: function(root, selector) {
86
+ const matches = this.queryAll(root, selector);
87
+ return matches.length ? matches[0] : null;
88
+ },
89
+ runInRoot: function(root, fn) {
90
+ const scope = this.normalizeRoot(root);
91
+ return fn(scope);
92
+ },
93
+ register: function(element, componentName, cleanupFns, options) {
94
+ if (!(element instanceof Element) || !componentName) return;
95
+ const optionBag = normalizeOptions(options);
96
+ const cleanup = normalizeCallbacks(cleanupFns);
97
+ const onDestroy = normalizeCallbacks(optionBag.onDestroy);
98
+ const componentEntries = this.instances.get(element) || /* @__PURE__ */ new Map();
99
+ const existing = componentEntries.get(componentName);
100
+ if (existing) {
101
+ existing.cleanup = existing.cleanup.concat(cleanup);
102
+ existing.onDestroy = existing.onDestroy.concat(onDestroy);
44
103
  return;
45
104
  }
46
- this.instances.set(element, {
105
+ componentEntries.set(componentName, {
47
106
  component: componentName,
48
- cleanup: cleanupFns,
107
+ cleanup,
108
+ onDestroy,
49
109
  registeredAt: Date.now()
50
110
  });
111
+ this.instances.set(element, componentEntries);
51
112
  },
52
- /**
53
- * Unregister a single element and run its cleanup
54
- * @param {HTMLElement} element - The element to unregister
55
- */
56
- unregister: function(element) {
57
- const instance = this.instances.get(element);
58
- if (!instance) return;
59
- instance.cleanup.forEach(function(fn) {
60
- try {
61
- fn();
62
- } catch (e) {
63
- console.warn("[Vanduo Lifecycle] Cleanup error:", e);
113
+ unregister: function(element, componentName) {
114
+ const componentEntries = this.instances.get(element);
115
+ if (!componentEntries) return;
116
+ if (componentName) {
117
+ const entry = componentEntries.get(componentName);
118
+ if (!entry) return;
119
+ componentEntries.delete(componentName);
120
+ if (!componentEntries.size) {
121
+ this.instances.delete(element);
64
122
  }
65
- });
123
+ entry.cleanup.forEach(function(fn) {
124
+ callSafely("Cleanup", fn);
125
+ });
126
+ entry.onDestroy.forEach(function(fn) {
127
+ callSafely("Destroy", fn);
128
+ });
129
+ return;
130
+ }
131
+ const entries = Array.from(componentEntries.values());
66
132
  this.instances.delete(element);
133
+ entries.forEach(function(entry) {
134
+ entry.cleanup.forEach(function(fn) {
135
+ callSafely("Cleanup", fn);
136
+ });
137
+ entry.onDestroy.forEach(function(fn) {
138
+ callSafely("Destroy", fn);
139
+ });
140
+ });
67
141
  },
68
- /**
69
- * Destroy all instances of a specific component
70
- * @param {string} componentName - Optional component name filter
71
- */
72
142
  destroyAll: function(componentName) {
73
143
  const toRemove = [];
74
- this.instances.forEach(function(instance, element) {
75
- if (!componentName || instance.component === componentName) {
76
- toRemove.push(element);
144
+ this.instances.forEach(function(componentEntries, element) {
145
+ if (!componentName) {
146
+ toRemove.push([element, null]);
147
+ return;
148
+ }
149
+ if (componentEntries.has(componentName)) {
150
+ toRemove.push([element, componentName]);
77
151
  }
78
152
  });
79
- toRemove.forEach(function(element) {
80
- Lifecycle.unregister(element);
153
+ toRemove.forEach(function(entry) {
154
+ Lifecycle.unregister(entry[0], entry[1] || void 0);
81
155
  });
156
+ return toRemove.length;
82
157
  },
83
- /**
84
- * Destroy all instances within a specific container
85
- * Useful for SPAs when navigating between pages
86
- * @param {HTMLElement} container - Container element
87
- */
88
- destroyAllInContainer: function(container) {
158
+ destroyAllInContainer: function(container, componentName) {
159
+ const scope = this.normalizeRoot(container);
89
160
  const toRemove = [];
90
- this.instances.forEach(function(instance, element) {
91
- if (container.contains(element)) {
92
- toRemove.push(element);
161
+ this.instances.forEach(function(componentEntries, element) {
162
+ if (!Lifecycle.isInRoot(scope, element)) return;
163
+ if (!componentName) {
164
+ toRemove.push([element, null]);
165
+ return;
166
+ }
167
+ if (componentEntries.has(componentName)) {
168
+ toRemove.push([element, componentName]);
93
169
  }
94
170
  });
95
- toRemove.forEach(function(element) {
96
- Lifecycle.unregister(element);
171
+ toRemove.forEach(function(entry) {
172
+ Lifecycle.unregister(entry[0], entry[1] || void 0);
97
173
  });
174
+ return toRemove.length;
98
175
  },
99
- /**
100
- * Get all registered instances (for debugging)
101
- * @returns {Array} Array of instance info objects
102
- */
103
176
  getAll: function() {
104
177
  const result = [];
105
- this.instances.forEach(function(instance, element) {
106
- result.push({
107
- element,
108
- component: instance.component,
109
- registeredAt: instance.registeredAt
178
+ this.instances.forEach(function(componentEntries, element) {
179
+ componentEntries.forEach(function(entry) {
180
+ result.push({
181
+ element,
182
+ component: entry.component,
183
+ registeredAt: entry.registeredAt
184
+ });
110
185
  });
111
186
  });
112
187
  return result;
113
188
  },
114
- /**
115
- * Check if an element is registered
116
- * @param {HTMLElement} element - The element to check
117
- * @returns {boolean}
118
- */
119
- has: function(element) {
120
- return this.instances.has(element);
189
+ has: function(element, componentName) {
190
+ const componentEntries = this.instances.get(element);
191
+ if (!componentEntries) return false;
192
+ return componentName ? componentEntries.has(componentName) : componentEntries.size > 0;
121
193
  }
122
194
  };
123
195
  window.addEventListener("beforeunload", function() {
124
196
  Lifecycle.destroyAll();
125
197
  });
126
198
  window.VanduoLifecycle = Lifecycle;
127
- if (typeof window.Vanduo !== "undefined") {
128
- window.Vanduo.register("lifecycle", Lifecycle);
129
- }
130
199
  })();
131
200
 
132
201
  // js/vanduo.js
133
202
  (function() {
134
203
  "use strict";
135
- const VANDUO_VERSION = true ? "1.3.9" : "0.0.0-dev";
204
+ const VANDUO_VERSION = true ? "1.4.0" : "0.0.0-dev";
205
+ const hasOwn = Object.prototype.hasOwnProperty;
136
206
  const Vanduo2 = {
137
207
  version: VANDUO_VERSION,
138
208
  components: {},
209
+ aliases: {},
210
+ _decoratedComponents: /* @__PURE__ */ new WeakSet(),
211
+ resolveComponentName: function(name) {
212
+ return this.aliases[name] || name;
213
+ },
214
+ _isRoot: function(root) {
215
+ if (typeof window.VanduoLifecycle !== "undefined" && typeof window.VanduoLifecycle.isRoot === "function") {
216
+ return window.VanduoLifecycle.isRoot(root);
217
+ }
218
+ return !!root && (root === document || root.nodeType === 1 || root.nodeType === 9 || root.nodeType === 11);
219
+ },
220
+ _normalizeRoot: function(root) {
221
+ return this._isRoot(root) ? root : document;
222
+ },
223
+ _queryAll: function(root, selector) {
224
+ const scope = this._normalizeRoot(root);
225
+ const matches = [];
226
+ if (scope instanceof Element && typeof scope.matches === "function" && scope.matches(selector)) {
227
+ matches.push(scope);
228
+ }
229
+ if (typeof scope.querySelectorAll === "function") {
230
+ const descendants = scope.querySelectorAll(selector);
231
+ for (let i = 0; i < descendants.length; i++) {
232
+ matches.push(descendants[i]);
233
+ }
234
+ }
235
+ return matches;
236
+ },
237
+ queryAll: function(root, selector) {
238
+ if (typeof selector === "undefined") {
239
+ selector = root;
240
+ root = document;
241
+ }
242
+ return this._queryAll(root, selector);
243
+ },
244
+ queryOne: function(root, selector) {
245
+ const matches = this.queryAll(root, selector);
246
+ return matches.length ? matches[0] : null;
247
+ },
248
+ _isLifecycleManagedComponent: function(component) {
249
+ if (!component || typeof component !== "object") return false;
250
+ for (const key in component) {
251
+ if (hasOwn.call(component, key) && component[key] instanceof Map) {
252
+ return true;
253
+ }
254
+ }
255
+ return false;
256
+ },
257
+ _syncComponentLifecycle: function(name, component, root) {
258
+ const lifecycle = window.VanduoLifecycle;
259
+ if (!lifecycle || !this._isLifecycleManagedComponent(component)) return;
260
+ const componentName = this.resolveComponentName(name);
261
+ const scope = this._normalizeRoot(root);
262
+ for (const key in component) {
263
+ if (!hasOwn.call(component, key) || !(component[key] instanceof Map)) {
264
+ continue;
265
+ }
266
+ component[key].forEach(function(instance, element) {
267
+ if (!(element instanceof Element) || !lifecycle.isInRoot(scope, element) || lifecycle.has(element, componentName)) {
268
+ return;
269
+ }
270
+ if (typeof component.destroy === "function") {
271
+ lifecycle.register(element, componentName, [], function() {
272
+ component.destroy(element);
273
+ });
274
+ return;
275
+ }
276
+ const cleanup = instance && Array.isArray(instance.cleanup) ? instance.cleanup : [];
277
+ lifecycle.register(element, componentName, cleanup, function() {
278
+ component[key].delete(element);
279
+ });
280
+ });
281
+ }
282
+ },
283
+ _decorateComponent: function(name, component) {
284
+ const framework = this;
285
+ const lifecycle = window.VanduoLifecycle;
286
+ if (!component || typeof component !== "object" || this._decoratedComponents.has(component)) {
287
+ return;
288
+ }
289
+ const originalInit = typeof component.init === "function" ? component.init : null;
290
+ if (originalInit) {
291
+ component.init = function(...args) {
292
+ const scopedRoot = framework._isRoot(args[0]) ? args[0] : null;
293
+ const result = originalInit.apply(this, args);
294
+ if (window.Vanduo) {
295
+ const syncRoot = scopedRoot || document;
296
+ window.Vanduo._syncComponentLifecycle(name, this, syncRoot);
297
+ }
298
+ return result;
299
+ };
300
+ }
301
+ const originalDestroyAll = typeof component.destroyAll === "function" ? component.destroyAll : null;
302
+ if (originalDestroyAll) {
303
+ component.destroyAll = function(...args) {
304
+ const scopedRoot = framework._isRoot(args[0]) ? args[0] : null;
305
+ const componentName = window.Vanduo ? window.Vanduo.resolveComponentName(name) : name;
306
+ if (lifecycle && window.Vanduo && window.Vanduo._isLifecycleManagedComponent(this)) {
307
+ if (scopedRoot && scopedRoot !== document) {
308
+ lifecycle.destroyAllInContainer(scopedRoot, componentName);
309
+ if (this.__vanduoScopedDestroyAll === true) {
310
+ return originalDestroyAll.apply(this, args);
311
+ }
312
+ return;
313
+ }
314
+ lifecycle.destroyAll(componentName);
315
+ }
316
+ return originalDestroyAll.apply(this, args);
317
+ };
318
+ }
319
+ this._decoratedComponents.add(component);
320
+ },
139
321
  /**
140
322
  * Initialize framework
141
323
  * Call this after DOM is ready and all components are loaded
142
324
  */
143
- init: function() {
325
+ init: function(root) {
326
+ const scope = this._normalizeRoot(root);
327
+ if (scope !== document) {
328
+ this.initComponents(scope);
329
+ return;
330
+ }
144
331
  if (typeof ready !== "undefined") {
145
332
  ready(() => {
146
- this.initComponents();
333
+ this.initComponents(document);
147
334
  });
148
- } else {
149
- if (document.readyState === "loading") {
150
- document.addEventListener("DOMContentLoaded", () => {
151
- this.initComponents();
152
- });
153
- } else {
154
- this.initComponents();
155
- }
335
+ return;
156
336
  }
337
+ if (document.readyState === "loading") {
338
+ document.addEventListener("DOMContentLoaded", () => {
339
+ this.initComponents(document);
340
+ });
341
+ return;
342
+ }
343
+ this.initComponents(document);
157
344
  },
158
345
  /**
159
346
  * Initialize all components
160
347
  */
161
- initComponents: function() {
348
+ initComponents: function(root) {
349
+ const scope = this._normalizeRoot(root);
162
350
  Object.keys(this.components).forEach((name) => {
163
351
  const component = this.components[name];
164
352
  if (component.init && typeof component.init === "function") {
165
353
  try {
166
- component.init();
354
+ component.init(scope);
167
355
  } catch (e) {
168
356
  console.warn('[Vanduo] Failed to initialize component "' + name + '":', e);
169
357
  }
170
358
  }
171
359
  });
172
- console.log("Vanduo Framework v" + this.version + " initialized");
173
360
  },
174
361
  /**
175
362
  * Register a component
176
363
  * @param {string} name - Component name
177
364
  * @param {Object} component - Component object with init method
178
365
  */
179
- register: function(name, component) {
366
+ register: function(name, component, options) {
367
+ const opts = options || {};
368
+ this._decorateComponent(name, component);
180
369
  this.components[name] = component;
370
+ if (Array.isArray(opts.aliases)) {
371
+ opts.aliases.forEach((alias) => {
372
+ this.aliases[alias] = name;
373
+ });
374
+ }
375
+ },
376
+ registerAlias: function(alias, name) {
377
+ const canonicalName = this.resolveComponentName(name);
378
+ if (this.components[canonicalName]) {
379
+ this.aliases[alias] = canonicalName;
380
+ }
181
381
  },
182
382
  /**
183
383
  * Re-initialize a component (useful after dynamic DOM changes)
184
384
  * @param {string} name - Component name
185
385
  */
186
- reinit: function(name) {
187
- const component = this.components[name];
386
+ reinit: function(name, root) {
387
+ const scope = this._normalizeRoot(root);
388
+ const componentName = this.resolveComponentName(name);
389
+ const component = this.components[componentName];
188
390
  if (component && component.init && typeof component.init === "function") {
189
391
  try {
190
- component.init();
392
+ if (component.destroyAll && typeof component.destroyAll === "function") {
393
+ component.destroyAll(scope);
394
+ }
395
+ component.init(scope);
191
396
  } catch (e) {
192
- console.warn('[Vanduo] Failed to reinitialize component "' + name + '":', e);
397
+ console.warn('[Vanduo] Failed to reinitialize component "' + componentName + '":', e);
193
398
  }
194
399
  }
195
400
  },
196
401
  /**
197
- * Destroy all component instances and clean up event listeners
198
- * Uses lifecycle manager for memory leak prevention
402
+ * Destroy component instances within the provided root.
199
403
  */
200
- destroyAll: function() {
404
+ destroy: function(root) {
405
+ const scope = this._normalizeRoot(root);
201
406
  const names = Object.keys(this.components);
202
407
  for (let i = 0; i < names.length; i++) {
203
408
  const component = this.components[names[i]];
204
409
  if (component && component.destroyAll && typeof component.destroyAll === "function") {
205
410
  try {
206
- component.destroyAll();
411
+ component.destroyAll(scope);
207
412
  } catch (e) {
208
413
  console.warn('[Vanduo] Failed to destroy component "' + names[i] + '":', e);
209
414
  }
210
415
  }
211
416
  }
212
- if (typeof window.VanduoLifecycle !== "undefined") {
213
- window.VanduoLifecycle.destroyAll();
214
- }
417
+ },
418
+ /**
419
+ * Destroy all component instances and clean up event listeners.
420
+ */
421
+ destroyAll: function() {
422
+ this.destroy(document);
215
423
  },
216
424
  /**
217
425
  * Get component instance
@@ -219,7 +427,8 @@ module.exports = __toCommonJS(index_exports);
219
427
  * @returns {Object|null}
220
428
  */
221
429
  getComponent: function(name) {
222
- return this.components[name] || null;
430
+ const componentName = this.resolveComponentName(name);
431
+ return this.components[componentName] || null;
223
432
  }
224
433
  };
225
434
  window.Vanduo = Vanduo2;
@@ -230,6 +439,26 @@ module.exports = __toCommonJS(index_exports);
230
439
  "use strict";
231
440
  const CodeSnippet = {
232
441
  _snippetIdCounter: 0,
442
+ resolveRoot: function(root) {
443
+ if (root && (root.nodeType === 1 || root.nodeType === 9 || root.nodeType === 11)) {
444
+ return root;
445
+ }
446
+ return document;
447
+ },
448
+ queryWithin: function(root, selector) {
449
+ const scope = this.resolveRoot(root);
450
+ const matches = [];
451
+ if (scope instanceof Element && typeof scope.matches === "function" && scope.matches(selector)) {
452
+ matches.push(scope);
453
+ }
454
+ if (typeof scope.querySelectorAll === "function") {
455
+ const descendants = scope.querySelectorAll(selector);
456
+ for (let i = 0; i < descendants.length; i++) {
457
+ matches.push(descendants[i]);
458
+ }
459
+ }
460
+ return matches;
461
+ },
233
462
  getSnippetInstanceId: function(snippet) {
234
463
  if (snippet.dataset.codeSnippetId) {
235
464
  return snippet.dataset.codeSnippetId;
@@ -254,8 +483,8 @@ module.exports = __toCommonJS(index_exports);
254
483
  /**
255
484
  * Initialize all code snippet components
256
485
  */
257
- init: function() {
258
- const snippets = document.querySelectorAll(".vd-code-snippet");
486
+ init: function(root) {
487
+ const snippets = this.queryWithin(root, ".vd-code-snippet");
259
488
  snippets.forEach((snippet) => {
260
489
  if (!snippet.dataset.initialized) {
261
490
  this.initSnippet(snippet);
@@ -287,6 +516,10 @@ module.exports = __toCommonJS(index_exports);
287
516
  extractPanes.forEach((pane) => {
288
517
  this.extractHtml(pane);
289
518
  });
519
+ const panesToHighlight = snippet.querySelectorAll(".vd-code-snippet-pane:not([data-extract])");
520
+ panesToHighlight.forEach((pane) => {
521
+ this.applyPaneHighlighting(pane);
522
+ });
290
523
  const lineNumberPanes = snippet.querySelectorAll(".has-line-numbers");
291
524
  lineNumberPanes.forEach((pane) => {
292
525
  this.addLineNumbers(pane);
@@ -522,6 +755,7 @@ module.exports = __toCommonJS(index_exports);
522
755
  codeEl.innerHTML = html;
523
756
  pane.replaceChildren(codeEl);
524
757
  pane.dataset.extracted = "true";
758
+ pane.dataset.highlighted = "true";
525
759
  },
526
760
  /**
527
761
  * Format HTML with proper indentation
@@ -563,6 +797,77 @@ module.exports = __toCommonJS(index_exports);
563
797
  div.textContent = html;
564
798
  return div.innerHTML;
565
799
  },
800
+ needsHighlighting: function(pane, codeEl) {
801
+ if (!codeEl) return false;
802
+ if (pane.dataset.highlighted === "true") return false;
803
+ if (codeEl.querySelector('[class^="code-"], [class*=" code-"]')) return false;
804
+ return true;
805
+ },
806
+ getHighlightMode: function(lang) {
807
+ const normalized = String(lang || "").trim().toLowerCase();
808
+ if ([
809
+ "html",
810
+ "xml",
811
+ "svg",
812
+ "vue",
813
+ "svelte",
814
+ "astro"
815
+ ].includes(normalized)) {
816
+ return "html";
817
+ }
818
+ if ([
819
+ "css",
820
+ "scss",
821
+ "sass",
822
+ "less"
823
+ ].includes(normalized)) {
824
+ return "css";
825
+ }
826
+ if ([
827
+ "js",
828
+ "mjs",
829
+ "cjs",
830
+ "ts",
831
+ "jsx",
832
+ "tsx",
833
+ "json",
834
+ "bash",
835
+ "sh"
836
+ ].includes(normalized)) {
837
+ return "js";
838
+ }
839
+ return "plain";
840
+ },
841
+ highlightCodeByLang: function(rawCode, lang) {
842
+ const escaped = this.escapeHtml(rawCode);
843
+ const mode = this.getHighlightMode(lang);
844
+ if (mode === "html") {
845
+ return this.highlightHtml(escaped);
846
+ }
847
+ if (mode === "css") {
848
+ return this.highlightCss(escaped);
849
+ }
850
+ if (mode === "js") {
851
+ return this.highlightJs(escaped);
852
+ }
853
+ return escaped;
854
+ },
855
+ applyPaneHighlighting: function(pane) {
856
+ if (!pane) return;
857
+ const codeEl = pane.querySelector("code") || pane;
858
+ if (!this.needsHighlighting(pane, codeEl)) {
859
+ pane.dataset.highlighted = "true";
860
+ return;
861
+ }
862
+ const rawCode = codeEl.textContent || "";
863
+ const highlighted = this.highlightCodeByLang(rawCode, pane.dataset.lang);
864
+ const nextCodeEl = codeEl.tagName === "CODE" ? codeEl : document.createElement("code");
865
+ nextCodeEl.innerHTML = highlighted;
866
+ if (nextCodeEl !== codeEl) {
867
+ pane.replaceChildren(nextCodeEl);
868
+ }
869
+ pane.dataset.highlighted = "true";
870
+ },
566
871
  /**
567
872
  * Apply syntax highlighting to HTML
568
873
  * @param {string} html - Escaped HTML string
@@ -570,7 +875,9 @@ module.exports = __toCommonJS(index_exports);
570
875
  */
571
876
  highlightHtml: function(html) {
572
877
  html = html.replace(/(&lt;\/?)([\w-]+)/g, '$1<span class="code-tag">$2</span>');
878
+ html = html.replace(/([\w-]+)(=)(["'])/g, '<span class="code-attr">$1</span>$2$3');
573
879
  html = html.replace(/([\w-]+)(=)(&quot;|&#39;)/g, '<span class="code-attr">$1</span>$2$3');
880
+ html = html.replace(/(["'])([^"']*)(["'])/g, '$1<span class="code-string">$2</span>$3');
574
881
  html = html.replace(/(&quot;|&#39;)([^&]*)(&quot;|&#39;)/g, '$1<span class="code-string">$2</span>$3');
575
882
  html = html.replace(/(&lt;!--)(.*?)(--&gt;)/g, '<span class="code-comment">$1$2$3</span>');
576
883
  return html;
@@ -695,9 +1002,12 @@ module.exports = __toCommonJS(index_exports);
695
1002
  /**
696
1003
  * Destroy all code snippet instances
697
1004
  */
698
- destroyAll: function() {
699
- const snippets = document.querySelectorAll('.vd-code-snippet[data-initialized="true"]');
700
- snippets.forEach((snippet) => this.destroy(snippet));
1005
+ destroyAll: function(root) {
1006
+ const scope = this.resolveRoot(root);
1007
+ const snippets = this.queryWithin(scope, '.vd-code-snippet[data-initialized="true"]');
1008
+ snippets.forEach((snippet) => {
1009
+ this.destroy(snippet);
1010
+ });
701
1011
  }
702
1012
  };
703
1013
  if (typeof window.Vanduo !== "undefined") {
@@ -715,8 +1025,8 @@ module.exports = __toCommonJS(index_exports);
715
1025
  /**
716
1026
  * Initialize collapsible components
717
1027
  */
718
- init: function() {
719
- const collapsibles = document.querySelectorAll(".vd-collapsible, .accordion");
1028
+ init: function(root) {
1029
+ const collapsibles = window.Vanduo.queryAll(root, ".vd-collapsible, .accordion");
720
1030
  collapsibles.forEach((container) => {
721
1031
  if (this.instances.has(container)) {
722
1032
  return;
@@ -893,8 +1203,8 @@ module.exports = __toCommonJS(index_exports);
893
1203
  /**
894
1204
  * Initialize dropdown components
895
1205
  */
896
- init: function() {
897
- const dropdowns = document.querySelectorAll(".vd-dropdown");
1206
+ init: function(root) {
1207
+ const dropdowns = window.Vanduo.queryAll(root, ".vd-dropdown");
898
1208
  dropdowns.forEach((dropdown) => {
899
1209
  if (this.instances.has(dropdown)) {
900
1210
  return;
@@ -1212,7 +1522,13 @@ module.exports = __toCommonJS(index_exports);
1212
1522
  description: "Friendly, rounded sans-serif"
1213
1523
  }
1214
1524
  },
1215
- init: function() {
1525
+ getToggles: function(root) {
1526
+ if (window.Vanduo && typeof window.Vanduo.queryAll === "function") {
1527
+ return window.Vanduo.queryAll(root, '[data-toggle="font"]');
1528
+ }
1529
+ return Array.from(document.querySelectorAll('[data-toggle="font"]'));
1530
+ },
1531
+ init: function(root) {
1216
1532
  this.state = {
1217
1533
  preference: this.getPreference()
1218
1534
  };
@@ -1222,14 +1538,13 @@ module.exports = __toCommonJS(index_exports);
1222
1538
  }
1223
1539
  if (this.isInitialized) {
1224
1540
  this.applyFont();
1225
- this.renderUI();
1226
- this.updateUI();
1541
+ this.renderUI(root);
1542
+ this.updateUI(root);
1227
1543
  return;
1228
1544
  }
1229
1545
  this.isInitialized = true;
1230
1546
  this.applyFont();
1231
- this.renderUI();
1232
- console.log("Vanduo Font Switcher initialized");
1547
+ this.renderUI(root);
1233
1548
  },
1234
1549
  /**
1235
1550
  * Get saved font preference from localStorage
@@ -1271,8 +1586,8 @@ module.exports = __toCommonJS(index_exports);
1271
1586
  /**
1272
1587
  * Initialize UI elements with data-toggle="font"
1273
1588
  */
1274
- renderUI: function() {
1275
- const toggles = document.querySelectorAll('[data-toggle="font"]');
1589
+ renderUI: function(root) {
1590
+ const toggles = this.getToggles(root);
1276
1591
  toggles.forEach((toggle) => {
1277
1592
  if (toggle.getAttribute("data-font-initialized") === "true") {
1278
1593
  if (toggle.tagName === "SELECT") {
@@ -1303,8 +1618,8 @@ module.exports = __toCommonJS(index_exports);
1303
1618
  /**
1304
1619
  * Update all UI elements to reflect current state
1305
1620
  */
1306
- updateUI: function() {
1307
- const toggles = document.querySelectorAll('[data-toggle="font"]');
1621
+ updateUI: function(root) {
1622
+ const toggles = this.getToggles(root);
1308
1623
  toggles.forEach((toggle) => {
1309
1624
  if (toggle.tagName === "SELECT") {
1310
1625
  toggle.value = this.state.preference;
@@ -1331,8 +1646,10 @@ module.exports = __toCommonJS(index_exports);
1331
1646
  getFontData: function(fontKey) {
1332
1647
  return this.fonts[fontKey] || null;
1333
1648
  },
1334
- destroyAll: function() {
1335
- const toggles = document.querySelectorAll('[data-toggle="font"][data-font-initialized="true"]');
1649
+ destroyAll: function(root) {
1650
+ const toggles = this.getToggles(root || document).filter(function(toggle) {
1651
+ return toggle.getAttribute("data-font-initialized") === "true";
1652
+ });
1336
1653
  toggles.forEach((toggle) => {
1337
1654
  if (toggle._fontToggleHandler) {
1338
1655
  const eventName = toggle.tagName === "SELECT" ? "change" : "click";
@@ -1341,7 +1658,9 @@ module.exports = __toCommonJS(index_exports);
1341
1658
  }
1342
1659
  toggle.removeAttribute("data-font-initialized");
1343
1660
  });
1344
- this.isInitialized = false;
1661
+ if (!root || root === document) {
1662
+ this.isInitialized = false;
1663
+ }
1345
1664
  },
1346
1665
  getStorageValue: function(key, fallback) {
1347
1666
  if (typeof window.safeStorageGet === "function") {
@@ -1384,18 +1703,19 @@ module.exports = __toCommonJS(index_exports);
1384
1703
  })();
1385
1704
  const GridLayout = {
1386
1705
  instances: /* @__PURE__ */ new Map(),
1706
+ __vanduoScopedDestroyAll: true,
1387
1707
  /**
1388
1708
  * Initialize all grid layout containers
1389
1709
  */
1390
- init: function() {
1391
- const containers = document.querySelectorAll("[data-layout-mode]");
1710
+ init: function(root) {
1711
+ const containers = window.Vanduo.queryAll(root, "[data-layout-mode]");
1392
1712
  containers.forEach(function(container) {
1393
1713
  if (this.instances.has(container)) {
1394
1714
  return;
1395
1715
  }
1396
1716
  this.initContainer(container);
1397
1717
  }.bind(this));
1398
- this.initToggleButtons();
1718
+ this.initToggleButtons(root);
1399
1719
  },
1400
1720
  /**
1401
1721
  * Initialize a single grid container
@@ -1415,8 +1735,8 @@ module.exports = __toCommonJS(index_exports);
1415
1735
  /**
1416
1736
  * Initialize toggle buttons that target grid containers
1417
1737
  */
1418
- initToggleButtons: function() {
1419
- const toggleButtons = document.querySelectorAll("[data-grid-toggle]");
1738
+ initToggleButtons: function(root) {
1739
+ const toggleButtons = window.Vanduo && typeof window.Vanduo.queryAll === "function" ? window.Vanduo.queryAll(root, "[data-grid-toggle]") : document.querySelectorAll("[data-grid-toggle]");
1420
1740
  toggleButtons.forEach(function(button) {
1421
1741
  if (button.getAttribute("data-grid-initialized") === "true") {
1422
1742
  return;
@@ -1584,11 +1904,14 @@ module.exports = __toCommonJS(index_exports);
1584
1904
  /**
1585
1905
  * Destroy all grid layout instances and clean up toggle buttons
1586
1906
  */
1587
- destroyAll: function() {
1907
+ destroyAll: function(root) {
1908
+ const scope = window.Vanduo && typeof window.Vanduo._normalizeRoot === "function" ? window.Vanduo._normalizeRoot(root) : root || document;
1588
1909
  this.instances.forEach(function(instance, container) {
1589
- this.destroy(container);
1910
+ if (scope === document || scope === container || typeof scope.contains === "function" && scope.contains(container)) {
1911
+ this.destroy(container);
1912
+ }
1590
1913
  }.bind(this));
1591
- const toggleButtons = document.querySelectorAll('[data-grid-initialized="true"]');
1914
+ const toggleButtons = window.Vanduo && typeof window.Vanduo.queryAll === "function" ? window.Vanduo.queryAll(scope, '[data-grid-toggle][data-grid-initialized="true"]') : document.querySelectorAll('[data-grid-initialized="true"]');
1592
1915
  toggleButtons.forEach(function(button) {
1593
1916
  if (button._gridCleanup) {
1594
1917
  button._gridCleanup();
@@ -1618,12 +1941,18 @@ module.exports = __toCommonJS(index_exports);
1618
1941
  isOpen: false,
1619
1942
  // Store cleanup functions for event listeners
1620
1943
  _cleanupFunctions: [],
1944
+ getTriggers: function(root) {
1945
+ if (window.Vanduo && typeof window.Vanduo.queryAll === "function") {
1946
+ return window.Vanduo.queryAll(root, "[data-image-box]");
1947
+ }
1948
+ return Array.from(document.querySelectorAll("[data-image-box]"));
1949
+ },
1621
1950
  /**
1622
1951
  * Initialize Image Box component
1623
1952
  */
1624
- init: function() {
1953
+ init: function(root) {
1625
1954
  this.createBackdrop();
1626
- this.bindTriggers();
1955
+ this.bindTriggers(root);
1627
1956
  },
1628
1957
  /**
1629
1958
  * Create backdrop elements
@@ -1707,9 +2036,9 @@ module.exports = __toCommonJS(index_exports);
1707
2036
  /**
1708
2037
  * Bind triggers to all images with data-image-box attribute
1709
2038
  */
1710
- bindTriggers: function() {
2039
+ bindTriggers: function(root) {
1711
2040
  const self = this;
1712
- const triggers = document.querySelectorAll("[data-image-box]");
2041
+ const triggers = this.getTriggers(root);
1713
2042
  triggers.forEach(function(trigger) {
1714
2043
  if (trigger.dataset.imageBoxInitialized) return;
1715
2044
  trigger.dataset.imageBoxInitialized = "true";
@@ -1726,6 +2055,8 @@ module.exports = __toCommonJS(index_exports);
1726
2055
  trigger.classList.remove("is-broken");
1727
2056
  };
1728
2057
  trigger.addEventListener("load", loadHandler);
2058
+ trigger._imageBoxErrorHandler = errorHandler;
2059
+ trigger._imageBoxLoadHandler = loadHandler;
1729
2060
  }
1730
2061
  const clickHandler = function(e) {
1731
2062
  e.preventDefault();
@@ -1744,12 +2075,24 @@ module.exports = __toCommonJS(index_exports);
1744
2075
  }
1745
2076
  };
1746
2077
  trigger.addEventListener("keydown", keyHandler);
1747
- const originalCleanup = trigger._imageBoxCleanup;
2078
+ const originalCleanup2 = trigger._imageBoxCleanup;
1748
2079
  trigger._imageBoxCleanup = () => {
1749
- originalCleanup();
2080
+ originalCleanup2();
1750
2081
  trigger.removeEventListener("keydown", keyHandler);
1751
2082
  };
1752
2083
  }
2084
+ const originalCleanup = trigger._imageBoxCleanup;
2085
+ trigger._imageBoxCleanup = () => {
2086
+ originalCleanup();
2087
+ if (trigger._imageBoxErrorHandler) {
2088
+ trigger.removeEventListener("error", trigger._imageBoxErrorHandler);
2089
+ delete trigger._imageBoxErrorHandler;
2090
+ }
2091
+ if (trigger._imageBoxLoadHandler) {
2092
+ trigger.removeEventListener("load", trigger._imageBoxLoadHandler);
2093
+ delete trigger._imageBoxLoadHandler;
2094
+ }
2095
+ };
1753
2096
  });
1754
2097
  },
1755
2098
  /**
@@ -1820,13 +2163,25 @@ module.exports = __toCommonJS(index_exports);
1820
2163
  /**
1821
2164
  * Reinitialize - useful after dynamic DOM changes
1822
2165
  */
1823
- reinit: function() {
1824
- this.bindTriggers();
2166
+ reinit: function(root) {
2167
+ this.bindTriggers(root);
1825
2168
  },
1826
2169
  /**
1827
2170
  * Destroy component and clean up
1828
2171
  */
1829
- destroy: function() {
2172
+ destroy: function(root) {
2173
+ if (root && root !== document) {
2174
+ const triggersInRoot = this.getTriggers(root);
2175
+ triggersInRoot.forEach((trigger) => {
2176
+ trigger.classList.remove("vd-image-box-trigger");
2177
+ if (trigger._imageBoxCleanup) {
2178
+ trigger._imageBoxCleanup();
2179
+ delete trigger._imageBoxCleanup;
2180
+ }
2181
+ delete trigger.dataset.imageBoxInitialized;
2182
+ });
2183
+ return;
2184
+ }
1830
2185
  if (this.isOpen) {
1831
2186
  this.close();
1832
2187
  }
@@ -1835,7 +2190,7 @@ module.exports = __toCommonJS(index_exports);
1835
2190
  }
1836
2191
  this._cleanupFunctions.forEach((fn) => fn());
1837
2192
  this._cleanupFunctions = [];
1838
- const triggers = document.querySelectorAll("[data-image-box-initialized]");
2193
+ const triggers = window.Vanduo && typeof window.Vanduo.queryAll === "function" ? window.Vanduo.queryAll(root, "[data-image-box-initialized]") : document.querySelectorAll("[data-image-box-initialized]");
1839
2194
  triggers.forEach((trigger) => {
1840
2195
  trigger.classList.remove("vd-image-box-trigger");
1841
2196
  if (trigger._imageBoxCleanup) {
@@ -1852,8 +2207,8 @@ module.exports = __toCommonJS(index_exports);
1852
2207
  this.currentTrigger = null;
1853
2208
  this.isOpen = false;
1854
2209
  },
1855
- destroyAll: function() {
1856
- this.destroy();
2210
+ destroyAll: function(root) {
2211
+ this.destroy(root);
1857
2212
  }
1858
2213
  };
1859
2214
  if (typeof window.Vanduo !== "undefined") {
@@ -1869,6 +2224,7 @@ module.exports = __toCommonJS(index_exports);
1869
2224
  modals: /* @__PURE__ */ new Map(),
1870
2225
  openModals: [],
1871
2226
  zIndexCounter: 1050,
2227
+ __vanduoScopedDestroyAll: true,
1872
2228
  // Store trigger cleanup functions
1873
2229
  _triggerCleanups: [],
1874
2230
  // Shared ESC key handler (installed once)
@@ -1924,15 +2280,15 @@ module.exports = __toCommonJS(index_exports);
1924
2280
  /**
1925
2281
  * Initialize modals
1926
2282
  */
1927
- init: function() {
1928
- const modals = document.querySelectorAll(".vd-modal");
2283
+ init: function(root) {
2284
+ const modals = window.Vanduo.queryAll(root, ".vd-modal");
1929
2285
  modals.forEach((modal) => {
1930
2286
  if (this.modals.has(modal)) {
1931
2287
  return;
1932
2288
  }
1933
2289
  this.initModal(modal);
1934
2290
  });
1935
- const triggers = document.querySelectorAll("[data-modal]");
2291
+ const triggers = window.Vanduo && typeof window.Vanduo.queryAll === "function" ? window.Vanduo.queryAll(root, "[data-modal]") : document.querySelectorAll("[data-modal]");
1936
2292
  triggers.forEach((trigger) => {
1937
2293
  if (trigger.dataset.modalTriggerInitialized) return;
1938
2294
  trigger.dataset.modalTriggerInitialized = "true";
@@ -1945,7 +2301,7 @@ module.exports = __toCommonJS(index_exports);
1945
2301
  }
1946
2302
  };
1947
2303
  trigger.addEventListener("click", triggerClickHandler);
1948
- this._triggerCleanups.push(() => trigger.removeEventListener("click", triggerClickHandler));
2304
+ trigger._modalTriggerCleanup = () => trigger.removeEventListener("click", triggerClickHandler);
1949
2305
  });
1950
2306
  },
1951
2307
  /**
@@ -2183,13 +2539,22 @@ module.exports = __toCommonJS(index_exports);
2183
2539
  /**
2184
2540
  * Destroy all modal instances
2185
2541
  */
2186
- destroyAll: function() {
2542
+ destroyAll: function(root) {
2543
+ const scope = window.Vanduo && typeof window.Vanduo._normalizeRoot === "function" ? window.Vanduo._normalizeRoot(root) : root || document;
2187
2544
  this.modals.forEach((data, modal) => {
2188
- this.destroy(modal);
2545
+ if (scope === document || scope === modal || typeof scope.contains === "function" && scope.contains(modal)) {
2546
+ this.destroy(modal);
2547
+ }
2189
2548
  });
2190
- this._triggerCleanups.forEach((fn) => fn());
2191
- this._triggerCleanups = [];
2192
- if (this._sharedEscHandler) {
2549
+ const triggers = window.Vanduo && typeof window.Vanduo.queryAll === "function" ? window.Vanduo.queryAll(scope, "[data-modal][data-modal-trigger-initialized]") : document.querySelectorAll("[data-modal][data-modal-trigger-initialized]");
2550
+ triggers.forEach((trigger) => {
2551
+ if (trigger._modalTriggerCleanup) {
2552
+ trigger._modalTriggerCleanup();
2553
+ delete trigger._modalTriggerCleanup;
2554
+ }
2555
+ delete trigger.dataset.modalTriggerInitialized;
2556
+ });
2557
+ if (scope === document && this._sharedEscHandler) {
2193
2558
  document.removeEventListener("keydown", this._sharedEscHandler);
2194
2559
  this._sharedEscHandler = null;
2195
2560
  }
@@ -2220,8 +2585,8 @@ module.exports = __toCommonJS(index_exports);
2220
2585
  /**
2221
2586
  * Initialize navbar component
2222
2587
  */
2223
- init: function() {
2224
- const navbars = document.querySelectorAll(".vd-navbar");
2588
+ init: function(root) {
2589
+ const navbars = window.Vanduo.queryAll(root, ".vd-navbar");
2225
2590
  navbars.forEach((navbar) => {
2226
2591
  if (this.instances.has(navbar)) {
2227
2592
  return;
@@ -2442,8 +2807,8 @@ module.exports = __toCommonJS(index_exports);
2442
2807
  /**
2443
2808
  * Initialize pagination components
2444
2809
  */
2445
- init: function() {
2446
- const paginations = document.querySelectorAll(".vd-pagination[data-pagination]");
2810
+ init: function(root) {
2811
+ const paginations = window.Vanduo.queryAll(root, ".vd-pagination[data-pagination]");
2447
2812
  paginations.forEach((pagination) => {
2448
2813
  if (this.instances.has(pagination)) {
2449
2814
  return;
@@ -2666,21 +3031,21 @@ module.exports = __toCommonJS(index_exports);
2666
3031
  /**
2667
3032
  * Initialize parallax components
2668
3033
  */
2669
- init: function() {
2670
- if (this.isInitialized) {
2671
- this.refresh();
2672
- return;
2673
- }
2674
- this.isInitialized = true;
3034
+ init: function(root) {
2675
3035
  if (this.reducedMotion) {
2676
3036
  return;
2677
3037
  }
2678
- const parallaxElements = document.querySelectorAll(".vd-parallax");
3038
+ const parallaxElements = window.Vanduo.queryAll(root, ".vd-parallax");
2679
3039
  parallaxElements.forEach((element) => {
2680
3040
  if (!element.dataset.parallaxInitialized) {
2681
3041
  this.initParallax(element);
2682
3042
  }
2683
3043
  });
3044
+ if (this.isInitialized) {
3045
+ this.refresh();
3046
+ return;
3047
+ }
3048
+ this.isInitialized = true;
2684
3049
  this.handleScroll();
2685
3050
  this._onScroll = () => {
2686
3051
  this.handleScroll();
@@ -2823,11 +3188,17 @@ module.exports = __toCommonJS(index_exports);
2823
3188
  (function() {
2824
3189
  "use strict";
2825
3190
  const Preloader = {
3191
+ getProgressBars: function(root) {
3192
+ if (window.Vanduo && typeof window.Vanduo.queryAll === "function") {
3193
+ return window.Vanduo.queryAll(root, ".vd-progress-bar[data-progress], .progress-bar[data-progress]");
3194
+ }
3195
+ return Array.from(document.querySelectorAll(".vd-progress-bar[data-progress], .progress-bar[data-progress]"));
3196
+ },
2826
3197
  /**
2827
3198
  * Initialize preloader components
2828
3199
  */
2829
- init: function() {
2830
- const progressBars = document.querySelectorAll(".vd-progress-bar[data-progress], .progress-bar[data-progress]");
3200
+ init: function(root) {
3201
+ const progressBars = this.getProgressBars(root);
2831
3202
  progressBars.forEach((bar) => {
2832
3203
  if (!bar.dataset.progressInitialized) {
2833
3204
  this.initProgressBar(bar);
@@ -2947,8 +3318,10 @@ module.exports = __toCommonJS(index_exports);
2947
3318
  /**
2948
3319
  * Destroy all progress bar instances
2949
3320
  */
2950
- destroyAll: function() {
2951
- const progressBars = document.querySelectorAll('.vd-progress-bar[data-progress-initialized="true"], .progress-bar[data-progress-initialized="true"]');
3321
+ destroyAll: function(root) {
3322
+ const progressBars = this.getProgressBars(root || document).filter(function(bar) {
3323
+ return bar.dataset.progressInitialized === "true";
3324
+ });
2952
3325
  progressBars.forEach((bar) => {
2953
3326
  delete bar.dataset.progressInitialized;
2954
3327
  });
@@ -2969,8 +3342,8 @@ module.exports = __toCommonJS(index_exports);
2969
3342
  /**
2970
3343
  * Initialize select components
2971
3344
  */
2972
- init: function() {
2973
- const selects = document.querySelectorAll("select.vd-custom-select-input, select[data-custom-select]");
3345
+ init: function(root) {
3346
+ const selects = window.Vanduo.queryAll(root, "select.vd-custom-select-input, select[data-custom-select]");
2974
3347
  selects.forEach((select) => {
2975
3348
  if (this.instances.has(select)) {
2976
3349
  return;
@@ -3331,8 +3704,10 @@ module.exports = __toCommonJS(index_exports);
3331
3704
  breakpoint: 992,
3332
3705
  // Desktop breakpoint
3333
3706
  restoreDelayMs: 450,
3707
+ __vanduoScopedDestroyAll: true,
3334
3708
  // Global cleanup functions (toggles, resize)
3335
3709
  _globalCleanups: [],
3710
+ _resizeCleanup: null,
3336
3711
  isFixedVariant: function(sidenav) {
3337
3712
  return sidenav.classList.contains("vd-sidenav-fixed") || sidenav.classList.contains("sidenav-fixed");
3338
3713
  },
@@ -3433,15 +3808,15 @@ module.exports = __toCommonJS(index_exports);
3433
3808
  /**
3434
3809
  * Initialize sidenav components
3435
3810
  */
3436
- init: function() {
3437
- const sidenavs = document.querySelectorAll(".vd-sidenav, .vd-offcanvas");
3811
+ init: function(root) {
3812
+ const sidenavs = window.Vanduo.queryAll(root, ".vd-sidenav, .vd-offcanvas");
3438
3813
  sidenavs.forEach((sidenav) => {
3439
3814
  if (this.sidenavs.has(sidenav)) {
3440
3815
  return;
3441
3816
  }
3442
3817
  this.initSidenav(sidenav);
3443
3818
  });
3444
- const toggles = document.querySelectorAll("[data-sidenav-toggle]");
3819
+ const toggles = window.Vanduo && typeof window.Vanduo.queryAll === "function" ? window.Vanduo.queryAll(root, "[data-sidenav-toggle]") : document.querySelectorAll("[data-sidenav-toggle]");
3445
3820
  toggles.forEach((toggle) => {
3446
3821
  if (toggle.dataset.sidenavToggleInitialized) return;
3447
3822
  toggle.dataset.sidenavToggleInitialized = "true";
@@ -3454,14 +3829,16 @@ module.exports = __toCommonJS(index_exports);
3454
3829
  }
3455
3830
  };
3456
3831
  toggle.addEventListener("click", toggleClickHandler);
3457
- this._globalCleanups.push(() => toggle.removeEventListener("click", toggleClickHandler));
3832
+ toggle._sidenavToggleCleanup = () => toggle.removeEventListener("click", toggleClickHandler);
3458
3833
  });
3459
3834
  this.handleResize();
3460
- const resizeHandler = () => {
3461
- this.handleResize();
3462
- };
3463
- window.addEventListener("resize", resizeHandler);
3464
- this._globalCleanups.push(() => window.removeEventListener("resize", resizeHandler));
3835
+ if (!this._resizeCleanup) {
3836
+ const resizeHandler = () => {
3837
+ this.handleResize();
3838
+ };
3839
+ window.addEventListener("resize", resizeHandler);
3840
+ this._resizeCleanup = () => window.removeEventListener("resize", resizeHandler);
3841
+ }
3465
3842
  },
3466
3843
  /**
3467
3844
  * Initialize a single sidenav
@@ -3634,12 +4011,29 @@ module.exports = __toCommonJS(index_exports);
3634
4011
  /**
3635
4012
  * Destroy all sidenav instances
3636
4013
  */
3637
- destroyAll: function() {
4014
+ destroyAll: function(root) {
4015
+ const scope = window.Vanduo && typeof window.Vanduo._normalizeRoot === "function" ? window.Vanduo._normalizeRoot(root) : root || document;
3638
4016
  this.sidenavs.forEach((data, sidenav) => {
3639
- this.destroy(sidenav);
4017
+ if (scope === document || scope === sidenav || typeof scope.contains === "function" && scope.contains(sidenav)) {
4018
+ this.destroy(sidenav);
4019
+ }
3640
4020
  });
3641
- this._globalCleanups.forEach((fn) => fn());
3642
- this._globalCleanups = [];
4021
+ const toggles = window.Vanduo && typeof window.Vanduo.queryAll === "function" ? window.Vanduo.queryAll(scope, "[data-sidenav-toggle][data-sidenav-toggle-initialized]") : document.querySelectorAll("[data-sidenav-toggle][data-sidenav-toggle-initialized]");
4022
+ toggles.forEach((toggle) => {
4023
+ if (toggle._sidenavToggleCleanup) {
4024
+ toggle._sidenavToggleCleanup();
4025
+ delete toggle._sidenavToggleCleanup;
4026
+ }
4027
+ delete toggle.dataset.sidenavToggleInitialized;
4028
+ });
4029
+ if (scope === document) {
4030
+ if (this._resizeCleanup) {
4031
+ this._resizeCleanup();
4032
+ this._resizeCleanup = null;
4033
+ }
4034
+ this._globalCleanups.forEach((fn) => fn());
4035
+ this._globalCleanups = [];
4036
+ }
3643
4037
  }
3644
4038
  };
3645
4039
  if (typeof window.Vanduo !== "undefined") {
@@ -3657,8 +4051,8 @@ module.exports = __toCommonJS(index_exports);
3657
4051
  /**
3658
4052
  * Initialize all tab components
3659
4053
  */
3660
- init: function() {
3661
- const tabContainers = document.querySelectorAll(".vd-tabs, [data-tabs]");
4054
+ init: function(root) {
4055
+ const tabContainers = window.Vanduo.queryAll(root, ".vd-tabs, [data-tabs]");
3662
4056
  tabContainers.forEach((container) => {
3663
4057
  if (this.instances.has(container)) {
3664
4058
  return;
@@ -3962,21 +4356,65 @@ module.exports = __toCommonJS(index_exports);
3962
4356
  },
3963
4357
  isInitialized: false,
3964
4358
  _cleanup: [],
4359
+ _ownsDynamicPanel: false,
3965
4360
  // DOM references
3966
4361
  elements: {
3967
4362
  customizer: null,
3968
4363
  trigger: null,
4364
+ activeTrigger: null,
3969
4365
  triggers: [],
3970
4366
  panel: null,
3971
4367
  overlay: null
3972
4368
  },
4369
+ isRoot: function(root) {
4370
+ return !!root && (root === document || root.nodeType === 1 || root.nodeType === 9 || root.nodeType === 11);
4371
+ },
4372
+ normalizeRoot: function(root) {
4373
+ return this.isRoot(root) ? root : document;
4374
+ },
4375
+ queryAll: function(root, selector) {
4376
+ const scope = this.normalizeRoot(root);
4377
+ if (typeof window.VanduoLifecycle !== "undefined" && typeof window.VanduoLifecycle.queryAll === "function") {
4378
+ return window.VanduoLifecycle.queryAll(scope, selector);
4379
+ }
4380
+ const matches = [];
4381
+ if (scope instanceof Element && typeof scope.matches === "function" && scope.matches(selector)) {
4382
+ matches.push(scope);
4383
+ }
4384
+ if (typeof scope.querySelectorAll === "function") {
4385
+ const descendants = scope.querySelectorAll(selector);
4386
+ for (let i = 0; i < descendants.length; i++) {
4387
+ matches.push(descendants[i]);
4388
+ }
4389
+ }
4390
+ return matches;
4391
+ },
4392
+ queryOne: function(root, selector) {
4393
+ const matches = this.queryAll(root, selector);
4394
+ return matches.length ? matches[0] : null;
4395
+ },
4396
+ getTriggers: function(root) {
4397
+ return this.queryAll(root, "[data-theme-customizer-trigger]");
4398
+ },
4399
+ pruneTriggers: function() {
4400
+ this.elements.triggers = this.elements.triggers.filter(function(trigger) {
4401
+ return trigger && trigger.isConnected;
4402
+ });
4403
+ if (this.elements.trigger && !this.elements.trigger.isConnected) {
4404
+ this.elements.trigger = null;
4405
+ }
4406
+ if (this.elements.activeTrigger && !this.elements.activeTrigger.isConnected) {
4407
+ this.elements.activeTrigger = null;
4408
+ }
4409
+ },
3973
4410
  /**
3974
4411
  * Initialize the Theme Customizer
3975
4412
  */
3976
- init: function() {
4413
+ init: function(root) {
4414
+ const scope = this.normalizeRoot(root);
3977
4415
  if (this.isInitialized) {
3978
- this.bindExistingElements();
3979
- this.bindTriggerEvents();
4416
+ this.bindExistingElements(scope);
4417
+ this.bindTriggerEvents(scope);
3980
4418
  this.bindPanelEvents();
3981
4419
  this.updateUI();
3982
4420
  return;
@@ -3985,9 +4423,8 @@ module.exports = __toCommonJS(index_exports);
3985
4423
  this._cleanup = [];
3986
4424
  this.loadPreferences();
3987
4425
  this.applyAllPreferences();
3988
- this.bindExistingElements();
3989
- this.bindEvents();
3990
- console.log("Vanduo Theme Customizer initialized");
4426
+ this.bindExistingElements(scope);
4427
+ this.bindEvents(scope);
3991
4428
  },
3992
4429
  addListener: function(target, event, handler, options) {
3993
4430
  if (!target) return;
@@ -4148,18 +4585,26 @@ module.exports = __toCommonJS(index_exports);
4148
4585
  /**
4149
4586
  * Bind to existing DOM elements or create them dynamically
4150
4587
  */
4151
- bindExistingElements: function() {
4152
- this.elements.customizer = document.querySelector(".vd-theme-customizer");
4153
- this.elements.triggers = Array.from(document.querySelectorAll("[data-theme-customizer-trigger]"));
4588
+ bindExistingElements: function(root) {
4589
+ const scope = this.normalizeRoot(root);
4590
+ this.pruneTriggers();
4591
+ const scopedTriggers = this.getTriggers(scope);
4592
+ scopedTriggers.forEach((trigger) => {
4593
+ if (!this.elements.triggers.includes(trigger)) {
4594
+ this.elements.triggers.push(trigger);
4595
+ }
4596
+ });
4154
4597
  if (!this.elements.trigger && this.elements.triggers.length) {
4155
4598
  this.elements.trigger = this.elements.triggers[0];
4156
4599
  }
4157
- if (this.elements.customizer) {
4600
+ const existingCustomizer = this.queryOne(scope, ".vd-theme-customizer") || (this.elements.customizer && typeof this.elements.customizer.contains === "function" ? this.elements.customizer : null) || document.querySelector(".vd-theme-customizer");
4601
+ if (existingCustomizer instanceof Element) {
4602
+ this.elements.customizer = existingCustomizer;
4158
4603
  this.elements.trigger = this.elements.customizer.querySelector(".vd-theme-customizer-trigger") || this.elements.trigger;
4159
4604
  this.elements.panel = this.elements.customizer.querySelector(".vd-theme-customizer-panel");
4160
4605
  this.elements.overlay = this.elements.customizer.querySelector(".vd-theme-customizer-overlay");
4161
4606
  } else {
4162
- if (this.elements.triggers.length) {
4607
+ if (scopedTriggers.length && !this.elements.panel) {
4163
4608
  this.createDynamicPanel();
4164
4609
  }
4165
4610
  }
@@ -4169,7 +4614,7 @@ module.exports = __toCommonJS(index_exports);
4169
4614
  * Create the panel dynamically when only a trigger button exists
4170
4615
  */
4171
4616
  createDynamicPanel: function() {
4172
- if (!this.elements.triggers.length) {
4617
+ if (!this.elements.triggers.length || this.elements.panel && this.elements.panel.isConnected) {
4173
4618
  return;
4174
4619
  }
4175
4620
  this.elements.trigger = this.elements.triggers[0];
@@ -4182,6 +4627,7 @@ module.exports = __toCommonJS(index_exports);
4182
4627
  document.body.appendChild(panel);
4183
4628
  this.elements.panel = panel;
4184
4629
  this.elements.overlay = overlay;
4630
+ this._ownsDynamicPanel = true;
4185
4631
  this.elements.customizer = {
4186
4632
  contains: (el) => panel.contains(el) || this.elements.triggers.some((trigger) => trigger.contains(el))
4187
4633
  };
@@ -4364,8 +4810,8 @@ module.exports = __toCommonJS(index_exports);
4364
4810
  this.state.primary = expected;
4365
4811
  }
4366
4812
  },
4367
- bindEvents: function() {
4368
- this.bindTriggerEvents();
4813
+ bindEvents: function(root) {
4814
+ this.bindTriggerEvents(root);
4369
4815
  this.bindPanelEvents();
4370
4816
  if (window.matchMedia) {
4371
4817
  const mq = window.matchMedia("(prefers-color-scheme: dark)");
@@ -4392,21 +4838,44 @@ module.exports = __toCommonJS(index_exports);
4392
4838
  }
4393
4839
  });
4394
4840
  },
4395
- bindTriggerEvents: function() {
4396
- this.elements.triggers.forEach((trigger) => {
4841
+ bindTriggerEvents: function(root) {
4842
+ const triggers = root ? this.getTriggers(root) : this.elements.triggers;
4843
+ triggers.forEach((trigger) => {
4397
4844
  if (trigger.getAttribute("data-customizer-trigger-initialized") === "true") {
4398
4845
  return;
4399
4846
  }
4400
- this.addListener(trigger, "click", (e) => {
4847
+ const onClick = (e) => {
4401
4848
  e.preventDefault();
4402
4849
  e.stopPropagation();
4403
4850
  this.elements.activeTrigger = trigger;
4404
4851
  this.elements.trigger = trigger;
4405
4852
  this.toggle();
4406
- });
4853
+ };
4854
+ trigger.addEventListener("click", onClick);
4855
+ trigger._themeCustomizerTriggerHandler = onClick;
4407
4856
  trigger.setAttribute("data-customizer-trigger-initialized", "true");
4408
4857
  });
4409
4858
  },
4859
+ cleanupTrigger: function(trigger) {
4860
+ if (!trigger || trigger.getAttribute("data-customizer-trigger-initialized") !== "true") {
4861
+ return;
4862
+ }
4863
+ if (trigger._themeCustomizerTriggerHandler) {
4864
+ trigger.removeEventListener("click", trigger._themeCustomizerTriggerHandler);
4865
+ delete trigger._themeCustomizerTriggerHandler;
4866
+ }
4867
+ trigger.setAttribute("aria-expanded", "false");
4868
+ trigger.removeAttribute("data-customizer-trigger-initialized");
4869
+ if (this.elements.activeTrigger === trigger) {
4870
+ this.elements.activeTrigger = null;
4871
+ }
4872
+ this.elements.triggers = this.elements.triggers.filter(function(candidate) {
4873
+ return candidate !== trigger;
4874
+ });
4875
+ if (this.elements.trigger === trigger) {
4876
+ this.elements.trigger = this.elements.triggers[0] || null;
4877
+ }
4878
+ },
4410
4879
  /**
4411
4880
  * Toggle panel open/close
4412
4881
  */
@@ -4517,13 +4986,42 @@ module.exports = __toCommonJS(index_exports);
4517
4986
  return false;
4518
4987
  }
4519
4988
  },
4520
- destroyAll: function() {
4989
+ destroyAll: function(root) {
4990
+ const scope = this.normalizeRoot(root);
4991
+ if (scope !== document) {
4992
+ this.getTriggers(scope).forEach((trigger) => {
4993
+ this.cleanupTrigger(trigger);
4994
+ });
4995
+ this.pruneTriggers();
4996
+ if (!this.elements.triggers.length) {
4997
+ this.destroyAll(document);
4998
+ }
4999
+ return;
5000
+ }
4521
5001
  this._cleanup.forEach((fn) => fn());
4522
5002
  this._cleanup = [];
4523
5003
  if (this.elements.panel) {
4524
5004
  this.elements.panel.removeAttribute("data-customizer-initialized");
4525
5005
  }
5006
+ this.elements.triggers.slice().forEach((trigger) => {
5007
+ this.cleanupTrigger(trigger);
5008
+ });
5009
+ if (this._ownsDynamicPanel) {
5010
+ if (this.elements.panel && this.elements.panel.parentNode) {
5011
+ this.elements.panel.parentNode.removeChild(this.elements.panel);
5012
+ }
5013
+ if (this.elements.overlay && this.elements.overlay.parentNode) {
5014
+ this.elements.overlay.parentNode.removeChild(this.elements.overlay);
5015
+ }
5016
+ this._ownsDynamicPanel = false;
5017
+ }
4526
5018
  this.close();
5019
+ this.elements.customizer = null;
5020
+ this.elements.trigger = null;
5021
+ this.elements.activeTrigger = null;
5022
+ this.elements.triggers = [];
5023
+ this.elements.panel = null;
5024
+ this.elements.overlay = null;
4527
5025
  this.isInitialized = false;
4528
5026
  }
4529
5027
  };
@@ -4540,7 +5038,13 @@ module.exports = __toCommonJS(index_exports);
4540
5038
  isInitialized: false,
4541
5039
  _mediaQuery: null,
4542
5040
  _onMediaChange: null,
4543
- init: function() {
5041
+ getToggles: function(root) {
5042
+ if (window.Vanduo && typeof window.Vanduo.queryAll === "function") {
5043
+ return window.Vanduo.queryAll(root, '[data-toggle="theme"]');
5044
+ }
5045
+ return Array.from(document.querySelectorAll('[data-toggle="theme"]'));
5046
+ },
5047
+ init: function(root) {
4544
5048
  this.STORAGE_KEY = "vanduo-theme-preference";
4545
5049
  this.state = {
4546
5050
  preference: this.getPreference()
@@ -4548,15 +5052,14 @@ module.exports = __toCommonJS(index_exports);
4548
5052
  };
4549
5053
  if (this.isInitialized) {
4550
5054
  this.applyTheme();
4551
- this.renderUI();
4552
- this.updateUI();
5055
+ this.renderUI(root);
5056
+ this.updateUI(root);
4553
5057
  return;
4554
5058
  }
4555
5059
  this.isInitialized = true;
4556
5060
  this.applyTheme();
4557
5061
  this.listenForSystemChanges();
4558
- this.renderUI();
4559
- console.log("Vanduo Theme Switcher initialized");
5062
+ this.renderUI(root);
4560
5063
  },
4561
5064
  getPreference: function() {
4562
5065
  return this.getStorageValue(this.STORAGE_KEY, "system");
@@ -4616,8 +5119,8 @@ module.exports = __toCommonJS(index_exports);
4616
5119
  this._mediaQuery.addEventListener("change", this._onMediaChange);
4617
5120
  },
4618
5121
  // Helper to facilitate UI creation if needed, though often UI is in HTML
4619
- renderUI: function() {
4620
- const toggles = document.querySelectorAll('[data-toggle="theme"]');
5122
+ renderUI: function(root) {
5123
+ const toggles = this.getToggles(root);
4621
5124
  toggles.forEach((toggle) => {
4622
5125
  if (toggle.getAttribute("data-theme-initialized") === "true") {
4623
5126
  if (toggle.tagName === "SELECT") {
@@ -4644,8 +5147,8 @@ module.exports = __toCommonJS(index_exports);
4644
5147
  toggle.setAttribute("data-theme-initialized", "true");
4645
5148
  });
4646
5149
  },
4647
- updateUI: function() {
4648
- const toggles = document.querySelectorAll('[data-toggle="theme"]');
5150
+ updateUI: function(root) {
5151
+ const toggles = this.getToggles(root);
4649
5152
  toggles.forEach((toggle) => {
4650
5153
  if (toggle.tagName === "SELECT") {
4651
5154
  toggle.value = this.state.preference;
@@ -4657,8 +5160,11 @@ module.exports = __toCommonJS(index_exports);
4657
5160
  }
4658
5161
  });
4659
5162
  },
4660
- destroyAll: function() {
4661
- const toggles = document.querySelectorAll('[data-toggle="theme"][data-theme-initialized="true"]');
5163
+ destroyAll: function(root) {
5164
+ const scope = root || document;
5165
+ const toggles = this.getToggles(scope).filter(function(toggle) {
5166
+ return toggle.getAttribute("data-theme-initialized") === "true";
5167
+ });
4662
5168
  toggles.forEach((toggle) => {
4663
5169
  if (toggle._themeToggleHandler) {
4664
5170
  const eventName = toggle.tagName === "SELECT" ? "change" : "click";
@@ -4667,12 +5173,14 @@ module.exports = __toCommonJS(index_exports);
4667
5173
  }
4668
5174
  toggle.removeAttribute("data-theme-initialized");
4669
5175
  });
4670
- if (this._mediaQuery && this._onMediaChange) {
5176
+ if (scope === document && this._mediaQuery && this._onMediaChange) {
4671
5177
  this._mediaQuery.removeEventListener("change", this._onMediaChange);
4672
5178
  }
4673
- this._mediaQuery = null;
4674
- this._onMediaChange = null;
4675
- this.isInitialized = false;
5179
+ if (scope === document) {
5180
+ this._mediaQuery = null;
5181
+ this._onMediaChange = null;
5182
+ this.isInitialized = false;
5183
+ }
4676
5184
  }
4677
5185
  };
4678
5186
  if (window.Vanduo) {
@@ -4749,7 +5257,7 @@ module.exports = __toCommonJS(index_exports);
4749
5257
  let html = "";
4750
5258
  if (config.icon) {
4751
5259
  const allowSvg = config.iconAllowSvg === true;
4752
- const safeIcon = typeof sanitizeHtml === "function" ? sanitizeHtml(config.icon, { allowSvg }) : escapeHtml(config.icon);
5260
+ const safeIcon = typeof sanitizeHtml === "function" ? sanitizeHtml(config.icon, { allowSvg, allowStyle: false }) : escapeHtml(config.icon);
4753
5261
  html += `<span class="vd-toast-icon">${safeIcon}</span>`;
4754
5262
  } else if (config.type) {
4755
5263
  html += `<span class="vd-toast-icon">${this.getDefaultIcon(config.type)}</span>`;
@@ -4969,8 +5477,8 @@ module.exports = __toCommonJS(index_exports);
4969
5477
  /**
4970
5478
  * Initialize tooltips
4971
5479
  */
4972
- init: function() {
4973
- const elements = document.querySelectorAll("[data-tooltip], [data-tooltip-html]");
5480
+ init: function(root) {
5481
+ const elements = window.Vanduo.queryAll(root, "[data-tooltip], [data-tooltip-html]");
4974
5482
  elements.forEach((element) => {
4975
5483
  if (this.tooltips.has(element)) {
4976
5484
  return;
@@ -5026,7 +5534,7 @@ module.exports = __toCommonJS(index_exports);
5026
5534
  const textContent = element.dataset.tooltip;
5027
5535
  if (htmlContent) {
5028
5536
  const allowSvg = element.hasAttribute("data-tooltip-allow-svg");
5029
- tooltip.innerHTML = this.sanitizeHtml(htmlContent, { allowSvg });
5537
+ tooltip.innerHTML = this.sanitizeHtml(htmlContent, { allowSvg, allowStyle: false });
5030
5538
  tooltip.classList.add("vd-tooltip-html");
5031
5539
  } else if (textContent) {
5032
5540
  tooltip.textContent = textContent;
@@ -5159,7 +5667,7 @@ module.exports = __toCommonJS(index_exports);
5159
5667
  const { tooltip } = this.tooltips.get(el);
5160
5668
  if (isHtml) {
5161
5669
  const allowSvg = el.hasAttribute("data-tooltip-allow-svg");
5162
- tooltip.innerHTML = this.sanitizeHtml(content, { allowSvg });
5670
+ tooltip.innerHTML = this.sanitizeHtml(content, { allowSvg, allowStyle: false });
5163
5671
  tooltip.classList.add("vd-tooltip-html");
5164
5672
  } else {
5165
5673
  tooltip.textContent = content;
@@ -5249,8 +5757,26 @@ module.exports = __toCommonJS(index_exports);
5249
5757
  emptyText: "Try different keywords or check spelling",
5250
5758
  placeholder: "Search..."
5251
5759
  };
5760
+ const ALLOWED_HIGHLIGHT_TAGS = {
5761
+ mark: true,
5762
+ span: true,
5763
+ strong: true,
5764
+ em: true
5765
+ };
5766
+ function isRoot(value) {
5767
+ return typeof window.VanduoLifecycle !== "undefined" && window.VanduoLifecycle.isRoot(value);
5768
+ }
5769
+ function normalizeRoot(root) {
5770
+ return isRoot(root) ? root : document;
5771
+ }
5772
+ function normalizeHighlightTag(tagName) {
5773
+ const normalized = typeof tagName === "string" ? tagName.toLowerCase() : "mark";
5774
+ return ALLOWED_HIGHLIGHT_TAGS[normalized] ? normalized : "mark";
5775
+ }
5252
5776
  function createSearch(options) {
5253
5777
  const config = Object.assign({}, DEFAULTS, options || {});
5778
+ config.root = normalizeRoot(config.root);
5779
+ config.highlightTag = normalizeHighlightTag(config.highlightTag);
5254
5780
  const state = {
5255
5781
  initialized: false,
5256
5782
  index: [],
@@ -5264,6 +5790,24 @@ module.exports = __toCommonJS(index_exports);
5264
5790
  debounceTimer: null,
5265
5791
  boundHandlers: {}
5266
5792
  };
5793
+ function queryAll(selector) {
5794
+ if (window.Vanduo && typeof window.Vanduo.queryAll === "function") {
5795
+ return window.Vanduo.queryAll(config.root, selector);
5796
+ }
5797
+ const scope = normalizeRoot(config.root);
5798
+ if (scope === document) {
5799
+ return Array.from(document.querySelectorAll(selector));
5800
+ }
5801
+ const matches = [];
5802
+ if (scope instanceof Element && scope.matches(selector)) {
5803
+ matches.push(scope);
5804
+ }
5805
+ return matches.concat(Array.from(scope.querySelectorAll(selector)));
5806
+ }
5807
+ function queryOne(selector) {
5808
+ const matches = queryAll(selector);
5809
+ return matches.length ? matches[0] : null;
5810
+ }
5267
5811
  function safeInvokeCallback(name, fn, ...args) {
5268
5812
  try {
5269
5813
  fn(...args);
@@ -5283,7 +5827,7 @@ module.exports = __toCommonJS(index_exports);
5283
5827
  if (state.initialized) {
5284
5828
  return instance;
5285
5829
  }
5286
- state.container = document.querySelector(config.containerSelector);
5830
+ state.container = queryOne(config.containerSelector);
5287
5831
  if (!state.container) {
5288
5832
  state.initialized = false;
5289
5833
  return null;
@@ -5320,7 +5864,7 @@ module.exports = __toCommonJS(index_exports);
5320
5864
  });
5321
5865
  return;
5322
5866
  }
5323
- const sections = document.querySelectorAll(config.contentSelector);
5867
+ const sections = queryAll(config.contentSelector);
5324
5868
  const categoryMap = buildCategoryMap();
5325
5869
  sections.forEach(function(section) {
5326
5870
  const id = section.id;
@@ -5355,7 +5899,7 @@ module.exports = __toCommonJS(index_exports);
5355
5899
  function buildCategoryMap() {
5356
5900
  const map = {};
5357
5901
  let currentCategory = "Documentation";
5358
- const navItems = document.querySelectorAll(config.navSelector + ", " + config.sectionSelector);
5902
+ const navItems = queryAll(config.navSelector + ", " + config.sectionSelector);
5359
5903
  navItems.forEach(function(item) {
5360
5904
  if (item.classList.contains("doc-nav-section")) {
5361
5905
  currentCategory = item.textContent.trim();
@@ -5684,7 +6228,7 @@ module.exports = __toCommonJS(index_exports);
5684
6228
  safeInvokeCallback("onSelect", config.onSelect, result);
5685
6229
  return;
5686
6230
  }
5687
- const section = document.querySelector(result.url);
6231
+ const section = queryOne(result.url) || document.querySelector(result.url);
5688
6232
  if (section) {
5689
6233
  section.scrollIntoView({ behavior: "smooth", block: "start" });
5690
6234
  window.history.pushState(null, "", result.url);
@@ -5692,7 +6236,7 @@ module.exports = __toCommonJS(index_exports);
5692
6236
  }
5693
6237
  }
5694
6238
  function updateSidebarActive(sectionId) {
5695
- const navLinks = document.querySelectorAll(config.navSelector);
6239
+ const navLinks = queryAll(config.navSelector);
5696
6240
  navLinks.forEach(function(link) {
5697
6241
  link.classList.remove("active");
5698
6242
  if (link.getAttribute("href") === "#" + sectionId) {
@@ -5739,6 +6283,8 @@ module.exports = __toCommonJS(index_exports);
5739
6283
  }
5740
6284
  function setConfig(newConfig) {
5741
6285
  Object.assign(config, newConfig);
6286
+ config.root = normalizeRoot(config.root);
6287
+ config.highlightTag = normalizeHighlightTag(config.highlightTag);
5742
6288
  }
5743
6289
  function getConfig() {
5744
6290
  return Object.assign({}, config);
@@ -5755,7 +6301,10 @@ module.exports = __toCommonJS(index_exports);
5755
6301
  close,
5756
6302
  setConfig,
5757
6303
  getConfig,
5758
- getIndex
6304
+ getIndex,
6305
+ getContainer: function() {
6306
+ return state.container;
6307
+ }
5759
6308
  };
5760
6309
  return instance;
5761
6310
  }
@@ -5777,27 +6326,34 @@ module.exports = __toCommonJS(index_exports);
5777
6326
  /**
5778
6327
  * Initialize the default search instance
5779
6328
  */
5780
- init: function(options) {
6329
+ init: function(rootOrOptions, maybeOptions) {
6330
+ const root = isRoot(rootOrOptions) ? rootOrOptions : null;
6331
+ const options = root ? maybeOptions : rootOrOptions;
5781
6332
  if (this._instance) {
5782
6333
  this._instance.destroy();
5783
6334
  }
5784
6335
  if (options) {
5785
6336
  Object.assign(this.config, options);
5786
6337
  }
5787
- this._instance = createSearch(this.config);
6338
+ this._instance = createSearch(Object.assign({}, this.config, root ? { root } : {}));
5788
6339
  return this._instance ? this._instance.init() : null;
5789
6340
  },
5790
6341
  /**
5791
6342
  * Destroy the default instance
5792
6343
  */
5793
- destroy: function() {
6344
+ destroy: function(root) {
6345
+ if (root && this._instance && this._instance.getContainer() && typeof window.VanduoLifecycle !== "undefined") {
6346
+ if (!window.VanduoLifecycle.isInRoot(root, this._instance.getContainer())) {
6347
+ return;
6348
+ }
6349
+ }
5794
6350
  if (this._instance) {
5795
6351
  this._instance.destroy();
5796
6352
  this._instance = null;
5797
6353
  }
5798
6354
  },
5799
- destroyAll: function() {
5800
- this.destroy();
6355
+ destroyAll: function(root) {
6356
+ this.destroy(root);
5801
6357
  },
5802
6358
  /**
5803
6359
  * Rebuild the default instance index
@@ -5855,21 +6411,21 @@ module.exports = __toCommonJS(index_exports);
5855
6411
  /**
5856
6412
  * Initialize draggable components
5857
6413
  */
5858
- init: function() {
5859
- const draggables = document.querySelectorAll(".vd-draggable, [data-draggable]");
6414
+ init: function(root) {
6415
+ const draggables = window.Vanduo.queryAll(root, ".vd-draggable, [data-draggable]");
5860
6416
  draggables.forEach((element) => {
5861
6417
  if (this.instances.has(element)) {
5862
6418
  return;
5863
6419
  }
5864
6420
  this.initDraggable(element);
5865
6421
  });
5866
- const containers = document.querySelectorAll(this.containerSelector);
6422
+ const containers = window.Vanduo.queryAll(root, this.containerSelector);
5867
6423
  containers.forEach((container) => {
5868
6424
  if (!this.instances.has(container)) {
5869
6425
  this.initContainer(container);
5870
6426
  }
5871
6427
  });
5872
- const dropZones = document.querySelectorAll(".vd-drop-zone");
6428
+ const dropZones = window.Vanduo.queryAll(root, ".vd-drop-zone");
5873
6429
  dropZones.forEach((zone) => {
5874
6430
  if (!this.instances.has(zone)) {
5875
6431
  this.initDropZone(zone);
@@ -6479,6 +7035,35 @@ module.exports = __toCommonJS(index_exports);
6479
7035
  (function() {
6480
7036
  "use strict";
6481
7037
  const _observerMap = /* @__PURE__ */ new Map();
7038
+ function _isRoot(root) {
7039
+ return !!root && (root === document || root.nodeType === 1 || root.nodeType === 9 || root.nodeType === 11);
7040
+ }
7041
+ function _normalizeRoot(root) {
7042
+ return _isRoot(root) ? root : document;
7043
+ }
7044
+ function _isInRoot(root, element) {
7045
+ const scope = _normalizeRoot(root);
7046
+ if (!(element instanceof Element)) return false;
7047
+ if (scope === document) {
7048
+ return document.documentElement ? document.documentElement.contains(element) : document.contains(element);
7049
+ }
7050
+ if (scope === element) return true;
7051
+ return typeof scope.contains === "function" && scope.contains(element);
7052
+ }
7053
+ function _queryAll(root, selector) {
7054
+ const scope = _normalizeRoot(root);
7055
+ const matches = [];
7056
+ if (scope instanceof Element && typeof scope.matches === "function" && scope.matches(selector)) {
7057
+ matches.push(scope);
7058
+ }
7059
+ if (typeof scope.querySelectorAll === "function") {
7060
+ const descendants = scope.querySelectorAll(selector);
7061
+ for (let i = 0; i < descendants.length; i++) {
7062
+ matches.push(descendants[i]);
7063
+ }
7064
+ }
7065
+ return matches;
7066
+ }
6482
7067
  function _isSafeUrl(url) {
6483
7068
  try {
6484
7069
  const resolved = new URL(url, window.location.href);
@@ -6566,6 +7151,9 @@ module.exports = __toCommonJS(index_exports);
6566
7151
  if (entry.isIntersecting) {
6567
7152
  obs.unobserve(entry.target);
6568
7153
  _observerMap.delete(entry.target);
7154
+ if (typeof window.VanduoLifecycle !== "undefined" && window.VanduoLifecycle.has(entry.target, "lazyLoad")) {
7155
+ window.VanduoLifecycle.unregister(entry.target, "lazyLoad");
7156
+ }
6569
7157
  try {
6570
7158
  callback(entry.target);
6571
7159
  } catch (e) {
@@ -6575,27 +7163,39 @@ module.exports = __toCommonJS(index_exports);
6575
7163
  });
6576
7164
  }, { threshold, rootMargin });
6577
7165
  _observerMap.set(element, observer);
7166
+ if (typeof window.VanduoLifecycle !== "undefined" && !window.VanduoLifecycle.has(element, "lazyLoad")) {
7167
+ window.VanduoLifecycle.register(element, "lazyLoad", [() => {
7168
+ VanduoLazyLoad.unobserve(element, { skipLifecycle: true });
7169
+ }]);
7170
+ }
6578
7171
  observer.observe(element);
6579
7172
  },
6580
7173
  /**
6581
7174
  * Stop observing an element that was previously passed to observe().
6582
7175
  * @param {Element} element
6583
7176
  */
6584
- unobserve: function(element) {
7177
+ unobserve: function(element, options) {
7178
+ const opts = options || {};
6585
7179
  const observer = _observerMap.get(element);
6586
7180
  if (observer) {
6587
7181
  observer.unobserve(element);
7182
+ if (typeof observer.disconnect === "function") {
7183
+ observer.disconnect();
7184
+ }
6588
7185
  _observerMap.delete(element);
6589
7186
  }
7187
+ if (!opts.skipLifecycle && typeof window.VanduoLifecycle !== "undefined" && window.VanduoLifecycle.has(element, "lazyLoad")) {
7188
+ window.VanduoLifecycle.unregister(element, "lazyLoad");
7189
+ }
6590
7190
  },
6591
7191
  /**
6592
7192
  * Stop observing ALL currently observed elements.
6593
7193
  */
6594
7194
  unobserveAll: function() {
6595
- _observerMap.forEach(function(observer, element) {
6596
- observer.unobserve(element);
7195
+ const observed = Array.from(_observerMap.keys());
7196
+ observed.forEach(function(element) {
7197
+ VanduoLazyLoad.unobserve(element);
6597
7198
  });
6598
- _observerMap.clear();
6599
7199
  },
6600
7200
  /* ─────────────────────────────────────────────────
6601
7201
  * HIGH-LEVEL API
@@ -6644,7 +7244,7 @@ module.exports = __toCommonJS(index_exports);
6644
7244
  _safeInjectHtml(containerEl, html);
6645
7245
  _dispatch(containerEl, "lazysection:loaded", { url });
6646
7246
  if (typeof window.Vanduo !== "undefined") {
6647
- window.Vanduo.init();
7247
+ window.Vanduo.init(containerEl);
6648
7248
  }
6649
7249
  if (typeof opts.onLoaded === "function") {
6650
7250
  opts.onLoaded(containerEl);
@@ -6679,9 +7279,9 @@ module.exports = __toCommonJS(index_exports);
6679
7279
  * Scan the DOM for [data-vd-lazy] elements and wire them up.
6680
7280
  * Safe to call multiple times — already-observed elements are skipped.
6681
7281
  */
6682
- init: function() {
7282
+ init: function(root) {
6683
7283
  const self = this;
6684
- const elements = document.querySelectorAll("[data-vd-lazy]");
7284
+ const elements = _queryAll(root, "[data-vd-lazy]");
6685
7285
  elements.forEach(function(el) {
6686
7286
  if (_observerMap.has(el) || el.dataset.vdLazyState === "loading" || el.dataset.vdLazyState === "loaded") return;
6687
7287
  const url = el.getAttribute("data-vd-lazy");
@@ -6698,10 +7298,26 @@ module.exports = __toCommonJS(index_exports);
6698
7298
  }
6699
7299
  });
6700
7300
  });
7301
+ },
7302
+ destroy: function(element) {
7303
+ this.unobserve(element);
7304
+ },
7305
+ destroyAll: function(root) {
7306
+ const scope = _normalizeRoot(root);
7307
+ if (scope === document) {
7308
+ this.unobserveAll();
7309
+ return;
7310
+ }
7311
+ const observed = Array.from(_observerMap.keys());
7312
+ observed.forEach((element) => {
7313
+ if (_isInRoot(scope, element)) {
7314
+ this.unobserve(element);
7315
+ }
7316
+ });
6701
7317
  }
6702
7318
  };
6703
7319
  if (typeof window.Vanduo !== "undefined") {
6704
- window.Vanduo.register("LazyLoad", VanduoLazyLoad);
7320
+ window.Vanduo.register("lazyLoad", VanduoLazyLoad, { aliases: ["LazyLoad"] });
6705
7321
  }
6706
7322
  window.VanduoLazyLoad = VanduoLazyLoad;
6707
7323
  })();
@@ -6712,8 +7328,8 @@ module.exports = __toCommonJS(index_exports);
6712
7328
  const GlassScroll = {
6713
7329
  /** @type {Map<Element, IntersectionObserver>} */
6714
7330
  observers: /* @__PURE__ */ new Map(),
6715
- init: function() {
6716
- document.querySelectorAll("[data-glass-scroll]").forEach((el) => {
7331
+ init: function(root) {
7332
+ window.Vanduo.queryAll(root, "[data-glass-scroll]").forEach((el) => {
6717
7333
  if (this.observers.has(el)) return;
6718
7334
  this.initElement(el);
6719
7335
  });
@@ -6773,8 +7389,8 @@ module.exports = __toCommonJS(index_exports);
6773
7389
  const MORPH_DURATION_MS = 750;
6774
7390
  const Morph = {
6775
7391
  instances: /* @__PURE__ */ new Map(),
6776
- init: function() {
6777
- const elements = document.querySelectorAll(".vd-morph, [data-vd-morph]");
7392
+ init: function(root) {
7393
+ const elements = window.Vanduo.queryAll(root, ".vd-morph, [data-vd-morph]");
6778
7394
  elements.forEach(function(el) {
6779
7395
  if (Morph.instances.has(el)) return;
6780
7396
  if (el.getAttribute("data-vd-morph") === "manual") return;
@@ -6879,8 +7495,8 @@ module.exports = __toCommonJS(index_exports);
6879
7495
  "use strict";
6880
7496
  const ExpandingCards = {
6881
7497
  instances: /* @__PURE__ */ new Map(),
6882
- init: function() {
6883
- document.querySelectorAll(".vd-expanding-cards").forEach(function(el) {
7498
+ init: function(root) {
7499
+ window.Vanduo.queryAll(root, ".vd-expanding-cards").forEach(function(el) {
6884
7500
  if (el.getAttribute("data-vd-expanding-cards") === "manual") return;
6885
7501
  if (ExpandingCards.instances.has(el)) return;
6886
7502
  ExpandingCards.initContainer(el);
@@ -7012,6 +7628,8 @@ module.exports = __toCommonJS(index_exports);
7012
7628
  const playBtn = scope.querySelector("[data-vd-timeline-play]");
7013
7629
  const pauseBtn = scope.querySelector("[data-vd-timeline-pause]");
7014
7630
  let playTimer = null;
7631
+ let isPlaying = false;
7632
+ let playToken = 0;
7015
7633
  function updateNavButtons() {
7016
7634
  const k = countRevealedPrefix(items);
7017
7635
  const n = items.length;
@@ -7026,10 +7644,10 @@ module.exports = __toCommonJS(index_exports);
7026
7644
  nextBtn.setAttribute("aria-disabled", atEnd ? "true" : "false");
7027
7645
  }
7028
7646
  if (playBtn) {
7029
- playBtn.setAttribute("aria-pressed", playTimer ? "true" : "false");
7647
+ playBtn.setAttribute("aria-pressed", isPlaying ? "true" : "false");
7030
7648
  }
7031
7649
  if (pauseBtn) {
7032
- pauseBtn.disabled = !playTimer;
7650
+ pauseBtn.disabled = !isPlaying;
7033
7651
  }
7034
7652
  }
7035
7653
  function stepNext() {
@@ -7046,20 +7664,36 @@ module.exports = __toCommonJS(index_exports);
7046
7664
  }
7047
7665
  updateNavButtons();
7048
7666
  }
7049
- function play() {
7050
- if (playTimer) return;
7051
- playTimer = setInterval(function() {
7667
+ function scheduleNext() {
7668
+ const token = ++playToken;
7669
+ playTimer = setTimeout(function() {
7670
+ playTimer = null;
7671
+ if (!isPlaying || token !== playToken) {
7672
+ return;
7673
+ }
7052
7674
  if (countRevealedPrefix(items) >= items.length) {
7053
7675
  pause();
7054
7676
  return;
7055
7677
  }
7056
7678
  stepNext();
7679
+ if (countRevealedPrefix(items) >= items.length) {
7680
+ pause();
7681
+ return;
7682
+ }
7683
+ scheduleNext();
7057
7684
  }, PLAY_INTERVAL_MS);
7685
+ }
7686
+ function play() {
7687
+ if (isPlaying) return;
7688
+ isPlaying = true;
7689
+ scheduleNext();
7058
7690
  updateNavButtons();
7059
7691
  }
7060
7692
  function pause() {
7693
+ isPlaying = false;
7694
+ playToken++;
7061
7695
  if (playTimer) {
7062
- clearInterval(playTimer);
7696
+ clearTimeout(playTimer);
7063
7697
  playTimer = null;
7064
7698
  }
7065
7699
  updateNavButtons();
@@ -7092,15 +7726,15 @@ module.exports = __toCommonJS(index_exports);
7092
7726
  }
7093
7727
  const Timeline = {
7094
7728
  instances: /* @__PURE__ */ new Map(),
7095
- init: function() {
7096
- document.querySelectorAll(".vd-timeline.vd-timeline-animated").forEach(function(el) {
7729
+ init: function(root) {
7730
+ window.Vanduo.queryAll(root, ".vd-timeline.vd-timeline-animated").forEach(function(el) {
7097
7731
  if (Timeline.instances.has(el)) return;
7098
7732
  Timeline.initInstance(el);
7099
7733
  });
7100
7734
  },
7101
- reinit: function() {
7102
- Timeline.destroyAll();
7103
- Timeline.init();
7735
+ reinit: function(root) {
7736
+ Timeline.destroyAll(root);
7737
+ Timeline.init(root);
7104
7738
  },
7105
7739
  initInstance: function(container) {
7106
7740
  const cleanup = [];
@@ -7159,8 +7793,10 @@ module.exports = __toCommonJS(index_exports);
7159
7793
  });
7160
7794
  this.instances.delete(container);
7161
7795
  },
7162
- destroyAll: function() {
7796
+ destroyAll: function(root) {
7797
+ const scope = window.Vanduo && typeof window.Vanduo._normalizeRoot === "function" ? window.Vanduo._normalizeRoot(root) : document;
7163
7798
  this.instances.forEach(function(_, el) {
7799
+ if (scope !== document && scope !== el && (!scope.contains || !scope.contains(el))) return;
7164
7800
  Timeline.destroy(el);
7165
7801
  });
7166
7802
  }
@@ -7176,8 +7812,8 @@ module.exports = __toCommonJS(index_exports);
7176
7812
  "use strict";
7177
7813
  const Flow = {
7178
7814
  instances: /* @__PURE__ */ new Map(),
7179
- init: function() {
7180
- const carousels = document.querySelectorAll(".vd-flow, .vd-carousel");
7815
+ init: function(root) {
7816
+ const carousels = window.Vanduo.queryAll(root, ".vd-flow, .vd-carousel");
7181
7817
  carousels.forEach((el) => {
7182
7818
  if (this.instances.has(el)) return;
7183
7819
  this.initInstance(el);
@@ -7394,8 +8030,8 @@ module.exports = __toCommonJS(index_exports);
7394
8030
  const Bubble = {
7395
8031
  instances: /* @__PURE__ */ new Map(),
7396
8032
  _globalCleanups: [],
7397
- init: function() {
7398
- const triggers = document.querySelectorAll("[data-vd-bubble], [data-vd-popover]");
8033
+ init: function(root) {
8034
+ const triggers = window.Vanduo.queryAll(root, "[data-vd-bubble], [data-vd-popover]");
7399
8035
  triggers.forEach((el) => {
7400
8036
  if (this.instances.has(el)) return;
7401
8037
  this.initInstance(el);
@@ -7456,7 +8092,7 @@ module.exports = __toCommonJS(index_exports);
7456
8092
  body.className = "vd-bubble-body";
7457
8093
  if (htmlContent) {
7458
8094
  if (typeof sanitizeHtml === "function") {
7459
- body.innerHTML = sanitizeHtml(htmlContent, { allowSvg });
8095
+ body.innerHTML = sanitizeHtml(htmlContent, { allowSvg, allowStyle: false });
7460
8096
  } else {
7461
8097
  body.textContent = htmlContent;
7462
8098
  }
@@ -7567,8 +8203,8 @@ module.exports = __toCommonJS(index_exports);
7567
8203
  "use strict";
7568
8204
  const Waypoint = {
7569
8205
  instances: /* @__PURE__ */ new Map(),
7570
- init: function() {
7571
- const navs = document.querySelectorAll("[data-vd-waypoint-nav], [data-vd-scrollspy-nav]");
8206
+ init: function(root) {
8207
+ const navs = window.Vanduo.queryAll(root, "[data-vd-waypoint-nav], [data-vd-scrollspy-nav]");
7572
8208
  navs.forEach((nav) => {
7573
8209
  if (this.instances.has(nav)) return;
7574
8210
  this.initInstance(nav);
@@ -7661,8 +8297,8 @@ module.exports = __toCommonJS(index_exports);
7661
8297
  "use strict";
7662
8298
  const Ripple = {
7663
8299
  instances: /* @__PURE__ */ new Map(),
7664
- init: function() {
7665
- const elements = document.querySelectorAll(".vd-ripple, [data-vd-ripple]");
8300
+ init: function(root) {
8301
+ const elements = window.Vanduo.queryAll(root, ".vd-ripple, [data-vd-ripple]");
7666
8302
  elements.forEach((el) => {
7667
8303
  if (this.instances.has(el)) return;
7668
8304
  this.initInstance(el);
@@ -7733,8 +8369,8 @@ module.exports = __toCommonJS(index_exports);
7733
8369
  }
7734
8370
  const Affix = {
7735
8371
  instances: /* @__PURE__ */ new Map(),
7736
- init: function() {
7737
- const elements = document.querySelectorAll(".vd-affix, .vd-sticky, [data-vd-affix]");
8372
+ init: function(root) {
8373
+ const elements = window.Vanduo.queryAll(root, ".vd-affix, .vd-sticky, [data-vd-affix]");
7738
8374
  elements.forEach((el) => {
7739
8375
  if (this.instances.has(el)) return;
7740
8376
  this.initInstance(el);
@@ -7836,8 +8472,8 @@ module.exports = __toCommonJS(index_exports);
7836
8472
  }
7837
8473
  const Suggest = {
7838
8474
  instances: /* @__PURE__ */ new Map(),
7839
- init: function() {
7840
- const inputs = document.querySelectorAll("[data-vd-suggest], [data-vd-autocomplete]");
8475
+ init: function(root) {
8476
+ const inputs = window.Vanduo.queryAll(root, "[data-vd-suggest], [data-vd-autocomplete]");
7841
8477
  inputs.forEach((el) => {
7842
8478
  if (this.instances.has(el)) return;
7843
8479
  this.initInstance(el);
@@ -7999,16 +8635,20 @@ module.exports = __toCommonJS(index_exports);
7999
8635
  const blurHandler = () => {
8000
8636
  setTimeout(close, 200);
8001
8637
  };
8638
+ const focusHandler = () => {
8639
+ if (input.value.length >= minChars) {
8640
+ doSearch(input.value);
8641
+ }
8642
+ };
8002
8643
  input.addEventListener("input", inputHandler);
8003
8644
  input.addEventListener("keydown", keyHandler);
8004
8645
  input.addEventListener("blur", blurHandler);
8005
- input.addEventListener("focus", () => {
8006
- if (input.value.length >= minChars) doSearch(input.value);
8007
- });
8646
+ input.addEventListener("focus", focusHandler);
8008
8647
  cleanup.push(
8009
8648
  () => input.removeEventListener("input", inputHandler),
8010
8649
  () => input.removeEventListener("keydown", keyHandler),
8011
8650
  () => input.removeEventListener("blur", blurHandler),
8651
+ () => input.removeEventListener("focus", focusHandler),
8012
8652
  () => clearTimeout(debounceTimer),
8013
8653
  () => {
8014
8654
  if (list.parentNode) list.parentNode.removeChild(list);
@@ -8083,8 +8723,8 @@ module.exports = __toCommonJS(index_exports);
8083
8723
  pattern: "Invalid format",
8084
8724
  match: "Fields do not match"
8085
8725
  },
8086
- init: function() {
8087
- const forms = document.querySelectorAll("[data-vd-validate], .vd-validate");
8726
+ init: function(root) {
8727
+ const forms = window.Vanduo.queryAll(root, "[data-vd-validate], .vd-validate");
8088
8728
  forms.forEach((form) => {
8089
8729
  if (this.instances.has(form)) return;
8090
8730
  this.initInstance(form);
@@ -8321,8 +8961,8 @@ module.exports = __toCommonJS(index_exports);
8321
8961
  }
8322
8962
  const Datepicker = {
8323
8963
  instances: /* @__PURE__ */ new Map(),
8324
- init: function() {
8325
- const inputs = document.querySelectorAll("[data-vd-datepicker]");
8964
+ init: function(root) {
8965
+ const inputs = window.Vanduo.queryAll(root, "[data-vd-datepicker]");
8326
8966
  inputs.forEach((el) => {
8327
8967
  if (this.instances.has(el)) return;
8328
8968
  this.initInstance(el);
@@ -8774,8 +9414,8 @@ module.exports = __toCommonJS(index_exports);
8774
9414
  "use strict";
8775
9415
  const Timepicker = {
8776
9416
  instances: /* @__PURE__ */ new Map(),
8777
- init: function() {
8778
- const inputs = document.querySelectorAll("[data-vd-timepicker]");
9417
+ init: function(root) {
9418
+ const inputs = window.Vanduo.queryAll(root, "[data-vd-timepicker]");
8779
9419
  inputs.forEach((el) => {
8780
9420
  if (this.instances.has(el)) return;
8781
9421
  this.initInstance(el);
@@ -8889,8 +9529,8 @@ module.exports = __toCommonJS(index_exports);
8889
9529
  "use strict";
8890
9530
  const Stepper = {
8891
9531
  instances: /* @__PURE__ */ new Map(),
8892
- init: function() {
8893
- const steppers = document.querySelectorAll(".vd-stepper");
9532
+ init: function(root) {
9533
+ const steppers = window.Vanduo.queryAll(root, ".vd-stepper");
8894
9534
  steppers.forEach((el) => {
8895
9535
  if (this.instances.has(el)) return;
8896
9536
  this.initInstance(el);
@@ -8965,8 +9605,8 @@ module.exports = __toCommonJS(index_exports);
8965
9605
  "use strict";
8966
9606
  const Rating = {
8967
9607
  instances: /* @__PURE__ */ new Map(),
8968
- init: function() {
8969
- const ratings = document.querySelectorAll("[data-vd-rating]");
9608
+ init: function(root) {
9609
+ const ratings = window.Vanduo.queryAll(root, "[data-vd-rating]");
8970
9610
  ratings.forEach((el) => {
8971
9611
  if (this.instances.has(el)) return;
8972
9612
  this.initInstance(el);
@@ -9100,8 +9740,8 @@ module.exports = __toCommonJS(index_exports);
9100
9740
  "use strict";
9101
9741
  const Transfer = {
9102
9742
  instances: /* @__PURE__ */ new Map(),
9103
- init: function() {
9104
- const transfers = document.querySelectorAll("[data-vd-transfer]");
9743
+ init: function(root) {
9744
+ const transfers = window.Vanduo.queryAll(root, "[data-vd-transfer]");
9105
9745
  transfers.forEach((el) => {
9106
9746
  if (this.instances.has(el)) return;
9107
9747
  this.initInstance(el);
@@ -9264,8 +9904,8 @@ module.exports = __toCommonJS(index_exports);
9264
9904
  "use strict";
9265
9905
  const Tree = {
9266
9906
  instances: /* @__PURE__ */ new Map(),
9267
- init: function() {
9268
- const trees = document.querySelectorAll("[data-vd-tree]");
9907
+ init: function(root) {
9908
+ const trees = window.Vanduo.queryAll(root, "[data-vd-tree]");
9269
9909
  trees.forEach((el) => {
9270
9910
  if (this.instances.has(el)) return;
9271
9911
  this.initInstance(el);
@@ -9429,8 +10069,8 @@ module.exports = __toCommonJS(index_exports);
9429
10069
  _cleanup: [],
9430
10070
  _boundTriggers: /* @__PURE__ */ new WeakMap(),
9431
10071
  _triggerElement: null,
9432
- init: function() {
9433
- const triggers = document.querySelectorAll("[data-vd-spotlight]");
10072
+ init: function(root) {
10073
+ const triggers = window.Vanduo.queryAll(root, "[data-vd-spotlight]");
9434
10074
  triggers.forEach((trigger) => {
9435
10075
  if (this._boundTriggers.has(trigger)) return;
9436
10076
  const clickHandler = (event) => {
@@ -9703,8 +10343,8 @@ module.exports = __toCommonJS(index_exports);
9703
10343
  * Auto-initialize all .vd-music-player / [data-music-player] elements.
9704
10344
  * Options can be provided via data-music-player-options (JSON string).
9705
10345
  */
9706
- init: function() {
9707
- document.querySelectorAll(".vd-music-player, [data-music-player]").forEach((el) => {
10346
+ init: function(root) {
10347
+ window.Vanduo.queryAll(root, ".vd-music-player, [data-music-player]").forEach((el) => {
9708
10348
  if (this.instances.has(el)) return;
9709
10349
  let opts = {};
9710
10350
  const attr = el.getAttribute("data-music-player-options");