From cdebc2265da683b706c47f13eb8e0d0b6cd30a5d Mon Sep 17 00:00:00 2001 From: Vula Builder Date: Sun, 26 Jul 2026 16:40:59 +0000 Subject: [PATCH] Deploy --- src/components/ui/Modal.tsx | 87 +++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/components/ui/Modal.tsx diff --git a/src/components/ui/Modal.tsx b/src/components/ui/Modal.tsx new file mode 100644 index 0000000..ceae0dc --- /dev/null +++ b/src/components/ui/Modal.tsx @@ -0,0 +1,87 @@ +'use client' + +import { cn } from "@/lib/utils" +import { useEffect, useRef } from "react" +import { X } from 'lucide-react' + +interface ModalProps { + open: boolean + onClose: () => void + title?: string + description?: string + className?: string + children: React.ReactNode +} + +export default function Modal({ open, onClose, title, description, className, children }: ModalProps) { + const overlayRef = useRef(null) + const contentRef = useRef(null) + + // Close on Escape key + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === "Escape") onClose() + } + if (open) { + document.addEventListener("keydown", handleKeyDown) + // Prevent body scroll + document.body.style.overflow = "hidden" + } + return () => { + document.removeEventListener("keydown", handleKeyDown) + document.body.style.overflow = "auto" + } + }, [open, onClose]) + + // Focus trap (basic) – focus content on open + useEffect(() => { + if (open && contentRef.current) { + contentRef.current.focus() + } + }, [open]) + + if (!open) return null + + return ( +
{ + if (e.target === overlayRef.current) onClose() + }} + > +
+ + + {title && ( + + )} + {description && ( + + )} + {children} +
+
+ ) +} \ No newline at end of file