@ministryofjustice/frontend 3.5.0 → 3.6.1

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 (37) hide show
  1. package/moj/all.jquery.min.js +1 -81
  2. package/moj/all.js +2577 -2853
  3. package/moj/all.mjs +126 -0
  4. package/moj/all.scss +1 -1
  5. package/moj/components/add-another/add-another.js +111 -132
  6. package/moj/components/add-another/add-another.mjs +106 -0
  7. package/moj/components/alert/alert.js +352 -479
  8. package/moj/components/alert/alert.mjs +251 -0
  9. package/moj/components/alert/alert.spec.helper.js +6 -24
  10. package/moj/components/alert/alert.spec.helper.mjs +66 -0
  11. package/moj/components/button-menu/button-menu.js +326 -343
  12. package/moj/components/button-menu/button-menu.mjs +329 -0
  13. package/moj/components/cookie-banner/_cookie-banner.scss +1 -1
  14. package/moj/components/date-picker/date-picker.js +905 -922
  15. package/moj/components/date-picker/date-picker.mjs +961 -0
  16. package/moj/components/filter-toggle-button/filter-toggle-button.js +98 -119
  17. package/moj/components/filter-toggle-button/filter-toggle-button.mjs +93 -0
  18. package/moj/components/form-validator/form-validator.js +201 -396
  19. package/moj/components/form-validator/form-validator.mjs +168 -0
  20. package/moj/components/multi-file-upload/multi-file-upload.js +227 -441
  21. package/moj/components/multi-file-upload/multi-file-upload.mjs +219 -0
  22. package/moj/components/multi-select/multi-select.js +82 -103
  23. package/moj/components/multi-select/multi-select.mjs +77 -0
  24. package/moj/components/password-reveal/password-reveal.js +40 -61
  25. package/moj/components/password-reveal/password-reveal.mjs +35 -0
  26. package/moj/components/rich-text-editor/rich-text-editor.js +162 -183
  27. package/moj/components/rich-text-editor/rich-text-editor.mjs +157 -0
  28. package/moj/components/search-toggle/search-toggle.js +52 -73
  29. package/moj/components/search-toggle/search-toggle.mjs +54 -0
  30. package/moj/components/sortable-table/sortable-table.js +143 -164
  31. package/moj/components/sortable-table/sortable-table.mjs +138 -0
  32. package/moj/helpers.js +196 -215
  33. package/moj/helpers.mjs +123 -0
  34. package/moj/moj-frontend.min.js +1 -81
  35. package/moj/version.js +6 -23
  36. package/moj/version.mjs +3 -0
  37. package/package.json +24 -6
