diff --git a/packages/core/src/helpers/markIsActive.ts b/packages/core/src/helpers/markIsActive.ts index 65338fc1..9e9317ad 100644 --- a/packages/core/src/helpers/markIsActive.ts +++ b/packages/core/src/helpers/markIsActive.ts @@ -3,31 +3,62 @@ import { Mark, MarkType } from 'prosemirror-model' import objectIncludes from '../utilities/objectIncludes' import getMarkType from '../helpers/getMarkType' +type MarkRange = { + mark: Mark, + from: number, + to: number, +} + export default function markIsActive(state: EditorState, typeOrName: MarkType | string | null, attributes = {}) { const { from, to, empty } = state.selection const type = typeOrName ? getMarkType(typeOrName, state.schema) : null - let marks: Mark[] = [] - if (empty) { - marks = state.selection.$head.marks() - } else { - state.doc.nodesBetween(from, to, node => { - marks = [...marks, ...node.marks] - }) + return !!state.selection.$head.marks() + .filter(mark => { + if (!type) { + return true + } + + return type.name === mark.type.name + }) + .find(mark => objectIncludes(mark.attrs, attributes)) } - const markWithAttributes = marks - .filter(mark => { + let selectionRange = 0 + let markRanges: MarkRange[] = [] + + state.doc.nodesBetween(from, to, (node, pos) => { + if (node.isInline) { + const relativeFrom = Math.max(from, pos) + const relativeTo = Math.min(to, pos + node.nodeSize) + const range = relativeTo - relativeFrom + + selectionRange += range + + markRanges = [...markRanges, ...node.marks.map(mark => ({ + mark, + from: relativeFrom, + to: relativeTo, + }))] + } + }) + + const range = markRanges + .filter(markRange => { if (!type) { return true } - return type.name === mark.type.name + return type.name === markRange.mark.type.name }) - .find(mark => objectIncludes(mark.attrs, attributes)) + .filter(markRange => objectIncludes(markRange.mark.attrs, attributes)) + .reduce((sum, markRange) => { + const size = markRange.to - markRange.from + return sum + size + }, 0) - return !!markWithAttributes + return selectionRange <= range }