govuk_tech_docs 6.5.2.1 → 6.6.0.rc.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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/publish-gem.yaml +1 -1
  3. data/lib/assets/stylesheets/_govuk_tech_docs.scss +39 -1
  4. data/lib/govuk_tech_docs/version.rb +1 -1
  5. data/node_modules/govuk-frontend/dist/govuk/all.bundle.js +202 -137
  6. data/node_modules/govuk-frontend/dist/govuk/all.bundle.mjs +202 -137
  7. data/node_modules/govuk-frontend/dist/govuk/common/configuration.mjs +5 -1
  8. data/node_modules/govuk-frontend/dist/govuk/common/create-element.mjs +13 -0
  9. data/node_modules/govuk-frontend/dist/govuk/common/govuk-frontend-version.mjs +1 -1
  10. data/node_modules/govuk-frontend/dist/govuk/component.mjs +2 -1
  11. data/node_modules/govuk-frontend/dist/govuk/components/_index.import.scss +2 -0
  12. data/node_modules/govuk-frontend/dist/govuk/components/_index.scss +2 -0
  13. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js +87 -62
  14. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs +87 -62
  15. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.mjs +60 -56
  16. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.js +17 -6
  17. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.mjs +17 -6
  18. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js +90 -32
  19. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs +90 -32
  20. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.mjs +64 -27
  21. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js +12 -5
  22. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs +12 -5
  23. data/node_modules/govuk-frontend/dist/govuk/components/cookie-banner/_mixin.scss +6 -0
  24. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js +17 -6
  25. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs +17 -6
  26. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js +43 -18
  27. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs +43 -18
  28. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs +16 -12
  29. data/node_modules/govuk-frontend/dist/govuk/components/feedback/_feedback.import.scss +6 -0
  30. data/node_modules/govuk-frontend/dist/govuk/components/feedback/_index.import.scss +8 -0
  31. data/node_modules/govuk-frontend/dist/govuk/components/feedback/_index.scss +5 -0
  32. data/node_modules/govuk-frontend/dist/govuk/components/feedback/_mixin.scss +48 -0
  33. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.js +54 -30
  34. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.mjs +54 -30
  35. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.mjs +27 -24
  36. data/node_modules/govuk-frontend/dist/govuk/components/footer/_mixin.scss +6 -0
  37. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/_index.import.scss +8 -0
  38. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/_index.scss +6 -0
  39. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/_language-navigation.import.scss +6 -0
  40. data/node_modules/govuk-frontend/dist/govuk/components/language-navigation/_mixin.scss +68 -0
  41. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js +17 -6
  42. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs +17 -6
  43. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js +32 -9
  44. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs +32 -9
  45. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.mjs +5 -3
  46. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.js +12 -5
  47. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs +12 -5
  48. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/_mixin.scss +48 -3
  49. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js +12 -5
  50. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs +12 -5
  51. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js +14 -6
  52. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs +14 -6
  53. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs +2 -1
  54. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js +12 -5
  55. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs +12 -5
  56. data/node_modules/govuk-frontend/dist/govuk/custom-properties/_frontend-version.mixin.scss +1 -1
  57. data/node_modules/govuk-frontend/dist/govuk/custom-properties/_functional-colours.mixin.scss +1 -0
  58. data/node_modules/govuk-frontend/dist/govuk/errors/index.mjs +8 -5
  59. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.js +1 -1
  60. data/node_modules/govuk-frontend/dist/govuk/helpers/_colour.scss +1 -1
  61. data/node_modules/govuk-frontend/dist/govuk/init.mjs +8 -8
  62. data/node_modules/govuk-frontend/dist/govuk/settings/_colours-organisations.scss +16 -2
  63. data/package-lock.json +4 -4
  64. data/package.json +1 -1
  65. metadata +10 -1
