@mortenbrudvik/waveui 0.8.0 → 0.9.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 (132) hide show
  1. package/README.md +231 -85
  2. package/dist/components/data-display/InfoButton.cjs +2 -0
  3. package/dist/components/data-display/InfoButton.cjs.map +1 -0
  4. package/dist/components/data-display/InfoButton.mjs +173 -0
  5. package/dist/components/data-display/InfoButton.mjs.map +1 -0
  6. package/dist/components/data-display/InfoLabel.cjs +1 -1
  7. package/dist/components/data-display/InfoLabel.cjs.map +1 -1
  8. package/dist/components/data-display/InfoLabel.mjs +39 -96
  9. package/dist/components/data-display/InfoLabel.mjs.map +1 -1
  10. package/dist/components/input/Checkbox.cjs +1 -1
  11. package/dist/components/input/Checkbox.cjs.map +1 -1
  12. package/dist/components/input/Checkbox.mjs +91 -75
  13. package/dist/components/input/Checkbox.mjs.map +1 -1
  14. package/dist/components/input/ColorPicker.parts.cjs +1 -1
  15. package/dist/components/input/ColorPicker.parts.cjs.map +1 -1
  16. package/dist/components/input/ColorPicker.parts.mjs +1 -1
  17. package/dist/components/input/ColorPicker.parts.mjs.map +1 -1
  18. package/dist/components/input/Combobox.cjs +1 -1
  19. package/dist/components/input/Combobox.cjs.map +1 -1
  20. package/dist/components/input/Combobox.expand.cjs +1 -1
  21. package/dist/components/input/Combobox.expand.cjs.map +1 -1
  22. package/dist/components/input/Combobox.expand.mjs +20 -20
  23. package/dist/components/input/Combobox.expand.mjs.map +1 -1
  24. package/dist/components/input/Combobox.mjs +143 -138
  25. package/dist/components/input/Combobox.mjs.map +1 -1
  26. package/dist/components/input/DatePicker.cjs +1 -1
  27. package/dist/components/input/DatePicker.cjs.map +1 -1
  28. package/dist/components/input/DatePicker.mjs +213 -209
  29. package/dist/components/input/DatePicker.mjs.map +1 -1
  30. package/dist/components/input/Dropdown.cjs +1 -1
  31. package/dist/components/input/Dropdown.cjs.map +1 -1
  32. package/dist/components/input/Dropdown.mjs +80 -74
  33. package/dist/components/input/Dropdown.mjs.map +1 -1
  34. package/dist/components/input/Field.cjs +1 -1
  35. package/dist/components/input/Field.cjs.map +1 -1
  36. package/dist/components/input/Field.mjs +99 -66
  37. package/dist/components/input/Field.mjs.map +1 -1
  38. package/dist/components/input/Input.cjs +1 -1
  39. package/dist/components/input/Input.cjs.map +1 -1
  40. package/dist/components/input/Input.mjs +79 -55
  41. package/dist/components/input/Input.mjs.map +1 -1
  42. package/dist/components/input/Label.cjs +1 -1
  43. package/dist/components/input/Label.cjs.map +1 -1
  44. package/dist/components/input/Label.mjs +19 -13
  45. package/dist/components/input/Label.mjs.map +1 -1
  46. package/dist/components/input/Rating.cjs +1 -1
  47. package/dist/components/input/Rating.cjs.map +1 -1
  48. package/dist/components/input/Rating.item.cjs +2 -0
  49. package/dist/components/input/Rating.item.cjs.map +1 -0
  50. package/dist/components/input/Rating.item.mjs +255 -0
  51. package/dist/components/input/Rating.item.mjs.map +1 -0
  52. package/dist/components/input/Rating.mjs +150 -151
  53. package/dist/components/input/Rating.mjs.map +1 -1
  54. package/dist/components/input/SearchBox.cjs +1 -1
  55. package/dist/components/input/SearchBox.cjs.map +1 -1
  56. package/dist/components/input/SearchBox.mjs +146 -115
  57. package/dist/components/input/SearchBox.mjs.map +1 -1
  58. package/dist/components/input/Select.cjs +1 -1
  59. package/dist/components/input/Select.cjs.map +1 -1
  60. package/dist/components/input/Select.mjs +34 -25
  61. package/dist/components/input/Select.mjs.map +1 -1
  62. package/dist/components/input/Slider.cjs +1 -1
  63. package/dist/components/input/Slider.cjs.map +1 -1
  64. package/dist/components/input/Slider.mjs +77 -54
  65. package/dist/components/input/Slider.mjs.map +1 -1
  66. package/dist/components/input/SpinButton.cjs +1 -1
  67. package/dist/components/input/SpinButton.cjs.map +1 -1
  68. package/dist/components/input/SpinButton.mjs +198 -96
  69. package/dist/components/input/SpinButton.mjs.map +1 -1
  70. package/dist/components/input/Switch.cjs +1 -1
  71. package/dist/components/input/Switch.cjs.map +1 -1
  72. package/dist/components/input/Switch.mjs +71 -55
  73. package/dist/components/input/Switch.mjs.map +1 -1
  74. package/dist/components/input/TagPicker.cjs +1 -1
  75. package/dist/components/input/TagPicker.cjs.map +1 -1
  76. package/dist/components/input/TagPicker.mjs +142 -116
  77. package/dist/components/input/TagPicker.mjs.map +1 -1
  78. package/dist/components/input/Textarea.cjs +1 -1
  79. package/dist/components/input/Textarea.cjs.map +1 -1
  80. package/dist/components/input/Textarea.mjs +28 -21
  81. package/dist/components/input/Textarea.mjs.map +1 -1
  82. package/dist/components/input/TimePicker.cjs +1 -1
  83. package/dist/components/input/TimePicker.cjs.map +1 -1
  84. package/dist/components/input/TimePicker.mjs +189 -184
  85. package/dist/components/input/TimePicker.mjs.map +1 -1
  86. package/dist/components/input/fieldLabel.cjs +2 -0
  87. package/dist/components/input/fieldLabel.cjs.map +1 -0
  88. package/dist/components/input/fieldLabel.mjs +17 -0
  89. package/dist/components/input/fieldLabel.mjs.map +1 -0
  90. package/dist/components/input/inputLook.cjs +2 -0
  91. package/dist/components/input/inputLook.cjs.map +1 -0
  92. package/dist/components/input/inputLook.mjs +28 -0
  93. package/dist/components/input/inputLook.mjs.map +1 -0
  94. package/dist/components/input/pickerStyles.cjs +1 -1
  95. package/dist/components/input/pickerStyles.cjs.map +1 -1
  96. package/dist/components/input/pickerStyles.mjs +42 -4
  97. package/dist/components/input/pickerStyles.mjs.map +1 -1
  98. package/dist/components/navigation/Menu.popover.cjs +1 -1
  99. package/dist/components/navigation/Menu.popover.cjs.map +1 -1
  100. package/dist/components/navigation/Menu.popover.mjs +10 -10
  101. package/dist/components/navigation/Menu.root.cjs +1 -1
  102. package/dist/components/navigation/Menu.root.cjs.map +1 -1
  103. package/dist/components/navigation/Menu.root.mjs +10 -10
  104. package/dist/components/overlays/Popover.cjs +1 -1
  105. package/dist/components/overlays/Popover.cjs.map +1 -1
  106. package/dist/components/overlays/Popover.mjs +203 -208
  107. package/dist/components/overlays/Popover.mjs.map +1 -1
  108. package/dist/components/overlays/Popover.shared.cjs +1 -1
  109. package/dist/components/overlays/Popover.shared.cjs.map +1 -1
  110. package/dist/components/overlays/Popover.shared.mjs +82 -77
  111. package/dist/components/overlays/Popover.shared.mjs.map +1 -1
  112. package/dist/components/provider/WaveProvider.cjs +1 -1
  113. package/dist/components/provider/WaveProvider.cjs.map +1 -1
  114. package/dist/components/provider/WaveProvider.mjs +25 -19
  115. package/dist/components/provider/WaveProvider.mjs.map +1 -1
  116. package/dist/hooks/useFieldControl.cjs.map +1 -1
  117. package/dist/hooks/useFieldControl.mjs.map +1 -1
  118. package/dist/index.cjs +1 -1
  119. package/dist/index.d.cts +805 -99
  120. package/dist/index.d.ts +805 -99
  121. package/dist/index.mjs +101 -99
  122. package/dist/lib/classNames.cjs +1 -1
  123. package/dist/lib/classNames.cjs.map +1 -1
  124. package/dist/lib/classNames.mjs +74 -66
  125. package/dist/lib/classNames.mjs.map +1 -1
  126. package/dist/lib/styles.cjs +1 -1
  127. package/dist/lib/styles.cjs.map +1 -1
  128. package/dist/lib/styles.mjs +21 -4
  129. package/dist/lib/styles.mjs.map +1 -1
  130. package/dist/styles.css +1 -1
  131. package/package.json +1 -1
  132. package/src/styles/tokens.css +13 -0
