From 28907acf0ec6bd4c31dd33a365d2e8ccd5935ab1 Mon Sep 17 00:00:00 2001 From: maaz519 Date: Sat, 18 Jul 2026 17:52:32 +0530 Subject: [PATCH] fix(dashboard): portal modals to .dash-root so they anchor to the viewport MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A transformed/overflow panel ancestor was trapping the modal overlay's position:fixed, so the modal rendered offset inside the messenger/inbox panel and clipped (Group settings sat inside the thread pane; the compose modal's top was cut at the panel edge). Portal the overlay up to .dash-root — above those panels but still inside the scoped design-system CSS — so it centers on the viewport and the 90vh cap works. Falls back to inline render if no .dash-root is present. Co-Authored-By: Claude Opus 4.8 --- src/components/dashboard/ui.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/dashboard/ui.tsx b/src/components/dashboard/ui.tsx index dbd151e..5b57735 100644 --- a/src/components/dashboard/ui.tsx +++ b/src/components/dashboard/ui.tsx @@ -14,6 +14,7 @@ import { createContext, useCallback, useContext, useEffect, useId, useRef, useState, type ReactNode, } from "react"; +import { createPortal } from "react-dom"; import { MessageCircle, Ticket, Phone, Mail, BookOpen, Rocket, Shield, ShieldCheck, Lock, CreditCard, User, Bell, Eye, EyeOff, Camera, Upload, Plus, Star, Send, @@ -221,6 +222,11 @@ export function Modal({ open, onClose, title, subtitle, icon, children, footer, children: ReactNode; footer?: ReactNode; size?: "sm" | "md" | "lg"; }) { const titleId = useId(); + // Portal the overlay up to `.dash-root` so its position:fixed anchors to the viewport, + // not to a transformed/overflow panel ancestor (which would clip or offset the modal). + const [host, setHost] = useState(null); + const [mounted, setMounted] = useState(false); + useEffect(() => { setHost(document.querySelector(".dash-root")); setMounted(true); }, []); useEffect(() => { if (!open) return; const onKey = (e: KeyboardEvent) => { if (e.key === "Escape") onClose(); }; @@ -228,8 +234,8 @@ export function Modal({ open, onClose, title, subtitle, icon, children, footer, return () => document.removeEventListener("keydown", onKey); }, [open, onClose]); - if (!open) return null; - return ( + if (!open || !mounted) return null; + const overlay = (
e.stopPropagation()}>
@@ -247,6 +253,7 @@ export function Modal({ open, onClose, title, subtitle, icon, children, footer,
); + return host ? createPortal(overlay, host) : overlay; } /* ---------------------------------------------------------- */