@react-md/core 6.4.0 → 6.5.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 (38) hide show
  1. package/dist/_a11y.scss +3 -1
  2. package/dist/_box-shadows.scss +20 -12
  3. package/dist/_core.scss +1 -1
  4. package/dist/_utils.scss +25 -11
  5. package/dist/app-bar/_app-bar.scss +3 -3
  6. package/dist/autocomplete/_autocomplete.scss +20 -16
  7. package/dist/avatar/_avatar.scss +2 -1
  8. package/dist/button/_button.scss +9 -5
  9. package/dist/card/_card.scss +6 -6
  10. package/dist/chip/_chip.scss +6 -6
  11. package/dist/dialog/_dialog.scss +6 -6
  12. package/dist/divider/_divider.scss +6 -2
  13. package/dist/form/Select.d.ts +24 -0
  14. package/dist/form/Select.js +14 -3
  15. package/dist/form/Select.js.map +1 -1
  16. package/dist/form/SelectedOption.d.ts +1 -2
  17. package/dist/form/SelectedOption.js +2 -2
  18. package/dist/form/SelectedOption.js.map +1 -1
  19. package/dist/form/_input-toggle.scss +6 -5
  20. package/dist/form/_label.scss +2 -2
  21. package/dist/form/_legend.scss +22 -13
  22. package/dist/form/_slider.scss +7 -5
  23. package/dist/form/_switch.scss +7 -5
  24. package/dist/form/_text-field.scss +13 -11
  25. package/dist/form/defaultGetSelectedOptionChildren.d.ts +1 -0
  26. package/dist/form/getSelectedOptionChildren.d.ts +1 -0
  27. package/dist/form/legendStyles.d.ts +1 -1
  28. package/dist/form/legendStyles.js.map +1 -1
  29. package/dist/interaction/_interaction.scss +5 -3
  30. package/dist/snackbar/_snackbar.scss +3 -3
  31. package/dist/tabs/_tabs.scss +5 -6
  32. package/dist/theme/_a11y.scss +3 -1
  33. package/dist/theme/_theme.scss +16 -12
  34. package/dist/window-splitter/_window-splitter.scss +15 -17
  35. package/package.json +7 -7
  36. package/src/form/Select.tsx +53 -2
  37. package/src/form/SelectedOption.tsx +2 -4
  38. package/src/form/legendStyles.ts +1 -1
package/dist/_a11y.scss CHANGED
@@ -183,5 +183,7 @@ $_linear-channel-values: (
183
183
  $light-contrast: _contrast($background-color, $light-color);
184
184
  $dark-contrast: _contrast($background-color, $dark-color);
185
185
 
186
- @return if($light-contrast > $dark-contrast, $light-color, $dark-color);
186
+ @return if(
187
+ sass($light-contrast > $dark-contrast): $light-color; else: $dark-color
188
+ );
187
189
  }
