@tabworthy/components 0.2.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/LICENSE +21 -0
- package/README.md +69 -0
- package/dist/cjs/app-globals-V2Kpy_OQ.js +5 -0
- package/dist/cjs/index-C15oswCE.js +2148 -0
- package/dist/cjs/index.cjs.js +2 -0
- package/dist/cjs/loader.cjs.js +13 -0
- package/dist/cjs/moment-CdViwxPQ.js +5681 -0
- package/dist/cjs/tabworthy-components.cjs.js +25 -0
- package/dist/cjs/tabworthy-dates-calendar_2.cjs.entry.js +884 -0
- package/dist/cjs/tabworthy-dates.cjs.entry.js +10906 -0
- package/dist/cjs/tabworthy-times-picker.cjs.entry.js +181 -0
- package/dist/cjs/tabworthy-times.cjs.entry.js +242 -0
- package/dist/cjs/utils-y5Vtky2t.js +214 -0
- package/dist/collection/collection-manifest.json +16 -0
- package/dist/collection/components/tabworthy-dates/tabworthy-dates.css +10 -0
- package/dist/collection/components/tabworthy-dates/tabworthy-dates.js +1197 -0
- package/dist/collection/components/tabworthy-dates-calendar/tabworthy-dates-calendar.css +10 -0
- package/dist/collection/components/tabworthy-dates-calendar/tabworthy-dates-calendar.js +986 -0
- package/dist/collection/components/tabworthy-modal/tabworthy-dates-modal.css +14 -0
- package/dist/collection/components/tabworthy-modal/tabworthy-dates-modal.js +237 -0
- package/dist/collection/components/tabworthy-times/tabworthy-times.js +832 -0
- package/dist/collection/components/tabworthy-times-picker/tabworthy-times-picker.js +356 -0
- package/dist/collection/index.js +1 -0
- package/dist/components/index.d.ts +35 -0
- package/dist/components/index.js +1 -0
- package/dist/components/moment.js +8 -0
- package/dist/components/tabworthy-dates-calendar.d.ts +11 -0
- package/dist/components/tabworthy-dates-calendar.js +1 -0
- package/dist/components/tabworthy-dates-calendar2.js +1 -0
- package/dist/components/tabworthy-dates-modal.d.ts +11 -0
- package/dist/components/tabworthy-dates-modal.js +1 -0
- package/dist/components/tabworthy-dates-modal2.js +1 -0
- package/dist/components/tabworthy-dates.d.ts +11 -0
- package/dist/components/tabworthy-dates.js +1 -0
- package/dist/components/tabworthy-times-picker.d.ts +11 -0
- package/dist/components/tabworthy-times-picker.js +1 -0
- package/dist/components/tabworthy-times-picker2.js +1 -0
- package/dist/components/tabworthy-times.d.ts +11 -0
- package/dist/components/tabworthy-times.js +1 -0
- package/dist/esm/app-globals-DQuL1Twl.js +3 -0
- package/dist/esm/index-BusoZVTR.js +2139 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/loader.js +11 -0
- package/dist/esm/moment-Mki5YqAR.js +5679 -0
- package/dist/esm/tabworthy-components.js +21 -0
- package/dist/esm/tabworthy-dates-calendar_2.entry.js +881 -0
- package/dist/esm/tabworthy-dates.entry.js +10904 -0
- package/dist/esm/tabworthy-times-picker.entry.js +179 -0
- package/dist/esm/tabworthy-times.entry.js +240 -0
- package/dist/esm/utils-BVHu5CWV.js +188 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.js +1 -0
- package/dist/loader/cdn.js +1 -0
- package/dist/loader/index.cjs.js +1 -0
- package/dist/loader/index.d.ts +24 -0
- package/dist/loader/index.es2017.js +1 -0
- package/dist/loader/index.js +2 -0
- package/dist/shared/utils/chrono-parser/chrono-parser.js +146 -0
- package/dist/shared/utils/chrono-parser/chrono-parser.type.js +1 -0
- package/dist/shared/utils/utils.js +186 -0
- package/dist/tabworthy-components/index.esm.js +0 -0
- package/dist/tabworthy-components/p-170bc6ca.entry.js +1 -0
- package/dist/tabworthy-components/p-3ce9a767.entry.js +1 -0
- package/dist/tabworthy-components/p-77bd1bd4.entry.js +1 -0
- package/dist/tabworthy-components/p-BVHu5CWV.js +1 -0
- package/dist/tabworthy-components/p-BusoZVTR.js +2 -0
- package/dist/tabworthy-components/p-DQuL1Twl.js +1 -0
- package/dist/tabworthy-components/p-Mki5YqAR.js +8 -0
- package/dist/tabworthy-components/p-ebbb4c46.entry.js +1 -0
- package/dist/tabworthy-components/tabworthy-components.esm.js +1 -0
- package/dist/themes/dark.css +1 -0
- package/dist/themes/light.css +1 -0
- package/dist/types/Users/damirbogdanov_1/work/tabworthy-components/.stencil/shared/utils/chrono-parser/chrono-parser.d.ts +3 -0
- package/dist/types/Users/damirbogdanov_1/work/tabworthy-components/.stencil/shared/utils/chrono-parser/chrono-parser.type.d.ts +40 -0
- package/dist/types/Users/damirbogdanov_1/work/tabworthy-components/.stencil/shared/utils/utils.d.ts +28 -0
- package/dist/types/components/tabworthy-dates/tabworthy-dates.d.ts +80 -0
- package/dist/types/components/tabworthy-dates-calendar/tabworthy-dates-calendar.d.ts +89 -0
- package/dist/types/components/tabworthy-modal/tabworthy-dates-modal.d.ts +29 -0
- package/dist/types/components/tabworthy-times/tabworthy-times.d.ts +65 -0
- package/dist/types/components/tabworthy-times-picker/tabworthy-times-picker.d.ts +46 -0
- package/dist/types/components.d.ts +879 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/stencil-public-runtime.d.ts +1858 -0
- package/package.json +132 -0
|
@@ -0,0 +1,884 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var index = require('./index-C15oswCE.js');
|
|
4
|
+
var utils = require('./utils-y5Vtky2t.js');
|
|
5
|
+
|
|
6
|
+
const tabworthyDatesCalendarCss = () => `.visually-hidden.sc-tabworthy-dates-calendar{position:absolute;overflow:hidden;width:1px;height:1px;white-space:nowrap;clip:rect(0 0 0 0);-webkit-clip-path:inset(50%);clip-path:inset(50%)}`;
|
|
7
|
+
|
|
8
|
+
const defaultLabels = {
|
|
9
|
+
clearButton: "Clear value",
|
|
10
|
+
monthSelect: "Select month",
|
|
11
|
+
nextMonthButton: "Next month",
|
|
12
|
+
nextYearButton: "Next year",
|
|
13
|
+
picker: "Choose date",
|
|
14
|
+
previousMonthButton: "Previous month",
|
|
15
|
+
previousYearButton: "Previous year",
|
|
16
|
+
todayButton: "Show today",
|
|
17
|
+
yearSelect: "Select year",
|
|
18
|
+
keyboardHint: "Keyboard commands",
|
|
19
|
+
selected: "Selected date",
|
|
20
|
+
chooseAsStartDate: "choose as start date",
|
|
21
|
+
chooseAsEndDate: "choose as end date"
|
|
22
|
+
};
|
|
23
|
+
const InclusiveDatesCalendar = class {
|
|
24
|
+
constructor(hostRef) {
|
|
25
|
+
index.registerInstance(this, hostRef);
|
|
26
|
+
this.selectDate = index.createEvent(this, "selectDate");
|
|
27
|
+
this.changeMonth = index.createEvent(this, "changeMonth");
|
|
28
|
+
this.changeYear = index.createEvent(this, "changeYear");
|
|
29
|
+
this.disabled = false;
|
|
30
|
+
this.modalIsOpen = false;
|
|
31
|
+
this.disableDate = () => false;
|
|
32
|
+
this.elementClassName = "tabworthy-dates-calendar";
|
|
33
|
+
this.firstDayOfWeek = 0;
|
|
34
|
+
this.range = false;
|
|
35
|
+
this.labels = defaultLabels;
|
|
36
|
+
this.locale = (navigator === null || navigator === void 0 ? void 0 : navigator.language) || "en-US";
|
|
37
|
+
this.inline = false;
|
|
38
|
+
this.showClearButton = false;
|
|
39
|
+
this.showMonthStepper = true;
|
|
40
|
+
this.showTodayButton = true;
|
|
41
|
+
this.showYearStepper = false;
|
|
42
|
+
this.showKeyboardHint = false;
|
|
43
|
+
this.showHiddenTitle = true;
|
|
44
|
+
this.startDate = utils.getISODateString(new Date());
|
|
45
|
+
this.init = () => {
|
|
46
|
+
this.currentDate = this.startDate
|
|
47
|
+
? utils.removeTimezoneOffset(new Date(this.startDate))
|
|
48
|
+
: new Date();
|
|
49
|
+
this.updateWeekdays();
|
|
50
|
+
};
|
|
51
|
+
this.nextMonth = () => {
|
|
52
|
+
this.updateCurrentDate(utils.getNextMonth(this.currentDate));
|
|
53
|
+
};
|
|
54
|
+
this.nextYear = () => {
|
|
55
|
+
this.updateCurrentDate(utils.getNextYear(this.currentDate));
|
|
56
|
+
};
|
|
57
|
+
this.previousMonth = () => {
|
|
58
|
+
this.updateCurrentDate(utils.getPreviousMonth(this.currentDate));
|
|
59
|
+
};
|
|
60
|
+
this.previousYear = () => {
|
|
61
|
+
this.updateCurrentDate(utils.getPreviousYear(this.currentDate));
|
|
62
|
+
};
|
|
63
|
+
this.showToday = () => {
|
|
64
|
+
this.updateCurrentDate(new Date(), true);
|
|
65
|
+
};
|
|
66
|
+
this.clear = () => {
|
|
67
|
+
var _a;
|
|
68
|
+
this.value = undefined;
|
|
69
|
+
(_a = this.selectDate) === null || _a === void 0 ? void 0 : _a.emit(undefined);
|
|
70
|
+
};
|
|
71
|
+
this.onClick = (event) => {
|
|
72
|
+
if (this.disabled) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const target = event.target.closest("[data-date]");
|
|
76
|
+
if (!Boolean(target)) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const date = utils.removeTimezoneOffset(new Date(target.dataset.date));
|
|
80
|
+
this.updateCurrentDate(date);
|
|
81
|
+
this.onSelectDate(date);
|
|
82
|
+
};
|
|
83
|
+
this.onMonthSelect = (event) => {
|
|
84
|
+
const month = +event.target.value - 1;
|
|
85
|
+
const date = new Date(this.currentDate);
|
|
86
|
+
if (!utils.dateIsWithinBounds(date, this.minDate, this.maxDate))
|
|
87
|
+
return;
|
|
88
|
+
date.setMonth(month);
|
|
89
|
+
this.updateCurrentDate(date);
|
|
90
|
+
};
|
|
91
|
+
this.onYearSelect = (event) => {
|
|
92
|
+
var _a;
|
|
93
|
+
const year = +event.target.value;
|
|
94
|
+
const date = new Date(this.currentDate);
|
|
95
|
+
if (!utils.dateIsWithinBounds(date, this.minDate, this.maxDate))
|
|
96
|
+
return;
|
|
97
|
+
date.setFullYear(year);
|
|
98
|
+
(_a = this.changeYear) === null || _a === void 0 ? void 0 : _a.emit({ year });
|
|
99
|
+
this.updateCurrentDate(date);
|
|
100
|
+
};
|
|
101
|
+
this.onKeyDown = (event) => {
|
|
102
|
+
if (this.disabled) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (event.code === "ArrowLeft") {
|
|
106
|
+
event.preventDefault();
|
|
107
|
+
this.updateCurrentDate(utils.getPreviousDay(this.currentDate), true);
|
|
108
|
+
}
|
|
109
|
+
else if (event.code === "ArrowRight") {
|
|
110
|
+
event.preventDefault();
|
|
111
|
+
this.updateCurrentDate(utils.getNextDay(this.currentDate), true);
|
|
112
|
+
}
|
|
113
|
+
else if (event.code === "ArrowUp") {
|
|
114
|
+
event.preventDefault();
|
|
115
|
+
this.updateCurrentDate(utils.subDays(this.currentDate, 7), true);
|
|
116
|
+
}
|
|
117
|
+
else if (event.code === "ArrowDown") {
|
|
118
|
+
event.preventDefault();
|
|
119
|
+
this.updateCurrentDate(utils.addDays(this.currentDate, 7), true);
|
|
120
|
+
}
|
|
121
|
+
else if (event.code === "PageUp") {
|
|
122
|
+
event.preventDefault();
|
|
123
|
+
if (event.shiftKey) {
|
|
124
|
+
this.updateCurrentDate(utils.getPreviousYear(this.currentDate), true);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
this.updateCurrentDate(utils.getPreviousMonth(this.currentDate), true);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else if (event.code === "PageDown") {
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
if (event.shiftKey) {
|
|
133
|
+
this.updateCurrentDate(utils.getNextYear(this.currentDate), true);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
this.updateCurrentDate(utils.getNextMonth(this.currentDate), true);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else if (event.code === "Home") {
|
|
140
|
+
event.preventDefault();
|
|
141
|
+
this.updateCurrentDate(utils.getFirstOfMonth(this.currentDate), true);
|
|
142
|
+
}
|
|
143
|
+
else if (event.code === "End") {
|
|
144
|
+
event.preventDefault();
|
|
145
|
+
this.updateCurrentDate(utils.getLastOfMonth(this.currentDate), true);
|
|
146
|
+
}
|
|
147
|
+
else if (event.code === "Space" || event.code === "Enter") {
|
|
148
|
+
event.preventDefault();
|
|
149
|
+
this.onSelectDate(this.currentDate);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
this.onMouseEnter = (event) => {
|
|
153
|
+
var _a;
|
|
154
|
+
if (this.disabled) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const date = utils.removeTimezoneOffset(new Date((_a = event.target.closest("td")) === null || _a === void 0 ? void 0 : _a.dataset.date));
|
|
158
|
+
this.hoveredDate = date;
|
|
159
|
+
};
|
|
160
|
+
this.onMouseLeave = () => {
|
|
161
|
+
this.hoveredDate = undefined;
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
componentWillLoad() {
|
|
165
|
+
this.init();
|
|
166
|
+
}
|
|
167
|
+
watchModalIsOpen() {
|
|
168
|
+
if (this.modalIsOpen === true) {
|
|
169
|
+
this.moveFocusOnModalOpen = true;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
watchFirstDayOfWeek() {
|
|
173
|
+
this.updateWeekdays();
|
|
174
|
+
}
|
|
175
|
+
watchLocale() {
|
|
176
|
+
if (!Boolean(this.locale)) {
|
|
177
|
+
this.locale = (navigator === null || navigator === void 0 ? void 0 : navigator.language) || "en-US";
|
|
178
|
+
}
|
|
179
|
+
this.updateWeekdays();
|
|
180
|
+
}
|
|
181
|
+
watchRange() {
|
|
182
|
+
var _a;
|
|
183
|
+
this.value = undefined;
|
|
184
|
+
(_a = this.selectDate) === null || _a === void 0 ? void 0 : _a.emit(undefined);
|
|
185
|
+
}
|
|
186
|
+
watchStartDate() {
|
|
187
|
+
this.currentDate = this.startDate
|
|
188
|
+
? utils.removeTimezoneOffset(new Date(this.startDate))
|
|
189
|
+
: new Date();
|
|
190
|
+
}
|
|
191
|
+
watchValue() {
|
|
192
|
+
if (Boolean(this.value)) {
|
|
193
|
+
if (Array.isArray(this.value) && this.value.length >= 1) {
|
|
194
|
+
this.currentDate = this.value[0];
|
|
195
|
+
}
|
|
196
|
+
else if (this.value instanceof Date) {
|
|
197
|
+
this.currentDate = this.value;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
componentDidRender() {
|
|
202
|
+
if (this.moveFocusAfterMonthChanged) {
|
|
203
|
+
this.focusDate(this.currentDate);
|
|
204
|
+
this.moveFocusAfterMonthChanged = false;
|
|
205
|
+
}
|
|
206
|
+
if (this.moveFocusOnModalOpen) {
|
|
207
|
+
// Timeout added to stop VoiceOver from crashing Safari when openin the calendar. TODO: Investigate a neater solution
|
|
208
|
+
setTimeout(() => {
|
|
209
|
+
this.focusDate(this.currentDate);
|
|
210
|
+
this.moveFocusOnModalOpen = false;
|
|
211
|
+
}, 100);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
updateWeekdays() {
|
|
215
|
+
this.weekdays = utils.getWeekDays(this.firstDayOfWeek, this.locale);
|
|
216
|
+
}
|
|
217
|
+
getClassName(element) {
|
|
218
|
+
return Boolean(element)
|
|
219
|
+
? `${this.elementClassName}__${element}`
|
|
220
|
+
: this.elementClassName;
|
|
221
|
+
}
|
|
222
|
+
getCalendarRows() {
|
|
223
|
+
const daysOfMonth = utils.getDaysOfMonth(this.currentDate, true, this.firstDayOfWeek === 0 ? 7 : this.firstDayOfWeek);
|
|
224
|
+
const calendarRows = [];
|
|
225
|
+
for (let i = 0; i < daysOfMonth.length; i += 7) {
|
|
226
|
+
const row = daysOfMonth.slice(i, i + 7);
|
|
227
|
+
calendarRows.push(row);
|
|
228
|
+
}
|
|
229
|
+
return calendarRows;
|
|
230
|
+
}
|
|
231
|
+
getTitle() {
|
|
232
|
+
if (!Boolean(this.currentDate)) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
return Intl.DateTimeFormat(this.locale, {
|
|
236
|
+
month: "long",
|
|
237
|
+
year: "numeric"
|
|
238
|
+
}).format(this.currentDate);
|
|
239
|
+
}
|
|
240
|
+
focusDate(date) {
|
|
241
|
+
var _a;
|
|
242
|
+
date && ((_a = this.el
|
|
243
|
+
.querySelector(`[data-date="${utils.getISODateString(date)}"]`)) === null || _a === void 0 ? void 0 : _a.focus());
|
|
244
|
+
}
|
|
245
|
+
updateCurrentDate(date, moveFocus) {
|
|
246
|
+
var _a, _b;
|
|
247
|
+
const month = date.getMonth();
|
|
248
|
+
const year = date.getFullYear();
|
|
249
|
+
if (!utils.dateIsWithinLowerBounds(date, this.minDate))
|
|
250
|
+
date = new Date(this.minDate);
|
|
251
|
+
if (!utils.dateIsWithinUpperBounds(date, this.maxDate))
|
|
252
|
+
date = new Date(this.maxDate);
|
|
253
|
+
const monthChanged = month !== ((_a = this.currentDate) === null || _a === void 0 ? void 0 : _a.getMonth()) ||
|
|
254
|
+
year !== this.currentDate.getFullYear();
|
|
255
|
+
if (monthChanged) {
|
|
256
|
+
(_b = this.changeMonth) === null || _b === void 0 ? void 0 : _b.emit({ month: utils.getMonth(date), year: utils.getYear(date) });
|
|
257
|
+
if (moveFocus) {
|
|
258
|
+
this.moveFocusAfterMonthChanged = true;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
this.currentDate = date;
|
|
262
|
+
if (moveFocus) {
|
|
263
|
+
this.focusDate(this.currentDate);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
onSelectDate(date) {
|
|
267
|
+
var _a, _b, _c, _d;
|
|
268
|
+
if (this.disableDate(date) ||
|
|
269
|
+
!utils.dateIsWithinBounds(date, this.minDate, this.maxDate)) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (this.isRangeValue(this.value)) {
|
|
273
|
+
const newValue = ((_a = this.value) === null || _a === void 0 ? void 0 : _a[0]) === undefined || this.value.length === 2
|
|
274
|
+
? [date]
|
|
275
|
+
: [this.value[0], date];
|
|
276
|
+
if (newValue.length === 2 && newValue[0] > newValue[1]) {
|
|
277
|
+
newValue.reverse();
|
|
278
|
+
}
|
|
279
|
+
const isoValue = newValue[1] === undefined
|
|
280
|
+
? [utils.getISODateString(newValue[0])]
|
|
281
|
+
: [utils.getISODateString(newValue[0]), utils.getISODateString(newValue[1])];
|
|
282
|
+
this.value = newValue;
|
|
283
|
+
(_b = this.selectDate) === null || _b === void 0 ? void 0 : _b.emit(isoValue);
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
if (((_c = this.value) === null || _c === void 0 ? void 0 : _c.getTime()) === date.getTime()) {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
this.value = date;
|
|
290
|
+
(_d = this.selectDate) === null || _d === void 0 ? void 0 : _d.emit(utils.getISODateString(date));
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
isRangeValue(_value) {
|
|
294
|
+
return !!this.range;
|
|
295
|
+
}
|
|
296
|
+
render() {
|
|
297
|
+
var _a;
|
|
298
|
+
const showFooter = this.showTodayButton || this.showClearButton || this.showKeyboardHint;
|
|
299
|
+
const disabled = {
|
|
300
|
+
year: {
|
|
301
|
+
prev: this.disabled || (!!this.minDate && new Date(this.minDate).getFullYear() > utils.getPreviousYear(this.currentDate).getFullYear()),
|
|
302
|
+
next: this.disabled || (!!this.maxDate && new Date(this.maxDate).getFullYear() < utils.getNextYear(this.currentDate).getFullYear())
|
|
303
|
+
},
|
|
304
|
+
month: {
|
|
305
|
+
prev: this.disabled ||
|
|
306
|
+
utils.monthIsDisabled(utils.getPreviousMonth(this.currentDate).getMonth(), utils.getPreviousMonth(this.currentDate).getFullYear(), this.minDate, this.maxDate),
|
|
307
|
+
next: this.disabled ||
|
|
308
|
+
utils.monthIsDisabled(utils.getNextMonth(this.currentDate).getMonth(), utils.getNextMonth(this.currentDate).getFullYear(), this.minDate, this.maxDate)
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
return (index.h(index.Host, { key: '79018439c3f99dc228ac0d429763d1e86fe9bb03' }, index.h("div", { key: '8863cf5d0de75a1f358723440f11b70128d7c739', class: {
|
|
312
|
+
[`${this.getClassName()}-wrapper`]: true,
|
|
313
|
+
[`${this.getClassName()}-wrapper--inline`]: this.inline
|
|
314
|
+
} }, index.h("div", { key: 'b47630e94a50c0bb74da62f1d9e9931ed06e15ab', class: {
|
|
315
|
+
[this.getClassName()]: true,
|
|
316
|
+
[`${this.getClassName()}--disabled`]: this.disabled,
|
|
317
|
+
} }, index.h("div", { key: '594429a8b241c0024edde2e4adb211935e3579fd', class: this.getClassName("header") }, this.showHiddenTitle && (index.h("span", { key: '3258ebc3b0a325f0f21af5126fa31c5cb0197ebb', "aria-atomic": "true", "aria-live": "polite", class: "visually-hidden" }, this.getTitle())), this.showYearStepper && (index.h("button", { key: '0f7d853b969a89b76b5794d9b8c5e03f7ece778b', "aria-label": this.labels.previousYearButton, class: this.getClassName("previous-year-button"), "aria-disabled": disabled.year.prev, innerHTML: this.previousYearButtonContent || undefined, onClick: this.previousYear, type: "button" }, index.h("svg", { key: '1d4da9d54e875a85e22beae6f608de9ec0495a03', fill: "none", height: "24", "stroke-linecap": "round", "stroke-linejoin": "round", "stroke-width": "2", stroke: "currentColor", viewBox: "0 0 24 24", width: "24" }, index.h("polyline", { key: '0fd84be75c074c61a0d839694e5e1b8e7efa480e', points: "11 17 6 12 11 7" }), index.h("polyline", { key: '4b1c8d3e29718cabc669d9194af749ffc2cac7aa', points: "18 17 13 12 18 7" })))), this.showMonthStepper && (index.h("button", { key: '27402a2f431d68487775e4fbe548804755c569cc', "aria-label": this.labels.previousMonthButton, class: this.getClassName("previous-month-button"), "aria-disabled": disabled.month.prev, innerHTML: this.previousMonthButtonContent || undefined, onClick: this.previousMonth, type: "button" }, index.h("svg", { key: 'b503e9f1d393c1a245da483b25edb14f473aac7d', fill: "none", height: "24", "stroke-linecap": "round", "stroke-linejoin": "round", "stroke-width": "2", stroke: "currentColor", viewBox: "0 0 24 24", width: "24" }, index.h("polyline", { key: '37241e518f64e1a7aba4153d0222649e62671ed4', points: "15 18 9 12 15 6" })))), index.h("span", { key: '3e87bb8129d4d7b1db718ee87f5164dec158fb1a', class: this.getClassName("current-month") }, index.h("select", { key: 'ae6c5128f2dc9ec17bd4d4c0090df4a62743b09c', "aria-label": this.labels.monthSelect, class: this.getClassName("month-select"), "aria-disabled": this.disabled, name: "month", onChange: this.onMonthSelect }, utils.getMonths(this.locale).map((month, index$1) => {
|
|
318
|
+
return (index.h("option", { key: month, selected: this.currentDate.getMonth() === index$1, value: index$1 + 1, disabled: utils.monthIsDisabled(index$1, this.currentDate.getFullYear(), this.minDate, this.maxDate) }, month));
|
|
319
|
+
})), index.h("input", { key: '733a5e0025571c54fc27616c200bfbf07de436cc', "aria-label": this.labels.yearSelect, class: this.getClassName("year-select"), "aria-disabled": this.disabled, max: this.maxDate ? this.maxDate.slice(0, 4) : 9999, min: this.minDate ? this.minDate.slice(0, 4) : 1, name: "year", onChange: this.onYearSelect, type: "number", value: this.currentDate.getFullYear() })), this.showMonthStepper && (index.h("button", { key: 'eaa9e5e613835a9108f17991ba4743020cfa3146', "aria-label": this.labels.nextMonthButton, class: this.getClassName("next-month-button"), "aria-disabled": disabled.month.next, innerHTML: this.nextMonthButtonContent || undefined, onClick: this.nextMonth, type: "button" }, index.h("svg", { key: '5729113b90336e0e8d2ade0a24952d186e12867c', fill: "none", height: "24", "stroke-linecap": "round", "stroke-linejoin": "round", "stroke-width": "2", stroke: "currentColor", viewBox: "0 0 24 24", width: "24" }, index.h("polyline", { key: 'a6cc05a5b83eb6f162654782466a43bd98ada883', points: "9 18 15 12 9 6" })))), this.showYearStepper && (index.h("button", { key: '6a8556ddc516e5c9a06fd9d71cfa939de48e9bbe', "aria-label": this.labels.nextYearButton, class: this.getClassName("next-year-button"), "aria-disabled": disabled.year.next, innerHTML: this.nextYearButtonContent || undefined, onClick: this.nextYear, type: "button" }, index.h("svg", { key: '17e51e43e8a378fb73e1d51c8a75bb8e890af433', fill: "none", height: "24", "stroke-linecap": "round", "stroke-linejoin": "round", "stroke-width": "2", stroke: "currentColor", viewBox: "0 0 24 24", width: "24" }, index.h("polyline", { key: 'bdf9cf173de2dc96beaf2bc615aea901899e5907', points: "13 17 18 12 13 7" }), index.h("polyline", { key: '638e86d7b823782b2331c2569531def9f267dce9', points: "6 17 11 12 6 7" }))))), index.h("div", { key: '8fbe9e86646e09853205865351f3aa298877c43a', class: this.getClassName("body") }, index.h("table", { key: 'bf374b391788b26485362a368a10c009b42a9d84', class: this.getClassName("calendar"), onKeyDown: this.onKeyDown, role: "grid", "aria-label": this.getTitle() }, index.h("thead", { key: '7cb065ee0fa4bd944c79a130b107d59e8e622b89', class: this.getClassName("calendar-header") }, index.h("tr", { key: '30b196641286a6f9adb3d37167172858a34f2933', class: this.getClassName("weekday-row") }, (_a = this.weekdays) === null || _a === void 0 ? void 0 : _a.map((weekday) => (index.h("th", { role: "columnheader", abbr: weekday[1], class: this.getClassName("weekday"), key: weekday[0], scope: "col" }, index.h("span", { "aria-hidden": "true" }, weekday[0]), index.h("span", { class: "visually-hidden" }, weekday[1])))))), index.h("tbody", { key: '922edf01c35e7512654d8661348301d275c67647' }, this.getCalendarRows().map((calendarRow) => {
|
|
320
|
+
const rowKey = `row-${calendarRow[0].getMonth()}-${calendarRow[0].getDate()}`;
|
|
321
|
+
return (index.h("tr", { class: this.getClassName("calendar-row"), key: rowKey }, calendarRow.map((day) => {
|
|
322
|
+
var _a, _b, _c;
|
|
323
|
+
const isCurrent = utils.isSameDay(day, this.currentDate);
|
|
324
|
+
const isOverflowing = day.getMonth() !== ((_a = this.currentDate) === null || _a === void 0 ? void 0 : _a.getMonth());
|
|
325
|
+
const isSelected = Array.isArray(this.value)
|
|
326
|
+
? utils.isSameDay(day, this.value[0]) ||
|
|
327
|
+
(this.value[1] &&
|
|
328
|
+
utils.dateIsWithinBounds(day, utils.getISODateString(this.value[0]), utils.getISODateString(this.value[1])))
|
|
329
|
+
: utils.isSameDay(day, this.value);
|
|
330
|
+
const isDisabled = this.disableDate(day) ||
|
|
331
|
+
!utils.dateIsWithinBounds(day, this.minDate, this.maxDate);
|
|
332
|
+
const isInRange = !this.isRangeValue(this.value)
|
|
333
|
+
? false
|
|
334
|
+
: utils.isDateInRange(day, {
|
|
335
|
+
from: (_b = this.value) === null || _b === void 0 ? void 0 : _b[0],
|
|
336
|
+
to: ((_c = this.value) === null || _c === void 0 ? void 0 : _c[1]) ||
|
|
337
|
+
this.hoveredDate ||
|
|
338
|
+
this.currentDate
|
|
339
|
+
}) && !isDisabled;
|
|
340
|
+
const isToday = utils.isSameDay(day, new Date());
|
|
341
|
+
const cellKey = `cell-${day.getMonth()}-${day.getDate()}`;
|
|
342
|
+
const getScreenReaderText = () => {
|
|
343
|
+
if (this.range) {
|
|
344
|
+
let suffix = !this.value
|
|
345
|
+
? `, ${this.labels.chooseAsStartDate}.`
|
|
346
|
+
: "";
|
|
347
|
+
if (Array.isArray(this.value)) {
|
|
348
|
+
suffix = {
|
|
349
|
+
1: `, ${this.labels.chooseAsEndDate}.`,
|
|
350
|
+
2: `, ${this.labels.chooseAsStartDate}.`
|
|
351
|
+
}[this.value.length];
|
|
352
|
+
}
|
|
353
|
+
return `${isSelected ? `${this.labels.selected}, ` : ""}${Intl.DateTimeFormat(this.locale, {
|
|
354
|
+
day: "numeric",
|
|
355
|
+
month: "long",
|
|
356
|
+
year: "numeric"
|
|
357
|
+
}).format(day)}${suffix}`;
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
return `${isSelected ? `${this.labels.selected}, ` : ""}${Intl.DateTimeFormat(this.locale, {
|
|
361
|
+
day: "numeric",
|
|
362
|
+
month: "long",
|
|
363
|
+
year: "numeric"
|
|
364
|
+
}).format(day)}`;
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
const className = {
|
|
368
|
+
[this.getClassName("date")]: true,
|
|
369
|
+
[this.getClassName("date--current")]: isCurrent,
|
|
370
|
+
[this.getClassName("date--disabled")]: isDisabled,
|
|
371
|
+
[this.getClassName("date--overflowing")]: isOverflowing,
|
|
372
|
+
[this.getClassName("date--today")]: isToday,
|
|
373
|
+
[this.getClassName("date--selected")]: isSelected,
|
|
374
|
+
[this.getClassName("date--in-range")]: isInRange
|
|
375
|
+
};
|
|
376
|
+
const Tag = isSelected
|
|
377
|
+
? "strong"
|
|
378
|
+
: isToday
|
|
379
|
+
? "em"
|
|
380
|
+
: "span";
|
|
381
|
+
return (index.h("td", { "aria-disabled": String(isDisabled), "aria-selected": isSelected ? "true" : undefined, class: className, "data-date": utils.getISODateString(day), key: cellKey, onClick: this.onClick, onMouseEnter: this.onMouseEnter, onMouseLeave: this.onMouseLeave, role: "gridcell", tabIndex: utils.isSameDay(day, this.currentDate) && !this.disabled
|
|
382
|
+
? 0
|
|
383
|
+
: -1 }, index.h(Tag, { "aria-hidden": "true" }, day.getDate()), index.h("span", { class: "visually-hidden" }, getScreenReaderText())));
|
|
384
|
+
})));
|
|
385
|
+
})))), showFooter && (index.h("div", { key: '0a189fdb44b39bddc7a26c7bd3e4a889307fee39', class: this.getClassName("footer") }, index.h("div", { key: 'fbdf81d3a93afa19cdedba1423d2c64ab4e1fbcb', class: this.getClassName("footer-buttons") }, this.showTodayButton && (index.h("button", { key: '4faad216c53bda804e8b660d758e30e0bf538940', class: this.getClassName("today-button"), disabled: this.disabled, innerHTML: this.todayButtonContent || undefined, onClick: this.showToday, type: "button" }, this.labels.todayButton)), this.showClearButton && (index.h("button", { key: '84ad553438da2c701c0ec75328eac36d01b3daa3', class: this.getClassName("clear-button"), disabled: this.disabled, innerHTML: this.clearButtonContent || undefined, onClick: this.clear, type: "button" }, this.labels.clearButton))), this.showKeyboardHint &&
|
|
386
|
+
!window.matchMedia("(pointer: coarse)").matches && (index.h("button", { key: 'f63c1d1c802173072424a098ab52fffe35df7f56', type: "button", onClick: () => alert("Todo: Add Keyboard helper!"), class: this.getClassName("keyboard-hint") }, index.h("svg", { key: '790b14010416be81d39a52549a5677116e436a63', xmlns: "http://www.w3.org/2000/svg", height: "1em", width: "1em", viewBox: "0 0 48 48", fill: "currentColor" }, index.h("path", { key: '83a801f97bf0a2fbd33f728cd00c5dfab75eb213', d: "M7 38q-1.2 0-2.1-.925Q4 36.15 4 35V13q0-1.2.9-2.1.9-.9 2.1-.9h34q1.2 0 2.1.9.9.9.9 2.1v22q0 1.15-.9 2.075Q42.2 38 41 38Zm0-3h34V13H7v22Zm8-3.25h18v-3H15Zm-4.85-6.25h3v-3h-3Zm6.2 0h3v-3h-3Zm6.15 0h3v-3h-3Zm6.2 0h3v-3h-3Zm6.15 0h3v-3h-3Zm-24.7-6.25h3v-3h-3Zm6.2 0h3v-3h-3Zm6.15 0h3v-3h-3Zm6.2 0h3v-3h-3Zm6.15 0h3v-3h-3ZM7 35V13v22Z" })), this.labels.keyboardHint))))), index.h("slot", { key: '1b6c88f7c9e4e6fa7109b99ef774af1ee8de24ea', name: "after-calendar" }))));
|
|
387
|
+
}
|
|
388
|
+
get el() { return index.getElement(this); }
|
|
389
|
+
static get watchers() { return {
|
|
390
|
+
"modalIsOpen": [{
|
|
391
|
+
"watchModalIsOpen": 0
|
|
392
|
+
}],
|
|
393
|
+
"firstDayOfWeek": [{
|
|
394
|
+
"watchFirstDayOfWeek": 0
|
|
395
|
+
}],
|
|
396
|
+
"locale": [{
|
|
397
|
+
"watchLocale": 0
|
|
398
|
+
}],
|
|
399
|
+
"range": [{
|
|
400
|
+
"watchRange": 0
|
|
401
|
+
}],
|
|
402
|
+
"startDate": [{
|
|
403
|
+
"watchStartDate": 0
|
|
404
|
+
}],
|
|
405
|
+
"value": [{
|
|
406
|
+
"watchValue": 0
|
|
407
|
+
}]
|
|
408
|
+
}; }
|
|
409
|
+
};
|
|
410
|
+
InclusiveDatesCalendar.style = tabworthyDatesCalendarCss();
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Traverses the slots of the open shadowroots and returns all children matching the query.
|
|
414
|
+
* @param {ShadowRoot | HTMLElement} root
|
|
415
|
+
* @param skipNode
|
|
416
|
+
* @param isMatch
|
|
417
|
+
* @param {number} maxDepth
|
|
418
|
+
* @param {number} depth
|
|
419
|
+
* @returns {HTMLElement[]}
|
|
420
|
+
*/
|
|
421
|
+
function queryShadowRoot(root, skipNode, isMatch, maxDepth = 20, depth = 0) {
|
|
422
|
+
let matches = [];
|
|
423
|
+
// If the depth is above the max depth, abort the searching here.
|
|
424
|
+
if (depth >= maxDepth) {
|
|
425
|
+
return matches;
|
|
426
|
+
}
|
|
427
|
+
// Traverses a slot element
|
|
428
|
+
const traverseSlot = ($slot) => {
|
|
429
|
+
// Only check nodes that are of the type Node.ELEMENT_NODE
|
|
430
|
+
// Read more here https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
|
|
431
|
+
const assignedNodes = $slot.assignedNodes().filter(node => node.nodeType === 1);
|
|
432
|
+
if (assignedNodes.length > 0) {
|
|
433
|
+
return queryShadowRoot(assignedNodes[0].parentElement, skipNode, isMatch, maxDepth, depth + 1);
|
|
434
|
+
}
|
|
435
|
+
return [];
|
|
436
|
+
};
|
|
437
|
+
// Go through each child and continue the traversing if necessary
|
|
438
|
+
// Even though the typing says that children can't be undefined, Edge 15 sometimes gives an undefined value.
|
|
439
|
+
// Therefore we fallback to an empty array if it is undefined.
|
|
440
|
+
const children = Array.from(root.children || []);
|
|
441
|
+
for (const $child of children) {
|
|
442
|
+
// Check if the node and its descendants should be skipped
|
|
443
|
+
if (skipNode($child)) {
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
// If the child matches we always add it
|
|
447
|
+
if (isMatch($child)) {
|
|
448
|
+
matches.push($child);
|
|
449
|
+
}
|
|
450
|
+
if ($child.shadowRoot != null) {
|
|
451
|
+
matches.push(...queryShadowRoot($child.shadowRoot, skipNode, isMatch, maxDepth, depth + 1));
|
|
452
|
+
}
|
|
453
|
+
else if ($child.tagName === "SLOT") {
|
|
454
|
+
matches.push(...traverseSlot($child));
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
matches.push(...queryShadowRoot($child, skipNode, isMatch, maxDepth, depth + 1));
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return matches;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Returns whether the element is hidden.
|
|
465
|
+
* @param $elem
|
|
466
|
+
*/
|
|
467
|
+
function isHidden($elem) {
|
|
468
|
+
return $elem.hasAttribute("hidden")
|
|
469
|
+
|| ($elem.hasAttribute("aria-hidden") && $elem.getAttribute("aria-hidden") !== "false")
|
|
470
|
+
// A quick and dirty way to check whether the element is hidden.
|
|
471
|
+
// For a more fine-grained check we could use "window.getComputedStyle" but we don't because of bad performance.
|
|
472
|
+
// If the element has visibility set to "hidden" or "collapse", display set to "none" or opacity set to "0" through CSS
|
|
473
|
+
// we won't be able to catch it here. We accept it due to the huge performance benefits.
|
|
474
|
+
|| $elem.style.display === `none`
|
|
475
|
+
|| $elem.style.opacity === `0`
|
|
476
|
+
|| $elem.style.visibility === `hidden`
|
|
477
|
+
|| $elem.style.visibility === `collapse`;
|
|
478
|
+
// If offsetParent is null we can assume that the element is hidden
|
|
479
|
+
// https://stackoverflow.com/questions/306305/what-would-make-offsetparent-null
|
|
480
|
+
//|| $elem.offsetParent == null;
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Returns whether the element is disabled.
|
|
484
|
+
* @param $elem
|
|
485
|
+
*/
|
|
486
|
+
function isDisabled($elem) {
|
|
487
|
+
return $elem.hasAttribute("disabled")
|
|
488
|
+
|| ($elem.hasAttribute("aria-disabled") && $elem.getAttribute("aria-disabled") !== "false");
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Determines whether an element is focusable.
|
|
492
|
+
* Read more here: https://stackoverflow.com/questions/1599660/which-html-elements-can-receive-focus/1600194#1600194
|
|
493
|
+
* Or here: https://stackoverflow.com/questions/18261595/how-to-check-if-a-dom-element-is-focusable
|
|
494
|
+
* @param $elem
|
|
495
|
+
*/
|
|
496
|
+
function isFocusable($elem) {
|
|
497
|
+
// Discard elements that are removed from the tab order.
|
|
498
|
+
if ($elem.getAttribute("tabindex") === "-1" || isHidden($elem) || isDisabled($elem)) {
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
501
|
+
return (
|
|
502
|
+
// At this point we know that the element can have focus (eg. won't be -1) if the tabindex attribute exists
|
|
503
|
+
$elem.hasAttribute("tabindex")
|
|
504
|
+
// Anchor tags or area tags with a href set
|
|
505
|
+
|| ($elem instanceof HTMLAnchorElement || $elem instanceof HTMLAreaElement) && $elem.hasAttribute("href")
|
|
506
|
+
// Form elements which are not disabled
|
|
507
|
+
|| ($elem instanceof HTMLButtonElement
|
|
508
|
+
|| $elem instanceof HTMLInputElement
|
|
509
|
+
|| $elem instanceof HTMLTextAreaElement
|
|
510
|
+
|| $elem instanceof HTMLSelectElement)
|
|
511
|
+
// IFrames
|
|
512
|
+
|| $elem instanceof HTMLIFrameElement);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const timeouts = new Map();
|
|
516
|
+
/**
|
|
517
|
+
* Debounces a callback.
|
|
518
|
+
* @param cb
|
|
519
|
+
* @param ms
|
|
520
|
+
* @param id
|
|
521
|
+
*/
|
|
522
|
+
function debounce(cb, ms, id) {
|
|
523
|
+
// Clear current timeout for id
|
|
524
|
+
const timeout = timeouts.get(id);
|
|
525
|
+
if (timeout != null) {
|
|
526
|
+
window.clearTimeout(timeout);
|
|
527
|
+
}
|
|
528
|
+
// Set new timeout
|
|
529
|
+
timeouts.set(id, window.setTimeout(() => {
|
|
530
|
+
cb();
|
|
531
|
+
timeouts.delete(id);
|
|
532
|
+
}, ms));
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Template for the focus trap.
|
|
537
|
+
*/
|
|
538
|
+
const template = document.createElement("template");
|
|
539
|
+
template.innerHTML = `
|
|
540
|
+
<div id="start"></div>
|
|
541
|
+
<div id="backup"></div>
|
|
542
|
+
<slot></slot>
|
|
543
|
+
<div id="end"></div>
|
|
544
|
+
`;
|
|
545
|
+
/**
|
|
546
|
+
* Focus trap web component.
|
|
547
|
+
* @customElement focus-trap
|
|
548
|
+
* @slot - Default content.
|
|
549
|
+
*/
|
|
550
|
+
class FocusTrap extends HTMLElement {
|
|
551
|
+
/**
|
|
552
|
+
* Attaches the shadow root.
|
|
553
|
+
*/
|
|
554
|
+
constructor() {
|
|
555
|
+
super();
|
|
556
|
+
// The debounce id is used to distinguish this focus trap from others when debouncing
|
|
557
|
+
this.debounceId = Math.random().toString();
|
|
558
|
+
this._focused = false;
|
|
559
|
+
const shadow = this.attachShadow({ mode: "open" });
|
|
560
|
+
shadow.appendChild(template.content.cloneNode(true));
|
|
561
|
+
this.$backup = shadow.querySelector("#backup");
|
|
562
|
+
this.$start = shadow.querySelector("#start");
|
|
563
|
+
this.$end = shadow.querySelector("#end");
|
|
564
|
+
this.focusLastElement = this.focusLastElement.bind(this);
|
|
565
|
+
this.focusFirstElement = this.focusFirstElement.bind(this);
|
|
566
|
+
this.onFocusIn = this.onFocusIn.bind(this);
|
|
567
|
+
this.onFocusOut = this.onFocusOut.bind(this);
|
|
568
|
+
}
|
|
569
|
+
// Whenever one of these attributes changes we need to render the template again.
|
|
570
|
+
static get observedAttributes() {
|
|
571
|
+
return [
|
|
572
|
+
"inactive"
|
|
573
|
+
];
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Determines whether the focus trap is active or not.
|
|
577
|
+
* @attr
|
|
578
|
+
*/
|
|
579
|
+
get inactive() {
|
|
580
|
+
return this.hasAttribute("inactive");
|
|
581
|
+
}
|
|
582
|
+
set inactive(value) {
|
|
583
|
+
value ? this.setAttribute("inactive", "") : this.removeAttribute("inactive");
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Returns whether the element currently has focus.
|
|
587
|
+
*/
|
|
588
|
+
get focused() {
|
|
589
|
+
return this._focused;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Hooks up the element.
|
|
593
|
+
*/
|
|
594
|
+
connectedCallback() {
|
|
595
|
+
this.$start.addEventListener("focus", this.focusLastElement);
|
|
596
|
+
this.$end.addEventListener("focus", this.focusFirstElement);
|
|
597
|
+
// Focus out is called every time the user tabs around inside the element
|
|
598
|
+
this.addEventListener("focusin", this.onFocusIn);
|
|
599
|
+
this.addEventListener("focusout", this.onFocusOut);
|
|
600
|
+
this.render();
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Tears down the element.
|
|
604
|
+
*/
|
|
605
|
+
disconnectedCallback() {
|
|
606
|
+
this.$start.removeEventListener("focus", this.focusLastElement);
|
|
607
|
+
this.$end.removeEventListener("focus", this.focusFirstElement);
|
|
608
|
+
this.removeEventListener("focusin", this.onFocusIn);
|
|
609
|
+
this.removeEventListener("focusout", this.onFocusOut);
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* When the attributes changes we need to re-render the template.
|
|
613
|
+
*/
|
|
614
|
+
attributeChangedCallback() {
|
|
615
|
+
this.render();
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Focuses the first focusable element in the focus trap.
|
|
619
|
+
*/
|
|
620
|
+
focusFirstElement() {
|
|
621
|
+
this.trapFocus();
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Focuses the last focusable element in the focus trap.
|
|
625
|
+
*/
|
|
626
|
+
focusLastElement() {
|
|
627
|
+
this.trapFocus(true);
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Returns a list of the focusable children found within the element.
|
|
631
|
+
*/
|
|
632
|
+
getFocusableElements() {
|
|
633
|
+
return queryShadowRoot(this, isHidden, isFocusable);
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Focuses on either the last or first focusable element.
|
|
637
|
+
* @param {boolean} trapToEnd
|
|
638
|
+
*/
|
|
639
|
+
trapFocus(trapToEnd) {
|
|
640
|
+
if (this.inactive)
|
|
641
|
+
return;
|
|
642
|
+
let focusableChildren = this.getFocusableElements();
|
|
643
|
+
if (focusableChildren.length > 0) {
|
|
644
|
+
if (trapToEnd) {
|
|
645
|
+
focusableChildren[focusableChildren.length - 1].focus();
|
|
646
|
+
}
|
|
647
|
+
else {
|
|
648
|
+
focusableChildren[0].focus();
|
|
649
|
+
}
|
|
650
|
+
this.$backup.setAttribute("tabindex", "-1");
|
|
651
|
+
}
|
|
652
|
+
else {
|
|
653
|
+
// If there are no focusable children we need to focus on the backup
|
|
654
|
+
// to trap the focus. This is a useful behavior if the focus trap is
|
|
655
|
+
// for example used in a dialog and we don't want the user to tab
|
|
656
|
+
// outside the dialog even though there are no focusable children
|
|
657
|
+
// in the dialog.
|
|
658
|
+
this.$backup.setAttribute("tabindex", "0");
|
|
659
|
+
this.$backup.focus();
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* When the element gains focus this function is called.
|
|
664
|
+
*/
|
|
665
|
+
onFocusIn() {
|
|
666
|
+
this.updateFocused(true);
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* When the element looses its focus this function is called.
|
|
670
|
+
*/
|
|
671
|
+
onFocusOut() {
|
|
672
|
+
this.updateFocused(false);
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Updates the focused property and updates the view.
|
|
676
|
+
* The update is debounced because the focusin and focusout out
|
|
677
|
+
* might fire multiple times in a row. We only want to render
|
|
678
|
+
* the element once, therefore waiting until the focus is "stable".
|
|
679
|
+
* @param value
|
|
680
|
+
*/
|
|
681
|
+
updateFocused(value) {
|
|
682
|
+
debounce(() => {
|
|
683
|
+
if (this.focused !== value) {
|
|
684
|
+
this._focused = value;
|
|
685
|
+
this.render();
|
|
686
|
+
}
|
|
687
|
+
}, 0, this.debounceId);
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Updates the template.
|
|
691
|
+
*/
|
|
692
|
+
render() {
|
|
693
|
+
this.$start.setAttribute("tabindex", !this.focused || this.inactive ? `-1` : `0`);
|
|
694
|
+
this.$end.setAttribute("tabindex", !this.focused || this.inactive ? `-1` : `0`);
|
|
695
|
+
this.focused ? this.setAttribute("focused", "") : this.removeAttribute("focused");
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
window.customElements.define("focus-trap", FocusTrap);
|
|
699
|
+
|
|
700
|
+
var getDefaultParent = function (originalTarget) {
|
|
701
|
+
if (typeof document === 'undefined') {
|
|
702
|
+
return null;
|
|
703
|
+
}
|
|
704
|
+
var sampleTarget = Array.isArray(originalTarget) ? originalTarget[0] : originalTarget;
|
|
705
|
+
return sampleTarget.ownerDocument.body;
|
|
706
|
+
};
|
|
707
|
+
var counterMap = new WeakMap();
|
|
708
|
+
var uncontrolledNodes = new WeakMap();
|
|
709
|
+
var markerMap = {};
|
|
710
|
+
var lockCount = 0;
|
|
711
|
+
var unwrapHost = function (node) {
|
|
712
|
+
return node && (node.host || unwrapHost(node.parentNode));
|
|
713
|
+
};
|
|
714
|
+
var correctTargets = function (parent, targets) {
|
|
715
|
+
return targets.map(function (target) {
|
|
716
|
+
if (parent.contains(target)) {
|
|
717
|
+
return target;
|
|
718
|
+
}
|
|
719
|
+
var correctedTarget = unwrapHost(target);
|
|
720
|
+
if (correctedTarget && parent.contains(correctedTarget)) {
|
|
721
|
+
return correctedTarget;
|
|
722
|
+
}
|
|
723
|
+
console.error('aria-hidden', target, 'in not contained inside', parent, '. Doing nothing');
|
|
724
|
+
return null;
|
|
725
|
+
}).filter(function (x) { return Boolean(x); });
|
|
726
|
+
};
|
|
727
|
+
/**
|
|
728
|
+
* Marks everything except given node(or nodes) as aria-hidden
|
|
729
|
+
* @param {Element | Element[]} originalTarget - elements to keep on the page
|
|
730
|
+
* @param [parentNode] - top element, defaults to document.body
|
|
731
|
+
* @param {String} [markerName] - a special attribute to mark every node
|
|
732
|
+
* @param {String} [controlAttribute] - html Attribute to control
|
|
733
|
+
* @return {Undo} undo command
|
|
734
|
+
*/
|
|
735
|
+
var applyAttributeToOthers = function (originalTarget, parentNode, markerName, controlAttribute) {
|
|
736
|
+
var targets = correctTargets(parentNode, Array.isArray(originalTarget) ? originalTarget : [originalTarget]);
|
|
737
|
+
if (!markerMap[markerName]) {
|
|
738
|
+
markerMap[markerName] = new WeakMap();
|
|
739
|
+
}
|
|
740
|
+
var markerCounter = markerMap[markerName];
|
|
741
|
+
var hiddenNodes = [];
|
|
742
|
+
var elementsToKeep = new Set();
|
|
743
|
+
var elementsToStop = new Set(targets);
|
|
744
|
+
var keep = function (el) {
|
|
745
|
+
if (!el || elementsToKeep.has(el)) {
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
elementsToKeep.add(el);
|
|
749
|
+
keep(el.parentNode);
|
|
750
|
+
};
|
|
751
|
+
targets.forEach(keep);
|
|
752
|
+
var deep = function (parent) {
|
|
753
|
+
if (!parent || elementsToStop.has(parent)) {
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
Array.prototype.forEach.call(parent.children, function (node) {
|
|
757
|
+
if (elementsToKeep.has(node)) {
|
|
758
|
+
deep(node);
|
|
759
|
+
}
|
|
760
|
+
else {
|
|
761
|
+
var attr = node.getAttribute(controlAttribute);
|
|
762
|
+
var alreadyHidden = attr !== null && attr !== 'false';
|
|
763
|
+
var counterValue = (counterMap.get(node) || 0) + 1;
|
|
764
|
+
var markerValue = (markerCounter.get(node) || 0) + 1;
|
|
765
|
+
counterMap.set(node, counterValue);
|
|
766
|
+
markerCounter.set(node, markerValue);
|
|
767
|
+
hiddenNodes.push(node);
|
|
768
|
+
if (counterValue === 1 && alreadyHidden) {
|
|
769
|
+
uncontrolledNodes.set(node, true);
|
|
770
|
+
}
|
|
771
|
+
if (markerValue === 1) {
|
|
772
|
+
node.setAttribute(markerName, 'true');
|
|
773
|
+
}
|
|
774
|
+
if (!alreadyHidden) {
|
|
775
|
+
node.setAttribute(controlAttribute, 'true');
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
});
|
|
779
|
+
};
|
|
780
|
+
deep(parentNode);
|
|
781
|
+
elementsToKeep.clear();
|
|
782
|
+
lockCount++;
|
|
783
|
+
return function () {
|
|
784
|
+
hiddenNodes.forEach(function (node) {
|
|
785
|
+
var counterValue = counterMap.get(node) - 1;
|
|
786
|
+
var markerValue = markerCounter.get(node) - 1;
|
|
787
|
+
counterMap.set(node, counterValue);
|
|
788
|
+
markerCounter.set(node, markerValue);
|
|
789
|
+
if (!counterValue) {
|
|
790
|
+
if (!uncontrolledNodes.has(node)) {
|
|
791
|
+
node.removeAttribute(controlAttribute);
|
|
792
|
+
}
|
|
793
|
+
uncontrolledNodes.delete(node);
|
|
794
|
+
}
|
|
795
|
+
if (!markerValue) {
|
|
796
|
+
node.removeAttribute(markerName);
|
|
797
|
+
}
|
|
798
|
+
});
|
|
799
|
+
lockCount--;
|
|
800
|
+
if (!lockCount) {
|
|
801
|
+
// clear
|
|
802
|
+
counterMap = new WeakMap();
|
|
803
|
+
counterMap = new WeakMap();
|
|
804
|
+
uncontrolledNodes = new WeakMap();
|
|
805
|
+
markerMap = {};
|
|
806
|
+
}
|
|
807
|
+
};
|
|
808
|
+
};
|
|
809
|
+
/**
|
|
810
|
+
* Marks everything except given node(or nodes) as aria-hidden
|
|
811
|
+
* @param {Element | Element[]} originalTarget - elements to keep on the page
|
|
812
|
+
* @param [parentNode] - top element, defaults to document.body
|
|
813
|
+
* @param {String} [markerName] - a special attribute to mark every node
|
|
814
|
+
* @return {Undo} undo command
|
|
815
|
+
*/
|
|
816
|
+
var hideOthers = function (originalTarget, parentNode, markerName) {
|
|
817
|
+
if (markerName === void 0) { markerName = 'data-aria-hidden'; }
|
|
818
|
+
var targets = Array.from(Array.isArray(originalTarget) ? originalTarget : [originalTarget]);
|
|
819
|
+
var activeParentNode = getDefaultParent(originalTarget);
|
|
820
|
+
if (!activeParentNode) {
|
|
821
|
+
return function () { return null; };
|
|
822
|
+
}
|
|
823
|
+
// we should not hide ariaLive elements - https://github.com/theKashey/aria-hidden/issues/10
|
|
824
|
+
targets.push.apply(targets, Array.from(activeParentNode.querySelectorAll('[aria-live]')));
|
|
825
|
+
return applyAttributeToOthers(targets, activeParentNode, markerName, 'aria-hidden');
|
|
826
|
+
};
|
|
827
|
+
|
|
828
|
+
const tabworthyDatesModalCss = () => `:host::part(body){position:absolute;width:-moz-fit-content;width:fit-content;z-index:1200;margin-top:0.5rem}:host::part(backdrop){}:host::part(content){}`;
|
|
829
|
+
|
|
830
|
+
const InclusiveDatesModal = class {
|
|
831
|
+
constructor(hostRef) {
|
|
832
|
+
index.registerInstance(this, hostRef);
|
|
833
|
+
this.opened = index.createEvent(this, "opened");
|
|
834
|
+
this.closed = index.createEvent(this, "closed");
|
|
835
|
+
this.inline = false;
|
|
836
|
+
this.closing = false;
|
|
837
|
+
this.showing = this.inline || false;
|
|
838
|
+
this.onKeyDown = (event) => {
|
|
839
|
+
if (event.code === "Escape") {
|
|
840
|
+
this.close();
|
|
841
|
+
}
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Open the dialog.
|
|
846
|
+
*/
|
|
847
|
+
async open() {
|
|
848
|
+
if (this.inline)
|
|
849
|
+
return;
|
|
850
|
+
this.showing = true;
|
|
851
|
+
this.undo = hideOthers(this.el);
|
|
852
|
+
this.opened.emit(undefined);
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* Close the dialog.
|
|
856
|
+
*/
|
|
857
|
+
async close() {
|
|
858
|
+
if (this.inline)
|
|
859
|
+
return;
|
|
860
|
+
this.showing = false;
|
|
861
|
+
this.closed.emit(undefined);
|
|
862
|
+
this.undo();
|
|
863
|
+
if (this.triggerElement)
|
|
864
|
+
this.triggerElement.focus();
|
|
865
|
+
}
|
|
866
|
+
async getState() {
|
|
867
|
+
return this.showing;
|
|
868
|
+
}
|
|
869
|
+
async setTriggerElement(element) {
|
|
870
|
+
this.triggerElement = element;
|
|
871
|
+
}
|
|
872
|
+
handleClick(event) {
|
|
873
|
+
if (this.showing && !this.el.contains(event.target)) {
|
|
874
|
+
this.close();
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
render() {
|
|
878
|
+
return (index.h(index.Host, { key: 'dd44f82a23c471268369362e7f0899d197b6686a', showing: this.showing, ref: (r) => r && (this.el = r) }, !this.inline && this.showing && (index.h("div", { key: '6c5d845e75737c366defff2434f51ca345a172f3', part: "body", onKeyDown: this.onKeyDown, role: "dialog", tabindex: -1, "aria-hidden": !this.showing, "aria-label": this.label, "aria-modal": this.showing }, index.h("focus-trap", { key: '56beecf073b790849d2761b3ac135641612744e1' }, index.h("div", { key: '85aca24946135337732f404ac164553f4374c9ec', part: "content" }, index.h("slot", { key: 'cb7b7c57ed1012256e3e045f64b40ce8c5d8dd8b' }))))), this.inline && (index.h("div", { key: '0a6d50757d0c77f1cc781dfe7676a4b3f8e74c22', part: "content" }, index.h("slot", { key: '17e71b147f00061c3f3f4deb3b66abb465714f8a' })))));
|
|
879
|
+
}
|
|
880
|
+
};
|
|
881
|
+
InclusiveDatesModal.style = tabworthyDatesModalCss();
|
|
882
|
+
|
|
883
|
+
exports.tabworthy_dates_calendar = InclusiveDatesCalendar;
|
|
884
|
+
exports.tabworthy_dates_modal = InclusiveDatesModal;
|