@stll/folio-core 0.6.1 → 0.8.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 (107) hide show
  1. package/dist/ai-edits/blockRange.d.ts +13 -2
  2. package/dist/ai-edits/blockRange.js +23 -2
  3. package/dist/ai-edits/index.d.ts +4 -2
  4. package/dist/ai-edits/index.js +3 -1
  5. package/dist/ai-edits/scoped-reading.d.ts +9 -0
  6. package/dist/ai-edits/scoped-reading.js +60 -0
  7. package/dist/ai-edits/snapshot.js +13 -4
  8. package/dist/ai-edits/types.d.ts +44 -2
  9. package/dist/compat/eigenpal.d.ts +5 -2
  10. package/dist/compat/eigenpal.js +4 -1
  11. package/dist/controller/fontReadiness.d.ts +29 -0
  12. package/dist/controller/fontReadiness.js +139 -0
  13. package/dist/controller/layoutPipeline.js +86 -11
  14. package/dist/docx/blockContentParser.js +51 -8
  15. package/dist/docx/capabilities.d.ts +41 -0
  16. package/dist/docx/capabilities.js +322 -0
  17. package/dist/docx/compatibility.d.ts +34 -2
  18. package/dist/docx/compatibility.js +128 -38
  19. package/dist/docx/conformance.d.ts +6 -0
  20. package/dist/docx/conformance.js +18 -0
  21. package/dist/docx/ensureParaIds.d.ts +29 -0
  22. package/dist/docx/ensureParaIds.js +423 -0
  23. package/dist/docx/groupDrawingParser.d.ts +1 -1
  24. package/dist/docx/groupDrawingParser.js +49 -8
  25. package/dist/docx/numberingParser.js +1 -0
  26. package/dist/docx/paragraphParser.js +9 -0
  27. package/dist/docx/paragraphTextBoxEnrichment.js +141 -2
  28. package/dist/docx/parser.js +2 -0
  29. package/dist/docx/runParser.js +11 -2
  30. package/dist/docx/selectiveXmlPatch.d.ts +10 -1
  31. package/dist/docx/selectiveXmlPatch.js +1 -1
  32. package/dist/docx/serializer/paragraphSerializer.js +4 -0
  33. package/dist/docx/serializer/runSerializer.js +7 -2
  34. package/dist/docx/serializer/tableSerializer.js +4 -0
  35. package/dist/docx/server/boundedArchive.d.ts +24 -0
  36. package/dist/docx/server/boundedArchive.js +106 -0
  37. package/dist/docx/server/extractDocxText.d.ts +23 -0
  38. package/dist/docx/server/extractDocxText.js +154 -0
  39. package/dist/docx/tableParser.js +8 -0
  40. package/dist/docx/textBoxParser.js +6 -1
  41. package/dist/docx/vmlImageParser.js +145 -1
  42. package/dist/index.d.ts +5 -2
  43. package/dist/index.js +4 -1
  44. package/dist/layout-bridge/convert/headerFooterLayout.js +16 -2
  45. package/dist/layout-bridge/convert/paragraphFrames.d.ts +7 -0
  46. package/dist/layout-bridge/convert/paragraphFrames.js +136 -0
  47. package/dist/layout-bridge/convert/toFlowBlocks.js +106 -13
  48. package/dist/layout-bridge/engine/hitTest.js +2 -1
  49. package/dist/layout-bridge/engine/selectionRects.js +2 -1
  50. package/dist/layout-engine/headerFooterRefs.d.ts +7 -0
  51. package/dist/layout-engine/headerFooterRefs.js +40 -0
  52. package/dist/layout-engine/index.d.ts +3 -2
  53. package/dist/layout-engine/index.js +125 -72
  54. package/dist/layout-engine/keep-together.d.ts +7 -5
  55. package/dist/layout-engine/keep-together.js +20 -4
  56. package/dist/layout-engine/measure/cache.js +2 -0
  57. package/dist/layout-engine/measure/listMarkerWidth.d.ts +3 -1
  58. package/dist/layout-engine/measure/listMarkerWidth.js +23 -4
  59. package/dist/layout-engine/measure/measureBlocks.d.ts +3 -0
  60. package/dist/layout-engine/measure/measureBlocks.js +133 -51
  61. package/dist/layout-engine/measure/measureParagraph.js +42 -15
  62. package/dist/layout-engine/measure/tableCellGrid.d.ts +15 -0
  63. package/dist/layout-engine/measure/tableCellGrid.js +62 -0
  64. package/dist/layout-engine/measure/textBoxParagraphLayout.d.ts +18 -0
  65. package/dist/layout-engine/measure/textBoxParagraphLayout.js +32 -0
  66. package/dist/layout-engine/paginator.d.ts +2 -1
  67. package/dist/layout-engine/paginator.js +17 -8
  68. package/dist/layout-engine/paragraphFrame.d.ts +22 -0
  69. package/dist/layout-engine/paragraphFrame.js +17 -0
  70. package/dist/layout-engine/paragraphSequence.d.ts +7 -0
  71. package/dist/layout-engine/paragraphSequence.js +25 -0
  72. package/dist/layout-engine/paragraphSpacing.d.ts +17 -0
  73. package/dist/layout-engine/paragraphSpacing.js +30 -0
  74. package/dist/layout-engine/renderedBreakReconciliation.d.ts +58 -0
  75. package/dist/layout-engine/renderedBreakReconciliation.js +63 -0
  76. package/dist/layout-engine/types.d.ts +31 -10
  77. package/dist/layout-engine/types.js +15 -2
  78. package/dist/layout-painter/renderPage.js +2 -2
  79. package/dist/layout-painter/renderParagraph.js +94 -10
  80. package/dist/layout-painter/renderTable.js +42 -12
  81. package/dist/layout-painter/renderTextBox.js +17 -7
  82. package/dist/managers/DocumentLoaderManager.js +1 -1
  83. package/dist/paged-layout/sectionBlockWidths.d.ts +3 -0
  84. package/dist/paged-layout/sectionBlockWidths.js +9 -0
  85. package/dist/paged-layout/sectionGeometry.js +1 -1
  86. package/dist/prosemirror/attrs/index.js +11 -0
  87. package/dist/prosemirror/conversion/fromProseDoc.js +2 -0
  88. package/dist/prosemirror/conversion/toProseDoc.js +29 -23
  89. package/dist/prosemirror/extensions/core/ParagraphExtension.js +1 -0
  90. package/dist/prosemirror/extensions/features/ListExtension.js +1 -0
  91. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +68 -16
  92. package/dist/prosemirror/extensions/nodes/TableExtension.js +1 -0
  93. package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +2 -1
  94. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +7 -0
  95. package/dist/prosemirror/schema/nodes.d.ts +6 -3
  96. package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
  97. package/dist/prosemirror/utils/tabCalculator.js +1 -1
  98. package/dist/server.d.ts +6 -2
  99. package/dist/server.js +5 -1
  100. package/dist/types/index.d.ts +2 -1
  101. package/dist/utils/createDocument.js +26 -18
  102. package/dist/utils/formatToStyle.js +3 -3
  103. package/dist/utils/hexId.d.ts +8 -1
  104. package/dist/utils/hexId.js +11 -3
  105. package/dist/utils/units.d.ts +6 -6
  106. package/dist/utils/units.js +8 -8
  107. package/package.json +1 -1
