️ feat: implement card style for radio

This commit is contained in:
Andre H 2024-03-01 10:41:12 +08:00
parent d9392c095d
commit a8ad6c6eec
3 changed files with 47 additions and 10 deletions

View File

@ -2,7 +2,7 @@ import { VariantProps, tv } from 'tailwind-variants';
export const radioTheme = tv({
slots: {
root: ['flex', 'gap-3', 'flex-wrap'],
root: ['flex', 'gap-3'],
wrapper: ['flex', 'items-center', 'gap-2', 'group'],
label: ['text-sm', 'tracking-[-0.006em]', 'text-elements-high-em'],
radio: [
@ -39,15 +39,34 @@ export const radioTheme = tv({
'after:data-[state=checked]:group-hover:bg-elements-on-primary',
'after:data-[state=checked]:group-focus-visible:bg-elements-on-primary',
],
icon: ['w-[18px]', 'h-[18px]'],
},
variants: {
orientation: {
vertical: { root: ['flex-col'] },
horizontal: { root: ['flex-row'] },
},
variant: {
unstyled: {},
card: {
wrapper: [
'px-4',
'py-3',
'rounded-lg',
'border',
'border-border-interactive',
'bg-controls-tertiary',
'shadow-button',
'w-full',
'cursor-pointer',
],
label: ['select-none', 'cursor-pointer'],
},
},
},
defaultVariants: {
orientation: 'vertical',
variant: 'unstyled',
},
});

View File

@ -49,14 +49,15 @@ export const Radio = ({
className,
options,
orientation,
variant,
...props
}: RadioProps) => {
const { root } = radioTheme({ orientation });
const { root } = radioTheme({ orientation, variant });
return (
<RadixRoot {...props} className={root({ className })}>
{options.map((option) => (
<RadioItem key={option.value} {...option} />
<RadioItem key={option.value} variant={variant} {...option} />
))}
</RadixRoot>
);

View File

@ -1,13 +1,16 @@
import React, { ComponentPropsWithoutRef } from 'react';
import React, { ReactNode, ComponentPropsWithoutRef } from 'react';
import {
Item as RadixRadio,
Indicator as RadixIndicator,
RadioGroupItemProps,
RadioGroupIndicatorProps,
} from '@radix-ui/react-radio-group';
import { radioTheme } from './Radio.theme';
import { RadioTheme, radioTheme } from './Radio.theme';
import { cloneIcon } from 'utils/cloneIcon';
export interface RadioItemProps extends RadioGroupItemProps {
export interface RadioItemProps
extends RadioGroupItemProps,
Pick<RadioTheme, 'variant'> {
/**
* The wrapper props of the radio item.
* You can use this prop to customize the wrapper props.
@ -27,6 +30,10 @@ export interface RadioItemProps extends RadioGroupItemProps {
* The id of the radio item.
*/
id?: string;
/**
* The left icon of the radio item.
*/
leftIcon?: ReactNode;
/**
* The label of the radio item.
*/
@ -41,18 +48,26 @@ export const RadioItem = ({
wrapperProps,
labelProps,
indicatorProps,
leftIcon,
label,
id,
variant,
...props
}: RadioItemProps) => {
const { wrapper, label: labelClass, radio, indicator } = radioTheme();
const {
wrapper,
label: labelClass,
radio,
indicator,
icon,
} = radioTheme({ variant });
// Generate a unique id for the radio item from the label if the id is not provided
const kebabCaseLabel = label?.toLowerCase().replace(/\s+/g, '-');
const componentId = id ?? kebabCaseLabel;
return (
<div className={wrapper({ className: wrapperProps?.className })}>
<label className={wrapper({ className: wrapperProps?.className })}>
<RadixRadio {...props} className={radio({ className })} id={componentId}>
<RadixIndicator
forceMount
@ -60,15 +75,17 @@ export const RadioItem = ({
className={indicator({ className: indicatorProps?.className })}
/>
</RadixRadio>
{leftIcon &&
cloneIcon(leftIcon, { className: icon(), 'aria-hidden': true })}
{label && (
<label
{...labelProps}
className={labelClass({ className: labelProps?.className })}
htmlFor={componentId}
className={labelClass({ className: labelProps?.className })}
>
{label}
</label>
)}
</div>
</label>
);
};