@mitcsutt/kiln-ui 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/actions/Button/Button.d.ts +8 -0
- package/dist/components/actions/Button/Button.js.map +1 -1
- package/dist/components/actions/ChipGroup/ChipGroup.d.ts +9 -0
- package/dist/components/actions/ChipGroup/ChipGroup.js.map +1 -1
- package/dist/components/actions/IconButton/IconButton.d.ts +8 -0
- package/dist/components/actions/IconButton/IconButton.js.map +1 -1
- package/dist/components/actions/ModeToggle/ModeToggle.d.ts +8 -0
- package/dist/components/actions/ModeToggle/ModeToggle.js.map +1 -1
- package/dist/components/actions/SegmentedControl/SegmentedControl.d.ts +9 -0
- package/dist/components/actions/SegmentedControl/SegmentedControl.js.map +1 -1
- package/dist/components/actions/ToggleChip/ToggleChip.d.ts +9 -0
- package/dist/components/actions/ToggleChip/ToggleChip.js.map +1 -1
- package/dist/components/display/Avatar/Avatar.d.ts +10 -0
- package/dist/components/display/Avatar/Avatar.js.map +1 -1
- package/dist/components/display/AvatarGroup/AvatarGroup.d.ts +7 -0
- package/dist/components/display/AvatarGroup/AvatarGroup.js.map +1 -1
- package/dist/components/display/Badge/Badge.d.ts +7 -0
- package/dist/components/display/Badge/Badge.js.map +1 -1
- package/dist/components/display/Card/Card.js.map +1 -1
- package/dist/components/display/CodeBlock/CodeBlock.d.ts +9 -0
- package/dist/components/display/CodeBlock/CodeBlock.js.map +1 -1
- package/dist/components/display/DataList/DataList.js.map +1 -1
- package/dist/components/display/Delta/Delta.d.ts +9 -0
- package/dist/components/display/Delta/Delta.js.map +1 -1
- package/dist/components/display/EmptyState/EmptyState.d.ts +8 -0
- package/dist/components/display/EmptyState/EmptyState.js.map +1 -1
- package/dist/components/display/List/List.js.map +1 -1
- package/dist/components/display/Marquee/Marquee.d.ts +8 -0
- package/dist/components/display/Marquee/Marquee.js.map +1 -1
- package/dist/components/display/Media/Media.d.ts +7 -0
- package/dist/components/display/Media/Media.js.map +1 -1
- package/dist/components/display/Meter/Meter.d.ts +9 -0
- package/dist/components/display/Meter/Meter.js.map +1 -1
- package/dist/components/display/Progress/Progress.d.ts +8 -0
- package/dist/components/display/Progress/Progress.js.map +1 -1
- package/dist/components/display/Skeleton/Skeleton.js.map +1 -1
- package/dist/components/display/Stamp/Stamp.d.ts +8 -0
- package/dist/components/display/Stamp/Stamp.js.map +1 -1
- package/dist/components/display/Stat/Stat.d.ts +8 -0
- package/dist/components/display/Stat/Stat.js.map +1 -1
- package/dist/components/display/Table/Table.js.map +1 -1
- package/dist/components/display/Tag/Tag.d.ts +7 -0
- package/dist/components/display/Tag/Tag.js.map +1 -1
- package/dist/components/feedback/Alert/Alert.d.ts +10 -0
- package/dist/components/feedback/Alert/Alert.js.map +1 -1
- package/dist/components/feedback/LiveIndicator/LiveIndicator.d.ts +7 -0
- package/dist/components/feedback/LiveIndicator/LiveIndicator.js.map +1 -1
- package/dist/components/feedback/RelativeTime/RelativeTime.d.ts +8 -0
- package/dist/components/feedback/RelativeTime/RelativeTime.js.map +1 -1
- package/dist/components/feedback/Spinner/Spinner.d.ts +10 -1
- package/dist/components/feedback/Spinner/Spinner.js.map +1 -1
- package/dist/components/feedback/StatusDot/StatusDot.d.ts +10 -1
- package/dist/components/feedback/StatusDot/StatusDot.js.map +1 -1
- package/dist/components/inputs/AmountField/AmountField.d.ts +7 -0
- package/dist/components/inputs/AmountField/AmountField.js.map +1 -1
- package/dist/components/inputs/AmountInput/AmountInput.d.ts +8 -0
- package/dist/components/inputs/AmountInput/AmountInput.js.map +1 -1
- package/dist/components/inputs/Checkbox/Checkbox.d.ts +8 -0
- package/dist/components/inputs/Checkbox/Checkbox.js.map +1 -1
- package/dist/components/inputs/CheckboxField/CheckboxField.d.ts +7 -0
- package/dist/components/inputs/CheckboxField/CheckboxField.js.map +1 -1
- package/dist/components/inputs/CheckboxGroup/CheckboxGroup.d.ts +8 -0
- package/dist/components/inputs/CheckboxGroup/CheckboxGroup.js.map +1 -1
- package/dist/components/inputs/CheckboxGroupField/CheckboxGroupField.d.ts +7 -0
- package/dist/components/inputs/CheckboxGroupField/CheckboxGroupField.js.map +1 -1
- package/dist/components/inputs/ChipGroupField/ChipGroupField.d.ts +7 -0
- package/dist/components/inputs/ChipGroupField/ChipGroupField.js.map +1 -1
- package/dist/components/inputs/ChoiceCards/ChoiceCards.d.ts +9 -0
- package/dist/components/inputs/ChoiceCards/ChoiceCards.js.map +1 -1
- package/dist/components/inputs/ChoiceCardsField/ChoiceCardsField.d.ts +7 -0
- package/dist/components/inputs/ChoiceCardsField/ChoiceCardsField.js.map +1 -1
- package/dist/components/inputs/ColorField/ColorField.d.ts +6 -0
- package/dist/components/inputs/ColorField/ColorField.js.map +1 -1
- package/dist/components/inputs/ColorInput/ColorInput.d.ts +8 -0
- package/dist/components/inputs/ColorInput/ColorInput.js.map +1 -1
- package/dist/components/inputs/Combobox/Combobox.d.ts +9 -0
- package/dist/components/inputs/Combobox/Combobox.js.map +1 -1
- package/dist/components/inputs/ComboboxField/ComboboxField.d.ts +7 -0
- package/dist/components/inputs/ComboboxField/ComboboxField.js.map +1 -1
- package/dist/components/inputs/DateRangeField/DateRangeField.d.ts +7 -0
- package/dist/components/inputs/DateRangeField/DateRangeField.js.map +1 -1
- package/dist/components/inputs/Field/Field.d.ts +26 -0
- package/dist/components/inputs/Field/Field.js.map +1 -1
- package/dist/components/inputs/Fieldset/Fieldset.d.ts +8 -0
- package/dist/components/inputs/Fieldset/Fieldset.js.map +1 -1
- package/dist/components/inputs/FileDrop/FileDrop.d.ts +10 -0
- package/dist/components/inputs/FileDrop/FileDrop.js.map +1 -1
- package/dist/components/inputs/FileField/FileField.d.ts +7 -0
- package/dist/components/inputs/FileField/FileField.js.map +1 -1
- package/dist/components/inputs/Input/Input.d.ts +9 -0
- package/dist/components/inputs/Input/Input.js.map +1 -1
- package/dist/components/inputs/NumberField/NumberField.d.ts +7 -0
- package/dist/components/inputs/NumberField/NumberField.js.map +1 -1
- package/dist/components/inputs/NumberInput/NumberInput.d.ts +8 -0
- package/dist/components/inputs/NumberInput/NumberInput.js.map +1 -1
- package/dist/components/inputs/OneTimeCodeField/OneTimeCodeField.d.ts +7 -0
- package/dist/components/inputs/OneTimeCodeField/OneTimeCodeField.js.map +1 -1
- package/dist/components/inputs/OneTimeCodeInput/OneTimeCodeInput.d.ts +8 -0
- package/dist/components/inputs/OneTimeCodeInput/OneTimeCodeInput.js.map +1 -1
- package/dist/components/inputs/PasswordField/PasswordField.d.ts +7 -0
- package/dist/components/inputs/PasswordField/PasswordField.js.map +1 -1
- package/dist/components/inputs/PasswordInput/PasswordInput.d.ts +10 -0
- package/dist/components/inputs/PasswordInput/PasswordInput.js.map +1 -1
- package/dist/components/inputs/RadioGroup/RadioGroup.d.ts +9 -0
- package/dist/components/inputs/RadioGroup/RadioGroup.js.map +1 -1
- package/dist/components/inputs/RadioGroupField/RadioGroupField.d.ts +8 -0
- package/dist/components/inputs/RadioGroupField/RadioGroupField.js.map +1 -1
- package/dist/components/inputs/RangeSlider/RangeSlider.d.ts +8 -0
- package/dist/components/inputs/RangeSlider/RangeSlider.js.map +1 -1
- package/dist/components/inputs/RangeSliderField/RangeSliderField.d.ts +7 -0
- package/dist/components/inputs/RangeSliderField/RangeSliderField.js.map +1 -1
- package/dist/components/inputs/Rating/Rating.d.ts +8 -0
- package/dist/components/inputs/Rating/Rating.js.map +1 -1
- package/dist/components/inputs/RatingField/RatingField.d.ts +7 -0
- package/dist/components/inputs/RatingField/RatingField.js.map +1 -1
- package/dist/components/inputs/SegmentedField/SegmentedField.d.ts +7 -0
- package/dist/components/inputs/SegmentedField/SegmentedField.js.map +1 -1
- package/dist/components/inputs/Select/Select.d.ts +9 -0
- package/dist/components/inputs/Select/Select.js.map +1 -1
- package/dist/components/inputs/SelectField/SelectField.d.ts +7 -0
- package/dist/components/inputs/SelectField/SelectField.js.map +1 -1
- package/dist/components/inputs/Slider/Slider.d.ts +8 -0
- package/dist/components/inputs/Slider/Slider.js.map +1 -1
- package/dist/components/inputs/SliderField/SliderField.d.ts +7 -0
- package/dist/components/inputs/SliderField/SliderField.js.map +1 -1
- package/dist/components/inputs/Switch/Switch.d.ts +8 -0
- package/dist/components/inputs/Switch/Switch.js.map +1 -1
- package/dist/components/inputs/SwitchField/SwitchField.d.ts +8 -0
- package/dist/components/inputs/SwitchField/SwitchField.js.map +1 -1
- package/dist/components/inputs/TagsField/TagsField.d.ts +6 -0
- package/dist/components/inputs/TagsField/TagsField.js.map +1 -1
- package/dist/components/inputs/TagsInput/TagsInput.d.ts +8 -0
- package/dist/components/inputs/TagsInput/TagsInput.js.map +1 -1
- package/dist/components/inputs/TextField/TextField.d.ts +8 -0
- package/dist/components/inputs/TextField/TextField.js.map +1 -1
- package/dist/components/inputs/Textarea/Textarea.d.ts +8 -0
- package/dist/components/inputs/Textarea/Textarea.js.map +1 -1
- package/dist/components/inputs/TextareaField/TextareaField.d.ts +7 -0
- package/dist/components/inputs/TextareaField/TextareaField.js.map +1 -1
- package/dist/components/layout/ActionBar/ActionBar.d.ts +7 -0
- package/dist/components/layout/ActionBar/ActionBar.js.map +1 -1
- package/dist/components/layout/AppShell/AppShell.js.map +1 -1
- package/dist/components/layout/AspectRatio/AspectRatio.d.ts +8 -0
- package/dist/components/layout/AspectRatio/AspectRatio.js.map +1 -1
- package/dist/components/layout/Box/Box.d.ts +8 -0
- package/dist/components/layout/Box/Box.js.map +1 -1
- package/dist/components/layout/Container/Container.d.ts +17 -0
- package/dist/components/layout/Container/Container.js.map +1 -1
- package/dist/components/layout/Divider/Divider.d.ts +7 -0
- package/dist/components/layout/Divider/Divider.js.map +1 -1
- package/dist/components/layout/Grid/Grid.d.ts +9 -0
- package/dist/components/layout/Grid/Grid.js.map +1 -1
- package/dist/components/layout/Inline/Inline.d.ts +8 -0
- package/dist/components/layout/Inline/Inline.js.map +1 -1
- package/dist/components/layout/Section/Section.d.ts +15 -0
- package/dist/components/layout/Section/Section.js.map +1 -1
- package/dist/components/layout/Split/Split.d.ts +9 -0
- package/dist/components/layout/Split/Split.js.map +1 -1
- package/dist/components/layout/Stack/Stack.d.ts +12 -0
- package/dist/components/layout/Stack/Stack.js.map +1 -1
- package/dist/components/layout/VisuallyHidden/VisuallyHidden.d.ts +7 -0
- package/dist/components/layout/VisuallyHidden/VisuallyHidden.js.map +1 -1
- package/dist/components/navigation/Accordion/Accordion.d.ts +7 -0
- package/dist/components/navigation/Accordion/Accordion.js.map +1 -1
- package/dist/components/navigation/BottomNav/BottomNav.d.ts +9 -0
- package/dist/components/navigation/BottomNav/BottomNav.js.map +1 -1
- package/dist/components/navigation/NavLinks/NavLinks.d.ts +9 -0
- package/dist/components/navigation/NavLinks/NavLinks.js.map +1 -1
- package/dist/components/navigation/Stepper/Stepper.d.ts +7 -0
- package/dist/components/navigation/Stepper/Stepper.js.map +1 -1
- package/dist/components/navigation/Tabs/Tabs.d.ts +8 -0
- package/dist/components/navigation/Tabs/Tabs.js.map +1 -1
- package/dist/components/overlays/Dialog/Dialog.d.ts +13 -0
- package/dist/components/overlays/Dialog/Dialog.js.map +1 -1
- package/dist/components/overlays/DropdownMenu/DropdownMenu.d.ts +8 -0
- package/dist/components/overlays/DropdownMenu/DropdownMenu.js.map +1 -1
- package/dist/components/overlays/Popover/Popover.d.ts +7 -0
- package/dist/components/overlays/Popover/Popover.js.map +1 -1
- package/dist/components/overlays/Sheet/Sheet.d.ts +8 -0
- package/dist/components/overlays/Sheet/Sheet.js.map +1 -1
- package/dist/components/overlays/Tooltip/Tooltip.d.ts +8 -0
- package/dist/components/overlays/Tooltip/Tooltip.js.map +1 -1
- package/dist/components/typography/Amount/Amount.d.ts +8 -0
- package/dist/components/typography/Amount/Amount.js.map +1 -1
- package/dist/components/typography/Code/Code.d.ts +8 -0
- package/dist/components/typography/Code/Code.js.map +1 -1
- package/dist/components/typography/Heading/Heading.d.ts +8 -0
- package/dist/components/typography/Heading/Heading.js.map +1 -1
- package/dist/components/typography/Kbd/Kbd.d.ts +6 -0
- package/dist/components/typography/Kbd/Kbd.js.map +1 -1
- package/dist/components/typography/Link/Link.d.ts +9 -0
- package/dist/components/typography/Link/Link.js.map +1 -1
- package/dist/components/typography/Numeral/Numeral.d.ts +8 -0
- package/dist/components/typography/Numeral/Numeral.js.map +1 -1
- package/dist/components/typography/Prose/Prose.d.ts +9 -0
- package/dist/components/typography/Prose/Prose.js.map +1 -1
- package/dist/components/typography/Quote/Quote.d.ts +7 -0
- package/dist/components/typography/Quote/Quote.js.map +1 -1
- package/dist/components/typography/SectionHeader/SectionHeader.d.ts +8 -0
- package/dist/components/typography/SectionHeader/SectionHeader.js.map +1 -1
- package/dist/components/typography/Text/Text.d.ts +8 -0
- package/dist/components/typography/Text/Text.js.map +1 -1
- package/package.json +1 -1
- package/skills/layout-composition/SKILL.md +27 -88
- package/skills/layout-composition/references/action-bar.md +3 -3
- package/skills/layout-composition/references/app-shell.md +10 -3
- package/skills/layout-composition/references/aspect-ratio.md +2 -0
- package/skills/layout-composition/references/box.md +6 -6
- package/skills/layout-composition/references/container.md +14 -12
- package/skills/layout-composition/references/divider.md +4 -4
- package/skills/layout-composition/references/section.md +69 -0
- package/skills/layout-composition/references/visually-hidden.md +3 -3
|
@@ -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":";;;;;
|
|
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
|
-
/**
|
|
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
|
|
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
|
-
/**
|
|
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
|
|
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":";;;;;;
|
|
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":";;;;;;;;
|
|
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":";;;;;;;;;;
|
|
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":";;;;;;;
|
|
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":";;;;;;;
|
|
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.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChoiceCards.js","names":["_Fragment","styles","RadixRadioGroup","RadixCheckbox","ChoiceCards_module_default","Fragment$1","EMPTY","tracks","n","CardBody","ids","option","kind","CheckIcon","cardIds","base","index","cardAria","joinIds","ChoiceCards","markFieldAware","forwardRef","valueProp","disabledProp","readOnlyProp","invalidProp","idProp","describedByProp","ariaInvalid","labelledByProp","rest","props","autoId","useId","field","useResolvedField","handleBlur","useFocusLeave","onBlur","toArray","v","emit","onValueChange","type","next","values","setValues","useControllableValue","defaultValue","rootProps","cx","className","mergeStyles","responsiveVars","columns","style","RadioGroup","options","i","o","hiddenInputs","name","checked","Checkbox","on","state","x"],"sources":["../../../../src/components/inputs/ChoiceCards/ChoiceCards.tsx"],"sourcesContent":["import { forwardRef, useId, type HTMLAttributes, type ReactNode } from 'react'\nimport { Checkbox as RadixCheckbox, RadioGroup as RadixRadioGroup } from 'radix-ui'\nimport { CheckIcon } from '#icons'\nimport { cx } from '#utils/cx'\nimport { mergeStyles, responsiveVars, type Responsive } from '#utils/responsive'\nimport {\n hiddenInputs,\n useControllableValue,\n useFocusLeave,\n type ChoiceOption,\n} from '#components/inputs/CheckboxGroup/choice'\nimport { markFieldAware, useResolvedField } from '#components/inputs/internal/FieldContext'\nimport { joinIds } from '#components/inputs/internal/refs'\nimport styles from './ChoiceCards.module.css'\n\nexport interface ChoiceCardOption extends ChoiceOption {\n /** A figure or short fact set at the foot of the card — `<Amount value={10} />`, \"Most picked\". */\n meta?: ReactNode\n}\n\nexport type ChoiceCardsColumns = 1 | 2 | 3 | 4\n\ninterface ChoiceCardsBaseProps {\n options: readonly ChoiceCardOption[]\n /** Fixed column count, 1–4. Responsive. Default: as many ~12rem cards as fit. */\n columns?: Responsive<ChoiceCardsColumns>\n /** Emits one hidden input per selected value, for native form submission. */\n name?: string\n disabled?: boolean\n /** Focusable but not editable: selection changes are ignored. */\n readOnly?: boolean\n /** Critical edge on the unselected cards + `aria-invalid`. Set for you inside a `<Fieldset error>`. */\n invalid?: boolean\n}\n\nexport interface ChoiceCardsSingleProps {\n /** One card — the cards are radios (arrow keys move and select; one tab stop). */\n type: 'single'\n value?: string\n defaultValue?: string\n onValueChange?: (value: string) => void\n}\n\nexport interface ChoiceCardsMultipleProps {\n /** Any number of cards — the cards are checkboxes (each a tab stop; Space toggles). */\n type: 'multiple'\n value?: readonly string[]\n defaultValue?: readonly string[]\n onValueChange?: (value: string[]) => void\n}\n\nexport type ChoiceCardsProps = ChoiceCardsBaseProps &\n Omit<HTMLAttributes<HTMLDivElement>, 'onChange' | 'defaultValue' | 'dir'> &\n (ChoiceCardsSingleProps | ChoiceCardsMultipleProps)\n\nconst EMPTY: readonly string[] = []\nconst tracks = (n: ChoiceCardsColumns): string => `repeat(${String(n)}, minmax(0, 1fr))`\n\nfunction CardBody({\n option,\n ids,\n kind,\n}: {\n option: ChoiceCardOption\n ids: CardIds\n kind: 'radio' | 'checkbox'\n}) {\n return (\n <>\n <span className={styles.head}>\n <span id={ids.label} className={styles.label}>\n {option.label}\n </span>\n <span className={styles.mark} data-kind={kind} aria-hidden=\"true\">\n {kind === 'checkbox' ? <CheckIcon className={styles.check} /> : null}\n </span>\n </span>\n {option.description != null ? (\n <span id={ids.description} className={styles.description}>\n {option.description}\n </span>\n ) : null}\n {option.meta != null ? (\n <span id={ids.meta} className={styles.meta}>\n {option.meta}\n </span>\n ) : null}\n </>\n )\n}\n\ninterface CardIds {\n label: string\n description: string\n meta: string\n}\n\nfunction cardIds(base: string, index: number): CardIds {\n return {\n label: `${base}card${String(index)}-label`,\n description: `${base}card${String(index)}-description`,\n meta: `${base}card${String(index)}-meta`,\n }\n}\n\n/** The card is named by its label and described by its description and meta. */\nfunction cardAria(option: ChoiceCardOption, ids: CardIds) {\n return {\n 'aria-labelledby': ids.label,\n 'aria-describedby': joinIds(\n option.description != null && ids.description,\n option.meta != null && ids.meta,\n ),\n }\n}\n\n/**\n * Choices as cards — for a handful of options that each need a sentence or a figure to\n * choose between (\"Plan\": £5 / £10 / £20). The whole card is the hit target; the\n * selected card takes the accent edge and nothing else.\n *\n * `type=\"single\"` — Radix RadioGroup; the cards are the radios.\n * `type=\"multiple\"` — each card is a checkbox inside a `role=\"group\"`.\n *\n * Label it with a `<Fieldset legend>` (see `ChoiceCardsField`), a `<Field>` or `aria-label`.\n * `onBlur` fires once, when focus leaves the whole set.\n *\n * <ChoiceCards type=\"single\" aria-label=\"Plan\" name=\"plan\" options={plans} columns={{ base: 1, sm: 3 }} />\n */\nexport const ChoiceCards = markFieldAware(\n forwardRef<HTMLDivElement, ChoiceCardsProps>(function ChoiceCards(props, ref) {\n const {\n type,\n value: valueProp,\n defaultValue,\n onValueChange,\n options,\n columns,\n name,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n invalid: invalidProp,\n id: idProp,\n className,\n style,\n onBlur,\n 'aria-describedby': describedByProp,\n 'aria-invalid': ariaInvalid,\n 'aria-labelledby': labelledByProp,\n ...rest\n } = props\n const autoId = useId()\n const field = useResolvedField({\n id: idProp,\n describedBy: describedByProp,\n invalid: invalidProp,\n ariaInvalid,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n })\n const handleBlur = useFocusLeave(onBlur)\n\n const toArray = (v: string | readonly string[] | undefined): readonly string[] | undefined =>\n v === undefined ? undefined : typeof v === 'string' ? (v ? [v] : EMPTY) : v\n const emit = onValueChange\n ? (next: readonly string[]) => {\n if (type === 'single') onValueChange(next[0] ?? '')\n else onValueChange([...next])\n }\n : undefined\n const [values, setValues] = useControllableValue<readonly string[]>(\n toArray(valueProp),\n toArray(defaultValue) ?? EMPTY,\n emit,\n field.readOnly,\n )\n\n const rootProps = {\n ref,\n id: field.id,\n className: cx(styles.cards, className),\n style: mergeStyles(responsiveVars('choice-cards-columns', columns, tracks), style),\n 'data-type': type,\n 'data-columns': columns !== undefined || undefined,\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 onBlur: handleBlur,\n ...rest,\n }\n\n if (type === 'single') {\n return (\n <RadixRadioGroup.Root\n {...rootProps}\n value={values[0] ?? ''}\n onValueChange={(v) => {\n setValues(v ? [v] : EMPTY)\n }}\n disabled={field.disabled}\n aria-required={field.required || undefined}\n aria-readonly={field.readOnly || undefined}\n >\n {options.map((o, i) => {\n const ids = cardIds(autoId, i)\n return (\n <RadixRadioGroup.Item\n key={o.value}\n value={o.value}\n disabled={o.disabled}\n className={styles.card}\n {...cardAria(o, ids)}\n >\n <CardBody option={o} ids={ids} kind=\"radio\" />\n </RadixRadioGroup.Item>\n )\n })}\n {hiddenInputs(name, values, field.disabled)}\n </RadixRadioGroup.Root>\n )\n }\n\n return (\n <div role=\"group\" {...rootProps}>\n {options.map((o, i) => {\n const ids = cardIds(autoId, i)\n const checked = values.includes(o.value)\n return (\n <RadixCheckbox.Root\n key={o.value}\n checked={checked}\n disabled={field.disabled || o.disabled}\n aria-readonly={field.readOnly || undefined}\n className={styles.card}\n {...cardAria(o, ids)}\n onCheckedChange={(state) => {\n const on = state === true\n // Keep option order, whatever order the cards were picked in.\n setValues(\n options\n .map((x) => x.value)\n .filter((v) => (v === o.value ? on : values.includes(v))),\n )\n }}\n >\n <CardBody option={o} ids={ids} kind=\"checkbox\" />\n </RadixCheckbox.Root>\n )\n })}\n {hiddenInputs(name, values, field.disabled)}\n </div>\n )\n }),\n)\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ChoiceCards.js","names":["_Fragment","styles","RadixRadioGroup","RadixCheckbox","ChoiceCards_module_default","Fragment$1","EMPTY","tracks","n","CardBody","ids","option","kind","CheckIcon","cardIds","base","index","cardAria","joinIds","ChoiceCards","markFieldAware","forwardRef","valueProp","disabledProp","readOnlyProp","invalidProp","idProp","describedByProp","ariaInvalid","labelledByProp","rest","props","autoId","useId","field","useResolvedField","handleBlur","useFocusLeave","onBlur","toArray","v","emit","onValueChange","type","next","values","setValues","useControllableValue","defaultValue","rootProps","cx","className","mergeStyles","responsiveVars","columns","style","RadioGroup","options","i","o","hiddenInputs","name","checked","Checkbox","on","state","x"],"sources":["../../../../src/components/inputs/ChoiceCards/ChoiceCards.tsx"],"sourcesContent":["import { forwardRef, useId, type HTMLAttributes, type ReactNode } from 'react'\nimport { Checkbox as RadixCheckbox, RadioGroup as RadixRadioGroup } from 'radix-ui'\nimport { CheckIcon } from '#icons'\nimport { cx } from '#utils/cx'\nimport { mergeStyles, responsiveVars, type Responsive } from '#utils/responsive'\nimport {\n hiddenInputs,\n useControllableValue,\n useFocusLeave,\n type ChoiceOption,\n} from '#components/inputs/CheckboxGroup/choice'\nimport { markFieldAware, useResolvedField } from '#components/inputs/internal/FieldContext'\nimport { joinIds } from '#components/inputs/internal/refs'\nimport styles from './ChoiceCards.module.css'\n\nexport interface ChoiceCardOption extends ChoiceOption {\n /** A figure or short fact set at the foot of the card — `<Amount value={10} />`, \"Most picked\". */\n meta?: ReactNode\n}\n\nexport type ChoiceCardsColumns = 1 | 2 | 3 | 4\n\ninterface ChoiceCardsBaseProps {\n options: readonly ChoiceCardOption[]\n /** Fixed column count, 1–4. Responsive. Default: as many ~12rem cards as fit. */\n columns?: Responsive<ChoiceCardsColumns>\n /** Emits one hidden input per selected value, for native form submission. */\n name?: string\n disabled?: boolean\n /** Focusable but not editable: selection changes are ignored. */\n readOnly?: boolean\n /** Critical edge on the unselected cards + `aria-invalid`. Set for you inside a `<Fieldset error>`. */\n invalid?: boolean\n}\n\nexport interface ChoiceCardsSingleProps {\n /** One card — the cards are radios (arrow keys move and select; one tab stop). */\n type: 'single'\n value?: string\n defaultValue?: string\n onValueChange?: (value: string) => void\n}\n\nexport interface ChoiceCardsMultipleProps {\n /** Any number of cards — the cards are checkboxes (each a tab stop; Space toggles). */\n type: 'multiple'\n value?: readonly string[]\n defaultValue?: readonly string[]\n onValueChange?: (value: string[]) => void\n}\n\nexport type ChoiceCardsProps = ChoiceCardsBaseProps &\n Omit<HTMLAttributes<HTMLDivElement>, 'onChange' | 'defaultValue' | 'dir'> &\n (ChoiceCardsSingleProps | ChoiceCardsMultipleProps)\n\nconst EMPTY: readonly string[] = []\nconst tracks = (n: ChoiceCardsColumns): string => `repeat(${String(n)}, minmax(0, 1fr))`\n\nfunction CardBody({\n option,\n ids,\n kind,\n}: {\n option: ChoiceCardOption\n ids: CardIds\n kind: 'radio' | 'checkbox'\n}) {\n return (\n <>\n <span className={styles.head}>\n <span id={ids.label} className={styles.label}>\n {option.label}\n </span>\n <span className={styles.mark} data-kind={kind} aria-hidden=\"true\">\n {kind === 'checkbox' ? <CheckIcon className={styles.check} /> : null}\n </span>\n </span>\n {option.description != null ? (\n <span id={ids.description} className={styles.description}>\n {option.description}\n </span>\n ) : null}\n {option.meta != null ? (\n <span id={ids.meta} className={styles.meta}>\n {option.meta}\n </span>\n ) : null}\n </>\n )\n}\n\ninterface CardIds {\n label: string\n description: string\n meta: string\n}\n\nfunction cardIds(base: string, index: number): CardIds {\n return {\n label: `${base}card${String(index)}-label`,\n description: `${base}card${String(index)}-description`,\n meta: `${base}card${String(index)}-meta`,\n }\n}\n\n/** The card is named by its label and described by its description and meta. */\nfunction cardAria(option: ChoiceCardOption, ids: CardIds) {\n return {\n 'aria-labelledby': ids.label,\n 'aria-describedby': joinIds(\n option.description != null && ids.description,\n option.meta != null && ids.meta,\n ),\n }\n}\n\n/**\n * Choices as cards, for a handful of options that each need a sentence or a price to choose\n * between.\n *\n * @remarks\n * `ChoiceCards` is for a few options that need more than a label: a pass with a price, a plan with\n * a sentence. The whole card is the target, and the selected card takes the accent edge and\n * nothing else. `type=\"single\"` is a radio group; `type=\"multiple\"` is a set of checkboxes.\n *\n * @privateRemarks\n * Choices as cards — for a handful of options that each need a sentence or a figure to\n * choose between (\"Plan\": £5 / £10 / £20). The whole card is the hit target; the\n * selected card takes the accent edge and nothing else.\n *\n * `type=\"single\"` — Radix RadioGroup; the cards are the radios.\n * `type=\"multiple\"` — each card is a checkbox inside a `role=\"group\"`.\n *\n * Label it with a `<Fieldset legend>` (see `ChoiceCardsField`), a `<Field>` or `aria-label`.\n * `onBlur` fires once, when focus leaves the whole set.\n *\n * <ChoiceCards type=\"single\" aria-label=\"Plan\" name=\"plan\" options={plans} columns={{ base: 1, sm: 3 }} />\n */\nexport const ChoiceCards = markFieldAware(\n forwardRef<HTMLDivElement, ChoiceCardsProps>(function ChoiceCards(props, ref) {\n const {\n type,\n value: valueProp,\n defaultValue,\n onValueChange,\n options,\n columns,\n name,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n invalid: invalidProp,\n id: idProp,\n className,\n style,\n onBlur,\n 'aria-describedby': describedByProp,\n 'aria-invalid': ariaInvalid,\n 'aria-labelledby': labelledByProp,\n ...rest\n } = props\n const autoId = useId()\n const field = useResolvedField({\n id: idProp,\n describedBy: describedByProp,\n invalid: invalidProp,\n ariaInvalid,\n disabled: disabledProp,\n readOnly: readOnlyProp,\n })\n const handleBlur = useFocusLeave(onBlur)\n\n const toArray = (v: string | readonly string[] | undefined): readonly string[] | undefined =>\n v === undefined ? undefined : typeof v === 'string' ? (v ? [v] : EMPTY) : v\n const emit = onValueChange\n ? (next: readonly string[]) => {\n if (type === 'single') onValueChange(next[0] ?? '')\n else onValueChange([...next])\n }\n : undefined\n const [values, setValues] = useControllableValue<readonly string[]>(\n toArray(valueProp),\n toArray(defaultValue) ?? EMPTY,\n emit,\n field.readOnly,\n )\n\n const rootProps = {\n ref,\n id: field.id,\n className: cx(styles.cards, className),\n style: mergeStyles(responsiveVars('choice-cards-columns', columns, tracks), style),\n 'data-type': type,\n 'data-columns': columns !== undefined || undefined,\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 onBlur: handleBlur,\n ...rest,\n }\n\n if (type === 'single') {\n return (\n <RadixRadioGroup.Root\n {...rootProps}\n value={values[0] ?? ''}\n onValueChange={(v) => {\n setValues(v ? [v] : EMPTY)\n }}\n disabled={field.disabled}\n aria-required={field.required || undefined}\n aria-readonly={field.readOnly || undefined}\n >\n {options.map((o, i) => {\n const ids = cardIds(autoId, i)\n return (\n <RadixRadioGroup.Item\n key={o.value}\n value={o.value}\n disabled={o.disabled}\n className={styles.card}\n {...cardAria(o, ids)}\n >\n <CardBody option={o} ids={ids} kind=\"radio\" />\n </RadixRadioGroup.Item>\n )\n })}\n {hiddenInputs(name, values, field.disabled)}\n </RadixRadioGroup.Root>\n )\n }\n\n return (\n <div role=\"group\" {...rootProps}>\n {options.map((o, i) => {\n const ids = cardIds(autoId, i)\n const checked = values.includes(o.value)\n return (\n <RadixCheckbox.Root\n key={o.value}\n checked={checked}\n disabled={field.disabled || o.disabled}\n aria-readonly={field.readOnly || undefined}\n className={styles.card}\n {...cardAria(o, ids)}\n onCheckedChange={(state) => {\n const on = state === true\n // Keep option order, whatever order the cards were picked in.\n setValues(\n options\n .map((x) => x.value)\n .filter((v) => (v === o.value ? on : values.includes(v))),\n )\n }}\n >\n <CardBody option={o} ids={ids} kind=\"checkbox\" />\n </RadixCheckbox.Root>\n )\n })}\n {hiddenInputs(name, values, field.disabled)}\n </div>\n )\n }),\n)\n"],"mappings":"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"}
|
|
@@ -3,6 +3,13 @@ import type { FieldLabelProps } from '../Field/index.js';
|
|
|
3
3
|
type Shared = Omit<ChoiceCardsProps, 'invalid' | 'type' | 'value' | 'defaultValue' | 'onValueChange' | keyof FieldLabelProps>;
|
|
4
4
|
export type ChoiceCardsFieldProps = FieldLabelProps & Shared & (ChoiceCardsSingleProps | ChoiceCardsMultipleProps);
|
|
5
5
|
/**
|
|
6
|
+
* Choice cards under a legend, with help, warning and error for the set.
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* `ChoiceCardsField` is {@link ChoiceCards | ChoiceCards} under a {@link Fieldset | Fieldset}
|
|
10
|
+
* legend. Use `type="single"` for one of the cards, `type="multiple"` for any number.
|
|
11
|
+
*
|
|
12
|
+
* @privateRemarks
|
|
6
13
|
* `ChoiceCards` under a `<Fieldset>` legend, with help, warning and error for the set.
|
|
7
14
|
* `className`/`style` go to the fieldset; `ref`, `id`, `name` and the rest go to the cards.
|
|
8
15
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChoiceCardsField.js","names":["ChoiceCardsField","forwardRef","fieldProps","rest","splitFieldLabelProps","props","cardsProps","Fieldset","toFieldsetProps","ChoiceCards"],"sources":["../../../../src/components/inputs/ChoiceCardsField/ChoiceCardsField.tsx"],"sourcesContent":["import { forwardRef } from 'react'\nimport {\n ChoiceCards,\n type ChoiceCardsMultipleProps,\n type ChoiceCardsProps,\n type ChoiceCardsSingleProps,\n} from '#components/inputs/ChoiceCards'\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 ChoiceCardsProps,\n 'invalid' | 'type' | 'value' | 'defaultValue' | 'onValueChange' | keyof FieldLabelProps\n>\n\nexport type ChoiceCardsFieldProps = FieldLabelProps &\n Shared &\n (ChoiceCardsSingleProps | ChoiceCardsMultipleProps)\n\n/**\n * `ChoiceCards` under a `<Fieldset>` legend, with help, warning and error for the set.\n * `className`/`style` go to the fieldset; `ref`, `id`, `name` and the rest go to the cards.\n *\n * <ChoiceCardsField type=\"single\" label=\"Plan\" name=\"plan\" options={plans} columns={{ base: 1, sm: 3 }} />\n */\nexport const ChoiceCardsField = forwardRef<HTMLDivElement, ChoiceCardsFieldProps>(\n function ChoiceCardsField(props, ref) {\n const [fieldProps, rest] = splitFieldLabelProps(props)\n const { className, style, disabled, ...cardsProps } = rest\n return (\n <Fieldset\n {...toFieldsetProps(fieldProps)}\n disabled={disabled}\n className={className}\n style={style}\n >\n <ChoiceCards ref={ref} {...(cardsProps as ChoiceCardsProps)} />\n </Fieldset>\n )\n },\n)\n"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"ChoiceCardsField.js","names":["ChoiceCardsField","forwardRef","fieldProps","rest","splitFieldLabelProps","props","cardsProps","Fieldset","toFieldsetProps","ChoiceCards"],"sources":["../../../../src/components/inputs/ChoiceCardsField/ChoiceCardsField.tsx"],"sourcesContent":["import { forwardRef } from 'react'\nimport {\n ChoiceCards,\n type ChoiceCardsMultipleProps,\n type ChoiceCardsProps,\n type ChoiceCardsSingleProps,\n} from '#components/inputs/ChoiceCards'\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 ChoiceCardsProps,\n 'invalid' | 'type' | 'value' | 'defaultValue' | 'onValueChange' | keyof FieldLabelProps\n>\n\nexport type ChoiceCardsFieldProps = FieldLabelProps &\n Shared &\n (ChoiceCardsSingleProps | ChoiceCardsMultipleProps)\n\n/**\n * Choice cards under a legend, with help, warning and error for the set.\n *\n * @remarks\n * `ChoiceCardsField` is {@link ChoiceCards | ChoiceCards} under a {@link Fieldset | Fieldset}\n * legend. Use `type=\"single\"` for one of the cards, `type=\"multiple\"` for any number.\n *\n * @privateRemarks\n * `ChoiceCards` under a `<Fieldset>` legend, with help, warning and error for the set.\n * `className`/`style` go to the fieldset; `ref`, `id`, `name` and the rest go to the cards.\n *\n * <ChoiceCardsField type=\"single\" label=\"Plan\" name=\"plan\" options={plans} columns={{ base: 1, sm: 3 }} />\n */\nexport const ChoiceCardsField = forwardRef<HTMLDivElement, ChoiceCardsFieldProps>(\n function ChoiceCardsField(props, ref) {\n const [fieldProps, rest] = splitFieldLabelProps(props)\n const { className, style, disabled, ...cardsProps } = rest\n return (\n <Fieldset\n {...toFieldsetProps(fieldProps)}\n disabled={disabled}\n className={className}\n style={style}\n >\n <ChoiceCards ref={ref} {...(cardsProps as ChoiceCardsProps)} />\n </Fieldset>\n )\n },\n)\n"],"mappings":";;;;;;;AAkCA,IAAaA,IAAmBC,EAC9B,SAA0B,GAAO,GAAK;CACpC,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;GAAkB;GAAK,GAAKH;EAAkC,CAAA;CACtD,CAAA;AAEd,CACF"}
|
|
@@ -3,6 +3,12 @@ import { type ColorInputProps } from '../ColorInput/index.js';
|
|
|
3
3
|
export interface ColorFieldProps extends FieldLabelProps, Omit<ColorInputProps, 'invalid' | keyof FieldLabelProps> {
|
|
4
4
|
}
|
|
5
5
|
/**
|
|
6
|
+
* A labelled colour input with a picker, a hex code and named presets.
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* `ColorField` is a {@link Field | Field} around a {@link ColorInput | ColorInput}.
|
|
10
|
+
*
|
|
11
|
+
* @privateRemarks
|
|
6
12
|
* Label + ColorInput + description + error. Input props (`value`, `swatches`,
|
|
7
13
|
* `swatchesOnly`…) and the ref go to the hex input (or the swatch group with
|
|
8
14
|
* `swatchesOnly`); `className`/`style` go to the wrapper.
|