menu-dialog.tsx 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. import { Fragment, useCallback, useEffect } from 'react'
  2. import type { ReactNode } from 'react'
  3. import { Dialog, Transition } from '@headlessui/react'
  4. import cn from '@/utils/classnames'
  5. type DialogProps = {
  6. className?: string
  7. children: ReactNode
  8. show: boolean
  9. onClose?: () => void
  10. }
  11. const MenuDialog = ({
  12. className,
  13. children,
  14. show,
  15. onClose,
  16. }: DialogProps) => {
  17. const close = useCallback(() => onClose?.(), [onClose])
  18. useEffect(() => {
  19. const handleKeyDown = (event: KeyboardEvent) => {
  20. if (event.key === 'Escape')
  21. close()
  22. }
  23. document.addEventListener('keydown', handleKeyDown)
  24. return () => {
  25. document.removeEventListener('keydown', handleKeyDown)
  26. }
  27. }, [close])
  28. return (
  29. <Transition appear show={show} as={Fragment}>
  30. <Dialog as="div" className="relative z-[60]" onClose={() => {}}>
  31. <div className="fixed inset-0">
  32. <div className="flex flex-col items-center justify-center min-h-full">
  33. <Transition.Child
  34. as={Fragment}
  35. enter="ease-out duration-300"
  36. enterFrom="opacity-0 scale-95"
  37. enterTo="opacity-100 scale-100"
  38. leave="ease-in duration-200"
  39. leaveFrom="opacity-100 scale-100"
  40. leaveTo="opacity-0 scale-95"
  41. >
  42. <Dialog.Panel className={cn('grow relative w-full h-full p-0 overflow-hidden text-left align-middle transition-all transform bg-background-sidenav-bg backdrop-blur-md', className)}>
  43. <div className='absolute top-0 right-0 h-full w-1/2 bg-components-panel-bg' />
  44. {children}
  45. </Dialog.Panel>
  46. </Transition.Child>
  47. </div>
  48. </div>
  49. </Dialog>
  50. </Transition >
  51. )
  52. }
  53. export default MenuDialog