"use client"; import * as React from "react"; import { cn } from "../../lib/utils"; // Assuming 'cn' utility is correctly set up export interface SwitchProps extends Omit< React.InputHTMLAttributes, "onChange" | "size" > { onCheckedChange?: (checked: boolean) => void; size?: "sm" | "md" | "lg"; thumbColor?: string; trackColor?: string; animation?: "smooth" | "bounce" | "slide"; } const Switch = React.forwardRef( ( { className, onCheckedChange, checked, defaultChecked, size = "md", thumbColor, trackColor, animation = "smooth", ...props }, ref ) => { // Manages the internal checked state of the switch const [isChecked, setIsChecked] = React.useState( checked !== undefined ? checked : defaultChecked || false ); // Synchronizes internal state with external 'checked' prop for controlled components React.useEffect(() => { if (checked !== undefined) { setIsChecked(checked); } }, [checked]); // Defines Tailwind CSS classes for different switch sizes const sizeClasses = { sm: { track: "h-4 w-8", thumb: "h-3 w-3", translate: "translate-x-4", // Tailwind class for thumb movement }, md: { track: "h-6 w-11", thumb: "h-5 w-5", translate: "translate-x-5", // Tailwind class for thumb movement }, lg: { track: "h-8 w-14", thumb: "h-7 w-7", translate: "translate-x-6", // Tailwind class for thumb movement }, }; // Defines Tailwind CSS classes for different animation types const animationClasses = { smooth: { transition: "transition-transform duration-200 ease-in-out" }, // Note: "ease-spring" is not a standard CSS easing function. // For a true spring animation, you'd typically need a CSS keyframe animation // or a JavaScript animation library. Using ease-in-out for demonstration. bounce: { transition: "transition-transform duration-300 ease-in-out" }, slide: { transition: "transition-all duration-300 ease-out" }, }; // Handles changes from the hidden native checkbox input const handleChange = (event: React.ChangeEvent) => { const newChecked = event.target.checked; // Only update internal state if the component is uncontrolled if (checked === undefined) { setIsChecked(newChecked); } // Call the external onCheckedChange handler onCheckedChange?.(newChecked); }; // Handles clicks on the main div, simulating checkbox behavior const handleClick = () => { if (!props.disabled) { const newChecked = !isChecked; // Only update internal state if the component is uncontrolled if (checked === undefined) { setIsChecked(newChecked); } // Call the external onCheckedChange handler onCheckedChange?.(newChecked); } }; // Apply custom track color dynamically based on isChecked state // The default Tailwind 'bg-primary' or 'bg-input' will be overridden if trackColor is provided. const customTrackStyle = trackColor ? { backgroundColor: isChecked ? trackColor : undefined } // Only applies custom color when checked : {}; // Apply custom thumb color if provided const customThumbStyle = thumbColor ? { backgroundColor: thumbColor } : {}; return (
{/* Hidden native checkbox to handle form submissions and accessibility */} {/* The thumb element that visually moves */}
); } ); Switch.displayName = "Switch"; export { Switch };