From a65b828c7861addd9e5eac31da2bf71d817acc9d Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 1 Aug 2026 13:00:22 +0000 Subject: [PATCH] fix: isolate note title in memoized component to prevent focus leak to search field --- apps/web/src/routes/_app/notes.tsx | 45 ++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/apps/web/src/routes/_app/notes.tsx b/apps/web/src/routes/_app/notes.tsx index 89dce5f..ed17f2b 100644 --- a/apps/web/src/routes/_app/notes.tsx +++ b/apps/web/src/routes/_app/notes.tsx @@ -50,6 +50,33 @@ const NoteEditor = memo(function NoteEditor({ initialContent, onSave, placeholde ); }); +// Isolated title input component - memo prevents re-render when parent re-renders +const NoteTitleInput = memo(function NoteTitleInput({ noteId, initialTitle }: { noteId: string; initialTitle: string }) { + const [title, setTitle] = useState(initialTitle); + const queryClient = useQueryClient(); + + useEffect(() => { + setTitle(initialTitle); + }, [noteId]); + + const handleBlur = () => { + if (title !== initialTitle) { + api.patch("/notes/" + noteId, { title: title }).then(() => { + queryClient.invalidateQueries({ queryKey: ["notes"] }); + }); + } + }; + + return ( + setTitle(e.target.value)} + onBlur={handleBlur} + className="flex h-9 w-full rounded-md border-0 bg-transparent px-0 py-1 text-lg font-semibold text-base shadow-none transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-0 disabled:cursor-not-allowed disabled:opacity-50" + /> + ); +}); + function NotesPage() { const queryClient = useQueryClient(); const [search, setSearch] = useState(""); @@ -166,17 +193,13 @@ function NotesPage() { {selectedNote ? ( <>
- { - if (selectedNote && e.target.value !== selectedNote.title) { - updateMutation.mutate({ id: selectedNote.id, data: { title: e.target.value } }); - setSelectedNote({ ...selectedNote, title: e.target.value }); - } - }} - className="flex h-9 w-full rounded-md border-0 bg-transparent px-0 py-1 text-lg font-semibold text-base shadow-none transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-0 disabled:cursor-not-allowed disabled:opacity-50" - /> + {selectedNote && ( + + )}