@vanduo-oss/framework 1.3.8 → 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 -41
  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 +28 -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 +61 -35
  48. package/css/core/grid.css +1 -6
  49. package/css/core/helpers.css +11 -11
  50. package/css/core/tokens.css +114 -36
  51. package/css/core/typography.css +15 -13
  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 +935 -294
  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 +7942 -7824
  64. package/dist/vanduo.css.map +1 -1
  65. package/dist/vanduo.esm.js +935 -294
  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 +935 -294
  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 +26 -16
  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 +154 -23
  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 +3 -4
@@ -1,4 +1,4 @@
1
- /*! Vanduo v1.3.8 | Built: 2026-05-06T18:32:43.703Z | git:6042eac | 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.8" : "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,31 +1522,36 @@ 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
  };
1219
1535
  if (!this.fonts[this.state.preference]) {
1220
- this.state.preference = "lato";
1536
+ this.state.preference = "ubuntu";
1221
1537
  this.setStorageValue(this.STORAGE_KEY, this.state.preference);
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
1236
- * @returns {string} Font key or 'lato' (default)
1551
+ * @returns {string} Font key or 'ubuntu' (default)
1237
1552
  */
1238
1553
  getPreference: function() {
1239
- return this.getStorageValue(this.STORAGE_KEY, "lato");
1554
+ return this.getStorageValue(this.STORAGE_KEY, "ubuntu");
1240
1555
  },
1241
1556
  /**
1242
1557
  * Set font preference and apply it
@@ -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;
@@ -3904,9 +4298,9 @@ module.exports = __toCommonJS(index_exports);
3904
4298
  DEFAULTS: {
3905
4299
  PRIMARY_LIGHT: "black",
3906
4300
  PRIMARY_DARK: "amber",
3907
- NEUTRAL: "neutral",
4301
+ NEUTRAL: "charcoal",
3908
4302
  RADIUS: "0.5",
3909
- FONT: "lato",
4303
+ FONT: "ubuntu",
3910
4304
  THEME: "system"
3911
4305
  },
3912
4306
  // Primary color definitions (Open Color based)
@@ -3932,6 +4326,7 @@ module.exports = __toCommonJS(index_exports);
3932
4326
  },
3933
4327
  // Neutral color definitions
3934
4328
  NEUTRAL_COLORS: {
4329
+ "charcoal": { name: "Charcoal", color: "#0d1117" },
3935
4330
  "slate": { name: "Slate", color: "#64748b" },
3936
4331
  "gray": { name: "Gray", color: "#6b7280" },
3937
4332
  "zinc": { name: "Zinc", color: "#71717a" },
@@ -3961,21 +4356,65 @@ module.exports = __toCommonJS(index_exports);
3961
4356
  },
3962
4357
  isInitialized: false,
3963
4358
  _cleanup: [],
4359
+ _ownsDynamicPanel: false,
3964
4360
  // DOM references
3965
4361
  elements: {
3966
4362
  customizer: null,
3967
4363
  trigger: null,
4364
+ activeTrigger: null,
3968
4365
  triggers: [],
3969
4366
  panel: null,
3970
4367
  overlay: null
3971
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
+ },
3972
4410
  /**
3973
4411
  * Initialize the Theme Customizer
3974
4412
  */