@@ -1 +1 @@
1
- {"version":3,"file":"SearchBox.mjs","names":["React","BUTTON_ONLY_KEYS","HANDLER_KEY","NAMING_KEYS","DEFAULT_CLEAR_LABEL","noop","INTERACTIVE_CONTENT","DEFAULT_DISMISS","isButtonType","type","Button","splitButtonLike","hasChildren","slotRendersContent","children","content","materialiseSlotContent","literalTextLabel","hasTextLabel","buttonProps","key","value","props","BUTTON_OWN_PROP_KEYS","iconNode","renderSlot","cn","searchBoxClassNames","placeButtonIcon","_children","resolveDismiss","node","dismiss","isElementOfType","getElementType","resolved","resolveSlot","Component","contentProps","hasButtonProps","empty","slotWrapsDefaultContent","contentChildren","DismissIcon","iconProps","SearchBox","controlledValue","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","ariaErrorMessage","ariaDetails","rest","onChange","warnDeprecated","setValue","useControllable","defaultValue","onValueChange","next","inputRef","mergedInputRef","useMergedRefs","controlRef","form","fieldProps","useFieldControl","invalidLook","isInvalidLook","dismissParts","dismissKind","warnOnce","handleClear","onClear","handleKeyDown","event","readOnly","disabled","handleRootMouseDown","input","root","target","control","slotOnClick","slotRef","slotButtonProps","hasOwnName","checksContent","labelTarget","setLabelTarget","subscribeToContent","observeTextLabel","contentHasTextLabel","hasRenderedTextLabel","namedByContent","clearRef","clearButtonProps","mergeProps","focusRing","mergedAriaDisabledClasses","clearContent","hasBefore","contentBefore","hasAfter","contentAfter","inputFocusWithin","className","composeEventHandlers","onMouseDown","SearchIcon","onKeyDown","MERGED_DISABLED_FOCUSABLE_PROPS"],"sources":["../../../src/components/input/SearchBox.tsx"],"sourcesContent":["import * as React from 'react';\nimport { getElementType, isElementOfType } from '../../lib/children';\nimport { searchBoxClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { warnDeprecated, warnOnce } from '../../lib/dev';\nimport { DismissIcon, SearchIcon } from '../../lib/icons';\nimport { hasRenderedTextLabel, hasTextLabel, observeTextLabel } from '../../lib/labelInName';\nimport { mergeProps } from '../../lib/mergeProps';\nimport {\n materialiseSlotContent,\n renderSlot,\n resolveSlot,\n slotRendersContent,\n slotWrapsDefaultContent,\n} from '../../lib/slot';\nimport { focusRing, inputFocusWithin, inputInvalidWithin } from '../../lib/styles';\nimport type { Slot, SlotObject } from '../../lib/types';\nimport { useControllable } from '../../hooks/useControllable';\nimport { useFieldControl } from '../../hooks/useFieldControl';\nimport { useFormReset } from '../../hooks/useFormReset';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { Button } from '../button/Button';\nimport {\n BUTTON_OWN_PROP_KEYS,\n MERGED_DISABLED_FOCUSABLE_PROPS,\n mergedAriaDisabledClasses,\n placeButtonIcon,\n} from '../button/Button.slots';\nimport { isInvalidLook } from './Input';\n\n/**\n * Props that SearchBox routes to its `<input>` (C-ROUTING): the id, the ARIA naming/validation\n * attributes, native text-input attributes and the focus/keyboard handlers.\n */\nexport type SearchBoxInputProps = Pick<\n React.InputHTMLAttributes<HTMLInputElement>,\n | 'id'\n | 'aria-label'\n | 'aria-labelledby'\n | 'aria-describedby'\n | 'aria-invalid'\n | 'aria-required'\n | 'aria-errormessage'\n | 'aria-details'\n | 'name'\n | 'form'\n | 'required'\n | 'readOnly'\n | 'autoComplete'\n | 'autoFocus'\n | 'autoCapitalize'\n | 'autoCorrect'\n | 'inputMode'\n | 'enterKeyHint'\n | 'spellCheck'\n | 'maxLength'\n | 'minLength'\n | 'pattern'\n | 'tabIndex'\n | 'onFocus'\n | 'onBlur'\n | 'onKeyDown'\n | 'onKeyUp'\n>;\n\n/** Properties for the SearchBox component. */\nexport interface SearchBoxProps\n extends\n Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onChange' | 'defaultValue' | keyof SearchBoxInputProps\n >,\n SearchBoxInputProps {\n /** Controlled search text value. */\n value?: string;\n /** Initial search text for uncontrolled usage (also what a form reset restores).\n * @default ''\n */\n defaultValue?: string;\n /** Called with the new search text when it changes (typing or clearing). */\n onValueChange?: (value: string) => void;\n /**\n * Called with the new search text when it changes.\n * @deprecated Use `onValueChange`. (`onChange` is reserved for native change events.)\n */\n onChange?: (value: string) => void;\n /**\n * Called when the user clears the search: with the clear button, or with Escape while there is\n * text (after `onValueChange('')`).\n */\n onClear?: () => void;\n /** Placeholder text shown when the input is empty.\n * @default 'Search'\n */\n placeholder?: string;\n /** Whether the search box is disabled and non-interactive. */\n disabled?: boolean;\n /**\n * Slot rendered before the text (replaces the default search icon). It takes the room it needs;\n * the text starts after it. A value that renders nothing (`null`, `false`, `''`, an empty array\n * or Fragment) keeps the default icon.\n */\n contentBefore?: Slot<'span'>;\n /**\n * Slot rendered after the text, before the clear button. It takes the room it needs; the text\n * ends before it. A value that renders nothing (`false`, `''`, an empty array or Fragment) is no\n * slot: nothing takes room.\n */\n contentAfter?: Slot<'span'>;\n /**\n * Content of the clear button (replaces the default dismiss icon). It always renders **inside**\n * the built-in `<button type=\"button\" aria-label=\"Clear search\">`, which clears the value, calls\n * `onClear` and moves focus back to the input. The slot cannot hide the clear button or leave\n * it empty: content that renders nothing (`null`, `false`, `true`, `''`, or an array, `Set`,\n * generator or Fragment of only those) keeps the default icon, and a slot object without\n * children (`{ className: 'text-error' }`) wraps the default icon in its element (not when it\n * brings markup of its own through `dangerouslySetInnerHTML`, or is a void or component element).\n *\n * A `<button>` element or a Wave `Button` passed here is not nested: its props are merged into\n * the built-in button (its `onClick` runs first; `preventDefault()` cancels the clear) and its\n * children become the content, with a development warning. A Wave `Button`'s own props are not\n * attributes: its `icon` becomes decorative content before its children (after them with\n * `iconPosition=\"after\"`), `disabledFocusable` makes the clear button unavailable but focusable\n * as on the Button (nothing is cleared), and `appearance` and `size` are ignored. The 0.4\n * button-object form (`{ as: 'button', onClick, … }` or an object with button props) is\n * **deprecated**: its button props are merged the same way. Pass icon content instead.\n *\n * Name (WCAG 2.5.3 Label in Name): content is decorative (`aria-hidden`), so the button keeps\n * the name \"Clear search\". An `aria-label`, `aria-labelledby` or `title` on the merged button or\n * on a slot object names the button instead (`{ children: 'Reset', 'aria-label': 'Reset' }`).\n * The children of a merged `<button>`/`Button` (or of `{ as: 'button' }`) are rendered as is:\n * when they render a text label (at least two letters or digits outside `aria-hidden`/`hidden`\n * content, text from components such as translations included), that text names the button;\n * an icon or a lone character (`X`, `×`) keeps \"Clear search\". Text hidden only with CSS still\n * counts as the label, so give a button with a responsive label an explicit `aria-label`.\n */\n dismiss?: Slot<'span'> | SlotObject<'button'>;\n /** Ref to the root `<div>`. */\n ref?: React.Ref<HTMLDivElement>;\n /** Ref to the `<input type=\"search\">` (the focusable control). */\n controlRef?: React.Ref<HTMLInputElement>;\n}\n\ntype UnknownProps = Record<string, unknown>;\n\n/** Attributes that only make sense on the clear `<button>` itself (merged onto it). */\nconst BUTTON_ONLY_KEYS: ReadonlySet<string> = new Set([\n 'type',\n 'disabled',\n 'form',\n 'formAction',\n 'formEncType',\n 'formMethod',\n 'formNoValidate',\n 'formTarget',\n 'name',\n 'value',\n 'popoverTarget',\n 'popoverTargetAction',\n]);\nconst HANDLER_KEY = /^on[A-Z]/;\n\n/**\n * Attributes that name the clear button (C-SLOTS naming). On a merged button or a slot object they\n * go to the clear button (slot content is `aria-hidden`), and any of them replaces the default\n * `aria-label`.\n */\nconst NAMING_KEYS: ReadonlySet<string> = new Set(['aria-label', 'aria-labelledby', 'title']);\n\n/** Default name of the clear button. */\nconst DEFAULT_CLEAR_LABEL = 'Clear search';\n\ninterface DismissParts {\n /**\n * `default`: no slot (default icon); `content`: icon content; `element`: a `<button>`/`Button`\n * element; `button-object`: the deprecated button-object form.\n */\n kind: 'default' | 'content' | 'element' | 'button-object';\n /** Props merged onto the built-in clear button. */\n buttonProps: UnknownProps;\n /** Content of the clear button (`null` = the default icon, except for `content`). */\n content: React.ReactNode;\n /**\n * `true` when the content is rendered as is (a merged `<button>`/`Button` or `{ as: 'button' }`),\n * so a text label in it names the button (C-SLOTS naming, WCAG 2.5.3); `false` when the content\n * is decorative (`aria-hidden`).\n */\n contentMayName: boolean;\n /**\n * Whether the literal children contain a text label: the name for the server render and the\n * first client render. After mount the rendered button's text decides.\n */\n literalTextLabel: boolean;\n /**\n * Whether a merged Wave `Button` set `disabledFocusable`: the clear button is then unavailable\n * but focusable, as the Button would be.\n */\n disabledFocusable: boolean;\n}\n\nconst noop = () => {};\n\n/**\n * Elements inside the field that keep a press to themselves: a control in a slot, the clear\n * button.\n */\nconst INTERACTIVE_CONTENT =\n 'a[href], button, input, select, textarea, [tabindex], [contenteditable]:not([contenteditable=\"false\"])';\n\nconst DEFAULT_DISMISS: DismissParts = {\n kind: 'default',\n buttonProps: {},\n content: null,\n contentMayName: false,\n literalTextLabel: false,\n disabledFocusable: false,\n};\n\nfunction isButtonType(type: unknown): boolean {\n return type === 'button' || type === Button;\n}\n\n/**\n * Splits the props of a button-like element or object into button props and content. The content\n * is rendered as is, so a text label in it names the button (C-SLOTS naming). Content that renders\n * nothing is `null` (the default icon); a generator is read once and rendered as its items.\n */\nfunction splitButtonLike(type: unknown, props: UnknownProps, children: React.ReactNode) {\n const hasChildren = slotRendersContent(children);\n const content = materialiseSlotContent(children);\n const literalTextLabel = hasTextLabel(content);\n if (type === Button) {\n // Wave Button's own props do not belong on a native <button>: its icon becomes content (after\n // the children with `iconPosition=\"after\"`) and `disabledFocusable` is applied by the caller.\n const buttonProps: UnknownProps = {};\n for (const [key, value] of Object.entries(props)) {\n if (key !== 'children' && !BUTTON_OWN_PROP_KEYS.has(key)) buttonProps[key] = value;\n }\n const iconNode = renderSlot(\n props.icon as Slot<'span'>,\n 'span',\n cn(searchBoxClassNames.dismissIcon, 'inline-flex'),\n { 'aria-hidden': true },\n );\n const buttonContent =\n iconNode || hasChildren ? placeButtonIcon(iconNode, content, props.iconPosition) : null;\n return {\n buttonProps,\n content: buttonContent,\n contentMayName: true,\n literalTextLabel,\n disabledFocusable: Boolean(props.disabledFocusable),\n };\n }\n const { as, children: _children, ...buttonProps } = props;\n // `null` content falls back to the default icon.\n return {\n buttonProps,\n content: hasChildren ? content : null,\n contentMayName: true,\n literalTextLabel,\n disabledFocusable: false,\n };\n}\n\n/**\n * Splits `dismiss` into the props merged onto the built-in clear button and its content. Content\n * that renders nothing (`slotRendersContent`) never leaves the button empty: without other props\n * it is the default icon; a slot object with its own content props (`className`, `style`, …)\n * wraps the default icon in its element.\n */\nfunction resolveDismiss(dismiss: SearchBoxProps['dismiss']): DismissParts {\n // The type is unwrapped (C-COMPOUND): a Button written in a Server Component arrives as a lazy\n // client reference, and must be merged like a plain one rather than nested inside the clear\n // button. A slot object is never an element, so the check can take any slot value as a node.\n const node = dismiss as React.ReactNode;\n if (isElementOfType<UnknownProps>(node, 'button', Button)) {\n const children = node.props.children as React.ReactNode;\n return {\n kind: 'element',\n ...splitButtonLike(getElementType(node), node.props, children),\n };\n }\n // Resolved once: a generator is materialised (and cached) by resolveSlot, so it can be checked\n // for emptiness and rendered without being consumed twice.\n const resolved = resolveSlot(dismiss as Slot<'span'>, 'span');\n if (!resolved) return DEFAULT_DISMISS;\n const { Component, props, children } = resolved;\n if (isButtonType(Component)) {\n return { kind: 'button-object', ...splitButtonLike(Component, props, children) };\n }\n const buttonProps: UnknownProps = {};\n const contentProps: UnknownProps = {};\n let hasButtonProps = false;\n for (const [key, value] of Object.entries(props)) {\n // resolveSlot sets `className: undefined` when there are no classes.\n if (value === undefined) continue;\n if (BUTTON_ONLY_KEYS.has(key) || HANDLER_KEY.test(key)) {\n buttonProps[key] = value;\n hasButtonProps = true;\n } else if (NAMING_KEYS.has(key)) {\n // The content is aria-hidden, so a naming attribute names the clear button instead (not the\n // deprecated button-object form).\n buttonProps[key] = value;\n } else {\n contentProps[key] = value;\n }\n }\n // A void (`img`), component (`{ as: MyIcon }`) or markup (`dangerouslySetInnerHTML`) slot\n // renders content of its own.\n const hasChildren = slotRendersContent(children);\n const empty = slotWrapsDefaultContent(Component, { ...contentProps, children });\n if (empty && Object.keys(buttonProps).length === 0 && Object.keys(contentProps).length === 0) {\n return DEFAULT_DISMISS;\n }\n // A button object without content (`{ onClick }`, `{ type: 'button' }`) or a content object\n // without children (`{ className }`) keeps the default icon inside the object's own element (its\n // className/style/attributes still apply). Markup of its own takes no children at all.\n const contentChildren = empty ? <DismissIcon /> : hasChildren ? children : undefined;\n // The element the slot renders carries the dismissIcon part class, before the slot's own.\n const iconProps = {\n 'aria-hidden': true,\n ...contentProps,\n className: cn(searchBoxClassNames.dismissIcon, contentProps.className as string | undefined),\n };\n const content =\n contentChildren === undefined\n ? React.createElement(Component, iconProps)\n : React.createElement(Component, iconProps, contentChildren);\n return {\n kind: hasButtonProps ? 'button-object' : 'content',\n buttonProps,\n content,\n contentMayName: false,\n literalTextLabel: false,\n disabledFocusable: false,\n };\n}\n\n/**\n * A search input with a leading search icon and a clear button that appears while there is text\n * (not while `readOnly`).\n *\n * - **Layout**: the root `<div>` draws the field (its outline, focus and invalid look). The icon\n * (or `contentBefore`), the text, `contentAfter` and the clear button sit side by side in it, so\n * no slot covers the text. Pressing the field outside a control of its own focuses the input.\n * - **Clearing**: the clear button clears the text and moves focus back to the input. Escape\n * clears the text too while there is any, and is then consumed, so an enclosing Dialog, Drawer\n * or Popover stays open; in an empty field Escape reaches them. Both call `onClear`.\n * - **Routing**: `id`, ARIA and native input attributes and the focus/keyboard handlers go to the\n * `<input type=\"search\">` (role `searchbox`); `className`, `style`, `data-*`, other handlers and\n * `ref` stay on the root `<div>` (`controlRef` reaches the input). Inside a `Field` it picks up\n * the label, hint, error and required state automatically.\n * - **Forms**: with `name` the text is submitted with the form; a form reset restores\n * `defaultValue`.\n *\n * @example\n * <SearchBox aria-label=\"Search files\" value={query} onValueChange={setQuery} />\n */\nexport const SearchBox = ({\n value: controlledValue,\n defaultValue = '',\n onValueChange,\n onChange,\n onClear,\n placeholder = 'Search',\n disabled,\n contentBefore,\n contentAfter,\n dismiss,\n className,\n ref,\n controlRef,\n // Routed to the input (C-ROUTING)\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n 'aria-errormessage': ariaErrorMessage,\n 'aria-details': ariaDetails,\n required,\n name,\n form,\n readOnly,\n autoComplete,\n autoFocus,\n autoCapitalize,\n autoCorrect,\n inputMode,\n enterKeyHint,\n spellCheck,\n maxLength,\n minLength,\n pattern,\n tabIndex,\n onFocus,\n onBlur,\n onKeyDown,\n onKeyUp,\n onMouseDown,\n hidden,\n ...rest\n}: SearchBoxProps) => {\n if (onChange !== undefined) warnDeprecated('SearchBox', 'onChange', 'onValueChange');\n\n const [value, setValue] = useControllable(controlledValue, defaultValue, (next: string) => {\n onValueChange?.(next);\n onChange?.(next);\n });\n\n const inputRef = React.useRef<HTMLInputElement>(null);\n const mergedInputRef = useMergedRefs(inputRef, controlRef);\n // The input is always React-controlled, so the browser's own reset would put the current text\n // back: restore the default here instead (C-FORMS).\n useFormReset(inputRef, () => setValue(defaultValue), form);\n\n const fieldProps = useFieldControl(\n {\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n required,\n },\n { nativeRequired: true },\n );\n const invalidLook = isInvalidLook(false, fieldProps['aria-invalid']);\n\n const dismissParts = resolveDismiss(dismiss);\n const dismissKind = dismissParts.kind;\n React.useEffect(() => {\n if (dismissKind === 'element') {\n warnOnce(\n 'SearchBox:dismiss-button-element',\n 'SearchBox: `dismiss` received a button element; its props were merged into the built-in clear button (buttons cannot be nested). Pass icon content instead, e.g. `dismiss={<MyIcon />}`.',\n );\n } else if (dismissKind === 'button-object') {\n warnOnce(\n 'SearchBox:dismiss-button-object',\n 'SearchBox: `dismiss` with button props (`as: \"button\"`, `onClick`, `type`, …) is deprecated and will be removed in 1.0; the props were merged into the built-in clear button. Pass icon content instead, e.g. `dismiss={<MyIcon />}`.',\n );\n }\n }, [dismissKind]);\n\n const handleClear = () => {\n setValue('');\n onClear?.();\n inputRef.current?.focus();\n };\n\n // Escape clears the text first, as native search fields do, and is consumed so an enclosing\n // Dialog, Drawer or Popover stays open; with an empty field it reaches them (C-POPUPS).\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (event.key !== 'Escape' || event.nativeEvent.isComposing) return;\n if (!value || readOnly || disabled) return;\n event.preventDefault();\n setValue('');\n onClear?.();\n };\n\n // The whole box is the field: pressing the icon, a slot or the padding around the text focuses\n // the input, as it does in a native search field. A control inside a slot keeps its press.\n const handleRootMouseDown = (event: React.MouseEvent<HTMLDivElement>) => {\n const input = inputRef.current;\n const root = event.currentTarget;\n const target = event.target;\n if (!input || disabled || event.button !== 0 || target === input) return;\n // Events that bubble through React portals from outside this box are not ours (C-COMPOSE).\n if (!(target instanceof Element) || !root.contains(target)) return;\n const control = target.closest(INTERACTIVE_CONTENT);\n if (control && root.contains(control)) return;\n event.preventDefault(); // keeps the press from moving focus to the page\n input.focus();\n };\n\n // The slot's onClick is composed at click time (it runs first; preventDefault() cancels the\n // clear), so handleClear, which reads the input ref, is never passed to a render-time helper.\n // The slot's ref joins ours through a stable merged ref (never a new callback per render).\n const {\n onClick: slotOnClick,\n ref: slotRef,\n ...slotButtonProps\n } = dismissParts.buttonProps as UnknownProps & {\n onClick?: React.MouseEventHandler<HTMLButtonElement>;\n ref?: React.Ref<HTMLButtonElement>;\n };\n\n // C-SLOTS naming (WCAG 2.5.3 Label in Name): a consumer naming attribute names the clear button;\n // otherwise content rendered as is names it when it has a text label, and the default\n // `aria-label` would hide that label. The literal children decide on the server and on the first\n // render; after mount, the rendered button's text does (text from components, later changes).\n const hasOwnName = Object.keys(slotButtonProps).some(\n (key) => NAMING_KEYS.has(key) && slotButtonProps[key] != null,\n );\n const checksContent = dismissParts.contentMayName && !hasOwnName;\n const literalTextLabel = dismissParts.literalTextLabel;\n const [labelTarget, setLabelTarget] = React.useState<HTMLButtonElement | null>(null);\n const subscribeToContent = React.useCallback(\n (onChange: () => void) => (labelTarget ? observeTextLabel(labelTarget, onChange) : noop),\n [labelTarget],\n );\n const contentHasTextLabel = React.useSyncExternalStore(\n subscribeToContent,\n () => (labelTarget ? hasRenderedTextLabel(labelTarget) : literalTextLabel),\n () => literalTextLabel,\n );\n const namedByContent = checksContent && contentHasTextLabel;\n const clearRef = useMergedRefs<HTMLButtonElement>(\n slotRef,\n checksContent ? setLabelTarget : undefined,\n );\n\n const clearButtonProps = mergeProps(\n {\n type: 'button',\n disabled,\n 'aria-label': hasOwnName || namedByContent ? undefined : DEFAULT_CLEAR_LABEL,\n className: cn(\n searchBoxClassNames.dismissButton,\n // Padding and background set here (C-NATIVE): an app-wide `button` rule cannot fill it.\n 'me-1 flex h-6 w-6 shrink-0 items-center justify-center rounded bg-transparent p-0 text-muted-foreground',\n 'not-disabled:not-aria-disabled:hover:text-foreground',\n focusRing,\n 'disabled:cursor-not-allowed',\n mergedAriaDisabledClasses,\n ),\n },\n slotButtonProps,\n ) as React.ComponentPropsWithoutRef<'button'>;\n\n // A merged button with markup of its own (`dangerouslySetInnerHTML`) takes no children.\n const clearContent =\n clearButtonProps.dangerouslySetInnerHTML != null\n ? undefined\n : dismissKind === 'content'\n ? dismissParts.content\n : (dismissParts.content ?? <DismissIcon className={searchBoxClassNames.dismissIcon} />);\n // A slot value that renders nothing is no slot (the default icon before the text, no box after).\n const hasBefore = slotRendersContent(contentBefore);\n const hasAfter = slotRendersContent(contentAfter);\n\n return (\n <div\n ref={ref}\n className={cn(\n searchBoxClassNames.root,\n // The root draws the field; the slots, the text and the clear button are laid out side by\n // side inside it, so a slot never covers the text.\n 'relative inline-flex h-8 w-full items-center rounded border border-input border-b-stroke-accessible bg-background text-body-1 text-foreground',\n inputFocusWithin,\n invalidLook && inputInvalidWithin,\n // The dimmed look lifts while a focus ring shows inside the root (a clear button kept\n // focusable by a merged `disabledFocusable` Button, focusable slot content; the disabled\n // input never takes focus): opacity would dim the ring below 3:1.\n disabled && 'cursor-not-allowed opacity-50 has-focus-visible:opacity-100',\n className,\n )}\n hidden={hidden}\n {...rest}\n // Composed at press time, like the clear button's click: the handler reads the input ref.\n onMouseDown={(event) => composeEventHandlers(onMouseDown, handleRootMouseDown)(event)}\n >\n <span className={cn(searchBoxClassNames.contentBefore, 'flex shrink-0 items-center ps-2')}>\n {hasBefore ? (\n renderSlot(contentBefore, 'span', 'shrink-0')\n ) : (\n <SearchIcon className=\"text-muted-foreground\" />\n )}\n </span>\n\n <input\n ref={mergedInputRef}\n type=\"search\"\n value={value}\n onChange={(event) => setValue(event.target.value)}\n placeholder={placeholder}\n disabled={disabled}\n className={cn(\n searchBoxClassNames.input,\n 'h-full min-w-0 flex-1 appearance-none border-none bg-transparent px-2 text-body-1 text-foreground',\n 'placeholder:text-muted-foreground',\n 'focus:outline-hidden',\n 'disabled:cursor-not-allowed',\n '[&::-webkit-search-cancel-button]:hidden',\n )}\n aria-errormessage={ariaErrorMessage}\n aria-details={ariaDetails}\n name={name}\n form={form}\n readOnly={readOnly}\n autoComplete={autoComplete}\n autoFocus={autoFocus}\n autoCapitalize={autoCapitalize}\n autoCorrect={autoCorrect}\n inputMode={inputMode}\n enterKeyHint={enterKeyHint}\n spellCheck={spellCheck}\n maxLength={maxLength}\n minLength={minLength}\n pattern={pattern}\n tabIndex={tabIndex}\n onFocus={onFocus}\n onBlur={onBlur}\n onKeyDown={composeEventHandlers(onKeyDown, handleKeyDown)}\n onKeyUp={onKeyUp}\n {...fieldProps}\n />\n\n {hasAfter && (\n <span className={cn(searchBoxClassNames.contentAfter, 'flex shrink-0 items-center pe-2')}>\n {renderSlot(contentAfter, 'span', 'shrink-0')}\n </span>\n )}\n\n {/* No clear button while read-only: clearing would change a value the user cannot edit. */}\n {value && !readOnly ? (\n <button\n {...clearButtonProps}\n ref={clearRef}\n // mergeProps keeps a slot's `type: null`, which would drop the attribute and make the\n // button submit its form; only nullish falls back (an explicit type is kept).\n type={clearButtonProps.type ?? 'button'}\n disabled={disabled || clearButtonProps.disabled}\n onClick={(event) => composeEventHandlers(slotOnClick, handleClear)(event)}\n // A merged `disabledFocusable` Button makes the clear button unavailable but focusable\n // (spread last: it wins over `disabled` and the clear handler).\n {...(dismissParts.disabledFocusable ? MERGED_DISABLED_FOCUSABLE_PROPS : undefined)}\n >\n {clearContent}\n </button>\n ) : null}\n </div>\n );\n};\n\nSearchBox.displayName = 'SearchBox';\n"],"mappings":"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"}
1
+ {"version":3,"file":"SearchBox.mjs","names":["React","SEARCH_SIZE","BUTTON_ONLY_KEYS","HANDLER_KEY","NAMING_KEYS","DEFAULT_CLEAR_LABEL","noop","INTERACTIVE_CONTENT","DEFAULT_DISMISS","isButtonType","type","Button","splitButtonLike","hasChildren","slotRendersContent","children","content","materialiseSlotContent","literalTextLabel","hasTextLabel","buttonProps","key","value","props","BUTTON_OWN_PROP_KEYS","iconNode","renderSlot","cn","searchBoxClassNames","placeButtonIcon","_children","resolveDismiss","node","dismiss","isElementOfType","getElementType","resolved","resolveSlot","Component","contentProps","hasButtonProps","empty","slotWrapsDefaultContent","contentChildren","DismissIcon","size","iconProps","SearchBox","controlledValue","sizeProp","appearanceProp","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","ariaErrorMessage","ariaDetails","rest","onChange","warnDeprecated","setValue","useControllable","defaultValue","onValueChange","next","inputRef","mergedInputRef","useMergedRefs","controlRef","form","fieldProps","useFieldControl","invalidLook","isInvalidLook","useInputLook","dismissParts","dismissKind","warnOnce","handleClear","onClear","handleKeyDown","event","readOnly","disabled","handleRootMouseDown","input","root","target","control","slotOnClick","slotRef","slotButtonProps","hasOwnName","checksContent","labelTarget","setLabelTarget","subscribeToContent","observeTextLabel","contentHasTextLabel","hasRenderedTextLabel","namedByContent","clearRef","clearButtonProps","mergeProps","focusRing","mergedAriaDisabledClasses","clearContent","hasBefore","contentBefore","hasAfter","contentAfter","appearance","inputHeightClasses","inputTextClasses","inputAppearanceClasses","inputFocusWithin","className","composeEventHandlers","onMouseDown","SearchIcon","onKeyDown","MERGED_DISABLED_FOCUSABLE_PROPS"],"sources":["../../../src/components/input/SearchBox.tsx"],"sourcesContent":["import * as React from 'react';\nimport { getElementType, isElementOfType } from '../../lib/children';\nimport { searchBoxClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { warnDeprecated, warnOnce } from '../../lib/dev';\nimport { DismissIcon, SearchIcon } from '../../lib/icons';\nimport { hasRenderedTextLabel, hasTextLabel, observeTextLabel } from '../../lib/labelInName';\nimport { mergeProps } from '../../lib/mergeProps';\nimport {\n materialiseSlotContent,\n renderSlot,\n resolveSlot,\n slotRendersContent,\n slotWrapsDefaultContent,\n} from '../../lib/slot';\nimport {\n focusRing,\n hitAreaLayer,\n inputAppearanceClasses,\n inputFocusWithin,\n inputHeightClasses,\n inputInvalidWithin,\n inputTextClasses,\n} from '../../lib/styles';\nimport type { CoreSize, InputAppearance, Slot, SlotObject } from '../../lib/types';\nimport { useControllable } from '../../hooks/useControllable';\nimport { useFieldControl } from '../../hooks/useFieldControl';\nimport { useFormReset } from '../../hooks/useFormReset';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { Button } from '../button/Button';\nimport {\n BUTTON_OWN_PROP_KEYS,\n MERGED_DISABLED_FOCUSABLE_PROPS,\n mergedAriaDisabledClasses,\n placeButtonIcon,\n} from '../button/Button.slots';\nimport { isInvalidLook } from './Input';\nimport { useInputLook } from './inputLook';\n\n/**\n * Props that SearchBox routes to its `<input>` (C-ROUTING): the id, the ARIA naming/validation\n * attributes, native text-input attributes and the focus/keyboard handlers.\n */\nexport type SearchBoxInputProps = Pick<\n React.InputHTMLAttributes<HTMLInputElement>,\n | 'id'\n | 'aria-label'\n | 'aria-labelledby'\n | 'aria-describedby'\n | 'aria-invalid'\n | 'aria-required'\n | 'aria-errormessage'\n | 'aria-details'\n | 'name'\n | 'form'\n | 'required'\n | 'readOnly'\n | 'autoComplete'\n | 'autoFocus'\n | 'autoCapitalize'\n | 'autoCorrect'\n | 'inputMode'\n | 'enterKeyHint'\n | 'spellCheck'\n | 'maxLength'\n | 'minLength'\n | 'pattern'\n | 'tabIndex'\n | 'onFocus'\n | 'onBlur'\n | 'onKeyDown'\n | 'onKeyUp'\n>;\n\n/** Properties for the SearchBox component. */\nexport interface SearchBoxProps\n extends\n Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onChange' | 'defaultValue' | keyof SearchBoxInputProps\n >,\n SearchBoxInputProps {\n /** Controlled search text value. */\n value?: string;\n /** Initial search text for uncontrolled usage (also what a form reset restores).\n * @default ''\n */\n defaultValue?: string;\n /** Called with the new search text when it changes (typing or clearing). */\n onValueChange?: (value: string) => void;\n /**\n * Called with the new search text when it changes.\n * @deprecated Use `onValueChange`. (`onChange` is reserved for native change events.)\n */\n onChange?: (value: string) => void;\n /**\n * Called when the user clears the search: with the clear button, or with Escape while there is\n * text (after `onValueChange('')`).\n */\n onClear?: () => void;\n /** Placeholder text shown when the input is empty.\n * @default 'Search'\n */\n placeholder?: string;\n /** Whether the search box is disabled and non-interactive. */\n disabled?: boolean;\n /**\n * Size of the field: `small` (24px tall), `medium` (32px) or `large` (40px). Default: the\n * surrounding Field's `size`, else `WaveProvider inputDefaults.size`, else `'medium'`.\n */\n size?: CoreSize;\n /**\n * Look of the field: `outline` (a full border), `underline` (a bottom stroke only),\n * `filled-darker` or `filled-lighter` (a fill without a visible stroke: give the field a visible\n * label). Default: `WaveProvider inputDefaults.appearance`, else `'outline'`.\n */\n appearance?: InputAppearance;\n /**\n * Slot rendered before the text (replaces the default search icon). It takes the room it needs;\n * the text starts after it. A value that renders nothing (`null`, `false`, `''`, an empty array\n * or Fragment) keeps the default icon.\n */\n contentBefore?: Slot<'span'>;\n /**\n * Slot rendered after the text, before the clear button. It takes the room it needs; the text\n * ends before it. A value that renders nothing (`false`, `''`, an empty array or Fragment) is no\n * slot: nothing takes room.\n */\n contentAfter?: Slot<'span'>;\n /**\n * Content of the clear button (replaces the default dismiss icon). It always renders **inside**\n * the built-in `<button type=\"button\" aria-label=\"Clear search\">`, which clears the value, calls\n * `onClear` and moves focus back to the input. The slot cannot hide the clear button or leave\n * it empty: content that renders nothing (`null`, `false`, `true`, `''`, or an array, `Set`,\n * generator or Fragment of only those) keeps the default icon, and a slot object without\n * children (`{ className: 'text-error' }`) wraps the default icon in its element (not when it\n * brings markup of its own through `dangerouslySetInnerHTML`, or is a void or component element).\n *\n * A `<button>` element or a Wave `Button` passed here is not nested: its props are merged into\n * the built-in button (its `onClick` runs first; `preventDefault()` cancels the clear) and its\n * children become the content, with a development warning. A Wave `Button`'s own props are not\n * attributes: its `icon` becomes decorative content before its children (after them with\n * `iconPosition=\"after\"`), `disabledFocusable` makes the clear button unavailable but focusable\n * as on the Button (nothing is cleared), and `appearance` and `size` are ignored. The 0.4\n * button-object form (`{ as: 'button', onClick, … }` or an object with button props) is\n * **deprecated**: its button props are merged the same way. Pass icon content instead.\n *\n * Name (WCAG 2.5.3 Label in Name): content is decorative (`aria-hidden`), so the button keeps\n * the name \"Clear search\". An `aria-label`, `aria-labelledby` or `title` on the merged button or\n * on a slot object names the button instead (`{ children: 'Reset', 'aria-label': 'Reset' }`).\n * The children of a merged `<button>`/`Button` (or of `{ as: 'button' }`) are rendered as is:\n * when they render a text label (at least two letters or digits outside `aria-hidden`/`hidden`\n * content, text from components such as translations included), that text names the button;\n * an icon or a lone character (`X`, `×`) keeps \"Clear search\". Text hidden only with CSS still\n * counts as the label, so give a button with a responsive label an explicit `aria-label`.\n */\n dismiss?: Slot<'span'> | SlotObject<'button'>;\n /** Ref to the root `<div>`. */\n ref?: React.Ref<HTMLDivElement>;\n /** Ref to the `<input type=\"search\">` (the focusable control). */\n controlRef?: React.Ref<HTMLInputElement>;\n}\n\n/** Per-size metrics of SearchBox (medium is the 0.7 look). */\nconst SEARCH_SIZE: Readonly<\n Record<CoreSize, { before: string; after: string; input: string; clear: string; glyph: number }>\n> = {\n small: { before: 'ps-1.5', after: 'pe-1.5', input: 'px-1.5', clear: 'size-5', glyph: 12 },\n medium: { before: 'ps-2', after: 'pe-2', input: 'px-2', clear: 'h-6 w-6', glyph: 16 },\n large: { before: 'ps-3', after: 'pe-3', input: 'px-3', clear: 'size-8', glyph: 20 },\n};\n\ntype UnknownProps = Record<string, unknown>;\n\n/** Attributes that only make sense on the clear `<button>` itself (merged onto it). */\nconst BUTTON_ONLY_KEYS: ReadonlySet<string> = new Set([\n 'type',\n 'disabled',\n 'form',\n 'formAction',\n 'formEncType',\n 'formMethod',\n 'formNoValidate',\n 'formTarget',\n 'name',\n 'value',\n 'popoverTarget',\n 'popoverTargetAction',\n]);\nconst HANDLER_KEY = /^on[A-Z]/;\n\n/**\n * Attributes that name the clear button (C-SLOTS naming). On a merged button or a slot object they\n * go to the clear button (slot content is `aria-hidden`), and any of them replaces the default\n * `aria-label`.\n */\nconst NAMING_KEYS: ReadonlySet<string> = new Set(['aria-label', 'aria-labelledby', 'title']);\n\n/** Default name of the clear button. */\nconst DEFAULT_CLEAR_LABEL = 'Clear search';\n\ninterface DismissParts {\n /**\n * `default`: no slot (default icon); `content`: icon content; `element`: a `<button>`/`Button`\n * element; `button-object`: the deprecated button-object form.\n */\n kind: 'default' | 'content' | 'element' | 'button-object';\n /** Props merged onto the built-in clear button. */\n buttonProps: UnknownProps;\n /** Content of the clear button (`null` = the default icon, except for `content`). */\n content: React.ReactNode;\n /**\n * `true` when the content is rendered as is (a merged `<button>`/`Button` or `{ as: 'button' }`),\n * so a text label in it names the button (C-SLOTS naming, WCAG 2.5.3); `false` when the content\n * is decorative (`aria-hidden`).\n */\n contentMayName: boolean;\n /**\n * Whether the literal children contain a text label: the name for the server render and the\n * first client render. After mount the rendered button's text decides.\n */\n literalTextLabel: boolean;\n /**\n * Whether a merged Wave `Button` set `disabledFocusable`: the clear button is then unavailable\n * but focusable, as the Button would be.\n */\n disabledFocusable: boolean;\n}\n\nconst noop = () => {};\n\n/**\n * Elements inside the field that keep a press to themselves: a control in a slot, the clear\n * button.\n */\nconst INTERACTIVE_CONTENT =\n 'a[href], button, input, select, textarea, [tabindex], [contenteditable]:not([contenteditable=\"false\"])';\n\nconst DEFAULT_DISMISS: DismissParts = {\n kind: 'default',\n buttonProps: {},\n content: null,\n contentMayName: false,\n literalTextLabel: false,\n disabledFocusable: false,\n};\n\nfunction isButtonType(type: unknown): boolean {\n return type === 'button' || type === Button;\n}\n\n/**\n * Splits the props of a button-like element or object into button props and content. The content\n * is rendered as is, so a text label in it names the button (C-SLOTS naming). Content that renders\n * nothing is `null` (the default icon); a generator is read once and rendered as its items.\n */\nfunction splitButtonLike(type: unknown, props: UnknownProps, children: React.ReactNode) {\n const hasChildren = slotRendersContent(children);\n const content = materialiseSlotContent(children);\n const literalTextLabel = hasTextLabel(content);\n if (type === Button) {\n // Wave Button's own props do not belong on a native <button>: its icon becomes content (after\n // the children with `iconPosition=\"after\"`) and `disabledFocusable` is applied by the caller.\n const buttonProps: UnknownProps = {};\n for (const [key, value] of Object.entries(props)) {\n if (key !== 'children' && !BUTTON_OWN_PROP_KEYS.has(key)) buttonProps[key] = value;\n }\n const iconNode = renderSlot(\n props.icon as Slot<'span'>,\n 'span',\n cn(searchBoxClassNames.dismissIcon, 'inline-flex'),\n { 'aria-hidden': true },\n );\n const buttonContent =\n iconNode || hasChildren ? placeButtonIcon(iconNode, content, props.iconPosition) : null;\n return {\n buttonProps,\n content: buttonContent,\n contentMayName: true,\n literalTextLabel,\n disabledFocusable: Boolean(props.disabledFocusable),\n };\n }\n const { as, children: _children, ...buttonProps } = props;\n // `null` content falls back to the default icon.\n return {\n buttonProps,\n content: hasChildren ? content : null,\n contentMayName: true,\n literalTextLabel,\n disabledFocusable: false,\n };\n}\n\n/**\n * Splits `dismiss` into the props merged onto the built-in clear button and its content. Content\n * that renders nothing (`slotRendersContent`) never leaves the button empty: without other props\n * it is the default icon; a slot object with its own content props (`className`, `style`, …)\n * wraps the default icon in its element.\n */\nfunction resolveDismiss(dismiss: SearchBoxProps['dismiss'], size: CoreSize): DismissParts {\n // The type is unwrapped (C-COMPOUND): a Button written in a Server Component arrives as a lazy\n // client reference, and must be merged like a plain one rather than nested inside the clear\n // button. A slot object is never an element, so the check can take any slot value as a node.\n const node = dismiss as React.ReactNode;\n if (isElementOfType<UnknownProps>(node, 'button', Button)) {\n const children = node.props.children as React.ReactNode;\n return {\n kind: 'element',\n ...splitButtonLike(getElementType(node), node.props, children),\n };\n }\n // Resolved once: a generator is materialised (and cached) by resolveSlot, so it can be checked\n // for emptiness and rendered without being consumed twice.\n const resolved = resolveSlot(dismiss as Slot<'span'>, 'span');\n if (!resolved) return DEFAULT_DISMISS;\n const { Component, props, children } = resolved;\n if (isButtonType(Component)) {\n return { kind: 'button-object', ...splitButtonLike(Component, props, children) };\n }\n const buttonProps: UnknownProps = {};\n const contentProps: UnknownProps = {};\n let hasButtonProps = false;\n for (const [key, value] of Object.entries(props)) {\n // resolveSlot sets `className: undefined` when there are no classes.\n if (value === undefined) continue;\n if (BUTTON_ONLY_KEYS.has(key) || HANDLER_KEY.test(key)) {\n buttonProps[key] = value;\n hasButtonProps = true;\n } else if (NAMING_KEYS.has(key)) {\n // The content is aria-hidden, so a naming attribute names the clear button instead (not the\n // deprecated button-object form).\n buttonProps[key] = value;\n } else {\n contentProps[key] = value;\n }\n }\n // A void (`img`), component (`{ as: MyIcon }`) or markup (`dangerouslySetInnerHTML`) slot\n // renders content of its own.\n const hasChildren = slotRendersContent(children);\n const empty = slotWrapsDefaultContent(Component, { ...contentProps, children });\n if (empty && Object.keys(buttonProps).length === 0 && Object.keys(contentProps).length === 0) {\n return DEFAULT_DISMISS;\n }\n // A button object without content (`{ onClick }`, `{ type: 'button' }`) or a content object\n // without children (`{ className }`) keeps the default icon inside the object's own element (its\n // className/style/attributes still apply). Markup of its own takes no children at all.\n const contentChildren = empty ? (\n <DismissIcon size={SEARCH_SIZE[size].glyph} />\n ) : hasChildren ? (\n children\n ) : undefined;\n // The element the slot renders carries the dismissIcon part class, before the slot's own.\n const iconProps = {\n 'aria-hidden': true,\n ...contentProps,\n className: cn(searchBoxClassNames.dismissIcon, contentProps.className as string | undefined),\n };\n const content =\n contentChildren === undefined\n ? React.createElement(Component, iconProps)\n : React.createElement(Component, iconProps, contentChildren);\n return {\n kind: hasButtonProps ? 'button-object' : 'content',\n buttonProps,\n content,\n contentMayName: false,\n literalTextLabel: false,\n disabledFocusable: false,\n };\n}\n\n/**\n * A search input with a leading search icon and a clear button that appears while there is text\n * (not while `readOnly`).\n *\n * - **Layout**: the root `<div>` draws the field (its outline, focus and invalid look). The icon\n * (or `contentBefore`), the text, `contentAfter` and the clear button sit side by side in it, so\n * no slot covers the text. Pressing the field outside a control of its own focuses the input.\n * - **Clearing**: the clear button clears the text and moves focus back to the input. Escape\n * clears the text too while there is any, and is then consumed, so an enclosing Dialog, Drawer\n * or Popover stays open; in an empty field Escape reaches them. Both call `onClear`.\n * - **Routing**: `id`, ARIA and native input attributes and the focus/keyboard handlers go to the\n * `<input type=\"search\">` (role `searchbox`); `className`, `style`, `data-*`, other handlers and\n * `ref` stay on the root `<div>` (`controlRef` reaches the input). Inside a `Field` it picks up\n * the label, hint, error and required state automatically.\n * - **Forms**: with `name` the text is submitted with the form; a form reset restores\n * `defaultValue`.\n * - **Size and appearance**: `size` resolves from its own prop, then the surrounding `Field`'s\n * `size`, then `WaveProvider inputDefaults.size`, else `'medium'`; `appearance` from its own\n * prop, then `WaveProvider inputDefaults.appearance`, else `'outline'`; both render as\n * `data-size` and `data-appearance` on the root `<div>`.\n *\n * @example\n * <SearchBox aria-label=\"Search files\" value={query} onValueChange={setQuery} />\n */\nexport const SearchBox = ({\n value: controlledValue,\n defaultValue = '',\n onValueChange,\n onChange,\n onClear,\n placeholder = 'Search',\n disabled,\n size: sizeProp,\n appearance: appearanceProp,\n contentBefore,\n contentAfter,\n dismiss,\n className,\n ref,\n controlRef,\n // Routed to the input (C-ROUTING)\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n 'aria-errormessage': ariaErrorMessage,\n 'aria-details': ariaDetails,\n required,\n name,\n form,\n readOnly,\n autoComplete,\n autoFocus,\n autoCapitalize,\n autoCorrect,\n inputMode,\n enterKeyHint,\n spellCheck,\n maxLength,\n minLength,\n pattern,\n tabIndex,\n onFocus,\n onBlur,\n onKeyDown,\n onKeyUp,\n onMouseDown,\n hidden,\n ...rest\n}: SearchBoxProps) => {\n if (onChange !== undefined) warnDeprecated('SearchBox', 'onChange', 'onValueChange');\n\n const [value, setValue] = useControllable(controlledValue, defaultValue, (next: string) => {\n onValueChange?.(next);\n onChange?.(next);\n });\n\n const inputRef = React.useRef<HTMLInputElement>(null);\n const mergedInputRef = useMergedRefs(inputRef, controlRef);\n // The input is always React-controlled, so the browser's own reset would put the current text\n // back: restore the default here instead (C-FORMS).\n useFormReset(inputRef, () => setValue(defaultValue), form);\n\n const fieldProps = useFieldControl(\n {\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n required,\n },\n { nativeRequired: true },\n );\n const invalidLook = isInvalidLook(false, fieldProps['aria-invalid']);\n const { size, appearance } = useInputLook(sizeProp, appearanceProp);\n\n const dismissParts = resolveDismiss(dismiss, size);\n const dismissKind = dismissParts.kind;\n React.useEffect(() => {\n if (dismissKind === 'element') {\n warnOnce(\n 'SearchBox:dismiss-button-element',\n 'SearchBox: `dismiss` received a button element; its props were merged into the built-in clear button (buttons cannot be nested). Pass icon content instead, e.g. `dismiss={<MyIcon />}`.',\n );\n } else if (dismissKind === 'button-object') {\n warnOnce(\n 'SearchBox:dismiss-button-object',\n 'SearchBox: `dismiss` with button props (`as: \"button\"`, `onClick`, `type`, …) is deprecated and will be removed in 1.0; the props were merged into the built-in clear button. Pass icon content instead, e.g. `dismiss={<MyIcon />}`.',\n );\n }\n }, [dismissKind]);\n\n const handleClear = () => {\n setValue('');\n onClear?.();\n inputRef.current?.focus();\n };\n\n // Escape clears the text first, as native search fields do, and is consumed so an enclosing\n // Dialog, Drawer or Popover stays open; with an empty field it reaches them (C-POPUPS).\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (event.key !== 'Escape' || event.nativeEvent.isComposing) return;\n if (!value || readOnly || disabled) return;\n event.preventDefault();\n setValue('');\n onClear?.();\n };\n\n // The whole box is the field: pressing the icon, a slot or the padding around the text focuses\n // the input, as it does in a native search field. A control inside a slot keeps its press.\n const handleRootMouseDown = (event: React.MouseEvent<HTMLDivElement>) => {\n const input = inputRef.current;\n const root = event.currentTarget;\n const target = event.target;\n if (!input || disabled || event.button !== 0 || target === input) return;\n // Events that bubble through React portals from outside this box are not ours (C-COMPOSE).\n if (!(target instanceof Element) || !root.contains(target)) return;\n const control = target.closest(INTERACTIVE_CONTENT);\n if (control && root.contains(control)) return;\n event.preventDefault(); // keeps the press from moving focus to the page\n input.focus();\n };\n\n // The slot's onClick is composed at click time (it runs first; preventDefault() cancels the\n // clear), so handleClear, which reads the input ref, is never passed to a render-time helper.\n // The slot's ref joins ours through a stable merged ref (never a new callback per render).\n const {\n onClick: slotOnClick,\n ref: slotRef,\n ...slotButtonProps\n } = dismissParts.buttonProps as UnknownProps & {\n onClick?: React.MouseEventHandler<HTMLButtonElement>;\n ref?: React.Ref<HTMLButtonElement>;\n };\n\n // C-SLOTS naming (WCAG 2.5.3 Label in Name): a consumer naming attribute names the clear button;\n // otherwise content rendered as is names it when it has a text label, and the default\n // `aria-label` would hide that label. The literal children decide on the server and on the first\n // render; after mount, the rendered button's text does (text from components, later changes).\n const hasOwnName = Object.keys(slotButtonProps).some(\n (key) => NAMING_KEYS.has(key) && slotButtonProps[key] != null,\n );\n const checksContent = dismissParts.contentMayName && !hasOwnName;\n const literalTextLabel = dismissParts.literalTextLabel;\n const [labelTarget, setLabelTarget] = React.useState<HTMLButtonElement | null>(null);\n const subscribeToContent = React.useCallback(\n (onChange: () => void) => (labelTarget ? observeTextLabel(labelTarget, onChange) : noop),\n [labelTarget],\n );\n const contentHasTextLabel = React.useSyncExternalStore(\n subscribeToContent,\n () => (labelTarget ? hasRenderedTextLabel(labelTarget) : literalTextLabel),\n () => literalTextLabel,\n );\n const namedByContent = checksContent && contentHasTextLabel;\n const clearRef = useMergedRefs<HTMLButtonElement>(\n slotRef,\n checksContent ? setLabelTarget : undefined,\n );\n\n const clearButtonProps = mergeProps(\n {\n type: 'button',\n disabled,\n 'aria-label': hasOwnName || namedByContent ? undefined : DEFAULT_CLEAR_LABEL,\n className: cn(\n searchBoxClassNames.dismissButton,\n // Padding and background set here (C-NATIVE): an app-wide `button` rule cannot fill it.\n 'me-1 flex shrink-0 items-center justify-center rounded bg-transparent p-0 text-muted-foreground',\n SEARCH_SIZE[size].clear,\n // hitAreaLayer needs a positioned element: unlike the picker buttons, the small clear\n // button sits in the row without its own position, so it sets one here.\n size === 'small' && cn('relative', hitAreaLayer),\n 'not-disabled:not-aria-disabled:hover:text-foreground',\n focusRing,\n 'disabled:cursor-not-allowed',\n mergedAriaDisabledClasses,\n ),\n },\n slotButtonProps,\n ) as React.ComponentPropsWithoutRef<'button'>;\n\n // A merged button with markup of its own (`dangerouslySetInnerHTML`) takes no children.\n const clearContent =\n clearButtonProps.dangerouslySetInnerHTML != null\n ? undefined\n : dismissKind === 'content'\n ? dismissParts.content\n : (dismissParts.content ?? (\n <DismissIcon\n size={SEARCH_SIZE[size].glyph}\n className={searchBoxClassNames.dismissIcon}\n />\n ));\n // A slot value that renders nothing is no slot (the default icon before the text, no box after).\n const hasBefore = slotRendersContent(contentBefore);\n const hasAfter = slotRendersContent(contentAfter);\n\n return (\n <div\n ref={ref}\n data-size={size}\n data-appearance={appearance}\n className={cn(\n searchBoxClassNames.root,\n // The root draws the field; the slots, the text and the clear button are laid out side by\n // side inside it, so a slot never covers the text.\n 'relative inline-flex w-full items-center',\n inputHeightClasses[size],\n inputTextClasses[size],\n inputAppearanceClasses[appearance],\n 'text-foreground',\n inputFocusWithin,\n invalidLook && inputInvalidWithin,\n // The dimmed look lifts while a focus ring shows inside the root (a clear button kept\n // focusable by a merged `disabledFocusable` Button, focusable slot content; the disabled\n // input never takes focus): opacity would dim the ring below 3:1.\n disabled && 'cursor-not-allowed opacity-50 has-focus-visible:opacity-100',\n className,\n )}\n hidden={hidden}\n {...rest}\n // Composed at press time, like the clear button's click: the handler reads the input ref.\n onMouseDown={(event) => composeEventHandlers(onMouseDown, handleRootMouseDown)(event)}\n >\n <span\n className={cn(\n searchBoxClassNames.contentBefore,\n 'flex shrink-0 items-center',\n SEARCH_SIZE[size].before,\n )}\n >\n {hasBefore ? (\n renderSlot(contentBefore, 'span', 'shrink-0')\n ) : (\n <SearchIcon size={SEARCH_SIZE[size].glyph} className=\"text-muted-foreground\" />\n )}\n </span>\n\n <input\n ref={mergedInputRef}\n type=\"search\"\n value={value}\n onChange={(event) => setValue(event.target.value)}\n placeholder={placeholder}\n disabled={disabled}\n className={cn(\n searchBoxClassNames.input,\n 'h-full min-w-0 flex-1 appearance-none border-none bg-transparent text-foreground',\n SEARCH_SIZE[size].input,\n inputTextClasses[size],\n 'placeholder:text-muted-foreground',\n 'focus:outline-hidden',\n 'disabled:cursor-not-allowed',\n '[&::-webkit-search-cancel-button]:hidden',\n )}\n aria-errormessage={ariaErrorMessage}\n aria-details={ariaDetails}\n name={name}\n form={form}\n readOnly={readOnly}\n autoComplete={autoComplete}\n autoFocus={autoFocus}\n autoCapitalize={autoCapitalize}\n autoCorrect={autoCorrect}\n inputMode={inputMode}\n enterKeyHint={enterKeyHint}\n spellCheck={spellCheck}\n maxLength={maxLength}\n minLength={minLength}\n pattern={pattern}\n tabIndex={tabIndex}\n onFocus={onFocus}\n onBlur={onBlur}\n onKeyDown={composeEventHandlers(onKeyDown, handleKeyDown)}\n onKeyUp={onKeyUp}\n {...fieldProps}\n />\n\n {hasAfter && (\n <span\n className={cn(\n searchBoxClassNames.contentAfter,\n 'flex shrink-0 items-center',\n SEARCH_SIZE[size].after,\n )}\n >\n {renderSlot(contentAfter, 'span', 'shrink-0')}\n </span>\n )}\n\n {/* No clear button while read-only: clearing would change a value the user cannot edit. */}\n {value && !readOnly ? (\n <button\n {...clearButtonProps}\n ref={clearRef}\n // mergeProps keeps a slot's `type: null`, which would drop the attribute and make the\n // button submit its form; only nullish falls back (an explicit type is kept).\n type={clearButtonProps.type ?? 'button'}\n disabled={disabled || clearButtonProps.disabled}\n onClick={(event) => composeEventHandlers(slotOnClick, handleClear)(event)}\n // A merged `disabledFocusable` Button makes the clear button unavailable but focusable\n // (spread last: it wins over `disabled` and the clear handler).\n {...(dismissParts.disabledFocusable ? MERGED_DISABLED_FOCUSABLE_PROPS : undefined)}\n >\n {clearContent}\n </button>\n ) : null}\n </div>\n );\n};\n\nSearchBox.displayName = 'SearchBox';\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/classNames.cjs"),r=require("../../lib/aria.cjs"),i=require("../../hooks/useFieldControl.cjs"),a=require("../../lib/styles.cjs"),o=require("./Input.cjs");let s=require("react");s=e.__toESM(s,1);let c=require("react/jsx-runtime");var l=({error:e,errorMessageProps:s,className:l,children:u,ref:d,id:f,"aria-label":p,"aria-labelledby":m,"aria-describedby":h,"aria-invalid":g,"aria-required":_,"aria-errormessage":v,required:y,...b})=>{let{invalid:x,messageId:S,message:C}=o.useControlErrorMessage(e,s,g,n.selectClassNames.errorMessage),w=i.useFieldControl({id:f,"aria-label":p,"aria-labelledby":m,"aria-describedby":r.joinIds(h,S),"aria-invalid":g??(x||void 0),"aria-required":_,required:y},{nativeRequired:!0}),T=o.isInvalidLook(x,w[`aria-invalid`]),E=(0,c.jsx)(`select`,{ref:d,className:t.cn(n.selectClassNames.root,`h-8 w-full appearance-none rounded border border-input border-b-stroke-accessible bg-background ps-3 pe-8 text-body-1 text-foreground`,`bg-no-repeat bg-[size:5px_5px,5px_5px] bg-[position:right_16px_center,right_11px_center] wave-rtl:bg-[position:left_11px_center,left_16px_center]`,`bg-[image:linear-gradient(45deg,transparent_50%,var(--wave-muted-foreground)_50%),linear-gradient(135deg,var(--wave-muted-foreground)_50%,transparent_50%)]`,`forced-colors:appearance-auto forced-colors:bg-none`,a.inputFocus,`disabled:cursor-not-allowed disabled:opacity-50`,T&&`border-destructive focus:border-b-destructive`,l),...b,...w,"aria-errormessage":r.joinIds(v,S),children:u});return C?(0,c.jsxs)(c.Fragment,{children:[E,C]}):E};l.displayName=`Select`,exports.Select=l;
1
+ "use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/dev.cjs"),r=require("../../lib/classNames.cjs"),i=require("../../lib/aria.cjs"),a=require("../../hooks/useFieldControl.cjs"),o=require("../../lib/styles.cjs"),s=require("./inputLook.cjs"),c=require("./Input.cjs");let l=require("react");l=e.__toESM(l,1);let u=require("react/jsx-runtime");var d={small:`ps-2 pe-6 bg-[size:4px_4px,4px_4px] bg-[position:right_12px_center,right_8px_center] wave-rtl:bg-[position:left_8px_center,left_12px_center]`,medium:`ps-3 pe-8 bg-[size:5px_5px,5px_5px] bg-[position:right_16px_center,right_11px_center] wave-rtl:bg-[position:left_11px_center,left_16px_center]`,large:`ps-4 pe-10 bg-[size:6px_6px,6px_6px] bg-[position:right_20px_center,right_14px_center] wave-rtl:bg-[position:left_14px_center,left_20px_center]`},f=({error:e,errorMessageProps:l,size:f,htmlSize:p,appearance:m,className:h,children:g,ref:_,id:v,"aria-label":y,"aria-labelledby":b,"aria-describedby":x,"aria-invalid":S,"aria-required":C,"aria-errormessage":w,required:T,...E})=>{let{invalid:D,messageId:O,message:k}=c.useControlErrorMessage(e,l,S,r.selectClassNames.errorMessage),A=a.useFieldControl({id:v,"aria-label":y,"aria-labelledby":b,"aria-describedby":i.joinIds(x,O),"aria-invalid":S??(D||void 0),"aria-required":C,required:T},{nativeRequired:!0}),j=c.isInvalidLook(D,A[`aria-invalid`]),M=s.legacyNativeSize(f),N=n.resolveDeprecatedProp(`Select`,p,M,`size={number}`,`htmlSize`),{size:P,appearance:F}=s.useInputLook(M===void 0&&typeof f!=`number`?f:void 0,m),I=(0,u.jsx)(`select`,{ref:_,"data-size":P,"data-appearance":F,className:t.cn(r.selectClassNames.root,o.inputHeightClasses[P],`w-full appearance-none`,o.inputTextClasses[P],o.inputAppearanceClasses[F],`text-foreground`,`bg-no-repeat`,d[P],`bg-[image:linear-gradient(45deg,transparent_50%,var(--wave-muted-foreground)_50%),linear-gradient(135deg,var(--wave-muted-foreground)_50%,transparent_50%)]`,`forced-colors:appearance-auto forced-colors:bg-none`,o.inputFocus,`disabled:cursor-not-allowed disabled:opacity-50`,j&&`border-destructive`,h),...E,...A,"aria-errormessage":i.joinIds(w,O),size:N,children:g});return k?(0,u.jsxs)(u.Fragment,{children:[I,k]}):I};f.displayName=`Select`,exports.Select=f;
2
2
  //# sourceMappingURL=Select.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Select.cjs","names":["useControlErrorMessage","selectClassNames","useFieldControl","joinIds","isInvalidLook","cn","inputFocus","_Fragment","require_runtime","require_cn","require_classNames","require_aria","require_useFieldControl","require_styles","require_Input","react","react_jsx_runtime","Select","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","ariaErrorMessage","props","error","errorMessageProps","fieldProps","messageId","invalid","invalidLook","control","className","message"],"sources":["../../../src/components/input/Select.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { joinIds } from '../../lib/aria';\nimport { selectClassNames } from '../../lib/classNames';\nimport { inputFocus, inputInvalid } from '../../lib/styles';\nimport { useFieldControl } from '../../hooks/useFieldControl';\nimport { isInvalidLook, useControlErrorMessage, type InputErrorMessageProps } from './Input';\n\n/** Properties for the Select component. */\nexport interface SelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> {\n /**\n * Validation error.\n * - A non-empty string renders the message in a `role=\"alert\"` element **after** the select\n * (a sibling, so `ref` and `className` stay on the select) and links it through\n * `aria-describedby` and `aria-errormessage`. Inside a `Field` that renders its own `error`,\n * the message is not repeated.\n * - `true` only marks the select invalid (`aria-invalid` and the error border), as in 0.4.\n *\n * The error border also shows whenever the select ends up `aria-invalid=\"true\"` without this\n * prop (an `error` on the surrounding `Field`, or your own `aria-invalid`).\n * Your own `aria-invalid={false}` (or `\"false\"`) wins over this prop: the select is reported\n * valid and shows neither the error border nor the message.\n */\n error?: string | boolean;\n /** Props of the error message element (`id`, `className`, …) rendered for a string `error`. */\n errorMessageProps?: InputErrorMessageProps;\n /** Ref to the `<select>` element. */\n ref?: React.Ref<HTMLSelectElement>;\n}\n\n/**\n * A native `<select>` with Fluent styling: a 1px border with an accessible bottom stroke, a token\n * chevron at the inline end and a primary bottom border while focused. Give it a name with a\n * `Field` label, `aria-label` or `aria-labelledby`. Inside a `Field` it picks up the label, hint,\n * error, `required` (native attribute) and invalid state automatically.\n *\n * @example\n * <Field label=\"Country\" required>\n * <Select defaultValue=\"\">\n * <option value=\"\" disabled>Choose a country</option>\n * <option value=\"no\">Norway</option>\n * </Select>\n * </Field>\n */\nexport const Select = ({\n error,\n errorMessageProps,\n className,\n children,\n ref,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n 'aria-errormessage': ariaErrorMessage,\n required,\n ...props\n}: SelectProps) => {\n const { invalid, messageId, message } = useControlErrorMessage(\n error,\n errorMessageProps,\n ariaInvalid,\n selectClassNames.errorMessage,\n );\n const fieldProps = useFieldControl(\n {\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': joinIds(ariaDescribedBy, messageId),\n 'aria-invalid': ariaInvalid ?? (invalid || undefined),\n 'aria-required': ariaRequired,\n required,\n },\n { nativeRequired: true },\n );\n const invalidLook = isInvalidLook(invalid, fieldProps['aria-invalid']);\n\n const control = (\n <select\n ref={ref}\n className={cn(\n selectClassNames.root,\n 'h-8 w-full appearance-none rounded border border-input border-b-stroke-accessible bg-background ps-3 pe-8 text-body-1 text-foreground',\n // Chevron: two token-colored gradient halves of a small triangle at the inline end.\n 'bg-no-repeat bg-[size:5px_5px,5px_5px] bg-[position:right_16px_center,right_11px_center] wave-rtl:bg-[position:left_11px_center,left_16px_center]',\n 'bg-[image:linear-gradient(45deg,transparent_50%,var(--wave-muted-foreground)_50%),linear-gradient(135deg,var(--wave-muted-foreground)_50%,transparent_50%)]',\n // Forced colors drop the background chevron: show the native arrow instead.\n 'forced-colors:appearance-auto forced-colors:bg-none',\n inputFocus,\n 'disabled:cursor-not-allowed disabled:opacity-50',\n invalidLook && inputInvalid,\n className,\n )}\n {...props}\n {...fieldProps}\n aria-errormessage={joinIds(ariaErrorMessage, messageId)}\n >\n {children}\n </select>\n );\n\n if (!message) return control;\n return (\n <>\n {control}\n {message}\n </>\n );\n};\n\nSelect.displayName = 'Select';\n"],"mappings":"4VA4CA,IAAaiB,GAAU,CACrB,QACA,oBACA,YACA,WACA,MACA,KACA,aAAcC,EACd,kBAAmBC,EACnB,mBAAoBC,EACpB,eAAgBC,EAChB,gBAAiBC,EACjB,oBAAqBC,EACrB,WACA,GAAGC,KACc,CACjB,GAAM,CAAE,UAAS,YAAW,WAAYxB,EAAAA,uBACtCyB,EACAC,EACAL,EACApB,EAAAA,iBAAiB,YACnB,EACM0B,EAAazB,EAAAA,gBACjB,CACE,KACA,aAAcgB,EACd,kBAAmBC,EACnB,mBAAoBhB,EAAAA,QAAQiB,EAAiBQ,CAAS,EACtD,eAAgBP,IAAgBQ,GAAW,IAAA,IAC3C,gBAAiBP,EACjB,UACF,EACA,CAAE,eAAgB,EAAK,CACzB,EACMQ,EAAc1B,EAAAA,cAAcyB,EAASF,EAAW,eAAe,EAE/DI,GACJ,EAAAf,EAAA,IAAA,CAAC,SAAD,CACO,MACL,UAAWX,EAAAA,GACTJ,EAAAA,iBAAiB,KACjB,wIAEA,oJACA,8JAEA,sDACAK,EAAAA,WACA,kDACAwB,GAAA,gDACAE,CACF,EACA,GAAIR,EACJ,GAAIG,EACJ,oBAAmBxB,EAAAA,QAAQoB,EAAkBK,CAAS,EAErD,UACK,CAAA,EAIV,OADKK,GAEH,EAAAjB,EAAA,KAAA,CAAAT,EAAAA,SAAA,CAAA,SAAA,CACGwB,EACAE,CACD,CAAA,CAAA,EALiBF,CAOvB,EAEA,EAAO,YAAc"}
