govuk_publishing_components 55.0.1 → 55.1.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 (167) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/govuk_publishing_components/components/file-upload.js +5 -0
  3. data/app/assets/stylesheets/govuk_publishing_components/components/_layout-super-navigation-header.scss +1 -0
  4. data/app/assets/stylesheets/govuk_publishing_components/components/_organisation-logo.scss +5 -2
  5. data/app/views/govuk_publishing_components/components/_file_upload.html.erb +13 -1
  6. data/app/views/govuk_publishing_components/components/_layout_super_navigation_header.html.erb +0 -1
  7. data/app/views/govuk_publishing_components/components/docs/file_upload.yml +6 -0
  8. data/app/views/govuk_publishing_components/components/feedback/_survey_signup_form.html.erb +1 -1
  9. data/lib/govuk_publishing_components/version.rb +1 -1
  10. data/node_modules/govuk-frontend/dist/govuk/all.bundle.js +313 -47
  11. data/node_modules/govuk-frontend/dist/govuk/all.bundle.js.map +1 -1
  12. data/node_modules/govuk-frontend/dist/govuk/all.bundle.mjs +312 -47
  13. data/node_modules/govuk-frontend/dist/govuk/all.bundle.mjs.map +1 -1
  14. data/node_modules/govuk-frontend/dist/govuk/all.mjs +2 -1
  15. data/node_modules/govuk-frontend/dist/govuk/all.mjs.map +1 -1
  16. data/node_modules/govuk-frontend/dist/govuk/common/configuration.mjs +21 -16
  17. data/node_modules/govuk-frontend/dist/govuk/common/configuration.mjs.map +1 -1
  18. data/node_modules/govuk-frontend/dist/govuk/common/govuk-frontend-version.mjs +1 -1
  19. data/node_modules/govuk-frontend/dist/govuk/common/index.mjs +3 -0
  20. data/node_modules/govuk-frontend/dist/govuk/common/index.mjs.map +1 -1
  21. data/node_modules/govuk-frontend/dist/govuk/{govuk-frontend-component.mjs → component.mjs} +5 -5
  22. data/node_modules/govuk-frontend/dist/govuk/component.mjs.map +1 -0
  23. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js +27 -19
  24. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js.map +1 -1
  25. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs +27 -19
  26. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs.map +1 -1
  27. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.mjs +1 -1
  28. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.mjs.map +1 -1
  29. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.js +27 -19
  30. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.js.map +1 -1
  31. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.mjs +27 -19
  32. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.mjs.map +1 -1
  33. data/node_modules/govuk-frontend/dist/govuk/components/button/button.mjs +1 -1
  34. data/node_modules/govuk-frontend/dist/govuk/components/button/button.mjs.map +1 -1
  35. data/node_modules/govuk-frontend/dist/govuk/components/button/macro-options.json +2 -1
  36. data/node_modules/govuk-frontend/dist/govuk/components/character-count/_index.scss +8 -0
  37. data/node_modules/govuk-frontend/dist/govuk/components/character-count/_index.scss.map +1 -1
  38. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js +28 -20
  39. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js.map +1 -1
  40. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs +28 -20
  41. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs.map +1 -1
  42. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.mjs +2 -2
  43. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.mjs.map +1 -1
  44. data/node_modules/govuk-frontend/dist/govuk/components/character-count/fixtures.json +16 -1
  45. data/node_modules/govuk-frontend/dist/govuk/components/character-count/macro-options.json +2 -2
  46. data/node_modules/govuk-frontend/dist/govuk/components/character-count/template.njk +5 -4
  47. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js +8 -5
  48. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js.map +1 -1
  49. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs +8 -5
  50. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs.map +1 -1
  51. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.mjs +2 -2
  52. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.mjs.map +1 -1
  53. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js +27 -19
  54. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js.map +1 -1
  55. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs +27 -19
  56. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs.map +1 -1
  57. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs +1 -1
  58. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs.map +1 -1
  59. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js +27 -19
  60. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js.map +1 -1
  61. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs +27 -19
  62. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs.map +1 -1
  63. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs +1 -1
  64. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs.map +1 -1
  65. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/_index.scss +167 -0
  66. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/_index.scss.map +1 -1
  67. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.js +754 -0
  68. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.js.map +1 -0
  69. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.mjs +746 -0
  70. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.mjs.map +1 -0
  71. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.mjs +267 -0
  72. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.mjs.map +1 -0
  73. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/fixtures.json +207 -16
  74. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/macro-options.json +52 -3
  75. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template-allows-direct-media-capture.html +6 -0
  76. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template-allows-image-files-only.html +6 -0
  77. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template-allows-multiple-files.html +6 -0
  78. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template-disabled.html +6 -0
  79. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template-enhanced-disabled.html +13 -0
  80. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template-enhanced-with-error-message-and-hint.html +16 -0
  81. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template-enhanced.html +10 -0
  82. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template-translated.html +10 -0
  83. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template.njk +42 -5
  84. data/node_modules/govuk-frontend/dist/govuk/components/header/_index.scss +14 -10
  85. data/node_modules/govuk-frontend/dist/govuk/components/header/_index.scss.map +1 -1
  86. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.js +8 -5
  87. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.js.map +1 -1
  88. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.mjs +8 -5
  89. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.mjs.map +1 -1
  90. data/node_modules/govuk-frontend/dist/govuk/components/header/header.mjs +2 -2
  91. data/node_modules/govuk-frontend/dist/govuk/components/header/header.mjs.map +1 -1
  92. data/node_modules/govuk-frontend/dist/govuk/components/header/macro-options.json +25 -12
  93. data/node_modules/govuk-frontend/dist/govuk/components/input/fixtures.json +16 -2
  94. data/node_modules/govuk-frontend/dist/govuk/components/input/macro-options.json +2 -2
  95. data/node_modules/govuk-frontend/dist/govuk/components/input/template-default.html +2 -2
  96. data/node_modules/govuk-frontend/dist/govuk/components/input/template.njk +5 -4
  97. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js +27 -19
  98. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js.map +1 -1
  99. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs +27 -19
  100. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs.map +1 -1
  101. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs +1 -1
  102. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs.map +1 -1
  103. data/node_modules/govuk-frontend/dist/govuk/components/password-input/fixtures.json +16 -2
  104. data/node_modules/govuk-frontend/dist/govuk/components/password-input/macro-options.json +2 -2
  105. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js +27 -20
  106. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js.map +1 -1
  107. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs +27 -20
  108. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs.map +1 -1
  109. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.mjs +1 -2
  110. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.mjs.map +1 -1
  111. data/node_modules/govuk-frontend/dist/govuk/components/password-input/template-default.html +3 -3
  112. data/node_modules/govuk-frontend/dist/govuk/components/password-input/template.njk +4 -2
  113. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.js +8 -5
  114. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.js.map +1 -1
  115. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs +8 -5
  116. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs.map +1 -1
  117. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.mjs +2 -2
  118. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.mjs.map +1 -1
  119. data/node_modules/govuk-frontend/dist/govuk/components/select/fixtures.json +16 -1
  120. data/node_modules/govuk-frontend/dist/govuk/components/select/macro-options.json +2 -2
  121. data/node_modules/govuk-frontend/dist/govuk/components/select/template-id.html +7 -0
  122. data/node_modules/govuk-frontend/dist/govuk/components/select/template.njk +6 -4
  123. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js +8 -5
  124. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js.map +1 -1
  125. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs +8 -5
  126. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs.map +1 -1
  127. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.mjs +2 -2
  128. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.mjs.map +1 -1
  129. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js +9 -6
  130. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js.map +1 -1
  131. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs +9 -6
  132. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs.map +1 -1
  133. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs +3 -3
  134. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs.map +1 -1
  135. data/node_modules/govuk-frontend/dist/govuk/components/summary-list/_index.scss +12 -21
  136. data/node_modules/govuk-frontend/dist/govuk/components/summary-list/_index.scss.map +1 -1
  137. data/node_modules/govuk-frontend/dist/govuk/components/summary-list/fixtures.json +142 -0
  138. data/node_modules/govuk-frontend/dist/govuk/components/summary-list/template-as-a-summary-card-extreme.html +106 -0
  139. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js +8 -5
  140. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js.map +1 -1
  141. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs +8 -5
  142. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs.map +1 -1
  143. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.mjs +2 -2
  144. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.mjs.map +1 -1
  145. data/node_modules/govuk-frontend/dist/govuk/components/textarea/fixtures.json +15 -1
  146. data/node_modules/govuk-frontend/dist/govuk/components/textarea/macro-options.json +2 -2
  147. data/node_modules/govuk-frontend/dist/govuk/components/textarea/template.njk +6 -4
  148. data/node_modules/govuk-frontend/dist/govuk/core/_govuk-frontend-properties.scss +1 -1
  149. data/node_modules/govuk-frontend/dist/govuk/errors/index.mjs +1 -1
  150. data/node_modules/govuk-frontend/dist/govuk/errors/index.mjs.map +1 -1
  151. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.css +2 -2
  152. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.css.map +1 -1
  153. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.js +1 -1
  154. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.js.map +1 -1
  155. data/node_modules/govuk-frontend/dist/govuk/helpers/_colour.scss +2 -2
  156. data/node_modules/govuk-frontend/dist/govuk/helpers/_colour.scss.map +1 -1
  157. data/node_modules/govuk-frontend/dist/govuk/init.mjs +11 -11
  158. data/node_modules/govuk-frontend/dist/govuk/init.mjs.map +1 -1
  159. data/node_modules/govuk-frontend/dist/govuk/settings/_colours-organisations.scss +18 -5
  160. data/node_modules/govuk-frontend/dist/govuk/settings/_colours-organisations.scss.map +1 -1
  161. data/node_modules/govuk-frontend/dist/govuk-prototype-kit/init.scss +1 -1
  162. data/node_modules/govuk-frontend/dist/govuk-prototype-kit/init.scss.map +1 -1
  163. data/node_modules/govuk-frontend/govuk-prototype-kit.config.json +1 -1
  164. data/node_modules/govuk-frontend/package.json +7 -7
  165. metadata +21 -5
  166. data/node_modules/govuk-frontend/dist/govuk/components/file-upload/template-with-value.html +0 -6
  167. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend-component.mjs.map +0 -1
