Something went wrong. Try again.
A local-first note taking app
Something went wrong. Try again.
2.4 kB · 82 lines
TSX
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283import { useEffect, type ReactNode } from 'react';
type ModalProps = { open: boolean; onClose: () => void; ariaLabel: string; title?: string; panelClassName?: string; bodyClassName?: string; children: ReactNode;};
export function Modal({ open, onClose, ariaLabel, title, panelClassName, bodyClassName, children,}: ModalProps) { useEffect(() => { if (!open) return; const handleKeyDown = (e: globalThis.KeyboardEvent) => { if (e.key === 'Escape') { e.preventDefault(); onClose(); } }; document.addEventListener('keydown', handleKeyDown); return () => document.removeEventListener('keydown', handleKeyDown); }, [open, onClose]);
if (!open) return null;
return ( <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/35 backdrop-blur-sm" onMouseDown={onClose} role="dialog" aria-modal="true" aria-label={ariaLabel} > <div className={`border-border bg-background text-foreground flex max-w-[92vw] overflow-hidden rounded-lg border shadow-xl ${panelClassName ?? ''}`} onMouseDown={(event) => event.stopPropagation()} > <div className="flex min-w-0 flex-1 flex-col"> <header className="border-border relative flex h-11 shrink-0 items-center border-b px-3"> {title ? ( <div className="pointer-events-none absolute inset-0 flex items-center justify-center"> <h2 className="text-sm font-semibold">{title}</h2> </div> ) : null} <button type="button" onClick={onClose} aria-label="Close modal" className="text-foreground/80 hover:bg-border/40 ml-auto rounded p-1" > <svg className="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden > <path d="M6 6l12 12M18 6 6 18" /> </svg> </button> </header> <div className={bodyClassName ?? 'flex min-h-0 min-w-0 flex-1'}> {children} </div> </div> </div> </div> );}