|
|
@@ -0,0 +1,76 @@
|
|
|
+import { useState } from 'react'
|
|
|
+import { View } from '@tarojs/components'
|
|
|
+import { cn } from '@/utils/cn'
|
|
|
+
|
|
|
+interface SwitchProps {
|
|
|
+ checked?: boolean
|
|
|
+ onChange?: (checked: boolean) => void
|
|
|
+ disabled?: boolean
|
|
|
+ color?: string
|
|
|
+ size?: 'sm' | 'md' | 'lg'
|
|
|
+ className?: string
|
|
|
+}
|
|
|
+
|
|
|
+export function Switch({
|
|
|
+ checked = false,
|
|
|
+ onChange,
|
|
|
+ disabled = false,
|
|
|
+ color = '#1976D2',
|
|
|
+ size = 'md',
|
|
|
+ className,
|
|
|
+}: SwitchProps) {
|
|
|
+ const [isChecked, setIsChecked] = useState(checked)
|
|
|
+
|
|
|
+ const handleToggle = () => {
|
|
|
+ if (disabled) return
|
|
|
+
|
|
|
+ const newValue = !isChecked
|
|
|
+ setIsChecked(newValue)
|
|
|
+ onChange?.(newValue)
|
|
|
+ }
|
|
|
+
|
|
|
+ const sizes = {
|
|
|
+ sm: {
|
|
|
+ track: 'w-10 h-5',
|
|
|
+ thumb: 'w-4 h-4',
|
|
|
+ translate: 'translate-x-5',
|
|
|
+ },
|
|
|
+ md: {
|
|
|
+ track: 'w-12 h-6',
|
|
|
+ thumb: 'w-5 h-5',
|
|
|
+ translate: 'translate-x-6',
|
|
|
+ },
|
|
|
+ lg: {
|
|
|
+ track: 'w-14 h-7',
|
|
|
+ thumb: 'w-6 h-6',
|
|
|
+ translate: 'translate-x-7',
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ const currentSize = sizes[size]
|
|
|
+
|
|
|
+ return (
|
|
|
+ <View
|
|
|
+ className={cn(
|
|
|
+ 'relative inline-flex items-center rounded-full cursor-pointer transition-colors duration-200 ease-in-out',
|
|
|
+ currentSize.track,
|
|
|
+ isChecked ? '' : 'bg-gray-300',
|
|
|
+ disabled && 'opacity-50 cursor-not-allowed',
|
|
|
+ className,
|
|
|
+ )}
|
|
|
+ style={{
|
|
|
+ backgroundColor: isChecked ? color : undefined,
|
|
|
+ }}
|
|
|
+ onClick={handleToggle}
|
|
|
+ hoverClass={disabled ? '' : 'opacity-80'}
|
|
|
+ >
|
|
|
+ <View
|
|
|
+ className={cn(
|
|
|
+ 'absolute left-1 bg-white rounded-full shadow-lg transition-transform duration-200 ease-in-out',
|
|
|
+ currentSize.thumb,
|
|
|
+ isChecked ? currentSize.translate : '',
|
|
|
+ )}
|
|
|
+ />
|
|
|
+ </View>
|
|
|
+ )
|
|
|
+}
|