import React, { useEffect, useRef } from 'react'; import { Card } from './ui/card'; interface ModalProps { children: React.ReactNode; footer?: React.ReactNode; // Optional footer onClose: () => void; // Function to call when modal should close preventBackdropClose?: boolean; // Optional prop to prevent closing on backdrop click } /** * A reusable modal component that renders content with a semi-transparent backdrop and blur effect. * Closes when clicking outside the modal or pressing Esc key. */ export default function Modal({ children, footer, onClose, preventBackdropClose = false, }: ModalProps) { const modalRef = useRef(null); // Handle click outside the modal content const handleBackdropClick = (e: React.MouseEvent) => { if (preventBackdropClose) return; // Check if the click was on the backdrop and not on the modal content // Also check if the click target is not part of a Select menu if ( modalRef.current && !modalRef.current.contains(e.target as Node) && !(e.target as HTMLElement).closest('.select__menu') && window.getSelection()?.toString().length === 0 // Ensure no text is selected ) { onClose(); } }; // Handle Esc key press useEffect(() => { const handleEscKey = (e: KeyboardEvent) => { if (e.key === 'Escape') { // Don't close if a select menu is open const selectMenu = document.querySelector('.select__menu'); if (!selectMenu) { onClose(); } } }; // Add event listener for Escape key document.addEventListener('keydown', handleEscKey); // Add overflow-hidden to body to prevent scrolling background document.body.style.overflow = 'hidden'; // Clean up return () => { document.removeEventListener('keydown', handleEscKey); // Restore body scrolling when modal closes document.body.style.overflow = ''; }; }, [onClose]); return (
{children}
{footer && (
{footer}
)}
); }