@ministryofjustice/frontend 5.2.1 → 7.0.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.
Files changed (84) hide show
  1. package/moj/all.bundle.js +30 -12
  2. package/moj/all.bundle.js.map +1 -1
  3. package/moj/all.bundle.mjs +85 -38
  4. package/moj/all.bundle.mjs.map +1 -1
  5. package/moj/all.mjs +13 -5
  6. package/moj/all.mjs.map +1 -1
  7. package/moj/common/index.mjs.map +1 -1
  8. package/moj/common/moj-frontend-version.mjs +2 -2
  9. package/moj/common/moj-frontend-version.mjs.map +1 -1
  10. package/moj/components/add-another/add-another.bundle.js.map +1 -1
  11. package/moj/components/add-another/add-another.bundle.mjs +10 -2
  12. package/moj/components/add-another/add-another.bundle.mjs.map +1 -1
  13. package/moj/components/add-another/add-another.mjs.map +1 -1
  14. package/moj/components/alert/alert.bundle.js +1 -1
  15. package/moj/components/alert/alert.bundle.js.map +1 -1
  16. package/moj/components/alert/alert.bundle.mjs +5 -3
  17. package/moj/components/alert/alert.bundle.mjs.map +1 -1
  18. package/moj/components/alert/alert.mjs.map +1 -1
  19. package/moj/components/button-menu/button-menu.bundle.js.map +1 -1
  20. package/moj/components/button-menu/button-menu.bundle.mjs +4 -2
  21. package/moj/components/button-menu/button-menu.bundle.mjs.map +1 -1
  22. package/moj/components/button-menu/button-menu.mjs.map +1 -1
  23. package/moj/components/date-picker/date-picker.bundle.js +11 -1
  24. package/moj/components/date-picker/date-picker.bundle.js.map +1 -1
  25. package/moj/components/date-picker/date-picker.bundle.mjs +15 -3
  26. package/moj/components/date-picker/date-picker.bundle.mjs.map +1 -1
  27. package/moj/components/date-picker/date-picker.mjs +11 -1
  28. package/moj/components/date-picker/date-picker.mjs.map +1 -1
  29. package/moj/components/domain-specific/probation/header/header.bundle.js.map +1 -1
  30. package/moj/components/domain-specific/probation/header/header.bundle.mjs +10 -2
  31. package/moj/components/domain-specific/probation/header/header.bundle.mjs.map +1 -1
  32. package/moj/components/domain-specific/probation/header/header.mjs.map +1 -1
  33. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.js.map +1 -1
  34. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs +4 -2
  35. package/moj/components/filter-toggle-button/filter-toggle-button.bundle.mjs.map +1 -1
  36. package/moj/components/filter-toggle-button/filter-toggle-button.mjs.map +1 -1
  37. package/moj/components/form-validator/form-validator.bundle.js.map +1 -1
  38. package/moj/components/form-validator/form-validator.bundle.mjs +4 -2
  39. package/moj/components/form-validator/form-validator.bundle.mjs.map +1 -1
  40. package/moj/components/form-validator/form-validator.mjs.map +1 -1
  41. package/moj/components/messages/README.md +1 -1
  42. package/moj/components/multi-file-upload/multi-file-upload.bundle.js +3 -3
  43. package/moj/components/multi-file-upload/multi-file-upload.bundle.js.map +1 -1
  44. package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs +7 -5
  45. package/moj/components/multi-file-upload/multi-file-upload.bundle.mjs.map +1 -1
  46. package/moj/components/multi-file-upload/multi-file-upload.mjs +3 -3
  47. package/moj/components/multi-file-upload/multi-file-upload.mjs.map +1 -1
  48. package/moj/components/multi-select/multi-select.bundle.js.map +1 -1
  49. package/moj/components/multi-select/multi-select.bundle.mjs +4 -2
  50. package/moj/components/multi-select/multi-select.bundle.mjs.map +1 -1
  51. package/moj/components/multi-select/multi-select.mjs.map +1 -1
  52. package/moj/components/notification-badge/_notification-badge.scss +10 -6
  53. package/moj/components/notification-badge/_notification-badge.scss.map +1 -1
  54. package/moj/components/notification-badge/template.njk +11 -5
  55. package/moj/components/pagination/template.njk +2 -2
  56. package/moj/components/password-reveal/password-reveal.bundle.js.map +1 -1
  57. package/moj/components/password-reveal/password-reveal.bundle.mjs +10 -2
  58. package/moj/components/password-reveal/password-reveal.bundle.mjs.map +1 -1
  59. package/moj/components/password-reveal/password-reveal.mjs.map +1 -1
  60. package/moj/components/rich-text-editor/rich-text-editor.bundle.js.map +1 -1
  61. package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs +4 -2
  62. package/moj/components/rich-text-editor/rich-text-editor.bundle.mjs.map +1 -1
  63. package/moj/components/rich-text-editor/rich-text-editor.mjs.map +1 -1
  64. package/moj/components/search-toggle/search-toggle.bundle.js.map +1 -1
  65. package/moj/components/search-toggle/search-toggle.bundle.mjs +4 -2
  66. package/moj/components/search-toggle/search-toggle.bundle.mjs.map +1 -1
  67. package/moj/components/search-toggle/search-toggle.mjs.map +1 -1
  68. package/moj/components/sortable-table/sortable-table.bundle.js.map +1 -1
  69. package/moj/components/sortable-table/sortable-table.bundle.mjs +4 -2
  70. package/moj/components/sortable-table/sortable-table.bundle.mjs.map +1 -1
  71. package/moj/components/sortable-table/sortable-table.mjs.map +1 -1
  72. package/moj/components/timeline/README.md +1 -1
  73. package/moj/core/_moj-frontend-properties.scss +1 -1
  74. package/moj/helpers.bundle.js.map +1 -1
  75. package/moj/helpers.bundle.mjs.map +1 -1
  76. package/moj/helpers.mjs +1 -1
  77. package/moj/helpers.mjs.map +1 -1
  78. package/moj/moj-frontend.min.css +1 -1
  79. package/moj/moj-frontend.min.css.map +1 -1
  80. package/moj/moj-frontend.min.js +1 -1
  81. package/moj/moj-frontend.min.js.map +1 -1
  82. package/moj/objects/_scrollable-pane.scss +2 -2
  83. package/moj/objects/_scrollable-pane.scss.map +1 -1
  84. package/package.json +2 -2
