@mitcsutt/kiln-ui 0.2.0 → 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 (220) 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/List/List.module.js.map +1 -1
  29. package/dist/components/display/Marquee/Marquee.d.ts +8 -0
  30. package/dist/components/display/Marquee/Marquee.js.map +1 -1
  31. package/dist/components/display/Media/Media.d.ts +7 -0
  32. package/dist/components/display/Media/Media.js.map +1 -1
  33. package/dist/components/display/Meter/Meter.d.ts +9 -0
  34. package/dist/components/display/Meter/Meter.js.map +1 -1
  35. package/dist/components/display/Progress/Progress.d.ts +8 -0
  36. package/dist/components/display/Progress/Progress.js.map +1 -1
  37. package/dist/components/display/Skeleton/Skeleton.js.map +1 -1
  38. package/dist/components/display/Stamp/Stamp.d.ts +8 -0
  39. package/dist/components/display/Stamp/Stamp.js.map +1 -1
  40. package/dist/components/display/Stat/Stat.d.ts +8 -0
  41. package/dist/components/display/Stat/Stat.js.map +1 -1
  42. package/dist/components/display/Table/Table.js.map +1 -1
  43. package/dist/components/display/Table/Table.module.js.map +1 -1
  44. package/dist/components/display/Tag/Tag.d.ts +7 -0
  45. package/dist/components/display/Tag/Tag.js.map +1 -1
  46. package/dist/components/feedback/Alert/Alert.d.ts +10 -0
  47. package/dist/components/feedback/Alert/Alert.js.map +1 -1
  48. package/dist/components/feedback/LiveIndicator/LiveIndicator.d.ts +7 -0
  49. package/dist/components/feedback/LiveIndicator/LiveIndicator.js.map +1 -1
  50. package/dist/components/feedback/RelativeTime/RelativeTime.d.ts +8 -0
  51. package/dist/components/feedback/RelativeTime/RelativeTime.js.map +1 -1
  52. package/dist/components/feedback/Spinner/Spinner.d.ts +10 -1
  53. package/dist/components/feedback/Spinner/Spinner.js.map +1 -1
  54. package/dist/components/feedback/StatusDot/StatusDot.d.ts +10 -1
  55. package/dist/components/feedback/StatusDot/StatusDot.js.map +1 -1
  56. package/dist/components/inputs/AmountField/AmountField.d.ts +7 -0
  57. package/dist/components/inputs/AmountField/AmountField.js.map +1 -1
  58. package/dist/components/inputs/AmountInput/AmountInput.d.ts +8 -0
  59. package/dist/components/inputs/AmountInput/AmountInput.js.map +1 -1
  60. package/dist/components/inputs/Checkbox/Checkbox.d.ts +8 -0
  61. package/dist/components/inputs/Checkbox/Checkbox.js.map +1 -1
  62. package/dist/components/inputs/CheckboxField/CheckboxField.d.ts +7 -0
  63. package/dist/components/inputs/CheckboxField/CheckboxField.js.map +1 -1
  64. package/dist/components/inputs/CheckboxGroup/CheckboxGroup.d.ts +8 -0
  65. package/dist/components/inputs/CheckboxGroup/CheckboxGroup.js.map +1 -1
  66. package/dist/components/inputs/CheckboxGroupField/CheckboxGroupField.d.ts +7 -0
  67. package/dist/components/inputs/CheckboxGroupField/CheckboxGroupField.js.map +1 -1
  68. package/dist/components/inputs/ChipGroupField/ChipGroupField.d.ts +7 -0
  69. package/dist/components/inputs/ChipGroupField/ChipGroupField.js.map +1 -1
  70. package/dist/components/inputs/ChoiceCards/ChoiceCards.d.ts +9 -0
  71. package/dist/components/inputs/ChoiceCards/ChoiceCards.js.map +1 -1
  72. package/dist/components/inputs/ChoiceCardsField/ChoiceCardsField.d.ts +7 -0
  73. package/dist/components/inputs/ChoiceCardsField/ChoiceCardsField.js.map +1 -1
  74. package/dist/components/inputs/ColorField/ColorField.d.ts +6 -0
  75. package/dist/components/inputs/ColorField/ColorField.js.map +1 -1
  76. package/dist/components/inputs/ColorInput/ColorInput.d.ts +8 -0
  77. package/dist/components/inputs/ColorInput/ColorInput.js.map +1 -1
  78. package/dist/components/inputs/Combobox/Combobox.d.ts +9 -0
  79. package/dist/components/inputs/Combobox/Combobox.js.map +1 -1
  80. package/dist/components/inputs/ComboboxField/ComboboxField.d.ts +7 -0
  81. package/dist/components/inputs/ComboboxField/ComboboxField.js.map +1 -1
  82. package/dist/components/inputs/DateRangeField/DateRangeField.d.ts +7 -0
  83. package/dist/components/inputs/DateRangeField/DateRangeField.js.map +1 -1
  84. package/dist/components/inputs/Field/Field.d.ts +26 -0
  85. package/dist/components/inputs/Field/Field.js.map +1 -1
  86. package/dist/components/inputs/Fieldset/Fieldset.d.ts +8 -0
  87. package/dist/components/inputs/Fieldset/Fieldset.js.map +1 -1
  88. package/dist/components/inputs/FileDrop/FileDrop.d.ts +10 -0
  89. package/dist/components/inputs/FileDrop/FileDrop.js.map +1 -1
  90. package/dist/components/inputs/FileField/FileField.d.ts +7 -0
  91. package/dist/components/inputs/FileField/FileField.js.map +1 -1
  92. package/dist/components/inputs/Input/Input.d.ts +9 -0
  93. package/dist/components/inputs/Input/Input.js.map +1 -1
  94. package/dist/components/inputs/NumberField/NumberField.d.ts +7 -0
  95. package/dist/components/inputs/NumberField/NumberField.js.map +1 -1
  96. package/dist/components/inputs/NumberInput/NumberInput.d.ts +8 -0
  97. package/dist/components/inputs/NumberInput/NumberInput.js.map +1 -1
  98. package/dist/components/inputs/OneTimeCodeField/OneTimeCodeField.d.ts +7 -0
  99. package/dist/components/inputs/OneTimeCodeField/OneTimeCodeField.js.map +1 -1
  100. package/dist/components/inputs/OneTimeCodeInput/OneTimeCodeInput.d.ts +8 -0
  101. package/dist/components/inputs/OneTimeCodeInput/OneTimeCodeInput.js.map +1 -1
  102. package/dist/components/inputs/PasswordField/PasswordField.d.ts +7 -0
  103. package/dist/components/inputs/PasswordField/PasswordField.js.map +1 -1
  104. package/dist/components/inputs/PasswordInput/PasswordInput.d.ts +10 -0
  105. package/dist/components/inputs/PasswordInput/PasswordInput.js.map +1 -1
  106. package/dist/components/inputs/RadioGroup/RadioGroup.d.ts +9 -0
  107. package/dist/components/inputs/RadioGroup/RadioGroup.js.map +1 -1
  108. package/dist/components/inputs/RadioGroupField/RadioGroupField.d.ts +8 -0
  109. package/dist/components/inputs/RadioGroupField/RadioGroupField.js.map +1 -1
  110. package/dist/components/inputs/RangeSlider/RangeSlider.d.ts +8 -0
  111. package/dist/components/inputs/RangeSlider/RangeSlider.js.map +1 -1
  112. package/dist/components/inputs/RangeSliderField/RangeSliderField.d.ts +7 -0
  113. package/dist/components/inputs/RangeSliderField/RangeSliderField.js.map +1 -1
  114. package/dist/components/inputs/Rating/Rating.d.ts +8 -0
  115. package/dist/components/inputs/Rating/Rating.js.map +1 -1
  116. package/dist/components/inputs/RatingField/RatingField.d.ts +7 -0
  117. package/dist/components/inputs/RatingField/RatingField.js.map +1 -1
  118. package/dist/components/inputs/SegmentedField/SegmentedField.d.ts +7 -0
  119. package/dist/components/inputs/SegmentedField/SegmentedField.js.map +1 -1
  120. package/dist/components/inputs/Select/Select.d.ts +9 -0
  121. package/dist/components/inputs/Select/Select.js.map +1 -1
  122. package/dist/components/inputs/SelectField/SelectField.d.ts +7 -0
  123. package/dist/components/inputs/SelectField/SelectField.js.map +1 -1
  124. package/dist/components/inputs/Slider/Slider.d.ts +8 -0
  125. package/dist/components/inputs/Slider/Slider.js.map +1 -1
  126. package/dist/components/inputs/SliderField/SliderField.d.ts +7 -0
  127. package/dist/components/inputs/SliderField/SliderField.js.map +1 -1
  128. package/dist/components/inputs/Switch/Switch.d.ts +8 -0
  129. package/dist/components/inputs/Switch/Switch.js.map +1 -1
  130. package/dist/components/inputs/SwitchField/SwitchField.d.ts +8 -0
  131. package/dist/components/inputs/SwitchField/SwitchField.js.map +1 -1
  132. package/dist/components/inputs/TagsField/TagsField.d.ts +6 -0
  133. package/dist/components/inputs/TagsField/TagsField.js.map +1 -1
  134. package/dist/components/inputs/TagsInput/TagsInput.d.ts +8 -0
  135. package/dist/components/inputs/TagsInput/TagsInput.js.map +1 -1
  136. package/dist/components/inputs/TextField/TextField.d.ts +8 -0
  137. package/dist/components/inputs/TextField/TextField.js.map +1 -1
  138. package/dist/components/inputs/Textarea/Textarea.d.ts +8 -0
  139. package/dist/components/inputs/Textarea/Textarea.js.map +1 -1
  140. package/dist/components/inputs/TextareaField/TextareaField.d.ts +7 -0
  141. package/dist/components/inputs/TextareaField/TextareaField.js.map +1 -1
  142. package/dist/components/layout/ActionBar/ActionBar.d.ts +7 -0
  143. package/dist/components/layout/ActionBar/ActionBar.js.map +1 -1
  144. package/dist/components/layout/AppShell/AppShell.js.map +1 -1
  145. package/dist/components/layout/AspectRatio/AspectRatio.d.ts +8 -0
  146. package/dist/components/layout/AspectRatio/AspectRatio.js.map +1 -1
  147. package/dist/components/layout/Box/Box.d.ts +8 -0
  148. package/dist/components/layout/Box/Box.js.map +1 -1
  149. package/dist/components/layout/Container/Container.d.ts +17 -0
  150. package/dist/components/layout/Container/Container.js.map +1 -1
  151. package/dist/components/layout/Divider/Divider.d.ts +7 -0
  152. package/dist/components/layout/Divider/Divider.js.map +1 -1
  153. package/dist/components/layout/Grid/Grid.d.ts +9 -0
  154. package/dist/components/layout/Grid/Grid.js.map +1 -1
  155. package/dist/components/layout/Inline/Inline.d.ts +8 -0
  156. package/dist/components/layout/Inline/Inline.js.map +1 -1
  157. package/dist/components/layout/Section/Section.d.ts +15 -0
  158. package/dist/components/layout/Section/Section.js.map +1 -1
  159. package/dist/components/layout/Split/Split.d.ts +9 -0
  160. package/dist/components/layout/Split/Split.js.map +1 -1
  161. package/dist/components/layout/Stack/Stack.d.ts +12 -0
  162. package/dist/components/layout/Stack/Stack.js.map +1 -1
  163. package/dist/components/layout/VisuallyHidden/VisuallyHidden.d.ts +7 -0
  164. package/dist/components/layout/VisuallyHidden/VisuallyHidden.js.map +1 -1
  165. package/dist/components/navigation/Accordion/Accordion.d.ts +7 -0
  166. package/dist/components/navigation/Accordion/Accordion.js.map +1 -1
  167. package/dist/components/navigation/BottomNav/BottomNav.d.ts +9 -0
  168. package/dist/components/navigation/BottomNav/BottomNav.js.map +1 -1
  169. package/dist/components/navigation/NavLinks/NavLinks.d.ts +9 -0
  170. package/dist/components/navigation/NavLinks/NavLinks.js.map +1 -1
  171. package/dist/components/navigation/Stepper/Stepper.d.ts +7 -0
  172. package/dist/components/navigation/Stepper/Stepper.js.map +1 -1
  173. package/dist/components/navigation/Tabs/Tabs.d.ts +8 -0
  174. package/dist/components/navigation/Tabs/Tabs.js.map +1 -1
  175. package/dist/components/overlays/Dialog/Dialog.d.ts +13 -0
  176. package/dist/components/overlays/Dialog/Dialog.js.map +1 -1
  177. package/dist/components/overlays/DropdownMenu/DropdownMenu.d.ts +8 -0
  178. package/dist/components/overlays/DropdownMenu/DropdownMenu.js.map +1 -1
  179. package/dist/components/overlays/Popover/Popover.d.ts +7 -0
  180. package/dist/components/overlays/Popover/Popover.js.map +1 -1
  181. package/dist/components/overlays/Sheet/Sheet.d.ts +8 -0
  182. package/dist/components/overlays/Sheet/Sheet.js.map +1 -1
  183. package/dist/components/overlays/Tooltip/Tooltip.d.ts +8 -0
  184. package/dist/components/overlays/Tooltip/Tooltip.js.map +1 -1
  185. package/dist/components/typography/Amount/Amount.d.ts +8 -0
  186. package/dist/components/typography/Amount/Amount.js.map +1 -1
  187. package/dist/components/typography/Code/Code.d.ts +8 -0
  188. package/dist/components/typography/Code/Code.js.map +1 -1
  189. package/dist/components/typography/Heading/Heading.d.ts +8 -0
  190. package/dist/components/typography/Heading/Heading.js.map +1 -1
  191. package/dist/components/typography/Kbd/Kbd.d.ts +6 -0
  192. package/dist/components/typography/Kbd/Kbd.js.map +1 -1
  193. package/dist/components/typography/Link/Link.d.ts +9 -0
  194. package/dist/components/typography/Link/Link.js.map +1 -1
  195. package/dist/components/typography/Numeral/Numeral.d.ts +8 -0
  196. package/dist/components/typography/Numeral/Numeral.js.map +1 -1
  197. package/dist/components/typography/Prose/Prose.d.ts +9 -0
  198. package/dist/components/typography/Prose/Prose.js.map +1 -1
  199. package/dist/components/typography/Quote/Quote.d.ts +7 -0
  200. package/dist/components/typography/Quote/Quote.js.map +1 -1
  201. package/dist/components/typography/SectionHeader/SectionHeader.d.ts +8 -0
  202. package/dist/components/typography/SectionHeader/SectionHeader.js.map +1 -1
  203. package/dist/components/typography/Text/Text.d.ts +8 -0
  204. package/dist/components/typography/Text/Text.js.map +1 -1
  205. package/dist/styles.css +1 -1
  206. package/package.json +1 -1
  207. package/skills/custom-theme/SKILL.md +1 -1
  208. package/skills/layout-composition/SKILL.md +37 -98
  209. package/skills/layout-composition/references/action-bar.md +4 -4
  210. package/skills/layout-composition/references/app-shell.md +11 -4
  211. package/skills/layout-composition/references/aspect-ratio.md +3 -1
  212. package/skills/layout-composition/references/box.md +7 -7
  213. package/skills/layout-composition/references/checkout.md +1 -1
  214. package/skills/layout-composition/references/container.md +15 -13
  215. package/skills/layout-composition/references/dashboard.md +1 -1
  216. package/skills/layout-composition/references/divider.md +5 -5
  217. package/skills/layout-composition/references/section.md +69 -0
  218. package/skills/layout-composition/references/settings.md +1 -1
  219. package/skills/layout-composition/references/visually-hidden.md +4 -4
  220. package/skills/setup-and-theming/SKILL.md +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Alert.js","names":["styles","Alert_module_default","GLYPH","InfoIcon","CircleCheckIcon","WarningIcon","ErrorIcon","Alert","forwardRef","rest","titleId","useId","glyph","icon","tone","role","title","cx","className","variant","onDismiss","children","action","dismissLabel","CloseIcon"],"sources":["../../../../src/components/feedback/Alert/Alert.tsx"],"sourcesContent":["import { forwardRef, useId, type HTMLAttributes, type ReactNode } from 'react'\nimport { CircleCheckIcon, CloseIcon, ErrorIcon, InfoIcon, WarningIcon } from '#icons'\nimport { cx } from '#utils/cx'\nimport styles from './Alert.module.css'\n\nexport type AlertTone = 'info' | 'positive' | 'caution' | 'critical' | 'neutral'\nexport type AlertVariant = 'soft' | 'outline'\n\nexport interface AlertProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n /** Meaning. `critical` and `caution` interrupt (role=\"alert\"); the rest are polite (role=\"status\"). */\n tone?: AlertTone\n /**\n * `outline` (default): a neutral hairline frame on the surface — the tone shows only in\n * the glyph and a short tab on the top edge. `soft`: the louder form, a tinted fill with a\n * tone keyline, for notices that must not be missed.\n */\n variant?: AlertVariant\n /** Short summary, read first. */\n title?: ReactNode\n /** Replaces the tone glyph. Pass `null` to drop it. */\n icon?: ReactNode\n /** A follow-up action, e.g. `<Button size=\"sm\" variant=\"outline\">Retry</Button>`. */\n action?: ReactNode\n /** Shows a dismiss button that calls this. */\n onDismiss?: () => void\n /** Accessible name of the dismiss button. Default \"Dismiss\". */\n dismissLabel?: string\n}\n\nconst GLYPH: Record<AlertTone, ReactNode> = {\n info: <InfoIcon />,\n neutral: <InfoIcon />,\n positive: <CircleCheckIcon />,\n caution: <WarningIcon />,\n critical: <ErrorIcon />,\n}\n\n/**\n * An inline message about the thing next to it. A full hairline frame, the tone in the\n * glyph and a short tab on the top edge, the title in the heading face — never a tinted\n * box by default, never a coloured stripe down the left edge.\n *\n * <Alert tone=\"critical\" title=\"Couldn't load invoices\" action={<Button …>Retry</Button>}>\n * The billing service didn't answer. We'll try again in 30 seconds.\n * </Alert>\n */\nexport const Alert = forwardRef<HTMLDivElement, AlertProps>(function Alert(\n {\n tone = 'info',\n variant = 'outline',\n title,\n icon,\n action,\n onDismiss,\n dismissLabel = 'Dismiss',\n role,\n className,\n children,\n ...rest\n },\n ref,\n) {\n const titleId = useId()\n const glyph = icon === undefined ? GLYPH[tone] : icon\n return (\n <div\n ref={ref}\n role={role ?? (tone === 'critical' || tone === 'caution' ? 'alert' : 'status')}\n aria-labelledby={title ? titleId : undefined}\n className={cx(styles.alert, className)}\n data-kiln-component=\"\"\n data-tone={tone}\n data-variant={variant}\n data-dismissible={onDismiss ? '' : undefined}\n {...rest}\n >\n {glyph ? (\n <span className={styles.glyph} aria-hidden=\"true\">\n {glyph}\n </span>\n ) : null}\n <div className={styles.body}>\n {title ? (\n <p id={titleId} className={styles.title}>\n {title}\n </p>\n ) : null}\n {children ? <div className={styles.description}>{children}</div> : null}\n {action ? <div className={styles.action}>{action}</div> : null}\n </div>\n {onDismiss ? (\n <button\n type=\"button\"\n className={styles.dismiss}\n aria-label={dismissLabel}\n onClick={onDismiss}\n >\n <CloseIcon />\n </button>\n ) : null}\n </div>\n )\n})\n"],"mappings":";;;;;;AA6BA,IAAME,IAAsC;CAC1C,MAAM,kBAACC,GAAD,CAAW,CAAA;CACjB,SAAS,kBAACA,GAAD,CAAW,CAAA;CACpB,UAAU,kBAACC,GAAD,CAAkB,CAAA;CAC5B,SAAS,kBAACC,GAAD,CAAc,CAAA;CACvB,UAAU,kBAACC,GAAD,CAAY,CAAA;AACxB,GAWaC,IAAQC,EAAuC,SAC1D,EACE,UAAO,QACP,aAAU,WACV,UACA,SACA,WACA,cACA,kBAAe,WACf,SACA,cACA,aACA,GAAGC,KAEL,GACA;CACA,IAAMC,IAAUC,EAAM,GAChBC,IAAQC,MAAS,KAAA,IAAYX,EAAMY,KAAQD;CACjD,OACE,kBAAC,OAAD;EACO;EACL,MAAME,MAASD,MAAS,cAAcA,MAAS,YAAY,UAAU;EACrE,mBAAiBE,IAAQN,IAAU,KAAA;EACnC,WAAWO,EAAGjB,EAAO,OAAOkB,CAAS;EACrC,uBAAoB;EACpB,aAAWJ;EACX,gBAAcK;EACd,oBAAkBC,IAAY,KAAK,KAAA;EACnC,GAAIX;EATN,UAAA;GAWGG,IACC,kBAAC,QAAD;IAAM,WAAWZ,EAAO;IAAO,eAAY;IACxC,UAAAY;GACG,CAAA,IACJ;GACJ,kBAAC,OAAD;IAAK,WAAWZ,EAAO;IAAvB,UAAA;KACGgB,IACC,kBAAC,KAAD;MAAG,IAAIN;MAAS,WAAWV,EAAO;MAC/B,UAAAgB;KACA,CAAA,IACD;KACHK,IAAW,kBAAC,OAAD;MAAK,WAAWrB,EAAO;MAAc;KAAc,CAAA,IAAI;KAClEsB,IAAS,kBAAC,OAAD;MAAK,WAAWtB,EAAO;MAAS,UAAAsB;KAAY,CAAA,IAAI;IACvD;;GACJF,IACC,kBAAC,UAAD;IACE,MAAK;IACL,WAAWpB,EAAO;IAClB,cAAYuB;IACZ,SAASH;IAET,UAAA,kBAACI,GAAD,CAAY,CAAA;GACN,CAAA,IACN;EACD;;AAET,CAAC"}
1
+ {"version":3,"file":"Alert.js","names":["styles","Alert_module_default","GLYPH","InfoIcon","CircleCheckIcon","WarningIcon","ErrorIcon","Alert","forwardRef","rest","titleId","useId","glyph","icon","tone","role","title","cx","className","variant","onDismiss","children","action","dismissLabel","CloseIcon"],"sources":["../../../../src/components/feedback/Alert/Alert.tsx"],"sourcesContent":["import { forwardRef, useId, type HTMLAttributes, type ReactNode } from 'react'\nimport { CircleCheckIcon, CloseIcon, ErrorIcon, InfoIcon, WarningIcon } from '#icons'\nimport { cx } from '#utils/cx'\nimport styles from './Alert.module.css'\n\nexport type AlertTone = 'info' | 'positive' | 'caution' | 'critical' | 'neutral'\nexport type AlertVariant = 'soft' | 'outline'\n\nexport interface AlertProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n /** Meaning. `critical` and `caution` interrupt (role=\"alert\"); the rest are polite (role=\"status\"). */\n tone?: AlertTone\n /**\n * `outline` (default): a neutral hairline frame on the surface — the tone shows only in\n * the glyph and a short tab on the top edge. `soft`: the louder form, a tinted fill with a\n * tone keyline, for notices that must not be missed.\n */\n variant?: AlertVariant\n /** Short summary, read first. */\n title?: ReactNode\n /** Replaces the tone glyph. Pass `null` to drop it. */\n icon?: ReactNode\n /** A follow-up action, e.g. `<Button size=\"sm\" variant=\"outline\">Retry</Button>`. */\n action?: ReactNode\n /** Shows a dismiss button that calls this. */\n onDismiss?: () => void\n /** Accessible name of the dismiss button. Default \"Dismiss\". */\n dismissLabel?: string\n}\n\nconst GLYPH: Record<AlertTone, ReactNode> = {\n info: <InfoIcon />,\n neutral: <InfoIcon />,\n positive: <CircleCheckIcon />,\n caution: <WarningIcon />,\n critical: <ErrorIcon />,\n}\n\n/**\n * An inline message about the thing next to it. A hairline frame, the tone in its glyph, never a\n * coloured stripe.\n *\n * @remarks\n * `Alert` tells the reader something about the content around it: an error loading it, a change to\n * it, a success. It's a full hairline frame with the tone in the glyph and a short tab on the top\n * edge, and its title in the heading face. It isn't a tinted box by default, and it never has a\n * coloured stripe down the left edge.\n *\n * @privateRemarks\n * An inline message about the thing next to it. A full hairline frame, the tone in the\n * glyph and a short tab on the top edge, the title in the heading face — never a tinted\n * box by default, never a coloured stripe down the left edge.\n *\n * <Alert tone=\"critical\" title=\"Couldn't load invoices\" action={<Button …>Retry</Button>}>\n * The billing service didn't answer. We'll try again in 30 seconds.\n * </Alert>\n */\nexport const Alert = forwardRef<HTMLDivElement, AlertProps>(function Alert(\n {\n tone = 'info',\n variant = 'outline',\n title,\n icon,\n action,\n onDismiss,\n dismissLabel = 'Dismiss',\n role,\n className,\n children,\n ...rest\n },\n ref,\n) {\n const titleId = useId()\n const glyph = icon === undefined ? GLYPH[tone] : icon\n return (\n <div\n ref={ref}\n role={role ?? (tone === 'critical' || tone === 'caution' ? 'alert' : 'status')}\n aria-labelledby={title ? titleId : undefined}\n className={cx(styles.alert, className)}\n data-kiln-component=\"\"\n data-tone={tone}\n data-variant={variant}\n data-dismissible={onDismiss ? '' : undefined}\n {...rest}\n >\n {glyph ? (\n <span className={styles.glyph} aria-hidden=\"true\">\n {glyph}\n </span>\n ) : null}\n <div className={styles.body}>\n {title ? (\n <p id={titleId} className={styles.title}>\n {title}\n </p>\n ) : null}\n {children ? <div className={styles.description}>{children}</div> : null}\n {action ? <div className={styles.action}>{action}</div> : null}\n </div>\n {onDismiss ? (\n <button\n type=\"button\"\n className={styles.dismiss}\n aria-label={dismissLabel}\n onClick={onDismiss}\n >\n <CloseIcon />\n </button>\n ) : null}\n </div>\n )\n})\n"],"mappings":";;;;;;AA6BA,IAAME,IAAsC;CAC1C,MAAM,kBAACC,GAAD,CAAW,CAAA;CACjB,SAAS,kBAACA,GAAD,CAAW,CAAA;CACpB,UAAU,kBAACC,GAAD,CAAkB,CAAA;CAC5B,SAAS,kBAACC,GAAD,CAAc,CAAA;CACvB,UAAU,kBAACC,GAAD,CAAY,CAAA;AACxB,GAqBaC,IAAQC,EAAuC,SAC1D,EACE,UAAO,QACP,aAAU,WACV,UACA,SACA,WACA,cACA,kBAAe,WACf,SACA,cACA,aACA,GAAGC,KAEL,GACA;CACA,IAAMC,IAAUC,EAAM,GAChBC,IAAQC,MAAS,KAAA,IAAYX,EAAMY,KAAQD;CACjD,OACE,kBAAC,OAAD;EACO;EACL,MAAME,MAASD,MAAS,cAAcA,MAAS,YAAY,UAAU;EACrE,mBAAiBE,IAAQN,IAAU,KAAA;EACnC,WAAWO,EAAGjB,EAAO,OAAOkB,CAAS;EACrC,uBAAoB;EACpB,aAAWJ;EACX,gBAAcK;EACd,oBAAkBC,IAAY,KAAK,KAAA;EACnC,GAAIX;EATN,UAAA;GAWGG,IACC,kBAAC,QAAD;IAAM,WAAWZ,EAAO;IAAO,eAAY;IACxC,UAAAY;GACG,CAAA,IACJ;GACJ,kBAAC,OAAD;IAAK,WAAWZ,EAAO;IAAvB,UAAA;KACGgB,IACC,kBAAC,KAAD;MAAG,IAAIN;MAAS,WAAWV,EAAO;MAC/B,UAAAgB;KACA,CAAA,IACD;KACHK,IAAW,kBAAC,OAAD;MAAK,WAAWrB,EAAO;MAAc;KAAc,CAAA,IAAI;KAClEsB,IAAS,kBAAC,OAAD;MAAK,WAAWtB,EAAO;MAAS,UAAAsB;KAAY,CAAA,IAAI;IACvD;;GACJF,IACC,kBAAC,UAAD;IACE,MAAK;IACL,WAAWpB,EAAO;IAClB,cAAYuB;IACZ,SAASH;IAET,UAAA,kBAACI,GAAD,CAAY,CAAA;GACN,CAAA,IACN;EACD;;AAET,CAAC"}
@@ -13,6 +13,13 @@ export interface LiveIndicatorProps extends HTMLAttributes<HTMLSpanElement> {
13
13
  size?: Exclude<Size, 'lg'>;
14
14
  }
15
15
  /**
16
+ * This is happening now. A dot with a slow ring and a short label.
17
+ *
18
+ * @remarks
19
+ * `LiveIndicator` marks something in progress: live tracking, a sync, a recording. The ring pulses
20
+ * slowly and stops under reduced motion.
21
+ *
22
+ * @privateRemarks
16
23
  * "This is happening now." A dot with a slow ring and a short label — for a live call,
17
24
  * an in-progress sync, a recording.
18
25
  *
@@ -1 +1 @@
1
- {"version":3,"file":"LiveIndicator.js","names":["styles","LiveIndicator_module_default","LiveIndicator","forwardRef","rest","cx","className","tone","variant","size","pulse","label"],"sources":["../../../../src/components/feedback/LiveIndicator/LiveIndicator.tsx"],"sourcesContent":["import { forwardRef, type HTMLAttributes, type ReactNode } from 'react'\nimport { cx } from '#utils/cx'\nimport type { Size, Tone } from '#utils/tokens'\nimport styles from './LiveIndicator.module.css'\n\nexport type LiveIndicatorVariant = 'inline' | 'pill'\n\nexport interface LiveIndicatorProps extends HTMLAttributes<HTMLSpanElement> {\n /** What's live, or how far in: \"Live\", \"72'\", \"Recording\". Default \"Live\". */\n label?: ReactNode\n /** Colour of the dot (and the label in `inline`). Default `accent` — live *is* the accent's job. */\n tone?: Tone\n /** A ring that swells out of the dot. Stills under reduced motion. Default `true`. */\n pulse?: boolean\n /** `inline` sits in running text; `pill` is a keylined chip for cards and list rows. */\n variant?: LiveIndicatorVariant\n size?: Exclude<Size, 'lg'>\n}\n\n/**\n * \"This is happening now.\" A dot with a slow ring and a short label — for a live call,\n * an in-progress sync, a recording.\n *\n * Deliberately not a live region: a minute counter that announces itself every minute is\n * noise. If the change matters, announce it where it happens.\n */\nexport const LiveIndicator = forwardRef<HTMLSpanElement, LiveIndicatorProps>(function LiveIndicator(\n {\n label = 'Live',\n tone = 'accent',\n pulse = true,\n variant = 'inline',\n size = 'md',\n className,\n ...rest\n },\n ref,\n) {\n return (\n <span\n ref={ref}\n className={cx(styles.live, className)}\n data-tone={tone}\n data-variant={variant}\n data-size={size}\n data-pulse={pulse || undefined}\n {...rest}\n >\n <span className={styles.dot} aria-hidden=\"true\" />\n <span className={styles.label}>{label}</span>\n </span>\n )\n})\n"],"mappings":";;;;;AA0BA,IAAaE,IAAgBC,EAAgD,SAC3E,EACE,WAAQ,QACR,UAAO,UACP,WAAQ,IACR,aAAU,UACV,UAAO,MACP,cACA,GAAGC,KAEL,GACA;CACA,OACE,kBAAC,QAAD;EACO;EACL,WAAWC,EAAGL,EAAO,MAAMM,CAAS;EACpC,aAAWC;EACX,gBAAcC;EACd,aAAWC;EACX,cAAYC,KAAS,KAAA;EACrB,GAAIN;EAPN,UAAA,CASE,kBAAC,QAAD;GAAM,WAAWJ,EAAO;GAAK,eAAY;EAAQ,CAAA,GACjD,kBAAC,QAAD;GAAM,WAAWA,EAAO;GAAQ,UAAAW;EAAY,CAAA,CACxC;;AAEV,CAAC"}
1
+ {"version":3,"file":"LiveIndicator.js","names":["styles","LiveIndicator_module_default","LiveIndicator","forwardRef","rest","cx","className","tone","variant","size","pulse","label"],"sources":["../../../../src/components/feedback/LiveIndicator/LiveIndicator.tsx"],"sourcesContent":["import { forwardRef, type HTMLAttributes, type ReactNode } from 'react'\nimport { cx } from '#utils/cx'\nimport type { Size, Tone } from '#utils/tokens'\nimport styles from './LiveIndicator.module.css'\n\nexport type LiveIndicatorVariant = 'inline' | 'pill'\n\nexport interface LiveIndicatorProps extends HTMLAttributes<HTMLSpanElement> {\n /** What's live, or how far in: \"Live\", \"72'\", \"Recording\". Default \"Live\". */\n label?: ReactNode\n /** Colour of the dot (and the label in `inline`). Default `accent` — live *is* the accent's job. */\n tone?: Tone\n /** A ring that swells out of the dot. Stills under reduced motion. Default `true`. */\n pulse?: boolean\n /** `inline` sits in running text; `pill` is a keylined chip for cards and list rows. */\n variant?: LiveIndicatorVariant\n size?: Exclude<Size, 'lg'>\n}\n\n/**\n * This is happening now. A dot with a slow ring and a short label.\n *\n * @remarks\n * `LiveIndicator` marks something in progress: live tracking, a sync, a recording. The ring pulses\n * slowly and stops under reduced motion.\n *\n * @privateRemarks\n * \"This is happening now.\" A dot with a slow ring and a short label — for a live call,\n * an in-progress sync, a recording.\n *\n * Deliberately not a live region: a minute counter that announces itself every minute is\n * noise. If the change matters, announce it where it happens.\n */\nexport const LiveIndicator = forwardRef<HTMLSpanElement, LiveIndicatorProps>(function LiveIndicator(\n {\n label = 'Live',\n tone = 'accent',\n pulse = true,\n variant = 'inline',\n size = 'md',\n className,\n ...rest\n },\n ref,\n) {\n return (\n <span\n ref={ref}\n className={cx(styles.live, className)}\n data-tone={tone}\n data-variant={variant}\n data-size={size}\n data-pulse={pulse || undefined}\n {...rest}\n >\n <span className={styles.dot} aria-hidden=\"true\" />\n <span className={styles.label}>{label}</span>\n </span>\n )\n})\n"],"mappings":";;;;;AAiCA,IAAaE,IAAgBC,EAAgD,SAC3E,EACE,WAAQ,QACR,UAAO,UACP,WAAQ,IACR,aAAU,UACV,UAAO,MACP,cACA,GAAGC,KAEL,GACA;CACA,OACE,kBAAC,QAAD;EACO;EACL,WAAWC,EAAGL,EAAO,MAAMM,CAAS;EACpC,aAAWC;EACX,gBAAcC;EACd,aAAWC;EACX,cAAYC,KAAS,KAAA;EACrB,GAAIN;EAPN,UAAA,CASE,kBAAC,QAAD;GAAM,WAAWJ,EAAO;GAAK,eAAY;EAAQ,CAAA,GACjD,kBAAC,QAAD;GAAM,WAAWA,EAAO;GAAQ,UAAAW;EAAY,CAAA,CACxC;;AAEV,CAAC"}
@@ -13,6 +13,14 @@ export interface RelativeTimeProps extends Omit<TimeHTMLAttributes<HTMLTimeEleme
13
13
  prefix?: ReactNode;
14
14
  }
