visual-novel-web/src/components/ui/inputs/switch.tsx

59 lines
1.8 KiB
TypeScript
Raw Normal View History

2025-10-28 07:59:26 +00:00
'use client';
import { cn } from '@/lib';
import { useControllableValue } from 'ahooks';
import { InputLeft } from '.';
2025-11-03 10:03:34 +00:00
import { Switch as SwitchPrimitive } from 'radix-ui';
2025-10-28 07:59:26 +00:00
const { Root, Thumb } = SwitchPrimitive;
type SwitchProps = {
value?: boolean;
onChange?: (value: boolean) => void;
icon?: any;
text?: string;
} & React.HTMLAttributes<HTMLDivElement>;
export default function Switch(props: SwitchProps) {
2025-11-04 10:42:16 +00:00
const {
icon,
text,
onChange: onChangeProps,
value: valueProps,
...rest
} = props;
2025-10-28 07:59:26 +00:00
const [value, onChange] = useControllableValue(props);
2025-11-04 10:42:16 +00:00
2025-10-28 07:59:26 +00:00
return (
<div {...rest} className={cn('input-view justify-between', rest.className)}>
<InputLeft icon={icon} text={text} />
<Root
checked={value}
onCheckedChange={onChange}
className={cn(
'relative inline-flex h-[28px] w-[52px] shrink-0 items-center',
'cursor-pointer rounded-full',
'transition-colors duration-200 ease-in-out',
'focus-visible:ring-2 focus-visible:ring-white/20 focus-visible:outline-none',
'disabled:cursor-not-allowed disabled:opacity-50',
// 未选中状态 - 灰色背景
'bg-white/20',
// 选中状态 - 绿色背景
'data-[state=checked]:bg-[rgb(0,110,74)]' // 注意RGB 值之间不能有空格
)}
>
<Thumb
className={cn(
'pointer-events-none block h-[24px] w-[24px] rounded-full',
'bg-white shadow-lg',
'transition-transform duration-200 ease-in-out',
// 未选中时在左侧2px 偏移)
'translate-x-[2px]',
// 选中时移到右侧52px - 24px - 2px = 26px
'data-[state=checked]:translate-x-[26px]'
)}
/>
</Root>
</div>
);
}