import React, { forwardRef, useId } from 'react'; import { cn } from '../../utils/cn'; export interface CheckboxProps extends Omit, 'size'> { /** * The label for the checkbox */ label?: React.ReactNode; /** * Description text shown below the checkbox */ description?: React.ReactNode; /** * Whether the checkbox is in an error state */ error?: boolean | string; /** * Size of the checkbox * @default 'md' */ size?: 'sm' | 'md' | 'lg'; /** * Whether the checkbox is indeterminate * @default false */ indeterminate?: boolean; /** * Help text shown below the checkbox */ helpText?: React.ReactNode; /** * Custom class for the container */ containerClassName?: string; /** * Custom class for the label */ labelClassName?: string; } export const Checkbox = forwardRef( ( { id, label, description, error, size = 'md', className, containerClassName, labelClassName, indeterminate = false, disabled, helpText, checked, ...props }, ref ) => { // Use React's useId hook for stable ID generation const generatedId = useId(); const checkboxId = id || `checkbox-${generatedId}`; // Set indeterminate property using a callback ref const checkboxRef = React.useCallback( (checkbox: HTMLInputElement | null) => { if (checkbox) { checkbox.indeterminate = indeterminate; // Forward the ref if provided if (typeof ref === 'function') { ref(checkbox); } else if (ref) { ref.current = checkbox; } } }, [indeterminate, ref] ); const isChecked = checked || props.defaultChecked || false; return (
{/* Visible indicator - shown when checked or indeterminate */} {(isChecked || indeterminate) && (
{isChecked && !indeterminate && ( )} {indeterminate && ( )}
)}
{label && ( )}
{(error || helpText) && (
{typeof error === 'string' ? error : helpText}
)}
); } ); Checkbox.displayName = 'Checkbox'; export default Checkbox;