@@ -28,6 +28,9 @@ function isArray(option) {
28
28
  function isObject(option) {
29
29
  return !!option && typeof option === 'object' && !isArray(option);
30
30
  }
31
+ function isScope($scope) {
32
+ return !!$scope && ($scope instanceof Element || $scope instanceof Document);
33
+ }
31
34
  function formatErrorMessage(Component, message) {
32
35
  return `${Component.moduleName}: ${message}`;
33
36
  }
@@ -46,11 +49,14 @@ class SupportError extends GOVUKFrontendError {
46
49
  /**
47
50
  * Checks if GOV.UK Frontend is supported on this page
48
51
  *
49
- * @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support
52
+ * @param {Element | Document | null | string} [scopeOrMessage] - HTML element `<body>` checked for browser support or support error message
50
53
  */
51
- constructor($scope = document.body) {
52
- const supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
53
- super($scope ? supportMessage : 'GOV.UK Frontend initialised without `<script type="module">`');
54
+ constructor(scopeOrMessage = document.body) {
55
+ let supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
56
+ if (!isScope(scopeOrMessage)) {
57
+ supportMessage = 'GOV.UK Frontend initialised without `<script type="module">`';
58
+ }
59
+ super(typeof scopeOrMessage === 'string' ? scopeOrMessage : supportMessage);
54
60
  this.name = 'SupportError';
55
61
  }
56
62
  }
@@ -91,6 +97,7 @@ class InitError extends GOVUKFrontendError {
91
97
  * @import { ComponentWithModuleName } from '../common/index.mjs'
92
98
  */
93
99
 
100
+ const _self = typeof globalThis !== 'undefined' ? globalThis : self;
94
101
  class Component {
95
102
  /**
96
103
  * Returns the root element of the component
@@ -144,7 +151,7 @@ class Component {
144
151
  /**
145
152
  * @typedef {typeof Component & ChildClass} ChildClassConstructor
146
153
  */
147
- Component.elementType = HTMLElement;
154
+ Component.elementType = _self.HTMLElement;
148
155
 
149
156
  const configOverride = Symbol.for('configOverride');
150
157
  class ConfigurableComponent extends Component {
@@ -169,10 +176,14 @@ class ConfigurableComponent extends Component {
169
176
  throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));
170
177
  }
171
178
  const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);
172
- this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}, this[configOverride](datasetConfig), datasetConfig);
179
+ this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {});
180
+ this._config = mergeConfigs(this._config, this[configOverride](datasetConfig), datasetConfig);
173
181
  }
174
182
  }
