switch.tsx 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. import { useState } from 'react'
  2. import { View } from '@tarojs/components'
  3. import { cn } from '@/utils/cn'
  4. interface SwitchProps {
  5. checked?: boolean
  6. onChange?: (checked: boolean) => void
  7. disabled?: boolean
  8. color?: string
  9. size?: 'sm' | 'md' | 'lg'
  10. className?: string
  11. }
  12. export function Switch({
  13. checked = false,
  14. onChange,
  15. disabled = false,
  16. color = '#1976D2',
  17. size = 'md',
  18. className,
  19. }: SwitchProps) {
  20. const [isChecked, setIsChecked] = useState(checked)
  21. const handleToggle = () => {
  22. if (disabled) return
  23. const newValue = !isChecked
  24. setIsChecked(newValue)
  25. onChange?.(newValue)
  26. }
  27. const sizes = {
  28. sm: {
  29. track: 'w-10 h-5',
  30. thumb: 'w-4 h-4',
  31. translate: 'translate-x-5',
  32. },
  33. md: {
  34. track: 'w-12 h-6',
  35. thumb: 'w-5 h-5',
  36. translate: 'translate-x-6',
  37. },
  38. lg: {
  39. track: 'w-14 h-7',
  40. thumb: 'w-6 h-6',
  41. translate: 'translate-x-7',
  42. },
  43. }
  44. const currentSize = sizes[size]
  45. return (
  46. <View
  47. className={cn(
  48. 'relative inline-flex items-center rounded-full cursor-pointer transition-colors duration-200 ease-in-out',
  49. currentSize.track,
  50. isChecked ? '' : 'bg-gray-300',
  51. disabled && 'opacity-50 cursor-not-allowed',
  52. className,
  53. )}
  54. style={{
  55. backgroundColor: isChecked ? color : undefined,
  56. }}
  57. onClick={handleToggle}
  58. hoverClass={disabled ? '' : 'opacity-80'}
  59. >
  60. <View
  61. className={cn(
  62. 'absolute left-1 bg-white rounded-full shadow-lg transition-transform duration-200 ease-in-out',
  63. currentSize.thumb,
  64. isChecked ? currentSize.translate : '',
  65. )}
  66. />
  67. </View>
  68. )
  69. }