new-personal-site/components/lib/form/Checkbox.tsx
Benjamin Toby 5587024789 Updates
2025-01-05 07:25:38 +01:00

99 lines
2.7 KiB
TypeScript

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>
);
}