feat: footnotes (#2384)

* feat: footnotes

* feat: proper DOCX support
This commit is contained in:
Philip Okugbe
2026-08-12 12:30:30 +01:00
committed by GitHub
parent 7439da2f6e
commit a0b2ac6ae3
21 changed files with 987 additions and 9 deletions
@@ -1,4 +1,4 @@
import { HeadingLevel, ShadingType } from 'docx';
import { FootnoteReferenceRun, HeadingLevel, Paragraph, ShadingType } from 'docx';
import { Node } from 'prosemirror-model';
import {
DocxSerializerAsync,
@@ -168,6 +168,27 @@ export const defaultAsyncNodes: NodeSerializerAsync = {
pageBreak(state, node) {
state.closeBlock(node, { pageBreakBefore: true });
},
footnoteReference(state, node) {
const number =
Number(node.attrs?.referenceNumber) || state.$footnoteCounter + 1;
state.$footnoteCounter = Math.max(state.$footnoteCounter, number);
// seed an empty body so the reference stays valid even if the trailing
// footnotes list is missing; the footnotes node overwrites it with content
if (!state.footnotes[number]) {
state.footnotes[number] = { children: [new Paragraph('')] };
}
state.current.push(new FootnoteReferenceRun(number));
},
async footnotes(state, node) {
for (let i = 0; i < node.childCount; i += 1) {
const item = node.child(i);
const number =
Number(String(item.attrs?.id ?? '').replace('fn:', '')) || i + 1;
await state.footnoteDefinition(item, number);
}
},
// items are consumed by the footnotes handler above
footnote() {},
// No usable static export representation: skip without failing.
subpages() {},
transclusionReference() {},