71 lines
2.4 KiB
TypeScript
71 lines
2.4 KiB
TypeScript
// frontend\src\components\ui\Checkbox.tsx
|
|
|
|
'use client'
|
|
|
|
import { useEffect, useRef } from 'react'
|
|
|
|
type Props = {
|
|
checked: boolean
|
|
indeterminate?: boolean
|
|
disabled?: boolean
|
|
onChange: (checked: boolean) => void
|
|
ariaLabel?: string
|
|
id?: string
|
|
name?: string
|
|
className?: string
|
|
}
|
|
|
|
export default function Checkbox({
|
|
checked,
|
|
indeterminate = false,
|
|
disabled = false,
|
|
onChange,
|
|
ariaLabel,
|
|
id,
|
|
name,
|
|
className = '',
|
|
}: Props) {
|
|
const ref = useRef<HTMLInputElement | null>(null)
|
|
|
|
useEffect(() => {
|
|
if (ref.current) {
|
|
ref.current.indeterminate = indeterminate && !checked
|
|
}
|
|
}, [indeterminate, checked])
|
|
|
|
return (
|
|
<div className={['relative z-0 group grid size-4 grid-cols-1', className].filter(Boolean).join(' ')}>
|
|
<input
|
|
ref={ref}
|
|
id={id}
|
|
name={name}
|
|
type="checkbox"
|
|
checked={checked}
|
|
disabled={disabled}
|
|
aria-label={ariaLabel}
|
|
onChange={(e) => onChange(e.target.checked)}
|
|
className="col-start-1 row-start-1 appearance-none rounded-sm border border-gray-300 bg-white checked:border-indigo-600 checked:bg-indigo-600 indeterminate:border-indigo-600 indeterminate:bg-indigo-600 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 disabled:border-gray-300 disabled:bg-gray-100 disabled:checked:bg-gray-100 dark:border-white/20 dark:bg-gray-900 dark:checked:border-indigo-500 dark:checked:bg-indigo-500 dark:indeterminate:border-indigo-500 dark:indeterminate:bg-indigo-500 dark:focus-visible:outline-indigo-500 dark:disabled:border-white/10 dark:disabled:bg-white/10 dark:disabled:checked:bg-white/10 forced-colors:appearance-auto"
|
|
/>
|
|
<svg
|
|
fill="none"
|
|
viewBox="0 0 14 14"
|
|
className="pointer-events-none col-start-1 row-start-1 size-3.5 self-center justify-self-center stroke-white group-has-disabled:stroke-gray-950/25 dark:group-has-disabled:stroke-white/25"
|
|
>
|
|
<path
|
|
d="M3 8L6 11L11 3.5"
|
|
strokeWidth={2}
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
className="opacity-0 group-has-checked:opacity-100"
|
|
/>
|
|
<path
|
|
d="M3 7H11"
|
|
strokeWidth={2}
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
className="opacity-0 group-has-indeterminate:opacity-100"
|
|
/>
|
|
</svg>
|
|
</div>
|
|
)
|
|
} |