@mitcsutt/kiln-ui 0.2.1 → 0.2.2

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 (212) hide show
  1. package/dist/components/actions/Button/Button.d.ts +8 -0
  2. package/dist/components/actions/Button/Button.js.map +1 -1
  3. package/dist/components/actions/ChipGroup/ChipGroup.d.ts +9 -0
  4. package/dist/components/actions/ChipGroup/ChipGroup.js.map +1 -1
  5. package/dist/components/actions/IconButton/IconButton.d.ts +8 -0
  6. package/dist/components/actions/IconButton/IconButton.js.map +1 -1
  7. package/dist/components/actions/ModeToggle/ModeToggle.d.ts +8 -0
  8. package/dist/components/actions/ModeToggle/ModeToggle.js.map +1 -1
  9. package/dist/components/actions/SegmentedControl/SegmentedControl.d.ts +9 -0
  10. package/dist/components/actions/SegmentedControl/SegmentedControl.js.map +1 -1
  11. package/dist/components/actions/ToggleChip/ToggleChip.d.ts +9 -0
  12. package/dist/components/actions/ToggleChip/ToggleChip.js.map +1 -1
  13. package/dist/components/display/Avatar/Avatar.d.ts +10 -0
  14. package/dist/components/display/Avatar/Avatar.js.map +1 -1
  15. package/dist/components/display/AvatarGroup/AvatarGroup.d.ts +7 -0
  16. package/dist/components/display/AvatarGroup/AvatarGroup.js.map +1 -1
  17. package/dist/components/display/Badge/Badge.d.ts +7 -0
  18. package/dist/components/display/Badge/Badge.js.map +1 -1
  19. package/dist/components/display/Card/Card.js.map +1 -1
  20. package/dist/components/display/CodeBlock/CodeBlock.d.ts +9 -0
  21. package/dist/components/display/CodeBlock/CodeBlock.js.map +1 -1
  22. package/dist/components/display/DataList/DataList.js.map +1 -1
  23. package/dist/components/display/Delta/Delta.d.ts +9 -0
  24. package/dist/components/display/Delta/Delta.js.map +1 -1
  25. package/dist/components/display/EmptyState/EmptyState.d.ts +8 -0
  26. package/dist/components/display/EmptyState/EmptyState.js.map +1 -1
  27. package/dist/components/display/List/List.js.map +1 -1
  28. package/dist/components/display/Marquee/Marquee.d.ts +8 -0
  29. package/dist/components/display/Marquee/Marquee.js.map +1 -1
  30. package/dist/components/display/Media/Media.d.ts +7 -0
  31. package/dist/components/display/Media/Media.js.map +1 -1
  32. package/dist/components/display/Meter/Meter.d.ts +9 -0
  33. package/dist/components/display/Meter/Meter.js.map +1 -1
  34. package/dist/components/display/Progress/Progress.d.ts +8 -0
  35. package/dist/components/display/Progress/Progress.js.map +1 -1
  36. package/dist/components/display/Skeleton/Skeleton.js.map +1 -1
  37. package/dist/components/display/Stamp/Stamp.d.ts +8 -0
  38. package/dist/components/display/Stamp/Stamp.js.map +1 -1
  39. package/dist/components/display/Stat/Stat.d.ts +8 -0
  40. package/dist/components/display/Stat/Stat.js.map +1 -1
  41. package/dist/components/display/Table/Table.js.map +1 -1
  42. package/dist/components/display/Tag/Tag.d.ts +7 -0
  43. package/dist/components/display/Tag/Tag.js.map +1 -1
  44. package/dist/components/feedback/Alert/Alert.d.ts +10 -0
  45. package/dist/components/feedback/Alert/Alert.js.map +1 -1
  46. package/dist/components/feedback/LiveIndicator/LiveIndicator.d.ts +7 -0
  47. package/dist/components/feedback/LiveIndicator/LiveIndicator.js.map +1 -1
  48. package/dist/components/feedback/RelativeTime/RelativeTime.d.ts +8 -0
  49. package/dist/components/feedback/RelativeTime/RelativeTime.js.map +1 -1
  50. package/dist/components/feedback/Spinner/Spinner.d.ts +10 -1
  51. package/dist/components/feedback/Spinner/Spinner.js.map +1 -1
  52. package/dist/components/feedback/StatusDot/StatusDot.d.ts +10 -1
  53. package/dist/components/feedback/StatusDot/StatusDot.js.map +1 -1
  54. package/dist/components/inputs/AmountField/AmountField.d.ts +7 -0
  55. package/dist/components/inputs/AmountField/AmountField.js.map +1 -1
  56. package/dist/components/inputs/AmountInput/AmountInput.d.ts +8 -0
  57. package/dist/components/inputs/AmountInput/AmountInput.js.map +1 -1
  58. package/dist/components/inputs/Checkbox/Checkbox.d.ts +8 -0
  59. package/dist/components/inputs/Checkbox/Checkbox.js.map +1 -1
  60. package/dist/components/inputs/CheckboxField/CheckboxField.d.ts +7 -0
  61. package/dist/components/inputs/CheckboxField/CheckboxField.js.map +1 -1
  62. package/dist/components/inputs/CheckboxGroup/CheckboxGroup.d.ts +8 -0
  63. package/dist/components/inputs/CheckboxGroup/CheckboxGroup.js.map +1 -1
  64. package/dist/components/inputs/CheckboxGroupField/CheckboxGroupField.d.ts +7 -0
  65. package/dist/components/inputs/CheckboxGroupField/CheckboxGroupField.js.map +1 -1
  66. package/dist/components/inputs/ChipGroupField/ChipGroupField.d.ts +7 -0
  67. package/dist/components/inputs/ChipGroupField/ChipGroupField.js.map +1 -1
  68. package/dist/components/inputs/ChoiceCards/ChoiceCards.d.ts +9 -0
  69. package/dist/components/inputs/ChoiceCards/ChoiceCards.js.map +1 -1
  70. package/dist/components/inputs/ChoiceCardsField/ChoiceCardsField.d.ts +7 -0
  71. package/dist/components/inputs/ChoiceCardsField/ChoiceCardsField.js.map +1 -1
  72. package/dist/components/inputs/ColorField/ColorField.d.ts +6 -0
  73. package/dist/components/inputs/ColorField/ColorField.js.map +1 -1
  74. package/dist/components/inputs/ColorInput/ColorInput.d.ts +8 -0
  75. package/dist/components/inputs/ColorInput/ColorInput.js.map +1 -1
  76. package/dist/components/inputs/Combobox/Combobox.d.ts +9 -0
  77. package/dist/components/inputs/Combobox/Combobox.js.map +1 -1
  78. package/dist/components/inputs/ComboboxField/ComboboxField.d.ts +7 -0
  79. package/dist/components/inputs/ComboboxField/ComboboxField.js.map +1 -1
  80. package/dist/components/inputs/DateRangeField/DateRangeField.d.ts +7 -0
  81. package/dist/components/inputs/DateRangeField/DateRangeField.js.map +1 -1
  82. package/dist/components/inputs/Field/Field.d.ts +26 -0
  83. package/dist/components/inputs/Field/Field.js.map +1 -1
  84. package/dist/components/inputs/Fieldset/Fieldset.d.ts +8 -0
  85. package/dist/components/inputs/Fieldset/Fieldset.js.map +1 -1
  86. package/dist/components/inputs/FileDrop/FileDrop.d.ts +10 -0
  87. package/dist/components/inputs/FileDrop/FileDrop.js.map +1 -1
  88. package/dist/components/inputs/FileField/FileField.d.ts +7 -0
  89. package/dist/components/inputs/FileField/FileField.js.map +1 -1
  90. package/dist/components/inputs/Input/Input.d.ts +9 -0
  91. package/dist/components/inputs/Input/Input.js.map +1 -1
  92. package/dist/components/inputs/NumberField/NumberField.d.ts +7 -0
  93. package/dist/components/inputs/NumberField/NumberField.js.map +1 -1
  94. package/dist/components/inputs/NumberInput/NumberInput.d.ts +8 -0
  95. package/dist/components/inputs/NumberInput/NumberInput.js.map +1 -1
  96. package/dist/components/inputs/OneTimeCodeField/OneTimeCodeField.d.ts +7 -0
  97. package/dist/components/inputs/OneTimeCodeField/OneTimeCodeField.js.map +1 -1
  98. package/dist/components/inputs/OneTimeCodeInput/OneTimeCodeInput.d.ts +8 -0
  99. package/dist/components/inputs/OneTimeCodeInput/OneTimeCodeInput.js.map +1 -1
  100. package/dist/components/inputs/PasswordField/PasswordField.d.ts +7 -0
  101. package/dist/components/inputs/PasswordField/PasswordField.js.map +1 -1
  102. package/dist/components/inputs/PasswordInput/PasswordInput.d.ts +10 -0
  103. package/dist/components/inputs/PasswordInput/PasswordInput.js.map +1 -1
  104. package/dist/components/inputs/RadioGroup/RadioGroup.d.ts +9 -0
  105. package/dist/components/inputs/RadioGroup/RadioGroup.js.map +1 -1
  106. package/dist/components/inputs/RadioGroupField/RadioGroupField.d.ts +8 -0
  107. package/dist/components/inputs/RadioGroupField/RadioGroupField.js.map +1 -1
  108. package/dist/components/inputs/RangeSlider/RangeSlider.d.ts +8 -0
  109. package/dist/components/inputs/RangeSlider/RangeSlider.js.map +1 -1
  110. package/dist/components/inputs/RangeSliderField/RangeSliderField.d.ts +7 -0
  111. package/dist/components/inputs/RangeSliderField/RangeSliderField.js.map +1 -1
  112. package/dist/components/inputs/Rating/Rating.d.ts +8 -0
  113. package/dist/components/inputs/Rating/Rating.js.map +1 -1
  114. package/dist/components/inputs/RatingField/RatingField.d.ts +7 -0
  115. package/dist/components/inputs/RatingField/RatingField.js.map +1 -1
  116. package/dist/components/inputs/SegmentedField/SegmentedField.d.ts +7 -0
  117. package/dist/components/inputs/SegmentedField/SegmentedField.js.map +1 -1
  118. package/dist/components/inputs/Select/Select.d.ts +9 -0
  119. package/dist/components/inputs/Select/Select.js.map +1 -1
  120. package/dist/components/inputs/SelectField/SelectField.d.ts +7 -0
  121. package/dist/components/inputs/SelectField/SelectField.js.map +1 -1
  122. package/dist/components/inputs/Slider/Slider.d.ts +8 -0
  123. package/dist/components/inputs/Slider/Slider.js.map +1 -1
  124. package/dist/components/inputs/SliderField/SliderField.d.ts +7 -0
  125. package/dist/components/inputs/SliderField/SliderField.js.map +1 -1
  126. package/dist/components/inputs/Switch/Switch.d.ts +8 -0
  127. package/dist/components/inputs/Switch/Switch.js.map +1 -1
  128. package/dist/components/inputs/SwitchField/SwitchField.d.ts +8 -0
  129. package/dist/components/inputs/SwitchField/SwitchField.js.map +1 -1
  130. package/dist/components/inputs/TagsField/TagsField.d.ts +6 -0
  131. package/dist/components/inputs/TagsField/TagsField.js.map +1 -1
  132. package/dist/components/inputs/TagsInput/TagsInput.d.ts +8 -0
  133. package/dist/components/inputs/TagsInput/TagsInput.js.map +1 -1
  134. package/dist/components/inputs/TextField/TextField.d.ts +8 -0
  135. package/dist/components/inputs/TextField/TextField.js.map +1 -1
  136. package/dist/components/inputs/Textarea/Textarea.d.ts +8 -0
  137. package/dist/components/inputs/Textarea/Textarea.js.map +1 -1
  138. package/dist/components/inputs/TextareaField/TextareaField.d.ts +7 -0
  139. package/dist/components/inputs/TextareaField/TextareaField.js.map +1 -1
  140. package/dist/components/layout/ActionBar/ActionBar.d.ts +7 -0
  141. package/dist/components/layout/ActionBar/ActionBar.js.map +1 -1
  142. package/dist/components/layout/AppShell/AppShell.js.map +1 -1
  143. package/dist/components/layout/AspectRatio/AspectRatio.d.ts +8 -0
  144. package/dist/components/layout/AspectRatio/AspectRatio.js.map +1 -1
  145. package/dist/components/layout/Box/Box.d.ts +8 -0
  146. package/dist/components/layout/Box/Box.js.map +1 -1
  147. package/dist/components/layout/Container/Container.d.ts +17 -0
  148. package/dist/components/layout/Container/Container.js.map +1 -1
  149. package/dist/components/layout/Divider/Divider.d.ts +7 -0
  150. package/dist/components/layout/Divider/Divider.js.map +1 -1
  151. package/dist/components/layout/Grid/Grid.d.ts +9 -0
  152. package/dist/components/layout/Grid/Grid.js.map +1 -1
  153. package/dist/components/layout/Inline/Inline.d.ts +8 -0
  154. package/dist/components/layout/Inline/Inline.js.map +1 -1
  155. package/dist/components/layout/Section/Section.d.ts +15 -0
  156. package/dist/components/layout/Section/Section.js.map +1 -1
  157. package/dist/components/layout/Split/Split.d.ts +9 -0
  158. package/dist/components/layout/Split/Split.js.map +1 -1
  159. package/dist/components/layout/Stack/Stack.d.ts +12 -0
  160. package/dist/components/layout/Stack/Stack.js.map +1 -1
  161. package/dist/components/layout/VisuallyHidden/VisuallyHidden.d.ts +7 -0
  162. package/dist/components/layout/VisuallyHidden/VisuallyHidden.js.map +1 -1
  163. package/dist/components/navigation/Accordion/Accordion.d.ts +7 -0
  164. package/dist/components/navigation/Accordion/Accordion.js.map +1 -1
  165. package/dist/components/navigation/BottomNav/BottomNav.d.ts +9 -0
  166. package/dist/components/navigation/BottomNav/BottomNav.js.map +1 -1
  167. package/dist/components/navigation/NavLinks/NavLinks.d.ts +9 -0
  168. package/dist/components/navigation/NavLinks/NavLinks.js.map +1 -1
  169. package/dist/components/navigation/Stepper/Stepper.d.ts +7 -0
  170. package/dist/components/navigation/Stepper/Stepper.js.map +1 -1
  171. package/dist/components/navigation/Tabs/Tabs.d.ts +8 -0
  172. package/dist/components/navigation/Tabs/Tabs.js.map +1 -1
  173. package/dist/components/overlays/Dialog/Dialog.d.ts +13 -0
  174. package/dist/components/overlays/Dialog/Dialog.js.map +1 -1
  175. package/dist/components/overlays/DropdownMenu/DropdownMenu.d.ts +8 -0
  176. package/dist/components/overlays/DropdownMenu/DropdownMenu.js.map +1 -1
  177. package/dist/components/overlays/Popover/Popover.d.ts +7 -0
  178. package/dist/components/overlays/Popover/Popover.js.map +1 -1
  179. package/dist/components/overlays/Sheet/Sheet.d.ts +8 -0
  180. package/dist/components/overlays/Sheet/Sheet.js.map +1 -1
  181. package/dist/components/overlays/Tooltip/Tooltip.d.ts +8 -0
  182. package/dist/components/overlays/Tooltip/Tooltip.js.map +1 -1
  183. package/dist/components/typography/Amount/Amount.d.ts +8 -0
  184. package/dist/components/typography/Amount/Amount.js.map +1 -1
  185. package/dist/components/typography/Code/Code.d.ts +8 -0
  186. package/dist/components/typography/Code/Code.js.map +1 -1
  187. package/dist/components/typography/Heading/Heading.d.ts +8 -0
  188. package/dist/components/typography/Heading/Heading.js.map +1 -1
  189. package/dist/components/typography/Kbd/Kbd.d.ts +6 -0
  190. package/dist/components/typography/Kbd/Kbd.js.map +1 -1
  191. package/dist/components/typography/Link/Link.d.ts +9 -0
  192. package/dist/components/typography/Link/Link.js.map +1 -1
  193. package/dist/components/typography/Numeral/Numeral.d.ts +8 -0
  194. package/dist/components/typography/Numeral/Numeral.js.map +1 -1
  195. package/dist/components/typography/Prose/Prose.d.ts +9 -0
  196. package/dist/components/typography/Prose/Prose.js.map +1 -1
  197. package/dist/components/typography/Quote/Quote.d.ts +7 -0
  198. package/dist/components/typography/Quote/Quote.js.map +1 -1
  199. package/dist/components/typography/SectionHeader/SectionHeader.d.ts +8 -0
  200. package/dist/components/typography/SectionHeader/SectionHeader.js.map +1 -1
  201. package/dist/components/typography/Text/Text.d.ts +8 -0
  202. package/dist/components/typography/Text/Text.js.map +1 -1
  203. package/package.json +1 -1
  204. package/skills/layout-composition/SKILL.md +27 -88
  205. package/skills/layout-composition/references/action-bar.md +3 -3
  206. package/skills/layout-composition/references/app-shell.md +10 -3
  207. package/skills/layout-composition/references/aspect-ratio.md +2 -0
  208. package/skills/layout-composition/references/box.md +6 -6
  209. package/skills/layout-composition/references/container.md +14 -12
  210. package/skills/layout-composition/references/divider.md +4 -4
  211. package/skills/layout-composition/references/section.md +69 -0
  212. package/skills/layout-composition/references/visually-hidden.md +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"ColorField.js","names":["ColorField","forwardRef","fieldProps","rest","splitFieldLabelProps","props","inputRest","Field","id","ColorInput"],"sources":["../../../../src/components/inputs/ColorField/ColorField.tsx"],"sourcesContent":["import { forwardRef } from 'react'\nimport { Field, type FieldLabelProps } from '#components/inputs/Field'\nimport { ColorInput, type ColorInputProps } from '#components/inputs/ColorInput'\nimport { splitFieldLabelProps } from '#components/inputs/internal/fieldProps'\n\nexport interface ColorFieldProps\n extends FieldLabelProps, Omit<ColorInputProps, 'invalid' | keyof FieldLabelProps> {}\n\n/**\n * Label + ColorInput + description + error. Input props (`value`, `swatches`,\n * `swatchesOnly`…) and the ref go to the hex input (or the swatch group with\n * `swatchesOnly`); `className`/`style` go to the wrapper.\n *\n * <ColorField label=\"Label colour\" swatches={palette} value={colour} onValueChange={setColour} />\n */\nexport const ColorField = forwardRef<HTMLElement, ColorFieldProps>(function ColorField(props, ref) {\n const [fieldProps, rest] = splitFieldLabelProps(props)\n const { id, disabled, className, style, ...inputRest } = rest\n return (\n <Field {...fieldProps} htmlFor={id} disabled={disabled} className={className} style={style}>\n <ColorInput ref={ref} id={id} disabled={disabled} {...inputRest} />\n </Field>\n )\n})\n"],"mappings":";;;;;;AAeA,IAAaA,IAAaC,EAAyC,SAAoB,GAAO,GAAK;CACjG,IAAM,CAACC,GAAYC,KAAQC,EAAqBC,CAAK,GAC/C,EAAE,OAAI,aAAU,cAAW,UAAO,GAAGC,MAAcH;CACzD,OACE,kBAACI,GAAD;EAAO,GAAIL;EAAY,SAASM;EAAc;EAAqB;EAAkB;EACnF,UAAA,kBAACC,GAAD;GAAiB;GAAS;GAAc;GAAU,GAAIH;EAAY,CAAA;CAC7D,CAAA;AAEX,CAAC"}
