import { faCheck, faMinus } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { ReactNode, useId } from "react"; import { FieldSize, useErrorPulse, useShake } from "./fieldShell"; export interface CheckboxProps { checked: boolean; onChange: (checked: boolean) => void; label?: ReactNode; description?: ReactNode; /** Render a dash instead of a check (mixed state). Visual only. */ indeterminate?: boolean; /** Error message; flips the box to the error colour and shakes it. */ error?: ReactNode; size?: FieldSize; disabled?: boolean; className?: string; ariaLabel?: string; } const BOX: Record = { sm: "w-4 h-4", md: "w-5 h-5", lg: "w-6 h-6", }; const ICON: Record = { sm: "text-[9px]", md: "text-[11px]", lg: "text-sm", }; const LABEL_TEXT: Record = { sm: "text-sm", md: "text-sm", lg: "text-base", }; /** A checkbox whose checked state fills with the primary colour (not the default grey). */ export default function Checkbox({ checked, onChange, label, description, indeterminate = false, error, size = "md", disabled = false, className = "", ariaLabel, }: CheckboxProps) { const labelId = useId(); const { ref: shakeRef, shake } = useShake(); useErrorPulse(error, shake); const active = checked || indeterminate; const hasError = Boolean(error); const box = ( ); if (!label && !description) { return
{box}
; } return (
{box}
{label && ( {label} )} {description && {description}} {hasError && {error}}
); }