@stll/folio-core 0.47.7 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/dist/controller/fontReadiness.js +3 -3
  2. package/dist/controller/hyphenationReadiness.d.ts +19 -0
  3. package/dist/controller/hyphenationReadiness.js +47 -0
  4. package/dist/controller/layoutPipeline.d.ts +3 -0
  5. package/dist/controller/layoutPipeline.js +59 -17
  6. package/dist/display-list/build/buildDisplayList.js +39 -12
  7. package/dist/display-list/build/pageFurniture.d.ts +7 -1
  8. package/dist/display-list/build/pageFurniture.js +21 -8
  9. package/dist/display-list/build/paragraphPrimitives.js +5 -4
  10. package/dist/display-list/build/tablePrimitives.js +10 -6
  11. package/dist/docx/attributeRemainder.js +10 -2
  12. package/dist/docx/blockContentParser.d.ts +2 -0
  13. package/dist/docx/blockContentParser.js +77 -62
  14. package/dist/docx/commentParser.d.ts +2 -1
  15. package/dist/docx/commentParser.js +57 -45
  16. package/dist/docx/containerChildren.d.ts +21 -8
  17. package/dist/docx/containerChildren.js +39 -9
  18. package/dist/docx/documentParser.d.ts +5 -1
  19. package/dist/docx/documentParser.js +8 -5
  20. package/dist/docx/documentSectionFacts.d.ts +22 -0
  21. package/dist/docx/documentSectionFacts.js +43 -0
  22. package/dist/docx/fieldParser.d.ts +8 -1
  23. package/dist/docx/fieldParser.js +47 -3
  24. package/dist/docx/fontTableParser.js +34 -27
  25. package/dist/docx/footnoteParser.d.ts +3 -2
  26. package/dist/docx/footnoteParser.js +15 -12
  27. package/dist/docx/groupDrawingParser.d.ts +2 -1
  28. package/dist/docx/groupDrawingParser.js +3 -6
  29. package/dist/docx/headerFooterParser.d.ts +7 -2
  30. package/dist/docx/headerFooterParser.js +15 -5
  31. package/dist/docx/hyperlinkParser.d.ts +48 -36
  32. package/dist/docx/hyperlinkParser.js +97 -82
  33. package/dist/docx/numberingParser.js +108 -84
  34. package/dist/docx/paragraphParser.d.ts +5 -1
  35. package/dist/docx/paragraphParser.js +381 -362
  36. package/dist/docx/paragraphProperties.js +123 -109
  37. package/dist/docx/paragraphPropertySource.d.ts +6 -1
  38. package/dist/docx/paragraphPropertySource.js +9 -1
  39. package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
  40. package/dist/docx/paragraphTextBoxEnrichment.js +17 -6
  41. package/dist/docx/parser.d.ts +7 -1
  42. package/dist/docx/parser.js +33 -16
  43. package/dist/docx/previewBudget.d.ts +55 -33
  44. package/dist/docx/previewBudget.js +59 -65
  45. package/dist/docx/rezip.js +41 -58
  46. package/dist/docx/runParser.d.ts +4 -1
  47. package/dist/docx/runParser.js +172 -184
  48. package/dist/docx/sdtProperties.js +87 -84
  49. package/dist/docx/sectionParser.js +169 -160
  50. package/dist/docx/serializer/paragraphSerializer.js +42 -38
  51. package/dist/docx/serializer/settingsSerializer.js +19 -1
  52. package/dist/docx/settingsParser.js +8 -0
  53. package/dist/docx/streamingXmlParser.d.ts +6 -2
  54. package/dist/docx/streamingXmlParser.js +12 -7
  55. package/dist/docx/styleParser.js +34 -8
  56. package/dist/docx/tableParser.d.ts +21 -12
  57. package/dist/docx/tableParser.js +518 -441
  58. package/dist/docx/textBoxParser.d.ts +8 -3
  59. package/dist/docx/textBoxParser.js +3 -3
  60. package/dist/docx/verbatimCapture.d.ts +10 -8
  61. package/dist/docx/verbatimCapture.js +45 -2
  62. package/dist/docx/vmlImageParser.d.ts +15 -13
  63. package/dist/docx/vmlImageParser.js +75 -60
  64. package/dist/docx/vmlPreview.d.ts +3 -3
  65. package/dist/docx/vmlPreview.js +3 -4
  66. package/dist/docx/xmlNamespaceContext.d.ts +9 -0
  67. package/dist/docx/xmlNamespaceContext.js +54 -0
  68. package/dist/docx/xmlParser.d.ts +6 -3
  69. package/dist/docx/xmlParser.js +11 -41
  70. package/dist/docx/xmlResourceLimits.d.ts +2 -1
  71. package/dist/docx/xmlResourceLimits.js +4 -1
  72. package/dist/fonts/headlessMeasure.js +0 -0
  73. package/dist/headless-layout.d.ts +11 -2
  74. package/dist/headless-layout.js +153 -107
  75. package/dist/internal/paragraphFormattingSerialization.js +3 -3
  76. package/dist/layout-bridge/convert/endnoteLayout.d.ts +65 -0
  77. package/dist/layout-bridge/convert/endnoteLayout.js +227 -0
  78. package/dist/layout-bridge/convert/footnoteLayout.d.ts +19 -3
  79. package/dist/layout-bridge/convert/footnoteLayout.js +40 -31
  80. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -7
  81. package/dist/layout-bridge/convert/headerFooterLayout.js +5 -20
  82. package/dist/layout-bridge/convert/paragraphMarkFormatting.d.ts +10 -0
  83. package/dist/layout-bridge/convert/paragraphMarkFormatting.js +59 -0
  84. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +29 -1
  85. package/dist/layout-bridge/convert/toFlowBlocks.js +258 -35
  86. package/dist/layout-bridge/engine/hitTest.js +5 -3
  87. package/dist/layout-bridge/engine/selectionRects.js +5 -3
  88. package/dist/layout-engine/anchorLayoutInCellCompatibility.d.ts +10 -0
  89. package/dist/layout-engine/anchorLayoutInCellCompatibility.js +22 -0
  90. package/dist/layout-engine/index.d.ts +2 -2
  91. package/dist/layout-engine/index.js +70 -11
  92. package/dist/layout-engine/justificationCompatibility.d.ts +1 -1
  93. package/dist/layout-engine/justificationCompatibility.js +9 -5
  94. package/dist/layout-engine/keep-together.d.ts +11 -5
  95. package/dist/layout-engine/keep-together.js +39 -16
  96. package/dist/layout-engine/layoutInstrumentation.d.ts +8 -2
  97. package/dist/layout-engine/layoutInstrumentation.js +8 -1
  98. package/dist/layout-engine/measure/advanceComposition.js +4 -7
  99. package/dist/layout-engine/measure/hyphenationDictionaries.d.ts +74 -0
  100. package/dist/layout-engine/measure/hyphenationDictionaries.js +138 -0
  101. package/dist/layout-engine/measure/hyphenationPreload.d.ts +11 -0
  102. package/dist/layout-engine/measure/hyphenationPreload.js +24 -0
  103. package/dist/layout-engine/measure/lineBreakProvider.d.ts +12 -2
  104. package/dist/layout-engine/measure/lineBreakProvider.js +30 -30
  105. package/dist/layout-engine/measure/lineBreaks.d.ts +6 -1
  106. package/dist/layout-engine/measure/lineBreaks.js +10 -3
  107. package/dist/layout-engine/measure/listMarkerWidth.d.ts +9 -6
  108. package/dist/layout-engine/measure/listMarkerWidth.js +20 -22
  109. package/dist/layout-engine/measure/measureBlocks.js +42 -8
  110. package/dist/layout-engine/measure/measureContainer.js +5 -5
  111. package/dist/layout-engine/measure/measureHelpers.d.ts +15 -3
  112. package/dist/layout-engine/measure/measureHelpers.js +21 -5
  113. package/dist/layout-engine/measure/measureParagraph.js +109 -30
  114. package/dist/layout-engine/measure/measureTypes.d.ts +5 -0
  115. package/dist/layout-engine/measure/tabCalculator.d.ts +2 -0
  116. package/dist/layout-engine/measure/tabCalculator.js +2 -1
  117. package/dist/layout-engine/measure/tableCellFloating.d.ts +2 -0
  118. package/dist/layout-engine/measure/tableCellFloating.js +51 -19
  119. package/dist/layout-engine/measure/tableCellGrid.d.ts +28 -3
  120. package/dist/layout-engine/measure/tableCellGrid.js +45 -5
  121. package/dist/layout-engine/measure/tableFragmentBorderGeometry.js +2 -1
  122. package/dist/layout-engine/noteAreaFlow.d.ts +19 -0
  123. package/dist/layout-engine/noteAreaFlow.js +83 -0
  124. package/dist/layout-engine/paginator.d.ts +10 -1
  125. package/dist/layout-engine/paginator.js +13 -1
  126. package/dist/layout-engine/tableRowBreak.js +3 -1
  127. package/dist/layout-engine/types.d.ts +89 -3
  128. package/dist/layout-engine/types.js +96 -1
  129. package/dist/layout-painter/index.d.ts +3 -0
  130. package/dist/layout-painter/renderPage.js +32 -83
  131. package/dist/layout-painter/renderParagraph.d.ts +6 -1
  132. package/dist/layout-painter/renderParagraph.js +34 -22
  133. package/dist/layout-painter/renderTable.js +26 -13
  134. package/dist/prosemirror/attrs/index.d.ts +9 -9
  135. package/dist/prosemirror/attrs/index.js +43 -11
  136. package/dist/prosemirror/conversion/fromProseDoc.js +8 -1
  137. package/dist/prosemirror/conversion/markInterner.d.ts +21 -0
  138. package/dist/prosemirror/conversion/markInterner.js +90 -0
  139. package/dist/prosemirror/conversion/toProseDoc.js +77 -41
  140. package/dist/prosemirror/extensions/core/DocExtension.js +2 -1
  141. package/dist/prosemirror/extensions/core/ParagraphExtension.js +1 -0
  142. package/dist/prosemirror/extensions/marks/markUtils.d.ts +6 -2
  143. package/dist/prosemirror/extensions/marks/markUtils.js +39 -51
  144. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +2 -1
  145. package/dist/prosemirror/listMarker.d.ts +1 -0
  146. package/dist/prosemirror/listMarker.js +2 -0
  147. package/dist/prosemirror/listRenderingAttrs.d.ts +1 -0
  148. package/dist/prosemirror/listRenderingAttrs.js +3 -0
  149. package/dist/prosemirror/schema/nodes.d.ts +13 -1
  150. package/dist/prosemirror/textBoxHostParagraph.d.ts +13 -0
  151. package/dist/prosemirror/textBoxHostParagraph.js +21 -0
  152. package/dist/prosemirror/validation.js +91 -80
  153. package/dist/utils/createDocument.js +10 -1
  154. package/dist/utils/scriptSegments.d.ts +33 -4
  155. package/dist/utils/scriptSegments.js +39 -6
  156. package/dist/utils/textFormattingMerge.d.ts +17 -3
  157. package/dist/utils/textFormattingMerge.js +18 -12
  158. package/dist/utils/trailingText.d.ts +22 -0
  159. package/dist/utils/trailingText.js +32 -0
  160. package/package.json +2 -2
