diff --git a/.changeset/fresh-ads-nail.md b/.changeset/fresh-ads-nail.md new file mode 100644 index 000000000..ead724dcc --- /dev/null +++ b/.changeset/fresh-ads-nail.md @@ -0,0 +1,5 @@ +--- +"@tiptap/core": minor +--- + +Add config option to emit content error when content check is disabled diff --git a/packages/core/src/Editor.ts b/packages/core/src/Editor.ts index 7a5572146..beee261e5 100644 --- a/packages/core/src/Editor.ts +++ b/packages/core/src/Editor.ts @@ -81,6 +81,7 @@ export class Editor extends EventEmitter { enablePasteRules: true, enableCoreExtensions: true, enableContentCheck: false, + emitContentError: false, onBeforeCreate: () => null, onCreate: () => null, onUpdate: () => null, diff --git a/packages/core/src/commands/insertContentAt.ts b/packages/core/src/commands/insertContentAt.ts index 33c84524d..c5aa7186f 100644 --- a/packages/core/src/commands/insertContentAt.ts +++ b/packages/core/src/commands/insertContentAt.ts @@ -72,24 +72,43 @@ export const insertContentAt: RawCommands['insertContentAt'] = (position, value, let content: Fragment | ProseMirrorNode - try { - content = createNodeFromContent(value, editor.schema, { - parseOptions: { - preserveWhitespace: 'full', - ...options.parseOptions, - }, - errorOnInvalidContent: options.errorOnInvalidContent ?? editor.options.enableContentCheck, - }) - } catch (e) { + const emitContentError = (error: Error) => { editor.emit('contentError', { editor, - error: e as Error, + error, disableCollaboration: () => { if (editor.storage.collaboration) { editor.storage.collaboration.isDisabled = true } }, }) + } + + const parseOptions: ParseOptions = { + preserveWhitespace: 'full', + ...options.parseOptions, + } + + // If `emitContentError` is enabled, we want to check the content for errors + // but ignore them (do not remove the invalid content from the document) + if (!options.errorOnInvalidContent && !editor.options.enableContentCheck && editor.options.emitContentError) { + try { + createNodeFromContent(value, editor.schema, { + parseOptions, + errorOnInvalidContent: true, + }) + } catch (e) { + emitContentError(e as Error) + } + } + + try { + content = createNodeFromContent(value, editor.schema, { + parseOptions, + errorOnInvalidContent: options.errorOnInvalidContent ?? editor.options.enableContentCheck, + }) + } catch (e) { + emitContentError(e as Error) return false } diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 0f231190b..f01018502 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -127,6 +127,15 @@ export interface EditorOptions { * @default false */ enableContentCheck: boolean; + /** + * If `true`, the editor will emit the `contentError` event if invalid content is + * encountered but `enableContentCheck` is `false`. This lets you preserve the + * invalid editor content while still showing a warning or error message to + * the user. + * + * @default false + */ + emitContentError: boolean; onBeforeCreate: (props: EditorEvents['beforeCreate']) => void; onCreate: (props: EditorEvents['create']) => void; /**