@vanduo-oss/framework 1.4.1 → 1.4.2
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 +3 -3
- package/css/components/datepicker.css +3 -1
- package/css/components/modals.css +10 -6
- package/css/components/timepicker.css +3 -1
- package/dist/build-info.json +3 -3
- package/dist/vanduo.cjs.js +86 -11
- package/dist/vanduo.cjs.js.map +2 -2
- package/dist/vanduo.cjs.min.js +5 -5
- package/dist/vanduo.cjs.min.js.map +3 -3
- package/dist/vanduo.css +17 -11
- package/dist/vanduo.css.map +1 -1
- package/dist/vanduo.esm.js +86 -11
- package/dist/vanduo.esm.js.map +2 -2
- package/dist/vanduo.esm.min.js +5 -5
- package/dist/vanduo.esm.min.js.map +3 -3
- package/dist/vanduo.js +86 -11
- package/dist/vanduo.js.map +2 -2
- package/dist/vanduo.min.css +2 -2
- package/dist/vanduo.min.css.map +1 -1
- package/dist/vanduo.min.js +5 -5
- package/dist/vanduo.min.js.map +3 -3
- package/js/components/datepicker.js +51 -4
- package/js/components/timepicker.js +48 -6
- package/package.json +1 -1
|
@@ -128,6 +128,32 @@
|
|
|
128
128
|
return x;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
function positionAnchoredPopup(anchor, popup, gap) {
|
|
132
|
+
const padding = 8;
|
|
133
|
+
const offset = gap != null ? gap : 4;
|
|
134
|
+
const rect = anchor.getBoundingClientRect();
|
|
135
|
+
|
|
136
|
+
popup.style.minWidth = Math.max(rect.width, 0) + 'px';
|
|
137
|
+
|
|
138
|
+
let top = rect.bottom + offset;
|
|
139
|
+
let left = rect.left;
|
|
140
|
+
popup.style.top = top + 'px';
|
|
141
|
+
popup.style.left = left + 'px';
|
|
142
|
+
|
|
143
|
+
const popRect = popup.getBoundingClientRect();
|
|
144
|
+
if (popRect.bottom > window.innerHeight - padding && rect.top - popRect.height > padding) {
|
|
145
|
+
top = rect.top - popRect.height - offset;
|
|
146
|
+
popup.style.top = top + 'px';
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const alignedRect = popup.getBoundingClientRect();
|
|
150
|
+
left = rect.left;
|
|
151
|
+
if (left + alignedRect.width > window.innerWidth - padding) {
|
|
152
|
+
left = window.innerWidth - alignedRect.width - padding;
|
|
153
|
+
}
|
|
154
|
+
popup.style.left = Math.max(padding, left) + 'px';
|
|
155
|
+
}
|
|
156
|
+
|
|
131
157
|
const Datepicker = {
|
|
132
158
|
instances: new Map(),
|
|
133
159
|
|
|
@@ -221,7 +247,7 @@
|
|
|
221
247
|
wrapper.style.display = 'inline-block';
|
|
222
248
|
input.parentNode.insertBefore(wrapper, input);
|
|
223
249
|
wrapper.appendChild(input);
|
|
224
|
-
|
|
250
|
+
document.body.appendChild(popup);
|
|
225
251
|
|
|
226
252
|
const isSameDay = (a, b) => a && b &&
|
|
227
253
|
a.getFullYear() === b.getFullYear() &&
|
|
@@ -442,6 +468,10 @@
|
|
|
442
468
|
}
|
|
443
469
|
popup.appendChild(grid);
|
|
444
470
|
}
|
|
471
|
+
|
|
472
|
+
if (popup.classList.contains('is-open')) {
|
|
473
|
+
requestAnimationFrame(positionPopup);
|
|
474
|
+
}
|
|
445
475
|
};
|
|
446
476
|
|
|
447
477
|
const handleGridKeydown = (e) => {
|
|
@@ -523,6 +553,15 @@
|
|
|
523
553
|
requestAnimationFrame(focusFocusedDay);
|
|
524
554
|
};
|
|
525
555
|
|
|
556
|
+
const positionPopup = () => {
|
|
557
|
+
if (!popup.classList.contains('is-open')) return;
|
|
558
|
+
positionAnchoredPopup(input, popup);
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
const repositionHandler = () => {
|
|
562
|
+
positionPopup();
|
|
563
|
+
};
|
|
564
|
+
|
|
526
565
|
const open = () => {
|
|
527
566
|
viewMode = 'days';
|
|
528
567
|
if (selectedDate) {
|
|
@@ -542,7 +581,10 @@
|
|
|
542
581
|
render();
|
|
543
582
|
popup.classList.add('is-open');
|
|
544
583
|
input.setAttribute('aria-expanded', 'true');
|
|
545
|
-
requestAnimationFrame(
|
|
584
|
+
requestAnimationFrame(() => {
|
|
585
|
+
positionPopup();
|
|
586
|
+
focusFocusedDay();
|
|
587
|
+
});
|
|
546
588
|
};
|
|
547
589
|
|
|
548
590
|
const close = () => {
|
|
@@ -559,7 +601,7 @@
|
|
|
559
601
|
open();
|
|
560
602
|
};
|
|
561
603
|
const outsideHandler = (e) => {
|
|
562
|
-
if (!
|
|
604
|
+
if (!input.contains(e.target) && !popup.contains(e.target)) close();
|
|
563
605
|
};
|
|
564
606
|
const escHandler = (e) => {
|
|
565
607
|
if (e.key === 'Escape' && popup.classList.contains('is-open')) {
|
|
@@ -573,6 +615,8 @@
|
|
|
573
615
|
document.addEventListener('click', outsideHandler, true);
|
|
574
616
|
document.addEventListener('keydown', escHandler);
|
|
575
617
|
popup.addEventListener('keydown', handleGridKeydown);
|
|
618
|
+
window.addEventListener('resize', repositionHandler);
|
|
619
|
+
window.addEventListener('scroll', repositionHandler, true);
|
|
576
620
|
|
|
577
621
|
input.setAttribute('aria-haspopup', 'dialog');
|
|
578
622
|
input.setAttribute('aria-expanded', 'false');
|
|
@@ -582,7 +626,10 @@
|
|
|
582
626
|
() => input.removeEventListener('focus', focusHandler),
|
|
583
627
|
() => document.removeEventListener('click', outsideHandler, true),
|
|
584
628
|
() => document.removeEventListener('keydown', escHandler),
|
|
585
|
-
() => popup.removeEventListener('keydown', handleGridKeydown)
|
|
629
|
+
() => popup.removeEventListener('keydown', handleGridKeydown),
|
|
630
|
+
() => window.removeEventListener('resize', repositionHandler),
|
|
631
|
+
() => window.removeEventListener('scroll', repositionHandler, true),
|
|
632
|
+
() => popup.remove()
|
|
586
633
|
);
|
|
587
634
|
|
|
588
635
|
this.instances.set(input, { cleanup: cleanup, open: open, close: close, popup: popup });
|
|
@@ -6,6 +6,32 @@
|
|
|
6
6
|
(function () {
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
+
function positionAnchoredPopup(anchor, popup, gap) {
|
|
10
|
+
const padding = 8;
|
|
11
|
+
const offset = gap != null ? gap : 4;
|
|
12
|
+
const rect = anchor.getBoundingClientRect();
|
|
13
|
+
|
|
14
|
+
popup.style.minWidth = Math.max(rect.width, 0) + 'px';
|
|
15
|
+
|
|
16
|
+
let top = rect.bottom + offset;
|
|
17
|
+
let left = rect.left;
|
|
18
|
+
popup.style.top = top + 'px';
|
|
19
|
+
popup.style.left = left + 'px';
|
|
20
|
+
|
|
21
|
+
const popRect = popup.getBoundingClientRect();
|
|
22
|
+
if (popRect.bottom > window.innerHeight - padding && rect.top - popRect.height > padding) {
|
|
23
|
+
top = rect.top - popRect.height - offset;
|
|
24
|
+
popup.style.top = top + 'px';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const alignedRect = popup.getBoundingClientRect();
|
|
28
|
+
left = rect.left;
|
|
29
|
+
if (left + alignedRect.width > window.innerWidth - padding) {
|
|
30
|
+
left = window.innerWidth - alignedRect.width - padding;
|
|
31
|
+
}
|
|
32
|
+
popup.style.left = Math.max(padding, left) + 'px';
|
|
33
|
+
}
|
|
34
|
+
|
|
9
35
|
const Timepicker = {
|
|
10
36
|
instances: new Map(),
|
|
11
37
|
|
|
@@ -36,7 +62,7 @@
|
|
|
36
62
|
const popup = document.createElement('div');
|
|
37
63
|
popup.className = 'vd-timepicker-popup';
|
|
38
64
|
popup.setAttribute('role', 'listbox');
|
|
39
|
-
|
|
65
|
+
document.body.appendChild(popup);
|
|
40
66
|
|
|
41
67
|
// Generate time slots
|
|
42
68
|
const times = [];
|
|
@@ -84,13 +110,24 @@
|
|
|
84
110
|
});
|
|
85
111
|
};
|
|
86
112
|
|
|
113
|
+
const positionPopup = () => {
|
|
114
|
+
if (!popup.classList.contains('is-open')) return;
|
|
115
|
+
positionAnchoredPopup(input, popup);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const repositionHandler = () => {
|
|
119
|
+
positionPopup();
|
|
120
|
+
};
|
|
121
|
+
|
|
87
122
|
const open = () => {
|
|
88
123
|
render();
|
|
89
124
|
popup.classList.add('is-open');
|
|
90
125
|
input.setAttribute('aria-expanded', 'true');
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
126
|
+
requestAnimationFrame(() => {
|
|
127
|
+
positionPopup();
|
|
128
|
+
const selected = popup.querySelector('.is-selected');
|
|
129
|
+
if (selected) selected.scrollIntoView({ block: 'center' });
|
|
130
|
+
});
|
|
94
131
|
};
|
|
95
132
|
|
|
96
133
|
const close = () => {
|
|
@@ -100,13 +137,15 @@
|
|
|
100
137
|
|
|
101
138
|
const focusHandler = () => open();
|
|
102
139
|
const outsideHandler = (e) => {
|
|
103
|
-
if (!
|
|
140
|
+
if (!input.contains(e.target) && !popup.contains(e.target)) close();
|
|
104
141
|
};
|
|
105
142
|
const escHandler = (e) => { if (e.key === 'Escape') close(); };
|
|
106
143
|
|
|
107
144
|
input.addEventListener('focus', focusHandler);
|
|
108
145
|
document.addEventListener('click', outsideHandler, true);
|
|
109
146
|
document.addEventListener('keydown', escHandler);
|
|
147
|
+
window.addEventListener('resize', repositionHandler);
|
|
148
|
+
window.addEventListener('scroll', repositionHandler, true);
|
|
110
149
|
input.setAttribute('aria-haspopup', 'listbox');
|
|
111
150
|
input.setAttribute('aria-expanded', 'false');
|
|
112
151
|
input.setAttribute('autocomplete', 'off');
|
|
@@ -115,7 +154,10 @@
|
|
|
115
154
|
cleanup.push(
|
|
116
155
|
() => input.removeEventListener('focus', focusHandler),
|
|
117
156
|
() => document.removeEventListener('click', outsideHandler, true),
|
|
118
|
-
() => document.removeEventListener('keydown', escHandler)
|
|
157
|
+
() => document.removeEventListener('keydown', escHandler),
|
|
158
|
+
() => window.removeEventListener('resize', repositionHandler),
|
|
159
|
+
() => window.removeEventListener('scroll', repositionHandler, true),
|
|
160
|
+
() => popup.remove()
|
|
119
161
|
);
|
|
120
162
|
|
|
121
163
|
this.instances.set(input, { cleanup, open, close });
|