import React, { DetailedHTMLProps, HTMLAttributes, InputHTMLAttributes, ReactNode, } from "react"; import { twMerge } from "tailwind-merge"; import CheckMarkSVG from "../svgs/CheckMarkSVG"; export type CheckboxProps = DetailedHTMLProps< InputHTMLAttributes<HTMLInputElement>, HTMLInputElement > & { name: string; wrapperProps?: DetailedHTMLProps< HTMLAttributes<HTMLDivElement>, HTMLDivElement >; label?: string | ReactNode; labelProps?: DetailedHTMLProps< HTMLAttributes<HTMLLabelElement>, HTMLLabelElement >; defaultChecked?: boolean; wrapperClassName?: string; setChecked?: React.Dispatch<React.SetStateAction<boolean>>; }; /** * # Checkbox Component * @className twui-checkbox * @className twui-checkbox-checked * @className twui-checkbox-unchecked */ export default function Checkbox({ wrapperProps, label, labelProps, size, name, wrapperClassName, defaultChecked, setChecked, ...props }: CheckboxProps) { const finalSize = size || 20; const [internalChecked, setInternalChecked] = React.useState( defaultChecked || false ); const checkMarkRef = React.useRef<HTMLInputElement>(); return ( <div {...wrapperProps} onClick={(e) => { checkMarkRef.current?.click(); wrapperProps?.onClick?.(e); }} className={twMerge( "flex items-center gap-2", wrapperClassName, wrapperProps?.className )} > <input type="checkbox" {...props} width={finalSize} height={finalSize} className={twMerge("hidden")} name={name} onChange={(e) => { setInternalChecked(e.target.checked); setChecked?.(e.target.checked); }} ref={checkMarkRef as any} /> <div className={twMerge( "flex items-center justify-center p-[3px] rounded", internalChecked ? "bg-emerald-700 twui-checkbox-checked" : "outline-slate-600 dark:outline-white/50 outline-2 outline -outline-offset-2 twui-checkbox-unchecked", "twui-checkbox" )} style={{ width: finalSize + "px", height: finalSize + "px", }} > {internalChecked && <CheckMarkSVG />} </div> {label && <label>{label}</label>} </div> ); }