Spaces:
Paused
Paused
| "use client"; | |
| import { cn } from "@/shared/utils/cn"; | |
| interface ToggleProps { | |
| checked?: boolean; | |
| onChange?: (checked: boolean) => void; | |
| label?: string; | |
| description?: string; | |
| disabled?: boolean; | |
| size?: "sm" | "md" | "lg"; | |
| className?: string; | |
| title?: string; | |
| } | |
| export default function Toggle({ | |
| checked = false, | |
| onChange, | |
| label, | |
| description, | |
| disabled = false, | |
| size = "md", | |
| className, | |
| }: ToggleProps) { | |
| const sizes = { | |
| sm: { | |
| track: "w-8 h-4", | |
| thumb: "size-3", | |
| translate: "translate-x-4", | |
| }, | |
| md: { | |
| track: "w-11 h-6", | |
| thumb: "size-5", | |
| translate: "translate-x-5", | |
| }, | |
| lg: { | |
| track: "w-14 h-7", | |
| thumb: "size-6", | |
| translate: "translate-x-7", | |
| }, | |
| }; | |
| const handleClick = () => { | |
| if (!disabled && onChange) { | |
| onChange(!checked); | |
| } | |
| }; | |
| return ( | |
| <div | |
| className={cn( | |
| "flex items-center gap-3", | |
| disabled && "opacity-50 cursor-not-allowed", | |
| className | |
| )} | |
| > | |
| <button | |
| type="button" | |
| role="switch" | |
| aria-checked={checked} | |
| aria-label={!label ? description || "Toggle" : undefined} | |
| disabled={disabled} | |
| onClick={handleClick} | |
| className={cn( | |
| "relative inline-flex shrink-0 cursor-pointer rounded-full", | |
| "transition-colors duration-200 ease-in-out", | |
| "focus:outline-none focus:ring-1 focus:ring-primary/30", | |
| checked ? "bg-primary" : "bg-black/10 dark:bg-white/20", | |
| sizes[size].track, | |
| disabled && "cursor-not-allowed" | |
| )} | |
| > | |
| <span | |
| aria-hidden="true" | |
| className={cn( | |
| "pointer-events-none inline-block rounded-full bg-white shadow-sm", | |
| "transform transition duration-200 ease-in-out", | |
| checked ? sizes[size].translate : "translate-x-0.5", | |
| sizes[size].thumb, | |
| "mt-0.5" | |
| )} | |
| /> | |
| </button> | |
| {(label || description) && ( | |
| <div className="flex flex-col"> | |
| {label && <span className="text-sm font-medium text-text-main">{label}</span>} | |
| {description && <span className="text-xs text-text-muted">{description}</span>} | |
| </div> | |
| )} | |
| </div> | |
| ); | |
| } | |