@@ -1,17 +1,19 @@
1
1
  import { NUMBER_FORMAT_VALUES } from "../../types/documentEnumValues.js";
2
- import { halfPointsToPixels, halfPointsToPoints, pointsToPixels } from "../../utils/units.js";
2
+ import { AUTO_PARAGRAPH_SPACING_PX, halfPointsToPixels, halfPointsToPoints, pointsToPixels } from "../../utils/units.js";
3
3
  import { padDecimal } from "../../docx/numberingParser.js";
4
4
  import { DEFAULT_TEXTBOX_MARGINS } from "../../layout-engine/types.js";
5
5
  import { resolveColor, resolveHighlightToCss } from "../../utils/colorResolver.js";
6
6
  import { resolveShadingFill } from "../../utils/formatToStyle.js";
7
7
  import { convertBulletToUnicode } from "../../docx/bulletMarkers.js";
8
8
  import { setTextBoxGroupId } from "../../layout-engine/textBoxGroup.js";
9
+ import { setParagraphFrame } from "../../layout-engine/paragraphFrame.js";
9
10
  import { getColumns } from "../sectionColumns.js";
10
11
  import { directionIsRtl } from "../../prosemirror/paragraphDirection.js";
11
12
  import { expectBlockSdtAttrs, expectCharacterSpacingMarkAttrs, expectCommentMarkAttrs, expectEmphasisMarkAttrs, expectFieldAttrs, expectFontFamilyMarkAttrs, expectFontSizeMarkAttrs, expectFootnoteRefMarkAttrs, expectHardBreakAttrs, expectHighlightMarkAttrs, expectHyperlinkMarkAttrs, expectImageAttrs, expectMathAttrs, expectParagraphAttrs, expectRunFormattingOverrideMarkAttrs, expectRunShadingMarkAttrs, expectTableAttrs, expectTableCellAttrs, expectTableRowAttrs, expectTextBoxAttrs, expectTextColorMarkAttrs, expectTextEffectMarkAttrs, expectTrackedChangeMarkAttrs, expectUnderlineMarkAttrs } from "../../prosemirror/attrs/index.js";
