109 lines
3.2 KiB
TypeScript
109 lines
3.2 KiB
TypeScript
"use client";
|
|
|
|
import { cn } from "@core/lib/utils";
|
|
import * as React from "react";
|
|
|
|
export interface CustomCheckboxProps {
|
|
id: string;
|
|
name?: string;
|
|
label: string;
|
|
checked?: boolean;
|
|
onChange?: (checked: boolean) => void;
|
|
variant?: "primary" | "info" | "error";
|
|
disabled?: boolean;
|
|
error?: string;
|
|
}
|
|
|
|
const CustomCheckbox = React.forwardRef<HTMLInputElement, CustomCheckboxProps>(
|
|
(
|
|
{
|
|
id,
|
|
name,
|
|
label,
|
|
checked,
|
|
onChange,
|
|
variant = "primary",
|
|
disabled,
|
|
error,
|
|
},
|
|
ref
|
|
) => {
|
|
const finalVariant = error ? "error" : variant;
|
|
|
|
return (
|
|
<div className="flex flex-col gap-1">
|
|
<div className="flex items-center gap-3">
|
|
<div className="relative flex items-center">
|
|
<input
|
|
type="checkbox"
|
|
id={id}
|
|
name={name}
|
|
checked={checked}
|
|
onChange={(e) => onChange?.(e.target.checked)}
|
|
disabled={disabled}
|
|
ref={ref}
|
|
className={cn(
|
|
"peer h-5 w-5 cursor-pointer appearance-none rounded border-2 transition-all duration-200 checked:border-0 disabled:cursor-not-allowed disabled:opacity-50",
|
|
{
|
|
"border-blue-600 checked:bg-blue-600":
|
|
finalVariant === "primary" && !disabled,
|
|
"border-cyan-600 checked:bg-cyan-600":
|
|
finalVariant === "info" && !disabled,
|
|
"border-red-600 checked:bg-red-600":
|
|
finalVariant === "error" && !disabled,
|
|
"border-gray-300 checked:bg-gray-400": disabled,
|
|
}
|
|
)}
|
|
/>
|
|
<svg
|
|
className="pointer-events-none absolute left-1/2 top-1/2 h-3.5 w-3.5 -translate-x-1/2 -translate-y-1/2 text-white opacity-0 transition-opacity duration-200 peer-checked:opacity-100"
|
|
fill="none"
|
|
strokeWidth="3"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
d="M4.5 12.75l6 6 9-13.5"
|
|
/>
|
|
</svg>
|
|
</div>
|
|
<label
|
|
htmlFor={id}
|
|
className={cn(
|
|
"cursor-pointer text-sm font-medium transition-colors",
|
|
disabled
|
|
? "cursor-not-allowed text-gray-400"
|
|
: "text-foreground hover:text-foreground/80"
|
|
)}
|
|
>
|
|
{label}
|
|
</label>
|
|
</div>
|
|
{error && (
|
|
<p className="ml-8 text-sm text-red-600 flex items-center gap-1">
|
|
<svg
|
|
className="h-4 w-4"
|
|
fill="none"
|
|
strokeWidth="2"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z"
|
|
/>
|
|
</svg>
|
|
{error}
|
|
</p>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
);
|
|
CustomCheckbox.displayName = "CustomCheckbox";
|
|
|
|
export { CustomCheckbox };
|