1
+ {"version":3,"file":"ColorField.js","names":["ColorField","forwardRef","fieldProps","rest","splitFieldLabelProps","props","inputRest","Field","id","ColorInput"],"sources":["../../../../src/components/inputs/ColorField/ColorField.tsx"],"sourcesContent":["import { forwardRef } from 'react'\nimport { Field, type FieldLabelProps } from '#components/inputs/Field'\nimport { ColorInput, type ColorInputProps } from '#components/inputs/ColorInput'\nimport { splitFieldLabelProps } from '#components/inputs/internal/fieldProps'\n\nexport interface ColorFieldProps\n extends FieldLabelProps, Omit<ColorInputProps, 'invalid' | keyof FieldLabelProps> {}\n\n/**\n * A labelled colour input with a picker, a hex code and named presets.\n *\n * @remarks\n * `ColorField` is a {@link Field | Field} around a {@link ColorInput | ColorInput}.\n *\n * @privateRemarks\n * Label + ColorInput + description + error. Input props (`value`, `swatches`,\n * `swatchesOnly`…) and the ref go to the hex input (or the swatch group with\n * `swatchesOnly`); `className`/`style` go to the wrapper.\n *\n * <ColorField label=\"Label colour\" swatches={palette} value={colour} onValueChange={setColour} />\n */\nexport const ColorField = forwardRef<HTMLElement, ColorFieldProps>(function ColorField(props, ref) {\n const [fieldProps, rest] = splitFieldLabelProps(props)\n const { id, disabled, className, style, ...inputRest } = rest\n return (\n <Field {...fieldProps} htmlFor={id} disabled={disabled} className={className} style={style}>\n <ColorInput ref={ref} id={id} disabled={disabled} {...inputRest} />\n </Field>\n )\n})\n"],"mappings":";;;;;;AAqBA,IAAaA,IAAaC,EAAyC,SAAoB,GAAO,GAAK;CACjG,IAAM,CAACC,GAAYC,KAAQC,EAAqBC,CAAK,GAC/C,EAAE,OAAI,aAAU,cAAW,UAAO,GAAGC,MAAcH;CACzD,OACE,kBAACI,GAAD;EAAO,GAAIL;EAAY,SAASM;EAAc;EAAqB;EAAkB;EACnF,UAAA,kBAACC,GAAD;GAAiB;GAAS;GAAc;GAAU,GAAIH;EAAY,CAAA;CAC7D,CAAA;AAEX,CAAC"}
@@ -20,6 +20,14 @@ export interface ColorInputProps extends Omit<InputProps, 'type' | 'value' | 'de
20
20
  swatchesLabel?: string;
21
21
  }
