import { forwardRef, useEffect, useId, useRef, type InputHTMLAttributes, type ReactNode } from "react"; import { cx } from "../../utils/cx"; export interface CheckboxProps extends Omit, "type"> { /** Visible label. Use `aria-label` instead only when a visible label is impossible (e.g. table rows). */ label?: ReactNode; description?: ReactNode; /** Mixed state, e.g. a "select all" box when only some rows are selected. */ indeterminate?: boolean; } export const Checkbox = forwardRef(function Checkbox( { label, description, indeterminate = false, id, className, ...rest }, forwardedRef ) { const generated = useId(); const inputId = id ?? `fp-checkbox-${generated}`; const descriptionId = `${inputId}-description`; const innerRef = useRef(null); // `indeterminate` is a DOM property only; it can't be set through an attribute. useEffect(() => { if (innerRef.current) innerRef.current.indeterminate = indeterminate; }, [indeterminate]); const setRefs = (node: HTMLInputElement | null) => { innerRef.current = node; if (typeof forwardedRef === "function") forwardedRef(node); else if (forwardedRef) forwardedRef.current = node; }; const input = ( ); if (!label) { return {input}; } return (
{input} {description && (

{description}

)}
); });