From 5979c09b65ca2fd616f0b112f76e3ba340137ece Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Tue, 15 Sep 2026 16:16:14 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B(frontend)=20fix=20find=20&=20repla?= =?UTF-8?q?ce=20crash=20when=20editor=20becomes=20read-only?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BlockNoteReader (read-only docs) doesn't register the find & replace tiptap extension. If the panel is left open while the active editor switches to it -- e.g. a collaborative doc turning read-only after a WebSocket disconnect -- calling into its commands threw "commands.clearSearch is not a function". useFindReplace now exposes whether the current editor actually supports find & replace, and FindReplace closes the panel and renders nothing when it doesn't, instead of crashing. --- CHANGELOG.md | 1 + .../doc-find-replace/components/FindReplace.tsx | 15 +++++++++++++++ .../docs/doc-find-replace/hooks/useFindReplace.ts | 5 ++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b753d1799..7a68597f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ and this project adheres to - 🐛(frontend) keep commented text sharp when printing to PDF #2674 - 🐛(docker) pull minio images from quay.io #2675 - ♿️(frontend) restore presenter focus trapping after share links #2533 +- 🐛(frontend) fix find & replace crash when editor becomes read-only #2684 ## [v5.6.1] - 2026-09-04 diff --git a/src/frontend/apps/impress/src/features/docs/doc-find-replace/components/FindReplace.tsx b/src/frontend/apps/impress/src/features/docs/doc-find-replace/components/FindReplace.tsx index a71e4eeeb..5394f400f 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-find-replace/components/FindReplace.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-find-replace/components/FindReplace.tsx @@ -36,6 +36,7 @@ export const FindReplace = () => { const findInputRef = useRef(null); const { + isSupported, query, setQuery, replacement, @@ -70,6 +71,16 @@ export const FindReplace = () => { findInputRef.current?.select(); }, [editor?._tiptapEditor, setQuery, openCount]); + // The editor can lose find & replace support while the panel is open, e.g. + // when a collaborative doc briefly turns read-only after a WebSocket + // disconnect. Close the panel so the floating bar falls back to its normal + // controls instead of rendering nothing. + useEffect(() => { + if (!isSupported) { + close(); + } + }, [isSupported, close]); + const handleClose = () => { close(); restoreFocus(); @@ -151,6 +162,10 @@ export const FindReplace = () => { handleReplaceCurrent(); }; + if (!isSupported) { + return null; + } + return ( { const [matchCount, setMatchCount] = useState(0); const [activeIndex, setActiveIndex] = useState(-1); - const tiptapEditor = editor?._tiptapEditor; + const isSupported = + typeof editor?._tiptapEditor.commands.clearSearch === 'function'; + const tiptapEditor = isSupported ? editor?._tiptapEditor : undefined; const syncFromStorage = useCallback(() => { if (!tiptapEditor) { @@ -111,6 +113,7 @@ export const useFindReplace = (editor: DocsBlockNoteEditor | undefined) => { }, [tiptapEditor]); return { + isSupported, query, setQuery, replacement,