3975
- init: function() {
4413
+ init: function(root) {
4414
+ const scope = this.normalizeRoot(root);
3976
4415
  if (this.isInitialized) {
3977
- this.bindExistingElements();
3978
- this.bindTriggerEvents();
4416
+ this.bindExistingElements(scope);
4417
+ this.bindTriggerEvents(scope);
3979
4418
  this.bindPanelEvents();
3980
4419
  this.updateUI();
3981
4420
  return;
@@ -3984,9 +4423,8 @@ module.exports = __toCommonJS(index_exports);
3984
4423
  this._cleanup = [];
3985
4424
  this.loadPreferences();
3986
4425
  this.applyAllPreferences();
3987
- this.bindExistingElements();
3988
- this.bindEvents();
3989
- console.log("Vanduo Theme Customizer initialized");
4426
+ this.bindExistingElements(scope);
4427
+ this.bindEvents(scope);
3990
4428
  },
3991
4429
  addListener: function(target, event, handler, options) {
3992
4430
  if (!target) return;
@@ -4147,18 +4585,26 @@ module.exports = __toCommonJS(index_exports);
4147
4585
  /**
4148
4586
  * Bind to existing DOM elements or create them dynamically
4149
4587
  */
4150
- bindExistingElements: function() {
4151
- this.elements.customizer = document.querySelector(".vd-theme-customizer");
4152
- 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
+ });
4153
4597
  if (!this.elements.trigger && this.elements.triggers.length) {
4154
4598
  this.elements.trigger = this.elements.triggers[0];
4155
4599
  }
4156
- 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;
4157
4603
  this.elements.trigger = this.elements.customizer.querySelector(".vd-theme-customizer-trigger") || this.elements.trigger;
4158
4604
  this.elements.panel = this.elements.customizer.querySelector(".vd-theme-customizer-panel");
4159
4605
  this.elements.overlay = this.elements.customizer.querySelector(".vd-theme-customizer-overlay");
4160
4606
  } else {
4161
- if (this.elements.triggers.length) {
4607
+ if (scopedTriggers.length && !this.elements.panel) {
4162
4608
  this.createDynamicPanel();
4163
4609
  }
4164
4610
  }
@@ -4168,7 +4614,7 @@ module.exports = __toCommonJS(index_exports);
4168
4614
  * Create the panel dynamically when only a trigger button exists
4169
4615
  */
4170
4616
  createDynamicPanel: function() {
4171
- if (!this.elements.triggers.length) {
4617
+ if (!this.elements.triggers.length || this.elements.panel && this.elements.panel.isConnected) {
4172
4618
  return;
4173
4619
  }
4174
4620
  this.elements.trigger = this.elements.triggers[0];
@@ -4181,6 +4627,7 @@ module.exports = __toCommonJS(index_exports);
4181
4627
  document.body.appendChild(panel);
4182
4628
  this.elements.panel = panel;
4183
4629
  this.elements.overlay = overlay;
4630
+ this._ownsDynamicPanel = true;
4184
4631
  this.elements.customizer = {
4185
4632
  contains: (el) => panel.contains(el) || this.elements.triggers.some((trigger) => trigger.contains(el))
4186
4633
  };
@@ -4363,8 +4810,8 @@ module.exports = __toCommonJS(index_exports);
4363
4810
  this.state.primary = expected;
4364
4811
  }
4365
4812
  },
4366
- bindEvents: function() {
4367
- this.bindTriggerEvents();
4813
+ bindEvents: function(root) {
4814
+ this.bindTriggerEvents(root);
4368
4815
  this.bindPanelEvents();
4369
4816
  if (window.matchMedia) {
4370
4817
  const mq = window.matchMedia("(prefers-color-scheme: dark)");
@@ -4391,21 +4838,44 @@ module.exports = __toCommonJS(index_exports);
4391
4838
  }
4392
4839
  });
4393
4840
  },
4394
- bindTriggerEvents: function() {
4395
- this.elements.triggers.forEach((trigger) => {
4841
+ bindTriggerEvents: function(root) {
4842
+ const triggers = root ? this.getTriggers(root) : this.elements.triggers;
4843
+ triggers.forEach((trigger) => {
4396
4844
  if (trigger.getAttribute("data-customizer-trigger-initialized") === "true") {
4397
4845
  return;
4398
4846
  }
4399
- this.addListener(trigger, "click", (e) => {
4847
+ const onClick = (e) => {
4400
4848
  e.preventDefault();
4401
4849
  e.stopPropagation();
4402
4850
  this.elements.activeTrigger = trigger;
4403
4851
  this.elements.trigger = trigger;
4404
4852
  this.toggle();
4405
- });
4853
+ };
4854
+ trigger.addEventListener("click", onClick);
4855
+ trigger._themeCustomizerTriggerHandler = onClick;
4406
4856
  trigger.setAttribute("data-customizer-trigger-initialized", "true");
4407
4857
  });
4408
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
+ },
4409
4879
  /**
4410
4880
  * Toggle panel open/close
4411
4881
  */
@@ -4516,13 +4986,42 @@ module.exports = __toCommonJS(index_exports);
4516
4986
  return false;
4517
4987
  }
4518
4988
  },
4519
- 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
+ }
4520
5001
  this._cleanup.forEach((fn) => fn());
4521
5002
  this._cleanup = [];
4522
5003
  if (this.elements.panel) {
4523
5004
  this.elements.panel.removeAttribute("data-customizer-initialized");
4524
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
+ }
4525
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;
4526
5025
  this.isInitialized = false;
4527
5026
  }
4528
5027
  };
@@ -4539,7 +5038,13 @@ module.exports = __toCommonJS(index_exports);
4539
5038
  isInitialized: false,
4540
5039
  _mediaQuery: null,
4541
5040
  _onMediaChange: null,
4542
- 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) {
4543
5048
  this.STORAGE_KEY = "vanduo-theme-preference";
4544
5049
  this.state = {
4545
5050
  preference: this.getPreference()
@@ -4547,15 +5052,14 @@ module.exports = __toCommonJS(index_exports);
4547
5052
  };
4548
5053
  if (this.isInitialized) {
4549
5054
  this.applyTheme();
4550
- this.renderUI();
4551
- this.updateUI();
5055
+ this.renderUI(root);
5056
+ this.updateUI(root);
4552
5057
  return;
4553
5058
  }
4554
5059
  this.isInitialized = true;
4555
5060
  this.applyTheme();
4556
5061
  this.listenForSystemChanges();
4557
- this.renderUI();
4558
- console.log("Vanduo Theme Switcher initialized");
5062
+ this.renderUI(root);
4559
5063
  },
4560
5064
  getPreference: function() {
4561
5065
  return this.getStorageValue(this.STORAGE_KEY, "system");
@@ -4615,8 +5119,8 @@ module.exports = __toCommonJS(index_exports);
4615
5119
  this._mediaQuery.addEventListener("change", this._onMediaChange);
4616
5120
  },
4617
5121
  // Helper to facilitate UI creation if needed, though often UI is in HTML
