import type { ReactNode } from "react"; import type { SwitchProps as AriaSwitchProps } from "react-aria-components"; import { Switch as AriaSwitch } from "react-aria-components"; import { cx } from "@/utils/cx"; interface ToggleBaseProps { size?: "sm" | "md"; slim?: boolean; className?: string; isHovered?: boolean; isFocusVisible?: boolean; isSelected?: boolean; isDisabled?: boolean; } export const ToggleBase = ({ className, isHovered, isDisabled, isFocusVisible, isSelected, slim, size = "sm" }: ToggleBaseProps) => { const styles = { default: { sm: { root: "h-5 w-9 p-0.5", switch: cx("size-4", isSelected && "translate-x-4"), }, md: { root: "h-6 w-11 p-0.5", switch: cx("size-5", isSelected && "translate-x-5"), }, }, slim: { sm: { root: "h-4 w-8", switch: cx("size-4", isSelected && "translate-x-4"), }, md: { root: "h-5 w-10", switch: cx("size-5", isSelected && "translate-x-5"), }, }, }; const classes = slim ? styles.slim[size] : styles.default[size]; return (
); }; interface ToggleProps extends AriaSwitchProps { size?: "sm" | "md"; label?: string; hint?: ReactNode; slim?: boolean; } export const Toggle = ({ label, hint, className, size = "sm", slim, ...ariaSwitchProps }: ToggleProps) => { const sizes = { sm: { root: "gap-2", textWrapper: "", label: "text-sm font-medium", hint: "text-sm", }, md: { root: "gap-3", textWrapper: "gap-0.5", label: "text-md font-medium", hint: "text-md", }, }; return ( cx( "flex w-max items-start", renderProps.isDisabled && "cursor-not-allowed", sizes[size].root, typeof className === "function" ? className(renderProps) : className, ) } > {({ isSelected, isDisabled, isFocusVisible, isHovered }) => ( <> {(label || hint) && (
{label &&

{label}

} {hint && ( event.stopPropagation()}> {hint} )}
)} )}
); };