index.tsx 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. 'use client'
  2. import React, { useEffect, useState } from 'react'
  3. import classNames from 'classnames'
  4. import { Switch as OriginalSwitch } from '@headlessui/react'
  5. type SwitchProps = {
  6. onChange: (value: boolean) => void
  7. size?: 'md' | 'lg'
  8. defaultValue?: boolean
  9. disabled?: boolean
  10. }
  11. const Switch = ({ onChange, size = 'lg', defaultValue = false, disabled = false }: SwitchProps) => {
  12. const [enabled, setEnabled] = useState(defaultValue)
  13. useEffect(() => {
  14. setEnabled(defaultValue)
  15. }, [defaultValue])
  16. const wrapStyle = {
  17. lg: 'h-6 w-11',
  18. md: 'h-4 w-7',
  19. }
  20. const circleStyle = {
  21. lg: 'h-5 w-5',
  22. md: 'h-3 w-3',
  23. }
  24. const translateLeft = {
  25. lg: 'translate-x-5',
  26. md: 'translate-x-3',
  27. }
  28. return (
  29. <OriginalSwitch
  30. checked={enabled}
  31. onChange={(checked: boolean) => {
  32. if (disabled)
  33. return
  34. setEnabled(checked)
  35. onChange(checked)
  36. }}
  37. className={classNames(
  38. wrapStyle[size],
  39. enabled ? 'bg-blue-600' : 'bg-gray-200',
  40. 'relative inline-flex flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out',
  41. disabled ? '!opacity-50 !cursor-not-allowed' : '',
  42. )}
  43. >
  44. <span
  45. aria-hidden="true"
  46. className={classNames(
  47. circleStyle[size],
  48. enabled ? translateLeft[size] : 'translate-x-0',
  49. 'pointer-events-none inline-block transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out',
  50. )}
  51. />
  52. </OriginalSwitch>
  53. )
  54. }
  55. export default React.memo(Switch)