index.tsx 1.8 KB

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