From 85da6ef9b40db2785a479a3de73918b41c4b9300 Mon Sep 17 00:00:00 2001 From: Krystian Sienkiewicz Date: Tue, 18 Aug 2026 13:13:42 +0200 Subject: [PATCH 1/4] fix: destroyed editor check --- src/web/EnrichedTextInput.tsx | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/web/EnrichedTextInput.tsx b/src/web/EnrichedTextInput.tsx index fecc1ee74..0ecfc5033 100644 --- a/src/web/EnrichedTextInput.tsx +++ b/src/web/EnrichedTextInput.tsx @@ -88,11 +88,15 @@ import { } from './sanitization/htmlSanitizer'; import { assertBrowserEnvironment } from './utils/assertBrowserEnvironment'; +function runSafelyInEditor(editor: Editor | null, toRun: () => void) { + !!editor && !editor.isDestroyed && toRun(); +} + function runFocused( editor: Editor, apply: (chain: ChainedCommands) => ChainedCommands ) { - apply(editor.chain().focus()).run(); + runSafelyInEditor(editor, () => apply(editor.chain().focus()).run()); } export const EnrichedTextInput = ({ @@ -180,7 +184,9 @@ export const EnrichedTextInput = ({ const text = nativeLeafText(doc, 0, doc.content.size); onSubmitEditingRef.current?.(adaptWebToNativeEvent(event, { text })); if (sb === 'blurAndSubmit') { - editorInstanceRef.current?.commands.blur(); + runSafelyInEditor(editorInstanceRef.current, () => + editorInstanceRef.current?.commands.blur() + ); } return true; } @@ -259,7 +265,9 @@ export const EnrichedTextInput = ({ autofocus: autoFocus, onCreate: ({ editor: _editor }) => { // Setting initial content in this way ensures all custom plugins are run and applied - _editor.commands.setContent(tiptapContent ?? ''); + runSafelyInEditor(_editor, () => + _editor.commands.setContent(tiptapContent ?? '') + ); }, onFocus: ({ event }) => { onFocus?.(adaptWebToNativeEvent(event, { target: -1 })); @@ -319,7 +327,9 @@ export const EnrichedTextInput = ({ }, [editor, returnKeyType]); useEffect(() => { - editor?.commands.normalizeBoldInStyledHeadings(); + runSafelyInEditor(editor, () => + editor?.commands.normalizeBoldInStyledHeadings() + ); }, [editor, resolvedHtmlStyle]); const getMentionCallbacks = useCallback( @@ -336,14 +346,16 @@ export const EnrichedTextInput = ({ useImperativeHandle( ref, (): EnrichedTextInputInstance => ({ - focus: () => editor.commands.focus(), - blur: () => editor.commands.blur(), + focus: () => runSafelyInEditor(editor, () => editor.commands.focus()), + blur: () => runSafelyInEditor(editor, () => editor.commands.blur()), setValue: (value: string) => - editor.commands.setContent( - prepareHtmlForTiptap( - value, - useHtmlNormalizerRef.current, - sanitizationConfigRef.current + runSafelyInEditor(editor, () => + editor.commands.setContent( + prepareHtmlForTiptap( + value, + useHtmlNormalizerRef.current, + sanitizationConfigRef.current + ) ) ), setSelection: (start, end) => { From 04d5ae9e3e188323ddee41e272415035df3dd843 Mon Sep 17 00:00:00 2001 From: Krystian Sienkiewicz Date: Tue, 18 Aug 2026 13:46:17 +0200 Subject: [PATCH 2/4] refactor: code review suggestions --- src/web/EnrichedTextInput.tsx | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/web/EnrichedTextInput.tsx b/src/web/EnrichedTextInput.tsx index 0ecfc5033..f24f5bd50 100644 --- a/src/web/EnrichedTextInput.tsx +++ b/src/web/EnrichedTextInput.tsx @@ -88,15 +88,21 @@ import { } from './sanitization/htmlSanitizer'; import { assertBrowserEnvironment } from './utils/assertBrowserEnvironment'; -function runSafelyInEditor(editor: Editor | null, toRun: () => void) { - !!editor && !editor.isDestroyed && toRun(); +function runSafelyInEditor( + editor: Editor | null, + toRun: (editor: Editor) => T +): T | null { + if (editor && !editor.isDestroyed) { + return toRun(editor); + } + return null; } function runFocused( editor: Editor, apply: (chain: ChainedCommands) => ChainedCommands ) { - runSafelyInEditor(editor, () => apply(editor.chain().focus()).run()); + runSafelyInEditor(editor, (e) => apply(e.chain().focus()).run()); } export const EnrichedTextInput = ({ @@ -184,9 +190,7 @@ export const EnrichedTextInput = ({ const text = nativeLeafText(doc, 0, doc.content.size); onSubmitEditingRef.current?.(adaptWebToNativeEvent(event, { text })); if (sb === 'blurAndSubmit') { - runSafelyInEditor(editorInstanceRef.current, () => - editorInstanceRef.current?.commands.blur() - ); + runSafelyInEditor(editorInstanceRef.current, (e) => e.commands.blur()); } return true; } @@ -265,8 +269,8 @@ export const EnrichedTextInput = ({ autofocus: autoFocus, onCreate: ({ editor: _editor }) => { // Setting initial content in this way ensures all custom plugins are run and applied - runSafelyInEditor(_editor, () => - _editor.commands.setContent(tiptapContent ?? '') + runSafelyInEditor(_editor, (e) => + e.commands.setContent(tiptapContent ?? '') ); }, onFocus: ({ event }) => { @@ -327,8 +331,8 @@ export const EnrichedTextInput = ({ }, [editor, returnKeyType]); useEffect(() => { - runSafelyInEditor(editor, () => - editor?.commands.normalizeBoldInStyledHeadings() + runSafelyInEditor(editor, (e) => + e.commands.normalizeBoldInStyledHeadings() ); }, [editor, resolvedHtmlStyle]); @@ -346,11 +350,11 @@ export const EnrichedTextInput = ({ useImperativeHandle( ref, (): EnrichedTextInputInstance => ({ - focus: () => runSafelyInEditor(editor, () => editor.commands.focus()), - blur: () => runSafelyInEditor(editor, () => editor.commands.blur()), + focus: () => runSafelyInEditor(editor, (e) => e.commands.focus()), + blur: () => runSafelyInEditor(editor, (e) => e.commands.blur()), setValue: (value: string) => - runSafelyInEditor(editor, () => - editor.commands.setContent( + runSafelyInEditor(editor, (e) => + e.commands.setContent( prepareHtmlForTiptap( value, useHtmlNormalizerRef.current, From 26e7225f72af09efb591de581f57f47df61238cc Mon Sep 17 00:00:00 2001 From: Krystian Sienkiewicz Date: Tue, 18 Aug 2026 15:43:52 +0200 Subject: [PATCH 3/4] fix: additional checks --- src/web/EnrichedTextInput.tsx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/web/EnrichedTextInput.tsx b/src/web/EnrichedTextInput.tsx index f24f5bd50..a17b53d6d 100644 --- a/src/web/EnrichedTextInput.tsx +++ b/src/web/EnrichedTextInput.tsx @@ -397,11 +397,13 @@ export const EnrichedTextInput = ({ toggleCheckboxList: (checked: boolean) => runFocused(editor, (c) => c.toggleCheckboxList(checked)), setLink: (start: number, end: number, text: string, url: string) => - setLink(editor, start, end, text, url), + runSafelyInEditor(editor, (e) => setLink(e, start, end, text, url)), removeLink: (start: number, end: number) => - removeLink(editor, start, end), + runSafelyInEditor(editor, (e) => removeLink(e, start, end)), startMention: (indicator: string) => { - startMention(editor, indicator, mentionIndicatorsRef.current); + runSafelyInEditor(editor, (e) => + startMention(e, indicator, mentionIndicatorsRef.current) + ); }, setMention: ( indicator: string, @@ -409,11 +411,8 @@ export const EnrichedTextInput = ({ attributes?: Record ) => { checkMentionAttributes(attributes); - setMention( - editor, - indicator, - text, - sanitizeMentionAttributes(attributes) + runSafelyInEditor(editor, (e) => + setMention(e, indicator, text, sanitizeMentionAttributes(attributes)) ); }, setImage: (src: string, width: number, height: number) => From 7ea5f30f8cc095c47ea5da9954bd832edbd02d93 Mon Sep 17 00:00:00 2001 From: Krystian Sienkiewicz Date: Tue, 18 Aug 2026 15:45:15 +0200 Subject: [PATCH 4/4] refactor: callback name change --- src/web/EnrichedTextInput.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/web/EnrichedTextInput.tsx b/src/web/EnrichedTextInput.tsx index a17b53d6d..4e448e5b4 100644 --- a/src/web/EnrichedTextInput.tsx +++ b/src/web/EnrichedTextInput.tsx @@ -90,10 +90,10 @@ import { assertBrowserEnvironment } from './utils/assertBrowserEnvironment'; function runSafelyInEditor( editor: Editor | null, - toRun: (editor: Editor) => T + callback: (editor: Editor) => T ): T | null { if (editor && !editor.isDestroyed) { - return toRun(editor); + return callback(editor); } return null; }