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
@@ -29,6 +29,9 @@
29
29
  function isObject(option) {
30
30
  return !!option && typeof option === 'object' && !isArray(option);
31
31
  }
32
+ function isScope($scope) {
33
+ return !!$scope && ($scope instanceof Element || $scope instanceof Document);
34
+ }
32
35
  function formatErrorMessage(Component, message) {
33
36
  return `${Component.moduleName}: ${message}`;
34
37
  }
@@ -47,11 +50,14 @@
47
50
  /**
48
51
  * Checks if GOV.UK Frontend is supported on this page
49
52
  *
50
- * @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support
53
+ * @param {Element | Document | null | string} [scopeOrMessage] - HTML element `<body>` checked for browser support or support error message
51
54
  */
52
- constructor($scope = document.body) {
53
- 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';
54
- super($scope ? supportMessage : 'GOV.UK Frontend initialised without `<script type="module">`');
55
+ constructor(scopeOrMessage = document.body) {
56
+ 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';
57
+ if (!isScope(scopeOrMessage)) {
58
+ supportMessage = 'GOV.UK Frontend initialised without `<script type="module">`';
59
+ }
60
+ super(typeof scopeOrMessage === 'string' ? scopeOrMessage : supportMessage);
55
61
  this.name = 'SupportError';
56
62
  }
57
63
  }
@@ -92,6 +98,7 @@
92
98
  * @import { ComponentWithModuleName } from '../common/index.mjs'
93
99
  */
94
100
 
101
+ const _self = typeof globalThis !== 'undefined' ? globalThis : self;
95
102
  class Component {
96
103
  /**
97
104
  * Returns the root element of the component
@@ -145,7 +152,7 @@
145
152
  /**
146
153
  * @typedef {typeof Component & ChildClass} ChildClassConstructor
147
154
  */
148
- Component.elementType = HTMLElement;
155
+ Component.elementType = _self.HTMLElement;
149
156
 
150
157
  const configOverride = Symbol.for('configOverride');
151
158
  class ConfigurableComponent extends Component {
@@ -170,10 +177,14 @@
170
177
  throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));
171
178
  }
172
179
  const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);
173
- this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}, this[configOverride](datasetConfig), datasetConfig);
180
+ this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {});
181
+ this._config = mergeConfigs(this._config, this[configOverride](datasetConfig), datasetConfig);
174
182
  }
175
183
  }
176
184
  function normaliseString(value, property) {
185
+ if (property != null && property.type && !['string', 'number', 'boolean'].includes(property.type)) {
186
+ return;
187
+ }
177
188
  const trimmedValue = value ? value.trim() : '';
178
189
  let output;
179
190
  let outputType = property == null ? void 0 : property.type;
@@ -293,6 +304,17 @@
293
304
  * @import { CompatibleClass, Config, CreateAllOptions, OnErrorCallback } from '../init.mjs'
294
305
  */
295
306
 
307
+ function createElement(tagName, attributes = {}, children = []) {
308
+ const $element = document.createElement(tagName);
309
+ Object.entries(attributes).forEach(([name, value]) => {
310
+ $element.setAttribute(name, value);
311
+ });
312
+ for (const child of children) {
313
+ $element.append(child);
314
+ }
315
+ return $element;
316
+ }
317
+
296
318
  class I18n {
297
319
  constructor(translations = {}, config = {}) {
298
320
  var _config$locale;
@@ -410,9 +432,10 @@
410
432
  window.addEventListener('pageshow', this.resetPage.bind(this));
411
433
  }
412
434
  initUpdateSpan() {
413
- this.$updateSpan = document.createElement('span');
414
- this.$updateSpan.setAttribute('role', 'status');
415
- this.$updateSpan.className = 'govuk-visually-hidden';
435
+ this.$updateSpan = createElement('span', {
436
+ role: 'status',
437
+ class: 'govuk-visually-hidden'
438
+ });
416
439
  this.$root.appendChild(this.$updateSpan);
417
440
  }
418
441
  initButtonClickHandler() {
@@ -422,13 +445,14 @@
422
445
  }
423
446
  }
424
447
  buildIndicator() {
425
- this.$indicatorContainer = document.createElement('div');
426
- this.$indicatorContainer.className = 'govuk-exit-this-page__indicator';
427
- this.$indicatorContainer.setAttribute('aria-hidden', 'true');
448
+ this.$indicatorContainer = createElement('div', {
449
+ class: 'govuk-exit-this-page__indicator',
450
+ 'aria-hidden': 'true'
451
+ });
428
452
  for (let i = 0; i < 3; i++) {
429
- const $indicator = document.createElement('div');
430
- $indicator.className = 'govuk-exit-this-page__indicator-light';
431
- this.$indicatorContainer.appendChild($indicator);
453
+ this.$indicatorContainer.appendChild(createElement('div', {
454
+ class: 'govuk-exit-this-page__indicator-light'
455
+ }));
432
456
  }
433
457
  this.$button.appendChild(this.$indicatorContainer);
434
458
  }
@@ -448,9 +472,10 @@
448
472
  }
