diff --git a/packages/core/src/extensions/delete.ts b/packages/core/src/extensions/delete.ts index 3cd7d14cc..d1d94b927 100644 --- a/packages/core/src/extensions/delete.ts +++ b/packages/core/src/extensions/delete.ts @@ -1,3 +1,5 @@ +import { RemoveMarkStep } from '@tiptap/pm/transform' + import { Extension } from '../Extension.js' import { combineTransactionSteps, getChangedRanges } from '../helpers/index.js' @@ -23,13 +25,17 @@ export const Delete = Extension.create({ nextTransaction.mapping.mapResult(change.oldRange.from).deletedAfter && nextTransaction.mapping.mapResult(change.oldRange.to).deletedBefore ) { - nextTransaction.before.nodesBetween(change.oldRange.from, change.oldRange.to, (node, pos) => { - const isFullyWithinRange = change.oldRange.from <= pos && pos + node.nodeSize - 2 <= change.oldRange.to + nextTransaction.before.nodesBetween(change.oldRange.from, change.oldRange.to, (node, from) => { + const to = from + node.nodeSize - 2 + const isFullyWithinRange = change.oldRange.from <= from && to <= change.oldRange.to this.editor.emit('delete', { + type: 'node', node, - pos, - newPos: nextTransaction.mapping.map(pos), + from, + to, + newFrom: nextTransaction.mapping.map(from), + newTo: nextTransaction.mapping.map(to), deletedRange: change.oldRange, newRange: change.newRange, partial: !isFullyWithinRange, @@ -40,6 +46,38 @@ export const Delete = Extension.create({ }) } }) + + const mapping = nextTransaction.mapping + nextTransaction.steps.forEach((step, index) => { + if (step instanceof RemoveMarkStep) { + const newStart = mapping.slice(index).map(step.from, -1) + const newEnd = mapping.slice(index).map(step.to) + const oldStart = mapping.invert().map(newStart, -1) + const oldEnd = mapping.invert().map(newEnd) + + const foundBeforeMark = nextTransaction.doc.nodeAt(newStart - 1)?.marks.some(mark => mark.eq(step.mark)) + const foundAfterMark = nextTransaction.doc.nodeAt(newEnd)?.marks.some(mark => mark.eq(step.mark)) + + this.editor.emit('delete', { + type: 'mark', + mark: step.mark, + from: step.from, + to: step.to, + deletedRange: { + from: oldStart, + to: oldEnd, + }, + newRange: { + from: newStart, + to: newEnd, + }, + partial: Boolean(foundAfterMark || foundBeforeMark), + editor: this.editor, + transaction, + combinedTransform: nextTransaction, + }) + } + }) } if (this.editor.options.coreExtensionOptions?.delete?.async ?? true) { diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 1b3862a7a..1a72c2ce6 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -182,23 +182,6 @@ export interface EditorEvents { * The editor instance */ editor: Editor - /** - * The node which the deletion occurred in - * @note This can be a parent node of the deleted content - */ - node: ProseMirrorNode - /** - * Whether the deletion was partial (only a part of this node was deleted) - */ - partial: boolean - /** - * This is the position of the node in the document (before the deletion) - */ - pos: number - /** - * The new position of the node in the document (after the deletion) - */ - newPos: number /** * The range of the deleted content (before the deletion) */ @@ -215,7 +198,49 @@ export interface EditorEvents { * The combined transform (including all appended transactions) that caused the deletion */ combinedTransform: Transform - } + /** + * Whether the deletion was partial (only a part of this content was deleted) + */ + partial: boolean + /** + * This is the start position of the mark in the document (before the deletion) + */ + from: number + /** + * This is the end position of the mark in the document (before the deletion) + */ + to: number + } & ( + | { + /** + * The content that was deleted + */ + type: 'node' + /** + * The node which the deletion occurred in + * @note This can be a parent node of the deleted content + */ + node: ProseMirrorNode + /** + * The new start position of the node in the document (after the deletion) + */ + newFrom: number + /** + * The new end position of the node in the document (after the deletion) + */ + newTo: number + } + | { + /** + * The content that was deleted + */ + type: 'mark' + /** + * The mark that was deleted + */ + mark: ProseMirrorMark + } + ) } export type EnableRules = (AnyExtension | string)[] | boolean