Spaces:
Running
Running
| import { useEffect, type ReactNode } from "react"; | |
| interface ModalProps { | |
| open: boolean; | |
| title: string; | |
| onClose: () => void; | |
| children: ReactNode; | |
| footer?: ReactNode; | |
| size?: "sm" | "md" | "lg"; | |
| } | |
| export function Modal({ open, title, onClose, children, footer, size = "md" }: ModalProps) { | |
| useEffect(() => { | |
| if (!open) return; | |
| const onKey = (event: KeyboardEvent) => { | |
| if (event.key === "Escape") onClose(); | |
| }; | |
| window.addEventListener("keydown", onKey); | |
| return () => window.removeEventListener("keydown", onKey); | |
| }, [open, onClose]); | |
| if (!open) return null; | |
| return ( | |
| <div | |
| aria-modal="true" | |
| className="modal-backdrop" | |
| onClick={(event) => { | |
| if (event.target === event.currentTarget) onClose(); | |
| }} | |
| role="dialog" | |
| > | |
| <div className={`modal modal-${size}`}> | |
| <header className="modal-header"> | |
| <h3>{title}</h3> | |
| <button aria-label="Close" className="icon-button" onClick={onClose} type="button"> | |
| ✕ | |
| </button> | |
| </header> | |
| <div className="modal-body">{children}</div> | |
| {footer ? <footer className="modal-footer">{footer}</footer> : null} | |
| </div> | |
| </div> | |
| ); | |
| } | |