175
183
  function normaliseString(value, property) {
184
+ if (property != null && property.type && !['string', 'number', 'boolean'].includes(property.type)) {
185
+ return;
186
+ }
176
187
  const trimmedValue = value ? value.trim() : '';
177
188
  let output;
178
189
  let outputType = property == null ? void 0 : property.type;
@@ -292,6 +303,17 @@ function extractConfigByNamespace(schema, dataset, namespace) {
292
303
  * @import { CompatibleClass, Config, CreateAllOptions, OnErrorCallback } from '../init.mjs'
293
304
  */
294
305
 
306
+ function createElement(tagName, attributes = {}, children = []) {
307
+ const $element = document.createElement(tagName);
308
+ Object.entries(attributes).forEach(([name, value]) => {
309
+ $element.setAttribute(name, value);
310
+ });
311
+ for (const child of children) {
312
+ $element.append(child);
313
+ }
314
+ return $element;
315
+ }
316
+
295
317
  class I18n {
296
318
  constructor(translations = {}, config = {}) {
297
319
  var _config$locale;
@@ -412,46 +434,48 @@ class FileUpload extends ConfigurableComponent {
412
434
  this.$input.addEventListener('change', this.onChange.bind(this));
413
435
  this.updateDisabledState();
414
436
  this.observeDisabledState();
415
- this.$announcements = document.createElement('span');
416
- this.$announcements.classList.add('govuk-file-upload-announcements');
417
- this.$announcements.classList.add('govuk-visually-hidden');
418
- this.$announcements.setAttribute('aria-live', 'assertive');
437
+ this.$announcements = createElement('span', {
438
+ class: 'govuk-file-upload-announcements govuk-visually-hidden',
439
+ 'aria-live': 'assertive'
440
+ });
419
441
  this.$root.insertAdjacentElement('afterend', this.$announcements);
420
442
  this.bindDraggingEvents();
421
443
  }
422
444
  createStatus() {
423
- const $status = document.createElement('span');
424
- $status.className = 'govuk-body govuk-file-upload-button__status';
425
- $status.setAttribute('aria-live', 'polite');
445
+ const $status = createElement('span', {
446
+ class: 'govuk-body govuk-file-upload-button__status',
447
+ 'aria-live': 'polite'
448
+ });
426
449
  $status.innerText = this.i18n.t('noFileChosen');
427
450
  return $status;
428
451
  }
429
452
  createButton() {
430
- const $button = document.createElement('button');
431
- $button.classList.add('govuk-file-upload-button');
432
- $button.type = 'button';
433
- $button.id = this.id;
434
- $button.classList.add('govuk-file-upload-button--empty');
453
+ const $button = createElement('button', {
454
+ class: 'govuk-file-upload-button govuk-file-upload-button--empty',
455
+ type: 'button',
456
+ id: this.id
457
+ });
435
458
  const ariaDescribedBy = this.$input.getAttribute('aria-describedby');
436
459
  if (ariaDescribedBy) {
437
460
  $button.setAttribute('aria-describedby', ariaDescribedBy);
438
461
  }
439
462
  $button.appendChild(this.$status);
440
- const commaSpan = document.createElement('span');
441
- commaSpan.className = 'govuk-visually-hidden';
442
- commaSpan.innerText = ', ';
443
- commaSpan.id = `${this.id}-comma`;
463
+ const commaSpan = createElement('span', {
464
+ class: 'govuk-visually-hidden',
465
+ id: `${this.id}-comma`
466
+ }, [', ']);
444
467
  $button.appendChild(commaSpan);
445
- const containerSpan = document.createElement('span');
446
- containerSpan.className = 'govuk-file-upload-button__pseudo-button-container';
447
- const buttonSpan = document.createElement('span');
448
- buttonSpan.className = 'govuk-button govuk-button--secondary govuk-file-upload-button__pseudo-button';
449
- buttonSpan.innerText = this.i18n.t('chooseFilesButton');
468
+ const containerSpan = createElement('span', {
469
+ class: 'govuk-file-upload-button__pseudo-button-container'
470
+ });
471
+ const buttonSpan = createElement('span', {
472
+ class: 'govuk-button govuk-button--secondary govuk-file-upload-button__pseudo-button'
473
+ }, [this.i18n.t('chooseFilesButton')]);
450
474
  containerSpan.appendChild(buttonSpan);
451
475
  containerSpan.insertAdjacentText('beforeend', ' ');
452
- const instructionSpan = document.createElement('span');
453
- instructionSpan.className = 'govuk-body govuk-file-upload-button__instruction';
454
- instructionSpan.innerText = this.i18n.t('dropInstruction');
476
+ const instructionSpan = createElement('span', {
477
+ class: 'govuk-body govuk-file-upload-button__instruction'
478
+ }, [this.i18n.t('dropInstruction')]);
455
479
  containerSpan.appendChild(instructionSpan);
456
480
  $button.appendChild(containerSpan);
457
481
  $button.setAttribute('aria-labelledby', `${this.$label.id} ${commaSpan.id} ${$button.id}`);
@@ -1,5 +1,6 @@
1
1
  import { closestAttributeValue } from '../../common/closest-attribute-value.mjs';
2
2
  import { ConfigurableComponent } from '../../common/configuration.mjs';
3
+ import { createElement } from '../../common/create-element.mjs';
3
4
  import { ElementError } from '../../errors/index.mjs';
4
5
  import { I18n } from '../../i18n.mjs';
5
6
 
@@ -55,46 +56,48 @@ class FileUpload extends ConfigurableComponent {
55
56
  this.$input.addEventListener('change', this.onChange.bind(this));
56
57
  this.updateDisabledState();
57
58
  this.observeDisabledState();
58
- this.$announcements = document.createElement('span');
59
- this.$announcements.classList.add('govuk-file-upload-announcements');
60
- this.$announcements.classList.add('govuk-visually-hidden');
61
- this.$announcements.setAttribute('aria-live', 'assertive');
59
+ this.$announcements = createElement('span', {
60
+ class: 'govuk-file-upload-announcements govuk-visually-hidden',
61
+ 'aria-live': 'assertive'
62
+ });
62
63
  this.$root.insertAdjacentElement('afterend', this.$announcements);
63
64
  this.bindDraggingEvents();
64
65
  }
65
66
  createStatus() {
66
- const $status = document.createElement('span');
67
- $status.className = 'govuk-body govuk-file-upload-button__status';
68
- $status.setAttribute('aria-live', 'polite');
67
+ const $status = createElement('span', {
68
+ class: 'govuk-body govuk-file-upload-button__status',
69
+ 'aria-live': 'polite'
70
+ });
69
71
  $status.innerText = this.i18n.t('noFileChosen');
70
72
  return $status;
71
73
  }
72
74
  createButton() {
73
- const $button = document.createElement('button');
74
- $button.classList.add('govuk-file-upload-button');
75
- $button.type = 'button';
76
- $button.id = this.id;
77
- $button.classList.add('govuk-file-upload-button--empty');
75
+ const $button = createElement('button', {
76
+ class: 'govuk-file-upload-button govuk-file-upload-button--empty',
77
+ type: 'button',
78
+ id: this.id
79
+ });
78
80
  const ariaDescribedBy = this.$input.getAttribute('aria-describedby');
79
81
  if (ariaDescribedBy) {
80
82
  $button.setAttribute('aria-describedby', ariaDescribedBy);
81
83
  }
82
84
  $button.appendChild(this.$status);
83
- const commaSpan = document.createElement('span');
84
- commaSpan.className = 'govuk-visually-hidden';
85
- commaSpan.innerText = ', ';
86
- commaSpan.id = `${this.id}-comma`;
85
+ const commaSpan = createElement('span', {
86
+ class: 'govuk-visually-hidden',
87
+ id: `${this.id}-comma`
88
+ }, [', ']);
87
89
  $button.appendChild(commaSpan);
88
- const containerSpan = document.createElement('span');
89
- containerSpan.className = 'govuk-file-upload-button__pseudo-button-container';
90
- const buttonSpan = document.createElement('span');
91
- buttonSpan.className = 'govuk-button govuk-button--secondary govuk-file-upload-button__pseudo-button';
92
- buttonSpan.innerText = this.i18n.t('chooseFilesButton');
90
+ const containerSpan = createElement('span', {
91
+ class: 'govuk-file-upload-button__pseudo-button-container'
92
+ });
93
+ const buttonSpan = createElement('span', {
94
+ class: 'govuk-button govuk-button--secondary govuk-file-upload-button__pseudo-button'
95
+ }, [this.i18n.t('chooseFilesButton')]);
93
96
  containerSpan.appendChild(buttonSpan);
94
97
  containerSpan.insertAdjacentText('beforeend', ' ');
95
- const instructionSpan = document.createElement('span');
96
- instructionSpan.className = 'govuk-body govuk-file-upload-button__instruction';
97
- instructionSpan.innerText = this.i18n.t('dropInstruction');
98
+ const instructionSpan = createElement('span', {
99
+ class: 'govuk-body govuk-file-upload-button__instruction'
100
+ }, [this.i18n.t('dropInstruction')]);
98
101
  containerSpan.appendChild(instructionSpan);
99
102
  $button.appendChild(containerSpan);
100
103
  $button.setAttribute('aria-labelledby', `${this.$label.id} ${commaSpan.id} ${$button.id}`);
@@ -19,6 +19,12 @@
19
19
  border-top-color: base.govuk-functional-colour(brand);
20
20
  color: $govuk-footer-text;
21
21
  background: base.govuk-functional-colour(template-background);
22
+
23
+ @media print {
24
+ border-top-color: currentcolor;
25
+ color: base.govuk-functional-colour(text);
26
+ background-color: transparent;
27
+ }
22
28
  }
23
29
 
24
30
  .govuk-footer__crown {
@@ -0,0 +1,8 @@
1
+ @use "mixin";
2
+
3
+ @import "../../base";
4
+
5
+ @include govuk-exports("govuk/component/language-navigation") {
6
+ @include mixin.styles;
7
+ }
8
+
@@ -0,0 +1,6 @@
1
+ @use "../../custom-properties";
2
+
3
+ @use "mixin";
4
+
5
+ @include mixin.styles;
6
+
@@ -0,0 +1,6 @@
1
+ @use "../../settings/warnings--internal";
2
+
3
+ @include warnings--internal.component-scss-file-warning("language-navigation");
4
+
5
+ @import "index";
6
+
@@ -0,0 +1,68 @@
1
+ @use "../../base";
2
+
3
+ /// @access private
4
+ @mixin styles {
5
+ .govuk-language-navigation {
6
+ @include base.govuk-font($size: 19);
7
+
8
+ @include base.govuk-responsive-margin(6, "bottom");
9
+ color: base.govuk-functional-colour(text);
10
+ }
11
+
12
+ .govuk-language-navigation__list {
13
+ display: inline-flex;
14
+ flex-wrap: wrap;
15
+ row-gap: base.govuk-spacing(2);
16
+ margin: 0;
17
+ padding: 0;
18
+ list-style-type: none;
19
+ }
20
+
21
+ .govuk-language-navigation__list-item {
22
+ display: flex;
23
+ align-items: center;
24
+
25
+ &:not(:last-child) {
26
+ &::after {
27
+ content: "";
28
+ display: block;
29
+ height: 1em;
30
+ margin-right: base.govuk-spacing(2);
31
+ margin-left: base.govuk-spacing(2);
32
+ border-right: 1px solid;
33
+ border-right-color: base.govuk-functional-colour(border);
34
+ }
35
+ }
36
+ }
37
+
38
+ .govuk-language-navigation__link {
39
+ @include base.govuk-link-common;
40
+ @include base.govuk-link-style-default;
41
+ }
42
+
43
+ .govuk-language-navigation--inverse {
44
+ color: base.govuk-functional-colour(inverse-text);
45
+
46
+ .govuk-language-navigation__link {
47
+ @include base.govuk-link-style-inverse;
48
+ }
49
+
50
+ .govuk-language-navigation__list-item::after {
51
+ border-right-color: currentcolor;
52
+ }
53
+ }
54
+
55
+ // Ensure the Language navigation has enough
56
+ // spacing with the rest of the Service Navigation
57
+ .govuk-service-navigation .govuk-language-navigation {
58
+ // Slightly smaller margin because the Service Navigation's menu toggle
59
+ // has a little margin underneath it already.
60
+ margin-top: base.govuk-spacing(1);
61
+ margin-bottom: base.govuk-spacing(3);
62
+
63
+ @media #{base.govuk-from-breakpoint(tablet)} {
64
+ margin-top: base.govuk-spacing(3);
65
+ }
66
+ }
67
+ }
68
+
@@ -53,6 +53,9 @@
53
53
  function isObject(option) {
54
54
  return !!option && typeof option === 'object' && !isArray(option);
55
55
  }
56
+ function isScope($scope) {
57
+ return !!$scope && ($scope instanceof Element || $scope instanceof Document);
58
+ }
56
59
  function formatErrorMessage(Component, message) {
57
60
  return `${Component.moduleName}: ${message}`;
58
61
  }
@@ -71,11 +74,14 @@
71
74
  /**
72
75
  * Checks if GOV.UK Frontend is supported on this page
73
76
  *
74
- * @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support
77
+ * @param {Element | Document | null | string} [scopeOrMessage] - HTML element `<body>` checked for browser support or support error message
75
78
  */
76
- constructor($scope = document.body) {
77
- const supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
78
- super($scope ? supportMessage : 'GOV.UK Frontend initialised without `<script type="module">`');
79
+ constructor(scopeOrMessage = document.body) {
80
+ let supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
81
+ if (!isScope(scopeOrMessage)) {
82
+ supportMessage = 'GOV.UK Frontend initialised without `<script type="module">`';
83
+ }
84
+ super(typeof scopeOrMessage === 'string' ? scopeOrMessage : supportMessage);
79
85
  this.name = 'SupportError';
80
86
  }
81
87
  }
@@ -116,6 +122,7 @@
116
122
  * @import { ComponentWithModuleName } from '../common/index.mjs'
117
123
  */
118
124
 
125
+ const _self = typeof globalThis !== 'undefined' ? globalThis : self;
119
126
  class Component {
120
127
  /**
121
128
  * Returns the root element of the component
@@ -169,7 +176,7 @@
169
176
  /**
170
177
  * @typedef {typeof Component & ChildClass} ChildClassConstructor
171
178
  */
172
- Component.elementType = HTMLElement;
179
+ Component.elementType = _self.HTMLElement;
173
180
 
174
181
  const configOverride = Symbol.for('configOverride');
175
182
  class ConfigurableComponent extends Component {
@@ -194,10 +201,14 @@
194
201
  throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));
195
202
  }
196
203
  const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);
197
- this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}, this[configOverride](datasetConfig), datasetConfig);
204
+ this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {});
205
+ this._config = mergeConfigs(this._config, this[configOverride](datasetConfig), datasetConfig);
198
206
  }
