@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,72 +1,38 @@
|
|
|
1
1
|
(function (global, factory) {
|
|
2
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
3
|
-
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
4
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.MOJFrontend = global.MOJFrontend || {}));
|
|
5
|
-
})(this, (function (exports) { 'use strict';
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('govuk-frontend')) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports', 'govuk-frontend'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.MOJFrontend = global.MOJFrontend || {}, global.GOVUKFrontend));
|
|
5
|
+
})(this, (function (exports, govukFrontend) { 'use strict';
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* @augments {ConfigurableComponent<DatePickerConfig>}
|
|
9
|
+
*/
|
|
10
|
+
class DatePicker extends govukFrontend.ConfigurableComponent {
|
|
8
11
|
/**
|
|
9
|
-
* @param {Element | null} $
|
|
12
|
+
* @param {Element | null} $root - HTML element to use for date picker
|
|
10
13
|
* @param {DatePickerConfig} [config] - Date picker config
|
|
11
14
|
*/
|
|
12
|
-
constructor($
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const $input = $module.querySelector('.moj-js-datepicker-input');
|
|
17
|
-
|
|
18
|
-
// Check that required elements are present
|
|
15
|
+
constructor($root, config = {}) {
|
|
16
|
+
var _this$config$input$el;
|
|
17
|
+
super($root, config);
|
|
18
|
+
const $input = (_this$config$input$el = this.config.input.element) != null ? _this$config$input$el : this.$root.querySelector(this.config.input.selector);
|
|
19
19
|
if (!$input || !($input instanceof HTMLInputElement)) {
|
|
20
20
|
return this;
|
|
21
21
|
}
|
|
22
|
-
this.$module = $module;
|
|
23
22
|
this.$input = $input;
|
|
24
|
-
const schema = Object.freeze({
|
|
25
|
-
properties: {
|
|
26
|
-
excludedDates: {
|
|
27
|
-
type: 'string'
|
|
28
|
-
},
|
|
29
|
-
excludedDays: {
|
|
30
|
-
type: 'string'
|
|
31
|
-
},
|
|
32
|
-
leadingZeros: {
|
|
33
|
-
type: 'string'
|
|
34
|
-
},
|
|
35
|
-
maxDate: {
|
|
36
|
-
type: 'string'
|
|
37
|
-
},
|
|
38
|
-
minDate: {
|
|
39
|
-
type: 'string'
|
|
40
|
-
},
|
|
41
|
-
weekStartDay: {
|
|
42
|
-
type: 'string'
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
const defaults = {
|
|
47
|
-
leadingZeros: false,
|
|
48
|
-
weekStartDay: 'monday'
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// data attributes override JS config, which overrides defaults
|
|
52
|
-
this.config = this.mergeConfigs(defaults, config, this.parseDataset(schema, $module.dataset));
|
|
53
23
|
this.dayLabels = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
|
|
54
24
|
this.monthLabels = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
|
55
25
|
this.currentDate = new Date();
|
|
56
26
|
this.currentDate.setHours(0, 0, 0, 0);
|
|
57
|
-
this.calendarDays = [];
|
|
58
|
-
this.excludedDates = [];
|
|
59
|
-
this.excludedDays = [];
|
|
27
|
+
this.calendarDays = /** @type {DSCalendarDay[]} */[];
|
|
28
|
+
this.excludedDates = /** @type {Date[]} */[];
|
|
29
|
+
this.excludedDays = /** @type {number[]} */[];
|
|
60
30
|
this.buttonClass = 'moj-datepicker__button';
|
|
61
31
|
this.selectedDayButtonClass = 'moj-datepicker__button--selected';
|
|
62
32
|
this.currentDayButtonClass = 'moj-datepicker__button--current';
|
|
63
33
|
this.todayButtonClass = 'moj-datepicker__button--today';
|
|
64
|
-
if (this.$module.dataset.initialized) {
|
|
65
|
-
return this;
|
|
66
|
-
}
|
|
67
34
|
this.setOptions();
|
|
68
35
|
this.initControls();
|
|
69
|
-
this.$module.setAttribute('data-initialized', 'true');
|
|
70
36
|
}
|
|
71
37
|
initControls() {
|
|
72
38
|
this.id = `datepicker-${this.$input.id}`;
|
|
@@ -81,15 +47,23 @@
|
|
|
81
47
|
$inputWrapper.appendChild(this.$input);
|
|
82
48
|
$inputWrapper.insertAdjacentHTML('beforeend', this.toggleTemplate());
|
|
83
49
|
$componentWrapper.insertAdjacentElement('beforeend', this.$dialog);
|
|
84
|
-
this.$calendarButton =
|
|
85
|
-
this.$
|
|
50
|
+
this.$calendarButton = /** @type {HTMLButtonElement} */
|
|
51
|
+
this.$root.querySelector('.moj-js-datepicker-toggle');
|
|
52
|
+
this.$dialogTitle = /** @type {HTMLHeadingElement} */
|
|
53
|
+
this.$dialog.querySelector('.moj-js-datepicker-month-year');
|
|
86
54
|
this.createCalendar();
|
|
87
|
-
this.$prevMonthButton =
|
|
88
|
-
this.$
|
|
89
|
-
this.$
|
|
90
|
-
this.$
|
|
91
|
-
this.$
|
|
92
|
-
this.$
|
|
55
|
+
this.$prevMonthButton = /** @type {HTMLButtonElement} */
|
|
56
|
+
this.$dialog.querySelector('.moj-js-datepicker-prev-month');
|
|
57
|
+
this.$prevYearButton = /** @type {HTMLButtonElement} */
|
|
58
|
+
this.$dialog.querySelector('.moj-js-datepicker-prev-year');
|
|
59
|
+
this.$nextMonthButton = /** @type {HTMLButtonElement} */
|
|
60
|
+
this.$dialog.querySelector('.moj-js-datepicker-next-month');
|
|
61
|
+
this.$nextYearButton = /** @type {HTMLButtonElement} */
|
|
62
|
+
this.$dialog.querySelector('.moj-js-datepicker-next-year');
|
|
63
|
+
this.$cancelButton = /** @type {HTMLButtonElement} */
|
|
64
|
+
this.$dialog.querySelector('.moj-js-datepicker-cancel');
|
|
65
|
+
this.$okButton = /** @type {HTMLButtonElement} */
|
|
66
|
+
this.$dialog.querySelector('.moj-js-datepicker-ok');
|
|
93
67
|
|
|
94
68
|
// add event listeners
|
|
95
69
|
this.$prevMonthButton.addEventListener('click', event => this.focusPreviousMonth(event, false));
|
|
@@ -103,9 +77,9 @@
|
|
|
103
77
|
this.$okButton.addEventListener('click', () => {
|
|
104
78
|
this.selectDate(this.currentDate);
|
|
105
79
|
});
|
|
106
|
-
const dialogButtons = this.$dialog.querySelectorAll('button:not([disabled="true"])');
|
|
107
|
-
this.$firstButtonInDialog = dialogButtons[0];
|
|
108
|
-
this.$lastButtonInDialog = dialogButtons[dialogButtons.length - 1];
|
|
80
|
+
const $dialogButtons = this.$dialog.querySelectorAll('button:not([disabled="true"])');
|
|
81
|
+
this.$firstButtonInDialog = $dialogButtons[0];
|
|
82
|
+
this.$lastButtonInDialog = $dialogButtons[$dialogButtons.length - 1];
|
|
109
83
|
this.$firstButtonInDialog.addEventListener('keydown', event => this.firstButtonKeydown(event));
|
|
110
84
|
this.$lastButtonInDialog.addEventListener('keydown', event => this.lastButtonKeydown(event));
|
|
111
85
|
this.$calendarButton.addEventListener('click', event => this.toggleDialog(event));
|
|
@@ -251,7 +225,6 @@
|
|
|
251
225
|
this.setMinAndMaxDatesOnCalendar();
|
|
252
226
|
this.setExcludedDates();
|
|
253
227
|
this.setExcludedDays();
|
|
254
|
-
this.setLeadingZeros();
|
|
255
228
|
this.setWeekStartDay();
|
|
256
229
|
}
|
|
257
230
|
setMinAndMaxDatesOnCalendar() {
|
|
@@ -276,10 +249,10 @@
|
|
|
276
249
|
}
|
|
277
250
|
}
|
|
278
251
|
|
|
279
|
-
|
|
252
|
+
/**
|
|
280
253
|
* Parses a daterange string into an array of dates
|
|
281
|
-
*
|
|
282
|
-
* @
|
|
254
|
+
*
|
|
255
|
+
* @param {string} datestring - A daterange string in the format "dd/mm/yyyy-dd/mm/yyyy"
|
|
283
256
|
*/
|
|
284
257
|
parseDateRangeString(datestring) {
|
|
285
258
|
const dates = [];
|
|
@@ -306,17 +279,6 @@
|
|
|
306
279
|
this.excludedDays = this.config.excludedDays.replace(/\s+/, ' ').toLowerCase().split(' ').map(item => weekDays.indexOf(item)).filter(item => item !== -1);
|
|
307
280
|
}
|
|
308
281
|
}
|
|
309
|
-
setLeadingZeros() {
|
|
310
|
-
if (typeof this.config.leadingZeros !== 'boolean') {
|
|
311
|
-
if (this.config.leadingZeros.toLowerCase() === 'true') {
|
|
312
|
-
this.config.leadingZeros = true;
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
if (this.config.leadingZeros.toLowerCase() === 'false') {
|
|
316
|
-
this.config.leadingZeros = false;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
282
|
setWeekStartDay() {
|
|
321
283
|
const weekStartDayParam = this.config.weekStartDay;
|
|
322
284
|
if (weekStartDayParam && weekStartDayParam.toLowerCase() === 'sunday') {
|
|
@@ -329,7 +291,7 @@
|
|
|
329
291
|
}
|
|
330
292
|
|
|
331
293
|
/**
|
|
332
|
-
* Determine if a date is
|
|
294
|
+
* Determine if a date is selectable
|
|
333
295
|
*
|
|
334
296
|
* @param {Date} date - the date to check
|
|
335
297
|
* @returns {boolean}
|
|
@@ -395,24 +357,36 @@
|
|
|
395
357
|
/**
|
|
396
358
|
* Get a human readable date in the format Monday 2 March 2024
|
|
397
359
|
*
|
|
398
|
-
* @param {Date} date -
|
|
360
|
+
* @param {Date} date - Date to format
|
|
399
361
|
* @returns {string}
|
|
400
362
|
*/
|
|
401
363
|
formattedDateHuman(date) {
|
|
402
364
|
return `${this.dayLabels[(date.getDay() + 6) % 7]} ${date.getDate()} ${this.monthLabels[date.getMonth()]} ${date.getFullYear()}`;
|
|
403
365
|
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* @param {MouseEvent} event - Click event
|
|
369
|
+
*/
|
|
404
370
|
backgroundClick(event) {
|
|
405
371
|
if (this.isOpen() && event.target instanceof Node && !this.$dialog.contains(event.target) && !this.$input.contains(event.target) && !this.$calendarButton.contains(event.target)) {
|
|
406
372
|
event.preventDefault();
|
|
407
373
|
this.closeDialog();
|
|
408
374
|
}
|
|
409
375
|
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* @param {KeyboardEvent} event - Keydown event
|
|
379
|
+
*/
|
|
410
380
|
firstButtonKeydown(event) {
|
|
411
381
|
if (event.key === 'Tab' && event.shiftKey) {
|
|
412
382
|
this.$lastButtonInDialog.focus();
|
|
413
383
|
event.preventDefault();
|
|
414
384
|
}
|
|
415
385
|
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* @param {KeyboardEvent} event - Keydown event
|
|
389
|
+
*/
|
|
416
390
|
lastButtonKeydown(event) {
|
|
417
391
|
if (event.key === 'Tab' && !event.shiftKey) {
|
|
418
392
|
this.$firstButtonInDialog.focus();
|
|
@@ -442,49 +416,57 @@
|
|
|
442
416
|
thisDay.setDate(thisDay.getDate() + 1);
|
|
443
417
|
}
|
|
444
418
|
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* @param {boolean} [focus] - Focus the day button
|
|
422
|
+
*/
|
|
445
423
|
setCurrentDate(focus = true) {
|
|
446
424
|
const {
|
|
447
425
|
currentDate
|
|
448
426
|
} = this;
|
|
449
427
|
this.calendarDays.forEach(calendarDay => {
|
|
450
|
-
calendarDay
|
|
451
|
-
calendarDay
|
|
452
|
-
calendarDay
|
|
453
|
-
calendarDay
|
|
428
|
+
calendarDay.$button.classList.add('moj-datepicker__button');
|
|
429
|
+
calendarDay.$button.classList.add('moj-datepicker__calendar-day');
|
|
430
|
+
calendarDay.$button.setAttribute('tabindex', '-1');
|
|
431
|
+
calendarDay.$button.classList.remove(this.selectedDayButtonClass);
|
|
454
432
|
const calendarDayDate = calendarDay.date;
|
|
455
433
|
calendarDayDate.setHours(0, 0, 0, 0);
|
|
456
434
|
const today = new Date();
|
|
457
435
|
today.setHours(0, 0, 0, 0);
|
|
458
436
|
if (calendarDayDate.getTime() === currentDate.getTime() /* && !calendarDay.button.disabled */) {
|
|
459
437
|
if (focus) {
|
|
460
|
-
calendarDay
|
|
461
|
-
calendarDay
|
|
462
|
-
calendarDay
|
|
438
|
+
calendarDay.$button.setAttribute('tabindex', '0');
|
|
439
|
+
calendarDay.$button.focus();
|
|
440
|
+
calendarDay.$button.classList.add(this.selectedDayButtonClass);
|
|
463
441
|
}
|
|
464
442
|
}
|
|
465
443
|
if (this.inputDate && calendarDayDate.getTime() === this.inputDate.getTime()) {
|
|
466
|
-
calendarDay
|
|
467
|
-
calendarDay
|
|
444
|
+
calendarDay.$button.classList.add(this.currentDayButtonClass);
|
|
445
|
+
calendarDay.$button.setAttribute('aria-current', 'date');
|
|
468
446
|
} else {
|
|
469
|
-
calendarDay
|
|
470
|
-
calendarDay
|
|
447
|
+
calendarDay.$button.classList.remove(this.currentDayButtonClass);
|
|
448
|
+
calendarDay.$button.removeAttribute('aria-current');
|
|
471
449
|
}
|
|
472
450
|
if (calendarDayDate.getTime() === today.getTime()) {
|
|
473
|
-
calendarDay
|
|
451
|
+
calendarDay.$button.classList.add(this.todayButtonClass);
|
|
474
452
|
} else {
|
|
475
|
-
calendarDay
|
|
453
|
+
calendarDay.$button.classList.remove(this.todayButtonClass);
|
|
476
454
|
}
|
|
477
455
|
});
|
|
478
456
|
|
|
479
457
|
// if no date is tab-able, make the first non-disabled date tab-able
|
|
480
458
|
if (!focus) {
|
|
481
459
|
const enabledDays = this.calendarDays.filter(calendarDay => {
|
|
482
|
-
return window.getComputedStyle(calendarDay
|
|
460
|
+
return window.getComputedStyle(calendarDay.$button).display === 'block' && !calendarDay.$button.disabled;
|
|
483
461
|
});
|
|
484
|
-
enabledDays[0]
|
|
462
|
+
enabledDays[0].$button.setAttribute('tabindex', '0');
|
|
485
463
|
this.currentDate = enabledDays[0].date;
|
|
486
464
|
}
|
|
487
465
|
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* @param {Date} date - Date to select
|
|
469
|
+
*/
|
|
488
470
|
selectDate(date) {
|
|
489
471
|
if (this.isExcludedDate(date)) {
|
|
490
472
|
return;
|
|
@@ -501,6 +483,10 @@
|
|
|
501
483
|
isOpen() {
|
|
502
484
|
return this.$dialog.classList.contains('moj-datepicker__dialog--open');
|
|
503
485
|
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* @param {MouseEvent} event - Click event
|
|
489
|
+
*/
|
|
504
490
|
toggleDialog(event) {
|
|
505
491
|
event.preventDefault();
|
|
506
492
|
if (this.isOpen()) {
|
|
@@ -535,6 +521,11 @@
|
|
|
535
521
|
this.$calendarButton.setAttribute('aria-expanded', 'false');
|
|
536
522
|
this.$calendarButton.focus();
|
|
537
523
|
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* @param {Date} date - Date to go to
|
|
527
|
+
* @param {boolean} [focus] - Focus the day button
|
|
528
|
+
*/
|
|
538
529
|
goToDate(date, focus) {
|
|
539
530
|
const current = this.currentDate;
|
|
540
531
|
this.currentDate = date;
|
|
@@ -586,13 +577,23 @@
|
|
|
586
577
|
this.goToDate(date);
|
|
587
578
|
}
|
|
588
579
|
|
|
589
|
-
|
|
580
|
+
/**
|
|
581
|
+
* Month navigation
|
|
582
|
+
*
|
|
583
|
+
* @param {KeyboardEvent | MouseEvent} event - Key press or click event
|
|
584
|
+
* @param {boolean} [focus] - Focus the day button
|
|
585
|
+
*/
|
|
590
586
|
focusNextMonth(event, focus = true) {
|
|
591
587
|
event.preventDefault();
|
|
592
588
|
const date = new Date(this.currentDate);
|
|
593
589
|
date.setMonth(date.getMonth() + 1, 1);
|
|
594
590
|
this.goToDate(date, focus);
|
|
595
591
|
}
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* @param {KeyboardEvent | MouseEvent} event - Key press or click event
|
|
595
|
+
* @param {boolean} [focus] - Focus the day button
|
|
596
|
+
*/
|
|
596
597
|
focusPreviousMonth(event, focus = true) {
|
|
597
598
|
event.preventDefault();
|
|
598
599
|
const date = new Date(this.currentDate);
|
|
@@ -600,13 +601,23 @@
|
|
|
600
601
|
this.goToDate(date, focus);
|
|
601
602
|
}
|
|
602
603
|
|
|
603
|
-
|
|
604
|
+
/**
|
|
605
|
+
* Year navigation
|
|
606
|
+
*
|
|
607
|
+
* @param {KeyboardEvent | MouseEvent} event - Key press or click event
|
|
608
|
+
* @param {boolean} [focus] - Focus the day button
|
|
609
|
+
*/
|
|
604
610
|
focusNextYear(event, focus = true) {
|
|
605
611
|
event.preventDefault();
|
|
606
612
|
const date = new Date(this.currentDate);
|
|
607
613
|
date.setFullYear(date.getFullYear() + 1, date.getMonth(), 1);
|
|
608
614
|
this.goToDate(date, focus);
|
|
609
615
|
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* @param {KeyboardEvent | MouseEvent} event - Key press or click event
|
|
619
|
+
* @param {boolean} [focus] - Focus the day button
|
|
620
|
+
*/
|
|
610
621
|
focusPreviousYear(event, focus = true) {
|
|
611
622
|
event.preventDefault();
|
|
612
623
|
const date = new Date(this.currentDate);
|
|
@@ -615,72 +626,70 @@
|
|
|
615
626
|
}
|
|
616
627
|
|
|
617
628
|
/**
|
|
618
|
-
*
|
|
619
|
-
*
|
|
620
|
-
* @param {Schema} schema - Component class
|
|
621
|
-
* @param {DOMStringMap} dataset - HTML element dataset
|
|
622
|
-
* @returns {object} Normalised dataset
|
|
623
|
-
*/
|
|
624
|
-
parseDataset(schema, dataset) {
|
|
625
|
-
const parsed = {};
|
|
626
|
-
for (const [field,,] of Object.entries(schema.properties)) {
|
|
627
|
-
if (field in dataset) {
|
|
628
|
-
parsed[field] = dataset[field];
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
return parsed;
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
/**
|
|
635
|
-
* Config merging function
|
|
636
|
-
*
|
|
637
|
-
* Takes any number of objects and combines them together, with
|
|
638
|
-
* greatest priority on the LAST item passed in.
|
|
639
|
-
*
|
|
640
|
-
* @param {...{ [key: string]: unknown }} configObjects - Config objects to merge
|
|
641
|
-
* @returns {{ [key: string]: unknown }} A merged config object
|
|
629
|
+
* Name for the component used when initialising using data-module attributes.
|
|
642
630
|
*/
|
|
643
|
-
mergeConfigs(...configObjects) {
|
|
644
|
-
const formattedConfigObject = {};
|
|
645
|
-
|
|
646
|
-
// Loop through each of the passed objects
|
|
647
|
-
for (const configObject of configObjects) {
|
|
648
|
-
for (const key of Object.keys(configObject)) {
|
|
649
|
-
const option = formattedConfigObject[key];
|
|
650
|
-
const override = configObject[key];
|
|
651
|
-
|
|
652
|
-
// Push their keys one-by-one into formattedConfigObject. Any duplicate
|
|
653
|
-
// keys with object values will be merged, otherwise the new value will
|
|
654
|
-
// override the existing value.
|
|
655
|
-
if (typeof option === 'object' && typeof override === 'object') {
|
|
656
|
-
// @ts-expect-error Index signature for type 'string' is missing
|
|
657
|
-
formattedConfigObject[key] = this.mergeConfigs(option, override);
|
|
658
|
-
} else {
|
|
659
|
-
formattedConfigObject[key] = override;
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
return formattedConfigObject;
|
|
664
|
-
}
|
|
665
631
|
}
|
|
632
|
+
DatePicker.moduleName = 'moj-date-picker';
|
|
633
|
+
/**
|
|
634
|
+
* Date picker default config
|
|
635
|
+
*
|
|
636
|
+
* @type {DatePickerConfig}
|
|
637
|
+
*/
|
|
638
|
+
DatePicker.defaults = Object.freeze({
|
|
639
|
+
leadingZeros: false,
|
|
640
|
+
weekStartDay: 'monday',
|
|
641
|
+
input: {
|
|
642
|
+
selector: '.moj-js-datepicker-input'
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
/**
|
|
646
|
+
* Date picker config schema
|
|
647
|
+
*
|
|
648
|
+
* @satisfies {Schema<DatePickerConfig>}
|
|
649
|
+
*/
|
|
650
|
+
DatePicker.schema = Object.freeze(/** @type {const} */{
|
|
651
|
+
properties: {
|
|
652
|
+
excludedDates: {
|
|
653
|
+
type: 'string'
|
|
654
|
+
},
|
|
655
|
+
excludedDays: {
|
|
656
|
+
type: 'string'
|
|
657
|
+
},
|
|
658
|
+
leadingZeros: {
|
|
659
|
+
type: 'boolean'
|
|
660
|
+
},
|
|
661
|
+
maxDate: {
|
|
662
|
+
type: 'string'
|
|
663
|
+
},
|
|
664
|
+
minDate: {
|
|
665
|
+
type: 'string'
|
|
666
|
+
},
|
|
667
|
+
weekStartDay: {
|
|
668
|
+
type: 'string'
|
|
669
|
+
},
|
|
670
|
+
input: {
|
|
671
|
+
type: 'object'
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
});
|
|
666
675
|
class DSCalendarDay {
|
|
667
676
|
/**
|
|
668
677
|
*
|
|
669
|
-
* @param {
|
|
678
|
+
* @param {HTMLButtonElement} $button
|
|
670
679
|
* @param {number} index
|
|
671
680
|
* @param {number} row
|
|
672
681
|
* @param {number} column
|
|
673
682
|
* @param {DatePicker} picker
|
|
674
683
|
*/
|
|
675
|
-
constructor(button, index, row, column, picker) {
|
|
684
|
+
constructor($button, index, row, column, picker) {
|
|
676
685
|
this.index = index;
|
|
677
686
|
this.row = row;
|
|
678
687
|
this.column = column;
|
|
679
|
-
this
|
|
688
|
+
this.$button = $button;
|
|
680
689
|
this.picker = picker;
|
|
681
690
|
this.date = new Date();
|
|
682
|
-
this
|
|
683
|
-
this
|
|
691
|
+
this.$button.addEventListener('keydown', this.keyPress.bind(this));
|
|
692
|
+
this.$button.addEventListener('click', this.click.bind(this));
|
|
684
693
|
}
|
|
685
694
|
|
|
686
695
|
/**
|
|
@@ -692,26 +701,34 @@
|
|
|
692
701
|
const label = day.getDate();
|
|
693
702
|
let accessibleLabel = this.picker.formattedDateHuman(day);
|
|
694
703
|
if (disabled) {
|
|
695
|
-
this
|
|
704
|
+
this.$button.setAttribute('aria-disabled', 'true');
|
|
696
705
|
accessibleLabel = `Excluded date, ${accessibleLabel}`;
|
|
697
706
|
} else {
|
|
698
|
-
this
|
|
707
|
+
this.$button.removeAttribute('aria-disabled');
|
|
699
708
|
}
|
|
700
709
|
if (hidden) {
|
|
701
|
-
this
|
|
710
|
+
this.$button.style.display = 'none';
|
|
702
711
|
} else {
|
|
703
|
-
this
|
|
712
|
+
this.$button.style.display = 'block';
|
|
704
713
|
}
|
|
705
|
-
this
|
|
706
|
-
this
|
|
714
|
+
this.$button.setAttribute('data-testid', this.picker.formattedDateFromDate(day));
|
|
715
|
+
this.$button.innerHTML = `<span class="govuk-visually-hidden">${accessibleLabel}</span><span aria-hidden="true">${label}</span>`;
|
|
707
716
|
this.date = new Date(day);
|
|
708
717
|
}
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* @param {MouseEvent} event - Click event
|
|
721
|
+
*/
|
|
709
722
|
click(event) {
|
|
710
723
|
this.picker.goToDate(this.date);
|
|
711
724
|
this.picker.selectDate(this.date);
|
|
712
725
|
event.stopPropagation();
|
|
713
726
|
event.preventDefault();
|
|
714
727
|
}
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* @param {KeyboardEvent} event - Keydown event
|
|
731
|
+
*/
|
|
715
732
|
keyPress(event) {
|
|
716
733
|
let calendarNavKey = true;
|
|
717
734
|
switch (event.key) {
|
|
@@ -768,14 +785,17 @@
|
|
|
768
785
|
* @typedef {object} DatePickerConfig
|
|
769
786
|
* @property {string} [excludedDates] - Dates that cannot be selected
|
|
770
787
|
* @property {string} [excludedDays] - Days that cannot be selected
|
|
771
|
-
* @property {boolean} [
|
|
788
|
+
* @property {boolean} [leadingZeros] - Whether to add leading zeroes when populating the field
|
|
772
789
|
* @property {string} [minDate] - The earliest available date
|
|
773
790
|
* @property {string} [maxDate] - The latest available date
|
|
774
791
|
* @property {string} [weekStartDay] - First day of the week in calendar view
|
|
792
|
+
* @property {object} [input] - Input config
|
|
793
|
+
* @property {string} [input.selector] - Selector for the input element
|
|
794
|
+
* @property {Element | null} [input.element] - HTML element for the input
|
|
775
795
|
*/
|
|
776
796
|
|
|
777
797
|
/**
|
|
778
|
-
* @import { Schema } from '
|
|
798
|
+
* @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'
|
|
779
799
|
*/
|
|
780
800
|
|
|
781
801
|
exports.DatePicker = DatePicker;
|