@@ -9,7 +9,8 @@ const tableFragmentBottomBorders = ({ fragment, block, measure, placements: supp
9
9
  const placements = suppliedPlacements ?? buildTableCellPlacements({
10
10
  grid: buildTableCellGrid(block.rows, measure.columnWidths.length),
11
11
  columnWidths: measure.columnWidths,
12
- bidi: block.bidi === true
12
+ bidi: block.bidi === true,
13
+ cellSpacing: block.cellSpacing
13
14
  });
14
15
  return splitRow.cells.flatMap((cell) => {
15
16
  const placement = placements.get(cell);
@@ -0,0 +1,19 @@
1
+ import { FlowBlock, Layout, Measure, NoteAreaLayout } from "./types.js";
2
+ import { PageTopContinuation, Paginator } from "./paginator.js";
3
+ //#region src/layout-engine/noteAreaFlow.d.ts
4
+ /**
5
+ * The continuation separator a page opens with while a note area continues
6
+ * onto it. Its space after collapses with the next note paragraph's space
7
+ * before, as between any two paragraphs.
8
+ */
9
+ declare function createNoteAreaContinuation(noteAreas: NoteAreaLayout | undefined, paginator: Paginator): PageTopContinuation | undefined;
10
+ /** Whether laying out `block` continues a note area onto any page it opens. */
11
+ declare function continuesNoteArea(noteAreas: NoteAreaLayout | undefined, block: FlowBlock): boolean;
12
+ /**
13
+ * Record where each separator mark landed. A rule is centred on the first line
14
+ * of the separator paragraph: a `w:separator` spans part of the column and a
15
+ * `w:continuationSeparator` all of it.
16
+ */
17
+ declare function annotateNoteSeparators(layout: Layout, blocks: readonly FlowBlock[], measures: readonly Measure[], noteAreas: NoteAreaLayout | undefined): Layout;
18
+ //#endregion
19
+ export { annotateNoteSeparators, continuesNoteArea, createNoteAreaContinuation };
@@ -0,0 +1,83 @@
1
+ import { measuredLineRangeHeight } from "./lineFlow.js";
2
+ import { getParagraphSpacingAfter } from "./paragraphSpacing.js";
3
+ import { NOTE_SEPARATOR_RULE_THICKNESS, NOTE_SEPARATOR_WIDTH_FRACTION } from "./types.js";
4
+ //#region src/layout-engine/noteAreaFlow.ts
5
+ /**
6
+ * Note areas that flow with the body (ECMA-376 §17.11).
7
+ *
8
+ * Endnotes are collected after the last body block of the document, or of a
9
+ * section, and paginate exactly as body content does. Two things set them
10
+ * apart from the body: the area opens with its `w:separator` story, and every
11
+ * page the area continues onto opens with its `w:continuationSeparator` story.
12
+ * Both stories draw their separator mark as a horizontal rule.
13
+ */
14
+ /**
15
+ * The continuation separator a page opens with while a note area continues
16
+ * onto it. Its space after collapses with the next note paragraph's space
17
+ * before, as between any two paragraphs.
18
+ */
19
+ function createNoteAreaContinuation(noteAreas, paginator) {
20
+ const continuation = noteAreas?.continuationSeparator;
21
+ if (continuation === void 0) return;
22
+ const { block, measure } = continuation;
23
+ const height = measuredLineRangeHeight(measure.lines, 0, measure.lines.length);
24
+ return (state, x, width) => {
25
+ const fragment = {
26
+ kind: "paragraph",
27
+ blockId: block.id,
28
+ x,
29
+ y: state.cursorY,
30
+ width,
31
+ height,
32
+ fromLine: 0,
33
+ toLine: measure.lines.length
34
+ };
35
+ paginator.addUnflowedFragment(fragment);
36
+ state.trailingSpacing = getParagraphSpacingAfter(block);
37
+ return height;
38
+ };
39
+ }
40
+ /** Whether laying out `block` continues a note area onto any page it opens. */
41
+ function continuesNoteArea(noteAreas, block) {
42
+ return noteAreas?.contentBlockIds.has(String(block.id)) === true;
43
+ }
44
+ /**
45
+ * Record where each separator mark landed. A rule is centred on the first line
46
+ * of the separator paragraph: a `w:separator` spans part of the column and a
47
+ * `w:continuationSeparator` all of it.
48
+ */
49
+ function annotateNoteSeparators(layout, blocks, measures, noteAreas) {
50
+ if (noteAreas === void 0 || noteAreas.separatorBlockIds.size === 0) return layout;
51
+ const measureById = /* @__PURE__ */ new Map();
52
+ for (const [index, block] of blocks.entries()) {
53
+ const measure = measures[index];
54
+ if (noteAreas.separatorBlockIds.has(String(block.id)) && measure?.kind === "paragraph") measureById.set(String(block.id), measure);
55
+ }
56
+ const continuation = noteAreas.continuationSeparator;
57
+ if (continuation !== void 0) measureById.set(String(continuation.block.id), continuation.measure);
58
+ for (const page of layout.pages) {
59
+ const rules = [];
60
+ for (const fragment of page.fragments) {
61
+ if (fragment.kind !== "paragraph" || fragment.fromLine !== 0) continue;
62
+ const kind = noteAreas.separatorBlockIds.get(String(fragment.blockId));
63
+ const firstLine = measureById.get(String(fragment.blockId))?.lines.at(0);
64
+ if (kind === void 0 || firstLine === void 0) continue;
65
+ rules.push({
66
+ x: fragment.x,
67
+ y: fragment.y + (firstLine.lineHeight - NOTE_SEPARATOR_RULE_THICKNESS) / 2,
68
+ width: fragment.width * separatorWidthFraction(kind)
69
+ });
70
+ }
71
+ if (rules.length > 0) page.noteSeparators = rules;
72
+ }
73
+ return layout;
74
+ }
75
+ function separatorWidthFraction(kind) {
76
+ switch (kind) {
77
+ case "separator": return NOTE_SEPARATOR_WIDTH_FRACTION;
78
+ case "continuationSeparator": return 1;
79
+ default: return kind;
80
+ }
81
+ }
82
+ //#endregion
83
+ export { annotateNoteSeparators, continuesNoteArea, createNoteAreaContinuation };
@@ -65,6 +65,13 @@ type PaginatorOptions = {
65
65
  type ForcePageBreakOptions = {
66
66
  coalesceBlankPage?: boolean;
67
67
  };
68
+ /**
69
+ * Content that opens every page created while a flow continues from an
70
+ * earlier page (a note area's continuation separator). Called with the new
71
+ * page's state and the first column's box; returns the height it placed,
72
+ * which the page's flow then starts below.
73
+ */
74
+ type PageTopContinuation = (state: PageState, x: number, width: number) => number;
68
75
  declare const SECTION_START_PLACEMENT: {
69
76
  readonly CONTINUOUS: "continuous";
70
77
  readonly NEXT_PAGE: "nextPage";
@@ -147,7 +154,9 @@ declare function createPaginator(options: PaginatorOptions): {
147
154
  }, newMargins?: PageMargins, applyImmediately?: boolean) => void;
148
155
  /** Mark the next created page as the first page of a new section. */
149
156
  startSection: ({ sectionIndex, pageNumbering, placement }: StartSectionOptions) => void;
157
+ /** Set (or clear) the content that opens each page a flow continues onto. */
158
+ setPageTopContinuation: (continuation: PageTopContinuation | undefined) => void;
150
159
  };
151
160
  type Paginator = ReturnType<typeof createPaginator>;
152
161
  //#endregion
153
- export { FOOTNOTE_SEPARATOR_HEIGHT, PageState, Paginator, PaginatorOptions, SECTION_START_PLACEMENT, calculateColumnLefts, calculateColumnWidths, createPaginator, resolveColumnLeft };
162
+ export { FOOTNOTE_SEPARATOR_HEIGHT, PageState, PageTopContinuation, Paginator, PaginatorOptions, SECTION_START_PLACEMENT, calculateColumnLefts, calculateColumnWidths, createPaginator, resolveColumnLeft };
@@ -62,6 +62,7 @@ function createPaginator(options) {
62
62
  type: "pending",
63
63
  placement: "nextPage"
64
64
  };
65
+ let pageTopContinuation;
65
66
  const pages = [];
66
67
  const states = [];
67
68
  const paginationStateByPage = /* @__PURE__ */ new WeakMap();
@@ -180,6 +181,13 @@ function createPaginator(options) {
180
181
  states.push(state);
181
182
  columnRegionTop = topMargin;
182
183
  columnRegionMaxBottom = topMargin;
184
+ const continuationHeight = pageTopContinuation?.(state, getColumnX(0), columnWidths[0] ?? getContentWidth()) ?? 0;
185
+ if (continuationHeight > 0) {
186
+ state.cursorY += continuationHeight;
187
+ state.topMargin += continuationHeight;
188
+ columnRegionTop = state.topMargin;
189
+ columnRegionMaxBottom = state.topMargin;
190
+ }
183
191
  if (options.onNewPage) options.onNewPage(state);
184
192
  return state;
185
193
  }
@@ -503,7 +511,11 @@ function createPaginator(options) {
503
511
  /** Update page size/margins for subsequent pages. */
504
512
  updatePageLayout,
505
513
  /** Mark the next created page as the first page of a new section. */
506
- startSection
514
+ startSection,
515
+ /** Set (or clear) the content that opens each page a flow continues onto. */
516
+ setPageTopContinuation: (continuation) => {
517
+ pageTopContinuation = continuation;
518
+ }
507
519
  };
508
520
  }
509
521
  //#endregion
@@ -2,6 +2,7 @@ import { measuredLineAdvance } from "./lineFlow.js";
2
2
  import { measureParagraph } from "./measure/measureParagraph.js";
3
3
  import { buildTableCellFloatingZones, getTableCellContentWidth, getTableCellFloatingImages } from "./measure/tableCellFloating.js";
4
4
  import { createTableCellFlowState, placeTableCellBlock } from "./measure/tableCellFlow.js";
5
+ import { getTableCellSpacingInsetsY } from "./measure/tableCellGrid.js";
5
6
  import { isEmptyParagraph } from "./paragraphSpacing.js";
6
7
  import { resolveTableCellPadding } from "./types.js";
7
8
  //#region src/layout-engine/tableRowBreak.ts
@@ -164,7 +165,8 @@ function buildTableRowBreakInfo(block, measure) {
164
165
  const measuredCell = measuredCells[c];
165
166
  if (!measuredCell) continue;
166
167
  const sourceCell = sourceCells[c];
167
- const geometry = shiftCellGeometry(cellBreakGeometry(sourceCell, measuredCell), getVerticalAlignmentOffset(sourceCell, measuredCell, rowHeight));
168
+ const spacing = getTableCellSpacingInsetsY(block.cellSpacing, r, sourceCell?.rowSpan ?? 1, block.rows.length);
169
+ const geometry = shiftCellGeometry(cellBreakGeometry(sourceCell, measuredCell), spacing.top + getVerticalAlignmentOffset(sourceCell, measuredCell, Math.max(0, rowHeight - spacing.top - spacing.bottom)));
168
170
  cellGeometries.push(geometry);
169
171
  for (const b of geometry.bottoms) if (b > 0 && b < rowHeight) offsets.add(b);
170
172
  }
@@ -2,7 +2,7 @@ import { OutlineStyleAttr } from "../types/documentEnumValues.js";
2
2
  import { CssBorderStyle } from "../utils/borderCss.js";
3
3
  import { ImagePosition, ImageWrap, InlineWrapper, NumberFormat, OutlineLevel, ParagraphNumberingOverride, PreviewDescriptor, SdtProperties, SdtType, SectionStart, ShapeTextBody, TableCellFormatting, TableWidthType, UnderlineStyle, VerticalAlign } from "@stll/docx-core/model";
4
4
  declare namespace types_d_exports {
5
- export { BlockId, BorderStyle, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, Layout, LayoutOptions, LineBreakRun, ListMarkerFormatting, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, RenderedPageBreakRun, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, SectionPageNumbering, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isListNumPr, isTextWrappingFloatingImageRun, resolveTableCellPadding, resolveTableWidthPx, tableColumnsArePinned };
5
+ export { BlockId, BorderStyle, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, Layout, LayoutOptions, LineBreakRun, ListMarkerFormatting, MathRun, Measure, MeasuredLine, NOTE_SEPARATOR_RULE_THICKNESS, NOTE_SEPARATOR_WIDTH_FRACTION, NoteAreaLayout, NoteSeparatorKind, NoteSeparatorRule, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, RenderedPageBreakRun, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, SectionPageNumbering, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isListNumPr, isTextWrappingFloatingImageRun, resolveTableCellPadding, resolveTableWidthPx, stripFlowBlockPmAnchors, tableColumnsArePinned };
6
6
  }
7
7
  /**
8
8
  * Unique identifier for a block in the document.
@@ -47,6 +47,11 @@ type RunFormatting = {
47
47
  eastAsiaFontFamily?: string;
48
48
  /** OOXML alternate-name fallback for `eastAsiaFontFamily`. */
49
49
  eastAsiaAlternateFontFamily?: string;
50
+ /**
51
+ * `w:rFonts/@w:hint="eastAsia"`: the symbols and punctuation shared with East
52
+ * Asian text also take `eastAsiaFontFamily` (see `isEastAsiaHintCodePoint`).
53
+ */
54
+ eastAsiaHint?: boolean;
50
55
  /**
51
56
  * Resolved complex-script font (`w:cs` / `cstheme`). Arabic, Hebrew, Indic
52
57
  * and South-East Asian code points in this run measure and paint with this
@@ -155,7 +160,7 @@ type RunFormatting = {
155
160
  /** Groups a suggestion's runs for accept/reject and scroll-to. */
156
161
  suggestionId?: string;
157
162
  };
158
- type ListMarkerFormatting = Pick<RunFormatting, "fontFamily" | "alternateFontFamily" | "eastAsiaFontFamily" | "eastAsiaAlternateFontFamily" | "complexScriptFontFamily" | "complexScriptAlternateFontFamily" | "fontSize" | "complexScriptFontSize" | "bold" | "complexScriptBold" | "italic" | "complexScriptItalic" | "rtl" | "forceComplexScript">;
163
+ type ListMarkerFormatting = Pick<RunFormatting, "fontFamily" | "alternateFontFamily" | "eastAsiaFontFamily" | "eastAsiaAlternateFontFamily" | "complexScriptFontFamily" | "complexScriptAlternateFontFamily" | "fontSize" | "complexScriptFontSize" | "bold" | "complexScriptBold" | "italic" | "complexScriptItalic" | "rtl" | "forceComplexScript" | "color">;
159
164
  /**
160
165
  * Hyperlink information for a run.
161
166
  */
@@ -519,6 +524,12 @@ type ParagraphAttrs = {
519
524
  * one space glyph; `nothing` lets body text butt against the marker.
520
525
  */
521
526
  listMarkerSuffix?: "tab" | "space" | "nothing";
527
+ /**
528
+ * `w:doNotUseIndentAsNumberingTabStop` (§17.15.3): the hanging indent is
529
+ * not an implicit stop for the tab after the number, so the first custom
530
+ * stop past the marker wins wherever it is.
531
+ */
532
+ listNumberingTabIgnoresIndent?: boolean;
522
533
  /**
523
534
  * Tracked-change state of the list numbering itself. When a list is applied
524
535
  * (or removed) under suggesting mode, the marker paints in the insertion /
@@ -681,6 +692,14 @@ type TableBlock = {
681
692
  justification?: "left" | "center" | "right";
682
693
  /** Table indent from the leading margin (in pixels, from w:tblInd). */
683
694
  indent?: number;
695
+ /**
696
+ * Default cell spacing in pixels (`w:tblCellSpacing`, §17.4.43). Each cell
697
+ * box sits this far inside its grid slot on every side, so adjacent cells
698
+ * stand twice this apart, and the table edge adds one more unit around the
699
+ * outermost cells. Borders then follow the separated model: every cell
700
+ * paints its own four edges.
701
+ */
702
+ cellSpacing?: number;
684
703
  /**
685
704
  * Pre-Word-2013 `w:tblInd` semantics: the indent measures to the leading
686
705
  * cell's text edge instead of the table border. Derived from the document's
@@ -865,6 +884,23 @@ type TextBoxBlock = {
865
884
  left: number;
866
885
  right: number;
867
886
  };
887
+ /**
888
+ * An inline box's `wp:effectExtent`, in pixels. The line reserves these
889
+ * beyond the box's own extent on each side, so the box sits `left`/`top`
890
+ * inside the space it occupies (ECMA-376 §20.4.2.6).
891
+ */
892
+ effectExtent?: {
893
+ top: number;
894
+ bottom: number;
895
+ left: number;
896
+ right: number;
897
+ };
898
+ /**
899
+ * The paragraph an inline box is the only content of. The box is run
900
+ * content of that paragraph, so its spacing surrounds the box and its
901
+ * indentation and alignment place it on the line.
902
+ */
903
+ hostParagraph?: ParagraphAttrs;
868
904
  /** Flow blocks inside the text box */
869
905
  content: (ParagraphBlock | TableBlock)[];
870
906
  /** Display mode copied from the ProseMirror text box node. */
@@ -1208,9 +1244,23 @@ type Page = {
1208
1244
  footnoteIds?: number[];
1209
1245
  /** Height reserved for the footnote area at page bottom (pixels). */
1210
1246
  footnoteReservedHeight?: number;
1247
+ /**
1248
+ * Rules drawn for the `w:separator` / `w:continuationSeparator` marks of a
1249
+ * note area that flows with the body (endnotes), in page coordinates.
1250
+ */
1251
+ noteSeparators?: NoteSeparatorRule[];
1211
1252
  /** Column layout for this page (if multi-column). */
1212
1253
  columns?: ColumnLayout;
1213
1254
  };
1255
+ /**
1256
+ * One separator rule of a flowed note area: the top-left corner of a
1257
+ * `NOTE_SEPARATOR_RULE_THICKNESS`-high rule and its width, in page pixels.
1258
+ */
1259
+ type NoteSeparatorRule = {
1260
+ x: number;
1261
+ y: number;
1262
+ width: number;
1263
+ };
1214
1264
  /**
1215
1265
  * Column layout configuration.
1216
1266
  */
@@ -1341,6 +1391,32 @@ type LayoutOptions = {
1341
1391
  footnoteHeightById?: Map<number, number>;
1342
1392
  /** Header/footer references for each document section, by section index. */
1343
1393
  sectionHeaderFooterRefs?: PageHeaderFooterRefs[];
1394
+ /** Note areas (endnotes) whose blocks flow with the body blocks. */
1395
+ noteAreas?: NoteAreaLayout;
1396
+ };
1397
+ /** Which separator story a flowed note-area block renders. */
1398
+ type NoteSeparatorKind = "separator" | "continuationSeparator";
1399
+ /**
1400
+ * Note areas laid out in the body flow (ECMA-376 §17.11): endnotes collected
1401
+ * at the end of the document or of a section. Their blocks sit in the body's
1402
+ * block list; this names the ones the paginator treats specially.
1403
+ */
1404
+ type NoteAreaLayout = {
1405
+ /**
1406
+ * Separator-story paragraphs that carry a `w:separator` mark, keyed by block
1407
+ * id. A rule is drawn across the first line of each of their fragments.
1408
+ */
1409
+ separatorBlockIds: ReadonlyMap<string, NoteSeparatorKind>;
1410
+ /**
1411
+ * Note content blocks. A page opened while one of them is laid out
1412
+ * continues the area, so it starts with the continuation separator.
1413
+ */
1414
+ contentBlockIds: ReadonlySet<string>;
1415
+ /** The `w:continuationSeparator` story's first paragraph, already measured. */
1416
+ continuationSeparator?: {
1417
+ block: ParagraphBlock;
1418
+ measure: ParagraphMeasure;
1419
+ };
1344
1420
  };
1345
1421
  /**
1346
1422
  * Result of hit-testing a click position.
@@ -1383,6 +1459,10 @@ declare const FOOTNOTE_SEPARATOR_HEIGHT = 12;
1383
1459
  * present in the source DOCX.
1384
1460
  */
1385
1461
  declare const FOOTNOTE_ENTRY_MARGIN_BOTTOM = 0;
1462
+ /** Thickness of a note separator rule, in the footnote band and in flowed endnotes. */
1463
+ declare const NOTE_SEPARATOR_RULE_THICKNESS = 0.5;
1464
+ /** Width of a `w:separator` rule as a fraction of its column. */
1465
+ declare const NOTE_SEPARATOR_WIDTH_FRACTION = 0.33;
1386
1466
  /**
1387
1467
  * Line height used when a footnote entry has no measured line height yet.
1388
1468
  * Conservative fallback so a missing measure does not collapse the entry.
@@ -1489,5 +1569,11 @@ declare function tableColumnsArePinned(table: TableBlock): boolean;
1489
1569
  declare function resolveTableWidthPx(width: number | undefined, widthType: TableWidthType | undefined, containerWidth: number): number | undefined;
1490
1570
  /** Return the leading visual offset for a row with omitted grid columns. */
1491
1571
  declare const getTableRowLeadingWidth: (row: TableRow, columnWidths: readonly number[]) => number;
1572
+ /**
1573
+ * A copy of a block with every ProseMirror anchor removed. A note story's
1574
+ * blocks carry positions in the note's own document; painted beside the body
1575
+ * they must not resolve a click, a selection or a caret into the body.
1576
+ */
1577
+ declare function stripFlowBlockPmAnchors(block: FlowBlock): FlowBlock;
1492
1578
  //#endregion
1493
- export { BlockId, BorderStyle, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, Layout, LayoutOptions, LineBreakRun, ListMarkerFormatting, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, RenderedPageBreakRun, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, SectionPageNumbering, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isListNumPr, isTextWrappingFloatingImageRun, resolveTableCellPadding, resolveTableWidthPx, tableColumnsArePinned, types_d_exports };
1579
+ export { BlockId, BorderStyle, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, Layout, LayoutOptions, LineBreakRun, ListMarkerFormatting, MathRun, Measure, MeasuredLine, NOTE_SEPARATOR_RULE_THICKNESS, NOTE_SEPARATOR_WIDTH_FRACTION, NoteAreaLayout, NoteSeparatorKind, NoteSeparatorRule, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, RenderedPageBreakRun, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, SectionPageNumbering, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isListNumPr, isTextWrappingFloatingImageRun, resolveTableCellPadding, resolveTableWidthPx, stripFlowBlockPmAnchors, tableColumnsArePinned, types_d_exports };
@@ -7,6 +7,8 @@ var types_exports = /* @__PURE__ */ __exportAll({
7
7
  FOOTNOTE_ENTRY_MARGIN_BOTTOM: () => 0,
8
8
  FOOTNOTE_FALLBACK_LINE_HEIGHT: () => 13,
9
9
  FOOTNOTE_SEPARATOR_HEIGHT: () => 12,
10
+ NOTE_SEPARATOR_RULE_THICKNESS: () => NOTE_SEPARATOR_RULE_THICKNESS,
11
+ NOTE_SEPARATOR_WIDTH_FRACTION: () => NOTE_SEPARATOR_WIDTH_FRACTION,
10
12
  floatingTextBoxReservesBand: () => floatingTextBoxReservesBand,
11
13
  floatingTextBoxWrapsText: () => floatingTextBoxWrapsText,
12
14
  getTableRowLeadingWidth: () => getTableRowLeadingWidth,
@@ -16,6 +18,7 @@ var types_exports = /* @__PURE__ */ __exportAll({
16
18
  isTextWrappingFloatingImageRun: () => isTextWrappingFloatingImageRun,
17
19
  resolveTableCellPadding: () => resolveTableCellPadding,
18
20
  resolveTableWidthPx: () => resolveTableWidthPx,
21
+ stripFlowBlockPmAnchors: () => stripFlowBlockPmAnchors,
19
22
  tableColumnsArePinned: () => tableColumnsArePinned
20
23
  });
21
24
  /**
@@ -69,6 +72,10 @@ const FOOTNOTE_SEPARATOR_HEIGHT = 12;
69
72
  * present in the source DOCX.
70
73
  */
71
74
  const FOOTNOTE_ENTRY_MARGIN_BOTTOM = 0;
75
+ /** Thickness of a note separator rule, in the footnote band and in flowed endnotes. */
76
+ const NOTE_SEPARATOR_RULE_THICKNESS = .5;
77
+ /** Width of a `w:separator` rule as a fraction of its column. */
78
+ const NOTE_SEPARATOR_WIDTH_FRACTION = .33;
72
79
  /**
73
80
  * Line height used when a footnote entry has no measured line height yet.
74
81
  * Conservative fallback so a missing measure does not collapse the entry.
@@ -189,5 +196,93 @@ const getTableRowLeadingWidth = (row, columnWidths) => {
189
196
  if (tableRowOwnsNestedGrid(row)) return 0;
190
197
  return columnWidths.slice(0, row.gridBefore ?? 0).reduce((sum, columnWidth) => sum + columnWidth, 0);
191
198
  };
199
+ /**
200
+ * A copy of a block with every ProseMirror anchor removed. A note story's
201
+ * blocks carry positions in the note's own document; painted beside the body
202
+ * they must not resolve a click, a selection or a caret into the body.
203
+ */
204
+ function stripFlowBlockPmAnchors(block) {
205
+ switch (block.kind) {
206
+ case "paragraph": return stripParagraphPmAnchors(block);
207
+ case "table": return stripTablePmAnchors(block);
208
+ case "image": {
209
+ const { pmStart: _pmStart, pmEnd: _pmEnd, ...image } = block;
210
+ return image;
211
+ }
212
+ case "textBox": {
213
+ const { pmStart: _pmStart, pmEnd: _pmEnd, ...textBox } = block;
214
+ return {
215
+ ...textBox,
216
+ content: textBox.content.map((contentBlock) => contentBlock.kind === "table" ? stripTablePmAnchors(contentBlock) : stripParagraphPmAnchors(contentBlock))
217
+ };
218
+ }
219
+ case "pageBreak":
220
+ case "columnBreak": {
221
+ const { pmStart: _pmStart, pmEnd: _pmEnd, ...breakBlock } = block;
222
+ return breakBlock;
223
+ }
224
+ case "sectionBreak": return block;
225
+ default: return block;
226
+ }
227
+ }
228
+ function stripTablePmAnchors(block) {
229
+ const { pmStart: _pmStart, pmEnd: _pmEnd, ...table } = block;
230
+ return {
231
+ ...table,
232
+ rows: table.rows.map(stripTableRowPmAnchors)
233
+ };
234
+ }
235
+ function stripTableRowPmAnchors(row) {
236
+ return {
237
+ ...row,
238
+ cells: row.cells.map(stripTableCellPmAnchors)
239
+ };
240
+ }
241
+ function stripTableCellPmAnchors(cell) {
242
+ return {
243
+ ...cell,
244
+ blocks: cell.blocks.map(stripFlowBlockPmAnchors)
245
+ };
246
+ }
247
+ function stripParagraphPmAnchors(block) {
248
+ const { pmStart: _pmStart, pmEnd: _pmEnd, ...paragraph } = block;
249
+ return {
250
+ ...paragraph,
251
+ runs: paragraph.runs.map(stripRunPmAnchors)
252
+ };
253
+ }
254
+ function stripRunPmAnchors(run) {
255
+ switch (run.kind) {
256
+ case "text": {
257
+ const { pmStart: _pmStart, pmEnd: _pmEnd, ...textRun } = run;
258
+ return textRun;
259
+ }
260
+ case "tab": {
261
+ const { pmStart: _pmStart, pmEnd: _pmEnd, ...tabRun } = run;
262
+ return tabRun;
263
+ }
264
+ case "image": {
265
+ const { pmStart: _pmStart, pmEnd: _pmEnd, ...imageRun } = run;
266
+ return imageRun;
267
+ }
268
+ case "lineBreak": {
269
+ const { pmStart: _pmStart, pmEnd: _pmEnd, ...lineBreakRun } = run;
270
+ return lineBreakRun;
271
+ }
272
+ case "field": {
273
+ const { pmStart: _pmStart, pmEnd: _pmEnd, ...fieldRun } = run;
274
+ return fieldRun;
275
+ }
276
+ case "math": {
277
+ const { pmStart: _pmStart, pmEnd: _pmEnd, ...mathRun } = run;
278
+ return mathRun;
279
+ }
280
+ case "renderedPageBreak": {
281
+ const { pmStart: _pmStart, pmEnd: _pmEnd, ...breakRun } = run;
282
+ return breakRun;
283
+ }
284
+ default: return run;
285
+ }
286
+ }
192
287
  //#endregion
193
- export { DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isListNumPr, isTextWrappingFloatingImageRun, resolveTableCellPadding, resolveTableWidthPx, tableColumnsArePinned, types_exports };
288
+ export { DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, NOTE_SEPARATOR_RULE_THICKNESS, NOTE_SEPARATOR_WIDTH_FRACTION, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isListNumPr, isTextWrappingFloatingImageRun, resolveTableCellPadding, resolveTableWidthPx, stripFlowBlockPmAnchors, tableColumnsArePinned, types_exports };
@@ -1,4 +1,5 @@
1
1
  import { FlowBlock, Layout, Measure } from "../layout-engine/types.js";
2
+ import { NoteStoryKey } from "../types/editor-story.js";
2
3
  import { RenderContext } from "./renderUtils.js";
3
4
  import { BlockFor, FeatureDispatchInput, FeatureFallback, FeatureModule, FeatureRenderInput, FragmentFor, MeasureFor } from "./registry/types.js";
4
5
  import { FeatureRegistry, createFeatureRegistry } from "./registry/registry.js";
@@ -17,6 +18,8 @@ type BlockLookupEntry = {
17
18
  block: FlowBlock;
18
19
  measure: Measure;
19
20
  version?: string;
21
+ /** The note story a block flowed with the body belongs to (endnote content). */
22
+ noteStory?: NoteStoryKey;
20
23
  };
21
24
  /**
22
25
  * Block lookup map type