199
207
  }
200
208
  function normaliseString(value, property) {
209
+ if (property != null && property.type && !['string', 'number', 'boolean'].includes(property.type)) {
210
+ return;
211
+ }
201
212
  const trimmedValue = value ? value.trim() : '';
202
213
  let output;
203
214
  let outputType = property == null ? void 0 : property.type;
@@ -47,6 +47,9 @@ function isArray(option) {
47
47
  function isObject(option) {
48
48
  return !!option && typeof option === 'object' && !isArray(option);
49
49
  }
50
+ function isScope($scope) {
51
+ return !!$scope && ($scope instanceof Element || $scope instanceof Document);
52
+ }
50
53
  function formatErrorMessage(Component, message) {
51
54
  return `${Component.moduleName}: ${message}`;
52
55
  }
@@ -65,11 +68,14 @@ class SupportError extends GOVUKFrontendError {
65
68
  /**
66
69
  * Checks if GOV.UK Frontend is supported on this page
67
70
  *
68
- * @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support
71
+ * @param {Element | Document | null | string} [scopeOrMessage] - HTML element `<body>` checked for browser support or support error message
69
72
  */
70
- constructor($scope = document.body) {
71
- const supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
72
- super($scope ? supportMessage : 'GOV.UK Frontend initialised without `<script type="module">`');
73
+ constructor(scopeOrMessage = document.body) {
74
+ let supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
75
+ if (!isScope(scopeOrMessage)) {
76
+ supportMessage = 'GOV.UK Frontend initialised without `<script type="module">`';
77
+ }
78
+ super(typeof scopeOrMessage === 'string' ? scopeOrMessage : supportMessage);
73
79
  this.name = 'SupportError';
74
80
  }
75
81
  }
@@ -110,6 +116,7 @@ class InitError extends GOVUKFrontendError {
110
116
  * @import { ComponentWithModuleName } from '../common/index.mjs'
111
117
  */
112
118
 
119
+ const _self = typeof globalThis !== 'undefined' ? globalThis : self;
113
120
  class Component {
114
121
  /**
115
122
  * Returns the root element of the component
@@ -163,7 +170,7 @@ class Component {
163
170
  /**
164
171
  * @typedef {typeof Component & ChildClass} ChildClassConstructor
165
172
  */
166
- Component.elementType = HTMLElement;
173
+ Component.elementType = _self.HTMLElement;
167
174
 
168
175
  const configOverride = Symbol.for('configOverride');
169
176
  class ConfigurableComponent extends Component {
@@ -188,10 +195,14 @@ class ConfigurableComponent extends Component {
188
195
  throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));
189
196
  }
190
197
  const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);
191
- this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}, this[configOverride](datasetConfig), datasetConfig);
198
+ this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {});
199
+ this._config = mergeConfigs(this._config, this[configOverride](datasetConfig), datasetConfig);
192
200
  }
