govuk_publishing_components 51.1.1 → 51.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/component_guide/application.scss +1 -1
  3. data/app/assets/stylesheets/govuk_publishing_components/_all_components.scss +1 -0
  4. data/app/assets/stylesheets/govuk_publishing_components/components/helpers/_markdown-typography.scss +1 -0
  5. data/app/models/govuk_publishing_components/audit_comparer.rb +3 -3
  6. data/app/views/govuk_publishing_components/components/_title.html.erb +2 -3
  7. data/app/views/govuk_publishing_components/components/docs/add_another.yml +1 -1
  8. data/lib/govuk_publishing_components/presenters/checkboxes_helper.rb +1 -1
  9. data/lib/govuk_publishing_components/presenters/shared_helper.rb +0 -11
  10. data/lib/govuk_publishing_components/version.rb +1 -1
  11. data/node_modules/govuk-frontend/dist/govuk/all.bundle.js +217 -184
  12. data/node_modules/govuk-frontend/dist/govuk/all.bundle.js.map +1 -1
  13. data/node_modules/govuk-frontend/dist/govuk/all.bundle.mjs +216 -184
  14. data/node_modules/govuk-frontend/dist/govuk/all.bundle.mjs.map +1 -1
  15. data/node_modules/govuk-frontend/dist/govuk/all.mjs +1 -0
  16. data/node_modules/govuk-frontend/dist/govuk/all.mjs.map +1 -1
  17. data/node_modules/govuk-frontend/dist/govuk/all.scss +6 -0
  18. data/node_modules/govuk-frontend/dist/govuk/all.scss.map +1 -1
  19. data/node_modules/govuk-frontend/dist/govuk/common/configuration.mjs +164 -0
  20. data/node_modules/govuk-frontend/dist/govuk/common/configuration.mjs.map +1 -0
  21. data/node_modules/govuk-frontend/dist/govuk/common/govuk-frontend-version.mjs +1 -1
  22. data/node_modules/govuk-frontend/dist/govuk/common/index.mjs +1 -87
  23. data/node_modules/govuk-frontend/dist/govuk/common/index.mjs.map +1 -1
  24. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js +149 -112
  25. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js.map +1 -1
  26. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs +148 -111
  27. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs.map +1 -1
  28. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.mjs +5 -8
  29. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.mjs.map +1 -1
  30. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.js +149 -112
  31. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.js.map +1 -1
  32. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.mjs +148 -111
  33. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.mjs.map +1 -1
  34. data/node_modules/govuk-frontend/dist/govuk/components/button/button.mjs +5 -8
  35. data/node_modules/govuk-frontend/dist/govuk/components/button/button.mjs.map +1 -1
  36. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js +174 -140
  37. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js.map +1 -1
  38. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs +173 -139
  39. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs.map +1 -1
  40. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.mjs +17 -16
  41. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.mjs.map +1 -1
  42. data/node_modules/govuk-frontend/dist/govuk/components/character-count/macro-options.json +4 -4
  43. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js +1 -24
  44. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js.map +1 -1
  45. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs +0 -23
  46. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs.map +1 -1
  47. data/node_modules/govuk-frontend/dist/govuk/components/date-input/macro-options.json +2 -2
  48. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js +149 -112
  49. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js.map +1 -1
  50. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs +148 -111
  51. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs.map +1 -1
  52. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs +6 -8
  53. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs.map +1 -1
  54. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js +149 -112
  55. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js.map +1 -1
  56. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs +148 -111
  57. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs.map +1 -1
  58. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs +5 -8
  59. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs.map +1 -1
  60. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.js +1 -24
  61. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.js.map +1 -1
  62. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.mjs +0 -23
  63. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.mjs.map +1 -1
  64. data/node_modules/govuk-frontend/dist/govuk/components/input/macro-options.json +4 -4
  65. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js +149 -112
  66. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js.map +1 -1
  67. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs +148 -111
  68. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs.map +1 -1
  69. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs +6 -8
  70. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs.map +1 -1
  71. data/node_modules/govuk-frontend/dist/govuk/components/password-input/macro-options.json +1 -1
  72. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js +149 -112
  73. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js.map +1 -1
  74. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs +148 -111
  75. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs.map +1 -1
  76. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.mjs +5 -8
  77. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.mjs.map +1 -1
  78. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.js +1 -24
  79. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.js.map +1 -1
  80. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs +0 -23
  81. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs.map +1 -1
  82. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js +1 -24
  83. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js.map +1 -1
  84. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs +0 -23
  85. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs.map +1 -1
  86. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js +1 -24
  87. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js.map +1 -1
  88. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs +0 -23
  89. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs.map +1 -1
  90. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js +1 -24
  91. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js.map +1 -1
  92. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs +0 -23
  93. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs.map +1 -1
  94. data/node_modules/govuk-frontend/dist/govuk/components/textarea/macro-options.json +1 -1
  95. data/node_modules/govuk-frontend/dist/govuk/core/_govuk-frontend-properties.scss +1 -1
  96. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.css +1 -1
  97. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.css.map +1 -1
  98. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.js +1 -1
  99. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.js.map +1 -1
  100. data/node_modules/govuk-frontend/dist/govuk/init.mjs +17 -13
  101. data/node_modules/govuk-frontend/dist/govuk/init.mjs.map +1 -1
  102. data/node_modules/govuk-frontend/dist/govuk/settings/_typography-responsive.scss +5 -10
  103. data/node_modules/govuk-frontend/dist/govuk/settings/_typography-responsive.scss.map +1 -1
  104. data/node_modules/govuk-frontend/govuk-prototype-kit.config.json +1 -1
  105. data/node_modules/govuk-frontend/package.json +9 -9
  106. metadata +4 -6
  107. data/node_modules/govuk-frontend/dist/govuk/common/normalise-dataset.mjs +0 -18
  108. data/node_modules/govuk-frontend/dist/govuk/common/normalise-dataset.mjs.map +0 -1
  109. data/node_modules/govuk-frontend/dist/govuk/common/normalise-string.mjs +0 -31
  110. data/node_modules/govuk-frontend/dist/govuk/common/normalise-string.mjs.map +0 -1
