diff --git a/src/components/overlays/OverlayDisplay.tsx b/src/components/overlays/OverlayDisplay.tsx index 57c695f4..9143094d 100644 --- a/src/components/overlays/OverlayDisplay.tsx +++ b/src/components/overlays/OverlayDisplay.tsx @@ -80,6 +80,7 @@ export function OverlayPortal(props: { zIndex?: number; }) { const [portalElement, setPortalElement] = useState(null); + const [isReady, setIsReady] = useState(false); const ref = useRef(null); const close = props.close; const zIndex = props.zIndex ?? 999; @@ -87,6 +88,44 @@ export function OverlayPortal(props: { useEffect(() => { const element = ref.current?.closest(".popout-location"); setPortalElement(element ?? document.body); + + // Ensure DOM is ready before enabling focus trap + const timer = setTimeout(() => { + setIsReady(true); + }, 100); // Increased delay to ensure DOM is fully rendered + + return () => clearTimeout(timer); + }, []); + + // Add global error handler for unhandled promise rejections + useEffect(() => { + const handleUnhandledRejection = (event: PromiseRejectionEvent) => { + if ( + event.reason && + typeof event.reason === "object" && + "message" in event.reason + ) { + const message = event.reason.message; + if ( + message && + typeof message === "string" && + message.includes("matches.call") + ) { + console.warn( + "Caught focus-trap matches.call error, preventing crash:", + event.reason, + ); + event.preventDefault(); + } + } + }; + + window.addEventListener("unhandledrejection", handleUnhandledRejection); + return () => + window.removeEventListener( + "unhandledrejection", + handleUnhandledRejection, + ); }, []); return ( @@ -94,7 +133,19 @@ export function OverlayPortal(props: { {portalElement ? createPortal( - + document.body, + returnFocusOnDeactivate: true, + escapeDeactivates: true, + preventScroll: true, + // Disable the problematic check that causes the matches.call error + checkCanFocusTrap: () => Promise.resolve(), + }} + >