diff --git a/apps/storybook/stories/radio-list.stories.tsx b/apps/storybook/stories/radio-list.stories.tsx index 7da530bb..4217bd13 100644 --- a/apps/storybook/stories/radio-list.stories.tsx +++ b/apps/storybook/stories/radio-list.stories.tsx @@ -83,6 +83,7 @@ export function Controlled() { return ( setValue(newValue)}> @@ -93,6 +94,132 @@ export function Controlled() { ); } +export function Required() { + const items = [ + { + label: 'Apple', + value: 'apple', + }, + { + label: 'Banana', + value: 'banana', + }, + { + label: 'Orange', + value: 'orange', + }, + ]; + + const [value, setValue] = useState('apple'); + + return ( + setValue(newValue)}> + {items.map(({ label: itemLabel, value: itemValue }) => ( + + ))} + + ); +} + +export function Disabled() { + const items = [ + { + description: 'A red fruit', + disabled: false, + label: 'Apple', + value: 'apple', + }, + { + description: 'A yellow fruit', + disabled: true, + label: 'Banana', + value: 'banana', + }, + { + description: 'An orange fruit', + disabled: false, + label: 'Orange', + value: 'orange', + }, + ]; + + const [value, setValue] = useState('apple'); + + return ( +
+ setValue(newValue)}> + {items.map(({ label: itemLabel, value: itemValue }) => ( + + ))} + + + + {items.map( + ({ description, label: itemLabel, value: itemValue, disabled }) => ( + + ), + )} + +
+ ); +} + +export function ItemDescriptions() { + const items = [ + { + description: 'A red fruit', + label: 'Apple', + value: 'apple', + }, + { + description: 'A yellow fruit', + label: 'Banana', + value: 'banana', + }, + { + description: 'An orange fruit', + label: 'Orange', + value: 'orange', + }, + ]; + + const [value, setValue] = useState('apple'); + + return ( + setValue(newValue)}> + {items.map(({ description, label: itemLabel, value: itemValue }) => ( + + ))} + + ); +} + export function Orientation() { const items = [ { diff --git a/packages/ui/src/RadioList/RadioList.tsx b/packages/ui/src/RadioList/RadioList.tsx index 1d94fe8b..974491f1 100644 --- a/packages/ui/src/RadioList/RadioList.tsx +++ b/packages/ui/src/RadioList/RadioList.tsx @@ -1,5 +1,6 @@ import clsx from 'clsx'; import type { ChangeEvent } from 'react'; +import { useId } from 'react'; import { RadioListContext } from './RadioListContext'; import RadioListItem from './RadioListItem'; @@ -10,11 +11,13 @@ type Props = Readonly<{ children: ReadonlyArray>; defaultValue?: T; description?: string; + disabled?: boolean; isLabelHidden?: boolean; label: string; name?: string; onChange?: (value: T, event: ChangeEvent) => void; orientation?: RadioListOrientation; + required?: boolean; value?: T; }>; @@ -24,35 +27,47 @@ export default function RadioList({ children, defaultValue, description, + disabled, orientation = 'vertical', isLabelHidden, name, label, + required, value, onChange, }: Props) { + const labelId = useId(); return ( - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore TODO: Figure out how to type the onChange. - +
-
- +
+ {description && ( -

{description}

+

{description}

)}
-
- TODO -
- {children} -
-
+
+ {children} +
); diff --git a/packages/ui/src/RadioList/RadioListContext.ts b/packages/ui/src/RadioList/RadioListContext.ts index 6058bc09..0e23210f 100644 --- a/packages/ui/src/RadioList/RadioListContext.ts +++ b/packages/ui/src/RadioList/RadioListContext.ts @@ -3,6 +3,7 @@ import { createContext, useContext } from 'react'; type RadioListContextValue = { defaultValue?: T; + disabled?: boolean; name?: string; onChange?: ( value: T, diff --git a/packages/ui/src/RadioList/RadioListItem.tsx b/packages/ui/src/RadioList/RadioListItem.tsx index fd0e8c43..3b852a89 100644 --- a/packages/ui/src/RadioList/RadioListItem.tsx +++ b/packages/ui/src/RadioList/RadioListItem.tsx @@ -1,42 +1,78 @@ +import clsx from 'clsx'; import { useId } from 'react'; import { useRadioListContext } from './RadioListContext'; type Props = Readonly<{ - label?: string; + description?: string; + disabled?: boolean; + label: string; value: T; }>; -export default function RadioListItem({ label, value }: Props) { +export default function RadioListItem({ + description, + disabled: disabledProp = false, + label, + value, +}: Props) { const id = useId(); + const descriptionId = useId(); const context = useRadioListContext(); + const disabled = context?.disabled ?? disabledProp; return ( -
- { - context?.onChange?.(value, event); - } - : undefined - } - /> - +
+
+ { + context?.onChange?.(value, event); + } + : undefined + } + /> +
+
+ + {description && ( +

+ {description} +

+ )} +
); }