diff --git a/packages/core/src/commands/toggleMark.ts b/packages/core/src/commands/toggleMark.ts index fa0b9ed11e..d43a8982e6 100644 --- a/packages/core/src/commands/toggleMark.ts +++ b/packages/core/src/commands/toggleMark.ts @@ -9,17 +9,27 @@ declare module '@tiptap/core' { /** * Toggle a mark on and off. */ - toggleMark: (typeOrName: string | MarkType, attributes?: Record) => ReturnType, + toggleMark: ( + typeOrName: string | MarkType, + attributes?: Record, + options?: { + /** + * Removes the mark even across the current selection. Defaults to `false`. + */ + extendEmptyMarkRange?: boolean, + }, + ) => ReturnType, } } } -export const toggleMark: RawCommands['toggleMark'] = (typeOrName, attributes = {}) => ({ state, commands }) => { +export const toggleMark: RawCommands['toggleMark'] = (typeOrName, attributes = {}, options = {}) => ({ state, commands }) => { + const { extendEmptyMarkRange = false } = options const type = getMarkType(typeOrName, state.schema) const isActive = isMarkActive(state, type, attributes) if (isActive) { - return commands.unsetMark(type) + return commands.unsetMark(type, { extendEmptyMarkRange }) } return commands.setMark(type, attributes) diff --git a/packages/core/src/commands/unsetMark.ts b/packages/core/src/commands/unsetMark.ts index a4db42fc7f..d9db99a2d3 100644 --- a/packages/core/src/commands/unsetMark.ts +++ b/packages/core/src/commands/unsetMark.ts @@ -9,35 +9,46 @@ declare module '@tiptap/core' { /** * Remove all marks in the current selection. */ - unsetMark: (typeOrName: string | MarkType) => ReturnType, + unsetMark: ( + typeOrName: string | MarkType, + options?: { + /** + * Removes the mark even across the current selection. Defaults to `false`. + */ + extendEmptyMarkRange?: boolean, + }, + ) => ReturnType, } } } -export const unsetMark: RawCommands['unsetMark'] = typeOrName => ({ tr, state, dispatch }) => { +export const unsetMark: RawCommands['unsetMark'] = (typeOrName, options = {}) => ({ tr, state, dispatch }) => { + const { extendEmptyMarkRange = false } = options const { selection } = tr const type = getMarkType(typeOrName, state.schema) const { $from, empty, ranges } = selection - if (dispatch) { - if (empty) { - let { from, to } = selection - const range = getMarkRange($from, type) - - if (range) { - from = range.from - to = range.to - } - - tr.removeMark(from, to, type) - } else { - ranges.forEach(range => { - tr.removeMark(range.$from.pos, range.$to.pos, type) - }) + if (!dispatch) { + return true + } + + if (empty && extendEmptyMarkRange) { + let { from, to } = selection + const range = getMarkRange($from, type) + + if (range) { + from = range.from + to = range.to } - tr.removeStoredMark(type) + tr.removeMark(from, to, type) + } else { + ranges.forEach(range => { + tr.removeMark(range.$from.pos, range.$to.pos, type) + }) } + tr.removeStoredMark(type) + return true } diff --git a/packages/extension-link/src/link.ts b/packages/extension-link/src/link.ts index c92a8ffcb9..f906bd0290 100644 --- a/packages/extension-link/src/link.ts +++ b/packages/extension-link/src/link.ts @@ -92,10 +92,10 @@ export const Link = Mark.create({ return commands.setMark('link', attributes) }, toggleLink: attributes => ({ commands }) => { - return commands.toggleMark('link', attributes) + return commands.toggleMark('link', attributes, { extendEmptyMarkRange: true }) }, unsetLink: () => ({ commands }) => { - return commands.unsetMark('link') + return commands.unsetMark('link', { extendEmptyMarkRange: true }) }, } },