···1818 let scan = scanIndex(tx);
1919 return scan.eav(blockID, "block/footnote");
2020 });
2121- let lastPosition =
2222- existingFootnotes.length > 0
2323- ? existingFootnotes
2424- .map((f) => f.data.position)
2525- .sort()
2626- .at(-1)!
2727- : null;
2828- let position = generateKeyBetween(lastPosition, null);
2121+2222+ // Build a map from footnoteEntityID to its fractional-index position
2323+ let positionByEntityID: Record<string, string> = {};
2424+ for (let f of existingFootnotes) {
2525+ positionByEntityID[f.data.value] = f.data.position;
2626+ }
2727+2828+ // Find footnotes that appear before and after the insertion point in the text
2929+ let { from } = view.state.selection;
3030+ let beforePosition: string | null = null;
3131+ let afterPosition: string | null = null;
3232+ let foundInsertionPoint = false;
3333+3434+ view.state.doc.descendants((node, pos) => {
3535+ if (node.type.name === "footnote") {
3636+ let entityID = node.attrs.footnoteEntityID;
3737+ let p = positionByEntityID[entityID];
3838+ if (p !== undefined) {
3939+ if (pos < from) {
4040+ // This footnote is before the insertion point
4141+ if (beforePosition === null || p > beforePosition) {
4242+ beforePosition = p;
4343+ }
4444+ } else {
4545+ // This footnote is at or after the insertion point
4646+ if (!foundInsertionPoint) {
4747+ afterPosition = p;
4848+ foundInsertionPoint = true;
4949+ } else if (afterPosition !== null && p < afterPosition) {
5050+ afterPosition = p;
5151+ }
5252+ }
5353+ }
5454+ }
5555+ });
5656+5757+ let position = generateKeyBetween(beforePosition, afterPosition);
29583059 await rep.mutate.createFootnote({
3160 footnoteEntityID,
···3564 });
36653766 let node = schema.nodes.footnote.create({ footnoteEntityID });
3838- let { from } = view.state.selection;
3967 let tr = view.state.tr.insert(from, node);
4068 view.dispatch(tr);
4169