Feat/crm mail ui #30

Merged
maaz519 merged 8 commits from feat/crm-mail-ui into goutamnextflow 2026-07-18 12:31:19 +00:00
Showing only changes of commit 28907acf0e - Show all commits
+9 -2
View File
@@ -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<Element | null>(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 = (
<div className="ds-modal-overlay" onMouseDown={onClose}>
<div className={`ds-modal size-${size}`} role="dialog" aria-modal="true" aria-labelledby={titleId} onMouseDown={(e) => e.stopPropagation()}>
<div className="ds-modal-head">
@@ -247,6 +253,7 @@ export function Modal({ open, onClose, title, subtitle, icon, children, footer,
</div>
</div>
);
return host ? createPortal(overlay, host) : overlay;
}
/* ---------------------------------------------------------- */