15
15
  /**
16
+ * How long ago, or how long until. A time element that keeps itself current and renders safely on
17
+ * the server.
18
+ *
19
+ * @remarks
20
+ * `RelativeTime` renders a `<time>` that reads "3 mins ago" or "in 2 hours", and updates itself
21
+ * (every 30 seconds by default). The full date is always in its `title`.
22
+ *
23
+ * @privateRemarks
16
24
  * A `<time>` that says how long ago (or until) something happened, and keeps itself current.
17
25
  *
18
26
  * SSR: the server and the first client render show the absolute date (no clock is read
@@ -1 +1 @@
1
- {"version":3,"file":"RelativeTime.js","names":["styles","RelativeTime_module_default","RelativeTime","forwardRef","rest","now","setNow","useState","updateInterval","id","d","toDate","date","valid","absolute","formatAbsoluteTime","locale","text","formatRelativeTime","format","title","prefix"],"sources":["../../../../src/components/feedback/RelativeTime/RelativeTime.tsx"],"sourcesContent":["import { forwardRef, useEffect, useState, type ReactNode, type TimeHTMLAttributes } from 'react'\nimport { formatAbsoluteTime, formatRelativeTime, toDate, type RelativeTimeStyle } from './format'\nimport styles from './RelativeTime.module.css'\n\nexport interface RelativeTimeProps extends Omit<\n TimeHTMLAttributes<HTMLTimeElement>,\n 'dateTime' | 'children' | 'prefix'\n> {\n /** The moment to describe. Anything `new Date()` accepts. */\n date: Date | string | number\n /** BCP 47 locale. Default `en-AU`. */\n locale?: string\n /** Wording length: \"3 minutes ago\" (`long`), \"3 mins ago\" (`short`, default), `narrow`. */\n format?: RelativeTimeStyle\n /** Re-render every N ms so the text stays true. `0` disables. Default 30 000. */\n updateInterval?: number\n /** Text before the time, e.g. \"Updated\". A space is added for you. */\n prefix?: ReactNode\n}\n\n/**\n * A `<time>` that says how long ago (or until) something happened, and keeps itself current.\n *\n * SSR: the server and the first client render show the absolute date (no clock is read\n * during render, so hydration can't disagree about \"now\"); the relative wording appears\n * once mounted. The absolute date stays available as the `title`.\n *\n * <RelativeTime date={fetchedAt} prefix=\"Updated\" />\n */\nexport const RelativeTime = forwardRef<HTMLTimeElement, RelativeTimeProps>(function RelativeTime(\n {\n date,\n locale = 'en-AU',\n format = 'short',\n updateInterval = 30_000,\n prefix,\n title,\n className,\n ...rest\n },\n ref,\n) {\n const [now, setNow] = useState<number | null>(null)\n\n useEffect(() => {\n setNow(Date.now())\n if (!updateInterval) return\n const id = setInterval(() => {\n setNow(Date.now())\n }, updateInterval)\n return () => {\n clearInterval(id)\n }\n }, [updateInterval])\n\n const d = toDate(date)\n const valid = !Number.isNaN(d.getTime())\n const absolute = valid ? formatAbsoluteTime(d, locale) : ''\n const text = !valid ? '' : now === null ? absolute : formatRelativeTime(d, now, locale, format)\n\n return (\n <time\n ref={ref}\n dateTime={valid ? d.toISOString() : undefined}\n title={title ?? absolute}\n className={className}\n suppressHydrationWarning\n {...rest}\n >\n {prefix ? <span className={styles.prefix}>{prefix} </span> : null}\n {/* Server renders the absolute date in its timezone; the client re-renders relative text on mount. */}\n <span className={styles.value} suppressHydrationWarning>\n {text}\n </span>\n </time>\n )\n})\n"],"mappings":";;;;;AA6BA,IAAaE,IAAeC,EAA+C,SACzE,EACE,SACA,YAAS,SACT,YAAS,SACT,oBAAiB,KACjB,WACA,UACA,cACA,GAAGC,KAEL,GACA;CACA,IAAM,CAACC,GAAKC,KAAUC,EAAwB,IAAI;CAElD,QAAgB;EAEd,IADAD,EAAO,KAAK,IAAI,CAAC,GACb,CAACE,GAAgB;EACrB,IAAMC,IAAK,kBAAkB;GAC3B,EAAO,KAAK,IAAI,CAAC;EACnB,GAAGD,CAAc;EACjB,aAAa;GACX,cAAcC,CAAE;EAClB;CACF,GAAG,CAACD,CAAc,CAAC;CAEnB,IAAME,IAAIC,EAAOC,CAAI,GACfC,IAAQ,CAAC,OAAO,MAAMH,EAAE,QAAQ,CAAC,GACjCI,IAAWD,IAAQE,EAAmBL,GAAGM,CAAM,IAAI,IACnDC,IAAQJ,IAAaR,MAAQ,OAAOS,IAAWI,EAAmBR,GAAGL,GAAKW,GAAQG,CAAM,IAAxE;CAEtB,OACE,kBAAC,QAAD;EACO;EACL,UAAUN,IAAQH,EAAE,YAAY,IAAI,KAAA;EACpC,OAAOU,KAASN;EACL;EACX,0BAAA;EACA,GAAIV;EANN,UAAA,CAQGiB,IAAS,kBAAC,QAAD;GAAM,WAAWrB,EAAO;GAAxB,UAAA,CAAiCqB,GAAO,GAAO;EAAI,CAAA,IAAA,MAE7D,kBAAC,QAAD;GAAM,WAAWrB,EAAO;GAAO,0BAAA;GAC5B,UAAAiB;EACG,CAAA,CACF;;AAEV,CAAC"}
1
+ {"version":3,"file":"RelativeTime.js","names":["styles","RelativeTime_module_default","RelativeTime","forwardRef","rest","now","setNow","useState","updateInterval","id","d","toDate","date","valid","absolute","formatAbsoluteTime","locale","text","formatRelativeTime","format","title","prefix"],"sources":["../../../../src/components/feedback/RelativeTime/RelativeTime.tsx"],"sourcesContent":["import { forwardRef, useEffect, useState, type ReactNode, type TimeHTMLAttributes } from 'react'\nimport { formatAbsoluteTime, formatRelativeTime, toDate, type RelativeTimeStyle } from './format'\nimport styles from './RelativeTime.module.css'\n\nexport interface RelativeTimeProps extends Omit<\n TimeHTMLAttributes<HTMLTimeElement>,\n 'dateTime' | 'children' | 'prefix'\n> {\n /** The moment to describe. Anything `new Date()` accepts. */\n date: Date | string | number\n /** BCP 47 locale. Default `en-AU`. */\n locale?: string\n /** Wording length: \"3 minutes ago\" (`long`), \"3 mins ago\" (`short`, default), `narrow`. */\n format?: RelativeTimeStyle\n /** Re-render every N ms so the text stays true. `0` disables. Default 30 000. */\n updateInterval?: number\n /** Text before the time, e.g. \"Updated\". A space is added for you. */\n prefix?: ReactNode\n}\n\n/**\n * How long ago, or how long until. A time element that keeps itself current and renders safely on\n * the server.\n *\n * @remarks\n * `RelativeTime` renders a `<time>` that reads \"3 mins ago\" or \"in 2 hours\", and updates itself\n * (every 30 seconds by default). The full date is always in its `title`.\n *\n * @privateRemarks\n * A `<time>` that says how long ago (or until) something happened, and keeps itself current.\n *\n * SSR: the server and the first client render show the absolute date (no clock is read\n * during render, so hydration can't disagree about \"now\"); the relative wording appears\n * once mounted. The absolute date stays available as the `title`.\n *\n * <RelativeTime date={fetchedAt} prefix=\"Updated\" />\n */\nexport const RelativeTime = forwardRef<HTMLTimeElement, RelativeTimeProps>(function RelativeTime(\n {\n date,\n locale = 'en-AU',\n format = 'short',\n updateInterval = 30_000,\n prefix,\n title,\n className,\n ...rest\n },\n ref,\n) {\n const [now, setNow] = useState<number | null>(null)\n\n useEffect(() => {\n setNow(Date.now())\n if (!updateInterval) return\n const id = setInterval(() => {\n setNow(Date.now())\n }, updateInterval)\n return () => {\n clearInterval(id)\n }\n }, [updateInterval])\n\n const d = toDate(date)\n const valid = !Number.isNaN(d.getTime())\n const absolute = valid ? formatAbsoluteTime(d, locale) : ''\n const text = !valid ? '' : now === null ? absolute : formatRelativeTime(d, now, locale, format)\n\n return (\n <time\n ref={ref}\n dateTime={valid ? d.toISOString() : undefined}\n title={title ?? absolute}\n className={className}\n suppressHydrationWarning\n {...rest}\n >\n {prefix ? <span className={styles.prefix}>{prefix} </span> : null}\n {/* Server renders the absolute date in its timezone; the client re-renders relative text on mount. */}\n <span className={styles.value} suppressHydrationWarning>\n {text}\n </span>\n </time>\n )\n})\n"],"mappings":";;;;;AAqCA,IAAaE,IAAeC,EAA+C,SACzE,EACE,SACA,YAAS,SACT,YAAS,SACT,oBAAiB,KACjB,WACA,UACA,cACA,GAAGC,KAEL,GACA;CACA,IAAM,CAACC,GAAKC,KAAUC,EAAwB,IAAI;CAElD,QAAgB;EAEd,IADAD,EAAO,KAAK,IAAI,CAAC,GACb,CAACE,GAAgB;EACrB,IAAMC,IAAK,kBAAkB;GAC3B,EAAO,KAAK,IAAI,CAAC;EACnB,GAAGD,CAAc;EACjB,aAAa;GACX,cAAcC,CAAE;EAClB;CACF,GAAG,CAACD,CAAc,CAAC;CAEnB,IAAME,IAAIC,EAAOC,CAAI,GACfC,IAAQ,CAAC,OAAO,MAAMH,EAAE,QAAQ,CAAC,GACjCI,IAAWD,IAAQE,EAAmBL,GAAGM,CAAM,IAAI,IACnDC,IAAQJ,IAAaR,MAAQ,OAAOS,IAAWI,EAAmBR,GAAGL,GAAKW,GAAQG,CAAM,IAAxE;CAEtB,OACE,kBAAC,QAAD;EACO;EACL,UAAUN,IAAQH,EAAE,YAAY,IAAI,KAAA;EACpC,OAAOU,KAASN;EACL;EACX,0BAAA;EACA,GAAIV;EANN,UAAA,CAQGiB,IAAS,kBAAC,QAAD;GAAM,WAAWrB,EAAO;GAAxB,UAAA,CAAiCqB,GAAO,GAAO;EAAI,CAAA,IAAA,MAE7D,kBAAC,QAAD;GAAM,WAAWrB,EAAO;GAAO,0BAAA;GAC5B,UAAAiB;EACG,CAAA,CACF;;AAEV,CAAC"}
@@ -4,5 +4,14 @@ export interface SpinnerProps extends HTMLAttributes<HTMLSpanElement> {
4
4
  /** Accessible label. Defaults to "Loading". Pass `null` when a parent already announces busy state. */
5
5
  label?: string | null;
6
6
  }
