@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
@@ -31,12 +31,20 @@
31
31
  // Store cleanup functions for event listeners
32
32
  _cleanupFunctions: [],
33
33
 
34
+ getTriggers: function (root) {
35
+ if (window.Vanduo && typeof window.Vanduo.queryAll === 'function') {
36
+ return window.Vanduo.queryAll(root, '[data-image-box]');
37
+ }
38
+
39
+ return Array.from(document.querySelectorAll('[data-image-box]'));
40
+ },
41
+
34
42
  /**
35
43
  * Initialize Image Box component
36
44
  */
37
- init: function () {
45
+ init: function (root) {
38
46
  this.createBackdrop();
39
- this.bindTriggers();
47
+ this.bindTriggers(root);
40
48
  },
41
49
 
42
50
  /**
@@ -151,9 +159,9 @@
151
159
  /**
152
160
  * Bind triggers to all images with data-image-box attribute
153
161
  */
154
- bindTriggers: function () {
162
+ bindTriggers: function (root) {
155
163
  const self = this;
156
- const triggers = document.querySelectorAll('[data-image-box]');
164
+ const triggers = this.getTriggers(root);
157
165
 
158
166
  triggers.forEach(function (trigger) {
159
167
  // Skip if already initialized
@@ -181,6 +189,9 @@
181
189
  trigger.classList.remove('is-broken');
182
190
  };
183
191
  trigger.addEventListener('load', loadHandler);
192
+
193
+ trigger._imageBoxErrorHandler = errorHandler;
194
+ trigger._imageBoxLoadHandler = loadHandler;
184
195
  }
185
196
 
186
197
  // Bind click event
@@ -213,6 +224,19 @@
213
224
  trigger.removeEventListener('keydown', keyHandler);
214
225
  };
215
226
  }
227
+
228
+ const originalCleanup = trigger._imageBoxCleanup;
229
+ trigger._imageBoxCleanup = () => {
230
+ originalCleanup();
231
+ if (trigger._imageBoxErrorHandler) {
232
+ trigger.removeEventListener('error', trigger._imageBoxErrorHandler);
233
+ delete trigger._imageBoxErrorHandler;
234
+ }
235
+ if (trigger._imageBoxLoadHandler) {
236
+ trigger.removeEventListener('load', trigger._imageBoxLoadHandler);
237
+ delete trigger._imageBoxLoadHandler;
238
+ }
239
+ };
216
240
  });
217
241
  },
218
242
 
@@ -320,14 +344,27 @@
320
344
  /**
321
345
  * Reinitialize - useful after dynamic DOM changes
322
346
  */
