Skip to content
53 changes: 34 additions & 19 deletions src/web/EnrichedTextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,21 @@ import {
} from './sanitization/htmlSanitizer';
import { assertBrowserEnvironment } from './utils/assertBrowserEnvironment';

function runSafelyInEditor<T>(
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 = ({
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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 }));
Expand Down Expand Up @@ -319,7 +331,9 @@ export const EnrichedTextInput = ({
}, [editor, returnKeyType]);

useEffect(() => {
editor?.commands.normalizeBoldInStyledHeadings();
runSafelyInEditor(editor, (e) =>
e.commands.normalizeBoldInStyledHeadings()
);
}, [editor, resolvedHtmlStyle]);

const getMentionCallbacks = useCallback(
Expand All @@ -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) => {
Expand Down Expand Up @@ -381,23 +397,22 @@ 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,
text: string,
attributes?: Record<string, string>
) => {
checkMentionAttributes(attributes);
setMention(
editor,
indicator,
text,
sanitizeMentionAttributes(attributes)
runSafelyInEditor(editor, (e) =>
setMention(e, indicator, text, sanitizeMentionAttributes(attributes))
);
},
setImage: (src: string, width: number, height: number) =>
Expand Down
Loading