import Fieldset, { type FieldsetProps, } from '@components/molecules/forms/fieldset'; import useStateChange from '@utils/hooks/use-state-change'; import { ChangeEvent, FC, MouseEvent, SetStateAction } from 'react'; import LabelledBooleanField, { type LabelledBooleanFieldProps, } from './labelled-boolean-field'; import styles from './radio-group.module.scss'; export type RadioGroupCallbackProps = { choices: { new: string; prev: string; }; updateChoice: (value: SetStateAction) => void; }; export type RadioGroupCallback = (props: RadioGroupCallbackProps) => void; export type RadioGroupOption = Pick< LabelledBooleanFieldProps, 'id' | 'label' | 'name' | 'value' >; export type RadioGroupProps = Pick< FieldsetProps, 'bodyClassName' | 'className' | 'legend' | 'legendClassName' | 'Tooltip' > & Pick & { /** * Set additional classnames to the radio group wrapper when kind is toggle. */ groupClassName?: string; /** * The default option value. */ initialChoice: string; /** * The radio group kind. * * @default 'regular */ kind?: 'regular' | 'toggle'; /** * The legend position. * * @default 'inline' */ legendPosition?: FieldsetProps['legendPosition']; /** * A callback function to execute when choice is changed. */ onChange?: RadioGroupCallback; /** * A callback function to execute when clicking on a choice. */ onClick?: RadioGroupCallback; /** * Set additional classnames to the labelled field wrapper. */ optionClassName?: string; /** * The options. */ options: RadioGroupOption[]; }; /** * RadioGroup component * * Render a group of labelled radio buttons. */ const RadioGroup: FC = ({ className, groupClassName = '', initialChoice, kind = 'regular', labelPosition, labelSize, legendPosition = 'inline', onChange, optionClassName = '', options, ...props }) => { const [selectedChoice, setSelectedChoice] = useStateChange(initialChoice); const isToggle = kind === 'toggle'; const alignmentModifier = `wrapper--${legendPosition}`; const toggleModifier = isToggle ? 'wrapper--toggle' : 'wrapper--regular'; /** * Update the selected choice on click or change event. */ const updateChoice = ( e: | ChangeEvent | MouseEvent ) => { const input = e.target as HTMLInputElement; onChange && onChange({ choices: { new: input.value, prev: selectedChoice }, updateChoice: setSelectedChoice, }); if (e.type === 'change') setSelectedChoice(input.value); }; /** * Retrieve an array of radio buttons. * * @returns {JSX.Element[]} The radio buttons. */ const getOptions = (): JSX.Element[] => { return options.map((option) => (