@ministryofjustice/frontend 5.0.0 → 5.1.1
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/moj/all.bundle.js +1598 -1062
- package/moj/all.bundle.js.map +1 -1
- package/moj/all.bundle.mjs +1894 -1054
- package/moj/all.bundle.mjs.map +1 -1
- package/moj/all.mjs +7 -90
- package/moj/all.mjs.map +1 -1
- package/moj/all.scss +1 -0
- package/moj/all.scss.map +1 -1
- package/moj/common/index.mjs +57 -0
- package/moj/common/index.mjs.map +1 -0
- package/moj/common/moj-frontend-version.mjs +14 -0
- package/moj/common/moj-frontend-version.mjs.map +1 -0
- package/moj/components/add-another/add-another.bundle.js +105 -76
- package/moj/components/add-another/add-another.bundle.js.map +1 -1
- package/moj/components/add-another/add-another.bundle.mjs +222 -71
- package/moj/components/add-another/add-another.bundle.mjs.map +1 -1
- package/moj/components/add-another/add-another.mjs +103 -72
- package/moj/components/add-another/add-another.mjs.map +1 -1
- package/moj/components/alert/alert.bundle.js +115 -191
- package/moj/components/alert/alert.bundle.js.map +1 -1
- package/moj/components/alert/alert.bundle.mjs +354 -186
- package/moj/components/alert/alert.bundle.mjs.map +1 -1
- package/moj/components/alert/alert.mjs +55 -140
- package/moj/components/alert/alert.mjs.map +1 -1
- package/moj/components/button-menu/README.md +3 -1
- package/moj/components/button-menu/button-menu.bundle.js +91 -120
- package/moj/components/button-menu/button-menu.bundle.js.map +1 -1
- package/moj/components/button-menu/button-menu.bundle.mjs +329 -114
- package/moj/components/button-menu/button-menu.bundle.mjs.map +1 -1
- package/moj/components/button-menu/button-menu.mjs +89 -116
- package/moj/components/button-menu/button-menu.mjs.map +1 -1
- package/moj/components/date-picker/date-picker.bundle.js +174 -154
- package/moj/components/date-picker/date-picker.bundle.js.map +1 -1
- package/moj/components/date-picker/date-picker.bundle.mjs +411 -147
- package/moj/components/date-picker/date-picker.bundle.mjs.map +1 -1
- package/moj/components/date-picker/date-picker.mjs +172 -150
- package/moj/components/date-picker/date-picker.mjs.map +1 -1
- package/moj/components/filter/template.njk +1 -1
- package/moj/components/filter-toggle-button/filter-toggle-button.bundle.js +133 -44
- package/moj/components/filter-toggle-button/filter-toggle-button.bundle.js.map +1 -1
- package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs +374 -41
- package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs.map +1 -1
- package/moj/components/filter-toggle-button/filter-toggle-button.mjs +131 -40
- package/moj/components/filter-toggle-button/filter-toggle-button.mjs.map +1 -1
- package/moj/components/form-validator/form-validator.bundle.js +159 -69
- package/moj/components/form-validator/form-validator.bundle.js.map +1 -1
- package/moj/components/form-validator/form-validator.bundle.mjs +399 -65
- package/moj/components/form-validator/form-validator.bundle.mjs.map +1 -1
- package/moj/components/form-validator/form-validator.mjs +134 -54
- package/moj/components/form-validator/form-validator.mjs.map +1 -1
- package/moj/components/multi-file-upload/multi-file-upload.bundle.js +291 -117
- package/moj/components/multi-file-upload/multi-file-upload.bundle.js.map +1 -1
- package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs +527 -109
- package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs.map +1 -1
- package/moj/components/multi-file-upload/multi-file-upload.mjs +288 -101
- package/moj/components/multi-file-upload/multi-file-upload.mjs.map +1 -1
- package/moj/components/multi-file-upload/template.njk +1 -1
- package/moj/components/multi-select/multi-select.bundle.js +106 -41
- package/moj/components/multi-select/multi-select.bundle.js.map +1 -1
- package/moj/components/multi-select/multi-select.bundle.mjs +346 -37
- package/moj/components/multi-select/multi-select.bundle.mjs.map +1 -1
- package/moj/components/multi-select/multi-select.mjs +104 -37
- package/moj/components/multi-select/multi-select.mjs.map +1 -1
- package/moj/components/password-reveal/_password-reveal.scss +3 -1
- package/moj/components/password-reveal/_password-reveal.scss.map +1 -1
- package/moj/components/password-reveal/password-reveal.bundle.js +32 -29
- package/moj/components/password-reveal/password-reveal.bundle.js.map +1 -1
- package/moj/components/password-reveal/password-reveal.bundle.mjs +149 -24
- package/moj/components/password-reveal/password-reveal.bundle.mjs.map +1 -1
- package/moj/components/password-reveal/password-reveal.mjs +30 -25
- package/moj/components/password-reveal/password-reveal.mjs.map +1 -1
- package/moj/components/rich-text-editor/README.md +4 -3
- package/moj/components/rich-text-editor/rich-text-editor.bundle.js +127 -62
- package/moj/components/rich-text-editor/rich-text-editor.bundle.js.map +1 -1
- package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs +367 -58
- package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs.map +1 -1
- package/moj/components/rich-text-editor/rich-text-editor.mjs +125 -58
- package/moj/components/rich-text-editor/rich-text-editor.mjs.map +1 -1
- package/moj/components/search-toggle/search-toggle.bundle.js +94 -26
- package/moj/components/search-toggle/search-toggle.bundle.js.map +1 -1
- package/moj/components/search-toggle/search-toggle.bundle.mjs +334 -22
- package/moj/components/search-toggle/search-toggle.bundle.mjs.map +1 -1
- package/moj/components/search-toggle/search-toggle.mjs +92 -22
- package/moj/components/search-toggle/search-toggle.mjs.map +1 -1
- package/moj/components/sortable-table/_sortable-table.scss +3 -42
- package/moj/components/sortable-table/_sortable-table.scss.map +1 -1
- package/moj/components/sortable-table/sortable-table.bundle.js +200 -83
- package/moj/components/sortable-table/sortable-table.bundle.js.map +1 -1
- package/moj/components/sortable-table/sortable-table.bundle.mjs +439 -78
- package/moj/components/sortable-table/sortable-table.bundle.mjs.map +1 -1
- package/moj/components/sortable-table/sortable-table.mjs +198 -79
- package/moj/components/sortable-table/sortable-table.mjs.map +1 -1
- package/moj/core/_all.scss +3 -0
- package/moj/core/_all.scss.map +1 -0
- package/moj/core/_moj-frontend-properties.scss +7 -0
- package/moj/core/_moj-frontend-properties.scss.map +1 -0
- package/moj/filters/prototype-kit-13-filters.js +4 -3
- package/moj/helpers.bundle.js +22 -77
- package/moj/helpers.bundle.js.map +1 -1
- package/moj/helpers.bundle.mjs +23 -74
- package/moj/helpers.bundle.mjs.map +1 -1
- package/moj/helpers.mjs +23 -74
- package/moj/helpers.mjs.map +1 -1
- package/moj/moj-frontend.min.css +1 -1
- package/moj/moj-frontend.min.css.map +1 -1
- package/moj/moj-frontend.min.js +1 -1
- package/moj/moj-frontend.min.js.map +1 -1
- package/package.json +1 -1
- package/moj/version.bundle.js +0 -12
- package/moj/version.bundle.js.map +0 -1
- package/moj/version.bundle.mjs +0 -4
- package/moj/version.bundle.mjs.map +0 -1
- package/moj/version.mjs +0 -4
- package/moj/version.mjs.map +0 -1
|
@@ -1,66 +1,34 @@
|
|
|
1
|
-
|
|
1
|
+
import { ConfigurableComponent } from 'govuk-frontend';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @augments {ConfigurableComponent<DatePickerConfig>}
|
|
5
|
+
*/
|
|
6
|
+
class DatePicker extends ConfigurableComponent {
|
|
2
7
|
/**
|
|
3
|
-
* @param {Element | null} $
|
|
8
|
+
* @param {Element | null} $root - HTML element to use for date picker
|
|
4
9
|
* @param {DatePickerConfig} [config] - Date picker config
|
|
5
10
|
*/
|
|
6
|
-
constructor($
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const $input = $module.querySelector('.moj-js-datepicker-input');
|
|
11
|
-
|
|
12
|
-
// Check that required elements are present
|
|
11
|
+
constructor($root, config = {}) {
|
|
12
|
+
var _this$config$input$el;
|
|
13
|
+
super($root, config);
|
|
14
|
+
const $input = (_this$config$input$el = this.config.input.element) != null ? _this$config$input$el : this.$root.querySelector(this.config.input.selector);
|
|
13
15
|
if (!$input || !($input instanceof HTMLInputElement)) {
|
|
14
16
|
return this;
|
|
15
17
|
}
|
|
16
|
-
this.$module = $module;
|
|
17
18
|
this.$input = $input;
|
|
18
|
-
const schema = Object.freeze({
|
|
19
|
-
properties: {
|
|
20
|
-
excludedDates: {
|
|
21
|
-
type: 'string'
|
|
22
|
-
},
|
|
23
|
-
excludedDays: {
|
|
24
|
-
type: 'string'
|
|
25
|
-
},
|
|
26
|
-
leadingZeros: {
|
|
27
|
-
type: 'string'
|
|
28
|
-
},
|
|
29
|
-
maxDate: {
|
|
30
|
-
type: 'string'
|
|
31
|
-
},
|
|
32
|
-
minDate: {
|
|
33
|
-
type: 'string'
|
|
34
|
-
},
|
|
35
|
-
weekStartDay: {
|
|
36
|
-
type: 'string'
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
const defaults = {
|
|
41
|
-
leadingZeros: false,
|
|
42
|
-
weekStartDay: 'monday'
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
// data attributes override JS config, which overrides defaults
|
|
46
|
-
this.config = this.mergeConfigs(defaults, config, this.parseDataset(schema, $module.dataset));
|
|
47
19
|
this.dayLabels = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
|
|
48
20
|
this.monthLabels = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
|
49
21
|
this.currentDate = new Date();
|
|
50
22
|
this.currentDate.setHours(0, 0, 0, 0);
|
|
51
|
-
this.calendarDays = [];
|
|
52
|
-
this.excludedDates = [];
|
|
53
|
-
this.excludedDays = [];
|
|
23
|
+
this.calendarDays = /** @type {DSCalendarDay[]} */[];
|
|
24
|
+
this.excludedDates = /** @type {Date[]} */[];
|
|
25
|
+
this.excludedDays = /** @type {number[]} */[];
|
|
54
26
|
this.buttonClass = 'moj-datepicker__button';
|
|
55
27
|
this.selectedDayButtonClass = 'moj-datepicker__button--selected';
|
|
56
28
|
this.currentDayButtonClass = 'moj-datepicker__button--current';
|
|
57
29
|
this.todayButtonClass = 'moj-datepicker__button--today';
|
|
58
|
-
if (this.$module.dataset.initialized) {
|
|
59
|
-
return this;
|
|
60
|
-
}
|
|
61
30
|
this.setOptions();
|
|
62
31
|
this.initControls();
|
|
63
|
-
this.$module.setAttribute('data-initialized', 'true');
|
|
64
32
|
}
|
|
65
33
|
initControls() {
|
|
66
34
|
this.id = `datepicker-${this.$input.id}`;
|
|
@@ -75,15 +43,23 @@ class DatePicker {
|
|
|
75
43
|
$inputWrapper.appendChild(this.$input);
|
|
76
44
|
$inputWrapper.insertAdjacentHTML('beforeend', this.toggleTemplate());
|
|
77
45
|
$componentWrapper.insertAdjacentElement('beforeend', this.$dialog);
|
|
78
|
-
this.$calendarButton =
|
|
79
|
-
this.$
|
|
46
|
+
this.$calendarButton = /** @type {HTMLButtonElement} */
|
|
47
|
+
this.$root.querySelector('.moj-js-datepicker-toggle');
|
|
48
|
+
this.$dialogTitle = /** @type {HTMLHeadingElement} */
|
|
49
|
+
this.$dialog.querySelector('.moj-js-datepicker-month-year');
|
|
80
50
|
this.createCalendar();
|
|
81
|
-
this.$prevMonthButton =
|
|
82
|
-
this.$
|
|
83
|
-
this.$
|
|
84
|
-
this.$
|
|
85
|
-
this.$
|
|
86
|
-
this.$
|
|
51
|
+
this.$prevMonthButton = /** @type {HTMLButtonElement} */
|
|
52
|
+
this.$dialog.querySelector('.moj-js-datepicker-prev-month');
|
|
53
|
+
this.$prevYearButton = /** @type {HTMLButtonElement} */
|
|
54
|
+
this.$dialog.querySelector('.moj-js-datepicker-prev-year');
|
|
55
|
+
this.$nextMonthButton = /** @type {HTMLButtonElement} */
|
|
56
|
+
this.$dialog.querySelector('.moj-js-datepicker-next-month');
|
|
57
|
+
this.$nextYearButton = /** @type {HTMLButtonElement} */
|
|
58
|
+
this.$dialog.querySelector('.moj-js-datepicker-next-year');
|
|
59
|
+
this.$cancelButton = /** @type {HTMLButtonElement} */
|
|
60
|
+
this.$dialog.querySelector('.moj-js-datepicker-cancel');
|
|
61
|
+
this.$okButton = /** @type {HTMLButtonElement} */
|
|
62
|
+
this.$dialog.querySelector('.moj-js-datepicker-ok');
|
|
87
63
|
|
|
88
64
|
// add event listeners
|
|
89
65
|
this.$prevMonthButton.addEventListener('click', event => this.focusPreviousMonth(event, false));
|
|
@@ -97,9 +73,9 @@ class DatePicker {
|
|
|
97
73
|
this.$okButton.addEventListener('click', () => {
|
|
98
74
|
this.selectDate(this.currentDate);
|
|
99
75
|
});
|
|
100
|
-
const dialogButtons = this.$dialog.querySelectorAll('button:not([disabled="true"])');
|
|
101
|
-
this.$firstButtonInDialog = dialogButtons[0];
|
|
102
|
-
this.$lastButtonInDialog = dialogButtons[dialogButtons.length - 1];
|
|
76
|
+
const $dialogButtons = this.$dialog.querySelectorAll('button:not([disabled="true"])');
|
|
77
|
+
this.$firstButtonInDialog = $dialogButtons[0];
|
|
78
|
+
this.$lastButtonInDialog = $dialogButtons[$dialogButtons.length - 1];
|
|
103
79
|
this.$firstButtonInDialog.addEventListener('keydown', event => this.firstButtonKeydown(event));
|
|
104
80
|
this.$lastButtonInDialog.addEventListener('keydown', event => this.lastButtonKeydown(event));
|
|
105
81
|
this.$calendarButton.addEventListener('click', event => this.toggleDialog(event));
|
|
@@ -245,7 +221,6 @@ class DatePicker {
|
|
|
245
221
|
this.setMinAndMaxDatesOnCalendar();
|
|
246
222
|
this.setExcludedDates();
|
|
247
223
|
this.setExcludedDays();
|
|
248
|
-
this.setLeadingZeros();
|
|
249
224
|
this.setWeekStartDay();
|
|
250
225
|
}
|
|
251
226
|
setMinAndMaxDatesOnCalendar() {
|
|
@@ -270,10 +245,10 @@ class DatePicker {
|
|
|
270
245
|
}
|
|
271
246
|
}
|
|
272
247
|
|
|
273
|
-
|
|
248
|
+
/**
|
|
274
249
|
* Parses a daterange string into an array of dates
|
|
275
|
-
*
|
|
276
|
-
* @
|
|
250
|
+
*
|
|
251
|
+
* @param {string} datestring - A daterange string in the format "dd/mm/yyyy-dd/mm/yyyy"
|
|
277
252
|
*/
|
|
278
253
|
parseDateRangeString(datestring) {
|
|
279
254
|
const dates = [];
|
|
@@ -300,17 +275,6 @@ class DatePicker {
|
|
|
300
275
|
this.excludedDays = this.config.excludedDays.replace(/\s+/, ' ').toLowerCase().split(' ').map(item => weekDays.indexOf(item)).filter(item => item !== -1);
|
|
301
276
|
}
|
|
302
277
|
}
|
|
303
|
-
setLeadingZeros() {
|
|
304
|
-
if (typeof this.config.leadingZeros !== 'boolean') {
|
|
305
|
-
if (this.config.leadingZeros.toLowerCase() === 'true') {
|
|
306
|
-
this.config.leadingZeros = true;
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
|
-
if (this.config.leadingZeros.toLowerCase() === 'false') {
|
|
310
|
-
this.config.leadingZeros = false;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
278
|
setWeekStartDay() {
|
|
315
279
|
const weekStartDayParam = this.config.weekStartDay;
|
|
316
280
|
if (weekStartDayParam && weekStartDayParam.toLowerCase() === 'sunday') {
|
|
@@ -323,7 +287,7 @@ class DatePicker {
|
|
|
323
287
|
}
|
|
324
288
|
|
|
325
289
|
/**
|
|
326
|
-
* Determine if a date is
|
|
290
|
+
* Determine if a date is selectable
|
|
327
291
|
*
|
|
328
292
|
* @param {Date} date - the date to check
|
|
329
293
|
* @returns {boolean}
|
|
@@ -389,24 +353,36 @@ class DatePicker {
|
|
|
389
353
|
/**
|
|
390
354
|
* Get a human readable date in the format Monday 2 March 2024
|
|
391
355
|
*
|
|
392
|
-
* @param {Date} date -
|
|
356
|
+
* @param {Date} date - Date to format
|
|
393
357
|
* @returns {string}
|
|
394
358
|
*/
|
|
395
359
|
formattedDateHuman(date) {
|
|
396
360
|
return `${this.dayLabels[(date.getDay() + 6) % 7]} ${date.getDate()} ${this.monthLabels[date.getMonth()]} ${date.getFullYear()}`;
|
|
397
361
|
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* @param {MouseEvent} event - Click event
|
|
365
|
+
*/
|
|
398
366
|
backgroundClick(event) {
|
|
399
367
|
if (this.isOpen() && event.target instanceof Node && !this.$dialog.contains(event.target) && !this.$input.contains(event.target) && !this.$calendarButton.contains(event.target)) {
|
|
400
368
|
event.preventDefault();
|
|
401
369
|
this.closeDialog();
|
|
402
370
|
}
|
|
403
371
|
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* @param {KeyboardEvent} event - Keydown event
|
|
375
|
+
*/
|
|
404
376
|
firstButtonKeydown(event) {
|
|
405
377
|
if (event.key === 'Tab' && event.shiftKey) {
|
|
406
378
|
this.$lastButtonInDialog.focus();
|
|
407
379
|
event.preventDefault();
|
|
408
380
|
}
|
|
409
381
|
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* @param {KeyboardEvent} event - Keydown event
|
|
385
|
+
*/
|
|
410
386
|
lastButtonKeydown(event) {
|
|
411
387
|
if (event.key === 'Tab' && !event.shiftKey) {
|
|
412
388
|
this.$firstButtonInDialog.focus();
|
|
@@ -436,49 +412,57 @@ class DatePicker {
|
|
|
436
412
|
thisDay.setDate(thisDay.getDate() + 1);
|
|
437
413
|
}
|
|
438
414
|
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* @param {boolean} [focus] - Focus the day button
|
|
418
|
+
*/
|
|
439
419
|
setCurrentDate(focus = true) {
|
|
440
420
|
const {
|
|
441
421
|
currentDate
|
|
442
422
|
} = this;
|
|
443
423
|
this.calendarDays.forEach(calendarDay => {
|
|
444
|
-
calendarDay
|
|
445
|
-
calendarDay
|
|
446
|
-
calendarDay
|
|
447
|
-
calendarDay
|
|
424
|
+
calendarDay.$button.classList.add('moj-datepicker__button');
|
|
425
|
+
calendarDay.$button.classList.add('moj-datepicker__calendar-day');
|
|
426
|
+
calendarDay.$button.setAttribute('tabindex', '-1');
|
|
427
|
+
calendarDay.$button.classList.remove(this.selectedDayButtonClass);
|
|
448
428
|
const calendarDayDate = calendarDay.date;
|
|
449
429
|
calendarDayDate.setHours(0, 0, 0, 0);
|
|
450
430
|
const today = new Date();
|
|
451
431
|
today.setHours(0, 0, 0, 0);
|
|
452
432
|
if (calendarDayDate.getTime() === currentDate.getTime() /* && !calendarDay.button.disabled */) {
|
|
453
433
|
if (focus) {
|
|
454
|
-
calendarDay
|
|
455
|
-
calendarDay
|
|
456
|
-
calendarDay
|
|
434
|
+
calendarDay.$button.setAttribute('tabindex', '0');
|
|
435
|
+
calendarDay.$button.focus();
|
|
436
|
+
calendarDay.$button.classList.add(this.selectedDayButtonClass);
|
|
457
437
|
}
|
|
458
438
|
}
|
|
459
439
|
if (this.inputDate && calendarDayDate.getTime() === this.inputDate.getTime()) {
|
|
460
|
-
calendarDay
|
|
461
|
-
calendarDay
|
|
440
|
+
calendarDay.$button.classList.add(this.currentDayButtonClass);
|
|
441
|
+
calendarDay.$button.setAttribute('aria-current', 'date');
|
|
462
442
|
} else {
|
|
463
|
-
calendarDay
|
|
464
|
-
calendarDay
|
|
443
|
+
calendarDay.$button.classList.remove(this.currentDayButtonClass);
|
|
444
|
+
calendarDay.$button.removeAttribute('aria-current');
|
|
465
445
|
}
|
|
466
446
|
if (calendarDayDate.getTime() === today.getTime()) {
|
|
467
|
-
calendarDay
|
|
447
|
+
calendarDay.$button.classList.add(this.todayButtonClass);
|
|
468
448
|
} else {
|
|
469
|
-
calendarDay
|
|
449
|
+
calendarDay.$button.classList.remove(this.todayButtonClass);
|
|
470
450
|
}
|
|
471
451
|
});
|
|
472
452
|
|
|
473
453
|
// if no date is tab-able, make the first non-disabled date tab-able
|
|
474
454
|
if (!focus) {
|
|
475
455
|
const enabledDays = this.calendarDays.filter(calendarDay => {
|
|
476
|
-
return window.getComputedStyle(calendarDay
|
|
456
|
+
return window.getComputedStyle(calendarDay.$button).display === 'block' && !calendarDay.$button.disabled;
|
|
477
457
|
});
|
|
478
|
-
enabledDays[0]
|
|
458
|
+
enabledDays[0].$button.setAttribute('tabindex', '0');
|
|
479
459
|
this.currentDate = enabledDays[0].date;
|
|
480
460
|
}
|
|
481
461
|
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* @param {Date} date - Date to select
|
|
465
|
+
*/
|
|
482
466
|
selectDate(date) {
|
|
483
467
|
if (this.isExcludedDate(date)) {
|
|
484
468
|
return;
|
|
@@ -495,6 +479,10 @@ class DatePicker {
|
|
|
495
479
|
isOpen() {
|
|
496
480
|
return this.$dialog.classList.contains('moj-datepicker__dialog--open');
|
|
497
481
|
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* @param {MouseEvent} event - Click event
|
|
485
|
+
*/
|
|
498
486
|
toggleDialog(event) {
|
|
499
487
|
event.preventDefault();
|
|
500
488
|
if (this.isOpen()) {
|
|
@@ -529,6 +517,11 @@ class DatePicker {
|
|
|
529
517
|
this.$calendarButton.setAttribute('aria-expanded', 'false');
|
|
530
518
|
this.$calendarButton.focus();
|
|
531
519
|
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* @param {Date} date - Date to go to
|
|
523
|
+
* @param {boolean} [focus] - Focus the day button
|
|
524
|
+
*/
|
|
532
525
|
goToDate(date, focus) {
|
|
533
526
|
const current = this.currentDate;
|
|
534
527
|
this.currentDate = date;
|
|
@@ -580,13 +573,23 @@ class DatePicker {
|
|
|
580
573
|
this.goToDate(date);
|
|
581
574
|
}
|
|
582
575
|
|
|
583
|
-
|
|
576
|
+
/**
|
|
577
|
+
* Month navigation
|
|
578
|
+
*
|
|
579
|
+
* @param {KeyboardEvent | MouseEvent} event - Key press or click event
|
|
580
|
+
* @param {boolean} [focus] - Focus the day button
|
|
581
|
+
*/
|
|
584
582
|
focusNextMonth(event, focus = true) {
|
|
585
583
|
event.preventDefault();
|
|
586
584
|
const date = new Date(this.currentDate);
|
|
587
585
|
date.setMonth(date.getMonth() + 1, 1);
|
|
588
586
|
this.goToDate(date, focus);
|
|
589
587
|
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* @param {KeyboardEvent | MouseEvent} event - Key press or click event
|
|
591
|
+
* @param {boolean} [focus] - Focus the day button
|
|
592
|
+
*/
|
|
590
593
|
focusPreviousMonth(event, focus = true) {
|
|
591
594
|
event.preventDefault();
|
|
592
595
|
const date = new Date(this.currentDate);
|
|
@@ -594,13 +597,23 @@ class DatePicker {
|
|
|
594
597
|
this.goToDate(date, focus);
|
|
595
598
|
}
|
|
596
599
|
|
|
597
|
-
|
|
600
|
+
/**
|
|
601
|
+
* Year navigation
|
|
602
|
+
*
|
|
603
|
+
* @param {KeyboardEvent | MouseEvent} event - Key press or click event
|
|
604
|
+
* @param {boolean} [focus] - Focus the day button
|
|
605
|
+
*/
|
|
598
606
|
focusNextYear(event, focus = true) {
|
|
599
607
|
event.preventDefault();
|
|
600
608
|
const date = new Date(this.currentDate);
|
|
601
609
|
date.setFullYear(date.getFullYear() + 1, date.getMonth(), 1);
|
|
602
610
|
this.goToDate(date, focus);
|
|
603
611
|
}
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* @param {KeyboardEvent | MouseEvent} event - Key press or click event
|
|
615
|
+
* @param {boolean} [focus] - Focus the day button
|
|
616
|
+
*/
|
|
604
617
|
focusPreviousYear(event, focus = true) {
|
|
605
618
|
event.preventDefault();
|
|
606
619
|
const date = new Date(this.currentDate);
|
|
@@ -609,72 +622,70 @@ class DatePicker {
|
|
|
609
622
|
}
|
|
610
623
|
|
|
611
624
|
/**
|
|
612
|
-
*
|
|
613
|
-
*
|
|
614
|
-
* @param {Schema} schema - Component class
|
|
615
|
-
* @param {DOMStringMap} dataset - HTML element dataset
|
|
616
|
-
* @returns {object} Normalised dataset
|
|
617
|
-
*/
|
|
618
|
-
parseDataset(schema, dataset) {
|
|
619
|
-
const parsed = {};
|
|
620
|
-
for (const [field,,] of Object.entries(schema.properties)) {
|
|
621
|
-
if (field in dataset) {
|
|
622
|
-
parsed[field] = dataset[field];
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
return parsed;
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
/**
|
|
629
|
-
* Config merging function
|
|
630
|
-
*
|
|
631
|
-
* Takes any number of objects and combines them together, with
|
|
632
|
-
* greatest priority on the LAST item passed in.
|
|
633
|
-
*
|
|
634
|
-
* @param {...{ [key: string]: unknown }} configObjects - Config objects to merge
|
|
635
|
-
* @returns {{ [key: string]: unknown }} A merged config object
|
|
625
|
+
* Name for the component used when initialising using data-module attributes.
|
|
636
626
|
*/
|
|
637
|
-
mergeConfigs(...configObjects) {
|
|
638
|
-
const formattedConfigObject = {};
|
|
639
|
-
|
|
640
|
-
// Loop through each of the passed objects
|
|
641
|
-
for (const configObject of configObjects) {
|
|
642
|
-
for (const key of Object.keys(configObject)) {
|
|
643
|
-
const option = formattedConfigObject[key];
|
|
644
|
-
const override = configObject[key];
|
|
645
|
-
|
|
646
|
-
// Push their keys one-by-one into formattedConfigObject. Any duplicate
|
|
647
|
-
// keys with object values will be merged, otherwise the new value will
|
|
648
|
-
// override the existing value.
|
|
649
|
-
if (typeof option === 'object' && typeof override === 'object') {
|
|
650
|
-
// @ts-expect-error Index signature for type 'string' is missing
|
|
651
|
-
formattedConfigObject[key] = this.mergeConfigs(option, override);
|
|
652
|
-
} else {
|
|
653
|
-
formattedConfigObject[key] = override;
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
return formattedConfigObject;
|
|
658
|
-
}
|
|
659
627
|
}
|
|
628
|
+
DatePicker.moduleName = 'moj-date-picker';
|
|
629
|
+
/**
|
|
630
|
+
* Date picker default config
|
|
631
|
+
*
|
|
632
|
+
* @type {DatePickerConfig}
|
|
633
|
+
*/
|
|
634
|
+
DatePicker.defaults = Object.freeze({
|
|
635
|
+
leadingZeros: false,
|
|
636
|
+
weekStartDay: 'monday',
|
|
637
|
+
input: {
|
|
638
|
+
selector: '.moj-js-datepicker-input'
|
|
639
|
+
}
|
|
640
|
+
});
|
|
641
|
+
/**
|
|
642
|
+
* Date picker config schema
|
|
643
|
+
*
|
|
644
|
+
* @satisfies {Schema<DatePickerConfig>}
|
|
645
|
+
*/
|
|
646
|
+
DatePicker.schema = Object.freeze(/** @type {const} */{
|
|
647
|
+
properties: {
|
|
648
|
+
excludedDates: {
|
|
649
|
+
type: 'string'
|
|
650
|
+
},
|
|
651
|
+
excludedDays: {
|
|
652
|
+
type: 'string'
|
|
653
|
+
},
|
|
654
|
+
leadingZeros: {
|
|
655
|
+
type: 'boolean'
|
|
656
|
+
},
|
|
657
|
+
maxDate: {
|
|
658
|
+
type: 'string'
|
|
659
|
+
},
|
|
660
|
+
minDate: {
|
|
661
|
+
type: 'string'
|
|
662
|
+
},
|
|
663
|
+
weekStartDay: {
|
|
664
|
+
type: 'string'
|
|
665
|
+
},
|
|
666
|
+
input: {
|
|
667
|
+
type: 'object'
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
});
|
|
660
671
|
class DSCalendarDay {
|
|
661
672
|
/**
|
|
662
673
|
*
|
|
663
|
-
* @param {
|
|
674
|
+
* @param {HTMLButtonElement} $button
|
|
664
675
|
* @param {number} index
|
|
665
676
|
* @param {number} row
|
|
666
677
|
* @param {number} column
|
|
667
678
|
* @param {DatePicker} picker
|
|
668
679
|
*/
|
|
669
|
-
constructor(button, index, row, column, picker) {
|
|
680
|
+
constructor($button, index, row, column, picker) {
|
|
670
681
|
this.index = index;
|
|
671
682
|
this.row = row;
|
|
672
683
|
this.column = column;
|
|
673
|
-
this
|
|
684
|
+
this.$button = $button;
|
|
674
685
|
this.picker = picker;
|
|
675
686
|
this.date = new Date();
|
|
676
|
-
this
|
|
677
|
-
this
|
|
687
|
+
this.$button.addEventListener('keydown', this.keyPress.bind(this));
|
|
688
|
+
this.$button.addEventListener('click', this.click.bind(this));
|
|
678
689
|
}
|
|
679
690
|
|
|
680
691
|
/**
|
|
@@ -686,26 +697,34 @@ class DSCalendarDay {
|
|
|
686
697
|
const label = day.getDate();
|
|
687
698
|
let accessibleLabel = this.picker.formattedDateHuman(day);
|
|
688
699
|
if (disabled) {
|
|
689
|
-
this
|
|
700
|
+
this.$button.setAttribute('aria-disabled', 'true');
|
|
690
701
|
accessibleLabel = `Excluded date, ${accessibleLabel}`;
|
|
691
702
|
} else {
|
|
692
|
-
this
|
|
703
|
+
this.$button.removeAttribute('aria-disabled');
|
|
693
704
|
}
|
|
694
705
|
if (hidden) {
|
|
695
|
-
this
|
|
706
|
+
this.$button.style.display = 'none';
|
|
696
707
|
} else {
|
|
697
|
-
this
|
|
708
|
+
this.$button.style.display = 'block';
|
|
698
709
|
}
|
|
699
|
-
this
|
|
700
|
-
this
|
|
710
|
+
this.$button.setAttribute('data-testid', this.picker.formattedDateFromDate(day));
|
|
711
|
+
this.$button.innerHTML = `<span class="govuk-visually-hidden">${accessibleLabel}</span><span aria-hidden="true">${label}</span>`;
|
|
701
712
|
this.date = new Date(day);
|
|
702
713
|
}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* @param {MouseEvent} event - Click event
|
|
717
|
+
*/
|
|
703
718
|
click(event) {
|
|
704
719
|
this.picker.goToDate(this.date);
|
|
705
720
|
this.picker.selectDate(this.date);
|
|
706
721
|
event.stopPropagation();
|
|
707
722
|
event.preventDefault();
|
|
708
723
|
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* @param {KeyboardEvent} event - Keydown event
|
|
727
|
+
*/
|
|
709
728
|
keyPress(event) {
|
|
710
729
|
let calendarNavKey = true;
|
|
711
730
|
switch (event.key) {
|
|
@@ -762,14 +781,17 @@ class DSCalendarDay {
|
|
|
762
781
|
* @typedef {object} DatePickerConfig
|
|
763
782
|
* @property {string} [excludedDates] - Dates that cannot be selected
|
|
764
783
|
* @property {string} [excludedDays] - Days that cannot be selected
|
|
765
|
-
* @property {boolean} [
|
|
784
|
+
* @property {boolean} [leadingZeros] - Whether to add leading zeroes when populating the field
|
|
766
785
|
* @property {string} [minDate] - The earliest available date
|
|
767
786
|
* @property {string} [maxDate] - The latest available date
|
|
768
787
|
* @property {string} [weekStartDay] - First day of the week in calendar view
|
|
788
|
+
* @property {object} [input] - Input config
|
|
789
|
+
* @property {string} [input.selector] - Selector for the input element
|
|
790
|
+
* @property {Element | null} [input.element] - HTML element for the input
|
|
769
791
|
*/
|
|
770
792
|
|
|
771
793
|
/**
|
|
772
|
-
* @import { Schema } from '
|
|
794
|
+
* @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'
|
|
773
795
|
*/
|
|
774
796
|
|
|
775
797
|
export { DatePicker };
|