Files
leaudit-platform-frontend/app/components/ui/Modal.tsx
T

72 lines
1.8 KiB
TypeScript

// app/components/ui/Modal.tsx
import React, { useEffect } from 'react';
interface ModalProps {
isOpen: boolean;
onClose: () => void;
title: React.ReactNode;
children: React.ReactNode;
footer?: React.ReactNode;
width?: number | string;
}
export function Modal({ isOpen, onClose, title, children, footer, width = 500 }: ModalProps) {
// 点击ESC键关闭模态框
useEffect(() => {
const handleEsc = (e: KeyboardEvent) => {
if (e.key === 'Escape' && isOpen) {
onClose();
}
};
window.addEventListener('keydown', handleEsc);
return () => window.removeEventListener('keydown', handleEsc);
}, [isOpen, onClose]);
// 禁用背景滚动
useEffect(() => {
if (isOpen) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = '';
}
return () => {
document.body.style.overflow = '';
};
}, [isOpen]);
if (!isOpen) return null;
return (
<div
className="modal-backdrop"
onClick={(e) => {
if (e.target === e.currentTarget) onClose();
}}
>
<div
className="modal-content"
style={{ maxWidth: typeof width === 'number' ? `${width}px` : width }}
onClick={e => e.stopPropagation()}
>
<div className="modal-header">
<h3 className="text-lg font-medium">{title}</h3>
<button
className="text-gray-400 hover:text-gray-500"
onClick={onClose}
aria-label="关闭"
>
<i className="ri-close-line"></i>
</button>
</div>
<div className="modal-body py-4">
{children}
</div>
{footer && (
<div className="modal-footer flex justify-end space-x-2 pt-4 border-t border-gray-100">
{footer}
</div>
)}
</div>
</div>
);
}