index.tsx 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import { Dialog, DialogPanel, DialogTitle, Transition, TransitionChild } from '@headlessui/react'
  2. import { Fragment } from 'react'
  3. import { RiCloseLine } from '@remixicon/react'
  4. import classNames from '@/utils/classnames'
  5. // https://headlessui.com/react/dialog
  6. type IModal = {
  7. className?: string
  8. wrapperClassName?: string
  9. isShow: boolean
  10. onClose?: () => void
  11. title?: React.ReactNode
  12. description?: React.ReactNode
  13. children?: React.ReactNode
  14. closable?: boolean
  15. overflowVisible?: boolean
  16. }
  17. export default function Modal({
  18. className,
  19. wrapperClassName,
  20. isShow,
  21. onClose = () => { },
  22. title,
  23. description,
  24. children,
  25. closable = false,
  26. overflowVisible = false,
  27. }: IModal) {
  28. return (
  29. <Transition appear show={isShow} as={Fragment}>
  30. <Dialog as="div" className={classNames('relative z-[60]', wrapperClassName)} onClose={onClose}>
  31. <TransitionChild>
  32. <div className={classNames(
  33. 'fixed inset-0 bg-background-overlay',
  34. 'duration-300 ease-in data-[closed]:opacity-0',
  35. 'data-[enter]:opacity-100',
  36. 'data-[leave]:opacity-0',
  37. )} />
  38. </TransitionChild>
  39. <div
  40. className="fixed inset-0 overflow-y-auto"
  41. onClick={(e) => {
  42. e.preventDefault()
  43. e.stopPropagation()
  44. }}
  45. >
  46. <div className="flex min-h-full items-center justify-center p-4 text-center">
  47. <TransitionChild>
  48. <DialogPanel className={classNames(
  49. 'w-full max-w-[480px] transform rounded-2xl bg-components-panel-bg p-6 text-left align-middle shadow-xl transition-all',
  50. overflowVisible ? 'overflow-visible' : 'overflow-hidden',
  51. 'duration-100 ease-in data-[closed]:opacity-0 data-[closed]:scale-95',
  52. 'data-[enter]:opacity-100 data-[enter]:scale-100',
  53. 'data-[leave]:opacity-0 data-[enter]:scale-95',
  54. className,
  55. )}>
  56. {title && <DialogTitle
  57. as="h3"
  58. className="title-2xl-semi-bold text-text-primary"
  59. >
  60. {title}
  61. </DialogTitle>}
  62. {description && <div className='body-md-regular mt-2 text-text-secondary'>
  63. {description}
  64. </div>}
  65. {closable
  66. && <div className='absolute right-6 top-6 z-10 flex h-5 w-5 items-center justify-center rounded-2xl hover:cursor-pointer hover:bg-state-base-hover'>
  67. <RiCloseLine className='h-4 w-4 text-text-tertiary' onClick={
  68. (e) => {
  69. e.stopPropagation()
  70. onClose()
  71. }
  72. } />
  73. </div>}
  74. {children}
  75. </DialogPanel>
  76. </TransitionChild>
  77. </div>
  78. </div>
  79. </Dialog>
  80. </Transition>
  81. )
  82. }