mithril-materialized 3.16.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.
Files changed (46) hide show
  1. package/README.md +32 -2
  2. package/dist/advanced.css +92 -1
  3. package/dist/button.d.ts +3 -1
  4. package/dist/circular-progress.d.ts +2 -2
  5. package/dist/combobox.d.ts +35 -0
  6. package/dist/components.css +127 -14
  7. package/dist/core.css +278 -3
  8. package/dist/floating-action-button.d.ts +2 -1
  9. package/dist/form-section.d.ts +35 -0
  10. package/dist/forms.css +280 -5
  11. package/dist/index.css +340 -19
  12. package/dist/index.d.ts +3 -2
  13. package/dist/index.esm.js +697 -296
  14. package/dist/index.esm.js.map +1 -0
  15. package/dist/index.js +710 -295
  16. package/dist/index.js.map +1 -0
  17. package/dist/index.min.css +2 -2
  18. package/dist/index.umd.js +710 -295
  19. package/dist/index.umd.js.map +1 -0
  20. package/dist/input-options.d.ts +4 -1
  21. package/dist/likert-scale.d.ts +2 -1
  22. package/dist/linear-progress.d.ts +2 -2
  23. package/dist/material-icon.d.ts +2 -1
  24. package/dist/radio.d.ts +9 -0
  25. package/dist/range-slider.d.ts +3 -2
  26. package/dist/rating.d.ts +2 -1
  27. package/dist/search-select.d.ts +15 -2
  28. package/dist/select.d.ts +14 -1
  29. package/dist/sidenav.d.ts +6 -0
  30. package/dist/treeview.d.ts +2 -2
  31. package/dist/types.d.ts +5 -0
  32. package/dist/utilities.css +93 -2
  33. package/dist/utils.d.ts +30 -1
  34. package/package.json +16 -19
  35. package/sass/components/_badge-component.scss +8 -0
  36. package/sass/components/_buttons.scss +9 -9
  37. package/sass/components/_global.scss +93 -0
  38. package/sass/components/_likert-scale.scss +24 -0
  39. package/sass/components/_theme-variables.scss +22 -1
  40. package/sass/components/_toggle-group.scss +3 -0
  41. package/sass/components/forms/_form-groups.scss +1 -1
  42. package/sass/components/forms/_form-section.scss +63 -0
  43. package/sass/components/forms/_forms.scss +1 -0
  44. package/sass/components/forms/_input-fields.scss +55 -0
  45. package/sass/components/forms/_range-enhanced.scss +3 -3
  46. package/sass/components/forms/_select.scss +85 -0
package/dist/index.esm.js CHANGED
@@ -34,6 +34,35 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
34
34
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
35
35
  };
36
36
 
37
+ // import './styles/input.css';
38
+ const Mandatory = { view: ({ attrs }) => m('span.mandatory', Object.assign({}, attrs), '*') };
39
+ /** Simple label element, used for most components. */
40
+ const Label = () => {
41
+ return {
42
+ view: (_a) => {
43
+ var _b = _a.attrs, { label, id, isMandatory, isActive, className, initialValue } = _b, params = __rest(_b, ["label", "id", "isMandatory", "isActive", "className", "initialValue"]);
44
+ return label
45
+ ? m('label', Object.assign(Object.assign({}, params), { className: [className, isActive ? 'active' : ''].filter(Boolean).join(' ').trim() || undefined, for: id, oncreate: ({ dom }) => {
46
+ if (!initialValue)
47
+ return;
48
+ const labelEl = dom;
49
+ labelEl.classList.add('active');
50
+ } }), [m.trust(label), isMandatory ? m(Mandatory) : undefined])
51
+ : undefined;
52
+ },
53
+ };
54
+ };
55
+ /** Create a helper text, often used for displaying a small help text. May be replaced by the validation message. */
56
+ const HelperText = () => {
57
+ return {
58
+ view: ({ attrs: { helperText, dataError, dataSuccess, className } }) => {
59
+ return helperText || dataError || dataSuccess
60
+ ? m('span.helper-text.left', { className, 'data-error': dataError, 'data-success': dataSuccess }, dataError ? m.trust(dataError) : dataSuccess ? m.trust(dataSuccess) : helperText ? m.trust(helperText) : '')
61
+ : undefined;
62
+ },
63
+ };
64
+ };
65
+
37
66
  // Utility functions for the library
38
67
  /**
39
68
  * Create a unique ID
@@ -94,6 +123,42 @@ const sortOptions = (options, sortConfig) => {
94
123
  * @returns
95
124
  */
96
125
  const padLeft = (n, width = 2, z = '0') => String(n).padStart(width, z);
126
+ const normalizeSelection = (value) => {
127
+ if (value === undefined) {
128
+ return [];
129
+ }
130
+ return Array.isArray(value) ? value : [value];
131
+ };
132
+ const resolveControllableValue = ({ controlled, disabled, controlledValue, defaultValue, internalValue, fallbackValue, }) => {
133
+ var _a, _b;
134
+ if (controlled) {
135
+ return controlledValue !== null && controlledValue !== void 0 ? controlledValue : fallbackValue;
136
+ }
137
+ if (disabled) {
138
+ return (_a = defaultValue !== null && defaultValue !== void 0 ? defaultValue : controlledValue) !== null && _a !== void 0 ? _a : fallbackValue;
139
+ }
140
+ return (_b = internalValue !== null && internalValue !== void 0 ? internalValue : defaultValue) !== null && _b !== void 0 ? _b : fallbackValue;
141
+ };
142
+ const renderFieldChrome = ({ label, id, isMandatory, isActive, initialValue, helperText, dataError, dataSuccess, }) => {
143
+ return [
144
+ label
145
+ ? m(Label, {
146
+ label,
147
+ id,
148
+ isMandatory,
149
+ isActive,
150
+ initialValue,
151
+ })
152
+ : undefined,
153
+ helperText || dataError || dataSuccess
154
+ ? m(HelperText, {
155
+ helperText,
156
+ dataError,
157
+ dataSuccess,
158
+ })
159
+ : undefined,
160
+ ].filter(Boolean);
161
+ };
97
162
  // Keep only essential dropdown positioning styles
98
163
  const getDropdownStyles = (inputRef, overlap = false, options, isDropDown = false) => {
99
164
  if (!inputRef) {
@@ -125,8 +190,10 @@ const getDropdownStyles = (inputRef, overlap = false, options, isDropDown = fals
125
190
  groups.add(option.group);
126
191
  }
127
192
  });
128
- // Calculate total height: options + group headers + padding
129
- estimatedHeight = totalOptions * itemHeight + groups.size * groupHeaderHeight;
193
+ // Match the select dropdown's CSS max-height. Positioning with the full
194
+ // option count would otherwise leave a gap above an input near the bottom
195
+ // of the viewport when the rendered menu is capped at 400px.
196
+ estimatedHeight = Math.min(totalOptions * itemHeight + groups.size * groupHeaderHeight, 400);
130
197
  }
131
198
  const spaceBelow = viewportHeight - rect.bottom;
132
199
  const spaceAbove = rect.top;
