@dodlhuat/basix 1.4.2 → 1.4.3
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 +13 -1
- package/css/calendar.scss +4 -3
- package/css/code-viewer.scss +1 -1
- package/css/datepicker.scss +83 -70
- package/css/editor.scss +2 -1
- package/css/flyout-menu.scss +2 -1
- package/css/form.scss +11 -32
- package/css/mixins.scss +25 -0
- package/css/range-slider.scss +7 -6
- package/css/stepper.scss +2 -1
- package/css/style.css +84 -71
- package/css/style.css.map +1 -1
- package/css/style.min.css +1 -1
- package/css/style.min.css.map +1 -1
- package/css/timepicker.scss +1 -1
- package/css/virtual-dropdown.scss +6 -16
- package/js/bottom-sheet.d.ts +3 -5
- package/js/bottom-sheet.js +39 -58
- package/js/calendar.d.ts +1 -2
- package/js/calendar.js +77 -84
- package/js/carousel.d.ts +1 -1
- package/js/carousel.js +22 -14
- package/js/chart.d.ts +1 -1
- package/js/chart.js +104 -65
- package/js/code-viewer.d.ts +1 -1
- package/js/code-viewer.js +7 -18
- package/js/color-picker.d.ts +2 -2
- package/js/color-picker.js +20 -22
- package/js/context-menu.d.ts +1 -1
- package/js/context-menu.js +10 -12
- package/js/datepicker.d.ts +14 -3
- package/js/datepicker.js +180 -99
- package/js/dropdown.d.ts +1 -1
- package/js/dropdown.js +4 -5
- package/js/editor.d.ts +1 -1
- package/js/editor.js +30 -34
- package/js/file-uploader.d.ts +2 -9
- package/js/file-uploader.js +57 -86
- package/js/flyout-menu.d.ts +3 -3
- package/js/flyout-menu.js +20 -22
- package/js/gallery.d.ts +1 -2
- package/js/gallery.js +14 -20
- package/js/group-picker.d.ts +1 -1
- package/js/group-picker.js +22 -29
- package/js/lightbox.d.ts +2 -2
- package/js/lightbox.js +28 -27
- package/js/listeners.d.ts +7 -0
- package/js/listeners.js +14 -0
- package/js/modal.d.ts +2 -1
- package/js/modal.js +13 -20
- package/js/popover.d.ts +2 -2
- package/js/popover.js +42 -37
- package/js/position.js +3 -5
- package/js/push-menu.d.ts +2 -0
- package/js/push-menu.js +21 -15
- package/js/range-slider.d.ts +2 -2
- package/js/range-slider.js +7 -6
- package/js/scroll.js +4 -7
- package/js/scrollbar.d.ts +3 -3
- package/js/scrollbar.js +39 -42
- package/js/select.d.ts +1 -1
- package/js/select.js +19 -23
- package/js/sidebar-nav.d.ts +1 -1
- package/js/sidebar-nav.js +13 -9
- package/js/stepper.d.ts +1 -1
- package/js/stepper.js +9 -11
- package/js/table.d.ts +1 -1
- package/js/table.js +24 -23
- package/js/tabs.d.ts +1 -1
- package/js/tabs.js +10 -17
- package/js/theme.d.ts +1 -0
- package/js/theme.js +6 -15
- package/js/timepicker.d.ts +8 -6
- package/js/timepicker.js +36 -36
- package/js/toast.d.ts +2 -1
- package/js/toast.js +8 -4
- package/js/tooltip.d.ts +1 -4
- package/js/tooltip.js +14 -23
- package/js/tree.d.ts +0 -1
- package/js/tree.js +6 -11
- package/js/utils.js +7 -8
- package/js/virtual-dropdown.d.ts +1 -1
- package/js/virtual-dropdown.js +26 -28
- package/package.json +1 -1
- package/css/calendar.css +0 -928
- package/css/guitar-chords.css +0 -251
- package/js/form-builder.js +0 -107
- package/js/guitar-chords.js +0 -268
- package/js/lazy-loader.js +0 -121
- package/js/request.js +0 -51
package/js/tabs.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
+
import { ListenerGroup } from './listeners.js';
|
|
1
2
|
class Tabs {
|
|
2
3
|
container;
|
|
3
4
|
options;
|
|
4
5
|
tabItems;
|
|
5
6
|
tabPanels;
|
|
6
7
|
currentTab;
|
|
7
|
-
|
|
8
|
+
listeners = new ListenerGroup();
|
|
8
9
|
constructor(elementOrSelector, options = {}) {
|
|
9
|
-
const element = typeof elementOrSelector === 'string'
|
|
10
|
-
? document.querySelector(elementOrSelector)
|
|
11
|
-
: elementOrSelector;
|
|
10
|
+
const element = typeof elementOrSelector === 'string' ? document.querySelector(elementOrSelector) : elementOrSelector;
|
|
12
11
|
if (!element) {
|
|
13
12
|
throw new Error(`Tabs: Element not found for selector "${elementOrSelector}"`);
|
|
14
13
|
}
|
|
@@ -18,7 +17,7 @@ class Tabs {
|
|
|
18
17
|
layout,
|
|
19
18
|
defaultTab: options.defaultTab ?? 0,
|
|
20
19
|
menuPos: options.menuPos ?? (layout === 'vertical' ? 'left' : 'top'),
|
|
21
|
-
onChange: options.onChange
|
|
20
|
+
onChange: options.onChange,
|
|
22
21
|
};
|
|
23
22
|
this.currentTab = this.options.defaultTab;
|
|
24
23
|
this.tabItems = this.container.querySelectorAll('.tab-item');
|
|
@@ -29,8 +28,6 @@ class Tabs {
|
|
|
29
28
|
if (this.options.layout === 'vertical') {
|
|
30
29
|
this.container.classList.add('tabs-vertical');
|
|
31
30
|
}
|
|
32
|
-
this.tabItems = this.container.querySelectorAll('.tab-item');
|
|
33
|
-
this.tabPanels = this.container.querySelectorAll('.tab-panel');
|
|
34
31
|
if (this.tabItems.length === 0) {
|
|
35
32
|
console.warn('No tab items found in container');
|
|
36
33
|
return;
|
|
@@ -46,16 +43,13 @@ class Tabs {
|
|
|
46
43
|
this.activateTab(this.options.defaultTab);
|
|
47
44
|
}
|
|
48
45
|
bindEvents() {
|
|
49
|
-
const sig = { signal: this.
|
|
46
|
+
const sig = { signal: this.listeners.signal };
|
|
50
47
|
this.tabItems.forEach((item, index) => {
|
|
51
48
|
item.addEventListener('click', (e) => {
|
|
52
49
|
e.preventDefault();
|
|
53
50
|
this.activateTab(index);
|
|
54
51
|
}, sig);
|
|
55
|
-
item.addEventListener('keydown', (e) =>
|
|
56
|
-
const keyEvent = e;
|
|
57
|
-
this.handleKeyboardNavigation(keyEvent, index);
|
|
58
|
-
}, sig);
|
|
52
|
+
item.addEventListener('keydown', (e) => this.handleKeyboardNavigation(e, index), sig);
|
|
59
53
|
item.setAttribute('role', 'tab');
|
|
60
54
|
item.setAttribute('tabindex', index === this.options.defaultTab ? '0' : '-1');
|
|
61
55
|
item.setAttribute('aria-selected', index === this.options.defaultTab ? 'true' : 'false');
|
|
@@ -114,7 +108,7 @@ class Tabs {
|
|
|
114
108
|
console.warn(`Invalid tab index: ${index}`);
|
|
115
109
|
return;
|
|
116
110
|
}
|
|
117
|
-
this.tabItems.forEach((item
|
|
111
|
+
this.tabItems.forEach((item) => {
|
|
118
112
|
item.classList.remove('active');
|
|
119
113
|
item.setAttribute('tabindex', '-1');
|
|
120
114
|
item.setAttribute('aria-selected', 'false');
|
|
@@ -130,9 +124,8 @@ class Tabs {
|
|
|
130
124
|
this.tabPanels[index].setAttribute('aria-hidden', 'false');
|
|
131
125
|
const previousTab = this.currentTab;
|
|
132
126
|
this.currentTab = index;
|
|
133
|
-
if (
|
|
134
|
-
this.options.onChange(index);
|
|
135
|
-
}
|
|
127
|
+
if (previousTab !== index)
|
|
128
|
+
this.options.onChange?.(index);
|
|
136
129
|
}
|
|
137
130
|
goToTab(index) {
|
|
138
131
|
this.activateTab(index);
|
|
@@ -169,7 +162,7 @@ class Tabs {
|
|
|
169
162
|
}
|
|
170
163
|
}
|
|
171
164
|
destroy() {
|
|
172
|
-
this.
|
|
165
|
+
this.listeners.destroy();
|
|
173
166
|
this.container.classList.remove('tabs-vertical');
|
|
174
167
|
this.tabItems.forEach((item) => {
|
|
175
168
|
item.removeAttribute('role');
|
package/js/theme.d.ts
CHANGED
package/js/theme.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
class Theme {
|
|
2
2
|
static STORAGE_KEY = 'theme';
|
|
3
|
+
static isMac = /Mac|iPhone|iPod|iPad/i.test(navigator.platform);
|
|
3
4
|
static root;
|
|
4
5
|
static elements = null;
|
|
5
6
|
static mediaQuery = null;
|
|
@@ -99,14 +100,11 @@ class Theme {
|
|
|
99
100
|
static bindToggleClick() {
|
|
100
101
|
if (!this.elements)
|
|
101
102
|
return;
|
|
102
|
-
this.elements.toggleBtn.addEventListener('click', () =>
|
|
103
|
-
this.toggleTheme();
|
|
104
|
-
});
|
|
103
|
+
this.elements.toggleBtn.addEventListener('click', () => this.toggleTheme());
|
|
105
104
|
}
|
|
106
105
|
static bindKeyboardShortcut() {
|
|
107
106
|
window.addEventListener('keydown', (ev) => {
|
|
108
|
-
const
|
|
109
|
-
const modifierPressed = isMac ? ev.metaKey : ev.ctrlKey;
|
|
107
|
+
const modifierPressed = Theme.isMac ? ev.metaKey : ev.ctrlKey;
|
|
110
108
|
if (modifierPressed && ev.key.toLowerCase() === 'j') {
|
|
111
109
|
ev.preventDefault();
|
|
112
110
|
this.toggleTheme();
|
|
@@ -116,18 +114,11 @@ class Theme {
|
|
|
116
114
|
static bindSystemThemeChange() {
|
|
117
115
|
if (!this.mediaQuery)
|
|
118
116
|
return;
|
|
119
|
-
|
|
117
|
+
this.mediaQuery.addEventListener('change', (e) => {
|
|
120
118
|
if (!this.getSavedTheme()) {
|
|
121
|
-
|
|
122
|
-
this.applyTheme(matches ? 'dark' : 'light');
|
|
119
|
+
this.applyTheme(e.matches ? 'dark' : 'light');
|
|
123
120
|
}
|
|
124
|
-
};
|
|
125
|
-
if ('addEventListener' in this.mediaQuery) {
|
|
126
|
-
this.mediaQuery.addEventListener('change', handler);
|
|
127
|
-
}
|
|
128
|
-
else if ('addListener' in this.mediaQuery) {
|
|
129
|
-
this.mediaQuery.addListener(handler);
|
|
130
|
-
}
|
|
121
|
+
});
|
|
131
122
|
}
|
|
132
123
|
static getTheme() {
|
|
133
124
|
return this.getCurrentTheme();
|
package/js/timepicker.d.ts
CHANGED
|
@@ -24,18 +24,20 @@ declare class TimeSpanPicker {
|
|
|
24
24
|
private startHandleEl;
|
|
25
25
|
private endHandleEl;
|
|
26
26
|
private dragState;
|
|
27
|
+
private listeners;
|
|
28
|
+
private dragListeners;
|
|
27
29
|
constructor(elementOrSelector: string | HTMLElement, options?: TimeSpanPickerOptions);
|
|
28
30
|
private queryEl;
|
|
29
31
|
private render;
|
|
30
|
-
private
|
|
32
|
+
private handleChange;
|
|
31
33
|
private attachEventListeners;
|
|
32
34
|
private attachBarListeners;
|
|
33
35
|
private beginDrag;
|
|
34
|
-
private
|
|
35
|
-
private
|
|
36
|
-
private
|
|
37
|
-
private
|
|
38
|
-
private
|
|
36
|
+
private onStartHandleDown;
|
|
37
|
+
private onEndHandleDown;
|
|
38
|
+
private onFillDown;
|
|
39
|
+
private onPointerMove;
|
|
40
|
+
private onPointerUp;
|
|
39
41
|
private toMinutes;
|
|
40
42
|
private minutesToTime;
|
|
41
43
|
private snap;
|
package/js/timepicker.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ListenerGroup } from './listeners.js';
|
|
1
2
|
class TimeSpanPicker {
|
|
2
3
|
container;
|
|
3
4
|
startTimeInput;
|
|
@@ -13,11 +14,13 @@ class TimeSpanPicker {
|
|
|
13
14
|
startHandleEl;
|
|
14
15
|
endHandleEl;
|
|
15
16
|
dragState = null;
|
|
17
|
+
listeners = new ListenerGroup();
|
|
18
|
+
dragListeners = null;
|
|
16
19
|
constructor(elementOrSelector, options) {
|
|
17
20
|
const element = typeof elementOrSelector === 'string'
|
|
18
|
-
?
|
|
21
|
+
? elementOrSelector.startsWith('#') || elementOrSelector.startsWith('.')
|
|
19
22
|
? document.querySelector(elementOrSelector)
|
|
20
|
-
: document.getElementById(elementOrSelector)
|
|
23
|
+
: document.getElementById(elementOrSelector)
|
|
21
24
|
: elementOrSelector;
|
|
22
25
|
if (!element) {
|
|
23
26
|
throw new Error(`TimeSpanPicker: Element not found for "${elementOrSelector}"`);
|
|
@@ -74,17 +77,17 @@ class TimeSpanPicker {
|
|
|
74
77
|
</div>
|
|
75
78
|
`;
|
|
76
79
|
}
|
|
77
|
-
handleChange
|
|
80
|
+
handleChange() {
|
|
78
81
|
this.updateUI();
|
|
79
82
|
const start = this.startTimeInput.value;
|
|
80
83
|
const end = this.endTimeInput.value;
|
|
81
|
-
if (
|
|
82
|
-
this.onChange(start, end);
|
|
83
|
-
|
|
84
|
-
};
|
|
84
|
+
if (start && end)
|
|
85
|
+
this.onChange?.(start, end);
|
|
86
|
+
}
|
|
85
87
|
attachEventListeners() {
|
|
86
|
-
this.
|
|
87
|
-
this.
|
|
88
|
+
const sig = { signal: this.listeners.signal };
|
|
89
|
+
this.startTimeInput.addEventListener('change', () => this.handleChange(), sig);
|
|
90
|
+
this.endTimeInput.addEventListener('change', () => this.handleChange(), sig);
|
|
88
91
|
}
|
|
89
92
|
attachBarListeners() {
|
|
90
93
|
this.pickerEl = this.queryEl('.timespan-picker');
|
|
@@ -93,9 +96,10 @@ class TimeSpanPicker {
|
|
|
93
96
|
this.barFillEl = this.queryEl('.timespan-bar-fill');
|
|
94
97
|
this.startHandleEl = this.queryEl('.timespan-handle-start');
|
|
95
98
|
this.endHandleEl = this.queryEl('.timespan-handle-end');
|
|
96
|
-
this.
|
|
97
|
-
this.
|
|
98
|
-
this.
|
|
99
|
+
const sig = { signal: this.listeners.signal };
|
|
100
|
+
this.startHandleEl.addEventListener('pointerdown', (e) => this.onStartHandleDown(e), sig);
|
|
101
|
+
this.endHandleEl.addEventListener('pointerdown', (e) => this.onEndHandleDown(e), sig);
|
|
102
|
+
this.barFillEl.addEventListener('pointerdown', (e) => this.onFillDown(e), sig);
|
|
99
103
|
}
|
|
100
104
|
beginDrag(type, clickOffsetMins = 0, rect) {
|
|
101
105
|
const start = this.startTimeInput.value;
|
|
@@ -112,20 +116,22 @@ class TimeSpanPicker {
|
|
|
112
116
|
clickOffsetMins,
|
|
113
117
|
};
|
|
114
118
|
this.barEl.classList.add('is-dragging');
|
|
115
|
-
|
|
116
|
-
|
|
119
|
+
this.dragListeners = new ListenerGroup();
|
|
120
|
+
const dragSig = { signal: this.dragListeners.signal };
|
|
121
|
+
document.addEventListener('pointermove', (e) => this.onPointerMove(e), dragSig);
|
|
122
|
+
document.addEventListener('pointerup', () => this.onPointerUp(), dragSig);
|
|
117
123
|
}
|
|
118
|
-
onStartHandleDown
|
|
124
|
+
onStartHandleDown(e) {
|
|
119
125
|
e.stopPropagation();
|
|
120
126
|
e.preventDefault();
|
|
121
127
|
this.beginDrag('start');
|
|
122
|
-
}
|
|
123
|
-
onEndHandleDown
|
|
128
|
+
}
|
|
129
|
+
onEndHandleDown(e) {
|
|
124
130
|
e.stopPropagation();
|
|
125
131
|
e.preventDefault();
|
|
126
132
|
this.beginDrag('end');
|
|
127
|
-
}
|
|
128
|
-
onFillDown
|
|
133
|
+
}
|
|
134
|
+
onFillDown(e) {
|
|
129
135
|
if (e.target.classList.contains('timespan-handle'))
|
|
130
136
|
return;
|
|
131
137
|
e.preventDefault();
|
|
@@ -135,8 +141,8 @@ class TimeSpanPicker {
|
|
|
135
141
|
const rect = this.barEl.getBoundingClientRect();
|
|
136
142
|
const clickMins = ((e.clientX - rect.left) / rect.width) * 1440;
|
|
137
143
|
this.beginDrag('move', clickMins - this.toMinutes(start), rect);
|
|
138
|
-
}
|
|
139
|
-
onPointerMove
|
|
144
|
+
}
|
|
145
|
+
onPointerMove(e) {
|
|
140
146
|
if (!this.dragState)
|
|
141
147
|
return;
|
|
142
148
|
e.preventDefault();
|
|
@@ -162,17 +168,16 @@ class TimeSpanPicker {
|
|
|
162
168
|
this.endTimeInput.value = end;
|
|
163
169
|
}
|
|
164
170
|
this.updateUI();
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
onPointerUp = () => {
|
|
171
|
+
this.onChange?.(start, end);
|
|
172
|
+
}
|
|
173
|
+
onPointerUp() {
|
|
169
174
|
if (!this.dragState)
|
|
170
175
|
return;
|
|
171
176
|
this.dragState = null;
|
|
172
177
|
this.barEl.classList.remove('is-dragging');
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
178
|
+
this.dragListeners?.destroy();
|
|
179
|
+
this.dragListeners = null;
|
|
180
|
+
}
|
|
176
181
|
toMinutes(time) {
|
|
177
182
|
const [h, m] = time.split(':').map(Number);
|
|
178
183
|
return h * 60 + m;
|
|
@@ -225,7 +230,7 @@ class TimeSpanPicker {
|
|
|
225
230
|
getValue() {
|
|
226
231
|
return {
|
|
227
232
|
start: this.startTimeInput.value,
|
|
228
|
-
end: this.endTimeInput.value
|
|
233
|
+
end: this.endTimeInput.value,
|
|
229
234
|
};
|
|
230
235
|
}
|
|
231
236
|
setValue(start, end) {
|
|
@@ -248,13 +253,8 @@ class TimeSpanPicker {
|
|
|
248
253
|
return !!(start && end && start < end);
|
|
249
254
|
}
|
|
250
255
|
destroy() {
|
|
251
|
-
this.
|
|
252
|
-
this.
|
|
253
|
-
this.startHandleEl.removeEventListener('pointerdown', this.onStartHandleDown);
|
|
254
|
-
this.endHandleEl.removeEventListener('pointerdown', this.onEndHandleDown);
|
|
255
|
-
this.barFillEl.removeEventListener('pointerdown', this.onFillDown);
|
|
256
|
-
document.removeEventListener('pointermove', this.onPointerMove);
|
|
257
|
-
document.removeEventListener('pointerup', this.onPointerUp);
|
|
256
|
+
this.listeners.destroy();
|
|
257
|
+
this.dragListeners?.destroy();
|
|
258
258
|
}
|
|
259
259
|
}
|
|
260
260
|
export { TimeSpanPicker };
|
package/js/toast.d.ts
CHANGED
|
@@ -14,10 +14,11 @@ declare class Toast {
|
|
|
14
14
|
private readonly template;
|
|
15
15
|
private toastElement;
|
|
16
16
|
private timerId;
|
|
17
|
+
private openListeners;
|
|
17
18
|
constructor(options: ToastOptions);
|
|
18
19
|
constructor(content: string, header?: string, type?: ToastType, closeable?: boolean);
|
|
19
20
|
show(ms?: number): void;
|
|
20
|
-
hide
|
|
21
|
+
hide(): void;
|
|
21
22
|
private startTimer;
|
|
22
23
|
destroy(): void;
|
|
23
24
|
private buildTemplate;
|
package/js/toast.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { escapeHtml } from './utils.js';
|
|
2
|
+
import { ListenerGroup } from './listeners.js';
|
|
2
3
|
class Toast {
|
|
3
4
|
content;
|
|
4
5
|
header;
|
|
@@ -8,6 +9,7 @@ class Toast {
|
|
|
8
9
|
template;
|
|
9
10
|
toastElement = null;
|
|
10
11
|
timerId = null;
|
|
12
|
+
openListeners = null;
|
|
11
13
|
constructor(contentOrOptions, header = '', type, closeable = true) {
|
|
12
14
|
if (typeof contentOrOptions === 'object') {
|
|
13
15
|
this.content = contentOrOptions.content;
|
|
@@ -37,7 +39,8 @@ class Toast {
|
|
|
37
39
|
this.toastElement?.classList.add('show');
|
|
38
40
|
const closeButton = this.toastElement?.querySelector('.close');
|
|
39
41
|
if (closeButton) {
|
|
40
|
-
|
|
42
|
+
this.openListeners = new ListenerGroup();
|
|
43
|
+
closeButton.addEventListener('click', () => this.hide(), { signal: this.openListeners.signal });
|
|
41
44
|
}
|
|
42
45
|
if (ms !== undefined && ms > 0) {
|
|
43
46
|
this.startTimer(ms);
|
|
@@ -45,18 +48,19 @@ class Toast {
|
|
|
45
48
|
});
|
|
46
49
|
});
|
|
47
50
|
}
|
|
48
|
-
hide
|
|
51
|
+
hide() {
|
|
49
52
|
if (this.timerId !== null) {
|
|
50
53
|
clearTimeout(this.timerId);
|
|
51
54
|
this.timerId = null;
|
|
52
55
|
}
|
|
53
56
|
this.toastElement?.classList.remove('show');
|
|
57
|
+
this.openListeners?.destroy();
|
|
58
|
+
this.openListeners = null;
|
|
54
59
|
setTimeout(() => {
|
|
55
|
-
this.toastElement?.querySelector('.close')?.removeEventListener('click', this.hide);
|
|
56
60
|
this.toastElement?.remove();
|
|
57
61
|
this.toastElement = null;
|
|
58
62
|
}, 150);
|
|
59
|
-
}
|
|
63
|
+
}
|
|
60
64
|
startTimer(ms, elapsed = 0) {
|
|
61
65
|
const stepSize = 250;
|
|
62
66
|
if (elapsed >= ms) {
|
package/js/tooltip.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ declare class Tooltip {
|
|
|
14
14
|
private tooltipElement;
|
|
15
15
|
private showTimeout;
|
|
16
16
|
private isVisible;
|
|
17
|
+
private listeners;
|
|
17
18
|
constructor(trigger: HTMLElement, content: string, options?: TooltipOptions);
|
|
18
19
|
static initializeAll(): void;
|
|
19
20
|
show(): void;
|
|
@@ -22,10 +23,6 @@ declare class Tooltip {
|
|
|
22
23
|
private createTooltip;
|
|
23
24
|
private position;
|
|
24
25
|
private attachEvents;
|
|
25
|
-
private handleMouseEnter;
|
|
26
|
-
private handleMouseLeave;
|
|
27
|
-
private handleFocus;
|
|
28
|
-
private handleBlur;
|
|
29
26
|
destroy(): void;
|
|
30
27
|
}
|
|
31
28
|
export { Tooltip };
|
package/js/tooltip.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { computePosition } from './position.js';
|
|
2
|
+
import { ListenerGroup } from './listeners.js';
|
|
2
3
|
class Tooltip {
|
|
3
4
|
static activeTooltip = null;
|
|
4
5
|
static idCounter = 0;
|
|
@@ -8,6 +9,7 @@ class Tooltip {
|
|
|
8
9
|
tooltipElement = null;
|
|
9
10
|
showTimeout = null;
|
|
10
11
|
isVisible = false;
|
|
12
|
+
listeners = new ListenerGroup();
|
|
11
13
|
constructor(trigger, content, options = {}) {
|
|
12
14
|
this.trigger = trigger;
|
|
13
15
|
this.content = content;
|
|
@@ -22,7 +24,7 @@ class Tooltip {
|
|
|
22
24
|
}
|
|
23
25
|
static initializeAll() {
|
|
24
26
|
const triggers = document.querySelectorAll('[data-tooltip]');
|
|
25
|
-
triggers.forEach(trigger => {
|
|
27
|
+
triggers.forEach((trigger) => {
|
|
26
28
|
const content = trigger.getAttribute('data-tooltip');
|
|
27
29
|
const position = trigger.getAttribute('data-tooltip-position') ?? 'auto';
|
|
28
30
|
const className = trigger.getAttribute('data-tooltip-class') ?? '';
|
|
@@ -31,7 +33,7 @@ class Tooltip {
|
|
|
31
33
|
}
|
|
32
34
|
});
|
|
33
35
|
const advancedTriggers = document.querySelectorAll('[data-tooltip-id]');
|
|
34
|
-
advancedTriggers.forEach(trigger => {
|
|
36
|
+
advancedTriggers.forEach((trigger) => {
|
|
35
37
|
const contentId = trigger.getAttribute('data-tooltip-id');
|
|
36
38
|
const position = trigger.getAttribute('data-tooltip-position') ?? 'auto';
|
|
37
39
|
const className = trigger.getAttribute('data-tooltip-class') ?? '';
|
|
@@ -107,35 +109,24 @@ class Tooltip {
|
|
|
107
109
|
position() {
|
|
108
110
|
if (!this.tooltipElement)
|
|
109
111
|
return;
|
|
110
|
-
const { left, top, placement } = computePosition(this.trigger.getBoundingClientRect(), this.tooltipElement.getBoundingClientRect(), {
|
|
112
|
+
const { left, top, placement } = computePosition(this.trigger.getBoundingClientRect(), this.tooltipElement.getBoundingClientRect(), {
|
|
113
|
+
placement: this.options.position,
|
|
114
|
+
offset: this.options.offset,
|
|
115
|
+
});
|
|
111
116
|
this.tooltipElement.style.left = `${left}px`;
|
|
112
117
|
this.tooltipElement.style.top = `${top}px`;
|
|
113
118
|
this.tooltipElement.setAttribute('data-position', placement);
|
|
114
119
|
}
|
|
115
120
|
attachEvents() {
|
|
116
|
-
this.
|
|
117
|
-
this.trigger.addEventListener('
|
|
118
|
-
this.trigger.addEventListener('
|
|
119
|
-
this.trigger.addEventListener('
|
|
121
|
+
const sig = { signal: this.listeners.signal };
|
|
122
|
+
this.trigger.addEventListener('mouseenter', () => this.show(), sig);
|
|
123
|
+
this.trigger.addEventListener('mouseleave', () => this.hide(), sig);
|
|
124
|
+
this.trigger.addEventListener('focus', () => this.show(), sig);
|
|
125
|
+
this.trigger.addEventListener('blur', () => this.hide(), sig);
|
|
120
126
|
}
|
|
121
|
-
handleMouseEnter = () => {
|
|
122
|
-
this.show();
|
|
123
|
-
};
|
|
124
|
-
handleMouseLeave = () => {
|
|
125
|
-
this.hide();
|
|
126
|
-
};
|
|
127
|
-
handleFocus = () => {
|
|
128
|
-
this.show();
|
|
129
|
-
};
|
|
130
|
-
handleBlur = () => {
|
|
131
|
-
this.hide();
|
|
132
|
-
};
|
|
133
127
|
destroy() {
|
|
134
128
|
this.hide();
|
|
135
|
-
this.
|
|
136
|
-
this.trigger.removeEventListener('mouseleave', this.handleMouseLeave);
|
|
137
|
-
this.trigger.removeEventListener('focus', this.handleFocus);
|
|
138
|
-
this.trigger.removeEventListener('blur', this.handleBlur);
|
|
129
|
+
this.listeners.destroy();
|
|
139
130
|
const previousDescribedBy = this.trigger.getAttribute('data-previous-describedby');
|
|
140
131
|
if (previousDescribedBy) {
|
|
141
132
|
this.trigger.setAttribute('aria-describedby', previousDescribedBy);
|
package/js/tree.d.ts
CHANGED
|
@@ -18,7 +18,6 @@ declare class TreeComponent {
|
|
|
18
18
|
private selectedNode;
|
|
19
19
|
private readonly options;
|
|
20
20
|
constructor(elementOrSelector: string | HTMLElement, data: TreeNode[], options?: TreeOptions);
|
|
21
|
-
private init;
|
|
22
21
|
render(): void;
|
|
23
22
|
private renderNode;
|
|
24
23
|
private createIconElement;
|
package/js/tree.js
CHANGED
|
@@ -22,9 +22,7 @@ class TreeComponent {
|
|
|
22
22
|
selectedNode;
|
|
23
23
|
options;
|
|
24
24
|
constructor(elementOrSelector, data, options = {}) {
|
|
25
|
-
const container = typeof elementOrSelector === 'string'
|
|
26
|
-
? document.querySelector(elementOrSelector)
|
|
27
|
-
: elementOrSelector;
|
|
25
|
+
const container = typeof elementOrSelector === 'string' ? document.querySelector(elementOrSelector) : elementOrSelector;
|
|
28
26
|
if (!container) {
|
|
29
27
|
throw new Error(`TreeComponent: Element not found for selector "${elementOrSelector}"`);
|
|
30
28
|
}
|
|
@@ -32,14 +30,11 @@ class TreeComponent {
|
|
|
32
30
|
this.data = data;
|
|
33
31
|
this.selectedNode = null;
|
|
34
32
|
this.options = options;
|
|
35
|
-
this.init();
|
|
36
|
-
}
|
|
37
|
-
init() {
|
|
38
33
|
this.render();
|
|
39
34
|
}
|
|
40
35
|
render() {
|
|
41
36
|
this.container.innerHTML = '';
|
|
42
|
-
this.data.forEach(node => {
|
|
37
|
+
this.data.forEach((node) => {
|
|
43
38
|
this.renderNode(node, this.container);
|
|
44
39
|
});
|
|
45
40
|
}
|
|
@@ -107,7 +102,7 @@ class TreeComponent {
|
|
|
107
102
|
childrenUl.classList.add('expanded');
|
|
108
103
|
childrenUl.style.height = 'auto';
|
|
109
104
|
}
|
|
110
|
-
node.children.forEach(child => {
|
|
105
|
+
node.children.forEach((child) => {
|
|
111
106
|
this.renderNode(child, childrenUl);
|
|
112
107
|
});
|
|
113
108
|
return childrenUl;
|
|
@@ -126,13 +121,13 @@ class TreeComponent {
|
|
|
126
121
|
}
|
|
127
122
|
}
|
|
128
123
|
expandChildren(container) {
|
|
129
|
-
container.style.height = container.scrollHeight
|
|
124
|
+
container.style.height = `${container.scrollHeight}px`;
|
|
130
125
|
container.addEventListener('transitionend', () => {
|
|
131
126
|
container.style.height = 'auto';
|
|
132
127
|
}, { once: true });
|
|
133
128
|
}
|
|
134
129
|
collapseChildren(container) {
|
|
135
|
-
container.style.height = container.offsetHeight
|
|
130
|
+
container.style.height = `${container.offsetHeight}px`;
|
|
136
131
|
requestAnimationFrame(() => {
|
|
137
132
|
container.style.height = '0';
|
|
138
133
|
});
|
|
@@ -172,7 +167,7 @@ class TreeComponent {
|
|
|
172
167
|
});
|
|
173
168
|
}
|
|
174
169
|
traverseNodes(nodes, callback) {
|
|
175
|
-
nodes.forEach(node => {
|
|
170
|
+
nodes.forEach((node) => {
|
|
176
171
|
callback(node);
|
|
177
172
|
if (node.children.length > 0) {
|
|
178
173
|
this.traverseNodes(node.children, callback);
|
package/js/utils.js
CHANGED
|
@@ -9,10 +9,10 @@ const utils = {
|
|
|
9
9
|
},
|
|
10
10
|
value(element) {
|
|
11
11
|
if (element.hasAttribute('value')) {
|
|
12
|
-
return element.getAttribute('value')
|
|
12
|
+
return element.getAttribute('value');
|
|
13
13
|
}
|
|
14
14
|
if (element.hasAttribute('data-value')) {
|
|
15
|
-
return element.getAttribute('data-value')
|
|
15
|
+
return element.getAttribute('data-value');
|
|
16
16
|
}
|
|
17
17
|
return element.innerText;
|
|
18
18
|
},
|
|
@@ -26,11 +26,11 @@ const utils = {
|
|
|
26
26
|
return undefined;
|
|
27
27
|
},
|
|
28
28
|
isList(element) {
|
|
29
|
-
return NodeList
|
|
29
|
+
return element instanceof NodeList;
|
|
30
30
|
},
|
|
31
31
|
isHidden(element) {
|
|
32
32
|
return element.offsetParent === null;
|
|
33
|
-
}
|
|
33
|
+
},
|
|
34
34
|
};
|
|
35
35
|
function escapeHtml(text) {
|
|
36
36
|
const div = document.createElement('div');
|
|
@@ -40,11 +40,10 @@ function escapeHtml(text) {
|
|
|
40
40
|
function sanitizeHtml(html) {
|
|
41
41
|
const parser = new DOMParser();
|
|
42
42
|
const doc = parser.parseFromString(html, 'text/html');
|
|
43
|
-
doc.querySelectorAll('script, style, iframe, object, embed').forEach(el => el.remove());
|
|
44
|
-
doc.querySelectorAll('*').forEach(el => {
|
|
43
|
+
doc.querySelectorAll('script, style, iframe, object, embed').forEach((el) => el.remove());
|
|
44
|
+
doc.querySelectorAll('*').forEach((el) => {
|
|
45
45
|
for (const attr of Array.from(el.attributes)) {
|
|
46
|
-
if (attr.name.startsWith('on') ||
|
|
47
|
-
attr.value.trim().toLowerCase().startsWith('javascript:')) {
|
|
46
|
+
if (attr.name.startsWith('on') || attr.value.trim().toLowerCase().startsWith('javascript:')) {
|
|
48
47
|
el.removeAttribute(attr.name);
|
|
49
48
|
}
|
|
50
49
|
}
|
package/js/virtual-dropdown.d.ts
CHANGED