1
+ {"version":3,"file":"Select.cjs","names":["useControlErrorMessage","selectClassNames","useFieldControl","joinIds","isInvalidLook","legacyNativeSize","resolveDeprecatedProp","useInputLook","cn","inputHeightClasses","inputTextClasses","inputAppearanceClasses","inputFocus","_Fragment","require_runtime","require_cn","require_dev","require_classNames","require_aria","require_useFieldControl","require_styles","require_inputLook","require_Input","react","react_jsx_runtime","SELECT_SIZE","Select","sizeProp","appearanceProp","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","ariaErrorMessage","props","error","errorMessageProps","fieldProps","messageId","invalid","invalidLook","numericSize","nativeSize","htmlSize","control","size","appearance","className","message"],"sources":["../../../src/components/input/Select.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { joinIds } from '../../lib/aria';\nimport { selectClassNames } from '../../lib/classNames';\nimport { resolveDeprecatedProp } from '../../lib/dev';\nimport {\n inputAppearanceClasses,\n inputFocus,\n inputHeightClasses,\n inputInvalid,\n inputTextClasses,\n} from '../../lib/styles';\nimport type { CoreSize, InputAppearance } from '../../lib/types';\nimport { useFieldControl } from '../../hooks/useFieldControl';\nimport { isInvalidLook, useControlErrorMessage, type InputErrorMessageProps } from './Input';\nimport { legacyNativeSize, useInputLook } from './inputLook';\n\n/** Properties for the Select component. */\nexport interface SelectProps extends Omit<React.SelectHTMLAttributes<HTMLSelectElement>, 'size'> {\n /**\n * Validation error.\n * - A non-empty string renders the message in a `role=\"alert\"` element **after** the select\n * (a sibling, so `ref` and `className` stay on the select) and links it through\n * `aria-describedby` and `aria-errormessage`. Inside a `Field` that renders its own `error`,\n * the message is not repeated.\n * - `true` only marks the select invalid (`aria-invalid` and the error border), as in 0.4.\n *\n * The error border also shows whenever the select ends up `aria-invalid=\"true\"` without this\n * prop (an `error` on the surrounding `Field`, or your own `aria-invalid`).\n * Your own `aria-invalid={false}` (or `\"false\"`) wins over this prop: the select is reported\n * valid and shows neither the error border nor the message.\n */\n error?: string | boolean;\n /** Props of the error message element (`id`, `className`, …) rendered for a string `error`. */\n errorMessageProps?: InputErrorMessageProps;\n /**\n * Size of the field: `small` (24px tall), `medium` (32px) or `large` (40px). Default: the\n * surrounding Field's `size`, else `WaveProvider inputDefaults.size`, else `'medium'`.\n *\n * A number is the native `size` attribute (the number of visible rows), as in 0.8: it still\n * renders, warns once in development and is removed in 1.0. Use `htmlSize` for it.\n * A string of digits only (`size=\"20\"` from untyped code) counts as that number. Any other value\n * outside the three sizes renders as if `size` were not set.\n */\n size?: CoreSize | number;\n /** The native `size` attribute: the number of visible rows. */\n htmlSize?: number;\n /**\n * Look of the field: `outline` (a full border), `underline` (a bottom stroke only),\n * `filled-darker` or `filled-lighter` (a fill without a visible stroke: give the field a visible\n * label). Default: `WaveProvider inputDefaults.appearance`, else `'outline'`.\n */\n appearance?: InputAppearance;\n /** Ref to the `<select>` element. */\n ref?: React.Ref<HTMLSelectElement>;\n}\n\n/** Inline paddings and chevron geometry of each size (medium is the 0.7 look). */\nconst SELECT_SIZE: Readonly<Record<CoreSize, string>> = {\n small:\n 'ps-2 pe-6 bg-[size:4px_4px,4px_4px] bg-[position:right_12px_center,right_8px_center] wave-rtl:bg-[position:left_8px_center,left_12px_center]',\n medium:\n 'ps-3 pe-8 bg-[size:5px_5px,5px_5px] bg-[position:right_16px_center,right_11px_center] wave-rtl:bg-[position:left_11px_center,left_16px_center]',\n large:\n 'ps-4 pe-10 bg-[size:6px_6px,6px_6px] bg-[position:right_20px_center,right_14px_center] wave-rtl:bg-[position:left_14px_center,left_20px_center]',\n};\n\n/**\n * A native `<select>` with Fluent styling: a 1px border with an accessible bottom stroke, a token\n * chevron at the inline end and a primary bottom border while focused. Give it a name with a\n * `Field` label, `aria-label` or `aria-labelledby`. Inside a `Field` it picks up the label, hint,\n * error, `required` (native attribute) and invalid state automatically.\n *\n * `size` resolves from its own prop, then the surrounding `Field`'s `size`, then\n * `WaveProvider inputDefaults.size`, else `'medium'`; `appearance` from its own prop, then\n * `WaveProvider inputDefaults.appearance`, else `'outline'`; both render as `data-size` and\n * `data-appearance` on the `<select>`.\n *\n * @example\n * <Field label=\"Country\" required>\n * <Select defaultValue=\"\">\n * <option value=\"\" disabled>Choose a country</option>\n * <option value=\"no\">Norway</option>\n * </Select>\n * </Field>\n */\nexport const Select = ({\n error,\n errorMessageProps,\n size: sizeProp,\n htmlSize,\n appearance: appearanceProp,\n className,\n children,\n ref,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n 'aria-errormessage': ariaErrorMessage,\n required,\n ...props\n}: SelectProps) => {\n const { invalid, messageId, message } = useControlErrorMessage(\n error,\n errorMessageProps,\n ariaInvalid,\n selectClassNames.errorMessage,\n );\n const fieldProps = useFieldControl(\n {\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': joinIds(ariaDescribedBy, messageId),\n 'aria-invalid': ariaInvalid ?? (invalid || undefined),\n 'aria-required': ariaRequired,\n required,\n },\n { nativeRequired: true },\n );\n const invalidLook = isInvalidLook(invalid, fieldProps['aria-invalid']);\n const numericSize = legacyNativeSize(sizeProp);\n const nativeSize = resolveDeprecatedProp(\n 'Select',\n htmlSize,\n numericSize,\n 'size={number}',\n 'htmlSize',\n );\n const { size, appearance } = useInputLook(\n numericSize === undefined && typeof sizeProp !== 'number' ? sizeProp : undefined,\n appearanceProp,\n );\n\n const control = (\n <select\n ref={ref}\n data-size={size}\n data-appearance={appearance}\n className={cn(\n selectClassNames.root,\n inputHeightClasses[size],\n 'w-full appearance-none',\n inputTextClasses[size],\n inputAppearanceClasses[appearance],\n 'text-foreground',\n // Chevron: two token-colored gradient halves of a small triangle at the inline end.\n 'bg-no-repeat',\n SELECT_SIZE[size],\n 'bg-[image:linear-gradient(45deg,transparent_50%,var(--wave-muted-foreground)_50%),linear-gradient(135deg,var(--wave-muted-foreground)_50%,transparent_50%)]',\n // Forced colors drop the background chevron: show the native arrow instead.\n 'forced-colors:appearance-auto forced-colors:bg-none',\n inputFocus,\n 'disabled:cursor-not-allowed disabled:opacity-50',\n invalidLook && inputInvalid,\n className,\n )}\n {...props}\n {...fieldProps}\n aria-errormessage={joinIds(ariaErrorMessage, messageId)}\n size={nativeSize}\n >\n {children}\n </select>\n );\n\n if (!message) return control;\n return (\n <>\n {control}\n {message}\n </>\n );\n};\n\nSelect.displayName = 'Select';\n"],"mappings":"wZA0DA,IAAMyB,EAAkD,CACtD,MACE,+IACF,OACE,iJACF,MACE,iJACJ,EAqBaC,GAAU,CACrB,QACA,oBACA,KAAMC,EACN,WACA,WAAYC,EACZ,YACA,WACA,MACA,KACA,aAAcC,EACd,kBAAmBC,EACnB,mBAAoBC,EACpB,eAAgBC,EAChB,gBAAiBC,EACjB,oBAAqBC,EACrB,WACA,GAAGC,KACc,CACjB,GAAM,CAAE,UAAS,YAAW,WAAYnC,EAAAA,uBACtCoC,EACAC,EACAL,EACA/B,EAAAA,iBAAiB,YACnB,EACMqC,EAAapC,EAAAA,gBACjB,CACE,KACA,aAAc2B,EACd,kBAAmBC,EACnB,mBAAoB3B,EAAAA,QAAQ4B,EAAiBQ,CAAS,EACtD,eAAgBP,IAAgBQ,GAAW,IAAA,IAC3C,gBAAiBP,EACjB,UACF,EACA,CAAE,eAAgB,EAAK,CACzB,EACMQ,EAAcrC,EAAAA,cAAcoC,EAASF,EAAW,eAAe,EAC/DI,EAAcrC,EAAAA,iBAAiBsB,CAAQ,EACvCgB,EAAarC,EAAAA,sBACjB,SACAsC,EACAF,EACA,gBACA,UACF,EACM,CAAE,OAAM,cAAenC,EAAAA,aAC3BmC,IAAgB,IAAA,IAAa,OAAOf,GAAa,SAAWA,EAAW,IAAA,GACvEC,CACF,EAEMiB,GACJ,EAAArB,EAAA,IAAA,CAAC,SAAD,CACO,MACL,YAAWsB,EACX,kBAAiBC,EACjB,UAAWvC,EAAAA,GACTP,EAAAA,iBAAiB,KACjBQ,EAAAA,mBAAmBqC,GACnB,yBACApC,EAAAA,iBAAiBoC,GACjBnC,EAAAA,uBAAuBoC,GACvB,kBAEA,eACAtB,EAAYqB,GACZ,8JAEA,sDACAlC,EAAAA,WACA,kDACA6B,GAAA,qBACAO,CACF,EACA,GAAIb,EACJ,GAAIG,EACJ,oBAAmBnC,EAAAA,QAAQ+B,EAAkBK,CAAS,EACtD,KAAMI,EAEL,UACK,CAAA,EAIV,OADKM,GAEH,EAAAzB,EAAA,KAAA,CAAAX,EAAAA,SAAA,CAAA,SAAA,CACGgC,EACAI,CACD,CAAA,CAAA,EALiBJ,CAOvB,EAEA,EAAO,YAAc"}
@@ -1,34 +1,43 @@
1
1
  "use client";