@@ -142,33 +209,26 @@ const getDropdownStyles = (inputRef, overlap = false, options, isDropDown = fals
142
209
  const needsScrolling = estimatedHeight > effectiveAvailableSpace;
143
210
  // Calculate the actual height the dropdown will take
144
211
  const actualHeight = needsScrolling ? effectiveAvailableSpace : estimatedHeight;
145
- // Calculate positioning when dropdown should appear above
146
- let topOffset;
147
- if (shouldPositionAbove) {
148
- // Calculate how much space we actually have from top of viewport to top of input
149
- const availableSpaceFromViewportTop = rect.top;
150
- // If dropdown fits comfortably above input, use normal positioning
151
- if (actualHeight <= availableSpaceFromViewportTop) {
152
- topOffset = 12 - actualHeight + (isDropDown ? itemHeight : 0); // Bottom of dropdown aligns with top of input
153
- }
154
- else {
155
- // If dropdown is too tall, position it at the very top of viewport
156
- // This makes the dropdown use all available space from viewport top to input top
157
- topOffset = -availableSpaceFromViewportTop + 5; // 5px margin from viewport top
158
- }
159
- }
160
- else {
161
- topOffset = overlap ? 0 : '100%';
162
- }
163
212
  const styles = {
164
213
  display: 'block',
165
214
  opacity: 1,
166
215
  position: 'absolute',
167
- top: typeof topOffset === 'number' ? `${topOffset}px` : topOffset,
168
216
  left: '0',
169
217
  zIndex: 1000,
170
218
  width: `${rect.width}px`,
171
219
  };
220
+ if (shouldPositionAbove) {
221
+ // This menu is absolutely positioned inside the select wrapper. A negative
222
+ // `top` calculated from viewport coordinates becomes wrong when an ancestor
223
+ // scrolls (as ScenarioSpark's main area does). Anchor the menu to its local
224
+ // containing block instead; its height can then change without detaching it
225
+ // from the input.
226
+ styles.top = 'auto';
227
+ styles.bottom = `${isDropDown ? -18 : inputRef.offsetHeight - 12}px`;
228
+ }
229
+ else {
230
+ styles.top = overlap ? 0 : '100%';
231
+ }
172
232
  // Only add scrolling constraints when necessary
173
233
  if (needsScrolling) {
174
234
  styles.maxHeight = `${actualHeight}px`;
@@ -235,9 +295,17 @@ const releasePortalContainer = (id) => {
235
295
  * @param zIndex - Z-index for portal container (default: 1004)
236
296
  */
237
297
  const renderToPortal = (containerId, vnode, zIndex = 1004) => {
238
- const container = getPortalContainer(containerId, zIndex);
298
+ const existingContainer = portalContainers.get(containerId);
299
+ const container = existingContainer ? existingContainer.element : getPortalContainer(containerId, zIndex);
239
300
  m.render(container, vnode);
240
301
  };
302
+ const syncPortalContent = ({ containerId, shouldRender, vnode, zIndex = 1004 }) => {
303
+ if (!shouldRender || vnode === null) {
304
+ clearPortal(containerId);
305
+ return;
306
+ }
307
+ renderToPortal(containerId, vnode, zIndex);
308
+ };
241
309
  /**
242
310
  * Clears portal content and releases container reference.
243
311
  * If this is the last reference, the container will be removed from the DOM.
@@ -252,35 +320,6 @@ const clearPortal = (containerId) => {
252
320
  }
253
321
  };
254
322
 
255
- // import './styles/input.css';
256
- const Mandatory = { view: ({ attrs }) => m('span.mandatory', Object.assign({}, attrs), '*') };
257
- /** Simple label element, used for most components. */
258
- const Label = () => {
259
- return {
260
- view: (_a) => {
261
- var _b = _a.attrs, { label, id, isMandatory, isActive, className, initialValue } = _b, params = __rest(_b, ["label", "id", "isMandatory", "isActive", "className", "initialValue"]);
262
- return label
263
- ? m('label', Object.assign(Object.assign({}, params), { className: [className, isActive ? 'active' : ''].filter(Boolean).join(' ').trim() || undefined, for: id, oncreate: ({ dom }) => {
264
- if (!initialValue)
265
- return;
266
- const labelEl = dom;
267
- labelEl.classList.add('active');
268
- } }), [m.trust(label), isMandatory ? m(Mandatory) : undefined])
269
- : undefined;
270
- },
271
- };
272
- };
273
- /** Create a helper text, often used for displaying a small help text. May be replaced by the validation message. */
274
- const HelperText = () => {
275
- return {
276
- view: ({ attrs: { helperText, dataError, dataSuccess, className } }) => {
277
- return helperText || dataError || dataSuccess
278
- ? m('span.helper-text.left', { className, 'data-error': dataError, 'data-success': dataSuccess }, dataError ? m.trust(dataError) : dataSuccess ? m.trust(dataSuccess) : helperText ? m.trust(helperText) : '')
279
- : undefined;
280
- },
281
- };
282
- };
283
-
284
323
  /** Component to auto complete your text input - Pure Mithril implementation */
285
324
  const Autocomplete = () => {
286
325
  const state = {
@@ -303,6 +342,28 @@ const Autocomplete = () => {
303
342
  .slice(0, limit);
304
343
  return filtered;
305
344
  };
345
+ const highlightMatch = (text, query) => {
346
+ if (!query) {
347
+ return text;
348
+ }
349
+ const lowerText = text.toLowerCase();
350
+ const lowerQuery = query.toLowerCase();
351
+ const nodes = [];
352
+ let start = 0;
353
+ let index = lowerText.indexOf(lowerQuery, start);
354
+ while (index !== -1) {
355
+ if (index > start) {
356
+ nodes.push(text.slice(start, index));
357
+ }
358
+ nodes.push(m('span.highlight', text.slice(index, index + query.length)));
359
+ start = index + query.length;
360
+ index = lowerText.indexOf(lowerQuery, start);
361
+ }
362
+ if (start < text.length) {
363
+ nodes.push(text.slice(start));
364
+ }
365
+ return nodes.length > 0 ? nodes : text;
366
+ };
306
367
  const selectSuggestion = (suggestion, attrs) => {
307
368
  const controlled = isControlled(attrs);
308
369
  // Update internal state for uncontrolled mode
@@ -408,7 +469,6 @@ const Autocomplete = () => {
408
469
  Object.keys(data).some((key) => key.toLowerCase() === currentValue.toLowerCase());
409
470
  // Only open dropdown if there are suggestions and no perfect match
410
471
  state.isOpen = state.suggestions.length > 0 && currentValue.length >= minLength && !hasExactMatch;
411
- const replacer = new RegExp(`(${currentValue})`, 'i');
412
472
  return m('.input-field.autocomplete-wrapper', {
413
473
  className: cn,
414
474
  style,
@@ -489,9 +549,7 @@ const Autocomplete = () => {
489
549
  },
490
550
  }, suggestion.value.replace('icon:', ''))
491
551
  : null,
492
- m('span', suggestion.key
493
- ? m.trust(suggestion.key.replace(replacer, (i) => `<span class="highlight">${i}</span>`))
494
- : ''),
552
+ m('span', suggestion.key ? highlightMatch(suggestion.key, currentValue) : ''),
495
553
  ]))),
496
554
  m(Label, {
497
555
  label,
@@ -718,7 +776,7 @@ WavesEffect.onTouchEnd = (e) => {
718
776
  /**
719
777
  * A factory to create new buttons.
720
778
  *
721
- * @example FlatButton = ButtonFactory('a.waves-effect.waves-teal.btn-flat');
779
+ * @example FlatButton = ButtonFactory('button.waves-effect.waves-teal.btn-flat');
722
780
  */
723
781
  const ButtonFactory = (element, defaultClassNames, type = '') => {
724
782
  return () => {
@@ -741,15 +799,21 @@ const ButtonFactory = (element, defaultClassNames, type = '') => {
741
799
  ontouchend: WavesEffect.onTouchEnd,
742
800
  }
743
801
  : {};
744
- return m(element, Object.assign(Object.assign(Object.assign({}, params), wavesHandlers), { className: cn, 'data-position': tooltip ? position : undefined, 'data-tooltip': tooltip || undefined, type: buttonType }), iconName ? m(Icon, { iconName, className: iconClass !== undefined ? iconClass : 'left' }) : undefined, label ? label : undefined, children);
802
+ const tagName = element.split(/[.#]/)[0] || element;
803
+ const elementSuffix = element.slice(tagName.length);
804
+ const isLink = Boolean(attrs.href);
805
+ const renderedElement = `${isLink ? 'a' : 'button'}${elementSuffix}`;
806
+ return m(renderedElement, Object.assign(Object.assign(Object.assign({}, params), wavesHandlers), { className: cn, 'data-position': tooltip ? position : undefined, 'data-tooltip': tooltip || undefined,
807
+ // Links retain native navigation semantics and must not have a button type.
808
+ type: isLink ? undefined : buttonType }), iconName ? m(Icon, { iconName, className: iconClass !== undefined ? iconClass : 'left' }) : undefined, label ? label : undefined, children);
745
809
  },
746
810
  };
747
811
  };
748
812
  };
749
- const Button = ButtonFactory('a', 'waves-effect waves-light btn', 'button');
750
- const LargeButton = ButtonFactory('a', 'waves-effect waves-light btn-large', 'button');
751
- const SmallButton = ButtonFactory('a', 'waves-effect waves-light btn-small', 'button');
752
- const FlatButton = ButtonFactory('a', 'waves-effect waves-teal btn-flat', 'button');
813
+ const Button = ButtonFactory('button', 'waves-effect waves-light btn', 'button');
814
+ const LargeButton = ButtonFactory('button', 'waves-effect waves-light btn-large', 'button');
815
+ const SmallButton = ButtonFactory('button', 'waves-effect waves-light btn-small', 'button');
816
+ const FlatButton = ButtonFactory('button', 'waves-effect waves-teal btn-flat', 'button');
753
817
  const IconButton = ButtonFactory('button', 'btn-flat btn-icon waves-effect waves-teal', 'button');
754
818
  const RoundIconButton = ButtonFactory('button', 'btn-floating btn-large waves-effect waves-light', 'button');
755
819
  const SubmitButton = ButtonFactory('button', 'btn waves-effect waves-light', 'submit');
@@ -806,7 +870,7 @@ const ConfirmButton = () => {
806
870
  // Add square styling for icon-only confirming state
807
871
  const buttonStyle = !label && isConfirming
808
872
  ? 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;
809
- return m(ButtonComponent, Object.assign(Object.assign({}, props), { style: buttonStyle, className: `${props.className || ''} ${cn}`, iconName: currentIconName, iconClass: label ? (iconClass || 'left') : '', label, onclick: handleClick }));
873
+ return m(ButtonComponent, Object.assign(Object.assign({}, props), { style: buttonStyle, className: `${props.className || ''} ${cn}`, iconName: currentIconName, iconClass: label ? iconClass || 'left' : '', label, onclick: handleClick }));
810
874
  },
811
875
  };
812
876
  };
@@ -1273,11 +1337,19 @@ const MaterialIcon = () => {
1273
1337
  };
1274
1338
  const rotation = (_a = rotationMap[direction]) !== null && _a !== void 0 ? _a : 0;
1275
1339
  const transform = rotation ? `rotate(${rotation}deg)` : undefined;
1340
+ const baseStyle = {
1341
+ display: 'inline-block',
1342
+ verticalAlign: 'middle',
1343
+ transform,
1344
+ };
1345
+ const combinedStyle = typeof style === 'string'
1346
+ ? `display:inline-block;vertical-align:middle;${transform ? `transform:${transform};` : ''}${style}`
1347
+ : Object.assign(Object.assign({}, baseStyle), style);
1276
1348
  const icon = iconPaths[name];
1277
1349
  if (!icon || !Array.isArray(icon)) {
1278
1350
  return m(Icon, Object.assign(Object.assign({}, props), { iconName: name }));
1279
1351
  }
1280
- return m('svg', Object.assign(Object.assign({}, props), { style: Object.assign({ display: 'inline-block', verticalAlign: 'middle', transform }, style), 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', {
1352
+ 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', {
1281
1353
  d,
1282
1354
  fill: d.includes('M0 0h24v24H0z') ? 'none' : 'currentColor',
1283
1355
  })));
@@ -1676,6 +1748,106 @@ const Collapsible = () => {
1676
1748
  };
1677
1749
  };
1678
1750
 
1751
+ const isHandledKey = (key) => key === 'ArrowDown' || key === 'ArrowUp' || key === 'Enter' || key === ' ' || key === 'Escape';
1752
+ const getTotalRows = (optionCount, includeActionRow) => Math.max(0, optionCount) + (includeActionRow ? 1 : 0);
1753
+ const getComboboxKeyResult = ({ key, isOpen, focusedIndex, optionCount, includeActionRow, }) => {
1754
+ const totalRows = getTotalRows(optionCount, includeActionRow);
1755
+ if (!isHandledKey(key)) {
1756
+ return { isOpen, focusedIndex, action: 'none', preventDefault: false };
1757
+ }
1758
+ if (key === 'Escape') {
1759
+ return { isOpen: false, focusedIndex: -1, action: 'close', preventDefault: true };
1760
+ }
1761
+ if (key === 'ArrowDown') {
1762
+ if (!isOpen) {
1763
+ return {
1764
+ isOpen: true,
1765
+ focusedIndex: totalRows > 0 ? 0 : -1,
1766
+ action: 'open',
1767
+ preventDefault: true,
1768
+ };
1769
+ }
1770
+ return {
1771
+ isOpen: true,
1772
+ focusedIndex: totalRows > 0 ? Math.min(focusedIndex + 1, totalRows - 1) : -1,
1773
+ action: 'none',
1774
+ preventDefault: true,
1775
+ };
1776
+ }
1777
+ if (key === 'ArrowUp') {
1778
+ if (!isOpen) {
1779
+ return {
1780
+ isOpen: true,
1781
+ focusedIndex: totalRows > 0 ? 0 : -1,
1782
+ action: 'open',
1783
+ preventDefault: true,
1784
+ };
1785
+ }
1786
+ return {
1787
+ isOpen: true,
1788
+ focusedIndex: totalRows > 0 ? Math.max(focusedIndex - 1, 0) : -1,
1789
+ action: 'none',
1790
+ preventDefault: true,
1791
+ };
1792
+ }
1793
+ if (!isOpen) {
1794
+ return {
1795
+ isOpen: true,
1796
+ focusedIndex: totalRows > 0 ? 0 : -1,
1797
+ action: 'open',
1798
+ preventDefault: true,
1799
+ };
1800
+ }
1801
+ if (focusedIndex < 0) {
1802
+ return { isOpen, focusedIndex, action: 'none', preventDefault: true };
1803
+ }
1804
+ const isActionRow = includeActionRow && focusedIndex === optionCount;
1805
+ return {
1806
+ isOpen,
1807
+ focusedIndex,
1808
+ action: isActionRow ? 'selectAction' : 'selectFocused',
1809
+ preventDefault: true,
1810
+ };
1811
+ };
1812
+ const getComboboxOptionId = (baseId, optionIndex) => `${baseId}-option-${optionIndex}`;
1813
+ const createAsyncComboboxState = (initialOptions = []) => ({
1814
+ options: initialOptions,
1815
+ isLoading: false,
1816
+ error: null,
1817
+ latestRequestId: 0,
1818
+ });
1819
+ const startAsyncComboboxRequest = (state) => {
1820
+ const requestId = state.latestRequestId + 1;
1821
+ return {
1822
+ requestId,
1823
+ nextState: Object.assign(Object.assign({}, state), { isLoading: true, error: null, latestRequestId: requestId }),
1824
+ };
1825
+ };
1826
+ const resolveAsyncComboboxRequest = (state, requestId, options) => {
1827
+ if (requestId !== state.latestRequestId) {
1828
+ return state;
1829
+ }
1830
+ return Object.assign(Object.assign({}, state), { options, isLoading: false, error: null });
1831
+ };
1832
+ const rejectAsyncComboboxRequest = (state, requestId, errorMessage) => {
1833
+ if (requestId !== state.latestRequestId) {
1834
+ return state;
1835
+ }
1836
+ return Object.assign(Object.assign({}, state), { options: [], isLoading: false, error: errorMessage });
1837
+ };
1838
+ const getComboboxViewState = ({ isLoading, error, optionCount, }) => {
1839
+ if (isLoading) {
1840
+ return 'loading';
1841
+ }
1842
+ if (error) {
1843
+ return 'error';
1844
+ }
1845
+ if (optionCount === 0) {
1846
+ return 'empty';
1847
+ }
1848
+ return 'ready';
1849
+ };
1850
+
1679
1851
  var CollectionMode;
1680
1852
  (function (CollectionMode) {
1681
1853
  CollectionMode[CollectionMode["BASIC"] = 0] = "BASIC";
@@ -3285,6 +3457,10 @@ const DoubleRangeSlider = {
3285
3457
  },
3286
3458
  };
3287
3459
 
3460
+ const isReadonly = (attrs) => {
3461
+ const legacyReadonly = attrs.readonly;
3462
+ return Boolean(attrs.readOnly || legacyReadonly);
3463
+ };
3288
3464
  /** Character counter component that tracks text length against maxLength */
3289
3465
  const CharacterCounter = () => {
3290
3466
  return {
@@ -3363,7 +3539,7 @@ const TextArea = () => {
3363
3539
  return {
3364
3540
  oninit: ({ attrs }) => {
3365
3541
  const controlled = isControlled(attrs);
3366
- const isNonInteractive = attrs.readonly || attrs.disabled;
3542
+ const isNonInteractive = isReadonly(attrs) || attrs.disabled;
3367
3543
  // Warn developer for improper controlled usage
3368
3544
  if (attrs.value !== undefined && !controlled && !isNonInteractive) {
3369
3545
  console.warn(`TextArea received 'value' prop without 'oninput' or 'onchange' handler. ` +
@@ -3380,7 +3556,7 @@ const TextArea = () => {
3380
3556
  var _a, _b, _c, _d;
3381
3557
  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
3558
  const controlled = isControlled(attrs);
3383
- const isNonInteractive = attrs.readonly || attrs.disabled;
3559
+ const isNonInteractive = isReadonly(attrs) || attrs.disabled;
3384
3560
  let currentValue;
3385
3561
  if (controlled) {
3386
3562
  currentValue = value || '';
@@ -3496,14 +3672,12 @@ const TextArea = () => {
3496
3672
  onkeypress(ev, ev.target.value);
3497
3673
  }
3498
3674
  : undefined })),
3499
- m(Label, {
3675
+ ...renderFieldChrome({
3500
3676
  label,
3501
3677
  id,
3502
3678
  isMandatory,
3503
3679
  isActive: currentValue || placeholder || state.active,
3504
3680
  initialValue: currentValue !== '',
3505
- }),
3506
- m(HelperText, {
3507
3681
  helperText,
3508
3682
  dataError: state.hasInteracted && attrs.dataError ? attrs.dataError : undefined,
3509
3683
  dataSuccess: state.hasInteracted && attrs.dataSuccess ? attrs.dataSuccess : undefined,
@@ -3583,7 +3757,7 @@ const InputField = (type, defaultClass = '') => () => {
3583
3757
  return {
3584
3758
  oninit: ({ attrs }) => {
3585
3759
  const controlled = isControlled(attrs);
3586
- const isNonInteractive = attrs.readonly || attrs.disabled;
3760
+ const isNonInteractive = isReadonly(attrs) || attrs.disabled;
3587
3761
  // Warn developer for improper controlled usage
3588
3762
  if (attrs.value !== undefined && !controlled && !isNonInteractive) {
3589
3763
  console.warn(`${type} input with label '${attrs.label}' received 'value' prop without 'oninput' handler. ` +
@@ -3623,7 +3797,7 @@ const InputField = (type, defaultClass = '') => () => {
3623
3797
  }
3624
3798
  const isNumeric = ['number', 'range'].includes(type);
3625
3799
  const controlled = isControlled(attrs);
3626
- const isNonInteractive = attrs.readonly || attrs.disabled;
3800
+ const isNonInteractive = isReadonly(attrs) || attrs.disabled;
3627
3801
  let value;
3628
3802
  if (controlled) {
3629
3803
  value = attrs.value;
@@ -3642,9 +3816,28 @@ const InputField = (type, defaultClass = '') => () => {
3642
3816
  const rangeType = type === 'range' && !attrs.minmax;
3643
3817
  // Only add validate class if input is interactive and validation is needed
3644
3818
  const shouldValidate = !isNonInteractive && (validate || type === 'email' || type === 'url' || isNumeric);
3819
+ const inputClass = [
3820
+ type === 'number' ? 'number-input' : '',
3821
+ type === 'range' && attrs.vertical ? 'range-slider vertical' : '',
3822
+ shouldValidate ? 'validate' : '',
3823
+ ]
3824
+ .filter(Boolean)
3825
+ .join(' ');
3826
+ const stepNumberInput = (direction) => {
3827
+ const input = state.inputElement;
3828
+ if (!input)
3829
+ return;
3830
+ if (direction === 'up') {
3831
+ input.stepUp();
3832
+ }
3833
+ else {
3834
+ input.stepDown();
3835
+ }
3836
+ input.dispatchEvent(new Event('input', { bubbles: true }));
3837
+ };
3645
3838
  return m('.input-field', { className: cn, style }, [
3646
3839
  iconName ? m('i.material-icons.prefix', iconName) : undefined,
3647
- m('input', Object.assign(Object.assign({ class: type === 'range' && attrs.vertical ? 'range-slider vertical' : shouldValidate ? 'validate' : undefined }, params), { type, tabindex: 0, id,
3840
+ m('input', Object.assign(Object.assign({ class: inputClass || undefined }, params), { type, tabindex: 0, id,
3648
3841
  placeholder, value: controlled ? value : undefined, style: type === 'range' && attrs.vertical
3649
3842
  ? {
3650
3843
  height: attrs.height || '200px',
@@ -3726,7 +3919,7 @@ const InputField = (type, defaultClass = '') => () => {
3726
3919
  const target = e.target;
3727
3920
  state.hasInteracted = true;
3728
3921
  // Skip validation for readonly/disabled inputs
3729
- if (attrs.readonly || attrs.disabled) {
3922
+ if (isReadonly(attrs) || attrs.disabled) {
3730
3923
  // Call original onblur if provided
3731
3924
  if (attrs.onblur) {
3732
3925
  attrs.onblur(e);
@@ -3816,6 +4009,22 @@ const InputField = (type, defaultClass = '') => () => {
3816
4009
  onchange(getValue(state.inputElement));
3817
4010
  }
3818
4011
  } })),
4012
+ type === 'number' && !isNonInteractive
4013
+ ? m('.number-input-controls', [
4014
+ m('button.number-input-control.number-input-control-up[type=button]', {
4015
+ 'aria-label': `Increase ${label || 'value'}`,
4016
+ title: 'Increase value',
4017
+ onmousedown: (event) => event.preventDefault(),
4018
+ onclick: () => stepNumberInput('up'),
4019
+ }, m(MaterialIcon, { name: 'chevron', direction: 'up' })),
4020
+ m('button.number-input-control.number-input-control-down[type=button]', {
4021
+ 'aria-label': `Decrease ${label || 'value'}`,
4022
+ title: 'Decrease value',
4023
+ onmousedown: (event) => event.preventDefault(),
4024
+ onclick: () => stepNumberInput('down'),
4025
+ }, m(MaterialIcon, { name: 'chevron' })),
4026
+ ])
4027
+ : undefined,
3819
4028
  // Clear button - only for text inputs with canClear enabled and has content
3820
4029
  canClear && type === 'text' && ((_f = state.inputElement) === null || _f === void 0 ? void 0 : _f.value)
3821
4030
  ? m(MaterialIcon, {
@@ -3828,14 +4037,12 @@ const InputField = (type, defaultClass = '') => () => {
3828
4037
  },
3829
4038
  })
3830
4039
  : undefined,
3831
- m(Label, {
4040
+ ...renderFieldChrome({
3832
4041
  label,
3833
4042
  id,
3834
4043
  isMandatory,
3835
4044
  isActive,
3836
4045
  initialValue: value !== undefined && value !== '',
3837
- }),
3838
- m(HelperText, {
3839
4046
  helperText,
3840
4047
  dataError: state.hasInteracted && !state.isValid ? dataError : undefined,
3841
4048
  dataSuccess: state.hasInteracted && state.isValid ? dataSuccess : undefined,
@@ -3935,7 +4142,7 @@ const InputCheckbox = () => {
3935
4142
  view: ({ attrs: { className = 'col s12', onchange, label, checked, disabled, description, style, inputId } }) => {
3936
4143
  if (!checkboxId)
3937
4144
  checkboxId = inputId || uniqueId();
3938
- return m('div', { className, style }, m('label', { for: checkboxId }, [
4145
+ return m('div', { className, style }, m('label', { for: checkboxId, style: { position: 'relative', display: 'inline-block' } }, [
3939
4146
  m('input[type=checkbox][tabindex=0]', {
3940
4147
  className: disabled ? 'disabled' : undefined,
3941
4148
  id: checkboxId,
@@ -4700,17 +4907,6 @@ const Dropdown = () => {
4700
4907
  const updatePortalDropdown = (items, selectedLabel, onSelectItem, maxHeight) => {
4701
4908
  if (!state.isInsideModal)
4702
4909
  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
4910
  // Create dropdown content
4715
4911
  const availableItems = items.filter((item) => !item.divider && !item.disabled);
4716
4912
  const dropdownContent = items.map((item) => {
@@ -4724,15 +4920,14 @@ const Dropdown = () => {
4724
4920
  class: `${isSelected ? 'selected' : ''} ${isFocused ? 'focused' : ''}${item.disabled ? ' disabled' : ''}`,
4725
4921
  onclick: item.disabled ? undefined : () => onSelectItem(item),
4726
4922
  }, m('span', {
4923
+ class: 'mm-layout-row mm-layout-row--center',
4727
4924
  style: {
4728
- display: 'flex',
4729
- alignItems: 'center',
4730
4925
  padding: '14px 16px',
4731
4926
  },
4732
4927
  }, [
4733
4928
  item.iconName
4734
4929
  ? m('i.material-icons', {
4735
- style: { marginRight: '32px' },
4930
+ class: 'mm-layout-item-icon',
4736
4931
  }, item.iconName)
4737
4932
  : undefined,
4738
4933
  item.label,
@@ -4749,8 +4944,12 @@ const Dropdown = () => {
4749
4944
  state.dropdownRef = null;
4750
4945
  },
4751
4946
  }, dropdownContent);
4752
- // Render to portal
4753
- m.render(portalElement, dropdownVnode);
4947
+ syncPortalContent({
4948
+ containerId: `${state.id}-dropdown`,
4949
+ shouldRender: state.isOpen && !!state.inputRef,
4950
+ vnode: dropdownVnode,
4951
+ zIndex: 10000,
4952
+ });
4754
4953
  };
4755
4954
  return {
4756
4955
  oninit: ({ attrs }) => {
@@ -4771,15 +4970,19 @@ const Dropdown = () => {
4771
4970
  // Cleanup global listener
4772
4971
  document.removeEventListener('click', closeDropdown);
4773
4972
  // Cleanup portal
4774
- const portalElement = document.getElementById(`${state.id}-dropdown`);
4775
- if (portalElement) {
4776
- portalElement.remove();
4777
- }
4973
+ syncPortalContent({ containerId: `${state.id}-dropdown`, shouldRender: false, vnode: null });
4778
4974
  },
4779
4975
  view: ({ attrs }) => {
4780
4976
  const { checkedId, key, label, onchange, disabled = false, items, iconName, helperText, style, className = 'col s12', } = attrs;
4781
4977
  const controlled = isControlled(attrs);
4782
- const currentCheckedId = controlled ? checkedId : state.internalCheckedId;
4978
+ const currentCheckedId = resolveControllableValue({
4979
+ controlled,
4980
+ disabled,
4981
+ controlledValue: checkedId,
4982
+ defaultValue: attrs.defaultCheckedId,
4983
+ internalValue: state.internalCheckedId,
4984
+ fallbackValue: undefined,
4985
+ });
4783
4986
  const handleSelection = (value) => {
4784
4987
  // Update internal state for uncontrolled mode
4785
4988
  if (!controlled) {
@@ -4811,6 +5014,7 @@ const Dropdown = () => {
4811
5014
  iconName ? m('i.material-icons.prefix', iconName) : undefined,
4812
5015
  m(HelperText, { helperText }),
4813
5016
  m('.select-wrapper', {
5017
+ class: 'mm-layout-row mm-layout-row--center',
4814
5018
  onkeydown: disabled
4815
5019
  ? undefined
4816
5020
  : (e) => {
@@ -4878,15 +5082,14 @@ const Dropdown = () => {
4878
5082
  handleSelection(value);
4879
5083
  },
4880
5084
  }, m('span', {
5085
+ class: 'mm-layout-row mm-layout-row--center',
4881
5086
  style: {
4882
- display: 'flex',
4883
- alignItems: 'center',
4884
5087
  padding: '14px 16px',
4885
5088
  },
4886
5089
  }, [
4887
5090
  item.iconName
4888
5091
  ? m('i.material-icons', {
4889
- style: { marginRight: '32px' },
5092
+ class: 'mm-layout-item-icon',
4890
5093
  }, item.iconName)
4891
5094
  : undefined,
4892
5095
  item.label,
@@ -6843,9 +7046,9 @@ const initPushpins = (selector = '.pushpin', options = {}) => {
6843
7046
  };
6844
7047
 
6845
7048
  const RadioButton = () => ({
6846
- view: ({ attrs: { id, groupId, label, onchange, className = 'col s12', checked, disabled, inputId } }) => {
7049
+ view: ({ attrs: { id, groupId, label, onchange, className = 'col s12', checked, disabled, inputId, allowHtml } }) => {
6847
7050
  const radioId = inputId || `${groupId}-${id}`;
6848
- return m('p', { className }, m('label', { for: radioId }, [
7051
+ return m('p', { className }, m('label', { for: radioId, style: { position: 'relative', display: 'inline-block' } }, [
6849
7052
  m('input[type=radio][tabindex=0]', {
6850
7053
  id: radioId,
6851
7054
  name: groupId,
@@ -6853,7 +7056,7 @@ const RadioButton = () => ({
6853
7056
  checked,
6854
7057
  onclick: onchange ? () => onchange(id) : undefined,
6855
7058
  }),
6856
- m('span', m.trust(label)),
7059
+ m('span', allowHtml ? m.trust(label) : label),
6857
7060
  ]));
6858
7061
  },
6859
7062
  });
@@ -6880,8 +7083,9 @@ const RadioButtons = () => {
6880
7083
  }
6881
7084
  },
6882
7085
  view: ({ attrs }) => {
6883
- var _a, _b;
6884
- const { checkedId, newRow, className = 'col s12', label = '', disabled, description, options, isMandatory, checkboxClass, layout = 'vertical', onchange, } = attrs;
7086
+ var _a, _b, _c;
7087
+ const { checkedId, newRow, className = 'col s12', label = '', disabled, description, options, isMandatory, checkboxClass, layout, direction, allowHtml = false, onchange, } = attrs;
7088
+ const resolvedLayout = (_a = layout !== null && layout !== void 0 ? layout : direction) !== null && _a !== void 0 ? _a : 'vertical';
6885
7089
  const { groupId, componentId } = state;
6886
7090
  const controlled = isControlled(attrs);
6887
7091
  // Get current checked ID from props or internal state
@@ -6891,11 +7095,11 @@ const RadioButtons = () => {
6891
7095
  }
6892
7096
  else if (disabled) {
6893
7097
  // Non-interactive components: prefer defaultCheckedId, fallback to checkedId
6894
- currentCheckedId = (_a = attrs.defaultCheckedId) !== null && _a !== void 0 ? _a : checkedId;
7098
+ currentCheckedId = (_b = attrs.defaultCheckedId) !== null && _b !== void 0 ? _b : checkedId;
6895
7099
  }
6896
7100
  else {
6897
7101
  // Interactive uncontrolled: use internal state
6898
- currentCheckedId = (_b = state.internalCheckedId) !== null && _b !== void 0 ? _b : attrs.defaultCheckedId;
7102
+ currentCheckedId = (_c = state.internalCheckedId) !== null && _c !== void 0 ? _c : attrs.defaultCheckedId;
6899
7103
  }
6900
7104
  const handleChange = (id) => {
6901
7105
  // Update internal state for uncontrolled mode
@@ -6910,16 +7114,16 @@ const RadioButtons = () => {
6910
7114
  const cn = [newRow ? 'clear' : '', className].filter(Boolean).join(' ').trim() || undefined;
6911
7115
  const radioItems = options.map((r) => ({
6912
7116
  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}` }),
7117
+ 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
7118
  key: r.id,
6915
7119
  }));
6916
7120
  const optionsContent = m(OptionsList, {
6917
7121
  options: radioItems,
6918
- layout,
7122
+ layout: resolvedLayout,
6919
7123
  });
6920
7124
  return m('div', { id: componentId, className: cn }, [
6921
7125
  label && m('h5.form-group-label', label + (isMandatory ? ' *' : '')),
6922
- description && m('p.helper-text', m.trust(description)),
7126
+ description && m('p.helper-text', allowHtml ? m.trust(description) : description),
6923
7127
  m('form', { action: '#' }, optionsContent),
6924
7128
  ]);
6925
7129
  },
@@ -7056,6 +7260,26 @@ const Select = () => {
7056
7260
  opacity: 1,
7057
7261
  };
7058
7262
  };
7263
+ const formatSelectionSummary = (attrs, selectedOptions, selectedIds, placeholder) => {
7264
+ const mode = attrs.summaryMode || 'labels';
7265
+ const selectedCount = selectedIds.length;
7266
+ const totalCount = attrs.options.filter((option) => !option.disabled).length;
7267
+ if (mode === 'labels') {
7268
+ return selectedOptions.length > 0 ? selectedOptions.map((o) => o.label || o.id).join(', ') : placeholder;
7269
+ }
7270
+ const defaultCountLabel = `${selectedCount}/${totalCount} selected`;
7271
+ const formattedCount = attrs.countLabel ? attrs.countLabel(selectedCount, totalCount) : defaultCountLabel;
7272
+ if (mode === 'count') {
7273
+ return selectedCount > 0 ? formattedCount : placeholder;
7274
+ }
7275
+ if (selectedCount === 0) {
7276
+ return attrs.noneSelectedLabel || placeholder;
7277
+ }
7278
+ if (totalCount > 0 && selectedCount >= totalCount) {
7279
+ return attrs.allSelectedLabel || 'All selected';
7280
+ }
7281
+ return formattedCount;
7282
+ };
7059
7283
  const renderDropdownContent = (attrs, selectedIds, multiple, placeholder) => [
7060
7284
  placeholder && m('li.disabled', { tabindex: 0 }, m('span', placeholder)),
7061
7285
  // Render ungrouped options first
@@ -7124,17 +7348,6 @@ const Select = () => {
7124
7348
  const updatePortalDropdown = (attrs, selectedIds, multiple, placeholder) => {
7125
7349
  if (!state.isInsideModal)
7126
7350
  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
7351
  // Create dropdown with proper positioning
7139
7352
  const dropdownVnode = m('ul.dropdown-content.select-dropdown', {
7140
7353
  tabindex: 0,
@@ -7146,8 +7359,12 @@ const Select = () => {
7146
7359
  state.dropdownRef = null;
7147
7360
  },
7148
7361
  }, renderDropdownContent(attrs, selectedIds, multiple, placeholder));
7149
- // Render to portal
7150
- m.render(portalElement, dropdownVnode);
7362
+ syncPortalContent({
7363
+ containerId: state.dropdownId,
7364
+ shouldRender: state.isOpen && !!state.inputRef,
7365
+ vnode: dropdownVnode,
7366
+ zIndex: 10000,
7367
+ });
7151
7368
  };
7152
7369
  return {
7153
7370
  oninit: ({ attrs }) => {
@@ -7180,35 +7397,29 @@ const Select = () => {
7180
7397
  document.removeEventListener('click', closeDropdown);
7181
7398
  // Cleanup portaled dropdown if it exists
7182
7399
  if (state.isInsideModal && state.dropdownRef) {
7183
- const portalElement = document.getElementById(state.dropdownId);
7184
- if (portalElement && portalElement.parentNode) {
7185
- portalElement.parentNode.removeChild(portalElement);
7186
- }
7400
+ syncPortalContent({ containerId: state.dropdownId, shouldRender: false, vnode: null });
7187
7401
  }
7188
7402
  },
7189
7403
  view: ({ attrs }) => {
7190
- var _a;
7191
7404
  const controlled = isControlled(attrs);
7192
- const { newRow, className = 'col s12', key, options = [], multiple = false, label, helperText, placeholder = '', isMandatory, iconName, style, disabled, } = attrs;
7405
+ const { newRow, className = 'col s12', key, options = [], multiple = false, label, helperText, placeholder = '', isMandatory, iconName, appearance = 'standard', style, disabled, } = attrs;
7193
7406
  state.isMultiple = multiple;
7194
7407
  // Get selected IDs from props or internal state
7195
- let selectedIds;
7196
- if (controlled) {
7197
- selectedIds =
7198
- attrs.checkedId !== undefined ? (Array.isArray(attrs.checkedId) ? attrs.checkedId : [attrs.checkedId]) : [];
7199
- }
7200
- else if (disabled) {
7201
- // Non-interactive components: prefer defaultCheckedId, fallback to checkedId
7202
- const fallbackId = (_a = attrs.defaultCheckedId) !== null && _a !== void 0 ? _a : attrs.checkedId;
7203
- selectedIds = fallbackId !== undefined ? (Array.isArray(fallbackId) ? fallbackId : [fallbackId]) : [];
7204
- }
7205
- else {
7206
- // Interactive uncontrolled: use internal state
7207
- selectedIds = state.internalSelectedIds;
7208
- }
7209
- const finalClassName = newRow ? `${className} clear` : className;
7408
+ const selectedIds = resolveControllableValue({
7409
+ controlled,
7410
+ disabled,
7411
+ controlledValue: normalizeSelection(attrs.checkedId),
7412
+ defaultValue: normalizeSelection(attrs.defaultCheckedId),
7413
+ internalValue: state.internalSelectedIds,
7414
+ fallbackValue: [],
7415
+ });
7416
+ const layoutClassName = newRow ? `${className} clear` : className;
7417
+ const appearanceClassName = appearance === 'outlined' ? 'select-appearance-outlined' : '';
7418
+ const finalClassName = [layoutClassName, appearanceClassName].filter(Boolean).join(' ');
7419
+ const shouldInlineLabel = appearance === 'outlined' && !!label;
7210
7420
  const selectedOptionsUnsorted = options.filter((opt) => isSelected(opt.id, selectedIds));
7211
7421
  const selectedOptions = sortOptions(selectedOptionsUnsorted, attrs.sortSelected);
7422
+ const triggerValue = formatSelectionSummary(attrs, selectedOptions, selectedIds, placeholder);
7212
7423
  // Update portal dropdown when inside modal
7213
7424
  if (state.isInsideModal) {
7214
7425
  updatePortalDropdown(attrs, selectedIds, multiple, placeholder);
@@ -7228,9 +7439,15 @@ const Select = () => {
7228
7439
  'aria-controls': state.dropdownId,
7229
7440
  role: 'combobox',
7230
7441
  }, [
7442
+ shouldInlineLabel &&
7443
+ m('span.select-inline-label', [
7444
+ label,
7445
+ isMandatory && m('span.mandatory', { style: { marginLeft: '2px' } }, '*'),
7446
+ ]),
7231
7447
  m('input[type=text][readonly=true].select-dropdown.dropdown-trigger', {
7232
7448
  id: state.id,
7233
- value: selectedOptions.length > 0 ? selectedOptions.map((o) => o.label || o.id).join(', ') : placeholder,
7449
+ value: triggerValue,
7450
+ 'aria-label': label,
7234
7451
  oncreate: ({ dom }) => {
7235
7452
  state.inputRef = dom;
7236
7453
  },
@@ -7262,14 +7479,12 @@ const Select = () => {
7262
7479
  }),
7263
7480
  ]),
7264
7481
  // Label
7265
- label &&
7266
- m(Label, {
7267
- id: state.id,
7268
- label,
7269
- isMandatory,
7270
- }),
7271
- // Helper text
7272
- helperText && m(HelperText, { helperText }),
7482
+ ...renderFieldChrome({
7483
+ label: shouldInlineLabel ? undefined : label,
7484
+ id: state.id,
7485
+ isMandatory,
7486
+ helperText,
7487
+ }),
7273
7488
  ]);
7274
7489
  },
7275
7490
  };
@@ -7488,59 +7703,65 @@ const Tabs = () => {
7488
7703
  };
7489
7704
  };
7490
7705
 
7491
- // Proper components to avoid anonymous closures
7492
- const SelectedChip = () => {
7493
- return {
7494
- view: ({ attrs: { option, onRemove } }) => m('.chip', [
7495
- option.label || option.id.toString(),
7496
- m(MaterialIcon, {
7497
- name: 'close',
7498
- className: 'close',
7499
- onclick: (e) => {
7500
- e.stopPropagation();
7501
- onRemove(option.id);
7502
- },
7503
- }),
7504
- ]),
7505
- };
7506
- };
7507
- const DropdownOption = () => {
7508
- return {
7509
- view: ({ attrs: { option, index, selectedIds, isFocused, onToggle, onMouseOver, showCheckbox } }) => {
7510
- const checkboxId = `search-select-option-${option.id}`;
7511
- const optionLabel = option.label || option.id.toString();
7512
- return m('li', {
7513
- key: option.id,
7514
- onclick: (e) => {
7515
- e.preventDefault();
7706
+ const SelectedChip = ({ option, onRemove, }) => m('.chip', [
7707
+ option.label || option.id.toString(),
7708
+ m(MaterialIcon, {
7709
+ name: 'close',
7710
+ className: 'close',
7711
+ onclick: (e) => {
7712
+ e.stopPropagation();
7713
+ onRemove(option.id);
7714
+ },
7715
+ }),
7716
+ ]);
7717
+ const DropdownOption = ({ option, index, optionId, selectedIds, isFocused, onToggle, onMouseOver, showCheckbox, }) => {
7718
+ const optionLabel = option.label || option.id.toString();
7719
+ return m('li', {
7720
+ id: optionId,
7721
+ role: 'option',
7722
+ 'aria-selected': selectedIds.includes(option.id) ? 'true' : 'false',
7723
+ class: `${option.disabled ? 'disabled' : ''} ${isFocused ? 'active' : ''}`.trim(),
7724
+ onmouseover: () => {
7725
+ if (!option.disabled) {
7726
+ onMouseOver(index);
7727
+ }
7728
+ },
7729
+ }, m('label', {
7730
+ class: 'search-select-option-label',
7731
+ onclick: (e) => {
7732
+ // A single-select row has no native checkbox to emit change.
7733
+ if (!showCheckbox) {
7734
+ e.preventDefault();
7735
+ onToggle(option);
7736
+ }
7737
+ },
7738
+ }, [
7739
+ showCheckbox &&
7740
+ m('input', {
7741
+ type: 'checkbox',
7742
+ checked: selectedIds.includes(option.id),
7743
+ disabled: option.disabled,
7744
+ onchange: (e) => {
7516
7745
  e.stopPropagation();
7517
7746
  onToggle(option);
7518
7747
  },
7519
- class: `${option.disabled ? 'disabled' : ''} ${isFocused ? 'active' : ''}`.trim(),
7520
- onmouseover: () => {
7521
- if (!option.disabled) {
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
- };
7748
+ }),
7749
+ m('span', optionLabel),
7750
+ ]));
7536
7751
  };
7537
7752
  /**
7538
7753
  * Mithril Factory Component for Multi-Select Dropdown with search
7539
7754
  */
7540
- const SearchSelect = () => {
7755
+ const SearchSelect = (maybeVnode) => {
7756
+ var _a;
7757
+ const cachedInstance = (_a = maybeVnode === null || maybeVnode === void 0 ? void 0 : maybeVnode.state) === null || _a === void 0 ? void 0 : _a.__searchSelectInstance;
7758
+ if (cachedInstance) {
7759
+ return cachedInstance;
7760
+ }
7541
7761
  // State initialization
7542
7762
  const state = {
7543
7763
  id: '',
7764
+ listboxId: '',
7544
7765
  isOpen: false,
7545
7766
  searchTerm: '',
7546
7767
  inputRef: null,
@@ -7548,17 +7769,38 @@ const SearchSelect = () => {
7548
7769
  focusedIndex: -1,
7549
7770
  internalSelectedIds: [],
7550
7771
  createdOptions: [],
7551
- };
7772
+ asyncOptions: [],
7773
+ isLoading: false,
7774
+ loadError: null,
7775
+ latestRequestId: 0,
7776
+ };
7777
+ const updateAsyncState = (nextState) => {
7778
+ state.asyncOptions = nextState.options;
7779
+ state.isLoading = nextState.isLoading;
7780
+ state.loadError = nextState.error;
7781
+ state.latestRequestId = nextState.latestRequestId;
7782
+ };
7783
+ const readAsyncState = () => ({
7784
+ options: state.asyncOptions,
7785
+ isLoading: state.isLoading,
7786
+ error: state.loadError,
7787
+ latestRequestId: state.latestRequestId,
7788
+ });
7552
7789
  const isControlled = (attrs) => attrs.checkedId !== undefined && typeof attrs.onchange === 'function';
7553
7790
  const componentId = uniqueId();
7554
7791
  const searchInputId = `${componentId}-search`;
7555
7792
  // Handle click outside
7556
7793
  const handleClickOutside = (e) => {
7557
7794
  const target = e.target;
7795
+ const targetElement = e.target instanceof Element ? e.target : null;
7558
7796
  if (state.dropdownRef && state.dropdownRef.contains(target)) {
7559
7797
  // Click inside dropdown, do nothing
7560
7798
  return;
7561
7799
  }
7800
+ if (targetElement && targetElement.closest('.chips-container')) {
7801
+ // Click on trigger, do nothing
7802
+ return;
7803
+ }
7562
7804
  if (state.inputRef && state.inputRef.contains(target)) {
7563
7805
  // Click on trigger handled by onclick event
7564
7806
  return;
@@ -7569,40 +7811,51 @@ const SearchSelect = () => {
7569
7811
  }
7570
7812
  m.redraw();
7571
7813
  };
7572
- // Handle keyboard navigation
7573
- const handleKeyDown = (e, filteredOptions, showAddNew) => {
7574
- if (!state.isOpen)
7814
+ // Handle keyboard navigation through shared combobox primitive.
7815
+ const handleKeyDown = (e, optionCount, includeActionRow) => {
7816
+ const result = getComboboxKeyResult({
7817
+ key: e.key,
7818
+ isOpen: state.isOpen,
7819
+ focusedIndex: state.focusedIndex,
7820
+ optionCount,
7821
+ includeActionRow,
7822
+ });
7823
+ if (result.preventDefault) {
7824
+ e.preventDefault();
7825
+ }
7826
+ state.isOpen = result.isOpen;
7827
+ state.focusedIndex = result.focusedIndex;
7828
+ return result.action;
7829
+ };
7830
+ const loadAsyncOptions = async (attrs, query) => {
7831
+ if (!attrs.loadOptions) {
7575
7832
  return;
7576
- const totalOptions = filteredOptions.length + (showAddNew ? 1 : 0);
7577
- switch (e.key) {
7578
- case 'ArrowDown':
7579
- e.preventDefault();
7580
- state.focusedIndex = Math.min(state.focusedIndex + 1, totalOptions - 1);
7581
- break;
7582
- case 'ArrowUp':
7583
- e.preventDefault();
7584
- state.focusedIndex = Math.max(state.focusedIndex - 1, -1);
7585
- break;
7586
- case 'Enter':
7587
- e.preventDefault();
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;
7833
+ }
7834
+ const started = startAsyncComboboxRequest(readAsyncState());
7835
+ updateAsyncState(started.nextState);
7836
+ m.redraw();
7837
+ try {
7838
+ const loadedOptions = await attrs.loadOptions(query);
7839
+ const resolved = resolveAsyncComboboxRequest(readAsyncState(), started.requestId, loadedOptions);
7840
+ updateAsyncState(resolved);
7841
+ if (started.requestId !== state.latestRequestId) {
7842
+ return;
7843
+ }
7844
+ if (state.focusedIndex >= loadedOptions.length) {
7602
7845
  state.focusedIndex = -1;
7603
- break;
7846
+ }
7847
+ }
7848
+ catch (error) {
7849
+ const rejected = rejectAsyncComboboxRequest(readAsyncState(), started.requestId, error instanceof Error ? error.message : 'Unable to load options');
7850
+ updateAsyncState(rejected);
7851
+ if (started.requestId !== state.latestRequestId) {
7852
+ return;
7853
+ }
7854
+ state.focusedIndex = -1;
7855
+ }
7856
+ finally {
7857
+ m.redraw();
7604
7858
  }
7605
- return null;
7606
7859
  };
7607
7860
  // Create new option and add to state
7608
7861
  const createAndSelectOption = async (attrs) => {
@@ -7683,9 +7936,10 @@ const SearchSelect = () => {
7683
7936
  attrs.onchange(newIds);
7684
7937
  }
7685
7938
  };
7686
- return {
7939
+ const componentInstance = {
7687
7940
  oninit: ({ attrs }) => {
7688
7941
  state.id = attrs.id || uniqueId();
7942
+ state.listboxId = `${state.id}-listbox`;
7689
7943
  // Initialize internal state for uncontrolled mode
7690
7944
  if (!isControlled(attrs)) {
7691
7945
  const defaultIds = attrs.defaultCheckedId !== undefined
@@ -7712,20 +7966,26 @@ const SearchSelect = () => {
7712
7966
  : [attrs.checkedId]
7713
7967
  : []
7714
7968
  : state.internalSelectedIds;
7715
- const { options = [], oncreateNewOption, className, placeholder, searchPlaceholder = 'Search options...', noOptionsFound = 'No options found', label, i18n = {}, maxDisplayedOptions, maxSelectedOptions, maxHeight, } = attrs;
7969
+ const { options = [], loadOptions, oncreateNewOption, className, placeholder, searchPlaceholder = 'Search options...', noOptionsFound = 'No options found', label, i18n = {}, maxDisplayedOptions, maxSelectedOptions, maxHeight, } = attrs;
7716
7970
  // Use i18n values if provided, otherwise use defaults
7717
7971
  const texts = {
7718
7972
  noOptionsFound: i18n.noOptionsFound || noOptionsFound,
7973
+ loadingOptions: i18n.loadingOptions || 'Loading options...',
7974
+ loadingError: i18n.loadingError || 'Unable to load options',
7719
7975
  addNewPrefix: i18n.addNewPrefix || '+',
7720
7976
  showingXofY: i18n.showingXofY || 'Showing {shown} of {total} options',
7721
7977
  maxSelectionsReached: i18n.maxSelectionsReached || 'Maximum {max} selections reached',
7722
7978
  };
7723
7979
  // Check if max selections is reached
7724
7980
  const isMaxSelectionsReached = maxSelectedOptions && selectedIds.length >= maxSelectedOptions;
7725
- // Merge provided options with internally created options
7726
- const allOptions = [...options, ...state.createdOptions];
7981
+ // In async mode, the active list is sourced remotely.
7982
+ const sourceOptions = loadOptions ? state.asyncOptions : options;
7983
+ // Merge active options with internally created options
7984
+ const allOptions = [...sourceOptions, ...state.createdOptions];
7985
+ // Keep selected label lookups stable across static, async, and created sets.
7986
+ const lookupOptions = [...options, ...state.asyncOptions, ...state.createdOptions];
7727
7987
  // Get selected options for display
7728
- const selectedOptionsUnsorted = allOptions.filter((opt) => selectedIds.includes(opt.id));
7988
+ const selectedOptionsUnsorted = lookupOptions.filter((opt) => selectedIds.includes(opt.id));
7729
7989
  const selectedOptions = sortOptions(selectedOptionsUnsorted, attrs.sortSelected);
7730
7990
  // Safely filter options
7731
7991
  const filteredOptions = allOptions.filter((option) => (option.label || option.id.toString()).toLowerCase().includes((state.searchTerm || '').toLowerCase()) &&
@@ -7738,6 +7998,14 @@ const SearchSelect = () => {
7738
7998
  const showAddNew = oncreateNewOption &&
7739
7999
  state.searchTerm &&
7740
8000
  !displayedOptions.some((o) => (o.label || o.id.toString()).toLowerCase() === state.searchTerm.toLowerCase());
8001
+ const activeDescendantId = state.isOpen && state.focusedIndex >= 0 && state.focusedIndex < displayedOptions.length
8002
+ ? getComboboxOptionId(state.id, state.focusedIndex)
8003
+ : undefined;
8004
+ const viewState = getComboboxViewState({
8005
+ isLoading: state.isLoading,
8006
+ error: state.loadError,
8007
+ optionCount: displayedOptions.length,
8008
+ });
7741
8009
  // Render the dropdown
7742
8010
  return m('.input-field.multi-select-dropdown', { className }, [
7743
8011
  m('.chips.chips-initial.chips-container', {
@@ -7748,14 +8016,34 @@ const SearchSelect = () => {
7748
8016
  // console.log('SearchSelect clicked', state.isOpen, e); // Debug log
7749
8017
  e.preventDefault();
7750
8018
  e.stopPropagation();
8019
+ const wasOpen = state.isOpen;
7751
8020
  state.isOpen = !state.isOpen;
8021
+ if (!wasOpen && state.isOpen && loadOptions) {
8022
+ void loadAsyncOptions(attrs, state.searchTerm);
8023
+ }
7752
8024
  // console.log('SearchSelect state changed to', state.isOpen); // Debug log
7753
8025
  },
7754
- class: 'chips chips-container',
8026
+ onkeydown: async (e) => {
8027
+ const action = handleKeyDown(e, displayedOptions.length, !!showAddNew);
8028
+ if (action === 'open' && loadOptions) {
8029
+ await loadAsyncOptions(attrs, state.searchTerm);
8030
+ return;
8031
+ }
8032
+ if (action === 'selectAction' && oncreateNewOption) {
8033
+ await createAndSelectOption(attrs);
8034
+ }
8035
+ if (action === 'selectFocused' && state.focusedIndex < displayedOptions.length) {
8036
+ toggleOption(displayedOptions[state.focusedIndex], attrs);
8037
+ }
8038
+ },
8039
+ class: 'chips chips-container mm-layout-row mm-layout-row--wrap mm-layout-row--align-end',
8040
+ role: 'combobox',
8041
+ tabindex: 0,
8042
+ 'aria-expanded': state.isOpen ? 'true' : 'false',
8043
+ 'aria-haspopup': 'listbox',
8044
+ 'aria-controls': state.isOpen ? state.listboxId : undefined,
8045
+ 'aria-activedescendant': activeDescendantId,
7755
8046
  style: {
7756
- display: 'flex',
7757
- alignItems: 'end',
7758
- flexWrap: 'wrap',
7759
8047
  cursor: 'pointer',
7760
8048
  position: 'relative',
7761
8049
  },
@@ -7768,30 +8056,41 @@ const SearchSelect = () => {
7768
8056
  value: selectedOptions.map((o) => o.label || o.id.toString()).join(', '),
7769
8057
  readonly: true,
7770
8058
  class: 'sr-only',
7771
- style: { position: 'absolute', left: '-9999px', opacity: 0 },
8059
+ style: {
8060
+ position: 'absolute',
8061
+ width: '1px',
8062
+ height: '1px',
8063
+ margin: '-1px',
8064
+ padding: 0,
8065
+ border: 0,
8066
+ overflow: 'hidden',
8067
+ clip: 'rect(0 0 0 0)',
8068
+ clipPath: 'inset(50%)',
8069
+ whiteSpace: 'nowrap',
8070
+ },
7772
8071
  }),
7773
8072
  // Selected Options (chips)
7774
- ...selectedOptions.map((option) => m(SelectedChip(), {
7775
- option,
8073
+ ...selectedOptions.map((option) => SelectedChip({
8074
+ option: option,
7776
8075
  onRemove: (id) => removeOption(id, attrs),
7777
8076
  })),
7778
8077
  // Placeholder when no options selected
7779
8078
  selectedOptions.length === 0 &&
7780
8079
  placeholder &&
7781
8080
  m('span.placeholder', {
8081
+ class: 'mm-layout-grow',
7782
8082
  style: {
7783
8083
  color: 'var(--mm-text-hint, #9e9e9e)',
7784
- flexGrow: 1,
7785
8084
  padding: '8px 0',
7786
8085
  },
7787
8086
  }, placeholder),
7788
8087
  // Spacer to push caret to the right
7789
- m('span.spacer', { style: { flexGrow: 1 } }),
8088
+ m('span.spacer.mm-layout-grow'),
7790
8089
  m(MaterialIcon, {
7791
8090
  name: 'caret',
7792
8091
  direction: state.isOpen ? 'up' : 'down',
7793
- class: 'caret',
7794
- style: { marginLeft: 'auto', cursor: 'pointer' },
8092
+ class: 'caret mm-layout-ml-auto',
8093
+ style: { cursor: 'pointer' },
7795
8094
  }),
7796
8095
  ]),
7797
8096
  // Label
@@ -7803,6 +8102,8 @@ const SearchSelect = () => {
7803
8102
  // Dropdown Menu
7804
8103
  state.isOpen &&
7805
8104
  m('ul.dropdown-content.select-dropdown', {
8105
+ id: state.listboxId,
8106
+ role: 'listbox',
7806
8107
  oncreate: ({ dom }) => {
7807
8108
  state.dropdownRef = dom;
7808
8109
  },
@@ -7827,23 +8128,39 @@ const SearchSelect = () => {
7827
8128
  oninput: (e) => {
7828
8129
  state.searchTerm = e.target.value;
7829
8130
  state.focusedIndex = -1; // Reset focus when typing
8131
+ if (loadOptions) {
8132
+ void loadAsyncOptions(attrs, state.searchTerm);
8133
+ }
7830
8134
  },
7831
8135
  onkeydown: async (e) => {
7832
- const result = handleKeyDown(e, displayedOptions, !!showAddNew);
7833
- if (result === 'addNew' && oncreateNewOption) {
8136
+ const action = handleKeyDown(e, displayedOptions.length, !!showAddNew);
8137
+ if (action === 'open' && loadOptions) {
8138
+ await loadAsyncOptions(attrs, state.searchTerm);
8139
+ }
8140
+ else if (action === 'selectAction' && oncreateNewOption) {
7834
8141
  await createAndSelectOption(attrs);
7835
8142
  }
7836
- else if (result === 'selectOption' && state.focusedIndex < displayedOptions.length) {
8143
+ else if (action === 'selectFocused' && state.focusedIndex < displayedOptions.length) {
7837
8144
  toggleOption(displayedOptions[state.focusedIndex], attrs);
7838
8145
  }
7839
8146
  },
7840
8147
  class: 'search-select-input',
8148
+ 'aria-autocomplete': 'list',
8149
+ 'aria-controls': state.listboxId,
7841
8150
  }),
7842
8151
  ]),
7843
- // No options found message or list of options
7844
- ...(displayedOptions.length === 0 && !showAddNew
7845
- ? [m('li.search-select-no-options', texts.noOptionsFound)]
8152
+ // Async loading status
8153
+ ...(viewState === 'loading'
8154
+ ? [m('li.search-select-loading-info', { role: 'status', 'aria-live': 'polite' }, texts.loadingOptions)]
8155
+ : []),
8156
+ // Async loading error
8157
+ ...(viewState === 'error' && state.loadError
8158
+ ? [
8159
+ m('li.search-select-error-info', { role: 'status', 'aria-live': 'assertive' }, `${texts.loadingError}: ${state.loadError}`),
8160
+ ]
7846
8161
  : []),
8162
+ // No options found message or list of options
8163
+ ...(viewState === 'empty' && !showAddNew ? [m('li.search-select-no-options', texts.noOptionsFound)] : []),
7847
8164
  // Truncation message
7848
8165
  ...(isTruncated
7849
8166
  ? [
@@ -7876,6 +8193,9 @@ const SearchSelect = () => {
7876
8193
  ...(showAddNew
7877
8194
  ? [
7878
8195
  m('li', {
8196
+ id: `${state.listboxId}-action`,
8197
+ role: 'option',
8198
+ 'aria-selected': 'false',
7879
8199
  onclick: async () => {
7880
8200
  await createAndSelectOption(attrs);
7881
8201
  },
@@ -7887,9 +8207,10 @@ const SearchSelect = () => {
7887
8207
  ]
7888
8208
  : []),
7889
8209
  // List of filtered options
7890
- ...displayedOptions.map((option, index) => m(DropdownOption(), {
8210
+ ...displayedOptions.map((option, index) => DropdownOption({
7891
8211
  option,
7892
8212
  index,
8213
+ optionId: getComboboxOptionId(state.id, index),
7893
8214
  selectedIds,
7894
8215
  isFocused: state.focusedIndex === index,
7895
8216
  onToggle: (opt) => toggleOption(opt, attrs),
@@ -7902,6 +8223,10 @@ const SearchSelect = () => {
7902
8223
  ]);
7903
8224
  },
7904
8225
  };
8226
+ if (maybeVnode === null || maybeVnode === void 0 ? void 0 : maybeVnode.state) {
8227
+ maybeVnode.state.__searchSelectInstance = componentInstance;
8228
+ }
8229
+ return componentInstance;
7905
8230
  };
7906
8231
 
7907
8232
  const defaultI18n$2 = {
@@ -9275,6 +9600,53 @@ const FileUpload = () => {
9275
9600
  };
9276
9601
  };
9277
9602
 
9603
+ /** A semantic native fieldset for related controls. */
9604
+ const Fieldset = () => ({
9605
+ view: ({ attrs, children }) => {
9606
+ const { legend, description, required, disabled, error, className } = attrs, params = __rest(attrs, ["legend", "description", "required", "disabled", "error", "className"]);
9607
+ const descriptionId = params.id ? `${params.id}-description` : undefined;
9608
+ const errorId = params.id ? `${params.id}-error` : undefined;
9609
+ const describedBy = [description && descriptionId, error && errorId].filter(Boolean).join(' ') || undefined;
9610
+ return m('fieldset.mm-fieldset', Object.assign(Object.assign({}, params), { className, disabled, 'aria-describedby': describedBy }), [
9611
+ m('legend.mm-fieldset__legend', [legend, required && m('span.mm-fieldset__required[aria-hidden=true]', ' *')]),
9612
+ description && m('p.mm-fieldset__description', { id: descriptionId }, description),
9613
+ children,
9614
+ error && m('p.mm-fieldset__error[role=alert]', { id: errorId }, error),
9615
+ ]);
9616
+ },
9617
+ });
9618
+ const focusErrorTarget = (fieldId) => {
9619
+ var _a;
9620
+ if (!fieldId || typeof document === 'undefined')
9621
+ return;
9622
+ (_a = document.getElementById(fieldId)) === null || _a === void 0 ? void 0 : _a.focus();
9623
+ };
9624
+ /** A visual form section with an optional accessible validation summary. */
9625
+ const FormSection = () => ({
9626
+ view: ({ attrs, children }) => {
9627
+ const { title, description, errors = [], summaryTitle = 'Please correct the following errors', className } = attrs, params = __rest(attrs, ["title", "description", "errors", "summaryTitle", "className"]);
9628
+ return m('section.mm-form-section', Object.assign(Object.assign({}, params), { className }), [
9629
+ (title || description) &&
9630
+ m('.mm-form-section__header', [
9631
+ title && m('h3.mm-form-section__title', title),
9632
+ description && m('p.mm-form-section__description', description),
9633
+ ]),
9634
+ errors.length > 0 &&
9635
+ m('div.mm-validation-summary[role=alert][aria-live=assertive]', [
9636
+ m('p.mm-validation-summary__title', summaryTitle),
9637
+ m('ul.mm-validation-summary__list', errors.map((error, index) => {
9638
+ var _a, _b, _c;
9639
+ const href = (_a = error.href) !== null && _a !== void 0 ? _a : (error.fieldId ? `#${error.fieldId}` : undefined);
9640
+ return m('li', { key: `${(_c = (_b = error.fieldId) !== null && _b !== void 0 ? _b : href) !== null && _c !== void 0 ? _c : 'error'}-${index}` }, href
9641
+ ? m('a', { href, onclick: () => focusErrorTarget(error.fieldId) }, error.message)
9642
+ : error.message);
9643
+ })),
9644
+ ]),
9645
+ children,
9646
+ ]);
9647
+ },
9648
+ });
9649
+
9278
9650
  // List of MaterialIcon SVG icons that are available
9279
9651
  const materialIconSvgNames = [
9280
9652
  'caret',
@@ -9297,6 +9669,7 @@ const materialIconSvgNames = [
9297
9669
  const renderIcon = (icon, style) => {
9298
9670
  if (!icon)
9299
9671
  return null;
9672
+ const objectStyle = typeof style === 'string' ? undefined : style;
9300
9673
  if (typeof icon === 'string') {
9301
9674
  // Check if this is a MaterialIcon SVG name
9302
9675
  if (materialIconSvgNames.includes(icon)) {
@@ -9313,7 +9686,7 @@ const renderIcon = (icon, style) => {
9313
9686
  // Image URL
9314
9687
  return m('img', {
9315
9688
  src: icon.content,
9316
- style: Object.assign(Object.assign({}, style), { width: '24px', height: '24px', objectFit: 'contain' }),
9689
+ style: Object.assign(Object.assign({}, objectStyle), { width: '24px', height: '24px', objectFit: 'contain' }),
9317
9690
  });
9318
9691
  }
9319
9692
  return null;
@@ -9324,8 +9697,10 @@ const renderIcon = (icon, style) => {
9324
9697
  const SidenavHeaderFooterItem = () => {
9325
9698
  return {
9326
9699
  view: ({ attrs }) => {
9327
- const { text, icon, onclick, href, className = '', _isExpanded = true, _position = 'left' } = attrs;
9700
+ const { text, icon, onclick, href, className = '', title, tooltip, tooltipWhenCollapsedOnly = true, _isExpanded = true, _position = 'left', } = attrs;
9328
9701
  const isRightAligned = _position === 'right';
9702
+ const tooltipText = title || tooltip || text;
9703
+ const shouldShowTooltip = tooltipWhenCollapsedOnly ? !_isExpanded : true;
9329
9704
  const handleClick = (e) => {
9330
9705
  if (onclick) {
9331
9706
  e.preventDefault();
@@ -9334,24 +9709,25 @@ const SidenavHeaderFooterItem = () => {
9334
9709
  };
9335
9710
  const content = isRightAligned
9336
9711
  ? [
9337
- _isExpanded &&
9338
- m('span.sidenav-item-text', { style: { flex: '1', 'text-align': 'left', 'margin-right': '8px' } }, text),
9712
+ _isExpanded && m('span.sidenav-item-text.mm-layout-grow.mm-layout-mr-8.left-align', text),
9339
9713
  renderIcon(icon, { 'min-width': '24px', width: '24px' }),
9340
9714
  ]
9341
9715
  : [
9342
9716
  renderIcon(icon, { 'min-width': '24px', width: '24px' }),
9343
- _isExpanded && m('span.sidenav-item-text', { style: { 'margin-left': '8px', flex: '1' } }, text),
9717
+ _isExpanded && m('span.sidenav-item-text.mm-layout-grow.mm-layout-ml-8', text),
9344
9718
  ];
9345
9719
  const linkStyle = {
9346
- display: 'flex',
9347
- 'align-items': 'center',
9348
9720
  padding: _isExpanded ? '12px 16px' : '12px 18px',
9349
9721
  'justify-content': _isExpanded ? (isRightAligned ? 'flex-end' : 'flex-start') : 'center',
9350
9722
  };
9723
+ const linkClass = 'mm-layout-row mm-layout-row--center';
9351
9724
  return m('li', { class: className }, m('a', {
9352
9725
  href: href || '#!',
9353
9726
  onclick: handleClick,
9727
+ class: linkClass,
9354
9728
  style: linkStyle,
9729
+ title: shouldShowTooltip ? tooltipText : undefined,
9730
+ 'aria-label': shouldShowTooltip ? tooltipText : undefined,
9355
9731
  }, content));
9356
9732
  },
9357
9733
  };
@@ -9452,6 +9828,7 @@ const Sidenav = () => {
9452
9828
  fixed ? 'sidenav-fixed' : '',
9453
9829
  mode === 'push' ? 'sidenav-push' : '',
9454
9830
  expandable && !isExpanded ? 'sidenav-collapsed' : '',
9831
+ 'mm-layout-stack',
9455
9832
  className,
9456
9833
  ]
9457
9834
  .filter(Boolean)
@@ -9461,8 +9838,6 @@ const Sidenav = () => {
9461
9838
  transform: isOpen ? 'translateX(0)' : position === 'left' ? 'translateX(-105%)' : 'translateX(105%)',
9462
9839
  'transition-duration': `${animationDuration}ms`,
9463
9840
  'transition-property': 'transform, width',
9464
- display: 'flex',
9465
- 'flex-direction': 'column',
9466
9841
  },
9467
9842
  }, [
9468
9843
  // Header content slot (rendered first, before hamburger)
@@ -9479,10 +9854,8 @@ const Sidenav = () => {
9479
9854
  // Hamburger toggle button (inside sidenav, at the top)
9480
9855
  showHamburger &&
9481
9856
  m('li.sidenav-hamburger-item', {
9857
+ class: `mm-layout-row mm-layout-row--center ${position === 'right' ? 'mm-layout-row--justify-end' : 'mm-layout-row--justify-start'}`,
9482
9858
  style: {
9483
- display: 'flex',
9484
- 'justify-content': position === 'right' ? 'flex-end' : 'flex-start',
9485
- 'align-items': 'center',
9486
9859
  padding: '12px 16px',
9487
9860
  cursor: 'pointer',
9488
9861
  'border-bottom': '1px solid rgba(0,0,0,0.1)',
@@ -9498,10 +9871,8 @@ const Sidenav = () => {
9498
9871
  // Expand/collapse toggle button (if expandable, right below hamburger)
9499
9872
  expandable &&
9500
9873
  m('li.sidenav-expand-toggle', {
9874
+ class: `mm-layout-row mm-layout-row--center ${position === 'right' ? 'mm-layout-row--justify-end' : 'mm-layout-row--justify-start'}`,
9501
9875
  style: {
9502
- display: 'flex',
9503
- 'justify-content': position === 'right' ? 'flex-end' : 'flex-start',
9504
- 'align-items': 'center',
9505
9876
  padding: '12px 16px',
9506
9877
  cursor: 'pointer',
9507
9878
  'border-bottom': '1px solid rgba(0,0,0,0.1)',
@@ -9574,7 +9945,7 @@ const NavbarSubItem = () => {
9574
9945
  const submenuContent = isRightAligned
9575
9946
  ? [
9576
9947
  // Right-aligned: text on left, icons on right
9577
- isExpanded && m('span', { style: { flex: '1', 'text-align': 'left' } }, text),
9948
+ isExpanded && m('span.mm-layout-grow.left-align', text),
9578
9949
  icon && isExpanded && renderIcon(icon, { 'font-size': '18px' }),
9579
9950
  indicatorIcon,
9580
9951
  ]
@@ -9582,18 +9953,22 @@ const NavbarSubItem = () => {
9582
9953
  // Left-aligned: indicator on left, text and icon on right
9583
9954
  indicatorIcon,
9584
9955
  icon && isExpanded && renderIcon(icon, { 'font-size': '18px', 'margin-left': indicatorIcon ? '8px' : '0' }),
9585
- isExpanded && m('span', { style: { 'margin-left': icon || indicatorIcon ? '8px' : '0' } }, text),
9956
+ isExpanded && m('span', { class: icon || indicatorIcon ? 'mm-layout-ml-8' : undefined }, text),
9586
9957
  ];
9587
9958
  return m('li.sidenav-subitem', {
9588
- class: selected ? 'selected' : '',
9959
+ class: [
9960
+ selected ? 'selected' : '',
9961
+ 'mm-layout-row',
9962
+ 'mm-layout-row--center',
9963
+ 'mm-layout-gap-sm',
9964
+ isRightAligned ? 'mm-layout-row--justify-between' : 'mm-layout-row--justify-start',
9965
+ ]
9966
+ .filter(Boolean)
9967
+ .join(' ') || undefined,
9589
9968
  style: {
9590
9969
  padding: isExpanded ? '0 16px 0 48px' : '0 16px',
9591
9970
  cursor: 'pointer',
9592
- display: 'flex',
9593
- 'align-items': 'center',
9594
- gap: '8px',
9595
9971
  'font-size': '0.9em',
9596
- 'justify-content': isRightAligned ? 'space-between' : 'flex-start',
9597
9972
  height: '48px',
9598
9973
  'min-height': '48px',
9599
9974
  },
@@ -9610,7 +9985,7 @@ const SidenavItem = () => {
9610
9985
  let isSubmenuOpen = false;
9611
9986
  return {
9612
9987
  view: ({ attrs, children }) => {
9613
- const { text, icon, active = false, disabled = false, onclick, href, className = '', divider = false, subheader = false, submenu = [], submenuMode = 'checkbox', } = attrs;
9988
+ const { text, icon, active = false, disabled = false, onclick, href, className = '', divider = false, subheader = false, submenu = [], submenuMode = 'checkbox', title, tooltip, tooltipWhenCollapsedOnly = true, } = attrs;
9614
9989
  if (divider) {
9615
9990
  return m('li.divider');
9616
9991
  }
@@ -9635,39 +10010,45 @@ const SidenavItem = () => {
9635
10010
  const isExpanded = attrs._isExpanded !== false;
9636
10011
  const position = attrs._position || 'left';
9637
10012
  const isRightAligned = position === 'right';
10013
+ const tooltipText = title || tooltip || text;
10014
+ const shouldShowTooltip = tooltipWhenCollapsedOnly ? !isExpanded : true;
9638
10015
  // In expanded mode, icons are at the outside edge
9639
10016
  // In collapsed mode, icons are centered
9640
10017
  const content = isRightAligned
9641
10018
  ? [
9642
10019
  // Right-aligned: text on left, icon on right
9643
- isExpanded &&
9644
- m('span.sidenav-item-text', { style: { flex: '1', 'text-align': 'left', 'margin-right': '8px' } }, text || children),
10020
+ isExpanded && m('span.sidenav-item-text.mm-layout-grow.mm-layout-mr-8.left-align', text || children),
9645
10021
  renderIcon(icon, { 'min-width': '24px', width: '24px' }),
9646
10022
  ]
9647
10023
  : [
9648
10024
  // Left-aligned: icon on left, text on right
9649
10025
  renderIcon(icon, { 'min-width': '24px', width: '24px' }),
9650
- isExpanded && m('span.sidenav-item-text', { style: { 'margin-left': '8px', flex: '1' } }, text || children),
10026
+ isExpanded && m('span.sidenav-item-text.mm-layout-grow.mm-layout-ml-8', text || children),
9651
10027
  ];
9652
10028
  const linkStyle = {
9653
- display: 'flex',
9654
- 'align-items': 'center',
9655
10029
  padding: isExpanded ? '12px 16px' : '12px 18px',
9656
10030
  'justify-content': isExpanded ? (isRightAligned ? 'flex-end' : 'flex-start') : 'center',
9657
10031
  };
10032
+ const linkClass = 'mm-layout-row mm-layout-row--center';
9658
10033
  const mainItem = href && !disabled
9659
10034
  ? m('li', { class: itemClasses }, [
9660
10035
  m('a', {
9661
10036
  href,
9662
10037
  onclick: handleMainClick,
10038
+ class: linkClass,
9663
10039
  style: linkStyle,
10040
+ title: shouldShowTooltip ? tooltipText : undefined,
10041
+ 'aria-label': shouldShowTooltip ? tooltipText : undefined,
9664
10042
  }, content),
9665
10043
  ])
9666
10044
  : m('li', { class: itemClasses }, [
9667
10045
  m('a', {
9668
10046
  onclick: handleMainClick,
9669
10047
  href: '#!',
10048
+ class: linkClass,
9670
10049
  style: linkStyle,
10050
+ title: shouldShowTooltip ? tooltipText : undefined,
10051
+ 'aria-label': shouldShowTooltip ? tooltipText : undefined,
9671
10052
  }, content),
9672
10053
  ]);
9673
10054
  // Return main item with submenu if applicable
@@ -10183,8 +10564,9 @@ const TreeNodeComponent = () => {
10183
10564
  const childIsFocused = ((_e = attrs.treeState) === null || _e === void 0 ? void 0 : _e.focusedNodeId) === child.id;
10184
10565
  // Calculate if this child is last in branch
10185
10566
  const childPath = [...(attrs.currentPath || []), childIndex];
10186
- const childIsLastInBranch = ((_f = attrs.treeAttrs) === null || _f === void 0 ? void 0 : _f.data) ?
10187
- isNodeLastInBranch(childPath, attrs.treeAttrs.data) : false;
10567
+ const childIsLastInBranch = ((_f = attrs.treeAttrs) === null || _f === void 0 ? void 0 : _f.data)
10568
+ ? isNodeLastInBranch(childPath, attrs.treeAttrs.data)
10569
+ : false;
10188
10570
  return m(TreeNodeComponent, {
10189
10571
  key: child.id,
10190
10572
  node: child,
@@ -10317,10 +10699,7 @@ const TreeView = () => {
10317
10699
  view: ({ attrs }) => {
10318
10700
  const { data, className, style, id, selectionMode = 'single', showConnectors = true } = attrs;
10319
10701
  return m('div.tree-view', {
10320
- class: [
10321
- className,
10322
- showConnectors && 'show-connectors'
10323
- ].filter(Boolean).join(' ') || undefined,
10702
+ class: [className, showConnectors && 'show-connectors'].filter(Boolean).join(' ') || undefined,
10324
10703
  style,
10325
10704
  id,
10326
10705
  role: selectionMode === 'multiple' ? 'listbox' : 'tree',
@@ -11018,6 +11397,7 @@ const Rating = () => {
11018
11397
  };
11019
11398
  };
11020
11399
 
11400
+ const MOBILE_LAYOUT_BREAKPOINT = 600;
11021
11401
  /** Create a LikertScale component */
11022
11402
  const LikertScale = () => {
11023
11403
  const state = {
@@ -11080,6 +11460,22 @@ const LikertScale = () => {
11080
11460
  return 'likert-scale--responsive';
11081
11461
  }
11082
11462
  };
11463
+ const isVerticalLayout = (layout) => {
11464
+ if (layout === 'vertical')
11465
+ return true;
11466
+ if (layout === 'horizontal')
11467
+ return false;
11468
+ return typeof window !== 'undefined' ? window.innerWidth <= MOBILE_LAYOUT_BREAKPOINT : false;
11469
+ };
11470
+ const getInlineAnchorLabel = (value, min, max, middleValue, startLabel, middleLabel, endLabel) => {
11471
+ if (value === min && startLabel)
11472
+ return startLabel;
11473
+ if (middleLabel && middleValue !== undefined && value === middleValue)
11474
+ return middleLabel;
11475
+ if (value === max && endLabel)
11476
+ return endLabel;
11477
+ return undefined;
11478
+ };
11083
11479
  const handleChange = (attrs, newValue) => {
11084
11480
  var _a;
11085
11481
  if (attrs.readonly || attrs.disabled)
@@ -11126,7 +11522,7 @@ const LikertScale = () => {
11126
11522
  const LikertScaleItem = () => {
11127
11523
  return {
11128
11524
  view: ({ attrs }) => {
11129
- const { value, currentValue, showNumber, showTooltip, tooltipLabel, groupId, name, disabled, readonly, onchange, } = attrs;
11525
+ const { value, currentValue, showNumber, showTooltip, tooltipLabel, groupId, name, disabled, readonly, anchorLabel, onchange, } = attrs;
11130
11526
  const radioId = `${groupId}-${value}`;
11131
11527
  const isChecked = currentValue === value;
11132
11528
  return m('.likert-scale__item.no-select', {
@@ -11153,6 +11549,7 @@ const LikertScale = () => {
11153
11549
  m('label.likert-scale__label', {
11154
11550
  for: radioId,
11155
11551
  }),
11552
+ anchorLabel && m('.likert-scale__item-anchor', anchorLabel),
11156
11553
  // Tooltip (optional)
11157
11554
  showTooltip && tooltipLabel && m('.likert-scale__tooltip', tooltipLabel),
11158
11555
  ]);
@@ -11176,6 +11573,8 @@ const LikertScale = () => {
11176
11573
  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"]);
11177
11574
  const currentValue = getCurrentValue(attrs);
11178
11575
  const itemCount = Math.floor((max - min) / step) + 1;
11576
+ const useInlineAnchors = isVerticalLayout(layout);
11577
+ const middleValue = middleLabel ? min + Math.floor((itemCount - 1) / 2) * step : undefined;
11179
11578
  // Generate scale values
11180
11579
  const scaleValues = Array.from({ length: itemCount }, (_, i) => min + i * step);
11181
11580
  return m('.likert-scale', {
@@ -11224,6 +11623,9 @@ const LikertScale = () => {
11224
11623
  showNumber: showNumbers,
11225
11624
  showTooltip: showTooltips,
11226
11625
  tooltipLabel: tooltipLabels === null || tooltipLabels === void 0 ? void 0 : tooltipLabels[value - min],
11626
+ anchorLabel: useInlineAnchors
11627
+ ? getInlineAnchorLabel(value, min, max, middleValue, startLabel, middleLabel, endLabel)
11628
+ : undefined,
11227
11629
  groupId: state.groupId,
11228
11630
  name,
11229
11631
  disabled,
@@ -11231,7 +11633,8 @@ const LikertScale = () => {
11231
11633
  onchange: (v) => handleChange(attrs, v),
11232
11634
  }))),
11233
11635
  // Scale anchors
11234
- (startLabel || middleLabel || endLabel) &&
11636
+ !useInlineAnchors &&
11637
+ (startLabel || middleLabel || endLabel) &&
11235
11638
  m('.likert-scale__anchors', [
11236
11639
  startLabel && m('.likert-scale__anchor.likert-scale__anchor--start', startLabel),
11237
11640
  middleLabel && m('.likert-scale__anchor.likert-scale__anchor--middle', middleLabel),
@@ -11416,6 +11819,9 @@ const CircularProgress = () => {
11416
11819
  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']);
11417
11820
  const isDeterminate = mode === 'determinate';
11418
11821
  const sizePixels = SIZE_MAP[size];
11822
+ const styleValue = typeof style === 'string'
11823
+ ? `width:${sizePixels}px;height:${sizePixels}px;${style}`
11824
+ : Object.assign({ width: `${sizePixels}px`, height: `${sizePixels}px` }, style);
11419
11825
  const { radius, circumference, strokeDashoffset, percentage } = isDeterminate
11420
11826
  ? calculateStrokeProperties(sizePixels, value, max)
11421
11827
  : { radius: 0, circumference: 0, strokeDashoffset: 0, percentage: 0 };
@@ -11442,7 +11848,7 @@ const CircularProgress = () => {
11442
11848
  : {
11443
11849
  'aria-valuetext': ariaValueText || label || 'Loading',
11444
11850
  };
11445
- return m('.circular-progress', Object.assign(Object.assign(Object.assign({}, params), { className: classNames, style: Object.assign({ width: `${sizePixels}px`, height: `${sizePixels}px` }, style), id, role: 'progressbar', 'aria-label': ariaLabel || (isDeterminate ? `Progress: ${Math.round(percentage)}%` : 'Loading') }), ariaAttrs), [
11851
+ 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), [
11446
11852
  // SVG circle
11447
11853
  m('svg.circular-progress__svg', {
11448
11854
  viewBox: `0 0 ${sizePixels} ${sizePixels}`,
@@ -11507,13 +11913,7 @@ const LinearProgress = () => {
11507
11913
  // Determine label content
11508
11914
  const labelContent = label !== undefined ? label : showPercentage && isDeterminate ? `${Math.round(percentage)}%` : '';
11509
11915
  // Build class names
11510
- const classNames = [
11511
- 'linear-progress',
11512
- getColorClass(color, colorIntensity),
11513
- className,
11514
- ]
11515
- .filter(Boolean)
11516
- .join(' ');
11916
+ const classNames = ['linear-progress', getColorClass(color, colorIntensity), className].filter(Boolean).join(' ');
11517
11917
  // ARIA attributes
11518
11918
  const ariaAttrs = isDeterminate
11519
11919
  ? {
@@ -11566,4 +11966,5 @@ const isValidationError = (result) => !isValidationSuccess(result);
11566
11966
  // ============================================================================
11567
11967
  // All types are already exported via individual export declarations above
11568
11968
 
11569
- export { AnalogClock, AnchorItem, Autocomplete, Badge, Breadcrumb, BreadcrumbManager, Button, ButtonFactory, Carousel, CharacterCounter, Chips, CircularProgress, CodeBlock, Collapsible, CollapsibleItem, Collection, CollectionMode, ColorInput, ConfirmButton, DataTable, DatePicker, DigitalClock, DoubleRangeSlider, Dropdown, EmailInput, FileInput, FileUpload, FlatButton, FloatingActionButton, HelperText, Icon, IconButton, ImageList, InputCheckbox, Label, LargeButton, LikertScale, LinearProgress, ListItem, Mandatory, Masonry, MaterialBox, MaterialIcon, ModalPanel, NumberInput, Options, OptionsList, Pagination, PaginationControls, Parallax, PasswordInput, Pushpin, PushpinComponent, RadioButton, RadioButtons, RangeInput, Rating, RoundIconButton, SearchSelect, SecondaryContent, Select, Sidenav, SidenavItem, SidenavManager, SingleRangeSlider, SmallButton, Stepper, SubmitButton, Switch, Tabs, TextArea, TextInput, ThemeManager, ThemeSwitcher, ThemeToggle, TimePicker, TimeRangePicker, Timeline, Toast, ToastComponent, ToggleGroup, Tooltip, TooltipComponent, TreeView, UrlInput, Wizard, addLeadingZero, clearPortal, createBreadcrumb, formatTime, generateHourOptions, generateMinuteOptions, getDropdownStyles, getPortalContainer, initPushpins, initTooltips, isNumeric, isTimeDisabled, isValidationError, isValidationSuccess, padLeft, parseTime, range, releasePortalContainer, renderToPortal, scrollToValue, snapToNearestItem, sortOptions, timeToMinutes, toast, uniqueId, uuid4 };
11969
+ export { AnalogClock, AnchorItem, Autocomplete, Badge, Breadcrumb, BreadcrumbManager, Button, ButtonFactory, Carousel, CharacterCounter, Chips, CircularProgress, CodeBlock, Collapsible, CollapsibleItem, Collection, CollectionMode, ColorInput, ConfirmButton, DataTable, DatePicker, DigitalClock, DoubleRangeSlider, Dropdown, EmailInput, Fieldset, FileInput, FileUpload, FlatButton, FloatingActionButton, FormSection, HelperText, Icon, IconButton, ImageList, InputCheckbox, Label, LargeButton, LikertScale, LinearProgress, ListItem, Mandatory, Masonry, MaterialBox, MaterialIcon, ModalPanel, NumberInput, Options, OptionsList, Pagination, PaginationControls, Parallax, PasswordInput, Pushpin, PushpinComponent, RadioButton, RadioButtons, RangeInput, Rating, RoundIconButton, SearchSelect, SecondaryContent, Select, Sidenav, SidenavItem, SidenavManager, SingleRangeSlider, SmallButton, Stepper, SubmitButton, Switch, Tabs, TextArea, TextInput, ThemeManager, ThemeSwitcher, ThemeToggle, TimePicker, TimeRangePicker, Timeline, Toast, ToastComponent, ToggleButton, ToggleGroup, Tooltip, TooltipComponent, TreeView, UrlInput, Wizard, addLeadingZero, clearPortal, createAsyncComboboxState, createBreadcrumb, formatTime, generateHourOptions, generateMinuteOptions, getComboboxKeyResult, getComboboxOptionId, getComboboxViewState, getDropdownStyles, getPortalContainer, initPushpins, initTooltips, isNumeric, isTimeDisabled, isValidationError, isValidationSuccess, normalizeSelection, padLeft, parseTime, range, rejectAsyncComboboxRequest, releasePortalContainer, renderFieldChrome, renderToPortal, resolveAsyncComboboxRequest, resolveControllableValue, scrollToValue, snapToNearestItem, sortOptions, startAsyncComboboxRequest, syncPortalContent, timeToMinutes, toast, uniqueId, uuid4 };
11970
+ //# sourceMappingURL=index.esm.js.map