mithril-materialized 3.15.0 → 3.17.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/README.md +32 -2
- package/dist/advanced.css +109 -4
- package/dist/button.d.ts +3 -1
- package/dist/circular-progress.d.ts +2 -2
- package/dist/combobox.d.ts +35 -0
- package/dist/components.css +144 -17
- package/dist/core.css +278 -3
- package/dist/floating-action-button.d.ts +2 -1
- package/dist/form-section.d.ts +35 -0
- package/dist/forms.css +280 -5
- package/dist/index.css +357 -22
- package/dist/index.d.ts +3 -2
- package/dist/index.esm.js +728 -299
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +741 -298
- package/dist/index.js.map +1 -0
- package/dist/index.min.css +2 -2
- package/dist/index.umd.js +741 -298
- package/dist/index.umd.js.map +1 -0
- package/dist/input-options.d.ts +4 -1
- package/dist/likert-scale.d.ts +2 -1
- package/dist/linear-progress.d.ts +2 -2
- package/dist/material-icon.d.ts +2 -1
- package/dist/radio.d.ts +9 -0
- package/dist/range-slider.d.ts +3 -2
- package/dist/rating.d.ts +2 -1
- package/dist/search-select.d.ts +15 -2
- package/dist/select.d.ts +14 -1
- package/dist/sidenav.d.ts +11 -1
- package/dist/treeview.d.ts +2 -2
- package/dist/types.d.ts +5 -0
- package/dist/utilities.css +93 -2
- package/dist/utils.d.ts +30 -1
- package/package.json +20 -20
- package/sass/components/_badge-component.scss +8 -0
- package/sass/components/_buttons.scss +9 -9
- package/sass/components/_global.scss +93 -0
- package/sass/components/_likert-scale.scss +24 -0
- package/sass/components/_sidenav.scss +21 -3
- package/sass/components/_theme-variables.scss +22 -1
- package/sass/components/_toggle-group.scss +3 -0
- package/sass/components/forms/_form-groups.scss +1 -1
- package/sass/components/forms/_form-section.scss +63 -0
- package/sass/components/forms/_forms.scss +1 -0
- package/sass/components/forms/_input-fields.scss +55 -0
- package/sass/components/forms/_range-enhanced.scss +3 -3
- package/sass/components/forms/_select.scss +85 -0
package/dist/index.js
CHANGED
|
@@ -36,6 +36,35 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
36
36
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
+
// import './styles/input.css';
|
|
40
|
+
const Mandatory = { view: ({ attrs }) => m('span.mandatory', Object.assign({}, attrs), '*') };
|
|
41
|
+
/** Simple label element, used for most components. */
|
|
42
|
+
const Label = () => {
|
|
43
|
+
return {
|
|
44
|
+
view: (_a) => {
|
|
45
|
+
var _b = _a.attrs, { label, id, isMandatory, isActive, className, initialValue } = _b, params = __rest(_b, ["label", "id", "isMandatory", "isActive", "className", "initialValue"]);
|
|
46
|
+
return label
|
|
47
|
+
? m('label', Object.assign(Object.assign({}, params), { className: [className, isActive ? 'active' : ''].filter(Boolean).join(' ').trim() || undefined, for: id, oncreate: ({ dom }) => {
|
|
48
|
+
if (!initialValue)
|
|
49
|
+
return;
|
|
50
|
+
const labelEl = dom;
|
|
51
|
+
labelEl.classList.add('active');
|
|
52
|
+
} }), [m.trust(label), isMandatory ? m(Mandatory) : undefined])
|
|
53
|
+
: undefined;
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
/** Create a helper text, often used for displaying a small help text. May be replaced by the validation message. */
|
|
58
|
+
const HelperText = () => {
|
|
59
|
+
return {
|
|
60
|
+
view: ({ attrs: { helperText, dataError, dataSuccess, className } }) => {
|
|
61
|
+
return helperText || dataError || dataSuccess
|
|
62
|
+
? m('span.helper-text.left', { className, 'data-error': dataError, 'data-success': dataSuccess }, dataError ? m.trust(dataError) : dataSuccess ? m.trust(dataSuccess) : helperText ? m.trust(helperText) : '')
|
|
63
|
+
: undefined;
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
|
|
39
68
|
// Utility functions for the library
|
|
40
69
|
/**
|
|
41
70
|
* Create a unique ID
|
|
@@ -96,6 +125,42 @@ const sortOptions = (options, sortConfig) => {
|
|
|
96
125
|
* @returns
|
|
97
126
|
*/
|
|
98
127
|
const padLeft = (n, width = 2, z = '0') => String(n).padStart(width, z);
|
|
128
|
+
const normalizeSelection = (value) => {
|
|
129
|
+
if (value === undefined) {
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
return Array.isArray(value) ? value : [value];
|
|
133
|
+
};
|
|
134
|
+
const resolveControllableValue = ({ controlled, disabled, controlledValue, defaultValue, internalValue, fallbackValue, }) => {
|
|
135
|
+
var _a, _b;
|
|
136
|
+
if (controlled) {
|
|
137
|
+
return controlledValue !== null && controlledValue !== void 0 ? controlledValue : fallbackValue;
|
|
138
|
+
}
|
|
139
|
+
if (disabled) {
|
|
140
|
+
return (_a = defaultValue !== null && defaultValue !== void 0 ? defaultValue : controlledValue) !== null && _a !== void 0 ? _a : fallbackValue;
|
|
141
|
+
}
|
|
142
|
+
return (_b = internalValue !== null && internalValue !== void 0 ? internalValue : defaultValue) !== null && _b !== void 0 ? _b : fallbackValue;
|
|
143
|
+
};
|
|
144
|
+
const renderFieldChrome = ({ label, id, isMandatory, isActive, initialValue, helperText, dataError, dataSuccess, }) => {
|
|
145
|
+
return [
|
|
146
|
+
label
|
|
147
|
+
? m(Label, {
|
|
148
|
+
label,
|
|
149
|
+
id,
|
|
150
|
+
isMandatory,
|
|
151
|
+
isActive,
|
|
152
|
+
initialValue,
|
|
153
|
+
})
|
|
154
|
+
: undefined,
|
|
155
|
+
helperText || dataError || dataSuccess
|
|
156
|
+
? m(HelperText, {
|
|
157
|
+
helperText,
|
|
158
|
+
dataError,
|
|
159
|
+
dataSuccess,
|
|
160
|
+
})
|
|
161
|
+
: undefined,
|
|
162
|
+
].filter(Boolean);
|
|
163
|
+
};
|
|
99
164
|
// Keep only essential dropdown positioning styles
|
|
100
165
|
const getDropdownStyles = (inputRef, overlap = false, options, isDropDown = false) => {
|
|
101
166
|
if (!inputRef) {
|
|
@@ -127,8 +192,10 @@ const getDropdownStyles = (inputRef, overlap = false, options, isDropDown = fals
|
|
|
127
192
|
groups.add(option.group);
|
|
128
193
|
}
|
|
129
194
|
});
|
|
130
|
-
//
|
|
131
|
-
|
|
195
|
+
// Match the select dropdown's CSS max-height. Positioning with the full
|
|
196
|
+
// option count would otherwise leave a gap above an input near the bottom
|
|
197
|
+
// of the viewport when the rendered menu is capped at 400px.
|
|
198
|
+
estimatedHeight = Math.min(totalOptions * itemHeight + groups.size * groupHeaderHeight, 400);
|
|
132
199
|
}
|
|
133
200
|
const spaceBelow = viewportHeight - rect.bottom;
|
|
134
201
|
const spaceAbove = rect.top;
|
|
@@ -144,33 +211,26 @@ const getDropdownStyles = (inputRef, overlap = false, options, isDropDown = fals
|
|
|
144
211
|
const needsScrolling = estimatedHeight > effectiveAvailableSpace;
|
|
145
212
|
// Calculate the actual height the dropdown will take
|
|
146
213
|
const actualHeight = needsScrolling ? effectiveAvailableSpace : estimatedHeight;
|
|
147
|
-
// Calculate positioning when dropdown should appear above
|
|
148
|
-
let topOffset;
|
|
149
|
-
if (shouldPositionAbove) {
|
|
150
|
-
// Calculate how much space we actually have from top of viewport to top of input
|
|
151
|
-
const availableSpaceFromViewportTop = rect.top;
|
|
152
|
-
// If dropdown fits comfortably above input, use normal positioning
|
|
153
|
-
if (actualHeight <= availableSpaceFromViewportTop) {
|
|
154
|
-
topOffset = 12 - actualHeight + (isDropDown ? itemHeight : 0); // Bottom of dropdown aligns with top of input
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
// If dropdown is too tall, position it at the very top of viewport
|
|
158
|
-
// This makes the dropdown use all available space from viewport top to input top
|
|
159
|
-
topOffset = -availableSpaceFromViewportTop + 5; // 5px margin from viewport top
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
topOffset = overlap ? 0 : '100%';
|
|
164
|
-
}
|
|
165
214
|
const styles = {
|
|
166
215
|
display: 'block',
|
|
167
216
|
opacity: 1,
|
|
168
217
|
position: 'absolute',
|
|
169
|
-
top: typeof topOffset === 'number' ? `${topOffset}px` : topOffset,
|
|
170
218
|
left: '0',
|
|
171
219
|
zIndex: 1000,
|
|
172
220
|
width: `${rect.width}px`,
|
|
173
221
|
};
|
|
222
|
+
if (shouldPositionAbove) {
|
|
223
|
+
// This menu is absolutely positioned inside the select wrapper. A negative
|
|
224
|
+
// `top` calculated from viewport coordinates becomes wrong when an ancestor
|
|
225
|
+
// scrolls (as ScenarioSpark's main area does). Anchor the menu to its local
|
|
226
|
+
// containing block instead; its height can then change without detaching it
|
|
227
|
+
// from the input.
|
|
228
|
+
styles.top = 'auto';
|
|
229
|
+
styles.bottom = `${isDropDown ? -18 : inputRef.offsetHeight - 12}px`;
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
styles.top = overlap ? 0 : '100%';
|
|
233
|
+
}
|
|
174
234
|
// Only add scrolling constraints when necessary
|
|
175
235
|
if (needsScrolling) {
|
|
176
236
|
styles.maxHeight = `${actualHeight}px`;
|
|
@@ -237,9 +297,17 @@ const releasePortalContainer = (id) => {
|
|
|
237
297
|
* @param zIndex - Z-index for portal container (default: 1004)
|
|
238
298
|
*/
|
|
239
299
|
const renderToPortal = (containerId, vnode, zIndex = 1004) => {
|
|
240
|
-
const
|
|
300
|
+
const existingContainer = portalContainers.get(containerId);
|
|
301
|
+
const container = existingContainer ? existingContainer.element : getPortalContainer(containerId, zIndex);
|
|
241
302
|
m.render(container, vnode);
|
|
242
303
|
};
|
|
304
|
+
const syncPortalContent = ({ containerId, shouldRender, vnode, zIndex = 1004 }) => {
|
|
305
|
+
if (!shouldRender || vnode === null) {
|
|
306
|
+
clearPortal(containerId);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
renderToPortal(containerId, vnode, zIndex);
|
|
310
|
+
};
|
|
243
311
|
/**
|
|
244
312
|
* Clears portal content and releases container reference.
|
|
245
313
|
* If this is the last reference, the container will be removed from the DOM.
|
|
@@ -254,35 +322,6 @@ const clearPortal = (containerId) => {
|
|
|
254
322
|
}
|
|
255
323
|
};
|
|
256
324
|
|
|
257
|
-
// import './styles/input.css';
|
|
258
|
-
const Mandatory = { view: ({ attrs }) => m('span.mandatory', Object.assign({}, attrs), '*') };
|
|
259
|
-
/** Simple label element, used for most components. */
|
|
260
|
-
const Label = () => {
|
|
261
|
-
return {
|
|
262
|
-
view: (_a) => {
|
|
263
|
-
var _b = _a.attrs, { label, id, isMandatory, isActive, className, initialValue } = _b, params = __rest(_b, ["label", "id", "isMandatory", "isActive", "className", "initialValue"]);
|
|
264
|
-
return label
|
|
265
|
-
? m('label', Object.assign(Object.assign({}, params), { className: [className, isActive ? 'active' : ''].filter(Boolean).join(' ').trim() || undefined, for: id, oncreate: ({ dom }) => {
|
|
266
|
-
if (!initialValue)
|
|
267
|
-
return;
|
|
268
|
-
const labelEl = dom;
|
|
269
|
-
labelEl.classList.add('active');
|
|
270
|
-
} }), [m.trust(label), isMandatory ? m(Mandatory) : undefined])
|
|
271
|
-
: undefined;
|
|
272
|
-
},
|
|
273
|
-
};
|
|
274
|
-
};
|
|
275
|
-
/** Create a helper text, often used for displaying a small help text. May be replaced by the validation message. */
|
|
276
|
-
const HelperText = () => {
|
|
277
|
-
return {
|
|
278
|
-
view: ({ attrs: { helperText, dataError, dataSuccess, className } }) => {
|
|
279
|
-
return helperText || dataError || dataSuccess
|
|
280
|
-
? m('span.helper-text.left', { className, 'data-error': dataError, 'data-success': dataSuccess }, dataError ? m.trust(dataError) : dataSuccess ? m.trust(dataSuccess) : helperText ? m.trust(helperText) : '')
|
|
281
|
-
: undefined;
|
|
282
|
-
},
|
|
283
|
-
};
|
|
284
|
-
};
|
|
285
|
-
|
|
286
325
|
/** Component to auto complete your text input - Pure Mithril implementation */
|
|
287
326
|
const Autocomplete = () => {
|
|
288
327
|
const state = {
|
|
@@ -305,6 +344,28 @@ const Autocomplete = () => {
|
|
|
305
344
|
.slice(0, limit);
|
|
306
345
|
return filtered;
|
|
307
346
|
};
|
|
347
|
+
const highlightMatch = (text, query) => {
|
|
348
|
+
if (!query) {
|
|
349
|
+
return text;
|
|
350
|
+
}
|
|
351
|
+
const lowerText = text.toLowerCase();
|
|
352
|
+
const lowerQuery = query.toLowerCase();
|
|
353
|
+
const nodes = [];
|
|
354
|
+
let start = 0;
|
|
355
|
+
let index = lowerText.indexOf(lowerQuery, start);
|
|
356
|
+
while (index !== -1) {
|
|
357
|
+
if (index > start) {
|
|
358
|
+
nodes.push(text.slice(start, index));
|
|
359
|
+
}
|
|
360
|
+
nodes.push(m('span.highlight', text.slice(index, index + query.length)));
|
|
361
|
+
start = index + query.length;
|
|
362
|
+
index = lowerText.indexOf(lowerQuery, start);
|
|
363
|
+
}
|
|
364
|
+
if (start < text.length) {
|
|
365
|
+
nodes.push(text.slice(start));
|
|
366
|
+
}
|
|
367
|
+
return nodes.length > 0 ? nodes : text;
|
|
368
|
+
};
|
|
308
369
|
const selectSuggestion = (suggestion, attrs) => {
|
|
309
370
|
const controlled = isControlled(attrs);
|
|
310
371
|
// Update internal state for uncontrolled mode
|
|
@@ -410,7 +471,6 @@ const Autocomplete = () => {
|
|
|
410
471
|
Object.keys(data).some((key) => key.toLowerCase() === currentValue.toLowerCase());
|
|
411
472
|
// Only open dropdown if there are suggestions and no perfect match
|
|
412
473
|
state.isOpen = state.suggestions.length > 0 && currentValue.length >= minLength && !hasExactMatch;
|
|
413
|
-
const replacer = new RegExp(`(${currentValue})`, 'i');
|
|
414
474
|
return m('.input-field.autocomplete-wrapper', {
|
|
415
475
|
className: cn,
|
|
416
476
|
style,
|
|
@@ -491,9 +551,7 @@ const Autocomplete = () => {
|
|
|
491
551
|
},
|
|
492
552
|
}, suggestion.value.replace('icon:', ''))
|
|
493
553
|
: null,
|
|
494
|
-
m('span', suggestion.key
|
|
495
|
-
? m.trust(suggestion.key.replace(replacer, (i) => `<span class="highlight">${i}</span>`))
|
|
496
|
-
: ''),
|
|
554
|
+
m('span', suggestion.key ? highlightMatch(suggestion.key, currentValue) : ''),
|
|
497
555
|
]))),
|
|
498
556
|
m(Label, {
|
|
499
557
|
label,
|
|
@@ -720,7 +778,7 @@ WavesEffect.onTouchEnd = (e) => {
|
|
|
720
778
|
/**
|
|
721
779
|
* A factory to create new buttons.
|
|
722
780
|
*
|
|
723
|
-
* @example FlatButton = ButtonFactory('
|
|
781
|
+
* @example FlatButton = ButtonFactory('button.waves-effect.waves-teal.btn-flat');
|
|
724
782
|
*/
|
|
725
783
|
const ButtonFactory = (element, defaultClassNames, type = '') => {
|
|
726
784
|
return () => {
|
|
@@ -743,15 +801,21 @@ const ButtonFactory = (element, defaultClassNames, type = '') => {
|
|
|
743
801
|
ontouchend: WavesEffect.onTouchEnd,
|
|
744
802
|
}
|
|
745
803
|
: {};
|
|
746
|
-
|
|
804
|
+
const tagName = element.split(/[.#]/)[0] || element;
|
|
805
|
+
const elementSuffix = element.slice(tagName.length);
|
|
806
|
+
const isLink = Boolean(attrs.href);
|
|
807
|
+
const renderedElement = `${isLink ? 'a' : 'button'}${elementSuffix}`;
|
|
808
|
+
return m(renderedElement, Object.assign(Object.assign(Object.assign({}, params), wavesHandlers), { className: cn, 'data-position': tooltip ? position : undefined, 'data-tooltip': tooltip || undefined,
|
|
809
|
+
// Links retain native navigation semantics and must not have a button type.
|
|
810
|
+
type: isLink ? undefined : buttonType }), iconName ? m(Icon, { iconName, className: iconClass !== undefined ? iconClass : 'left' }) : undefined, label ? label : undefined, children);
|
|
747
811
|
},
|
|
748
812
|
};
|
|
749
813
|
};
|
|
750
814
|
};
|
|
751
|
-
const Button = ButtonFactory('
|
|
752
|
-
const LargeButton = ButtonFactory('
|
|
753
|
-
const SmallButton = ButtonFactory('
|
|
754
|
-
const FlatButton = ButtonFactory('
|
|
815
|
+
const Button = ButtonFactory('button', 'waves-effect waves-light btn', 'button');
|
|
816
|
+
const LargeButton = ButtonFactory('button', 'waves-effect waves-light btn-large', 'button');
|
|
817
|
+
const SmallButton = ButtonFactory('button', 'waves-effect waves-light btn-small', 'button');
|
|
818
|
+
const FlatButton = ButtonFactory('button', 'waves-effect waves-teal btn-flat', 'button');
|
|
755
819
|
const IconButton = ButtonFactory('button', 'btn-flat btn-icon waves-effect waves-teal', 'button');
|
|
756
820
|
const RoundIconButton = ButtonFactory('button', 'btn-floating btn-large waves-effect waves-light', 'button');
|
|
757
821
|
const SubmitButton = ButtonFactory('button', 'btn waves-effect waves-light', 'submit');
|
|
@@ -808,7 +872,7 @@ const ConfirmButton = () => {
|
|
|
808
872
|
// Add square styling for icon-only confirming state
|
|
809
873
|
const buttonStyle = !label && isConfirming
|
|
810
874
|
? Object.assign(Object.assign({}, props.style), { width: '36px', height: '36px', padding: '0', minWidth: '28px', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', borderRadius: '2px' }) : props.style;
|
|
811
|
-
return m(ButtonComponent, Object.assign(Object.assign({}, props), { style: buttonStyle, className: `${props.className || ''} ${cn}`, iconName: currentIconName, iconClass: label ?
|
|
875
|
+
return m(ButtonComponent, Object.assign(Object.assign({}, props), { style: buttonStyle, className: `${props.className || ''} ${cn}`, iconName: currentIconName, iconClass: label ? iconClass || 'left' : '', label, onclick: handleClick }));
|
|
812
876
|
},
|
|
813
877
|
};
|
|
814
878
|
};
|
|
@@ -1275,11 +1339,19 @@ const MaterialIcon = () => {
|
|
|
1275
1339
|
};
|
|
1276
1340
|
const rotation = (_a = rotationMap[direction]) !== null && _a !== void 0 ? _a : 0;
|
|
1277
1341
|
const transform = rotation ? `rotate(${rotation}deg)` : undefined;
|
|
1342
|
+
const baseStyle = {
|
|
1343
|
+
display: 'inline-block',
|
|
1344
|
+
verticalAlign: 'middle',
|
|
1345
|
+
transform,
|
|
1346
|
+
};
|
|
1347
|
+
const combinedStyle = typeof style === 'string'
|
|
1348
|
+
? `display:inline-block;vertical-align:middle;${transform ? `transform:${transform};` : ''}${style}`
|
|
1349
|
+
: Object.assign(Object.assign({}, baseStyle), style);
|
|
1278
1350
|
const icon = iconPaths[name];
|
|
1279
1351
|
if (!icon || !Array.isArray(icon)) {
|
|
1280
1352
|
return m(Icon, Object.assign(Object.assign({}, props), { iconName: name }));
|
|
1281
1353
|
}
|
|
1282
|
-
return m('svg', Object.assign(Object.assign({}, props), { style:
|
|
1354
|
+
return m('svg', Object.assign(Object.assign({}, props), { style: combinedStyle, height: '24px', width: '24px', viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg' }), icon === null || icon === void 0 ? void 0 : icon.map((d) => m('path', {
|
|
1283
1355
|
d,
|
|
1284
1356
|
fill: d.includes('M0 0h24v24H0z') ? 'none' : 'currentColor',
|
|
1285
1357
|
})));
|
|
@@ -1678,6 +1750,106 @@ const Collapsible = () => {
|
|
|
1678
1750
|
};
|
|
1679
1751
|
};
|
|
1680
1752
|
|
|
1753
|
+
const isHandledKey = (key) => key === 'ArrowDown' || key === 'ArrowUp' || key === 'Enter' || key === ' ' || key === 'Escape';
|
|
1754
|
+
const getTotalRows = (optionCount, includeActionRow) => Math.max(0, optionCount) + (includeActionRow ? 1 : 0);
|
|
1755
|
+
const getComboboxKeyResult = ({ key, isOpen, focusedIndex, optionCount, includeActionRow, }) => {
|
|
1756
|
+
const totalRows = getTotalRows(optionCount, includeActionRow);
|
|
1757
|
+
if (!isHandledKey(key)) {
|
|
1758
|
+
return { isOpen, focusedIndex, action: 'none', preventDefault: false };
|
|
1759
|
+
}
|
|
1760
|
+
if (key === 'Escape') {
|
|
1761
|
+
return { isOpen: false, focusedIndex: -1, action: 'close', preventDefault: true };
|
|
1762
|
+
}
|
|
1763
|
+
if (key === 'ArrowDown') {
|
|
1764
|
+
if (!isOpen) {
|
|
1765
|
+
return {
|
|
1766
|
+
isOpen: true,
|
|
1767
|
+
focusedIndex: totalRows > 0 ? 0 : -1,
|
|
1768
|
+
action: 'open',
|
|
1769
|
+
preventDefault: true,
|
|
1770
|
+
};
|
|
1771
|
+
}
|
|
1772
|
+
return {
|
|
1773
|
+
isOpen: true,
|
|
1774
|
+
focusedIndex: totalRows > 0 ? Math.min(focusedIndex + 1, totalRows - 1) : -1,
|
|
1775
|
+
action: 'none',
|
|
1776
|
+
preventDefault: true,
|
|
1777
|
+
};
|
|
1778
|
+
}
|
|
1779
|
+
if (key === 'ArrowUp') {
|
|
1780
|
+
if (!isOpen) {
|
|
1781
|
+
return {
|
|
1782
|
+
isOpen: true,
|
|
1783
|
+
focusedIndex: totalRows > 0 ? 0 : -1,
|
|
1784
|
+
action: 'open',
|
|
1785
|
+
preventDefault: true,
|
|
1786
|
+
};
|
|
1787
|
+
}
|
|
1788
|
+
return {
|
|
1789
|
+
isOpen: true,
|
|
1790
|
+
focusedIndex: totalRows > 0 ? Math.max(focusedIndex - 1, 0) : -1,
|
|
1791
|
+
action: 'none',
|
|
1792
|
+
preventDefault: true,
|
|
1793
|
+
};
|
|
1794
|
+
}
|
|
1795
|
+
if (!isOpen) {
|
|
1796
|
+
return {
|
|
1797
|
+
isOpen: true,
|
|
1798
|
+
focusedIndex: totalRows > 0 ? 0 : -1,
|
|
1799
|
+
action: 'open',
|
|
1800
|
+
preventDefault: true,
|
|
1801
|
+
};
|
|
1802
|
+
}
|
|
1803
|
+
if (focusedIndex < 0) {
|
|
1804
|
+
return { isOpen, focusedIndex, action: 'none', preventDefault: true };
|
|
1805
|
+
}
|
|
1806
|
+
const isActionRow = includeActionRow && focusedIndex === optionCount;
|
|
1807
|
+
return {
|
|
1808
|
+
isOpen,
|
|
1809
|
+
focusedIndex,
|
|
1810
|
+
action: isActionRow ? 'selectAction' : 'selectFocused',
|
|
1811
|
+
preventDefault: true,
|
|
1812
|
+
};
|
|
1813
|
+
};
|
|
1814
|
+
const getComboboxOptionId = (baseId, optionIndex) => `${baseId}-option-${optionIndex}`;
|
|
1815
|
+
const createAsyncComboboxState = (initialOptions = []) => ({
|
|
1816
|
+
options: initialOptions,
|
|
1817
|
+
isLoading: false,
|
|
1818
|
+
error: null,
|
|
1819
|
+
latestRequestId: 0,
|
|
1820
|
+
});
|
|
1821
|
+
const startAsyncComboboxRequest = (state) => {
|
|
1822
|
+
const requestId = state.latestRequestId + 1;
|
|
1823
|
+
return {
|
|
1824
|
+
requestId,
|
|
1825
|
+
nextState: Object.assign(Object.assign({}, state), { isLoading: true, error: null, latestRequestId: requestId }),
|
|
1826
|
+
};
|
|
1827
|
+
};
|
|
1828
|
+
const resolveAsyncComboboxRequest = (state, requestId, options) => {
|
|
1829
|
+
if (requestId !== state.latestRequestId) {
|
|
1830
|
+
return state;
|
|
1831
|
+
}
|
|
1832
|
+
return Object.assign(Object.assign({}, state), { options, isLoading: false, error: null });
|
|
1833
|
+
};
|
|
1834
|
+
const rejectAsyncComboboxRequest = (state, requestId, errorMessage) => {
|
|
1835
|
+
if (requestId !== state.latestRequestId) {
|
|
1836
|
+
return state;
|
|
1837
|
+
}
|
|
1838
|
+
return Object.assign(Object.assign({}, state), { options: [], isLoading: false, error: errorMessage });
|
|
1839
|
+
};
|
|
1840
|
+
const getComboboxViewState = ({ isLoading, error, optionCount, }) => {
|
|
1841
|
+
if (isLoading) {
|
|
1842
|
+
return 'loading';
|
|
1843
|
+
}
|
|
1844
|
+
if (error) {
|
|
1845
|
+
return 'error';
|
|
1846
|
+
}
|
|
1847
|
+
if (optionCount === 0) {
|
|
1848
|
+
return 'empty';
|
|
1849
|
+
}
|
|
1850
|
+
return 'ready';
|
|
1851
|
+
};
|
|
1852
|
+
|
|
1681
1853
|
exports.CollectionMode = void 0;
|
|
1682
1854
|
(function (CollectionMode) {
|
|
1683
1855
|
CollectionMode[CollectionMode["BASIC"] = 0] = "BASIC";
|
|
@@ -2377,6 +2549,7 @@ const DatePicker = () => {
|
|
|
2377
2549
|
e.stopPropagation();
|
|
2378
2550
|
gotoMonth(index);
|
|
2379
2551
|
state.monthDropdownOpen = false;
|
|
2552
|
+
m.redraw();
|
|
2380
2553
|
},
|
|
2381
2554
|
}, monthName))),
|
|
2382
2555
|
]),
|
|
@@ -2401,6 +2574,7 @@ const DatePicker = () => {
|
|
|
2401
2574
|
e.stopPropagation();
|
|
2402
2575
|
gotoYear(i);
|
|
2403
2576
|
state.yearDropdownOpen = false;
|
|
2577
|
+
m.redraw();
|
|
2404
2578
|
},
|
|
2405
2579
|
}, i))),
|
|
2406
2580
|
]),
|
|
@@ -3285,6 +3459,10 @@ const DoubleRangeSlider = {
|
|
|
3285
3459
|
},
|
|
3286
3460
|
};
|
|
3287
3461
|
|
|
3462
|
+
const isReadonly = (attrs) => {
|
|
3463
|
+
const legacyReadonly = attrs.readonly;
|
|
3464
|
+
return Boolean(attrs.readOnly || legacyReadonly);
|
|
3465
|
+
};
|
|
3288
3466
|
/** Character counter component that tracks text length against maxLength */
|
|
3289
3467
|
const CharacterCounter = () => {
|
|
3290
3468
|
return {
|
|
@@ -3363,7 +3541,7 @@ const TextArea = () => {
|
|
|
3363
3541
|
return {
|
|
3364
3542
|
oninit: ({ attrs }) => {
|
|
3365
3543
|
const controlled = isControlled(attrs);
|
|
3366
|
-
const isNonInteractive = attrs
|
|
3544
|
+
const isNonInteractive = isReadonly(attrs) || attrs.disabled;
|
|
3367
3545
|
// Warn developer for improper controlled usage
|
|
3368
3546
|
if (attrs.value !== undefined && !controlled && !isNonInteractive) {
|
|
3369
3547
|
console.warn(`TextArea received 'value' prop without 'oninput' or 'onchange' handler. ` +
|
|
@@ -3380,7 +3558,7 @@ const TextArea = () => {
|
|
|
3380
3558
|
var _a, _b, _c, _d;
|
|
3381
3559
|
const { className = 'col s12', helperText, iconName, id = state.id, value, placeholder, isMandatory, label, maxLength, oninput, onchange, onkeydown, onkeypress, onkeyup, onblur, style } = attrs, params = __rest(attrs, ["className", "helperText", "iconName", "id", "value", "placeholder", "isMandatory", "label", "maxLength", "oninput", "onchange", "onkeydown", "onkeypress", "onkeyup", "onblur", "style"]);
|
|
3382
3560
|
const controlled = isControlled(attrs);
|
|
3383
|
-
const isNonInteractive = attrs
|
|
3561
|
+
const isNonInteractive = isReadonly(attrs) || attrs.disabled;
|
|
3384
3562
|
let currentValue;
|
|
3385
3563
|
if (controlled) {
|
|
3386
3564
|
currentValue = value || '';
|
|
@@ -3496,14 +3674,12 @@ const TextArea = () => {
|
|
|
3496
3674
|
onkeypress(ev, ev.target.value);
|
|
3497
3675
|
}
|
|
3498
3676
|
: undefined })),
|
|
3499
|
-
|
|
3677
|
+
...renderFieldChrome({
|
|
3500
3678
|
label,
|
|
3501
3679
|
id,
|
|
3502
3680
|
isMandatory,
|
|
3503
3681
|
isActive: currentValue || placeholder || state.active,
|
|
3504
3682
|
initialValue: currentValue !== '',
|
|
3505
|
-
}),
|
|
3506
|
-
m(HelperText, {
|
|
3507
3683
|
helperText,
|
|
3508
3684
|
dataError: state.hasInteracted && attrs.dataError ? attrs.dataError : undefined,
|
|
3509
3685
|
dataSuccess: state.hasInteracted && attrs.dataSuccess ? attrs.dataSuccess : undefined,
|
|
@@ -3583,7 +3759,7 @@ const InputField = (type, defaultClass = '') => () => {
|
|
|
3583
3759
|
return {
|
|
3584
3760
|
oninit: ({ attrs }) => {
|
|
3585
3761
|
const controlled = isControlled(attrs);
|
|
3586
|
-
const isNonInteractive = attrs
|
|
3762
|
+
const isNonInteractive = isReadonly(attrs) || attrs.disabled;
|
|
3587
3763
|
// Warn developer for improper controlled usage
|
|
3588
3764
|
if (attrs.value !== undefined && !controlled && !isNonInteractive) {
|
|
3589
3765
|
console.warn(`${type} input with label '${attrs.label}' received 'value' prop without 'oninput' handler. ` +
|
|
@@ -3623,7 +3799,7 @@ const InputField = (type, defaultClass = '') => () => {
|
|
|
3623
3799
|
}
|
|
3624
3800
|
const isNumeric = ['number', 'range'].includes(type);
|
|
3625
3801
|
const controlled = isControlled(attrs);
|
|
3626
|
-
const isNonInteractive = attrs
|
|
3802
|
+
const isNonInteractive = isReadonly(attrs) || attrs.disabled;
|
|
3627
3803
|
let value;
|
|
3628
3804
|
if (controlled) {
|
|
3629
3805
|
value = attrs.value;
|
|
@@ -3642,9 +3818,28 @@ const InputField = (type, defaultClass = '') => () => {
|
|
|
3642
3818
|
const rangeType = type === 'range' && !attrs.minmax;
|
|
3643
3819
|
// Only add validate class if input is interactive and validation is needed
|
|
3644
3820
|
const shouldValidate = !isNonInteractive && (validate || type === 'email' || type === 'url' || isNumeric);
|
|
3821
|
+
const inputClass = [
|
|
3822
|
+
type === 'number' ? 'number-input' : '',
|
|
3823
|
+
type === 'range' && attrs.vertical ? 'range-slider vertical' : '',
|
|
3824
|
+
shouldValidate ? 'validate' : '',
|
|
3825
|
+
]
|
|
3826
|
+
.filter(Boolean)
|
|
3827
|
+
.join(' ');
|
|
3828
|
+
const stepNumberInput = (direction) => {
|
|
3829
|
+
const input = state.inputElement;
|
|
3830
|
+
if (!input)
|
|
3831
|
+
return;
|
|
3832
|
+
if (direction === 'up') {
|
|
3833
|
+
input.stepUp();
|
|
3834
|
+
}
|
|
3835
|
+
else {
|
|
3836
|
+
input.stepDown();
|
|
3837
|
+
}
|
|
3838
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
3839
|
+
};
|
|
3645
3840
|
return m('.input-field', { className: cn, style }, [
|
|
3646
3841
|
iconName ? m('i.material-icons.prefix', iconName) : undefined,
|
|
3647
|
-
m('input', Object.assign(Object.assign({ class:
|
|
3842
|
+
m('input', Object.assign(Object.assign({ class: inputClass || undefined }, params), { type, tabindex: 0, id,
|
|
3648
3843
|
placeholder, value: controlled ? value : undefined, style: type === 'range' && attrs.vertical
|
|
3649
3844
|
? {
|
|
3650
3845
|
height: attrs.height || '200px',
|
|
@@ -3726,7 +3921,7 @@ const InputField = (type, defaultClass = '') => () => {
|
|
|
3726
3921
|
const target = e.target;
|
|
3727
3922
|
state.hasInteracted = true;
|
|
3728
3923
|
// Skip validation for readonly/disabled inputs
|
|
3729
|
-
if (attrs
|
|
3924
|
+
if (isReadonly(attrs) || attrs.disabled) {
|
|
3730
3925
|
// Call original onblur if provided
|
|
3731
3926
|
if (attrs.onblur) {
|
|
3732
3927
|
attrs.onblur(e);
|
|
@@ -3816,6 +4011,22 @@ const InputField = (type, defaultClass = '') => () => {
|
|
|
3816
4011
|
onchange(getValue(state.inputElement));
|
|
3817
4012
|
}
|
|
3818
4013
|
} })),
|
|
4014
|
+
type === 'number' && !isNonInteractive
|
|
4015
|
+
? m('.number-input-controls', [
|
|
4016
|
+
m('button.number-input-control.number-input-control-up[type=button]', {
|
|
4017
|
+
'aria-label': `Increase ${label || 'value'}`,
|
|
4018
|
+
title: 'Increase value',
|
|
4019
|
+
onmousedown: (event) => event.preventDefault(),
|
|
4020
|
+
onclick: () => stepNumberInput('up'),
|
|
4021
|
+
}, m(MaterialIcon, { name: 'chevron', direction: 'up' })),
|
|
4022
|
+
m('button.number-input-control.number-input-control-down[type=button]', {
|
|
4023
|
+
'aria-label': `Decrease ${label || 'value'}`,
|
|
4024
|
+
title: 'Decrease value',
|
|
4025
|
+
onmousedown: (event) => event.preventDefault(),
|
|
4026
|
+
onclick: () => stepNumberInput('down'),
|
|
4027
|
+
}, m(MaterialIcon, { name: 'chevron' })),
|
|
4028
|
+
])
|
|
4029
|
+
: undefined,
|
|
3819
4030
|
// Clear button - only for text inputs with canClear enabled and has content
|
|
3820
4031
|
canClear && type === 'text' && ((_f = state.inputElement) === null || _f === void 0 ? void 0 : _f.value)
|
|
3821
4032
|
? m(MaterialIcon, {
|
|
@@ -3828,14 +4039,12 @@ const InputField = (type, defaultClass = '') => () => {
|
|
|
3828
4039
|
},
|
|
3829
4040
|
})
|
|
3830
4041
|
: undefined,
|
|
3831
|
-
|
|
4042
|
+
...renderFieldChrome({
|
|
3832
4043
|
label,
|
|
3833
4044
|
id,
|
|
3834
4045
|
isMandatory,
|
|
3835
4046
|
isActive,
|
|
3836
4047
|
initialValue: value !== undefined && value !== '',
|
|
3837
|
-
}),
|
|
3838
|
-
m(HelperText, {
|
|
3839
4048
|
helperText,
|
|
3840
4049
|
dataError: state.hasInteracted && !state.isValid ? dataError : undefined,
|
|
3841
4050
|
dataSuccess: state.hasInteracted && state.isValid ? dataSuccess : undefined,
|
|
@@ -3935,7 +4144,7 @@ const InputCheckbox = () => {
|
|
|
3935
4144
|
view: ({ attrs: { className = 'col s12', onchange, label, checked, disabled, description, style, inputId } }) => {
|
|
3936
4145
|
if (!checkboxId)
|
|
3937
4146
|
checkboxId = inputId || uniqueId();
|
|
3938
|
-
return m('div', { className, style }, m('label', { for: checkboxId }, [
|
|
4147
|
+
return m('div', { className, style }, m('label', { for: checkboxId, style: { position: 'relative', display: 'inline-block' } }, [
|
|
3939
4148
|
m('input[type=checkbox][tabindex=0]', {
|
|
3940
4149
|
className: disabled ? 'disabled' : undefined,
|
|
3941
4150
|
id: checkboxId,
|
|
@@ -4700,17 +4909,6 @@ const Dropdown = () => {
|
|
|
4700
4909
|
const updatePortalDropdown = (items, selectedLabel, onSelectItem, maxHeight) => {
|
|
4701
4910
|
if (!state.isInsideModal)
|
|
4702
4911
|
return;
|
|
4703
|
-
// Clean up existing portal
|
|
4704
|
-
const existingPortal = document.getElementById(`${state.id}-dropdown`);
|
|
4705
|
-
if (existingPortal) {
|
|
4706
|
-
existingPortal.remove();
|
|
4707
|
-
}
|
|
4708
|
-
if (!state.isOpen || !state.inputRef)
|
|
4709
|
-
return;
|
|
4710
|
-
// Create portal element
|
|
4711
|
-
const portalElement = document.createElement('div');
|
|
4712
|
-
portalElement.id = `${state.id}-dropdown`;
|
|
4713
|
-
document.body.appendChild(portalElement);
|
|
4714
4912
|
// Create dropdown content
|
|
4715
4913
|
const availableItems = items.filter((item) => !item.divider && !item.disabled);
|
|
4716
4914
|
const dropdownContent = items.map((item) => {
|
|
@@ -4724,15 +4922,14 @@ const Dropdown = () => {
|
|
|
4724
4922
|
class: `${isSelected ? 'selected' : ''} ${isFocused ? 'focused' : ''}${item.disabled ? ' disabled' : ''}`,
|
|
4725
4923
|
onclick: item.disabled ? undefined : () => onSelectItem(item),
|
|
4726
4924
|
}, m('span', {
|
|
4925
|
+
class: 'mm-layout-row mm-layout-row--center',
|
|
4727
4926
|
style: {
|
|
4728
|
-
display: 'flex',
|
|
4729
|
-
alignItems: 'center',
|
|
4730
4927
|
padding: '14px 16px',
|
|
4731
4928
|
},
|
|
4732
4929
|
}, [
|
|
4733
4930
|
item.iconName
|
|
4734
4931
|
? m('i.material-icons', {
|
|
4735
|
-
|
|
4932
|
+
class: 'mm-layout-item-icon',
|
|
4736
4933
|
}, item.iconName)
|
|
4737
4934
|
: undefined,
|
|
4738
4935
|
item.label,
|
|
@@ -4749,8 +4946,12 @@ const Dropdown = () => {
|
|
|
4749
4946
|
state.dropdownRef = null;
|
|
4750
4947
|
},
|
|
4751
4948
|
}, dropdownContent);
|
|
4752
|
-
|
|
4753
|
-
|
|
4949
|
+
syncPortalContent({
|
|
4950
|
+
containerId: `${state.id}-dropdown`,
|
|
4951
|
+
shouldRender: state.isOpen && !!state.inputRef,
|
|
4952
|
+
vnode: dropdownVnode,
|
|
4953
|
+
zIndex: 10000,
|
|
4954
|
+
});
|
|
4754
4955
|
};
|
|
4755
4956
|
return {
|
|
4756
4957
|
oninit: ({ attrs }) => {
|
|
@@ -4771,15 +4972,19 @@ const Dropdown = () => {
|
|
|
4771
4972
|
// Cleanup global listener
|
|
4772
4973
|
document.removeEventListener('click', closeDropdown);
|
|
4773
4974
|
// Cleanup portal
|
|
4774
|
-
|
|
4775
|
-
if (portalElement) {
|
|
4776
|
-
portalElement.remove();
|
|
4777
|
-
}
|
|
4975
|
+
syncPortalContent({ containerId: `${state.id}-dropdown`, shouldRender: false, vnode: null });
|
|
4778
4976
|
},
|
|
4779
4977
|
view: ({ attrs }) => {
|
|
4780
4978
|
const { checkedId, key, label, onchange, disabled = false, items, iconName, helperText, style, className = 'col s12', } = attrs;
|
|
4781
4979
|
const controlled = isControlled(attrs);
|
|
4782
|
-
const currentCheckedId =
|
|
4980
|
+
const currentCheckedId = resolveControllableValue({
|
|
4981
|
+
controlled,
|
|
4982
|
+
disabled,
|
|
4983
|
+
controlledValue: checkedId,
|
|
4984
|
+
defaultValue: attrs.defaultCheckedId,
|
|
4985
|
+
internalValue: state.internalCheckedId,
|
|
4986
|
+
fallbackValue: undefined,
|
|
4987
|
+
});
|
|
4783
4988
|
const handleSelection = (value) => {
|
|
4784
4989
|
// Update internal state for uncontrolled mode
|
|
4785
4990
|
if (!controlled) {
|
|
@@ -4811,6 +5016,7 @@ const Dropdown = () => {
|
|
|
4811
5016
|
iconName ? m('i.material-icons.prefix', iconName) : undefined,
|
|
4812
5017
|
m(HelperText, { helperText }),
|
|
4813
5018
|
m('.select-wrapper', {
|
|
5019
|
+
class: 'mm-layout-row mm-layout-row--center',
|
|
4814
5020
|
onkeydown: disabled
|
|
4815
5021
|
? undefined
|
|
4816
5022
|
: (e) => {
|
|
@@ -4878,15 +5084,14 @@ const Dropdown = () => {
|
|
|
4878
5084
|
handleSelection(value);
|
|
4879
5085
|
},
|
|
4880
5086
|
}, m('span', {
|
|
5087
|
+
class: 'mm-layout-row mm-layout-row--center',
|
|
4881
5088
|
style: {
|
|
4882
|
-
display: 'flex',
|
|
4883
|
-
alignItems: 'center',
|
|
4884
5089
|
padding: '14px 16px',
|
|
4885
5090
|
},
|
|
4886
5091
|
}, [
|
|
4887
5092
|
item.iconName
|
|
4888
5093
|
? m('i.material-icons', {
|
|
4889
|
-
|
|
5094
|
+
class: 'mm-layout-item-icon',
|
|
4890
5095
|
}, item.iconName)
|
|
4891
5096
|
: undefined,
|
|
4892
5097
|
item.label,
|
|
@@ -6843,9 +7048,9 @@ const initPushpins = (selector = '.pushpin', options = {}) => {
|
|
|
6843
7048
|
};
|
|
6844
7049
|
|
|
6845
7050
|
const RadioButton = () => ({
|
|
6846
|
-
view: ({ attrs: { id, groupId, label, onchange, className = 'col s12', checked, disabled, inputId } }) => {
|
|
7051
|
+
view: ({ attrs: { id, groupId, label, onchange, className = 'col s12', checked, disabled, inputId, allowHtml } }) => {
|
|
6847
7052
|
const radioId = inputId || `${groupId}-${id}`;
|
|
6848
|
-
return m('p', { className }, m('label', { for: radioId }, [
|
|
7053
|
+
return m('p', { className }, m('label', { for: radioId, style: { position: 'relative', display: 'inline-block' } }, [
|
|
6849
7054
|
m('input[type=radio][tabindex=0]', {
|
|
6850
7055
|
id: radioId,
|
|
6851
7056
|
name: groupId,
|
|
@@ -6853,7 +7058,7 @@ const RadioButton = () => ({
|
|
|
6853
7058
|
checked,
|
|
6854
7059
|
onclick: onchange ? () => onchange(id) : undefined,
|
|
6855
7060
|
}),
|
|
6856
|
-
m('span', m.trust(label)),
|
|
7061
|
+
m('span', allowHtml ? m.trust(label) : label),
|
|
6857
7062
|
]));
|
|
6858
7063
|
},
|
|
6859
7064
|
});
|
|
@@ -6880,8 +7085,9 @@ const RadioButtons = () => {
|
|
|
6880
7085
|
}
|
|
6881
7086
|
},
|
|
6882
7087
|
view: ({ attrs }) => {
|
|
6883
|
-
var _a, _b;
|
|
6884
|
-
const { checkedId, newRow, className = 'col s12', label = '', disabled, description, options, isMandatory, checkboxClass, layout =
|
|
7088
|
+
var _a, _b, _c;
|
|
7089
|
+
const { checkedId, newRow, className = 'col s12', label = '', disabled, description, options, isMandatory, checkboxClass, layout, direction, allowHtml = false, onchange, } = attrs;
|
|
7090
|
+
const resolvedLayout = (_a = layout !== null && layout !== void 0 ? layout : direction) !== null && _a !== void 0 ? _a : 'vertical';
|
|
6885
7091
|
const { groupId, componentId } = state;
|
|
6886
7092
|
const controlled = isControlled(attrs);
|
|
6887
7093
|
// Get current checked ID from props or internal state
|
|
@@ -6891,11 +7097,11 @@ const RadioButtons = () => {
|
|
|
6891
7097
|
}
|
|
6892
7098
|
else if (disabled) {
|
|
6893
7099
|
// Non-interactive components: prefer defaultCheckedId, fallback to checkedId
|
|
6894
|
-
currentCheckedId = (
|
|
7100
|
+
currentCheckedId = (_b = attrs.defaultCheckedId) !== null && _b !== void 0 ? _b : checkedId;
|
|
6895
7101
|
}
|
|
6896
7102
|
else {
|
|
6897
7103
|
// Interactive uncontrolled: use internal state
|
|
6898
|
-
currentCheckedId = (
|
|
7104
|
+
currentCheckedId = (_c = state.internalCheckedId) !== null && _c !== void 0 ? _c : attrs.defaultCheckedId;
|
|
6899
7105
|
}
|
|
6900
7106
|
const handleChange = (id) => {
|
|
6901
7107
|
// Update internal state for uncontrolled mode
|
|
@@ -6910,16 +7116,16 @@ const RadioButtons = () => {
|
|
|
6910
7116
|
const cn = [newRow ? 'clear' : '', className].filter(Boolean).join(' ').trim() || undefined;
|
|
6911
7117
|
const radioItems = options.map((r) => ({
|
|
6912
7118
|
component: (RadioButton),
|
|
6913
|
-
props: Object.assign(Object.assign({}, r), { onchange: handleChange, groupId, disabled: disabled || r.disabled, className: checkboxClass, checked: r.id === currentCheckedId, inputId: `${componentId}-${r.id}
|
|
7119
|
+
props: Object.assign(Object.assign({}, r), { onchange: handleChange, groupId, disabled: disabled || r.disabled, className: checkboxClass, checked: r.id === currentCheckedId, inputId: `${componentId}-${r.id}`, allowHtml }),
|
|
6914
7120
|
key: r.id,
|
|
6915
7121
|
}));
|
|
6916
7122
|
const optionsContent = m(OptionsList, {
|
|
6917
7123
|
options: radioItems,
|
|
6918
|
-
layout,
|
|
7124
|
+
layout: resolvedLayout,
|
|
6919
7125
|
});
|
|
6920
7126
|
return m('div', { id: componentId, className: cn }, [
|
|
6921
7127
|
label && m('h5.form-group-label', label + (isMandatory ? ' *' : '')),
|
|
6922
|
-
description && m('p.helper-text', m.trust(description)),
|
|
7128
|
+
description && m('p.helper-text', allowHtml ? m.trust(description) : description),
|
|
6923
7129
|
m('form', { action: '#' }, optionsContent),
|
|
6924
7130
|
]);
|
|
6925
7131
|
},
|
|
@@ -7056,6 +7262,26 @@ const Select = () => {
|
|
|
7056
7262
|
opacity: 1,
|
|
7057
7263
|
};
|
|
7058
7264
|
};
|
|
7265
|
+
const formatSelectionSummary = (attrs, selectedOptions, selectedIds, placeholder) => {
|
|
7266
|
+
const mode = attrs.summaryMode || 'labels';
|
|
7267
|
+
const selectedCount = selectedIds.length;
|
|
7268
|
+
const totalCount = attrs.options.filter((option) => !option.disabled).length;
|
|
7269
|
+
if (mode === 'labels') {
|
|
7270
|
+
return selectedOptions.length > 0 ? selectedOptions.map((o) => o.label || o.id).join(', ') : placeholder;
|
|
7271
|
+
}
|
|
7272
|
+
const defaultCountLabel = `${selectedCount}/${totalCount} selected`;
|
|
7273
|
+
const formattedCount = attrs.countLabel ? attrs.countLabel(selectedCount, totalCount) : defaultCountLabel;
|
|
7274
|
+
if (mode === 'count') {
|
|
7275
|
+
return selectedCount > 0 ? formattedCount : placeholder;
|
|
7276
|
+
}
|
|
7277
|
+
if (selectedCount === 0) {
|
|
7278
|
+
return attrs.noneSelectedLabel || placeholder;
|
|
7279
|
+
}
|
|
7280
|
+
if (totalCount > 0 && selectedCount >= totalCount) {
|
|
7281
|
+
return attrs.allSelectedLabel || 'All selected';
|
|
7282
|
+
}
|
|
7283
|
+
return formattedCount;
|
|
7284
|
+
};
|
|
7059
7285
|
const renderDropdownContent = (attrs, selectedIds, multiple, placeholder) => [
|
|
7060
7286
|
placeholder && m('li.disabled', { tabindex: 0 }, m('span', placeholder)),
|
|
7061
7287
|
// Render ungrouped options first
|
|
@@ -7124,17 +7350,6 @@ const Select = () => {
|
|
|
7124
7350
|
const updatePortalDropdown = (attrs, selectedIds, multiple, placeholder) => {
|
|
7125
7351
|
if (!state.isInsideModal)
|
|
7126
7352
|
return;
|
|
7127
|
-
// Clean up existing portal
|
|
7128
|
-
const existingPortal = document.getElementById(state.dropdownId);
|
|
7129
|
-
if (existingPortal) {
|
|
7130
|
-
existingPortal.remove();
|
|
7131
|
-
}
|
|
7132
|
-
if (!state.isOpen || !state.inputRef)
|
|
7133
|
-
return;
|
|
7134
|
-
// Create portal element
|
|
7135
|
-
const portalElement = document.createElement('div');
|
|
7136
|
-
portalElement.id = state.dropdownId;
|
|
7137
|
-
document.body.appendChild(portalElement);
|
|
7138
7353
|
// Create dropdown with proper positioning
|
|
7139
7354
|
const dropdownVnode = m('ul.dropdown-content.select-dropdown', {
|
|
7140
7355
|
tabindex: 0,
|
|
@@ -7146,8 +7361,12 @@ const Select = () => {
|
|
|
7146
7361
|
state.dropdownRef = null;
|
|
7147
7362
|
},
|
|
7148
7363
|
}, renderDropdownContent(attrs, selectedIds, multiple, placeholder));
|
|
7149
|
-
|
|
7150
|
-
|
|
7364
|
+
syncPortalContent({
|
|
7365
|
+
containerId: state.dropdownId,
|
|
7366
|
+
shouldRender: state.isOpen && !!state.inputRef,
|
|
7367
|
+
vnode: dropdownVnode,
|
|
7368
|
+
zIndex: 10000,
|
|
7369
|
+
});
|
|
7151
7370
|
};
|
|
7152
7371
|
return {
|
|
7153
7372
|
oninit: ({ attrs }) => {
|
|
@@ -7180,35 +7399,29 @@ const Select = () => {
|
|
|
7180
7399
|
document.removeEventListener('click', closeDropdown);
|
|
7181
7400
|
// Cleanup portaled dropdown if it exists
|
|
7182
7401
|
if (state.isInsideModal && state.dropdownRef) {
|
|
7183
|
-
|
|
7184
|
-
if (portalElement && portalElement.parentNode) {
|
|
7185
|
-
portalElement.parentNode.removeChild(portalElement);
|
|
7186
|
-
}
|
|
7402
|
+
syncPortalContent({ containerId: state.dropdownId, shouldRender: false, vnode: null });
|
|
7187
7403
|
}
|
|
7188
7404
|
},
|
|
7189
7405
|
view: ({ attrs }) => {
|
|
7190
|
-
var _a;
|
|
7191
7406
|
const controlled = isControlled(attrs);
|
|
7192
|
-
const { newRow, className = 'col s12', key, options = [], multiple = false, label, helperText, placeholder = '', isMandatory, iconName, style, disabled, } = attrs;
|
|
7407
|
+
const { newRow, className = 'col s12', key, options = [], multiple = false, label, helperText, placeholder = '', isMandatory, iconName, appearance = 'standard', style, disabled, } = attrs;
|
|
7193
7408
|
state.isMultiple = multiple;
|
|
7194
7409
|
// Get selected IDs from props or internal state
|
|
7195
|
-
|
|
7196
|
-
|
|
7197
|
-
|
|
7198
|
-
|
|
7199
|
-
|
|
7200
|
-
|
|
7201
|
-
|
|
7202
|
-
|
|
7203
|
-
|
|
7204
|
-
|
|
7205
|
-
|
|
7206
|
-
|
|
7207
|
-
selectedIds = state.internalSelectedIds;
|
|
7208
|
-
}
|
|
7209
|
-
const finalClassName = newRow ? `${className} clear` : className;
|
|
7410
|
+
const selectedIds = resolveControllableValue({
|
|
7411
|
+
controlled,
|
|
7412
|
+
disabled,
|
|
7413
|
+
controlledValue: normalizeSelection(attrs.checkedId),
|
|
7414
|
+
defaultValue: normalizeSelection(attrs.defaultCheckedId),
|
|
7415
|
+
internalValue: state.internalSelectedIds,
|
|
7416
|
+
fallbackValue: [],
|
|
7417
|
+
});
|
|
7418
|
+
const layoutClassName = newRow ? `${className} clear` : className;
|
|
7419
|
+
const appearanceClassName = appearance === 'outlined' ? 'select-appearance-outlined' : '';
|
|
7420
|
+
const finalClassName = [layoutClassName, appearanceClassName].filter(Boolean).join(' ');
|
|
7421
|
+
const shouldInlineLabel = appearance === 'outlined' && !!label;
|
|
7210
7422
|
const selectedOptionsUnsorted = options.filter((opt) => isSelected(opt.id, selectedIds));
|
|
7211
7423
|
const selectedOptions = sortOptions(selectedOptionsUnsorted, attrs.sortSelected);
|
|
7424
|
+
const triggerValue = formatSelectionSummary(attrs, selectedOptions, selectedIds, placeholder);
|
|
7212
7425
|
// Update portal dropdown when inside modal
|
|
7213
7426
|
if (state.isInsideModal) {
|
|
7214
7427
|
updatePortalDropdown(attrs, selectedIds, multiple, placeholder);
|
|
@@ -7228,9 +7441,15 @@ const Select = () => {
|
|
|
7228
7441
|
'aria-controls': state.dropdownId,
|
|
7229
7442
|
role: 'combobox',
|
|
7230
7443
|
}, [
|
|
7444
|
+
shouldInlineLabel &&
|
|
7445
|
+
m('span.select-inline-label', [
|
|
7446
|
+
label,
|
|
7447
|
+
isMandatory && m('span.mandatory', { style: { marginLeft: '2px' } }, '*'),
|
|
7448
|
+
]),
|
|
7231
7449
|
m('input[type=text][readonly=true].select-dropdown.dropdown-trigger', {
|
|
7232
7450
|
id: state.id,
|
|
7233
|
-
value:
|
|
7451
|
+
value: triggerValue,
|
|
7452
|
+
'aria-label': label,
|
|
7234
7453
|
oncreate: ({ dom }) => {
|
|
7235
7454
|
state.inputRef = dom;
|
|
7236
7455
|
},
|
|
@@ -7262,14 +7481,12 @@ const Select = () => {
|
|
|
7262
7481
|
}),
|
|
7263
7482
|
]),
|
|
7264
7483
|
// Label
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
// Helper text
|
|
7272
|
-
helperText && m(HelperText, { helperText }),
|
|
7484
|
+
...renderFieldChrome({
|
|
7485
|
+
label: shouldInlineLabel ? undefined : label,
|
|
7486
|
+
id: state.id,
|
|
7487
|
+
isMandatory,
|
|
7488
|
+
helperText,
|
|
7489
|
+
}),
|
|
7273
7490
|
]);
|
|
7274
7491
|
},
|
|
7275
7492
|
};
|
|
@@ -7488,59 +7705,65 @@ const Tabs = () => {
|
|
|
7488
7705
|
};
|
|
7489
7706
|
};
|
|
7490
7707
|
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
|
|
7498
|
-
|
|
7499
|
-
|
|
7500
|
-
|
|
7501
|
-
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
7507
|
-
|
|
7508
|
-
|
|
7509
|
-
|
|
7510
|
-
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7515
|
-
|
|
7708
|
+
const SelectedChip = ({ option, onRemove, }) => m('.chip', [
|
|
7709
|
+
option.label || option.id.toString(),
|
|
7710
|
+
m(MaterialIcon, {
|
|
7711
|
+
name: 'close',
|
|
7712
|
+
className: 'close',
|
|
7713
|
+
onclick: (e) => {
|
|
7714
|
+
e.stopPropagation();
|
|
7715
|
+
onRemove(option.id);
|
|
7716
|
+
},
|
|
7717
|
+
}),
|
|
7718
|
+
]);
|
|
7719
|
+
const DropdownOption = ({ option, index, optionId, selectedIds, isFocused, onToggle, onMouseOver, showCheckbox, }) => {
|
|
7720
|
+
const optionLabel = option.label || option.id.toString();
|
|
7721
|
+
return m('li', {
|
|
7722
|
+
id: optionId,
|
|
7723
|
+
role: 'option',
|
|
7724
|
+
'aria-selected': selectedIds.includes(option.id) ? 'true' : 'false',
|
|
7725
|
+
class: `${option.disabled ? 'disabled' : ''} ${isFocused ? 'active' : ''}`.trim(),
|
|
7726
|
+
onmouseover: () => {
|
|
7727
|
+
if (!option.disabled) {
|
|
7728
|
+
onMouseOver(index);
|
|
7729
|
+
}
|
|
7730
|
+
},
|
|
7731
|
+
}, m('label', {
|
|
7732
|
+
class: 'search-select-option-label',
|
|
7733
|
+
onclick: (e) => {
|
|
7734
|
+
// A single-select row has no native checkbox to emit change.
|
|
7735
|
+
if (!showCheckbox) {
|
|
7736
|
+
e.preventDefault();
|
|
7737
|
+
onToggle(option);
|
|
7738
|
+
}
|
|
7739
|
+
},
|
|
7740
|
+
}, [
|
|
7741
|
+
showCheckbox &&
|
|
7742
|
+
m('input', {
|
|
7743
|
+
type: 'checkbox',
|
|
7744
|
+
checked: selectedIds.includes(option.id),
|
|
7745
|
+
disabled: option.disabled,
|
|
7746
|
+
onchange: (e) => {
|
|
7516
7747
|
e.stopPropagation();
|
|
7517
7748
|
onToggle(option);
|
|
7518
7749
|
},
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
onMouseOver(index);
|
|
7523
|
-
}
|
|
7524
|
-
},
|
|
7525
|
-
}, m('label', { for: checkboxId, class: 'search-select-option-label' }, [
|
|
7526
|
-
showCheckbox &&
|
|
7527
|
-
m('input', {
|
|
7528
|
-
type: 'checkbox',
|
|
7529
|
-
id: checkboxId,
|
|
7530
|
-
checked: selectedIds.includes(option.id),
|
|
7531
|
-
}),
|
|
7532
|
-
m('span', optionLabel),
|
|
7533
|
-
]));
|
|
7534
|
-
},
|
|
7535
|
-
};
|
|
7750
|
+
}),
|
|
7751
|
+
m('span', optionLabel),
|
|
7752
|
+
]));
|
|
7536
7753
|
};
|
|
7537
7754
|
/**
|
|
7538
7755
|
* Mithril Factory Component for Multi-Select Dropdown with search
|
|
7539
7756
|
*/
|
|
7540
|
-
const SearchSelect = () => {
|
|
7757
|
+
const SearchSelect = (maybeVnode) => {
|
|
7758
|
+
var _a;
|
|
7759
|
+
const cachedInstance = (_a = maybeVnode === null || maybeVnode === void 0 ? void 0 : maybeVnode.state) === null || _a === void 0 ? void 0 : _a.__searchSelectInstance;
|
|
7760
|
+
if (cachedInstance) {
|
|
7761
|
+
return cachedInstance;
|
|
7762
|
+
}
|
|
7541
7763
|
// State initialization
|
|
7542
7764
|
const state = {
|
|
7543
7765
|
id: '',
|
|
7766
|
+
listboxId: '',
|
|
7544
7767
|
isOpen: false,
|
|
7545
7768
|
searchTerm: '',
|
|
7546
7769
|
inputRef: null,
|
|
@@ -7548,17 +7771,38 @@ const SearchSelect = () => {
|
|
|
7548
7771
|
focusedIndex: -1,
|
|
7549
7772
|
internalSelectedIds: [],
|
|
7550
7773
|
createdOptions: [],
|
|
7551
|
-
|
|
7774
|
+
asyncOptions: [],
|
|
7775
|
+
isLoading: false,
|
|
7776
|
+
loadError: null,
|
|
7777
|
+
latestRequestId: 0,
|
|
7778
|
+
};
|
|
7779
|
+
const updateAsyncState = (nextState) => {
|
|
7780
|
+
state.asyncOptions = nextState.options;
|
|
7781
|
+
state.isLoading = nextState.isLoading;
|
|
7782
|
+
state.loadError = nextState.error;
|
|
7783
|
+
state.latestRequestId = nextState.latestRequestId;
|
|
7784
|
+
};
|
|
7785
|
+
const readAsyncState = () => ({
|
|
7786
|
+
options: state.asyncOptions,
|
|
7787
|
+
isLoading: state.isLoading,
|
|
7788
|
+
error: state.loadError,
|
|
7789
|
+
latestRequestId: state.latestRequestId,
|
|
7790
|
+
});
|
|
7552
7791
|
const isControlled = (attrs) => attrs.checkedId !== undefined && typeof attrs.onchange === 'function';
|
|
7553
7792
|
const componentId = uniqueId();
|
|
7554
7793
|
const searchInputId = `${componentId}-search`;
|
|
7555
7794
|
// Handle click outside
|
|
7556
7795
|
const handleClickOutside = (e) => {
|
|
7557
7796
|
const target = e.target;
|
|
7797
|
+
const targetElement = e.target instanceof Element ? e.target : null;
|
|
7558
7798
|
if (state.dropdownRef && state.dropdownRef.contains(target)) {
|
|
7559
7799
|
// Click inside dropdown, do nothing
|
|
7560
7800
|
return;
|
|
7561
7801
|
}
|
|
7802
|
+
if (targetElement && targetElement.closest('.chips-container')) {
|
|
7803
|
+
// Click on trigger, do nothing
|
|
7804
|
+
return;
|
|
7805
|
+
}
|
|
7562
7806
|
if (state.inputRef && state.inputRef.contains(target)) {
|
|
7563
7807
|
// Click on trigger handled by onclick event
|
|
7564
7808
|
return;
|
|
@@ -7569,40 +7813,51 @@ const SearchSelect = () => {
|
|
|
7569
7813
|
}
|
|
7570
7814
|
m.redraw();
|
|
7571
7815
|
};
|
|
7572
|
-
// Handle keyboard navigation
|
|
7573
|
-
const handleKeyDown = (e,
|
|
7574
|
-
|
|
7816
|
+
// Handle keyboard navigation through shared combobox primitive.
|
|
7817
|
+
const handleKeyDown = (e, optionCount, includeActionRow) => {
|
|
7818
|
+
const result = getComboboxKeyResult({
|
|
7819
|
+
key: e.key,
|
|
7820
|
+
isOpen: state.isOpen,
|
|
7821
|
+
focusedIndex: state.focusedIndex,
|
|
7822
|
+
optionCount,
|
|
7823
|
+
includeActionRow,
|
|
7824
|
+
});
|
|
7825
|
+
if (result.preventDefault) {
|
|
7826
|
+
e.preventDefault();
|
|
7827
|
+
}
|
|
7828
|
+
state.isOpen = result.isOpen;
|
|
7829
|
+
state.focusedIndex = result.focusedIndex;
|
|
7830
|
+
return result.action;
|
|
7831
|
+
};
|
|
7832
|
+
const loadAsyncOptions = async (attrs, query) => {
|
|
7833
|
+
if (!attrs.loadOptions) {
|
|
7575
7834
|
return;
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
7585
|
-
|
|
7586
|
-
|
|
7587
|
-
|
|
7588
|
-
if (state.focusedIndex >= 0) {
|
|
7589
|
-
if (showAddNew && state.focusedIndex === filteredOptions.length) {
|
|
7590
|
-
// Handle add new option
|
|
7591
|
-
return 'addNew';
|
|
7592
|
-
}
|
|
7593
|
-
else if (state.focusedIndex < filteredOptions.length) {
|
|
7594
|
-
// This will be handled in the view method where attrs are available
|
|
7595
|
-
return 'selectOption';
|
|
7596
|
-
}
|
|
7597
|
-
}
|
|
7598
|
-
break;
|
|
7599
|
-
case 'Escape':
|
|
7600
|
-
e.preventDefault();
|
|
7601
|
-
state.isOpen = false;
|
|
7835
|
+
}
|
|
7836
|
+
const started = startAsyncComboboxRequest(readAsyncState());
|
|
7837
|
+
updateAsyncState(started.nextState);
|
|
7838
|
+
m.redraw();
|
|
7839
|
+
try {
|
|
7840
|
+
const loadedOptions = await attrs.loadOptions(query);
|
|
7841
|
+
const resolved = resolveAsyncComboboxRequest(readAsyncState(), started.requestId, loadedOptions);
|
|
7842
|
+
updateAsyncState(resolved);
|
|
7843
|
+
if (started.requestId !== state.latestRequestId) {
|
|
7844
|
+
return;
|
|
7845
|
+
}
|
|
7846
|
+
if (state.focusedIndex >= loadedOptions.length) {
|
|
7602
7847
|
state.focusedIndex = -1;
|
|
7603
|
-
|
|
7848
|
+
}
|
|
7849
|
+
}
|
|
7850
|
+
catch (error) {
|
|
7851
|
+
const rejected = rejectAsyncComboboxRequest(readAsyncState(), started.requestId, error instanceof Error ? error.message : 'Unable to load options');
|
|
7852
|
+
updateAsyncState(rejected);
|
|
7853
|
+
if (started.requestId !== state.latestRequestId) {
|
|
7854
|
+
return;
|
|
7855
|
+
}
|
|
7856
|
+
state.focusedIndex = -1;
|
|
7857
|
+
}
|
|
7858
|
+
finally {
|
|
7859
|
+
m.redraw();
|
|
7604
7860
|
}
|
|
7605
|
-
return null;
|
|
7606
7861
|
};
|
|
7607
7862
|
// Create new option and add to state
|
|
7608
7863
|
const createAndSelectOption = async (attrs) => {
|
|
@@ -7683,9 +7938,10 @@ const SearchSelect = () => {
|
|
|
7683
7938
|
attrs.onchange(newIds);
|
|
7684
7939
|
}
|
|
7685
7940
|
};
|
|
7686
|
-
|
|
7941
|
+
const componentInstance = {
|
|
7687
7942
|
oninit: ({ attrs }) => {
|
|
7688
7943
|
state.id = attrs.id || uniqueId();
|
|
7944
|
+
state.listboxId = `${state.id}-listbox`;
|
|
7689
7945
|
// Initialize internal state for uncontrolled mode
|
|
7690
7946
|
if (!isControlled(attrs)) {
|
|
7691
7947
|
const defaultIds = attrs.defaultCheckedId !== undefined
|
|
@@ -7712,20 +7968,26 @@ const SearchSelect = () => {
|
|
|
7712
7968
|
: [attrs.checkedId]
|
|
7713
7969
|
: []
|
|
7714
7970
|
: state.internalSelectedIds;
|
|
7715
|
-
const { options = [], oncreateNewOption, className, placeholder, searchPlaceholder = 'Search options...', noOptionsFound = 'No options found', label, i18n = {}, maxDisplayedOptions, maxSelectedOptions, maxHeight, } = attrs;
|
|
7971
|
+
const { options = [], loadOptions, oncreateNewOption, className, placeholder, searchPlaceholder = 'Search options...', noOptionsFound = 'No options found', label, i18n = {}, maxDisplayedOptions, maxSelectedOptions, maxHeight, } = attrs;
|
|
7716
7972
|
// Use i18n values if provided, otherwise use defaults
|
|
7717
7973
|
const texts = {
|
|
7718
7974
|
noOptionsFound: i18n.noOptionsFound || noOptionsFound,
|
|
7975
|
+
loadingOptions: i18n.loadingOptions || 'Loading options...',
|
|
7976
|
+
loadingError: i18n.loadingError || 'Unable to load options',
|
|
7719
7977
|
addNewPrefix: i18n.addNewPrefix || '+',
|
|
7720
7978
|
showingXofY: i18n.showingXofY || 'Showing {shown} of {total} options',
|
|
7721
7979
|
maxSelectionsReached: i18n.maxSelectionsReached || 'Maximum {max} selections reached',
|
|
7722
7980
|
};
|
|
7723
7981
|
// Check if max selections is reached
|
|
7724
7982
|
const isMaxSelectionsReached = maxSelectedOptions && selectedIds.length >= maxSelectedOptions;
|
|
7725
|
-
//
|
|
7726
|
-
const
|
|
7983
|
+
// In async mode, the active list is sourced remotely.
|
|
7984
|
+
const sourceOptions = loadOptions ? state.asyncOptions : options;
|
|
7985
|
+
// Merge active options with internally created options
|
|
7986
|
+
const allOptions = [...sourceOptions, ...state.createdOptions];
|
|
7987
|
+
// Keep selected label lookups stable across static, async, and created sets.
|
|
7988
|
+
const lookupOptions = [...options, ...state.asyncOptions, ...state.createdOptions];
|
|
7727
7989
|
// Get selected options for display
|
|
7728
|
-
const selectedOptionsUnsorted =
|
|
7990
|
+
const selectedOptionsUnsorted = lookupOptions.filter((opt) => selectedIds.includes(opt.id));
|
|
7729
7991
|
const selectedOptions = sortOptions(selectedOptionsUnsorted, attrs.sortSelected);
|
|
7730
7992
|
// Safely filter options
|
|
7731
7993
|
const filteredOptions = allOptions.filter((option) => (option.label || option.id.toString()).toLowerCase().includes((state.searchTerm || '').toLowerCase()) &&
|
|
@@ -7738,6 +8000,14 @@ const SearchSelect = () => {
|
|
|
7738
8000
|
const showAddNew = oncreateNewOption &&
|
|
7739
8001
|
state.searchTerm &&
|
|
7740
8002
|
!displayedOptions.some((o) => (o.label || o.id.toString()).toLowerCase() === state.searchTerm.toLowerCase());
|
|
8003
|
+
const activeDescendantId = state.isOpen && state.focusedIndex >= 0 && state.focusedIndex < displayedOptions.length
|
|
8004
|
+
? getComboboxOptionId(state.id, state.focusedIndex)
|
|
8005
|
+
: undefined;
|
|
8006
|
+
const viewState = getComboboxViewState({
|
|
8007
|
+
isLoading: state.isLoading,
|
|
8008
|
+
error: state.loadError,
|
|
8009
|
+
optionCount: displayedOptions.length,
|
|
8010
|
+
});
|
|
7741
8011
|
// Render the dropdown
|
|
7742
8012
|
return m('.input-field.multi-select-dropdown', { className }, [
|
|
7743
8013
|
m('.chips.chips-initial.chips-container', {
|
|
@@ -7748,14 +8018,34 @@ const SearchSelect = () => {
|
|
|
7748
8018
|
// console.log('SearchSelect clicked', state.isOpen, e); // Debug log
|
|
7749
8019
|
e.preventDefault();
|
|
7750
8020
|
e.stopPropagation();
|
|
8021
|
+
const wasOpen = state.isOpen;
|
|
7751
8022
|
state.isOpen = !state.isOpen;
|
|
8023
|
+
if (!wasOpen && state.isOpen && loadOptions) {
|
|
8024
|
+
void loadAsyncOptions(attrs, state.searchTerm);
|
|
8025
|
+
}
|
|
7752
8026
|
// console.log('SearchSelect state changed to', state.isOpen); // Debug log
|
|
7753
8027
|
},
|
|
7754
|
-
|
|
8028
|
+
onkeydown: async (e) => {
|
|
8029
|
+
const action = handleKeyDown(e, displayedOptions.length, !!showAddNew);
|
|
8030
|
+
if (action === 'open' && loadOptions) {
|
|
8031
|
+
await loadAsyncOptions(attrs, state.searchTerm);
|
|
8032
|
+
return;
|
|
8033
|
+
}
|
|
8034
|
+
if (action === 'selectAction' && oncreateNewOption) {
|
|
8035
|
+
await createAndSelectOption(attrs);
|
|
8036
|
+
}
|
|
8037
|
+
if (action === 'selectFocused' && state.focusedIndex < displayedOptions.length) {
|
|
8038
|
+
toggleOption(displayedOptions[state.focusedIndex], attrs);
|
|
8039
|
+
}
|
|
8040
|
+
},
|
|
8041
|
+
class: 'chips chips-container mm-layout-row mm-layout-row--wrap mm-layout-row--align-end',
|
|
8042
|
+
role: 'combobox',
|
|
8043
|
+
tabindex: 0,
|
|
8044
|
+
'aria-expanded': state.isOpen ? 'true' : 'false',
|
|
8045
|
+
'aria-haspopup': 'listbox',
|
|
8046
|
+
'aria-controls': state.isOpen ? state.listboxId : undefined,
|
|
8047
|
+
'aria-activedescendant': activeDescendantId,
|
|
7755
8048
|
style: {
|
|
7756
|
-
display: 'flex',
|
|
7757
|
-
alignItems: 'end',
|
|
7758
|
-
flexWrap: 'wrap',
|
|
7759
8049
|
cursor: 'pointer',
|
|
7760
8050
|
position: 'relative',
|
|
7761
8051
|
},
|
|
@@ -7768,30 +8058,41 @@ const SearchSelect = () => {
|
|
|
7768
8058
|
value: selectedOptions.map((o) => o.label || o.id.toString()).join(', '),
|
|
7769
8059
|
readonly: true,
|
|
7770
8060
|
class: 'sr-only',
|
|
7771
|
-
style: {
|
|
8061
|
+
style: {
|
|
8062
|
+
position: 'absolute',
|
|
8063
|
+
width: '1px',
|
|
8064
|
+
height: '1px',
|
|
8065
|
+
margin: '-1px',
|
|
8066
|
+
padding: 0,
|
|
8067
|
+
border: 0,
|
|
8068
|
+
overflow: 'hidden',
|
|
8069
|
+
clip: 'rect(0 0 0 0)',
|
|
8070
|
+
clipPath: 'inset(50%)',
|
|
8071
|
+
whiteSpace: 'nowrap',
|
|
8072
|
+
},
|
|
7772
8073
|
}),
|
|
7773
8074
|
// Selected Options (chips)
|
|
7774
|
-
...selectedOptions.map((option) =>
|
|
7775
|
-
option,
|
|
8075
|
+
...selectedOptions.map((option) => SelectedChip({
|
|
8076
|
+
option: option,
|
|
7776
8077
|
onRemove: (id) => removeOption(id, attrs),
|
|
7777
8078
|
})),
|
|
7778
8079
|
// Placeholder when no options selected
|
|
7779
8080
|
selectedOptions.length === 0 &&
|
|
7780
8081
|
placeholder &&
|
|
7781
8082
|
m('span.placeholder', {
|
|
8083
|
+
class: 'mm-layout-grow',
|
|
7782
8084
|
style: {
|
|
7783
8085
|
color: 'var(--mm-text-hint, #9e9e9e)',
|
|
7784
|
-
flexGrow: 1,
|
|
7785
8086
|
padding: '8px 0',
|
|
7786
8087
|
},
|
|
7787
8088
|
}, placeholder),
|
|
7788
8089
|
// Spacer to push caret to the right
|
|
7789
|
-
m('span.spacer'
|
|
8090
|
+
m('span.spacer.mm-layout-grow'),
|
|
7790
8091
|
m(MaterialIcon, {
|
|
7791
8092
|
name: 'caret',
|
|
7792
8093
|
direction: state.isOpen ? 'up' : 'down',
|
|
7793
|
-
class: 'caret',
|
|
7794
|
-
style: {
|
|
8094
|
+
class: 'caret mm-layout-ml-auto',
|
|
8095
|
+
style: { cursor: 'pointer' },
|
|
7795
8096
|
}),
|
|
7796
8097
|
]),
|
|
7797
8098
|
// Label
|
|
@@ -7803,6 +8104,8 @@ const SearchSelect = () => {
|
|
|
7803
8104
|
// Dropdown Menu
|
|
7804
8105
|
state.isOpen &&
|
|
7805
8106
|
m('ul.dropdown-content.select-dropdown', {
|
|
8107
|
+
id: state.listboxId,
|
|
8108
|
+
role: 'listbox',
|
|
7806
8109
|
oncreate: ({ dom }) => {
|
|
7807
8110
|
state.dropdownRef = dom;
|
|
7808
8111
|
},
|
|
@@ -7827,23 +8130,39 @@ const SearchSelect = () => {
|
|
|
7827
8130
|
oninput: (e) => {
|
|
7828
8131
|
state.searchTerm = e.target.value;
|
|
7829
8132
|
state.focusedIndex = -1; // Reset focus when typing
|
|
8133
|
+
if (loadOptions) {
|
|
8134
|
+
void loadAsyncOptions(attrs, state.searchTerm);
|
|
8135
|
+
}
|
|
7830
8136
|
},
|
|
7831
8137
|
onkeydown: async (e) => {
|
|
7832
|
-
const
|
|
7833
|
-
if (
|
|
8138
|
+
const action = handleKeyDown(e, displayedOptions.length, !!showAddNew);
|
|
8139
|
+
if (action === 'open' && loadOptions) {
|
|
8140
|
+
await loadAsyncOptions(attrs, state.searchTerm);
|
|
8141
|
+
}
|
|
8142
|
+
else if (action === 'selectAction' && oncreateNewOption) {
|
|
7834
8143
|
await createAndSelectOption(attrs);
|
|
7835
8144
|
}
|
|
7836
|
-
else if (
|
|
8145
|
+
else if (action === 'selectFocused' && state.focusedIndex < displayedOptions.length) {
|
|
7837
8146
|
toggleOption(displayedOptions[state.focusedIndex], attrs);
|
|
7838
8147
|
}
|
|
7839
8148
|
},
|
|
7840
8149
|
class: 'search-select-input',
|
|
8150
|
+
'aria-autocomplete': 'list',
|
|
8151
|
+
'aria-controls': state.listboxId,
|
|
7841
8152
|
}),
|
|
7842
8153
|
]),
|
|
7843
|
-
//
|
|
7844
|
-
...(
|
|
7845
|
-
? [m('li.search-select-
|
|
8154
|
+
// Async loading status
|
|
8155
|
+
...(viewState === 'loading'
|
|
8156
|
+
? [m('li.search-select-loading-info', { role: 'status', 'aria-live': 'polite' }, texts.loadingOptions)]
|
|
8157
|
+
: []),
|
|
8158
|
+
// Async loading error
|
|
8159
|
+
...(viewState === 'error' && state.loadError
|
|
8160
|
+
? [
|
|
8161
|
+
m('li.search-select-error-info', { role: 'status', 'aria-live': 'assertive' }, `${texts.loadingError}: ${state.loadError}`),
|
|
8162
|
+
]
|
|
7846
8163
|
: []),
|
|
8164
|
+
// No options found message or list of options
|
|
8165
|
+
...(viewState === 'empty' && !showAddNew ? [m('li.search-select-no-options', texts.noOptionsFound)] : []),
|
|
7847
8166
|
// Truncation message
|
|
7848
8167
|
...(isTruncated
|
|
7849
8168
|
? [
|
|
@@ -7876,6 +8195,9 @@ const SearchSelect = () => {
|
|
|
7876
8195
|
...(showAddNew
|
|
7877
8196
|
? [
|
|
7878
8197
|
m('li', {
|
|
8198
|
+
id: `${state.listboxId}-action`,
|
|
8199
|
+
role: 'option',
|
|
8200
|
+
'aria-selected': 'false',
|
|
7879
8201
|
onclick: async () => {
|
|
7880
8202
|
await createAndSelectOption(attrs);
|
|
7881
8203
|
},
|
|
@@ -7887,9 +8209,10 @@ const SearchSelect = () => {
|
|
|
7887
8209
|
]
|
|
7888
8210
|
: []),
|
|
7889
8211
|
// List of filtered options
|
|
7890
|
-
...displayedOptions.map((option, index) =>
|
|
8212
|
+
...displayedOptions.map((option, index) => DropdownOption({
|
|
7891
8213
|
option,
|
|
7892
8214
|
index,
|
|
8215
|
+
optionId: getComboboxOptionId(state.id, index),
|
|
7893
8216
|
selectedIds,
|
|
7894
8217
|
isFocused: state.focusedIndex === index,
|
|
7895
8218
|
onToggle: (opt) => toggleOption(opt, attrs),
|
|
@@ -7902,6 +8225,10 @@ const SearchSelect = () => {
|
|
|
7902
8225
|
]);
|
|
7903
8226
|
},
|
|
7904
8227
|
};
|
|
8228
|
+
if (maybeVnode === null || maybeVnode === void 0 ? void 0 : maybeVnode.state) {
|
|
8229
|
+
maybeVnode.state.__searchSelectInstance = componentInstance;
|
|
8230
|
+
}
|
|
8231
|
+
return componentInstance;
|
|
7905
8232
|
};
|
|
7906
8233
|
|
|
7907
8234
|
const defaultI18n$2 = {
|
|
@@ -9275,6 +9602,53 @@ const FileUpload = () => {
|
|
|
9275
9602
|
};
|
|
9276
9603
|
};
|
|
9277
9604
|
|
|
9605
|
+
/** A semantic native fieldset for related controls. */
|
|
9606
|
+
const Fieldset = () => ({
|
|
9607
|
+
view: ({ attrs, children }) => {
|
|
9608
|
+
const { legend, description, required, disabled, error, className } = attrs, params = __rest(attrs, ["legend", "description", "required", "disabled", "error", "className"]);
|
|
9609
|
+
const descriptionId = params.id ? `${params.id}-description` : undefined;
|
|
9610
|
+
const errorId = params.id ? `${params.id}-error` : undefined;
|
|
9611
|
+
const describedBy = [description && descriptionId, error && errorId].filter(Boolean).join(' ') || undefined;
|
|
9612
|
+
return m('fieldset.mm-fieldset', Object.assign(Object.assign({}, params), { className, disabled, 'aria-describedby': describedBy }), [
|
|
9613
|
+
m('legend.mm-fieldset__legend', [legend, required && m('span.mm-fieldset__required[aria-hidden=true]', ' *')]),
|
|
9614
|
+
description && m('p.mm-fieldset__description', { id: descriptionId }, description),
|
|
9615
|
+
children,
|
|
9616
|
+
error && m('p.mm-fieldset__error[role=alert]', { id: errorId }, error),
|
|
9617
|
+
]);
|
|
9618
|
+
},
|
|
9619
|
+
});
|
|
9620
|
+
const focusErrorTarget = (fieldId) => {
|
|
9621
|
+
var _a;
|
|
9622
|
+
if (!fieldId || typeof document === 'undefined')
|
|
9623
|
+
return;
|
|
9624
|
+
(_a = document.getElementById(fieldId)) === null || _a === void 0 ? void 0 : _a.focus();
|
|
9625
|
+
};
|
|
9626
|
+
/** A visual form section with an optional accessible validation summary. */
|
|
9627
|
+
const FormSection = () => ({
|
|
9628
|
+
view: ({ attrs, children }) => {
|
|
9629
|
+
const { title, description, errors = [], summaryTitle = 'Please correct the following errors', className } = attrs, params = __rest(attrs, ["title", "description", "errors", "summaryTitle", "className"]);
|
|
9630
|
+
return m('section.mm-form-section', Object.assign(Object.assign({}, params), { className }), [
|
|
9631
|
+
(title || description) &&
|
|
9632
|
+
m('.mm-form-section__header', [
|
|
9633
|
+
title && m('h3.mm-form-section__title', title),
|
|
9634
|
+
description && m('p.mm-form-section__description', description),
|
|
9635
|
+
]),
|
|
9636
|
+
errors.length > 0 &&
|
|
9637
|
+
m('div.mm-validation-summary[role=alert][aria-live=assertive]', [
|
|
9638
|
+
m('p.mm-validation-summary__title', summaryTitle),
|
|
9639
|
+
m('ul.mm-validation-summary__list', errors.map((error, index) => {
|
|
9640
|
+
var _a, _b, _c;
|
|
9641
|
+
const href = (_a = error.href) !== null && _a !== void 0 ? _a : (error.fieldId ? `#${error.fieldId}` : undefined);
|
|
9642
|
+
return m('li', { key: `${(_c = (_b = error.fieldId) !== null && _b !== void 0 ? _b : href) !== null && _c !== void 0 ? _c : 'error'}-${index}` }, href
|
|
9643
|
+
? m('a', { href, onclick: () => focusErrorTarget(error.fieldId) }, error.message)
|
|
9644
|
+
: error.message);
|
|
9645
|
+
})),
|
|
9646
|
+
]),
|
|
9647
|
+
children,
|
|
9648
|
+
]);
|
|
9649
|
+
},
|
|
9650
|
+
});
|
|
9651
|
+
|
|
9278
9652
|
// List of MaterialIcon SVG icons that are available
|
|
9279
9653
|
const materialIconSvgNames = [
|
|
9280
9654
|
'caret',
|
|
@@ -9297,6 +9671,7 @@ const materialIconSvgNames = [
|
|
|
9297
9671
|
const renderIcon = (icon, style) => {
|
|
9298
9672
|
if (!icon)
|
|
9299
9673
|
return null;
|
|
9674
|
+
const objectStyle = typeof style === 'string' ? undefined : style;
|
|
9300
9675
|
if (typeof icon === 'string') {
|
|
9301
9676
|
// Check if this is a MaterialIcon SVG name
|
|
9302
9677
|
if (materialIconSvgNames.includes(icon)) {
|
|
@@ -9313,7 +9688,7 @@ const renderIcon = (icon, style) => {
|
|
|
9313
9688
|
// Image URL
|
|
9314
9689
|
return m('img', {
|
|
9315
9690
|
src: icon.content,
|
|
9316
|
-
style: Object.assign(Object.assign({},
|
|
9691
|
+
style: Object.assign(Object.assign({}, objectStyle), { width: '24px', height: '24px', objectFit: 'contain' }),
|
|
9317
9692
|
});
|
|
9318
9693
|
}
|
|
9319
9694
|
return null;
|
|
@@ -9324,8 +9699,10 @@ const renderIcon = (icon, style) => {
|
|
|
9324
9699
|
const SidenavHeaderFooterItem = () => {
|
|
9325
9700
|
return {
|
|
9326
9701
|
view: ({ attrs }) => {
|
|
9327
|
-
const { text, icon, onclick, href, className = '', _isExpanded = true, _position = 'left' } = attrs;
|
|
9702
|
+
const { text, icon, onclick, href, className = '', title, tooltip, tooltipWhenCollapsedOnly = true, _isExpanded = true, _position = 'left', } = attrs;
|
|
9328
9703
|
const isRightAligned = _position === 'right';
|
|
9704
|
+
const tooltipText = title || tooltip || text;
|
|
9705
|
+
const shouldShowTooltip = tooltipWhenCollapsedOnly ? !_isExpanded : true;
|
|
9329
9706
|
const handleClick = (e) => {
|
|
9330
9707
|
if (onclick) {
|
|
9331
9708
|
e.preventDefault();
|
|
@@ -9334,24 +9711,25 @@ const SidenavHeaderFooterItem = () => {
|
|
|
9334
9711
|
};
|
|
9335
9712
|
const content = isRightAligned
|
|
9336
9713
|
? [
|
|
9337
|
-
_isExpanded &&
|
|
9338
|
-
m('span.sidenav-item-text', { style: { flex: '1', 'text-align': 'left', 'margin-right': '8px' } }, text),
|
|
9714
|
+
_isExpanded && m('span.sidenav-item-text.mm-layout-grow.mm-layout-mr-8.left-align', text),
|
|
9339
9715
|
renderIcon(icon, { 'min-width': '24px', width: '24px' }),
|
|
9340
9716
|
]
|
|
9341
9717
|
: [
|
|
9342
9718
|
renderIcon(icon, { 'min-width': '24px', width: '24px' }),
|
|
9343
|
-
_isExpanded && m('span.sidenav-item-text
|
|
9719
|
+
_isExpanded && m('span.sidenav-item-text.mm-layout-grow.mm-layout-ml-8', text),
|
|
9344
9720
|
];
|
|
9345
9721
|
const linkStyle = {
|
|
9346
|
-
display: 'flex',
|
|
9347
|
-
'align-items': 'center',
|
|
9348
9722
|
padding: _isExpanded ? '12px 16px' : '12px 18px',
|
|
9349
9723
|
'justify-content': _isExpanded ? (isRightAligned ? 'flex-end' : 'flex-start') : 'center',
|
|
9350
9724
|
};
|
|
9725
|
+
const linkClass = 'mm-layout-row mm-layout-row--center';
|
|
9351
9726
|
return m('li', { class: className }, m('a', {
|
|
9352
9727
|
href: href || '#!',
|
|
9353
9728
|
onclick: handleClick,
|
|
9729
|
+
class: linkClass,
|
|
9354
9730
|
style: linkStyle,
|
|
9731
|
+
title: shouldShowTooltip ? tooltipText : undefined,
|
|
9732
|
+
'aria-label': shouldShowTooltip ? tooltipText : undefined,
|
|
9355
9733
|
}, content));
|
|
9356
9734
|
},
|
|
9357
9735
|
};
|
|
@@ -9373,9 +9751,9 @@ const Sidenav = () => {
|
|
|
9373
9751
|
m.redraw();
|
|
9374
9752
|
}
|
|
9375
9753
|
};
|
|
9376
|
-
const setBodyOverflow = (isOpen, mode) => {
|
|
9754
|
+
const setBodyOverflow = (isOpen, mode, fixed) => {
|
|
9377
9755
|
if (typeof document !== 'undefined') {
|
|
9378
|
-
document.body.style.overflow = isOpen && mode === 'overlay' ? 'hidden' : '';
|
|
9756
|
+
document.body.style.overflow = isOpen && mode === 'overlay' && !fixed ? 'hidden' : '';
|
|
9379
9757
|
}
|
|
9380
9758
|
};
|
|
9381
9759
|
const toggleExpanded = (attrs) => {
|
|
@@ -9411,7 +9789,7 @@ const Sidenav = () => {
|
|
|
9411
9789
|
if (wasOpen !== isOpen) {
|
|
9412
9790
|
state.isOpen = isOpen;
|
|
9413
9791
|
state.isAnimating = true;
|
|
9414
|
-
setBodyOverflow(isOpen, attrs.mode || 'overlay');
|
|
9792
|
+
setBodyOverflow(isOpen, attrs.mode || 'overlay', attrs.fixed || false);
|
|
9415
9793
|
// Clear animation state after animation completes
|
|
9416
9794
|
setTimeout(() => {
|
|
9417
9795
|
state.isAnimating = false;
|
|
@@ -9421,7 +9799,7 @@ const Sidenav = () => {
|
|
|
9421
9799
|
},
|
|
9422
9800
|
onremove: ({ attrs }) => {
|
|
9423
9801
|
// Clean up
|
|
9424
|
-
setBodyOverflow(false, attrs.mode || 'overlay');
|
|
9802
|
+
setBodyOverflow(false, attrs.mode || 'overlay', attrs.fixed || false);
|
|
9425
9803
|
if (typeof document !== 'undefined' && attrs.closeOnEscape !== false) {
|
|
9426
9804
|
document.removeEventListener('keydown', (e) => handleEscapeKey(e, attrs));
|
|
9427
9805
|
}
|
|
@@ -9450,7 +9828,9 @@ const Sidenav = () => {
|
|
|
9450
9828
|
class: [
|
|
9451
9829
|
position === 'right' ? 'right-aligned' : '',
|
|
9452
9830
|
fixed ? 'sidenav-fixed' : '',
|
|
9831
|
+
mode === 'push' ? 'sidenav-push' : '',
|
|
9453
9832
|
expandable && !isExpanded ? 'sidenav-collapsed' : '',
|
|
9833
|
+
'mm-layout-stack',
|
|
9454
9834
|
className,
|
|
9455
9835
|
]
|
|
9456
9836
|
.filter(Boolean)
|
|
@@ -9462,13 +9842,22 @@ const Sidenav = () => {
|
|
|
9462
9842
|
'transition-property': 'transform, width',
|
|
9463
9843
|
},
|
|
9464
9844
|
}, [
|
|
9845
|
+
// Header content slot (rendered first, before hamburger)
|
|
9846
|
+
attrs.headerContent &&
|
|
9847
|
+
m('li.sidenav-header-slot', {
|
|
9848
|
+
style: {
|
|
9849
|
+
'flex-shrink': 0,
|
|
9850
|
+
'list-style': 'none',
|
|
9851
|
+
height: 'auto',
|
|
9852
|
+
'line-height': 'normal',
|
|
9853
|
+
padding: 0,
|
|
9854
|
+
},
|
|
9855
|
+
}, attrs.headerContent),
|
|
9465
9856
|
// Hamburger toggle button (inside sidenav, at the top)
|
|
9466
9857
|
showHamburger &&
|
|
9467
9858
|
m('li.sidenav-hamburger-item', {
|
|
9859
|
+
class: `mm-layout-row mm-layout-row--center ${position === 'right' ? 'mm-layout-row--justify-end' : 'mm-layout-row--justify-start'}`,
|
|
9468
9860
|
style: {
|
|
9469
|
-
display: 'flex',
|
|
9470
|
-
'justify-content': position === 'right' ? 'flex-end' : 'flex-start',
|
|
9471
|
-
'align-items': 'center',
|
|
9472
9861
|
padding: '12px 16px',
|
|
9473
9862
|
cursor: 'pointer',
|
|
9474
9863
|
'border-bottom': '1px solid rgba(0,0,0,0.1)',
|
|
@@ -9484,10 +9873,8 @@ const Sidenav = () => {
|
|
|
9484
9873
|
// Expand/collapse toggle button (if expandable, right below hamburger)
|
|
9485
9874
|
expandable &&
|
|
9486
9875
|
m('li.sidenav-expand-toggle', {
|
|
9876
|
+
class: `mm-layout-row mm-layout-row--center ${position === 'right' ? 'mm-layout-row--justify-end' : 'mm-layout-row--justify-start'}`,
|
|
9487
9877
|
style: {
|
|
9488
|
-
display: 'flex',
|
|
9489
|
-
'justify-content': position === 'right' ? 'flex-end' : 'flex-start',
|
|
9490
|
-
'align-items': 'center',
|
|
9491
9878
|
padding: '12px 16px',
|
|
9492
9879
|
cursor: 'pointer',
|
|
9493
9880
|
'border-bottom': '1px solid rgba(0,0,0,0.1)',
|
|
@@ -9515,7 +9902,19 @@ const Sidenav = () => {
|
|
|
9515
9902
|
: children,
|
|
9516
9903
|
// Footer item (if provided, appears at the bottom)
|
|
9517
9904
|
attrs.footer &&
|
|
9518
|
-
m(SidenavHeaderFooterItem, Object.assign(Object.assign({}, attrs.footer), { _isExpanded: isExpanded, _position: position, className: 'sidenav-footer-item' })),
|
|
9905
|
+
m(SidenavHeaderFooterItem, Object.assign(Object.assign({}, attrs.footer), { _isExpanded: isExpanded, _position: position, className: ['sidenav-footer-item', attrs.footer.className].filter(Boolean).join(' ') })),
|
|
9906
|
+
// Footer content slot (rendered last, pushed to bottom via margin-top: auto)
|
|
9907
|
+
attrs.footerContent &&
|
|
9908
|
+
m('li.sidenav-footer-slot', {
|
|
9909
|
+
style: {
|
|
9910
|
+
'margin-top': 'auto',
|
|
9911
|
+
'flex-shrink': 0,
|
|
9912
|
+
'list-style': 'none',
|
|
9913
|
+
height: 'auto',
|
|
9914
|
+
'line-height': 'normal',
|
|
9915
|
+
padding: 0,
|
|
9916
|
+
},
|
|
9917
|
+
}, attrs.footerContent),
|
|
9519
9918
|
]),
|
|
9520
9919
|
];
|
|
9521
9920
|
},
|
|
@@ -9548,7 +9947,7 @@ const NavbarSubItem = () => {
|
|
|
9548
9947
|
const submenuContent = isRightAligned
|
|
9549
9948
|
? [
|
|
9550
9949
|
// Right-aligned: text on left, icons on right
|
|
9551
|
-
isExpanded && m('span
|
|
9950
|
+
isExpanded && m('span.mm-layout-grow.left-align', text),
|
|
9552
9951
|
icon && isExpanded && renderIcon(icon, { 'font-size': '18px' }),
|
|
9553
9952
|
indicatorIcon,
|
|
9554
9953
|
]
|
|
@@ -9556,18 +9955,22 @@ const NavbarSubItem = () => {
|
|
|
9556
9955
|
// Left-aligned: indicator on left, text and icon on right
|
|
9557
9956
|
indicatorIcon,
|
|
9558
9957
|
icon && isExpanded && renderIcon(icon, { 'font-size': '18px', 'margin-left': indicatorIcon ? '8px' : '0' }),
|
|
9559
|
-
isExpanded && m('span', {
|
|
9958
|
+
isExpanded && m('span', { class: icon || indicatorIcon ? 'mm-layout-ml-8' : undefined }, text),
|
|
9560
9959
|
];
|
|
9561
9960
|
return m('li.sidenav-subitem', {
|
|
9562
|
-
class:
|
|
9961
|
+
class: [
|
|
9962
|
+
selected ? 'selected' : '',
|
|
9963
|
+
'mm-layout-row',
|
|
9964
|
+
'mm-layout-row--center',
|
|
9965
|
+
'mm-layout-gap-sm',
|
|
9966
|
+
isRightAligned ? 'mm-layout-row--justify-between' : 'mm-layout-row--justify-start',
|
|
9967
|
+
]
|
|
9968
|
+
.filter(Boolean)
|
|
9969
|
+
.join(' ') || undefined,
|
|
9563
9970
|
style: {
|
|
9564
9971
|
padding: isExpanded ? '0 16px 0 48px' : '0 16px',
|
|
9565
9972
|
cursor: 'pointer',
|
|
9566
|
-
display: 'flex',
|
|
9567
|
-
'align-items': 'center',
|
|
9568
|
-
gap: '8px',
|
|
9569
9973
|
'font-size': '0.9em',
|
|
9570
|
-
'justify-content': isRightAligned ? 'space-between' : 'flex-start',
|
|
9571
9974
|
height: '48px',
|
|
9572
9975
|
'min-height': '48px',
|
|
9573
9976
|
},
|
|
@@ -9584,7 +9987,7 @@ const SidenavItem = () => {
|
|
|
9584
9987
|
let isSubmenuOpen = false;
|
|
9585
9988
|
return {
|
|
9586
9989
|
view: ({ attrs, children }) => {
|
|
9587
|
-
const { text, icon, active = false, disabled = false, onclick, href, className = '', divider = false, subheader = false, submenu = [], submenuMode = 'checkbox', } = attrs;
|
|
9990
|
+
const { text, icon, active = false, disabled = false, onclick, href, className = '', divider = false, subheader = false, submenu = [], submenuMode = 'checkbox', title, tooltip, tooltipWhenCollapsedOnly = true, } = attrs;
|
|
9588
9991
|
if (divider) {
|
|
9589
9992
|
return m('li.divider');
|
|
9590
9993
|
}
|
|
@@ -9609,39 +10012,45 @@ const SidenavItem = () => {
|
|
|
9609
10012
|
const isExpanded = attrs._isExpanded !== false;
|
|
9610
10013
|
const position = attrs._position || 'left';
|
|
9611
10014
|
const isRightAligned = position === 'right';
|
|
10015
|
+
const tooltipText = title || tooltip || text;
|
|
10016
|
+
const shouldShowTooltip = tooltipWhenCollapsedOnly ? !isExpanded : true;
|
|
9612
10017
|
// In expanded mode, icons are at the outside edge
|
|
9613
10018
|
// In collapsed mode, icons are centered
|
|
9614
10019
|
const content = isRightAligned
|
|
9615
10020
|
? [
|
|
9616
10021
|
// Right-aligned: text on left, icon on right
|
|
9617
|
-
isExpanded &&
|
|
9618
|
-
m('span.sidenav-item-text', { style: { flex: '1', 'text-align': 'left', 'margin-right': '8px' } }, text || children),
|
|
10022
|
+
isExpanded && m('span.sidenav-item-text.mm-layout-grow.mm-layout-mr-8.left-align', text || children),
|
|
9619
10023
|
renderIcon(icon, { 'min-width': '24px', width: '24px' }),
|
|
9620
10024
|
]
|
|
9621
10025
|
: [
|
|
9622
10026
|
// Left-aligned: icon on left, text on right
|
|
9623
10027
|
renderIcon(icon, { 'min-width': '24px', width: '24px' }),
|
|
9624
|
-
isExpanded && m('span.sidenav-item-text
|
|
10028
|
+
isExpanded && m('span.sidenav-item-text.mm-layout-grow.mm-layout-ml-8', text || children),
|
|
9625
10029
|
];
|
|
9626
10030
|
const linkStyle = {
|
|
9627
|
-
display: 'flex',
|
|
9628
|
-
'align-items': 'center',
|
|
9629
10031
|
padding: isExpanded ? '12px 16px' : '12px 18px',
|
|
9630
10032
|
'justify-content': isExpanded ? (isRightAligned ? 'flex-end' : 'flex-start') : 'center',
|
|
9631
10033
|
};
|
|
10034
|
+
const linkClass = 'mm-layout-row mm-layout-row--center';
|
|
9632
10035
|
const mainItem = href && !disabled
|
|
9633
10036
|
? m('li', { class: itemClasses }, [
|
|
9634
10037
|
m('a', {
|
|
9635
10038
|
href,
|
|
9636
10039
|
onclick: handleMainClick,
|
|
10040
|
+
class: linkClass,
|
|
9637
10041
|
style: linkStyle,
|
|
10042
|
+
title: shouldShowTooltip ? tooltipText : undefined,
|
|
10043
|
+
'aria-label': shouldShowTooltip ? tooltipText : undefined,
|
|
9638
10044
|
}, content),
|
|
9639
10045
|
])
|
|
9640
10046
|
: m('li', { class: itemClasses }, [
|
|
9641
10047
|
m('a', {
|
|
9642
10048
|
onclick: handleMainClick,
|
|
9643
10049
|
href: '#!',
|
|
10050
|
+
class: linkClass,
|
|
9644
10051
|
style: linkStyle,
|
|
10052
|
+
title: shouldShowTooltip ? tooltipText : undefined,
|
|
10053
|
+
'aria-label': shouldShowTooltip ? tooltipText : undefined,
|
|
9645
10054
|
}, content),
|
|
9646
10055
|
]);
|
|
9647
10056
|
// Return main item with submenu if applicable
|
|
@@ -10157,8 +10566,9 @@ const TreeNodeComponent = () => {
|
|
|
10157
10566
|
const childIsFocused = ((_e = attrs.treeState) === null || _e === void 0 ? void 0 : _e.focusedNodeId) === child.id;
|
|
10158
10567
|
// Calculate if this child is last in branch
|
|
10159
10568
|
const childPath = [...(attrs.currentPath || []), childIndex];
|
|
10160
|
-
const childIsLastInBranch = ((_f = attrs.treeAttrs) === null || _f === void 0 ? void 0 : _f.data)
|
|
10161
|
-
isNodeLastInBranch(childPath, attrs.treeAttrs.data)
|
|
10569
|
+
const childIsLastInBranch = ((_f = attrs.treeAttrs) === null || _f === void 0 ? void 0 : _f.data)
|
|
10570
|
+
? isNodeLastInBranch(childPath, attrs.treeAttrs.data)
|
|
10571
|
+
: false;
|
|
10162
10572
|
return m(TreeNodeComponent, {
|
|
10163
10573
|
key: child.id,
|
|
10164
10574
|
node: child,
|
|
@@ -10291,10 +10701,7 @@ const TreeView = () => {
|
|
|
10291
10701
|
view: ({ attrs }) => {
|
|
10292
10702
|
const { data, className, style, id, selectionMode = 'single', showConnectors = true } = attrs;
|
|
10293
10703
|
return m('div.tree-view', {
|
|
10294
|
-
class: [
|
|
10295
|
-
className,
|
|
10296
|
-
showConnectors && 'show-connectors'
|
|
10297
|
-
].filter(Boolean).join(' ') || undefined,
|
|
10704
|
+
class: [className, showConnectors && 'show-connectors'].filter(Boolean).join(' ') || undefined,
|
|
10298
10705
|
style,
|
|
10299
10706
|
id,
|
|
10300
10707
|
role: selectionMode === 'multiple' ? 'listbox' : 'tree',
|
|
@@ -10992,6 +11399,7 @@ const Rating = () => {
|
|
|
10992
11399
|
};
|
|
10993
11400
|
};
|
|
10994
11401
|
|
|
11402
|
+
const MOBILE_LAYOUT_BREAKPOINT = 600;
|
|
10995
11403
|
/** Create a LikertScale component */
|
|
10996
11404
|
const LikertScale = () => {
|
|
10997
11405
|
const state = {
|
|
@@ -11054,6 +11462,22 @@ const LikertScale = () => {
|
|
|
11054
11462
|
return 'likert-scale--responsive';
|
|
11055
11463
|
}
|
|
11056
11464
|
};
|
|
11465
|
+
const isVerticalLayout = (layout) => {
|
|
11466
|
+
if (layout === 'vertical')
|
|
11467
|
+
return true;
|
|
11468
|
+
if (layout === 'horizontal')
|
|
11469
|
+
return false;
|
|
11470
|
+
return typeof window !== 'undefined' ? window.innerWidth <= MOBILE_LAYOUT_BREAKPOINT : false;
|
|
11471
|
+
};
|
|
11472
|
+
const getInlineAnchorLabel = (value, min, max, middleValue, startLabel, middleLabel, endLabel) => {
|
|
11473
|
+
if (value === min && startLabel)
|
|
11474
|
+
return startLabel;
|
|
11475
|
+
if (middleLabel && middleValue !== undefined && value === middleValue)
|
|
11476
|
+
return middleLabel;
|
|
11477
|
+
if (value === max && endLabel)
|
|
11478
|
+
return endLabel;
|
|
11479
|
+
return undefined;
|
|
11480
|
+
};
|
|
11057
11481
|
const handleChange = (attrs, newValue) => {
|
|
11058
11482
|
var _a;
|
|
11059
11483
|
if (attrs.readonly || attrs.disabled)
|
|
@@ -11100,7 +11524,7 @@ const LikertScale = () => {
|
|
|
11100
11524
|
const LikertScaleItem = () => {
|
|
11101
11525
|
return {
|
|
11102
11526
|
view: ({ attrs }) => {
|
|
11103
|
-
const { value, currentValue, showNumber, showTooltip, tooltipLabel, groupId, name, disabled, readonly, onchange, } = attrs;
|
|
11527
|
+
const { value, currentValue, showNumber, showTooltip, tooltipLabel, groupId, name, disabled, readonly, anchorLabel, onchange, } = attrs;
|
|
11104
11528
|
const radioId = `${groupId}-${value}`;
|
|
11105
11529
|
const isChecked = currentValue === value;
|
|
11106
11530
|
return m('.likert-scale__item.no-select', {
|
|
@@ -11127,6 +11551,7 @@ const LikertScale = () => {
|
|
|
11127
11551
|
m('label.likert-scale__label', {
|
|
11128
11552
|
for: radioId,
|
|
11129
11553
|
}),
|
|
11554
|
+
anchorLabel && m('.likert-scale__item-anchor', anchorLabel),
|
|
11130
11555
|
// Tooltip (optional)
|
|
11131
11556
|
showTooltip && tooltipLabel && m('.likert-scale__tooltip', tooltipLabel),
|
|
11132
11557
|
]);
|
|
@@ -11150,6 +11575,8 @@ const LikertScale = () => {
|
|
|
11150
11575
|
const { min = 1, max = 5, step = 1, size = 'medium', density = 'standard', layout = 'responsive', className = '', style = {}, readonly = false, disabled = false, id = state.id, name, label, description, isMandatory, startLabel, middleLabel, endLabel, showNumbers = false, showTooltips = false, tooltipLabels, alignLabels = false } = attrs, ariaAttrs = __rest(attrs, ["min", "max", "step", "size", "density", "layout", "className", "style", "readonly", "disabled", "id", "name", "label", "description", "isMandatory", "startLabel", "middleLabel", "endLabel", "showNumbers", "showTooltips", "tooltipLabels", "alignLabels"]);
|
|
11151
11576
|
const currentValue = getCurrentValue(attrs);
|
|
11152
11577
|
const itemCount = Math.floor((max - min) / step) + 1;
|
|
11578
|
+
const useInlineAnchors = isVerticalLayout(layout);
|
|
11579
|
+
const middleValue = middleLabel ? min + Math.floor((itemCount - 1) / 2) * step : undefined;
|
|
11153
11580
|
// Generate scale values
|
|
11154
11581
|
const scaleValues = Array.from({ length: itemCount }, (_, i) => min + i * step);
|
|
11155
11582
|
return m('.likert-scale', {
|
|
@@ -11198,6 +11625,9 @@ const LikertScale = () => {
|
|
|
11198
11625
|
showNumber: showNumbers,
|
|
11199
11626
|
showTooltip: showTooltips,
|
|
11200
11627
|
tooltipLabel: tooltipLabels === null || tooltipLabels === void 0 ? void 0 : tooltipLabels[value - min],
|
|
11628
|
+
anchorLabel: useInlineAnchors
|
|
11629
|
+
? getInlineAnchorLabel(value, min, max, middleValue, startLabel, middleLabel, endLabel)
|
|
11630
|
+
: undefined,
|
|
11201
11631
|
groupId: state.groupId,
|
|
11202
11632
|
name,
|
|
11203
11633
|
disabled,
|
|
@@ -11205,7 +11635,8 @@ const LikertScale = () => {
|
|
|
11205
11635
|
onchange: (v) => handleChange(attrs, v),
|
|
11206
11636
|
}))),
|
|
11207
11637
|
// Scale anchors
|
|
11208
|
-
|
|
11638
|
+
!useInlineAnchors &&
|
|
11639
|
+
(startLabel || middleLabel || endLabel) &&
|
|
11209
11640
|
m('.likert-scale__anchors', [
|
|
11210
11641
|
startLabel && m('.likert-scale__anchor.likert-scale__anchor--start', startLabel),
|
|
11211
11642
|
middleLabel && m('.likert-scale__anchor.likert-scale__anchor--middle', middleLabel),
|
|
@@ -11390,6 +11821,9 @@ const CircularProgress = () => {
|
|
|
11390
11821
|
const { mode = 'indeterminate', value = 0, max = 100, size = 'medium', color = 'teal', colorIntensity, label, showPercentage = false, className = '', style = {}, id = state.id, 'aria-label': ariaLabel, 'aria-valuemin': ariaValueMin = 0, 'aria-valuemax': ariaValueMax = max, 'aria-valuenow': ariaValueNow, 'aria-valuetext': ariaValueText } = attrs, params = __rest(attrs, ["mode", "value", "max", "size", "color", "colorIntensity", "label", "showPercentage", "className", "style", "id", 'aria-label', 'aria-valuemin', 'aria-valuemax', 'aria-valuenow', 'aria-valuetext']);
|
|
11391
11822
|
const isDeterminate = mode === 'determinate';
|
|
11392
11823
|
const sizePixels = SIZE_MAP[size];
|
|
11824
|
+
const styleValue = typeof style === 'string'
|
|
11825
|
+
? `width:${sizePixels}px;height:${sizePixels}px;${style}`
|
|
11826
|
+
: Object.assign({ width: `${sizePixels}px`, height: `${sizePixels}px` }, style);
|
|
11393
11827
|
const { radius, circumference, strokeDashoffset, percentage } = isDeterminate
|
|
11394
11828
|
? calculateStrokeProperties(sizePixels, value, max)
|
|
11395
11829
|
: { radius: 0, circumference: 0, strokeDashoffset: 0, percentage: 0 };
|
|
@@ -11416,7 +11850,7 @@ const CircularProgress = () => {
|
|
|
11416
11850
|
: {
|
|
11417
11851
|
'aria-valuetext': ariaValueText || label || 'Loading',
|
|
11418
11852
|
};
|
|
11419
|
-
return m('.circular-progress', Object.assign(Object.assign(Object.assign({}, params), { className: classNames, style:
|
|
11853
|
+
return m('.circular-progress', Object.assign(Object.assign(Object.assign({}, params), { className: classNames, style: styleValue, id, role: 'progressbar', 'aria-label': ariaLabel || (isDeterminate ? `Progress: ${Math.round(percentage)}%` : 'Loading') }), ariaAttrs), [
|
|
11420
11854
|
// SVG circle
|
|
11421
11855
|
m('svg.circular-progress__svg', {
|
|
11422
11856
|
viewBox: `0 0 ${sizePixels} ${sizePixels}`,
|
|
@@ -11481,13 +11915,7 @@ const LinearProgress = () => {
|
|
|
11481
11915
|
// Determine label content
|
|
11482
11916
|
const labelContent = label !== undefined ? label : showPercentage && isDeterminate ? `${Math.round(percentage)}%` : '';
|
|
11483
11917
|
// Build class names
|
|
11484
|
-
const classNames = [
|
|
11485
|
-
'linear-progress',
|
|
11486
|
-
getColorClass(color, colorIntensity),
|
|
11487
|
-
className,
|
|
11488
|
-
]
|
|
11489
|
-
.filter(Boolean)
|
|
11490
|
-
.join(' ');
|
|
11918
|
+
const classNames = ['linear-progress', getColorClass(color, colorIntensity), className].filter(Boolean).join(' ');
|
|
11491
11919
|
// ARIA attributes
|
|
11492
11920
|
const ariaAttrs = isDeterminate
|
|
11493
11921
|
? {
|
|
@@ -11564,10 +11992,12 @@ exports.DigitalClock = DigitalClock;
|
|
|
11564
11992
|
exports.DoubleRangeSlider = DoubleRangeSlider;
|
|
11565
11993
|
exports.Dropdown = Dropdown;
|
|
11566
11994
|
exports.EmailInput = EmailInput;
|
|
11995
|
+
exports.Fieldset = Fieldset;
|
|
11567
11996
|
exports.FileInput = FileInput;
|
|
11568
11997
|
exports.FileUpload = FileUpload;
|
|
11569
11998
|
exports.FlatButton = FlatButton;
|
|
11570
11999
|
exports.FloatingActionButton = FloatingActionButton;
|
|
12000
|
+
exports.FormSection = FormSection;
|
|
11571
12001
|
exports.HelperText = HelperText;
|
|
11572
12002
|
exports.Icon = Icon;
|
|
11573
12003
|
exports.IconButton = IconButton;
|
|
@@ -11619,6 +12049,7 @@ exports.TimeRangePicker = TimeRangePicker;
|
|
|
11619
12049
|
exports.Timeline = Timeline;
|
|
11620
12050
|
exports.Toast = Toast;
|
|
11621
12051
|
exports.ToastComponent = ToastComponent;
|
|
12052
|
+
exports.ToggleButton = ToggleButton;
|
|
11622
12053
|
exports.ToggleGroup = ToggleGroup;
|
|
11623
12054
|
exports.Tooltip = Tooltip;
|
|
11624
12055
|
exports.TooltipComponent = TooltipComponent;
|
|
@@ -11627,10 +12058,14 @@ exports.UrlInput = UrlInput;
|
|
|
11627
12058
|
exports.Wizard = Wizard;
|
|
11628
12059
|
exports.addLeadingZero = addLeadingZero;
|
|
11629
12060
|
exports.clearPortal = clearPortal;
|
|
12061
|
+
exports.createAsyncComboboxState = createAsyncComboboxState;
|
|
11630
12062
|
exports.createBreadcrumb = createBreadcrumb;
|
|
11631
12063
|
exports.formatTime = formatTime;
|
|
11632
12064
|
exports.generateHourOptions = generateHourOptions;
|
|
11633
12065
|
exports.generateMinuteOptions = generateMinuteOptions;
|
|
12066
|
+
exports.getComboboxKeyResult = getComboboxKeyResult;
|
|
12067
|
+
exports.getComboboxOptionId = getComboboxOptionId;
|
|
12068
|
+
exports.getComboboxViewState = getComboboxViewState;
|
|
11634
12069
|
exports.getDropdownStyles = getDropdownStyles;
|
|
11635
12070
|
exports.getPortalContainer = getPortalContainer;
|
|
11636
12071
|
exports.initPushpins = initPushpins;
|
|
@@ -11639,15 +12074,23 @@ exports.isNumeric = isNumeric;
|
|
|
11639
12074
|
exports.isTimeDisabled = isTimeDisabled;
|
|
11640
12075
|
exports.isValidationError = isValidationError;
|
|
11641
12076
|
exports.isValidationSuccess = isValidationSuccess;
|
|
12077
|
+
exports.normalizeSelection = normalizeSelection;
|
|
11642
12078
|
exports.padLeft = padLeft;
|
|
11643
12079
|
exports.parseTime = parseTime;
|
|
11644
12080
|
exports.range = range;
|
|
12081
|
+
exports.rejectAsyncComboboxRequest = rejectAsyncComboboxRequest;
|
|
11645
12082
|
exports.releasePortalContainer = releasePortalContainer;
|
|
12083
|
+
exports.renderFieldChrome = renderFieldChrome;
|
|
11646
12084
|
exports.renderToPortal = renderToPortal;
|
|
12085
|
+
exports.resolveAsyncComboboxRequest = resolveAsyncComboboxRequest;
|
|
12086
|
+
exports.resolveControllableValue = resolveControllableValue;
|
|
11647
12087
|
exports.scrollToValue = scrollToValue;
|
|
11648
12088
|
exports.snapToNearestItem = snapToNearestItem;
|
|
11649
12089
|
exports.sortOptions = sortOptions;
|
|
12090
|
+
exports.startAsyncComboboxRequest = startAsyncComboboxRequest;
|
|
12091
|
+
exports.syncPortalContent = syncPortalContent;
|
|
11650
12092
|
exports.timeToMinutes = timeToMinutes;
|
|
11651
12093
|
exports.toast = toast;
|
|
11652
12094
|
exports.uniqueId = uniqueId;
|
|
11653
12095
|
exports.uuid4 = uuid4;
|
|
12096
|
+
//# sourceMappingURL=index.js.map
|