import cls from 'classnames'; import { useRef, type ReactElement, useEffect, useCallback, type FC, isValidElement } from 'react'; import { createPortal } from 'react-dom'; type Props = { clickAway?: boolean; noBlur?: boolean; focusOnOpen?: boolean; afterClose?: () => void; dialog: ReactElement | ((close: () => void) => ReactElement); children: ReactElement | ((open: () => void) => ReactElement); }; const DialogButton = ({ clickAway, noBlur, focusOnOpen, afterClose, dialog, children }: Props) => { const ref = useRef(null); const open = useCallback(() => { if (!ref.current) return; !focusOnOpen && (ref.current.inert = true); ref.current.showModal(); !focusOnOpen && (ref.current.inert = false); }, [focusOnOpen]); const close = useCallback(() => { ref.current?.close(); }, []); useEffect(() => { if (!clickAway) return; const callback = (e: MouseEvent) => e.target === ref.current && close(); window.addEventListener('click', callback); return () => window.removeEventListener('click', callback); }, [clickAway, close]); useEffect(() => { const callback = () => { afterClose?.(); return (document.activeElement as HTMLElement)?.blur(); }; const r = ref.current; r?.addEventListener('close', callback); return () => r?.removeEventListener('close', callback); }, [afterClose]); return ( <> {createPortal( e.stopPropagation()} className={cls( 'h-full w-full items-center justify-center bg-[transparent] [&[open]]:flex', { 'backdrop:backdrop-blur-md': !noBlur } )} > {typeof dialog === 'function' ? dialog(close) : dialog} , document.body )} {typeof children === 'function' ? children(open) : children} ); }; export default DialogButton;