import * as React from "react"; import { AriaRadioGroupProps, AriaRadioProps, useRadio, useRadioGroup } from "react-aria"; import { RadioGroupState, useRadioGroupState } from "react-stately"; import { animated, useSpring } from "@react-spring/web"; import { Clickable } from "../Clickable/Clickable"; import { Control, ControlInputProps } from "../Control/Control"; import { InputStatus, useInputColorToken } from "../Input/Input"; import { Stack } from "../Stack/Stack"; import { Text } from "../Text/Text"; import { useResolvedColorToken } from "../ThemeProvider/ThemeProvider"; import styles from "./RadioGroup.module.css"; const DOT_SPRING_CONFIG = { tension: 400, friction: 20, }; interface RadioGroupContextState { state: RadioGroupState | undefined; status: InputStatus; } const RadioGroupContext = React.createContext({ state: undefined, status: "default", }); export interface RadioItemProps extends AriaRadioProps { status?: InputStatus; } export function RadioItem(props: RadioItemProps) { const context = React.useContext(RadioGroupContext); const { status = context.status, children } = props; const ref = React.useRef(null); const { inputProps, isSelected } = useRadio(props, context.state!, ref); const inputColor = useInputColorToken(status, "color"); const defaultBackgroundColor = useResolvedColorToken("BACKGROUND_ACCENT").rgba; const resolvedColor = inputColor === "transparent" ? inputColor : inputColor.rawColor; const [{ opacity, transform, backgroundColor }] = useSpring( () => ({ backgroundColor: isSelected ? resolvedColor : defaultBackgroundColor, opacity: isSelected ? 1 : 0, transform: `scale(${isSelected ? 1 : 1.5})`, config: (key) => ({ ...DOT_SPRING_CONFIG, friction: key === "backgroundColor" ? DOT_SPRING_CONFIG.friction - 15 : DOT_SPRING_CONFIG.friction, clamp: key === "backgroundColor", }), }), [isSelected, defaultBackgroundColor, resolvedColor], ); const labelNode = typeof children === "string" ? ( {children} ) : (
{children}
); return ( {labelNode} ); } export interface RadioGroupProps extends AriaRadioGroupProps, ControlInputProps { status?: InputStatus; children: React.ReactElement | React.ReactElement[]; } export function RadioGroup(props: RadioGroupProps) { const { status = "default", children } = props; const state = useRadioGroupState(props); const { radioGroupProps, labelProps, descriptionProps, errorMessageProps } = useRadioGroup( props, state, ); const context = React.useMemo(() => ({ state, status }), [state, status]); return ( {children} ); }