22
22
  /**
23
+ * A colour as a hex code, with the native picker as its swatch and optional named presets.
24
+ *
25
+ * @remarks
26
+ * `ColorInput` holds a colour as a `#rrggbb` hex code: the native colour picker is its leading
27
+ * swatch, the hex text follows (normalised on blur, so `#ABC` becomes `#aabbcc`), and `swatches`
28
+ * adds named presets as a radio group. With `swatchesOnly`, only the presets can be chosen.
29
+ *
30
+ * @privateRemarks
23
31
  * A colour as a hex code: a native colour picker as the leading swatch, the `#rrggbb`
24
32
  * text after it (normalised on blur — `#ABC` becomes `#aabbcc`), and optional named
25
33
  * preset swatches as a radio group. The ref goes to the hex input (or, with
@@ -1 +1 @@
1
- {"version":3,"file":"ColorInput.js","names":["styles","ColorInput_module_default","ColorInput","markFieldAware","forwardRef","valueProp","idProp","disabledProp","readOnlyProp","requiredProp","describedByProp","ariaInvalid","rest","field","useResolvedField","autoId","useId","rootRef","useRef","swatchesLabelId","isControlled","internal","setInternal","useState","normaliseHex","defaultValue","value","draft","setDraft","editing","setEditing","editable","setValue","next","onValueChange","commit","text","hex","handleTextChange","event","leftControl","handleTextBlur","onBlur","handleOtherBlur","matching","swatches","s","labelTarget","offPalette","swatchesOnly","swatchGroup","RadioGroup","ref","name","swatchesLabel","swatch","cx","className","size","Input","onFocus","onKeyDown","pickerLabel"],"sources":["../../../../src/components/inputs/ColorInput/ColorInput.tsx"],"sourcesContent":["import {\n forwardRef,\n useEffect,\n useId,\n useRef,\n useState,\n type ChangeEvent,\n type CSSProperties,\n type FocusEvent,\n type KeyboardEvent,\n type Ref,\n} from 'react'\nimport { RadioGroup } from 'radix-ui'\nimport { cx } from '#utils/cx'\nimport { Input, type InputProps } from '#components/inputs/Input'\nimport { markFieldAware, useResolvedField } from '#components/inputs/internal/FieldContext'\nimport { normaliseHex } from './colorFormat'\nimport styles from './ColorInput.module.css'\n\nexport interface ColorSwatch {\n /** Any `#rgb` / `#rrggbb`; emitted normalised (`#rrggbb`, lowercase). */\n value: string\n /** The colour's name, read by assistive tech and shown on hover (\"Coral\"). Required. */\n label: string\n}\n\nexport interface ColorInputProps extends Omit<\n InputProps,\n 'type' | 'value' | 'defaultValue' | 'onChange' | 'leading'\n> {\n /** `#rrggbb` (lowercase), or `''` when empty. */\n value?: string\n defaultValue?: string\n onValueChange?: (hex: string) => void\n /** Preset colours, shown as a row of swatch radios under the input. */\n swatches?: readonly ColorSwatch[]\n /** Only the swatches — no hex input or picker (a label colour from a fixed palette). */\n swatchesOnly?: boolean\n /** Accessible name of the native colour picker button. Default `'Choose colour'`. */\n pickerLabel?: string\n /** Accessible name appended to the field label for the swatch group. Default `'presets'`. */\n swatchesLabel?: string\n}\n\n/**\n * A colour as a hex code: a native colour picker as the leading swatch, the `#rrggbb`\n * text after it (normalised on blur — `#ABC` becomes `#aabbcc`), and optional named\n * preset swatches as a radio group. The ref goes to the hex input (or, with\n * `swatchesOnly`, to the swatch group); `name` submits the hex.\n *\n * <ColorInput swatches={[{ value: '#ff6b57', label: 'Coral' }]} value={colour} onValueChange={setColour} />\n */\nexport const ColorInput = markFieldAware(\n forwardRef<HTMLElement, ColorInputProps>(function ColorInput(\n {\n value: valueProp,\n defaultValue,\n onValueChange,\n swatches,\n swatchesOnly = false,\n pickerLabel = 'Choose colour',\n swatchesLabel = 'presets',\n name,\n form,\n size = 'md',\n id: idProp,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n required: requiredProp,\n invalid,\n className,\n style,\n onBlur,\n onFocus,\n onKeyDown,\n 'aria-describedby': describedByProp,\n 'aria-invalid': ariaInvalid,\n ...rest\n },\n ref,\n ) {\n const field = useResolvedField({\n id: idProp,\n describedBy: describedByProp,\n invalid,\n ariaInvalid,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n required: requiredProp,\n })\n const autoId = useId()\n const rootRef = useRef<HTMLDivElement>(null)\n const swatchesLabelId = `${autoId}swatches`\n const isControlled = valueProp !== undefined\n const [internal, setInternal] = useState(() => normaliseHex(defaultValue ?? '') ?? '')\n const value = isControlled ? (normaliseHex(valueProp) ?? valueProp) : internal\n const [draft, setDraft] = useState(value)\n const [editing, setEditing] = useState(false)\n\n useEffect(() => {\n if (!editing) setDraft(value)\n }, [value, editing])\n\n const editable = !field.disabled && !field.readOnly\n\n const setValue = (next: string) => {\n if (!isControlled) setInternal(next)\n if (next !== value) onValueChange?.(next)\n }\n\n const commit = () => {\n const text = draft.trim()\n if (text === '') {\n setValue('')\n setDraft('')\n return\n }\n const hex = normaliseHex(text)\n if (hex) setValue(hex)\n setDraft(hex ?? value)\n }\n\n const handleTextChange = (event: ChangeEvent<HTMLInputElement>) => {\n const text = event.target.value\n setDraft(text)\n const hex = /^#?[0-9a-f]{6}$/i.test(text.trim()) ? normaliseHex(text) : null\n if (hex) setValue(hex)\n else if (text.trim() === '') setValue('')\n }\n\n // Blur fires once focus leaves the whole control (picker, text, swatches).\n const leftControl = (event: FocusEvent<HTMLElement>) =>\n !(event.relatedTarget instanceof Node && rootRef.current?.contains(event.relatedTarget))\n\n const handleTextBlur = (event: FocusEvent<HTMLInputElement>) => {\n commit()\n setEditing(false)\n if (leftControl(event)) onBlur?.(event)\n }\n const handleOtherBlur = (event: FocusEvent<HTMLElement>) => {\n // Same event, typed for the input's handler: the target is the picker or a swatch.\n if (leftControl(event)) onBlur?.(event as unknown as FocusEvent<HTMLInputElement>)\n }\n\n const matching = swatches?.find((s) => normaliseHex(s.value) === value)\n // With swatches only, the Field label points at the swatch a Tab would land on.\n const labelTarget = normaliseHex((matching ?? swatches?.[0])?.value ?? '')\n // Swatches only, with a value no swatch matches (saved data, a retired colour): no radio is\n // checked, so a hidden input submits it instead — and the radios get no name, so it's never\n // submitted twice. A non-empty value satisfies `required`, so the radios drop that too.\n const offPalette = swatchesOnly && value !== '' && !matching\n const swatchGroup =\n swatches && swatches.length > 0 ? (\n <RadioGroup.Root\n ref={swatchesOnly ? (ref as Ref<HTMLDivElement>) : undefined}\n className={styles.swatches}\n orientation=\"horizontal\"\n loop\n value={matching ? (normaliseHex(matching.value) ?? '') : ''}\n onValueChange={(next) => {\n if (editable) setValue(next)\n }}\n disabled={field.disabled}\n // Swatches only: the radios themselves submit `name` and carry `required` (Radix\n // renders named native radios inside a form). Otherwise the hex input does.\n name={swatchesOnly && !offPalette ? name : undefined}\n required={swatchesOnly && !offPalette ? field.required : undefined}\n aria-required={swatchesOnly ? field.required || undefined : undefined}\n // Swatches only: the group *is* the control, named by the Field label alone. Beside the\n // hex input it is a second control, \"Label colour presets\".\n aria-labelledby={\n field.labelId\n ? swatchesOnly\n ? field.labelId\n : `${field.labelId} ${swatchesLabelId}`\n : swatchesLabelId\n }\n aria-describedby={swatchesOnly ? field.describedBy : undefined}\n aria-invalid={swatchesOnly ? field.invalid || undefined : undefined}\n aria-readonly={field.readOnly || undefined}\n aria-busy={swatchesOnly ? field.busy || undefined : undefined}\n onBlur={handleOtherBlur}\n >\n <span id={swatchesLabelId} hidden>\n {swatchesLabel}\n </span>\n {swatches.map((swatch) => {\n const hex = normaliseHex(swatch.value) ?? swatch.value\n return (\n <RadioGroup.Item\n key={hex}\n value={hex}\n id={swatchesOnly && hex === labelTarget ? field.id : undefined}\n className={styles.swatch}\n aria-label={swatch.label}\n title={swatch.label}\n data-readonly={field.readOnly || undefined}\n // The swatch colour is data, not styling — the one place a raw colour renders.\n style={{ '--_swatch': hex } as CSSProperties}\n />\n )\n })}\n </RadioGroup.Root>\n ) : null\n\n if (swatchesOnly) {\n return (\n <div\n ref={rootRef}\n className={cx(styles.root, className)}\n style={style}\n data-size={size}\n data-swatches-only=\"\"\n >\n {swatchGroup}\n {offPalette && name != null ? (\n <input type=\"hidden\" name={name} form={form} value={value} disabled={field.disabled} />\n ) : null}\n </div>\n )\n }\n\n return (\n <div ref={rootRef} className={cx(styles.root, className)} style={style} data-size={size}>\n <Input\n ref={ref as Ref<HTMLInputElement>}\n {...rest}\n className={styles.box}\n id={idProp}\n size={size}\n numeric={false}\n type=\"text\"\n name={name}\n form={form}\n disabled={disabledProp}\n readOnly={readOnlyProp}\n required={requiredProp}\n invalid={invalid}\n aria-describedby={describedByProp}\n aria-invalid={ariaInvalid}\n maxLength={7}\n autoComplete=\"off\"\n autoCapitalize=\"off\"\n autoCorrect=\"off\"\n spellCheck={false}\n placeholder={rest.placeholder ?? '#rrggbb'}\n value={draft}\n onChange={handleTextChange}\n onFocus={(event) => {\n setEditing(true)\n onFocus?.(event)\n }}\n onBlur={handleTextBlur}\n onKeyDown={(event: KeyboardEvent<HTMLInputElement>) => {\n onKeyDown?.(event)\n if (!event.defaultPrevented && event.key === 'Enter') commit()\n }}\n leading={\n <span className={styles.picker} data-empty={value === '' || undefined}>\n <input\n type=\"color\"\n className={styles.pickerInput}\n aria-label={pickerLabel}\n value={value || '#000000'}\n disabled={!editable}\n tabIndex={field.readOnly ? -1 : undefined}\n onChange={(event) => {\n setValue(event.target.value.toLowerCase())\n }}\n onBlur={handleOtherBlur}\n />\n </span>\n }\n />\n {swatchGroup}\n </div>\n )\n }),\n)\n"],"mappings":"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"}
1
+ {"version":3,"file":"ColorInput.js","names":["styles","ColorInput_module_default","ColorInput","markFieldAware","forwardRef","valueProp","idProp","disabledProp","readOnlyProp","requiredProp","describedByProp","ariaInvalid","rest","field","useResolvedField","autoId","useId","rootRef","useRef","swatchesLabelId","isControlled","internal","setInternal","useState","normaliseHex","defaultValue","value","draft","setDraft","editing","setEditing","editable","setValue","next","onValueChange","commit","text","hex","handleTextChange","event","leftControl","handleTextBlur","onBlur","handleOtherBlur","matching","swatches","s","labelTarget","offPalette","swatchesOnly","swatchGroup","RadioGroup","ref","name","swatchesLabel","swatch","cx","className","size","Input","onFocus","onKeyDown","pickerLabel"],"sources":["../../../../src/components/inputs/ColorInput/ColorInput.tsx"],"sourcesContent":["import {\n forwardRef,\n useEffect,\n useId,\n useRef,\n useState,\n type ChangeEvent,\n type CSSProperties,\n type FocusEvent,\n type KeyboardEvent,\n type Ref,\n} from 'react'\nimport { RadioGroup } from 'radix-ui'\nimport { cx } from '#utils/cx'\nimport { Input, type InputProps } from '#components/inputs/Input'\nimport { markFieldAware, useResolvedField } from '#components/inputs/internal/FieldContext'\nimport { normaliseHex } from './colorFormat'\nimport styles from './ColorInput.module.css'\n\nexport interface ColorSwatch {\n /** Any `#rgb` / `#rrggbb`; emitted normalised (`#rrggbb`, lowercase). */\n value: string\n /** The colour's name, read by assistive tech and shown on hover (\"Coral\"). Required. */\n label: string\n}\n\nexport interface ColorInputProps extends Omit<\n InputProps,\n 'type' | 'value' | 'defaultValue' | 'onChange' | 'leading'\n> {\n /** `#rrggbb` (lowercase), or `''` when empty. */\n value?: string\n defaultValue?: string\n onValueChange?: (hex: string) => void\n /** Preset colours, shown as a row of swatch radios under the input. */\n swatches?: readonly ColorSwatch[]\n /** Only the swatches — no hex input or picker (a label colour from a fixed palette). */\n swatchesOnly?: boolean\n /** Accessible name of the native colour picker button. Default `'Choose colour'`. */\n pickerLabel?: string\n /** Accessible name appended to the field label for the swatch group. Default `'presets'`. */\n swatchesLabel?: string\n}\n\n/**\n * A colour as a hex code, with the native picker as its swatch and optional named presets.\n *\n * @remarks\n * `ColorInput` holds a colour as a `#rrggbb` hex code: the native colour picker is its leading\n * swatch, the hex text follows (normalised on blur, so `#ABC` becomes `#aabbcc`), and `swatches`\n * adds named presets as a radio group. With `swatchesOnly`, only the presets can be chosen.\n *\n * @privateRemarks\n * A colour as a hex code: a native colour picker as the leading swatch, the `#rrggbb`\n * text after it (normalised on blur — `#ABC` becomes `#aabbcc`), and optional named\n * preset swatches as a radio group. The ref goes to the hex input (or, with\n * `swatchesOnly`, to the swatch group); `name` submits the hex.\n *\n * <ColorInput swatches={[{ value: '#ff6b57', label: 'Coral' }]} value={colour} onValueChange={setColour} />\n */\nexport const ColorInput = markFieldAware(\n forwardRef<HTMLElement, ColorInputProps>(function ColorInput(\n {\n value: valueProp,\n defaultValue,\n onValueChange,\n swatches,\n swatchesOnly = false,\n pickerLabel = 'Choose colour',\n swatchesLabel = 'presets',\n name,\n form,\n size = 'md',\n id: idProp,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n required: requiredProp,\n invalid,\n className,\n style,\n onBlur,\n onFocus,\n onKeyDown,\n 'aria-describedby': describedByProp,\n 'aria-invalid': ariaInvalid,\n ...rest\n },\n ref,\n ) {\n const field = useResolvedField({\n id: idProp,\n describedBy: describedByProp,\n invalid,\n ariaInvalid,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n required: requiredProp,\n })\n const autoId = useId()\n const rootRef = useRef<HTMLDivElement>(null)\n const swatchesLabelId = `${autoId}swatches`\n const isControlled = valueProp !== undefined\n const [internal, setInternal] = useState(() => normaliseHex(defaultValue ?? '') ?? '')\n const value = isControlled ? (normaliseHex(valueProp) ?? valueProp) : internal\n const [draft, setDraft] = useState(value)\n const [editing, setEditing] = useState(false)\n\n useEffect(() => {\n if (!editing) setDraft(value)\n }, [value, editing])\n\n const editable = !field.disabled && !field.readOnly\n\n const setValue = (next: string) => {\n if (!isControlled) setInternal(next)\n if (next !== value) onValueChange?.(next)\n }\n\n const commit = () => {\n const text = draft.trim()\n if (text === '') {\n setValue('')\n setDraft('')\n return\n }\n const hex = normaliseHex(text)\n if (hex) setValue(hex)\n setDraft(hex ?? value)\n }\n\n const handleTextChange = (event: ChangeEvent<HTMLInputElement>) => {\n const text = event.target.value\n setDraft(text)\n const hex = /^#?[0-9a-f]{6}$/i.test(text.trim()) ? normaliseHex(text) : null\n if (hex) setValue(hex)\n else if (text.trim() === '') setValue('')\n }\n\n // Blur fires once focus leaves the whole control (picker, text, swatches).\n const leftControl = (event: FocusEvent<HTMLElement>) =>\n !(event.relatedTarget instanceof Node && rootRef.current?.contains(event.relatedTarget))\n\n const handleTextBlur = (event: FocusEvent<HTMLInputElement>) => {\n commit()\n setEditing(false)\n if (leftControl(event)) onBlur?.(event)\n }\n const handleOtherBlur = (event: FocusEvent<HTMLElement>) => {\n // Same event, typed for the input's handler: the target is the picker or a swatch.\n if (leftControl(event)) onBlur?.(event as unknown as FocusEvent<HTMLInputElement>)\n }\n\n const matching = swatches?.find((s) => normaliseHex(s.value) === value)\n // With swatches only, the Field label points at the swatch a Tab would land on.\n const labelTarget = normaliseHex((matching ?? swatches?.[0])?.value ?? '')\n // Swatches only, with a value no swatch matches (saved data, a retired colour): no radio is\n // checked, so a hidden input submits it instead — and the radios get no name, so it's never\n // submitted twice. A non-empty value satisfies `required`, so the radios drop that too.\n const offPalette = swatchesOnly && value !== '' && !matching\n const swatchGroup =\n swatches && swatches.length > 0 ? (\n <RadioGroup.Root\n ref={swatchesOnly ? (ref as Ref<HTMLDivElement>) : undefined}\n className={styles.swatches}\n orientation=\"horizontal\"\n loop\n value={matching ? (normaliseHex(matching.value) ?? '') : ''}\n onValueChange={(next) => {\n if (editable) setValue(next)\n }}\n disabled={field.disabled}\n // Swatches only: the radios themselves submit `name` and carry `required` (Radix\n // renders named native radios inside a form). Otherwise the hex input does.\n name={swatchesOnly && !offPalette ? name : undefined}\n required={swatchesOnly && !offPalette ? field.required : undefined}\n aria-required={swatchesOnly ? field.required || undefined : undefined}\n // Swatches only: the group *is* the control, named by the Field label alone. Beside the\n // hex input it is a second control, \"Label colour presets\".\n aria-labelledby={\n field.labelId\n ? swatchesOnly\n ? field.labelId\n : `${field.labelId} ${swatchesLabelId}`\n : swatchesLabelId\n }\n aria-describedby={swatchesOnly ? field.describedBy : undefined}\n aria-invalid={swatchesOnly ? field.invalid || undefined : undefined}\n aria-readonly={field.readOnly || undefined}\n aria-busy={swatchesOnly ? field.busy || undefined : undefined}\n onBlur={handleOtherBlur}\n >\n <span id={swatchesLabelId} hidden>\n {swatchesLabel}\n </span>\n {swatches.map((swatch) => {\n const hex = normaliseHex(swatch.value) ?? swatch.value\n return (\n <RadioGroup.Item\n key={hex}\n value={hex}\n id={swatchesOnly && hex === labelTarget ? field.id : undefined}\n className={styles.swatch}\n aria-label={swatch.label}\n title={swatch.label}\n data-readonly={field.readOnly || undefined}\n // The swatch colour is data, not styling — the one place a raw colour renders.\n style={{ '--_swatch': hex } as CSSProperties}\n />\n )\n })}\n </RadioGroup.Root>\n ) : null\n\n if (swatchesOnly) {\n return (\n <div\n ref={rootRef}\n className={cx(styles.root, className)}\n style={style}\n data-size={size}\n data-swatches-only=\"\"\n >\n {swatchGroup}\n {offPalette && name != null ? (\n <input type=\"hidden\" name={name} form={form} value={value} disabled={field.disabled} />\n ) : null}\n </div>\n )\n }\n\n return (\n <div ref={rootRef} className={cx(styles.root, className)} style={style} data-size={size}>\n <Input\n ref={ref as Ref<HTMLInputElement>}\n {...rest}\n className={styles.box}\n id={idProp}\n size={size}\n numeric={false}\n type=\"text\"\n name={name}\n form={form}\n disabled={disabledProp}\n readOnly={readOnlyProp}\n required={requiredProp}\n invalid={invalid}\n aria-describedby={describedByProp}\n aria-invalid={ariaInvalid}\n maxLength={7}\n autoComplete=\"off\"\n autoCapitalize=\"off\"\n autoCorrect=\"off\"\n spellCheck={false}\n placeholder={rest.placeholder ?? '#rrggbb'}\n value={draft}\n onChange={handleTextChange}\n onFocus={(event) => {\n setEditing(true)\n onFocus?.(event)\n }}\n onBlur={handleTextBlur}\n onKeyDown={(event: KeyboardEvent<HTMLInputElement>) => {\n onKeyDown?.(event)\n if (!event.defaultPrevented && event.key === 'Enter') commit()\n }}\n leading={\n <span className={styles.picker} data-empty={value === '' || undefined}>\n <input\n type=\"color\"\n className={styles.pickerInput}\n aria-label={pickerLabel}\n value={value || '#000000'}\n disabled={!editable}\n tabIndex={field.readOnly ? -1 : undefined}\n onChange={(event) => {\n setValue(event.target.value.toLowerCase())\n }}\n onBlur={handleOtherBlur}\n />\n </span>\n }\n />\n {swatchGroup}\n </div>\n )\n }),\n)\n"],"mappings":"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"}
@@ -63,6 +63,15 @@ export interface ComboboxMultipleProps extends ComboboxBase {
63
63
  }
64
64
  export type ComboboxProps = ComboboxSingleProps | ComboboxMultipleProps;
65
65
  /**
66
+ * Type to filter and pick from a list. Single or multiple, free text if you allow it, ready for
67
+ * async options.
68
+ *
69
+ * @remarks
70
+ * `Combobox` is an ARIA 1.2 combobox: a text input that filters a listbox as you type. With
71
+ * `multiple`, chosen values become removable chips in the box. With `creatable`, typed text that
72
+ * matches nothing can be added as a value.
73
+ *
74
+ * @privateRemarks
66
75
  * Type to filter, pick from a list (ARIA 1.2 combobox with a listbox popup). Single or
67
76
  * `multiple` (chosen values become removable chips), `creatable` for free text, and
68
77
  * async-ready: pass `filter="none"`, `loading` and the loader's results as `options`.
@@ -1 +1 @@
1
- {"version":3,"file":"Combobox.js","names":["PopoverPrimitive","styles","control","messageStyles","messages_module_default","control_module_default","Combobox_module_default","buildView","matched","shouldFilter","filterOptions","options","query","sections","byKey","option","key","section","defaultRemoveLabel","label","splitMode","props","base","defaultValue","onValueChange","next","removeLabel","multiple","value","themeScopeOf","scope","node","countMessage","count","ComboboxPopup","forwardRef","theme","usePortalTheme","Popover","Combobox","markFieldAware","mode","inputValueProp","openProp","invalidProp","idProp","disabledProp","requiredProp","readOnlyProp","describedByProp","ariaInvalid","ariaLabel","ariaLabelledBy","rest","field","useResolvedField","autoId","useId","inputId","listboxId","statusId","interactive","inputRef","useRef","boxRef","composedInputRef","useMergedRefs","ref","labelCache","labelOf","useCallback","values","setValues","useControllableState","selectedLabel","setQueryState","defaultInputValue","onInputValueChange","queryRef","setQuery","dirty","setDirty","useState","openState","setOpenState","defaultOpen","onOpenChange","openRef","setOpen","activeValue","setActiveValue","filter","useMemo","indexOf","index","optionId","atMax","maxSelected","isSelected","isDisabled","enabled","ordered","trimmedQuery","freeText","creatable","showEmpty","loading","hasPopupContent","expanded","autoHighlight","activeOption","active","announcement","setAnnouncement","countText","emptyMessage","timer","activeId","selectOption","commitText","folded","foldText","match","removeValue","v","clear","initialActive","fromEnd","move","delta","openList","highlight","handleChange","text","event","handleKeyDown","onKeyDown","handleBlur","onBlur","handleBoxPointerDown","target","handleInputClick","onClick","handleInteractOutside","listLabelledBy","showPlaceholder","canClear","clearable","renderOption","selected","disabled","CheckIcon","PortalAnchorContext","cx","className","size","TagList","Tag","placeholder","Spinner","clearLabel","CloseIcon","ChevronDownIcon","name","loadingMessage"],"sources":["../../../../src/components/inputs/Combobox/Combobox.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type FocusEvent,\n type FocusEventHandler,\n type InputHTMLAttributes,\n type KeyboardEvent,\n type MouseEvent,\n type PointerEvent,\n type ReactNode,\n} from 'react'\nimport { Popover as PopoverPrimitive } from 'radix-ui'\nimport { CheckIcon, ChevronDownIcon, CloseIcon } from '#icons'\nimport { cx } from '#utils/cx'\nimport type { Size } from '#utils/tokens'\nimport { Spinner } from '#components/feedback/Spinner'\nimport { Tag, TagList } from '#components/display/Tag'\nimport { PortalAnchorContext, usePortalTheme } from '#components/overlays/usePortalTheme'\nimport { markFieldAware, useResolvedField } from '#components/inputs/internal/FieldContext'\nimport { filterOptions, foldText } from '#components/inputs/internal/filterOptions'\nimport { useMergedRefs } from '#components/inputs/internal/refs'\nimport control from '#components/inputs/internal/control.module.css'\nimport messageStyles from '#components/inputs/internal/messages.module.css'\nimport { useControllableState } from './useControllableState'\nimport styles from './Combobox.module.css'\n\nexport interface ComboboxOption {\n value: string\n label: string\n /** A second, quieter line under the label. Also searched. */\n description?: string\n /** Extra search terms that aren't shown (\"USA\", \"Holland\"). An exact keyword ranks first. */\n keywords?: readonly string[]\n /** Heading the option is listed under. Groups appear in order of their first option. */\n group?: string\n disabled?: boolean\n}\n\nexport interface ComboboxBase extends Omit<\n InputHTMLAttributes<HTMLInputElement>,\n 'value' | 'defaultValue' | 'onChange' | 'size' | 'type' | 'multiple' | 'onBlur'\n> {\n options: readonly ComboboxOption[]\n /** The text in the box (the query). Controlled. */\n inputValue?: string\n defaultInputValue?: string\n onInputValueChange?: (query: string) => void\n /**\n * `auto` (default) filters and ranks `options` by the query. `none` shows `options` as\n * given — for async search, where the loader has already filtered.\n */\n filter?: 'auto' | 'none'\n /** Options are being fetched: a spinner in the box and `loadingMessage` in an empty list. */\n loading?: boolean\n loadingMessage?: ReactNode\n /** Shown in the list when nothing matches. Default \"No matches\". */\n emptyMessage?: ReactNode\n open?: boolean\n defaultOpen?: boolean\n onOpenChange?: (open: boolean) => void\n /**\n * Free text is allowed: whatever is typed becomes the value when committed (Enter, or\n * leaving the field). A typed label that matches an option picks that option instead.\n */\n creatable?: boolean\n /** Shows a clear button while there's a value. */\n clearable?: boolean\n /** Accessible name of the clear button. Default \"Clear\". */\n clearLabel?: string\n size?: Size\n /** Critical border + `aria-invalid`. Inside a `<Field error>` this is set for you. */\n invalid?: boolean\n /** Fires once focus leaves the whole control (input, chips, clear button, list). */\n onBlur?: FocusEventHandler<HTMLElement>\n}\n\nexport interface ComboboxSingleProps extends ComboboxBase {\n multiple?: false\n value?: string | null\n defaultValue?: string | null\n onValueChange?: (value: string | null) => void\n}\n\nexport interface ComboboxMultipleProps extends ComboboxBase {\n multiple: true\n value?: readonly string[]\n defaultValue?: readonly string[]\n onValueChange?: (value: string[]) => void\n /** Once this many are chosen, the rest of the list is disabled. */\n maxSelected?: number\n /** Accessible name of a chip's remove button. Default `Remove <label>`. */\n removeLabel?: (label: string) => string\n}\n\nexport type ComboboxProps = ComboboxSingleProps | ComboboxMultipleProps\n\n/* ─── Pure helpers ────────────────────────────────────────────────────────── */\n\ninterface Section {\n key: string\n label?: string\n options: ComboboxOption[]\n}\n\n/** Visible options, in groups (ordered by each group's first/best option), and flattened. */\nfunction buildView(options: readonly ComboboxOption[], query: string, shouldFilter: boolean) {\n const matched = shouldFilter ? filterOptions(options, query) : [...options]\n const sections: Section[] = []\n const byKey = new Map<string, Section>()\n for (const option of matched) {\n const key = option.group === undefined ? '' : `g:${option.group}`\n let section = byKey.get(key)\n if (!section) {\n section = { key, label: option.group, options: [] }\n byKey.set(key, section)\n sections.push(section)\n }\n section.options.push(option)\n }\n return { sections, ordered: sections.flatMap((section) => section.options) }\n}\n\ninterface ModeProps {\n multiple: boolean\n value: readonly string[] | undefined\n defaultValue: readonly string[]\n emit: (next: readonly string[]) => void\n maxSelected: number | undefined\n removeLabel: (label: string) => string\n}\n\nconst defaultRemoveLabel = (label: string) => `Remove ${label}`\n\n/** Splits the single/multiple union into one normalised shape (values are always arrays). */\nfunction splitMode(props: ComboboxProps): [ComboboxBase, ModeProps] {\n if (props.multiple === true) {\n const { multiple, value, defaultValue, onValueChange, maxSelected, removeLabel, ...base } =\n props\n return [\n base,\n {\n multiple,\n value,\n defaultValue: defaultValue ?? [],\n emit: (next) => onValueChange?.([...next]),\n maxSelected,\n removeLabel: removeLabel ?? defaultRemoveLabel,\n },\n ]\n }\n const { multiple, value, defaultValue, onValueChange, ...base } = props\n return [\n base,\n {\n multiple: Boolean(multiple),\n value: value === undefined ? undefined : value === null ? [] : [value],\n defaultValue: defaultValue == null ? [] : [defaultValue],\n emit: (next) => onValueChange?.(next[0] ?? null),\n maxSelected: undefined,\n removeLabel: defaultRemoveLabel,\n },\n ]\n}\n\n/** The nearest theme scope below `<html>` — the portal target, so the list opens in that theme. */\nfunction themeScopeOf(node: HTMLElement | null): HTMLElement | undefined {\n const scope = node?.closest<HTMLElement>('[data-theme]')\n return scope && scope !== node?.ownerDocument.documentElement ? scope : undefined\n}\n\nfunction countMessage(count: number): string {\n return `${String(count)} ${count === 1 ? 'option' : 'options'} available`\n}\n\n/* ─── Popup (mounts on open, so it reads the theme at open time) ─────────── */\n\ninterface PopupProps {\n children: ReactNode\n onInteractOutside: (event: Event) => void\n}\n\n// forwardRef: Radix Presence hands the popup a ref (React 18 warns without it).\nconst ComboboxPopup = forwardRef<HTMLDivElement, PopupProps>(function ComboboxPopup(\n { children, onInteractOutside },\n ref,\n) {\n const theme = usePortalTheme()\n return (\n <PopoverPrimitive.Content\n ref={ref}\n className={styles.popup}\n // A wrapper, not a dialog: the listbox inside carries the semantics.\n role={undefined}\n side=\"bottom\"\n align=\"start\"\n sideOffset={6}\n collisionPadding={8}\n // Focus never leaves the input (ARIA combobox): no auto-focus in or back.\n onOpenAutoFocus={(event) => {\n event.preventDefault()\n }}\n onCloseAutoFocus={(event) => {\n event.preventDefault()\n }}\n // The input's own keydown handles Escape (close, then clear).\n onEscapeKeyDown={(event) => {\n event.preventDefault()\n }}\n onInteractOutside={onInteractOutside}\n // Clicks on padding / messages must not take focus from the input.\n onMouseDown={(event) => {\n event.preventDefault()\n }}\n {...theme}\n >\n {children}\n </PopoverPrimitive.Content>\n )\n})\n\n/* ─── Combobox ────────────────────────────────────────────────────────────── */\n\n/**\n * Type to filter, pick from a list (ARIA 1.2 combobox with a listbox popup). Single or\n * `multiple` (chosen values become removable chips), `creatable` for free text, and\n * async-ready: pass `filter=\"none\"`, `loading` and the loader's results as `options`.\n * The ref and native input props go to the text input; `className`/`style` go to the box.\n *\n * <Combobox options={projects} placeholder=\"Search projects\" onValueChange={setProject} />\n * <Combobox multiple options={labels} maxSelected={3} />\n */\nexport const Combobox = markFieldAware(\n forwardRef<HTMLInputElement, ComboboxProps>(function Combobox(props, ref) {\n const [base, mode] = splitMode(props)\n const {\n options,\n inputValue: inputValueProp,\n defaultInputValue,\n onInputValueChange,\n filter = 'auto',\n loading = false,\n loadingMessage = 'Loading…',\n emptyMessage = 'No matches',\n open: openProp,\n defaultOpen = false,\n onOpenChange,\n creatable = false,\n clearable = false,\n clearLabel = 'Clear',\n size = 'md',\n invalid: invalidProp,\n id: idProp,\n disabled: disabledProp,\n required: requiredProp,\n readOnly: readOnlyProp,\n name,\n form,\n placeholder,\n className,\n style,\n onKeyDown,\n onBlur,\n onClick,\n 'aria-describedby': describedByProp,\n 'aria-invalid': ariaInvalid,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n ...rest\n } = base\n const { multiple, maxSelected, removeLabel } = mode\n\n const field = useResolvedField({\n id: idProp,\n describedBy: describedByProp,\n invalid: invalidProp,\n ariaInvalid,\n required: requiredProp,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n })\n const autoId = useId()\n const inputId = field.id ?? `${autoId}combobox`\n const listboxId = `${inputId}-listbox`\n const statusId = `${inputId}-status`\n const interactive = !field.disabled && !field.readOnly\n\n const inputRef = useRef<HTMLInputElement>(null)\n const boxRef = useRef<HTMLDivElement>(null)\n const composedInputRef = useMergedRefs(ref, inputRef)\n\n /* Labels of chosen values survive the options changing (async results, creatable). */\n const labelCache = useRef(new Map<string, string>())\n for (const option of options) labelCache.current.set(option.value, option.label)\n const labelOf = useCallback(\n (value: string) =>\n options.find((option) => option.value === value)?.label ??\n labelCache.current.get(value) ??\n value,\n [options],\n )\n\n const [values, setValues] = useControllableState<readonly string[]>(\n mode.value,\n mode.defaultValue,\n mode.emit,\n )\n const selectedLabel = !multiple && values[0] !== undefined ? labelOf(values[0]) : ''\n\n const [query, setQueryState] = useControllableState<string>(\n inputValueProp,\n defaultInputValue ??\n (multiple || mode.defaultValue[0] === undefined ? '' : labelOf(mode.defaultValue[0])),\n onInputValueChange,\n )\n const queryRef = useRef(query)\n queryRef.current = query\n const setQuery = useCallback(\n (next: string) => {\n if (next !== queryRef.current) setQueryState(next)\n },\n [setQueryState],\n )\n /** The user has typed since the last pick (single: the text is a query, not the label). */\n const [dirty, setDirty] = useState(false)\n\n const [openState, setOpenState] = useControllableState<boolean>(\n openProp,\n defaultOpen,\n onOpenChange,\n )\n const openRef = useRef(openState)\n openRef.current = openState\n const setOpen = useCallback(\n (next: boolean) => {\n if (next !== openRef.current) setOpenState(next)\n },\n [setOpenState],\n )\n\n const [activeValue, setActiveValue] = useState<string | null>(null)\n\n // Single: show the chosen option's label whenever the user isn't mid-edit (covers\n // external value changes such as a form reset).\n useEffect(() => {\n if (!multiple && !dirty) setQuery(selectedLabel)\n }, [multiple, dirty, selectedLabel, setQuery])\n\n /* ─── Derived view ─── */\n const shouldFilter = filter === 'auto' && (multiple || dirty)\n const { sections, ordered } = useMemo(\n () => buildView(options, query, shouldFilter),\n [options, query, shouldFilter],\n )\n const indexOf = useMemo(\n () => new Map(options.map((option, index) => [option.value, index])),\n [options],\n )\n const optionId = (value: string) => `${inputId}-option-${String(indexOf.get(value) ?? 0)}`\n\n const atMax = multiple && maxSelected !== undefined && values.length >= maxSelected\n const isSelected = (value: string) => values.includes(value)\n const isDisabled = (option: ComboboxOption) =>\n Boolean(option.disabled) || (atMax && !isSelected(option.value))\n const enabled = ordered.filter((option) => !isDisabled(option))\n\n const trimmedQuery = query.trim()\n const freeText = creatable && trimmedQuery !== '' && (multiple || dirty)\n const showEmpty = !loading && ordered.length === 0 && !freeText\n const hasPopupContent = ordered.length > 0 || loading || showEmpty\n const expanded = openState && interactive && hasPopupContent\n\n // Non-creatable: typing highlights the best match, so Enter picks it. Not while loading:\n // the list still shows the previous query's results, and Enter must not commit one of them.\n const autoHighlight =\n expanded && !loading && !creatable && trimmedQuery !== '' && (multiple || dirty)\n const activeOption =\n enabled.find((option) => option.value === activeValue) ??\n (autoHighlight ? enabled[0] : undefined)\n const active = expanded ? activeOption : undefined\n\n /* ─── Live region: result count, debounced ─── */\n const [announcement, setAnnouncement] = useState('')\n const countText = loading\n ? ''\n : ordered.length === 0\n ? typeof emptyMessage === 'string'\n ? emptyMessage\n : 'No matches'\n : countMessage(ordered.length)\n useEffect(() => {\n if (!expanded || countText === '') {\n if (!expanded) setAnnouncement('')\n return\n }\n const timer = setTimeout(() => {\n setAnnouncement(countText)\n }, 500)\n return () => {\n clearTimeout(timer)\n }\n }, [expanded, countText])\n\n /* Keep the highlighted row in view. */\n const activeId = active ? optionId(active.value) : undefined\n useEffect(() => {\n if (!activeId) return\n const node = inputRef.current?.ownerDocument.getElementById(activeId)\n node?.scrollIntoView({ block: 'nearest' })\n }, [activeId])\n\n /* ─── Actions ─── */\n const selectOption = (option: ComboboxOption) => {\n if (!interactive || isDisabled(option)) return\n labelCache.current.set(option.value, option.label)\n if (multiple) {\n const next = isSelected(option.value)\n ? values.filter((value) => value !== option.value)\n : [...values, option.value]\n setValues(next)\n setQuery('')\n setDirty(false)\n setActiveValue(option.value)\n } else {\n setValues([option.value])\n setQuery(option.label)\n setDirty(false)\n setActiveValue(null)\n setOpen(false)\n }\n }\n\n /** Creatable: turn the typed text into a value. Returns whether anything changed. */\n const commitText = (): boolean => {\n if (!creatable || trimmedQuery === '') return false\n const folded = foldText(trimmedQuery)\n const match = options.find((option) => !option.disabled && foldText(option.label) === folded)\n const value = match?.value ?? trimmedQuery\n const label = match?.label ?? trimmedQuery\n labelCache.current.set(value, label)\n if (multiple) {\n setQuery('')\n setDirty(false)\n if (isSelected(value) || atMax) return false\n setValues([...values, value])\n return true\n }\n setDirty(false)\n setQuery(label)\n if (values[0] === value) return false\n setValues([value])\n return true\n }\n\n const removeValue = (value: string) => {\n if (!interactive) return\n setValues(values.filter((v) => v !== value))\n }\n\n const clear = () => {\n if (!interactive) return\n setValues([])\n setQuery('')\n setDirty(false)\n setActiveValue(null)\n inputRef.current?.focus()\n }\n\n /** First visible selected option, else the first/last enabled one. */\n const initialActive = (fromEnd: boolean) =>\n enabled.find((option) => isSelected(option.value)) ??\n (fromEnd ? enabled[enabled.length - 1] : enabled[0])\n\n const move = (delta: 1 | -1) => {\n if (enabled.length === 0) return\n const index = active ? enabled.indexOf(active) : -1\n const next =\n index === -1\n ? delta === 1\n ? enabled[0]\n : enabled[enabled.length - 1]\n : enabled[(index + delta + enabled.length) % enabled.length]\n setActiveValue(next?.value ?? null)\n }\n\n const openList = (highlight: 'first' | 'last' | 'keep') => {\n if (!interactive) return\n setOpen(true)\n if (highlight !== 'keep') setActiveValue(initialActive(highlight === 'last')?.value ?? null)\n }\n\n /* ─── Events ─── */\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\n const text = event.target.value\n setQuery(text)\n setDirty(true)\n setActiveValue(null)\n if (interactive) setOpen(true)\n }\n\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n onKeyDown?.(event)\n if (event.nativeEvent.isComposing) return\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault()\n if (event.altKey) openList('keep')\n else if (expanded) move(1)\n else openList('first')\n return\n case 'ArrowUp':\n event.preventDefault()\n if (event.altKey) setOpen(false)\n else if (expanded) move(-1)\n else openList('last')\n return\n case 'Home':\n case 'End':\n if (!expanded || enabled.length === 0) return\n event.preventDefault()\n setActiveValue(\n (event.key === 'Home' ? enabled[0] : enabled[enabled.length - 1])?.value ?? null,\n )\n return\n case 'Enter':\n if (expanded && active) {\n event.preventDefault()\n selectOption(active)\n } else if (freeText) {\n event.preventDefault()\n commitText()\n if (!multiple) setOpen(false)\n } else if (expanded) {\n event.preventDefault()\n }\n return\n case 'Escape':\n if (expanded) {\n event.preventDefault()\n setOpen(false)\n } else if (query !== '' && interactive) {\n event.preventDefault()\n setQuery('')\n setDirty(!multiple)\n }\n return\n case 'Tab':\n setOpen(false)\n return\n case 'Backspace':\n if (multiple && query === '' && interactive && values.length > 0) {\n event.preventDefault()\n setValues(values.slice(0, -1))\n }\n return\n }\n }\n\n /** Focus left the whole control: settle the text, close, then tell the consumer. */\n const handleBlur = (event: FocusEvent<HTMLDivElement>) => {\n const next = event.relatedTarget as Node | null\n if (next && boxRef.current?.contains(next)) return\n if (interactive) {\n if (multiple) {\n if (!commitText()) setQuery('')\n } else if (dirty) {\n if (creatable && trimmedQuery !== '') commitText()\n else if (trimmedQuery === '') {\n if (values.length > 0) setValues([])\n setQuery('')\n } else setQuery(selectedLabel)\n }\n setDirty(false)\n }\n setOpen(false)\n setActiveValue(null)\n onBlur?.(event)\n }\n\n // Clicking the box's padding or chevron focuses the input and toggles the list.\n const handleBoxPointerDown = (event: PointerEvent<HTMLDivElement>) => {\n const target = event.target as HTMLElement\n if (target === inputRef.current || target.closest('button, a, input')) return\n event.preventDefault()\n inputRef.current?.focus()\n if (openRef.current) setOpen(false)\n else openList('keep')\n }\n\n const handleInputClick = (event: MouseEvent<HTMLInputElement>) => {\n onClick?.(event)\n if (!openRef.current) openList('keep')\n }\n\n const handleInteractOutside = (event: Event) => {\n const target = event.target as Node | null\n if (target && boxRef.current?.contains(target)) event.preventDefault()\n }\n\n /* ─── Render ─── */\n const listLabelledBy = ariaLabelledBy ?? field.labelId\n const showPlaceholder = !multiple || values.length === 0\n const canClear = clearable && interactive && (values.length > 0 || query !== '')\n\n const renderOption = (option: ComboboxOption) => {\n const selected = isSelected(option.value)\n const disabled = isDisabled(option)\n return (\n // The input owns focus and the keyboard (aria-activedescendant points here), so an\n // option is never focused itself and its click is the pointer path only.\n // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/interactive-supports-focus\n <div\n key={option.value}\n id={optionId(option.value)}\n role=\"option\"\n aria-selected={selected}\n aria-disabled={disabled || undefined}\n className={styles.option}\n data-active={active?.value === option.value || undefined}\n data-selected={selected || undefined}\n data-disabled={disabled || undefined}\n onMouseDown={(event) => {\n event.preventDefault()\n }}\n onPointerMove={() => {\n if (!disabled && activeValue !== option.value) setActiveValue(option.value)\n }}\n onClick={() => {\n selectOption(option)\n }}\n >\n {multiple ? (\n <span className={styles.box} aria-hidden=\"true\">\n {selected ? <CheckIcon /> : null}\n </span>\n ) : null}\n <span className={styles.optionText}>\n <span className={styles.optionLabel}>{option.label}</span>\n {option.description ? (\n <span className={styles.optionDescription}>{option.description}</span>\n ) : null}\n </span>\n {!multiple && selected ? <CheckIcon className={styles.check} /> : null}\n </div>\n )\n }\n\n return (\n <PopoverPrimitive.Root\n open={expanded}\n onOpenChange={(next) => {\n if (!next) setOpen(false)\n }}\n >\n <PortalAnchorContext.Provider value={boxRef}>\n <PopoverPrimitive.Anchor asChild>\n <div\n ref={boxRef}\n className={cx(control.box, styles.root, className)}\n style={style}\n data-size={size}\n data-multiple={multiple || undefined}\n data-state={expanded ? 'open' : 'closed'}\n data-invalid={field.invalid || undefined}\n data-disabled={field.disabled || undefined}\n data-readonly={field.readOnly || undefined}\n onPointerDown={handleBoxPointerDown}\n onBlur={handleBlur}\n >\n <div className={styles.values}>\n {multiple && values.length > 0 ? (\n <TagList className={styles.chips}>\n {values.map((value) => {\n const label = labelOf(value)\n return (\n <Tag\n key={value}\n className={styles.chip}\n onRemove={\n interactive\n ? () => {\n removeValue(value)\n inputRef.current?.focus()\n }\n : undefined\n }\n removeLabel={removeLabel(label)}\n >\n {label}\n </Tag>\n )\n })}\n </TagList>\n ) : null}\n <input\n ref={composedInputRef}\n id={inputId}\n type=\"text\"\n role=\"combobox\"\n className={styles.input}\n value={query}\n placeholder={showPlaceholder ? placeholder : undefined}\n autoComplete=\"off\"\n autoCapitalize=\"off\"\n autoCorrect=\"off\"\n spellCheck={false}\n disabled={field.disabled}\n readOnly={field.readOnly}\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n aria-expanded={expanded}\n aria-controls={listboxId}\n aria-activedescendant={activeId}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-describedby={field.describedBy}\n aria-invalid={field.invalid || undefined}\n aria-required={field.required || undefined}\n aria-busy={field.busy || undefined}\n {...rest}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n onClick={handleInputClick}\n />\n </div>\n <span className={styles.trailing}>\n {loading ? <Spinner size=\"sm\" label={null} className={styles.spinner} /> : null}\n {canClear ? (\n <button\n type=\"button\"\n className={styles.clear}\n aria-label={clearLabel}\n onMouseDown={(event) => {\n event.preventDefault()\n }}\n onClick={clear}\n >\n <CloseIcon />\n </button>\n ) : null}\n <ChevronDownIcon className={styles.chevron} />\n </span>\n {name !== undefined ? (\n multiple ? (\n values.map((value) => (\n <input\n key={value}\n type=\"hidden\"\n name={name}\n value={value}\n form={form}\n disabled={field.disabled || undefined}\n />\n ))\n ) : (\n <input\n type=\"hidden\"\n name={name}\n value={values[0] ?? ''}\n form={form}\n disabled={field.disabled || undefined}\n />\n )\n ) : null}\n <div\n id={statusId}\n role=\"status\"\n aria-live=\"polite\"\n className={messageStyles.visuallyHidden}\n >\n {announcement}\n </div>\n </div>\n </PopoverPrimitive.Anchor>\n <PopoverPrimitive.Portal container={expanded ? themeScopeOf(boxRef.current) : undefined}>\n <ComboboxPopup onInteractOutside={handleInteractOutside}>\n <div\n id={listboxId}\n role=\"listbox\"\n aria-labelledby={listLabelledBy}\n aria-label={listLabelledBy ? undefined : ariaLabel}\n aria-multiselectable={multiple || undefined}\n aria-busy={loading || undefined}\n className={styles.listbox}\n >\n {sections.map((section) =>\n section.label === undefined ? (\n section.options.map(renderOption)\n ) : (\n <div\n key={section.key}\n role=\"group\"\n aria-labelledby={`${inputId}-group-${String(sections.indexOf(section))}`}\n className={styles.group}\n >\n <div\n id={`${inputId}-group-${String(sections.indexOf(section))}`}\n role=\"presentation\"\n className={styles.groupLabel}\n >\n {section.label}\n </div>\n {section.options.map(renderOption)}\n </div>\n ),\n )}\n </div>\n {loading && ordered.length === 0 ? (\n <div className={styles.message}>\n <Spinner size=\"sm\" label={null} />\n <span>{loadingMessage}</span>\n </div>\n ) : null}\n {showEmpty ? <div className={styles.message}>{emptyMessage}</div> : null}\n </ComboboxPopup>\n </PopoverPrimitive.Portal>\n </PortalAnchorContext.Provider>\n </PopoverPrimitive.Root>\n )\n }),\n)\n"],"mappings":"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"}
1
+ {"version":3,"file":"Combobox.js","names":["PopoverPrimitive","styles","control","messageStyles","messages_module_default","control_module_default","Combobox_module_default","buildView","matched","shouldFilter","filterOptions","options","query","sections","byKey","option","key","section","defaultRemoveLabel","label","splitMode","props","base","defaultValue","onValueChange","next","removeLabel","multiple","value","themeScopeOf","scope","node","countMessage","count","ComboboxPopup","forwardRef","theme","usePortalTheme","Popover","Combobox","markFieldAware","mode","inputValueProp","openProp","invalidProp","idProp","disabledProp","requiredProp","readOnlyProp","describedByProp","ariaInvalid","ariaLabel","ariaLabelledBy","rest","field","useResolvedField","autoId","useId","inputId","listboxId","statusId","interactive","inputRef","useRef","boxRef","composedInputRef","useMergedRefs","ref","labelCache","labelOf","useCallback","values","setValues","useControllableState","selectedLabel","setQueryState","defaultInputValue","onInputValueChange","queryRef","setQuery","dirty","setDirty","useState","openState","setOpenState","defaultOpen","onOpenChange","openRef","setOpen","activeValue","setActiveValue","filter","useMemo","indexOf","index","optionId","atMax","maxSelected","isSelected","isDisabled","enabled","ordered","trimmedQuery","freeText","creatable","showEmpty","loading","hasPopupContent","expanded","autoHighlight","activeOption","active","announcement","setAnnouncement","countText","emptyMessage","timer","activeId","selectOption","commitText","folded","foldText","match","removeValue","v","clear","initialActive","fromEnd","move","delta","openList","highlight","handleChange","text","event","handleKeyDown","onKeyDown","handleBlur","onBlur","handleBoxPointerDown","target","handleInputClick","onClick","handleInteractOutside","listLabelledBy","showPlaceholder","canClear","clearable","renderOption","selected","disabled","CheckIcon","PortalAnchorContext","cx","className","size","TagList","Tag","placeholder","Spinner","clearLabel","CloseIcon","ChevronDownIcon","name","loadingMessage"],"sources":["../../../../src/components/inputs/Combobox/Combobox.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type FocusEvent,\n type FocusEventHandler,\n type InputHTMLAttributes,\n type KeyboardEvent,\n type MouseEvent,\n type PointerEvent,\n type ReactNode,\n} from 'react'\nimport { Popover as PopoverPrimitive } from 'radix-ui'\nimport { CheckIcon, ChevronDownIcon, CloseIcon } from '#icons'\nimport { cx } from '#utils/cx'\nimport type { Size } from '#utils/tokens'\nimport { Spinner } from '#components/feedback/Spinner'\nimport { Tag, TagList } from '#components/display/Tag'\nimport { PortalAnchorContext, usePortalTheme } from '#components/overlays/usePortalTheme'\nimport { markFieldAware, useResolvedField } from '#components/inputs/internal/FieldContext'\nimport { filterOptions, foldText } from '#components/inputs/internal/filterOptions'\nimport { useMergedRefs } from '#components/inputs/internal/refs'\nimport control from '#components/inputs/internal/control.module.css'\nimport messageStyles from '#components/inputs/internal/messages.module.css'\nimport { useControllableState } from './useControllableState'\nimport styles from './Combobox.module.css'\n\nexport interface ComboboxOption {\n value: string\n label: string\n /** A second, quieter line under the label. Also searched. */\n description?: string\n /** Extra search terms that aren't shown (\"USA\", \"Holland\"). An exact keyword ranks first. */\n keywords?: readonly string[]\n /** Heading the option is listed under. Groups appear in order of their first option. */\n group?: string\n disabled?: boolean\n}\n\nexport interface ComboboxBase extends Omit<\n InputHTMLAttributes<HTMLInputElement>,\n 'value' | 'defaultValue' | 'onChange' | 'size' | 'type' | 'multiple' | 'onBlur'\n> {\n options: readonly ComboboxOption[]\n /** The text in the box (the query). Controlled. */\n inputValue?: string\n defaultInputValue?: string\n onInputValueChange?: (query: string) => void\n /**\n * `auto` (default) filters and ranks `options` by the query. `none` shows `options` as\n * given — for async search, where the loader has already filtered.\n */\n filter?: 'auto' | 'none'\n /** Options are being fetched: a spinner in the box and `loadingMessage` in an empty list. */\n loading?: boolean\n loadingMessage?: ReactNode\n /** Shown in the list when nothing matches. Default \"No matches\". */\n emptyMessage?: ReactNode\n open?: boolean\n defaultOpen?: boolean\n onOpenChange?: (open: boolean) => void\n /**\n * Free text is allowed: whatever is typed becomes the value when committed (Enter, or\n * leaving the field). A typed label that matches an option picks that option instead.\n */\n creatable?: boolean\n /** Shows a clear button while there's a value. */\n clearable?: boolean\n /** Accessible name of the clear button. Default \"Clear\". */\n clearLabel?: string\n size?: Size\n /** Critical border + `aria-invalid`. Inside a `<Field error>` this is set for you. */\n invalid?: boolean\n /** Fires once focus leaves the whole control (input, chips, clear button, list). */\n onBlur?: FocusEventHandler<HTMLElement>\n}\n\nexport interface ComboboxSingleProps extends ComboboxBase {\n multiple?: false\n value?: string | null\n defaultValue?: string | null\n onValueChange?: (value: string | null) => void\n}\n\nexport interface ComboboxMultipleProps extends ComboboxBase {\n multiple: true\n value?: readonly string[]\n defaultValue?: readonly string[]\n onValueChange?: (value: string[]) => void\n /** Once this many are chosen, the rest of the list is disabled. */\n maxSelected?: number\n /** Accessible name of a chip's remove button. Default `Remove <label>`. */\n removeLabel?: (label: string) => string\n}\n\nexport type ComboboxProps = ComboboxSingleProps | ComboboxMultipleProps\n\n/* ─── Pure helpers ────────────────────────────────────────────────────────── */\n\ninterface Section {\n key: string\n label?: string\n options: ComboboxOption[]\n}\n\n/** Visible options, in groups (ordered by each group's first/best option), and flattened. */\nfunction buildView(options: readonly ComboboxOption[], query: string, shouldFilter: boolean) {\n const matched = shouldFilter ? filterOptions(options, query) : [...options]\n const sections: Section[] = []\n const byKey = new Map<string, Section>()\n for (const option of matched) {\n const key = option.group === undefined ? '' : `g:${option.group}`\n let section = byKey.get(key)\n if (!section) {\n section = { key, label: option.group, options: [] }\n byKey.set(key, section)\n sections.push(section)\n }\n section.options.push(option)\n }\n return { sections, ordered: sections.flatMap((section) => section.options) }\n}\n\ninterface ModeProps {\n multiple: boolean\n value: readonly string[] | undefined\n defaultValue: readonly string[]\n emit: (next: readonly string[]) => void\n maxSelected: number | undefined\n removeLabel: (label: string) => string\n}\n\nconst defaultRemoveLabel = (label: string) => `Remove ${label}`\n\n/** Splits the single/multiple union into one normalised shape (values are always arrays). */\nfunction splitMode(props: ComboboxProps): [ComboboxBase, ModeProps] {\n if (props.multiple === true) {\n const { multiple, value, defaultValue, onValueChange, maxSelected, removeLabel, ...base } =\n props\n return [\n base,\n {\n multiple,\n value,\n defaultValue: defaultValue ?? [],\n emit: (next) => onValueChange?.([...next]),\n maxSelected,\n removeLabel: removeLabel ?? defaultRemoveLabel,\n },\n ]\n }\n const { multiple, value, defaultValue, onValueChange, ...base } = props\n return [\n base,\n {\n multiple: Boolean(multiple),\n value: value === undefined ? undefined : value === null ? [] : [value],\n defaultValue: defaultValue == null ? [] : [defaultValue],\n emit: (next) => onValueChange?.(next[0] ?? null),\n maxSelected: undefined,\n removeLabel: defaultRemoveLabel,\n },\n ]\n}\n\n/** The nearest theme scope below `<html>` — the portal target, so the list opens in that theme. */\nfunction themeScopeOf(node: HTMLElement | null): HTMLElement | undefined {\n const scope = node?.closest<HTMLElement>('[data-theme]')\n return scope && scope !== node?.ownerDocument.documentElement ? scope : undefined\n}\n\nfunction countMessage(count: number): string {\n return `${String(count)} ${count === 1 ? 'option' : 'options'} available`\n}\n\n/* ─── Popup (mounts on open, so it reads the theme at open time) ─────────── */\n\ninterface PopupProps {\n children: ReactNode\n onInteractOutside: (event: Event) => void\n}\n\n// forwardRef: Radix Presence hands the popup a ref (React 18 warns without it).\nconst ComboboxPopup = forwardRef<HTMLDivElement, PopupProps>(function ComboboxPopup(\n { children, onInteractOutside },\n ref,\n) {\n const theme = usePortalTheme()\n return (\n <PopoverPrimitive.Content\n ref={ref}\n className={styles.popup}\n // A wrapper, not a dialog: the listbox inside carries the semantics.\n role={undefined}\n side=\"bottom\"\n align=\"start\"\n sideOffset={6}\n collisionPadding={8}\n // Focus never leaves the input (ARIA combobox): no auto-focus in or back.\n onOpenAutoFocus={(event) => {\n event.preventDefault()\n }}\n onCloseAutoFocus={(event) => {\n event.preventDefault()\n }}\n // The input's own keydown handles Escape (close, then clear).\n onEscapeKeyDown={(event) => {\n event.preventDefault()\n }}\n onInteractOutside={onInteractOutside}\n // Clicks on padding / messages must not take focus from the input.\n onMouseDown={(event) => {\n event.preventDefault()\n }}\n {...theme}\n >\n {children}\n </PopoverPrimitive.Content>\n )\n})\n\n/* ─── Combobox ────────────────────────────────────────────────────────────── */\n\n/**\n * Type to filter and pick from a list. Single or multiple, free text if you allow it, ready for\n * async options.\n *\n * @remarks\n * `Combobox` is an ARIA 1.2 combobox: a text input that filters a listbox as you type. With\n * `multiple`, chosen values become removable chips in the box. With `creatable`, typed text that\n * matches nothing can be added as a value.\n *\n * @privateRemarks\n * Type to filter, pick from a list (ARIA 1.2 combobox with a listbox popup). Single or\n * `multiple` (chosen values become removable chips), `creatable` for free text, and\n * async-ready: pass `filter=\"none\"`, `loading` and the loader's results as `options`.\n * The ref and native input props go to the text input; `className`/`style` go to the box.\n *\n * <Combobox options={projects} placeholder=\"Search projects\" onValueChange={setProject} />\n * <Combobox multiple options={labels} maxSelected={3} />\n */\nexport const Combobox = markFieldAware(\n forwardRef<HTMLInputElement, ComboboxProps>(function Combobox(props, ref) {\n const [base, mode] = splitMode(props)\n const {\n options,\n inputValue: inputValueProp,\n defaultInputValue,\n onInputValueChange,\n filter = 'auto',\n loading = false,\n loadingMessage = 'Loading…',\n emptyMessage = 'No matches',\n open: openProp,\n defaultOpen = false,\n onOpenChange,\n creatable = false,\n clearable = false,\n clearLabel = 'Clear',\n size = 'md',\n invalid: invalidProp,\n id: idProp,\n disabled: disabledProp,\n required: requiredProp,\n readOnly: readOnlyProp,\n name,\n form,\n placeholder,\n className,\n style,\n onKeyDown,\n onBlur,\n onClick,\n 'aria-describedby': describedByProp,\n 'aria-invalid': ariaInvalid,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n ...rest\n } = base\n const { multiple, maxSelected, removeLabel } = mode\n\n const field = useResolvedField({\n id: idProp,\n describedBy: describedByProp,\n invalid: invalidProp,\n ariaInvalid,\n required: requiredProp,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n })\n const autoId = useId()\n const inputId = field.id ?? `${autoId}combobox`\n const listboxId = `${inputId}-listbox`\n const statusId = `${inputId}-status`\n const interactive = !field.disabled && !field.readOnly\n\n const inputRef = useRef<HTMLInputElement>(null)\n const boxRef = useRef<HTMLDivElement>(null)\n const composedInputRef = useMergedRefs(ref, inputRef)\n\n /* Labels of chosen values survive the options changing (async results, creatable). */\n const labelCache = useRef(new Map<string, string>())\n for (const option of options) labelCache.current.set(option.value, option.label)\n const labelOf = useCallback(\n (value: string) =>\n options.find((option) => option.value === value)?.label ??\n labelCache.current.get(value) ??\n value,\n [options],\n )\n\n const [values, setValues] = useControllableState<readonly string[]>(\n mode.value,\n mode.defaultValue,\n mode.emit,\n )\n const selectedLabel = !multiple && values[0] !== undefined ? labelOf(values[0]) : ''\n\n const [query, setQueryState] = useControllableState<string>(\n inputValueProp,\n defaultInputValue ??\n (multiple || mode.defaultValue[0] === undefined ? '' : labelOf(mode.defaultValue[0])),\n onInputValueChange,\n )\n const queryRef = useRef(query)\n queryRef.current = query\n const setQuery = useCallback(\n (next: string) => {\n if (next !== queryRef.current) setQueryState(next)\n },\n [setQueryState],\n )\n /** The user has typed since the last pick (single: the text is a query, not the label). */\n const [dirty, setDirty] = useState(false)\n\n const [openState, setOpenState] = useControllableState<boolean>(\n openProp,\n defaultOpen,\n onOpenChange,\n )\n const openRef = useRef(openState)\n openRef.current = openState\n const setOpen = useCallback(\n (next: boolean) => {\n if (next !== openRef.current) setOpenState(next)\n },\n [setOpenState],\n )\n\n const [activeValue, setActiveValue] = useState<string | null>(null)\n\n // Single: show the chosen option's label whenever the user isn't mid-edit (covers\n // external value changes such as a form reset).\n useEffect(() => {\n if (!multiple && !dirty) setQuery(selectedLabel)\n }, [multiple, dirty, selectedLabel, setQuery])\n\n /* ─── Derived view ─── */\n const shouldFilter = filter === 'auto' && (multiple || dirty)\n const { sections, ordered } = useMemo(\n () => buildView(options, query, shouldFilter),\n [options, query, shouldFilter],\n )\n const indexOf = useMemo(\n () => new Map(options.map((option, index) => [option.value, index])),\n [options],\n )\n const optionId = (value: string) => `${inputId}-option-${String(indexOf.get(value) ?? 0)}`\n\n const atMax = multiple && maxSelected !== undefined && values.length >= maxSelected\n const isSelected = (value: string) => values.includes(value)\n const isDisabled = (option: ComboboxOption) =>\n Boolean(option.disabled) || (atMax && !isSelected(option.value))\n const enabled = ordered.filter((option) => !isDisabled(option))\n\n const trimmedQuery = query.trim()\n const freeText = creatable && trimmedQuery !== '' && (multiple || dirty)\n const showEmpty = !loading && ordered.length === 0 && !freeText\n const hasPopupContent = ordered.length > 0 || loading || showEmpty\n const expanded = openState && interactive && hasPopupContent\n\n // Non-creatable: typing highlights the best match, so Enter picks it. Not while loading:\n // the list still shows the previous query's results, and Enter must not commit one of them.\n const autoHighlight =\n expanded && !loading && !creatable && trimmedQuery !== '' && (multiple || dirty)\n const activeOption =\n enabled.find((option) => option.value === activeValue) ??\n (autoHighlight ? enabled[0] : undefined)\n const active = expanded ? activeOption : undefined\n\n /* ─── Live region: result count, debounced ─── */\n const [announcement, setAnnouncement] = useState('')\n const countText = loading\n ? ''\n : ordered.length === 0\n ? typeof emptyMessage === 'string'\n ? emptyMessage\n : 'No matches'\n : countMessage(ordered.length)\n useEffect(() => {\n if (!expanded || countText === '') {\n if (!expanded) setAnnouncement('')\n return\n }\n const timer = setTimeout(() => {\n setAnnouncement(countText)\n }, 500)\n return () => {\n clearTimeout(timer)\n }\n }, [expanded, countText])\n\n /* Keep the highlighted row in view. */\n const activeId = active ? optionId(active.value) : undefined\n useEffect(() => {\n if (!activeId) return\n const node = inputRef.current?.ownerDocument.getElementById(activeId)\n node?.scrollIntoView({ block: 'nearest' })\n }, [activeId])\n\n /* ─── Actions ─── */\n const selectOption = (option: ComboboxOption) => {\n if (!interactive || isDisabled(option)) return\n labelCache.current.set(option.value, option.label)\n if (multiple) {\n const next = isSelected(option.value)\n ? values.filter((value) => value !== option.value)\n : [...values, option.value]\n setValues(next)\n setQuery('')\n setDirty(false)\n setActiveValue(option.value)\n } else {\n setValues([option.value])\n setQuery(option.label)\n setDirty(false)\n setActiveValue(null)\n setOpen(false)\n }\n }\n\n /** Creatable: turn the typed text into a value. Returns whether anything changed. */\n const commitText = (): boolean => {\n if (!creatable || trimmedQuery === '') return false\n const folded = foldText(trimmedQuery)\n const match = options.find((option) => !option.disabled && foldText(option.label) === folded)\n const value = match?.value ?? trimmedQuery\n const label = match?.label ?? trimmedQuery\n labelCache.current.set(value, label)\n if (multiple) {\n setQuery('')\n setDirty(false)\n if (isSelected(value) || atMax) return false\n setValues([...values, value])\n return true\n }\n setDirty(false)\n setQuery(label)\n if (values[0] === value) return false\n setValues([value])\n return true\n }\n\n const removeValue = (value: string) => {\n if (!interactive) return\n setValues(values.filter((v) => v !== value))\n }\n\n const clear = () => {\n if (!interactive) return\n setValues([])\n setQuery('')\n setDirty(false)\n setActiveValue(null)\n inputRef.current?.focus()\n }\n\n /** First visible selected option, else the first/last enabled one. */\n const initialActive = (fromEnd: boolean) =>\n enabled.find((option) => isSelected(option.value)) ??\n (fromEnd ? enabled[enabled.length - 1] : enabled[0])\n\n const move = (delta: 1 | -1) => {\n if (enabled.length === 0) return\n const index = active ? enabled.indexOf(active) : -1\n const next =\n index === -1\n ? delta === 1\n ? enabled[0]\n : enabled[enabled.length - 1]\n : enabled[(index + delta + enabled.length) % enabled.length]\n setActiveValue(next?.value ?? null)\n }\n\n const openList = (highlight: 'first' | 'last' | 'keep') => {\n if (!interactive) return\n setOpen(true)\n if (highlight !== 'keep') setActiveValue(initialActive(highlight === 'last')?.value ?? null)\n }\n\n /* ─── Events ─── */\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\n const text = event.target.value\n setQuery(text)\n setDirty(true)\n setActiveValue(null)\n if (interactive) setOpen(true)\n }\n\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n onKeyDown?.(event)\n if (event.nativeEvent.isComposing) return\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault()\n if (event.altKey) openList('keep')\n else if (expanded) move(1)\n else openList('first')\n return\n case 'ArrowUp':\n event.preventDefault()\n if (event.altKey) setOpen(false)\n else if (expanded) move(-1)\n else openList('last')\n return\n case 'Home':\n case 'End':\n if (!expanded || enabled.length === 0) return\n event.preventDefault()\n setActiveValue(\n (event.key === 'Home' ? enabled[0] : enabled[enabled.length - 1])?.value ?? null,\n )\n return\n case 'Enter':\n if (expanded && active) {\n event.preventDefault()\n selectOption(active)\n } else if (freeText) {\n event.preventDefault()\n commitText()\n if (!multiple) setOpen(false)\n } else if (expanded) {\n event.preventDefault()\n }\n return\n case 'Escape':\n if (expanded) {\n event.preventDefault()\n setOpen(false)\n } else if (query !== '' && interactive) {\n event.preventDefault()\n setQuery('')\n setDirty(!multiple)\n }\n return\n case 'Tab':\n setOpen(false)\n return\n case 'Backspace':\n if (multiple && query === '' && interactive && values.length > 0) {\n event.preventDefault()\n setValues(values.slice(0, -1))\n }\n return\n }\n }\n\n /** Focus left the whole control: settle the text, close, then tell the consumer. */\n const handleBlur = (event: FocusEvent<HTMLDivElement>) => {\n const next = event.relatedTarget as Node | null\n if (next && boxRef.current?.contains(next)) return\n if (interactive) {\n if (multiple) {\n if (!commitText()) setQuery('')\n } else if (dirty) {\n if (creatable && trimmedQuery !== '') commitText()\n else if (trimmedQuery === '') {\n if (values.length > 0) setValues([])\n setQuery('')\n } else setQuery(selectedLabel)\n }\n setDirty(false)\n }\n setOpen(false)\n setActiveValue(null)\n onBlur?.(event)\n }\n\n // Clicking the box's padding or chevron focuses the input and toggles the list.\n const handleBoxPointerDown = (event: PointerEvent<HTMLDivElement>) => {\n const target = event.target as HTMLElement\n if (target === inputRef.current || target.closest('button, a, input')) return\n event.preventDefault()\n inputRef.current?.focus()\n if (openRef.current) setOpen(false)\n else openList('keep')\n }\n\n const handleInputClick = (event: MouseEvent<HTMLInputElement>) => {\n onClick?.(event)\n if (!openRef.current) openList('keep')\n }\n\n const handleInteractOutside = (event: Event) => {\n const target = event.target as Node | null\n if (target && boxRef.current?.contains(target)) event.preventDefault()\n }\n\n /* ─── Render ─── */\n const listLabelledBy = ariaLabelledBy ?? field.labelId\n const showPlaceholder = !multiple || values.length === 0\n const canClear = clearable && interactive && (values.length > 0 || query !== '')\n\n const renderOption = (option: ComboboxOption) => {\n const selected = isSelected(option.value)\n const disabled = isDisabled(option)\n return (\n // The input owns focus and the keyboard (aria-activedescendant points here), so an\n // option is never focused itself and its click is the pointer path only.\n // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/interactive-supports-focus\n <div\n key={option.value}\n id={optionId(option.value)}\n role=\"option\"\n aria-selected={selected}\n aria-disabled={disabled || undefined}\n className={styles.option}\n data-active={active?.value === option.value || undefined}\n data-selected={selected || undefined}\n data-disabled={disabled || undefined}\n onMouseDown={(event) => {\n event.preventDefault()\n }}\n onPointerMove={() => {\n if (!disabled && activeValue !== option.value) setActiveValue(option.value)\n }}\n onClick={() => {\n selectOption(option)\n }}\n >\n {multiple ? (\n <span className={styles.box} aria-hidden=\"true\">\n {selected ? <CheckIcon /> : null}\n </span>\n ) : null}\n <span className={styles.optionText}>\n <span className={styles.optionLabel}>{option.label}</span>\n {option.description ? (\n <span className={styles.optionDescription}>{option.description}</span>\n ) : null}\n </span>\n {!multiple && selected ? <CheckIcon className={styles.check} /> : null}\n </div>\n )\n }\n\n return (\n <PopoverPrimitive.Root\n open={expanded}\n onOpenChange={(next) => {\n if (!next) setOpen(false)\n }}\n >\n <PortalAnchorContext.Provider value={boxRef}>\n <PopoverPrimitive.Anchor asChild>\n <div\n ref={boxRef}\n className={cx(control.box, styles.root, className)}\n style={style}\n data-size={size}\n data-multiple={multiple || undefined}\n data-state={expanded ? 'open' : 'closed'}\n data-invalid={field.invalid || undefined}\n data-disabled={field.disabled || undefined}\n data-readonly={field.readOnly || undefined}\n onPointerDown={handleBoxPointerDown}\n onBlur={handleBlur}\n >\n <div className={styles.values}>\n {multiple && values.length > 0 ? (\n <TagList className={styles.chips}>\n {values.map((value) => {\n const label = labelOf(value)\n return (\n <Tag\n key={value}\n className={styles.chip}\n onRemove={\n interactive\n ? () => {\n removeValue(value)\n inputRef.current?.focus()\n }\n : undefined\n }\n removeLabel={removeLabel(label)}\n >\n {label}\n </Tag>\n )\n })}\n </TagList>\n ) : null}\n <input\n ref={composedInputRef}\n id={inputId}\n type=\"text\"\n role=\"combobox\"\n className={styles.input}\n value={query}\n placeholder={showPlaceholder ? placeholder : undefined}\n autoComplete=\"off\"\n autoCapitalize=\"off\"\n autoCorrect=\"off\"\n spellCheck={false}\n disabled={field.disabled}\n readOnly={field.readOnly}\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n aria-expanded={expanded}\n aria-controls={listboxId}\n aria-activedescendant={activeId}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-describedby={field.describedBy}\n aria-invalid={field.invalid || undefined}\n aria-required={field.required || undefined}\n aria-busy={field.busy || undefined}\n {...rest}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n onClick={handleInputClick}\n />\n </div>\n <span className={styles.trailing}>\n {loading ? <Spinner size=\"sm\" label={null} className={styles.spinner} /> : null}\n {canClear ? (\n <button\n type=\"button\"\n className={styles.clear}\n aria-label={clearLabel}\n onMouseDown={(event) => {\n event.preventDefault()\n }}\n onClick={clear}\n >\n <CloseIcon />\n </button>\n ) : null}\n <ChevronDownIcon className={styles.chevron} />\n </span>\n {name !== undefined ? (\n multiple ? (\n values.map((value) => (\n <input\n key={value}\n type=\"hidden\"\n name={name}\n value={value}\n form={form}\n disabled={field.disabled || undefined}\n />\n ))\n ) : (\n <input\n type=\"hidden\"\n name={name}\n value={values[0] ?? ''}\n form={form}\n disabled={field.disabled || undefined}\n />\n )\n ) : null}\n <div\n id={statusId}\n role=\"status\"\n aria-live=\"polite\"\n className={messageStyles.visuallyHidden}\n >\n {announcement}\n </div>\n </div>\n </PopoverPrimitive.Anchor>\n <PopoverPrimitive.Portal container={expanded ? themeScopeOf(boxRef.current) : undefined}>\n <ComboboxPopup onInteractOutside={handleInteractOutside}>\n <div\n id={listboxId}\n role=\"listbox\"\n aria-labelledby={listLabelledBy}\n aria-label={listLabelledBy ? undefined : ariaLabel}\n aria-multiselectable={multiple || undefined}\n aria-busy={loading || undefined}\n className={styles.listbox}\n >\n {sections.map((section) =>\n section.label === undefined ? (\n section.options.map(renderOption)\n ) : (\n <div\n key={section.key}\n role=\"group\"\n aria-labelledby={`${inputId}-group-${String(sections.indexOf(section))}`}\n className={styles.group}\n >\n <div\n id={`${inputId}-group-${String(sections.indexOf(section))}`}\n role=\"presentation\"\n className={styles.groupLabel}\n >\n {section.label}\n </div>\n {section.options.map(renderOption)}\n </div>\n ),\n )}\n </div>\n {loading && ordered.length === 0 ? (\n <div className={styles.message}>\n <Spinner size=\"sm\" label={null} />\n <span>{loadingMessage}</span>\n </div>\n ) : null}\n {showEmpty ? <div className={styles.message}>{emptyMessage}</div> : null}\n </ComboboxPopup>\n </PopoverPrimitive.Portal>\n </PortalAnchorContext.Provider>\n </PopoverPrimitive.Root>\n )\n }),\n)\n"],"mappings":"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"}
@@ -6,6 +6,13 @@ export type ComboboxFieldMultipleProps = FieldLabelProps & OwnProps<ComboboxMult
6
6
  /** Single (`value: string | null`) or `multiple` (`value: readonly string[]`). */
7
7
  export type ComboboxFieldProps = ComboboxFieldSingleProps | ComboboxFieldMultipleProps;
8
8
  /**
9
+ * A labelled combobox with description, warning and error.
10
+ *
11
+ * @remarks
12
+ * `ComboboxField` is a {@link Field | Field} around a {@link Combobox | Combobox}. Combobox props
13
+ * (`options`, `multiple`, `creatable`, `loading`) go to the combobox.
14
+ *
15
+ * @privateRemarks
9
16
  * Label + Combobox + description + warning + error. Combobox props (`options`, `value`,
10
17
  * `multiple`, `creatable`…) and the ref go to the text input; `className`/`style` go to
11
18
  * the field wrapper. `onBlur` fires once focus leaves the whole control.
@@ -1 +1 @@
1
- {"version":3,"file":"ComboboxField.js","names":["ComboboxField","forwardRef","fieldProps","rest","splitFieldLabelProps","props","comboboxProps","Field","id","Combobox"],"sources":["../../../../src/components/inputs/ComboboxField/ComboboxField.tsx"],"sourcesContent":["import { forwardRef } from 'react'\nimport { Field, type FieldLabelProps } from '#components/inputs/Field'\nimport {\n Combobox,\n type ComboboxMultipleProps,\n type ComboboxProps,\n type ComboboxSingleProps,\n} from '#components/inputs/Combobox'\nimport { splitFieldLabelProps } from '#components/inputs/internal/fieldProps'\n\ntype OwnProps<P> = Omit<P, 'invalid' | keyof FieldLabelProps>\n\nexport type ComboboxFieldSingleProps = FieldLabelProps & OwnProps<ComboboxSingleProps>\nexport type ComboboxFieldMultipleProps = FieldLabelProps & OwnProps<ComboboxMultipleProps>\n\n/** Single (`value: string | null`) or `multiple` (`value: readonly string[]`). */\nexport type ComboboxFieldProps = ComboboxFieldSingleProps | ComboboxFieldMultipleProps\n\n/**\n * Label + Combobox + description + warning + error. Combobox props (`options`, `value`,\n * `multiple`, `creatable`…) and the ref go to the text input; `className`/`style` go to\n * the field wrapper. `onBlur` fires once focus leaves the whole control.\n *\n * <ComboboxField label=\"Country\" options={countries} placeholder=\"Search countries\" />\n * <ComboboxField label=\"Labels\" multiple creatable options={labels} maxSelected={5} />\n */\nexport const ComboboxField = forwardRef<HTMLInputElement, ComboboxFieldProps>(\n function ComboboxField(props, ref) {\n const [fieldProps, rest] = splitFieldLabelProps(props)\n const { id, disabled, className, style, ...comboboxProps } = rest\n return (\n <Field {...fieldProps} htmlFor={id} disabled={disabled} className={className} style={style}>\n <Combobox ref={ref} id={id} disabled={disabled} {...(comboboxProps as ComboboxProps)} />\n </Field>\n )\n },\n)\n"],"mappings":";;;;;;AA0BA,IAAaA,IAAgBC,EAC3B,SAAuB,GAAO,GAAK;CACjC,IAAM,CAACC,GAAYC,KAAQC,EAAqBC,CAAK,GAC/C,EAAE,OAAI,aAAU,cAAW,UAAO,GAAGC,MAAkBH;CAC7D,OACE,kBAACI,GAAD;EAAO,GAAIL;EAAY,SAASM;EAAc;EAAqB;EAAkB;EACnF,UAAA,kBAACC,GAAD;GAAe;GAAS;GAAc;GAAU,GAAKH;EAAkC,CAAA;CAClF,CAAA;AAEX,CACF"}
1
+ {"version":3,"file":"ComboboxField.js","names":["ComboboxField","forwardRef","fieldProps","rest","splitFieldLabelProps","props","comboboxProps","Field","id","Combobox"],"sources":["../../../../src/components/inputs/ComboboxField/ComboboxField.tsx"],"sourcesContent":["import { forwardRef } from 'react'\nimport { Field, type FieldLabelProps } from '#components/inputs/Field'\nimport {\n Combobox,\n type ComboboxMultipleProps,\n type ComboboxProps,\n type ComboboxSingleProps,\n} from '#components/inputs/Combobox'\nimport { splitFieldLabelProps } from '#components/inputs/internal/fieldProps'\n\ntype OwnProps<P> = Omit<P, 'invalid' | keyof FieldLabelProps>\n\nexport type ComboboxFieldSingleProps = FieldLabelProps & OwnProps<ComboboxSingleProps>\nexport type ComboboxFieldMultipleProps = FieldLabelProps & OwnProps<ComboboxMultipleProps>\n\n/** Single (`value: string | null`) or `multiple` (`value: readonly string[]`). */\nexport type ComboboxFieldProps = ComboboxFieldSingleProps | ComboboxFieldMultipleProps\n\n/**\n * A labelled combobox with description, warning and error.\n *\n * @remarks\n * `ComboboxField` is a {@link Field | Field} around a {@link Combobox | Combobox}. Combobox props\n * (`options`, `multiple`, `creatable`, `loading`) go to the combobox.\n *\n * @privateRemarks\n * Label + Combobox + description + warning + error. Combobox props (`options`, `value`,\n * `multiple`, `creatable`…) and the ref go to the text input; `className`/`style` go to\n * the field wrapper. `onBlur` fires once focus leaves the whole control.\n *\n * <ComboboxField label=\"Country\" options={countries} placeholder=\"Search countries\" />\n * <ComboboxField label=\"Labels\" multiple creatable options={labels} maxSelected={5} />\n */\nexport const ComboboxField = forwardRef<HTMLInputElement, ComboboxFieldProps>(\n function ComboboxField(props, ref) {\n const [fieldProps, rest] = splitFieldLabelProps(props)\n const { id, disabled, className, style, ...comboboxProps } = rest\n return (\n <Field {...fieldProps} htmlFor={id} disabled={disabled} className={className} style={style}>\n <Combobox ref={ref} id={id} disabled={disabled} {...(comboboxProps as ComboboxProps)} />\n </Field>\n )\n },\n)\n"],"mappings":";;;;;;AAiCA,IAAaA,IAAgBC,EAC3B,SAAuB,GAAO,GAAK;CACjC,IAAM,CAACC,GAAYC,KAAQC,EAAqBC,CAAK,GAC/C,EAAE,OAAI,aAAU,cAAW,UAAO,GAAGC,MAAkBH;CAC7D,OACE,kBAACI,GAAD;EAAO,GAAIL;EAAY,SAASM;EAAc;EAAqB;EAAkB;EACnF,UAAA,kBAACC,GAAD;GAAe;GAAS;GAAc;GAAU,GAAKH;EAAkC,CAAA;CAClF,CAAA;AAEX,CACF"}
@@ -27,6 +27,13 @@ export interface DateRangeFieldProps extends FieldLabelProps, Omit<HTMLAttribute
27
27
  size?: Size;
28
28
  }
29
29
  /**
30
+ * A start and end date as two native date inputs under one legend.
31
+ *
32
+ * @remarks
33
+ * `DateRangeField` is two native date inputs, side by side and wrapping on a phone, under one
34
+ * legend. Native inputs mean the platform's own date picker and its accessibility.
35
+ *
36
+ * @privateRemarks
30
37
  * A date range as two native date inputs under one legend, side by side and wrapping
31
38
  * when narrow. The start can't pass the end and the end can't come before the start
32
39
  * (each input's `min`/`max` follows the other). `id` goes to the start input; the ref to
@@ -1 +1 @@
1
- {"version":3,"file":"DateRangeField.js","names":["styles","DateRangeField_module_default","EMPTY","DateRangeField","forwardRef","fieldProps","rest","splitFieldLabelProps","props","fieldsetProps","valueProp","restProps","internal","setInternal","useState","defaultValue","value","update","readOnly","nextValue","part","next","onValueChange","handleBlur","event","onBlur","invalid","hasError","required","busy","Fieldset","label","labelHidden","description","hint","cx","className","Field","startLabel","id","Input","name","max","endLabel","min"],"sources":["../../../../src/components/inputs/DateRangeField/DateRangeField.tsx"],"sourcesContent":["import {\n forwardRef,\n useState,\n type FocusEvent,\n type FocusEventHandler,\n type HTMLAttributes,\n} from 'react'\nimport { cx } from '#utils/cx'\nimport type { Size } from '#utils/tokens'\nimport { Field, type FieldLabelProps } from '#components/inputs/Field'\nimport { Fieldset } from '#components/inputs/Fieldset'\nimport { Input } from '#components/inputs/Input'\nimport { splitFieldLabelProps } from '#components/inputs/internal/fieldProps'\nimport { hasError } from '#components/inputs/internal/errors'\nimport styles from './DateRangeField.module.css'\n\n/** Two ISO dates (`YYYY-MM-DD`); `''` for an unset end. */\nexport interface DateRangeValue {\n start: string\n end: string\n}\n\nexport interface DateRangeFieldProps\n extends\n FieldLabelProps,\n Omit<\n HTMLAttributes<HTMLFieldSetElement>,\n 'onChange' | 'defaultValue' | 'onBlur' | keyof FieldLabelProps\n > {\n value?: DateRangeValue\n defaultValue?: DateRangeValue\n onValueChange?: (value: DateRangeValue) => void\n /** Earliest date either end may take (`YYYY-MM-DD`). */\n min?: string\n /** Latest date either end may take (`YYYY-MM-DD`). */\n max?: string\n /** Label of the first input. Default `'Start date'`. */\n startLabel?: string\n /** Label of the second input. Default `'End date'`. */\n endLabel?: string\n /** Submits `${name}.start` and `${name}.end`. */\n name?: string\n disabled?: boolean\n readOnly?: boolean\n /** Fires when focus leaves both inputs (not when it moves from start to end). */\n onBlur?: FocusEventHandler\n size?: Size\n}\n\nconst EMPTY: DateRangeValue = { start: '', end: '' }\n\n/**\n * A date range as two native date inputs under one legend, side by side and wrapping\n * when narrow. The start can't pass the end and the end can't come before the start\n * (each input's `min`/`max` follows the other). `id` goes to the start input; the ref to\n * the fieldset.\n *\n * <DateRangeField label=\"Trip dates\" value={dates} onValueChange={setDates} />\n */\nexport const DateRangeField = forwardRef<HTMLFieldSetElement, DateRangeFieldProps>(\n function DateRangeField(props, ref) {\n const [fieldProps, rest] = splitFieldLabelProps(props)\n // `layout` goes to the Fieldset (legend column for `horizontal`); the two inputs always\n // sit side by side.\n const { label, labelHidden, hint, description, readOnly = false, ...fieldsetProps } = fieldProps\n const {\n value: valueProp,\n defaultValue,\n onValueChange,\n min,\n max,\n startLabel = 'Start date',\n endLabel = 'End date',\n name,\n disabled = false,\n onBlur,\n size,\n id,\n className,\n ...restProps\n } = rest\n\n const [internal, setInternal] = useState<DateRangeValue>(defaultValue ?? EMPTY)\n const value = valueProp ?? internal\n\n const update = (part: keyof DateRangeValue, next: string) => {\n if (readOnly) return\n const nextValue = { ...value, [part]: next }\n if (valueProp === undefined) setInternal(nextValue)\n onValueChange?.(nextValue)\n }\n\n const handleBlur = (event: FocusEvent<HTMLFieldSetElement>) => {\n if (event.relatedTarget instanceof Node && event.currentTarget.contains(event.relatedTarget))\n return\n onBlur?.(event)\n }\n\n const invalid = hasError(fieldsetProps.error) || undefined\n const required = fieldsetProps.required\n const busy = fieldsetProps.validating ? true : undefined\n\n return (\n <Fieldset\n ref={ref}\n {...restProps}\n {...fieldsetProps}\n legend={label}\n legendHidden={labelHidden}\n description={description ?? hint}\n disabled={disabled}\n readOnly={readOnly}\n className={cx(styles.root, className)}\n onBlur={handleBlur}\n >\n <div className={styles.parts}>\n <Field\n label={startLabel}\n htmlFor={id}\n className={styles.part}\n error={invalid}\n errorHidden\n disabled={disabled}\n readOnly={readOnly}\n >\n <Input\n id={id}\n type=\"date\"\n size={size}\n name={name != null ? `${name}.start` : undefined}\n value={value.start}\n min={min}\n max={value.end || max}\n required={required}\n aria-busy={busy}\n onChange={(event) => {\n update('start', event.target.value)\n }}\n />\n </Field>\n <Field\n label={endLabel}\n className={styles.part}\n error={invalid}\n errorHidden\n disabled={disabled}\n readOnly={readOnly}\n >\n <Input\n type=\"date\"\n size={size}\n name={name != null ? `${name}.end` : undefined}\n value={value.end}\n min={value.start || min}\n max={max}\n required={required}\n aria-busy={busy}\n onChange={(event) => {\n update('end', event.target.value)\n }}\n />\n </Field>\n </div>\n </Fieldset>\n )\n },\n)\n"],"mappings":";;;;;;;;;;AAiDA,IAAME,IAAwB;CAAE,OAAO;CAAI,KAAK;AAAG,GAUtCC,IAAiBC,EAC5B,SAAwB,GAAO,GAAK;CAClC,IAAM,CAACC,GAAYC,KAAQC,EAAqBC,CAAK,GAG/C,EAAE,UAAO,gBAAa,SAAM,gBAAa,cAAW,IAAO,GAAGC,MAAkBJ,GAChF,EACJ,OAAOK,GACP,iBACA,kBACA,QACA,QACA,gBAAa,cACb,cAAW,YACX,SACA,cAAW,IACX,WACA,SACA,OACA,cACA,GAAGC,MACDL,GAEE,CAACM,GAAUC,KAAeC,EAAyBC,KAAgBb,CAAK,GACxEc,IAAQN,KAAaE,GAErBK,KAAU,GAA4B,MAAiB;EAC3D,IAAIC,GAAU;EACd,IAAMC,IAAY;GAAE,GAAGH;IAAQI,IAAOC;EAAK;EAE3C,AADIX,MAAc,KAAA,KAAWG,EAAYM,CAAS,GAClDG,IAAgBH,CAAS;CAC3B,GAEMI,KAAc,MAA2C;EAC7D,AAAIC,EAAM,yBAAyB,QAAQA,EAAM,cAAc,SAASA,EAAM,aAAa,KAE3FC,IAASD,CAAK;CAChB,GAEME,IAAUC,EAASlB,EAAc,KAAK,KAAK,KAAA,GAC3CmB,IAAWnB,EAAc,UACzBoB,IAAOpB,EAAc,aAAa,KAAO,KAAA;CAE/C,OACE,kBAACqB,GAAD;EACO;EACL,GAAInB;EACJ,GAAIF;EACJ,QAAQsB;EACR,cAAcC;EACd,aAAaC,KAAeC;EAClB;EACA;EACV,WAAWC,EAAGnC,EAAO,MAAMoC,CAAS;EACpC,QAAQb;EAER,UAAA,kBAAC,OAAD;GAAK,WAAWvB,EAAO;GAAvB,UAAA,CACE,kBAACqC,GAAD;IACE,OAAOC;IACP,SAASC;IACT,WAAWvC,EAAO;IAClB,OAAO0B;IACP,aAAA;IACU;IACA;IAEV,UAAA,kBAACc,GAAD;KACM;KACJ,MAAK;KACC;KACN,MAAMC,KAAQ,OAAyB,KAAA,IAAlB,GAAGA,EAAK;KAC7B,OAAOzB,EAAM;KACR;KACL,KAAKA,EAAM,OAAO0B;KACR;KACV,aAAWb;KACX,WAAW,MAAU;MACnB,EAAO,SAASL,EAAM,OAAO,KAAK;KACpC;IACD,CAAA;GACI,CAAA,GACP,kBAACa,GAAD;IACE,OAAOM;IACP,WAAW3C,EAAO;IAClB,OAAO0B;IACP,aAAA;IACU;IACA;IAEV,UAAA,kBAACc,GAAD;KACE,MAAK;KACC;KACN,MAAMC,KAAQ,OAAuB,KAAA,IAAhB,GAAGA,EAAK;KAC7B,OAAOzB,EAAM;KACb,KAAKA,EAAM,SAAS4B;KACf;KACK;KACV,aAAWf;KACX,WAAW,MAAU;MACnB,EAAO,OAAOL,EAAM,OAAO,KAAK;KAClC;IACD,CAAA;GACI,CAAA,CACJ;;CACG,CAAA;AAEd,CACF"}
1
+ {"version":3,"file":"DateRangeField.js","names":["styles","DateRangeField_module_default","EMPTY","DateRangeField","forwardRef","fieldProps","rest","splitFieldLabelProps","props","fieldsetProps","valueProp","restProps","internal","setInternal","useState","defaultValue","value","update","readOnly","nextValue","part","next","onValueChange","handleBlur","event","onBlur","invalid","hasError","required","busy","Fieldset","label","labelHidden","description","hint","cx","className","Field","startLabel","id","Input","name","max","endLabel","min"],"sources":["../../../../src/components/inputs/DateRangeField/DateRangeField.tsx"],"sourcesContent":["import {\n forwardRef,\n useState,\n type FocusEvent,\n type FocusEventHandler,\n type HTMLAttributes,\n} from 'react'\nimport { cx } from '#utils/cx'\nimport type { Size } from '#utils/tokens'\nimport { Field, type FieldLabelProps } from '#components/inputs/Field'\nimport { Fieldset } from '#components/inputs/Fieldset'\nimport { Input } from '#components/inputs/Input'\nimport { splitFieldLabelProps } from '#components/inputs/internal/fieldProps'\nimport { hasError } from '#components/inputs/internal/errors'\nimport styles from './DateRangeField.module.css'\n\n/** Two ISO dates (`YYYY-MM-DD`); `''` for an unset end. */\nexport interface DateRangeValue {\n start: string\n end: string\n}\n\nexport interface DateRangeFieldProps\n extends\n FieldLabelProps,\n Omit<\n HTMLAttributes<HTMLFieldSetElement>,\n 'onChange' | 'defaultValue' | 'onBlur' | keyof FieldLabelProps\n > {\n value?: DateRangeValue\n defaultValue?: DateRangeValue\n onValueChange?: (value: DateRangeValue) => void\n /** Earliest date either end may take (`YYYY-MM-DD`). */\n min?: string\n /** Latest date either end may take (`YYYY-MM-DD`). */\n max?: string\n /** Label of the first input. Default `'Start date'`. */\n startLabel?: string\n /** Label of the second input. Default `'End date'`. */\n endLabel?: string\n /** Submits `${name}.start` and `${name}.end`. */\n name?: string\n disabled?: boolean\n readOnly?: boolean\n /** Fires when focus leaves both inputs (not when it moves from start to end). */\n onBlur?: FocusEventHandler\n size?: Size\n}\n\nconst EMPTY: DateRangeValue = { start: '', end: '' }\n\n/**\n * A start and end date as two native date inputs under one legend.\n *\n * @remarks\n * `DateRangeField` is two native date inputs, side by side and wrapping on a phone, under one\n * legend. Native inputs mean the platform's own date picker and its accessibility.\n *\n * @privateRemarks\n * A date range as two native date inputs under one legend, side by side and wrapping\n * when narrow. The start can't pass the end and the end can't come before the start\n * (each input's `min`/`max` follows the other). `id` goes to the start input; the ref to\n * the fieldset.\n *\n * <DateRangeField label=\"Trip dates\" value={dates} onValueChange={setDates} />\n */\nexport const DateRangeField = forwardRef<HTMLFieldSetElement, DateRangeFieldProps>(\n function DateRangeField(props, ref) {\n const [fieldProps, rest] = splitFieldLabelProps(props)\n // `layout` goes to the Fieldset (legend column for `horizontal`); the two inputs always\n // sit side by side.\n const { label, labelHidden, hint, description, readOnly = false, ...fieldsetProps } = fieldProps\n const {\n value: valueProp,\n defaultValue,\n onValueChange,\n min,\n max,\n startLabel = 'Start date',\n endLabel = 'End date',\n name,\n disabled = false,\n onBlur,\n size,\n id,\n className,\n ...restProps\n } = rest\n\n const [internal, setInternal] = useState<DateRangeValue>(defaultValue ?? EMPTY)\n const value = valueProp ?? internal\n\n const update = (part: keyof DateRangeValue, next: string) => {\n if (readOnly) return\n const nextValue = { ...value, [part]: next }\n if (valueProp === undefined) setInternal(nextValue)\n onValueChange?.(nextValue)\n }\n\n const handleBlur = (event: FocusEvent<HTMLFieldSetElement>) => {\n if (event.relatedTarget instanceof Node && event.currentTarget.contains(event.relatedTarget))\n return\n onBlur?.(event)\n }\n\n const invalid = hasError(fieldsetProps.error) || undefined\n const required = fieldsetProps.required\n const busy = fieldsetProps.validating ? true : undefined\n\n return (\n <Fieldset\n ref={ref}\n {...restProps}\n {...fieldsetProps}\n legend={label}\n legendHidden={labelHidden}\n description={description ?? hint}\n disabled={disabled}\n readOnly={readOnly}\n className={cx(styles.root, className)}\n onBlur={handleBlur}\n >\n <div className={styles.parts}>\n <Field\n label={startLabel}\n htmlFor={id}\n className={styles.part}\n error={invalid}\n errorHidden\n disabled={disabled}\n readOnly={readOnly}\n >\n <Input\n id={id}\n type=\"date\"\n size={size}\n name={name != null ? `${name}.start` : undefined}\n value={value.start}\n min={min}\n max={value.end || max}\n required={required}\n aria-busy={busy}\n onChange={(event) => {\n update('start', event.target.value)\n }}\n />\n </Field>\n <Field\n label={endLabel}\n className={styles.part}\n error={invalid}\n errorHidden\n disabled={disabled}\n readOnly={readOnly}\n >\n <Input\n type=\"date\"\n size={size}\n name={name != null ? `${name}.end` : undefined}\n value={value.end}\n min={value.start || min}\n max={max}\n required={required}\n aria-busy={busy}\n onChange={(event) => {\n update('end', event.target.value)\n }}\n />\n </Field>\n </div>\n </Fieldset>\n )\n },\n)\n"],"mappings":";;;;;;;;;;AAiDA,IAAME,IAAwB;CAAE,OAAO;CAAI,KAAK;AAAG,GAiBtCC,IAAiBC,EAC5B,SAAwB,GAAO,GAAK;CAClC,IAAM,CAACC,GAAYC,KAAQC,EAAqBC,CAAK,GAG/C,EAAE,UAAO,gBAAa,SAAM,gBAAa,cAAW,IAAO,GAAGC,MAAkBJ,GAChF,EACJ,OAAOK,GACP,iBACA,kBACA,QACA,QACA,gBAAa,cACb,cAAW,YACX,SACA,cAAW,IACX,WACA,SACA,OACA,cACA,GAAGC,MACDL,GAEE,CAACM,GAAUC,KAAeC,EAAyBC,KAAgBb,CAAK,GACxEc,IAAQN,KAAaE,GAErBK,KAAU,GAA4B,MAAiB;EAC3D,IAAIC,GAAU;EACd,IAAMC,IAAY;GAAE,GAAGH;IAAQI,IAAOC;EAAK;EAE3C,AADIX,MAAc,KAAA,KAAWG,EAAYM,CAAS,GAClDG,IAAgBH,CAAS;CAC3B,GAEMI,KAAc,MAA2C;EAC7D,AAAIC,EAAM,yBAAyB,QAAQA,EAAM,cAAc,SAASA,EAAM,aAAa,KAE3FC,IAASD,CAAK;CAChB,GAEME,IAAUC,EAASlB,EAAc,KAAK,KAAK,KAAA,GAC3CmB,IAAWnB,EAAc,UACzBoB,IAAOpB,EAAc,aAAa,KAAO,KAAA;CAE/C,OACE,kBAACqB,GAAD;EACO;EACL,GAAInB;EACJ,GAAIF;EACJ,QAAQsB;EACR,cAAcC;EACd,aAAaC,KAAeC;EAClB;EACA;EACV,WAAWC,EAAGnC,EAAO,MAAMoC,CAAS;EACpC,QAAQb;EAER,UAAA,kBAAC,OAAD;GAAK,WAAWvB,EAAO;GAAvB,UAAA,CACE,kBAACqC,GAAD;IACE,OAAOC;IACP,SAASC;IACT,WAAWvC,EAAO;IAClB,OAAO0B;IACP,aAAA;IACU;IACA;IAEV,UAAA,kBAACc,GAAD;KACM;KACJ,MAAK;KACC;KACN,MAAMC,KAAQ,OAAyB,KAAA,IAAlB,GAAGA,EAAK;KAC7B,OAAOzB,EAAM;KACR;KACL,KAAKA,EAAM,OAAO0B;KACR;KACV,aAAWb;KACX,WAAW,MAAU;MACnB,EAAO,SAASL,EAAM,OAAO,KAAK;KACpC;IACD,CAAA;GACI,CAAA,GACP,kBAACa,GAAD;IACE,OAAOM;IACP,WAAW3C,EAAO;IAClB,OAAO0B;IACP,aAAA;IACU;IACA;IAEV,UAAA,kBAACc,GAAD;KACE,MAAK;KACC;KACN,MAAMC,KAAQ,OAAuB,KAAA,IAAhB,GAAGA,EAAK;KAC7B,OAAOzB,EAAM;KACb,KAAKA,EAAM,SAAS4B;KACf;KACK;KACV,aAAWf;KACX,WAAW,MAAU;MACnB,EAAO,OAAOL,EAAM,OAAO,KAAK;KAClC;IACD,CAAA;GACI,CAAA,CACJ;;CACG,CAAA;AAEd,CACF"}
@@ -70,6 +70,32 @@ export interface FieldProps extends FieldLabelProps, Omit<HTMLAttributes<HTMLDiv
70
70
  children: ReactNode | ((props: FieldRenderProps) => ReactNode);
71
71
  }
72
72
  /**
73
+ * Wires a label, a description, an error and a warning to one control. Every Kiln input works
74
+ * inside it.
75
+ *
76
+ * @remarks
77
+ * Every input in Kiln exists twice. The bare control (`Input`, `NumberInput`, `Combobox`) works
78
+ * anywhere, and the `*Field` version (`TextField`, `NumberField`, `ComboboxField`) adds the label,
79
+ * description, error and warning. `Field` is what the `*Field`s are made of, and what you use to
80
+ * give any other control the same treatment.
81
+ *
82
+ * ## Errors and warnings are two channels
83
+ *
84
+ * - **`error`** blocks submission. It sets `aria-invalid`, renders in the critical tone, and is
85
+ * announced as it appears.
86
+ * - **`warning`** is advice ("Usernames are case-sensitive") in the caution tone. It never blocks
87
+ * and is never announced as an alert.
88
+ *
89
+ * An error replaces the warning while it shows. Plain fields show whatever `error` you pass;
90
+ * [kiln-forms](/docs/forms) decides _when_ to show one (after the field is blurred or after a
91
+ * submit attempt). Pass `errorLive={false}` when an error summary owns the announcement, and
92
+ * `errorHidden` when the layout shows the message somewhere else.
93
+ *
94
+ * `required` marks the field for assistive technology; `optional` adds a visible "Optional" (or
95
+ * your own text) instead, for forms where most fields are required. `validating` shows that an
96
+ * async check is running.
97
+ *
98
+ * @privateRemarks
73
99
  * Wires a label, description and error to one control.
74
100
  *
75
101
  * <Field label="Amount" description="Include GST" error={errors.amount}>
@@ -1 +1 @@
1
- {"version":3,"file":"Field.js","names":["styles","messageStyles","messages_module_default","Field_module_default","Field","forwardRef","rest","autoId","useId","childProps","isValidElement","children","id","htmlFor","labelId","descriptionId","warningId","errorId","help","description","hint","invalid","hasError","error","showErrorMessage","hasErrorMessage","errorHidden","showWarning","warning","effectiveLabelHidden","labelHidden","layout","describedBy","joinIds","context","useMemo","validating","required","disabled","readOnly","control","isFieldAware","cloneElement","cx","className","LabelContent","label","FieldDescription","FieldContext","FieldWarning","FieldError","errorLive"],"sources":["../../../../src/components/inputs/Field/Field.tsx"],"sourcesContent":["import {\n cloneElement,\n forwardRef,\n isValidElement,\n useId,\n useMemo,\n type HTMLAttributes,\n type ReactElement,\n type ReactNode,\n} from 'react'\nimport { cx } from '#utils/cx'\nimport {\n FieldContext,\n isFieldAware,\n type FieldControlContext,\n} from '#components/inputs/internal/FieldContext'\nimport {\n FieldDescription,\n FieldError,\n FieldWarning,\n LabelContent,\n} from '#components/inputs/internal/messages'\nimport { hasError, hasErrorMessage } from '#components/inputs/internal/errors'\nimport messageStyles from '#components/inputs/internal/messages.module.css'\nimport { joinIds } from '#components/inputs/internal/refs'\nimport styles from './Field.module.css'\n\n/** Props handed to a render-function child — spread them onto your control. */\nexport interface FieldRenderProps {\n id: string\n 'aria-describedby'?: string\n 'aria-invalid'?: true\n 'aria-required'?: true\n /** The Field's `required`. Spreading it onto a native input also turns on browser validation. */\n required: boolean\n disabled?: boolean\n}\n\n/** `Field`'s (and `Fieldset`'s) `layout` values. */\nexport type FieldLayout = 'stack' | 'horizontal' | 'inline'\n\n/** The label/description/error props every field shares (TextField, SelectField… extend these). */\nexport interface FieldLabelProps {\n /** Visible label. Keep it short; put guidance in `description`. */\n label: ReactNode\n /** Help text under the label, linked to the control with `aria-describedby`. */\n description?: ReactNode\n /** Alias of `description` (the legacy name). */\n hint?: ReactNode\n /**\n * Validation message. When present the control gets `aria-invalid` and its border (only)\n * turns critical. Pass `true` to mark invalid without a message.\n */\n error?: ReactNode\n /** Shows a mark after the label and sets `aria-required` on the control. */\n required?: boolean\n /** Shows \"Optional\" after the label (or your own word). Ignored when `required`. */\n optional?: boolean | string\n /** Keep the label for assistive tech only — e.g. a search box beside a visible heading. */\n labelHidden?: boolean\n /**\n * Non-blocking advice (\"Usernames are case-sensitive\"). Shown under the control in a\n * caution tone, never `role=\"alert\"`. Hidden while an error message is shown.\n */\n warning?: ReactNode\n /**\n * Whether the error message is `role=\"alert\"` (announced as soon as it appears).\n * Default `true`. Pass `false` once a form-level `ErrorSummary` owns the announcement\n * — the message stays in `aria-describedby` either way.\n */\n errorLive?: boolean\n /**\n * Keeps the invalid state (border, `aria-invalid`) but doesn't render the error text —\n * for layouts that show the message elsewhere (a sentence, a table cell).\n */\n errorHidden?: boolean\n /** Shows a small spinner after the label and sets `aria-busy` on the control. */\n validating?: boolean\n /** Focusable but not editable. Controls set native `readOnly`/`aria-readonly`. */\n readOnly?: boolean\n /**\n * `stack` (default) — label above the control.\n * `horizontal` — label/description in one column, the control in another (collapses\n * to a stack below `sm`).\n * `inline` — the label is visually hidden and the control sits in text flow.\n */\n layout?: FieldLayout\n}\n\nexport interface FieldProps\n extends FieldLabelProps, Omit<HTMLAttributes<HTMLDivElement>, 'children'> {\n /** Id for the control. Defaults to the child's own `id`, then a generated one. */\n htmlFor?: string\n /** Disables the control inside and dims the label. */\n disabled?: boolean\n /**\n * The control. Library controls pick the wiring up from context; any other single element\n * gets `id` / `aria-*` cloned in; or pass a function and spread its props yourself.\n */\n children: ReactNode | ((props: FieldRenderProps) => ReactNode)\n}\n\ninterface ControlElementProps {\n id?: string\n 'aria-describedby'?: string\n 'aria-invalid'?: unknown\n}\n\n/**\n * Wires a label, description and error to one control.\n *\n * <Field label=\"Amount\" description=\"Include GST\" error={errors.amount}>\n * <Input numeric leading=\"$\" />\n * </Field>\n */\nexport const Field = forwardRef<HTMLDivElement, FieldProps>(function Field(\n {\n label,\n description,\n hint,\n error,\n required = false,\n optional,\n labelHidden = false,\n warning,\n errorLive = true,\n errorHidden = false,\n validating = false,\n readOnly = false,\n layout = 'stack',\n htmlFor,\n disabled = false,\n className,\n children,\n ...rest\n },\n ref,\n) {\n const autoId = useId()\n const childProps = isValidElement(children) ? (children.props as ControlElementProps) : undefined\n const id = htmlFor ?? childProps?.id ?? `${autoId}control`\n const labelId = `${id}-label`\n const descriptionId = `${id}-description`\n const warningId = `${id}-warning`\n const errorId = `${id}-error`\n\n const help = description ?? hint\n const invalid = hasError(error)\n const showErrorMessage = hasErrorMessage(error) && !errorHidden\n const showWarning = warning != null && !showErrorMessage\n const effectiveLabelHidden = labelHidden || layout === 'inline'\n const describedBy = joinIds(\n help != null && descriptionId,\n showWarning && warningId,\n showErrorMessage && errorId,\n )\n\n const context = useMemo<FieldControlContext>(\n () => ({\n id,\n labelId,\n describedBy,\n invalid,\n required,\n disabled,\n readOnly,\n busy: validating,\n warningId,\n }),\n [id, labelId, describedBy, invalid, required, disabled, readOnly, validating, warningId],\n )\n\n let control: ReactNode\n if (typeof children === 'function') {\n control = children({\n id,\n 'aria-describedby': describedBy,\n 'aria-invalid': invalid || undefined,\n 'aria-required': required || undefined,\n required,\n disabled: disabled || undefined,\n })\n } else if (isValidElement(children) && !isFieldAware(children.type)) {\n control = cloneElement(\n children as ReactElement<ControlElementProps & Record<string, unknown>>,\n {\n id,\n 'aria-describedby': joinIds(childProps?.['aria-describedby'], describedBy),\n 'aria-invalid': invalid\n ? true\n : childProps?.['aria-invalid'] === false\n ? undefined\n : childProps?.['aria-invalid'],\n 'aria-required': required || undefined,\n },\n )\n } else {\n control = children\n }\n\n return (\n <div\n ref={ref}\n className={cx(styles.field, className)}\n data-invalid={invalid || undefined}\n data-disabled={disabled || undefined}\n data-readonly={readOnly || undefined}\n data-label-hidden={effectiveLabelHidden || undefined}\n data-layout={layout}\n {...rest}\n >\n <div className={styles.header}>\n <label\n id={labelId}\n htmlFor={id}\n className={cx(messageStyles.label, effectiveLabelHidden && messageStyles.visuallyHidden)}\n >\n <LabelContent required={required} optional={optional} busy={validating}>\n {label}\n </LabelContent>\n </label>\n {help != null ? <FieldDescription id={descriptionId}>{help}</FieldDescription> : null}\n </div>\n <div className={styles.controlSlot}>\n <FieldContext.Provider value={context}>{control}</FieldContext.Provider>\n </div>\n {showWarning ? (\n <div className={styles.warningSlot}>\n <FieldWarning id={warningId}>{warning}</FieldWarning>\n </div>\n ) : null}\n {showErrorMessage ? (\n <div className={styles.errorSlot}>\n <FieldError id={errorId} live={errorLive}>\n {error}\n </FieldError>\n </div>\n ) : null}\n </div>\n )\n})\n"],"mappings":";;;;;;;;;;AAmHA,IAAaI,IAAQC,EAAuC,SAC1D,EACE,UACA,gBACA,SACA,UACA,cAAW,IACX,aACA,iBAAc,IACd,YACA,eAAY,IACZ,iBAAc,IACd,gBAAa,IACb,cAAW,IACX,YAAS,SACT,YACA,cAAW,IACX,cACA,aACA,GAAGC,KAEL,GACA;CACA,IAAMC,IAASC,EAAM,GACfC,IAAaC,EAAeC,CAAQ,IAAKA,EAAS,QAAgC,KAAA,GAClFC,IAAKC,KAAWJ,GAAY,MAAM,GAAGF,EAAO,UAC5CO,IAAU,GAAGF,EAAG,SAChBG,IAAgB,GAAGH,EAAG,eACtBI,IAAY,GAAGJ,EAAG,WAClBK,IAAU,GAAGL,EAAG,SAEhBM,IAAOC,KAAeC,GACtBC,IAAUC,EAASC,CAAK,GACxBC,IAAmBC,EAAgBF,CAAK,KAAK,CAACG,GAC9CC,IAAcC,KAAW,QAAQ,CAACJ,GAClCK,IAAuBC,KAAeC,MAAW,UACjDC,IAAcC,EAClBf,KAAQ,QAAQH,GAChBY,KAAeX,GACfQ,KAAoBP,CACtB,GAEMiB,IAAUC,SACP;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA,MAAMC;EACN;CACF,IACA;EAACxB;EAAIE;EAASkB;EAAaX;EAASgB;EAAUC;EAAUC;EAAUH;EAAYpB;CAAS,CACzF,GAEIwB;CA4BJ,OA3BA,AAwBEA,IAxBE,OAAO7B,KAAa,aACZA,EAAS;EACjB;EACA,oBAAoBqB;EACpB,gBAAgBX,KAAW,KAAA;EAC3B,iBAAiBgB,KAAY,KAAA;EAC7B;EACA,UAAUC,KAAY,KAAA;CACxB,CAAC,IACQ5B,EAAeC,CAAQ,KAAK,CAAC8B,EAAa9B,EAAS,IAAI,IACtD+B,EACR/B,GACA;EACE;EACA,oBAAoBsB,EAAQxB,IAAa,qBAAqBuB,CAAW;EACzE,gBAAgBX,IACZ,KACAZ,IAAa,oBAAoB,KAC/B,KAAA,IACAA,IAAa;EACnB,iBAAiB4B,KAAY,KAAA;CAC/B,CACF,IAEU1B,GAIV,kBAAC,OAAD;EACO;EACL,WAAWgC,EAAG3C,EAAO,OAAO4C,CAAS;EACrC,gBAAcvB,KAAW,KAAA;EACzB,iBAAeiB,KAAY,KAAA;EAC3B,iBAAeC,KAAY,KAAA;EAC3B,qBAAmBV,KAAwB,KAAA;EAC3C,eAAaE;EACb,GAAIzB;EARN,UAAA;GAUE,kBAAC,OAAD;IAAK,WAAWN,EAAO;IAAvB,UAAA,CACE,kBAAC,SAAD;KACE,IAAIc;KACJ,SAASF;KACT,WAAW+B,EAAG1C,EAAc,OAAO4B,KAAwB5B,EAAc,cAAc;KAEvF,UAAA,kBAAC4C,GAAD;MAAwB;MAAoB;MAAU,MAAMT;MACzD,UAAAU;KACW,CAAA;IACT,CAAA,GACN5B,KAAQ,OAAwE,OAAjE,kBAAC6B,GAAD;KAAkB,IAAIhC;KAAgB,UAAAG;IAAuB,CAAA,CAC1E;;GACL,kBAAC,OAAD;IAAK,WAAWlB,EAAO;IACrB,UAAA,kBAACgD,EAAa,UAAd;KAAuB,OAAOd;KAAU,UAAAM;IAA+B,CAAA;GACpE,CAAA;GACJb,IACC,kBAAC,OAAD;IAAK,WAAW3B,EAAO;IACrB,UAAA,kBAACiD,GAAD;KAAc,IAAIjC;KAAY,UAAAY;IAAsB,CAAA;GACjD,CAAA,IACH;GACHJ,IACC,kBAAC,OAAD;IAAK,WAAWxB,EAAO;IACrB,UAAA,kBAACkD,GAAD;KAAY,IAAIjC;KAAS,MAAMkC;KAC5B,UAAA5B;IACS,CAAA;GACT,CAAA,IACH;EACD;;AAET,CAAC"}
1
+ {"version":3,"file":"Field.js","names":["styles","messageStyles","messages_module_default","Field_module_default","Field","forwardRef","rest","autoId","useId","childProps","isValidElement","children","id","htmlFor","labelId","descriptionId","warningId","errorId","help","description","hint","invalid","hasError","error","showErrorMessage","hasErrorMessage","errorHidden","showWarning","warning","effectiveLabelHidden","labelHidden","layout","describedBy","joinIds","context","useMemo","validating","required","disabled","readOnly","control","isFieldAware","cloneElement","cx","className","LabelContent","label","FieldDescription","FieldContext","FieldWarning","FieldError","errorLive"],"sources":["../../../../src/components/inputs/Field/Field.tsx"],"sourcesContent":["import {\n cloneElement,\n forwardRef,\n isValidElement,\n useId,\n useMemo,\n type HTMLAttributes,\n type ReactElement,\n type ReactNode,\n} from 'react'\nimport { cx } from '#utils/cx'\nimport {\n FieldContext,\n isFieldAware,\n type FieldControlContext,\n} from '#components/inputs/internal/FieldContext'\nimport {\n FieldDescription,\n FieldError,\n FieldWarning,\n LabelContent,\n} from '#components/inputs/internal/messages'\nimport { hasError, hasErrorMessage } from '#components/inputs/internal/errors'\nimport messageStyles from '#components/inputs/internal/messages.module.css'\nimport { joinIds } from '#components/inputs/internal/refs'\nimport styles from './Field.module.css'\n\n/** Props handed to a render-function child — spread them onto your control. */\nexport interface FieldRenderProps {\n id: string\n 'aria-describedby'?: string\n 'aria-invalid'?: true\n 'aria-required'?: true\n /** The Field's `required`. Spreading it onto a native input also turns on browser validation. */\n required: boolean\n disabled?: boolean\n}\n\n/** `Field`'s (and `Fieldset`'s) `layout` values. */\nexport type FieldLayout = 'stack' | 'horizontal' | 'inline'\n\n/** The label/description/error props every field shares (TextField, SelectField… extend these). */\nexport interface FieldLabelProps {\n /** Visible label. Keep it short; put guidance in `description`. */\n label: ReactNode\n /** Help text under the label, linked to the control with `aria-describedby`. */\n description?: ReactNode\n /** Alias of `description` (the legacy name). */\n hint?: ReactNode\n /**\n * Validation message. When present the control gets `aria-invalid` and its border (only)\n * turns critical. Pass `true` to mark invalid without a message.\n */\n error?: ReactNode\n /** Shows a mark after the label and sets `aria-required` on the control. */\n required?: boolean\n /** Shows \"Optional\" after the label (or your own word). Ignored when `required`. */\n optional?: boolean | string\n /** Keep the label for assistive tech only — e.g. a search box beside a visible heading. */\n labelHidden?: boolean\n /**\n * Non-blocking advice (\"Usernames are case-sensitive\"). Shown under the control in a\n * caution tone, never `role=\"alert\"`. Hidden while an error message is shown.\n */\n warning?: ReactNode\n /**\n * Whether the error message is `role=\"alert\"` (announced as soon as it appears).\n * Default `true`. Pass `false` once a form-level `ErrorSummary` owns the announcement\n * — the message stays in `aria-describedby` either way.\n */\n errorLive?: boolean\n /**\n * Keeps the invalid state (border, `aria-invalid`) but doesn't render the error text —\n * for layouts that show the message elsewhere (a sentence, a table cell).\n */\n errorHidden?: boolean\n /** Shows a small spinner after the label and sets `aria-busy` on the control. */\n validating?: boolean\n /** Focusable but not editable. Controls set native `readOnly`/`aria-readonly`. */\n readOnly?: boolean\n /**\n * `stack` (default) — label above the control.\n * `horizontal` — label/description in one column, the control in another (collapses\n * to a stack below `sm`).\n * `inline` — the label is visually hidden and the control sits in text flow.\n */\n layout?: FieldLayout\n}\n\nexport interface FieldProps\n extends FieldLabelProps, Omit<HTMLAttributes<HTMLDivElement>, 'children'> {\n /** Id for the control. Defaults to the child's own `id`, then a generated one. */\n htmlFor?: string\n /** Disables the control inside and dims the label. */\n disabled?: boolean\n /**\n * The control. Library controls pick the wiring up from context; any other single element\n * gets `id` / `aria-*` cloned in; or pass a function and spread its props yourself.\n */\n children: ReactNode | ((props: FieldRenderProps) => ReactNode)\n}\n\ninterface ControlElementProps {\n id?: string\n 'aria-describedby'?: string\n 'aria-invalid'?: unknown\n}\n\n/**\n * Wires a label, a description, an error and a warning to one control. Every Kiln input works\n * inside it.\n *\n * @remarks\n * Every input in Kiln exists twice. The bare control (`Input`, `NumberInput`, `Combobox`) works\n * anywhere, and the `*Field` version (`TextField`, `NumberField`, `ComboboxField`) adds the label,\n * description, error and warning. `Field` is what the `*Field`s are made of, and what you use to\n * give any other control the same treatment.\n *\n * ## Errors and warnings are two channels\n *\n * - **`error`** blocks submission. It sets `aria-invalid`, renders in the critical tone, and is\n * announced as it appears.\n * - **`warning`** is advice (\"Usernames are case-sensitive\") in the caution tone. It never blocks\n * and is never announced as an alert.\n *\n * An error replaces the warning while it shows. Plain fields show whatever `error` you pass;\n * [kiln-forms](/docs/forms) decides _when_ to show one (after the field is blurred or after a\n * submit attempt). Pass `errorLive={false}` when an error summary owns the announcement, and\n * `errorHidden` when the layout shows the message somewhere else.\n *\n * `required` marks the field for assistive technology; `optional` adds a visible \"Optional\" (or\n * your own text) instead, for forms where most fields are required. `validating` shows that an\n * async check is running.\n *\n * @privateRemarks\n * Wires a label, description and error to one control.\n *\n * <Field label=\"Amount\" description=\"Include GST\" error={errors.amount}>\n * <Input numeric leading=\"$\" />\n * </Field>\n */\nexport const Field = forwardRef<HTMLDivElement, FieldProps>(function Field(\n {\n label,\n description,\n hint,\n error,\n required = false,\n optional,\n labelHidden = false,\n warning,\n errorLive = true,\n errorHidden = false,\n validating = false,\n readOnly = false,\n layout = 'stack',\n htmlFor,\n disabled = false,\n className,\n children,\n ...rest\n },\n ref,\n) {\n const autoId = useId()\n const childProps = isValidElement(children) ? (children.props as ControlElementProps) : undefined\n const id = htmlFor ?? childProps?.id ?? `${autoId}control`\n const labelId = `${id}-label`\n const descriptionId = `${id}-description`\n const warningId = `${id}-warning`\n const errorId = `${id}-error`\n\n const help = description ?? hint\n const invalid = hasError(error)\n const showErrorMessage = hasErrorMessage(error) && !errorHidden\n const showWarning = warning != null && !showErrorMessage\n const effectiveLabelHidden = labelHidden || layout === 'inline'\n const describedBy = joinIds(\n help != null && descriptionId,\n showWarning && warningId,\n showErrorMessage && errorId,\n )\n\n const context = useMemo<FieldControlContext>(\n () => ({\n id,\n labelId,\n describedBy,\n invalid,\n required,\n disabled,\n readOnly,\n busy: validating,\n warningId,\n }),\n [id, labelId, describedBy, invalid, required, disabled, readOnly, validating, warningId],\n )\n\n let control: ReactNode\n if (typeof children === 'function') {\n control = children({\n id,\n 'aria-describedby': describedBy,\n 'aria-invalid': invalid || undefined,\n 'aria-required': required || undefined,\n required,\n disabled: disabled || undefined,\n })\n } else if (isValidElement(children) && !isFieldAware(children.type)) {\n control = cloneElement(\n children as ReactElement<ControlElementProps & Record<string, unknown>>,\n {\n id,\n 'aria-describedby': joinIds(childProps?.['aria-describedby'], describedBy),\n 'aria-invalid': invalid\n ? true\n : childProps?.['aria-invalid'] === false\n ? undefined\n : childProps?.['aria-invalid'],\n 'aria-required': required || undefined,\n },\n )\n } else {\n control = children\n }\n\n return (\n <div\n ref={ref}\n className={cx(styles.field, className)}\n data-invalid={invalid || undefined}\n data-disabled={disabled || undefined}\n data-readonly={readOnly || undefined}\n data-label-hidden={effectiveLabelHidden || undefined}\n data-layout={layout}\n {...rest}\n >\n <div className={styles.header}>\n <label\n id={labelId}\n htmlFor={id}\n className={cx(messageStyles.label, effectiveLabelHidden && messageStyles.visuallyHidden)}\n >\n <LabelContent required={required} optional={optional} busy={validating}>\n {label}\n </LabelContent>\n </label>\n {help != null ? <FieldDescription id={descriptionId}>{help}</FieldDescription> : null}\n </div>\n <div className={styles.controlSlot}>\n <FieldContext.Provider value={context}>{control}</FieldContext.Provider>\n </div>\n {showWarning ? (\n <div className={styles.warningSlot}>\n <FieldWarning id={warningId}>{warning}</FieldWarning>\n </div>\n ) : null}\n {showErrorMessage ? (\n <div className={styles.errorSlot}>\n <FieldError id={errorId} live={errorLive}>\n {error}\n </FieldError>\n </div>\n ) : null}\n </div>\n )\n})\n"],"mappings":";;;;;;;;;;AA6IA,IAAaI,IAAQC,EAAuC,SAC1D,EACE,UACA,gBACA,SACA,UACA,cAAW,IACX,aACA,iBAAc,IACd,YACA,eAAY,IACZ,iBAAc,IACd,gBAAa,IACb,cAAW,IACX,YAAS,SACT,YACA,cAAW,IACX,cACA,aACA,GAAGC,KAEL,GACA;CACA,IAAMC,IAASC,EAAM,GACfC,IAAaC,EAAeC,CAAQ,IAAKA,EAAS,QAAgC,KAAA,GAClFC,IAAKC,KAAWJ,GAAY,MAAM,GAAGF,EAAO,UAC5CO,IAAU,GAAGF,EAAG,SAChBG,IAAgB,GAAGH,EAAG,eACtBI,IAAY,GAAGJ,EAAG,WAClBK,IAAU,GAAGL,EAAG,SAEhBM,IAAOC,KAAeC,GACtBC,IAAUC,EAASC,CAAK,GACxBC,IAAmBC,EAAgBF,CAAK,KAAK,CAACG,GAC9CC,IAAcC,KAAW,QAAQ,CAACJ,GAClCK,IAAuBC,KAAeC,MAAW,UACjDC,IAAcC,EAClBf,KAAQ,QAAQH,GAChBY,KAAeX,GACfQ,KAAoBP,CACtB,GAEMiB,IAAUC,SACP;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA,MAAMC;EACN;CACF,IACA;EAACxB;EAAIE;EAASkB;EAAaX;EAASgB;EAAUC;EAAUC;EAAUH;EAAYpB;CAAS,CACzF,GAEIwB;CA4BJ,OA3BA,AAwBEA,IAxBE,OAAO7B,KAAa,aACZA,EAAS;EACjB;EACA,oBAAoBqB;EACpB,gBAAgBX,KAAW,KAAA;EAC3B,iBAAiBgB,KAAY,KAAA;EAC7B;EACA,UAAUC,KAAY,KAAA;CACxB,CAAC,IACQ5B,EAAeC,CAAQ,KAAK,CAAC8B,EAAa9B,EAAS,IAAI,IACtD+B,EACR/B,GACA;EACE;EACA,oBAAoBsB,EAAQxB,IAAa,qBAAqBuB,CAAW;EACzE,gBAAgBX,IACZ,KACAZ,IAAa,oBAAoB,KAC/B,KAAA,IACAA,IAAa;EACnB,iBAAiB4B,KAAY,KAAA;CAC/B,CACF,IAEU1B,GAIV,kBAAC,OAAD;EACO;EACL,WAAWgC,EAAG3C,EAAO,OAAO4C,CAAS;EACrC,gBAAcvB,KAAW,KAAA;EACzB,iBAAeiB,KAAY,KAAA;EAC3B,iBAAeC,KAAY,KAAA;EAC3B,qBAAmBV,KAAwB,KAAA;EAC3C,eAAaE;EACb,GAAIzB;EARN,UAAA;GAUE,kBAAC,OAAD;IAAK,WAAWN,EAAO;IAAvB,UAAA,CACE,kBAAC,SAAD;KACE,IAAIc;KACJ,SAASF;KACT,WAAW+B,EAAG1C,EAAc,OAAO4B,KAAwB5B,EAAc,cAAc;KAEvF,UAAA,kBAAC4C,GAAD;MAAwB;MAAoB;MAAU,MAAMT;MACzD,UAAAU;KACW,CAAA;IACT,CAAA,GACN5B,KAAQ,OAAwE,OAAjE,kBAAC6B,GAAD;KAAkB,IAAIhC;KAAgB,UAAAG;IAAuB,CAAA,CAC1E;;GACL,kBAAC,OAAD;IAAK,WAAWlB,EAAO;IACrB,UAAA,kBAACgD,EAAa,UAAd;KAAuB,OAAOd;KAAU,UAAAM;IAA+B,CAAA;GACpE,CAAA;GACJb,IACC,kBAAC,OAAD;IAAK,WAAW3B,EAAO;IACrB,UAAA,kBAACiD,GAAD;KAAc,IAAIjC;KAAY,UAAAY;IAAsB,CAAA;GACjD,CAAA,IACH;GACHJ,IACC,kBAAC,OAAD;IAAK,WAAWxB,EAAO;IACrB,UAAA,kBAACkD,GAAD;KAAY,IAAIjC;KAAS,MAAMkC;KAC5B,UAAA5B;IACS,CAAA;GACT,CAAA,IACH;EACD;;AAET,CAAC"}
@@ -36,6 +36,14 @@ export interface FieldsetProps extends FieldsetHTMLAttributes<HTMLFieldSetElemen
36
36
  layout?: FieldLayout;
37
37
  }
38
38
  /**
39
+ * Groups related controls under one legend, with a description and an error for the group.
40
+ *
41
+ * @remarks
42
+ * `Fieldset` is a `<fieldset>` and `<legend>` with Kiln's styles: an address block, a set of
43
+ * checkboxes, a radio group. Screen readers announce the legend with each control inside, so
44
+ * "Town" becomes "Delivery address, Town".
45
+ *
46
+ * @privateRemarks
39
47
  * Groups related controls under a legend: a RadioGroup, a set of CheckboxFields, or an
40
48
  * address block. `disabled` disables every control inside (native fieldset behaviour).
41
49
  *