@@ -23,6 +23,9 @@ function isArray(option) {
23
23
  function isObject(option) {
24
24
  return !!option && typeof option === 'object' && !isArray(option);
25
25
  }
26
+ function isScope($scope) {
27
+ return !!$scope && ($scope instanceof Element || $scope instanceof Document);
28
+ }
26
29
  function formatErrorMessage(Component, message) {
27
30
  return `${Component.moduleName}: ${message}`;
28
31
  }
@@ -54,7 +57,7 @@ class ConfigError extends GOVUKFrontendError {
54
57
  class ElementError extends GOVUKFrontendError {
55
58
  constructor(messageOrOptions) {
56
59
  let message = typeof messageOrOptions === 'string' ? messageOrOptions : '';
57
- if (typeof messageOrOptions === 'object') {
60
+ if (isObject(messageOrOptions)) {
58
61
  const {
59
62
  component,
60
63
  identifier,
@@ -63,7 +66,9 @@ class ElementError extends GOVUKFrontendError {
63
66
  } = messageOrOptions;
64
67
  message = identifier;
65
68
  message += element ? ` is not of type ${expectedType != null ? expectedType : 'HTMLElement'}` : ' not found';
66
- message = formatErrorMessage(component, message);
69
+ if (component) {
70
+ message = formatErrorMessage(component, message);
71
+ }
67
72
  }
68
73
  super(message);
69
74
  this.name = 'ElementError';
@@ -200,6 +205,30 @@ function normaliseDataset(Component, dataset) {
200
205
  }
201
206
  return out;
202
207
  }
208
+ function normaliseOptions(scopeOrOptions) {
209
+ let $scope = document;
210
+ let onError;
211
+ if (isObject(scopeOrOptions)) {
212
+ const options = scopeOrOptions;
213
+ if (isScope(options.scope) || options.scope === null) {
214
+ $scope = options.scope;
215
+ }
216
+ if (typeof options.onError === 'function') {
217
+ onError = options.onError;
218
+ }
219
+ }
220
+ if (isScope(scopeOrOptions)) {
221
+ $scope = scopeOrOptions;
222
+ } else if (scopeOrOptions === null) {
223
+ $scope = null;
224
+ } else if (typeof scopeOrOptions === 'function') {
225
+ onError = scopeOrOptions;
226
+ }
227
+ return {
228
+ scope: $scope,
229
+ onError
230
+ };
231
+ }
203
232
  function mergeConfigs(...configObjects) {
204
233
  const formattedConfigObject = {};
205
234
  for (const configObject of configObjects) {
@@ -254,42 +283,42 @@ function extractConfigByNamespace(schema, dataset, namespace) {
254
283
  * @template {CompatibleClass} ComponentClass
255
284
  * @param {ComponentClass} Component - class of the component to create
256
285
  * @param {ComponentConfig<ComponentClass>} [config] - Config supplied to component
257
- * @param {OnErrorCallback<ComponentClass> | Element | Document | CreateAllOptions<ComponentClass> } [createAllOptions] - options for createAll including scope of the document to search within and callback function if error throw by component on init
286
+ * @param {OnErrorCallback<ComponentClass> | Element | Document | null | CreateAllOptions<ComponentClass>} [scopeOrOptions] - options for createAll including scope of the document to search within and callback function if error throw by component on init
258
287
  * @returns {Array<InstanceType<ComponentClass>>} - array of instantiated components
259
288
  */
260
- function createAll(Component, config, createAllOptions) {
261
- let $scope = document;
262
- let onError;
263
- if (typeof createAllOptions === 'object') {
264
- var _createAllOptions$sco;
265
- createAllOptions = createAllOptions;
266
- $scope = (_createAllOptions$sco = createAllOptions.scope) != null ? _createAllOptions$sco : $scope;
267
- onError = createAllOptions.onError;
268
- }
269
- if (typeof createAllOptions === 'function') {
270
- onError = createAllOptions;
271
- }
272
- if (createAllOptions instanceof HTMLElement) {
273
- $scope = createAllOptions;
274
- }
275
- const $elements = $scope.querySelectorAll(`[data-module="${Component.moduleName}"]`);
276
- if (!isSupported()) {
277
- if (onError) {
278
- onError(new SupportError(), {
289
+ function createAll(Component, config, scopeOrOptions) {
290
+ let $elements;
291
+ const options = normaliseOptions(scopeOrOptions);
292
+ try {
293
+ var _options$scope;
294
+ if (!isSupported()) {
295
+ throw new SupportError();
296
+ }
297
+ if (options.scope === null) {
298
+ throw new ElementError({
299
+ element: options.scope,
300
+ component: Component,
301
+ identifier: 'Scope element (`$scope`)'
302
+ });
303
+ }
304
+ $elements = (_options$scope = options.scope) == null ? void 0 : _options$scope.querySelectorAll(`[data-module="${Component.moduleName}"]`);
305
+ } catch (error) {
306
+ if (options.onError) {
307
+ options.onError(error, {
279
308
  component: Component,
280
309
  config
281
310
  });
282
311
  } else {
283
- console.log(new SupportError());
312
+ console.log(error);
284
313
  }
285
314
  return [];
286
315
  }
287
- return Array.from($elements).map($element => {
316
+ return Array.from($elements != null ? $elements : []).map($element => {
288
317
  try {
289
318
  return typeof config !== 'undefined' ? new Component($element, config) : new Component($element);
290
319
  } catch (error) {
291
- if (onError) {
292
- onError(error, {
320
+ if (options.onError) {
321
+ options.onError(error, {
293
322
  element: $element,
294
323
  component: Component,
295
324
  config
@@ -308,11 +337,11 @@ function createAll(Component, config, createAllOptions) {
308
337
  */
309
338
 
310
339
  /**
311
- * MoJ Frontend release version
340
+ * MOJ Frontend release version
312
341
  *
313
342
  * {@link https://github.com/ministryofjustice/moj-frontend/releases}
314
343
  */
315
- const version = '5.2.1';
344
+ const version = '7.0.0';
316
345
 
317
346
  class AddAnother extends Component {
318
347
  /**
@@ -601,7 +630,7 @@ function getPreviousSibling($element, selector) {
601
630
  */
602
631
  function findNearestMatchingElement($element, selector) {
603
632
  // If no element or selector is provided, return
604
- if (!$element || !($element instanceof HTMLElement) || false) {
633
+ if (!$element || !($element instanceof HTMLElement) || !selector) {
605
634
  return;
606
635
  }
607
636
 
@@ -1346,7 +1375,7 @@ class DatePicker extends ConfigurableComponent {
1346
1375
  const day = match[1];
1347
1376
  const month = match[3];
1348
1377
  const year = match[4];
1349
- formattedDate = new Date(`${year}-${month}-${day}`);
1378
+ formattedDate = new Date(Number(year), Number(month) - 1, Number(day));
1350
1379
  if (formattedDate instanceof Date && Number.isFinite(formattedDate.getTime())) {
1351
1380
  return formattedDate;
1352
1381
  }
@@ -1522,6 +1551,16 @@ class DatePicker extends ConfigurableComponent {
1522
1551
 
1523
1552
  // get the date from the input element
1524
1553
  this.inputDate = this.formattedDateFromString(this.$input.value);
1554
+ // move current date to the closest selectable date if it is out of range
1555
+ if (this.minDate && this.minDate > this.inputDate) {
1556
+ this.inputDate = new Date(this.minDate.getTime());
1557
+ }
1558
+ if (this.maxDate && this.maxDate < this.inputDate) {
1559
+ this.inputDate = new Date(this.maxDate.getTime());
1560
+ }
1561
+ if (this.minDate && this.maxDate && this.minDate > this.maxDate) {
1562
+ console.error('min date is after max date. No dates will be selectable');
1563
+ }
1525
1564
  this.currentDate = this.inputDate;
1526
1565
  this.currentDate.setHours(0, 0, 0, 0);
1527
1566
  this.updateCalendar();
@@ -2469,13 +2508,13 @@ class MultiFileUpload extends ConfigurableComponent {
2469
2508
  $message.innerHTML = this.getSuccessHtml(xhr.response.success);
2470
2509
  this.$status.textContent = xhr.response.success.messageText;
2471
2510
  $actions.append(this.getDeleteButton(xhr.response.file));
2472
- this.config.hooks.exitHook(this, file, xhr, xhr.responseText);
2511
+ this.config.hooks.exitHook(this, file, xhr, xhr.statusText);
2473
2512
  };
2474
2513
  const onError = () => {
2475
2514
  const error = new Error(xhr.response && 'error' in xhr.response ? xhr.response.error.message : xhr.statusText || 'Upload failed');
2476
2515
  $message.innerHTML = this.getErrorHtml(error);
2477
2516
  this.$status.textContent = error.message;
2478
- this.config.hooks.errorHook(this, file, xhr, xhr.responseText, error);
2517
+ this.config.hooks.errorHook(this, file, xhr, xhr.statusText, error);
2479
2518
  };
2480
2519
  xhr.addEventListener('load', onLoad);
2481
2520
  xhr.addEventListener('error', onError);
@@ -2512,7 +2551,7 @@ class MultiFileUpload extends ConfigurableComponent {
2512
2551
  }
2513
2552
  const $rowDelete = $rows.find($row => $row.contains($button));
2514
2553
  if ($rowDelete) $rowDelete.remove();
2515
- this.config.hooks.deleteHook(this, undefined, xhr, xhr.responseText);
2554
+ this.config.hooks.deleteHook(this, undefined, xhr, xhr.statusText);
2516
2555
  });
2517
2556
  xhr.open('POST', this.config.deleteUrl);
2518
2557
  xhr.setRequestHeader('Content-Type', 'application/json');
@@ -3407,16 +3446,24 @@ SortableTable.schema = Object.freeze(/** @type {const} */{
3407
3446
  });
3408
3447
 
3409
3448
  /**
3410
- * @param {Config} [config]
3449
+ * Initialise all components
3450
+ *
3451
+ * Use the `data-module` attributes to find, instantiate and init all of the
3452
+ * components provided as part of MOJ Frontend.
3453
+ *
3454
+ * @param {Config | Element | Document | null} [scopeOrConfig]
3411
3455
  */
3412
- function initAll(config) {
3413
- for (const Component of [AddAnother, Alert, ButtonMenu, DatePicker, MultiSelect, PasswordReveal, RichTextEditor, SearchToggle, SortableTable, PdsHeader]) {
3414
- createAll(Component, undefined, config);
3456
+ function initAll(scopeOrConfig) {
3457
+ for (const Component of [AddAnother, Alert, ButtonMenu, DatePicker, MultiSelect, PasswordReveal, PdsHeader, RichTextEditor, SearchToggle, SortableTable]) {
3458
+ createAll(Component, undefined, scopeOrConfig);
3415
3459
  }
3416
3460
  }
3417
3461
 
3418
3462
  /**
3419
- * @typedef {Parameters<typeof GOVUKFrontend.initAll>[0]} Config
3463
+ * Config for all components via `initAll()`
3464
+ *
3465
+ * @typedef {object} Config
3466
+ * @property {Element | Document | null } scope - the scope to search for components in
3420
3467
  */
3421
3468
 
3422
3469
  /**