2
2
  import { cn as e } from "../../lib/cn.mjs";
3
- import { selectClassNames as t } from "../../lib/classNames.mjs";
4
- import { joinIds as n } from "../../lib/aria.mjs";
5
- import { useFieldControl as r } from "../../hooks/useFieldControl.mjs";
6
- import { inputFocus as i } from "../../lib/styles.mjs";
7
- import { isInvalidLook as a, useControlErrorMessage as o } from "./Input.mjs";
3
+ import { resolveDeprecatedProp as t } from "../../lib/dev.mjs";
4
+ import { selectClassNames as n } from "../../lib/classNames.mjs";
5
+ import { joinIds as r } from "../../lib/aria.mjs";
6
+ import { useFieldControl as i } from "../../hooks/useFieldControl.mjs";
7
+ import { inputAppearanceClasses as a, inputFocus as o, inputHeightClasses as s, inputTextClasses as c } from "../../lib/styles.mjs";
8
+ import { legacyNativeSize as l, useInputLook as u } from "./inputLook.mjs";
9
+ import { isInvalidLook as d, useControlErrorMessage as f } from "./Input.mjs";
8
10
  import "react";
9
- import { Fragment as s, jsx as c, jsxs as l } from "react/jsx-runtime";
11
+ import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
10
12
  //#region src/components/input/Select.tsx