@@ -203,7 +203,11 @@ $box-shadow-3-layers: (
203
203
  $create-pseudo: true,
204
204
  $position-relative: true
205
205
  ) {
206
- $pseudo-selector: if($pseudo-before, "&::before", "&::after");
206
+ $pseudo-selector: "&::after";
207
+ @if $pseudo-before {
208
+ $pseudo-selector: "&::before";
209
+ }
210
+
207
211
  $suffix: string.slice($pseudo-selector, 2);
208
212
  $active-string: "";
209
213
 
@@ -230,7 +234,11 @@ $box-shadow-3-layers: (
230
234
  @for $i from 1 to list.length($active-selectors) + 1 {
231
235
  $selector: list.nth($active-selectors, $i);
232
236
 
233
- $prefix: $active-string + if($i > 1, ", ", "");
237
+ $maybe-comma: "";
238
+ @if $i > 1 {
239
+ $maybe-comma: ", ";
240
+ }
241
+ $prefix: $active-string + $maybe-comma;
234
242
  $active-string: $prefix + $selector + $suffix;
235
243
  }
236
244
  }
@@ -282,16 +290,16 @@ $box-shadow-3-layers: (
282
290
  $opacity-boost: 0,
283
291
  $position-relative: true
284
292
  ) {
285
- $start-shadow: if(
286
- $start-z-value == none or $start-z-value == 0,
287
- none,
288
- box-shadow($start-z-value, $color, $opacity-boost)
289
- );
290
- $end-shadow: if(
291
- $end-z-value == none or $end-z-value == 0,
292
- none,
293
- if($end-z-value, box-shadow($end-z-value, $color, $opacity-boost), null)
294
- );
293
+ $start-shadow: none;
294
+ $end-shadow: null;
295
+ @if $start-z-value != none and $start-z-value != 0 {
296
+ $start-shadow: box-shadow($start-z-value, $color, $opacity-boost);
297
+ }
298
+ @if $end-z-value {
299
+ @if $end-z-value != none and $end-z-value != 0 {
300
+ $end-shadow: box-shadow($end-z-value, $color, $opacity-boost);
301
+ }
302
+ }
295
303
 
296
304
  @include box-shadow-transition(
297
305
  $start-shadow,
package/dist/_core.scss CHANGED
@@ -15,9 +15,9 @@
15
15
  @forward "box-shadows";
16
16
  @forward "interaction/interaction" as interaction-*;
17
17
  @forward "draggable/draggable" as draggable-*;
18
+ @forward "divider/divider" as divider-*;
18
19
  @forward "window-splitter/window-splitter" as window-splitter-*;
19
20
  @forward "icon/icon" as icon-*;
20
- @forward "divider/divider" as divider-*;
21
21
  @forward "progress/progress" as progress-*;
22
22
  @forward "overlay/overlay" as overlay-*;
23
23
  @forward "button/button" as button-*;
package/dist/_utils.scss CHANGED
@@ -97,30 +97,40 @@ $_swappable-properties: text-align;
97
97
  /// @param {String} error-message - The additional error message to display
98
98
  /// @returns {any} the value from the list or map
99
99
  @function validate($options, $key-or-value, $error-message) {
100
- $options: if(
101
- meta.type-of($options) == string,
102
- list.append((), $options),
103
- $options
104
- );
100
+ @if meta.type-of($options) == string {
101
+ $options: list.append((), $options);
102
+ }
105
103
 
106
104
  $type: meta.type-of($options);
107
105
  $is-map: $type == map;
108
106
  $is-list: $type == list;
109
107
 
110
108
  @if $disable-validation {
111
- @return if($is-list, $key-or-value, map.get($options, $key-or-value));
109
+ @if $is-list {
110
+ @return $key-or-value;
111
+ }
112
+
113
+ @return map.get($options, $key-or-value);
112
114
  }
113
115
 
114
116
  @if not $is-map and not $is-list {
115
117
  @error "Unable to validate anything except for lists and maps at this time. Received: '#{$options}'.";
116
118
  }
117
119
 
118
- $choices: if($is-map, map.keys($options), $options);
120
+ $choices: $options;
121
+ @if $is-map {
122
+ $choices: map.keys($options);
123
+ }
124
+
119
125
  @if not list.index($choices, $key-or-value) {
120
126
  @error "Invalid #{$error-message}: '#{$key-or-value}'. Choose one of: #{$choices}";
121
127
  }
122
128
 
123
- @return if($is-list, $key-or-value, map.get($options, $key-or-value));
129
+ @if $is-list {
130
+ @return $key-or-value;
131
+ }
132
+
133
+ @return map.get($options, $key-or-value);
124
134
  }
125
135
 
126
136
  /// Used to get a custom property variable name.
@@ -272,7 +282,7 @@ $_swappable-properties: text-align;
272
282
  content: "";
273
283
  inset: $inset;
274
284
  pointer-events: none;
275
- position: if($fixed, fixed, absolute);
285
+ position: if(sass($fixed): fixed; else: absolute);
276
286
  z-index: $z-index;
277
287
  }
278
288
 
@@ -349,8 +359,12 @@ $_swappable-properties: text-align;
349
359
  $css-modules: false,
350
360
  $parent-selector: true
351
361
  ) {
352
- $selector: if($css-modules, ":global #{$selector} :local", $selector);
353
- $selector: if($parent-selector, "#{$selector} &", $selector);
362
+ @if $css-modules {
363
+ $selector: ":global #{$selector} :local";
364
+ }
365
+ @if $parent-selector {
366
+ $selector: "#{$selector} &";
367
+ }
354
368
 
355
369
  #{$selector} {
356
370
  @content;
@@ -115,10 +115,10 @@ $light-theme-surface-color: a11y.contrast-color(
115
115
  /// The background color to use when `theme="surface"` and using the global dark
116
116
  /// theme
117
117
  /// @type Color
118
+ // prettier-ignore
118
119
  $dark-theme-surface-background-color: if(
119
- theme.$disable-dark-elevation,
120
- theme.$dark-theme-surface-color,
121
- map.get(theme.$dark-elevation-colors, $fixed-elevation)
120
+ sass(theme.$disable-dark-elevation): theme.$dark-theme-surface-color;
121
+ else: map.get(theme.$dark-elevation-colors, $fixed-elevation)
122
122
  ) !default;
123
123
 
124
124
  /// The text color to use when `theme="surface"` and using the global dark theme
@@ -195,21 +195,22 @@ $variables: (
195
195
  @function _right-addon-calc() {
196
196
  $calc-spacing: get-var(addon-spacing);
197
197
  $calc-total-gap: calc(get-var(gap-count, 0) * get-var(addon-gap));
198
- $calc-clear-button: if(
199
- $disable-clear-button,
200
- "",
201
- " + " + get-var(clear-button-size, 0px)
202
- );
203
- $calc-dropdown-button: if(
204
- $disable-dropdown-button,
205
- "",
206
- " + " + get-var(dropdown-button-size, 0px)
207
- );
208
- $calc-circular-progress: if(
209
- $disable-circular-progress,
210
- "",
211
- " + " + get-var(circular-progress-size, 0px)
212
- );
198
+
199
+ $calc-clear-button: "";
200
+ @if not $disable-clear-button {
201
+ $calc-clear-button: " + " + get-var(clear-button-size, 0px);
202
+ }
203
+
204
+ $calc-dropdown-button: "";
205
+ @if not $disable-dropdown-button {
206
+ $calc-dropdown-button: " + " + get-var(dropdown-button-size, 0px);
207
+ }
208
+
209
+ $calc-circular-progress: "";
210
+ @if not $disable-circular-progress {
211
+ $calc-circular-progress: " + " + get-var(circular-progress-size, 0px);
212
+ }
213
+
213
214
  $calc-addon-size: $calc-clear-button + $calc-dropdown-button +
214
215
  $calc-circular-progress;
215
216
 
@@ -223,7 +224,10 @@ $variables: (
223
224
  /// @param {String} addon-selector
224
225
  /// @returns {String} a class name selector
225
226
  @function _add-has-selector($appending-selector, $addon-selector) {
226
- $prefix: if(string.length($appending-selector), "", "&");
227
+ $prefix: "";
228
+ @if not string.length($appending-selector) {
229
+ $prefix: "&";
230
+ }
227
231
 
228
232
  @return $appending-selector + $prefix + ":has(" + $addon-selector + ")";
229
233
  }
@@ -165,7 +165,8 @@ $variables: (
165
165
  /// @param {Boolean} disable-prefix [false] - Set to `true` to disable the
166
166
  /// `.rmd-avatar--` prefix for the class name
167
167
  @mixin custom-color($name, $color, $background-color, $disable-prefix: false) {
168
- $class-name: if($disable-prefix, $name, ".rmd-avatar--#{$name}");
168
+ // prettier-ignore
169
+ $class-name: if(sass($disable-prefix): $name; else: ".rmd-avatar--#{$name}");
169
170
 
170
171
  #{$class-name} {
171
172
  @include set-var(background-color, $background-color);
@@ -408,6 +408,14 @@ $variables: (
408
408
  }
409
409
 
410
410
  @if not $disable-contained {
411
+ $contained-elevation-end: null;
412
+ @if not
413
+ $disable-contained-pressed-elevation and
414
+ $contained-pressed-elevation
415
+ {
416
+ $contained-elevation-end: $contained-pressed-elevation;
417
+ }
418
+
411
419
  &--contained {
412
420
  // contained buttons should _normally_ always force dark background
413
421
  // colors for the interaction states This means use the default light
@@ -424,11 +432,7 @@ $variables: (
424
432
 
425
433
  @include box-shadows.elevation-transition(
426
434
  $contained-elevation,
427
- if(
428
- $disable-contained-pressed-elevation,
429
- null,
430
- $contained-pressed-elevation
431
- ),
435
+ $contained-elevation-end,
432
436
  "&.rmd-button--pressed",
433
437
  $pseudo-before: false,
434
438
  $position-relative: false
@@ -59,10 +59,10 @@ $light-theme-background-color: theme.theme-get-var(surface-color) !default;
59
59
 
60
60
  /// The background color to use when using the global dark theme
61
61
  /// @type Color
62
+ // prettier-ignore
62
63
  $dark-theme-background-color: if(
63
- theme.$disable-dark-elevation,
64
- theme.$dark-theme-surface-color,
65
- map.get(theme.$dark-elevation-colors, $elevation)
64
+ sass(theme.$disable-dark-elevation): theme.$dark-theme-surface-color;
65
+ else: map.get(theme.$dark-elevation-colors, $elevation)
66
66
  ) !default;
67
67
 
68
68
  /// The default card background color
@@ -226,10 +226,10 @@ $variables: (background-color, color);
226
226
  column-gap: $header-spacing;
227
227
  display: flex;
228
228
  max-width: 100%;
229
+ // prettier-ignore
229
230
  padding: if(
230
- $header-padding == $header-padding-top or not $header-padding-top,
231
- $header-padding,
232
- $header-padding-top $header-padding $header-padding
231
+ sass($header-padding == $header-padding-top or not $header-padding-top): $header-padding;
232
+ else: $header-padding-top $header-padding $header-padding
233
233
  );
234
234
  }
235
235
 
@@ -182,10 +182,10 @@ $solid-light-color: a11y.contrast-color($solid-light-background-color) !default;
182
182
 
183
183
  /// The dark theme background color for the `theme="solid"`
184
184
  /// @type Color
185
+ // prettier-ignore
185
186
  $solid-dark-background-color: if(
186
- theme.$disable-dark-elevation,
187
- colors.$grey-900,
188
- map.get(theme.$dark-elevation-colors, 12)
187
+ sass(theme.$disable-dark-elevation): colors.$grey-900;
188
+ else: map.get(theme.$dark-elevation-colors, 12)
189
189
  ) !default;
190
190
 
191
191
  /// The dark theme background color for the `theme="solid"` and the `Chip` is
@@ -261,10 +261,10 @@ $outline-dark-color: $outline-light-color !default;
261
261
 
262
262
  /// The background-color to use in dark themes when `theme="outline"`
263
263
  /// @type Color
264
+ // prettier-ignore
264
265
  $outline-dark-background-color: if(
265
- theme.$disable-dark-elevation,
266
- theme.$dark-theme-surface-color,
267
- map.get(theme.$dark-elevation-colors, $outline-raisable-box-shadow-z-value)
266
+ sass(theme.$disable-dark-elevation): theme.$dark-theme-surface-color;
267
+ else: map.get( theme.$dark-elevation-colors, $outline-raisable-box-shadow-z-value)
268
268
  ) !default;
269
269
 
270
270
  /// The text color to use in dark themes when `theme="outline"`
@@ -87,18 +87,18 @@ $z-index: utils.$temporary-element-z-index !default;
87
87
 
88
88
  /// The default background color for a dialog.
89
89
  /// @type Color
90
+ // prettier-ignore
90
91
  $background-color: if(
91
- theme.$disable-dark-elevation,
92
- theme.theme-get-var(surface-color),
93
- null
92
+ sass(theme.$disable-dark-elevation): theme.theme-get-var(surface-color);
93
+ else: null
94
94
  ) !default;
95
95
 
96
96
  /// The default text color for a dialog.
97
97
  /// @type Color
98
+ // prettier-ignore
98
99
  $color: if(
99
- theme.$disable-dark-elevation,
100
- theme.theme-get-var(text-primary-color),
101
- null
100
+ sass(theme.$disable-dark-elevation): theme.theme-get-var(text-primary-color);
101
+ else: null,
102
102
  ) !default;
103
103
 
104
104
  /// The `min-width` to apply to all `Dialog`s.
@@ -125,8 +125,12 @@ $variables: (
125
125
  /// @param {String} position [null] - This should be one of `left`, `right`,
126
126
  /// `top`, `bottom`
127
127
  @mixin border-style($position: null) {
128
- $property: if(not $position, border, "border-#{$position}");
129
- $var-name: if(not $position, size, border-size);
128
+ $property: border;
129
+ $var-name: size;
130
+ @if $position {
131
+ $property: "border-#{$position}";
132
+ $var-name: border-size;
133
+ }
130
134
 
131
135
  #{$property}: get-var($var-name) solid get-var(color);
132
136
  }
@@ -2,8 +2,27 @@ import { type ChangeEvent, type HTMLAttributes, type InputHTMLAttributes, type R
2
2
  import { type BoxProps } from "../box/Box.js";
3
3
  import { type MenuProps } from "../menu/Menu.js";
4
4
  import { type LabelA11y, type PropsWithRef, type RequireAtLeastOne } from "../types.js";
5
+ import { type OptionProps } from "./Option.js";
5
6
  import { type TextFieldContainerProps } from "./TextFieldContainer.js";
6
7
  import { type UserAgentAutocompleteProps } from "./types.js";
8
+ /**
9
+ * @since 6.5.0
10
+ */
11
+ export interface GetSelectedOptionChildrenOptions<Value extends string = string> {
12
+ value: "" | Value;
13
+ /**
14
+ * The option will be undefined if there is no value or matching option.
15
+ */
16
+ option: OptionProps | undefined;
17
+ /**
18
+ * This is a pass-through of the {@link SelectProps.placeholder}
19
+ */
20
+ placeholder?: ReactNode;
21
+ /**
22
+ * This is a pass-through of the {@link SelectProps.selectedOptionProps}
23
+ */
24
+ children?: ReactNode;
25
+ }
7
26
  /**
8
27
  * This is a convenience type for casting the `event.currentTarget.value` of a
9
28
  * `Select`'s change event to be union of available values.
@@ -145,6 +164,11 @@ export interface SelectProps<Value extends string> extends Omit<TextFieldContain
145
164
  * @defaultValue `false`
146
165
  */
147
166
  disableSelectedIcon?: boolean;
167
+ /**
168
+ * @since 6.5.0
169
+ * @defaultValue `({ children, option, placeholder }) => children ?? (option?.children || placeholder)`
170
+ */
171
+ getSelectedOptionChildren?: (options: GetSelectedOptionChildrenOptions<Value>) => ReactNode;
148
172
  /**
149
173
  * This should be the available `Option`s for the select to choose from. It
150
174
  * can also contain `OptGroup` or any other elements but only clicking on an
@@ -22,6 +22,12 @@ const EMPTY_STRING = "";
22
22
  const noop = ()=>{
23
23
  // do nothing
24
24
  };
25
+ /**
26
+ * @since 6.5.0
27
+ */ const defaultGetSelectedOptionChildren = (options)=>{
28
+ const { children, option, placeholder } = options;
29
+ return children ?? (option?.children || placeholder);
30
+ };
25
31
  /**
26
32
  * **Client Component**
27
33
  *
@@ -53,7 +59,7 @@ const noop = ()=>{
53
59
  * @see {@link https://react-md.dev/components/select | Select Demos}
54
60
  * @since 6.0.0 Rewritten with a new API.
55
61
  */ export function Select(props) {
56
- const { id, form, autoCompleteValue, autoComplete = autoCompleteValue, name = autoCompleteValue, className, onClick, onFocus, onKeyDown, inputRef: propInputRef, inputProps, containerRef, placeholder, menuProps = {}, label, labelProps = {}, selectedOptionProps, icon: propIcon, value, defaultValue, theme: propTheme, onChange = noop, rightAddon: propRightAddon, active = false, required, selectedIconAfter = false, disableOptionAddon = false, disableSelectedIcon = false, children, ...remaining } = props;
62
+ const { id, form, autoCompleteValue, autoComplete = autoCompleteValue, name = autoCompleteValue, className, onClick, onFocus, onKeyDown, inputRef: propInputRef, inputProps, containerRef, placeholder, menuProps = {}, label, labelProps = {}, selectedOptionProps, getSelectedOptionChildren = defaultGetSelectedOptionChildren, icon: propIcon, value, defaultValue, theme: propTheme, onChange = noop, rightAddon: propRightAddon, active = false, required, selectedIconAfter = false, disableOptionAddon = false, disableSelectedIcon = false, children, ...remaining } = props;
57
63
  const { dense, error, disabled } = props;
58
64
  const comboboxId = useEnsuredId(id, "select");
59
65
  const inputId = useEnsuredId(inputProps?.id, "select-value");
@@ -117,9 +123,14 @@ const noop = ()=>{
117
123
  children: [
118
124
  /*#__PURE__*/ _jsx(SelectedOption, {
119
125
  option: currentOption,
120
- placeholder: placeholder,
121
126
  disableAddon: disableOptionAddon,
122
- ...selectedOptionProps
127
+ ...selectedOptionProps,
128
+ children: getSelectedOptionChildren({
129
+ value: currentValue,
130
+ option: currentOption,
131
+ placeholder,
132
+ children: selectedOptionProps?.children
133
+ })
123
134
  }),
124
135
  /*#__PURE__*/ _jsx("input", {
125
136
  "aria-hidden": true,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/form/Select.tsx"],"sourcesContent":["\"use client\";\n\nimport { cnb } from \"cnbuilder\";\nimport {\n type ChangeEvent,\n type HTMLAttributes,\n type InputHTMLAttributes,\n type ReactElement,\n type ReactNode,\n type Ref,\n useCallback,\n useRef,\n useState,\n} from \"react\";\n\nimport { type BoxProps } from \"../box/Box.js\";\nimport { IconRotator } from \"../icon/IconRotator.js\";\nimport { getIcon } from \"../icon/config.js\";\nimport { type MenuProps } from \"../menu/Menu.js\";\nimport { KeyboardMovementProvider } from \"../movement/useKeyboardMovementProvider.js\";\nimport {\n type LabelA11y,\n type PropsWithRef,\n type RequireAtLeastOne,\n} from \"../types.js\";\nimport { useEnsuredId } from \"../useEnsuredId.js\";\nimport { useEnsuredRef } from \"../useEnsuredRef.js\";\nimport { Listbox } from \"./Listbox.js\";\nimport { SelectedOption } from \"./SelectedOption.js\";\nimport {\n TextFieldContainer,\n type TextFieldContainerProps,\n} from \"./TextFieldContainer.js\";\nimport { getFormConfig } from \"./formConfig.js\";\nimport { label as labelStyles } from \"./labelStyles.js\";\nimport { select } from \"./selectStyles.js\";\nimport { extractOptionsFromChildren } from \"./selectUtils.js\";\nimport { textField } from \"./textFieldStyles.js\";\nimport { type UserAgentAutocompleteProps } from \"./types.js\";\nimport { useFormReset } from \"./useFormReset.js\";\nimport { useSelectCombobox } from \"./useSelectCombobox.js\";\nimport { triggerManualChangeEvent } from \"./utils.js\";\n\nconst EMPTY_STRING = \"\" as const;\nconst noop = (): void => {\n // do nothing\n};\n\n/**\n * This is a convenience type for casting the `event.currentTarget.value` of a\n * `Select`'s change event to be union of available values.\n *\n * Note: The change event does not provide any sort of validation on the value\n * so automation tools like Cypress, Playwright, or Selenium might set an\n * invalid value. This also does not work for numbers, so you will need to\n * implement that yourself.\n *\n * @example Simple Usage\n * ```tsx\n * import { Select, type SelectChangeEvent } from \"@react-md/core/form/Select\";\n * import { Option } from \"@react-md/core/form/Option\";\n * import type { ReactElement } from \"react\";\n *\n * type Value = \"\" | \"a\" | \"b\" | \"c\" | \"d\";\n *\n * function Example(): ReactElement {\n * const [value, setValue] = useState<Value>(\"\");\n *\n * const handleChange = (event: SelectChangeEvent<Value>): void => {\n * // No type error!\n * // `event.currentTarget.value`'s type is `Value` instead of a generic `string`\n * setValue(event.currentTarget.value);\n * };\n *\n * return (\n * <Select\n * label=\"Label\"\n * value={value}\n * onChange={handleChange}\n * >\n * <Option value=\"a\">First</Option>\n * <Option value=\"b\">Second</Option>\n * <Option value=\"c\">Third</Option>\n * <Option value=\"d\">Fourth</Option>\n * </Select>\n * );\n * }\n * ```\n * @since 6.0.0\n */\nexport type SelectChangeEvent<Value extends string> =\n ChangeEvent<HTMLInputElement> & { currentTarget: { value: Value } };\n\n/**\n * @since 6.0.0 Rewritten with a new API.\n */\nexport interface SelectProps<Value extends string>\n extends\n Omit<TextFieldContainerProps, \"label\">,\n Pick<InputHTMLAttributes<HTMLInputElement>, \"form\" | \"required\">,\n UserAgentAutocompleteProps {\n /**\n * @defaultValue `\"select-\" + useId()`\n */\n id?: string;\n\n /**\n * Optional placeholder text or element to render while no options have been\n * selected.\n */\n placeholder?: ReactNode;\n\n /**\n * Set this to a custom dropdown icon or `null` to not render a dropdown icon.\n *\n * @defaultValue `getIcon(\"dropdown\")`\n */\n icon?: ReactNode;\n\n /**\n * Set this value to fully control the value of the select component. The\n * {@link onChange} handler **must** also be provided if this prop exists.\n */\n value?: Value;\n\n /**\n * An optional default value when the value of the select component is\n * uncontrolled.\n *\n * @defaultValue `\"\"`\n */\n defaultValue?: Value;\n\n /** @see {@link SelectChangeEvent} */\n onChange?: (event: SelectChangeEvent<Value>) => void;\n\n /**\n * An optional floating label to display like other form fields.\n */\n label?: ReactNode;\n\n /**\n * Optional props to pass to the `<span>` that surrounds the {@link label}\n */\n labelProps?: PropsWithRef<HTMLAttributes<HTMLSpanElement>>;\n\n /**\n * An optional ref to pass to the hidden `<input type=\"text\" />` element that\n * stores the current value. This is really only useful if you'd like to keep\n * this component uncontrolled and access the value through\n * `inputRef.current.value`.\n */\n inputRef?: Ref<HTMLInputElement>;\n inputProps?: InputHTMLAttributes<HTMLInputElement>;\n\n /**\n * A ref for the container `<div>` element.\n */\n containerRef?: Ref<HTMLDivElement>;\n\n /**\n * Any additional props to provide to the `Menu` component that renders all\n * the `Option`s.\n *\n * The menu will always have these default values unless explicity\n * overwritten by this prop:\n *\n * - `aria-labelledby={label ? labelId : id}` -- this will be undefined if\n * `aria-label` is provided\n * - `anchor={BELOW_CENTER_ANCHOR}`\n * - `width=\"min\"`\n */\n menuProps?: PropsWithRef<\n Omit<MenuProps, \"visible\" | \"onRequestClose\" | \"fixedTo\">\n >;\n\n /**\n * Any additional props to pass to the div that contains the current visible\n * option.\n */\n selectedOptionProps?: BoxProps;\n\n /**\n * Set this to `true` if all the `Option` components should display the\n * selected icon after the children instead of before.\n *\n * @see {@link disableSelectedIcon} to remove the selected icon instead.\n *\n * @defaultValue `false`\n */\n selectedIconAfter?: boolean;\n\n /**\n * Set this to `true` to prevent the current option from rendering the\n * `leftAddon` in the `TextFieldContainer`.\n *\n * @defaultValue `false`\n */\n disableOptionAddon?: boolean;\n\n /**\n * Set this to `true` to update all the `Option` components to no longer\n * render an icon while selected.\n *\n * @defaultValue `false`\n */\n disableSelectedIcon?: boolean;\n\n /**\n * This should be the available `Option`s for the select to choose from. It\n * can also contain `OptGroup` or any other elements but only clicking on an\n * `Option` component will update the value.\n */\n children: ReactNode;\n}\n\n/**\n * **Client Component**\n *\n * @example Simple Example\n * ```tsx\n * import { Option } from \"@react-md/core/form/Option\";\n * import { Select } from \"@react-md/core/form/Select\";\n * import { useState, type ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const [value, setValue] = useState(\"\");\n *\n * return (\n * <Select\n * label=\"Select\"\n * value={value}\n * onChange={(event) => setValue(event.currentTarget.value)}\n * placeholder=\"Select a value\"\n * >\n * <Option value=\"a\">Option 1</Option>\n * <Option value=\"b\">Option 2</Option>\n * <Option value=\"c\">Option 3</Option>\n * <Option value=\"d\">Option 4</Option>\n * </Select>\n * );\n * }\n * ```\n *\n * @see {@link https://react-md.dev/components/select | Select Demos}\n * @since 6.0.0 Rewritten with a new API.\n */\nexport function Select<Value extends string>(\n props: RequireAtLeastOne<SelectProps<Value>, \"label\" | keyof LabelA11y>\n): ReactElement {\n const {\n id,\n form,\n autoCompleteValue,\n autoComplete = autoCompleteValue,\n name = autoCompleteValue,\n className,\n onClick,\n onFocus,\n onKeyDown,\n inputRef: propInputRef,\n inputProps,\n containerRef,\n placeholder,\n menuProps = {},\n label,\n labelProps = {},\n selectedOptionProps,\n icon: propIcon,\n value,\n defaultValue,\n theme: propTheme,\n onChange = noop,\n rightAddon: propRightAddon,\n active = false,\n required,\n selectedIconAfter = false,\n disableOptionAddon = false,\n disableSelectedIcon = false,\n children,\n ...remaining\n } = props;\n const { dense, error, disabled } = props;\n\n const comboboxId = useEnsuredId(id, \"select\");\n const inputId = useEnsuredId(inputProps?.id, \"select-value\");\n const selectLabelId = useEnsuredId(labelProps.id, \"select-label\");\n const labelId = label ? selectLabelId : undefined;\n\n const [localValue, setLocalValue] = useState(() => {\n if (typeof defaultValue !== \"undefined\") {\n return defaultValue;\n }\n\n return typeof value !== \"undefined\" ? value : EMPTY_STRING;\n });\n const currentValue = typeof value === \"undefined\" ? localValue : value;\n const initialValue = useRef(currentValue);\n const { options, currentOption } = extractOptionsFromChildren(\n children,\n currentValue\n );\n\n const { visible, comboboxProps, movementContext, getMenuProps } =\n useSelectCombobox({\n form,\n value: currentValue,\n values: options,\n onClick,\n onFocus,\n onKeyDown,\n disabled,\n popupId: menuProps.id,\n popupRef: menuProps.ref,\n comboboxId,\n comboboxRef: containerRef,\n });\n\n const [inputRef, inputRefCallback] = useEnsuredRef(propInputRef);\n useFormReset({\n form,\n elementRef: inputRef,\n defaultValue: initialValue.current,\n });\n\n const icon = getIcon(\"dropdown\", propIcon);\n const theme = getFormConfig(\"theme\", propTheme);\n let rightAddon = propRightAddon;\n if (typeof rightAddon === \"undefined\" && icon) {\n rightAddon = <IconRotator rotated={visible}>{icon}</IconRotator>;\n }\n\n const { ref: listboxRef, ...listboxProps } = getMenuProps(menuProps);\n let listboxLabelledBy = menuProps[\"aria-labelledby\"];\n const listboxLabel = menuProps[\"aria-label\"];\n if (!listboxLabel && !listboxLabelledBy) {\n listboxLabelledBy = labelId || comboboxId;\n }\n\n return (\n <KeyboardMovementProvider value={movementContext}>\n <TextFieldContainer\n aria-labelledby={labelId}\n {...remaining}\n {...comboboxProps}\n label={!!label}\n theme={theme}\n active={active || visible}\n className={cnb(\"rmd-select-container\", className)}\n rightAddon={rightAddon}\n >\n <SelectedOption\n option={currentOption}\n placeholder={placeholder}\n disableAddon={disableOptionAddon}\n {...selectedOptionProps}\n />\n <input\n aria-hidden\n id={inputId}\n ref={inputRefCallback}\n type=\"text\"\n autoComplete={autoComplete}\n name={name}\n tabIndex={-1}\n disabled={disabled}\n required={required}\n placeholder=\" \"\n {...inputProps}\n value={value}\n defaultValue={defaultValue}\n className={cnb(select({ theme }), textField())}\n onChange={(event) => {\n onChange(event as SelectChangeEvent<Value>);\n if (typeof value !== \"undefined\") {\n return;\n }\n\n const nextValue = event.currentTarget.value;\n const nextOption = options.find((option) => option === nextValue);\n\n setLocalValue(nextOption ?? initialValue.current);\n }}\n />\n {label && (\n <span\n {...labelProps}\n id={labelId}\n className={labelStyles({\n dense,\n error,\n disabled,\n active: active || visible,\n floating: true,\n floatingActive: !!placeholder || !!currentOption,\n className: labelProps.className,\n })}\n >\n {label}\n </span>\n )}\n </TextFieldContainer>\n <Listbox\n {...listboxProps}\n aria-label={listboxLabel}\n aria-labelledby={listboxLabelledBy as string}\n nodeRef={listboxRef}\n value={currentValue}\n setValue={useCallback(\n (option: \"\" | Value) => {\n triggerManualChangeEvent(inputRef.current, option);\n },\n [inputRef]\n )}\n selectedIconAfter={selectedIconAfter}\n disableSelectedIcon={disableSelectedIcon}\n >\n {children}\n </Listbox>\n </KeyboardMovementProvider>\n );\n}\n"],"names":["cnb","useCallback","useRef","useState","IconRotator","getIcon","KeyboardMovementProvider","useEnsuredId","useEnsuredRef","Listbox","SelectedOption","TextFieldContainer","getFormConfig","label","labelStyles","select","extractOptionsFromChildren","textField","useFormReset","useSelectCombobox","triggerManualChangeEvent","EMPTY_STRING","noop","Select","props","id","form","autoCompleteValue","autoComplete","name","className","onClick","onFocus","onKeyDown","inputRef","propInputRef","inputProps","containerRef","placeholder","menuProps","labelProps","selectedOptionProps","icon","propIcon","value","defaultValue","theme","propTheme","onChange","rightAddon","propRightAddon","active","required","selectedIconAfter","disableOptionAddon","disableSelectedIcon","children","remaining","dense","error","disabled","comboboxId","inputId","selectLabelId","labelId","undefined","localValue","setLocalValue","currentValue","initialValue","options","currentOption","visible","comboboxProps","movementContext","getMenuProps","values","popupId","popupRef","ref","comboboxRef","inputRefCallback","elementRef","current","rotated","listboxRef","listboxProps","listboxLabelledBy","listboxLabel","aria-labelledby","option","disableAddon","input","aria-hidden","type","tabIndex","event","nextValue","currentTarget","nextOption","find","span","floating","floatingActive","aria-label","nodeRef","setValue"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/form/Select.tsx"],"sourcesContent":["\"use client\";\n\nimport { cnb } from \"cnbuilder\";\nimport {\n type ChangeEvent,\n type HTMLAttributes,\n type InputHTMLAttributes,\n type ReactElement,\n type ReactNode,\n type Ref,\n useCallback,\n useRef,\n useState,\n} from \"react\";\n\nimport { type BoxProps } from \"../box/Box.js\";\nimport { IconRotator } from \"../icon/IconRotator.js\";\nimport { getIcon } from \"../icon/config.js\";\nimport { type MenuProps } from \"../menu/Menu.js\";\nimport { KeyboardMovementProvider } from \"../movement/useKeyboardMovementProvider.js\";\nimport {\n type LabelA11y,\n type PropsWithRef,\n type RequireAtLeastOne,\n} from \"../types.js\";\nimport { useEnsuredId } from \"../useEnsuredId.js\";\nimport { useEnsuredRef } from \"../useEnsuredRef.js\";\nimport { Listbox } from \"./Listbox.js\";\nimport { type OptionProps } from \"./Option.js\";\nimport { SelectedOption } from \"./SelectedOption.js\";\nimport {\n TextFieldContainer,\n type TextFieldContainerProps,\n} from \"./TextFieldContainer.js\";\nimport { getFormConfig } from \"./formConfig.js\";\nimport { label as labelStyles } from \"./labelStyles.js\";\nimport { select } from \"./selectStyles.js\";\nimport { extractOptionsFromChildren } from \"./selectUtils.js\";\nimport { textField } from \"./textFieldStyles.js\";\nimport { type UserAgentAutocompleteProps } from \"./types.js\";\nimport { useFormReset } from \"./useFormReset.js\";\nimport { useSelectCombobox } from \"./useSelectCombobox.js\";\nimport { triggerManualChangeEvent } from \"./utils.js\";\n\nconst EMPTY_STRING = \"\" as const;\nconst noop = (): void => {\n // do nothing\n};\n\n/**\n * @since 6.5.0\n */\nexport interface GetSelectedOptionChildrenOptions<\n Value extends string = string,\n> {\n value: \"\" | Value;\n\n /**\n * The option will be undefined if there is no value or matching option.\n */\n option: OptionProps | undefined;\n\n /**\n * This is a pass-through of the {@link SelectProps.placeholder}\n */\n placeholder?: ReactNode;\n\n /**\n * This is a pass-through of the {@link SelectProps.selectedOptionProps}\n */\n children?: ReactNode;\n}\n\n/**\n * @since 6.5.0\n */\nconst defaultGetSelectedOptionChildren = (\n options: GetSelectedOptionChildrenOptions\n): ReactNode => {\n const { children, option, placeholder } = options;\n\n return children ?? (option?.children || placeholder);\n};\n\n/**\n * This is a convenience type for casting the `event.currentTarget.value` of a\n * `Select`'s change event to be union of available values.\n *\n * Note: The change event does not provide any sort of validation on the value\n * so automation tools like Cypress, Playwright, or Selenium might set an\n * invalid value. This also does not work for numbers, so you will need to\n * implement that yourself.\n *\n * @example Simple Usage\n * ```tsx\n * import { Select, type SelectChangeEvent } from \"@react-md/core/form/Select\";\n * import { Option } from \"@react-md/core/form/Option\";\n * import type { ReactElement } from \"react\";\n *\n * type Value = \"\" | \"a\" | \"b\" | \"c\" | \"d\";\n *\n * function Example(): ReactElement {\n * const [value, setValue] = useState<Value>(\"\");\n *\n * const handleChange = (event: SelectChangeEvent<Value>): void => {\n * // No type error!\n * // `event.currentTarget.value`'s type is `Value` instead of a generic `string`\n * setValue(event.currentTarget.value);\n * };\n *\n * return (\n * <Select\n * label=\"Label\"\n * value={value}\n * onChange={handleChange}\n * >\n * <Option value=\"a\">First</Option>\n * <Option value=\"b\">Second</Option>\n * <Option value=\"c\">Third</Option>\n * <Option value=\"d\">Fourth</Option>\n * </Select>\n * );\n * }\n * ```\n * @since 6.0.0\n */\nexport type SelectChangeEvent<Value extends string> =\n ChangeEvent<HTMLInputElement> & { currentTarget: { value: Value } };\n\n/**\n * @since 6.0.0 Rewritten with a new API.\n */\nexport interface SelectProps<Value extends string>\n extends\n Omit<TextFieldContainerProps, \"label\">,\n Pick<InputHTMLAttributes<HTMLInputElement>, \"form\" | \"required\">,\n UserAgentAutocompleteProps {\n /**\n * @defaultValue `\"select-\" + useId()`\n */\n id?: string;\n\n /**\n * Optional placeholder text or element to render while no options have been\n * selected.\n */\n placeholder?: ReactNode;\n\n /**\n * Set this to a custom dropdown icon or `null` to not render a dropdown icon.\n *\n * @defaultValue `getIcon(\"dropdown\")`\n */\n icon?: ReactNode;\n\n /**\n * Set this value to fully control the value of the select component. The\n * {@link onChange} handler **must** also be provided if this prop exists.\n */\n value?: Value;\n\n /**\n * An optional default value when the value of the select component is\n * uncontrolled.\n *\n * @defaultValue `\"\"`\n */\n defaultValue?: Value;\n\n /** @see {@link SelectChangeEvent} */\n onChange?: (event: SelectChangeEvent<Value>) => void;\n\n /**\n * An optional floating label to display like other form fields.\n */\n label?: ReactNode;\n\n /**\n * Optional props to pass to the `<span>` that surrounds the {@link label}\n */\n labelProps?: PropsWithRef<HTMLAttributes<HTMLSpanElement>>;\n\n /**\n * An optional ref to pass to the hidden `<input type=\"text\" />` element that\n * stores the current value. This is really only useful if you'd like to keep\n * this component uncontrolled and access the value through\n * `inputRef.current.value`.\n */\n inputRef?: Ref<HTMLInputElement>;\n inputProps?: InputHTMLAttributes<HTMLInputElement>;\n\n /**\n * A ref for the container `<div>` element.\n */\n containerRef?: Ref<HTMLDivElement>;\n\n /**\n * Any additional props to provide to the `Menu` component that renders all\n * the `Option`s.\n *\n * The menu will always have these default values unless explicity\n * overwritten by this prop:\n *\n * - `aria-labelledby={label ? labelId : id}` -- this will be undefined if\n * `aria-label` is provided\n * - `anchor={BELOW_CENTER_ANCHOR}`\n * - `width=\"min\"`\n */\n menuProps?: PropsWithRef<\n Omit<MenuProps, \"visible\" | \"onRequestClose\" | \"fixedTo\">\n >;\n\n /**\n * Any additional props to pass to the div that contains the current visible\n * option.\n */\n selectedOptionProps?: BoxProps;\n\n /**\n * Set this to `true` if all the `Option` components should display the\n * selected icon after the children instead of before.\n *\n * @see {@link disableSelectedIcon} to remove the selected icon instead.\n *\n * @defaultValue `false`\n */\n selectedIconAfter?: boolean;\n\n /**\n * Set this to `true` to prevent the current option from rendering the\n * `leftAddon` in the `TextFieldContainer`.\n *\n * @defaultValue `false`\n */\n disableOptionAddon?: boolean;\n\n /**\n * Set this to `true` to update all the `Option` components to no longer\n * render an icon while selected.\n *\n * @defaultValue `false`\n */\n disableSelectedIcon?: boolean;\n\n /**\n * @since 6.5.0\n * @defaultValue `({ children, option, placeholder }) => children ?? (option?.children || placeholder)`\n */\n getSelectedOptionChildren?: (\n options: GetSelectedOptionChildrenOptions<Value>\n ) => ReactNode;\n\n /**\n * This should be the available `Option`s for the select to choose from. It\n * can also contain `OptGroup` or any other elements but only clicking on an\n * `Option` component will update the value.\n */\n children: ReactNode;\n}\n\n/**\n * **Client Component**\n *\n * @example Simple Example\n * ```tsx\n * import { Option } from \"@react-md/core/form/Option\";\n * import { Select } from \"@react-md/core/form/Select\";\n * import { useState, type ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const [value, setValue] = useState(\"\");\n *\n * return (\n * <Select\n * label=\"Select\"\n * value={value}\n * onChange={(event) => setValue(event.currentTarget.value)}\n * placeholder=\"Select a value\"\n * >\n * <Option value=\"a\">Option 1</Option>\n * <Option value=\"b\">Option 2</Option>\n * <Option value=\"c\">Option 3</Option>\n * <Option value=\"d\">Option 4</Option>\n * </Select>\n * );\n * }\n * ```\n *\n * @see {@link https://react-md.dev/components/select | Select Demos}\n * @since 6.0.0 Rewritten with a new API.\n */\nexport function Select<Value extends string>(\n props: RequireAtLeastOne<SelectProps<Value>, \"label\" | keyof LabelA11y>\n): ReactElement {\n const {\n id,\n form,\n autoCompleteValue,\n autoComplete = autoCompleteValue,\n name = autoCompleteValue,\n className,\n onClick,\n onFocus,\n onKeyDown,\n inputRef: propInputRef,\n inputProps,\n containerRef,\n placeholder,\n menuProps = {},\n label,\n labelProps = {},\n selectedOptionProps,\n getSelectedOptionChildren = defaultGetSelectedOptionChildren,\n icon: propIcon,\n value,\n defaultValue,\n theme: propTheme,\n onChange = noop,\n rightAddon: propRightAddon,\n active = false,\n required,\n selectedIconAfter = false,\n disableOptionAddon = false,\n disableSelectedIcon = false,\n children,\n ...remaining\n } = props;\n const { dense, error, disabled } = props;\n\n const comboboxId = useEnsuredId(id, \"select\");\n const inputId = useEnsuredId(inputProps?.id, \"select-value\");\n const selectLabelId = useEnsuredId(labelProps.id, \"select-label\");\n const labelId = label ? selectLabelId : undefined;\n\n const [localValue, setLocalValue] = useState(() => {\n if (typeof defaultValue !== \"undefined\") {\n return defaultValue;\n }\n\n return typeof value !== \"undefined\" ? value : EMPTY_STRING;\n });\n const currentValue = typeof value === \"undefined\" ? localValue : value;\n const initialValue = useRef(currentValue);\n const { options, currentOption } = extractOptionsFromChildren(\n children,\n currentValue\n );\n\n const { visible, comboboxProps, movementContext, getMenuProps } =\n useSelectCombobox({\n form,\n value: currentValue,\n values: options,\n onClick,\n onFocus,\n onKeyDown,\n disabled,\n popupId: menuProps.id,\n popupRef: menuProps.ref,\n comboboxId,\n comboboxRef: containerRef,\n });\n\n const [inputRef, inputRefCallback] = useEnsuredRef(propInputRef);\n useFormReset({\n form,\n elementRef: inputRef,\n defaultValue: initialValue.current,\n });\n\n const icon = getIcon(\"dropdown\", propIcon);\n const theme = getFormConfig(\"theme\", propTheme);\n let rightAddon = propRightAddon;\n if (typeof rightAddon === \"undefined\" && icon) {\n rightAddon = <IconRotator rotated={visible}>{icon}</IconRotator>;\n }\n\n const { ref: listboxRef, ...listboxProps } = getMenuProps(menuProps);\n let listboxLabelledBy = menuProps[\"aria-labelledby\"];\n const listboxLabel = menuProps[\"aria-label\"];\n if (!listboxLabel && !listboxLabelledBy) {\n listboxLabelledBy = labelId || comboboxId;\n }\n\n return (\n <KeyboardMovementProvider value={movementContext}>\n <TextFieldContainer\n aria-labelledby={labelId}\n {...remaining}\n {...comboboxProps}\n label={!!label}\n theme={theme}\n active={active || visible}\n className={cnb(\"rmd-select-container\", className)}\n rightAddon={rightAddon}\n >\n <SelectedOption\n option={currentOption}\n disableAddon={disableOptionAddon}\n {...selectedOptionProps}\n >\n {getSelectedOptionChildren({\n value: currentValue,\n option: currentOption,\n placeholder,\n children: selectedOptionProps?.children,\n })}\n </SelectedOption>\n <input\n aria-hidden\n id={inputId}\n ref={inputRefCallback}\n type=\"text\"\n autoComplete={autoComplete}\n name={name}\n tabIndex={-1}\n disabled={disabled}\n required={required}\n placeholder=\" \"\n {...inputProps}\n value={value}\n defaultValue={defaultValue}\n className={cnb(select({ theme }), textField())}\n onChange={(event) => {\n onChange(event as SelectChangeEvent<Value>);\n if (typeof value !== \"undefined\") {\n return;\n }\n\n const nextValue = event.currentTarget.value;\n const nextOption = options.find((option) => option === nextValue);\n\n setLocalValue(nextOption ?? initialValue.current);\n }}\n />\n {label && (\n <span\n {...labelProps}\n id={labelId}\n className={labelStyles({\n dense,\n error,\n disabled,\n active: active || visible,\n floating: true,\n floatingActive: !!placeholder || !!currentOption,\n className: labelProps.className,\n })}\n >\n {label}\n </span>\n )}\n </TextFieldContainer>\n <Listbox\n {...listboxProps}\n aria-label={listboxLabel}\n aria-labelledby={listboxLabelledBy as string}\n nodeRef={listboxRef}\n value={currentValue}\n setValue={useCallback(\n (option: \"\" | Value) => {\n triggerManualChangeEvent(inputRef.current, option);\n },\n [inputRef]\n )}\n selectedIconAfter={selectedIconAfter}\n disableSelectedIcon={disableSelectedIcon}\n >\n {children}\n </Listbox>\n </KeyboardMovementProvider>\n );\n}\n"],"names":["cnb","useCallback","useRef","useState","IconRotator","getIcon","KeyboardMovementProvider","useEnsuredId","useEnsuredRef","Listbox","SelectedOption","TextFieldContainer","getFormConfig","label","labelStyles","select","extractOptionsFromChildren","textField","useFormReset","useSelectCombobox","triggerManualChangeEvent","EMPTY_STRING","noop","defaultGetSelectedOptionChildren","options","children","option","placeholder","Select","props","id","form","autoCompleteValue","autoComplete","name","className","onClick","onFocus","onKeyDown","inputRef","propInputRef","inputProps","containerRef","menuProps","labelProps","selectedOptionProps","getSelectedOptionChildren","icon","propIcon","value","defaultValue","theme","propTheme","onChange","rightAddon","propRightAddon","active","required","selectedIconAfter","disableOptionAddon","disableSelectedIcon","remaining","dense","error","disabled","comboboxId","inputId","selectLabelId","labelId","undefined","localValue","setLocalValue","currentValue","initialValue","currentOption","visible","comboboxProps","movementContext","getMenuProps","values","popupId","popupRef","ref","comboboxRef","inputRefCallback","elementRef","current","rotated","listboxRef","listboxProps","listboxLabelledBy","listboxLabel","aria-labelledby","disableAddon","input","aria-hidden","type","tabIndex","event","nextValue","currentTarget","nextOption","find","span","floating","floatingActive","aria-label","nodeRef","setValue"],"mappings":"AAAA;;AAEA,SAASA,GAAG,QAAQ,YAAY;AAChC,SAOEC,WAAW,EACXC,MAAM,EACNC,QAAQ,QACH,QAAQ;AAGf,SAASC,WAAW,QAAQ,yBAAyB;AACrD,SAASC,OAAO,QAAQ,oBAAoB;AAE5C,SAASC,wBAAwB,QAAQ,6CAA6C;AAMtF,SAASC,YAAY,QAAQ,qBAAqB;AAClD,SAASC,aAAa,QAAQ,sBAAsB;AACpD,SAASC,OAAO,QAAQ,eAAe;AAEvC,SAASC,cAAc,QAAQ,sBAAsB;AACrD,SACEC,kBAAkB,QAEb,0BAA0B;AACjC,SAASC,aAAa,QAAQ,kBAAkB;AAChD,SAASC,SAASC,WAAW,QAAQ,mBAAmB;AACxD,SAASC,MAAM,QAAQ,oBAAoB;AAC3C,SAASC,0BAA0B,QAAQ,mBAAmB;AAC9D,SAASC,SAAS,QAAQ,uBAAuB;AAEjD,SAASC,YAAY,QAAQ,oBAAoB;AACjD,SAASC,iBAAiB,QAAQ,yBAAyB;AAC3D,SAASC,wBAAwB,QAAQ,aAAa;AAEtD,MAAMC,eAAe;AACrB,MAAMC,OAAO;AACX,aAAa;AACf;AA0BA;;CAEC,GACD,MAAMC,mCAAmC,CACvCC;IAEA,MAAM,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,WAAW,EAAE,GAAGH;IAE1C,OAAOC,YAAaC,CAAAA,QAAQD,YAAYE,WAAU;AACpD;AAkLA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BC,GACD,OAAO,SAASC,OACdC,KAAuE;IAEvE,MAAM,EACJC,EAAE,EACFC,IAAI,EACJC,iBAAiB,EACjBC,eAAeD,iBAAiB,EAChCE,OAAOF,iBAAiB,EACxBG,SAAS,EACTC,OAAO,EACPC,OAAO,EACPC,SAAS,EACTC,UAAUC,YAAY,EACtBC,UAAU,EACVC,YAAY,EACZf,WAAW,EACXgB,YAAY,CAAC,CAAC,EACd9B,KAAK,EACL+B,aAAa,CAAC,CAAC,EACfC,mBAAmB,EACnBC,4BAA4BvB,gCAAgC,EAC5DwB,MAAMC,QAAQ,EACdC,KAAK,EACLC,YAAY,EACZC,OAAOC,SAAS,EAChBC,WAAW/B,IAAI,EACfgC,YAAYC,cAAc,EAC1BC,SAAS,KAAK,EACdC,QAAQ,EACRC,oBAAoB,KAAK,EACzBC,qBAAqB,KAAK,EAC1BC,sBAAsB,KAAK,EAC3BnC,QAAQ,EACR,GAAGoC,WACJ,GAAGhC;IACJ,MAAM,EAAEiC,KAAK,EAAEC,KAAK,EAAEC,QAAQ,EAAE,GAAGnC;IAEnC,MAAMoC,aAAa1D,aAAauB,IAAI;IACpC,MAAMoC,UAAU3D,aAAakC,YAAYX,IAAI;IAC7C,MAAMqC,gBAAgB5D,aAAaqC,WAAWd,EAAE,EAAE;IAClD,MAAMsC,UAAUvD,QAAQsD,gBAAgBE;IAExC,MAAM,CAACC,YAAYC,cAAc,GAAGpE,SAAS;QAC3C,IAAI,OAAO+C,iBAAiB,aAAa;YACvC,OAAOA;QACT;QAEA,OAAO,OAAOD,UAAU,cAAcA,QAAQ5B;IAChD;IACA,MAAMmD,eAAe,OAAOvB,UAAU,cAAcqB,aAAarB;IACjE,MAAMwB,eAAevE,OAAOsE;IAC5B,MAAM,EAAEhD,OAAO,EAAEkD,aAAa,EAAE,GAAG1D,2BACjCS,UACA+C;IAGF,MAAM,EAAEG,OAAO,EAAEC,aAAa,EAAEC,eAAe,EAAEC,YAAY,EAAE,GAC7D3D,kBAAkB;QAChBY;QACAkB,OAAOuB;QACPO,QAAQvD;QACRY;QACAC;QACAC;QACA0B;QACAgB,SAASrC,UAAUb,EAAE;QACrBmD,UAAUtC,UAAUuC,GAAG;QACvBjB;QACAkB,aAAazC;IACf;IAEF,MAAM,CAACH,UAAU6C,iBAAiB,GAAG5E,cAAcgC;IACnDtB,aAAa;QACXa;QACAsD,YAAY9C;QACZW,cAAcuB,aAAaa,OAAO;IACpC;IAEA,MAAMvC,OAAO1C,QAAQ,YAAY2C;IACjC,MAAMG,QAAQvC,cAAc,SAASwC;IACrC,IAAIE,aAAaC;IACjB,IAAI,OAAOD,eAAe,eAAeP,MAAM;QAC7CO,2BAAa,KAAClD;YAAYmF,SAASZ;sBAAU5B;;IAC/C;IAEA,MAAM,EAAEmC,KAAKM,UAAU,EAAE,GAAGC,cAAc,GAAGX,aAAanC;IAC1D,IAAI+C,oBAAoB/C,SAAS,CAAC,kBAAkB;IACpD,MAAMgD,eAAehD,SAAS,CAAC,aAAa;IAC5C,IAAI,CAACgD,gBAAgB,CAACD,mBAAmB;QACvCA,oBAAoBtB,WAAWH;IACjC;IAEA,qBACE,MAAC3D;QAAyB2C,OAAO4B;;0BAC/B,MAAClE;gBACCiF,mBAAiBxB;gBAChB,GAAGP,SAAS;gBACZ,GAAGe,aAAa;gBACjB/D,OAAO,CAAC,CAACA;gBACTsC,OAAOA;gBACPK,QAAQA,UAAUmB;gBAClBxC,WAAWnC,IAAI,wBAAwBmC;gBACvCmB,YAAYA;;kCAEZ,KAAC5C;wBACCgB,QAAQgD;wBACRmB,cAAclC;wBACb,GAAGd,mBAAmB;kCAEtBC,0BAA0B;4BACzBG,OAAOuB;4BACP9C,QAAQgD;4BACR/C;4BACAF,UAAUoB,qBAAqBpB;wBACjC;;kCAEF,KAACqE;wBACCC,aAAW;wBACXjE,IAAIoC;wBACJgB,KAAKE;wBACLY,MAAK;wBACL/D,cAAcA;wBACdC,MAAMA;wBACN+D,UAAU,CAAC;wBACXjC,UAAUA;wBACVP,UAAUA;wBACV9B,aAAY;wBACX,GAAGc,UAAU;wBACdQ,OAAOA;wBACPC,cAAcA;wBACdf,WAAWnC,IAAIe,OAAO;4BAAEoC;wBAAM,IAAIlC;wBAClCoC,UAAU,CAAC6C;4BACT7C,SAAS6C;4BACT,IAAI,OAAOjD,UAAU,aAAa;gCAChC;4BACF;4BAEA,MAAMkD,YAAYD,MAAME,aAAa,CAACnD,KAAK;4BAC3C,MAAMoD,aAAa7E,QAAQ8E,IAAI,CAAC,CAAC5E,SAAWA,WAAWyE;4BAEvD5B,cAAc8B,cAAc5B,aAAaa,OAAO;wBAClD;;oBAEDzE,uBACC,KAAC0F;wBACE,GAAG3D,UAAU;wBACdd,IAAIsC;wBACJjC,WAAWrB,YAAY;4BACrBgD;4BACAC;4BACAC;4BACAR,QAAQA,UAAUmB;4BAClB6B,UAAU;4BACVC,gBAAgB,CAAC,CAAC9E,eAAe,CAAC,CAAC+C;4BACnCvC,WAAWS,WAAWT,SAAS;wBACjC;kCAECtB;;;;0BAIP,KAACJ;gBACE,GAAGgF,YAAY;gBAChBiB,cAAYf;gBACZC,mBAAiBF;gBACjBiB,SAASnB;gBACTvC,OAAOuB;gBACPoC,UAAU3G,YACR,CAACyB;oBACCN,yBAAyBmB,SAAS+C,OAAO,EAAE5D;gBAC7C,GACA;oBAACa;iBAAS;gBAEZmB,mBAAmBA;gBACnBE,qBAAqBA;0BAEpBnC;;;;AAIT"}
@@ -1,4 +1,4 @@
1
- import { type ReactElement, type ReactNode } from "react";
1
+ import { type ReactElement } from "react";
2
2
  import { type BoxProps } from "../box/Box.js";
3
3
  import { type OptionProps } from "./Option.js";
4
4
  /**
@@ -7,7 +7,6 @@ import { type OptionProps } from "./Option.js";
7
7
  */
8
8
  export interface SelectedOptionProps extends BoxProps {
9
9
  option: OptionProps | undefined;
10
- placeholder?: ReactNode;
11
10
  disableAddon: boolean;
12
11
  }
13
12
  /**
@@ -9,8 +9,8 @@ import { textField } from "./textFieldStyles.js";
9
9
  * @since 6.0.0
10
10
  * @internal
11
11
  */ export function SelectedOption(props) {
12
- const { disableAddon, option, className, disableWrap = true, disablePadding = true, placeholder, ...remaining } = props;
13
- let children = option?.children || placeholder;
12
+ const { disableAddon, option, className, disableWrap = true, disablePadding = true, ...remaining } = props;
13
+ let { children } = remaining;
14
14
  // when the children are a string or number, wrap it in additional span so
15
15
  // that overflow can be ellipsis-ed
16
16
  if (typeof children === "string" || typeof children === "number") {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/form/SelectedOption.tsx"],"sourcesContent":["import { cnb } from \"cnbuilder\";\nimport { type ReactElement, type ReactNode } from \"react\";\n\nimport { Box, type BoxProps } from \"../box/Box.js\";\nimport { cssUtils } from \"../cssUtils.js\";\nimport { type OptionProps } from \"./Option.js\";\nimport { textField } from \"./textFieldStyles.js\";\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport interface SelectedOptionProps extends BoxProps {\n option: OptionProps | undefined;\n placeholder?: ReactNode;\n disableAddon: boolean;\n}\n\n/**\n * This component is used to render the current option.\n *\n * @since 6.0.0\n * @internal\n */\nexport function SelectedOption(props: SelectedOptionProps): ReactElement {\n const {\n disableAddon,\n option,\n className,\n disableWrap = true,\n disablePadding = true,\n placeholder,\n ...remaining\n } = props;\n\n let children = option?.children || placeholder;\n // when the children are a string or number, wrap it in additional span so\n // that overflow can be ellipsis-ed\n if (typeof children === \"string\" || typeof children === \"number\") {\n children = (\n <span className={cssUtils({ textOverflow: \"ellipsis\" })}>{children}</span>\n );\n }\n\n return (\n <Box\n {...remaining}\n className={cnb(\"rmd-selected-option\", textField(), className)}\n disableWrap={disableWrap}\n disablePadding={disablePadding}\n >\n {!disableAddon && option?.leftAddon}\n {children}\n </Box>\n );\n}\n"],"names":["cnb","Box","cssUtils","textField","SelectedOption","props","disableAddon","option","className","disableWrap","disablePadding","placeholder","remaining","children","span","textOverflow","leftAddon"],"mappings":";AAAA,SAASA,GAAG,QAAQ,YAAY;AAGhC,SAASC,GAAG,QAAuB,gBAAgB;AACnD,SAASC,QAAQ,QAAQ,iBAAiB;AAE1C,SAASC,SAAS,QAAQ,uBAAuB;AAYjD;;;;;CAKC,GACD,OAAO,SAASC,eAAeC,KAA0B;IACvD,MAAM,EACJC,YAAY,EACZC,MAAM,EACNC,SAAS,EACTC,cAAc,IAAI,EAClBC,iBAAiB,IAAI,EACrBC,WAAW,EACX,GAAGC,WACJ,GAAGP;IAEJ,IAAIQ,WAAWN,QAAQM,YAAYF;IACnC,0EAA0E;IAC1E,mCAAmC;IACnC,IAAI,OAAOE,aAAa,YAAY,OAAOA,aAAa,UAAU;QAChEA,yBACE,KAACC;YAAKN,WAAWN,SAAS;gBAAEa,cAAc;YAAW;sBAAKF;;IAE9D;IAEA,qBACE,MAACZ;QACE,GAAGW,SAAS;QACbJ,WAAWR,IAAI,uBAAuBG,aAAaK;QACnDC,aAAaA;QACbC,gBAAgBA;;YAEf,CAACJ,gBAAgBC,QAAQS;YACzBH;;;AAGP"}
1
+ {"version":3,"sources":["../../src/form/SelectedOption.tsx"],"sourcesContent":["import { cnb } from \"cnbuilder\";\nimport { type ReactElement } from \"react\";\n\nimport { Box, type BoxProps } from \"../box/Box.js\";\nimport { cssUtils } from \"../cssUtils.js\";\nimport { type OptionProps } from \"./Option.js\";\nimport { textField } from \"./textFieldStyles.js\";\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport interface SelectedOptionProps extends BoxProps {\n option: OptionProps | undefined;\n disableAddon: boolean;\n}\n\n/**\n * This component is used to render the current option.\n *\n * @since 6.0.0\n * @internal\n */\nexport function SelectedOption(props: SelectedOptionProps): ReactElement {\n const {\n disableAddon,\n option,\n className,\n disableWrap = true,\n disablePadding = true,\n ...remaining\n } = props;\n\n let { children } = remaining;\n // when the children are a string or number, wrap it in additional span so\n // that overflow can be ellipsis-ed\n if (typeof children === \"string\" || typeof children === \"number\") {\n children = (\n <span className={cssUtils({ textOverflow: \"ellipsis\" })}>{children}</span>\n );\n }\n\n return (\n <Box\n {...remaining}\n className={cnb(\"rmd-selected-option\", textField(), className)}\n disableWrap={disableWrap}\n disablePadding={disablePadding}\n >\n {!disableAddon && option?.leftAddon}\n {children}\n </Box>\n );\n}\n"],"names":["cnb","Box","cssUtils","textField","SelectedOption","props","disableAddon","option","className","disableWrap","disablePadding","remaining","children","span","textOverflow","leftAddon"],"mappings":";AAAA,SAASA,GAAG,QAAQ,YAAY;AAGhC,SAASC,GAAG,QAAuB,gBAAgB;AACnD,SAASC,QAAQ,QAAQ,iBAAiB;AAE1C,SAASC,SAAS,QAAQ,uBAAuB;AAWjD;;;;;CAKC,GACD,OAAO,SAASC,eAAeC,KAA0B;IACvD,MAAM,EACJC,YAAY,EACZC,MAAM,EACNC,SAAS,EACTC,cAAc,IAAI,EAClBC,iBAAiB,IAAI,EACrB,GAAGC,WACJ,GAAGN;IAEJ,IAAI,EAAEO,QAAQ,EAAE,GAAGD;IACnB,0EAA0E;IAC1E,mCAAmC;IACnC,IAAI,OAAOC,aAAa,YAAY,OAAOA,aAAa,UAAU;QAChEA,yBACE,KAACC;YAAKL,WAAWN,SAAS;gBAAEY,cAAc;YAAW;sBAAKF;;IAE9D;IAEA,qBACE,MAACX;QACE,GAAGU,SAAS;QACbH,WAAWR,IAAI,uBAAuBG,aAAaK;QACnDC,aAAaA;QACbC,gBAAgBA;;YAEf,CAACJ,gBAAgBC,QAAQQ;YACzBH;;;AAGP"}
@@ -91,13 +91,14 @@ $large-size: 2rem !default;
91
91
  @include hidden-input-styles(true);
92
92
 
93
93
  .rmd-input-toggle {
94
+ $focus-selector: "&:has(:focus-visible)";
95
+ @if utils.$disable-has-selectors or utils.$disable-focus-visible {
96
+ $focus-selector: "&:focus-within";
97
+ }
98
+
94
99
  @include icon.set-var(color, currentcolor);
95
100
  @include interaction.surface(
96
- $focus-selector: if(
97
- utils.$disable-has-selectors or utils.$disable-focus-visible,
98
- "&:focus-within",
99
- "&:has(:focus-visible)"
100
- ),
101
+ $focus-selector: $focus-selector,
101
102
  $keyboard-only-focus: utils.$disable-has-selectors or
102
103
  utils.$disable-focus-visible,
103
104
  $disabled-selector: "&--disabled",
@@ -151,8 +151,8 @@ $variables: (
151
151
  @include use-var(background-color, active-background-color);
152
152
  @include use-var(padding, active-padding);
153
153
 
154
- transform: scale($floating-scale)
155
- translate(get-var(floating-active-x), get-var(floating-active-y));
154
+ transform: translate(get-var(floating-active-x), get-var(floating-active-y))
155
+ scale($floating-scale);
156
156
  // need to add the `transform-origin` because of the scaling applied.
157
157
  // it'll change the position based on the size of the label otherwise
158
158
  transform-origin: 0 0;
@@ -28,33 +28,42 @@ $disable-floating: false !default;
28
28
  @if not $disable-floating {
29
29
  &--floating {
30
30
  @include label.set-var(floating-active-y, -50%);
31
- @include label.set-var(active-padding, 0 label.$floating-padding);
32
- @include label.set-var(
33
- active-background-color,
34
- theme.theme-get-var(background-color)
35
- );
36
31
  @include label.set-var(
37
32
  floating-active-x,
38
33
  text-field.get-var(padding-left)
39
34
  );
35
+
36
+ .rmd-fieldset:has(:focus-within) & {
37
+ @include label.active-styles;
38
+ }
40
39
  }
41
40
 
42
41
  @if not base.$form-disable-filled-theme {
43
- @include text-field.set-var(
44
- padding-left,
45
- text-field.get-var(filled-padding)
46
- );
42
+ &--floating-filled {
43
+ @include text-field.set-var(
44
+ padding-left,
45
+ text-field.get-var(filled-padding)
46
+ );
47
+ @include label.set-var(floating-active-y, -100%);
48
+ }
47
49
  }
48
50
 
49
51
  @if not base.$form-disable-underlined-theme {
50
- @include text-field.set-var(
51
- padding-left,
52
- text-field.get-var(underlined-padding)
53
- );
52
+ &--floating-underline {
53
+ @include text-field.set-var(
54
+ padding-left,
55
+ text-field.get-var(underlined-padding)
56
+ );
57
+ }
54
58
  }
55
59
 
56
60
  @if not base.$form-disable-outlined-theme {
57
61
  &--floating-outline {
62
+ @include label.set-var(active-padding, 0 label.$floating-padding);
63
+ @include label.set-var(
64
+ active-background-color,
65
+ theme.theme-get-var(background-color)
66
+ );
58
67
  @include text-field.set-var(
59
68
  padding-left,
60
69
  text-field.get-var(outlined-padding)
@@ -634,11 +634,13 @@ $variables: (
634
634
  }
635
635
 
636
636
  .rmd-slider-thumb {
637
- @include use-var(
638
- background-color,
639
- if($track-color, color, active-color),
640
- if($track-color, theme.theme-color-var-fallback($track-color), null)
641
- );
637
+ $color-name: active-color;
638
+ $color-fallback: null;
639
+ @if $track-color {
640
+ $color-name: color;
641
+ $color-fallback: theme.theme-color-var-fallback($track-color);
642
+ }
643
+ @include use-var(background-color, $color-name, $color-fallback);
642
644
 
643
645
  border-radius: $thumb-border-radius;
644
646
  height: $thumb-size;
@@ -80,10 +80,10 @@ $track-light-background-color: colors.$grey-400 !default;
80
80
 
81
81
  /// The background color to apply to the `SwitchTrack` in the dark theme.
82
82
  /// @type Color
83
+ // prettier-ignore
83
84
  $track-dark-background-color: if(
84
- theme.$disable-dark-elevation,
85
- $track-light-background-color,
86
- map.get(theme.$dark-elevation-colors, 24)
85
+ sass(theme.$disable-dark-elevation): $track-light-background-color;
86
+ else: map.get(theme.$dark-elevation-colors, 24)
87
87
  ) !default;
88
88
 
89
89
  /// The default background color to apply to the `SwitchTrack`.
@@ -274,8 +274,10 @@ $variables: (track-background-color, ball-background-color);
274
274
  z-index: 0;
275
275
  }
276
276
 
277
- $active-selector: ".rmd-switch__input:checked + &" +
278
- if($disable-menu-item-switch, "", ", &--active");
277
+ $active-selector: ".rmd-switch__input:checked + &";
278
+ @if not $disable-menu-item-switch {
279
+ $active-selector: $active-selector + ", &--active";
280
+ }
279
281
 
280
282
  #{$active-selector} {
281
283
  $offset: $ball-size + $ball-offset;
@@ -271,6 +271,11 @@ $variables: (
271
271
  /// @param {any} fallback [null] - An optional fallback value
272
272
  /// @returns {String} a `var()` statement
273
273
  @function get-var($name, $fallback: null) {
274
+ @if $name == underlined-padding and not $underlined-padding and not $fallback
275
+ {
276
+ $fallback: 0px;
277
+ }
278
+
274
279
  $var: utils.get-var-name($variables, $name, "text-field");
275
280
  @if $fallback {
276
281
  @return var(#{$var}, #{$fallback});
@@ -502,17 +507,14 @@ $variables: (
502
507
  &--filled {
503
508
  @include theme.theme-set-var(background-color, get-var(filled-color));
504
509
  @include theme.theme-use-var(background-color);
505
- @include set-var(padding-left, $filled-padding);
506
- @include set-var(padding-right, $filled-padding);
510
+ @include set-var(padding-left, get-var(filled-padding));
511
+ @include set-var(padding-right, get-var(filled-padding));
507
512
  @if not label.$disable-floating {
508
- @include label.set-var(
509
- floating-active-x,
510
- $filled-padding + label.$floating-padding
511
- );
513
+ @include label.set-var(floating-active-x, get-var(filled-padding));
512
514
  }
513
515
 
514
516
  @if not $disable-addon {
515
- @include set-var(addon-left-offset, $filled-padding);
517
+ @include set-var(addon-left-offset, get-var(filled-padding));
516
518
  }
517
519
  }
518
520
  }
@@ -529,8 +531,8 @@ $variables: (
529
531
  border-bottom-width: $border-width;
530
532
 
531
533
  @if $underlined-padding {
532
- @include set-var(padding-left, $underlined-padding);
533
- @include set-var(padding-right, $underlined-padding);
534
+ @include set-var(padding-left, get-var(underlined-padding));
535
+ @include set-var(padding-right, get-var(underlined-padding));
534
536
  }
535
537
 
536
538
  &::after {
@@ -594,8 +596,8 @@ $variables: (
594
596
 
595
597
  @if not $disable-addon {
596
598
  $addon-offset: calc(
597
- #{icon.get-var(size) +
598
- if($underlined-padding, "#{$underlined-padding} + ", "")} +
599
+ icon.get-var(size) +
600
+ get-var(underlined-padding) +
599
601
  $underlined-label-left-offset *
600
602
  2
601
603
  );
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -2,7 +2,7 @@ import { type FormTheme, type LabelClassNameOptions } from "./types.js";
2
2
  /**
3
3
  * @since 6.4.0
4
4
  */
5
- export type LegendLabelClassNameOptions = Pick<LabelClassNameOptions, "active" | "gap" | "dense" | "error" | "stacked" | "disabled" | "reversed">;
5
+ export type LegendLabelClassNameOptions = Pick<LabelClassNameOptions, "active" | "gap" | "error" | "stacked" | "disabled" | "reversed">;
6
6
  /**
7
7
  * @since 6.4.0
8
8
  */
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/form/legendStyles.ts"],"sourcesContent":["import { cnb } from \"cnbuilder\";\n\nimport { cssUtils } from \"../cssUtils.js\";\nimport { bem } from \"../utils/bem.js\";\nimport { getFormConfig } from \"./formConfig.js\";\nimport { label } from \"./labelStyles.js\";\nimport { type FormTheme, type LabelClassNameOptions } from \"./types.js\";\n\nconst styles = bem(\"rmd-legend\");\n\n/**\n * @since 6.4.0\n */\nexport type LegendLabelClassNameOptions = Pick<\n LabelClassNameOptions,\n \"active\" | \"gap\" | \"dense\" | \"error\" | \"stacked\" | \"disabled\" | \"reversed\"\n>;\n\n/**\n * @since 6.4.0\n */\nexport interface LegendClassNameOptions extends LegendLabelClassNameOptions {\n className?: string;\n\n /**\n * @defaultValue `false`\n */\n srOnly?: boolean;\n\n /**\n * Set this to `true` to make the `<legend>` have the styles of a floating label.\n * This requires the parent `<fieldset>` to have the `floatingLegend` flag\n * enabled.\n *\n * @defaultValue `false`\n */\n floating?: boolean;\n\n /**\n * This will only apply if {@link floating} is `true`.\n *\n * @see {@link FormTheme}\n * @defaultValue `getFormConfig(\"theme\")`\n */\n theme?: FormTheme;\n\n /**\n * This will only apply if {@link floating} is `true`.\n *\n * @see {@link LabelClassNameOptions.active}\n * @defaultValue `false`\n */\n active?: boolean;\n\n /**\n * This will only apply if {@link floating} is `true`.\n *\n * @see {@link LabelClassNameOptions.gap}\n * @defaultValue `false`\n */\n gap?: boolean;\n\n /**\n * This will only apply if {@link floating} is `true`.\n *\n * @see {@link LabelClassNameOptions.disabled}\n * @defaultValue `false`\n */\n disabled?: boolean;\n\n /**\n * This will only apply if {@link floating} is `true`.\n *\n * @see {@link LabelClassNameOptions.dense}\n * @defaultValue `false`\n */\n dense?: boolean;\n\n /**\n * This will only apply if {@link floating} is `true`.\n *\n * @see {@link LabelClassNameOptions.error}\n * @defaultValue `false`\n */\n error?: boolean;\n\n /**\n * This will only apply if {@link floating} is `true`.\n *\n * @see {@link LabelClassNameOptions.stacked}\n * @defaultValue `false`\n */\n stacked?: boolean;\n\n /**\n * This will only apply if {@link floating} is `true`.\n *\n * @see {@link LabelClassNameOptions.reversed}\n * @defaultValue `false`\n */\n reversed?: boolean;\n}\n\n/**\n * @since 6.4.0\n */\nexport function legend(options: LegendClassNameOptions = {}): string {\n const {\n className,\n srOnly,\n floating,\n theme = getFormConfig(\"theme\"),\n ...labelOptions\n } = options;\n\n return cnb(\n styles({\n floating,\n \"floating-filled\": floating && theme === \"filled\",\n \"floating-underline\": floating && theme === \"underline\",\n \"floating-outline\": floating && theme === \"outline\",\n }),\n floating &&\n label({\n ...labelOptions,\n floating: true,\n floatingActive: true,\n }),\n cssUtils({ srOnly }),\n className\n );\n}\n"],"names":["cnb","cssUtils","bem","getFormConfig","label","styles","legend","options","className","srOnly","floating","theme","labelOptions","floatingActive"],"mappings":"AAAA,SAASA,GAAG,QAAQ,YAAY;AAEhC,SAASC,QAAQ,QAAQ,iBAAiB;AAC1C,SAASC,GAAG,QAAQ,kBAAkB;AACtC,SAASC,aAAa,QAAQ,kBAAkB;AAChD,SAASC,KAAK,QAAQ,mBAAmB;AAGzC,MAAMC,SAASH,IAAI;AA+FnB;;CAEC,GACD,OAAO,SAASI,OAAOC,UAAkC,CAAC,CAAC;IACzD,MAAM,EACJC,SAAS,EACTC,MAAM,EACNC,QAAQ,EACRC,QAAQR,cAAc,QAAQ,EAC9B,GAAGS,cACJ,GAAGL;IAEJ,OAAOP,IACLK,OAAO;QACLK;QACA,mBAAmBA,YAAYC,UAAU;QACzC,sBAAsBD,YAAYC,UAAU;QAC5C,oBAAoBD,YAAYC,UAAU;IAC5C,IACAD,YACEN,MAAM;QACJ,GAAGQ,YAAY;QACfF,UAAU;QACVG,gBAAgB;IAClB,IACFZ,SAAS;QAAEQ;IAAO,IAClBD;AAEJ"}
1
+ {"version":3,"sources":["../../src/form/legendStyles.ts"],"sourcesContent":["import { cnb } from \"cnbuilder\";\n\nimport { cssUtils } from \"../cssUtils.js\";\nimport { bem } from \"../utils/bem.js\";\nimport { getFormConfig } from \"./formConfig.js\";\nimport { label } from \"./labelStyles.js\";\nimport { type FormTheme, type LabelClassNameOptions } from \"./types.js\";\n\nconst styles = bem(\"rmd-legend\");\n\n/**\n * @since 6.4.0\n */\nexport type LegendLabelClassNameOptions = Pick<\n LabelClassNameOptions,\n \"active\" | \"gap\" | \"error\" | \"stacked\" | \"disabled\" | \"reversed\"\n>;\n\n/**\n * @since 6.4.0\n */\nexport interface LegendClassNameOptions extends LegendLabelClassNameOptions {\n className?: string;\n\n /**\n * @defaultValue `false`\n */\n srOnly?: boolean;\n\n /**\n * Set this to `true` to make the `<legend>` have the styles of a floating label.\n * This requires the parent `<fieldset>` to have the `floatingLegend` flag\n * enabled.\n *\n * @defaultValue `false`\n */\n floating?: boolean;\n\n /**\n * This will only apply if {@link floating} is `true`.\n *\n * @see {@link FormTheme}\n * @defaultValue `getFormConfig(\"theme\")`\n */\n theme?: FormTheme;\n\n /**\n * This will only apply if {@link floating} is `true`.\n *\n * @see {@link LabelClassNameOptions.active}\n * @defaultValue `false`\n */\n active?: boolean;\n\n /**\n * This will only apply if {@link floating} is `true`.\n *\n * @see {@link LabelClassNameOptions.gap}\n * @defaultValue `false`\n */\n gap?: boolean;\n\n /**\n * This will only apply if {@link floating} is `true`.\n *\n * @see {@link LabelClassNameOptions.disabled}\n * @defaultValue `false`\n */\n disabled?: boolean;\n\n /**\n * This will only apply if {@link floating} is `true`.\n *\n * @see {@link LabelClassNameOptions.dense}\n * @defaultValue `false`\n */\n dense?: boolean;\n\n /**\n * This will only apply if {@link floating} is `true`.\n *\n * @see {@link LabelClassNameOptions.error}\n * @defaultValue `false`\n */\n error?: boolean;\n\n /**\n * This will only apply if {@link floating} is `true`.\n *\n * @see {@link LabelClassNameOptions.stacked}\n * @defaultValue `false`\n */\n stacked?: boolean;\n\n /**\n * This will only apply if {@link floating} is `true`.\n *\n * @see {@link LabelClassNameOptions.reversed}\n * @defaultValue `false`\n */\n reversed?: boolean;\n}\n\n/**\n * @since 6.4.0\n */\nexport function legend(options: LegendClassNameOptions = {}): string {\n const {\n className,\n srOnly,\n floating,\n theme = getFormConfig(\"theme\"),\n ...labelOptions\n } = options;\n\n return cnb(\n styles({\n floating,\n \"floating-filled\": floating && theme === \"filled\",\n \"floating-underline\": floating && theme === \"underline\",\n \"floating-outline\": floating && theme === \"outline\",\n }),\n floating &&\n label({\n ...labelOptions,\n floating: true,\n floatingActive: true,\n }),\n cssUtils({ srOnly }),\n className\n );\n}\n"],"names":["cnb","cssUtils","bem","getFormConfig","label","styles","legend","options","className","srOnly","floating","theme","labelOptions","floatingActive"],"mappings":"AAAA,SAASA,GAAG,QAAQ,YAAY;AAEhC,SAASC,QAAQ,QAAQ,iBAAiB;AAC1C,SAASC,GAAG,QAAQ,kBAAkB;AACtC,SAASC,aAAa,QAAQ,kBAAkB;AAChD,SAASC,KAAK,QAAQ,mBAAmB;AAGzC,MAAMC,SAASH,IAAI;AA+FnB;;CAEC,GACD,OAAO,SAASI,OAAOC,UAAkC,CAAC,CAAC;IACzD,MAAM,EACJC,SAAS,EACTC,MAAM,EACNC,QAAQ,EACRC,QAAQR,cAAc,QAAQ,EAC9B,GAAGS,cACJ,GAAGL;IAEJ,OAAOP,IACLK,OAAO;QACLK;QACA,mBAAmBA,YAAYC,UAAU;QACzC,sBAAsBD,YAAYC,UAAU;QAC5C,oBAAoBD,YAAYC,UAAU;IAC5C,IACAD,YACEN,MAAM;QACJ,GAAGQ,YAAY;QACfF,UAAU;QACVG,gBAAgB;IAClB,IACFZ,SAAS;QAAEQ;IAAO,IAClBD;AAEJ"}
@@ -533,7 +533,7 @@ $variables: (
533
533
  /// @include surface;
534
534
  /// }
535
535
  ///
536
- /// @param {String} $focus-selector ["&:focus" + if(utils.disable-focus-visible, "", "-visible")] -
536
+ /// @param {String} $focus-selector ["&:focus" + if(sass(not utils.disable-focus-visible): "-visible"; else: "")] -
537
537
  /// The selector to use indicating the element has been focused.
538
538
  /// @param {Boolean} $keyboard-only-focus [utils.$disable-focus-visible] -
539
539
  /// @param {String} $disabled-selector ["&:disabled"] - The selector to use
@@ -552,7 +552,8 @@ $variables: (
552
552
  /// @param {Boolean} $disable-background [$disable-focus-background] - Set to
553
553
  /// `true` to disable the focus background color styles.
554
554
  @mixin surface(
555
- $focus-selector: "&:focus" + if(utils.$disable-focus-visible, "", "-visible"),
555
+ $focus-selector: "&:focus" +
556
+ if(sass(not utils.$disable-focus-visible): "-visible" ; else: ""),
556
557
  $keyboard-only-focus: utils.$disable-focus-visible,
557
558
  $disabled-selector: "&:disabled",
558
559
  $clickable: true,
@@ -586,7 +587,8 @@ $variables: (
586
587
 
587
588
  transition-duration: transition.$linear-duration;
588
589
  transition-property:
589
- background-color, if($focus-box-shadow, box-shadow, outline-color);
590
+ background-color,
591
+ if(sass(not $focus-box-shadow): outline-color; else: box-shadow);
590
592
  transition-timing-function: transition.$linear-timing-function;
591
593
  }
592
594
 
@@ -152,10 +152,10 @@ $light-theme-color: a11y.contrast-color($light-theme-background-color) !default;
152
152
 
153
153
  /// The background-color to use in the dark theme.
154
154
  /// @type Color
155
+ // prettier-ignore
155
156
  $dark-theme-background-color: if(
156
- theme.$disable-dark-elevation,
157
- $light-theme-background-color,
158
- map.get(theme.$dark-elevation-colors, $elevation)
157
+ sass(theme.$disable-dark-elevation): $light-theme-background-color;
158
+ else: map.get(theme.$dark-elevation-colors, $elevation)
159
159
  ) !default;
160
160
 
161
161
  /// The text color to use in the dark theme.
@@ -368,12 +368,11 @@ $variables: (
368
368
  }
369
369
 
370
370
  @include utils.rtl {
371
- $button-selector: "&__button" +
372
- if(
373
- $disable-tablist-scroll-button-vertical,
374
- "",
375
- ":where(:not(.rmd-tablist-button__button--v))"
376
- );
371
+ $button-selector: "&__button";
372
+ @if not $disable-tablist-scroll-button-vertical {
373
+ $button-selector: $button-selector +
374
+ ":where(:not(.rmd-tablist-button__button--v))";
375
+ }
377
376
 
378
377
  &--left {
379
378
  left: auto;
@@ -183,5 +183,7 @@ $_linear-channel-values: (
183
183
  $light-contrast: _contrast($background-color, $light-color);
184
184
  $dark-contrast: _contrast($background-color, $dark-color);
185
185
 
186
- @return if($light-contrast > $dark-contrast, $light-color, $dark-color);
186
+ @return if(
187
+ sass($light-contrast > $dark-contrast): $light-color; else: $dark-color
188
+ );
187
189
  }
@@ -222,10 +222,10 @@ $dark-theme-background-color: #121212 !default;
222
222
  /// color depending on its elevation.
223
223
  ///
224
224
  /// @type Color
225
+ // prettier-ignore
225
226
  $dark-theme-surface-color: if(
226
- $disable-dark-elevation,
227
- colors.$grey-800,
228
- null
227
+ sass($disable-dark-elevation): colors.$grey-800;
228
+ else: null
229
229
  ) !default;
230
230
 
231
231
  /// The primary text color when using the dark theme.
@@ -250,7 +250,7 @@ $dark-theme-text-disabled-color: rgba($dark-theme-inverse-color, 0.38) !default;
250
250
  /// @param {Color} dark-color - The dark theme color
251
251
  /// @returns {Color} The correct color depending on the `$color-scheme`
252
252
  @function get-default-color($light-color, $dark-color) {
253
- @return if($color-scheme == dark, $dark-color, $light-color);
253
+ @return if(sass($color-scheme == dark): $dark-color; else: $light-color);
254
254
  }
255
255
 
256
256
  /// The default background color
@@ -519,7 +519,7 @@ $theme-variables: (
519
519
  /// @param {any} value - The value to maybe return
520
520
  /// @return {any} the `$value` if it was theme var, otherwise null
521
521
  @function theme-color-var-fallback($value) {
522
- @return if(is-theme-color-var($value), $value, null);
522
+ @return if(sass(is-theme-color-var($value)): $value; else: null);
523
523
  }
524
524
 
525
525
  /// @param {Number} z-value - The dark elevation value
@@ -777,11 +777,10 @@ $theme-variables: (
777
777
 
778
778
  @if not $current-color-index {
779
779
  @if not $fallback-color {
780
- $fallback: if(
781
- $fallback-name,
782
- "the '$#{$fallback-name}' variable",
783
- "a fallback color"
784
- );
780
+ $fallback: "a fallback color";
781
+ @if $fallback-name {
782
+ $fallback: "the '$#{$fallback-name}' variable";
783
+ }
785
784
 
786
785
  $error-msg: "Invalid material design color: '#{$color}'. If this was intentional because your app does " +
787
786
  "not use material design colors, set #{$fallback} instead to get a correct color for the provided swatch: " +
@@ -794,8 +793,13 @@ $theme-variables: (
794
793
  }
795
794
  }
796
795
 
796
+ // prettier-ignore
797
+ $current-suffixes: if(
798
+ sass(not $accent): colors.$primary-suffixes;
799
+ else: colors.$accent-suffixes
800
+ );
797
801
  $suffixes: utils.validate(
798
- if($accent, colors.$accent-suffixes, colors.$primary-suffixes),
802
+ $current-suffixes,
799
803
  $swatch,
800
804
  "material design color swatch"
801
805
  );
@@ -829,7 +833,7 @@ $theme-variables: (
829
833
  }
830
834
  }
831
835
 
832
- $color-name: "#{$current-color-name}#{if($accent, "-a", "")}-#{$swatch}";
836
+ $color-name: "#{$current-color-name}#{if(sass(not $accent): ""; else: "-a")}-#{$swatch}";
833
837
 
834
838
  @return map.get(colors.$color-map, $color-name);
835
839
  }
@@ -125,12 +125,11 @@ $variables: (
125
125
  /// layer behavior
126
126
  @mixin styles($disable-layer: false) {
127
127
  @if not $disable-everything {
128
+ // prettier-ignore
128
129
  $pseudo-selectors: if(
129
- not $disable-inactive-background-color,
130
- "&::before, ",
131
- ""
132
- ) +
133
- "&::after";
130
+ sass(not $disable-inactive-background-color): "&::before, ";
131
+ else: "",
132
+ ) + "&::after";
134
133
 
135
134
  @include utils.optional-layer(window-splitter, $disable-layer) {
136
135
  .rmd-window-splitter {
@@ -150,14 +149,12 @@ $variables: (
150
149
  }
151
150
 
152
151
  &::after {
153
- @include use-var(
154
- background-color,
155
- $fallback: if(
156
- $background-color == interaction.get-var(focus-color),
157
- $background-color,
158
- null
159
- )
152
+ // prettier-ignore
153
+ $fallback: if(
154
+ sass($background-color == interaction.get-var(focus-color)): $background-color;
155
+ else: null
160
156
  );
157
+ @include use-var(background-color, $fallback: $fallback);
161
158
  @include use-var(opacity);
162
159
 
163
160
  transition: opacity transition.$linear-duration;
@@ -169,14 +166,15 @@ $variables: (
169
166
  }
170
167
 
171
168
  &::before {
169
+ // prettier-ignore
170
+ $fallback: if(
171
+ sass($inactive-background-color == divider.get-var(color)): $inactive-background-color;
172
+ else: null,
173
+ );
172
174
  @include use-var(
173
175
  background-color,
174
176
  inactive-background-color,
175
- if(
176
- $inactive-background-color == divider.get-var(color),
177
- $inactive-background-color,
178
- null
179
- )
177
+ $fallback
180
178
  );
181
179
 
182
180
  pointer-events: none;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-md/core",
3
- "version": "6.4.0",
3
+ "version": "6.5.0",
4
4
  "description": "The core components and functionality for react-md.",
5
5
  "type": "module",
6
6
  "sass": "./dist/_core.scss",
@@ -80,25 +80,25 @@
80
80
  "devDependencies": {
81
81
  "@jest/globals": "^30.2.0",
82
82
  "@jest/types": "^30.2.0",
83
- "@microsoft/api-extractor": "^7.55.1",
83
+ "@microsoft/api-extractor": "^7.55.2",
84
84
  "@swc/cli": "^0.7.9",
85
- "@swc/core": "^1.15.3",
85
+ "@swc/core": "^1.15.7",
86
86
  "@testing-library/dom": "^10.4.1",
87
87
  "@testing-library/jest-dom": "^6.9.1",
88
- "@testing-library/react": "^16.3.0",
88
+ "@testing-library/react": "^16.3.1",
89
89
  "@testing-library/user-event": "^14.6.1",
90
90
  "@trivago/prettier-plugin-sort-imports": "^6.0.0",
91
91
  "@types/lodash": "^4.17.21",
92
- "@types/node": "^24.10.1",
92
+ "@types/node": "^24.10.4",
93
93
  "@types/react": "^18.3.27",
94
94
  "@types/react-dom": "^18.3.7",
95
95
  "@vitejs/plugin-react-swc": "^4.2.2",
96
96
  "@vitest/coverage-v8": "^3.2.4",
97
97
  "chokidar": "^5.0.0",
98
- "eslint": "^9.39.1",
98
+ "eslint": "^9.39.2",
99
99
  "filesize": "^11.0.13",
100
100
  "glob": "13.0.0",
101
- "jsdom": "^27.2.0",
101
+ "jsdom": "^27.3.0",
102
102
  "lodash": "^4.17.21",
103
103
  "lz-string": "^1.5.0",
104
104
  "npm-run-all2": "^8.0.2",
@@ -26,6 +26,7 @@ import {
26
26
  import { useEnsuredId } from "../useEnsuredId.js";
27
27
  import { useEnsuredRef } from "../useEnsuredRef.js";
28
28
  import { Listbox } from "./Listbox.js";
29
+ import { type OptionProps } from "./Option.js";
29
30
  import { SelectedOption } from "./SelectedOption.js";
30
31
  import {
31
32
  TextFieldContainer,
@@ -46,6 +47,41 @@ const noop = (): void => {
46
47
  // do nothing
47
48
  };
48
49
 
50
+ /**
51
+ * @since 6.5.0
52
+ */
53
+ export interface GetSelectedOptionChildrenOptions<
54
+ Value extends string = string,
55
+ > {
56
+ value: "" | Value;
57
+
58
+ /**
59
+ * The option will be undefined if there is no value or matching option.
60
+ */
61
+ option: OptionProps | undefined;
62
+
63
+ /**
64
+ * This is a pass-through of the {@link SelectProps.placeholder}
65
+ */
66
+ placeholder?: ReactNode;
67
+
68
+ /**
69
+ * This is a pass-through of the {@link SelectProps.selectedOptionProps}
70
+ */
71
+ children?: ReactNode;
72
+ }
73
+
74
+ /**
75
+ * @since 6.5.0
76
+ */
77
+ const defaultGetSelectedOptionChildren = (
78
+ options: GetSelectedOptionChildrenOptions
79
+ ): ReactNode => {
80
+ const { children, option, placeholder } = options;
81
+
82
+ return children ?? (option?.children || placeholder);
83
+ };
84
+
49
85
  /**
50
86
  * This is a convenience type for casting the `event.currentTarget.value` of a
51
87
  * `Select`'s change event to be union of available values.
@@ -206,6 +242,14 @@ export interface SelectProps<Value extends string>
206
242
  */
207
243
  disableSelectedIcon?: boolean;
208
244
 
245
+ /**
246
+ * @since 6.5.0
247
+ * @defaultValue `({ children, option, placeholder }) => children ?? (option?.children || placeholder)`
248
+ */
249
+ getSelectedOptionChildren?: (
250
+ options: GetSelectedOptionChildrenOptions<Value>
251
+ ) => ReactNode;
252
+
209
253
  /**
210
254
  * This should be the available `Option`s for the select to choose from. It
211
255
  * can also contain `OptGroup` or any other elements but only clicking on an
@@ -266,6 +310,7 @@ export function Select<Value extends string>(
266
310
  label,
267
311
  labelProps = {},
268
312
  selectedOptionProps,
313
+ getSelectedOptionChildren = defaultGetSelectedOptionChildren,
269
314
  icon: propIcon,
270
315
  value,
271
316
  defaultValue,
@@ -351,10 +396,16 @@ export function Select<Value extends string>(
351
396
  >
352
397
  <SelectedOption
353
398
  option={currentOption}
354
- placeholder={placeholder}
355
399
  disableAddon={disableOptionAddon}
356
400
  {...selectedOptionProps}
357
- />
401
+ >
402
+ {getSelectedOptionChildren({
403
+ value: currentValue,
404
+ option: currentOption,
405
+ placeholder,
406
+ children: selectedOptionProps?.children,
407
+ })}
408
+ </SelectedOption>
358
409
  <input
359
410
  aria-hidden
360
411
  id={inputId}
@@ -1,5 +1,5 @@
1
1
  import { cnb } from "cnbuilder";
2
- import { type ReactElement, type ReactNode } from "react";
2
+ import { type ReactElement } from "react";
3
3
 
4
4
  import { Box, type BoxProps } from "../box/Box.js";
5
5
  import { cssUtils } from "../cssUtils.js";
@@ -12,7 +12,6 @@ import { textField } from "./textFieldStyles.js";
12
12
  */
13
13
  export interface SelectedOptionProps extends BoxProps {
14
14
  option: OptionProps | undefined;
15
- placeholder?: ReactNode;
16
15
  disableAddon: boolean;
17
16
  }
18
17
 
@@ -29,11 +28,10 @@ export function SelectedOption(props: SelectedOptionProps): ReactElement {
29
28
  className,
30
29
  disableWrap = true,
31
30
  disablePadding = true,
32
- placeholder,
33
31
  ...remaining
34
32
  } = props;
35
33
 
36
- let children = option?.children || placeholder;
34
+ let { children } = remaining;
37
35
  // when the children are a string or number, wrap it in additional span so
38
36
  // that overflow can be ellipsis-ed
39
37
  if (typeof children === "string" || typeof children === "number") {
@@ -13,7 +13,7 @@ const styles = bem("rmd-legend");
13
13
  */
14
14
  export type LegendLabelClassNameOptions = Pick<
15
15
  LabelClassNameOptions,
16
- "active" | "gap" | "dense" | "error" | "stacked" | "disabled" | "reversed"
16
+ "active" | "gap" | "error" | "stacked" | "disabled" | "reversed"
17
17
  >;
18
18
 
19
19
  /**