4618
- renderUI: function() {
4619
- const toggles = document.querySelectorAll('[data-toggle="theme"]');
5122
+ renderUI: function(root) {
5123
+ const toggles = this.getToggles(root);
4620
5124
  toggles.forEach((toggle) => {
4621
5125
  if (toggle.getAttribute("data-theme-initialized") === "true") {
4622
5126
  if (toggle.tagName === "SELECT") {
@@ -4643,8 +5147,8 @@ module.exports = __toCommonJS(index_exports);
4643
5147
  toggle.setAttribute("data-theme-initialized", "true");
4644
5148
  });
4645
5149
  },
4646
- updateUI: function() {
4647
- const toggles = document.querySelectorAll('[data-toggle="theme"]');
5150
+ updateUI: function(root) {
5151
+ const toggles = this.getToggles(root);
4648
5152
  toggles.forEach((toggle) => {
4649
5153
  if (toggle.tagName === "SELECT") {
4650
5154
  toggle.value = this.state.preference;
@@ -4656,8 +5160,11 @@ module.exports = __toCommonJS(index_exports);
4656
5160
  }
4657
5161
  });
4658
5162
  },
4659
- destroyAll: function() {
4660
- 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
+ });
4661
5168
  toggles.forEach((toggle) => {
4662
5169
  if (toggle._themeToggleHandler) {
4663
5170
  const eventName = toggle.tagName === "SELECT" ? "change" : "click";
@@ -4666,12 +5173,14 @@ module.exports = __toCommonJS(index_exports);
4666
5173
  }
4667
5174
  toggle.removeAttribute("data-theme-initialized");
4668
5175
  });
4669
- if (this._mediaQuery && this._onMediaChange) {
5176
+ if (scope === document && this._mediaQuery && this._onMediaChange) {
4670
5177
  this._mediaQuery.removeEventListener("change", this._onMediaChange);
4671
5178
  }
4672
- this._mediaQuery = null;
4673
- this._onMediaChange = null;
4674
- this.isInitialized = false;
5179
+ if (scope === document) {
5180
+ this._mediaQuery = null;
5181
+ this._onMediaChange = null;
5182
+ this.isInitialized = false;
5183
+ }
4675
5184
  }
4676
5185
  };
4677
5186
  if (window.Vanduo) {
@@ -4748,7 +5257,7 @@ module.exports = __toCommonJS(index_exports);
4748
5257
  let html = "";
4749
5258
  if (config.icon) {
4750
5259
  const allowSvg = config.iconAllowSvg === true;
4751
- 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);
4752
5261
  html += `<span class="vd-toast-icon">${safeIcon}</span>`;
4753
5262
  } else if (config.type) {
4754
5263
  html += `<span class="vd-toast-icon">${this.getDefaultIcon(config.type)}</span>`;
@@ -4968,8 +5477,8 @@ module.exports = __toCommonJS(index_exports);
4968
5477
  /**
4969
5478
  * Initialize tooltips
4970
5479
  */
4971
- init: function() {
4972
- 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]");
4973
5482
  elements.forEach((element) => {
4974
5483
  if (this.tooltips.has(element)) {
4975
5484
  return;
@@ -5025,7 +5534,7 @@ module.exports = __toCommonJS(index_exports);
5025
5534
  const textContent = element.dataset.tooltip;
5026
5535
  if (htmlContent) {
5027
5536
  const allowSvg = element.hasAttribute("data-tooltip-allow-svg");
5028
- tooltip.innerHTML = this.sanitizeHtml(htmlContent, { allowSvg });
5537
+ tooltip.innerHTML = this.sanitizeHtml(htmlContent, { allowSvg, allowStyle: false });
5029
5538
  tooltip.classList.add("vd-tooltip-html");
5030
5539
  } else if (textContent) {
5031
5540
  tooltip.textContent = textContent;
@@ -5158,7 +5667,7 @@ module.exports = __toCommonJS(index_exports);
5158
5667
  const { tooltip } = this.tooltips.get(el);
5159
5668
  if (isHtml) {
5160
5669
  const allowSvg = el.hasAttribute("data-tooltip-allow-svg");
5161
- tooltip.innerHTML = this.sanitizeHtml(content, { allowSvg });
5670
+ tooltip.innerHTML = this.sanitizeHtml(content, { allowSvg, allowStyle: false });
5162
5671
  tooltip.classList.add("vd-tooltip-html");
5163
5672
  } else {
5164
5673
  tooltip.textContent = content;
@@ -5248,8 +5757,26 @@ module.exports = __toCommonJS(index_exports);
5248
5757
  emptyText: "Try different keywords or check spelling",
5249
5758
  placeholder: "Search..."
5250
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
+ }
5251
5776
  function createSearch(options) {
5252
5777
  const config = Object.assign({}, DEFAULTS, options || {});
5778
+ config.root = normalizeRoot(config.root);
5779
+ config.highlightTag = normalizeHighlightTag(config.highlightTag);
5253
5780
  const state = {
5254
5781
  initialized: false,
5255
5782
  index: [],
@@ -5263,6 +5790,24 @@ module.exports = __toCommonJS(index_exports);
5263
5790
  debounceTimer: null,
5264
5791
  boundHandlers: {}
5265
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
+ }
5266
5811
  function safeInvokeCallback(name, fn, ...args) {
5267
5812
  try {
5268
5813
  fn(...args);
@@ -5282,7 +5827,7 @@ module.exports = __toCommonJS(index_exports);
5282
5827
  if (state.initialized) {
5283
5828
  return instance;
5284
5829
  }
5285
- state.container = document.querySelector(config.containerSelector);
5830
+ state.container = queryOne(config.containerSelector);
5286
5831
  if (!state.container) {
5287
5832
  state.initialized = false;
5288
5833
  return null;
@@ -5319,7 +5864,7 @@ module.exports = __toCommonJS(index_exports);
5319
5864
  });
5320
5865
  return;
5321
5866
  }
5322
- const sections = document.querySelectorAll(config.contentSelector);
5867
+ const sections = queryAll(config.contentSelector);
5323
5868
  const categoryMap = buildCategoryMap();
5324
5869
  sections.forEach(function(section) {
5325
5870
  const id = section.id;
@@ -5354,7 +5899,7 @@ module.exports = __toCommonJS(index_exports);
5354
5899
  function buildCategoryMap() {
5355
5900
  const map = {};
5356
5901
  let currentCategory = "Documentation";
5357
- const navItems = document.querySelectorAll(config.navSelector + ", " + config.sectionSelector);
5902
+ const navItems = queryAll(config.navSelector + ", " + config.sectionSelector);
5358
5903
  navItems.forEach(function(item) {
5359
5904
  if (item.classList.contains("doc-nav-section")) {
5360
5905
  currentCategory = item.textContent.trim();
@@ -5683,7 +6228,7 @@ module.exports = __toCommonJS(index_exports);
5683
6228
  safeInvokeCallback("onSelect", config.onSelect, result);
5684
6229
  return;
5685
6230
  }
5686
- const section = document.querySelector(result.url);
6231
+ const section = queryOne(result.url) || document.querySelector(result.url);
5687
6232
  if (section) {
5688
6233
  section.scrollIntoView({ behavior: "smooth", block: "start" });
5689
6234
  window.history.pushState(null, "", result.url);
@@ -5691,7 +6236,7 @@ module.exports = __toCommonJS(index_exports);
5691
6236
  }
5692
6237
  }
5693
6238
  function updateSidebarActive(sectionId) {
5694
- const navLinks = document.querySelectorAll(config.navSelector);
6239
+ const navLinks = queryAll(config.navSelector);
5695
6240
  navLinks.forEach(function(link) {
5696
6241
  link.classList.remove("active");
5697
6242
  if (link.getAttribute("href") === "#" + sectionId) {
@@ -5738,6 +6283,8 @@ module.exports = __toCommonJS(index_exports);
5738
6283
  }
5739
6284
  function setConfig(newConfig) {
5740
6285
  Object.assign(config, newConfig);
6286
+ config.root = normalizeRoot(config.root);
6287
+ config.highlightTag = normalizeHighlightTag(config.highlightTag);
5741
6288
  }
5742
6289
  function getConfig() {
5743
6290
  return Object.assign({}, config);
@@ -5754,7 +6301,10 @@ module.exports = __toCommonJS(index_exports);
5754
6301
  close,
5755
6302
  setConfig,
5756
6303
  getConfig,
5757
- getIndex
6304
+ getIndex,
6305
+ getContainer: function() {
6306
+ return state.container;
6307
+ }
5758
6308
  };
5759
6309
  return instance;
5760
6310
  }
@@ -5776,27 +6326,34 @@ module.exports = __toCommonJS(index_exports);
5776
6326
  /**
5777
6327
  * Initialize the default search instance
5778
6328
  */
5779
- init: function(options) {
6329
+ init: function(rootOrOptions, maybeOptions) {
6330
+ const root = isRoot(rootOrOptions) ? rootOrOptions : null;
6331
+ const options = root ? maybeOptions : rootOrOptions;
5780
6332
  if (this._instance) {
5781
6333
  this._instance.destroy();
5782
6334
  }
5783
6335
  if (options) {
5784
6336
  Object.assign(this.config, options);
5785
6337
  }
5786
- this._instance = createSearch(this.config);
6338
+ this._instance = createSearch(Object.assign({}, this.config, root ? { root } : {}));
5787
6339
  return this._instance ? this._instance.init() : null;
5788
6340
  },
5789
6341
  /**
5790
6342
  * Destroy the default instance
5791
6343
  */
5792
- 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
+ }
5793
6350
  if (this._instance) {
5794
6351
  this._instance.destroy();
5795
6352
  this._instance = null;
5796
6353
  }
5797
6354
  },
5798
- destroyAll: function() {
5799
- this.destroy();
6355
+ destroyAll: function(root) {
6356
+ this.destroy(root);
5800
6357
  },
5801
6358
  /**
5802
6359
  * Rebuild the default instance index
@@ -5854,21 +6411,21 @@ module.exports = __toCommonJS(index_exports);
5854
6411
  /**
5855
6412
  * Initialize draggable components
5856
6413
  */
5857
- init: function() {
5858
- const draggables = document.querySelectorAll(".vd-draggable, [data-draggable]");
6414
+ init: function(root) {
6415
+ const draggables = window.Vanduo.queryAll(root, ".vd-draggable, [data-draggable]");
5859
6416
  draggables.forEach((element) => {
5860
6417
  if (this.instances.has(element)) {
5861
6418
  return;
5862
6419
  }
5863
6420
  this.initDraggable(element);
5864
6421
  });
5865
- const containers = document.querySelectorAll(this.containerSelector);
6422
+ const containers = window.Vanduo.queryAll(root, this.containerSelector);
5866
6423
  containers.forEach((container) => {
5867
6424
  if (!this.instances.has(container)) {
5868
6425
  this.initContainer(container);
5869
6426
  }
5870
6427
  });
5871
- const dropZones = document.querySelectorAll(".vd-drop-zone");
6428
+ const dropZones = window.Vanduo.queryAll(root, ".vd-drop-zone");
5872
6429
  dropZones.forEach((zone) => {
5873
6430
  if (!this.instances.has(zone)) {
5874
6431
  this.initDropZone(zone);
@@ -6478,6 +7035,35 @@ module.exports = __toCommonJS(index_exports);
6478
7035
  (function() {
6479
7036
  "use strict";
6480
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
+ }
6481
7067
  function _isSafeUrl(url) {
6482
7068
  try {
6483
7069
  const resolved = new URL(url, window.location.href);
@@ -6565,6 +7151,9 @@ module.exports = __toCommonJS(index_exports);
6565
7151
  if (entry.isIntersecting) {
6566
7152
  obs.unobserve(entry.target);
6567
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
+ }
6568
7157
  try {
6569
7158
  callback(entry.target);
6570
7159
  } catch (e) {
@@ -6574,27 +7163,39 @@ module.exports = __toCommonJS(index_exports);
6574
7163
  });
6575
7164
  }, { threshold, rootMargin });
6576
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
+ }
6577
7171
  observer.observe(element);
6578
7172
  },
6579
7173
  /**
6580
7174
  * Stop observing an element that was previously passed to observe().
6581
7175
  * @param {Element} element
6582
7176
  */
6583
- unobserve: function(element) {
7177
+ unobserve: function(element, options) {
7178
+ const opts = options || {};
6584
7179
  const observer = _observerMap.get(element);
6585
7180
  if (observer) {
6586
7181
  observer.unobserve(element);
7182
+ if (typeof observer.disconnect === "function") {
7183
+ observer.disconnect();
7184
+ }
6587
7185
  _observerMap.delete(element);
6588
7186
  }
7187
+ if (!opts.skipLifecycle && typeof window.VanduoLifecycle !== "undefined" && window.VanduoLifecycle.has(element, "lazyLoad")) {
7188
+ window.VanduoLifecycle.unregister(element, "lazyLoad");
7189
+ }
6589
7190
  },
6590
7191
  /**
6591
7192
  * Stop observing ALL currently observed elements.
6592
7193
  */
6593
7194
  unobserveAll: function() {
6594
- _observerMap.forEach(function(observer, element) {
6595
- observer.unobserve(element);
7195
+ const observed = Array.from(_observerMap.keys());
7196
+ observed.forEach(function(element) {
7197
+ VanduoLazyLoad.unobserve(element);
6596
7198
  });
6597
- _observerMap.clear();
6598
7199
  },
6599
7200
  /* ─────────────────────────────────────────────────
6600
7201
  * HIGH-LEVEL API
@@ -6643,7 +7244,7 @@ module.exports = __toCommonJS(index_exports);
6643
7244
  _safeInjectHtml(containerEl, html);
6644
7245
  _dispatch(containerEl, "lazysection:loaded", { url });
6645
7246
  if (typeof window.Vanduo !== "undefined") {
6646
- window.Vanduo.init();
7247
+ window.Vanduo.init(containerEl);
6647
7248
  }
6648
7249
  if (typeof opts.onLoaded === "function") {
6649
7250
  opts.onLoaded(containerEl);
@@ -6678,9 +7279,9 @@ module.exports = __toCommonJS(index_exports);
6678
7279
  * Scan the DOM for [data-vd-lazy] elements and wire them up.
6679
7280
  * Safe to call multiple times — already-observed elements are skipped.
6680
7281
  */
6681
- init: function() {
7282
+ init: function(root) {
6682
7283
  const self = this;
6683
- const elements = document.querySelectorAll("[data-vd-lazy]");
7284
+ const elements = _queryAll(root, "[data-vd-lazy]");
6684
7285
  elements.forEach(function(el) {
6685
7286
  if (_observerMap.has(el) || el.dataset.vdLazyState === "loading" || el.dataset.vdLazyState === "loaded") return;
6686
7287
  const url = el.getAttribute("data-vd-lazy");
@@ -6697,10 +7298,26 @@ module.exports = __toCommonJS(index_exports);
6697
7298
  }
6698
7299
  });
6699
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
+ });
6700
7317
  }
6701
7318
  };
6702
7319
  if (typeof window.Vanduo !== "undefined") {
6703
- window.Vanduo.register("LazyLoad", VanduoLazyLoad);
7320
+ window.Vanduo.register("lazyLoad", VanduoLazyLoad, { aliases: ["LazyLoad"] });
6704
7321
  }
6705
7322
  window.VanduoLazyLoad = VanduoLazyLoad;
6706
7323
  })();
@@ -6711,8 +7328,8 @@ module.exports = __toCommonJS(index_exports);
6711
7328
  const GlassScroll = {
6712
7329
  /** @type {Map<Element, IntersectionObserver>} */
6713
7330
  observers: /* @__PURE__ */ new Map(),
6714
- init: function() {
6715
- document.querySelectorAll("[data-glass-scroll]").forEach((el) => {
7331
+ init: function(root) {
7332
+ window.Vanduo.queryAll(root, "[data-glass-scroll]").forEach((el) => {
6716
7333
  if (this.observers.has(el)) return;
6717
7334
  this.initElement(el);
6718
7335
  });
@@ -6772,8 +7389,8 @@ module.exports = __toCommonJS(index_exports);
6772
7389
  const MORPH_DURATION_MS = 750;
6773
7390
  const Morph = {
6774
7391
  instances: /* @__PURE__ */ new Map(),
6775
- init: function() {
6776
- 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]");
6777
7394
  elements.forEach(function(el) {
6778
7395
  if (Morph.instances.has(el)) return;
6779
7396
  if (el.getAttribute("data-vd-morph") === "manual") return;
@@ -6878,8 +7495,8 @@ module.exports = __toCommonJS(index_exports);
6878
7495
  "use strict";
6879
7496
  const ExpandingCards = {
6880
7497
  instances: /* @__PURE__ */ new Map(),
6881
- init: function() {
6882
- document.querySelectorAll(".vd-expanding-cards").forEach(function(el) {
7498
+ init: function(root) {
7499
+ window.Vanduo.queryAll(root, ".vd-expanding-cards").forEach(function(el) {
6883
7500
  if (el.getAttribute("data-vd-expanding-cards") === "manual") return;
6884
7501
  if (ExpandingCards.instances.has(el)) return;
6885
7502
  ExpandingCards.initContainer(el);
@@ -7011,6 +7628,8 @@ module.exports = __toCommonJS(index_exports);
7011
7628
  const playBtn = scope.querySelector("[data-vd-timeline-play]");
7012
7629
  const pauseBtn = scope.querySelector("[data-vd-timeline-pause]");
7013
7630
  let playTimer = null;
7631
+ let isPlaying = false;
7632
+ let playToken = 0;
7014
7633
  function updateNavButtons() {
7015
7634
  const k = countRevealedPrefix(items);
7016
7635
  const n = items.length;
@@ -7025,10 +7644,10 @@ module.exports = __toCommonJS(index_exports);
7025
7644
  nextBtn.setAttribute("aria-disabled", atEnd ? "true" : "false");
7026
7645
  }
7027
7646
  if (playBtn) {
7028
- playBtn.setAttribute("aria-pressed", playTimer ? "true" : "false");
7647
+ playBtn.setAttribute("aria-pressed", isPlaying ? "true" : "false");
7029
7648
  }
7030
7649
  if (pauseBtn) {
7031
- pauseBtn.disabled = !playTimer;
7650
+ pauseBtn.disabled = !isPlaying;
7032
7651
  }
7033
7652
  }
7034
7653
  function stepNext() {
@@ -7045,20 +7664,36 @@ module.exports = __toCommonJS(index_exports);
7045
7664
  }
7046
7665
  updateNavButtons();
7047
7666
  }
7048
- function play() {
7049
- if (playTimer) return;
7050
- 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
+ }
7051
7674
  if (countRevealedPrefix(items) >= items.length) {
7052
7675
  pause();
7053
7676
  return;
7054
7677
  }
7055
7678
  stepNext();
7679
+ if (countRevealedPrefix(items) >= items.length) {
7680
+ pause();
7681
+ return;
7682
+ }
7683
+ scheduleNext();
7056
7684
  }, PLAY_INTERVAL_MS);
7685
+ }
7686
+ function play() {
7687
+ if (isPlaying) return;
7688
+ isPlaying = true;
7689
+ scheduleNext();
7057
7690
  updateNavButtons();
7058
7691
  }
7059
7692
  function pause() {
7693
+ isPlaying = false;
7694
+ playToken++;
7060
7695
  if (playTimer) {
7061
- clearInterval(playTimer);
7696
+ clearTimeout(playTimer);
7062
7697
  playTimer = null;
7063
7698
  }
7064
7699
  updateNavButtons();
@@ -7091,15 +7726,15 @@ module.exports = __toCommonJS(index_exports);
7091
7726
  }
7092
7727
  const Timeline = {
7093
7728
  instances: /* @__PURE__ */ new Map(),
7094
- init: function() {
7095
- 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) {
7096
7731
  if (Timeline.instances.has(el)) return;
7097
7732
  Timeline.initInstance(el);
7098
7733
  });
7099
7734
  },
7100
- reinit: function() {
7101
- Timeline.destroyAll();
7102
- Timeline.init();
7735
+ reinit: function(root) {
7736
+ Timeline.destroyAll(root);
7737
+ Timeline.init(root);
7103
7738
  },
7104
7739
  initInstance: function(container) {
7105
7740
  const cleanup = [];
@@ -7158,8 +7793,10 @@ module.exports = __toCommonJS(index_exports);
7158
7793
  });
7159
7794
  this.instances.delete(container);
7160
7795
  },
7161
- destroyAll: function() {
7796
+ destroyAll: function(root) {
7797
+ const scope = window.Vanduo && typeof window.Vanduo._normalizeRoot === "function" ? window.Vanduo._normalizeRoot(root) : document;
7162
7798
  this.instances.forEach(function(_, el) {
7799
+ if (scope !== document && scope !== el && (!scope.contains || !scope.contains(el))) return;
7163
7800
  Timeline.destroy(el);
7164
7801
  });
7165
7802
  }
@@ -7175,8 +7812,8 @@ module.exports = __toCommonJS(index_exports);
7175
7812
  "use strict";
7176
7813
  const Flow = {
7177
7814
  instances: /* @__PURE__ */ new Map(),
7178
- init: function() {
7179
- const carousels = document.querySelectorAll(".vd-flow, .vd-carousel");
7815
+ init: function(root) {
7816
+ const carousels = window.Vanduo.queryAll(root, ".vd-flow, .vd-carousel");
7180
7817
  carousels.forEach((el) => {
7181
7818
  if (this.instances.has(el)) return;
7182
7819
  this.initInstance(el);
@@ -7393,8 +8030,8 @@ module.exports = __toCommonJS(index_exports);
7393
8030
  const Bubble = {
7394
8031
  instances: /* @__PURE__ */ new Map(),
7395
8032
  _globalCleanups: [],
7396
- init: function() {
7397
- 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]");
7398
8035
  triggers.forEach((el) => {
7399
8036
  if (this.instances.has(el)) return;
7400
8037
  this.initInstance(el);
@@ -7455,7 +8092,7 @@ module.exports = __toCommonJS(index_exports);
7455
8092
  body.className = "vd-bubble-body";
7456
8093
  if (htmlContent) {
7457
8094
  if (typeof sanitizeHtml === "function") {
7458
- body.innerHTML = sanitizeHtml(htmlContent, { allowSvg });
8095
+ body.innerHTML = sanitizeHtml(htmlContent, { allowSvg, allowStyle: false });
7459
8096
  } else {
7460
8097
  body.textContent = htmlContent;
7461
8098
  }
@@ -7566,8 +8203,8 @@ module.exports = __toCommonJS(index_exports);
7566
8203
  "use strict";
7567
8204
  const Waypoint = {
7568
8205
  instances: /* @__PURE__ */ new Map(),
7569
- init: function() {
7570
- 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]");
7571
8208
  navs.forEach((nav) => {
7572
8209
  if (this.instances.has(nav)) return;
7573
8210
  this.initInstance(nav);
@@ -7660,8 +8297,8 @@ module.exports = __toCommonJS(index_exports);
7660
8297
  "use strict";
7661
8298
  const Ripple = {
7662
8299
  instances: /* @__PURE__ */ new Map(),
7663
- init: function() {
7664
- 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]");
7665
8302
  elements.forEach((el) => {
7666
8303
  if (this.instances.has(el)) return;
7667
8304
  this.initInstance(el);
@@ -7732,8 +8369,8 @@ module.exports = __toCommonJS(index_exports);
7732
8369
  }
7733
8370
  const Affix = {
7734
8371
  instances: /* @__PURE__ */ new Map(),
7735
- init: function() {
7736
- 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]");
7737
8374
  elements.forEach((el) => {
7738
8375
  if (this.instances.has(el)) return;
7739
8376
  this.initInstance(el);
@@ -7835,8 +8472,8 @@ module.exports = __toCommonJS(index_exports);
7835
8472
  }
7836
8473
  const Suggest = {
7837
8474
  instances: /* @__PURE__ */ new Map(),
7838
- init: function() {
7839
- 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]");
7840
8477
  inputs.forEach((el) => {
7841
8478
  if (this.instances.has(el)) return;
7842
8479
  this.initInstance(el);
@@ -7998,16 +8635,20 @@ module.exports = __toCommonJS(index_exports);
7998
8635
  const blurHandler = () => {
7999
8636
  setTimeout(close, 200);
8000
8637
  };
8638
+ const focusHandler = () => {
8639
+ if (input.value.length >= minChars) {
8640
+ doSearch(input.value);
8641
+ }
8642
+ };
8001
8643
  input.addEventListener("input", inputHandler);
8002
8644
  input.addEventListener("keydown", keyHandler);
8003
8645
  input.addEventListener("blur", blurHandler);
8004
- input.addEventListener("focus", () => {
8005
- if (input.value.length >= minChars) doSearch(input.value);
8006
- });
8646
+ input.addEventListener("focus", focusHandler);
8007
8647
  cleanup.push(
8008
8648
  () => input.removeEventListener("input", inputHandler),
8009
8649
  () => input.removeEventListener("keydown", keyHandler),
8010
8650
  () => input.removeEventListener("blur", blurHandler),
8651
+ () => input.removeEventListener("focus", focusHandler),
8011
8652
  () => clearTimeout(debounceTimer),
8012
8653
  () => {
8013
8654
  if (list.parentNode) list.parentNode.removeChild(list);
@@ -8082,8 +8723,8 @@ module.exports = __toCommonJS(index_exports);
8082
8723
  pattern: "Invalid format",
8083
8724
  match: "Fields do not match"
8084
8725
  },
8085
- init: function() {
8086
- 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");
8087
8728
  forms.forEach((form) => {
8088
8729
  if (this.instances.has(form)) return;
8089
8730
  this.initInstance(form);
@@ -8320,8 +8961,8 @@ module.exports = __toCommonJS(index_exports);
8320
8961
  }
8321
8962
  const Datepicker = {
8322
8963
  instances: /* @__PURE__ */ new Map(),
8323
- init: function() {
8324
- const inputs = document.querySelectorAll("[data-vd-datepicker]");
8964
+ init: function(root) {
8965
+ const inputs = window.Vanduo.queryAll(root, "[data-vd-datepicker]");
8325
8966
  inputs.forEach((el) => {
8326
8967
  if (this.instances.has(el)) return;
8327
8968
  this.initInstance(el);
@@ -8773,8 +9414,8 @@ module.exports = __toCommonJS(index_exports);
8773
9414
  "use strict";
8774
9415
  const Timepicker = {
8775
9416
  instances: /* @__PURE__ */ new Map(),
8776
- init: function() {
8777
- const inputs = document.querySelectorAll("[data-vd-timepicker]");
9417
+ init: function(root) {
9418
+ const inputs = window.Vanduo.queryAll(root, "[data-vd-timepicker]");
8778
9419
  inputs.forEach((el) => {
8779
9420
  if (this.instances.has(el)) return;
8780
9421
  this.initInstance(el);
@@ -8888,8 +9529,8 @@ module.exports = __toCommonJS(index_exports);
8888
9529
  "use strict";
8889
9530
  const Stepper = {
8890
9531
  instances: /* @__PURE__ */ new Map(),
8891
- init: function() {
8892
- const steppers = document.querySelectorAll(".vd-stepper");
9532
+ init: function(root) {
9533
+ const steppers = window.Vanduo.queryAll(root, ".vd-stepper");
8893
9534
  steppers.forEach((el) => {
8894
9535
  if (this.instances.has(el)) return;
8895
9536
  this.initInstance(el);
@@ -8964,8 +9605,8 @@ module.exports = __toCommonJS(index_exports);
8964
9605
  "use strict";
8965
9606
  const Rating = {
8966
9607
  instances: /* @__PURE__ */ new Map(),
8967
- init: function() {
8968
- const ratings = document.querySelectorAll("[data-vd-rating]");
9608
+ init: function(root) {
9609
+ const ratings = window.Vanduo.queryAll(root, "[data-vd-rating]");
8969
9610
  ratings.forEach((el) => {
8970
9611
  if (this.instances.has(el)) return;
8971
9612
  this.initInstance(el);
@@ -9099,8 +9740,8 @@ module.exports = __toCommonJS(index_exports);
9099
9740
  "use strict";
9100
9741
  const Transfer = {
9101
9742
  instances: /* @__PURE__ */ new Map(),
9102
- init: function() {
9103
- const transfers = document.querySelectorAll("[data-vd-transfer]");
9743
+ init: function(root) {
9744
+ const transfers = window.Vanduo.queryAll(root, "[data-vd-transfer]");
9104
9745
  transfers.forEach((el) => {
9105
9746
  if (this.instances.has(el)) return;
9106
9747
  this.initInstance(el);
@@ -9263,8 +9904,8 @@ module.exports = __toCommonJS(index_exports);
9263
9904
  "use strict";
9264
9905
  const Tree = {
9265
9906
  instances: /* @__PURE__ */ new Map(),
9266
- init: function() {
9267
- const trees = document.querySelectorAll("[data-vd-tree]");
9907
+ init: function(root) {
9908
+ const trees = window.Vanduo.queryAll(root, "[data-vd-tree]");
9268
9909
  trees.forEach((el) => {
9269
9910
  if (this.instances.has(el)) return;
9270
9911
  this.initInstance(el);
@@ -9428,8 +10069,8 @@ module.exports = __toCommonJS(index_exports);
9428
10069
  _cleanup: [],
9429
10070
  _boundTriggers: /* @__PURE__ */ new WeakMap(),
9430
10071
  _triggerElement: null,
9431
- init: function() {
9432
- const triggers = document.querySelectorAll("[data-vd-spotlight]");
10072
+ init: function(root) {
10073
+ const triggers = window.Vanduo.queryAll(root, "[data-vd-spotlight]");
9433
10074
  triggers.forEach((trigger) => {
9434
10075
  if (this._boundTriggers.has(trigger)) return;
9435
10076
  const clickHandler = (event) => {
@@ -9702,8 +10343,8 @@ module.exports = __toCommonJS(index_exports);
9702
10343
  * Auto-initialize all .vd-music-player / [data-music-player] elements.
9703
10344
  * Options can be provided via data-music-player-options (JSON string).
9704
10345
  */
9705
- init: function() {
9706
- 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) => {
9707
10348
  if (this.instances.has(el)) return;
9708
10349
  let opts = {};
9709
10350
  const attr = el.getAttribute("data-music-player-options");