7
- /** Indeterminate progress. Three bars that fill in turn — not the stock rotating ring. */
7
+ /**
8
+ * Indeterminate progress. Three bars that fill in turn, not the stock spinning ring.
9
+ *
10
+ * @remarks
11
+ * `Spinner` says something is happening without saying how long it'll take. It's three bars that
12
+ * fill in turn, and it holds still under reduced motion.
13
+ *
14
+ * @privateRemarks
15
+ * Indeterminate progress. Three bars that fill in turn — not the stock rotating ring.
16
+ */
8
17
  export declare const Spinner: import("react").ForwardRefExoticComponent<SpinnerProps & import("react").RefAttributes<HTMLSpanElement>>;
@@ -1 +1 @@
1
- {"version":3,"file":"Spinner.js","names":["styles","Spinner_module_default","Spinner","forwardRef","rest","cx","className","size","label"],"sources":["../../../../src/components/feedback/Spinner/Spinner.tsx"],"sourcesContent":["import { forwardRef, type HTMLAttributes } from 'react'\nimport { cx } from '#utils/cx'\nimport styles from './Spinner.module.css'\n\nexport interface SpinnerProps extends HTMLAttributes<HTMLSpanElement> {\n size?: 'sm' | 'md' | 'lg' | 'inherit'\n /** Accessible label. Defaults to \"Loading\". Pass `null` when a parent already announces busy state. */\n label?: string | null\n}\n\n/** Indeterminate progress. Three bars that fill in turn — not the stock rotating ring. */\nexport const Spinner = forwardRef<HTMLSpanElement, SpinnerProps>(function Spinner(\n { size = 'inherit', label = 'Loading', className, ...rest },\n ref,\n) {\n return (\n <span\n ref={ref}\n className={cx(styles.root, className)}\n data-size={size}\n role={label ? 'status' : undefined}\n aria-label={label ?? undefined}\n aria-hidden={label ? undefined : true}\n {...rest}\n >\n <span className={styles.bar} />\n <span className={styles.bar} />\n <span className={styles.bar} />\n </span>\n )\n})\n"],"mappings":";;;;;AAWA,IAAaE,IAAUC,EAA0C,SAC/D,EAAE,UAAO,WAAW,WAAQ,WAAW,cAAW,GAAGC,KACrD,GACA;CACA,OACE,kBAAC,QAAD;EACO;EACL,WAAWC,EAAGL,EAAO,MAAMM,CAAS;EACpC,aAAWC;EACX,MAAMC,IAAQ,WAAW,KAAA;EACzB,cAAYA,KAAS,KAAA;EACrB,eAAa,MAAQ,KAAA;EACrB,GAAIJ;EAPN,UAAA;GASE,kBAAC,QAAD,EAAM,WAAWJ,EAAO,IAAM,CAAA;GAC9B,kBAAC,QAAD,EAAM,WAAWA,EAAO,IAAM,CAAA;GAC9B,kBAAC,QAAD,EAAM,WAAWA,EAAO,IAAM,CAAA;EAC1B;;AAEV,CAAC"}
1
+ {"version":3,"file":"Spinner.js","names":["styles","Spinner_module_default","Spinner","forwardRef","rest","cx","className","size","label"],"sources":["../../../../src/components/feedback/Spinner/Spinner.tsx"],"sourcesContent":["import { forwardRef, type HTMLAttributes } from 'react'\nimport { cx } from '#utils/cx'\nimport styles from './Spinner.module.css'\n\nexport interface SpinnerProps extends HTMLAttributes<HTMLSpanElement> {\n size?: 'sm' | 'md' | 'lg' | 'inherit'\n /** Accessible label. Defaults to \"Loading\". Pass `null` when a parent already announces busy state. */\n label?: string | null\n}\n\n/**\n * Indeterminate progress. Three bars that fill in turn, not the stock spinning ring.\n *\n * @remarks\n * `Spinner` says something is happening without saying how long it'll take. It's three bars that\n * fill in turn, and it holds still under reduced motion.\n *\n * @privateRemarks\n * Indeterminate progress. Three bars that fill in turn — not the stock rotating ring.\n */\nexport const Spinner = forwardRef<HTMLSpanElement, SpinnerProps>(function Spinner(\n { size = 'inherit', label = 'Loading', className, ...rest },\n ref,\n) {\n return (\n <span\n ref={ref}\n className={cx(styles.root, className)}\n data-size={size}\n role={label ? 'status' : undefined}\n aria-label={label ?? undefined}\n aria-hidden={label ? undefined : true}\n {...rest}\n >\n <span className={styles.bar} />\n <span className={styles.bar} />\n <span className={styles.bar} />\n </span>\n )\n})\n"],"mappings":";;;;;AAoBA,IAAaE,IAAUC,EAA0C,SAC/D,EAAE,UAAO,WAAW,WAAQ,WAAW,cAAW,GAAGC,KACrD,GACA;CACA,OACE,kBAAC,QAAD;EACO;EACL,WAAWC,EAAGL,EAAO,MAAMM,CAAS;EACpC,aAAWC;EACX,MAAMC,IAAQ,WAAW,KAAA;EACzB,cAAYA,KAAS,KAAA;EACrB,eAAa,MAAQ,KAAA;EACrB,GAAIJ;EAPN,UAAA;GASE,kBAAC,QAAD,EAAM,WAAWJ,EAAO,IAAM,CAAA;GAC9B,kBAAC,QAAD,EAAM,WAAWA,EAAO,IAAM,CAAA;GAC9B,kBAAC,QAAD,EAAM,WAAWA,EAAO,IAAM,CAAA;EAC1B;;AAEV,CAAC"}
@@ -9,5 +9,14 @@ export interface StatusDotProps extends HTMLAttributes<HTMLSpanElement> {
9
9
  labelHidden?: boolean;
10
10
  size?: 'sm' | 'md';
11
11
  }
12
- /** A small static dot plus a label. For states that sit still; for "happening now" use LiveIndicator. */
12
+ /**
13
+ * A small static dot and a label, for states that sit still.
14
+ *
15
+ * @remarks
16
+ * `StatusDot` pairs a tone with a word, so status never depends on colour alone. For "happening
17
+ * now", use a {@link LiveIndicator | LiveIndicator}.
18
+ *
19
+ * @privateRemarks
20
+ * A small static dot plus a label. For states that sit still; for "happening now" use LiveIndicator.
21
+ */
13
22
  export declare const StatusDot: import("react").ForwardRefExoticComponent<StatusDotProps & import("react").RefAttributes<HTMLSpanElement>>;
