import classNames from "classnames"; import FocusTrap from "focus-trap-react"; import { ReactNode, useCallback, useEffect, useRef, useState } from "react"; import { createPortal } from "react-dom"; import { Transition } from "@/components/utils/Transition"; import { useInternalOverlayRouter, useRouterAnchorUpdate, } from "@/hooks/useOverlayRouter"; export interface OverlayProps { id: string; children?: ReactNode; darken?: boolean; } export function OverlayDisplay(props: { children: ReactNode }) { const router = useInternalOverlayRouter("hello world :)"); const refRouter = useRef(router); // close router on first mount, we dont want persist routes for overlays useEffect(() => { const r = refRouter.current; r.close(); return () => { r.close(); }; }, []); return
{props.children}
; } export function OverlayPortal(props: { children?: ReactNode; darken?: boolean; show?: boolean; close?: () => void; }) { const [portalElement, setPortalElement] = useState(null); const ref = useRef(null); const close = props.close; useEffect(() => { const element = ref.current?.closest(".popout-location"); setPortalElement(element ?? document.body); }, []); return (
{portalElement ? createPortal(
{/* a tabable index that does nothing - used so focus trap doesn't error when nothing is rendered yet */}
{props.children}
, portalElement, ) : null}
); } export function Overlay(props: OverlayProps) { const router = useInternalOverlayRouter(props.id); const realClose = router.close; // listen for anchor updates useRouterAnchorUpdate(props.id); const close = useCallback(() => { realClose(); }, [realClose]); return ( {props.children} ); }