193
201
  }
194
202
  function normaliseString(value, property) {
203
+ if (property != null && property.type && !['string', 'number', 'boolean'].includes(property.type)) {
204
+ return;
205
+ }
195
206
  const trimmedValue = value ? value.trim() : '';
196
207
  let output;
197
208
  let outputType = property == null ? void 0 : property.type;
@@ -34,6 +34,9 @@
34
34
  function isObject(option) {
35
35
  return !!option && typeof option === 'object' && !isArray(option);
36
36
  }
37
+ function isScope($scope) {
38
+ return !!$scope && ($scope instanceof Element || $scope instanceof Document);
39
+ }
37
40
  function formatErrorMessage(Component, message) {
38
41
  return `${Component.moduleName}: ${message}`;
39
42
  }
@@ -52,11 +55,14 @@
52
55
  /**
53
56
  * Checks if GOV.UK Frontend is supported on this page
54
57
  *
55
- * @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support
58
+ * @param {Element | Document | null | string} [scopeOrMessage] - HTML element `<body>` checked for browser support or support error message
56
59
  */
57
- constructor($scope = document.body) {
58
- const supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
59
- super($scope ? supportMessage : 'GOV.UK Frontend initialised without `<script type="module">`');
60
+ constructor(scopeOrMessage = document.body) {
61
+ let supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
62
+ if (!isScope(scopeOrMessage)) {
63
+ supportMessage = 'GOV.UK Frontend initialised without `<script type="module">`';
64
+ }
65
+ super(typeof scopeOrMessage === 'string' ? scopeOrMessage : supportMessage);
60
66
  this.name = 'SupportError';
61
67
  }
62
68
  }
@@ -97,6 +103,7 @@
97
103
  * @import { ComponentWithModuleName } from '../common/index.mjs'
98
104
  */
99
105
 
106
+ const _self = typeof globalThis !== 'undefined' ? globalThis : self;
100
107
  class Component {
101
108
  /**
102
109
  * Returns the root element of the component
@@ -150,7 +157,7 @@
150
157
  /**
151
158
  * @typedef {typeof Component & ChildClass} ChildClassConstructor
152
159
  */
153
- Component.elementType = HTMLElement;
160
+ Component.elementType = _self.HTMLElement;
154
161
 
155
162
  const configOverride = Symbol.for('configOverride');
156
163
  class ConfigurableComponent extends Component {
@@ -175,10 +182,14 @@
175
182
  throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));
176
183
  }
