In ProseMirror many times plugins may need to know the changed regions to update it’s internal state. For example tiptap-unique-id extension uses findChildrenInRange to get a list of ranges to get the changed nodes. In other scenarios plugins can have state dependencies and may keep computed properties based on nodes. When a transaction happens the plugin has two option
- Create the internal state from scratch
- Reuse some of the old state and incrementally update
Currently I am using the following code to get the old and new range.
function getReplacedRange(tr: Transaction) {
if (!tr.docChanged) {
return null
}
let fromA = Infinity
let toA = -Infinity
let fromB = Infinity
let toB = -Infinity
// Get bounds in the original document by mapping each step's range backward
tr.mapping.maps.forEach((map, i) => {
map.forEach((from, to) => {
const newStart = tr.mapping.slice(i).map(from, -1)
const newEnd = tr.mapping.slice(i).map(to)
const oldStart = tr.mapping.invert().map(newStart, -1)
const oldEnd = tr.mapping.invert().map(newEnd)
fromA = min(fromA, oldStart, oldEnd)
toA = max(toA, oldStart, oldEnd)
fromB = min(fromB, newStart, newEnd)
toB = max(toB, newEnd, newStart)
})
})
const delta = toB - fromB - (toA - fromA)
// range (fromA, toA) is replaced by (fromB, toB) in new document
return { fromA, toA, fromB, toB, delta }
}
Are there any better approaches? Having the plugins depend on each others state is a good design?