Files
LiquidCode_Frontend/src/components/checkbox/Checkbox.tsx
Виталий Лавшонок 4972836164 formatting
2025-11-04 15:04:59 +03:00

168 lines
5.1 KiB
TypeScript

import React from 'react';
import { cn } from '../../lib/cn';
import { motion } from 'framer-motion';
const pathVariants = {
hidden: {
opacity: 0,
pathLength: 0,
},
visible: {
opacity: 1,
pathLength: 1,
transition: {
delay: 0.15,
duration: 0.4,
ease: 'easeInOut',
},
},
};
const sizeVariants = {
sm: 'h-4 w-4',
md: 'h-5 w-5',
lg: 'h-6 w-6',
};
const colorsVariants = {
default: 'bg-default',
primary: 'bg-liquid-brightmain',
secondary: 'bg-liquid-darkmain',
success: 'bg-liquid-green',
warning: 'bg-liquid-orange',
danger: 'bg-liquid-red',
};
const borderColorsVariants = {
default: 'border-default',
primary: 'border-liquid-brightmain',
secondary: 'border-liquid-darkmain',
success: 'border-liquid-green',
warning: 'border-liquid-orange',
danger: 'border-liquid-red',
};
const focuseOutlineVariants = {
default: '[&:focus-visible+*]:outline-default',
primary: '[&:focus-visible+*]:outline-liquid-brightmain',
secondary: '[&:focus-visible+*]:outline-liquid-darkmain',
success: '[&:focus-visible+*]:outline-liquid-green',
warning: '[&:focus-visible+*]:outline-liquid-orange',
danger: '[&:focus-visible+*]:outline-liquid-red',
};
const radiusVraiants = {
none: '',
sm: 'rounded-[3.5px]',
md: 'rounded-[5px]',
lg: 'rounded-[7px]',
full: 'rounded-full',
};
interface CheckboxProps {
size?: 'sm' | 'md' | 'lg';
radius?: 'none' | 'sm' | 'md' | 'lg' | 'full';
disabled?: boolean;
color?:
| 'default'
| 'primary'
| 'secondary'
| 'success'
| 'warning'
| 'danger';
label?: string;
variant?: 'default' | 'label';
className?: string;
defaultState?: boolean;
onChange: (state: boolean) => void;
}
export const Checkbox: React.FC<CheckboxProps> = ({
size = 'md',
radius = 'md',
disabled = false,
color = 'primary',
label = '',
variant = 'label',
className,
onChange,
defaultState = false,
}) => {
const [active, setActive] = React.useState<boolean>(defaultState);
React.useEffect(() => onChange(active), [active]);
return (
<motion.label
className={cn(
variant == 'label' && 'grid-cols-[auto_1fr] items-center gap-2',
'grid relative cursor-pointer p-2 select-none group ',
className,
disabled && 'pointer-events-none opacity-50',
variant == 'default' && '',
)}
>
<div
className={cn(
'group-hover:bg-default-100 group-active:scale-90 flex items-center justify-center bg-transparent hover:bg-default-100 box-border border-solid border-[1px] border-liquid-white z-10 relative transition-all duration-300',
sizeVariants[size],
radiusVraiants[radius],
active && borderColorsVariants[color],
)}
>
<input
className={cn(
'absolute opacity-0 -z-10 h-0 w-0',
focuseOutlineVariants[color],
)}
disabled={disabled}
type="checkbox"
onChange={() => {
setActive(!active);
}}
/>
<div
className={cn(
'absolute outline-offset-[2.5px] outline-[2.5px] outline outline-transparent transition-all duration-200',
sizeVariants[size],
radiusVraiants[radius],
)}
></div>
<span
className={cn(
'absolute transition-all duration-300',
sizeVariants[size],
colorsVariants[color],
radiusVraiants[radius],
active && 'opacity-100 scale-100',
!active && 'opacity-0 scale-0',
)}
>
<svg
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
{active && (
<motion.path
strokeWidth="1.5"
d="M5 8.22L7.66571 10.44L11.22 6"
stroke="white"
strokeLinecap="round"
variants={pathVariants}
initial="hidden"
animate="visible"
/>
)}
</svg>
</span>
</div>
{variant == 'label' && (
<div className="select-none text-layout-foeground transition-all duration-200">
{label}
</div>
)}
</motion.label>
);
};