import { useEffect, useRef } from 'react'; /** * Универсальный Modal компонент * Простой и надёжный - работает как HistoryModal */ function Modal({ show, onClose, onOpen, title, children, footer, size = 'md', backdrop = true, keyboard = true, scrollable = false, centered = false, className = '' }) { const modalRef = useRef(null); // Управление классом modal-open на body useEffect(() => { if (show) { document.body.classList.add('modal-open'); setTimeout(() => modalRef.current?.focus(), 100); onOpen?.(); } else { document.body.classList.remove('modal-open'); } return () => { document.body.classList.remove('modal-open'); }; }, [show, onOpen]); // Обработка ESC useEffect(() => { if (keyboard && show) { const handleEsc = (e) => { if (e.key === 'Escape') { onClose?.(); } }; document.addEventListener('keydown', handleEsc); return () => document.removeEventListener('keydown', handleEsc); } }, [keyboard, show, onClose]); if (!show) return null; const handleBackdropClick = (e) => { if (backdrop && e.target === e.currentTarget) { onClose?.(); } }; return ( <> {/* Modal Backdrop */}
{/* Modal */}
{ if (e.key === 'Escape') onClose?.(); }} >
{ if (e.key === 'Tab') { const c = e.currentTarget; const focusable = c.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'); if (!focusable || focusable.length === 0) return; const first = focusable[0]; const last = focusable[focusable.length - 1]; if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); } else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); } } }} > {title && (
{title}
)}
{children}
{footer && (
{footer}
)}
); } export default Modal; /** * Готовые пресеты для быстрого использования */ export function SmallModal({ show, onClose, title, children, footer, ...props }) { return ( {children} ); } export function LargeModal({ show, onClose, title, children, footer, scrollable = true, ...props }) { return ( {children} ); } export function FullscreenModal({ show, onClose, title, children, footer, ...props }) { return ( {children} ); }