12
13
  import { autospacingMatchesBase } from "../../prosemirror/autospacingBase.js";
13
14
  import { runShadingAttrsToShading } from "../../prosemirror/conversion/runShadingMark.js";
14
15
  import { assertValidProseMirrorDocument } from "../../prosemirror/validation.js";
16
+ import { groupParagraphFrames } from "./paragraphFrames.js";
15
17
  //#region src/layout-bridge/convert/toFlowBlocks.ts
16
18
  const DEFAULT_FONT = "Calibri";
17
19
  const DEFAULT_TABLE_CELL_MARGIN_TWIPS = {
@@ -613,6 +615,9 @@ function readNumberFormats(value) {
613
615
  function readListMarkerSuffix(value) {
614
616
  if (value === "tab" || value === "space" || value === "nothing") return value;
615
617
  }
618
+ function readListMarkerAlignment(value) {
619
+ if (value === "left" || value === "center" || value === "right") return value;
620
+ }
616
621
  function toPreviousListAttrs(previousFormatting) {
617
622
  const attrs = {};
618
623
  const numPr = previousFormatting["numPr"];
@@ -639,6 +644,8 @@ function toPreviousListAttrs(previousFormatting) {
639
644
  if (typeof listMarkerFontFamily === "string") attrs.listMarkerFontFamily = listMarkerFontFamily;
640
645
  const listMarkerFontSize = previousFormatting["listMarkerFontSize"];
641
646
  if (typeof listMarkerFontSize === "number") attrs.listMarkerFontSize = listMarkerFontSize;
647
+ const listMarkerAlignment = readListMarkerAlignment(previousFormatting["listMarkerAlignment"]);
648
+ if (listMarkerAlignment) attrs.listMarkerAlignment = listMarkerAlignment;
642
649
  const listMarkerSuffix = readListMarkerSuffix(previousFormatting["listMarkerSuffix"]);
643
650
  if (listMarkerSuffix) attrs.listMarkerSuffix = listMarkerSuffix;
644
651
  return attrs;
@@ -662,6 +669,7 @@ function applyDeletedListMarkerAttrs(attrs, change, listCounters, listAbstractCo
662
669
  if (previousListAttrs.listMarkerHidden !== void 0) attrs.listMarkerHidden = previousListAttrs.listMarkerHidden;
663
670
  if (previousListAttrs.listMarkerFontFamily) attrs.listMarkerFontFamily = previousListAttrs.listMarkerFontFamily;
664
671
  if (previousListAttrs.listMarkerFontSize) attrs.listMarkerFontSize = previousListAttrs.listMarkerFontSize;
672
+ if (previousListAttrs.listMarkerAlignment) attrs.listMarkerAlignment = previousListAttrs.listMarkerAlignment;
665
673
  if (previousListAttrs.listMarkerSuffix) attrs.listMarkerSuffix = previousListAttrs.listMarkerSuffix;
666
674
  }
667
675
  function convertParagraphAttrs(pmAttrs, theme, listCounters, listAbstractCounters, listSeenNumIds, defaultTabStopTwips, originalListCounters, originalListAbstractCounters, originalListSeenNumIds) {
@@ -673,6 +681,7 @@ function convertParagraphAttrs(pmAttrs, theme, listCounters, listAbstractCounter
673
681
  else if (align === "center") attrs.alignment = "center";
674
682
  else if (align === "right") attrs.alignment = "right";
675
683
  }
684
+ if (typeof pmAttrs.outlineLevel === "number") attrs.outlineLevel = pmAttrs.outlineLevel;
676
685
  const spaceBefore = pmAttrs.spaceBefore;
677
686
  const spaceAfter = pmAttrs.spaceAfter;
678
687
  const lineSpacing = pmAttrs.lineSpacing;
@@ -680,10 +689,14 @@ function convertParagraphAttrs(pmAttrs, theme, listCounters, listAbstractCounter
680
689
  const autoAfter = autospacingMatchesBase(pmAttrs._autospacingBase, "after", spaceAfter);
681
690
  if (autoBefore || autoAfter || typeof spaceBefore === "number" || typeof spaceAfter === "number" || typeof lineSpacing === "number") {
682
691
  attrs.spacing = {};
683
- if (autoBefore) attrs.spacing.before = 14;
692
+ if (autoBefore) attrs.spacing.before = AUTO_PARAGRAPH_SPACING_PX;
684
693
  else if (typeof spaceBefore === "number") attrs.spacing.before = twipsToPixels(spaceBefore);
685
- if (autoAfter) attrs.spacing.after = 14;
694
+ if (autoAfter) attrs.spacing.after = AUTO_PARAGRAPH_SPACING_PX;
686
695
  else if (typeof spaceAfter === "number") attrs.spacing.after = twipsToPixels(spaceAfter);
696
+ if (autoBefore || autoAfter) attrs.automaticSpacing = {
697
+ ...autoBefore ? { before: true } : {},
698
+ ...autoAfter ? { after: true } : {}
699
+ };
687
700
  const pmSpacingExplicit = pmAttrs.spacingExplicit;
688
701
  const spacingFromDocDefaults = pmAttrs.spacingFromDocDefaults;
689
702
  const explicit = {};
@@ -703,7 +716,7 @@ function convertParagraphAttrs(pmAttrs, theme, listCounters, listAbstractCounter
703
716
  let indentLeft = typeof pmAttrs.indentLeft === "number" ? pmAttrs.indentLeft : void 0;
704
717
  let indentFirstLine = typeof pmAttrs.indentFirstLine === "number" ? pmAttrs.indentFirstLine : void 0;
705
718
  let hangingIndent = pmAttrs.hangingIndent;
706
- if (pmAttrs.numPr?.numId && indentLeft === void 0) {
719
+ if (pmAttrs.numPr?.numId && indentLeft === void 0 && indentFirstLine === void 0) {
707
720
  indentLeft = ((pmAttrs.numPr.ilvl ?? 0) + 1) * 720;
708
721
  if (indentFirstLine === void 0) {
709
722
  indentFirstLine = -360;
@@ -788,6 +801,7 @@ function convertParagraphAttrs(pmAttrs, theme, listCounters, listAbstractCounter
788
801
  if (pmAttrs.listMarkerHidden) attrs.listMarkerHidden = true;
789
802
  if (pmAttrs.listMarkerFontFamily) attrs.listMarkerFontFamily = pmAttrs.listMarkerFontFamily;
790
803
  if (pmAttrs.listMarkerFontSize) attrs.listMarkerFontSize = pmAttrs.listMarkerFontSize;
804
+ if (pmAttrs.listMarkerAlignment) attrs.listMarkerAlignment = pmAttrs.listMarkerAlignment;
791
805
  if (pmAttrs.listMarkerSuffix) attrs.listMarkerSuffix = pmAttrs.listMarkerSuffix;
792
806
  if (pmAttrs.listMarkerSecondSlotOffsetTwips !== void 0) attrs.listMarkerSecondSlotOffsetTwips = pmAttrs.listMarkerSecondSlotOffsetTwips;
793
807
  if (!pmAttrs.numPr) {
@@ -829,7 +843,9 @@ function convertParagraph(node, startPos, options) {
829
843
  const attrs = convertParagraphAttrs(pmAttrs, options.theme, options.listCounters, options.listAbstractCounters, options.listSeenNumIds, options.defaultTabStopTwips, options.originalListCounters, options.originalListAbstractCounters, options.originalListSeenNumIds);
830
844
  const defaultTextFormatting = pmAttrs.defaultTextFormatting;
831
845
  if (runs.length === 0) {
846
+ if (pmAttrs._originalFormatting && Object.entries(pmAttrs._originalFormatting).some(([key, value]) => key !== "runProperties" && value !== void 0 && value !== null)) attrs.hasDirectParagraphFormatting = true;
832
847
  const paragraphMarkFormatting = pmAttrs._originalFormatting?.runProperties;
848
+ if (paragraphMarkFormatting && Object.values(paragraphMarkFormatting).some((value) => value !== void 0 && value !== null)) attrs.hasDirectParagraphMarkFormatting = true;
833
849
  if (paragraphMarkFormatting?.fontSize !== void 0) attrs.defaultFontSize = paragraphMarkFormatting.fontSize / 2;
834
850
  const paragraphMarkFontFamily = paragraphMarkFormatting?.fontFamily?.ascii ?? paragraphMarkFormatting?.fontFamily?.hAnsi;
835
851
  if (paragraphMarkFontFamily) attrs.defaultFontFamily = paragraphMarkFontFamily;
@@ -839,7 +855,7 @@ function convertParagraph(node, startPos, options) {
839
855
  if (attrs.listMarker !== void 0) attrs.listMarkerHidden = true;
840
856
  }
841
857
  const bookmarkNames = pmAttrs.bookmarks?.map((b) => b.name);
842
- return {
858
+ const block = {
843
859
  kind: "paragraph",
844
860
  id: nextBlockId(),
845
861
  runs,
@@ -849,6 +865,62 @@ function convertParagraph(node, startPos, options) {
849
865
  pmStart: startPos,
850
866
  pmEnd: startPos + node.nodeSize
851
867
  };
868
+ const frame = pmAttrs._originalFormatting?.frame;
869
+ if (frame !== void 0 && frame.dropCap !== "drop" && frame.dropCap !== "margin") setParagraphFrame(block, {
870
+ ...frame.width !== void 0 ? { width: twipsToPixels(frame.width) } : {},
871
+ ...frame.height !== void 0 ? { height: twipsToPixels(frame.height) } : {},
872
+ ...frame.hSpace !== void 0 ? { hSpace: twipsToPixels(frame.hSpace) } : {},
873
+ ...frame.vSpace !== void 0 ? { vSpace: twipsToPixels(frame.vSpace) } : {},
874
+ ...frame.hAnchor !== void 0 ? { hAnchor: frame.hAnchor } : {},
875
+ ...frame.vAnchor !== void 0 ? { vAnchor: frame.vAnchor } : {},
876
+ ...frame.x !== void 0 ? { x: twipsToPixels(frame.x) } : {},
877
+ ...frame.y !== void 0 ? { y: twipsToPixels(frame.y) } : {},
878
+ ...frame.xAlign !== void 0 ? { xAlign: frame.xAlign } : {},
879
+ ...frame.yAlign !== void 0 ? { yAlign: frame.yAlign } : {},
880
+ ...frame.wrap !== void 0 ? { wrap: frame.wrap } : {}
881
+ });
882
+ return block;
883
+ }
884
+ /**
885
+ * Word keeps terminal empty body paragraphs after a final table as editable
886
+ * anchors, but they do not create a page of their own. Preserve every block
887
+ * and PM range while collapsing only the contiguous, run-free suffix; empty
888
+ * paragraphs elsewhere still retain their normal line height.
889
+ */
890
+ function isPaintlessTerminalParagraph(block) {
891
+ if (block?.kind !== "paragraph" || block.runs.length !== 0) return false;
892
+ const attrs = block.attrs;
893
+ return !(attrs?.listMarker !== void 0 && !attrs.listMarkerHidden || attrs?.borders?.top || attrs?.borders?.bottom || attrs?.borders?.left || attrs?.borders?.right || attrs?.borders?.between || attrs?.borders?.bar || attrs?.shading || attrs?.spacingExplicit?.before || attrs?.spacingExplicit?.after || attrs?.pageBreakBefore || attrs?.renderedPageBreakBefore);
894
+ }
895
+ function suppressTerminalEmptyParagraphsAfterTable(blocks) {
896
+ let suffixStart = blocks.length;
897
+ while (suffixStart > 0 && isPaintlessTerminalParagraph(blocks[suffixStart - 1])) suffixStart -= 1;
898
+ if (suffixStart === blocks.length || suffixStart === 0 || blocks[suffixStart - 1]?.kind !== "table") return;
899
+ for (let index = suffixStart; index < blocks.length; index += 1) {
900
+ const block = blocks[index];
901
+ if (isPaintlessTerminalParagraph(block)) block.attrs = {
902
+ ...block.attrs,
903
+ suppressEmptyParagraphHeight: true
904
+ };
905
+ }
906
+ }
907
+ function suppressFinalParagraphInRepeatedEmptySuffix(blocks) {
908
+ let suffixStart = blocks.length;
909
+ while (suffixStart > 0 && isPaintlessTerminalParagraph(blocks[suffixStart - 1])) suffixStart -= 1;
910
+ if (suffixStart === 0 || blocks.length - suffixStart < 2 || blocks[suffixStart - 1]?.kind === "table") return;
911
+ const finalBlock = blocks.at(-1);
912
+ if (isPaintlessTerminalParagraph(finalBlock)) finalBlock.attrs = {
913
+ ...finalBlock.attrs,
914
+ suppressEmptyParagraphHeight: true
915
+ };
916
+ }
917
+ function reserveLeadingEmptyOutlineHeight(blocks) {
918
+ const firstBlock = blocks.at(0);
919
+ if (firstBlock?.kind !== "paragraph" || firstBlock.runs.length !== 0 || firstBlock.attrs?.outlineLevel !== 0) return;
920
+ firstBlock.attrs = {
921
+ ...firstBlock.attrs,
922
+ reserveEmptyOutlineHeight: true
923
+ };
852
924
  }
853
925
  /**
854
926
  * Convert border width from eighths of a point to pixels.
@@ -946,7 +1018,7 @@ function convertTableCell(node, startPos, options, tableCellMargins) {
946
1018
  };
947
1019
  const cell = {
948
1020
  id: nextBlockId(),
949
- blocks,
1021
+ blocks: groupParagraphFrames(blocks, nextBlockId),
950
1022
  colSpan: attrs.colspan,
951
1023
  rowSpan: attrs.rowspan,
952
1024
  padding
@@ -974,6 +1046,8 @@ function convertTableRow(node, startPos, options, tableCellMargins) {
974
1046
  id: nextBlockId(),
975
1047
  cells
976
1048
  };
1049
+ if (attrs._originalFormatting?.gridBefore) row.gridBefore = attrs._originalFormatting.gridBefore;
1050
+ if (attrs._originalFormatting?.gridAfter) row.gridAfter = attrs._originalFormatting.gridAfter;
977
1051
  if (attrs.height) row.height = twipsToPixels(attrs.height);
978
1052
  if (attrs.heightRule) row.heightRule = attrs.heightRule;
979
1053
  if (attrs.isHeader) row.isHeader = attrs.isHeader;
@@ -1001,7 +1075,8 @@ function convertTable(node, startPos, options) {
1001
1075
  }
1002
1076
  const justification = attrs.justification;
1003
1077
  const originalFormatting = attrs._originalFormatting;
1004
- const indentPx = originalFormatting?.indent?.value && originalFormatting.indent.type === "dxa" ? twipsToPixels(originalFormatting.indent.value) : void 0;
1078
+ const effectiveIndent = attrs._resolvedIndent ?? originalFormatting?.indent;
1079
+ const indentPx = effectiveIndent?.value !== void 0 && effectiveIndent?.type === "dxa" ? twipsToPixels(effectiveIndent.value) : void 0;
1005
1080
  const floating = attrs.floating;
1006
1081
  let floatingPx;
1007
1082
  if (floating) {
@@ -1098,6 +1173,7 @@ function convertTextBoxNode(node, startPos, opts) {
1098
1173
  pmEnd: startPos + node.nodeSize
1099
1174
  };
1100
1175
  if (attrs.height !== void 0) textBox.height = attrs.height;
1176
+ if (attrs.autoFit !== void 0) textBox.autoFit = attrs.autoFit;
1101
1177
  if (attrs.fillColor !== void 0) textBox.fillColor = attrs.fillColor;
1102
1178
  if (attrs.outlineWidth !== void 0) textBox.outlineWidth = attrs.outlineWidth;
1103
1179
  if (attrs.outlineColor !== void 0) textBox.outlineColor = attrs.outlineColor;
@@ -1216,8 +1292,12 @@ function toFlowBlocks(doc, options = {}) {
1216
1292
  switch (node.type.name) {
1217
1293
  case "paragraph": {
1218
1294
  const pmAttrs = expectParagraphAttrs(node);
1219
- const onlyChild = node.childCount === 1 ? node.firstChild : null;
1220
- if (onlyChild?.type.name === "hardBreak" && expectHardBreakAttrs(onlyChild).breakType === "column") {
1295
+ const secProps = pmAttrs._sectionProperties;
1296
+ const hasSectionBreak = secProps !== void 0 || pmAttrs.sectionBreakType !== null && pmAttrs.sectionBreakType !== void 0;
1297
+ const hasListFormatting = pmAttrs.numPr !== null && pmAttrs.numPr !== void 0 || pmAttrs.listMarker !== null && pmAttrs.listMarker !== void 0;
1298
+ const firstChild = node.firstChild;
1299
+ const startsWithColumnBreak = firstChild?.type.name === "hardBreak" && expectHardBreakAttrs(firstChild).breakType === "column";
1300
+ if (node.childCount === 1 && startsWithColumnBreak) {
1221
1301
  const columnBreak = {
1222
1302
  kind: "columnBreak",
1223
1303
  id: nextBlockId(),
@@ -1225,9 +1305,19 @@ function toFlowBlocks(doc, options = {}) {
1225
1305
  pmEnd: pos + node.nodeSize
1226
1306
  };
1227
1307
  trackedPush(columnBreak);
1228
- } else trackedPush(convertParagraph(node, pos, opts));
1229
- const secProps = pmAttrs._sectionProperties;
1230
- if (secProps || pmAttrs.sectionBreakType) {
1308
+ } else if (startsWithColumnBreak && firstChild) {
1309
+ const columnBreak = {
1310
+ kind: "columnBreak",
1311
+ id: nextBlockId(),
1312
+ pmStart: pos + 1,
1313
+ pmEnd: pos + 1 + firstChild.nodeSize
1314
+ };
1315
+ trackedPush(columnBreak);
1316
+ const paragraph = convertParagraph(node, pos, opts);
1317
+ if (paragraph.runs.at(0)?.kind === "lineBreak") paragraph.runs.shift();
1318
+ trackedPush(paragraph);
1319
+ } else if (node.content.size > 0 || hasListFormatting || !hasSectionBreak) trackedPush(convertParagraph(node, pos, opts));
1320
+ if (hasSectionBreak) {
1231
1321
  const sectionBreak = {
1232
1322
  kind: "sectionBreak",
1233
1323
  id: nextBlockId()
@@ -1288,7 +1378,10 @@ function toFlowBlocks(doc, options = {}) {
1288
1378
  doc.forEach((node, nodeOffset) => {
1289
1379
  visit(node, offset + nodeOffset);
1290
1380
  });
1291
- return mergeRunInParagraphs(blocks);
1381
+ reserveLeadingEmptyOutlineHeight(blocks);
1382
+ suppressTerminalEmptyParagraphsAfterTable(blocks);
1383
+ suppressFinalParagraphInRepeatedEmptySuffix(blocks);
1384
+ return groupParagraphFrames(mergeRunInParagraphs(blocks), nextBlockId);
1292
1385
  }
1293
1386
  /**
1294
1387
  * Merge consecutive paragraph blocks where the first carries
@@ -1,4 +1,5 @@
1
1
  import { measuredLineRangeHeight } from "../../layout-engine/lineFlow.js";
2
+ import { getTableRowLeadingWidth } from "../../layout-engine/types.js";
2
3
  import { getHeaderRowsHeight } from "../../layout-engine/index.js";
3
4
  //#region src/layout-bridge/engine/hitTest.ts
4
5
  /**
@@ -213,7 +214,7 @@ function hitTestTableCell(pageHit, blocks, measures, pagePoint) {
213
214
  const rowMeasure = tableMeasure.rows[rowIndex];
214
215
  const row = tableBlock.rows[rowIndex];
215
216
  if (!rowMeasure || !row) continue;
216
- let colX = 0;
217
+ let colX = getTableRowLeadingWidth(row, tableMeasure.columnWidths);
217
218
  let colIndex = -1;
218
219
  if (rowMeasure.cells.length === 0 || row.cells.length === 0) continue;
219
220
  for (let c = 0; c < rowMeasure.cells.length; c++) {
@@ -2,6 +2,7 @@ import { measureRun } from "../../layout-engine/measure/measureProvider.js";
2
2
  import { buildRunFontStyle } from "../../layout-engine/measure/measureHelpers.js";
3
3
  import { inlineImageBoundingBox } from "../../utils/rotationBoundingBox.js";
4
4
  import { measuredLineContentOffset } from "../../layout-engine/lineFlow.js";
5
+ import { getTableRowLeadingWidth } from "../../layout-engine/types.js";
5
6
  import { measureParagraph } from "../../layout-engine/measure/measureParagraph.js";
6
7
  import { buildTableCellFloatingZones, getTableCellContentWidth, getTableCellFloatingImages } from "../../layout-engine/measure/tableCellFloating.js";
7
8
  import { getHeaderRowsHeight } from "../../layout-engine/index.js";
@@ -314,7 +315,7 @@ function selectionToRects(layout, blocks, measures, from, to) {
314
315
  if (!row || !rowMeasure) continue;
315
316
  const clipTop = tableFragment.topClip ?? 0;
316
317
  const clipBottom = tableFragment.bottomClip ?? rowMeasure.height;
317
- let cellX = 0;
318
+ let cellX = getTableRowLeadingWidth(row, tableMeasure.columnWidths);
318
319
  for (let cellIndex = 0; cellIndex < row.cells.length; cellIndex++) {
319
320
  const cell = row.cells[cellIndex];
320
321
  const cellMeasure = rowMeasure.cells[cellIndex];
@@ -0,0 +1,7 @@
1
+ import { document_d_exports } from "../types/document.js";
2
+ import { PageHeaderFooterRefs } from "./types.js";
3
+
4
+ //#region src/layout-engine/headerFooterRefs.d.ts
5
+ declare const resolveSectionHeaderFooterRefs: (documentModel: document_d_exports.Document | null | undefined) => PageHeaderFooterRefs[] | undefined;
6
+ //#endregion
7
+ export { resolveSectionHeaderFooterRefs };
@@ -0,0 +1,40 @@
1
+ //#region src/layout-engine/headerFooterRefs.ts
2
+ const resolveSectionRefs = (props, inherited, documentEvenAndOddHeaders) => {
3
+ const refs = {
4
+ ...inherited,
5
+ evenAndOddHeaders: props.evenAndOddHeaders ?? documentEvenAndOddHeaders
6
+ };
7
+ if (props.titlePg !== void 0) refs.titlePg = props.titlePg;
8
+ for (const ref of props.headerReferences ?? []) if (ref.type === "default") refs.headerDefault = ref.rId;
9
+ else if (ref.type === "first") refs.headerFirst = ref.rId;
10
+ else refs.headerEven = ref.rId;
11
+ for (const ref of props.footerReferences ?? []) if (ref.type === "default") refs.footerDefault = ref.rId;
12
+ else if (ref.type === "first") refs.footerFirst = ref.rId;
13
+ else refs.footerEven = ref.rId;
14
+ return refs;
15
+ };
16
+ const inheritedRefsFrom = (refs) => ({
17
+ ...refs.headerDefault === void 0 ? {} : { headerDefault: refs.headerDefault },
18
+ ...refs.headerFirst === void 0 ? {} : { headerFirst: refs.headerFirst },
19
+ ...refs.headerEven === void 0 ? {} : { headerEven: refs.headerEven },
20
+ ...refs.footerDefault === void 0 ? {} : { footerDefault: refs.footerDefault },
21
+ ...refs.footerFirst === void 0 ? {} : { footerFirst: refs.footerFirst },
22
+ ...refs.footerEven === void 0 ? {} : { footerEven: refs.footerEven }
23
+ });
24
+ const resolveSectionHeaderFooterRefs = (documentModel) => {
25
+ const body = documentModel?.package.document;
26
+ if (!body) return;
27
+ const sections = [];
28
+ if (body.sections && body.sections.length > 0) sections.push(...body.sections.map(({ properties }) => properties));
29
+ else if (body.finalSectionProperties) sections.push(body.finalSectionProperties);
30
+ if (sections.length === 0) return;
31
+ const documentEvenAndOddHeaders = documentModel.package.settings?.evenAndOddHeaders === true;
32
+ let inherited = {};
33
+ return sections.map((props) => {
34
+ const refs = resolveSectionRefs(props, inherited, documentEvenAndOddHeaders);
35
+ inherited = inheritedRefsFrom(refs);
36
+ return refs;
37
+ });
38
+ };
39
+ //#endregion
40
+ export { resolveSectionHeaderFooterRefs };
@@ -1,6 +1,7 @@
1
- import { 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, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, floatingTextBoxReservesBand, floatingTextBoxWrapsText, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, tableColumnsArePinned } from "./types.js";
1
+ import { 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, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, tableColumnsArePinned } from "./types.js";
2
2
  import { PageState, Paginator, PaginatorOptions, createPaginator } from "./paginator.js";
3
3
  import { KeepNextChain, calculateChainHeight, computeKeepNextChains, getMidChainIndices, hasKeepLines, hasPageBreakBefore } from "./keep-together.js";
4
+ import { resolveSectionHeaderFooterRefs } from "./headerFooterRefs.js";
4
5
  import { BreakDecision, SectionState, applyPendingToActive, createInitialSectionState, getEffectiveColumns, getEffectiveMargins, getEffectivePageSize, scheduleSectionBreak } from "./section-breaks.js";
5
6
  import { assertExhaustiveFlowBlock, findPageIndexContainingPmPos } from "./pmPageIndex.js";
6
7
 
@@ -43,4 +44,4 @@ declare function layoutDocument(blocks: FlowBlock[], measures: Measure[], option
43
44
  */
44
45
  declare function getHeaderRowsHeight(measure: TableMeasure, headerRowCount: number): number;
45
46
  //#endregion
46
- export { BlockId, BorderStyle, type BreakDecision, 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, type KeepNextChain, Layout, LayoutOptions, LineBreakRun, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, type PageState, type Paginator, type PaginatorOptions, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, SectionLayoutConfig, type SectionState, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, applyContextualSpacing, applyPendingToActive, assertExhaustiveFlowBlock, calculateChainHeight, collectSectionConfigs, computeKeepNextChains, createInitialSectionState, createPaginator, findPageIndexContainingPmPos, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getEffectiveColumns, getEffectiveMargins, getEffectivePageSize, getHeaderRowsHeight, getMidChainIndices, hasKeepLines, hasPageBreakBefore, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, layoutDocument, scheduleSectionBreak, tableColumnsArePinned };
47
+ export { BlockId, BorderStyle, type BreakDecision, 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, type KeepNextChain, Layout, LayoutOptions, LineBreakRun, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, type PageState, type Paginator, type PaginatorOptions, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, SectionLayoutConfig, type SectionState, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, applyContextualSpacing, applyPendingToActive, assertExhaustiveFlowBlock, calculateChainHeight, collectSectionConfigs, computeKeepNextChains, createInitialSectionState, createPaginator, findPageIndexContainingPmPos, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getEffectiveColumns, getEffectiveMargins, getEffectivePageSize, getHeaderRowsHeight, getMidChainIndices, getTableRowLeadingWidth, hasKeepLines, hasPageBreakBefore, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, layoutDocument, resolveSectionHeaderFooterRefs, scheduleSectionBreak, tableColumnsArePinned };