| import React, { useEffect } from 'react' | |
| import { X } from 'lucide-react' | |
| interface ModalProps { | |
| isOpen: boolean | |
| onClose: () => void | |
| title: React.ReactNode | |
| children: React.ReactNode | |
| maxWidth?: | |
| | 'sm' | |
| | 'md' | |
| | 'lg' | |
| | 'xl' | |
| | '2xl' | |
| | '3xl' | |
| | '4xl' | |
| | '5xl' | |
| | '6xl' | |
| | '7xl' | |
| } | |
| const Modal: React.FC<ModalProps> = ({ | |
| isOpen, | |
| onClose, | |
| title, | |
| children, | |
| maxWidth = '4xl' | |
| }) => { | |
| useEffect(() => { | |
| const handleEscape = (e: KeyboardEvent) => { | |
| if (e.key === 'Escape') { | |
| onClose() | |
| } | |
| } | |
| if (isOpen) { | |
| document.addEventListener('keydown', handleEscape) | |
| document.body.style.overflow = 'hidden' | |
| } | |
| return () => { | |
| document.removeEventListener('keydown', handleEscape) | |
| document.body.style.overflow = 'unset' | |
| } | |
| }, [isOpen, onClose]) | |
| if (!isOpen) return null | |
| const maxWidthClasses = { | |
| sm: 'max-w-sm', | |
| md: 'max-w-md', | |
| lg: 'max-w-lg', | |
| xl: 'max-w-xl', | |
| '2xl': 'max-w-2xl', | |
| '3xl': 'max-w-3xl', | |
| '4xl': 'max-w-4xl', | |
| '5xl': 'max-w-5xl', | |
| '6xl': 'max-w-6xl', | |
| '7xl': 'max-w-7xl' | |
| } | |
| return ( | |
| <div className="fixed inset-0 z-50 overflow-y-auto"> | |
| {/* Backdrop */} | |
| <div | |
| className="fixed inset-0 bg-black opacity-50 transition-opacity" | |
| onClick={onClose} | |
| /> | |
| {/* Modal */} | |
| <div className="flex min-h-full items-center justify-center p-4 text-center sm:p-0"> | |
| <div | |
| className={`relative transform overflow-hidden rounded-lg bg-white text-left shadow-xl transition-all sm:my-8 sm:w-full ${maxWidthClasses[maxWidth]}`} | |
| onClick={(e) => e.stopPropagation()} | |
| > | |
| {/* Header */} | |
| <div className="flex items-center justify-between px-6 py-4 border-b border-gray-200"> | |
| <h3 className="text-lg font-semibold text-gray-900">{title}</h3> | |
| <button | |
| onClick={onClose} | |
| className="rounded-md p-2 text-gray-400 hover:text-gray-600 hover:bg-gray-100 focus:outline-hidden focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2" | |
| > | |
| <span className="sr-only">Close</span> | |
| <X className="h-5 w-5" /> | |
| </button> | |
| </div> | |
| {/* Content */} | |
| <div className="px-6 py-4 max-h-[calc(100vh-200px)] overflow-y-auto"> | |
| {children} | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| ) | |
| } | |
| export default Modal | |