@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/lightbox.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ListenerGroup } from './listeners.js';
|
|
1
2
|
class Lightbox {
|
|
2
3
|
images;
|
|
3
4
|
currentIndex;
|
|
@@ -9,7 +10,7 @@ class Lightbox {
|
|
|
9
10
|
captionEl = null;
|
|
10
11
|
counterEl = null;
|
|
11
12
|
isZoomed = false;
|
|
12
|
-
|
|
13
|
+
listeners = new ListenerGroup();
|
|
13
14
|
constructor(options) {
|
|
14
15
|
if (options.images && options.images.length > 0) {
|
|
15
16
|
this.images = options.images;
|
|
@@ -36,12 +37,12 @@ class Lightbox {
|
|
|
36
37
|
this.imgEl = wrapper.querySelector('.lightbox-img');
|
|
37
38
|
this.captionEl = wrapper.querySelector('.lightbox-caption');
|
|
38
39
|
this.counterEl = wrapper.querySelector('.lightbox-counter');
|
|
39
|
-
const sig = { signal: this.
|
|
40
|
+
const sig = { signal: this.listeners.signal };
|
|
40
41
|
if (this.closeable) {
|
|
41
|
-
wrapper.querySelector('.lightbox-close')?.addEventListener('click', this.hide, sig);
|
|
42
|
-
wrapper.querySelector('.lightbox-background')?.addEventListener('click', this.handleBackgroundClick, sig);
|
|
42
|
+
wrapper.querySelector('.lightbox-close')?.addEventListener('click', () => this.hide(), sig);
|
|
43
|
+
wrapper.querySelector('.lightbox-background')?.addEventListener('click', (e) => this.handleBackgroundClick(e), sig);
|
|
43
44
|
}
|
|
44
|
-
document.addEventListener('keydown', this.handleKeydown, sig);
|
|
45
|
+
document.addEventListener('keydown', (e) => this.handleKeydown(e), sig);
|
|
45
46
|
if (this.images.length > 1) {
|
|
46
47
|
wrapper.querySelector('.lightbox-prev')?.addEventListener('click', () => this.prev(), sig);
|
|
47
48
|
wrapper.querySelector('.lightbox-next')?.addEventListener('click', () => this.next(), sig);
|
|
@@ -57,12 +58,11 @@ class Lightbox {
|
|
|
57
58
|
});
|
|
58
59
|
this.onOpen?.();
|
|
59
60
|
}
|
|
60
|
-
hide
|
|
61
|
+
hide() {
|
|
61
62
|
const wrapper = this.wrapper;
|
|
62
63
|
if (!wrapper)
|
|
63
64
|
return;
|
|
64
|
-
this.
|
|
65
|
-
this.abortController = new AbortController();
|
|
65
|
+
this.listeners.reset();
|
|
66
66
|
document.body.style.overflow = '';
|
|
67
67
|
wrapper.classList.remove('is-visible');
|
|
68
68
|
setTimeout(() => {
|
|
@@ -76,7 +76,7 @@ class Lightbox {
|
|
|
76
76
|
}
|
|
77
77
|
this.onClose?.();
|
|
78
78
|
}, 300);
|
|
79
|
-
}
|
|
79
|
+
}
|
|
80
80
|
next() {
|
|
81
81
|
if (this.images.length <= 1)
|
|
82
82
|
return;
|
|
@@ -137,7 +137,7 @@ class Lightbox {
|
|
|
137
137
|
return;
|
|
138
138
|
const prevIdx = (index - 1 + this.images.length) % this.images.length;
|
|
139
139
|
const nextIdx = (index + 1) % this.images.length;
|
|
140
|
-
[prevIdx, nextIdx].forEach(i => {
|
|
140
|
+
[prevIdx, nextIdx].forEach((i) => {
|
|
141
141
|
const img = new Image();
|
|
142
142
|
img.src = this.images[i].src;
|
|
143
143
|
});
|
|
@@ -164,7 +164,7 @@ class Lightbox {
|
|
|
164
164
|
this.imgEl.classList.toggle('is-zoomed', this.isZoomed);
|
|
165
165
|
this.wrapper?.querySelector('.lightbox-img-wrap')?.classList.toggle('is-zoomed', this.isZoomed);
|
|
166
166
|
}
|
|
167
|
-
handleKeydown
|
|
167
|
+
handleKeydown(e) {
|
|
168
168
|
switch (e.key) {
|
|
169
169
|
case 'Escape':
|
|
170
170
|
if (this.closeable)
|
|
@@ -180,11 +180,11 @@ class Lightbox {
|
|
|
180
180
|
this.trapFocus(e);
|
|
181
181
|
break;
|
|
182
182
|
}
|
|
183
|
-
}
|
|
183
|
+
}
|
|
184
184
|
trapFocus(e) {
|
|
185
185
|
if (!this.wrapper)
|
|
186
186
|
return;
|
|
187
|
-
const focusable = Array.from(this.wrapper.querySelectorAll('button:not([hidden]), [tabindex]:not([tabindex="-1"]):not([hidden])')).filter(el => el.offsetParent !== null);
|
|
187
|
+
const focusable = Array.from(this.wrapper.querySelectorAll('button:not([hidden]), [tabindex]:not([tabindex="-1"]):not([hidden])')).filter((el) => el.offsetParent !== null);
|
|
188
188
|
if (focusable.length === 0)
|
|
189
189
|
return;
|
|
190
190
|
const first = focusable[0];
|
|
@@ -202,11 +202,11 @@ class Lightbox {
|
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
|
-
handleBackgroundClick
|
|
205
|
+
handleBackgroundClick(e) {
|
|
206
206
|
if (e.target?.classList.contains('lightbox-background')) {
|
|
207
207
|
this.hide();
|
|
208
208
|
}
|
|
209
|
-
}
|
|
209
|
+
}
|
|
210
210
|
addTouchSupport() {
|
|
211
211
|
const wrap = this.wrapper?.querySelector('.lightbox-img-wrap');
|
|
212
212
|
if (!wrap)
|
|
@@ -216,16 +216,21 @@ class Lightbox {
|
|
|
216
216
|
wrap.addEventListener('touchstart', (e) => {
|
|
217
217
|
startX = e.touches[0].clientX;
|
|
218
218
|
isDragging = true;
|
|
219
|
-
}, { passive: true, signal: this.
|
|
219
|
+
}, { passive: true, signal: this.listeners.signal });
|
|
220
220
|
wrap.addEventListener('touchend', (e) => {
|
|
221
221
|
if (!isDragging)
|
|
222
222
|
return;
|
|
223
223
|
const deltaX = e.changedTouches[0].clientX - startX;
|
|
224
224
|
if (Math.abs(deltaX) > 50) {
|
|
225
|
-
deltaX < 0
|
|
225
|
+
if (deltaX < 0) {
|
|
226
|
+
this.next();
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
this.prev();
|
|
230
|
+
}
|
|
226
231
|
}
|
|
227
232
|
isDragging = false;
|
|
228
|
-
}, { signal: this.
|
|
233
|
+
}, { signal: this.listeners.signal });
|
|
229
234
|
}
|
|
230
235
|
buildTemplate() {
|
|
231
236
|
return `
|
|
@@ -250,13 +255,9 @@ class Lightbox {
|
|
|
250
255
|
static bind(selector = '[data-lightbox]') {
|
|
251
256
|
const elements = document.querySelectorAll(selector);
|
|
252
257
|
const groups = new Map();
|
|
253
|
-
elements.forEach(el => {
|
|
258
|
+
elements.forEach((el) => {
|
|
254
259
|
const groupKey = el.dataset.lightbox || `__solo__${el.dataset.lightboxId ?? Math.random()}`;
|
|
255
|
-
const src = el instanceof HTMLAnchorElement
|
|
256
|
-
? el.href
|
|
257
|
-
: el instanceof HTMLImageElement
|
|
258
|
-
? el.src
|
|
259
|
-
: (el.dataset.src ?? '');
|
|
260
|
+
const src = el instanceof HTMLAnchorElement ? el.href : el instanceof HTMLImageElement ? el.src : (el.dataset.src ?? '');
|
|
260
261
|
const imgChild = el.querySelector('img');
|
|
261
262
|
const alt = el instanceof HTMLImageElement ? el.alt : (imgChild?.alt ?? '');
|
|
262
263
|
const caption = el.dataset.lightboxCaption;
|
|
@@ -264,13 +265,13 @@ class Lightbox {
|
|
|
264
265
|
groups.set(groupKey, []);
|
|
265
266
|
groups.get(groupKey).push({ el, image: { src, alt, caption } });
|
|
266
267
|
});
|
|
267
|
-
groups.forEach(items => {
|
|
268
|
+
groups.forEach((items) => {
|
|
268
269
|
items.forEach(({ el }, idx) => {
|
|
269
270
|
el.style.cursor = 'zoom-in';
|
|
270
|
-
el.addEventListener('click', e => {
|
|
271
|
+
el.addEventListener('click', (e) => {
|
|
271
272
|
e.preventDefault();
|
|
272
273
|
new Lightbox({
|
|
273
|
-
images: items.map(i => i.image),
|
|
274
|
+
images: items.map((i) => i.image),
|
|
274
275
|
startIndex: idx,
|
|
275
276
|
}).show();
|
|
276
277
|
});
|
package/js/listeners.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class ListenerGroup {
|
|
2
|
+
controller = new AbortController();
|
|
3
|
+
get signal() {
|
|
4
|
+
return this.controller.signal;
|
|
5
|
+
}
|
|
6
|
+
reset() {
|
|
7
|
+
this.controller.abort();
|
|
8
|
+
this.controller = new AbortController();
|
|
9
|
+
}
|
|
10
|
+
destroy() {
|
|
11
|
+
this.controller.abort();
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export { ListenerGroup };
|
package/js/modal.d.ts
CHANGED
|
@@ -14,10 +14,11 @@ declare class Modal {
|
|
|
14
14
|
private readonly type;
|
|
15
15
|
private template;
|
|
16
16
|
private modalWrapper;
|
|
17
|
+
private listeners;
|
|
17
18
|
constructor(options: ModalOptions);
|
|
18
19
|
constructor(content: string, header?: string, footer?: string, closeable?: boolean, type?: ModalType);
|
|
19
20
|
show(): void;
|
|
20
|
-
hide
|
|
21
|
+
hide(): void;
|
|
21
22
|
private handleEscape;
|
|
22
23
|
private handleBackgroundClick;
|
|
23
24
|
private buildTemplate;
|
package/js/modal.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { sanitizeHtml } from './utils.js';
|
|
2
|
+
import { ListenerGroup } from './listeners.js';
|
|
2
3
|
const CLOSE_ICON = '<div class="icon icon-close close"></div>';
|
|
3
4
|
class Modal {
|
|
4
5
|
content;
|
|
@@ -8,6 +9,7 @@ class Modal {
|
|
|
8
9
|
type;
|
|
9
10
|
template;
|
|
10
11
|
modalWrapper = null;
|
|
12
|
+
listeners = new ListenerGroup();
|
|
11
13
|
constructor(contentOrOptions, header, footer, closeable = true, type = 'default') {
|
|
12
14
|
if (typeof contentOrOptions === 'object') {
|
|
13
15
|
this.content = contentOrOptions.content;
|
|
@@ -32,31 +34,22 @@ class Modal {
|
|
|
32
34
|
wrapper.innerHTML = this.template;
|
|
33
35
|
document.body.append(wrapper);
|
|
34
36
|
this.modalWrapper = wrapper;
|
|
37
|
+
const sig = { signal: this.listeners.signal };
|
|
35
38
|
if (this.closeable) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const background = wrapper.querySelector('.modal-background');
|
|
40
|
-
if (this.closeable && background) {
|
|
41
|
-
background.addEventListener('click', this.handleBackgroundClick);
|
|
42
|
-
}
|
|
43
|
-
if (this.closeable) {
|
|
44
|
-
document.addEventListener('keydown', this.handleEscape);
|
|
39
|
+
wrapper.querySelector('.close')?.addEventListener('click', () => this.hide(), sig);
|
|
40
|
+
wrapper.querySelector('.modal-background')?.addEventListener('click', (e) => this.handleBackgroundClick(e), sig);
|
|
41
|
+
document.addEventListener('keydown', (e) => this.handleEscape(e), sig);
|
|
45
42
|
}
|
|
46
43
|
document.body.style.overflow = 'hidden';
|
|
47
44
|
requestAnimationFrame(() => {
|
|
48
45
|
wrapper.classList.add('is-visible');
|
|
49
46
|
});
|
|
50
47
|
}
|
|
51
|
-
hide
|
|
48
|
+
hide() {
|
|
52
49
|
const wrapper = this.modalWrapper;
|
|
53
50
|
if (!wrapper)
|
|
54
51
|
return;
|
|
55
|
-
|
|
56
|
-
closeBtn?.removeEventListener('click', this.hide);
|
|
57
|
-
const background = wrapper.querySelector('.modal-background');
|
|
58
|
-
background?.removeEventListener('click', this.handleBackgroundClick);
|
|
59
|
-
document.removeEventListener('keydown', this.handleEscape);
|
|
52
|
+
this.listeners.reset();
|
|
60
53
|
document.body.style.overflow = '';
|
|
61
54
|
wrapper.classList.remove('is-visible');
|
|
62
55
|
setTimeout(() => {
|
|
@@ -65,17 +58,17 @@ class Modal {
|
|
|
65
58
|
this.modalWrapper = null;
|
|
66
59
|
}
|
|
67
60
|
}, 300);
|
|
68
|
-
}
|
|
69
|
-
handleEscape
|
|
61
|
+
}
|
|
62
|
+
handleEscape(e) {
|
|
70
63
|
if (e.key === 'Escape') {
|
|
71
64
|
this.hide();
|
|
72
65
|
}
|
|
73
|
-
}
|
|
74
|
-
handleBackgroundClick
|
|
66
|
+
}
|
|
67
|
+
handleBackgroundClick(e) {
|
|
75
68
|
if (e.target?.classList.contains('modal-background')) {
|
|
76
69
|
this.hide();
|
|
77
70
|
}
|
|
78
|
-
}
|
|
71
|
+
}
|
|
79
72
|
buildTemplate() {
|
|
80
73
|
const parts = [`<div class="modal modal-${this.type}">`];
|
|
81
74
|
if (this.closeable) {
|
package/js/popover.d.ts
CHANGED
|
@@ -21,8 +21,9 @@ declare class Popover {
|
|
|
21
21
|
private readonly trigger;
|
|
22
22
|
private readonly opts;
|
|
23
23
|
private popoverEl;
|
|
24
|
-
private _isOpen;
|
|
25
24
|
private hoverTimer;
|
|
25
|
+
private listeners;
|
|
26
|
+
private openListeners;
|
|
26
27
|
constructor(triggerEl: HTMLElement | string, options: PopoverOptions);
|
|
27
28
|
get isOpen(): boolean;
|
|
28
29
|
open(): void;
|
|
@@ -39,7 +40,6 @@ declare class Popover {
|
|
|
39
40
|
private onOutsideClick;
|
|
40
41
|
private onEscape;
|
|
41
42
|
private attachTrigger;
|
|
42
|
-
private detachTrigger;
|
|
43
43
|
}
|
|
44
44
|
export { Popover };
|
|
45
45
|
export type { PopoverOptions, PopoverPlacement, PopoverAlign, PopoverTrigger };
|
package/js/popover.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { computePosition } from './position.js';
|
|
2
2
|
import { sanitizeHtml } from './utils.js';
|
|
3
|
+
import { ListenerGroup } from './listeners.js';
|
|
3
4
|
const ARROW_SIZE = 6;
|
|
4
5
|
class Popover {
|
|
5
6
|
static openPopovers = new Set();
|
|
@@ -7,12 +8,11 @@ class Popover {
|
|
|
7
8
|
trigger;
|
|
8
9
|
opts;
|
|
9
10
|
popoverEl = null;
|
|
10
|
-
_isOpen = false;
|
|
11
11
|
hoverTimer = null;
|
|
12
|
+
listeners = new ListenerGroup();
|
|
13
|
+
openListeners = null;
|
|
12
14
|
constructor(triggerEl, options) {
|
|
13
|
-
const el = typeof triggerEl === 'string'
|
|
14
|
-
? document.querySelector(triggerEl)
|
|
15
|
-
: triggerEl;
|
|
15
|
+
const el = typeof triggerEl === 'string' ? document.querySelector(triggerEl) : triggerEl;
|
|
16
16
|
if (!el)
|
|
17
17
|
throw new Error('Popover: trigger element not found');
|
|
18
18
|
this.trigger = el;
|
|
@@ -31,9 +31,11 @@ class Popover {
|
|
|
31
31
|
};
|
|
32
32
|
this.attachTrigger();
|
|
33
33
|
}
|
|
34
|
-
get isOpen() {
|
|
34
|
+
get isOpen() {
|
|
35
|
+
return this.popoverEl !== null;
|
|
36
|
+
}
|
|
35
37
|
open() {
|
|
36
|
-
if (this.
|
|
38
|
+
if (this.popoverEl)
|
|
37
39
|
return;
|
|
38
40
|
if (this.opts.triggerMode === 'click')
|
|
39
41
|
Popover.closeAll();
|
|
@@ -42,40 +44,47 @@ class Popover {
|
|
|
42
44
|
this.reposition();
|
|
43
45
|
requestAnimationFrame(() => {
|
|
44
46
|
this.popoverEl?.classList.add('is-open');
|
|
45
|
-
this._isOpen = true;
|
|
46
47
|
Popover.openPopovers.add(this);
|
|
47
48
|
this.opts.onOpen();
|
|
49
|
+
this.openListeners = new ListenerGroup();
|
|
50
|
+
const openSig = { signal: this.openListeners.signal };
|
|
48
51
|
if (this.opts.closeOnOutsideClick)
|
|
49
|
-
document.addEventListener('pointerdown', this.onOutsideClick, { capture: true });
|
|
52
|
+
document.addEventListener('pointerdown', (e) => this.onOutsideClick(e), { ...openSig, capture: true });
|
|
50
53
|
if (this.opts.closeOnEscape)
|
|
51
|
-
document.addEventListener('keydown', this.onEscape);
|
|
54
|
+
document.addEventListener('keydown', (e) => this.onEscape(e), openSig);
|
|
52
55
|
});
|
|
53
56
|
}
|
|
54
57
|
close() {
|
|
55
|
-
if (!this.
|
|
58
|
+
if (!this.popoverEl)
|
|
56
59
|
return;
|
|
57
60
|
this.popoverEl.classList.remove('is-open');
|
|
58
|
-
this._isOpen = false;
|
|
59
61
|
Popover.openPopovers.delete(this);
|
|
60
62
|
this.opts.onClose();
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
this.openListeners?.destroy();
|
|
64
|
+
this.openListeners = null;
|
|
63
65
|
this.trigger.removeAttribute('aria-expanded');
|
|
64
66
|
this.trigger.removeAttribute('aria-controls');
|
|
65
67
|
const el = this.popoverEl;
|
|
66
68
|
setTimeout(() => el.remove(), 200);
|
|
67
69
|
this.popoverEl = null;
|
|
68
70
|
}
|
|
69
|
-
toggle() {
|
|
71
|
+
toggle() {
|
|
72
|
+
if (this.popoverEl) {
|
|
73
|
+
this.close();
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
this.open();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
70
79
|
destroy() {
|
|
71
80
|
this.close();
|
|
72
|
-
this.
|
|
81
|
+
this.listeners.destroy();
|
|
73
82
|
}
|
|
74
83
|
static closeAll() {
|
|
75
|
-
Popover.openPopovers.forEach(p => p.close());
|
|
84
|
+
Popover.openPopovers.forEach((p) => p.close());
|
|
76
85
|
}
|
|
77
86
|
static initAll() {
|
|
78
|
-
document.querySelectorAll('[data-popover]').forEach(trigger => {
|
|
87
|
+
document.querySelectorAll('[data-popover]').forEach((trigger) => {
|
|
79
88
|
const sel = trigger.getAttribute('data-popover');
|
|
80
89
|
if (!sel)
|
|
81
90
|
return;
|
|
@@ -100,9 +109,7 @@ class Popover {
|
|
|
100
109
|
el.setAttribute('data-arrow', String(this.opts.arrow));
|
|
101
110
|
const hasStructure = /class="popover-(header|body|footer|menu)/.test(this.opts.content);
|
|
102
111
|
const safeContent = sanitizeHtml(this.opts.content);
|
|
103
|
-
el.innerHTML = hasStructure
|
|
104
|
-
? safeContent
|
|
105
|
-
: `<div class="popover-body">${safeContent}</div>`;
|
|
112
|
+
el.innerHTML = hasStructure ? safeContent : `<div class="popover-body">${safeContent}</div>`;
|
|
106
113
|
this.trigger.setAttribute('aria-expanded', 'true');
|
|
107
114
|
this.trigger.setAttribute('aria-controls', id);
|
|
108
115
|
return el;
|
|
@@ -123,37 +130,35 @@ class Popover {
|
|
|
123
130
|
this.popoverEl.style.left = `${left}px`;
|
|
124
131
|
this.popoverEl.style.top = `${top}px`;
|
|
125
132
|
}
|
|
126
|
-
onClick
|
|
127
|
-
|
|
133
|
+
onClick() {
|
|
134
|
+
this.toggle();
|
|
135
|
+
}
|
|
136
|
+
onMouseEnter() {
|
|
128
137
|
if (this.hoverTimer !== null)
|
|
129
138
|
clearTimeout(this.hoverTimer);
|
|
130
139
|
this.open();
|
|
131
|
-
}
|
|
132
|
-
onMouseLeave
|
|
140
|
+
}
|
|
141
|
+
onMouseLeave() {
|
|
133
142
|
this.hoverTimer = window.setTimeout(() => this.close(), 120);
|
|
134
|
-
}
|
|
135
|
-
onOutsideClick
|
|
143
|
+
}
|
|
144
|
+
onOutsideClick(e) {
|
|
136
145
|
const t = e.target;
|
|
137
146
|
if (!this.popoverEl?.contains(t) && !this.trigger.contains(t))
|
|
138
147
|
this.close();
|
|
139
|
-
}
|
|
140
|
-
onEscape
|
|
148
|
+
}
|
|
149
|
+
onEscape(e) {
|
|
141
150
|
if (e.key === 'Escape')
|
|
142
151
|
this.close();
|
|
143
|
-
}
|
|
152
|
+
}
|
|
144
153
|
attachTrigger() {
|
|
154
|
+
const sig = { signal: this.listeners.signal };
|
|
145
155
|
if (this.opts.triggerMode === 'click') {
|
|
146
|
-
this.trigger.addEventListener('click', this.onClick);
|
|
156
|
+
this.trigger.addEventListener('click', () => this.onClick(), sig);
|
|
147
157
|
}
|
|
148
158
|
else {
|
|
149
|
-
this.trigger.addEventListener('mouseenter', this.onMouseEnter);
|
|
150
|
-
this.trigger.addEventListener('mouseleave', this.onMouseLeave);
|
|
159
|
+
this.trigger.addEventListener('mouseenter', () => this.onMouseEnter(), sig);
|
|
160
|
+
this.trigger.addEventListener('mouseleave', () => this.onMouseLeave(), sig);
|
|
151
161
|
}
|
|
152
162
|
}
|
|
153
|
-
detachTrigger() {
|
|
154
|
-
this.trigger.removeEventListener('click', this.onClick);
|
|
155
|
-
this.trigger.removeEventListener('mouseenter', this.onMouseEnter);
|
|
156
|
-
this.trigger.removeEventListener('mouseleave', this.onMouseLeave);
|
|
157
|
-
}
|
|
158
163
|
}
|
|
159
164
|
export { Popover };
|
package/js/position.js
CHANGED
|
@@ -13,7 +13,7 @@ function bestPlacement(trigger, floating, offset) {
|
|
|
13
13
|
return 'right';
|
|
14
14
|
if (space.left >= floating.width)
|
|
15
15
|
return 'left';
|
|
16
|
-
return
|
|
16
|
+
return Object.entries(space).sort((a, b) => b[1] - a[1])[0][0];
|
|
17
17
|
}
|
|
18
18
|
function maybeFlip(placement, trigger, floating, offset) {
|
|
19
19
|
const fits = {
|
|
@@ -23,15 +23,13 @@ function maybeFlip(placement, trigger, floating, offset) {
|
|
|
23
23
|
right: window.innerWidth - trigger.right - offset >= floating.width,
|
|
24
24
|
};
|
|
25
25
|
const opp = { top: 'bottom', bottom: 'top', left: 'right', right: 'left' };
|
|
26
|
-
return
|
|
26
|
+
return !fits[placement] && fits[opp[placement]] ? opp[placement] : placement;
|
|
27
27
|
}
|
|
28
28
|
function computePosition(trigger, floating, opts) {
|
|
29
29
|
const offset = opts.offset ?? 8;
|
|
30
30
|
const margin = opts.margin ?? 8;
|
|
31
31
|
const align = opts.align ?? 'center';
|
|
32
|
-
const placement = opts.placement === 'auto'
|
|
33
|
-
? bestPlacement(trigger, floating, offset)
|
|
34
|
-
: maybeFlip(opts.placement, trigger, floating, offset);
|
|
32
|
+
const placement = opts.placement === 'auto' ? bestPlacement(trigger, floating, offset) : maybeFlip(opts.placement, trigger, floating, offset);
|
|
35
33
|
let left = 0, top = 0;
|
|
36
34
|
switch (placement) {
|
|
37
35
|
case 'top':
|
package/js/push-menu.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ declare class PushMenu {
|
|
|
10
10
|
private static elements;
|
|
11
11
|
private static initialized;
|
|
12
12
|
private static panelStack;
|
|
13
|
+
private static listeners;
|
|
14
|
+
private static clickNavListeners;
|
|
13
15
|
static init(): void;
|
|
14
16
|
private static buildPanels;
|
|
15
17
|
private static extractSubPanels;
|
package/js/push-menu.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ListenerGroup } from './listeners.js';
|
|
1
2
|
class PushMenu {
|
|
2
3
|
static elements = {
|
|
3
4
|
navigation: null,
|
|
@@ -5,10 +6,12 @@ class PushMenu {
|
|
|
5
6
|
menu: null,
|
|
6
7
|
header: null,
|
|
7
8
|
controlIcon: null,
|
|
8
|
-
backdrop: null
|
|
9
|
+
backdrop: null,
|
|
9
10
|
};
|
|
10
11
|
static initialized = false;
|
|
11
12
|
static panelStack = [];
|
|
13
|
+
static listeners = new ListenerGroup();
|
|
14
|
+
static clickNavListeners = null;
|
|
12
15
|
static init() {
|
|
13
16
|
if (this.initialized) {
|
|
14
17
|
console.warn('PushMenu: Already initialized');
|
|
@@ -19,8 +22,9 @@ class PushMenu {
|
|
|
19
22
|
throw new Error('PushMenu: Required elements not found (.navigation, .push-content)');
|
|
20
23
|
}
|
|
21
24
|
this.buildPanels();
|
|
22
|
-
this.
|
|
23
|
-
this.elements.
|
|
25
|
+
const sig = { signal: this.listeners.signal };
|
|
26
|
+
this.elements.navigation.addEventListener('change', () => this.handleNavigationChange(), sig);
|
|
27
|
+
this.elements.backdrop?.addEventListener('click', () => this.handleBackdropClick(), sig);
|
|
24
28
|
this.initialized = true;
|
|
25
29
|
}
|
|
26
30
|
static buildPanels() {
|
|
@@ -117,17 +121,19 @@ class PushMenu {
|
|
|
117
121
|
}
|
|
118
122
|
}, 300);
|
|
119
123
|
}
|
|
120
|
-
static handleNavigationChange
|
|
124
|
+
static handleNavigationChange() {
|
|
121
125
|
const isPushed = this.elements.content?.classList.contains('pushed') ?? false;
|
|
122
126
|
if (!isPushed) {
|
|
123
|
-
this.
|
|
127
|
+
this.clickNavListeners = new ListenerGroup();
|
|
128
|
+
this.elements.content?.addEventListener('click', () => this.clickNav(), { signal: this.clickNavListeners.signal });
|
|
124
129
|
}
|
|
125
130
|
else {
|
|
126
|
-
this.
|
|
131
|
+
this.clickNavListeners?.destroy();
|
|
132
|
+
this.clickNavListeners = null;
|
|
127
133
|
this.resetPanels();
|
|
128
134
|
}
|
|
129
135
|
this.pushToggle();
|
|
130
|
-
}
|
|
136
|
+
}
|
|
131
137
|
static pushToggle() {
|
|
132
138
|
if (!this.elements.content || !this.elements.menu) {
|
|
133
139
|
throw new Error('PushMenu: Required elements not found (.push-content, .push-menu)');
|
|
@@ -148,14 +154,14 @@ class PushMenu {
|
|
|
148
154
|
}
|
|
149
155
|
}
|
|
150
156
|
}
|
|
151
|
-
static clickNav
|
|
157
|
+
static clickNav() {
|
|
152
158
|
PushMenu.elements.navigation.click();
|
|
153
|
-
}
|
|
154
|
-
static handleBackdropClick
|
|
159
|
+
}
|
|
160
|
+
static handleBackdropClick() {
|
|
155
161
|
if (PushMenu.isOpen()) {
|
|
156
162
|
PushMenu.elements.navigation.click();
|
|
157
163
|
}
|
|
158
|
-
}
|
|
164
|
+
}
|
|
159
165
|
static open() {
|
|
160
166
|
if (!this.elements.content?.classList.contains('pushed')) {
|
|
161
167
|
this.pushToggle();
|
|
@@ -172,9 +178,9 @@ class PushMenu {
|
|
|
172
178
|
static destroy() {
|
|
173
179
|
if (!this.initialized)
|
|
174
180
|
return;
|
|
175
|
-
this.
|
|
176
|
-
this.
|
|
177
|
-
this.
|
|
181
|
+
this.listeners.reset();
|
|
182
|
+
this.clickNavListeners?.destroy();
|
|
183
|
+
this.clickNavListeners = null;
|
|
178
184
|
this.close();
|
|
179
185
|
this.elements = {
|
|
180
186
|
navigation: null,
|
|
@@ -182,7 +188,7 @@ class PushMenu {
|
|
|
182
188
|
menu: null,
|
|
183
189
|
header: null,
|
|
184
190
|
controlIcon: null,
|
|
185
|
-
backdrop: null
|
|
191
|
+
backdrop: null,
|
|
186
192
|
};
|
|
187
193
|
this.panelStack = [];
|
|
188
194
|
this.initialized = false;
|
package/js/range-slider.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
declare class RangeSlider {
|
|
2
2
|
private readonly input;
|
|
3
|
-
private
|
|
3
|
+
private listeners;
|
|
4
4
|
constructor(input: HTMLInputElement);
|
|
5
5
|
static initAll(selector?: string): void;
|
|
6
6
|
private update;
|
|
@@ -12,7 +12,7 @@ declare class RangeSliderRange {
|
|
|
12
12
|
private readonly endInput;
|
|
13
13
|
private readonly fill;
|
|
14
14
|
private readonly fillCreatedByUs;
|
|
15
|
-
private
|
|
15
|
+
private listeners;
|
|
16
16
|
constructor(container: HTMLElement);
|
|
17
17
|
static initAll(selector?: string): void;
|
|
18
18
|
values(): [number, number];
|
package/js/range-slider.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { ListenerGroup } from './listeners.js';
|
|
1
2
|
class RangeSlider {
|
|
2
3
|
input;
|
|
3
|
-
|
|
4
|
+
listeners = new ListenerGroup();
|
|
4
5
|
constructor(input) {
|
|
5
6
|
this.input = input;
|
|
6
7
|
this.update();
|
|
7
|
-
this.input.addEventListener('input', () => this.update(), { signal: this.
|
|
8
|
+
this.input.addEventListener('input', () => this.update(), { signal: this.listeners.signal });
|
|
8
9
|
}
|
|
9
10
|
static initAll(selector = '.range-slider input[type="range"]') {
|
|
10
11
|
document.querySelectorAll(selector).forEach((input) => {
|
|
@@ -18,7 +19,7 @@ class RangeSlider {
|
|
|
18
19
|
this.input.style.setProperty('--range-fill', `${pct}%`);
|
|
19
20
|
}
|
|
20
21
|
destroy() {
|
|
21
|
-
this.
|
|
22
|
+
this.listeners.destroy();
|
|
22
23
|
this.input.style.removeProperty('--range-fill');
|
|
23
24
|
}
|
|
24
25
|
}
|
|
@@ -28,7 +29,7 @@ class RangeSliderRange {
|
|
|
28
29
|
endInput;
|
|
29
30
|
fill;
|
|
30
31
|
fillCreatedByUs;
|
|
31
|
-
|
|
32
|
+
listeners = new ListenerGroup();
|
|
32
33
|
constructor(container) {
|
|
33
34
|
const inputs = container.querySelectorAll('input[type="range"]');
|
|
34
35
|
if (inputs.length !== 2) {
|
|
@@ -45,7 +46,7 @@ class RangeSliderRange {
|
|
|
45
46
|
container.insertBefore(this.fill, container.firstChild);
|
|
46
47
|
}
|
|
47
48
|
this.update();
|
|
48
|
-
const signal = this.
|
|
49
|
+
const signal = this.listeners.signal;
|
|
49
50
|
this.startInput.addEventListener('input', () => this.handleInput(this.startInput), { signal });
|
|
50
51
|
this.endInput.addEventListener('input', () => this.handleInput(this.endInput), { signal });
|
|
51
52
|
}
|
|
@@ -75,7 +76,7 @@ class RangeSliderRange {
|
|
|
75
76
|
this.container.style.setProperty('--range-end', `${endPct}%`);
|
|
76
77
|
}
|
|
77
78
|
destroy() {
|
|
78
|
-
this.
|
|
79
|
+
this.listeners.destroy();
|
|
79
80
|
this.container.style.removeProperty('--range-start');
|
|
80
81
|
this.container.style.removeProperty('--range-end');
|
|
81
82
|
if (this.fillCreatedByUs) {
|
package/js/scroll.js
CHANGED
|
@@ -4,14 +4,11 @@ class Scroll {
|
|
|
4
4
|
const offset = fixedHeader ? fixedHeader.offsetHeight : 0;
|
|
5
5
|
const settings = {
|
|
6
6
|
behavior: 'smooth',
|
|
7
|
-
offset
|
|
7
|
+
offset,
|
|
8
8
|
block: 'start',
|
|
9
|
-
...options
|
|
9
|
+
...options,
|
|
10
10
|
};
|
|
11
|
-
|
|
12
|
-
if (typeof target === 'string') {
|
|
13
|
-
el = document.querySelector(target);
|
|
14
|
-
}
|
|
11
|
+
const el = typeof target === 'string' ? document.querySelector(target) : target;
|
|
15
12
|
if (!el)
|
|
16
13
|
return;
|
|
17
14
|
const rect = el.getBoundingClientRect();
|
|
@@ -19,7 +16,7 @@ class Scroll {
|
|
|
19
16
|
const offsetTop = rect.top + scrollTop - settings.offset;
|
|
20
17
|
window.scrollTo({
|
|
21
18
|
top: offsetTop,
|
|
22
|
-
behavior: settings.behavior
|
|
19
|
+
behavior: settings.behavior,
|
|
23
20
|
});
|
|
24
21
|
}
|
|
25
22
|
}
|