import { useEffect, useId, useRef, useState } from "react"; import { createPortal } from "react-dom"; import { XIcon } from "@primer/octicons-react"; import * as styles from "./modal.css"; import { useAppDispatch } from "@renderer/hooks"; import { toggleDragging } from "@renderer/features"; export interface ModalProps { visible: boolean; title: string; description: string; onClose: () => void; children: React.ReactNode; } export function Modal({ visible, title, description, onClose, children, }: ModalProps) { const [isClosing, setIsClosing] = useState(false); const dispatch = useAppDispatch(); const modalContentRef = useRef(null); const componentId = useId(); const handleCloseClick = () => { setIsClosing(true); const zero = performance.now(); requestAnimationFrame(function animateClosing(time) { if (time - zero <= 400) { requestAnimationFrame(animateClosing); } else { onClose(); setIsClosing(false); } }); }; const isTopMostModal = () => { const openModals = document.querySelectorAll("[role=modal]"); return ( openModals.length && openModals[openModals.length - 1] === modalContentRef.current ); }; useEffect(() => { const onKeyDown = (e: KeyboardEvent) => { if (e.key === "Escape" && isTopMostModal()) { handleCloseClick(); } }; window.addEventListener("keydown", onKeyDown); return () => window.removeEventListener("keydown", onKeyDown); }, []); useEffect(() => { const onMouseDown = (e: MouseEvent) => { if (!isTopMostModal()) return; const clickedOutsideContent = !modalContentRef.current.contains( e.target as Node ); if (clickedOutsideContent) { handleCloseClick(); } }; window.addEventListener("mousedown", onMouseDown); return () => window.removeEventListener("mousedown", onMouseDown); }, []); useEffect(() => { dispatch(toggleDragging(visible)); }, [dispatch, visible]); if (!visible) return null; return createPortal(

{title}

{description}

{children}
, document.body ); }