diff --git a/src/web/EnrichedTextInput.tsx b/src/web/EnrichedTextInput.tsx index fecc1ee74..4e448e5b4 100644 --- a/src/web/EnrichedTextInput.tsx +++ b/src/web/EnrichedTextInput.tsx @@ -88,11 +88,21 @@ import { } from './sanitization/htmlSanitizer'; import { assertBrowserEnvironment } from './utils/assertBrowserEnvironment'; +function runSafelyInEditor( + editor: Editor | null, + callback: (editor: Editor) => T +): T | null { + if (editor && !editor.isDestroyed) { + return callback(editor); + } + return null; +} + function runFocused( editor: Editor, apply: (chain: ChainedCommands) => ChainedCommands ) { - apply(editor.chain().focus()).run(); + runSafelyInEditor(editor, (e) => apply(e.chain().focus()).run()); } export const EnrichedTextInput = ({ @@ -180,7 +190,7 @@ 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, (e) => e.commands.blur()); } return true; } @@ -259,7 +269,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, (e) => + e.commands.setContent(tiptapContent ?? '') + ); }, onFocus: ({ event }) => { onFocus?.(adaptWebToNativeEvent(event, { target: -1 })); @@ -319,7 +331,9 @@ export const EnrichedTextInput = ({ }, [editor, returnKeyType]); useEffect(() => { - editor?.commands.normalizeBoldInStyledHeadings(); + runSafelyInEditor(editor, (e) => + e.commands.normalizeBoldInStyledHeadings() + ); }, [editor, resolvedHtmlStyle]); const getMentionCallbacks = useCallback( @@ -336,14 +350,16 @@ export const EnrichedTextInput = ({ useImperativeHandle( ref, (): EnrichedTextInputInstance => ({ - focus: () => editor.commands.focus(), - blur: () => editor.commands.blur(), + focus: () => runSafelyInEditor(editor, (e) => e.commands.focus()), + blur: () => runSafelyInEditor(editor, (e) => e.commands.blur()), setValue: (value: string) => - editor.commands.setContent( - prepareHtmlForTiptap( - value, - useHtmlNormalizerRef.current, - sanitizationConfigRef.current + runSafelyInEditor(editor, (e) => + e.commands.setContent( + prepareHtmlForTiptap( + value, + useHtmlNormalizerRef.current, + sanitizationConfigRef.current + ) ) ), setSelection: (start, end) => { @@ -381,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, @@ -393,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) =>