index.tsx 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import { Dialog, Transition } from '@headlessui/react'
  2. import { Fragment } from 'react'
  3. import { XMarkIcon } from '@heroicons/react/24/outline'
  4. // https://headlessui.com/react/dialog
  5. type IModal = {
  6. className?: string
  7. wrapperClassName?: string
  8. isShow: boolean
  9. onClose: () => void
  10. title?: React.ReactNode
  11. description?: React.ReactNode
  12. children: React.ReactNode
  13. closable?: boolean
  14. overflowVisible?: boolean
  15. }
  16. export default function Modal({
  17. className,
  18. wrapperClassName,
  19. isShow,
  20. onClose,
  21. title,
  22. description,
  23. children,
  24. closable = false,
  25. overflowVisible = false,
  26. }: IModal) {
  27. return (
  28. <Transition appear show={isShow} as={Fragment}>
  29. <Dialog as="div" className={`relative z-10 ${wrapperClassName}`} onClose={onClose}>
  30. <Transition.Child
  31. as={Fragment}
  32. enter="ease-out duration-300"
  33. enterFrom="opacity-0"
  34. enterTo="opacity-100"
  35. leave="ease-in duration-200"
  36. leaveFrom="opacity-100"
  37. leaveTo="opacity-0"
  38. >
  39. <div className="fixed inset-0 bg-black bg-opacity-25" />
  40. </Transition.Child>
  41. <div
  42. className="fixed inset-0 overflow-y-auto"
  43. onClick={(e) => {
  44. e.preventDefault()
  45. e.stopPropagation()
  46. }}
  47. >
  48. <div className="flex min-h-full items-center justify-center p-4 text-center">
  49. <Transition.Child
  50. as={Fragment}
  51. enter="ease-out duration-300"
  52. enterFrom="opacity-0 scale-95"
  53. enterTo="opacity-100 scale-100"
  54. leave="ease-in duration-200"
  55. leaveFrom="opacity-100 scale-100"
  56. leaveTo="opacity-0 scale-95"
  57. >
  58. <Dialog.Panel className={`w-full max-w-md transform ${overflowVisible ? 'overflow-visible' : 'overflow-hidden'} rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all ${className}`}>
  59. {title && <Dialog.Title
  60. as="h3"
  61. className="text-lg font-medium leading-6 text-gray-900"
  62. >
  63. {title}
  64. </Dialog.Title>}
  65. {description && <Dialog.Description className='text-gray-500 text-xs font-normal mt-2'>
  66. {description}
  67. </Dialog.Description>}
  68. {closable
  69. && <div className='absolute z-10 top-6 right-6 w-5 h-5 rounded-2xl flex items-center justify-center hover:cursor-pointer hover:bg-gray-100'>
  70. <XMarkIcon className='w-4 h-4 text-gray-500' onClick={
  71. (e) => {
  72. e.stopPropagation()
  73. onClose()
  74. }
  75. } />
  76. </div>}
  77. {children}
  78. </Dialog.Panel>
  79. </Transition.Child>
  80. </div>
  81. </div>
  82. </Dialog>
  83. </Transition>
  84. )
  85. }