177
184
  const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);
178
- this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}, this[configOverride](datasetConfig), datasetConfig);
185
+ this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {});
186
+ this._config = mergeConfigs(this._config, this[configOverride](datasetConfig), datasetConfig);
179
187
  }
180
188
  }
181
189
  function normaliseString(value, property) {
190
+ if (property != null && property.type && !['string', 'number', 'boolean'].includes(property.type)) {
191
+ return;
192
+ }
182
193
  const trimmedValue = value ? value.trim() : '';
183
194
  let output;
184
195
  let outputType = property == null ? void 0 : property.type;
@@ -298,6 +309,17 @@
298
309
  * @import { CompatibleClass, Config, CreateAllOptions, OnErrorCallback } from '../init.mjs'
299
310
  */
300
311
 
312
+ function createElement(tagName, attributes = {}, children = []) {
313
+ const $element = document.createElement(tagName);
314
+ Object.entries(attributes).forEach(([name, value]) => {
315
+ $element.setAttribute(name, value);
316
+ });
317
+ for (const child of children) {
318
+ $element.append(child);
319
+ }
320
+ return $element;
321
+ }
322
+
301
323
  class I18n {
302
324
  constructor(translations = {}, config = {}) {
303
325
  var _config$locale;
@@ -413,9 +435,10 @@
413
435
  locale: closestAttributeValue(this.$root, 'lang')
414
436
  });
415
437
  this.$showHideButton.removeAttribute('hidden');
416
- const $screenReaderStatusMessage = document.createElement('div');
417
- $screenReaderStatusMessage.className = 'govuk-password-input__sr-status govuk-visually-hidden';
418
- $screenReaderStatusMessage.setAttribute('aria-live', 'polite');
438
+ const $screenReaderStatusMessage = createElement('div', {
439
+ class: 'govuk-password-input__sr-status govuk-visually-hidden',
440
+ 'aria-live': 'polite'
441
+ });
419
442
  this.$screenReaderStatusMessage = $screenReaderStatusMessage;
420
443
  this.$input.insertAdjacentElement('afterend', $screenReaderStatusMessage);
421
444
  this.$showHideButton.addEventListener('click', this.toggle.bind(this));
@@ -28,6 +28,9 @@ function isArray(option) {
28
28
  function isObject(option) {
29
29
  return !!option && typeof option === 'object' && !isArray(option);
30
30
  }
31
+ function isScope($scope) {
32
+ return !!$scope && ($scope instanceof Element || $scope instanceof Document);
33
+ }
31
34
  function formatErrorMessage(Component, message) {
32
35
  return `${Component.moduleName}: ${message}`;
33
36
  }
@@ -46,11 +49,14 @@ class SupportError extends GOVUKFrontendError {
46
49
  /**
47
50
  * Checks if GOV.UK Frontend is supported on this page
48
51
  *
49
- * @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support
52
+ * @param {Element | Document | null | string} [scopeOrMessage] - HTML element `<body>` checked for browser support or support error message
50
53
  */
51
- constructor($scope = document.body) {
52
- const supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
53
- super($scope ? supportMessage : 'GOV.UK Frontend initialised without `<script type="module">`');
54
+ constructor(scopeOrMessage = document.body) {
55
+ let supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
56
+ if (!isScope(scopeOrMessage)) {
57
+ supportMessage = 'GOV.UK Frontend initialised without `<script type="module">`';
58
+ }
59
+ super(typeof scopeOrMessage === 'string' ? scopeOrMessage : supportMessage);
54
60
  this.name = 'SupportError';
55
61
  }
56
62
  }
@@ -91,6 +97,7 @@ class InitError extends GOVUKFrontendError {
91
97
  * @import { ComponentWithModuleName } from '../common/index.mjs'
92
98
  */
93
99
 
100
+ const _self = typeof globalThis !== 'undefined' ? globalThis : self;
94
101
  class Component {
95
102
  /**
96
103
  * Returns the root element of the component
@@ -144,7 +151,7 @@ class Component {
144
151
  /**
145
152
  * @typedef {typeof Component & ChildClass} ChildClassConstructor
146
153
  */
147
- Component.elementType = HTMLElement;
154
+ Component.elementType = _self.HTMLElement;
148
155
 
149
156
  const configOverride = Symbol.for('configOverride');
150
157
  class ConfigurableComponent extends Component {
@@ -169,10 +176,14 @@ class ConfigurableComponent extends Component {
169
176
  throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));
170
177
  }
171
178
  const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);
172
- this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}, this[configOverride](datasetConfig), datasetConfig);
179
+ this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {});
180
+ this._config = mergeConfigs(this._config, this[configOverride](datasetConfig), datasetConfig);
173
181
  }
