選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

index.tsx 2.9KB

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