@vanduo-oss/framework 1.3.9 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -42
- package/css/components/affix.css +1 -1
- package/css/components/alerts.css +40 -40
- package/css/components/avatar.css +33 -33
- package/css/components/badges.css +42 -42
- package/css/components/breadcrumbs.css +5 -5
- package/css/components/bubble.css +4 -4
- package/css/components/buttons.css +124 -124
- package/css/components/cards.css +10 -10
- package/css/components/chips.css +28 -28
- package/css/components/code-snippet.css +18 -18
- package/css/components/collapsible.css +20 -20
- package/css/components/collections.css +21 -21
- package/css/components/datepicker.css +13 -13
- package/css/components/doc-search.css +46 -53
- package/css/components/doc-tabs.css +10 -10
- package/css/components/draggable.css +34 -34
- package/css/components/dropdown.css +14 -14
- package/css/components/expanding-cards.css +1 -1
- package/css/components/fab.css +7 -7
- package/css/components/flow.css +3 -3
- package/css/components/footer.css +26 -26
- package/css/components/forms.css +95 -83
- package/css/components/image-box.css +13 -17
- package/css/components/modals.css +8 -8
- package/css/components/music-player.css +26 -26
- package/css/components/navbar.css +27 -27
- package/css/components/pagination.css +15 -15
- package/css/components/preloader.css +10 -10
- package/css/components/progress.css +8 -8
- package/css/components/rating.css +4 -4
- package/css/components/sidenav.css +14 -14
- package/css/components/skeleton.css +10 -9
- package/css/components/spinner.css +10 -10
- package/css/components/spotlight.css +7 -7
- package/css/components/stepper.css +13 -13
- package/css/components/suggest.css +10 -10
- package/css/components/tabs.css +22 -22
- package/css/components/theme-customizer.css +87 -87
- package/css/components/timeline.css +14 -14
- package/css/components/timepicker.css +7 -7
- package/css/components/toast.css +31 -31
- package/css/components/tooltips.css +11 -11
- package/css/components/transfer.css +12 -12
- package/css/components/tree.css +9 -9
- package/css/components/waypoint.css +3 -3
- package/css/core/colors.css +34 -34
- package/css/core/grid.css +1 -6
- package/css/core/helpers.css +11 -11
- package/css/core/tokens.css +113 -35
- package/css/core/typography.css +14 -12
- package/css/core/vd-aliases.css +100 -52
- package/css/effects/morph.css +5 -5
- package/css/utilities/media.css +2 -2
- package/css/utilities/table.css +34 -34
- package/css/utilities/transitions.css +22 -10
- package/css/vanduo.css +14 -34
- package/dist/build-info.json +3 -3
- package/dist/vanduo.cjs.js +929 -289
- package/dist/vanduo.cjs.js.map +3 -3
- package/dist/vanduo.cjs.min.js +7 -7
- package/dist/vanduo.cjs.min.js.map +3 -3
- package/dist/vanduo.css +7914 -7823
- package/dist/vanduo.css.map +1 -1
- package/dist/vanduo.esm.js +929 -289
- package/dist/vanduo.esm.js.map +3 -3
- package/dist/vanduo.esm.min.js +7 -7
- package/dist/vanduo.esm.min.js.map +3 -3
- package/dist/vanduo.js +929 -289
- package/dist/vanduo.js.map +3 -3
- package/dist/vanduo.min.css +2 -2
- package/dist/vanduo.min.css.map +1 -1
- package/dist/vanduo.min.js +7 -7
- package/dist/vanduo.min.js.map +3 -3
- package/js/components/affix.js +2 -2
- package/js/components/bubble.js +3 -3
- package/js/components/code-snippet.js +129 -5
- package/js/components/collapsible.js +2 -3
- package/js/components/datepicker.js +2 -2
- package/js/components/doc-search.js +69 -11
- package/js/components/draggable.js +4 -4
- package/js/components/dropdown.js +2 -3
- package/js/components/expanding-cards.js +2 -2
- package/js/components/flow.js +2 -2
- package/js/components/font-switcher.js +23 -13
- package/js/components/glass.js +2 -2
- package/js/components/grid.js +19 -8
- package/js/components/image-box.js +49 -10
- package/js/components/lazy-load.js +81 -9
- package/js/components/modals.js +28 -12
- package/js/components/morph.js +2 -2
- package/js/components/music-player.js +2 -2
- package/js/components/navbar.js +2 -2
- package/js/components/pagination.js +2 -3
- package/js/components/parallax.js +9 -10
- package/js/components/preloader.js +14 -5
- package/js/components/rating.js +2 -2
- package/js/components/ripple.js +2 -2
- package/js/components/select.js +2 -3
- package/js/components/sidenav.js +43 -14
- package/js/components/spotlight.js +2 -2
- package/js/components/stepper.js +2 -2
- package/js/components/suggest.js +9 -3
- package/js/components/tabs.js +2 -2
- package/js/components/theme-customizer.js +151 -21
- package/js/components/theme-switcher.js +27 -16
- package/js/components/timeline.js +41 -12
- package/js/components/timepicker.js +2 -2
- package/js/components/toast.js +1 -1
- package/js/components/tooltips.js +4 -4
- package/js/components/transfer.js +2 -2
- package/js/components/tree.js +2 -2
- package/js/components/validate.js +2 -2
- package/js/components/vd-hex.js +12 -6
- package/js/components/waypoint.js +2 -2
- package/js/utils/helpers.js +7 -4
- package/js/utils/lifecycle.js +158 -83
- package/js/vanduo.js +203 -34
- package/package.json +2 -1
package/js/components/suggest.js
CHANGED
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
const Suggest = {
|
|
37
37
|
instances: new Map(),
|
|
38
38
|
|
|
39
|
-
init: function () {
|
|
40
|
-
const inputs =
|
|
39
|
+
init: function (root) {
|
|
40
|
+
const inputs = window.Vanduo.queryAll(root, '[data-vd-suggest], [data-vd-autocomplete]');
|
|
41
41
|
inputs.forEach(el => {
|
|
42
42
|
if (this.instances.has(el)) return;
|
|
43
43
|
this.initInstance(el);
|
|
@@ -220,16 +220,22 @@
|
|
|
220
220
|
const blurHandler = () => {
|
|
221
221
|
setTimeout(close, 200);
|
|
222
222
|
};
|
|
223
|
+
const focusHandler = () => {
|
|
224
|
+
if (input.value.length >= minChars) {
|
|
225
|
+
doSearch(input.value);
|
|
226
|
+
}
|
|
227
|
+
};
|
|
223
228
|
|
|
224
229
|
input.addEventListener('input', inputHandler);
|
|
225
230
|
input.addEventListener('keydown', keyHandler);
|
|
226
231
|
input.addEventListener('blur', blurHandler);
|
|
227
|
-
input.addEventListener('focus',
|
|
232
|
+
input.addEventListener('focus', focusHandler);
|
|
228
233
|
|
|
229
234
|
cleanup.push(
|
|
230
235
|
() => input.removeEventListener('input', inputHandler),
|
|
231
236
|
() => input.removeEventListener('keydown', keyHandler),
|
|
232
237
|
() => input.removeEventListener('blur', blurHandler),
|
|
238
|
+
() => input.removeEventListener('focus', focusHandler),
|
|
233
239
|
() => clearTimeout(debounceTimer),
|
|
234
240
|
() => { if (list.parentNode) list.parentNode.removeChild(list); }
|
|
235
241
|
);
|
package/js/components/tabs.js
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
/**
|
|
17
17
|
* Initialize all tab components
|
|
18
18
|
*/
|
|
19
|
-
init: function() {
|
|
20
|
-
const tabContainers =
|
|
19
|
+
init: function(root) {
|
|
20
|
+
const tabContainers = window.Vanduo.queryAll(root, '.vd-tabs, [data-tabs]');
|
|
21
21
|
|
|
22
22
|
tabContainers.forEach(container => {
|
|
23
23
|
if (this.instances.has(container)) {
|
|
@@ -86,23 +86,77 @@
|
|
|
86
86
|
|
|
87
87
|
isInitialized: false,
|
|
88
88
|
_cleanup: [],
|
|
89
|
+
_ownsDynamicPanel: false,
|
|
89
90
|
|
|
90
91
|
// DOM references
|
|
91
92
|
elements: {
|
|
92
93
|
customizer: null,
|
|
93
94
|
trigger: null,
|
|
95
|
+
activeTrigger: null,
|
|
94
96
|
triggers: [],
|
|
95
97
|
panel: null,
|
|
96
98
|
overlay: null
|
|
97
99
|
},
|
|
98
100
|
|
|
101
|
+
isRoot: function (root) {
|
|
102
|
+
return !!root && (root === document || root.nodeType === 1 || root.nodeType === 9 || root.nodeType === 11);
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
normalizeRoot: function (root) {
|
|
106
|
+
return this.isRoot(root) ? root : document;
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
queryAll: function (root, selector) {
|
|
110
|
+
const scope = this.normalizeRoot(root);
|
|
111
|
+
if (typeof window.VanduoLifecycle !== 'undefined' && typeof window.VanduoLifecycle.queryAll === 'function') {
|
|
112
|
+
return window.VanduoLifecycle.queryAll(scope, selector);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const matches = [];
|
|
116
|
+
if (scope instanceof Element && typeof scope.matches === 'function' && scope.matches(selector)) {
|
|
117
|
+
matches.push(scope);
|
|
118
|
+
}
|
|
119
|
+
if (typeof scope.querySelectorAll === 'function') {
|
|
120
|
+
const descendants = scope.querySelectorAll(selector);
|
|
121
|
+
for (let i = 0; i < descendants.length; i++) {
|
|
122
|
+
matches.push(descendants[i]);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return matches;
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
queryOne: function (root, selector) {
|
|
129
|
+
const matches = this.queryAll(root, selector);
|
|
130
|
+
return matches.length ? matches[0] : null;
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
getTriggers: function (root) {
|
|
134
|
+
return this.queryAll(root, '[data-theme-customizer-trigger]');
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
pruneTriggers: function () {
|
|
138
|
+
this.elements.triggers = this.elements.triggers.filter(function (trigger) {
|
|
139
|
+
return trigger && trigger.isConnected;
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
if (this.elements.trigger && !this.elements.trigger.isConnected) {
|
|
143
|
+
this.elements.trigger = null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (this.elements.activeTrigger && !this.elements.activeTrigger.isConnected) {
|
|
147
|
+
this.elements.activeTrigger = null;
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
|
|
99
151
|
/**
|
|
100
152
|
* Initialize the Theme Customizer
|
|
101
153
|
*/
|
|
102
|
-
init: function () {
|
|
154
|
+
init: function (root) {
|
|
155
|
+
const scope = this.normalizeRoot(root);
|
|
156
|
+
|
|
103
157
|
if (this.isInitialized) {
|
|
104
|
-
this.bindExistingElements();
|
|
105
|
-
this.bindTriggerEvents();
|
|
158
|
+
this.bindExistingElements(scope);
|
|
159
|
+
this.bindTriggerEvents(scope);
|
|
106
160
|
this.bindPanelEvents();
|
|
107
161
|
this.updateUI();
|
|
108
162
|
return;
|
|
@@ -113,10 +167,8 @@
|
|
|
113
167
|
|
|
114
168
|
this.loadPreferences();
|
|
115
169
|
this.applyAllPreferences();
|
|
116
|
-
this.bindExistingElements();
|
|
117
|
-
this.bindEvents();
|
|
118
|
-
|
|
119
|
-
console.log('Vanduo Theme Customizer initialized');
|
|
170
|
+
this.bindExistingElements(scope);
|
|
171
|
+
this.bindEvents(scope);
|
|
120
172
|
},
|
|
121
173
|
|
|
122
174
|
addListener: function (target, event, handler, options) {
|
|
@@ -315,21 +367,33 @@
|
|
|
315
367
|
/**
|
|
316
368
|
* Bind to existing DOM elements or create them dynamically
|
|
317
369
|
*/
|
|
318
|
-
bindExistingElements: function () {
|
|
319
|
-
|
|
320
|
-
this.
|
|
321
|
-
|
|
370
|
+
bindExistingElements: function (root) {
|
|
371
|
+
const scope = this.normalizeRoot(root);
|
|
372
|
+
this.pruneTriggers();
|
|
373
|
+
|
|
374
|
+
const scopedTriggers = this.getTriggers(scope);
|
|
375
|
+
scopedTriggers.forEach((trigger) => {
|
|
376
|
+
if (!this.elements.triggers.includes(trigger)) {
|
|
377
|
+
this.elements.triggers.push(trigger);
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
|
|
322
381
|
if (!this.elements.trigger && this.elements.triggers.length) {
|
|
323
382
|
this.elements.trigger = this.elements.triggers[0];
|
|
324
383
|
}
|
|
325
384
|
|
|
326
|
-
|
|
385
|
+
const existingCustomizer = this.queryOne(scope, '.vd-theme-customizer')
|
|
386
|
+
|| (this.elements.customizer && typeof this.elements.customizer.contains === 'function' ? this.elements.customizer : null)
|
|
387
|
+
|| document.querySelector('.vd-theme-customizer');
|
|
388
|
+
|
|
389
|
+
if (existingCustomizer instanceof Element) {
|
|
390
|
+
this.elements.customizer = existingCustomizer;
|
|
327
391
|
this.elements.trigger = this.elements.customizer.querySelector('.vd-theme-customizer-trigger') || this.elements.trigger;
|
|
328
392
|
this.elements.panel = this.elements.customizer.querySelector('.vd-theme-customizer-panel');
|
|
329
393
|
this.elements.overlay = this.elements.customizer.querySelector('.vd-theme-customizer-overlay');
|
|
330
394
|
} else {
|
|
331
395
|
// Look for standalone trigger buttons with data attribute
|
|
332
|
-
if (this.elements.
|
|
396
|
+
if (scopedTriggers.length && !this.elements.panel) {
|
|
333
397
|
this.createDynamicPanel();
|
|
334
398
|
}
|
|
335
399
|
}
|
|
@@ -342,7 +406,7 @@
|
|
|
342
406
|
* Create the panel dynamically when only a trigger button exists
|
|
343
407
|
*/
|
|
344
408
|
createDynamicPanel: function () {
|
|
345
|
-
if (!this.elements.triggers.length) {
|
|
409
|
+
if (!this.elements.triggers.length || (this.elements.panel && this.elements.panel.isConnected)) {
|
|
346
410
|
return;
|
|
347
411
|
}
|
|
348
412
|
this.elements.trigger = this.elements.triggers[0];
|
|
@@ -363,6 +427,7 @@
|
|
|
363
427
|
// Store references
|
|
364
428
|
this.elements.panel = panel;
|
|
365
429
|
this.elements.overlay = overlay;
|
|
430
|
+
this._ownsDynamicPanel = true;
|
|
366
431
|
this.elements.customizer = {
|
|
367
432
|
contains: (el) => panel.contains(el) || this.elements.triggers.some((trigger) => trigger.contains(el))
|
|
368
433
|
};
|
|
@@ -595,8 +660,8 @@
|
|
|
595
660
|
}
|
|
596
661
|
},
|
|
597
662
|
|
|
598
|
-
bindEvents: function () {
|
|
599
|
-
this.bindTriggerEvents();
|
|
663
|
+
bindEvents: function (root) {
|
|
664
|
+
this.bindTriggerEvents(root);
|
|
600
665
|
|
|
601
666
|
this.bindPanelEvents();
|
|
602
667
|
|
|
@@ -631,22 +696,53 @@
|
|
|
631
696
|
});
|
|
632
697
|
},
|
|
633
698
|
|
|
634
|
-
bindTriggerEvents: function () {
|
|
635
|
-
this.
|
|
699
|
+
bindTriggerEvents: function (root) {
|
|
700
|
+
const triggers = root ? this.getTriggers(root) : this.elements.triggers;
|
|
701
|
+
triggers.forEach((trigger) => {
|
|
636
702
|
if (trigger.getAttribute('data-customizer-trigger-initialized') === 'true') {
|
|
637
703
|
return;
|
|
638
704
|
}
|
|
639
|
-
|
|
705
|
+
|
|
706
|
+
const onClick = (e) => {
|
|
640
707
|
e.preventDefault();
|
|
641
708
|
e.stopPropagation();
|
|
642
709
|
this.elements.activeTrigger = trigger;
|
|
643
710
|
this.elements.trigger = trigger;
|
|
644
711
|
this.toggle();
|
|
645
|
-
}
|
|
712
|
+
};
|
|
713
|
+
|
|
714
|
+
trigger.addEventListener('click', onClick);
|
|
715
|
+
trigger._themeCustomizerTriggerHandler = onClick;
|
|
646
716
|
trigger.setAttribute('data-customizer-trigger-initialized', 'true');
|
|
647
717
|
});
|
|
648
718
|
},
|
|
649
719
|
|
|
720
|
+
cleanupTrigger: function (trigger) {
|
|
721
|
+
if (!trigger || trigger.getAttribute('data-customizer-trigger-initialized') !== 'true') {
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
if (trigger._themeCustomizerTriggerHandler) {
|
|
726
|
+
trigger.removeEventListener('click', trigger._themeCustomizerTriggerHandler);
|
|
727
|
+
delete trigger._themeCustomizerTriggerHandler;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
trigger.setAttribute('aria-expanded', 'false');
|
|
731
|
+
trigger.removeAttribute('data-customizer-trigger-initialized');
|
|
732
|
+
|
|
733
|
+
if (this.elements.activeTrigger === trigger) {
|
|
734
|
+
this.elements.activeTrigger = null;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
this.elements.triggers = this.elements.triggers.filter(function (candidate) {
|
|
738
|
+
return candidate !== trigger;
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
if (this.elements.trigger === trigger) {
|
|
742
|
+
this.elements.trigger = this.elements.triggers[0] || null;
|
|
743
|
+
}
|
|
744
|
+
},
|
|
745
|
+
|
|
650
746
|
/**
|
|
651
747
|
* Toggle panel open/close
|
|
652
748
|
*/
|
|
@@ -782,7 +878,21 @@
|
|
|
782
878
|
}
|
|
783
879
|
},
|
|
784
880
|
|
|
785
|
-
destroyAll: function () {
|
|
881
|
+
destroyAll: function (root) {
|
|
882
|
+
const scope = this.normalizeRoot(root);
|
|
883
|
+
|
|
884
|
+
if (scope !== document) {
|
|
885
|
+
this.getTriggers(scope).forEach((trigger) => {
|
|
886
|
+
this.cleanupTrigger(trigger);
|
|
887
|
+
});
|
|
888
|
+
this.pruneTriggers();
|
|
889
|
+
|
|
890
|
+
if (!this.elements.triggers.length) {
|
|
891
|
+
this.destroyAll(document);
|
|
892
|
+
}
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
|
|
786
896
|
this._cleanup.forEach(fn => fn());
|
|
787
897
|
this._cleanup = [];
|
|
788
898
|
|
|
@@ -790,7 +900,27 @@
|
|
|
790
900
|
this.elements.panel.removeAttribute('data-customizer-initialized');
|
|
791
901
|
}
|
|
792
902
|
|
|
903
|
+
this.elements.triggers.slice().forEach((trigger) => {
|
|
904
|
+
this.cleanupTrigger(trigger);
|
|
905
|
+
});
|
|
906
|
+
|
|
907
|
+
if (this._ownsDynamicPanel) {
|
|
908
|
+
if (this.elements.panel && this.elements.panel.parentNode) {
|
|
909
|
+
this.elements.panel.parentNode.removeChild(this.elements.panel);
|
|
910
|
+
}
|
|
911
|
+
if (this.elements.overlay && this.elements.overlay.parentNode) {
|
|
912
|
+
this.elements.overlay.parentNode.removeChild(this.elements.overlay);
|
|
913
|
+
}
|
|
914
|
+
this._ownsDynamicPanel = false;
|
|
915
|
+
}
|
|
916
|
+
|
|
793
917
|
this.close();
|
|
918
|
+
this.elements.customizer = null;
|
|
919
|
+
this.elements.trigger = null;
|
|
920
|
+
this.elements.activeTrigger = null;
|
|
921
|
+
this.elements.triggers = [];
|
|
922
|
+
this.elements.panel = null;
|
|
923
|
+
this.elements.overlay = null;
|
|
794
924
|
this.isInitialized = false;
|
|
795
925
|
}
|
|
796
926
|
};
|
|
@@ -11,7 +11,15 @@
|
|
|
11
11
|
_mediaQuery: null,
|
|
12
12
|
_onMediaChange: null,
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
getToggles: function (root) {
|
|
15
|
+
if (window.Vanduo && typeof window.Vanduo.queryAll === 'function') {
|
|
16
|
+
return window.Vanduo.queryAll(root, '[data-toggle="theme"]');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return Array.from(document.querySelectorAll('[data-toggle="theme"]'));
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
init: function (root) {
|
|
15
23
|
this.STORAGE_KEY = 'vanduo-theme-preference';
|
|
16
24
|
this.state = {
|
|
17
25
|
preference: this.getPreference() // 'light', 'dark', or 'system'
|
|
@@ -19,8 +27,8 @@
|
|
|
19
27
|
|
|
20
28
|
if (this.isInitialized) {
|
|
21
29
|
this.applyTheme();
|
|
22
|
-
this.renderUI();
|
|
23
|
-
this.updateUI();
|
|
30
|
+
this.renderUI(root);
|
|
31
|
+
this.updateUI(root);
|
|
24
32
|
return;
|
|
25
33
|
}
|
|
26
34
|
|
|
@@ -28,9 +36,7 @@
|
|
|
28
36
|
|
|
29
37
|
this.applyTheme();
|
|
30
38
|
this.listenForSystemChanges();
|
|
31
|
-
this.renderUI();
|
|
32
|
-
|
|
33
|
-
console.log('Vanduo Theme Switcher initialized');
|
|
39
|
+
this.renderUI(root);
|
|
34
40
|
},
|
|
35
41
|
|
|
36
42
|
getPreference: function () {
|
|
@@ -113,9 +119,9 @@
|
|
|
113
119
|
},
|
|
114
120
|
|
|
115
121
|
// Helper to facilitate UI creation if needed, though often UI is in HTML
|
|
116
|
-
renderUI: function () {
|
|
122
|
+
renderUI: function (root) {
|
|
117
123
|
// Look for any uninitialized theme toggles
|
|
118
|
-
const toggles =
|
|
124
|
+
const toggles = this.getToggles(root);
|
|
119
125
|
toggles.forEach(toggle => {
|
|
120
126
|
if (toggle.getAttribute('data-theme-initialized') === 'true') {
|
|
121
127
|
if (toggle.tagName === 'SELECT') {
|
|
@@ -147,8 +153,8 @@
|
|
|
147
153
|
});
|
|
148
154
|
},
|
|
149
155
|
|
|
150
|
-
updateUI: function () {
|
|
151
|
-
const toggles =
|
|
156
|
+
updateUI: function (root) {
|
|
157
|
+
const toggles = this.getToggles(root);
|
|
152
158
|
toggles.forEach(toggle => {
|
|
153
159
|
if (toggle.tagName === 'SELECT') {
|
|
154
160
|
toggle.value = this.state.preference;
|
|
@@ -166,8 +172,11 @@
|
|
|
166
172
|
});
|
|
167
173
|
},
|
|
168
174
|
|
|
169
|
-
destroyAll: function () {
|
|
170
|
-
const
|
|
175
|
+
destroyAll: function (root) {
|
|
176
|
+
const scope = root || document;
|
|
177
|
+
const toggles = this.getToggles(scope).filter(function (toggle) {
|
|
178
|
+
return toggle.getAttribute('data-theme-initialized') === 'true';
|
|
179
|
+
});
|
|
171
180
|
toggles.forEach(toggle => {
|
|
172
181
|
if (toggle._themeToggleHandler) {
|
|
173
182
|
const eventName = toggle.tagName === 'SELECT' ? 'change' : 'click';
|
|
@@ -177,13 +186,15 @@
|
|
|
177
186
|
toggle.removeAttribute('data-theme-initialized');
|
|
178
187
|
});
|
|
179
188
|
|
|
180
|
-
if (this._mediaQuery && this._onMediaChange) {
|
|
189
|
+
if (scope === document && this._mediaQuery && this._onMediaChange) {
|
|
181
190
|
this._mediaQuery.removeEventListener('change', this._onMediaChange);
|
|
182
191
|
}
|
|
183
192
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
193
|
+
if (scope === document) {
|
|
194
|
+
this._mediaQuery = null;
|
|
195
|
+
this._onMediaChange = null;
|
|
196
|
+
this.isInitialized = false;
|
|
197
|
+
}
|
|
187
198
|
}
|
|
188
199
|
};
|
|
189
200
|
|
|
@@ -37,6 +37,8 @@
|
|
|
37
37
|
const pauseBtn = scope.querySelector('[data-vd-timeline-pause]');
|
|
38
38
|
|
|
39
39
|
let playTimer = null;
|
|
40
|
+
let isPlaying = false;
|
|
41
|
+
let playToken = 0;
|
|
40
42
|
|
|
41
43
|
function updateNavButtons() {
|
|
42
44
|
const k = countRevealedPrefix(items);
|
|
@@ -52,10 +54,10 @@
|
|
|
52
54
|
nextBtn.setAttribute('aria-disabled', atEnd ? 'true' : 'false');
|
|
53
55
|
}
|
|
54
56
|
if (playBtn) {
|
|
55
|
-
playBtn.setAttribute('aria-pressed',
|
|
57
|
+
playBtn.setAttribute('aria-pressed', isPlaying ? 'true' : 'false');
|
|
56
58
|
}
|
|
57
59
|
if (pauseBtn) {
|
|
58
|
-
pauseBtn.disabled = !
|
|
60
|
+
pauseBtn.disabled = !isPlaying;
|
|
59
61
|
}
|
|
60
62
|
}
|
|
61
63
|
|
|
@@ -75,21 +77,43 @@
|
|
|
75
77
|
updateNavButtons();
|
|
76
78
|
}
|
|
77
79
|
|
|
78
|
-
function
|
|
79
|
-
|
|
80
|
-
playTimer =
|
|
80
|
+
function scheduleNext() {
|
|
81
|
+
const token = ++playToken;
|
|
82
|
+
playTimer = setTimeout(function () {
|
|
83
|
+
playTimer = null;
|
|
84
|
+
|
|
85
|
+
if (!isPlaying || token !== playToken) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
81
89
|
if (countRevealedPrefix(items) >= items.length) {
|
|
82
90
|
pause();
|
|
83
91
|
return;
|
|
84
92
|
}
|
|
93
|
+
|
|
85
94
|
stepNext();
|
|
95
|
+
|
|
96
|
+
if (countRevealedPrefix(items) >= items.length) {
|
|
97
|
+
pause();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
scheduleNext();
|
|
86
102
|
}, PLAY_INTERVAL_MS);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function play() {
|
|
106
|
+
if (isPlaying) return;
|
|
107
|
+
isPlaying = true;
|
|
108
|
+
scheduleNext();
|
|
87
109
|
updateNavButtons();
|
|
88
110
|
}
|
|
89
111
|
|
|
90
112
|
function pause() {
|
|
113
|
+
isPlaying = false;
|
|
114
|
+
playToken++;
|
|
91
115
|
if (playTimer) {
|
|
92
|
-
|
|
116
|
+
clearTimeout(playTimer);
|
|
93
117
|
playTimer = null;
|
|
94
118
|
}
|
|
95
119
|
updateNavButtons();
|
|
@@ -129,16 +153,16 @@
|
|
|
129
153
|
const Timeline = {
|
|
130
154
|
instances: new Map(),
|
|
131
155
|
|
|
132
|
-
init: function () {
|
|
133
|
-
|
|
156
|
+
init: function (root) {
|
|
157
|
+
window.Vanduo.queryAll(root, '.vd-timeline.vd-timeline-animated').forEach(function (el) {
|
|
134
158
|
if (Timeline.instances.has(el)) return;
|
|
135
159
|
Timeline.initInstance(el);
|
|
136
160
|
});
|
|
137
161
|
},
|
|
138
162
|
|
|
139
|
-
reinit: function () {
|
|
140
|
-
Timeline.destroyAll();
|
|
141
|
-
Timeline.init();
|
|
163
|
+
reinit: function (root) {
|
|
164
|
+
Timeline.destroyAll(root);
|
|
165
|
+
Timeline.init(root);
|
|
142
166
|
},
|
|
143
167
|
|
|
144
168
|
initInstance: function (container) {
|
|
@@ -211,8 +235,13 @@
|
|
|
211
235
|
this.instances.delete(container);
|
|
212
236
|
},
|
|
213
237
|
|
|
214
|
-
destroyAll: function () {
|
|
238
|
+
destroyAll: function (root) {
|
|
239
|
+
const scope = window.Vanduo && typeof window.Vanduo._normalizeRoot === 'function'
|
|
240
|
+
? window.Vanduo._normalizeRoot(root)
|
|
241
|
+
: document;
|
|
242
|
+
|
|
215
243
|
this.instances.forEach(function (_, el) {
|
|
244
|
+
if (scope !== document && scope !== el && (!scope.contains || !scope.contains(el))) return;
|
|
216
245
|
Timeline.destroy(el);
|
|
217
246
|
});
|
|
218
247
|
}
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
const Timepicker = {
|
|
10
10
|
instances: new Map(),
|
|
11
11
|
|
|
12
|
-
init: function () {
|
|
13
|
-
const inputs =
|
|
12
|
+
init: function (root) {
|
|
13
|
+
const inputs = window.Vanduo.queryAll(root, '[data-vd-timepicker]');
|
|
14
14
|
inputs.forEach(el => {
|
|
15
15
|
if (this.instances.has(el)) return;
|
|
16
16
|
this.initInstance(el);
|
package/js/components/toast.js
CHANGED
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
if (config.icon) {
|
|
95
95
|
const allowSvg = config.iconAllowSvg === true;
|
|
96
96
|
const safeIcon = typeof sanitizeHtml === 'function'
|
|
97
|
-
? sanitizeHtml(config.icon, { allowSvg })
|
|
97
|
+
? sanitizeHtml(config.icon, { allowSvg, allowStyle: false })
|
|
98
98
|
: escapeHtml(config.icon);
|
|
99
99
|
html += `<span class="vd-toast-icon">${safeIcon}</span>`;
|
|
100
100
|
} else if (config.type) {
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
/**
|
|
32
32
|
* Initialize tooltips
|
|
33
33
|
*/
|
|
34
|
-
init: function () {
|
|
35
|
-
const elements =
|
|
34
|
+
init: function (root) {
|
|
35
|
+
const elements = window.Vanduo.queryAll(root, '[data-tooltip], [data-tooltip-html]');
|
|
36
36
|
|
|
37
37
|
elements.forEach(element => {
|
|
38
38
|
if (this.tooltips.has(element)) {
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
|
|
94
94
|
if (htmlContent) {
|
|
95
95
|
const allowSvg = element.hasAttribute('data-tooltip-allow-svg');
|
|
96
|
-
tooltip.innerHTML = this.sanitizeHtml(htmlContent, { allowSvg });
|
|
96
|
+
tooltip.innerHTML = this.sanitizeHtml(htmlContent, { allowSvg, allowStyle: false });
|
|
97
97
|
tooltip.classList.add('vd-tooltip-html');
|
|
98
98
|
} else if (textContent) {
|
|
99
99
|
tooltip.textContent = textContent;
|
|
@@ -253,7 +253,7 @@
|
|
|
253
253
|
const { tooltip } = this.tooltips.get(el);
|
|
254
254
|
if (isHtml) {
|
|
255
255
|
const allowSvg = el.hasAttribute('data-tooltip-allow-svg');
|
|
256
|
-
tooltip.innerHTML = this.sanitizeHtml(content, { allowSvg });
|
|
256
|
+
tooltip.innerHTML = this.sanitizeHtml(content, { allowSvg, allowStyle: false });
|
|
257
257
|
tooltip.classList.add('vd-tooltip-html');
|
|
258
258
|
} else {
|
|
259
259
|
tooltip.textContent = content;
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
const Transfer = {
|
|
10
10
|
instances: new Map(),
|
|
11
11
|
|
|
12
|
-
init: function () {
|
|
13
|
-
const transfers =
|
|
12
|
+
init: function (root) {
|
|
13
|
+
const transfers = window.Vanduo.queryAll(root, '[data-vd-transfer]');
|
|
14
14
|
transfers.forEach(el => {
|
|
15
15
|
if (this.instances.has(el)) return;
|
|
16
16
|
this.initInstance(el);
|
package/js/components/tree.js
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
const Tree = {
|
|
10
10
|
instances: new Map(),
|
|
11
11
|
|
|
12
|
-
init: function () {
|
|
13
|
-
const trees =
|
|
12
|
+
init: function (root) {
|
|
13
|
+
const trees = window.Vanduo.queryAll(root, '[data-vd-tree]');
|
|
14
14
|
trees.forEach(el => {
|
|
15
15
|
if (this.instances.has(el)) return;
|
|
16
16
|
this.initInstance(el);
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
match: 'Fields do not match'
|
|
50
50
|
},
|
|
51
51
|
|
|
52
|
-
init: function () {
|
|
53
|
-
const forms =
|
|
52
|
+
init: function (root) {
|
|
53
|
+
const forms = window.Vanduo.queryAll(root, '[data-vd-validate], .vd-validate');
|
|
54
54
|
forms.forEach(form => {
|
|
55
55
|
if (this.instances.has(form)) return;
|
|
56
56
|
this.initInstance(form);
|
package/js/components/vd-hex.js
CHANGED
|
@@ -90,13 +90,19 @@ export class VdHexGrid {
|
|
|
90
90
|
const root = document.documentElement;
|
|
91
91
|
const style = getComputedStyle(root);
|
|
92
92
|
|
|
93
|
+
const readToken = (canonical, fallback, defaultValue) => {
|
|
94
|
+
return style.getPropertyValue(canonical).trim()
|
|
95
|
+
|| style.getPropertyValue(fallback).trim()
|
|
96
|
+
|| defaultValue;
|
|
97
|
+
};
|
|
98
|
+
|
|
93
99
|
return {
|
|
94
|
-
bgPrimary:
|
|
95
|
-
bgSecondary:
|
|
96
|
-
borderColor:
|
|
97
|
-
colorPrimary:
|
|
98
|
-
textColor:
|
|
99
|
-
textMuted:
|
|
100
|
+
bgPrimary: readToken('--vd-bg-primary', '--bg-primary', '#ffffff'),
|
|
101
|
+
bgSecondary: readToken('--vd-bg-secondary', '--bg-secondary', '#f5f5f5'),
|
|
102
|
+
borderColor: readToken('--vd-border-color', '--border-color', '#e0e0e0'),
|
|
103
|
+
colorPrimary: readToken('--vd-color-primary', '--color-primary', '#3b82f6'),
|
|
104
|
+
textColor: readToken('--vd-text-primary', '--text-primary', '#1f2937'),
|
|
105
|
+
textMuted: readToken('--vd-text-muted', '--text-muted', '#6b7280')
|
|
100
106
|
};
|
|
101
107
|
}
|
|
102
108
|
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
const Waypoint = {
|
|
10
10
|
instances: new Map(),
|
|
11
11
|
|
|
12
|
-
init: function () {
|
|
13
|
-
const navs =
|
|
12
|
+
init: function (root) {
|
|
13
|
+
const navs = window.Vanduo.queryAll(root, '[data-vd-waypoint-nav], [data-vd-scrollspy-nav]');
|
|
14
14
|
navs.forEach(nav => {
|
|
15
15
|
if (this.instances.has(nav)) return;
|
|
16
16
|
this.initInstance(nav);
|
package/js/utils/helpers.js
CHANGED
|
@@ -258,7 +258,7 @@ function escapeHtml(str) {
|
|
|
258
258
|
* Keeps a small set of tags and strips disallowed tags and attributes. Safe for
|
|
259
259
|
* simple rich text (use server-side or DOMPurify for stronger guarantees).
|
|
260
260
|
* @param {string} input
|
|
261
|
-
* @param {{ allowSvg?: boolean }} [options]
|
|
261
|
+
* @param {{ allowSvg?: boolean, allowStyle?: boolean }} [options]
|
|
262
262
|
* @returns {string} sanitized HTML
|
|
263
263
|
*/
|
|
264
264
|
function sanitizeHtml(input, options = {}) {
|
|
@@ -271,6 +271,7 @@ function sanitizeHtml(input, options = {}) {
|
|
|
271
271
|
return escapeHtml(input);
|
|
272
272
|
}
|
|
273
273
|
const allowSvg = options && options.allowSvg === true;
|
|
274
|
+
const allowStyle = !options || options.allowStyle !== false;
|
|
274
275
|
const baseAllowed = ['B', 'STRONG', 'I', 'EM', 'BR', 'A', 'SPAN', 'U', 'DIV', 'P', 'KBD', 'CODE', 'SMALL', 'MARK'];
|
|
275
276
|
const svgAllowed = ['SVG', 'PATH', 'LINE', 'CIRCLE', 'POLYLINE', 'RECT', 'G'];
|
|
276
277
|
const allowed = allowSvg ? baseAllowed.concat(svgAllowed) : baseAllowed;
|
|
@@ -310,8 +311,11 @@ function sanitizeHtml(input, options = {}) {
|
|
|
310
311
|
}
|
|
311
312
|
});
|
|
312
313
|
} else {
|
|
313
|
-
// Keep class and style; strip everything else
|
|
314
|
-
const safeAttrs = new Set(['class'
|
|
314
|
+
// Keep class and optionally inline style; strip everything else.
|
|
315
|
+
const safeAttrs = new Set(['class']);
|
|
316
|
+
if (allowStyle) {
|
|
317
|
+
safeAttrs.add('style');
|
|
318
|
+
}
|
|
315
319
|
const otherAttrs = Array.from(child.attributes || []);
|
|
316
320
|
otherAttrs.forEach(function (a) {
|
|
317
321
|
if (!safeAttrs.has(a.name)) { child.removeAttribute(a.name); }
|
|
@@ -327,4 +331,3 @@ function sanitizeHtml(input, options = {}) {
|
|
|
327
331
|
}
|
|
328
332
|
|
|
329
333
|
|
|
330
|
-
|