@@ -1,150 +1,140 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
- typeof define === 'function' && define.amd ? define(factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.MOJFrontend = factory());
5
- })(this, (function () { 'use strict';
6
-
7
- function getDefaultExportFromCjs (x) {
8
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
9
- }
10
-
11
- /**
12
- * @typedef {object} ButtonMenuConfig
13
- * @property {string} [buttonText=Actions] - Label for the toggle button
14
- * @property {"left" | "right"} [alignMenu=left] - the alignment of the menu
15
- * @property {string} [buttonClasses=govuk-button--secondary] - css classes applied to the toggle button
16
- */
17
-
18
- var buttonMenu$1;
19
- var hasRequiredButtonMenu;
20
-
21
- function requireButtonMenu () {
22
- if (hasRequiredButtonMenu) return buttonMenu$1;
23
- hasRequiredButtonMenu = 1;
24
- /**
25
- * @param {HTMLElement} $module
26
- * @param {ButtonMenuConfig} config
27
- * @class
28
- */
29
- function ButtonMenu($module, config = {}) {
30
- if (!$module) {
31
- return this
32
- }
33
-
34
- const schema = Object.freeze({
35
- properties: {
36
- buttonText: { type: 'string' },
37
- buttonClasses: { type: 'string' },
38
- alignMenu: { type: 'string' }
39
- }
40
- });
41
-
42
- const defaults = {
43
- buttonText: 'Actions',
44
- alignMenu: 'left',
45
- buttonClasses: ''
46
- };
47
- // data attributes override JS config, which overrides defaults
48
- this.config = this.mergeConfigs(
49
- defaults,
50
- config,
51
- this.parseDataset(schema, $module.dataset)
52
- );
53
-
54
- this.$module = $module;
55
- }
56
-
57
- ButtonMenu.prototype.init = function () {
58
- // If only one button is provided, don't initiate a menu and toggle button
59
- // if classes have been provided for the toggleButton, apply them to the single item
60
- if (this.$module.children.length === 1) {
61
- const button = this.$module.children[0];
62
- button.classList.forEach((className) => {
63
- if (className.startsWith('govuk-button-')) {
64
- button.classList.remove(className);
65
- }
66
- button.classList.remove('moj-button-menu__item');
67
- });
68
- if (this.config.buttonClasses) {
69
- button.classList.add(...this.config.buttonClasses.split(' '));
70
- }
71
- }
72
- // Otherwise intialise a button menu
73
- if (this.$module.children.length > 1) {
74
- this.initMenu();
75
- }
76
- };
77
-
78
- ButtonMenu.prototype.initMenu = function () {
79
- this.$menu = this.createMenu();
80
- this.$module.insertAdjacentHTML('afterbegin', this.toggleTemplate());
81
- this.setupMenuItems();
82
-
83
- this.$menuToggle = this.$module.querySelector(':scope > button');
84
- this.items = this.$menu.querySelectorAll('a, button');
85
-
86
- this.$menuToggle.addEventListener('click', (event) => {
87
- this.toggleMenu(event);
88
- });
89
-
90
- this.$module.addEventListener('keydown', (event) => {
91
- this.handleKeyDown(event);
92
- });
93
-
94
- document.addEventListener('click', (event) => {
95
- if (!this.$module.contains(event.target)) {
96
- this.closeMenu(false);
97
- }
98
- });
99
- };
100
-
101
- ButtonMenu.prototype.createMenu = function () {
102
- const $menu = document.createElement('ul');
103
- $menu.setAttribute('role', 'list');
104
- $menu.hidden = true;
105
- $menu.classList.add('moj-button-menu__wrapper');
106
- if (this.config.alignMenu === 'right') {
107
- $menu.classList.add('moj-button-menu__wrapper--right');
108
- }
109
-
110
- this.$module.appendChild($menu);
111
- while (this.$module.firstChild !== $menu) {
112
- $menu.appendChild(this.$module.firstChild);
113
- }
114
-
115
- return $menu
116
- };
117
-
118
- ButtonMenu.prototype.setupMenuItems = function () {
119
- Array.from(this.$menu.children).forEach((item) => {
120
- // wrap item in li tag
121
- const listItem = document.createElement('li');
122
- this.$menu.insertBefore(listItem, item);
123
- listItem.appendChild(item);
124
-
125
- item.setAttribute('tabindex', -1);
126
-
127
- if (item.tagName === 'BUTTON') {
128
- item.setAttribute('type', 'button');
129
- }
130
-
131
- item.classList.forEach((className) => {
132
- if (className.startsWith('govuk-button')) {
133
- item.classList.remove(className);
134
- }
135
- });
136
-
137
- // add a slight delay after click before closing the menu, makes it *feel* better
138
- item.addEventListener('click', (event) => {
139
- setTimeout(() => {
140
- this.closeMenu(false);
141
- }, 50);
142
- });
143
- });
144
- };
145
-
146
- ButtonMenu.prototype.toggleTemplate = function () {
147
- return `
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.MOJFrontend = global.MOJFrontend || {}));
5
+ })(this, (function (exports) { 'use strict';
6
+
7
+ /**
8
+ * @typedef {object} ButtonMenuConfig
9
+ * @property {string} [buttonText=Actions] - Label for the toggle button
10
+ * @property {"left" | "right"} [alignMenu=left] - the alignment of the menu
11
+ * @property {string} [buttonClasses=govuk-button--secondary] - css classes applied to the toggle button
12
+ */
13
+
14
+ /**
15
+ * @param {HTMLElement} $module
16
+ * @param {ButtonMenuConfig} config
17
+ * @class
18
+ */
19
+ function ButtonMenu($module, config = {}) {
20
+ if (!$module) {
21
+ return this
22
+ }
23
+
24
+ const schema = Object.freeze({
25
+ properties: {
26
+ buttonText: { type: 'string' },
27
+ buttonClasses: { type: 'string' },
28
+ alignMenu: { type: 'string' }
29
+ }
30
+ });
31
+
32
+ const defaults = {
33
+ buttonText: 'Actions',
34
+ alignMenu: 'left',
35
+ buttonClasses: ''
36
+ };
37
+ // data attributes override JS config, which overrides defaults
38
+ this.config = this.mergeConfigs(
39
+ defaults,
40
+ config,
41
+ this.parseDataset(schema, $module.dataset)
42
+ );
43
+
44
+ this.$module = $module;
45
+ }
46
+
47
+ ButtonMenu.prototype.init = function () {
48
+ // If only one button is provided, don't initiate a menu and toggle button
49
+ // if classes have been provided for the toggleButton, apply them to the single item
50
+ if (this.$module.children.length === 1) {
51
+ const button = this.$module.children[0];
52
+ button.classList.forEach((className) => {
53
+ if (className.startsWith('govuk-button-')) {
54
+ button.classList.remove(className);
55
+ }
56
+ button.classList.remove('moj-button-menu__item');
57
+ });
58
+ if (this.config.buttonClasses) {
59
+ button.classList.add(...this.config.buttonClasses.split(' '));
60
+ }
61
+ }
62
+ // Otherwise intialise a button menu
63
+ if (this.$module.children.length > 1) {
64
+ this.initMenu();
65
+ }
66
+ };
67
+
68
+ ButtonMenu.prototype.initMenu = function () {
69
+ this.$menu = this.createMenu();
70
+ this.$module.insertAdjacentHTML('afterbegin', this.toggleTemplate());
71
+ this.setupMenuItems();
72
+
73
+ this.$menuToggle = this.$module.querySelector(':scope > button');
74
+ this.items = this.$menu.querySelectorAll('a, button');
75
+
76
+ this.$menuToggle.addEventListener('click', (event) => {
77
+ this.toggleMenu(event);
78
+ });
79
+
80
+ this.$module.addEventListener('keydown', (event) => {
81
+ this.handleKeyDown(event);
82
+ });
83
+
84
+ document.addEventListener('click', (event) => {
85
+ if (!this.$module.contains(event.target)) {
86
+ this.closeMenu(false);
87
+ }
88
+ });
89
+ };
90
+
91
+ ButtonMenu.prototype.createMenu = function () {
92
+ const $menu = document.createElement('ul');
93
+ $menu.setAttribute('role', 'list');
94
+ $menu.hidden = true;
95
+ $menu.classList.add('moj-button-menu__wrapper');
96
+ if (this.config.alignMenu === 'right') {
97
+ $menu.classList.add('moj-button-menu__wrapper--right');
98
+ }
99
+
100
+ this.$module.appendChild($menu);
101
+ while (this.$module.firstChild !== $menu) {
102
+ $menu.appendChild(this.$module.firstChild);
103
+ }
104
+
105
+ return $menu
106
+ };
107
+
108
+ ButtonMenu.prototype.setupMenuItems = function () {
109
+ Array.from(this.$menu.children).forEach((item) => {
110
+ // wrap item in li tag
111
+ const listItem = document.createElement('li');
112
+ this.$menu.insertBefore(listItem, item);
113
+ listItem.appendChild(item);
114
+
115
+ item.setAttribute('tabindex', -1);
116
+
117
+ if (item.tagName === 'BUTTON') {
118
+ item.setAttribute('type', 'button');
119
+ }
120
+
121
+ item.classList.forEach((className) => {
122
+ if (className.startsWith('govuk-button')) {
123
+ item.classList.remove(className);
124
+ }
125
+ });
126
+
127
+ // add a slight delay after click before closing the menu, makes it *feel* better
128
+ item.addEventListener('click', (event) => {
129
+ setTimeout(() => {
130
+ this.closeMenu(false);
131
+ }, 50);
132
+ });
133
+ });
134
+ };
135
+
136
+ ButtonMenu.prototype.toggleTemplate = function () {
137
+ return `
148
138
  <button type="button" class="govuk-button moj-button-menu__toggle-button ${this.config.buttonClasses || ''}" aria-haspopup="true" aria-expanded="false">
149
139
  <span>
150
140
  ${this.config.buttonText}
@@ -153,202 +143,195 @@
153
143
  </svg>
154
144
  </span>
155
145
  </button>`
156
- };
157
-
158
- /**
159
- * @returns {boolean}
160
- */
161
- ButtonMenu.prototype.isOpen = function () {
162
- return this.$menuToggle.getAttribute('aria-expanded') === 'true'
163
- };
164
-
165
- ButtonMenu.prototype.toggleMenu = function (event) {
166
- event.preventDefault();
167
-
168
- // If menu is triggered with mouse don't move focus to first item
169
- const keyboardEvent = event.detail === 0;
170
- const focusIndex = keyboardEvent ? 0 : -1;
171
-
172
- if (this.isOpen()) {
173
- this.closeMenu();
174
- } else {
175
- this.openMenu(focusIndex);
176
- }
177
- };
178
-
179
- /**
180
- * Opens the menu and optionally sets the focus to the item with given index
181
- *
182
- * @param {number} focusIndex - The index of the item to focus
183
- */
184
- ButtonMenu.prototype.openMenu = function (focusIndex = 0) {
185
- this.$menu.hidden = false;
186
- this.$menuToggle.setAttribute('aria-expanded', 'true');
187
- if (focusIndex !== -1) {
188
- this.focusItem(focusIndex);
189
- }
190
- };
191
-
192
- /**
193
- * Closes the menu and optionally returns focus back to menuToggle
194
- *
195
- * @param {boolean} moveFocus - whether to return focus to the toggle button
196
- */
197
- ButtonMenu.prototype.closeMenu = function (moveFocus = true) {
198
- this.$menu.hidden = true;
199
- this.$menuToggle.setAttribute('aria-expanded', 'false');
200
- if (moveFocus) {
201
- this.$menuToggle.focus();
202
- }
203
- };
204
-
205
- /**
206
- * Focuses the menu item at the specified index
207
- *
208
- * @param {number} index - the index of the item to focus
209
- */
210
- ButtonMenu.prototype.focusItem = function (index) {
211
- if (index >= this.items.length) index = 0;
212
- if (index < 0) index = this.items.length - 1;
213
-
214
- const menuItem = this.items.item(index);
215
- if (menuItem) {
216
- menuItem.focus();
217
- }
218
- };
219
-
220
- ButtonMenu.prototype.currentFocusIndex = function () {
221
- const activeElement = document.activeElement;
222
- const menuItems = Array.from(this.items);
223
-
224
- return menuItems.indexOf(activeElement)
225
- };
226
-
227
- ButtonMenu.prototype.handleKeyDown = function (event) {
228
- if (event.target === this.$menuToggle) {
229
- switch (event.key) {
230
- case 'ArrowDown':
231
- event.preventDefault();
232
- this.openMenu();
233
- break
234
- case 'ArrowUp':
235
- event.preventDefault();
236
- this.openMenu(this.items.length - 1);
237
- break
238
- }
239
- }
240
-
241
- if (this.$menu.contains(event.target) && this.isOpen()) {
242
- switch (event.key) {
243
- case 'ArrowDown':
244
- event.preventDefault();
245
- if (this.currentFocusIndex() !== -1) {
246
- this.focusItem(this.currentFocusIndex() + 1);
247
- }
248
- break
249
- case 'ArrowUp':
250
- event.preventDefault();
251
- if (this.currentFocusIndex() !== -1) {
252
- this.focusItem(this.currentFocusIndex() - 1);
253
- }
254
- break
255
- case 'Home':
256
- event.preventDefault();
257
- this.focusItem(0);
258
- break
259
- case 'End':
260
- event.preventDefault();
261
- this.focusItem(this.items.length - 1);
262
- break
263
- }
264
- }
265
-
266
- if (event.key === 'Escape' && this.isOpen()) {
267
- this.closeMenu();
268
- }
269
- if (event.key === 'Tab' && this.isOpen()) {
270
- this.closeMenu(false);
271
- }
272
- };
273
-
274
- /**
275
- * Parse dataset
276
- *
277
- * Loop over an object and normalise each value using {@link normaliseString},
278
- * optionally expanding nested `i18n.field`
279
- *
280
- * @param {Schema} schema - component schema
281
- * @param {DOMStringMap} dataset - HTML element dataset
282
- * @returns {object} Normalised dataset
283
- */
284
- ButtonMenu.prototype.parseDataset = function (schema, dataset) {
285
- const parsed = {};
286
-
287
- for (const [field, ,] of Object.entries(schema.properties)) {
288
- if (field in dataset) {
289
- if (dataset[field]) {
290
- parsed[field] = dataset[field];
291
- }
292
- }
293
- }
294
-
295
- return parsed
296
- };
297
-
298
- /**
299
- * Config merging function
300
- *
301
- * Takes any number of objects and combines them together, with
302
- * greatest priority on the LAST item passed in.
303
- *
304
- * @param {...{ [key: string]: unknown }} configObjects - Config objects to merge
305
- * @returns {{ [key: string]: unknown }} A merged config object
306
- */
307
- ButtonMenu.prototype.mergeConfigs = function (...configObjects) {
308
- const formattedConfigObject = {};
309
-
310
- // Loop through each of the passed objects
311
- for (const configObject of configObjects) {
312
- for (const key of Object.keys(configObject)) {
313
- const option = formattedConfigObject[key];
314
- const override = configObject[key];
315
-
316
- // Push their keys one-by-one into formattedConfigObject. Any duplicate
317
- // keys with object values will be merged, otherwise the new value will
318
- // override the existing value.
319
- if (typeof option === 'object' && typeof override === 'object') {
320
- // @ts-expect-error Index signature for type 'string' is missing
321
- formattedConfigObject[key] = this.mergeConfigs(option, override);
322
- } else {
323
- formattedConfigObject[key] = override;
324
- }
325
- }
326
- }
327
-
328
- return formattedConfigObject
329
- };
330
-
331
- buttonMenu$1 = { ButtonMenu };
332
-
333
- /**
334
- * Schema for component config
335
- *
336
- * @typedef {object} Schema
337
- * @property {{ [field: string]: SchemaProperty | undefined }} properties - Schema properties
338
- */
339
-
340
- /**
341
- * Schema property for component config
342
- *
343
- * @typedef {object} SchemaProperty
344
- * @property {'string' | 'boolean' | 'number' | 'object'} type - Property type
345
- */
346
- return buttonMenu$1;
347
- }
348
-
349
- var buttonMenuExports = requireButtonMenu();
350
- var buttonMenu = /*@__PURE__*/getDefaultExportFromCjs(buttonMenuExports);
351
-
352
- return buttonMenu;
146
+ };
147
+
148
+ /**
149
+ * @returns {boolean}
150
+ */
151
+ ButtonMenu.prototype.isOpen = function () {
152
+ return this.$menuToggle.getAttribute('aria-expanded') === 'true'
153
+ };
154
+
155
+ ButtonMenu.prototype.toggleMenu = function (event) {
156
+ event.preventDefault();
157
+
158
+ // If menu is triggered with mouse don't move focus to first item
159
+ const keyboardEvent = event.detail === 0;
160
+ const focusIndex = keyboardEvent ? 0 : -1;
161
+
162
+ if (this.isOpen()) {
163
+ this.closeMenu();
164
+ } else {
165
+ this.openMenu(focusIndex);
166
+ }
167
+ };
168
+
169
+ /**
170
+ * Opens the menu and optionally sets the focus to the item with given index
171
+ *
172
+ * @param {number} focusIndex - The index of the item to focus
173
+ */
174
+ ButtonMenu.prototype.openMenu = function (focusIndex = 0) {
175
+ this.$menu.hidden = false;
176
+ this.$menuToggle.setAttribute('aria-expanded', 'true');
177
+ if (focusIndex !== -1) {
178
+ this.focusItem(focusIndex);
179
+ }
180
+ };
181
+
182
+ /**
183
+ * Closes the menu and optionally returns focus back to menuToggle
184
+ *
185
+ * @param {boolean} moveFocus - whether to return focus to the toggle button
186
+ */
187
+ ButtonMenu.prototype.closeMenu = function (moveFocus = true) {
188
+ this.$menu.hidden = true;
189
+ this.$menuToggle.setAttribute('aria-expanded', 'false');
190
+ if (moveFocus) {
191
+ this.$menuToggle.focus();
192
+ }
193
+ };
194
+
195
+ /**
196
+ * Focuses the menu item at the specified index
197
+ *
198
+ * @param {number} index - the index of the item to focus
199
+ */
200
+ ButtonMenu.prototype.focusItem = function (index) {
201
+ if (index >= this.items.length) index = 0;
202
+ if (index < 0) index = this.items.length - 1;
203
+
204
+ const menuItem = this.items.item(index);
205
+ if (menuItem) {
206
+ menuItem.focus();
207
+ }
208
+ };
209
+
210
+ ButtonMenu.prototype.currentFocusIndex = function () {
211
+ const activeElement = document.activeElement;
212
+ const menuItems = Array.from(this.items);
213
+
214
+ return menuItems.indexOf(activeElement)
215
+ };
216
+
217
+ ButtonMenu.prototype.handleKeyDown = function (event) {
218
+ if (event.target === this.$menuToggle) {
219
+ switch (event.key) {
220
+ case 'ArrowDown':
221
+ event.preventDefault();
222
+ this.openMenu();
223
+ break
224
+ case 'ArrowUp':
225
+ event.preventDefault();
226
+ this.openMenu(this.items.length - 1);
227
+ break
228
+ }
229
+ }
230
+
231
+ if (this.$menu.contains(event.target) && this.isOpen()) {
232
+ switch (event.key) {
233
+ case 'ArrowDown':
234
+ event.preventDefault();
235
+ if (this.currentFocusIndex() !== -1) {
236
+ this.focusItem(this.currentFocusIndex() + 1);
237
+ }
238
+ break
239
+ case 'ArrowUp':
240
+ event.preventDefault();
241
+ if (this.currentFocusIndex() !== -1) {
242
+ this.focusItem(this.currentFocusIndex() - 1);
243
+ }
244
+ break
245
+ case 'Home':
246
+ event.preventDefault();
247
+ this.focusItem(0);
248
+ break
249
+ case 'End':
250
+ event.preventDefault();
251
+ this.focusItem(this.items.length - 1);
252
+ break
253
+ }
254
+ }
255
+
256
+ if (event.key === 'Escape' && this.isOpen()) {
257
+ this.closeMenu();
258
+ }
259
+ if (event.key === 'Tab' && this.isOpen()) {
260
+ this.closeMenu(false);
261
+ }
262
+ };
263
+
264
+ /**
265
+ * Parse dataset
266
+ *
267
+ * Loop over an object and normalise each value using {@link normaliseString},
268
+ * optionally expanding nested `i18n.field`
269
+ *
270
+ * @param {Schema} schema - component schema
271
+ * @param {DOMStringMap} dataset - HTML element dataset
272
+ * @returns {object} Normalised dataset
273
+ */
274
+ ButtonMenu.prototype.parseDataset = function (schema, dataset) {
275
+ const parsed = {};
276
+
277
+ for (const [field, ,] of Object.entries(schema.properties)) {
278
+ if (field in dataset) {
279
+ if (dataset[field]) {
280
+ parsed[field] = dataset[field];
281
+ }
282
+ }
283
+ }
284
+
285
+ return parsed
286
+ };
287
+
288
+ /**
289
+ * Config merging function
290
+ *
291
+ * Takes any number of objects and combines them together, with
292
+ * greatest priority on the LAST item passed in.
293
+ *
294
+ * @param {...{ [key: string]: unknown }} configObjects - Config objects to merge
295
+ * @returns {{ [key: string]: unknown }} A merged config object
296
+ */
297
+ ButtonMenu.prototype.mergeConfigs = function (...configObjects) {
298
+ const formattedConfigObject = {};
299
+
300
+ // Loop through each of the passed objects
301
+ for (const configObject of configObjects) {
302
+ for (const key of Object.keys(configObject)) {
303
+ const option = formattedConfigObject[key];
304
+ const override = configObject[key];
305
+
306
+ // Push their keys one-by-one into formattedConfigObject. Any duplicate
307
+ // keys with object values will be merged, otherwise the new value will
308
+ // override the existing value.
309
+ if (typeof option === 'object' && typeof override === 'object') {
310
+ // @ts-expect-error Index signature for type 'string' is missing
311
+ formattedConfigObject[key] = this.mergeConfigs(option, override);
312
+ } else {
313
+ formattedConfigObject[key] = override;
314
+ }
315
+ }
316
+ }
317
+
318
+ return formattedConfigObject
319
+ };
320
+
321
+ /**
322
+ * Schema for component config
323
+ *
324
+ * @typedef {object} Schema
325
+ * @property {{ [field: string]: SchemaProperty | undefined }} properties - Schema properties
326
+ */
327
+
328
+ /**
329
+ * Schema property for component config
330
+ *
331
+ * @typedef {object} SchemaProperty
332
+ * @property {'string' | 'boolean' | 'number' | 'object'} type - Property type
333
+ */
334
+
335
+ exports.ButtonMenu = ButtonMenu;
353
336
 
354
337
  }));