174
182
  }
175
183
  function normaliseString(value, property) {
184
+ if (property != null && property.type && !['string', 'number', 'boolean'].includes(property.type)) {
185
+ return;
186
+ }
176
187
  const trimmedValue = value ? value.trim() : '';
177
188
  let output;
178
189
  let outputType = property == null ? void 0 : property.type;
@@ -292,6 +303,17 @@ function extractConfigByNamespace(schema, dataset, namespace) {
292
303
  * @import { CompatibleClass, Config, CreateAllOptions, OnErrorCallback } from '../init.mjs'
293
304
  */
294
305
 
306
+ function createElement(tagName, attributes = {}, children = []) {
307
+ const $element = document.createElement(tagName);
308
+ Object.entries(attributes).forEach(([name, value]) => {
309
+ $element.setAttribute(name, value);
310
+ });
311
+ for (const child of children) {
312
+ $element.append(child);
313
+ }
314
+ return $element;
315
+ }
316
+
295
317
  class I18n {
296
318
  constructor(translations = {}, config = {}) {
297
319
  var _config$locale;
@@ -407,9 +429,10 @@ class PasswordInput extends ConfigurableComponent {
407
429
  locale: closestAttributeValue(this.$root, 'lang')
408
430
  });
409
431
  this.$showHideButton.removeAttribute('hidden');
410
- const $screenReaderStatusMessage = document.createElement('div');
411
- $screenReaderStatusMessage.className = 'govuk-password-input__sr-status govuk-visually-hidden';
412
- $screenReaderStatusMessage.setAttribute('aria-live', 'polite');
432
+ const $screenReaderStatusMessage = createElement('div', {
433
+ class: 'govuk-password-input__sr-status govuk-visually-hidden',
434
+ 'aria-live': 'polite'
435
+ });
413
436
  this.$screenReaderStatusMessage = $screenReaderStatusMessage;
414
437
  this.$input.insertAdjacentElement('afterend', $screenReaderStatusMessage);
415
438
  this.$showHideButton.addEventListener('click', this.toggle.bind(this));