🐛(frontend) fix find & replace crash when editor becomes read-only

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.
This commit is contained in:
Anthony LC
2026-09-15 16:19:23 +02:00
parent 26811a6bce
commit 5979c09b65
3 changed files with 20 additions and 1 deletions
+1
View File
@@ -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
@@ -36,6 +36,7 @@ export const FindReplace = () => {
const findInputRef = useRef<HTMLInputElement>(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 (
<Card
role="search"
@@ -9,7 +9,9 @@ export const useFindReplace = (editor: DocsBlockNoteEditor | undefined) => {
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,