@@ -1 +1 @@
1
- {"version":3,"file":"StatusDot.js","names":["styles","StatusDot_module_default","StatusDot","forwardRef","rest","cx","className","tone","size","labelHidden","label"],"sources":["../../../../src/components/feedback/StatusDot/StatusDot.tsx"],"sourcesContent":["import { forwardRef, type HTMLAttributes, type ReactNode } from 'react'\nimport { cx } from '#utils/cx'\nimport type { Tone } from '#utils/tokens'\nimport styles from './StatusDot.module.css'\n\nexport interface StatusDotProps extends HTMLAttributes<HTMLSpanElement> {\n /** State colour. Default `neutral`. */\n tone?: Tone\n /** What the colour means: \"Paid\", \"Through to the round of 32\", \"Deploying\". Always required — colour alone is not information. */\n label: ReactNode\n /** Keep the label for screen readers only (e.g. in a dense table with a legend). */\n labelHidden?: boolean\n size?: 'sm' | 'md'\n}\n\n/** A small static dot plus a label. For states that sit still; for \"happening now\" use LiveIndicator. */\nexport const StatusDot = forwardRef<HTMLSpanElement, StatusDotProps>(function StatusDot(\n { tone = 'neutral', label, labelHidden = false, size = 'md', className, ...rest },\n ref,\n) {\n return (\n <span\n ref={ref}\n className={cx(styles.status, className)}\n data-tone={tone}\n data-size={size}\n data-label-hidden={labelHidden || undefined}\n {...rest}\n >\n <span className={styles.dot} aria-hidden=\"true\" />\n <span className={labelHidden ? styles.hidden : styles.label}>{label}</span>\n </span>\n )\n})\n"],"mappings":";;;;;AAgBA,IAAaE,IAAYC,EAA4C,SACnE,EAAE,UAAO,WAAW,UAAO,iBAAc,IAAO,UAAO,MAAM,cAAW,GAAGC,KAC3E,GACA;CACA,OACE,kBAAC,QAAD;EACO;EACL,WAAWC,EAAGL,EAAO,QAAQM,CAAS;EACtC,aAAWC;EACX,aAAWC;EACX,qBAAmBC,KAAe,KAAA;EAClC,GAAIL;EANN,UAAA,CAQE,kBAAC,QAAD;GAAM,WAAWJ,EAAO;GAAK,eAAY;EAAQ,CAAA,GACjD,kBAAC,QAAD;GAAM,WAAWS,IAAcT,EAAO,SAASA,EAAO;GAAQ,UAAAU;EAAY,CAAA,CACtE;;AAEV,CAAC"}
1
+ {"version":3,"file":"StatusDot.js","names":["styles","StatusDot_module_default","StatusDot","forwardRef","rest","cx","className","tone","size","labelHidden","label"],"sources":["../../../../src/components/feedback/StatusDot/StatusDot.tsx"],"sourcesContent":["import { forwardRef, type HTMLAttributes, type ReactNode } from 'react'\nimport { cx } from '#utils/cx'\nimport type { Tone } from '#utils/tokens'\nimport styles from './StatusDot.module.css'\n\nexport interface StatusDotProps extends HTMLAttributes<HTMLSpanElement> {\n /** State colour. Default `neutral`. */\n tone?: Tone\n /** What the colour means: \"Paid\", \"Through to the round of 32\", \"Deploying\". Always required — colour alone is not information. */\n label: ReactNode\n /** Keep the label for screen readers only (e.g. in a dense table with a legend). */\n labelHidden?: boolean\n size?: 'sm' | 'md'\n}\n\n/**\n * A small static dot and a label, for states that sit still.\n *\n * @remarks\n * `StatusDot` pairs a tone with a word, so status never depends on colour alone. For \"happening\n * now\", use a {@link LiveIndicator | LiveIndicator}.\n *\n * @privateRemarks\n * A small static dot plus a label. For states that sit still; for \"happening now\" use LiveIndicator.\n */\nexport const StatusDot = forwardRef<HTMLSpanElement, StatusDotProps>(function StatusDot(\n { tone = 'neutral', label, labelHidden = false, size = 'md', className, ...rest },\n ref,\n) {\n return (\n <span\n ref={ref}\n className={cx(styles.status, className)}\n data-tone={tone}\n data-size={size}\n data-label-hidden={labelHidden || undefined}\n {...rest}\n >\n <span className={styles.dot} aria-hidden=\"true\" />\n <span className={labelHidden ? styles.hidden : styles.label}>{label}</span>\n </span>\n )\n})\n"],"mappings":";;;;;AAyBA,IAAaE,IAAYC,EAA4C,SACnE,EAAE,UAAO,WAAW,UAAO,iBAAc,IAAO,UAAO,MAAM,cAAW,GAAGC,KAC3E,GACA;CACA,OACE,kBAAC,QAAD;EACO;EACL,WAAWC,EAAGL,EAAO,QAAQM,CAAS;EACtC,aAAWC;EACX,aAAWC;EACX,qBAAmBC,KAAe,KAAA;EAClC,GAAIL;EANN,UAAA,CAQE,kBAAC,QAAD;GAAM,WAAWJ,EAAO;GAAK,eAAY;EAAQ,CAAA,GACjD,kBAAC,QAAD;GAAM,WAAWS,IAAcT,EAAO,SAASA,EAAO;GAAQ,UAAAU;EAAY,CAAA,CACtE;;AAEV,CAAC"}
@@ -3,6 +3,13 @@ import { type AmountInputProps } from '../AmountInput/index.js';
3
3
  export interface AmountFieldProps extends FieldLabelProps, Omit<AmountInputProps, 'invalid' | keyof FieldLabelProps> {
4
4
  }
5
5
  /**
6
+ * A labelled money input with the currency's decimals and tabular figures.
7
+ *
8
+ * @remarks
9
+ * `AmountField` is a {@link Field | Field} around an {@link AmountInput | AmountInput}. `currency`
10
+ * is required, and sets the decimal places and the symbol.
11
+ *
12
+ * @privateRemarks
6
13
  * Label + AmountInput + description + error. Input props (`currency`, `unit`, `value`…)
7
14
  * and the ref go to the text input; `className`/`style` go to the wrapper.
8
15
  *
@@ -1 +1 @@
1
- {"version":3,"file":"AmountField.js","names":["AmountField","forwardRef","fieldProps","rest","splitFieldLabelProps","props","inputRest","Field","id","AmountInput"],"sources":["../../../../src/components/inputs/AmountField/AmountField.tsx"],"sourcesContent":["import { forwardRef } from 'react'\nimport { Field, type FieldLabelProps } from '#components/inputs/Field'\nimport { AmountInput, type AmountInputProps } from '#components/inputs/AmountInput'\nimport { splitFieldLabelProps } from '#components/inputs/internal/fieldProps'\n\nexport interface AmountFieldProps\n extends FieldLabelProps, Omit<AmountInputProps, 'invalid' | keyof FieldLabelProps> {}\n\n/**\n * Label + AmountInput + description + error. Input props (`currency`, `unit`, `value`…)\n * and the ref go to the text input; `className`/`style` go to the wrapper.\n *\n * <AmountField label=\"Monthly retainer\" currency=\"GBP\" unit=\"minor\" value={retainer} onValueChange={setRetainer} />\n */\nexport const AmountField = forwardRef<HTMLInputElement, AmountFieldProps>(\n function AmountField(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 <AmountInput ref={ref} id={id} disabled={disabled} {...inputRest} />\n </Field>\n )\n },\n)\n"],"mappings":";;;;;;AAcA,IAAaA,IAAcC,EACzB,SAAqB,GAAO,GAAK;CAC/B,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;GAAkB;GAAS;GAAc;GAAU,GAAIH;EAAY,CAAA;CAC9D,CAAA;AAEX,CACF"}
1
+ {"version":3,"file":"AmountField.js","names":["AmountField","forwardRef","fieldProps","rest","splitFieldLabelProps","props","inputRest","Field","id","AmountInput"],"sources":["../../../../src/components/inputs/AmountField/AmountField.tsx"],"sourcesContent":["import { forwardRef } from 'react'\nimport { Field, type FieldLabelProps } from '#components/inputs/Field'\nimport { AmountInput, type AmountInputProps } from '#components/inputs/AmountInput'\nimport { splitFieldLabelProps } from '#components/inputs/internal/fieldProps'\n\nexport interface AmountFieldProps\n extends FieldLabelProps, Omit<AmountInputProps, 'invalid' | keyof FieldLabelProps> {}\n\n/**\n * A labelled money input with the currency's decimals and tabular figures.\n *\n * @remarks\n * `AmountField` is a {@link Field | Field} around an {@link AmountInput | AmountInput}. `currency`\n * is required, and sets the decimal places and the symbol.\n *\n * @privateRemarks\n * Label + AmountInput + description + error. Input props (`currency`, `unit`, `value`…)\n * and the ref go to the text input; `className`/`style` go to the wrapper.\n *\n * <AmountField label=\"Monthly retainer\" currency=\"GBP\" unit=\"minor\" value={retainer} onValueChange={setRetainer} />\n */\nexport const AmountField = forwardRef<HTMLInputElement, AmountFieldProps>(\n function AmountField(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 <AmountInput ref={ref} id={id} disabled={disabled} {...inputRest} />\n </Field>\n )\n },\n)\n"],"mappings":";;;;;;AAqBA,IAAaA,IAAcC,EACzB,SAAqB,GAAO,GAAK;CAC/B,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;GAAkB;GAAS;GAAc;GAAU,GAAIH;EAAY,CAAA;CAC9D,CAAA;AAEX,CACF"}
@@ -28,6 +28,14 @@ export interface AmountInputProps extends Omit<InputProps, 'type' | 'value' | 'd
28
28
  max?: number;
29
29
  }
