You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.tsx 2.9KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. 'use client'
  2. import { Dialog, DialogBackdrop, DialogTitle } from '@headlessui/react'
  3. import { useTranslation } from 'react-i18next'
  4. import { XMarkIcon } from '@heroicons/react/24/outline'
  5. import Button from '../button'
  6. import cn from '@/utils/classnames'
  7. export type IDrawerProps = {
  8. title?: string
  9. description?: string
  10. dialogClassName?: string
  11. dialogBackdropClassName?: string
  12. panelClassName?: string
  13. children: React.ReactNode
  14. footer?: React.ReactNode
  15. mask?: boolean
  16. positionCenter?: boolean
  17. isOpen: boolean
  18. showClose?: boolean
  19. clickOutsideNotOpen?: boolean
  20. onClose: () => void
  21. onCancel?: () => void
  22. onOk?: () => void
  23. unmount?: boolean
  24. }
  25. export default function Drawer({
  26. title = '',
  27. description = '',
  28. dialogClassName = '',
  29. dialogBackdropClassName = '',
  30. panelClassName = '',
  31. children,
  32. footer,
  33. mask = true,
  34. positionCenter,
  35. showClose = false,
  36. isOpen,
  37. clickOutsideNotOpen,
  38. onClose,
  39. onCancel,
  40. onOk,
  41. unmount = false,
  42. }: IDrawerProps) {
  43. const { t } = useTranslation()
  44. return (
  45. <Dialog
  46. unmount={unmount}
  47. open={isOpen}
  48. onClose={() => !clickOutsideNotOpen && onClose()}
  49. className={cn('fixed inset-0 z-[30] overflow-y-auto', dialogClassName)}
  50. >
  51. <div className={cn('flex h-screen w-screen justify-end', positionCenter && '!justify-center')}>
  52. {/* mask */}
  53. <DialogBackdrop
  54. className={cn('fixed inset-0 z-[40]', mask && 'bg-black/30', dialogBackdropClassName)}
  55. onClick={() => {
  56. !clickOutsideNotOpen && onClose()
  57. }}
  58. />
  59. <div className={cn('relative z-[50] flex w-full max-w-sm flex-col justify-between overflow-hidden bg-components-panel-bg p-6 text-left align-middle shadow-xl', panelClassName)}>
  60. <>
  61. <div className='flex justify-between'>
  62. {title && <DialogTitle
  63. as="h3"
  64. className="text-lg font-medium leading-6 text-text-primary"
  65. >
  66. {title}
  67. </DialogTitle>}
  68. {showClose && <DialogTitle className="mb-4 flex cursor-pointer items-center" as="div">
  69. <XMarkIcon className='h-4 w-4 text-text-tertiary' onClick={onClose} />
  70. </DialogTitle>}
  71. </div>
  72. {description && <div className='mt-2 text-xs font-normal text-text-tertiary'>{description}</div>}
  73. {children}
  74. </>
  75. {footer || (footer === null
  76. ? null
  77. : <div className="mt-10 flex flex-row justify-end">
  78. <Button
  79. className='mr-2'
  80. onClick={() => {
  81. onCancel && onCancel()
  82. }}>{t('common.operation.cancel')}</Button>
  83. <Button
  84. onClick={() => {
  85. onOk && onOk()
  86. }}>{t('common.operation.save')}</Button>
  87. </div>)}
  88. </div>
  89. </div>
  90. </Dialog>
  91. )
  92. }