51 lines
1.4 KiB
TypeScript
51 lines
1.4 KiB
TypeScript
import { useEffect, type ReactNode } from 'react';
|
||
|
||
interface ModalProps {
|
||
open: boolean;
|
||
title: string;
|
||
onClose: () => void;
|
||
children: ReactNode;
|
||
wide?: boolean;
|
||
}
|
||
|
||
export function Modal({ open, title, onClose, children, wide }: ModalProps) {
|
||
useEffect(() => {
|
||
if (!open) return;
|
||
const onKey = (e: KeyboardEvent) => {
|
||
if (e.key === 'Escape') onClose();
|
||
};
|
||
window.addEventListener('keydown', onKey);
|
||
return () => window.removeEventListener('keydown', onKey);
|
||
}, [open, onClose]);
|
||
|
||
if (!open) return null;
|
||
|
||
return (
|
||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
|
||
<button
|
||
type="button"
|
||
className="absolute inset-0 bg-black/60"
|
||
aria-label="Cerrar modal"
|
||
onClick={onClose}
|
||
/>
|
||
<div
|
||
className={`relative z-10 max-h-[90vh] w-full overflow-y-auto rounded-xl border border-surface-border bg-surface-raised shadow-2xl ${
|
||
wide ? 'max-w-2xl' : 'max-w-lg'
|
||
}`}
|
||
>
|
||
<div className="flex items-center justify-between border-b border-surface-border px-5 py-4">
|
||
<h2 className="text-lg font-semibold text-white">{title}</h2>
|
||
<button
|
||
type="button"
|
||
onClick={onClose}
|
||
className="rounded p-1 text-slate-400 hover:bg-surface-border hover:text-white"
|
||
>
|
||
×
|
||
</button>
|
||
</div>
|
||
<div className="p-5">{children}</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|