import { ChangeEventHandler, Children, cloneElement, isValidElement, ReactElement, ReactNode, useCallback, useId, useRef, } from "react"; import clsx from "clsx"; import { useControlledState } from "@react-stately/utils"; import { Orientation } from "../orientation"; import { CheckboxProps } from "./checkbox"; import { getInputFieldClassNames } from "../input-field/get-input-field-class-names"; interface CheckboxGroupProps { children: ReactElement | ReactElement[]; orientation?: Orientation; className?: string; value?: (string | number)[]; defaultValue?: (string | number)[]; onChange?: (newValue: (string | number)[]) => void; label?: ReactNode; disabled?: boolean; readOnly?: boolean; invalid?: boolean; } export function CheckboxGroup(props: CheckboxGroupProps) { const { label, children, orientation = "vertical", value, defaultValue, onChange, className, disabled, readOnly, invalid, } = props; const ref = useRef(null); const labelId = useId(); const [selectedValues, setSelectedValues] = useControlledState( value, defaultValue || [], onChange ); const style = getInputFieldClassNames(props); const handleCheckboxToggle: ChangeEventHandler = useCallback( (e) => { const c = e.currentTarget.value; const i = selectedValues.indexOf(c); if (i > -1) { selectedValues.splice(i, 1); } else { selectedValues.push(c); } setSelectedValues([...selectedValues]); }, [selectedValues, setSelectedValues] ); return (
{label && ( {label} )}
{Children.map(children, (child) => { if (isValidElement(child)) { return cloneElement(child, { disabled: child.props.disabled || disabled, readOnly: child.props.readOnly || readOnly, invalid: child.props.invalid || invalid, checked: selectedValues?.includes(child.props.value as string), onChange: handleCheckboxToggle, }); } })}
); }