index.tsx 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  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. }
  15. export default function Modal({
  16. className,
  17. wrapperClassName,
  18. isShow,
  19. onClose,
  20. title,
  21. description,
  22. children,
  23. closable = false,
  24. }: IModal) {
  25. return (
  26. <Transition appear show={isShow} as={Fragment}>
  27. <Dialog as="div" className={`relative z-10 ${wrapperClassName}`} onClose={onClose}>
  28. <Transition.Child
  29. as={Fragment}
  30. enter="ease-out duration-300"
  31. enterFrom="opacity-0"
  32. enterTo="opacity-100"
  33. leave="ease-in duration-200"
  34. leaveFrom="opacity-100"
  35. leaveTo="opacity-0"
  36. >
  37. <div className="fixed inset-0 bg-black bg-opacity-25" />
  38. </Transition.Child>
  39. <div className="fixed inset-0 overflow-y-auto">
  40. <div className="flex min-h-full items-center justify-center p-4 text-center">
  41. <Transition.Child
  42. as={Fragment}
  43. enter="ease-out duration-300"
  44. enterFrom="opacity-0 scale-95"
  45. enterTo="opacity-100 scale-100"
  46. leave="ease-in duration-200"
  47. leaveFrom="opacity-100 scale-100"
  48. leaveTo="opacity-0 scale-95"
  49. >
  50. <Dialog.Panel className={`w-full max-w-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all ${className}`}>
  51. {title && <Dialog.Title
  52. as="h3"
  53. className="text-lg font-medium leading-6 text-gray-900"
  54. >
  55. {title}
  56. </Dialog.Title>}
  57. {description && <Dialog.Description className='text-gray-500 text-xs font-normal mt-2'>
  58. {description}
  59. </Dialog.Description>}
  60. {closable
  61. && <div className='absolute top-6 right-6 w-5 h-5 rounded-2xl flex items-center justify-center hover:cursor-pointer hover:bg-gray-100'>
  62. <XMarkIcon className='w-4 h-4 text-gray-500' onClick={onClose} />
  63. </div>}
  64. {children}
  65. </Dialog.Panel>
  66. </Transition.Child>
  67. </div>
  68. </div>
  69. </Dialog>
  70. </Transition>
  71. )
  72. }