@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.
Files changed (114) hide show
  1. package/moj/all.bundle.js +1598 -1062
  2. package/moj/all.bundle.js.map +1 -1
  3. package/moj/all.bundle.mjs +1894 -1054
  4. package/moj/all.bundle.mjs.map +1 -1
  5. package/moj/all.mjs +7 -90
  6. package/moj/all.mjs.map +1 -1
  7. package/moj/all.scss +1 -0
  8. package/moj/all.scss.map +1 -1
  9. package/moj/common/index.mjs +57 -0
  10. package/moj/common/index.mjs.map +1 -0
  11. package/moj/common/moj-frontend-version.mjs +14 -0
  12. package/moj/common/moj-frontend-version.mjs.map +1 -0
  13. package/moj/components/add-another/add-another.bundle.js +105 -76
  14. package/moj/components/add-another/add-another.bundle.js.map +1 -1
  15. package/moj/components/add-another/add-another.bundle.mjs +222 -71
  16. package/moj/components/add-another/add-another.bundle.mjs.map +1 -1
  17. package/moj/components/add-another/add-another.mjs +103 -72
  18. package/moj/components/add-another/add-another.mjs.map +1 -1
  19. package/moj/components/alert/alert.bundle.js +115 -191
  20. package/moj/components/alert/alert.bundle.js.map +1 -1
  21. package/moj/components/alert/alert.bundle.mjs +354 -186
  22. package/moj/components/alert/alert.bundle.mjs.map +1 -1
  23. package/moj/components/alert/alert.mjs +55 -140
  24. package/moj/components/alert/alert.mjs.map +1 -1
  25. package/moj/components/button-menu/README.md +3 -1
  26. package/moj/components/button-menu/button-menu.bundle.js +91 -120
  27. package/moj/components/button-menu/button-menu.bundle.js.map +1 -1
  28. package/moj/components/button-menu/button-menu.bundle.mjs +329 -114
  29. package/moj/components/button-menu/button-menu.bundle.mjs.map +1 -1
  30. package/moj/components/button-menu/button-menu.mjs +89 -116
  31. package/moj/components/button-menu/button-menu.mjs.map +1 -1
  32. package/moj/components/date-picker/date-picker.bundle.js +174 -154
  33. package/moj/components/date-picker/date-picker.bundle.js.map +1 -1
  34. package/moj/components/date-picker/date-picker.bundle.mjs +411 -147
  35. package/moj/components/date-picker/date-picker.bundle.mjs.map +1 -1
  36. package/moj/components/date-picker/date-picker.mjs +172 -150
  37. package/moj/components/date-picker/date-picker.mjs.map +1 -1
  38. package/moj/components/filter/template.njk +1 -1
  39. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.js +133 -44
  40. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.js.map +1 -1
  41. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs +374 -41
  42. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs.map +1 -1
  43. package/moj/components/filter-toggle-button/filter-toggle-button.mjs +131 -40
  44. package/moj/components/filter-toggle-button/filter-toggle-button.mjs.map +1 -1
  45. package/moj/components/form-validator/form-validator.bundle.js +159 -69
  46. package/moj/components/form-validator/form-validator.bundle.js.map +1 -1
  47. package/moj/components/form-validator/form-validator.bundle.mjs +399 -65
  48. package/moj/components/form-validator/form-validator.bundle.mjs.map +1 -1
  49. package/moj/components/form-validator/form-validator.mjs +134 -54
  50. package/moj/components/form-validator/form-validator.mjs.map +1 -1
  51. package/moj/components/multi-file-upload/multi-file-upload.bundle.js +291 -117
  52. package/moj/components/multi-file-upload/multi-file-upload.bundle.js.map +1 -1
  53. package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs +527 -109
  54. package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs.map +1 -1
  55. package/moj/components/multi-file-upload/multi-file-upload.mjs +288 -101
  56. package/moj/components/multi-file-upload/multi-file-upload.mjs.map +1 -1
  57. package/moj/components/multi-file-upload/template.njk +1 -1
  58. package/moj/components/multi-select/multi-select.bundle.js +106 -41
  59. package/moj/components/multi-select/multi-select.bundle.js.map +1 -1
  60. package/moj/components/multi-select/multi-select.bundle.mjs +346 -37
  61. package/moj/components/multi-select/multi-select.bundle.mjs.map +1 -1
  62. package/moj/components/multi-select/multi-select.mjs +104 -37
  63. package/moj/components/multi-select/multi-select.mjs.map +1 -1
  64. package/moj/components/password-reveal/_password-reveal.scss +3 -1
  65. package/moj/components/password-reveal/_password-reveal.scss.map +1 -1
  66. package/moj/components/password-reveal/password-reveal.bundle.js +32 -29
  67. package/moj/components/password-reveal/password-reveal.bundle.js.map +1 -1
  68. package/moj/components/password-reveal/password-reveal.bundle.mjs +149 -24
  69. package/moj/components/password-reveal/password-reveal.bundle.mjs.map +1 -1
  70. package/moj/components/password-reveal/password-reveal.mjs +30 -25
  71. package/moj/components/password-reveal/password-reveal.mjs.map +1 -1
  72. package/moj/components/rich-text-editor/README.md +4 -3
  73. package/moj/components/rich-text-editor/rich-text-editor.bundle.js +127 -62
  74. package/moj/components/rich-text-editor/rich-text-editor.bundle.js.map +1 -1
  75. package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs +367 -58
  76. package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs.map +1 -1
  77. package/moj/components/rich-text-editor/rich-text-editor.mjs +125 -58
  78. package/moj/components/rich-text-editor/rich-text-editor.mjs.map +1 -1
  79. package/moj/components/search-toggle/search-toggle.bundle.js +94 -26
  80. package/moj/components/search-toggle/search-toggle.bundle.js.map +1 -1
  81. package/moj/components/search-toggle/search-toggle.bundle.mjs +334 -22
  82. package/moj/components/search-toggle/search-toggle.bundle.mjs.map +1 -1
  83. package/moj/components/search-toggle/search-toggle.mjs +92 -22
  84. package/moj/components/search-toggle/search-toggle.mjs.map +1 -1
  85. package/moj/components/sortable-table/_sortable-table.scss +3 -42
  86. package/moj/components/sortable-table/_sortable-table.scss.map +1 -1
  87. package/moj/components/sortable-table/sortable-table.bundle.js +200 -83
  88. package/moj/components/sortable-table/sortable-table.bundle.js.map +1 -1
  89. package/moj/components/sortable-table/sortable-table.bundle.mjs +439 -78
  90. package/moj/components/sortable-table/sortable-table.bundle.mjs.map +1 -1
  91. package/moj/components/sortable-table/sortable-table.mjs +198 -79
  92. package/moj/components/sortable-table/sortable-table.mjs.map +1 -1
  93. package/moj/core/_all.scss +3 -0
  94. package/moj/core/_all.scss.map +1 -0
  95. package/moj/core/_moj-frontend-properties.scss +7 -0
  96. package/moj/core/_moj-frontend-properties.scss.map +1 -0
  97. package/moj/filters/prototype-kit-13-filters.js +4 -3
  98. package/moj/helpers.bundle.js +22 -77
  99. package/moj/helpers.bundle.js.map +1 -1
  100. package/moj/helpers.bundle.mjs +23 -74
  101. package/moj/helpers.bundle.mjs.map +1 -1
  102. package/moj/helpers.mjs +23 -74
  103. package/moj/helpers.mjs.map +1 -1
  104. package/moj/moj-frontend.min.css +1 -1
  105. package/moj/moj-frontend.min.css.map +1 -1
  106. package/moj/moj-frontend.min.js +1 -1
  107. package/moj/moj-frontend.min.js.map +1 -1
  108. package/package.json +1 -1
  109. package/moj/version.bundle.js +0 -12
  110. package/moj/version.bundle.js.map +0 -1
  111. package/moj/version.bundle.mjs +0 -4
  112. package/moj/version.bundle.mjs.map +0 -1
  113. package/moj/version.mjs +0 -4
  114. 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