11
- var u = ({ error: u, errorMessageProps: d, className: f, children: p, ref: m, id: h, "aria-label": g, "aria-labelledby": _, "aria-describedby": v, "aria-invalid": y, "aria-required": b, "aria-errormessage": x, required: S, ...C }) => {
12
- let { invalid: w, messageId: T, message: E } = o(u, d, y, t.errorMessage), D = r({
13
- id: h,
14
- "aria-label": g,
15
- "aria-labelledby": _,
16
- "aria-describedby": n(v, T),
17
- "aria-invalid": y ?? (w || void 0),
18
- "aria-required": b,
19
- required: S
20
- }, { nativeRequired: !0 }), O = a(w, D["aria-invalid"]), k = /* @__PURE__ */ c("select", {
21
- ref: m,
22
- className: e(t.root, "h-8 w-full appearance-none rounded border border-input border-b-stroke-accessible bg-background ps-3 pe-8 text-body-1 text-foreground", "bg-no-repeat bg-[size:5px_5px,5px_5px] bg-[position:right_16px_center,right_11px_center] wave-rtl:bg-[position:left_11px_center,left_16px_center]", "bg-[image:linear-gradient(45deg,transparent_50%,var(--wave-muted-foreground)_50%),linear-gradient(135deg,var(--wave-muted-foreground)_50%,transparent_50%)]", "forced-colors:appearance-auto forced-colors:bg-none", i, "disabled:cursor-not-allowed disabled:opacity-50", O && "border-destructive focus:border-b-destructive", f),
23
- ...C,
24
- ...D,
25
- "aria-errormessage": n(x, T),
26
- children: p
13
+ var g = {
14
+ small: "ps-2 pe-6 bg-[size:4px_4px,4px_4px] bg-[position:right_12px_center,right_8px_center] wave-rtl:bg-[position:left_8px_center,left_12px_center]",
15
+ medium: "ps-3 pe-8 bg-[size:5px_5px,5px_5px] bg-[position:right_16px_center,right_11px_center] wave-rtl:bg-[position:left_11px_center,left_16px_center]",
16
+ large: "ps-4 pe-10 bg-[size:6px_6px,6px_6px] bg-[position:right_20px_center,right_14px_center] wave-rtl:bg-[position:left_14px_center,left_20px_center]"
17
+ }, _ = ({ error: _, errorMessageProps: v, size: y, htmlSize: b, appearance: x, className: S, children: C, ref: w, id: T, "aria-label": E, "aria-labelledby": D, "aria-describedby": O, "aria-invalid": k, "aria-required": A, "aria-errormessage": j, required: M, ...N }) => {
18
+ let { invalid: P, messageId: F, message: I } = f(_, v, k, n.errorMessage), L = i({
19
+ id: T,
20
+ "aria-label": E,
21
+ "aria-labelledby": D,
22
+ "aria-describedby": r(O, F),
23
+ "aria-invalid": k ?? (P || void 0),
24
+ "aria-required": A,
25
+ required: M
26
+ }, { nativeRequired: !0 }), R = d(P, L["aria-invalid"]), z = l(y), B = t("Select", b, z, "size={number}", "htmlSize"), { size: V, appearance: H } = u(z === void 0 && typeof y != "number" ? y : void 0, x), U = /* @__PURE__ */ m("select", {
27
+ ref: w,
28
+ "data-size": V,
29
+ "data-appearance": H,
30
+ className: e(n.root, s[V], "w-full appearance-none", c[V], a[H], "text-foreground", "bg-no-repeat", g[V], "bg-[image:linear-gradient(45deg,transparent_50%,var(--wave-muted-foreground)_50%),linear-gradient(135deg,var(--wave-muted-foreground)_50%,transparent_50%)]", "forced-colors:appearance-auto forced-colors:bg-none", o, "disabled:cursor-not-allowed disabled:opacity-50", R && "border-destructive", S),
31
+ ...N,
32
+ ...L,
33
+ "aria-errormessage": r(j, F),
34
+ size: B,
35
+ children: C
27
36
  });
28
- return E ? /* @__PURE__ */ l(s, { children: [k, E] }) : k;
37
+ return I ? /* @__PURE__ */ h(p, { children: [U, I] }) : U;
29
38
  };
30
- u.displayName = "Select";
39
+ _.displayName = "Select";
31
40
  //#endregion
32
- export { u as Select };
41
+ export { _ as Select };
33
42
 
34
43
  //# sourceMappingURL=Select.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Select.mjs","names":["_Fragment","Select","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","ariaErrorMessage","props","useControlErrorMessage","error","errorMessageProps","selectClassNames","fieldProps","useFieldControl","joinIds","messageId","invalid","invalidLook","isInvalidLook","control","cn","inputFocus","className","message","Fragment"],"sources":["../../../src/components/input/Select.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { joinIds } from '../../lib/aria';\nimport { selectClassNames } from '../../lib/classNames';\nimport { inputFocus, inputInvalid } from '../../lib/styles';\nimport { useFieldControl } from '../../hooks/useFieldControl';\nimport { isInvalidLook, useControlErrorMessage, type InputErrorMessageProps } from './Input';\n\n/** Properties for the Select component. */\nexport interface SelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> {\n /**\n * Validation error.\n * - A non-empty string renders the message in a `role=\"alert\"` element **after** the select\n * (a sibling, so `ref` and `className` stay on the select) and links it through\n * `aria-describedby` and `aria-errormessage`. Inside a `Field` that renders its own `error`,\n * the message is not repeated.\n * - `true` only marks the select invalid (`aria-invalid` and the error border), as in 0.4.\n *\n * The error border also shows whenever the select ends up `aria-invalid=\"true\"` without this\n * prop (an `error` on the surrounding `Field`, or your own `aria-invalid`).\n * Your own `aria-invalid={false}` (or `\"false\"`) wins over this prop: the select is reported\n * valid and shows neither the error border nor the message.\n */\n error?: string | boolean;\n /** Props of the error message element (`id`, `className`, …) rendered for a string `error`. */\n errorMessageProps?: InputErrorMessageProps;\n /** Ref to the `<select>` element. */\n ref?: React.Ref<HTMLSelectElement>;\n}\n\n/**\n * A native `<select>` with Fluent styling: a 1px border with an accessible bottom stroke, a token\n * chevron at the inline end and a primary bottom border while focused. Give it a name with a\n * `Field` label, `aria-label` or `aria-labelledby`. Inside a `Field` it picks up the label, hint,\n * error, `required` (native attribute) and invalid state automatically.\n *\n * @example\n * <Field label=\"Country\" required>\n * <Select defaultValue=\"\">\n * <option value=\"\" disabled>Choose a country</option>\n * <option value=\"no\">Norway</option>\n * </Select>\n * </Field>\n */\nexport const Select = ({\n error,\n errorMessageProps,\n className,\n children,\n ref,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n 'aria-errormessage': ariaErrorMessage,\n required,\n ...props\n}: SelectProps) => {\n const { invalid, messageId, message } = useControlErrorMessage(\n error,\n errorMessageProps,\n ariaInvalid,\n selectClassNames.errorMessage,\n );\n const fieldProps = useFieldControl(\n {\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': joinIds(ariaDescribedBy, messageId),\n 'aria-invalid': ariaInvalid ?? (invalid || undefined),\n 'aria-required': ariaRequired,\n required,\n },\n { nativeRequired: true },\n );\n const invalidLook = isInvalidLook(invalid, fieldProps['aria-invalid']);\n\n const control = (\n <select\n ref={ref}\n className={cn(\n selectClassNames.root,\n 'h-8 w-full appearance-none rounded border border-input border-b-stroke-accessible bg-background ps-3 pe-8 text-body-1 text-foreground',\n // Chevron: two token-colored gradient halves of a small triangle at the inline end.\n 'bg-no-repeat bg-[size:5px_5px,5px_5px] bg-[position:right_16px_center,right_11px_center] wave-rtl:bg-[position:left_11px_center,left_16px_center]',\n 'bg-[image:linear-gradient(45deg,transparent_50%,var(--wave-muted-foreground)_50%),linear-gradient(135deg,var(--wave-muted-foreground)_50%,transparent_50%)]',\n // Forced colors drop the background chevron: show the native arrow instead.\n 'forced-colors:appearance-auto forced-colors:bg-none',\n inputFocus,\n 'disabled:cursor-not-allowed disabled:opacity-50',\n invalidLook && inputInvalid,\n className,\n )}\n {...props}\n {...fieldProps}\n aria-errormessage={joinIds(ariaErrorMessage, messageId)}\n >\n {children}\n </select>\n );\n\n if (!message) return control;\n return (\n <>\n {control}\n {message}\n </>\n );\n};\n\nSelect.displayName = 'Select';\n"],"mappings":";;;;;;;;;;AA4CA,IAAaC,KAAU,EACrB,UACA,sBACA,cACA,aACA,QACA,OACA,cAAcC,GACd,mBAAmBC,GACnB,oBAAoBC,GACpB,gBAAgBC,GAChB,iBAAiBC,GACjB,qBAAqBC,GACrB,aACA,GAAGC,QACc;CACjB,IAAM,EAAE,YAAS,cAAW,eAAYC,EACtCC,GACAC,GACAN,GACAO,EAAiB,YACnB,GACMC,IAAaC,EACjB;EACE;EACA,cAAcZ;EACd,mBAAmBC;EACnB,oBAAoBY,EAAQX,GAAiBY,CAAS;EACtD,gBAAgBX,MAAgBY,KAAW,KAAA;EAC3C,iBAAiBX;EACjB;CACF,GACA,EAAE,gBAAgB,GAAK,CACzB,GACMY,IAAcC,EAAcF,GAASJ,EAAW,eAAe,GAE/DO,IACJ,kBAAC,UAAD;EACO;EACL,WAAWC,EACTT,EAAiB,MACjB,yIAEA,qJACA,+JAEA,uDACAU,GACA,mDACAJ,KAAA,iDACAK,CACF;EACA,GAAIf;EACJ,GAAIK;EACJ,qBAAmBE,EAAQR,GAAkBS,CAAS;EAErD;CACK,CAAA;CAIV,OADKQ,IAEH,kBAAAxB,GAAA,EAAA,UAAA,CACGoB,GACAI,CACD,EAAA,CAAA,IALiBJ;AAOvB;AAEA,EAAO,cAAc"}
1
+ {"version":3,"file":"Select.mjs","names":["_Fragment","SELECT_SIZE","Select","sizeProp","appearanceProp","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","ariaErrorMessage","props","useControlErrorMessage","error","errorMessageProps","selectClassNames","fieldProps","useFieldControl","joinIds","messageId","invalid","invalidLook","isInvalidLook","numericSize","legacyNativeSize","nativeSize","resolveDeprecatedProp","htmlSize","useInputLook","control","size","appearance","cn","inputHeightClasses","inputTextClasses","inputAppearanceClasses","inputFocus","className","message","Fragment"],"sources":["../../../src/components/input/Select.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { joinIds } from '../../lib/aria';\nimport { selectClassNames } from '../../lib/classNames';\nimport { resolveDeprecatedProp } from '../../lib/dev';\nimport {\n inputAppearanceClasses,\n inputFocus,\n inputHeightClasses,\n inputInvalid,\n inputTextClasses,\n} from '../../lib/styles';\nimport type { CoreSize, InputAppearance } from '../../lib/types';\nimport { useFieldControl } from '../../hooks/useFieldControl';\nimport { isInvalidLook, useControlErrorMessage, type InputErrorMessageProps } from './Input';\nimport { legacyNativeSize, useInputLook } from './inputLook';\n\n/** Properties for the Select component. */\nexport interface SelectProps extends Omit<React.SelectHTMLAttributes<HTMLSelectElement>, 'size'> {\n /**\n * Validation error.\n * - A non-empty string renders the message in a `role=\"alert\"` element **after** the select\n * (a sibling, so `ref` and `className` stay on the select) and links it through\n * `aria-describedby` and `aria-errormessage`. Inside a `Field` that renders its own `error`,\n * the message is not repeated.\n * - `true` only marks the select invalid (`aria-invalid` and the error border), as in 0.4.\n *\n * The error border also shows whenever the select ends up `aria-invalid=\"true\"` without this\n * prop (an `error` on the surrounding `Field`, or your own `aria-invalid`).\n * Your own `aria-invalid={false}` (or `\"false\"`) wins over this prop: the select is reported\n * valid and shows neither the error border nor the message.\n */\n error?: string | boolean;\n /** Props of the error message element (`id`, `className`, …) rendered for a string `error`. */\n errorMessageProps?: InputErrorMessageProps;\n /**\n * Size of the field: `small` (24px tall), `medium` (32px) or `large` (40px). Default: the\n * surrounding Field's `size`, else `WaveProvider inputDefaults.size`, else `'medium'`.\n *\n * A number is the native `size` attribute (the number of visible rows), as in 0.8: it still\n * renders, warns once in development and is removed in 1.0. Use `htmlSize` for it.\n * A string of digits only (`size=\"20\"` from untyped code) counts as that number. Any other value\n * outside the three sizes renders as if `size` were not set.\n */\n size?: CoreSize | number;\n /** The native `size` attribute: the number of visible rows. */\n htmlSize?: number;\n /**\n * Look of the field: `outline` (a full border), `underline` (a bottom stroke only),\n * `filled-darker` or `filled-lighter` (a fill without a visible stroke: give the field a visible\n * label). Default: `WaveProvider inputDefaults.appearance`, else `'outline'`.\n */\n appearance?: InputAppearance;\n /** Ref to the `<select>` element. */\n ref?: React.Ref<HTMLSelectElement>;\n}\n\n/** Inline paddings and chevron geometry of each size (medium is the 0.7 look). */\nconst SELECT_SIZE: Readonly<Record<CoreSize, string>> = {\n small:\n 'ps-2 pe-6 bg-[size:4px_4px,4px_4px] bg-[position:right_12px_center,right_8px_center] wave-rtl:bg-[position:left_8px_center,left_12px_center]',\n medium:\n 'ps-3 pe-8 bg-[size:5px_5px,5px_5px] bg-[position:right_16px_center,right_11px_center] wave-rtl:bg-[position:left_11px_center,left_16px_center]',\n large:\n 'ps-4 pe-10 bg-[size:6px_6px,6px_6px] bg-[position:right_20px_center,right_14px_center] wave-rtl:bg-[position:left_14px_center,left_20px_center]',\n};\n\n/**\n * A native `<select>` with Fluent styling: a 1px border with an accessible bottom stroke, a token\n * chevron at the inline end and a primary bottom border while focused. Give it a name with a\n * `Field` label, `aria-label` or `aria-labelledby`. Inside a `Field` it picks up the label, hint,\n * error, `required` (native attribute) and invalid state automatically.\n *\n * `size` resolves from its own prop, then the surrounding `Field`'s `size`, then\n * `WaveProvider inputDefaults.size`, else `'medium'`; `appearance` from its own prop, then\n * `WaveProvider inputDefaults.appearance`, else `'outline'`; both render as `data-size` and\n * `data-appearance` on the `<select>`.\n *\n * @example\n * <Field label=\"Country\" required>\n * <Select defaultValue=\"\">\n * <option value=\"\" disabled>Choose a country</option>\n * <option value=\"no\">Norway</option>\n * </Select>\n * </Field>\n */\nexport const Select = ({\n error,\n errorMessageProps,\n size: sizeProp,\n htmlSize,\n appearance: appearanceProp,\n className,\n children,\n ref,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n 'aria-errormessage': ariaErrorMessage,\n required,\n ...props\n}: SelectProps) => {\n const { invalid, messageId, message } = useControlErrorMessage(\n error,\n errorMessageProps,\n ariaInvalid,\n selectClassNames.errorMessage,\n );\n const fieldProps = useFieldControl(\n {\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': joinIds(ariaDescribedBy, messageId),\n 'aria-invalid': ariaInvalid ?? (invalid || undefined),\n 'aria-required': ariaRequired,\n required,\n },\n { nativeRequired: true },\n );\n const invalidLook = isInvalidLook(invalid, fieldProps['aria-invalid']);\n const numericSize = legacyNativeSize(sizeProp);\n const nativeSize = resolveDeprecatedProp(\n 'Select',\n htmlSize,\n numericSize,\n 'size={number}',\n 'htmlSize',\n );\n const { size, appearance } = useInputLook(\n numericSize === undefined && typeof sizeProp !== 'number' ? sizeProp : undefined,\n appearanceProp,\n );\n\n const control = (\n <select\n ref={ref}\n data-size={size}\n data-appearance={appearance}\n className={cn(\n selectClassNames.root,\n inputHeightClasses[size],\n 'w-full appearance-none',\n inputTextClasses[size],\n inputAppearanceClasses[appearance],\n 'text-foreground',\n // Chevron: two token-colored gradient halves of a small triangle at the inline end.\n 'bg-no-repeat',\n SELECT_SIZE[size],\n 'bg-[image:linear-gradient(45deg,transparent_50%,var(--wave-muted-foreground)_50%),linear-gradient(135deg,var(--wave-muted-foreground)_50%,transparent_50%)]',\n // Forced colors drop the background chevron: show the native arrow instead.\n 'forced-colors:appearance-auto forced-colors:bg-none',\n inputFocus,\n 'disabled:cursor-not-allowed disabled:opacity-50',\n invalidLook && inputInvalid,\n className,\n )}\n {...props}\n {...fieldProps}\n aria-errormessage={joinIds(ariaErrorMessage, messageId)}\n size={nativeSize}\n >\n {children}\n </select>\n );\n\n if (!message) return control;\n return (\n <>\n {control}\n {message}\n </>\n );\n};\n\nSelect.displayName = 'Select';\n"],"mappings":";;;;;;;;;;;;AA0DA,IAAMC,IAAkD;CACtD,OACE;CACF,QACE;CACF,OACE;AACJ,GAqBaC,KAAU,EACrB,UACA,sBACA,MAAMC,GACN,aACA,YAAYC,GACZ,cACA,aACA,QACA,OACA,cAAcC,GACd,mBAAmBC,GACnB,oBAAoBC,GACpB,gBAAgBC,GAChB,iBAAiBC,GACjB,qBAAqBC,GACrB,aACA,GAAGC,QACc;CACjB,IAAM,EAAE,YAAS,cAAW,eAAYC,EACtCC,GACAC,GACAN,GACAO,EAAiB,YACnB,GACMC,IAAaC,EACjB;EACE;EACA,cAAcZ;EACd,mBAAmBC;EACnB,oBAAoBY,EAAQX,GAAiBY,CAAS;EACtD,gBAAgBX,MAAgBY,KAAW,KAAA;EAC3C,iBAAiBX;EACjB;CACF,GACA,EAAE,gBAAgB,GAAK,CACzB,GACMY,IAAcC,EAAcF,GAASJ,EAAW,eAAe,GAC/DO,IAAcC,EAAiBrB,CAAQ,GACvCsB,IAAaC,EACjB,UACAC,GACAJ,GACA,iBACA,UACF,GACM,EAAE,SAAM,kBAAeK,EAC3BL,MAAgB,KAAA,KAAa,OAAOpB,KAAa,WAAWA,IAAW,KAAA,GACvEC,CACF,GAEMyB,IACJ,kBAAC,UAAD;EACO;EACL,aAAWC;EACX,mBAAiBC;EACjB,WAAWC,EACTjB,EAAiB,MACjBkB,EAAmBH,IACnB,0BACAI,EAAiBJ,IACjBK,EAAuBJ,IACvB,mBAEA,gBACA9B,EAAY6B,IACZ,+JAEA,uDACAM,GACA,mDACAf,KAAA,sBACAgB,CACF;EACA,GAAI1B;EACJ,GAAIK;EACJ,qBAAmBE,EAAQR,GAAkBS,CAAS;EACtD,MAAMM;EAEL;CACK,CAAA;CAIV,OADKa,IAEH,kBAAAtC,GAAA,EAAA,UAAA,CACG6B,GACAS,CACD,EAAA,CAAA,IALiBT;AAOvB;AAEA,EAAO,cAAc"}
@@ -1,2 +1,2 @@
1
- "use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/composeEventHandlers.cjs"),r=require("../../lib/classNames.cjs"),i=require("../../hooks/useEventCallback.cjs"),a=require("../../hooks/useMergedRefs.cjs"),o=require("../../hooks/useFieldControl.cjs"),s=require("../../lib/styles.cjs"),c=require("../../hooks/useFormReset.cjs");let l=require("react");l=e.__toESM(l,1);let u=require("react/jsx-runtime");var d=`--wave-slider-progress`;function f(e,t,n){let r=n>t?(e-t)/(n-t)*100:0;return`${Number.isFinite(r)?Math.min(100,Math.max(0,r)):0}%`}var p=[`[&::-webkit-slider-runnable-track]:h-1 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-stroke-accessible`,`[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_right,var(--wave-primary)_var(--wave-slider-progress),var(--wave-stroke-accessible)_var(--wave-slider-progress))]`,`wave-rtl:[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_left,var(--wave-primary)_var(--wave-slider-progress),var(--wave-stroke-accessible)_var(--wave-slider-progress))]`,`[&::-moz-range-track]:h-1 [&::-moz-range-track]:rounded-full [&::-moz-range-track]:bg-stroke-accessible`,`[&::-moz-range-progress]:h-1 [&::-moz-range-progress]:rounded-full [&::-moz-range-progress]:bg-primary`],m=[`forced-colors:[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_right,Highlight_var(--wave-slider-progress),CanvasText_var(--wave-slider-progress))]`,`forced-colors:wave-rtl:[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_left,Highlight_var(--wave-slider-progress),CanvasText_var(--wave-slider-progress))]`,`forced-colors:[&::-moz-range-progress]:bg-[Highlight]`,`forced-colors:disabled:[&::-webkit-slider-runnable-track]:bg-none forced-colors:disabled:[&::-moz-range-progress]:bg-[GrayText]`],h=({className:e,style:h,label:g,value:_,defaultValue:v,min:y,max:b,step:x,form:S,onChange:C,onValueChange:w,ref:T,id:E,"aria-label":D,"aria-labelledby":O,"aria-describedby":k,"aria-invalid":A,"aria-required":j,required:M,...N})=>{let P=o.useFieldControl({id:E,"aria-label":D??g,"aria-labelledby":O,"aria-describedby":k,"aria-invalid":A,"aria-required":j,required:M},{nativeRequired:!0}),F=l.useRef(null),I=a.useMergedRefs(F,T),L=y??0,R=b??100,z=f(_??v??L+(R-L)/2,L,R),B=i.useEventCallback(()=>{let e=F.current;if(!e)return;let t=f(Number(e.value),L,R);e.style.getPropertyValue(d)!==t&&e.style.setProperty(d,t)});l.useLayoutEffect(()=>{B()},[_,v,y,b,x,B]),c.useFormReset(F,()=>queueMicrotask(B),S);let V=n.composeEventHandlers(C,e=>{_===void 0&&B(),w?.(Number(e.currentTarget.value))},{checkDefaultPrevented:!1});return(0,u.jsx)(`input`,{ref:I,type:`range`,className:t.cn(r.sliderClassNames.root,`w-full cursor-pointer appearance-none bg-transparent`,p,`[&::-webkit-slider-thumb]:-mt-2 [&::-webkit-slider-thumb]:h-5 [&::-webkit-slider-thumb]:w-5 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-background [&::-webkit-slider-thumb]:bg-primary [&::-webkit-slider-thumb]:shadow`,`[&::-moz-range-thumb]:h-5 [&::-moz-range-thumb]:w-5 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-background [&::-moz-range-thumb]:bg-primary [&::-moz-range-thumb]:shadow`,`disabled:cursor-not-allowed disabled:opacity-50`,s.focusRing,s.forcedColors.rangeInput,m,e),style:{...h,[d]:z},value:_,defaultValue:v,min:y,max:b,step:x,form:S,...N,...P,onChange:V})};h.displayName=`Slider`,exports.Slider=h;
1
+ "use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/dev.cjs"),r=require("../../lib/composeEventHandlers.cjs"),i=require("../../lib/classNames.cjs"),a=require("../../hooks/useEventCallback.cjs"),o=require("../../hooks/useMergedRefs.cjs"),s=require("../../hooks/useFieldControl.cjs"),c=require("../../lib/styles.cjs"),l=require("../../hooks/useFormReset.cjs");let u=require("react");u=e.__toESM(u,1);let d=require("react/jsx-runtime");var f=`--wave-slider-progress`;function p(e,t,n){let r=n>t?(e-t)/(n-t)*100:0;return`${Number.isFinite(r)?Math.min(100,Math.max(0,r)):0}%`}var m={medium:{rail:[`[&::-webkit-slider-runnable-track]:h-1 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-stroke-accessible`,`[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_right,var(--wave-primary)_var(--wave-slider-progress),var(--wave-stroke-accessible)_var(--wave-slider-progress))]`,`wave-rtl:[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_left,var(--wave-primary)_var(--wave-slider-progress),var(--wave-stroke-accessible)_var(--wave-slider-progress))]`,`[&::-moz-range-track]:h-1 [&::-moz-range-track]:rounded-full [&::-moz-range-track]:bg-stroke-accessible`,`[&::-moz-range-progress]:h-1 [&::-moz-range-progress]:rounded-full [&::-moz-range-progress]:bg-primary`],thumbWebkit:`[&::-webkit-slider-thumb]:-mt-2 [&::-webkit-slider-thumb]:h-5 [&::-webkit-slider-thumb]:w-5 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-background [&::-webkit-slider-thumb]:bg-primary [&::-webkit-slider-thumb]:shadow`,thumbMoz:`[&::-moz-range-thumb]:h-5 [&::-moz-range-thumb]:w-5 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-background [&::-moz-range-thumb]:bg-primary [&::-moz-range-thumb]:shadow`},small:{rail:[`[&::-webkit-slider-runnable-track]:h-0.5 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-stroke-accessible`,`[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_right,var(--wave-primary)_var(--wave-slider-progress),var(--wave-stroke-accessible)_var(--wave-slider-progress))]`,`wave-rtl:[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_left,var(--wave-primary)_var(--wave-slider-progress),var(--wave-stroke-accessible)_var(--wave-slider-progress))]`,`[&::-moz-range-track]:h-0.5 [&::-moz-range-track]:rounded-full [&::-moz-range-track]:bg-stroke-accessible`,`[&::-moz-range-progress]:h-0.5 [&::-moz-range-progress]:rounded-full [&::-moz-range-progress]:bg-primary`],thumbWebkit:`[&::-webkit-slider-thumb]:-mt-1.75 [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-background [&::-webkit-slider-thumb]:bg-primary [&::-webkit-slider-thumb]:shadow`,thumbMoz:`[&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-background [&::-moz-range-thumb]:bg-primary [&::-moz-range-thumb]:shadow`}},h=[`forced-colors:[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_right,Highlight_var(--wave-slider-progress),CanvasText_var(--wave-slider-progress))]`,`forced-colors:wave-rtl:[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_left,Highlight_var(--wave-slider-progress),CanvasText_var(--wave-slider-progress))]`,`forced-colors:[&::-moz-range-progress]:bg-[Highlight]`,`forced-colors:disabled:[&::-webkit-slider-runnable-track]:bg-none forced-colors:disabled:[&::-moz-range-progress]:bg-[GrayText]`],g=({className:e,style:g,label:_,value:v,defaultValue:y,min:b,max:x,step:S,size:C,form:w,onChange:T,onValueChange:E,ref:D,id:O,"aria-label":k,"aria-labelledby":A,"aria-describedby":j,"aria-invalid":M,"aria-required":N,required:P,...F})=>{let I=typeof C==`number`;u.useEffect(()=>{I&&n.warnOnce(`Slider:size-number`,"Slider: a numeric `size` has no effect (a range input ignores the native attribute) and is removed in 1.0; remove it.")},[I]);let L=C===`small`?`small`:`medium`,R=m[L],z=s.useFieldControl({id:O,"aria-label":k??_,"aria-labelledby":A,"aria-describedby":j,"aria-invalid":M,"aria-required":N,required:P},{nativeRequired:!0}),B=u.useRef(null),V=o.useMergedRefs(B,D),H=b??0,U=x??100,W=p(v??y??H+(U-H)/2,H,U),G=a.useEventCallback(()=>{let e=B.current;if(!e)return;let t=p(Number(e.value),H,U);e.style.getPropertyValue(f)!==t&&e.style.setProperty(f,t)});u.useLayoutEffect(()=>{G()},[v,y,b,x,S,G]),l.useFormReset(B,()=>queueMicrotask(G),w);let K=r.composeEventHandlers(T,e=>{v===void 0&&G(),E?.(Number(e.currentTarget.value))},{checkDefaultPrevented:!1});return(0,d.jsx)(`input`,{ref:V,type:`range`,className:t.cn(i.sliderClassNames.root,`w-full cursor-pointer appearance-none bg-transparent`,L===`small`&&`h-6`,R.rail,R.thumbWebkit,R.thumbMoz,`disabled:cursor-not-allowed disabled:opacity-50`,c.focusRing,c.forcedColors.rangeInput,h,e),style:{...g,[f]:W},value:v,defaultValue:y,min:b,max:x,step:S,form:w,"data-size":L,...F,...z,onChange:K})};g.displayName=`Slider`,exports.Slider=g;
2
2
  //# sourceMappingURL=Slider.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Slider.cjs","names":["useFieldControl","React","useMergedRefs","useEventCallback","composeEventHandlers","cn","sliderClassNames","focusRing","forcedColors","require_runtime","require_cn","require_composeEventHandlers","require_classNames","require_useEventCallback","require_useMergedRefs","require_useFieldControl","require_styles","require_useFormReset","react","react_jsx_runtime","PROGRESS_VAR","progressPercent","share","max","min","value","railClasses","forcedColorsFill","Slider","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","props","fieldProps","label","inputRef","mergedRef","ref","rangeMin","rangeMax","renderedProgress","defaultValue","updateFill","input","next","step","form","handleChange","onChange","onValueChange","event","className","style"],"sources":["../../../src/components/input/Slider.tsx"],"sourcesContent":["import * as React from 'react';\nimport { sliderClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { focusRing, forcedColors } from '../../lib/styles';\nimport { useEventCallback } from '../../hooks/useEventCallback';\nimport { useFieldControl } from '../../hooks/useFieldControl';\nimport { useFormReset } from '../../hooks/useFormReset';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\n\n/** Properties for the Slider component. */\nexport interface SliderProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type'> {\n /** Controlled slider value. */\n value?: number;\n /** Initial value for uncontrolled usage. */\n defaultValue?: number;\n /** Native change event handler (`event.target.value` is a string). */\n onChange?: React.ChangeEventHandler<HTMLInputElement>;\n /** Called with the new value as a number on every change, next to the native `onChange`. */\n onValueChange?: (value: number) => void;\n /** Minimum allowed value. */\n min?: number;\n /** Maximum allowed value. */\n max?: number;\n /** Step increment between values. */\n step?: number;\n /**\n * Accessible label for the slider (sets `aria-label`; an explicit `aria-label` wins). Inside a\n * `Field`, leave it out so the Field's label names the slider.\n */\n label?: string;\n /** Ref to the `<input type=\"range\">` element. */\n ref?: React.Ref<HTMLInputElement>;\n}\n\n/** The CSS variable that holds how much of the rail the fill covers (`<p>%`). */\nconst PROGRESS_VAR = '--wave-slider-progress';\n\n/** The share of the rail up to `value`, as a CSS percentage: 0–100, and 0 when `max <= min`. */\nfunction progressPercent(value: number, min: number, max: number): string {\n const share = max > min ? ((value - min) / (max - min)) * 100 : 0;\n return `${Number.isFinite(share) ? Math.min(100, Math.max(0, share)) : 0}%`;\n}\n\n/**\n * The rail: the primary fill up to the thumb, the accessible stroke after it. WebKit and Blink\n * draw it as a gradient on the track (mirrored for right-to-left); Firefox has a progress part and\n * mirrors it itself. The track color stays underneath (the whole rail without the variable).\n */\nconst railClasses = [\n // The rail color gives the rail itself 3:1 non-text contrast.\n '[&::-webkit-slider-runnable-track]:h-1 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-stroke-accessible',\n '[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_right,var(--wave-primary)_var(--wave-slider-progress),var(--wave-stroke-accessible)_var(--wave-slider-progress))]',\n 'wave-rtl:[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_left,var(--wave-primary)_var(--wave-slider-progress),var(--wave-stroke-accessible)_var(--wave-slider-progress))]',\n '[&::-moz-range-track]:h-1 [&::-moz-range-track]:rounded-full [&::-moz-range-track]:bg-stroke-accessible',\n '[&::-moz-range-progress]:h-1 [&::-moz-range-progress]:rounded-full [&::-moz-range-progress]:bg-primary',\n];\n\n/**\n * Forced colors, after `forcedColors.rangeInput` (which draws the whole rail in CanvasText): the\n * filled part in Highlight; a disabled rail stays GrayText, without the fill.\n */\nconst forcedColorsFill = [\n 'forced-colors:[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_right,Highlight_var(--wave-slider-progress),CanvasText_var(--wave-slider-progress))]',\n 'forced-colors:wave-rtl:[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_left,Highlight_var(--wave-slider-progress),CanvasText_var(--wave-slider-progress))]',\n 'forced-colors:[&::-moz-range-progress]:bg-[Highlight]',\n 'forced-colors:disabled:[&::-webkit-slider-runnable-track]:bg-none forced-colors:disabled:[&::-moz-range-progress]:bg-[GrayText]',\n];\n\n/**\n * A native range input with Fluent styling: a rail drawn in the accessible stroke color (3:1\n * against the page), filled in the primary color up to a primary thumb; in forced-colors mode the\n * rail, fill and thumb are drawn in system colors. Inside a `Field` it picks up the label, hint,\n * validation message, `required` and invalid state automatically.\n *\n * The fill follows the value through the `--wave-slider-progress` variable on the input (also in\n * the server HTML), including the browser's snapping to `step` and a form reset.\n *\n * @example\n * <Slider label=\"Volume\" min={0} max={100} value={volume} onValueChange={setVolume} />\n */\nexport const Slider = ({\n className,\n style,\n label,\n value,\n defaultValue,\n min,\n max,\n step,\n form,\n onChange,\n onValueChange,\n ref,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n required,\n ...props\n}: SliderProps) => {\n const fieldProps = useFieldControl(\n {\n id,\n 'aria-label': ariaLabel ?? label,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n required,\n },\n { nativeRequired: true },\n );\n\n const inputRef = React.useRef<HTMLInputElement>(null);\n const mergedRef = useMergedRefs(inputRef, ref);\n const rangeMin = min ?? 0;\n const rangeMax = max ?? 100;\n // During render (and on the server): the value, else the default, else the native midpoint.\n const renderedProgress = progressPercent(\n value ?? defaultValue ?? rangeMin + (rangeMax - rangeMin) / 2,\n rangeMin,\n rangeMax,\n );\n\n /** Writes the fill of the value the input really has (the browser snaps it to `step`). */\n const updateFill = useEventCallback(() => {\n const input = inputRef.current;\n if (!input) return;\n const next = progressPercent(Number(input.value), rangeMin, rangeMax);\n if (input.style.getPropertyValue(PROGRESS_VAR) !== next) {\n input.style.setProperty(PROGRESS_VAR, next);\n }\n });\n\n // On mount and whenever the value or its range changes: React wrote the variable from the props,\n // the input may hold another value (step snapping, an uncontrolled value the user moved).\n React.useLayoutEffect(() => {\n updateFill();\n }, [value, defaultValue, min, max, step, updateFill]);\n\n // The reset event fires before the form restores the value: read it a microtask later.\n useFormReset(inputRef, () => queueMicrotask(updateFill), form);\n\n const handleChange = composeEventHandlers(\n onChange,\n (event: React.ChangeEvent<HTMLInputElement>) => {\n // A controlled fill follows `value` (a parent that rejects the change keeps it).\n if (value === undefined) updateFill();\n onValueChange?.(Number(event.currentTarget.value));\n },\n { checkDefaultPrevented: false },\n );\n\n return (\n <input\n ref={mergedRef}\n type=\"range\"\n className={cn(\n sliderClassNames.root,\n 'w-full cursor-pointer appearance-none bg-transparent',\n railClasses,\n // Thumb. WebKit and Blink align its top with the rail's top, so it is pulled up by half the\n // difference of the two heights (5 and 1 spacing units): it stays centred at any root\n // font size.\n '[&::-webkit-slider-thumb]:-mt-2 [&::-webkit-slider-thumb]:h-5 [&::-webkit-slider-thumb]:w-5 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-background [&::-webkit-slider-thumb]:bg-primary [&::-webkit-slider-thumb]:shadow',\n // Firefox thumb\n '[&::-moz-range-thumb]:h-5 [&::-moz-range-thumb]:w-5 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-background [&::-moz-range-thumb]:bg-primary [&::-moz-range-thumb]:shadow',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n focusRing,\n // Forced colors replace the author backgrounds of the rail and thumb with Canvas: give\n // every part a system color instead.\n forcedColors.rangeInput,\n forcedColorsFill,\n className,\n )}\n style={{ ...style, [PROGRESS_VAR]: renderedProgress } as React.CSSProperties}\n value={value}\n defaultValue={defaultValue}\n min={min}\n max={max}\n step={step}\n form={form}\n {...props}\n {...fieldProps}\n onChange={handleChange}\n />\n );\n};\n\nSlider.displayName = 'Slider';\n"],"mappings":"sdAoCA,IAAMoB,EAAe,yBAGrB,SAASC,EAAgB,EAAe,EAAa,EAAqB,CACxE,IAAMC,EAAQC,EAAMC,GAAQC,EAAQD,IAAQD,EAAMC,GAAQ,IAAM,EAChE,MAAO,GAAG,OAAO,SAASF,CAAK,EAAI,KAAK,IAAI,IAAK,KAAK,IAAI,EAAGA,CAAK,CAAC,EAAI,EAAE,EAC3E,CAOA,IAAMI,EAAc,CAElB,iJACA,8KACA,sLACA,0GACA,wGACF,EAMMC,EAAmB,CACvB,+JACA,uKACA,wDACA,iIACF,EAcaC,GAAU,CACrB,YACA,QACA,QACA,QACA,eACA,MACA,MACA,OACA,OACA,WACA,gBACA,MACA,KACA,aAAcC,EACd,kBAAmBC,EACnB,mBAAoBC,EACpB,eAAgBC,EAChB,gBAAiBC,EACjB,WACA,GAAGC,KACc,CACjB,IAAMC,EAAanC,EAAAA,gBACjB,CACE,KACA,aAAc6B,GAAaO,EAC3B,kBAAmBN,EACnB,mBAAoBC,EACpB,eAAgBC,EAChB,gBAAiBC,EACjB,UACF,EACA,CAAE,eAAgB,EAAK,CACzB,EAEMI,EAAWpC,EAAM,OAAyB,IAAI,EAC9CqC,EAAYpC,EAAAA,cAAcmC,EAAUE,CAAG,EACvCC,EAAWhB,GAAO,EAClBiB,EAAWlB,GAAO,IAElBmB,EAAmBrB,EACvBI,GAASkB,GAAgBH,GAAYC,EAAWD,GAAY,EAC5DA,EACAC,CACF,EAGMG,EAAazC,EAAAA,qBAAuB,CACxC,IAAM0C,EAAQR,EAAS,QACvB,GAAI,CAACQ,EAAO,OACZ,IAAMC,EAAOzB,EAAgB,OAAOwB,EAAM,KAAK,EAAGL,EAAUC,CAAQ,EAChEI,EAAM,MAAM,iBAAiBzB,CAAY,IAAM0B,GACjDD,EAAM,MAAM,YAAYzB,EAAc0B,CAAI,CAE9C,CAAC,EAID5B,EAAM,oBAAsB,CAC1B0B,EAAW,CACb,EAAG,CAACnB,EAAOkB,EAAcnB,EAAKD,EAAKwB,EAAMH,CAAU,CAAC,EAGpD3B,EAAA,aAAaoB,MAAgB,eAAeO,CAAU,EAAGI,CAAI,EAE7D,IAAMC,EAAe7C,EAAAA,qBACnB8C,EACC,GAA+C,CAE1CzB,IAAU,IAAA,IAAWmB,EAAW,EACpCO,IAAgB,OAAOC,EAAM,cAAc,KAAK,CAAC,CACnD,EACA,CAAE,sBAAuB,EAAM,CACjC,EAEA,OACE,EAAAjC,EAAA,IAAA,CAAC,QAAD,CACE,IAAKmB,EACL,KAAK,QACL,UAAWjC,EAAAA,GACTC,EAAAA,iBAAiB,KACjB,uDACAoB,EAIA,oUAEA,8NACA,kDACAnB,EAAAA,UAGAC,EAAAA,aAAa,WACbmB,EACA0B,CACF,EACA,MAAO,CAAE,GAAGC,GAAQlC,GAAesB,CAAiB,EAC7C,QACO,eACT,MACA,MACC,OACA,OACN,GAAIR,EACJ,GAAIC,EACJ,SAAUc,CACX,CAAA,CAEL,EAEA,EAAO,YAAc"}
1
+ {"version":3,"file":"Slider.cjs","names":["useFieldControl","React","useMergedRefs","useEventCallback","composeEventHandlers","cn","sliderClassNames","focusRing","forcedColors","require_runtime","require_cn","require_dev","require_composeEventHandlers","require_classNames","require_useEventCallback","require_useMergedRefs","require_useFieldControl","require_styles","require_useFormReset","react","react_jsx_runtime","PROGRESS_VAR","progressPercent","share","max","min","value","SLIDER_SIZE","forcedColorsFill","Slider","sizeProp","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","props","numericSize","size","sizeClasses","fieldProps","label","inputRef","mergedRef","ref","rangeMin","rangeMax","renderedProgress","defaultValue","updateFill","input","next","step","form","handleChange","onChange","onValueChange","event","className","style"],"sources":["../../../src/components/input/Slider.tsx"],"sourcesContent":["import * as React from 'react';\nimport { sliderClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { warnOnce } from '../../lib/dev';\nimport { focusRing, forcedColors } from '../../lib/styles';\nimport type { Size } from '../../lib/types';\nimport { useEventCallback } from '../../hooks/useEventCallback';\nimport { useFieldControl } from '../../hooks/useFieldControl';\nimport { useFormReset } from '../../hooks/useFormReset';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\n\n/** Size of the thumb and rail: a small 16px thumb on a 2px rail, or the 0.7 20px thumb on a 4px rail. */\nexport type SliderSize = Extract<Size, 'small' | 'medium'>;\n\n/** Properties for the Slider component. */\nexport interface SliderProps extends Omit<\n React.InputHTMLAttributes<HTMLInputElement>,\n 'type' | 'size'\n> {\n /** Controlled slider value. */\n value?: number;\n /** Initial value for uncontrolled usage. */\n defaultValue?: number;\n /** Native change event handler (`event.target.value` is a string). */\n onChange?: React.ChangeEventHandler<HTMLInputElement>;\n /** Called with the new value as a number on every change, next to the native `onChange`. */\n onValueChange?: (value: number) => void;\n /** Minimum allowed value. */\n min?: number;\n /** Maximum allowed value. */\n max?: number;\n /** Step increment between values. */\n step?: number;\n /**\n * Accessible label for the slider (sets `aria-label`; an explicit `aria-label` wins). Inside a\n * `Field`, leave it out so the Field's label names the slider.\n */\n label?: string;\n /**\n * Size of the thumb and rail: the 0.7 20px thumb on a 4px rail, or a small 16px thumb on a 2px\n * rail in a 24px-tall input. Unlike the text controls and pickers, Slider does not read a\n * surrounding `Field`'s size or a `WaveProvider`'s input defaults: this prop is the only source\n * of its size.\n *\n * `SliderProps` inherited the native HTML `size` attribute, which a range input ignores anyway.\n * A number is deprecated: it renders nothing (not even the native attribute), is reported once\n * in development, and is a type error from 1.0.\n * @default 'medium'\n */\n size?: SliderSize | number;\n /** Ref to the `<input type=\"range\">` element. */\n ref?: React.Ref<HTMLInputElement>;\n}\n\n/** The CSS variable that holds how much of the rail the fill covers (`<p>%`). */\nconst PROGRESS_VAR = '--wave-slider-progress';\n\n/** The share of the rail up to `value`, as a CSS percentage: 0–100, and 0 when `max <= min`. */\nfunction progressPercent(value: number, min: number, max: number): string {\n const share = max > min ? ((value - min) / (max - min)) * 100 : 0;\n return `${Number.isFinite(share) ? Math.min(100, Math.max(0, share)) : 0}%`;\n}\n\n/**\n * Per-size rail and thumb classes (D14). The rail is the primary fill up to the thumb, the\n * accessible stroke after it: WebKit and Blink draw it as a gradient on the track (mirrored for\n * right-to-left), Firefox has a progress part and mirrors it itself; the track color stays\n * underneath (the whole rail without the variable). WebKit and Blink align the thumb's top with\n * the rail's top, so the thumb is pulled up by half the difference of the two heights: it stays\n * centred at any root font size. Medium keeps the 0.7 strings exactly; small substitutes a\n * thinner rail and a smaller thumb (each `[&::…]` variant written out literally, since the CSS\n * build's class scanner needs whole class names, not assembled ones).\n */\nconst SLIDER_SIZE: Readonly<\n Record<SliderSize, { rail: readonly string[]; thumbWebkit: string; thumbMoz: string }>\n> = {\n medium: {\n rail: [\n // The rail color gives the rail itself 3:1 non-text contrast.\n '[&::-webkit-slider-runnable-track]:h-1 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-stroke-accessible',\n '[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_right,var(--wave-primary)_var(--wave-slider-progress),var(--wave-stroke-accessible)_var(--wave-slider-progress))]',\n 'wave-rtl:[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_left,var(--wave-primary)_var(--wave-slider-progress),var(--wave-stroke-accessible)_var(--wave-slider-progress))]',\n '[&::-moz-range-track]:h-1 [&::-moz-range-track]:rounded-full [&::-moz-range-track]:bg-stroke-accessible',\n '[&::-moz-range-progress]:h-1 [&::-moz-range-progress]:rounded-full [&::-moz-range-progress]:bg-primary',\n ],\n thumbWebkit:\n '[&::-webkit-slider-thumb]:-mt-2 [&::-webkit-slider-thumb]:h-5 [&::-webkit-slider-thumb]:w-5 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-background [&::-webkit-slider-thumb]:bg-primary [&::-webkit-slider-thumb]:shadow',\n thumbMoz:\n '[&::-moz-range-thumb]:h-5 [&::-moz-range-thumb]:w-5 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-background [&::-moz-range-thumb]:bg-primary [&::-moz-range-thumb]:shadow',\n },\n small: {\n rail: [\n '[&::-webkit-slider-runnable-track]:h-0.5 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-stroke-accessible',\n '[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_right,var(--wave-primary)_var(--wave-slider-progress),var(--wave-stroke-accessible)_var(--wave-slider-progress))]',\n 'wave-rtl:[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_left,var(--wave-primary)_var(--wave-slider-progress),var(--wave-stroke-accessible)_var(--wave-slider-progress))]',\n '[&::-moz-range-track]:h-0.5 [&::-moz-range-track]:rounded-full [&::-moz-range-track]:bg-stroke-accessible',\n '[&::-moz-range-progress]:h-0.5 [&::-moz-range-progress]:rounded-full [&::-moz-range-progress]:bg-primary',\n ],\n thumbWebkit:\n '[&::-webkit-slider-thumb]:-mt-1.75 [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-background [&::-webkit-slider-thumb]:bg-primary [&::-webkit-slider-thumb]:shadow',\n thumbMoz:\n '[&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-background [&::-moz-range-thumb]:bg-primary [&::-moz-range-thumb]:shadow',\n },\n};\n\n/**\n * Forced colors, after `forcedColors.rangeInput` (which draws the whole rail in CanvasText): the\n * filled part in Highlight; a disabled rail stays GrayText, without the fill.\n */\nconst forcedColorsFill = [\n 'forced-colors:[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_right,Highlight_var(--wave-slider-progress),CanvasText_var(--wave-slider-progress))]',\n 'forced-colors:wave-rtl:[&::-webkit-slider-runnable-track]:bg-[linear-gradient(to_left,Highlight_var(--wave-slider-progress),CanvasText_var(--wave-slider-progress))]',\n 'forced-colors:[&::-moz-range-progress]:bg-[Highlight]',\n 'forced-colors:disabled:[&::-webkit-slider-runnable-track]:bg-none forced-colors:disabled:[&::-moz-range-progress]:bg-[GrayText]',\n];\n\n/**\n * A native range input with Fluent styling: a rail drawn in the accessible stroke color (3:1\n * against the page), filled in the primary color up to a primary thumb; in forced-colors mode the\n * rail, fill and thumb are drawn in system colors. Inside a `Field` it picks up the label, hint,\n * validation message, `required` and invalid state automatically.\n *\n * The fill follows the value through the `--wave-slider-progress` variable on the input (also in\n * the server HTML), including the browser's snapping to `step` and a form reset.\n *\n * `size` (`small`, `medium`) sets the thumb and rail dimensions; the input carries `data-size`.\n * Slider does not read a surrounding `Field`'s size or a `WaveProvider`'s input defaults.\n *\n * @example\n * <Slider label=\"Volume\" min={0} max={100} value={volume} onValueChange={setVolume} />\n */\nexport const Slider = ({\n className,\n style,\n label,\n value,\n defaultValue,\n min,\n max,\n step,\n size: sizeProp,\n form,\n onChange,\n onValueChange,\n ref,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n required,\n ...props\n}: SliderProps) => {\n // D10: the deprecated numeric form of `size` never reaches the input (it was part of `...props`\n // in 0.7, which rendered it as the meaningless native `size` attribute); report it once.\n const numericSize = typeof sizeProp === 'number';\n React.useEffect(() => {\n if (numericSize) {\n warnOnce(\n 'Slider:size-number',\n 'Slider: a numeric `size` has no effect (a range input ignores the native attribute) and is removed in 1.0; remove it.',\n );\n }\n }, [numericSize]);\n // Any other value (an unknown string from untyped code) also resolves to medium, so the classes\n // and `data-size` always agree.\n const size: SliderSize = sizeProp === 'small' ? 'small' : 'medium';\n const sizeClasses = SLIDER_SIZE[size];\n\n const fieldProps = useFieldControl(\n {\n id,\n 'aria-label': ariaLabel ?? label,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n required,\n },\n { nativeRequired: true },\n );\n\n const inputRef = React.useRef<HTMLInputElement>(null);\n const mergedRef = useMergedRefs(inputRef, ref);\n const rangeMin = min ?? 0;\n const rangeMax = max ?? 100;\n // During render (and on the server): the value, else the default, else the native midpoint.\n const renderedProgress = progressPercent(\n value ?? defaultValue ?? rangeMin + (rangeMax - rangeMin) / 2,\n rangeMin,\n rangeMax,\n );\n\n /** Writes the fill of the value the input really has (the browser snaps it to `step`). */\n const updateFill = useEventCallback(() => {\n const input = inputRef.current;\n if (!input) return;\n const next = progressPercent(Number(input.value), rangeMin, rangeMax);\n if (input.style.getPropertyValue(PROGRESS_VAR) !== next) {\n input.style.setProperty(PROGRESS_VAR, next);\n }\n });\n\n // On mount and whenever the value or its range changes: React wrote the variable from the props,\n // the input may hold another value (step snapping, an uncontrolled value the user moved).\n React.useLayoutEffect(() => {\n updateFill();\n }, [value, defaultValue, min, max, step, updateFill]);\n\n // The reset event fires before the form restores the value: read it a microtask later.\n useFormReset(inputRef, () => queueMicrotask(updateFill), form);\n\n const handleChange = composeEventHandlers(\n onChange,\n (event: React.ChangeEvent<HTMLInputElement>) => {\n // A controlled fill follows `value` (a parent that rejects the change keeps it).\n if (value === undefined) updateFill();\n onValueChange?.(Number(event.currentTarget.value));\n },\n { checkDefaultPrevented: false },\n );\n\n return (\n <input\n ref={mergedRef}\n type=\"range\"\n className={cn(\n sliderClassNames.root,\n 'w-full cursor-pointer appearance-none bg-transparent',\n // A 24px-tall input at the small size, the rail centred in it (D14).\n size === 'small' && 'h-6',\n sizeClasses.rail,\n sizeClasses.thumbWebkit,\n sizeClasses.thumbMoz,\n 'disabled:cursor-not-allowed disabled:opacity-50',\n focusRing,\n // Forced colors replace the author backgrounds of the rail and thumb with Canvas: give\n // every part a system color instead.\n forcedColors.rangeInput,\n forcedColorsFill,\n className,\n )}\n style={{ ...style, [PROGRESS_VAR]: renderedProgress } as React.CSSProperties}\n value={value}\n defaultValue={defaultValue}\n min={min}\n max={max}\n step={step}\n form={form}\n data-size={size}\n {...props}\n {...fieldProps}\n onChange={handleChange}\n />\n );\n};\n\nSlider.displayName = 'Slider';\n"],"mappings":"qfAwDA,IAAMqB,EAAe,yBAGrB,SAASC,EAAgB,EAAe,EAAa,EAAqB,CACxE,IAAMC,EAAQC,EAAMC,GAAQC,EAAQD,IAAQD,EAAMC,GAAQ,IAAM,EAChE,MAAO,GAAG,OAAO,SAASF,CAAK,EAAI,KAAK,IAAI,IAAK,KAAK,IAAI,EAAGA,CAAK,CAAC,EAAI,EAAE,EAC3E,CAYA,IAAMI,EAEF,CACF,OAAQ,CACN,KAAM,CAEJ,iJACA,8KACA,sLACA,0GACA,wGACF,EACA,YACE,oUACF,SACE,6NACJ,EACA,MAAO,CACL,KAAM,CACJ,mJACA,8KACA,sLACA,4GACA,0GACF,EACA,YACE,uUACF,SACE,6NACJ,CACF,EAMMC,EAAmB,CACvB,+JACA,uKACA,wDACA,iIACF,EAiBaC,GAAU,CACrB,YACA,QACA,QACA,QACA,eACA,MACA,MACA,OACA,KAAMC,EACN,OACA,WACA,gBACA,MACA,KACA,aAAcC,EACd,kBAAmBC,EACnB,mBAAoBC,EACpB,eAAgBC,EAChB,gBAAiBC,EACjB,WACA,GAAGC,KACc,CAGjB,IAAMC,EAAc,OAAOP,GAAa,SACxCX,EAAM,cAAgB,CAChBkB,GACF1B,EAAA,SACE,qBACA,uHACF,CAEJ,EAAG,CAAC0B,CAAW,CAAC,EAGhB,IAAMC,EAAmBR,IAAa,QAAU,QAAU,SACpDS,EAAcZ,EAAYW,GAE1BE,EAAaxC,EAAAA,gBACjB,CACE,KACA,aAAc+B,GAAaU,EAC3B,kBAAmBT,EACnB,mBAAoBC,EACpB,eAAgBC,EAChB,gBAAiBC,EACjB,UACF,EACA,CAAE,eAAgB,EAAK,CACzB,EAEMO,EAAWzC,EAAM,OAAyB,IAAI,EAC9C0C,EAAYzC,EAAAA,cAAcwC,EAAUE,CAAG,EACvCC,EAAWpB,GAAO,EAClBqB,EAAWtB,GAAO,IAElBuB,EAAmBzB,EACvBI,GAASsB,GAAgBH,GAAYC,EAAWD,GAAY,EAC5DA,EACAC,CACF,EAGMG,EAAa9C,EAAAA,qBAAuB,CACxC,IAAM+C,EAAQR,EAAS,QACvB,GAAI,CAACQ,EAAO,OACZ,IAAMC,EAAO7B,EAAgB,OAAO4B,EAAM,KAAK,EAAGL,EAAUC,CAAQ,EAChEI,EAAM,MAAM,iBAAiB7B,CAAY,IAAM8B,GACjDD,EAAM,MAAM,YAAY7B,EAAc8B,CAAI,CAE9C,CAAC,EAIDhC,EAAM,oBAAsB,CAC1B8B,EAAW,CACb,EAAG,CAACvB,EAAOsB,EAAcvB,EAAKD,EAAK4B,EAAMH,CAAU,CAAC,EAGpD/B,EAAA,aAAawB,MAAgB,eAAeO,CAAU,EAAGI,CAAI,EAE7D,IAAMC,EAAelD,EAAAA,qBACnBmD,EACC,GAA+C,CAE1C7B,IAAU,IAAA,IAAWuB,EAAW,EACpCO,IAAgB,OAAOC,EAAM,cAAc,KAAK,CAAC,CACnD,EACA,CAAE,sBAAuB,EAAM,CACjC,EAEA,OACE,EAAArC,EAAA,IAAA,CAAC,QAAD,CACE,IAAKuB,EACL,KAAK,QACL,UAAWtC,EAAAA,GACTC,EAAAA,iBAAiB,KACjB,uDAEAgC,IAAS,SAAW,MACpBC,EAAY,KACZA,EAAY,YACZA,EAAY,SACZ,kDACAhC,EAAAA,UAGAC,EAAAA,aAAa,WACboB,EACA8B,CACF,EACA,MAAO,CAAE,GAAGC,GAAQtC,GAAe0B,CAAiB,EAC7C,QACO,eACT,MACA,MACC,OACA,OACN,YAAWT,EACX,GAAIF,EACJ,GAAII,EACJ,SAAUc,CACX,CAAA,CAEL,EAEA,EAAO,YAAc"}