diff --git a/src/components/ui/Modal.tsx b/src/components/ui/Modal.tsx new file mode 100644 index 0000000..ceb19ca --- /dev/null +++ b/src/components/ui/Modal.tsx @@ -0,0 +1,82 @@ +'use client' + +import { cn } from "@/lib/utils" +import { useEffect, useRef, forwardRef, useCallback } from "react" +import { X } from 'lucide-react' + +interface ModalProps { + isOpen: boolean + onClose: () => void + title?: string + children: React.ReactNode + className?: string +} + +const Modal = forwardRef( + ({ isOpen, onClose, title, children, className }, ref) => { + const overlayRef = useRef(null) + const contentRef = useRef(null) + + const handleKeyDown = useCallback( + (e: KeyboardEvent) => { + if (e.key === "Escape") { + onClose() + } + }, + [onClose] + ) + + useEffect(() => { + if (isOpen) { + document.addEventListener("keydown", handleKeyDown) + document.body.style.overflow = "hidden" + } + return () => { + document.removeEventListener("keydown", handleKeyDown) + document.body.style.overflow = "unset" + } + }, [isOpen, handleKeyDown]) + + if (!isOpen) return null + + return ( +
{ + if (e.target === overlayRef.current) onClose() + }} + role="dialog" + aria-modal="true" + aria-label={title || "Modal"} + > +
+ + {title && ( +

+ {title} +

+ )} + {children} +
+
+ ) + } +) + +Modal.displayName = "Modal" + +export default Modal