@@ -1,81 +1,11 @@
1
1
  (function (global, factory) {
2
2
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
3
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.GOVUKFrontend = {}));
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.GOVUKFrontend = global.GOVUKFrontend || {}));
5
5
  })(this, (function (exports) { 'use strict';
6
6
 
7
- const version = '5.7.1';
7
+ const version = '5.8.0';
8
8
 
9
- function normaliseString(value, property) {
10
- const trimmedValue = value ? value.trim() : '';
11
- let output;
12
- let outputType = property == null ? void 0 : property.type;
13
- if (!outputType) {
14
- if (['true', 'false'].includes(trimmedValue)) {
15
- outputType = 'boolean';
16
- }
17
- if (trimmedValue.length > 0 && isFinite(Number(trimmedValue))) {
18
- outputType = 'number';
19
- }
20
- }
21
- switch (outputType) {
22
- case 'boolean':
23
- output = trimmedValue === 'true';
24
- break;
25
- case 'number':
26
- output = Number(trimmedValue);
27
- break;
28
- default:
29
- output = value;
30
- }
31
- return output;
32
- }
33
-
34
- /**
35
- * @typedef {import('./index.mjs').SchemaProperty} SchemaProperty
36
- */
37
-
38
- function mergeConfigs(...configObjects) {
39
- const formattedConfigObject = {};
40
- for (const configObject of configObjects) {
41
- for (const key of Object.keys(configObject)) {
42
- const option = formattedConfigObject[key];
43
- const override = configObject[key];
44
- if (isObject(option) && isObject(override)) {
45
- formattedConfigObject[key] = mergeConfigs(option, override);
46
- } else {
47
- formattedConfigObject[key] = override;
48
- }
49
- }
50
- }
51
- return formattedConfigObject;
52
- }
53
- function extractConfigByNamespace(Component, dataset, namespace) {
54
- const property = Component.schema.properties[namespace];
55
- if ((property == null ? void 0 : property.type) !== 'object') {
56
- return;
57
- }
58
- const newObject = {
59
- [namespace]: ({})
60
- };
61
- for (const [key, value] of Object.entries(dataset)) {
62
- let current = newObject;
63
- const keyParts = key.split('.');
64
- for (const [index, name] of keyParts.entries()) {
65
- if (typeof current === 'object') {
66
- if (index < keyParts.length - 1) {
67
- if (!isObject(current[name])) {
68
- current[name] = {};
69
- }
70
- current = current[name];
71
- } else if (key !== namespace) {
72
- current[name] = normaliseString(value);
73
- }
74
- }
75
- }
76
- }
77
- return newObject[namespace];
78
- }
79
9
  function getFragmentFromUrl(url) {
80
10
  if (!url.includes('#')) {
81
11
  return undefined;
@@ -133,26 +63,6 @@
133
63
  }
134
64
  return $scope.classList.contains('govuk-frontend-supported');
135
65
  }
136
- function validateConfig(schema, config) {
137
- const validationErrors = [];
138
- for (const [name, conditions] of Object.entries(schema)) {
139
- const errors = [];
140
- if (Array.isArray(conditions)) {
141
- for (const {
142
- required,
143
- errorMessage
144
- } of conditions) {
145
- if (!required.every(key => !!config[key])) {
146
- errors.push(errorMessage);
147
- }
148
- }
149
- if (name === 'anyOf' && !(conditions.length - errors.length >= 1)) {
150
- validationErrors.push(...errors);
151
- }
152
- }
153
- }
154
- return validationErrors;
155
- }
156
66
  function isArray(option) {
157
67
  return Array.isArray(option);
158
68
  }
@@ -162,47 +72,11 @@
162
72
  function formatErrorMessage(Component, message) {
163
73
  return `${Component.moduleName}: ${message}`;
164
74
  }
165
-
166
- /**
167
- * Schema for component config
168
- *
169
- * @typedef {object} Schema
170
- * @property {{ [field: string]: SchemaProperty | undefined }} properties - Schema properties
171
- * @property {SchemaCondition[]} [anyOf] - List of schema conditions
172
- */
173
-
174
- /**
175
- * Schema property for component config
176
- *
177
- * @typedef {object} SchemaProperty
178
- * @property {'string' | 'boolean' | 'number' | 'object'} type - Property type
179
- */
180
-
181
- /**
182
- * Schema condition for component config
183
- *
184
- * @typedef {object} SchemaCondition
185
- * @property {string[]} required - List of required config fields
186
- * @property {string} errorMessage - Error message when required config fields not provided
187
- */
188
75
  /**
189
76
  * @typedef ComponentWithModuleName
190
77
  * @property {string} moduleName - Name of the component
191
78
  */
192
79
 
193
- function normaliseDataset(Component, dataset) {
194
- const out = {};
195
- for (const [field, property] of Object.entries(Component.schema.properties)) {
196
- if (field in dataset) {
197
- out[field] = normaliseString(dataset[field], property);
198
- }
199
- if ((property == null ? void 0 : property.type) === 'object') {
200
- out[field] = extractConfigByNamespace(Component, dataset, field);
201
- }
202
- }
203
- return out;
204
- }
205
-
206
80
  class GOVUKFrontendError extends Error {
207
81
  constructor(...args) {
208
82
  super(...args);
@@ -311,6 +185,164 @@
311
185
  */
312
186
  GOVUKFrontendComponent.elementType = HTMLElement;
313
187
 
188
+ const configOverride = Symbol.for('configOverride');
189
+ class ConfigurableComponent extends GOVUKFrontendComponent {
190
+ [configOverride](param) {
191
+ return {};
192
+ }
193
+
194
+ /**
195
+ * Returns the root element of the component
196
+ *
197
+ * @protected
198
+ * @returns {ConfigurationType} - the root element of component
199
+ */
200
+ get config() {
201
+ return this._config;
202
+ }
203
+ constructor($root, config) {
204
+ super($root);
205
+ this._config = void 0;
206
+ const childConstructor = this.constructor;
207
+ if (typeof childConstructor.defaults === 'undefined') {
208
+ throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));
209
+ }
210
+ const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);
211
+ this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}, this[configOverride](datasetConfig), datasetConfig);
212
+ }
213
+ }
214
+ function normaliseString(value, property) {
215
+ const trimmedValue = value ? value.trim() : '';
216
+ let output;
217
+ let outputType = property == null ? void 0 : property.type;
218
+ if (!outputType) {
219
+ if (['true', 'false'].includes(trimmedValue)) {
220
+ outputType = 'boolean';
221
+ }
222
+ if (trimmedValue.length > 0 && isFinite(Number(trimmedValue))) {
223
+ outputType = 'number';
224
+ }
225
+ }
226
+ switch (outputType) {
227
+ case 'boolean':
228
+ output = trimmedValue === 'true';
229
+ break;
230
+ case 'number':
231
+ output = Number(trimmedValue);
232
+ break;
233
+ default:
234
+ output = value;
235
+ }
236
+ return output;
237
+ }
238
+ function normaliseDataset(Component, dataset) {
239
+ if (typeof Component.schema === 'undefined') {
240
+ throw new ConfigError(formatErrorMessage(Component, 'Config passed as parameter into constructor but no schema defined'));
241
+ }
242
+ const out = {};
243
+ for (const [field, property] of Object.entries(Component.schema.properties)) {
244
+ if (field in dataset) {
245
+ out[field] = normaliseString(dataset[field], property);
246
+ }
247
+ if ((property == null ? void 0 : property.type) === 'object') {
248
+ out[field] = extractConfigByNamespace(Component.schema, dataset, field);
249
+ }
250
+ }
251
+ return out;
252
+ }
253
+ function mergeConfigs(...configObjects) {
254
+ const formattedConfigObject = {};
255
+ for (const configObject of configObjects) {
256
+ for (const key of Object.keys(configObject)) {
257
+ const option = formattedConfigObject[key];
258
+ const override = configObject[key];
259
+ if (isObject(option) && isObject(override)) {
260
+ formattedConfigObject[key] = mergeConfigs(option, override);
261
+ } else {
262
+ formattedConfigObject[key] = override;
263
+ }
264
+ }
265
+ }
266
+ return formattedConfigObject;
267
+ }
268
+ function validateConfig(schema, config) {
269
+ const validationErrors = [];
270
+ for (const [name, conditions] of Object.entries(schema)) {
271
+ const errors = [];
272
+ if (Array.isArray(conditions)) {
273
+ for (const {
274
+ required,
275
+ errorMessage
276
+ } of conditions) {
277
+ if (!required.every(key => !!config[key])) {
278
+ errors.push(errorMessage);
279
+ }
280
+ }
281
+ if (name === 'anyOf' && !(conditions.length - errors.length >= 1)) {
282
+ validationErrors.push(...errors);
283
+ }
284
+ }
285
+ }
286
+ return validationErrors;
287
+ }
288
+ function extractConfigByNamespace(schema, dataset, namespace) {
289
+ const property = schema.properties[namespace];
290
+ if ((property == null ? void 0 : property.type) !== 'object') {
291
+ return;
292
+ }
293
+ const newObject = {
294
+ [namespace]: ({})
295
+ };
296
+ for (const [key, value] of Object.entries(dataset)) {
297
+ let current = newObject;
298
+ const keyParts = key.split('.');
299
+ for (const [index, name] of keyParts.entries()) {
300
+ if (typeof current === 'object') {
301
+ if (index < keyParts.length - 1) {
302
+ if (!isObject(current[name])) {
303
+ current[name] = {};
304
+ }
305
+ current = current[name];
306
+ } else if (key !== namespace) {
307
+ current[name] = normaliseString(value);
308
+ }
309
+ }
310
+ }
311
+ }
312
+ return newObject[namespace];
313
+ }
314
+ /**
315
+ * Schema for component config
316
+ *
317
+ * @typedef {object} Schema
318
+ * @property {{ [field: string]: SchemaProperty | undefined }} properties - Schema properties
319
+ * @property {SchemaCondition[]} [anyOf] - List of schema conditions
320
+ */
321
+ /**
322
+ * Schema property for component config
323
+ *
324
+ * @typedef {object} SchemaProperty
325
+ * @property {'string' | 'boolean' | 'number' | 'object'} type - Property type
326
+ */
327
+ /**
328
+ * Schema condition for component config
329
+ *
330
+ * @typedef {object} SchemaCondition
331
+ * @property {string[]} required - List of required config fields
332
+ * @property {string} errorMessage - Error message when required config fields not provided
333
+ */
334
+ /**
335
+ * @template {ObjectNested} [ConfigurationType={}]
336
+ * @typedef ChildClass
337
+ * @property {string} moduleName - The module name that'll be looked for in the DOM when initialising the component
338
+ * @property {Schema} [schema] - The schema of the component configuration
339
+ * @property {ConfigurationType} [defaults] - The default values of the configuration of the component
340
+ */
341
+ /**
342
+ * @template {ObjectNested} [ConfigurationType={}]
343
+ * @typedef {typeof GOVUKFrontendComponent & ChildClass<ConfigurationType>} ChildClassConstructor<ConfigurationType>
344
+ */
345
+
314
346
  class I18n {
315
347
  constructor(translations = {}, config = {}) {
316
348
  var _config$locale;
@@ -517,15 +549,15 @@
517
549
  * attribute, which also provides accessibility.
518
550
  *
519
551
  * @preserve
552
+ * @augments ConfigurableComponent<AccordionConfig>
520
553
  */
521
- class Accordion extends GOVUKFrontendComponent {
554
+ class Accordion extends ConfigurableComponent {
522
555
  /**
523
556
  * @param {Element | null} $root - HTML element to use for accordion
524
557
  * @param {AccordionConfig} [config] - Accordion config
525
558
  */
526
559
  constructor($root, config = {}) {
527
- super($root);
528
- this.config = void 0;
560
+ super($root, config);
529
561
  this.i18n = void 0;
530
562
  this.controlsClass = 'govuk-accordion__controls';
531
563
  this.showAllClass = 'govuk-accordion__show-all';
@@ -550,7 +582,6 @@
550
582
  this.$showAllButton = null;
551
583
  this.$showAllIcon = null;
552
584
  this.$showAllText = null;
553
- this.config = mergeConfigs(Accordion.defaults, config, normaliseDataset(Accordion, this.$root.dataset));
554
585
  this.i18n = new I18n(this.config.i18n);
555
586
  const $sections = this.$root.querySelectorAll(`.${this.sectionClass}`);
556
587
  if (!$sections.length) {
@@ -820,7 +851,7 @@
820
851
  */
821
852
 
822
853
  /**
823
- * @typedef {import('../../common/index.mjs').Schema} Schema
854
+ * @typedef {import('../../common/configuration.mjs').Schema} Schema
824
855
  */
825
856
  Accordion.moduleName = 'govuk-accordion';
826
857
  Accordion.defaults = Object.freeze({
@@ -851,17 +882,16 @@
851
882
  * JavaScript enhancements for the Button component
852
883
  *
853
884
  * @preserve
885
+ * @augments ConfigurableComponent<ButtonConfig>
854
886
  */
855
- class Button extends GOVUKFrontendComponent {
887
+ class Button extends ConfigurableComponent {
856
888
  /**
857
889
  * @param {Element | null} $root - HTML element to use for button
858
890
  * @param {ButtonConfig} [config] - Button config
859
891
  */
860
892
  constructor($root, config = {}) {
861
- super($root);
862
- this.config = void 0;
893
+ super($root, config);
863
894
  this.debounceFormSubmitTimer = null;
864
- this.config = mergeConfigs(Button.defaults, config, normaliseDataset(Button, this.$root.dataset));
865
895
  this.$root.addEventListener('keydown', event => this.handleKeyDown(event));
866
896
  this.$root.addEventListener('click', event => this.debounce(event));
867
897
  }
@@ -898,7 +928,7 @@
898
928
  */
899
929
 
900
930
  /**
901
- * @typedef {import('../../common/index.mjs').Schema} Schema
931
+ * @typedef {import('../../common/configuration.mjs').Schema} Schema
902
932
  */
903
933
  Button.moduleName = 'govuk-button';
904
934
  Button.defaults = Object.freeze({
@@ -928,22 +958,33 @@
928
958
  * of the available characters/words has been entered.
929
959
  *
930
960
  * @preserve
961
+ * @augments ConfigurableComponent<CharacterCountConfig>
931
962
  */
932
- class CharacterCount extends GOVUKFrontendComponent {
963
+ class CharacterCount extends ConfigurableComponent {
964
+ [configOverride](datasetConfig) {
965
+ let configOverrides = {};
966
+ if ('maxwords' in datasetConfig || 'maxlength' in datasetConfig) {
967
+ configOverrides = {
968
+ maxlength: undefined,
969
+ maxwords: undefined
970
+ };
971
+ }
972
+ return configOverrides;
973
+ }
974
+
933
975
  /**
934
976
  * @param {Element | null} $root - HTML element to use for character count
935
977
  * @param {CharacterCountConfig} [config] - Character count config
936
978
  */
937
979
  constructor($root, config = {}) {
938
980
  var _ref, _this$config$maxwords;
939
- super($root);
981
+ super($root, config);
940
982
  this.$textarea = void 0;
941
983
  this.$visibleCountMessage = void 0;
942
984
  this.$screenReaderCountMessage = void 0;
943
985
  this.lastInputTimestamp = null;
944
986
  this.lastInputValue = '';
945
987
  this.valueChecker = null;
946
- this.config = void 0;
947
988
  this.i18n = void 0;
948
989
  this.maxLength = void 0;
949
990
  const $textarea = this.$root.querySelector('.govuk-js-character-count');
@@ -955,15 +996,6 @@
955
996
  identifier: 'Form field (`.govuk-js-character-count`)'
956
997
  });
957
998
  }
958
- const datasetConfig = normaliseDataset(CharacterCount, this.$root.dataset);
959
- let configOverrides = {};
960
- if ('maxwords' in datasetConfig || 'maxlength' in datasetConfig) {
961
- configOverrides = {
962
- maxlength: undefined,
963
- maxwords: undefined
964
- };
965
- }
966
- this.config = mergeConfigs(CharacterCount.defaults, config, configOverrides, datasetConfig);
967
999
  const errors = validateConfig(CharacterCount.schema, this.config);
968
1000
  if (errors[0]) {
969
1001
  throw new ConfigError(formatErrorMessage(CharacterCount, errors[0]));
@@ -1149,7 +1181,7 @@
1149
1181
  */
1150
1182
 
1151
1183
  /**
1152
- * @typedef {import('../../common/index.mjs').Schema} Schema
1184
+ * @typedef {import('../../common/configuration.mjs').Schema} Schema
1153
1185
  * @typedef {import('../../i18n.mjs').TranslationPluralForms} TranslationPluralForms
1154
1186
  */
1155
1187
  CharacterCount.moduleName = 'govuk-character-count';
@@ -1316,16 +1348,15 @@
1316
1348
  * configuration.
1317
1349
  *
1318
1350
  * @preserve
1351
+ * @augments ConfigurableComponent<ErrorSummaryConfig>
1319
1352
  */
1320
- class ErrorSummary extends GOVUKFrontendComponent {
1353
+ class ErrorSummary extends ConfigurableComponent {
1321
1354
  /**
1322
1355
  * @param {Element | null} $root - HTML element to use for error summary
1323
1356
  * @param {ErrorSummaryConfig} [config] - Error summary config
1324
1357
  */
1325
1358
  constructor($root, config = {}) {
1326
- super($root);
1327
- this.config = void 0;
1328
- this.config = mergeConfigs(ErrorSummary.defaults, config, normaliseDataset(ErrorSummary, this.$root.dataset));
1359
+ super($root, config);
1329
1360
  if (!this.config.disableAutoFocus) {
1330
1361
  setFocus(this.$root);
1331
1362
  }
@@ -1392,7 +1423,7 @@
1392
1423
  */
1393
1424
 
1394
1425
  /**
1395
- * @typedef {import('../../common/index.mjs').Schema} Schema
1426
+ * @typedef {import('../../common/configuration.mjs').Schema} Schema
1396
1427
  */
1397
1428
  ErrorSummary.moduleName = 'govuk-error-summary';
1398
1429
  ErrorSummary.defaults = Object.freeze({
@@ -1410,15 +1441,15 @@
1410
1441
  * Exit this page component
1411
1442
  *
1412
1443
  * @preserve
1444
+ * @augments ConfigurableComponent<ExitThisPageConfig>
1413
1445
  */
1414
- class ExitThisPage extends GOVUKFrontendComponent {
1446
+ class ExitThisPage extends ConfigurableComponent {
1415
1447
  /**
1416
1448
  * @param {Element | null} $root - HTML element that wraps the Exit This Page button
1417
1449
  * @param {ExitThisPageConfig} [config] - Exit This Page config
1418
1450
  */
1419
1451
  constructor($root, config = {}) {
1420
- super($root);
1421
- this.config = void 0;
1452
+ super($root, config);
1422
1453
  this.i18n = void 0;
1423
1454
  this.$button = void 0;
1424
1455
  this.$skiplinkButton = null;
@@ -1439,7 +1470,6 @@
1439
1470
  identifier: 'Button (`.govuk-exit-this-page__button`)'
1440
1471
  });
1441
1472
  }
1442
- this.config = mergeConfigs(ExitThisPage.defaults, config, normaliseDataset(ExitThisPage, this.$root.dataset));
1443
1473
  this.i18n = new I18n(this.config.i18n);
1444
1474
  this.$button = $button;
1445
1475
  const $skiplinkButton = document.querySelector('.govuk-js-exit-this-page-skiplink');
@@ -1605,7 +1635,7 @@
1605
1635
  */
1606
1636
 
1607
1637
  /**
1608
- * @typedef {import('../../common/index.mjs').Schema} Schema
1638
+ * @typedef {import('../../common/configuration.mjs').Schema} Schema
1609
1639
  */
1610
1640
  ExitThisPage.moduleName = 'govuk-exit-this-page';
1611
1641
  ExitThisPage.defaults = Object.freeze({
@@ -1710,16 +1740,15 @@
1710
1740
  * Notification Banner component
1711
1741
  *
1712
1742
  * @preserve
1743
+ * @augments ConfigurableComponent<NotificationBannerConfig>
1713
1744
  */
1714
- class NotificationBanner extends GOVUKFrontendComponent {
1745
+ class NotificationBanner extends ConfigurableComponent {
1715
1746
  /**
1716
1747
  * @param {Element | null} $root - HTML element to use for notification banner
1717
1748
  * @param {NotificationBannerConfig} [config] - Notification banner config
1718
1749
  */
1719
1750
  constructor($root, config = {}) {
1720
- super($root);
1721
- this.config = void 0;
1722
- this.config = mergeConfigs(NotificationBanner.defaults, config, normaliseDataset(NotificationBanner, this.$root.dataset));
1751
+ super($root, config);
1723
1752
  if (this.$root.getAttribute('role') === 'alert' && !this.config.disableAutoFocus) {
1724
1753
  setFocus(this.$root);
1725
1754
  }
@@ -1737,7 +1766,7 @@
1737
1766
  */
1738
1767
 
1739
1768
  /**
1740
- * @typedef {import('../../common/index.mjs').Schema} Schema
1769
+ * @typedef {import('../../common/configuration.mjs').Schema} Schema
1741
1770
  */
1742
1771
  NotificationBanner.moduleName = 'govuk-notification-banner';
1743
1772
  NotificationBanner.defaults = Object.freeze({
@@ -1755,15 +1784,15 @@
1755
1784
  * Password input component
1756
1785
  *
1757
1786
  * @preserve
1787
+ * @augments ConfigurableComponent<PasswordInputConfig>
1758
1788
  */
1759
- class PasswordInput extends GOVUKFrontendComponent {
1789
+ class PasswordInput extends ConfigurableComponent {
1760
1790
  /**
1761
1791
  * @param {Element | null} $root - HTML element to use for password input
1762
1792
  * @param {PasswordInputConfig} [config] - Password input config
1763
1793
  */
1764
1794
  constructor($root, config = {}) {
1765
- super($root);
1766
- this.config = void 0;
1795
+ super($root, config);
1767
1796
  this.i18n = void 0;
1768
1797
  this.$input = void 0;
1769
1798
  this.$showHideButton = void 0;
@@ -1794,7 +1823,6 @@
1794
1823
  }
1795
1824
  this.$input = $input;
1796
1825
  this.$showHideButton = $showHideButton;
1797
- this.config = mergeConfigs(PasswordInput.defaults, config, normaliseDataset(PasswordInput, this.$root.dataset));
1798
1826
  this.i18n = new I18n(this.config.i18n, {
1799
1827
  locale: closestAttributeValue(this.$root, 'lang')
1800
1828
  });
@@ -1874,7 +1902,7 @@
1874
1902
  */
1875
1903
 
1876
1904
  /**
1877
- * @typedef {import('../../common/index.mjs').Schema} Schema
1905
+ * @typedef {import('../../common/configuration.mjs').Schema} Schema
1878
1906
  * @typedef {import('../../i18n.mjs').TranslationPluralForms} TranslationPluralForms
1879
1907
  */
1880
1908
  PasswordInput.moduleName = 'govuk-password-input';
@@ -2427,11 +2455,11 @@
2427
2455
  *
2428
2456
  * Any component errors will be caught and logged to the console.
2429
2457
  *
2430
- * @template {CompatibleClass} T
2431
- * @param {T} Component - class of the component to create
2432
- * @param {T["defaults"]} [config] - Config supplied to component
2433
- * @param {OnErrorCallback<T> | Element | Document | CreateAllOptions<T> } [createAllOptions] - options for createAll including scope of the document to search within and callback function if error throw by component on init
2434
- * @returns {Array<InstanceType<T>>} - array of instantiated components
2458
+ * @template {CompatibleClass} ComponentClass
2459
+ * @param {ComponentClass} Component - class of the component to create
2460
+ * @param {ComponentConfig<ComponentClass>} [config] - Config supplied to component
2461
+ * @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
2462
+ * @returns {Array<InstanceType<ComponentClass>>} - array of instantiated components
2435
2463
  */
2436
2464
  function createAll(Component, config, createAllOptions) {
2437
2465
  let $scope = document;
@@ -2478,7 +2506,7 @@
2478
2506
  }).filter(Boolean);
2479
2507
  }
2480
2508
  /**
2481
- * @typedef {{new (...args: any[]): any, defaults?: object, moduleName: string}} CompatibleClass
2509
+ * @typedef {{new (...args: any[]): any, moduleName: string}} CompatibleClass
2482
2510
  */
2483
2511
  /**
2484
2512
  * Config for all components via `initAll()`
@@ -2512,23 +2540,27 @@
2512
2540
  * @typedef {keyof Config} ConfigKey
2513
2541
  */
2514
2542
  /**
2515
- * @template {CompatibleClass} T
2543
+ * @template {CompatibleClass} ComponentClass
2544
+ * @typedef {ConstructorParameters<ComponentClass>[1]} ComponentConfig
2545
+ */
2546
+ /**
2547
+ * @template {CompatibleClass} ComponentClass
2516
2548
  * @typedef {object} ErrorContext
2517
2549
  * @property {Element} [element] - Element used for component module initialisation
2518
- * @property {T} [component] - Class of component
2519
- * @property {T["defaults"]} config - Config supplied to component
2550
+ * @property {ComponentClass} [component] - Class of component
2551
+ * @property {ComponentConfig<ComponentClass>} config - Config supplied to component
2520
2552
  */
2521
2553
  /**
2522
- * @template {CompatibleClass} T
2554
+ * @template {CompatibleClass} ComponentClass
2523
2555
  * @callback OnErrorCallback
2524
2556
  * @param {unknown} error - Thrown error
2525
- * @param {ErrorContext<T>} context - Object containing the element, component class and configuration
2557
+ * @param {ErrorContext<ComponentClass>} context - Object containing the element, component class and configuration
2526
2558
  */
2527
2559
  /**
2528
- * @template {CompatibleClass} T
2560
+ * @template {CompatibleClass} ComponentClass
2529
2561
  * @typedef {object} CreateAllOptions
2530
2562
  * @property {Element | Document} [scope] - scope of the document to search within
2531
- * @property {OnErrorCallback<T>} [onError] - callback function if error throw by component on init
2563
+ * @property {OnErrorCallback<ComponentClass>} [onError] - callback function if error throw by component on init
2532
2564
  */
2533
2565
 
2534
2566
  exports.Accordion = Accordion;
@@ -2536,6 +2568,7 @@
2536
2568
  exports.CharacterCount = CharacterCount;
2537
2569
  exports.Checkboxes = Checkboxes;
2538
2570
  exports.Component = GOVUKFrontendComponent;
2571
+ exports.ConfigurableComponent = ConfigurableComponent;
2539
2572
  exports.ErrorSummary = ErrorSummary;
2540
2573
  exports.ExitThisPage = ExitThisPage;
2541
2574
  exports.Header = Header;