30
30
  /**
31
+ * Money typed as text, with the currency's decimals, grouped when you leave it.
32
+ *
33
+ * @remarks
34
+ * `AmountInput` is a text box for money, not a spinbutton: arrow keys shouldn't nudge a payment.
35
+ * Its decimal places come from the `currency`, it's tabular and right-aligned like every amount,
36
+ * and it's grouped when blurred ("1,450.00") and raw while focused.
37
+ *
38
+ * @privateRemarks
31
39
  * Money, typed as text (a textbox, not a spinbutton — arrow keys shouldn't nudge an invoice
32
40
  * total). Decimals come from the currency; grouped when blurred ("1,450.00"), raw while
33
41
  * focused ("1450.00"). Tabular and right-aligned like every amount. The ref goes to the
@@ -1 +1 @@
1
- {"version":3,"file":"AmountInput.js","names":["_Fragment","Fragment$1","currencyInfo","format","locale","p","currency","toMinor","unit","value","digits","fromMinor","minor","AmountInput","markFieldAware","forwardRef","valueProp","_min","_max","describedBy","rest","currencyId","useId","field","useResolvedField","useMemo","isControlled","internal","setInternal","useState","defaultValue","focused","setFocused","draft","setDraft","grouped","plain","display","m","raw","parse","parseMinorUnits","text","allowNegative","parsed","setMinor","nextValue","next","onValueChange","commit","handleChange","event","handleFocus","onFocus","handleBlur","onBlur","handleKeyDown","onKeyDown","code","leading","showCurrency","symbol","trailing","Input","joinIds","name"],"sources":["../../../../src/components/inputs/AmountInput/AmountInput.tsx"],"sourcesContent":["import {\n forwardRef,\n useEffect,\n useId,\n useMemo,\n useState,\n type ChangeEvent,\n type FocusEvent,\n type KeyboardEvent,\n} from 'react'\nimport { Input, type InputProps } from '#components/inputs/Input'\nimport { markFieldAware, useResolvedField } from '#components/inputs/internal/FieldContext'\nimport { joinIds } from '#components/inputs/internal/refs'\nimport { parseMinorUnits } from './amountFormat'\n\nexport type AmountUnit = 'major' | 'minor'\nexport type AmountCurrencyDisplay = 'symbol' | 'code' | 'both' | 'none'\n\nexport interface AmountInputProps extends Omit<\n InputProps,\n | 'type'\n | 'value'\n | 'defaultValue'\n | 'onChange'\n | 'numeric'\n | 'leading'\n | 'trailing'\n | 'min'\n | 'max'\n> {\n /** The amount in `unit`s, or `null` when empty. */\n value?: number | null\n defaultValue?: number | null\n /** Called while typing (on every text that parses) and on commit. `null` when cleared. */\n onValueChange?: (value: number | null) => void\n /** ISO 4217 code — sets the symbol and the number of decimals (AUD 2, JPY 0, BHD 3). */\n currency: string\n /** Locale for parsing and formatting. Defaults to the browser's. */\n locale?: string\n /**\n * `major` (default) — dollars as a number (`1450.5`).\n * `minor` — integer cents (`145050`): recommended for money, never a float.\n */\n unit?: AmountUnit\n /** Accept a leading minus (refunds, adjustments). Default `false`. */\n allowNegative?: boolean\n /** `symbol` (default) leads with \"$\"; `code` trails \"AUD\"; `both`; or `none`. */\n showCurrency?: AmountCurrencyDisplay\n /**\n * Bounds, in `unit`s, for form validation. The input never clamps money on its own —\n * a silently changed amount is worse than an error message.\n */\n min?: number\n max?: number\n}\n\ninterface CurrencyInfo {\n digits: number\n symbol: string\n}\n\nfunction currencyInfo(currency: string, locale: string | undefined): CurrencyInfo {\n try {\n const format = new Intl.NumberFormat(locale, { style: 'currency', currency })\n return {\n digits: format.resolvedOptions().maximumFractionDigits ?? 2,\n symbol: format.formatToParts(0).find((p) => p.type === 'currency')?.value ?? currency,\n }\n } catch {\n return { digits: 2, symbol: currency }\n }\n}\n\nconst toMinor = (value: number, unit: AmountUnit, digits: number) =>\n unit === 'minor' ? Math.round(value) : Math.round(Number(`${String(value)}e${String(digits)}`))\nconst fromMinor = (minor: number, unit: AmountUnit, digits: number) =>\n unit === 'minor' ? minor : Number(`${String(minor)}e-${String(digits)}`)\n\n/**\n * Money, typed as text (a textbox, not a spinbutton — arrow keys shouldn't nudge an invoice\n * total). Decimals come from the currency; grouped when blurred (\"1,450.00\"), raw while\n * focused (\"1450.00\"). Tabular and right-aligned like every amount. The ref goes to the\n * text input; `name` is submitted as a plain number in `unit`s.\n *\n * <AmountInput currency=\"AUD\" unit=\"minor\" value={retainerCents} onValueChange={setRetainerCents} />\n */\nexport const AmountInput = markFieldAware(\n forwardRef<HTMLInputElement, AmountInputProps>(function AmountInput(\n {\n value: valueProp,\n defaultValue,\n onValueChange,\n currency,\n locale,\n unit = 'major',\n allowNegative = false,\n showCurrency = 'symbol',\n // Bounds are for forms validation only — never sent to the text input, never clamped.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n min: _min,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n max: _max,\n name,\n form,\n disabled,\n onFocus,\n onBlur,\n onKeyDown,\n 'aria-describedby': describedBy,\n ...rest\n },\n ref,\n ) {\n const currencyId = `${useId()}currency`\n // Only for the hidden input: the visible Input resolves its own Field wiring.\n const field = useResolvedField({ disabled })\n const { digits, symbol } = useMemo(() => currencyInfo(currency, locale), [currency, locale])\n const isControlled = valueProp !== undefined\n const [internal, setInternal] = useState<number | null>(defaultValue ?? null)\n const value = isControlled ? valueProp : internal\n const minor = value == null ? null : toMinor(value, unit, digits)\n const [focused, setFocused] = useState(false)\n const [draft, setDraft] = useState('')\n\n const grouped = useMemo(\n () =>\n new Intl.NumberFormat(locale, {\n minimumFractionDigits: digits,\n maximumFractionDigits: digits,\n }),\n [locale, digits],\n )\n const plain = useMemo(\n () =>\n new Intl.NumberFormat(locale, {\n minimumFractionDigits: digits,\n maximumFractionDigits: digits,\n useGrouping: false,\n }),\n [locale, digits],\n )\n const display = (m: number | null) =>\n m == null ? '' : grouped.format(Number(`${String(m)}e-${String(digits)}`))\n const raw = (m: number | null) =>\n m == null ? '' : plain.format(Number(`${String(m)}e-${String(digits)}`))\n const parse = (text: string) => parseMinorUnits(text, locale, digits, allowNegative)\n\n useEffect(() => {\n if (!focused) return\n const parsed = parse(draft)\n if (parsed !== minor && !(parsed == null && minor == null)) setDraft(raw(minor))\n // eslint-disable-next-line react-hooks/exhaustive-deps -- only react to the value changing\n }, [minor])\n\n const setMinor = (next: number | null) => {\n const nextValue = next == null ? null : fromMinor(next, unit, digits)\n if (!isControlled) setInternal(nextValue)\n if (next !== minor) onValueChange?.(nextValue)\n }\n\n const commit = () => {\n const parsed = parse(draft)\n if (parsed != null && Number.isNaN(parsed)) {\n setDraft(raw(minor))\n return\n }\n setMinor(parsed)\n setDraft(raw(parsed))\n }\n\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\n const text = event.target.value\n setDraft(text)\n const parsed = parse(text)\n if (parsed == null || !Number.isNaN(parsed)) setMinor(parsed)\n }\n\n const handleFocus = (event: FocusEvent<HTMLInputElement>) => {\n setFocused(true)\n setDraft(raw(minor))\n onFocus?.(event)\n }\n\n const handleBlur = (event: FocusEvent<HTMLInputElement>) => {\n commit()\n setFocused(false)\n onBlur?.(event)\n }\n\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n onKeyDown?.(event)\n if (!event.defaultPrevented && event.key === 'Enter') commit()\n }\n\n const code = currency.toUpperCase()\n const leading = showCurrency === 'symbol' || showCurrency === 'both' ? symbol : undefined\n const trailing =\n showCurrency === 'code' || (showCurrency === 'both' && symbol !== code) ? code : undefined\n\n return (\n <>\n <Input\n ref={ref}\n {...rest}\n disabled={disabled}\n numeric\n type=\"text\"\n inputMode={allowNegative ? 'text' : digits === 0 ? 'numeric' : 'decimal'}\n autoComplete=\"off\"\n autoCorrect=\"off\"\n spellCheck={false}\n leading={leading}\n trailing={trailing}\n value={focused ? draft : display(minor)}\n onChange={handleChange}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n form={form}\n aria-describedby={joinIds(describedBy, currencyId)}\n />\n {/* The symbol is decorative in the box; this names the currency for screen readers. */}\n <span id={currencyId} hidden>\n {code}\n </span>\n {/* Disabled like the control it stands for: a disabled control submits nothing. */}\n {name != null ? (\n <input\n type=\"hidden\"\n name={name}\n form={form}\n value={value == null ? '' : String(value)}\n disabled={field.disabled}\n />\n ) : null}\n </>\n )\n }),\n)\n"],"mappings":"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"}
1
+ {"version":3,"file":"AmountInput.js","names":["_Fragment","Fragment$1","currencyInfo","format","locale","p","currency","toMinor","unit","value","digits","fromMinor","minor","AmountInput","markFieldAware","forwardRef","valueProp","_min","_max","describedBy","rest","currencyId","useId","field","useResolvedField","useMemo","isControlled","internal","setInternal","useState","defaultValue","focused","setFocused","draft","setDraft","grouped","plain","display","m","raw","parse","parseMinorUnits","text","allowNegative","parsed","setMinor","nextValue","next","onValueChange","commit","handleChange","event","handleFocus","onFocus","handleBlur","onBlur","handleKeyDown","onKeyDown","code","leading","showCurrency","symbol","trailing","Input","joinIds","name"],"sources":["../../../../src/components/inputs/AmountInput/AmountInput.tsx"],"sourcesContent":["import {\n forwardRef,\n useEffect,\n useId,\n useMemo,\n useState,\n type ChangeEvent,\n type FocusEvent,\n type KeyboardEvent,\n} from 'react'\nimport { Input, type InputProps } from '#components/inputs/Input'\nimport { markFieldAware, useResolvedField } from '#components/inputs/internal/FieldContext'\nimport { joinIds } from '#components/inputs/internal/refs'\nimport { parseMinorUnits } from './amountFormat'\n\nexport type AmountUnit = 'major' | 'minor'\nexport type AmountCurrencyDisplay = 'symbol' | 'code' | 'both' | 'none'\n\nexport interface AmountInputProps extends Omit<\n InputProps,\n | 'type'\n | 'value'\n | 'defaultValue'\n | 'onChange'\n | 'numeric'\n | 'leading'\n | 'trailing'\n | 'min'\n | 'max'\n> {\n /** The amount in `unit`s, or `null` when empty. */\n value?: number | null\n defaultValue?: number | null\n /** Called while typing (on every text that parses) and on commit. `null` when cleared. */\n onValueChange?: (value: number | null) => void\n /** ISO 4217 code — sets the symbol and the number of decimals (AUD 2, JPY 0, BHD 3). */\n currency: string\n /** Locale for parsing and formatting. Defaults to the browser's. */\n locale?: string\n /**\n * `major` (default) — dollars as a number (`1450.5`).\n * `minor` — integer cents (`145050`): recommended for money, never a float.\n */\n unit?: AmountUnit\n /** Accept a leading minus (refunds, adjustments). Default `false`. */\n allowNegative?: boolean\n /** `symbol` (default) leads with \"$\"; `code` trails \"AUD\"; `both`; or `none`. */\n showCurrency?: AmountCurrencyDisplay\n /**\n * Bounds, in `unit`s, for form validation. The input never clamps money on its own —\n * a silently changed amount is worse than an error message.\n */\n min?: number\n max?: number\n}\n\ninterface CurrencyInfo {\n digits: number\n symbol: string\n}\n\nfunction currencyInfo(currency: string, locale: string | undefined): CurrencyInfo {\n try {\n const format = new Intl.NumberFormat(locale, { style: 'currency', currency })\n return {\n digits: format.resolvedOptions().maximumFractionDigits ?? 2,\n symbol: format.formatToParts(0).find((p) => p.type === 'currency')?.value ?? currency,\n }\n } catch {\n return { digits: 2, symbol: currency }\n }\n}\n\nconst toMinor = (value: number, unit: AmountUnit, digits: number) =>\n unit === 'minor' ? Math.round(value) : Math.round(Number(`${String(value)}e${String(digits)}`))\nconst fromMinor = (minor: number, unit: AmountUnit, digits: number) =>\n unit === 'minor' ? minor : Number(`${String(minor)}e-${String(digits)}`)\n\n/**\n * Money typed as text, with the currency's decimals, grouped when you leave it.\n *\n * @remarks\n * `AmountInput` is a text box for money, not a spinbutton: arrow keys shouldn't nudge a payment.\n * Its decimal places come from the `currency`, it's tabular and right-aligned like every amount,\n * and it's grouped when blurred (\"1,450.00\") and raw while focused.\n *\n * @privateRemarks\n * Money, typed as text (a textbox, not a spinbutton — arrow keys shouldn't nudge an invoice\n * total). Decimals come from the currency; grouped when blurred (\"1,450.00\"), raw while\n * focused (\"1450.00\"). Tabular and right-aligned like every amount. The ref goes to the\n * text input; `name` is submitted as a plain number in `unit`s.\n *\n * <AmountInput currency=\"AUD\" unit=\"minor\" value={retainerCents} onValueChange={setRetainerCents} />\n */\nexport const AmountInput = markFieldAware(\n forwardRef<HTMLInputElement, AmountInputProps>(function AmountInput(\n {\n value: valueProp,\n defaultValue,\n onValueChange,\n currency,\n locale,\n unit = 'major',\n allowNegative = false,\n showCurrency = 'symbol',\n // Bounds are for forms validation only — never sent to the text input, never clamped.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n min: _min,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n max: _max,\n name,\n form,\n disabled,\n onFocus,\n onBlur,\n onKeyDown,\n 'aria-describedby': describedBy,\n ...rest\n },\n ref,\n ) {\n const currencyId = `${useId()}currency`\n // Only for the hidden input: the visible Input resolves its own Field wiring.\n const field = useResolvedField({ disabled })\n const { digits, symbol } = useMemo(() => currencyInfo(currency, locale), [currency, locale])\n const isControlled = valueProp !== undefined\n const [internal, setInternal] = useState<number | null>(defaultValue ?? null)\n const value = isControlled ? valueProp : internal\n const minor = value == null ? null : toMinor(value, unit, digits)\n const [focused, setFocused] = useState(false)\n const [draft, setDraft] = useState('')\n\n const grouped = useMemo(\n () =>\n new Intl.NumberFormat(locale, {\n minimumFractionDigits: digits,\n maximumFractionDigits: digits,\n }),\n [locale, digits],\n )\n const plain = useMemo(\n () =>\n new Intl.NumberFormat(locale, {\n minimumFractionDigits: digits,\n maximumFractionDigits: digits,\n useGrouping: false,\n }),\n [locale, digits],\n )\n const display = (m: number | null) =>\n m == null ? '' : grouped.format(Number(`${String(m)}e-${String(digits)}`))\n const raw = (m: number | null) =>\n m == null ? '' : plain.format(Number(`${String(m)}e-${String(digits)}`))\n const parse = (text: string) => parseMinorUnits(text, locale, digits, allowNegative)\n\n useEffect(() => {\n if (!focused) return\n const parsed = parse(draft)\n if (parsed !== minor && !(parsed == null && minor == null)) setDraft(raw(minor))\n // eslint-disable-next-line react-hooks/exhaustive-deps -- only react to the value changing\n }, [minor])\n\n const setMinor = (next: number | null) => {\n const nextValue = next == null ? null : fromMinor(next, unit, digits)\n if (!isControlled) setInternal(nextValue)\n if (next !== minor) onValueChange?.(nextValue)\n }\n\n const commit = () => {\n const parsed = parse(draft)\n if (parsed != null && Number.isNaN(parsed)) {\n setDraft(raw(minor))\n return\n }\n setMinor(parsed)\n setDraft(raw(parsed))\n }\n\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\n const text = event.target.value\n setDraft(text)\n const parsed = parse(text)\n if (parsed == null || !Number.isNaN(parsed)) setMinor(parsed)\n }\n\n const handleFocus = (event: FocusEvent<HTMLInputElement>) => {\n setFocused(true)\n setDraft(raw(minor))\n onFocus?.(event)\n }\n\n const handleBlur = (event: FocusEvent<HTMLInputElement>) => {\n commit()\n setFocused(false)\n onBlur?.(event)\n }\n\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n onKeyDown?.(event)\n if (!event.defaultPrevented && event.key === 'Enter') commit()\n }\n\n const code = currency.toUpperCase()\n const leading = showCurrency === 'symbol' || showCurrency === 'both' ? symbol : undefined\n const trailing =\n showCurrency === 'code' || (showCurrency === 'both' && symbol !== code) ? code : undefined\n\n return (\n <>\n <Input\n ref={ref}\n {...rest}\n disabled={disabled}\n numeric\n type=\"text\"\n inputMode={allowNegative ? 'text' : digits === 0 ? 'numeric' : 'decimal'}\n autoComplete=\"off\"\n autoCorrect=\"off\"\n spellCheck={false}\n leading={leading}\n trailing={trailing}\n value={focused ? draft : display(minor)}\n onChange={handleChange}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n form={form}\n aria-describedby={joinIds(describedBy, currencyId)}\n />\n {/* The symbol is decorative in the box; this names the currency for screen readers. */}\n <span id={currencyId} hidden>\n {code}\n </span>\n {/* Disabled like the control it stands for: a disabled control submits nothing. */}\n {name != null ? (\n <input\n type=\"hidden\"\n name={name}\n form={form}\n value={value == null ? '' : String(value)}\n disabled={field.disabled}\n />\n ) : null}\n </>\n )\n }),\n)\n"],"mappings":"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"}
@@ -10,6 +10,14 @@ export interface CheckboxProps extends Omit<ComponentPropsWithoutRef<typeof Radi
10
10
  readOnly?: boolean;
11
11
  }
12
12
  /**
13
+ * A bare checkbox, including the indeterminate state for "some of these".
14
+ *
15
+ * @remarks
16
+ * `Checkbox` is Radix Checkbox with Kiln's look. `checked` can be `true`, `false` or
17
+ * `'indeterminate'`, for a parent that controls a set where only some are on. It needs a label:
18
+ * use {@link CheckboxField | CheckboxField}, a `Field`, or an `aria-label`.
19
+ *
20
+ * @privateRemarks
13
21
  * A bare checkbox (Radix). `checked` may be `'indeterminate'` for a "some selected"
14
22
  * parent. Needs a label — use `CheckboxField`, a `<Field>`, or `aria-label`.
15
23
  *
@@ -1 +1 @@
1
- {"version":3,"file":"Checkbox.js","names":["Checkbox","RadixCheckbox","styles","Checkbox_module_default","Checkbox$1","markFieldAware","forwardRef","invalidProp","idProp","disabledProp","readOnlyProp","describedByProp","ariaInvalid","rest","field","useResolvedField","Checkbox","cx","className","size","onCheckedChange","CheckIcon","MinusIcon"],"sources":["../../../../src/components/inputs/Checkbox/Checkbox.tsx"],"sourcesContent":["import { forwardRef, type ComponentPropsWithoutRef } from 'react'\nimport { Checkbox as RadixCheckbox } from 'radix-ui'\nimport { CheckIcon, MinusIcon } from '#icons'\nimport { cx } from '#utils/cx'\nimport type { Size } from '#utils/tokens'\nimport { markFieldAware, useResolvedField } from '#components/inputs/internal/FieldContext'\nimport styles from './Checkbox.module.css'\n\nexport type CheckedState = boolean | 'indeterminate'\n\nexport interface CheckboxProps extends Omit<\n ComponentPropsWithoutRef<typeof RadixCheckbox.Root>,\n 'asChild'\n> {\n size?: Size\n /** Critical border + `aria-invalid`. Inside a `<Field error>` this is set for you. */\n invalid?: boolean\n /** Focusable but not editable: sets `aria-readonly` and ignores clicks. */\n readOnly?: boolean\n}\n\n/**\n * A bare checkbox (Radix). `checked` may be `'indeterminate'` for a \"some selected\"\n * parent. Needs a label — use `CheckboxField`, a `<Field>`, or `aria-label`.\n *\n * <Checkbox checked={allPaid ? true : somePaid ? 'indeterminate' : false} onCheckedChange={…} />\n */\nexport const Checkbox = markFieldAware(\n forwardRef<HTMLButtonElement, CheckboxProps>(function Checkbox(\n {\n size = 'md',\n invalid: invalidProp,\n id: idProp,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n onCheckedChange,\n className,\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: invalidProp,\n ariaInvalid,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n })\n return (\n <RadixCheckbox.Root\n ref={ref}\n id={field.id}\n className={cx(styles.checkbox, className)}\n data-size={size}\n data-invalid={field.invalid || undefined}\n data-readonly={field.readOnly || undefined}\n disabled={field.disabled}\n aria-readonly={field.readOnly || undefined}\n aria-describedby={field.describedBy}\n aria-invalid={field.invalid || undefined}\n aria-required={field.required || undefined}\n aria-busy={field.busy || undefined}\n onCheckedChange={field.readOnly ? undefined : onCheckedChange}\n {...rest}\n >\n <RadixCheckbox.Indicator className={styles.indicator}>\n <CheckIcon className={styles.check} />\n <MinusIcon className={styles.dash} />\n </RadixCheckbox.Indicator>\n </RadixCheckbox.Root>\n )\n }),\n)\n"],"mappings":";;;;;;;;AA2BA,IAAaA,IAAWK,EACtBC,EAA6C,SAC3C,EACE,UAAO,MACP,SAASC,GACT,IAAIC,GACJ,UAAUC,GACV,UAAUC,GACV,oBACA,cACA,oBAAoBC,GACpB,gBAAgBC,GAChB,GAAGC,KAEL,GACA;CACA,IAAMC,IAAQC,EAAiB;EAC7B,IAAIP;EACJ,aAAaG;EACb,SAASJ;EACT;EACA,UAAUE;EACV,UAAUC;CACZ,CAAC;CACD,OACE,kBAACT,EAAc,MAAf;EACO;EACL,IAAIa,EAAM;EACV,WAAWG,EAAGf,EAAO,UAAUgB,CAAS;EACxC,aAAWC;EACX,gBAAcL,EAAM,WAAW,KAAA;EAC/B,iBAAeA,EAAM,YAAY,KAAA;EACjC,UAAUA,EAAM;EAChB,iBAAeA,EAAM,YAAY,KAAA;EACjC,oBAAkBA,EAAM;EACxB,gBAAcA,EAAM,WAAW,KAAA;EAC/B,iBAAeA,EAAM,YAAY,KAAA;EACjC,aAAWA,EAAM,QAAQ,KAAA;EACzB,iBAAiBA,EAAM,WAAW,KAAA,IAAYM;EAC9C,GAAIP;EAEJ,UAAA,kBAACZ,EAAc,WAAf;GAAyB,WAAWC,EAAO;GAA3C,UAAA,CACE,kBAACmB,GAAD,EAAW,WAAWnB,EAAO,MAAQ,CAAA,GACrC,kBAACoB,GAAD,EAAW,WAAWpB,EAAO,KAAO,CAAA,CACb;;CACP,CAAA;AAExB,CAAC,CACH"}
1
+ {"version":3,"file":"Checkbox.js","names":["Checkbox","RadixCheckbox","styles","Checkbox_module_default","Checkbox$1","markFieldAware","forwardRef","invalidProp","idProp","disabledProp","readOnlyProp","describedByProp","ariaInvalid","rest","field","useResolvedField","Checkbox","cx","className","size","onCheckedChange","CheckIcon","MinusIcon"],"sources":["../../../../src/components/inputs/Checkbox/Checkbox.tsx"],"sourcesContent":["import { forwardRef, type ComponentPropsWithoutRef } from 'react'\nimport { Checkbox as RadixCheckbox } from 'radix-ui'\nimport { CheckIcon, MinusIcon } from '#icons'\nimport { cx } from '#utils/cx'\nimport type { Size } from '#utils/tokens'\nimport { markFieldAware, useResolvedField } from '#components/inputs/internal/FieldContext'\nimport styles from './Checkbox.module.css'\n\nexport type CheckedState = boolean | 'indeterminate'\n\nexport interface CheckboxProps extends Omit<\n ComponentPropsWithoutRef<typeof RadixCheckbox.Root>,\n 'asChild'\n> {\n size?: Size\n /** Critical border + `aria-invalid`. Inside a `<Field error>` this is set for you. */\n invalid?: boolean\n /** Focusable but not editable: sets `aria-readonly` and ignores clicks. */\n readOnly?: boolean\n}\n\n/**\n * A bare checkbox, including the indeterminate state for \"some of these\".\n *\n * @remarks\n * `Checkbox` is Radix Checkbox with Kiln's look. `checked` can be `true`, `false` or\n * `'indeterminate'`, for a parent that controls a set where only some are on. It needs a label:\n * use {@link CheckboxField | CheckboxField}, a `Field`, or an `aria-label`.\n *\n * @privateRemarks\n * A bare checkbox (Radix). `checked` may be `'indeterminate'` for a \"some selected\"\n * parent. Needs a label — use `CheckboxField`, a `<Field>`, or `aria-label`.\n *\n * <Checkbox checked={allPaid ? true : somePaid ? 'indeterminate' : false} onCheckedChange={…} />\n */\nexport const Checkbox = markFieldAware(\n forwardRef<HTMLButtonElement, CheckboxProps>(function Checkbox(\n {\n size = 'md',\n invalid: invalidProp,\n id: idProp,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n onCheckedChange,\n className,\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: invalidProp,\n ariaInvalid,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n })\n return (\n <RadixCheckbox.Root\n ref={ref}\n id={field.id}\n className={cx(styles.checkbox, className)}\n data-size={size}\n data-invalid={field.invalid || undefined}\n data-readonly={field.readOnly || undefined}\n disabled={field.disabled}\n aria-readonly={field.readOnly || undefined}\n aria-describedby={field.describedBy}\n aria-invalid={field.invalid || undefined}\n aria-required={field.required || undefined}\n aria-busy={field.busy || undefined}\n onCheckedChange={field.readOnly ? undefined : onCheckedChange}\n {...rest}\n >\n <RadixCheckbox.Indicator className={styles.indicator}>\n <CheckIcon className={styles.check} />\n <MinusIcon className={styles.dash} />\n </RadixCheckbox.Indicator>\n </RadixCheckbox.Root>\n )\n }),\n)\n"],"mappings":";;;;;;;;AAmCA,IAAaA,IAAWK,EACtBC,EAA6C,SAC3C,EACE,UAAO,MACP,SAASC,GACT,IAAIC,GACJ,UAAUC,GACV,UAAUC,GACV,oBACA,cACA,oBAAoBC,GACpB,gBAAgBC,GAChB,GAAGC,KAEL,GACA;CACA,IAAMC,IAAQC,EAAiB;EAC7B,IAAIP;EACJ,aAAaG;EACb,SAASJ;EACT;EACA,UAAUE;EACV,UAAUC;CACZ,CAAC;CACD,OACE,kBAACT,EAAc,MAAf;EACO;EACL,IAAIa,EAAM;EACV,WAAWG,EAAGf,EAAO,UAAUgB,CAAS;EACxC,aAAWC;EACX,gBAAcL,EAAM,WAAW,KAAA;EAC/B,iBAAeA,EAAM,YAAY,KAAA;EACjC,UAAUA,EAAM;EAChB,iBAAeA,EAAM,YAAY,KAAA;EACjC,oBAAkBA,EAAM;EACxB,gBAAcA,EAAM,WAAW,KAAA;EAC/B,iBAAeA,EAAM,YAAY,KAAA;EACjC,aAAWA,EAAM,QAAQ,KAAA;EACzB,iBAAiBA,EAAM,WAAW,KAAA,IAAYM;EAC9C,GAAIP;EAEJ,UAAA,kBAACZ,EAAc,WAAf;GAAyB,WAAWC,EAAO;GAA3C,UAAA,CACE,kBAACmB,GAAD,EAAW,WAAWnB,EAAO,MAAQ,CAAA,GACrC,kBAACoB,GAAD,EAAW,WAAWpB,EAAO,KAAO,CAAA,CACb;;CACP,CAAA;AAExB,CAAC,CACH"}
@@ -12,6 +12,13 @@ export interface CheckboxFieldProps extends FieldLabelProps, Omit<CheckboxProps,
12
12
  style?: CSSProperties;
13
13
  }
