diff --git a/src/components/ui/Modal.tsx b/src/components/ui/Modal.tsx index ca88e0a..9503626 100644 --- a/src/components/ui/Modal.tsx +++ b/src/components/ui/Modal.tsx @@ -17,19 +17,26 @@ const sizes = { sm: 'max-w-sm', md: 'max-w-lg', lg: 'max-w-2xl' } export function Modal({ open, onClose, title, children, footer, size = 'md' }: Props) { const panelRef = useRef(null) + // Lock scroll + focus the panel only when the modal opens (not on every render, + // otherwise typing in an input would keep stealing focus back to the panel). + useEffect(() => { + if (!open) return + const prev = document.body.style.overflow + document.body.style.overflow = 'hidden' + panelRef.current?.focus() + return () => { + document.body.style.overflow = prev + } + }, [open]) + + // Escape-to-close listener kept separate so its onClose dependency can change freely. useEffect(() => { if (!open) return function onKey(e: KeyboardEvent) { if (e.key === 'Escape') onClose() } document.addEventListener('keydown', onKey) - const prev = document.body.style.overflow - document.body.style.overflow = 'hidden' - panelRef.current?.focus() - return () => { - document.removeEventListener('keydown', onKey) - document.body.style.overflow = prev - } + return () => document.removeEventListener('keydown', onKey) }, [open, onClose]) if (!open) return null