@@ -0,0 +1,754 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.GOVUKFrontend = global.GOVUKFrontend || {}));
5
+ })(this, (function (exports) { 'use strict';
6
+
7
+ function closestAttributeValue($element, attributeName) {
8
+ const $closestElementWithAttribute = $element.closest(`[${attributeName}]`);
9
+ return $closestElementWithAttribute ? $closestElementWithAttribute.getAttribute(attributeName) : null;
10
+ }
11
+
12
+ function isInitialised($root, moduleName) {
13
+ return $root instanceof HTMLElement && $root.hasAttribute(`data-${moduleName}-init`);
14
+ }
15
+
16
+ /**
17
+ * Checks if GOV.UK Frontend is supported on this page
18
+ *
19
+ * Some browsers will load and run our JavaScript but GOV.UK Frontend
20
+ * won't be supported.
21
+ *
22
+ * @param {HTMLElement | null} [$scope] - (internal) `<body>` HTML element checked for browser support
23
+ * @returns {boolean} Whether GOV.UK Frontend is supported on this page
24
+ */
25
+ function isSupported($scope = document.body) {
26
+ if (!$scope) {
27
+ return false;
28
+ }
29
+ return $scope.classList.contains('govuk-frontend-supported');
30
+ }
31
+ function isArray(option) {
32
+ return Array.isArray(option);
33
+ }
34
+ function isObject(option) {
35
+ return !!option && typeof option === 'object' && !isArray(option);
36
+ }
37
+ function formatErrorMessage(Component, message) {
38
+ return `${Component.moduleName}: ${message}`;
39
+ }
40
+ /**
41
+ * @typedef ComponentWithModuleName
42
+ * @property {string} moduleName - Name of the component
43
+ */
44
+ /**
45
+ * @import { ObjectNested } from './configuration.mjs'
46
+ */
47
+
48
+ class GOVUKFrontendError extends Error {
49
+ constructor(...args) {
50
+ super(...args);
51
+ this.name = 'GOVUKFrontendError';
52
+ }
53
+ }
54
+ class SupportError extends GOVUKFrontendError {
55
+ /**
56
+ * Checks if GOV.UK Frontend is supported on this page
57
+ *
58
+ * @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support
59
+ */
60
+ constructor($scope = document.body) {
61
+ 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';
62
+ super($scope ? supportMessage : 'GOV.UK Frontend initialised without `<script type="module">`');
63
+ this.name = 'SupportError';
64
+ }
65
+ }
66
+ class ConfigError extends GOVUKFrontendError {
67
+ constructor(...args) {
68
+ super(...args);
69
+ this.name = 'ConfigError';
70
+ }
71
+ }
72
+ class ElementError extends GOVUKFrontendError {
73
+ constructor(messageOrOptions) {
74
+ let message = typeof messageOrOptions === 'string' ? messageOrOptions : '';
75
+ if (typeof messageOrOptions === 'object') {
76
+ const {
77
+ component,
78
+ identifier,
79
+ element,
80
+ expectedType
81
+ } = messageOrOptions;
82
+ message = identifier;
83
+ message += element ? ` is not of type ${expectedType != null ? expectedType : 'HTMLElement'}` : ' not found';
84
+ message = formatErrorMessage(component, message);
85
+ }
86
+ super(message);
87
+ this.name = 'ElementError';
88
+ }
89
+ }
90
+ class InitError extends GOVUKFrontendError {
91
+ constructor(componentOrMessage) {
92
+ const message = typeof componentOrMessage === 'string' ? componentOrMessage : formatErrorMessage(componentOrMessage, `Root element (\`$root\`) already initialised`);
93
+ super(message);
94
+ this.name = 'InitError';
95
+ }
96
+ }
97
+ /**
98
+ * @import { ComponentWithModuleName } from '../common/index.mjs'
99
+ */
100
+
101
+ class Component {
102
+ /**
103
+ * Returns the root element of the component
104
+ *
105
+ * @protected
106
+ * @returns {RootElementType} - the root element of component
107
+ */
108
+ get $root() {
109
+ return this._$root;
110
+ }
111
+ constructor($root) {
112
+ this._$root = void 0;
113
+ const childConstructor = this.constructor;
114
+ if (typeof childConstructor.moduleName !== 'string') {
115
+ throw new InitError(`\`moduleName\` not defined in component`);
116
+ }
117
+ if (!($root instanceof childConstructor.elementType)) {
118
+ throw new ElementError({
119
+ element: $root,
120
+ component: childConstructor,
121
+ identifier: 'Root element (`$root`)',
122
+ expectedType: childConstructor.elementType.name
123
+ });
124
+ } else {
125
+ this._$root = $root;
126
+ }
127
+ childConstructor.checkSupport();
128
+ this.checkInitialised();
129
+ const moduleName = childConstructor.moduleName;
130
+ this.$root.setAttribute(`data-${moduleName}-init`, '');
131
+ }
132
+ checkInitialised() {
133
+ const constructor = this.constructor;
134
+ const moduleName = constructor.moduleName;
135
+ if (moduleName && isInitialised(this.$root, moduleName)) {
136
+ throw new InitError(constructor);
137
+ }
138
+ }
139
+ static checkSupport() {
140
+ if (!isSupported()) {
141
+ throw new SupportError();
142
+ }
143
+ }
144
+ }
145
+
146
+ /**
147
+ * @typedef ChildClass
148
+ * @property {string} moduleName - The module name that'll be looked for in the DOM when initialising the component
149
+ */
150
+
151
+ /**
152
+ * @typedef {typeof Component & ChildClass} ChildClassConstructor
153
+ */
154
+ Component.elementType = HTMLElement;
155
+
156
+ const configOverride = Symbol.for('configOverride');
157
+ class ConfigurableComponent extends Component {
158
+ [configOverride](param) {
159
+ return {};
160
+ }
161
+
162
+ /**
163
+ * Returns the root element of the component
164
+ *
165
+ * @protected
166
+ * @returns {ConfigurationType} - the root element of component
167
+ */
168
+ get config() {
169
+ return this._config;
170
+ }
171
+ constructor($root, config) {
172
+ super($root);
173
+ this._config = void 0;
174
+ const childConstructor = this.constructor;
175
+ if (!isObject(childConstructor.defaults)) {
176
+ throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));
177
+ }
178
+ const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);
179
+ this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}, this[configOverride](datasetConfig), datasetConfig);
180
+ }
181
+ }
182
+ function normaliseString(value, property) {
183
+ const trimmedValue = value ? value.trim() : '';
184
+ let output;
185
+ let outputType = property == null ? void 0 : property.type;
186
+ if (!outputType) {
187
+ if (['true', 'false'].includes(trimmedValue)) {
188
+ outputType = 'boolean';
189
+ }
190
+ if (trimmedValue.length > 0 && isFinite(Number(trimmedValue))) {
191
+ outputType = 'number';
192
+ }
193
+ }
194
+ switch (outputType) {
195
+ case 'boolean':
196
+ output = trimmedValue === 'true';
197
+ break;
198
+ case 'number':
199
+ output = Number(trimmedValue);
200
+ break;
201
+ default:
202
+ output = value;
203
+ }
204
+ return output;
205
+ }
206
+ function normaliseDataset(Component, dataset) {
207
+ if (!isObject(Component.schema)) {
208
+ throw new ConfigError(formatErrorMessage(Component, 'Config passed as parameter into constructor but no schema defined'));
209
+ }
210
+ const out = {};
211
+ const entries = Object.entries(Component.schema.properties);
212
+ for (const entry of entries) {
213
+ const [namespace, property] = entry;
214
+ const field = namespace.toString();
215
+ if (field in dataset) {
216
+ out[field] = normaliseString(dataset[field], property);
217
+ }
218
+ if ((property == null ? void 0 : property.type) === 'object') {
219
+ out[field] = extractConfigByNamespace(Component.schema, dataset, namespace);
220
+ }
221
+ }
222
+ return out;
223
+ }
224
+ function mergeConfigs(...configObjects) {
225
+ const formattedConfigObject = {};
226
+ for (const configObject of configObjects) {
227
+ for (const key of Object.keys(configObject)) {
228
+ const option = formattedConfigObject[key];
229
+ const override = configObject[key];
230
+ if (isObject(option) && isObject(override)) {
231
+ formattedConfigObject[key] = mergeConfigs(option, override);
232
+ } else {
233
+ formattedConfigObject[key] = override;
234
+ }
235
+ }
236
+ }
237
+ return formattedConfigObject;
238
+ }
239
+ function extractConfigByNamespace(schema, dataset, namespace) {
240
+ const property = schema.properties[namespace];
241
+ if ((property == null ? void 0 : property.type) !== 'object') {
242
+ return;
243
+ }
244
+ const newObject = {
245
+ [namespace]: {}
246
+ };
247
+ for (const [key, value] of Object.entries(dataset)) {
248
+ let current = newObject;
249
+ const keyParts = key.split('.');
250
+ for (const [index, name] of keyParts.entries()) {
251
+ if (isObject(current)) {
252
+ if (index < keyParts.length - 1) {
253
+ if (!isObject(current[name])) {
254
+ current[name] = {};
255
+ }
256
+ current = current[name];
257
+ } else if (key !== namespace) {
258
+ current[name] = normaliseString(value);
259
+ }
260
+ }
261
+ }
262
+ }
263
+ return newObject[namespace];
264
+ }
265
+ /**
266
+ * Schema for component config
267
+ *
268
+ * @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType
269
+ * @typedef {object} Schema
270
+ * @property {Record<keyof ConfigurationType, SchemaProperty | undefined>} properties - Schema properties
271
+ * @property {SchemaCondition<ConfigurationType>[]} [anyOf] - List of schema conditions
272
+ */
273
+ /**
274
+ * Schema property for component config
275
+ *
276
+ * @typedef {object} SchemaProperty
277
+ * @property {'string' | 'boolean' | 'number' | 'object'} type - Property type
278
+ */
279
+ /**
280
+ * Schema condition for component config
281
+ *
282
+ * @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType
283
+ * @typedef {object} SchemaCondition
284
+ * @property {(keyof ConfigurationType)[]} required - List of required config fields
285
+ * @property {string} errorMessage - Error message when required config fields not provided
286
+ */
287
+ /**
288
+ * @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]
289
+ * @typedef ChildClass
290
+ * @property {string} moduleName - The module name that'll be looked for in the DOM when initialising the component
291
+ * @property {Schema<ConfigurationType>} [schema] - The schema of the component configuration
292
+ * @property {ConfigurationType} [defaults] - The default values of the configuration of the component
293
+ */
294
+ /**
295
+ * @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]
296
+ * @typedef {typeof Component & ChildClass<ConfigurationType>} ChildClassConstructor<ConfigurationType>
297
+ */
298
+
299
+ class I18n {
300
+ constructor(translations = {}, config = {}) {
301
+ var _config$locale;
302
+ this.translations = void 0;
303
+ this.locale = void 0;
304
+ this.translations = translations;
305
+ this.locale = (_config$locale = config.locale) != null ? _config$locale : document.documentElement.lang || 'en';
306
+ }
307
+ t(lookupKey, options) {
308
+ if (!lookupKey) {
309
+ throw new Error('i18n: lookup key missing');
310
+ }
311
+ let translation = this.translations[lookupKey];
312
+ if (typeof (options == null ? void 0 : options.count) === 'number' && typeof translation === 'object') {
313
+ const translationPluralForm = translation[this.getPluralSuffix(lookupKey, options.count)];
314
+ if (translationPluralForm) {
315
+ translation = translationPluralForm;
316
+ }
317
+ }
318
+ if (typeof translation === 'string') {
319
+ if (translation.match(/%{(.\S+)}/)) {
320
+ if (!options) {
321
+ throw new Error('i18n: cannot replace placeholders in string if no option data provided');
322
+ }
323
+ return this.replacePlaceholders(translation, options);
324
+ }
325
+ return translation;
326
+ }
327
+ return lookupKey;
328
+ }
329
+ replacePlaceholders(translationString, options) {
330
+ const formatter = Intl.NumberFormat.supportedLocalesOf(this.locale).length ? new Intl.NumberFormat(this.locale) : undefined;
331
+ return translationString.replace(/%{(.\S+)}/g, function (placeholderWithBraces, placeholderKey) {
332
+ if (Object.prototype.hasOwnProperty.call(options, placeholderKey)) {
333
+ const placeholderValue = options[placeholderKey];
334
+ if (placeholderValue === false || typeof placeholderValue !== 'number' && typeof placeholderValue !== 'string') {
335
+ return '';
336
+ }
337
+ if (typeof placeholderValue === 'number') {
338
+ return formatter ? formatter.format(placeholderValue) : `${placeholderValue}`;
339
+ }
340
+ return placeholderValue;
341
+ }
342
+ throw new Error(`i18n: no data found to replace ${placeholderWithBraces} placeholder in string`);
343
+ });
344
+ }
345
+ hasIntlPluralRulesSupport() {
346
+ return Boolean('PluralRules' in window.Intl && Intl.PluralRules.supportedLocalesOf(this.locale).length);
347
+ }
348
+ getPluralSuffix(lookupKey, count) {
349
+ count = Number(count);
350
+ if (!isFinite(count)) {
351
+ return 'other';
352
+ }
353
+ const translation = this.translations[lookupKey];
354
+ const preferredForm = this.hasIntlPluralRulesSupport() ? new Intl.PluralRules(this.locale).select(count) : this.selectPluralFormUsingFallbackRules(count);
355
+ if (typeof translation === 'object') {
356
+ if (preferredForm in translation) {
357
+ return preferredForm;
358
+ } else if ('other' in translation) {
359
+ console.warn(`i18n: Missing plural form ".${preferredForm}" for "${this.locale}" locale. Falling back to ".other".`);
360
+ return 'other';
361
+ }
362
+ }
363
+ throw new Error(`i18n: Plural form ".other" is required for "${this.locale}" locale`);
364
+ }
365
+ selectPluralFormUsingFallbackRules(count) {
366
+ count = Math.abs(Math.floor(count));
367
+ const ruleset = this.getPluralRulesForLocale();
368
+ if (ruleset) {
369
+ return I18n.pluralRules[ruleset](count);
370
+ }
371
+ return 'other';
372
+ }
373
+ getPluralRulesForLocale() {
374
+ const localeShort = this.locale.split('-')[0];
375
+ for (const pluralRule in I18n.pluralRulesMap) {
376
+ const languages = I18n.pluralRulesMap[pluralRule];
377
+ if (languages.includes(this.locale) || languages.includes(localeShort)) {
378
+ return pluralRule;
379
+ }
380
+ }
381
+ }
382
+ }
383
+ I18n.pluralRulesMap = {
384
+ arabic: ['ar'],
385
+ chinese: ['my', 'zh', 'id', 'ja', 'jv', 'ko', 'ms', 'th', 'vi'],
386
+ french: ['hy', 'bn', 'fr', 'gu', 'hi', 'fa', 'pa', 'zu'],
387
+ german: ['af', 'sq', 'az', 'eu', 'bg', 'ca', 'da', 'nl', 'en', 'et', 'fi', 'ka', 'de', 'el', 'hu', 'lb', 'no', 'so', 'sw', 'sv', 'ta', 'te', 'tr', 'ur'],
388
+ irish: ['ga'],
389
+ russian: ['ru', 'uk'],
390
+ scottish: ['gd'],
391
+ spanish: ['pt-PT', 'it', 'es'],
392
+ welsh: ['cy']
393
+ };
394
+ I18n.pluralRules = {
395
+ arabic(n) {
396
+ if (n === 0) {
397
+ return 'zero';
398
+ }
399
+ if (n === 1) {
400
+ return 'one';
401
+ }
402
+ if (n === 2) {
403
+ return 'two';
404
+ }
405
+ if (n % 100 >= 3 && n % 100 <= 10) {
406
+ return 'few';
407
+ }
408
+ if (n % 100 >= 11 && n % 100 <= 99) {
409
+ return 'many';
410
+ }
411
+ return 'other';
412
+ },
413
+ chinese() {
414
+ return 'other';
415
+ },
416
+ french(n) {
417
+ return n === 0 || n === 1 ? 'one' : 'other';
418
+ },
419
+ german(n) {
420
+ return n === 1 ? 'one' : 'other';
421
+ },
422
+ irish(n) {
423
+ if (n === 1) {
424
+ return 'one';
425
+ }
426
+ if (n === 2) {
427
+ return 'two';
428
+ }
429
+ if (n >= 3 && n <= 6) {
430
+ return 'few';
431
+ }
432
+ if (n >= 7 && n <= 10) {
433
+ return 'many';
434
+ }
435
+ return 'other';
436
+ },
437
+ russian(n) {
438
+ const lastTwo = n % 100;
439
+ const last = lastTwo % 10;
440
+ if (last === 1 && lastTwo !== 11) {
441
+ return 'one';
442
+ }
443
+ if (last >= 2 && last <= 4 && !(lastTwo >= 12 && lastTwo <= 14)) {
444
+ return 'few';
445
+ }
446
+ if (last === 0 || last >= 5 && last <= 9 || lastTwo >= 11 && lastTwo <= 14) {
447
+ return 'many';
448
+ }
449
+ return 'other';
450
+ },
451
+ scottish(n) {
452
+ if (n === 1 || n === 11) {
453
+ return 'one';
454
+ }
455
+ if (n === 2 || n === 12) {
456
+ return 'two';
457
+ }
458
+ if (n >= 3 && n <= 10 || n >= 13 && n <= 19) {
459
+ return 'few';
460
+ }
461
+ return 'other';
462
+ },
463
+ spanish(n) {
464
+ if (n === 1) {
465
+ return 'one';
466
+ }
467
+ if (n % 1000000 === 0 && n !== 0) {
468
+ return 'many';
469
+ }
470
+ return 'other';
471
+ },
472
+ welsh(n) {
473
+ if (n === 0) {
474
+ return 'zero';
475
+ }
476
+ if (n === 1) {
477
+ return 'one';
478
+ }
479
+ if (n === 2) {
480
+ return 'two';
481
+ }
482
+ if (n === 3) {
483
+ return 'few';
484
+ }
485
+ if (n === 6) {
486
+ return 'many';
487
+ }
488
+ return 'other';
489
+ }
490
+ };
491
+
492
+ /**
493
+ * File upload component
494
+ *
495
+ * @preserve
496
+ * @augments ConfigurableComponent<FileUploadConfig>
497
+ */
498
+ class FileUpload extends ConfigurableComponent {
499
+ /**
500
+ * @param {Element | null} $root - File input element
501
+ * @param {FileUploadConfig} [config] - File Upload config
502
+ */
503
+ constructor($root, config = {}) {
504
+ super($root, config);
505
+ this.$input = void 0;
506
+ this.$button = void 0;
507
+ this.$status = void 0;
508
+ this.i18n = void 0;
509
+ this.id = void 0;
510
+ const $input = this.$root.querySelector('input');
511
+ if ($input === null) {
512
+ throw new ElementError({
513
+ component: FileUpload,
514
+ identifier: 'File inputs (`<input type="file">`)'
515
+ });
516
+ }
517
+ if ($input.type !== 'file') {
518
+ throw new ElementError(formatErrorMessage(FileUpload, 'File input (`<input type="file">`) attribute (`type`) is not `file`'));
519
+ }
520
+ this.$input = $input;
521
+ this.$input.setAttribute('hidden', 'true');
522
+ if (!this.$input.id) {
523
+ throw new ElementError({
524
+ component: FileUpload,
525
+ identifier: 'File input (`<input type="file">`) attribute (`id`)'
526
+ });
527
+ }
528
+ this.id = this.$input.id;
529
+ this.i18n = new I18n(this.config.i18n, {
530
+ locale: closestAttributeValue(this.$root, 'lang')
531
+ });
532
+ const $label = this.findLabel();
533
+ if (!$label.id) {
534
+ $label.id = `${this.id}-label`;
535
+ }
536
+ this.$input.id = `${this.id}-input`;
537
+ const $button = document.createElement('button');
538
+ $button.classList.add('govuk-file-upload-button');
539
+ $button.type = 'button';
540
+ $button.id = this.id;
541
+ $button.classList.add('govuk-file-upload-button--empty');
542
+ const ariaDescribedBy = this.$input.getAttribute('aria-describedby');
543
+ if (ariaDescribedBy) {
544
+ $button.setAttribute('aria-describedby', ariaDescribedBy);
545
+ }
546
+ const $status = document.createElement('span');
547
+ $status.className = 'govuk-body govuk-file-upload-button__status';
548
+ $status.setAttribute('aria-live', 'polite');
549
+ $status.innerText = this.i18n.t('noFileChosen');
550
+ $button.appendChild($status);
551
+ const commaSpan = document.createElement('span');
552
+ commaSpan.className = 'govuk-visually-hidden';
553
+ commaSpan.innerText = ', ';
554
+ commaSpan.id = `${this.id}-comma`;
555
+ $button.appendChild(commaSpan);
556
+ const containerSpan = document.createElement('span');
557
+ containerSpan.className = 'govuk-file-upload-button__pseudo-button-container';
558
+ const buttonSpan = document.createElement('span');
559
+ buttonSpan.className = 'govuk-button govuk-button--secondary govuk-file-upload-button__pseudo-button';
560
+ buttonSpan.innerText = this.i18n.t('chooseFilesButton');
561
+ containerSpan.appendChild(buttonSpan);
562
+ containerSpan.insertAdjacentText('beforeend', ' ');
563
+ const instructionSpan = document.createElement('span');
564
+ instructionSpan.className = 'govuk-body govuk-file-upload-button__instruction';
565
+ instructionSpan.innerText = this.i18n.t('dropInstruction');
566
+ containerSpan.appendChild(instructionSpan);
567
+ $button.appendChild(containerSpan);
568
+ $button.setAttribute('aria-labelledby', `${$label.id} ${commaSpan.id} ${$button.id}`);
569
+ $button.addEventListener('click', this.onClick.bind(this));
570
+ $button.addEventListener('dragover', event => {
571
+ event.preventDefault();
572
+ });
573
+ this.$root.insertAdjacentElement('afterbegin', $button);
574
+ this.$input.setAttribute('tabindex', '-1');
575
+ this.$input.setAttribute('aria-hidden', 'true');
576
+ this.$button = $button;
577
+ this.$status = $status;
578
+ this.$input.addEventListener('change', this.onChange.bind(this));
579
+ this.updateDisabledState();
580
+ this.observeDisabledState();
581
+ this.$announcements = document.createElement('span');
582
+ this.$announcements.classList.add('govuk-file-upload-announcements');
583
+ this.$announcements.classList.add('govuk-visually-hidden');
584
+ this.$announcements.setAttribute('aria-live', 'assertive');
585
+ this.$root.insertAdjacentElement('afterend', this.$announcements);
586
+ this.$button.addEventListener('drop', this.onDrop.bind(this));
587
+ document.addEventListener('dragenter', this.updateDropzoneVisibility.bind(this));
588
+ document.addEventListener('dragenter', () => {
589
+ this.enteredAnotherElement = true;
590
+ });
591
+ document.addEventListener('dragleave', () => {
592
+ if (!this.enteredAnotherElement && !this.$button.disabled) {
593
+ this.hideDraggingState();
594
+ this.$announcements.innerText = this.i18n.t('leftDropZone');
595
+ }
596
+ this.enteredAnotherElement = false;
597
+ });
598
+ }
599
+
600
+ /**
601
+ * Updates the visibility of the dropzone as users enters the various elements on the page
602
+ *
603
+ * @param {DragEvent} event - The `dragenter` event
604
+ */
605
+ updateDropzoneVisibility(event) {
606
+ if (this.$button.disabled) return;
607
+ if (event.target instanceof Node) {
608
+ if (this.$root.contains(event.target)) {
609
+ if (event.dataTransfer && isContainingFiles(event.dataTransfer)) {
610
+ if (!this.$button.classList.contains('govuk-file-upload-button--dragging')) {
611
+ this.showDraggingState();
612
+ this.$announcements.innerText = this.i18n.t('enteredDropZone');
613
+ }
614
+ }
615
+ } else {
616
+ if (this.$button.classList.contains('govuk-file-upload-button--dragging')) {
617
+ this.hideDraggingState();
618
+ this.$announcements.innerText = this.i18n.t('leftDropZone');
619
+ }
620
+ }
621
+ }
622
+ }
623
+ showDraggingState() {
624
+ this.$button.classList.add('govuk-file-upload-button--dragging');
625
+ }
626
+ hideDraggingState() {
627
+ this.$button.classList.remove('govuk-file-upload-button--dragging');
628
+ }
629
+
630
+ /**
631
+ * Handles user dropping on the component
632
+ *
633
+ * @param {DragEvent} event - The `dragenter` event
634
+ */
635
+ onDrop(event) {
636
+ event.preventDefault();
637
+ if (event.dataTransfer && isContainingFiles(event.dataTransfer)) {
638
+ this.$input.files = event.dataTransfer.files;
639
+ this.$input.dispatchEvent(new CustomEvent('change'));
640
+ this.hideDraggingState();
641
+ }
642
+ }
643
+ onChange() {
644
+ const fileCount = this.$input.files.length;
645
+ if (fileCount === 0) {
646
+ this.$status.innerText = this.i18n.t('noFileChosen');
647
+ this.$button.classList.add('govuk-file-upload-button--empty');
648
+ } else {
649
+ if (fileCount === 1) {
650
+ this.$status.innerText = this.$input.files[0].name;
651
+ } else {
652
+ this.$status.innerText = this.i18n.t('multipleFilesChosen', {
653
+ count: fileCount
654
+ });
655
+ }
656
+ this.$button.classList.remove('govuk-file-upload-button--empty');
657
+ }
658
+ }
659
+ findLabel() {
660
+ const $label = document.querySelector(`label[for="${this.$input.id}"]`);
661
+ if (!$label) {
662
+ throw new ElementError({
663
+ component: FileUpload,
664
+ identifier: `Field label (\`<label for=${this.$input.id}>\`)`
665
+ });
666
+ }
667
+ return $label;
668
+ }
669
+ onClick() {
670
+ this.$input.click();
671
+ }
672
+ observeDisabledState() {
673
+ const observer = new MutationObserver(mutationList => {
674
+ for (const mutation of mutationList) {
675
+ if (mutation.type === 'attributes' && mutation.attributeName === 'disabled') {
676
+ this.updateDisabledState();
677
+ }
678
+ }
679
+ });
680
+ observer.observe(this.$input, {
681
+ attributes: true
682
+ });
683
+ }
684
+ updateDisabledState() {
685
+ this.$button.disabled = this.$input.disabled;
686
+ this.$root.classList.toggle('govuk-drop-zone--disabled', this.$button.disabled);
687
+ }
688
+ }
689
+ FileUpload.moduleName = 'govuk-file-upload';
690
+ FileUpload.defaults = Object.freeze({
691
+ i18n: {
692
+ chooseFilesButton: 'Choose file',
693
+ dropInstruction: 'or drop file',
694
+ noFileChosen: 'No file chosen',
695
+ multipleFilesChosen: {
696
+ one: '%{count} file chosen',
697
+ other: '%{count} files chosen'
698
+ },
699
+ enteredDropZone: 'Entered drop zone',
700
+ leftDropZone: 'Left drop zone'
701
+ }
702
+ });
703
+ FileUpload.schema = Object.freeze({
704
+ properties: {
705
+ i18n: {
706
+ type: 'object'
707
+ }
708
+ }
709
+ });
710
+ function isContainingFiles(dataTransfer) {
711
+ const hasNoTypesInfo = dataTransfer.types.length === 0;
712
+ const isDraggingFiles = dataTransfer.types.some(type => type === 'Files');
713
+ return hasNoTypesInfo || isDraggingFiles;
714
+ }
715
+
716
+ /**
717
+ * @typedef {HTMLInputElement & {files: FileList}} HTMLFileInputElement
718
+ */
719
+
720
+ /**
721
+ * File upload config
722
+ *
723
+ * @see {@link FileUpload.defaults}
724
+ * @typedef {object} FileUploadConfig
725
+ * @property {FileUploadTranslations} [i18n=FileUpload.defaults.i18n] - File upload translations
726
+ */
727
+
728
+ /**
729
+ * File upload translations
730
+ *
731
+ * @see {@link FileUpload.defaults.i18n}
732
+ * @typedef {object} FileUploadTranslations
733
+ *
734
+ * Messages used by the component
735
+ * @property {string} [chooseFile] - The text of the button that opens the file picker
736
+ * @property {string} [dropInstruction] - The text informing users they can drop files
737
+ * @property {TranslationPluralForms} [multipleFilesChosen] - The text displayed when multiple files
738
+ * have been chosen by the user
739
+ * @property {string} [noFileChosen] - The text to displayed when no file has been chosen by the user
740
+ * @property {string} [enteredDropZone] - The text announced by assistive technology
741
+ * when user drags files and enters the drop zone
742
+ * @property {string} [leftDropZone] - The text announced by assistive technology
743
+ * when user drags files and leaves the drop zone without dropping
744
+ */
745
+
746
+ /**
747
+ * @import { Schema } from '../../common/configuration.mjs'
748
+ * @import { TranslationPluralForms } from '../../i18n.mjs'
749
+ */
750
+
751
+ exports.FileUpload = FileUpload;
752
+
753
+ }));
754
+ //# sourceMappingURL=file-upload.bundle.js.map