- class DatePicker {
7
+ /**
8
+ * @augments {ConfigurableComponent<DatePickerConfig>}
9
+ */
10
+ class DatePicker extends govukFrontend.ConfigurableComponent {
8
11
  /**
9
- * @param {Element | null} $module - HTML element to use for date picker
12
+ * @param {Element | null} $root - HTML element to use for date picker
10
13
  * @param {DatePickerConfig} [config] - Date picker config
11
14
  */
12
- constructor($module, config = {}) {
13
- if (!$module || !($module instanceof HTMLElement)) {
14
- return this;
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 = this.$module.querySelector('.moj-js-datepicker-toggle');
85
- this.$dialogTitle = this.$dialog.querySelector('.moj-js-datepicker-month-year');
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 = this.$dialog.querySelector('.moj-js-datepicker-prev-month');
88
- this.$prevYearButton = this.$dialog.querySelector('.moj-js-datepicker-prev-year');
89
- this.$nextMonthButton = this.$dialog.querySelector('.moj-js-datepicker-next-month');
90
- this.$nextYearButton = this.$dialog.querySelector('.moj-js-datepicker-next-year');
91
- this.$cancelButton = this.$dialog.querySelector('.moj-js-datepicker-cancel');
92
- this.$okButton = this.$dialog.querySelector('.moj-js-datepicker-ok');
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
- * @param {String} datestring - A daterange string in the format "dd/mm/yyyy-dd/mm/yyyy"
282
- * @returns {Date[]}
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 selecteable
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 - date to format
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.button.classList.add('moj-datepicker__button');
451
- calendarDay.button.classList.add('moj-datepicker__calendar-day');
452
- calendarDay.button.setAttribute('tabindex', '-1');
453
- calendarDay.button.classList.remove(this.selectedDayButtonClass);
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.button.setAttribute('tabindex', '0');
461
- calendarDay.button.focus();
462
- calendarDay.button.classList.add(this.selectedDayButtonClass);
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.button.classList.add(this.currentDayButtonClass);
467
- calendarDay.button.setAttribute('aria-current', 'date');
444
+ calendarDay.$button.classList.add(this.currentDayButtonClass);
445
+ calendarDay.$button.setAttribute('aria-current', 'date');
468
446
  } else {
469
- calendarDay.button.classList.remove(this.currentDayButtonClass);
470
- calendarDay.button.removeAttribute('aria-current');
447
+ calendarDay.$button.classList.remove(this.currentDayButtonClass);
448
+ calendarDay.$button.removeAttribute('aria-current');
471
449
  }
472
450
  if (calendarDayDate.getTime() === today.getTime()) {
473
- calendarDay.button.classList.add(this.todayButtonClass);
451
+ calendarDay.$button.classList.add(this.todayButtonClass);
474
452
  } else {
475
- calendarDay.button.classList.remove(this.todayButtonClass);
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.button).display === 'block' && !calendarDay.button.disabled;
460
+ return window.getComputedStyle(calendarDay.$button).display === 'block' && !calendarDay.$button.disabled;
483
461
  });
484
- enabledDays[0].button.setAttribute('tabindex', '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
- // month navigation
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
- // year navigation
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
- * Parse dataset
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 {HTMLElement} button
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.button = button;
688
+ this.$button = $button;
680
689
  this.picker = picker;
681
690
  this.date = new Date();
682
- this.button.addEventListener('keydown', this.keyPress.bind(this));
683
- this.button.addEventListener('click', this.click.bind(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.button.setAttribute('aria-disabled', 'true');
704
+ this.$button.setAttribute('aria-disabled', 'true');
696
705
  accessibleLabel = `Excluded date, ${accessibleLabel}`;
697
706
  } else {
698
- this.button.removeAttribute('aria-disabled');
707
+ this.$button.removeAttribute('aria-disabled');
699
708
  }
700
709
  if (hidden) {
701
- this.button.style.display = 'none';
710
+ this.$button.style.display = 'none';
702
711
  } else {
703
- this.button.style.display = 'block';
712
+ this.$button.style.display = 'block';
704
713
  }
705
- this.button.setAttribute('data-testid', this.picker.formattedDateFromDate(day));
706
- this.button.innerHTML = `<span class="govuk-visually-hidden">${accessibleLabel}</span><span aria-hidden="true">${label}</span>`;
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} [leadingZeroes] - Whether to add leading zeroes when populating the field
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 '../../all.mjs'
798
+ * @import { Schema } from 'govuk-frontend/dist/govuk/common/configuration.mjs'
779
799
  */
780
800
 
781
801
  exports.DatePicker = DatePicker;