449
473
  this.$updateSpan.textContent = '';
450
474
  document.body.classList.add('govuk-exit-this-page-hide-content');
451
- this.$overlay = document.createElement('div');
452
- this.$overlay.className = 'govuk-exit-this-page-overlay';
453
- this.$overlay.setAttribute('role', 'alert');
475
+ this.$overlay = createElement('div', {
476
+ class: 'govuk-exit-this-page-overlay',
477
+ role: 'alert'
478
+ });
454
479
  document.body.appendChild(this.$overlay);
455
480
  this.$overlay.textContent = this.i18n.t('activated');
456
481
  window.location.href = this.$button.href;
@@ -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
  }
@@ -41,11 +44,14 @@ class SupportError extends GOVUKFrontendError {
41
44
  /**
42
45
  * Checks if GOV.UK Frontend is supported on this page
43
46
  *
44
- * @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support
47
+ * @param {Element | Document | null | string} [scopeOrMessage] - HTML element `<body>` checked for browser support or support error message
45
48
  */
46
- constructor($scope = document.body) {
47
- 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';
48
- super($scope ? supportMessage : 'GOV.UK Frontend initialised without `<script type="module">`');
49
+ constructor(scopeOrMessage = document.body) {
50
+ 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';
51
+ if (!isScope(scopeOrMessage)) {
52
+ supportMessage = 'GOV.UK Frontend initialised without `<script type="module">`';
53
+ }
54
+ super(typeof scopeOrMessage === 'string' ? scopeOrMessage : supportMessage);
49
55
  this.name = 'SupportError';
50
56
  }
51
57
  }
@@ -86,6 +92,7 @@ class InitError extends GOVUKFrontendError {
86
92
  * @import { ComponentWithModuleName } from '../common/index.mjs'
87
93
  */
88
94
 
95
+ const _self = typeof globalThis !== 'undefined' ? globalThis : self;
89
96
  class Component {
90
97
  /**
91
98
  * Returns the root element of the component
@@ -139,7 +146,7 @@ class Component {
139
146
  /**
140
147
  * @typedef {typeof Component & ChildClass} ChildClassConstructor
141
148
  */
142
- Component.elementType = HTMLElement;
149
+ Component.elementType = _self.HTMLElement;
143
150
 
144
151
  const configOverride = Symbol.for('configOverride');
145
152
  class ConfigurableComponent extends Component {
@@ -164,10 +171,14 @@ class ConfigurableComponent extends Component {
164
171
  throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));
165
172
  }
166
173
  const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);
167
- this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}, this[configOverride](datasetConfig), datasetConfig);
174
+ this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {});
175
+ this._config = mergeConfigs(this._config, this[configOverride](datasetConfig), datasetConfig);
168
176
  }
169
177
  }
