'use client'; import { useEffect, useCallback, useRef } from 'react'; import { X } from 'lucide-react'; import { cn } from '@/lib/utils'; interface ModalProps { isOpen: boolean; onClose: () => void; children: React.ReactNode; /** 是否显示关闭按钮 */ showCloseButton?: boolean; /** 点击遮罩是否关闭 */ closeOnBackdrop?: boolean; /** 按 ESC 是否关闭 */ closeOnEsc?: boolean; /** 自定义类名 */ className?: string; /** 遮罩类名 */ backdropClassName?: string; /** 内容区域最大宽度 */ maxWidth?: string; /** 是否全屏 */ fullScreen?: boolean; } export function Modal({ isOpen, onClose, children, showCloseButton = true, closeOnBackdrop = true, closeOnEsc = true, className, backdropClassName, maxWidth = '800px', fullScreen = false, }: ModalProps) { const contentRef = useRef(null); // ESC 关闭 const handleKeyDown = useCallback( (e: KeyboardEvent) => { if (closeOnEsc && e.key === 'Escape') { onClose(); } }, [closeOnEsc, onClose] ); // 绑定键盘事件 useEffect(() => { if (isOpen) { document.addEventListener('keydown', handleKeyDown); // 禁止背景滚动 document.body.style.overflow = 'hidden'; } return () => { document.removeEventListener('keydown', handleKeyDown); document.body.style.overflow = ''; }; }, [isOpen, handleKeyDown]); // 点击遮罩关闭 const handleBackdropClick = (e: React.MouseEvent) => { if (closeOnBackdrop && e.target === e.currentTarget) { onClose(); } }; if (!isOpen) return null; return (
{/* 内容区域 */}
e.stopPropagation()} > {/* 关闭按钮 */} {showCloseButton && ( )} {children}
); } // 添加动画样式到 globals.css // 这里导出需要添加的 CSS export const modalAnimationStyles = ` @keyframes fadeInFast { from { opacity: 0; } to { opacity: 1; } } @keyframes scaleInFast { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } } .animate-fade-in-fast { animation: fadeInFast 0.15s ease-out; } .animate-scale-in-fast { animation: scaleInFast 0.15s ease-out; } `;