323
- reinit: function () {
324
- this.bindTriggers();
347
+ reinit: function (root) {
348
+ this.bindTriggers(root);
325
349
  },
326
350
 
327
351
  /**
328
352
  * Destroy component and clean up
329
353
  */
330
- destroy: function () {
354
+ destroy: function (root) {
355
+ if (root && root !== document) {
356
+ const triggersInRoot = this.getTriggers(root);
357
+ triggersInRoot.forEach(trigger => {
358
+ trigger.classList.remove('vd-image-box-trigger');
359
+ if (trigger._imageBoxCleanup) {
360
+ trigger._imageBoxCleanup();
361
+ delete trigger._imageBoxCleanup;
362
+ }
363
+ delete trigger.dataset.imageBoxInitialized;
364
+ });
365
+ return;
366
+ }
367
+
331
368
  // Close if open
332
369
  if (this.isOpen) {
333
370
  this.close();
@@ -343,7 +380,9 @@
343
380
  this._cleanupFunctions = [];
344
381
 
345
382
  // Remove trigger bindings
346
- const triggers = document.querySelectorAll('[data-image-box-initialized]');
383
+ const triggers = window.Vanduo && typeof window.Vanduo.queryAll === 'function'
384
+ ? window.Vanduo.queryAll(root, '[data-image-box-initialized]')
385
+ : document.querySelectorAll('[data-image-box-initialized]');
347
386
  triggers.forEach(trigger => {
348
387
  trigger.classList.remove('vd-image-box-trigger');
349
388
  if (trigger._imageBoxCleanup) {
@@ -362,8 +401,8 @@
362
401
  this.isOpen = false;
363
402
  },
364
403
 
365
- destroyAll: function () {
366
- this.destroy();
404
+ destroyAll: function (root) {
405
+ this.destroy(root);
367
406
  }
368
407
  };
369
408
 
@@ -32,6 +32,42 @@
32
32
  /** @type {Map<Element, IntersectionObserver>} */
33
33
  const _observerMap = new Map();
34
34
 
35
+ function _isRoot(root) {
36
+ return !!root && (root === document || root.nodeType === 1 || root.nodeType === 9 || root.nodeType === 11);
37
+ }
38
+
39
+ function _normalizeRoot(root) {
40
+ return _isRoot(root) ? root : document;
41
+ }
42
+
43
+ function _isInRoot(root, element) {
44
+ const scope = _normalizeRoot(root);
45
+ if (!(element instanceof Element)) return false;
46
+ if (scope === document) {
47
+ return document.documentElement ? document.documentElement.contains(element) : document.contains(element);
48
+ }
49
+ if (scope === element) return true;
50
+ return typeof scope.contains === 'function' && scope.contains(element);
51
+ }
52
+
53
+ function _queryAll(root, selector) {
54
+ const scope = _normalizeRoot(root);
55
+ const matches = [];
56
+
57
+ if (scope instanceof Element && typeof scope.matches === 'function' && scope.matches(selector)) {
58
+ matches.push(scope);
59
+ }
60
+
61
+ if (typeof scope.querySelectorAll === 'function') {
62
+ const descendants = scope.querySelectorAll(selector);
63
+ for (let i = 0; i < descendants.length; i++) {
64
+ matches.push(descendants[i]);
65
+ }
66
+ }
67
+
68
+ return matches;
69
+ }
70
+
35
71
  /* ── Security helpers ─────────────────────────────── */
36
72
 
37
73
  /**
@@ -183,6 +219,9 @@
183
219
  if (entry.isIntersecting) {
184
220
  obs.unobserve(entry.target);
185
221
  _observerMap.delete(entry.target);
222
+ if (typeof window.VanduoLifecycle !== 'undefined' && window.VanduoLifecycle.has(entry.target, 'lazyLoad')) {
223
+ window.VanduoLifecycle.unregister(entry.target, 'lazyLoad');
224
+ }
186
225
  try {
187
226
  callback(entry.target);
188
227
  } catch (e) {
@@ -193,6 +232,11 @@
193
232
  }, { threshold: threshold, rootMargin: rootMargin });
194
233
 
195
234
  _observerMap.set(element, observer);
235
+ if (typeof window.VanduoLifecycle !== 'undefined' && !window.VanduoLifecycle.has(element, 'lazyLoad')) {
236
+ window.VanduoLifecycle.register(element, 'lazyLoad', [() => {
237
+ VanduoLazyLoad.unobserve(element, { skipLifecycle: true });
238
+ }]);
239
+ }
196
240
  observer.observe(element);
197
241
  },
198
242
 
@@ -200,22 +244,30 @@
200
244
  * Stop observing an element that was previously passed to observe().
201
245
  * @param {Element} element
202
246
  */
203
- unobserve: function (element) {
247
+ unobserve: function (element, options) {
248
+ const opts = options || {};
204
249
  const observer = _observerMap.get(element);
205
250
  if (observer) {
206
251
  observer.unobserve(element);
252
+ if (typeof observer.disconnect === 'function') {
253
+ observer.disconnect();
254
+ }
207
255
  _observerMap.delete(element);
208
256
  }
257
+
258
+ if (!opts.skipLifecycle && typeof window.VanduoLifecycle !== 'undefined' && window.VanduoLifecycle.has(element, 'lazyLoad')) {
259
+ window.VanduoLifecycle.unregister(element, 'lazyLoad');
260
+ }
209
261
  },
210
262
 
211
263
  /**
212
264
  * Stop observing ALL currently observed elements.
213
265
  */
214
266
  unobserveAll: function () {
215
- _observerMap.forEach(function (observer, element) {
216
- observer.unobserve(element);
267
+ const observed = Array.from(_observerMap.keys());
268
+ observed.forEach(function (element) {
269
+ VanduoLazyLoad.unobserve(element);
217
270
  });
218
- _observerMap.clear();
219
271
  },
220
272
 
221
273
  /* ─────────────────────────────────────────────────
@@ -275,9 +327,9 @@
275
327
  // raw innerHTML assignment of externally-sourced strings
276
328
  _safeInjectHtml(containerEl, html);
277
329
  _dispatch(containerEl, 'lazysection:loaded', { url: url });
278
- // Re-init Vanduo components inside the new content
330
+ // Re-init Vanduo components only inside the injected subtree
279
331
  if (typeof window.Vanduo !== 'undefined') {
280
- window.Vanduo.init();
332
+ window.Vanduo.init(containerEl);
281
333
  }
282
334
  if (typeof opts.onLoaded === 'function') {
283
335
  opts.onLoaded(containerEl);
@@ -316,9 +368,9 @@
316
368
  * Scan the DOM for [data-vd-lazy] elements and wire them up.
317
369
  * Safe to call multiple times — already-observed elements are skipped.
318
370
  */
319
- init: function () {
371
+ init: function (root) {
320
372
  const self = this;
321
- const elements = document.querySelectorAll('[data-vd-lazy]');
373
+ const elements = _queryAll(root, '[data-vd-lazy]');
322
374
  elements.forEach(function (el) {
323
375
  // Skip already-observed or already-loaded elements
324
376
  if (_observerMap.has(el) || el.dataset.vdLazyState === 'loading' || el.dataset.vdLazyState === 'loaded') return;
@@ -339,12 +391,32 @@
339
391
  }
340
392
  });
341
393
  });
394
+ },
395
+
396
+ destroy: function (element) {
397
+ this.unobserve(element);
398
+ },
399
+
400
+ destroyAll: function (root) {
401
+ const scope = _normalizeRoot(root);
402
+
403
+ if (scope === document) {
404
+ this.unobserveAll();
405
+ return;
406
+ }
407
+
408
+ const observed = Array.from(_observerMap.keys());
409
+ observed.forEach((element) => {
410
+ if (_isInRoot(scope, element)) {
411
+ this.unobserve(element);
412
+ }
413
+ });
342
414
  }
343
415
  };
344
416
 
345
417
  /* ── Register with Vanduo ─────────────────────────── */
346
418
  if (typeof window.Vanduo !== 'undefined') {
347
- window.Vanduo.register('LazyLoad', VanduoLazyLoad);
419
+ window.Vanduo.register('lazyLoad', VanduoLazyLoad, { aliases: ['LazyLoad'] });
348
420
  }
349
421
 
350
422
  /* ── Global convenience alias ─────────────────────── */
@@ -13,6 +13,7 @@
13
13
  modals: new Map(),
14
14
  openModals: [],
15
15
  zIndexCounter: 1050,
16
+ __vanduoScopedDestroyAll: true,
16
17
 
17
18
  // Store trigger cleanup functions
18
19
  _triggerCleanups: [],
@@ -79,8 +80,8 @@
79
80
  /**
80
81
  * Initialize modals
81
82
  */
82
- init: function () {
83
- const modals = document.querySelectorAll('.vd-modal');
83
+ init: function (root) {
84
+ const modals = window.Vanduo.queryAll(root, '.vd-modal');
84
85
 
85
86
  modals.forEach(modal => {
86
87
  if (this.modals.has(modal)) {
@@ -90,7 +91,9 @@
90
91
  });
91
92
 
92
93
  // Handle data-modal triggers
93
- const triggers = document.querySelectorAll('[data-modal]');
94
+ const triggers = window.Vanduo && typeof window.Vanduo.queryAll === 'function'
95
+ ? window.Vanduo.queryAll(root, '[data-modal]')
96
+ : document.querySelectorAll('[data-modal]');
94
97
  triggers.forEach(trigger => {
95
98
  if (trigger.dataset.modalTriggerInitialized) return;
96
99
  trigger.dataset.modalTriggerInitialized = 'true';
@@ -104,7 +107,7 @@
104
107
  }
105
108
  };
106
109
  trigger.addEventListener('click', triggerClickHandler);
107
- this._triggerCleanups.push(() => trigger.removeEventListener('click', triggerClickHandler));
110
+ trigger._modalTriggerCleanup = () => trigger.removeEventListener('click', triggerClickHandler);
108
111
  });
109
112
  },
110
113
 
@@ -421,15 +424,29 @@
421
424
  /**
422
425
  * Destroy all modal instances
423
426
  */
424
- destroyAll: function () {
427
+ destroyAll: function (root) {
428
+ const scope = window.Vanduo && typeof window.Vanduo._normalizeRoot === 'function'
429
+ ? window.Vanduo._normalizeRoot(root)
430
+ : (root || document);
431
+
425
432
  this.modals.forEach((data, modal) => {
426
- this.destroy(modal);
433
+ if (scope === document || scope === modal || (typeof scope.contains === 'function' && scope.contains(modal))) {
434
+ this.destroy(modal);
435
+ }
436
+ });
437
+
438
+ const triggers = window.Vanduo && typeof window.Vanduo.queryAll === 'function'
439
+ ? window.Vanduo.queryAll(scope, '[data-modal][data-modal-trigger-initialized]')
440
+ : document.querySelectorAll('[data-modal][data-modal-trigger-initialized]');
441
+ triggers.forEach(trigger => {
442
+ if (trigger._modalTriggerCleanup) {
443
+ trigger._modalTriggerCleanup();
444
+ delete trigger._modalTriggerCleanup;
445
+ }
446
+ delete trigger.dataset.modalTriggerInitialized;
427
447
  });
428
- // Clean up trigger listeners
429
- this._triggerCleanups.forEach(fn => fn());
430
- this._triggerCleanups = [];
431
- // Remove shared ESC handler
432
- if (this._sharedEscHandler) {
448
+
449
+ if (scope === document && this._sharedEscHandler) {
433
450
  document.removeEventListener('keydown', this._sharedEscHandler);
434
451
  this._sharedEscHandler = null;
435
452
  }
@@ -445,4 +462,3 @@
445
462
  window.VanduoModals = Modals;
446
463
 
447
464
  })();
448
-
@@ -21,8 +21,8 @@
21
21
  const Morph = {
22
22
  instances: new Map(),
23
23
 
24
- init: function () {
25
- const elements = document.querySelectorAll('.vd-morph, [data-vd-morph]');
24
+ init: function (root) {
25
+ const elements = window.Vanduo.queryAll(root, '.vd-morph, [data-vd-morph]');
26
26
  elements.forEach(function (el) {
27
27
  if (Morph.instances.has(el)) return;
28
28
  if (el.getAttribute('data-vd-morph') === 'manual') return;
@@ -155,8 +155,8 @@
155
155
  * Auto-initialize all .vd-music-player / [data-music-player] elements.
156
156
  * Options can be provided via data-music-player-options (JSON string).
157
157
  */
158
- init: function () {
159
- document.querySelectorAll('.vd-music-player, [data-music-player]').forEach((el) => {
158
+ init: function (root) {
159
+ window.Vanduo.queryAll(root, '.vd-music-player, [data-music-player]').forEach((el) => {
160
160
  if (this.instances.has(el)) return;
161
161
 
162
162
  let opts = {};
@@ -29,8 +29,8 @@
29
29
  /**
30
30
  * Initialize navbar component
31
31
  */
32
- init: function () {
33
- const navbars = document.querySelectorAll('.vd-navbar');
32
+ init: function (root) {
33
+ const navbars = window.Vanduo.queryAll(root, '.vd-navbar');
34
34
 
35
35
  navbars.forEach(navbar => {
36
36
  // Skip if already initialized
@@ -16,8 +16,8 @@
16
16
  /**
17
17
  * Initialize pagination components
18
18
  */
19
- init: function() {
20
- const paginations = document.querySelectorAll('.vd-pagination[data-pagination]');
19
+ init: function(root) {
20
+ const paginations = window.Vanduo.queryAll(root, '.vd-pagination[data-pagination]');
21
21
 
22
22
  paginations.forEach(pagination => {
23
23
  if (this.instances.has(pagination)) {
@@ -283,4 +283,3 @@
283
283
  window.VanduoPagination = Pagination;
284
284
 
285
285
  })();
286
-
@@ -21,20 +21,13 @@
21
21
  /**
22
22
  * Initialize parallax components
23
23
  */
24
- init: function () {
25
- if (this.isInitialized) {
26
- this.refresh();
27
- return;
28
- }
29
-
30
- this.isInitialized = true;
31
-
24
+ init: function (root) {
32
25
  // Check for reduced motion preference
33
26
  if (this.reducedMotion) {
34
27
  return; // Don't initialize if user prefers reduced motion
35
28
  }
36
29
 
37
- const parallaxElements = document.querySelectorAll('.vd-parallax');
30
+ const parallaxElements = window.Vanduo.queryAll(root, '.vd-parallax');
38
31
 
39
32
  parallaxElements.forEach(element => {
40
33
  if (!element.dataset.parallaxInitialized) {
@@ -42,6 +35,13 @@
42
35
  }
43
36
  });
44
37
 
38
+ if (this.isInitialized) {
39
+ this.refresh();
40
+ return;
41
+ }
42
+
43
+ this.isInitialized = true;
44
+
45
45
  // Handle scroll
46
46
  this.handleScroll();
47
47
  this._onScroll = () => {
@@ -213,4 +213,3 @@
213
213
  window.VanduoParallax = Parallax;
214
214
 
215
215
  })();
216
-
@@ -10,11 +10,19 @@
10
10
  * Preloader Component
11
11
  */
12
12
  const Preloader = {
13
+ getProgressBars: function(root) {
14
+ if (window.Vanduo && typeof window.Vanduo.queryAll === 'function') {
15
+ return window.Vanduo.queryAll(root, '.vd-progress-bar[data-progress], .progress-bar[data-progress]');
16
+ }
17
+
18
+ return Array.from(document.querySelectorAll('.vd-progress-bar[data-progress], .progress-bar[data-progress]'));
19
+ },
20
+
13
21
  /**
14
22
  * Initialize preloader components
15
23
  */
16
- init: function() {
17
- const progressBars = document.querySelectorAll('.vd-progress-bar[data-progress], .progress-bar[data-progress]');
24
+ init: function(root) {
25
+ const progressBars = this.getProgressBars(root);
18
26
 
19
27
  progressBars.forEach(bar => {
20
28
  if (!bar.dataset.progressInitialized) {
@@ -163,8 +171,10 @@
163
171
  /**
164
172
  * Destroy all progress bar instances
165
173
  */
166
- destroyAll: function() {
167
- const progressBars = document.querySelectorAll('.vd-progress-bar[data-progress-initialized="true"], .progress-bar[data-progress-initialized="true"]');
174
+ destroyAll: function(root) {
175
+ const progressBars = this.getProgressBars(root || document).filter(function(bar) {
176
+ return bar.dataset.progressInitialized === 'true';
177
+ });
168
178
  progressBars.forEach(bar => {
169
179
  delete bar.dataset.progressInitialized;
170
180
  });
@@ -180,4 +190,3 @@
180
190
  window.VanduoPreloader = Preloader;
181
191
 
182
192
  })();
183
-
@@ -9,8 +9,8 @@
9
9
  const Rating = {
10
10
  instances: new Map(),
11
11
 
12
- init: function () {
13
- const ratings = document.querySelectorAll('[data-vd-rating]');
12
+ init: function (root) {
13
+ const ratings = window.Vanduo.queryAll(root, '[data-vd-rating]');
14
14
  ratings.forEach(el => {
15
15
  if (this.instances.has(el)) return;
16
16
  this.initInstance(el);
@@ -9,8 +9,8 @@
9
9
  const Ripple = {
10
10
  instances: new Map(),
11
11
 
12
- init: function () {
13
- const elements = document.querySelectorAll('.vd-ripple, [data-vd-ripple]');
12
+ init: function (root) {
13
+ const elements = window.Vanduo.queryAll(root, '.vd-ripple, [data-vd-ripple]');
14
14
  elements.forEach(el => {
15
15
  if (this.instances.has(el)) return;
16
16
  this.initInstance(el);
@@ -16,8 +16,8 @@
16
16
  /**
17
17
  * Initialize select components
18
18
  */
19
- init: function () {
20
- const selects = document.querySelectorAll('select.vd-custom-select-input, select[data-custom-select]');
19
+ init: function (root) {
20
+ const selects = window.Vanduo.queryAll(root, 'select.vd-custom-select-input, select[data-custom-select]');
21
21
 
22
22
  selects.forEach(select => {
23
23
  if (this.instances.has(select)) {
@@ -443,4 +443,3 @@
443
443
  }
444
444
 
445
445
  })();
446
-
@@ -13,9 +13,11 @@
13
13
  sidenavs: new Map(),
14
14
  breakpoint: 992, // Desktop breakpoint
15
15
  restoreDelayMs: 450,
16
+ __vanduoScopedDestroyAll: true,
16
17
 
17
18
  // Global cleanup functions (toggles, resize)
18
19
  _globalCleanups: [],
20
+ _resizeCleanup: null,
19
21
 
20
22
  isFixedVariant: function(sidenav) {
21
23
  return sidenav.classList.contains('vd-sidenav-fixed') || sidenav.classList.contains('sidenav-fixed');
@@ -140,8 +142,8 @@
140
142
  /**
141
143
  * Initialize sidenav components
142
144
  */
143
- init: function() {
144
- const sidenavs = document.querySelectorAll('.vd-sidenav, .vd-offcanvas');
145
+ init: function(root) {
146
+ const sidenavs = window.Vanduo.queryAll(root, '.vd-sidenav, .vd-offcanvas');
145
147
 
146
148
  sidenavs.forEach(sidenav => {
147
149
  if (this.sidenavs.has(sidenav)) {
@@ -151,7 +153,9 @@
151
153
  });
152
154
 
153
155
  // Handle toggle buttons
154
- const toggles = document.querySelectorAll('[data-sidenav-toggle]');
156
+ const toggles = window.Vanduo && typeof window.Vanduo.queryAll === 'function'
157
+ ? window.Vanduo.queryAll(root, '[data-sidenav-toggle]')
158
+ : document.querySelectorAll('[data-sidenav-toggle]');
155
159
  toggles.forEach(toggle => {
156
160
  if (toggle.dataset.sidenavToggleInitialized) return;
157
161
  toggle.dataset.sidenavToggleInitialized = 'true';
@@ -165,16 +169,18 @@
165
169
  }
166
170
  };
167
171
  toggle.addEventListener('click', toggleClickHandler);
168
- this._globalCleanups.push(() => toggle.removeEventListener('click', toggleClickHandler));
172
+ toggle._sidenavToggleCleanup = () => toggle.removeEventListener('click', toggleClickHandler);
169
173
  });
170
174
 
171
175
  // Handle responsive behavior
172
176
  this.handleResize();
173
- const resizeHandler = () => {
174
- this.handleResize();
175
- };
176
- window.addEventListener('resize', resizeHandler);
177
- this._globalCleanups.push(() => window.removeEventListener('resize', resizeHandler));
177
+ if (!this._resizeCleanup) {
178
+ const resizeHandler = () => {
179
+ this.handleResize();
180
+ };
181
+ window.addEventListener('resize', resizeHandler);
182
+ this._resizeCleanup = () => window.removeEventListener('resize', resizeHandler);
183
+ }
178
184
  },
179
185
 
180
186
  /**
@@ -406,12 +412,36 @@
406
412
  /**
407
413
  * Destroy all sidenav instances
408
414
  */
409
- destroyAll: function() {
415
+ destroyAll: function(root) {
416
+ const scope = window.Vanduo && typeof window.Vanduo._normalizeRoot === 'function'
417
+ ? window.Vanduo._normalizeRoot(root)
418
+ : (root || document);
419
+
410
420
  this.sidenavs.forEach((data, sidenav) => {
411
- this.destroy(sidenav);
421
+ if (scope === document || scope === sidenav || (typeof scope.contains === 'function' && scope.contains(sidenav))) {
422
+ this.destroy(sidenav);
423
+ }
412
424
  });
413
- this._globalCleanups.forEach(fn => fn());
414
- this._globalCleanups = [];
425
+
426
+ const toggles = window.Vanduo && typeof window.Vanduo.queryAll === 'function'
427
+ ? window.Vanduo.queryAll(scope, '[data-sidenav-toggle][data-sidenav-toggle-initialized]')
428
+ : document.querySelectorAll('[data-sidenav-toggle][data-sidenav-toggle-initialized]');
429
+ toggles.forEach(toggle => {
430
+ if (toggle._sidenavToggleCleanup) {
431
+ toggle._sidenavToggleCleanup();
432
+ delete toggle._sidenavToggleCleanup;
433
+ }
434
+ delete toggle.dataset.sidenavToggleInitialized;
435
+ });
436
+
437
+ if (scope === document) {
438
+ if (this._resizeCleanup) {
439
+ this._resizeCleanup();
440
+ this._resizeCleanup = null;
441
+ }
442
+ this._globalCleanups.forEach(fn => fn());
443
+ this._globalCleanups = [];
444
+ }
415
445
  }
416
446
  };
417
447
 
@@ -424,4 +454,3 @@
424
454
  window.VanduoSidenav = Sidenav;
425
455
 
426
456
  })();
427
-
@@ -15,8 +15,8 @@
15
15
  _boundTriggers: new WeakMap(),
16
16
  _triggerElement: null,
17
17
 
18
- init: function () {
19
- const triggers = document.querySelectorAll('[data-vd-spotlight]');
18
+ init: function (root) {
19
+ const triggers = window.Vanduo.queryAll(root, '[data-vd-spotlight]');
20
20
 
21
21
  triggers.forEach(trigger => {
22
22
  if (this._boundTriggers.has(trigger)) return;
@@ -9,8 +9,8 @@
9
9
  const Stepper = {
10
10
  instances: new Map(),
11
11
 
12
- init: function () {
13
- const steppers = document.querySelectorAll('.vd-stepper');
12
+ init: function (root) {
13
+ const steppers = window.Vanduo.queryAll(root, '.vd-stepper');
14
14
  steppers.forEach(el => {
15
15
  if (this.instances.has(el)) return;
16
16
  this.initInstance(el);