import type { FC, FunctionComponent, ReactNode } from 'react' import type { ExtractProps } from '../types' import type { DialogActionProps } from './DialogActions' import type { DialogContentProps } from './DialogContent' import type { DialogDescriptionProps } from './DialogDescription' import type { DialogHeaderProps } from './DialogHeader' import { Dialog as HeadlessDialog, DialogPanel as HeadlessDialogPanel, Transition, TransitionChild } from '@headlessui/react' import { useEffect } from 'react' import { useBreakpoint } from '../useBreakpoint' import DialogActions from './DialogActions' import DialogContent from './DialogContent' import DialogDescription from './DialogDescription' import DialogHeader from './DialogHeader' export type DialogRootProps = ExtractProps & { afterLeave?: () => void children?: ReactNode } const DialogRoot: FC = ({ open, onClose, children, afterLeave, ...rest }) => { const { unmount } = rest const { isMd } = useBreakpoint('md') // iOS body lock fix // This gets the current scroll position and sets it as negative top margin before setting position fixed on body // This is necessary because adding position fixed to body scrolls the page to the top useEffect(() => { if (!isMd) { if (open) { document.body.style.top = `-${window.scrollY}px` document.body.style.position = 'fixed' document.body.style.left = '0' document.body.style.right = '0' } else { const scrollY = document.body.style.top document.body.style.position = '' document.body.style.top = '' document.body.style.left = '' document.body.style.right = '' window.scrollTo(0, Number.parseInt(scrollY || '0') * -1) } } }, [isMd, open]) return (
{children}
) } export const Dialog: FunctionComponent & { Description: FunctionComponent Header: FunctionComponent Actions: FunctionComponent Content: FunctionComponent } = Object.assign(DialogRoot, { Content: DialogContent, Header: DialogHeader, Description: DialogDescription, Actions: DialogActions, })