78 lines
2.2 KiB
TypeScript
78 lines
2.2 KiB
TypeScript
import type { ReactNode } from 'react';
|
|
import { useId } from 'react';
|
|
import type { RadioGroupProps as AriaRadioGroupProps, RadioProps as AriaRadioProps } from 'react-aria-components';
|
|
import { Radio as AriaRadio, RadioGroup as AriaRadioGroup, composeRenderProps } from 'react-aria-components';
|
|
|
|
import clsx from 'clsx';
|
|
import { tv } from 'tailwind-variants';
|
|
|
|
export type RadioOption = {
|
|
value: string;
|
|
label: ReactNode;
|
|
isDisabled?: boolean;
|
|
};
|
|
|
|
export interface RadioGroupProps extends AriaRadioGroupProps {
|
|
items: RadioOption[];
|
|
}
|
|
|
|
export const RadioGroup = (props: RadioGroupProps) => {
|
|
const radioGroupId = useId();
|
|
const { items, className, value, ...restProps } = props;
|
|
return (
|
|
<AriaRadioGroup
|
|
className={clsx('flex gap-4 data-[orientation=vertical]:flex-col data-[orientation=vertical]:gap-3', className)}
|
|
value={value === '' ? null : value}
|
|
{...restProps}
|
|
>
|
|
{items.map((item) => {
|
|
return (
|
|
<Radio key={`radio_group-${radioGroupId}-${item.value}`} value={item.value} isDisabled={item.isDisabled}>
|
|
{item.label}
|
|
</Radio>
|
|
);
|
|
})}
|
|
</AriaRadioGroup>
|
|
);
|
|
};
|
|
|
|
interface RadioProps extends AriaRadioProps {}
|
|
|
|
const radioStyles = tv({
|
|
base: 'shrink-0 w-4 h-4 box-border rounded-full border-[1.5px] border-dabeeo-gray-be bg-white transition-all',
|
|
variants: {
|
|
isSelected: {
|
|
true: 'border-4 border-primary ',
|
|
},
|
|
isFocusVisible: {
|
|
true: 'ring-2 ring-offset-2 ring-primary',
|
|
},
|
|
isInvalid: {
|
|
true: 'border-dabeeo-red',
|
|
},
|
|
isDisabled: {
|
|
true: 'border-dabeeo-gray-be',
|
|
},
|
|
},
|
|
compoundVariants: [{ isDisabled: true, isSelected: false, className: 'bg-dabeeo-gray-eb' }],
|
|
});
|
|
export const Radio = (props: RadioProps) => {
|
|
const { className, ...restProps } = props;
|
|
return (
|
|
<AriaRadio
|
|
className={clsx(
|
|
'inline-flex items-center gap-2.5 text-dabeeo-black-22 text-sm font-medium data-disabled:text-dabeeo-gray-be',
|
|
className
|
|
)}
|
|
{...restProps}
|
|
>
|
|
{composeRenderProps(props.children, (children, renderProps) => (
|
|
<>
|
|
<div className={radioStyles(renderProps)} />
|
|
{children}
|
|
</>
|
|
))}
|
|
</AriaRadio>
|
|
);
|
|
};
|