14
14
  /**
15
+ * A checkbox with its label beside it, optional help underneath and an error line.
16
+ *
17
+ * @remarks
18
+ * `CheckboxField` puts the label to the right of the checkbox, where people look for it, with help
19
+ * and an error underneath. Use it for a single yes or no: consent, a preference.
20
+ *
21
+ * @privateRemarks
15
22
  * A checkbox with its label to the right, optional help underneath and an error line.
16
23
  *
17
24
  * <CheckboxField label="I've read the house rules" error={errors.rules} />
@@ -1 +1 @@
1
- {"version":3,"file":"CheckboxField.js","names":["styles","CheckboxField_module_default","CheckboxField","forwardRef","fieldProps","rest","splitFieldLabelProps","props","idProp","describedByProp","restProps","autoId","useId","id","descriptionId","warningId","errorId","help","description","hint","showErrorMessage","hasErrorMessage","error","errorHidden","showWarning","warning","cx","className","disabled","readOnly","Checkbox","hasError","required","validating","joinIds","onCheckedChange","state","LabelContent","label","FieldDescription","FieldWarning","FieldError","errorLive"],"sources":["../../../../src/components/inputs/CheckboxField/CheckboxField.tsx"],"sourcesContent":["import { forwardRef, useId, type CSSProperties } from 'react'\nimport { cx } from '#utils/cx'\nimport { Checkbox, type CheckboxProps } from '#components/inputs/Checkbox'\nimport type { FieldLabelProps } from '#components/inputs/Field'\nimport { splitFieldLabelProps } from '#components/inputs/internal/fieldProps'\nimport {\n FieldDescription,\n FieldError,\n FieldWarning,\n LabelContent,\n} from '#components/inputs/internal/messages'\nimport { hasError, hasErrorMessage } from '#components/inputs/internal/errors'\nimport { joinIds } from '#components/inputs/internal/refs'\nimport styles from './CheckboxField.module.css'\n\nexport interface CheckboxFieldProps\n extends\n FieldLabelProps,\n Omit<\n CheckboxProps,\n | 'checked'\n | 'defaultChecked'\n | 'onCheckedChange'\n | 'invalid'\n | 'className'\n | 'style'\n | keyof FieldLabelProps\n > {\n /** `'indeterminate'` shows a dash — for a \"select all\" over a partly-selected list. */\n checked?: boolean | 'indeterminate'\n defaultChecked?: boolean | 'indeterminate'\n /** Called with a plain boolean (an indeterminate box becomes `true` when clicked). */\n onCheckedChange?: (checked: boolean) => void\n /** Goes to the wrapper; the ref goes to the checkbox. */\n className?: string\n style?: CSSProperties\n}\n\n/**\n * A checkbox with its label to the right, optional help underneath and an error line.\n *\n * <CheckboxField label=\"I've read the house rules\" error={errors.rules} />\n */\nexport const CheckboxField = forwardRef<HTMLButtonElement, CheckboxFieldProps>(\n function CheckboxField(props, ref) {\n const [fieldProps, rest] = splitFieldLabelProps(props)\n const {\n label,\n description,\n hint,\n error,\n required = false,\n optional,\n warning,\n errorLive = true,\n errorHidden = false,\n validating = false,\n readOnly,\n } = fieldProps\n const {\n onCheckedChange,\n id: idProp,\n disabled,\n className,\n style,\n 'aria-describedby': describedByProp,\n ...restProps\n } = rest\n\n const autoId = useId()\n const id = idProp ?? `${autoId}checkbox`\n const descriptionId = `${id}-description`\n const warningId = `${id}-warning`\n const errorId = `${id}-error`\n const help = description ?? hint\n const showErrorMessage = hasErrorMessage(error) && !errorHidden\n const showWarning = warning != null && !showErrorMessage\n\n return (\n <div\n className={cx(styles.root, className)}\n style={style}\n data-disabled={disabled ? true : undefined}\n data-readonly={readOnly ? true : undefined}\n >\n <span className={styles.slot}>\n <Checkbox\n ref={ref}\n id={id}\n disabled={disabled}\n readOnly={readOnly}\n invalid={hasError(error)}\n aria-required={required || undefined}\n aria-busy={validating || undefined}\n aria-describedby={joinIds(\n describedByProp,\n help != null && descriptionId,\n showWarning && warningId,\n showErrorMessage && errorId,\n )}\n onCheckedChange={\n onCheckedChange\n ? (state) => {\n onCheckedChange(state === true)\n }\n : undefined\n }\n {...restProps}\n />\n </span>\n <div className={styles.text}>\n <label htmlFor={id} className={styles.label}>\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 {showWarning ? (\n <FieldWarning id={warningId} className={styles.error}>\n {warning}\n </FieldWarning>\n ) : null}\n {showErrorMessage ? (\n <FieldError id={errorId} className={styles.error} live={errorLive}>\n {error}\n </FieldError>\n ) : null}\n </div>\n )\n },\n)\n"],"mappings":";;;;;;;;;;AA2CA,IAAaE,IAAgBC,EAC3B,SAAuB,GAAO,GAAK;CACjC,IAAM,CAACC,GAAYC,KAAQC,EAAqBC,CAAK,GAC/C,EACJ,UACA,gBACA,SACA,UACA,cAAW,IACX,aACA,YACA,eAAY,IACZ,iBAAc,IACd,gBAAa,IACb,gBACEH,GACE,EACJ,oBACA,IAAII,GACJ,aACA,cACA,UACA,oBAAoBC,GACpB,GAAGC,MACDL,GAEEM,IAASC,EAAM,GACfC,IAAKL,KAAU,GAAGG,EAAO,WACzBG,IAAgB,GAAGD,EAAG,eACtBE,IAAY,GAAGF,EAAG,WAClBG,IAAU,GAAGH,EAAG,SAChBI,IAAOC,KAAeC,GACtBC,IAAmBC,EAAgBC,CAAK,KAAK,CAACC,GAC9CC,IAAcC,KAAW,QAAQ,CAACL;CAExC,OACE,kBAAC,OAAD;EACE,WAAWM,EAAG1B,EAAO,MAAM2B,CAAS;EAC7B;EACP,iBAAeC,IAAW,KAAO,KAAA;EACjC,iBAAeC,IAAW,KAAO,KAAA;EAJnC,UAAA;GAME,kBAAC,QAAD;IAAM,WAAW7B,EAAO;IACtB,UAAA,kBAAC8B,GAAD;KACO;KACD;KACM;KACA;KACV,SAASC,EAAST,CAAK;KACvB,iBAAeU,KAAY,KAAA;KAC3B,aAAWC,KAAc,KAAA;KACzB,oBAAkBC,EAChBzB,GACAQ,KAAQ,QAAQH,GAChBU,KAAeT,GACfK,KAAoBJ,CACtB;KACA,iBACEmB,KACK,MAAU;MACT,EAAgBC,MAAU,EAAI;KAChC,IACA,KAAA;KAEN,GAAI1B;IACL,CAAA;GACG,CAAA;GACN,kBAAC,OAAD;IAAK,WAAWV,EAAO;IAAvB,UAAA,CACE,kBAAC,SAAD;KAAO,SAASa;KAAI,WAAWb,EAAO;KACpC,UAAA,kBAACqC,GAAD;MAAwB;MAAoB;MAAU,MAAMJ;MACzD,UAAAK;KACW,CAAA;IACT,CAAA,GACNrB,KAAQ,OAAwE,OAAjE,kBAACsB,GAAD;KAAkB,IAAIzB;KAAgB,UAAAG;IAAuB,CAAA,CAC1E;;GACJO,IACC,kBAACgB,GAAD;IAAc,IAAIzB;IAAW,WAAWf,EAAO;IAC5C,UAAAyB;GACW,CAAA,IACZ;GACHL,IACC,kBAACqB,GAAD;IAAY,IAAIzB;IAAS,WAAWhB,EAAO;IAAO,MAAM0C;IACrD,UAAApB;GACS,CAAA,IACV;EACD;;AAET,CACF"}
1
+ {"version":3,"file":"CheckboxField.js","names":["styles","CheckboxField_module_default","CheckboxField","forwardRef","fieldProps","rest","splitFieldLabelProps","props","idProp","describedByProp","restProps","autoId","useId","id","descriptionId","warningId","errorId","help","description","hint","showErrorMessage","hasErrorMessage","error","errorHidden","showWarning","warning","cx","className","disabled","readOnly","Checkbox","hasError","required","validating","joinIds","onCheckedChange","state","LabelContent","label","FieldDescription","FieldWarning","FieldError","errorLive"],"sources":["../../../../src/components/inputs/CheckboxField/CheckboxField.tsx"],"sourcesContent":["import { forwardRef, useId, type CSSProperties } from 'react'\nimport { cx } from '#utils/cx'\nimport { Checkbox, type CheckboxProps } from '#components/inputs/Checkbox'\nimport type { FieldLabelProps } from '#components/inputs/Field'\nimport { splitFieldLabelProps } from '#components/inputs/internal/fieldProps'\nimport {\n FieldDescription,\n FieldError,\n FieldWarning,\n LabelContent,\n} from '#components/inputs/internal/messages'\nimport { hasError, hasErrorMessage } from '#components/inputs/internal/errors'\nimport { joinIds } from '#components/inputs/internal/refs'\nimport styles from './CheckboxField.module.css'\n\nexport interface CheckboxFieldProps\n extends\n FieldLabelProps,\n Omit<\n CheckboxProps,\n | 'checked'\n | 'defaultChecked'\n | 'onCheckedChange'\n | 'invalid'\n | 'className'\n | 'style'\n | keyof FieldLabelProps\n > {\n /** `'indeterminate'` shows a dash — for a \"select all\" over a partly-selected list. */\n checked?: boolean | 'indeterminate'\n defaultChecked?: boolean | 'indeterminate'\n /** Called with a plain boolean (an indeterminate box becomes `true` when clicked). */\n onCheckedChange?: (checked: boolean) => void\n /** Goes to the wrapper; the ref goes to the checkbox. */\n className?: string\n style?: CSSProperties\n}\n\n/**\n * A checkbox with its label beside it, optional help underneath and an error line.\n *\n * @remarks\n * `CheckboxField` puts the label to the right of the checkbox, where people look for it, with help\n * and an error underneath. Use it for a single yes or no: consent, a preference.\n *\n * @privateRemarks\n * A checkbox with its label to the right, optional help underneath and an error line.\n *\n * <CheckboxField label=\"I've read the house rules\" error={errors.rules} />\n */\nexport const CheckboxField = forwardRef<HTMLButtonElement, CheckboxFieldProps>(\n function CheckboxField(props, ref) {\n const [fieldProps, rest] = splitFieldLabelProps(props)\n const {\n label,\n description,\n hint,\n error,\n required = false,\n optional,\n warning,\n errorLive = true,\n errorHidden = false,\n validating = false,\n readOnly,\n } = fieldProps\n const {\n onCheckedChange,\n id: idProp,\n disabled,\n className,\n style,\n 'aria-describedby': describedByProp,\n ...restProps\n } = rest\n\n const autoId = useId()\n const id = idProp ?? `${autoId}checkbox`\n const descriptionId = `${id}-description`\n const warningId = `${id}-warning`\n const errorId = `${id}-error`\n const help = description ?? hint\n const showErrorMessage = hasErrorMessage(error) && !errorHidden\n const showWarning = warning != null && !showErrorMessage\n\n return (\n <div\n className={cx(styles.root, className)}\n style={style}\n data-disabled={disabled ? true : undefined}\n data-readonly={readOnly ? true : undefined}\n >\n <span className={styles.slot}>\n <Checkbox\n ref={ref}\n id={id}\n disabled={disabled}\n readOnly={readOnly}\n invalid={hasError(error)}\n aria-required={required || undefined}\n aria-busy={validating || undefined}\n aria-describedby={joinIds(\n describedByProp,\n help != null && descriptionId,\n showWarning && warningId,\n showErrorMessage && errorId,\n )}\n onCheckedChange={\n onCheckedChange\n ? (state) => {\n onCheckedChange(state === true)\n }\n : undefined\n }\n {...restProps}\n />\n </span>\n <div className={styles.text}>\n <label htmlFor={id} className={styles.label}>\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 {showWarning ? (\n <FieldWarning id={warningId} className={styles.error}>\n {warning}\n </FieldWarning>\n ) : null}\n {showErrorMessage ? (\n <FieldError id={errorId} className={styles.error} live={errorLive}>\n {error}\n </FieldError>\n ) : null}\n </div>\n )\n },\n)\n"],"mappings":";;;;;;;;;;AAkDA,IAAaE,IAAgBC,EAC3B,SAAuB,GAAO,GAAK;CACjC,IAAM,CAACC,GAAYC,KAAQC,EAAqBC,CAAK,GAC/C,EACJ,UACA,gBACA,SACA,UACA,cAAW,IACX,aACA,YACA,eAAY,IACZ,iBAAc,IACd,gBAAa,IACb,gBACEH,GACE,EACJ,oBACA,IAAII,GACJ,aACA,cACA,UACA,oBAAoBC,GACpB,GAAGC,MACDL,GAEEM,IAASC,EAAM,GACfC,IAAKL,KAAU,GAAGG,EAAO,WACzBG,IAAgB,GAAGD,EAAG,eACtBE,IAAY,GAAGF,EAAG,WAClBG,IAAU,GAAGH,EAAG,SAChBI,IAAOC,KAAeC,GACtBC,IAAmBC,EAAgBC,CAAK,KAAK,CAACC,GAC9CC,IAAcC,KAAW,QAAQ,CAACL;CAExC,OACE,kBAAC,OAAD;EACE,WAAWM,EAAG1B,EAAO,MAAM2B,CAAS;EAC7B;EACP,iBAAeC,IAAW,KAAO,KAAA;EACjC,iBAAeC,IAAW,KAAO,KAAA;EAJnC,UAAA;GAME,kBAAC,QAAD;IAAM,WAAW7B,EAAO;IACtB,UAAA,kBAAC8B,GAAD;KACO;KACD;KACM;KACA;KACV,SAASC,EAAST,CAAK;KACvB,iBAAeU,KAAY,KAAA;KAC3B,aAAWC,KAAc,KAAA;KACzB,oBAAkBC,EAChBzB,GACAQ,KAAQ,QAAQH,GAChBU,KAAeT,GACfK,KAAoBJ,CACtB;KACA,iBACEmB,KACK,MAAU;MACT,EAAgBC,MAAU,EAAI;KAChC,IACA,KAAA;KAEN,GAAI1B;IACL,CAAA;GACG,CAAA;GACN,kBAAC,OAAD;IAAK,WAAWV,EAAO;IAAvB,UAAA,CACE,kBAAC,SAAD;KAAO,SAASa;KAAI,WAAWb,EAAO;KACpC,UAAA,kBAACqC,GAAD;MAAwB;MAAoB;MAAU,MAAMJ;MACzD,UAAAK;KACW,CAAA;IACT,CAAA,GACNrB,KAAQ,OAAwE,OAAjE,kBAACsB,GAAD;KAAkB,IAAIzB;KAAgB,UAAAG;IAAuB,CAAA,CAC1E;;GACJO,IACC,kBAACgB,GAAD;IAAc,IAAIzB;IAAW,WAAWf,EAAO;IAC5C,UAAAyB;GACW,CAAA,IACZ;GACHL,IACC,kBAACqB,GAAD;IAAY,IAAIzB;IAAS,WAAWhB,EAAO;IAAO,MAAM0C;IACrD,UAAApB;GACS,CAAA,IACV;EACD;;AAET,CACF"}
@@ -37,6 +37,14 @@ export interface CheckboxGroupItemProps {
37
37
  }
38
38
  /** One option. Must be a direct child of `CheckboxGroup` (so "select all" can count it). */
39
39
  declare function CheckboxGroupItem({ value, label, description, disabled, id, className, }: CheckboxGroupItemProps): import("react").JSX.Element;
40
+ /**
41
+ * Several choices from a set, as checkboxes, with an optional select-all.
42
+ *
43
+ * @remarks
44
+ * `CheckboxGroup` lays out a set of checkboxes from `options` (or `CheckboxGroup.Item` children)
45
+ * and holds their values as one array. `selectAllLabel` adds a parent checkbox that goes
46
+ * indeterminate when only some are chosen. `columns` lays a long set out in a responsive grid.
47
+ */
40
48
  export declare const CheckboxGroup: import("react").ForwardRefExoticComponent<CheckboxGroupProps & import("react").RefAttributes<HTMLDivElement>> & {
41
49
  Item: typeof CheckboxGroupItem;
42
50
  };
