Files
suaveplan/packages/ui/react/react-ui/src/components/radio-group/radio-group.tsx
2026-05-27 23:47:53 +01:00

79 lines
2.6 KiB
TypeScript

import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
import { CircleIcon } from "lucide-react";
import { type ComponentRef, forwardRef, type ReactElement } from "react";
import { useThemedVariants } from "../../theme/use-themed-variants/use-themed-variants.js";
import { cn } from "../../utils/cn/cn.js";
import type {
RadioGroupItemProps,
RadioGroupProps,
} from "./radio-group.types.js";
import {
radioGroupItemVariants,
radioGroupVariants,
} from "./radio-group.variants.js";
/**
* `<RadioGroup>` — chassis radio-group container built on
* `@radix-ui/react-radio-group`.
*
* Radix supplies the a11y semantics (`role="radiogroup"`, roving
* tabindex across items, arrow-key navigation, native `Space`
* activation, controlled `value` propagation). The chassis layers a
* vertical-stack flex/gap layout via cva.
*
* Per shadcn convention, items always sit inside the group via
* `<RadioGroupItem>`; rendering an item without a group is
* unsupported.
*/
export const RadioGroup = forwardRef<
ComponentRef<typeof RadioGroupPrimitive.Root>,
RadioGroupProps
>(function RadioGroup(props, ref): ReactElement {
const { className, ...rest } = props;
const variants = useThemedVariants("RadioGroup", radioGroupVariants);
const classes = cn(variants(), className);
return <RadioGroupPrimitive.Root ref={ref} className={classes} {...rest} />;
});
RadioGroup.displayName = "RadioGroup";
/**
* `<RadioGroupItem>` — single radio inside `<RadioGroup>`. Renders a
* Radix Item containing the circular indicator (`<CircleIcon>` filled
* with the current text colour) when checked.
*
* Refs are forwarded to the Radix Item (the rendered `<button>`).
*/
export const RadioGroupItem = forwardRef<
ComponentRef<typeof RadioGroupPrimitive.Item>,
RadioGroupItemProps
>(function RadioGroupItem(props, ref): ReactElement {
const { className, size, ...rest } = props;
const variants = useThemedVariants(
"RadioGroupItem",
radioGroupItemVariants
);
const classes = cn(variants({ size }), className);
return (
<RadioGroupPrimitive.Item ref={ref} className={classes} {...rest}>
<RadioGroupPrimitive.Indicator
className="flex items-center justify-center"
data-icon="indicator"
>
<CircleIcon
className="h-2 w-2 fill-current text-current"
data-icon="dot"
/>
</RadioGroupPrimitive.Indicator>
</RadioGroupPrimitive.Item>
);
});
RadioGroupItem.displayName = "RadioGroupItem";
export { radioGroupItemVariants, radioGroupVariants };