govuk_tech_docs 4.2.0 → 4.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/govuk_tech_docs.gemspec +1 -1
- data/lib/assets/stylesheets/_govuk_tech_docs.scss +3 -0
- data/lib/govuk_tech_docs/version.rb +1 -1
- data/lib/source/layouts/core.erb +16 -5
- data/node_modules/govuk-frontend/dist/govuk/all.bundle.js +508 -209
- data/node_modules/govuk-frontend/dist/govuk/all.bundle.mjs +505 -208
- data/node_modules/govuk-frontend/dist/govuk/all.mjs +3 -1
- data/node_modules/govuk-frontend/dist/govuk/all.scss +6 -0
- data/node_modules/govuk-frontend/dist/govuk/common/configuration.mjs +169 -0
- data/node_modules/govuk-frontend/dist/govuk/common/govuk-frontend-version.mjs +1 -1
- data/node_modules/govuk-frontend/dist/govuk/common/index.mjs +4 -87
- data/node_modules/govuk-frontend/dist/govuk/{govuk-frontend-component.mjs → component.mjs} +5 -5
- data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js +161 -116
- data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs +160 -115
- data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.mjs +5 -8
- data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.js +161 -116
- data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.mjs +160 -115
- data/node_modules/govuk-frontend/dist/govuk/components/button/button.mjs +5 -8
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/_index.scss +8 -0
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js +187 -145
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs +186 -144
- data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.mjs +18 -17
- data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js +9 -29
- data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs +8 -28
- data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.mjs +2 -2
- data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js +161 -116
- data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs +160 -115
- data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs +6 -8
- data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js +161 -116
- data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs +160 -115
- data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs +5 -8
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/_index.scss +167 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.js +754 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.bundle.mjs +746 -0
- data/node_modules/govuk-frontend/dist/govuk/components/file-upload/file-upload.mjs +267 -0
- data/node_modules/govuk-frontend/dist/govuk/components/header/_index.scss +14 -10
- data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.js +9 -29
- data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.mjs +8 -28
- data/node_modules/govuk-frontend/dist/govuk/components/header/header.mjs +2 -2
- data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js +161 -116
- data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs +160 -115
- data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs +6 -8
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js +161 -117
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs +160 -116
- data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.mjs +5 -9
- data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.js +9 -29
- data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs +8 -28
- data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.mjs +2 -2
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js +9 -29
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs +8 -28
- data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.mjs +2 -2
- data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js +10 -30
- data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs +9 -29
- data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.mjs +3 -3
- data/node_modules/govuk-frontend/dist/govuk/components/summary-list/_index.scss +12 -21
- data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js +9 -29
- data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs +8 -28
- data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.mjs +2 -2
- data/node_modules/govuk-frontend/dist/govuk/core/_govuk-frontend-properties.scss +1 -1
- data/node_modules/govuk-frontend/dist/govuk/errors/index.mjs +1 -1
- data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.js +1 -1
- data/node_modules/govuk-frontend/dist/govuk/helpers/_colour.scss +2 -2
- data/node_modules/govuk-frontend/dist/govuk/init.mjs +28 -24
- data/node_modules/govuk-frontend/dist/govuk/settings/_colours-organisations.scss +18 -5
- data/node_modules/govuk-frontend/dist/govuk/settings/_typography-responsive.scss +5 -10
- data/node_modules/govuk-frontend/dist/govuk-prototype-kit/init.scss +1 -1
- data/package-lock.json +8 -7
- data/package.json +1 -1
- metadata +12 -10
- data/node_modules/govuk-frontend/dist/govuk/common/normalise-dataset.mjs +0 -18
- data/node_modules/govuk-frontend/dist/govuk/common/normalise-string.mjs +0 -31
@@ -1,79 +1,9 @@
|
|
1
1
|
(function (global, factory) {
|
2
2
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
3
3
|
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
4
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.GOVUKFrontend = {}));
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.GOVUKFrontend = global.GOVUKFrontend || {}));
|
5
5
|
})(this, (function (exports) { 'use strict';
|
6
6
|
|
7
|
-
function normaliseString(value, property) {
|
8
|
-
const trimmedValue = value ? value.trim() : '';
|
9
|
-
let output;
|
10
|
-
let outputType = property == null ? void 0 : property.type;
|
11
|
-
if (!outputType) {
|
12
|
-
if (['true', 'false'].includes(trimmedValue)) {
|
13
|
-
outputType = 'boolean';
|
14
|
-
}
|
15
|
-
if (trimmedValue.length > 0 && isFinite(Number(trimmedValue))) {
|
16
|
-
outputType = 'number';
|
17
|
-
}
|
18
|
-
}
|
19
|
-
switch (outputType) {
|
20
|
-
case 'boolean':
|
21
|
-
output = trimmedValue === 'true';
|
22
|
-
break;
|
23
|
-
case 'number':
|
24
|
-
output = Number(trimmedValue);
|
25
|
-
break;
|
26
|
-
default:
|
27
|
-
output = value;
|
28
|
-
}
|
29
|
-
return output;
|
30
|
-
}
|
31
|
-
|
32
|
-
/**
|
33
|
-
* @typedef {import('./index.mjs').SchemaProperty} SchemaProperty
|
34
|
-
*/
|
35
|
-
|
36
|
-
function mergeConfigs(...configObjects) {
|
37
|
-
const formattedConfigObject = {};
|
38
|
-
for (const configObject of configObjects) {
|
39
|
-
for (const key of Object.keys(configObject)) {
|
40
|
-
const option = formattedConfigObject[key];
|
41
|
-
const override = configObject[key];
|
42
|
-
if (isObject(option) && isObject(override)) {
|
43
|
-
formattedConfigObject[key] = mergeConfigs(option, override);
|
44
|
-
} else {
|
45
|
-
formattedConfigObject[key] = override;
|
46
|
-
}
|
47
|
-
}
|
48
|
-
}
|
49
|
-
return formattedConfigObject;
|
50
|
-
}
|
51
|
-
function extractConfigByNamespace(Component, dataset, namespace) {
|
52
|
-
const property = Component.schema.properties[namespace];
|
53
|
-
if ((property == null ? void 0 : property.type) !== 'object') {
|
54
|
-
return;
|
55
|
-
}
|
56
|
-
const newObject = {
|
57
|
-
[namespace]: ({})
|
58
|
-
};
|
59
|
-
for (const [key, value] of Object.entries(dataset)) {
|
60
|
-
let current = newObject;
|
61
|
-
const keyParts = key.split('.');
|
62
|
-
for (const [index, name] of keyParts.entries()) {
|
63
|
-
if (typeof current === 'object') {
|
64
|
-
if (index < keyParts.length - 1) {
|
65
|
-
if (!isObject(current[name])) {
|
66
|
-
current[name] = {};
|
67
|
-
}
|
68
|
-
current = current[name];
|
69
|
-
} else if (key !== namespace) {
|
70
|
-
current[name] = normaliseString(value);
|
71
|
-
}
|
72
|
-
}
|
73
|
-
}
|
74
|
-
}
|
75
|
-
return newObject[namespace];
|
76
|
-
}
|
77
7
|
function setFocus($element, options = {}) {
|
78
8
|
var _options$onBeforeFocu;
|
79
9
|
const isFocusable = $element.getAttribute('tabindex');
|
@@ -126,46 +56,13 @@
|
|
126
56
|
function formatErrorMessage(Component, message) {
|
127
57
|
return `${Component.moduleName}: ${message}`;
|
128
58
|
}
|
129
|
-
|
130
|
-
/**
|
131
|
-
* Schema for component config
|
132
|
-
*
|
133
|
-
* @typedef {object} Schema
|
134
|
-
* @property {{ [field: string]: SchemaProperty | undefined }} properties - Schema properties
|
135
|
-
* @property {SchemaCondition[]} [anyOf] - List of schema conditions
|
136
|
-
*/
|
137
|
-
|
138
|
-
/**
|
139
|
-
* Schema property for component config
|
140
|
-
*
|
141
|
-
* @typedef {object} SchemaProperty
|
142
|
-
* @property {'string' | 'boolean' | 'number' | 'object'} type - Property type
|
143
|
-
*/
|
144
|
-
|
145
|
-
/**
|
146
|
-
* Schema condition for component config
|
147
|
-
*
|
148
|
-
* @typedef {object} SchemaCondition
|
149
|
-
* @property {string[]} required - List of required config fields
|
150
|
-
* @property {string} errorMessage - Error message when required config fields not provided
|
151
|
-
*/
|
152
59
|
/**
|
153
60
|
* @typedef ComponentWithModuleName
|
154
61
|
* @property {string} moduleName - Name of the component
|
155
62
|
*/
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
for (const [field, property] of Object.entries(Component.schema.properties)) {
|
160
|
-
if (field in dataset) {
|
161
|
-
out[field] = normaliseString(dataset[field], property);
|
162
|
-
}
|
163
|
-
if ((property == null ? void 0 : property.type) === 'object') {
|
164
|
-
out[field] = extractConfigByNamespace(Component, dataset, field);
|
165
|
-
}
|
166
|
-
}
|
167
|
-
return out;
|
168
|
-
}
|
63
|
+
/**
|
64
|
+
* @import { ObjectNested } from './configuration.mjs'
|
65
|
+
*/
|
169
66
|
|
170
67
|
class GOVUKFrontendError extends Error {
|
171
68
|
constructor(...args) {
|
@@ -185,6 +82,12 @@
|
|
185
82
|
this.name = 'SupportError';
|
186
83
|
}
|
187
84
|
}
|
85
|
+
class ConfigError extends GOVUKFrontendError {
|
86
|
+
constructor(...args) {
|
87
|
+
super(...args);
|
88
|
+
this.name = 'ConfigError';
|
89
|
+
}
|
90
|
+
}
|
188
91
|
class ElementError extends GOVUKFrontendError {
|
189
92
|
constructor(messageOrOptions) {
|
190
93
|
let message = typeof messageOrOptions === 'string' ? messageOrOptions : '';
|
@@ -211,10 +114,10 @@
|
|
211
114
|
}
|
212
115
|
}
|
213
116
|
/**
|
214
|
-
* @
|
117
|
+
* @import { ComponentWithModuleName } from '../common/index.mjs'
|
215
118
|
*/
|
216
119
|
|
217
|
-
class
|
120
|
+
class Component {
|
218
121
|
/**
|
219
122
|
* Returns the root element of the component
|
220
123
|
*
|
@@ -265,24 +168,166 @@
|
|
265
168
|
*/
|
266
169
|
|
267
170
|
/**
|
268
|
-
* @typedef {typeof
|
171
|
+
* @typedef {typeof Component & ChildClass} ChildClassConstructor
|
172
|
+
*/
|
173
|
+
Component.elementType = HTMLElement;
|
174
|
+
|
175
|
+
const configOverride = Symbol.for('configOverride');
|
176
|
+
class ConfigurableComponent extends Component {
|
177
|
+
[configOverride](param) {
|
178
|
+
return {};
|
179
|
+
}
|
180
|
+
|
181
|
+
/**
|
182
|
+
* Returns the root element of the component
|
183
|
+
*
|
184
|
+
* @protected
|
185
|
+
* @returns {ConfigurationType} - the root element of component
|
186
|
+
*/
|
187
|
+
get config() {
|
188
|
+
return this._config;
|
189
|
+
}
|
190
|
+
constructor($root, config) {
|
191
|
+
super($root);
|
192
|
+
this._config = void 0;
|
193
|
+
const childConstructor = this.constructor;
|
194
|
+
if (!isObject(childConstructor.defaults)) {
|
195
|
+
throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));
|
196
|
+
}
|
197
|
+
const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);
|
198
|
+
this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}, this[configOverride](datasetConfig), datasetConfig);
|
199
|
+
}
|
200
|
+
}
|
201
|
+
function normaliseString(value, property) {
|
202
|
+
const trimmedValue = value ? value.trim() : '';
|
203
|
+
let output;
|
204
|
+
let outputType = property == null ? void 0 : property.type;
|
205
|
+
if (!outputType) {
|
206
|
+
if (['true', 'false'].includes(trimmedValue)) {
|
207
|
+
outputType = 'boolean';
|
208
|
+
}
|
209
|
+
if (trimmedValue.length > 0 && isFinite(Number(trimmedValue))) {
|
210
|
+
outputType = 'number';
|
211
|
+
}
|
212
|
+
}
|
213
|
+
switch (outputType) {
|
214
|
+
case 'boolean':
|
215
|
+
output = trimmedValue === 'true';
|
216
|
+
break;
|
217
|
+
case 'number':
|
218
|
+
output = Number(trimmedValue);
|
219
|
+
break;
|
220
|
+
default:
|
221
|
+
output = value;
|
222
|
+
}
|
223
|
+
return output;
|
224
|
+
}
|
225
|
+
function normaliseDataset(Component, dataset) {
|
226
|
+
if (!isObject(Component.schema)) {
|
227
|
+
throw new ConfigError(formatErrorMessage(Component, 'Config passed as parameter into constructor but no schema defined'));
|
228
|
+
}
|
229
|
+
const out = {};
|
230
|
+
const entries = Object.entries(Component.schema.properties);
|
231
|
+
for (const entry of entries) {
|
232
|
+
const [namespace, property] = entry;
|
233
|
+
const field = namespace.toString();
|
234
|
+
if (field in dataset) {
|
235
|
+
out[field] = normaliseString(dataset[field], property);
|
236
|
+
}
|
237
|
+
if ((property == null ? void 0 : property.type) === 'object') {
|
238
|
+
out[field] = extractConfigByNamespace(Component.schema, dataset, namespace);
|
239
|
+
}
|
240
|
+
}
|
241
|
+
return out;
|
242
|
+
}
|
243
|
+
function mergeConfigs(...configObjects) {
|
244
|
+
const formattedConfigObject = {};
|
245
|
+
for (const configObject of configObjects) {
|
246
|
+
for (const key of Object.keys(configObject)) {
|
247
|
+
const option = formattedConfigObject[key];
|
248
|
+
const override = configObject[key];
|
249
|
+
if (isObject(option) && isObject(override)) {
|
250
|
+
formattedConfigObject[key] = mergeConfigs(option, override);
|
251
|
+
} else {
|
252
|
+
formattedConfigObject[key] = override;
|
253
|
+
}
|
254
|
+
}
|
255
|
+
}
|
256
|
+
return formattedConfigObject;
|
257
|
+
}
|
258
|
+
function extractConfigByNamespace(schema, dataset, namespace) {
|
259
|
+
const property = schema.properties[namespace];
|
260
|
+
if ((property == null ? void 0 : property.type) !== 'object') {
|
261
|
+
return;
|
262
|
+
}
|
263
|
+
const newObject = {
|
264
|
+
[namespace]: {}
|
265
|
+
};
|
266
|
+
for (const [key, value] of Object.entries(dataset)) {
|
267
|
+
let current = newObject;
|
268
|
+
const keyParts = key.split('.');
|
269
|
+
for (const [index, name] of keyParts.entries()) {
|
270
|
+
if (isObject(current)) {
|
271
|
+
if (index < keyParts.length - 1) {
|
272
|
+
if (!isObject(current[name])) {
|
273
|
+
current[name] = {};
|
274
|
+
}
|
275
|
+
current = current[name];
|
276
|
+
} else if (key !== namespace) {
|
277
|
+
current[name] = normaliseString(value);
|
278
|
+
}
|
279
|
+
}
|
280
|
+
}
|
281
|
+
}
|
282
|
+
return newObject[namespace];
|
283
|
+
}
|
284
|
+
/**
|
285
|
+
* Schema for component config
|
286
|
+
*
|
287
|
+
* @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType
|
288
|
+
* @typedef {object} Schema
|
289
|
+
* @property {Record<keyof ConfigurationType, SchemaProperty | undefined>} properties - Schema properties
|
290
|
+
* @property {SchemaCondition<ConfigurationType>[]} [anyOf] - List of schema conditions
|
291
|
+
*/
|
292
|
+
/**
|
293
|
+
* Schema property for component config
|
294
|
+
*
|
295
|
+
* @typedef {object} SchemaProperty
|
296
|
+
* @property {'string' | 'boolean' | 'number' | 'object'} type - Property type
|
297
|
+
*/
|
298
|
+
/**
|
299
|
+
* Schema condition for component config
|
300
|
+
*
|
301
|
+
* @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType
|
302
|
+
* @typedef {object} SchemaCondition
|
303
|
+
* @property {(keyof ConfigurationType)[]} required - List of required config fields
|
304
|
+
* @property {string} errorMessage - Error message when required config fields not provided
|
305
|
+
*/
|
306
|
+
/**
|
307
|
+
* @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]
|
308
|
+
* @typedef ChildClass
|
309
|
+
* @property {string} moduleName - The module name that'll be looked for in the DOM when initialising the component
|
310
|
+
* @property {Schema<ConfigurationType>} [schema] - The schema of the component configuration
|
311
|
+
* @property {ConfigurationType} [defaults] - The default values of the configuration of the component
|
312
|
+
*/
|
313
|
+
/**
|
314
|
+
* @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]
|
315
|
+
* @typedef {typeof Component & ChildClass<ConfigurationType>} ChildClassConstructor<ConfigurationType>
|
269
316
|
*/
|
270
|
-
GOVUKFrontendComponent.elementType = HTMLElement;
|
271
317
|
|
272
318
|
/**
|
273
319
|
* Notification Banner component
|
274
320
|
*
|
275
321
|
* @preserve
|
322
|
+
* @augments ConfigurableComponent<NotificationBannerConfig>
|
276
323
|
*/
|
277
|
-
class NotificationBanner extends
|
324
|
+
class NotificationBanner extends ConfigurableComponent {
|
278
325
|
/**
|
279
326
|
* @param {Element | null} $root - HTML element to use for notification banner
|
280
327
|
* @param {NotificationBannerConfig} [config] - Notification banner config
|
281
328
|
*/
|
282
329
|
constructor($root, config = {}) {
|
283
|
-
super($root);
|
284
|
-
this.config = void 0;
|
285
|
-
this.config = mergeConfigs(NotificationBanner.defaults, config, normaliseDataset(NotificationBanner, this.$root.dataset));
|
330
|
+
super($root, config);
|
286
331
|
if (this.$root.getAttribute('role') === 'alert' && !this.config.disableAutoFocus) {
|
287
332
|
setFocus(this.$root);
|
288
333
|
}
|
@@ -300,7 +345,7 @@
|
|
300
345
|
*/
|
301
346
|
|
302
347
|
/**
|
303
|
-
* @
|
348
|
+
* @import { Schema } from '../../common/configuration.mjs'
|
304
349
|
*/
|
305
350
|
NotificationBanner.moduleName = 'govuk-notification-banner';
|
306
351
|
NotificationBanner.defaults = Object.freeze({
|
@@ -1,73 +1,3 @@
|
|
1
|
-
function normaliseString(value, property) {
|
2
|
-
const trimmedValue = value ? value.trim() : '';
|
3
|
-
let output;
|
4
|
-
let outputType = property == null ? void 0 : property.type;
|
5
|
-
if (!outputType) {
|
6
|
-
if (['true', 'false'].includes(trimmedValue)) {
|
7
|
-
outputType = 'boolean';
|
8
|
-
}
|
9
|
-
if (trimmedValue.length > 0 && isFinite(Number(trimmedValue))) {
|
10
|
-
outputType = 'number';
|
11
|
-
}
|
12
|
-
}
|
13
|
-
switch (outputType) {
|
14
|
-
case 'boolean':
|
15
|
-
output = trimmedValue === 'true';
|
16
|
-
break;
|
17
|
-
case 'number':
|
18
|
-
output = Number(trimmedValue);
|
19
|
-
break;
|
20
|
-
default:
|
21
|
-
output = value;
|
22
|
-
}
|
23
|
-
return output;
|
24
|
-
}
|
25
|
-
|
26
|
-
/**
|
27
|
-
* @typedef {import('./index.mjs').SchemaProperty} SchemaProperty
|
28
|
-
*/
|
29
|
-
|
30
|
-
function mergeConfigs(...configObjects) {
|
31
|
-
const formattedConfigObject = {};
|
32
|
-
for (const configObject of configObjects) {
|
33
|
-
for (const key of Object.keys(configObject)) {
|
34
|
-
const option = formattedConfigObject[key];
|
35
|
-
const override = configObject[key];
|
36
|
-
if (isObject(option) && isObject(override)) {
|
37
|
-
formattedConfigObject[key] = mergeConfigs(option, override);
|
38
|
-
} else {
|
39
|
-
formattedConfigObject[key] = override;
|
40
|
-
}
|
41
|
-
}
|
42
|
-
}
|
43
|
-
return formattedConfigObject;
|
44
|
-
}
|
45
|
-
function extractConfigByNamespace(Component, dataset, namespace) {
|
46
|
-
const property = Component.schema.properties[namespace];
|
47
|
-
if ((property == null ? void 0 : property.type) !== 'object') {
|
48
|
-
return;
|
49
|
-
}
|
50
|
-
const newObject = {
|
51
|
-
[namespace]: ({})
|
52
|
-
};
|
53
|
-
for (const [key, value] of Object.entries(dataset)) {
|
54
|
-
let current = newObject;
|
55
|
-
const keyParts = key.split('.');
|
56
|
-
for (const [index, name] of keyParts.entries()) {
|
57
|
-
if (typeof current === 'object') {
|
58
|
-
if (index < keyParts.length - 1) {
|
59
|
-
if (!isObject(current[name])) {
|
60
|
-
current[name] = {};
|
61
|
-
}
|
62
|
-
current = current[name];
|
63
|
-
} else if (key !== namespace) {
|
64
|
-
current[name] = normaliseString(value);
|
65
|
-
}
|
66
|
-
}
|
67
|
-
}
|
68
|
-
}
|
69
|
-
return newObject[namespace];
|
70
|
-
}
|
71
1
|
function setFocus($element, options = {}) {
|
72
2
|
var _options$onBeforeFocu;
|
73
3
|
const isFocusable = $element.getAttribute('tabindex');
|
@@ -120,46 +50,13 @@ function isObject(option) {
|
|
120
50
|
function formatErrorMessage(Component, message) {
|
121
51
|
return `${Component.moduleName}: ${message}`;
|
122
52
|
}
|
123
|
-
|
124
|
-
/**
|
125
|
-
* Schema for component config
|
126
|
-
*
|
127
|
-
* @typedef {object} Schema
|
128
|
-
* @property {{ [field: string]: SchemaProperty | undefined }} properties - Schema properties
|
129
|
-
* @property {SchemaCondition[]} [anyOf] - List of schema conditions
|
130
|
-
*/
|
131
|
-
|
132
|
-
/**
|
133
|
-
* Schema property for component config
|
134
|
-
*
|
135
|
-
* @typedef {object} SchemaProperty
|
136
|
-
* @property {'string' | 'boolean' | 'number' | 'object'} type - Property type
|
137
|
-
*/
|
138
|
-
|
139
|
-
/**
|
140
|
-
* Schema condition for component config
|
141
|
-
*
|
142
|
-
* @typedef {object} SchemaCondition
|
143
|
-
* @property {string[]} required - List of required config fields
|
144
|
-
* @property {string} errorMessage - Error message when required config fields not provided
|
145
|
-
*/
|
146
53
|
/**
|
147
54
|
* @typedef ComponentWithModuleName
|
148
55
|
* @property {string} moduleName - Name of the component
|
149
56
|
*/
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
for (const [field, property] of Object.entries(Component.schema.properties)) {
|
154
|
-
if (field in dataset) {
|
155
|
-
out[field] = normaliseString(dataset[field], property);
|
156
|
-
}
|
157
|
-
if ((property == null ? void 0 : property.type) === 'object') {
|
158
|
-
out[field] = extractConfigByNamespace(Component, dataset, field);
|
159
|
-
}
|
160
|
-
}
|
161
|
-
return out;
|
162
|
-
}
|
57
|
+
/**
|
58
|
+
* @import { ObjectNested } from './configuration.mjs'
|
59
|
+
*/
|
163
60
|
|
164
61
|
class GOVUKFrontendError extends Error {
|
165
62
|
constructor(...args) {
|
@@ -179,6 +76,12 @@ class SupportError extends GOVUKFrontendError {
|
|
179
76
|
this.name = 'SupportError';
|
180
77
|
}
|
181
78
|
}
|
79
|
+
class ConfigError extends GOVUKFrontendError {
|
80
|
+
constructor(...args) {
|
81
|
+
super(...args);
|
82
|
+
this.name = 'ConfigError';
|
83
|
+
}
|
84
|
+
}
|
182
85
|
class ElementError extends GOVUKFrontendError {
|
183
86
|
constructor(messageOrOptions) {
|
184
87
|
let message = typeof messageOrOptions === 'string' ? messageOrOptions : '';
|
@@ -205,10 +108,10 @@ class InitError extends GOVUKFrontendError {
|
|
205
108
|
}
|
206
109
|
}
|
207
110
|
/**
|
208
|
-
* @
|
111
|
+
* @import { ComponentWithModuleName } from '../common/index.mjs'
|
209
112
|
*/
|
210
113
|
|
211
|
-
class
|
114
|
+
class Component {
|
212
115
|
/**
|
213
116
|
* Returns the root element of the component
|
214
117
|
*
|
@@ -259,24 +162,166 @@ class GOVUKFrontendComponent {
|
|
259
162
|
*/
|
260
163
|
|
261
164
|
/**
|
262
|
-
* @typedef {typeof
|
165
|
+
* @typedef {typeof Component & ChildClass} ChildClassConstructor
|
166
|
+
*/
|
167
|
+
Component.elementType = HTMLElement;
|
168
|
+
|
169
|
+
const configOverride = Symbol.for('configOverride');
|
170
|
+
class ConfigurableComponent extends Component {
|
171
|
+
[configOverride](param) {
|
172
|
+
return {};
|
173
|
+
}
|
174
|
+
|
175
|
+
/**
|
176
|
+
* Returns the root element of the component
|
177
|
+
*
|
178
|
+
* @protected
|
179
|
+
* @returns {ConfigurationType} - the root element of component
|
180
|
+
*/
|
181
|
+
get config() {
|
182
|
+
return this._config;
|
183
|
+
}
|
184
|
+
constructor($root, config) {
|
185
|
+
super($root);
|
186
|
+
this._config = void 0;
|
187
|
+
const childConstructor = this.constructor;
|
188
|
+
if (!isObject(childConstructor.defaults)) {
|
189
|
+
throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));
|
190
|
+
}
|
191
|
+
const datasetConfig = normaliseDataset(childConstructor, this._$root.dataset);
|
192
|
+
this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}, this[configOverride](datasetConfig), datasetConfig);
|
193
|
+
}
|
194
|
+
}
|
195
|
+
function normaliseString(value, property) {
|
196
|
+
const trimmedValue = value ? value.trim() : '';
|
197
|
+
let output;
|
198
|
+
let outputType = property == null ? void 0 : property.type;
|
199
|
+
if (!outputType) {
|
200
|
+
if (['true', 'false'].includes(trimmedValue)) {
|
201
|
+
outputType = 'boolean';
|
202
|
+
}
|
203
|
+
if (trimmedValue.length > 0 && isFinite(Number(trimmedValue))) {
|
204
|
+
outputType = 'number';
|
205
|
+
}
|
206
|
+
}
|
207
|
+
switch (outputType) {
|
208
|
+
case 'boolean':
|
209
|
+
output = trimmedValue === 'true';
|
210
|
+
break;
|
211
|
+
case 'number':
|
212
|
+
output = Number(trimmedValue);
|
213
|
+
break;
|
214
|
+
default:
|
215
|
+
output = value;
|
216
|
+
}
|
217
|
+
return output;
|
218
|
+
}
|
219
|
+
function normaliseDataset(Component, dataset) {
|
220
|
+
if (!isObject(Component.schema)) {
|
221
|
+
throw new ConfigError(formatErrorMessage(Component, 'Config passed as parameter into constructor but no schema defined'));
|
222
|
+
}
|
223
|
+
const out = {};
|
224
|
+
const entries = Object.entries(Component.schema.properties);
|
225
|
+
for (const entry of entries) {
|
226
|
+
const [namespace, property] = entry;
|
227
|
+
const field = namespace.toString();
|
228
|
+
if (field in dataset) {
|
229
|
+
out[field] = normaliseString(dataset[field], property);
|
230
|
+
}
|
231
|
+
if ((property == null ? void 0 : property.type) === 'object') {
|
232
|
+
out[field] = extractConfigByNamespace(Component.schema, dataset, namespace);
|
233
|
+
}
|
234
|
+
}
|
235
|
+
return out;
|
236
|
+
}
|
237
|
+
function mergeConfigs(...configObjects) {
|
238
|
+
const formattedConfigObject = {};
|
239
|
+
for (const configObject of configObjects) {
|
240
|
+
for (const key of Object.keys(configObject)) {
|
241
|
+
const option = formattedConfigObject[key];
|
242
|
+
const override = configObject[key];
|
243
|
+
if (isObject(option) && isObject(override)) {
|
244
|
+
formattedConfigObject[key] = mergeConfigs(option, override);
|
245
|
+
} else {
|
246
|
+
formattedConfigObject[key] = override;
|
247
|
+
}
|
248
|
+
}
|
249
|
+
}
|
250
|
+
return formattedConfigObject;
|
251
|
+
}
|
252
|
+
function extractConfigByNamespace(schema, dataset, namespace) {
|
253
|
+
const property = schema.properties[namespace];
|
254
|
+
if ((property == null ? void 0 : property.type) !== 'object') {
|
255
|
+
return;
|
256
|
+
}
|
257
|
+
const newObject = {
|
258
|
+
[namespace]: {}
|
259
|
+
};
|
260
|
+
for (const [key, value] of Object.entries(dataset)) {
|
261
|
+
let current = newObject;
|
262
|
+
const keyParts = key.split('.');
|
263
|
+
for (const [index, name] of keyParts.entries()) {
|
264
|
+
if (isObject(current)) {
|
265
|
+
if (index < keyParts.length - 1) {
|
266
|
+
if (!isObject(current[name])) {
|
267
|
+
current[name] = {};
|
268
|
+
}
|
269
|
+
current = current[name];
|
270
|
+
} else if (key !== namespace) {
|
271
|
+
current[name] = normaliseString(value);
|
272
|
+
}
|
273
|
+
}
|
274
|
+
}
|
275
|
+
}
|
276
|
+
return newObject[namespace];
|
277
|
+
}
|
278
|
+
/**
|
279
|
+
* Schema for component config
|
280
|
+
*
|
281
|
+
* @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType
|
282
|
+
* @typedef {object} Schema
|
283
|
+
* @property {Record<keyof ConfigurationType, SchemaProperty | undefined>} properties - Schema properties
|
284
|
+
* @property {SchemaCondition<ConfigurationType>[]} [anyOf] - List of schema conditions
|
285
|
+
*/
|
286
|
+
/**
|
287
|
+
* Schema property for component config
|
288
|
+
*
|
289
|
+
* @typedef {object} SchemaProperty
|
290
|
+
* @property {'string' | 'boolean' | 'number' | 'object'} type - Property type
|
291
|
+
*/
|
292
|
+
/**
|
293
|
+
* Schema condition for component config
|
294
|
+
*
|
295
|
+
* @template {Partial<Record<keyof ConfigurationType, unknown>>} ConfigurationType
|
296
|
+
* @typedef {object} SchemaCondition
|
297
|
+
* @property {(keyof ConfigurationType)[]} required - List of required config fields
|
298
|
+
* @property {string} errorMessage - Error message when required config fields not provided
|
299
|
+
*/
|
300
|
+
/**
|
301
|
+
* @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]
|
302
|
+
* @typedef ChildClass
|
303
|
+
* @property {string} moduleName - The module name that'll be looked for in the DOM when initialising the component
|
304
|
+
* @property {Schema<ConfigurationType>} [schema] - The schema of the component configuration
|
305
|
+
* @property {ConfigurationType} [defaults] - The default values of the configuration of the component
|
306
|
+
*/
|
307
|
+
/**
|
308
|
+
* @template {Partial<Record<keyof ConfigurationType, unknown>>} [ConfigurationType=ObjectNested]
|
309
|
+
* @typedef {typeof Component & ChildClass<ConfigurationType>} ChildClassConstructor<ConfigurationType>
|
263
310
|
*/
|
264
|
-
GOVUKFrontendComponent.elementType = HTMLElement;
|
265
311
|
|
266
312
|
/**
|
267
313
|
* Notification Banner component
|
268
314
|
*
|
269
315
|
* @preserve
|
316
|
+
* @augments ConfigurableComponent<NotificationBannerConfig>
|
270
317
|
*/
|
271
|
-
class NotificationBanner extends
|
318
|
+
class NotificationBanner extends ConfigurableComponent {
|
272
319
|
/**
|
273
320
|
* @param {Element | null} $root - HTML element to use for notification banner
|
274
321
|
* @param {NotificationBannerConfig} [config] - Notification banner config
|
275
322
|
*/
|
276
323
|
constructor($root, config = {}) {
|
277
|
-
super($root);
|
278
|
-
this.config = void 0;
|
279
|
-
this.config = mergeConfigs(NotificationBanner.defaults, config, normaliseDataset(NotificationBanner, this.$root.dataset));
|
324
|
+
super($root, config);
|
280
325
|
if (this.$root.getAttribute('role') === 'alert' && !this.config.disableAutoFocus) {
|
281
326
|
setFocus(this.$root);
|
282
327
|
}
|
@@ -294,7 +339,7 @@ class NotificationBanner extends GOVUKFrontendComponent {
|
|
294
339
|
*/
|
295
340
|
|
296
341
|
/**
|
297
|
-
* @
|
342
|
+
* @import { Schema } from '../../common/configuration.mjs'
|
298
343
|
*/
|
299
344
|
NotificationBanner.moduleName = 'govuk-notification-banner';
|
300
345
|
NotificationBanner.defaults = Object.freeze({
|
data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs
CHANGED
@@ -1,21 +1,19 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
3
|
-
import { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs';
|
1
|
+
import { ConfigurableComponent } from '../../common/configuration.mjs';
|
2
|
+
import { setFocus } from '../../common/index.mjs';
|
4
3
|
|
5
4
|
/**
|
6
5
|
* Notification Banner component
|
7
6
|
*
|
8
7
|
* @preserve
|
8
|
+
* @augments ConfigurableComponent<NotificationBannerConfig>
|
9
9
|
*/
|
10
|
-
class NotificationBanner extends
|
10
|
+
class NotificationBanner extends ConfigurableComponent {
|
11
11
|
/**
|
12
12
|
* @param {Element | null} $root - HTML element to use for notification banner
|
13
13
|
* @param {NotificationBannerConfig} [config] - Notification banner config
|
14
14
|
*/
|
15
15
|
constructor($root, config = {}) {
|
16
|
-
super($root);
|
17
|
-
this.config = void 0;
|
18
|
-
this.config = mergeConfigs(NotificationBanner.defaults, config, normaliseDataset(NotificationBanner, this.$root.dataset));
|
16
|
+
super($root, config);
|
19
17
|
if (this.$root.getAttribute('role') === 'alert' && !this.config.disableAutoFocus) {
|
20
18
|
setFocus(this.$root);
|
21
19
|
}
|
@@ -33,7 +31,7 @@ class NotificationBanner extends GOVUKFrontendComponent {
|
|
33
31
|
*/
|
34
32
|
|
35
33
|
/**
|
36
|
-
* @
|
34
|
+
* @import { Schema } from '../../common/configuration.mjs'
|
37
35
|
*/
|
38
36
|
NotificationBanner.moduleName = 'govuk-notification-banner';
|
39
37
|
NotificationBanner.defaults = Object.freeze({
|