@ministryofjustice/frontend 3.4.0 → 3.6.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.
- package/moj/all.jquery.js +13378 -0
- package/moj/all.jquery.min.js +1 -144
- package/moj/all.js +2266 -2551
- package/moj/all.mjs +126 -0
- package/moj/components/add-another/add-another.js +110 -100
- package/moj/components/add-another/add-another.mjs +106 -0
- package/moj/components/alert/alert.js +319 -211
- package/moj/components/alert/alert.mjs +251 -0
- package/moj/components/alert/alert.spec.helper.js +12 -5
- package/moj/components/alert/alert.spec.helper.mjs +66 -0
- package/moj/components/button-menu/button-menu.js +302 -292
- package/moj/components/button-menu/button-menu.mjs +329 -0
- package/moj/components/date-picker/date-picker.js +850 -842
- package/moj/components/date-picker/date-picker.mjs +961 -0
- package/moj/components/filter-toggle-button/filter-toggle-button.js +98 -88
- package/moj/components/filter-toggle-button/filter-toggle-button.mjs +93 -0
- package/moj/components/form-validator/form-validator.js +195 -155
- package/moj/components/form-validator/form-validator.mjs +168 -0
- package/moj/components/multi-file-upload/multi-file-upload.js +158 -137
- package/moj/components/multi-file-upload/multi-file-upload.mjs +219 -0
- package/moj/components/multi-select/multi-select.js +75 -65
- package/moj/components/multi-select/multi-select.mjs +77 -0
- package/moj/components/password-reveal/password-reveal.js +40 -30
- package/moj/components/password-reveal/password-reveal.mjs +35 -0
- package/moj/components/rich-text-editor/rich-text-editor.js +92 -80
- package/moj/components/rich-text-editor/rich-text-editor.mjs +157 -0
- package/moj/components/search-toggle/search-toggle.js +55 -45
- package/moj/components/search-toggle/search-toggle.mjs +54 -0
- package/moj/components/sortable-table/sortable-table.js +141 -141
- package/moj/components/sortable-table/sortable-table.mjs +138 -0
- package/moj/helpers/_links.scss +1 -1
- package/moj/helpers.js +171 -152
- package/moj/helpers.mjs +123 -0
- package/moj/moj-frontend.min.js +1 -144
- package/moj/version.js +11 -1
- package/moj/version.mjs +3 -0
- package/package.json +13 -1
- package/moj/all.spec.js +0 -24
- package/moj/components/add-another/add-another.spec.js +0 -165
- package/moj/components/alert/alert.spec.js +0 -229
- package/moj/components/button-menu/button-menu.spec.js +0 -360
- package/moj/components/date-picker/date-picker.spec.js +0 -1178
- package/moj/components/filter-toggle-button/filter-toggle-button.spec.js +0 -302
- package/moj/components/multi-file-upload/multi-file-upload.spec.js +0 -510
- package/moj/components/multi-select/multi-select.spec.js +0 -128
- package/moj/components/password-reveal/password-reveal.spec.js +0 -57
- package/moj/components/search-toggle/search-toggle.spec.js +0 -129
- package/moj/components/sortable-table/sortable-table.spec.js +0 -362
- package/moj/helpers.spec.js +0 -235
- package/moj/namespace.js +0 -2
|
@@ -1,134 +1,140 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
alignMenu: { type: 'string' }
|
|
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.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
|
|
23
22
|
}
|
|
24
|
-
})
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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;
|
|
30
45
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
this.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const button = this.$module.children[0]
|
|
46
|
-
button.classList.forEach((className) => {
|
|
47
|
-
if (className.startsWith('govuk-button-')) {
|
|
48
|
-
button.classList.remove(className)
|
|
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(' '));
|
|
49
60
|
}
|
|
50
|
-
button.classList.remove('moj-button-menu__item')
|
|
51
|
-
})
|
|
52
|
-
if (this.config.buttonClasses) {
|
|
53
|
-
button.classList.add(...this.config.buttonClasses.split(' '))
|
|
54
61
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
}
|
|
62
|
+
// Otherwise intialise a button menu
|
|
63
|
+
if (this.$module.children.length > 1) {
|
|
64
|
+
this.initMenu();
|
|
65
|
+
}
|
|
66
|
+
};
|
|
61
67
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
68
|
+
ButtonMenu.prototype.initMenu = function () {
|
|
69
|
+
this.$menu = this.createMenu();
|
|
70
|
+
this.$module.insertAdjacentHTML('afterbegin', this.toggleTemplate());
|
|
71
|
+
this.setupMenuItems();
|
|
66
72
|
|
|
67
|
-
|
|
68
|
-
|
|
73
|
+
this.$menuToggle = this.$module.querySelector(':scope > button');
|
|
74
|
+
this.items = this.$menu.querySelectorAll('a, button');
|
|
69
75
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
76
|
+
this.$menuToggle.addEventListener('click', (event) => {
|
|
77
|
+
this.toggleMenu(event);
|
|
78
|
+
});
|
|
73
79
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
80
|
+
this.$module.addEventListener('keydown', (event) => {
|
|
81
|
+
this.handleKeyDown(event);
|
|
82
|
+
});
|
|
77
83
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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');
|
|
81
98
|
}
|
|
82
|
-
})
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
MOJFrontend.ButtonMenu.prototype.createMenu = function () {
|
|
86
|
-
const $menu = document.createElement('ul')
|
|
87
|
-
$menu.setAttribute('role', 'list')
|
|
88
|
-
$menu.hidden = true
|
|
89
|
-
$menu.classList.add('moj-button-menu__wrapper')
|
|
90
|
-
if (this.config.alignMenu === 'right') {
|
|
91
|
-
$menu.classList.add('moj-button-menu__wrapper--right')
|
|
92
|
-
}
|
|
93
99
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
return $menu
|
|
100
|
-
}
|
|
100
|
+
this.$module.appendChild($menu);
|
|
101
|
+
while (this.$module.firstChild !== $menu) {
|
|
102
|
+
$menu.appendChild(this.$module.firstChild);
|
|
103
|
+
}
|
|
101
104
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
// wrap item in li tag
|
|
105
|
-
const listItem = document.createElement('li')
|
|
106
|
-
this.$menu.insertBefore(listItem, item)
|
|
107
|
-
listItem.appendChild(item)
|
|
105
|
+
return $menu
|
|
106
|
+
};
|
|
108
107
|
|
|
109
|
-
|
|
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);
|
|
110
114
|
|
|
111
|
-
|
|
112
|
-
item.setAttribute('type', 'button')
|
|
113
|
-
}
|
|
115
|
+
item.setAttribute('tabindex', -1);
|
|
114
116
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
item.classList.remove(className)
|
|
117
|
+
if (item.tagName === 'BUTTON') {
|
|
118
|
+
item.setAttribute('type', 'button');
|
|
118
119
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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 `
|
|
132
138
|
<button type="button" class="govuk-button moj-button-menu__toggle-button ${this.config.buttonClasses || ''}" aria-haspopup="true" aria-expanded="false">
|
|
133
139
|
<span>
|
|
134
140
|
${this.config.buttonText}
|
|
@@ -137,191 +143,195 @@ MOJFrontend.ButtonMenu.prototype.toggleTemplate = function () {
|
|
|
137
143
|
</svg>
|
|
138
144
|
</span>
|
|
139
145
|
</button>`
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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
|
+
}
|
|
222
229
|
}
|
|
223
|
-
}
|
|
224
230
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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
|
+
}
|
|
247
254
|
}
|
|
248
|
-
}
|
|
249
255
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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
|
+
}
|
|
275
282
|
}
|
|
276
283
|
}
|
|
277
|
-
}
|
|
278
284
|
|
|
279
|
-
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
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
|
+
}
|
|
308
315
|
}
|
|
309
316
|
}
|
|
310
|
-
}
|
|
311
317
|
|
|
312
|
-
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
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;
|
|
336
|
+
|
|
337
|
+
}));
|