168 lines
5.1 KiB
TypeScript
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>
|
|
);
|
|
};
|