@@ -1 +1 @@
1
- {"version":3,"file":"CheckboxGroup.js","names":["styles","messageStyles","messages_module_default","CheckboxGroup_module_default","GroupContext","createContext","ItemView","idProp","autoId","useId","id","descriptionId","cx","className","disabled","select","Checkbox","description","state","label","CheckboxGroupItem","group","useContext","value","checked","childOptions","found","Children","children","isValidElement","child","tracks","n","EMPTY","CheckboxGroupRoot","forwardRef","valueProp","disabledProp","readOnlyProp","invalidProp","describedByProp","ariaInvalid","labelledByProp","rest","field","useResolvedField","values","setValues","useControllableValue","defaultValue","onValueChange","next","handleBlur","useFocusLeave","onBlur","all","useMemo","options","o","toggle","useCallback","v","x","order","ia","a","ib","b","context","size","selectAll","selectAllLabel","enabled","checkedCount","locked","layout","columns","orientation","mergeStyles","responsiveVars","style","FieldContext","hiddenInputs","name","CheckboxGroup","markFieldAware"],"sources":["../../../../src/components/inputs/CheckboxGroup/CheckboxGroup.tsx"],"sourcesContent":["import {\n Children,\n createContext,\n forwardRef,\n isValidElement,\n useCallback,\n useContext,\n useId,\n useMemo,\n type HTMLAttributes,\n type ReactNode,\n} from 'react'\nimport { cx } from '#utils/cx'\nimport { mergeStyles, responsiveVars, type Responsive } from '#utils/responsive'\nimport type { Size } from '#utils/tokens'\nimport { Checkbox } from '#components/inputs/Checkbox'\nimport {\n FieldContext,\n markFieldAware,\n useResolvedField,\n} from '#components/inputs/internal/FieldContext'\nimport messageStyles from '#components/inputs/internal/messages.module.css'\nimport { hiddenInputs, useControllableValue, useFocusLeave, type ChoiceOption } from './choice'\nimport styles from './CheckboxGroup.module.css'\n\nexport type CheckboxGroupColumns = 1 | 2 | 3\n\nexport interface CheckboxGroupProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n 'onChange' | 'defaultValue'\n> {\n /** Options as data. Alternatively pass `<CheckboxGroup.Item>` children. */\n options?: readonly ChoiceOption[]\n children?: ReactNode\n /** Controlled checked values. */\n value?: readonly string[]\n defaultValue?: readonly string[]\n onValueChange?: (value: string[]) => void\n /** `vertical` (default) stacks the options; `horizontal` runs them in a wrapping row. */\n orientation?: 'vertical' | 'horizontal'\n /** Lay the options out in 1–3 equal columns (wins over `orientation`). Responsive. */\n columns?: Responsive<CheckboxGroupColumns>\n /** Adds a tri-state \"select all\" checkbox above the options, with this label. */\n selectAllLabel?: string\n /** Emits one hidden input per checked value, so FormData sees every choice. */\n name?: string\n disabled?: boolean\n /** Focusable but not editable: every box sets `aria-readonly` and clicks are ignored. */\n readOnly?: boolean\n /** Critical edge on the unchecked boxes. Inside a `<Fieldset error>` this is set for you. */\n invalid?: boolean\n size?: Size\n}\n\nexport interface CheckboxGroupItemProps {\n value: string\n label: ReactNode\n description?: ReactNode\n disabled?: boolean\n /** Id for the checkbox. Defaults to a generated one. */\n id?: string\n className?: string\n}\n\ninterface GroupContextValue {\n values: readonly string[]\n toggle: (value: string, checked: boolean) => void\n disabled: boolean\n readOnly: boolean\n size: Size\n}\n\nconst GroupContext = createContext<GroupContextValue | null>(null)\n\ninterface ItemViewProps {\n label: ReactNode\n description?: ReactNode\n disabled: boolean\n readOnly: boolean\n size: Size\n checked: boolean | 'indeterminate'\n onCheckedChange: (checked: boolean) => void\n id?: string\n className?: string\n select?: boolean\n}\n\nfunction ItemView({\n label,\n description,\n disabled,\n readOnly,\n size,\n checked,\n onCheckedChange,\n id: idProp,\n className,\n select,\n}: ItemViewProps) {\n const autoId = useId()\n const id = idProp ?? `${autoId}checkbox`\n const descriptionId = `${id}-description`\n return (\n <div\n className={cx(styles.item, className)}\n data-disabled={disabled || undefined}\n data-select-all={select ? true : undefined}\n >\n <span className={styles.slot}>\n <Checkbox\n id={id}\n size={size}\n checked={checked}\n disabled={disabled}\n readOnly={readOnly}\n aria-describedby={description != null ? descriptionId : undefined}\n onCheckedChange={(state) => {\n onCheckedChange(state === true)\n }}\n />\n </span>\n <span className={styles.text}>\n <label htmlFor={id} className={styles.label}>\n {label}\n </label>\n {description != null ? (\n <span id={descriptionId} className={messageStyles.description}>\n {description}\n </span>\n ) : null}\n </span>\n </div>\n )\n}\n\n/** One option. Must be a direct child of `CheckboxGroup` (so \"select all\" can count it). */\nfunction CheckboxGroupItem({\n value,\n label,\n description,\n disabled = false,\n id,\n className,\n}: CheckboxGroupItemProps) {\n const group = useContext(GroupContext)\n if (!group) throw new Error('CheckboxGroup.Item must be rendered inside a CheckboxGroup')\n return (\n <ItemView\n id={id}\n className={className}\n label={label}\n description={description}\n disabled={group.disabled || disabled}\n readOnly={group.readOnly}\n size={group.size}\n checked={group.values.includes(value)}\n onCheckedChange={(checked) => {\n group.toggle(value, checked)\n }}\n />\n )\n}\n\nfunction childOptions(children: ReactNode): { value: string; disabled: boolean }[] {\n const found: { value: string; disabled: boolean }[] = []\n Children.forEach(children, (child) => {\n if (\n isValidElement<Partial<CheckboxGroupItemProps>>(child) &&\n typeof child.props.value === 'string'\n ) {\n found.push({ value: child.props.value, disabled: child.props.disabled === true })\n }\n })\n return found\n}\n\nconst tracks = (n: CheckboxGroupColumns): string => `repeat(${String(n)}, minmax(0, 1fr))`\nconst EMPTY: readonly string[] = []\n\n/**\n * Several independent choices from a short list (\"Notify me about\"). A `role=\"group\"`\n * labelled by the surrounding `<Fieldset>` legend (or `<Field>` label, or `aria-label`);\n * each option is a real checkbox, so Tab visits each one and Space toggles it.\n *\n * <Fieldset legend=\"Notify me about\">\n * <CheckboxGroup name=\"notify\" options={topics} selectAllLabel=\"Everything\" />\n * </Fieldset>\n */\nconst CheckboxGroupRoot = forwardRef<HTMLDivElement, CheckboxGroupProps>(function CheckboxGroup(\n {\n options,\n children,\n value: valueProp,\n defaultValue,\n onValueChange,\n orientation = 'vertical',\n columns,\n selectAllLabel,\n name,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n invalid: invalidProp,\n size = 'md',\n className,\n style,\n onBlur,\n 'aria-describedby': describedByProp,\n 'aria-invalid': ariaInvalid,\n 'aria-labelledby': labelledByProp,\n ...rest\n },\n ref,\n) {\n const field = useResolvedField({\n describedBy: describedByProp,\n invalid: invalidProp,\n ariaInvalid,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n })\n const [values, setValues] = useControllableValue<readonly string[]>(\n valueProp,\n defaultValue ?? EMPTY,\n onValueChange &&\n ((next) => {\n onValueChange([...next])\n }),\n field.readOnly,\n )\n const handleBlur = useFocusLeave(onBlur)\n\n const all = useMemo(\n () =>\n options\n ? options.map((o) => ({ value: o.value, disabled: o.disabled === true }))\n : childOptions(children),\n [options, children],\n )\n\n const toggle = useCallback(\n (v: string, checked: boolean) => {\n const next = checked\n ? values.includes(v)\n ? [...values]\n : [...values, v]\n : values.filter((x) => x !== v)\n // Keep option order, whatever order they were ticked in.\n const order = all.map((o) => o.value)\n next.sort((a, b) => {\n const ia = order.indexOf(a)\n const ib = order.indexOf(b)\n return (ia === -1 ? Infinity : ia) - (ib === -1 ? Infinity : ib)\n })\n setValues(next)\n },\n [values, setValues, all],\n )\n\n const context = useMemo<GroupContextValue>(\n () => ({\n values,\n toggle,\n disabled: field.disabled,\n readOnly: field.readOnly,\n size,\n }),\n [values, toggle, field.disabled, field.readOnly, size],\n )\n\n let selectAll: ReactNode = null\n if (selectAllLabel != null) {\n const enabled = all.filter((o) => !o.disabled).map((o) => o.value)\n const checkedCount = enabled.filter((v) => values.includes(v)).length\n const state =\n enabled.length > 0 && checkedCount === enabled.length\n ? true\n : checkedCount > 0\n ? 'indeterminate'\n : false\n selectAll = (\n <ItemView\n select\n label={selectAllLabel}\n disabled={field.disabled || enabled.length === 0}\n readOnly={field.readOnly}\n size={size}\n checked={state}\n onCheckedChange={() => {\n // Disabled options keep whatever state they had.\n const locked = values.filter((v) => !enabled.includes(v))\n setValues(state === true ? locked : [...locked, ...enabled])\n }}\n />\n )\n }\n\n const layout = columns !== undefined ? 'columns' : orientation\n\n return (\n // aria-invalid on the group, not on each checkbox: the error belongs to the set.\n // eslint-disable-next-line jsx-a11y/role-supports-aria-props\n <div\n ref={ref}\n role=\"group\"\n className={cx(styles.group, className)}\n data-orientation={orientation}\n data-size={size}\n data-invalid={field.invalid || undefined}\n data-disabled={field.disabled || undefined}\n data-readonly={field.readOnly || undefined}\n aria-labelledby={labelledByProp ?? (rest['aria-label'] ? undefined : field.groupLabelId)}\n aria-describedby={field.describedBy}\n aria-invalid={field.invalid || undefined}\n aria-busy={field.busy || undefined}\n style={mergeStyles(responsiveVars('checkbox-group-columns', columns, tracks), style)}\n onBlur={handleBlur}\n {...rest}\n >\n {/* Options wire their own ids and descriptions; they must not inherit the Field's. */}\n <FieldContext.Provider value={null}>\n <GroupContext.Provider value={context}>\n {selectAll}\n <div className={styles.items} data-layout={layout}>\n {options\n ? options.map((o) => (\n <CheckboxGroupItem\n key={o.value}\n value={o.value}\n label={o.label}\n description={o.description}\n disabled={o.disabled}\n />\n ))\n : children}\n </div>\n </GroupContext.Provider>\n </FieldContext.Provider>\n {hiddenInputs(name, values, field.disabled)}\n </div>\n )\n})\n\nexport const CheckboxGroup = markFieldAware(\n Object.assign(CheckboxGroupRoot, { Item: CheckboxGroupItem }),\n)\n\n// Re-exported so consumers of the choice controls can type their option lists.\nexport type { ChoiceOption } from './choice'\n"],"mappings":"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"}
1
+ {"version":3,"file":"CheckboxGroup.js","names":["styles","messageStyles","messages_module_default","CheckboxGroup_module_default","GroupContext","createContext","ItemView","idProp","autoId","useId","id","descriptionId","cx","className","disabled","select","Checkbox","description","state","label","CheckboxGroupItem","group","useContext","value","checked","childOptions","found","Children","children","isValidElement","child","tracks","n","EMPTY","CheckboxGroupRoot","forwardRef","valueProp","disabledProp","readOnlyProp","invalidProp","describedByProp","ariaInvalid","labelledByProp","rest","field","useResolvedField","values","setValues","useControllableValue","defaultValue","onValueChange","next","handleBlur","useFocusLeave","onBlur","all","useMemo","options","o","toggle","useCallback","v","x","order","ia","a","ib","b","context","size","selectAll","selectAllLabel","enabled","checkedCount","locked","layout","columns","orientation","mergeStyles","responsiveVars","style","FieldContext","hiddenInputs","name","CheckboxGroup","markFieldAware"],"sources":["../../../../src/components/inputs/CheckboxGroup/CheckboxGroup.tsx"],"sourcesContent":["import {\n Children,\n createContext,\n forwardRef,\n isValidElement,\n useCallback,\n useContext,\n useId,\n useMemo,\n type HTMLAttributes,\n type ReactNode,\n} from 'react'\nimport { cx } from '#utils/cx'\nimport { mergeStyles, responsiveVars, type Responsive } from '#utils/responsive'\nimport type { Size } from '#utils/tokens'\nimport { Checkbox } from '#components/inputs/Checkbox'\nimport {\n FieldContext,\n markFieldAware,\n useResolvedField,\n} from '#components/inputs/internal/FieldContext'\nimport messageStyles from '#components/inputs/internal/messages.module.css'\nimport { hiddenInputs, useControllableValue, useFocusLeave, type ChoiceOption } from './choice'\nimport styles from './CheckboxGroup.module.css'\n\nexport type CheckboxGroupColumns = 1 | 2 | 3\n\nexport interface CheckboxGroupProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n 'onChange' | 'defaultValue'\n> {\n /** Options as data. Alternatively pass `<CheckboxGroup.Item>` children. */\n options?: readonly ChoiceOption[]\n children?: ReactNode\n /** Controlled checked values. */\n value?: readonly string[]\n defaultValue?: readonly string[]\n onValueChange?: (value: string[]) => void\n /** `vertical` (default) stacks the options; `horizontal` runs them in a wrapping row. */\n orientation?: 'vertical' | 'horizontal'\n /** Lay the options out in 1–3 equal columns (wins over `orientation`). Responsive. */\n columns?: Responsive<CheckboxGroupColumns>\n /** Adds a tri-state \"select all\" checkbox above the options, with this label. */\n selectAllLabel?: string\n /** Emits one hidden input per checked value, so FormData sees every choice. */\n name?: string\n disabled?: boolean\n /** Focusable but not editable: every box sets `aria-readonly` and clicks are ignored. */\n readOnly?: boolean\n /** Critical edge on the unchecked boxes. Inside a `<Fieldset error>` this is set for you. */\n invalid?: boolean\n size?: Size\n}\n\nexport interface CheckboxGroupItemProps {\n value: string\n label: ReactNode\n description?: ReactNode\n disabled?: boolean\n /** Id for the checkbox. Defaults to a generated one. */\n id?: string\n className?: string\n}\n\ninterface GroupContextValue {\n values: readonly string[]\n toggle: (value: string, checked: boolean) => void\n disabled: boolean\n readOnly: boolean\n size: Size\n}\n\nconst GroupContext = createContext<GroupContextValue | null>(null)\n\ninterface ItemViewProps {\n label: ReactNode\n description?: ReactNode\n disabled: boolean\n readOnly: boolean\n size: Size\n checked: boolean | 'indeterminate'\n onCheckedChange: (checked: boolean) => void\n id?: string\n className?: string\n select?: boolean\n}\n\nfunction ItemView({\n label,\n description,\n disabled,\n readOnly,\n size,\n checked,\n onCheckedChange,\n id: idProp,\n className,\n select,\n}: ItemViewProps) {\n const autoId = useId()\n const id = idProp ?? `${autoId}checkbox`\n const descriptionId = `${id}-description`\n return (\n <div\n className={cx(styles.item, className)}\n data-disabled={disabled || undefined}\n data-select-all={select ? true : undefined}\n >\n <span className={styles.slot}>\n <Checkbox\n id={id}\n size={size}\n checked={checked}\n disabled={disabled}\n readOnly={readOnly}\n aria-describedby={description != null ? descriptionId : undefined}\n onCheckedChange={(state) => {\n onCheckedChange(state === true)\n }}\n />\n </span>\n <span className={styles.text}>\n <label htmlFor={id} className={styles.label}>\n {label}\n </label>\n {description != null ? (\n <span id={descriptionId} className={messageStyles.description}>\n {description}\n </span>\n ) : null}\n </span>\n </div>\n )\n}\n\n/** One option. Must be a direct child of `CheckboxGroup` (so \"select all\" can count it). */\nfunction CheckboxGroupItem({\n value,\n label,\n description,\n disabled = false,\n id,\n className,\n}: CheckboxGroupItemProps) {\n const group = useContext(GroupContext)\n if (!group) throw new Error('CheckboxGroup.Item must be rendered inside a CheckboxGroup')\n return (\n <ItemView\n id={id}\n className={className}\n label={label}\n description={description}\n disabled={group.disabled || disabled}\n readOnly={group.readOnly}\n size={group.size}\n checked={group.values.includes(value)}\n onCheckedChange={(checked) => {\n group.toggle(value, checked)\n }}\n />\n )\n}\n\nfunction childOptions(children: ReactNode): { value: string; disabled: boolean }[] {\n const found: { value: string; disabled: boolean }[] = []\n Children.forEach(children, (child) => {\n if (\n isValidElement<Partial<CheckboxGroupItemProps>>(child) &&\n typeof child.props.value === 'string'\n ) {\n found.push({ value: child.props.value, disabled: child.props.disabled === true })\n }\n })\n return found\n}\n\nconst tracks = (n: CheckboxGroupColumns): string => `repeat(${String(n)}, minmax(0, 1fr))`\nconst EMPTY: readonly string[] = []\n\n/**\n * Several independent choices from a short list (\"Notify me about\"). A `role=\"group\"`\n * labelled by the surrounding `<Fieldset>` legend (or `<Field>` label, or `aria-label`);\n * each option is a real checkbox, so Tab visits each one and Space toggles it.\n *\n * <Fieldset legend=\"Notify me about\">\n * <CheckboxGroup name=\"notify\" options={topics} selectAllLabel=\"Everything\" />\n * </Fieldset>\n */\nconst CheckboxGroupRoot = forwardRef<HTMLDivElement, CheckboxGroupProps>(function CheckboxGroup(\n {\n options,\n children,\n value: valueProp,\n defaultValue,\n onValueChange,\n orientation = 'vertical',\n columns,\n selectAllLabel,\n name,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n invalid: invalidProp,\n size = 'md',\n className,\n style,\n onBlur,\n 'aria-describedby': describedByProp,\n 'aria-invalid': ariaInvalid,\n 'aria-labelledby': labelledByProp,\n ...rest\n },\n ref,\n) {\n const field = useResolvedField({\n describedBy: describedByProp,\n invalid: invalidProp,\n ariaInvalid,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n })\n const [values, setValues] = useControllableValue<readonly string[]>(\n valueProp,\n defaultValue ?? EMPTY,\n onValueChange &&\n ((next) => {\n onValueChange([...next])\n }),\n field.readOnly,\n )\n const handleBlur = useFocusLeave(onBlur)\n\n const all = useMemo(\n () =>\n options\n ? options.map((o) => ({ value: o.value, disabled: o.disabled === true }))\n : childOptions(children),\n [options, children],\n )\n\n const toggle = useCallback(\n (v: string, checked: boolean) => {\n const next = checked\n ? values.includes(v)\n ? [...values]\n : [...values, v]\n : values.filter((x) => x !== v)\n // Keep option order, whatever order they were ticked in.\n const order = all.map((o) => o.value)\n next.sort((a, b) => {\n const ia = order.indexOf(a)\n const ib = order.indexOf(b)\n return (ia === -1 ? Infinity : ia) - (ib === -1 ? Infinity : ib)\n })\n setValues(next)\n },\n [values, setValues, all],\n )\n\n const context = useMemo<GroupContextValue>(\n () => ({\n values,\n toggle,\n disabled: field.disabled,\n readOnly: field.readOnly,\n size,\n }),\n [values, toggle, field.disabled, field.readOnly, size],\n )\n\n let selectAll: ReactNode = null\n if (selectAllLabel != null) {\n const enabled = all.filter((o) => !o.disabled).map((o) => o.value)\n const checkedCount = enabled.filter((v) => values.includes(v)).length\n const state =\n enabled.length > 0 && checkedCount === enabled.length\n ? true\n : checkedCount > 0\n ? 'indeterminate'\n : false\n selectAll = (\n <ItemView\n select\n label={selectAllLabel}\n disabled={field.disabled || enabled.length === 0}\n readOnly={field.readOnly}\n size={size}\n checked={state}\n onCheckedChange={() => {\n // Disabled options keep whatever state they had.\n const locked = values.filter((v) => !enabled.includes(v))\n setValues(state === true ? locked : [...locked, ...enabled])\n }}\n />\n )\n }\n\n const layout = columns !== undefined ? 'columns' : orientation\n\n return (\n // aria-invalid on the group, not on each checkbox: the error belongs to the set.\n // eslint-disable-next-line jsx-a11y/role-supports-aria-props\n <div\n ref={ref}\n role=\"group\"\n className={cx(styles.group, className)}\n data-orientation={orientation}\n data-size={size}\n data-invalid={field.invalid || undefined}\n data-disabled={field.disabled || undefined}\n data-readonly={field.readOnly || undefined}\n aria-labelledby={labelledByProp ?? (rest['aria-label'] ? undefined : field.groupLabelId)}\n aria-describedby={field.describedBy}\n aria-invalid={field.invalid || undefined}\n aria-busy={field.busy || undefined}\n style={mergeStyles(responsiveVars('checkbox-group-columns', columns, tracks), style)}\n onBlur={handleBlur}\n {...rest}\n >\n {/* Options wire their own ids and descriptions; they must not inherit the Field's. */}\n <FieldContext.Provider value={null}>\n <GroupContext.Provider value={context}>\n {selectAll}\n <div className={styles.items} data-layout={layout}>\n {options\n ? options.map((o) => (\n <CheckboxGroupItem\n key={o.value}\n value={o.value}\n label={o.label}\n description={o.description}\n disabled={o.disabled}\n />\n ))\n : children}\n </div>\n </GroupContext.Provider>\n </FieldContext.Provider>\n {hiddenInputs(name, values, field.disabled)}\n </div>\n )\n})\n\n/**\n * Several choices from a set, as checkboxes, with an optional select-all.\n *\n * @remarks\n * `CheckboxGroup` lays out a set of checkboxes from `options` (or `CheckboxGroup.Item` children)\n * and holds their values as one array. `selectAllLabel` adds a parent checkbox that goes\n * indeterminate when only some are chosen. `columns` lays a long set out in a responsive grid.\n */\nexport const CheckboxGroup = markFieldAware(\n Object.assign(CheckboxGroupRoot, { Item: CheckboxGroupItem }),\n)\n\n// Re-exported so consumers of the choice controls can type their option lists.\nexport type { ChoiceOption } from './choice'\n"],"mappings":"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"}
@@ -3,6 +3,13 @@ import type { FieldLabelProps } from '../Field/index.js';
3
3
  export interface CheckboxGroupFieldProps extends FieldLabelProps, Omit<CheckboxGroupProps, 'invalid' | keyof FieldLabelProps> {
4
4
  }
