Skip to content

Commit

Permalink
fix(core): handle selections better for updateAttributes (#5738)
Browse files Browse the repository at this point in the history
  • Loading branch information
silenius authored Nov 4, 2024
1 parent e338858 commit c50eb4b
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 12 deletions.
5 changes: 5 additions & 0 deletions .changeset/swift-keys-collect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tiptap/core": patch
---

Improve handling of selections with `updateAttributes`. Should no longer modify parent nodes of the same type.
84 changes: 72 additions & 12 deletions packages/core/src/commands/updateAttributes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { MarkType, NodeType } from '@tiptap/pm/model'
import {
Mark, MarkType, Node, NodeType,
} from '@tiptap/pm/model'
import { SelectionRange } from '@tiptap/pm/state'

import { getMarkType } from '../helpers/getMarkType.js'
import { getNodeType } from '../helpers/getNodeType.js'
Expand Down Expand Up @@ -30,6 +33,7 @@ declare module '@tiptap/core' {
}

export const updateAttributes: RawCommands['updateAttributes'] = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => {

let nodeType: NodeType | null = null
let markType: MarkType | null = null

Expand All @@ -51,24 +55,80 @@ export const updateAttributes: RawCommands['updateAttributes'] = (typeOrName, at
}

if (dispatch) {
tr.selection.ranges.forEach(range => {
tr.selection.ranges.forEach((range: SelectionRange) => {

const from = range.$from.pos
const to = range.$to.pos

state.doc.nodesBetween(from, to, (node, pos) => {
if (nodeType && nodeType === node.type) {
tr.setNodeMarkup(pos, undefined, {
...node.attrs,
let lastPos: number | undefined
let lastNode: Node | undefined
let trimmedFrom: number
let trimmedTo: number

if (tr.selection.empty) {
state.doc.nodesBetween(from, to, (node: Node, pos: number) => {

if (nodeType && nodeType === node.type) {
trimmedFrom = Math.max(pos, from)
trimmedTo = Math.min(pos + node.nodeSize, to)
lastPos = pos
lastNode = node
}
})
} else {
state.doc.nodesBetween(from, to, (node: Node, pos: number) => {

if (pos < from && nodeType && nodeType === node.type) {
trimmedFrom = Math.max(pos, from)
trimmedTo = Math.min(pos + node.nodeSize, to)
lastPos = pos
lastNode = node
}

if (pos >= from && pos <= to) {

if (nodeType && nodeType === node.type) {
tr.setNodeMarkup(pos, undefined, {
...node.attrs,
...attributes,
})
}

if (markType && node.marks.length) {
node.marks.forEach((mark: Mark) => {

if (markType === mark.type) {
const trimmedFrom2 = Math.max(pos, from)
const trimmedTo2 = Math.min(pos + node.nodeSize, to)

tr.addMark(
trimmedFrom2,
trimmedTo2,
markType.create({
...mark.attrs,
...attributes,
}),
)
}
})
}
}
})
}

if (lastNode) {

if (lastPos !== undefined) {
tr.setNodeMarkup(lastPos, undefined, {
...lastNode.attrs,
...attributes,
})
}

if (markType && node.marks.length) {
node.marks.forEach(mark => {
if (markType === mark.type) {
const trimmedFrom = Math.max(pos, from)
const trimmedTo = Math.min(pos + node.nodeSize, to)
if (markType && lastNode.marks.length) {
lastNode.marks.forEach((mark: Mark) => {

if (markType === mark.type) {
tr.addMark(
trimmedFrom,
trimmedTo,
Expand All @@ -80,7 +140,7 @@ export const updateAttributes: RawCommands['updateAttributes'] = (typeOrName, at
}
})
}
})
}
})
}

Expand Down

0 comments on commit c50eb4b

Please sign in to comment.