From 1ecbc21dee5cf675fe12d6f4dac7904e64bb4ed8 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 22 Jan 2026 11:26:47 +0000 Subject: [PATCH] fix: guard all RichEditor imperative methods against unmounted view Add isEditorReady() helper to check if editor.view.dom is mounted before accessing editor commands. This prevents the TipTap error "The editor view is not available" that occurred when PostViewer's draft loading called editor methods before the view was fully mounted. --- src/components/editor/RichEditor.tsx | 52 ++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/src/components/editor/RichEditor.tsx b/src/components/editor/RichEditor.tsx index 947c911..ff808bc 100644 --- a/src/components/editor/RichEditor.tsx +++ b/src/components/editor/RichEditor.tsx @@ -528,15 +528,31 @@ export const RichEditor = forwardRef( }, }); + // Helper to check if editor view is ready (prevents "view not available" errors) + const isEditorReady = useCallback(() => { + return editor && editor.view && editor.view.dom; + }, [editor]); + // Expose editor methods useImperativeHandle( ref, () => ({ - focus: () => editor?.commands.focus(), - clear: () => editor?.commands.clearContent(), - getContent: () => editor?.getText({ blockSeparator: "\n" }) || "", + focus: () => { + if (isEditorReady()) { + editor?.commands.focus(); + } + }, + clear: () => { + if (isEditorReady()) { + editor?.commands.clearContent(); + } + }, + getContent: () => { + if (!isEditorReady()) return ""; + return editor?.getText({ blockSeparator: "\n" }) || ""; + }, getSerializedContent: () => { - if (!editor) + if (!isEditorReady() || !editor) return { text: "", emojiTags: [], @@ -545,32 +561,40 @@ export const RichEditor = forwardRef( }; return serializeContent(editor); }, - isEmpty: () => editor?.isEmpty ?? true, + isEmpty: () => { + if (!isEditorReady()) return true; + return editor?.isEmpty ?? true; + }, submit: () => { - if (editor) { + if (isEditorReady() && editor) { handleSubmit(editor); } }, insertText: (text: string) => { - editor?.commands.insertContent(text); + if (isEditorReady()) { + editor?.commands.insertContent(text); + } }, insertBlob: (blob: BlobAttachment) => { - editor?.commands.insertContent({ - type: "blobAttachment", - attrs: blob, - }); + if (isEditorReady()) { + editor?.commands.insertContent({ + type: "blobAttachment", + attrs: blob, + }); + } }, getJSON: () => { + if (!isEditorReady()) return null; return editor?.getJSON() || null; }, setContent: (json: any) => { // Check editor and view are ready before setting content - if (editor?.view?.dom && json) { - editor.commands.setContent(json); + if (isEditorReady() && json) { + editor?.commands.setContent(json); } }, }), - [editor, handleSubmit], + [editor, handleSubmit, isEditorReady], ); // Handle submit on Ctrl/Cmd+Enter