5
5
  /**
6
+ * Several choices from a set, under one legend, with help, warning and error for the set.
7
+ *
8
+ * @remarks
9
+ * `CheckboxGroupField` is a {@link CheckboxGroup | CheckboxGroup} under a {@link Fieldset |
10
+ * Fieldset} legend. The error and warning describe the set, not one box.
11
+ *
12
+ * @privateRemarks
6
13
  * A `CheckboxGroup` under a `<Fieldset>` legend, with help, warning and error for the
7
14
  * group as a whole. `className`/`style` go to the fieldset; `ref`, `id` and the rest go to
8
15
  * the group.
@@ -1 +1 @@
1
- {"version":3,"file":"CheckboxGroupField.js","names":["CheckboxGroupField","forwardRef","fieldProps","groupProps","splitFieldLabelProps","props","Fieldset","toFieldsetProps","CheckboxGroup"],"sources":["../../../../src/components/inputs/CheckboxGroupField/CheckboxGroupField.tsx"],"sourcesContent":["import { forwardRef } from 'react'\nimport { CheckboxGroup, type CheckboxGroupProps } from '#components/inputs/CheckboxGroup'\nimport { toFieldsetProps } from '#components/inputs/CheckboxGroup/choice'\nimport type { FieldLabelProps } from '#components/inputs/Field'\nimport { Fieldset } from '#components/inputs/Fieldset'\nimport { splitFieldLabelProps } from '#components/inputs/internal/fieldProps'\n\nexport interface CheckboxGroupFieldProps\n extends FieldLabelProps, Omit<CheckboxGroupProps, 'invalid' | keyof FieldLabelProps> {}\n\n/**\n * A `CheckboxGroup` under a `<Fieldset>` legend, with help, warning and error for the\n * group as a whole. `className`/`style` go to the fieldset; `ref`, `id` and the rest go to\n * the group.\n *\n * <CheckboxGroupField label=\"Notify me about\" name=\"notify\" options={topics} error={errors.notify} />\n */\nexport const CheckboxGroupField = forwardRef<HTMLDivElement, CheckboxGroupFieldProps>(\n function CheckboxGroupField(props, ref) {\n const [fieldProps, { className, style, disabled, ...groupProps }] = splitFieldLabelProps(props)\n return (\n <Fieldset\n {...toFieldsetProps(fieldProps)}\n disabled={disabled}\n className={className}\n style={style}\n >\n <CheckboxGroup ref={ref} {...groupProps} />\n </Fieldset>\n )\n },\n)\n"],"mappings":";;;;;;;AAiBA,IAAaA,IAAqBC,EAChC,SAA4B,GAAO,GAAK;CACtC,IAAM,CAACC,GAAY,EAAE,cAAW,UAAO,aAAU,GAAGC,OAAgBC,EAAqBC,CAAK;CAC9F,OACE,kBAACC,GAAD;EACE,GAAIC,EAAgBL,CAAU;EACpB;EACC;EACJ;EAEP,UAAA,kBAACM,GAAD;GAAoB;GAAK,GAAIL;EAAa,CAAA;CAClC,CAAA;AAEd,CACF"}
1
+ {"version":3,"file":"CheckboxGroupField.js","names":["CheckboxGroupField","forwardRef","fieldProps","groupProps","splitFieldLabelProps","props","Fieldset","toFieldsetProps","CheckboxGroup"],"sources":["../../../../src/components/inputs/CheckboxGroupField/CheckboxGroupField.tsx"],"sourcesContent":["import { forwardRef } from 'react'\nimport { CheckboxGroup, type CheckboxGroupProps } from '#components/inputs/CheckboxGroup'\nimport { toFieldsetProps } from '#components/inputs/CheckboxGroup/choice'\nimport type { FieldLabelProps } from '#components/inputs/Field'\nimport { Fieldset } from '#components/inputs/Fieldset'\nimport { splitFieldLabelProps } from '#components/inputs/internal/fieldProps'\n\nexport interface CheckboxGroupFieldProps\n extends FieldLabelProps, Omit<CheckboxGroupProps, 'invalid' | keyof FieldLabelProps> {}\n\n/**\n * Several choices from a set, under one legend, with help, warning and error for the set.\n *\n * @remarks\n * `CheckboxGroupField` is a {@link CheckboxGroup | CheckboxGroup} under a {@link Fieldset |\n * Fieldset} legend. The error and warning describe the set, not one box.\n *\n * @privateRemarks\n * A `CheckboxGroup` under a `<Fieldset>` legend, with help, warning and error for the\n * group as a whole. `className`/`style` go to the fieldset; `ref`, `id` and the rest go to\n * the group.\n *\n * <CheckboxGroupField label=\"Notify me about\" name=\"notify\" options={topics} error={errors.notify} />\n */\nexport const CheckboxGroupField = forwardRef<HTMLDivElement, CheckboxGroupFieldProps>(\n function CheckboxGroupField(props, ref) {\n const [fieldProps, { className, style, disabled, ...groupProps }] = splitFieldLabelProps(props)\n return (\n <Fieldset\n {...toFieldsetProps(fieldProps)}\n disabled={disabled}\n className={className}\n style={style}\n >\n <CheckboxGroup ref={ref} {...groupProps} />\n </Fieldset>\n )\n },\n)\n"],"mappings":";;;;;;;AAwBA,IAAaA,IAAqBC,EAChC,SAA4B,GAAO,GAAK;CACtC,IAAM,CAACC,GAAY,EAAE,cAAW,UAAO,aAAU,GAAGC,OAAgBC,EAAqBC,CAAK;CAC9F,OACE,kBAACC,GAAD;EACE,GAAIC,EAAgBL,CAAU;EACpB;EACC;EACJ;EAEP,UAAA,kBAACM,GAAD;GAAoB;GAAK,GAAIL;EAAa,CAAA;CAClC,CAAA;AAEd,CACF"}
@@ -3,6 +3,13 @@ import type { FieldLabelProps } from '../Field/index.js';
3
3
  type Shared = Omit<ChipGroupProps, 'invalid' | 'type' | 'value' | 'defaultValue' | 'onValueChange' | keyof FieldLabelProps>;
4
4
  export type ChipGroupFieldProps = FieldLabelProps & Shared & (ChipGroupSingleProps | ChipGroupMultipleProps);
5
5
  /**
6
+ * A group of chips under a legend, with help, warning and error for the group.
7
+ *
8
+ * @remarks
9
+ * `ChipGroupField` is a {@link ChipGroup | ChipGroup} under a {@link Fieldset | Fieldset} legend.
10
+ * `type="multiple"` picks several, `type="single"` at most one.
11
+ *
12
+ * @privateRemarks
6
13
  * A `ChipGroup` under a `<Fieldset>` legend, with help, warning and error for the group.
7
14
  * `className`/`style` go to the fieldset; `ref`, `id`, `name` and the rest go to the group.
8
15
  *
@@ -1 +1 @@
1
- {"version":3,"file":"ChipGroupField.js","names":["ChipGroupField","forwardRef","fieldProps","rest","splitFieldLabelProps","props","groupProps","Fieldset","toFieldsetProps","ChipGroup"],"sources":["../../../../src/components/inputs/ChipGroupField/ChipGroupField.tsx"],"sourcesContent":["import { forwardRef } from 'react'\nimport {\n ChipGroup,\n type ChipGroupMultipleProps,\n type ChipGroupProps,\n type ChipGroupSingleProps,\n} from '#components/actions/ChipGroup'\nimport { toFieldsetProps } from '#components/inputs/CheckboxGroup/choice'\nimport type { FieldLabelProps } from '#components/inputs/Field'\nimport { Fieldset } from '#components/inputs/Fieldset'\nimport { splitFieldLabelProps } from '#components/inputs/internal/fieldProps'\n\ntype Shared = Omit<\n ChipGroupProps,\n 'invalid' | 'type' | 'value' | 'defaultValue' | 'onValueChange' | keyof FieldLabelProps\n>\n\nexport type ChipGroupFieldProps = FieldLabelProps &\n Shared &\n (ChipGroupSingleProps | ChipGroupMultipleProps)\n\n/**\n * A `ChipGroup` under a `<Fieldset>` legend, with help, warning and error for the group.\n * `className`/`style` go to the fieldset; `ref`, `id`, `name` and the rest go to the group.\n *\n * <ChipGroupField type=\"multiple\" label=\"Deploy alerts\" name=\"alerts\" options={alerts} />\n */\nexport const ChipGroupField = forwardRef<HTMLDivElement, ChipGroupFieldProps>(\n function ChipGroupField(props, ref) {\n const [fieldProps, rest] = splitFieldLabelProps(props)\n const { className, style, disabled, ...groupProps } = rest\n return (\n <Fieldset\n {...toFieldsetProps(fieldProps)}\n disabled={disabled}\n className={className}\n style={style}\n >\n <ChipGroup ref={ref} {...(groupProps as ChipGroupProps)} />\n </Fieldset>\n )\n },\n)\n"],"mappings":";;;;;;;AA2BA,IAAaA,IAAiBC,EAC5B,SAAwB,GAAO,GAAK;CAClC,IAAM,CAACC,GAAYC,KAAQC,EAAqBC,CAAK,GAC/C,EAAE,cAAW,UAAO,aAAU,GAAGC,MAAeH;CACtD,OACE,kBAACI,GAAD;EACE,GAAIC,EAAgBN,CAAU;EACpB;EACC;EACJ;EAEP,UAAA,kBAACO,GAAD;GAAgB;GAAK,GAAKH;EAAgC,CAAA;CAClD,CAAA;AAEd,CACF"}
1
+ {"version":3,"file":"ChipGroupField.js","names":["ChipGroupField","forwardRef","fieldProps","rest","splitFieldLabelProps","props","groupProps","Fieldset","toFieldsetProps","ChipGroup"],"sources":["../../../../src/components/inputs/ChipGroupField/ChipGroupField.tsx"],"sourcesContent":["import { forwardRef } from 'react'\nimport {\n ChipGroup,\n type ChipGroupMultipleProps,\n type ChipGroupProps,\n type ChipGroupSingleProps,\n} from '#components/actions/ChipGroup'\nimport { toFieldsetProps } from '#components/inputs/CheckboxGroup/choice'\nimport type { FieldLabelProps } from '#components/inputs/Field'\nimport { Fieldset } from '#components/inputs/Fieldset'\nimport { splitFieldLabelProps } from '#components/inputs/internal/fieldProps'\n\ntype Shared = Omit<\n ChipGroupProps,\n 'invalid' | 'type' | 'value' | 'defaultValue' | 'onValueChange' | keyof FieldLabelProps\n>\n\nexport type ChipGroupFieldProps = FieldLabelProps &\n Shared &\n (ChipGroupSingleProps | ChipGroupMultipleProps)\n\n/**\n * A group of chips under a legend, with help, warning and error for the group.\n *\n * @remarks\n * `ChipGroupField` is a {@link ChipGroup | ChipGroup} under a {@link Fieldset | Fieldset} legend.\n * `type=\"multiple\"` picks several, `type=\"single\"` at most one.\n *\n * @privateRemarks\n * A `ChipGroup` under a `<Fieldset>` legend, with help, warning and error for the group.\n * `className`/`style` go to the fieldset; `ref`, `id`, `name` and the rest go to the group.\n *\n * <ChipGroupField type=\"multiple\" label=\"Deploy alerts\" name=\"alerts\" options={alerts} />\n */\nexport const ChipGroupField = forwardRef<HTMLDivElement, ChipGroupFieldProps>(\n function ChipGroupField(props, ref) {\n const [fieldProps, rest] = splitFieldLabelProps(props)\n const { className, style, disabled, ...groupProps } = rest\n return (\n <Fieldset\n {...toFieldsetProps(fieldProps)}\n disabled={disabled}\n className={className}\n style={style}\n >\n <ChipGroup ref={ref} {...(groupProps as ChipGroupProps)} />\n </Fieldset>\n )\n },\n)\n"],"mappings":";;;;;;;AAkCA,IAAaA,IAAiBC,EAC5B,SAAwB,GAAO,GAAK;CAClC,IAAM,CAACC,GAAYC,KAAQC,EAAqBC,CAAK,GAC/C,EAAE,cAAW,UAAO,aAAU,GAAGC,MAAeH;CACtD,OACE,kBAACI,GAAD;EACE,GAAIC,EAAgBN,CAAU;EACpB;EACC;EACJ;EAEP,UAAA,kBAACO,GAAD;GAAgB;GAAK,GAAKH;EAAgC,CAAA;CAClD,CAAA;AAEd,CACF"}
@@ -34,6 +34,15 @@ export interface ChoiceCardsMultipleProps {
34
34
  }
35
35
  export type ChoiceCardsProps = ChoiceCardsBaseProps & Omit<HTMLAttributes<HTMLDivElement>, 'onChange' | 'defaultValue' | 'dir'> & (ChoiceCardsSingleProps | ChoiceCardsMultipleProps);
36
36
  /**
37
+ * Choices as cards, for a handful of options that each need a sentence or a price to choose
38
+ * between.
39
+ *
40
+ * @remarks
41
+ * `ChoiceCards` is for a few options that need more than a label: a pass with a price, a plan with
42
+ * a sentence. The whole card is the target, and the selected card takes the accent edge and
43
+ * nothing else. `type="single"` is a radio group; `type="multiple"` is a set of checkboxes.
44
+ *
45
+ * @privateRemarks
37
46
  * Choices as cards — for a handful of options that each need a sentence or a figure to
38
47
  * choose between ("Plan": £5 / £10 / £20). The whole card is the hit target; the
39
48
  * selected card takes the accent edge and nothing else.