fix: merge lists in editor (#8639)

This commit is contained in:
Vipin Chaudhary 2026-03-02 20:29:20 +05:30 committed by GitHub
parent 779f5e272f
commit 9ee73d57ef
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -23,22 +23,27 @@ declare module "@tiptap/core" {
} }
} }
function autoJoin(tr: Transaction, newTr: Transaction, nodeTypes: NodeType[]) { function collectRanges(transactions: readonly Transaction[]): Array<number> {
// Find all ranges where we might want to join.
const ranges: Array<number> = []; const ranges: Array<number> = [];
for (let i = 0; i < tr.mapping.maps.length; i++) { for (const tr of transactions) {
const map = tr.mapping.maps[i]; for (let i = 0; i < tr.mapping.maps.length; i++) {
for (let j = 0; j < ranges.length; j++) ranges[j] = map.map(ranges[j]); const map = tr.mapping.maps[i];
map.forEach((_s, _e, from, to) => ranges.push(from, to)); map.forEach((_s, _e, from, to) => ranges.push(from, to));
}
} }
return ranges;
}
function autoJoin(ranges: Array<number>, newTr: Transaction, nodeTypes: NodeType[]) {
const doc = newTr.doc;
// Figure out which joinable points exist inside those ranges, // Figure out which joinable points exist inside those ranges,
// by checking all node boundaries in their parent nodes. // by checking all node boundaries in their parent nodes.
const joinable: number[] = []; const joinable: number[] = [];
for (let i = 0; i < ranges.length; i += 2) { for (let i = 0; i < ranges.length; i += 2) {
const from = ranges[i], const from = ranges[i],
to = ranges[i + 1]; to = ranges[i + 1];
const $from = tr.doc.resolve(from), if (from >= doc.content.size) continue;
const $from = doc.resolve(from),
depth = $from.sharedDepth(to), depth = $from.sharedDepth(to),
parent = $from.node(depth); parent = $from.node(depth);
for (let index = $from.indexAfter(depth), pos = $from.after(depth + 1); pos <= to; ++index) { for (let index = $from.indexAfter(depth), pos = $from.after(depth + 1); pos <= to; ++index) {
@ -54,10 +59,10 @@ function autoJoin(tr: Transaction, newTr: Transaction, nodeTypes: NodeType[]) {
let joined = false; let joined = false;
// Join the joinable points // Join the joinable points (reverse order to keep positions stable)
joinable.sort((a, b) => a - b); joinable.sort((a, b) => a - b);
for (let i = joinable.length - 1; i >= 0; i--) { for (let i = joinable.length - 1; i >= 0; i--) {
if (canJoin(tr.doc, joinable[i])) { if (canJoin(doc, joinable[i])) {
newTr.join(joinable[i]); newTr.join(joinable[i]);
joined = true; joined = true;
} }
@ -91,7 +96,6 @@ export const CustomKeymap = Extension.create({
new Plugin({ new Plugin({
key: new PluginKey("ordered-list-merging"), key: new PluginKey("ordered-list-merging"),
appendTransaction(transactions, oldState, newState) { appendTransaction(transactions, oldState, newState) {
// Create a new transaction.
const newTr = newState.tr; const newTr = newState.tr;
const joinableNodes = [ const joinableNodes = [
@ -100,12 +104,8 @@ export const CustomKeymap = Extension.create({
newState.schema.nodes[CORE_EXTENSIONS.BULLET_LIST], newState.schema.nodes[CORE_EXTENSIONS.BULLET_LIST],
]; ];
let joined = false; const ranges = collectRanges(transactions);
for (const transaction of transactions) { if (ranges.length && autoJoin(ranges, newTr, joinableNodes)) {
const anotherJoin = autoJoin(transaction, newTr, joinableNodes);
joined = anotherJoin || joined;
}
if (joined) {
return newTr; return newTr;
} }
}, },