170
178
  function normaliseString(value, property) {
179
+ if (property != null && property.type && !['string', 'number', 'boolean'].includes(property.type)) {
180
+ return;
181
+ }
171
182
  const trimmedValue = value ? value.trim() : '';
172
183
  let output;
173
184
  let outputType = property == null ? void 0 : property.type;
@@ -287,6 +298,17 @@ function extractConfigByNamespace(schema, dataset, namespace) {
287
298
  * @import { CompatibleClass, Config, CreateAllOptions, OnErrorCallback } from '../init.mjs'
288
299
  */
289
300
 
301
+ function createElement(tagName, attributes = {}, children = []) {
302
+ const $element = document.createElement(tagName);
303
+ Object.entries(attributes).forEach(([name, value]) => {
304
+ $element.setAttribute(name, value);
305
+ });
306
+ for (const child of children) {
307
+ $element.append(child);
308
+ }
309
+ return $element;
310
+ }
311
+
290
312
  class I18n {
291
313
  constructor(translations = {}, config = {}) {
292
314
  var _config$locale;
@@ -404,9 +426,10 @@ class ExitThisPage extends ConfigurableComponent {
404
426
  window.addEventListener('pageshow', this.resetPage.bind(this));
405
427
  }
406
428
  initUpdateSpan() {
407
- this.$updateSpan = document.createElement('span');
408
- this.$updateSpan.setAttribute('role', 'status');
409
- this.$updateSpan.className = 'govuk-visually-hidden';
429
+ this.$updateSpan = createElement('span', {
430
+ role: 'status',
431
+ class: 'govuk-visually-hidden'
432
+ });
410
433
  this.$root.appendChild(this.$updateSpan);
411
434
  }
412
435
  initButtonClickHandler() {
@@ -416,13 +439,14 @@ class ExitThisPage extends ConfigurableComponent {
416
439
  }
417
440
  }
418
441
  buildIndicator() {
419
- this.$indicatorContainer = document.createElement('div');
420
- this.$indicatorContainer.className = 'govuk-exit-this-page__indicator';
421
- this.$indicatorContainer.setAttribute('aria-hidden', 'true');
442
+ this.$indicatorContainer = createElement('div', {
443
+ class: 'govuk-exit-this-page__indicator',
444
+ 'aria-hidden': 'true'
445
+ });
422
446
  for (let i = 0; i < 3; i++) {
423
- const $indicator = document.createElement('div');
424
- $indicator.className = 'govuk-exit-this-page__indicator-light';
425
- this.$indicatorContainer.appendChild($indicator);
447
+ this.$indicatorContainer.appendChild(createElement('div', {
448
+ class: 'govuk-exit-this-page__indicator-light'
449
+ }));
426
450
  }
427
451
  this.$button.appendChild(this.$indicatorContainer);
428
452
  }
@@ -442,9 +466,10 @@ class ExitThisPage extends ConfigurableComponent {
442
466
  }
443
467
  this.$updateSpan.textContent = '';
444
468
  document.body.classList.add('govuk-exit-this-page-hide-content');
445
- this.$overlay = document.createElement('div');
446
- this.$overlay.className = 'govuk-exit-this-page-overlay';
447
- this.$overlay.setAttribute('role', 'alert');
469
+ this.$overlay = createElement('div', {
470
+ class: 'govuk-exit-this-page-overlay',
471
+ role: 'alert'
472
+ });
448
473
  document.body.appendChild(this.$overlay);
449
474
  this.$overlay.textContent = this.i18n.t('activated');
450
475
  window.location.href = this.$button.href;
@@ -1,4 +1,5 @@
1
1
  import { ConfigurableComponent } from '../../common/configuration.mjs';
2
+ import { createElement } from '../../common/create-element.mjs';
2
3
  import { ElementError } from '../../errors/index.mjs';
3
4
  import { I18n } from '../../i18n.mjs';
4
5
 
@@ -51,9 +52,10 @@ class ExitThisPage extends ConfigurableComponent {
51
52
  window.addEventListener('pageshow', this.resetPage.bind(this));
52
53
  }
53
54
  initUpdateSpan() {
54
- this.$updateSpan = document.createElement('span');
55
- this.$updateSpan.setAttribute('role', 'status');
56
- this.$updateSpan.className = 'govuk-visually-hidden';
55
+ this.$updateSpan = createElement('span', {
56
+ role: 'status',
57
+ class: 'govuk-visually-hidden'
58
+ });
57
59
  this.$root.appendChild(this.$updateSpan);
58
60
  }
59
61
  initButtonClickHandler() {
@@ -63,13 +65,14 @@ class ExitThisPage extends ConfigurableComponent {
63
65
  }
64
66
  }
65
67
  buildIndicator() {
66
- this.$indicatorContainer = document.createElement('div');
67
- this.$indicatorContainer.className = 'govuk-exit-this-page__indicator';
68
- this.$indicatorContainer.setAttribute('aria-hidden', 'true');
68
+ this.$indicatorContainer = createElement('div', {
69
+ class: 'govuk-exit-this-page__indicator',
70
+ 'aria-hidden': 'true'
71
+ });
69
72
  for (let i = 0; i < 3; i++) {
70
- const $indicator = document.createElement('div');
71
- $indicator.className = 'govuk-exit-this-page__indicator-light';
72
- this.$indicatorContainer.appendChild($indicator);
73
+ this.$indicatorContainer.appendChild(createElement('div', {
74
+ class: 'govuk-exit-this-page__indicator-light'
75
+ }));
73
76
  }
74
77
  this.$button.appendChild(this.$indicatorContainer);
75
78
  }
@@ -89,9 +92,10 @@ class ExitThisPage extends ConfigurableComponent {
89
92
  }
90
93
  this.$updateSpan.textContent = '';
91
94
  document.body.classList.add('govuk-exit-this-page-hide-content');
92
- this.$overlay = document.createElement('div');
93
- this.$overlay.className = 'govuk-exit-this-page-overlay';
94
- this.$overlay.setAttribute('role', 'alert');
95
+ this.$overlay = createElement('div', {
96
+ class: 'govuk-exit-this-page-overlay',
97
+ role: 'alert'
98
+ });
95
99
  document.body.appendChild(this.$overlay);
96
100
  this.$overlay.textContent = this.i18n.t('activated');
97
101
  window.location.href = this.$button.href;
@@ -0,0 +1,6 @@
1
+ @use "../../settings/warnings--internal";
2
+
3
+ @include warnings--internal.component-scss-file-warning("feedback");
4
+
5
+ @import "index";
6
+
@@ -0,0 +1,8 @@
1
+ @use "mixin";
2
+
3
+ @import "../../base";
4
+
5
+ @include govuk-exports("govuk/component/feedback") {
6
+ @include mixin.styles;
7
+ }
8
+
@@ -0,0 +1,5 @@
1
+ @use "../../custom-properties";
2
+ @use "mixin";
3
+
4
+ @include mixin.styles;
5
+
@@ -0,0 +1,48 @@
1
+ @use "../../base";
2
+
3
+ /// @access private
4
+ @mixin styles {
5
+ .govuk-feedback {
6
+ box-sizing: border-box;
7
+ // Tie left/right padding to page gutter as it stretches across the whole
8
+ // screen on smaller screens
9
+ padding: base.govuk-spacing(4) base.$govuk-gutter-half base.govuk-spacing(5);
10
+ border-top: 1px solid;
11
+ border-color: base.govuk-functional-colour("brand");
12
+ background-color: base.govuk-functional-colour("surface-background");
13
+
14
+ @media #{base.govuk-from-breakpoint(tablet)} {
15
+ padding-right: base.govuk-spacing(4);
16
+ padding-left: base.govuk-spacing(4);
17
+ }
18
+
19
+ // Override $govuk-width-container's left and right margin as we want Feedback
20
+ // to go across the whole screen on smaller screens
21
+ @media #{base.govuk-until-breakpoint(tablet)} {
22
+ margin-right: 0;
23
+ margin-left: 0;
24
+ }
25
+
26
+ @media print {
27
+ border-color: currentcolor;
28
+ background-color: transparent;
29
+ }
30
+ }
31
+
32
+ .govuk-feedback__title {
33
+ @include base.govuk-font($size: 24, $weight: bold);
34
+ margin-top: 0;
35
+ color: base.govuk-functional-colour(text);
36
+ @include base.govuk-responsive-margin(1, "bottom");
37
+ }
38
+
39
+ // Removes the bottom margin from the final child element eg: a paragraph
40
+ //
41
+ // Feedback body doesn't have any opinions about typography. Instead we defer
42
+ // to users to use typography classes in their input, or apply a `govuk-body`
43
+ // paragraph for if users pass `text`.
44
+ .govuk-feedback__body > :last-child {
45
+ margin-bottom: 0;
46
+ }
47
+ }
48
+
@@ -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;
@@ -418,46 +440,48 @@
418
440
  this.$input.addEventListener('change', this.onChange.bind(this));
419
441
  this.updateDisabledState();
420
442
  this.observeDisabledState();
421
- this.$announcements = document.createElement('span');
422
- this.$announcements.classList.add('govuk-file-upload-announcements');
423
- this.$announcements.classList.add('govuk-visually-hidden');
424
- this.$announcements.setAttribute('aria-live', 'assertive');
443
+ this.$announcements = createElement('span', {
444
+ class: 'govuk-file-upload-announcements govuk-visually-hidden',
445
+ 'aria-live': 'assertive'
446
+ });
425
447
  this.$root.insertAdjacentElement('afterend', this.$announcements);
426
448
  this.bindDraggingEvents();
427
449
  }
428
450
  createStatus() {
429
- const $status = document.createElement('span');
430
- $status.className = 'govuk-body govuk-file-upload-button__status';
431
- $status.setAttribute('aria-live', 'polite');
451
+ const $status = createElement('span', {
452
+ class: 'govuk-body govuk-file-upload-button__status',
453
+ 'aria-live': 'polite'
454
+ });
432
455
  $status.innerText = this.i18n.t('noFileChosen');
433
456
  return $status;
434
457
  }
435
458
  createButton() {
436
- const $button = document.createElement('button');
437
- $button.classList.add('govuk-file-upload-button');
438
- $button.type = 'button';
439
- $button.id = this.id;
440
- $button.classList.add('govuk-file-upload-button--empty');
459
+ const $button = createElement('button', {
460
+ class: 'govuk-file-upload-button govuk-file-upload-button--empty',
461
+ type: 'button',
462
+ id: this.id
463
+ });
441
464
  const ariaDescribedBy = this.$input.getAttribute('aria-describedby');
442
465
  if (ariaDescribedBy) {
443
466
  $button.setAttribute('aria-describedby', ariaDescribedBy);
444
467
  }
445
468
  $button.appendChild(this.$status);
446
- const commaSpan = document.createElement('span');
447
- commaSpan.className = 'govuk-visually-hidden';
448
- commaSpan.innerText = ', ';
449
- commaSpan.id = `${this.id}-comma`;
469
+ const commaSpan = createElement('span', {
470
+ class: 'govuk-visually-hidden',
471
+ id: `${this.id}-comma`
472
+ }, [', ']);
450
473
  $button.appendChild(commaSpan);
451
- const containerSpan = document.createElement('span');
452
- containerSpan.className = 'govuk-file-upload-button__pseudo-button-container';
453
- const buttonSpan = document.createElement('span');
454
- buttonSpan.className = 'govuk-button govuk-button--secondary govuk-file-upload-button__pseudo-button';
455
- buttonSpan.innerText = this.i18n.t('chooseFilesButton');
474
+ const containerSpan = createElement('span', {
475
+ class: 'govuk-file-upload-button__pseudo-button-container'
476
+ });
477
+ const buttonSpan = createElement('span', {
478
+ class: 'govuk-button govuk-button--secondary govuk-file-upload-button__pseudo-button'
479
+ }, [this.i18n.t('chooseFilesButton')]);
456
480
  containerSpan.appendChild(buttonSpan);
457
481
  containerSpan.insertAdjacentText('beforeend', ' ');
458
- const instructionSpan = document.createElement('span');
459
- instructionSpan.className = 'govuk-body govuk-file-upload-button__instruction';
460
- instructionSpan.innerText = this.i18n.t('dropInstruction');
482
+ const instructionSpan = createElement('span', {
483
+ class: 'govuk-body govuk-file-upload-button__instruction'
484
+ }, [this.i18n.t('dropInstruction')]);
461
485
  containerSpan.appendChild(instructionSpan);
462
486
  $button.appendChild(containerSpan);
463
487
  $button.setAttribute('aria-labelledby', `${this.$label.id} ${commaSpan.id} ${$button.id}`);