@stll/folio-core 0.28.1 → 0.30.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 (125) hide show
  1. package/dist/controller/folioEditor.d.ts +28 -1
  2. package/dist/controller/folioEditor.js +37 -26
  3. package/dist/controller/fontReadiness.js +28 -24
  4. package/dist/controller/hiddenEditorManager.d.ts +2 -7
  5. package/dist/controller/layoutPipeline.js +33 -3
  6. package/dist/controller/noteEditorManager.d.ts +3 -6
  7. package/dist/docx/metafileSvg.d.ts +12 -0
  8. package/dist/docx/metafileSvg.js +462 -0
  9. package/dist/docx/paragraphTextBoxEnrichment.js +55 -4
  10. package/dist/docx/parser.d.ts +2 -2
  11. package/dist/docx/parser.js +26 -0
  12. package/dist/docx/runParser.js +2 -1
  13. package/dist/docx/serializer/runSerializer.js +14 -2
  14. package/dist/docx/styleParser.js +2 -1
  15. package/dist/docx/textBoxParser.js +14 -0
  16. package/dist/docx/vmlImageParser.js +72 -152
  17. package/dist/docx/vmlPreview.d.ts +31 -0
  18. package/dist/docx/vmlPreview.js +535 -0
  19. package/dist/docx/wrapTypes.d.ts +2 -36
  20. package/dist/docx/wrapTypes.js +1 -39
  21. package/dist/fonts/fontAlternates.d.ts +8 -0
  22. package/dist/fonts/fontAlternates.js +16 -0
  23. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  24. package/dist/layout-bridge/convert/footnoteLayout.js +34 -3
  25. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  26. package/dist/layout-bridge/convert/headerFooterLayout.js +5 -0
  27. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -2
  28. package/dist/layout-bridge/convert/toFlowBlocks.js +136 -120
  29. package/dist/layout-bridge/dom/noteStoryDom.d.ts +1 -1
  30. package/dist/layout-bridge/engine/selectionRects.js +3 -1
  31. package/dist/layout-engine/index.js +65 -32
  32. package/dist/layout-engine/justifiedLineFit.d.ts +7 -0
  33. package/dist/layout-engine/justifiedLineFit.js +6 -0
  34. package/dist/layout-engine/keep-together.js +15 -10
  35. package/dist/layout-engine/measure/complexScriptFormatting.d.ts +6 -1
  36. package/dist/layout-engine/measure/complexScriptFormatting.js +11 -2
  37. package/dist/layout-engine/measure/floatingTablePosition.d.ts +16 -1
  38. package/dist/layout-engine/measure/floatingTablePosition.js +29 -6
  39. package/dist/layout-engine/measure/lineBreakProvider.js +67 -8
  40. package/dist/layout-engine/measure/listMarkerWidth.d.ts +1 -0
  41. package/dist/layout-engine/measure/listMarkerWidth.js +23 -10
  42. package/dist/layout-engine/measure/measureBlocks.d.ts +15 -0
  43. package/dist/layout-engine/measure/measureBlocks.js +197 -30
  44. package/dist/layout-engine/measure/measureContainer.js +20 -24
  45. package/dist/layout-engine/measure/measureHelpers.d.ts +1 -1
  46. package/dist/layout-engine/measure/measureHelpers.js +14 -8
  47. package/dist/layout-engine/measure/measureParagraph.js +111 -37
  48. package/dist/layout-engine/measure/measureTypes.d.ts +3 -0
  49. package/dist/layout-engine/measure/tabCalculator.d.ts +123 -0
  50. package/dist/layout-engine/measure/tabCalculator.js +144 -0
  51. package/dist/layout-engine/measure/tableCellFlow.d.ts +21 -1
  52. package/dist/layout-engine/measure/tableCellFlow.js +45 -8
  53. package/dist/layout-engine/measure/tableInlinePlacement.d.ts +10 -2
  54. package/dist/layout-engine/measure/tableInlinePlacement.js +17 -15
  55. package/dist/layout-engine/paginator.d.ts +26 -2
  56. package/dist/layout-engine/paginator.js +76 -14
  57. package/dist/layout-engine/paragraphSpacing.d.ts +3 -1
  58. package/dist/layout-engine/paragraphSpacing.js +4 -3
  59. package/dist/layout-engine/renderedBreakReconciliation.d.ts +14 -3
  60. package/dist/layout-engine/renderedBreakReconciliation.js +45 -14
  61. package/dist/layout-engine/section-breaks.d.ts +3 -1
  62. package/dist/layout-engine/section-breaks.js +6 -2
  63. package/dist/layout-engine/types.d.ts +18 -1
  64. package/dist/layout-engine/types.js +1 -1
  65. package/dist/layout-painter/imageLayout.d.ts +1 -1
  66. package/dist/layout-painter/renderPage.js +6 -1
  67. package/dist/layout-painter/renderParagraph.js +169 -82
  68. package/dist/layout-painter/renderTable.d.ts +1 -1
  69. package/dist/layout-painter/renderTable.js +18 -7
  70. package/dist/layout-painter/renderTextBox.d.ts +1 -1
  71. package/dist/layout-painter/renderTextBox.js +6 -1
  72. package/dist/markdown/renderParagraph.js +7 -2
  73. package/dist/model.d.ts +3 -3
  74. package/dist/model.js +2 -2
  75. package/dist/paged-layout/sectionBlockWidths.d.ts +14 -0
  76. package/dist/paged-layout/sectionBlockWidths.js +103 -14
  77. package/dist/prosemirror/attrs/index.js +14 -2
  78. package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +8 -0
  79. package/dist/prosemirror/bookmarkBoundaryAttrs.js +66 -0
  80. package/dist/prosemirror/conversion/fromProseDoc.js +176 -54
  81. package/dist/prosemirror/conversion/toProseDoc.js +179 -64
  82. package/dist/prosemirror/extensions/StarterKit.js +11 -3
  83. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +8 -4
  84. package/dist/prosemirror/extensions/features/PasteCleanupExtension.d.ts +4 -1
  85. package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +9 -5
  86. package/dist/prosemirror/extensions/features/pasteCleanup.d.ts +10 -23
  87. package/dist/prosemirror/extensions/features/pasteCleanup.js +77 -22
  88. package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.js +9 -5
  89. package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.d.ts +9 -0
  90. package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +67 -0
  91. package/dist/prosemirror/extensions/nodes/FieldExtension.d.ts +10 -4
  92. package/dist/prosemirror/extensions/nodes/FieldExtension.js +77 -59
  93. package/dist/prosemirror/extensions/nodes/TableExtension.js +2 -0
  94. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +4 -1
  95. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +4 -3
  96. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +6 -2
  97. package/dist/prosemirror/listMarker.d.ts +58 -0
  98. package/dist/prosemirror/listMarker.js +185 -0
  99. package/dist/prosemirror/numberedRefFields.d.ts +24 -0
  100. package/dist/prosemirror/numberedRefFields.js +276 -0
  101. package/dist/prosemirror/paraText.js +56 -17
  102. package/dist/prosemirror/plugins/anonymizationDecorations.js +1 -1
  103. package/dist/prosemirror/plugins/pmTextScan.d.ts +3 -1
  104. package/dist/prosemirror/plugins/pmTextScan.js +28 -7
  105. package/dist/prosemirror/plugins/templateDirectives.js +2 -2
  106. package/dist/prosemirror/schema/index.d.ts +2 -2
  107. package/dist/prosemirror/schema/nodes.d.ts +17 -1
  108. package/dist/prosemirror/utils/tabCalculator.d.ts +2 -123
  109. package/dist/prosemirror/utils/tabCalculator.js +1 -140
  110. package/dist/prosemirror/validation.js +93 -0
  111. package/dist/render-dom/RemoteSelectionOverlay.d.ts +4 -4
  112. package/dist/types/documentEnumValues.d.ts +4 -1
  113. package/dist/types/documentEnumValues.js +12 -1
  114. package/dist/types/editor-story.d.ts +8 -0
  115. package/dist/types/editor-story.js +0 -0
  116. package/dist/types/remote-selection.d.ts +11 -0
  117. package/dist/types/remote-selection.js +0 -0
  118. package/dist/types/wrap.d.ts +36 -0
  119. package/dist/types/wrap.js +40 -0
  120. package/dist/utils/fontResolver.d.ts +1 -1
  121. package/dist/utils/fontResolver.js +42 -2
  122. package/dist/utils/formatToStyle.js +4 -2
  123. package/dist/utils/horizontalScale.d.ts +28 -0
  124. package/dist/utils/horizontalScale.js +42 -0
  125. package/package.json +2 -2
@@ -1,10 +1,13 @@
1
1
  import { numPrEqual } from "../../docx/numberingParser.js";
2
2
  import { ShapeOutlineStyleSchema, narrowEnum } from "../../docx/parserEnums.js";
3
- import { OUTLINE_STYLE_CSS_ALIASES } from "../../types/documentEnumValues.js";
3
+ import { OUTLINE_STYLE_CSS_ALIASES, normalizeShapeTextAnchor } from "../../types/documentEnumValues.js";
4
+ import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
4
5
  import { pixelsToEmu } from "../../utils/units.js";
5
6
  import { expectBlockSdtAttrs, expectCharacterSpacingMarkAttrs, expectCharacterStyleMarkAttrs, expectCommentMarkAttrs, expectEmphasisMarkAttrs, expectFieldAttrs, expectFontFamilyMarkAttrs, expectFontSizeMarkAttrs, expectFootnoteRefMarkAttrs, expectHardBreakAttrs, expectHighlightMarkAttrs, expectHyperlinkMarkAttrs, expectImageAttrs, expectLanguageMarkAttrs, expectMathAttrs, expectParagraphAttrs, expectRunFormattingOverrideMarkAttrs, expectRunPropertyChangeMarkAttrs, expectRunShadingMarkAttrs, expectSdtAttrs, expectShapeAttrs, expectStrikeMarkAttrs, expectSymbolAttrs, expectTabAttrs, expectTableAttrs, expectTableCellAttrs, expectTableRowAttrs, expectTextBoxAttrs, expectTextColorMarkAttrs, expectTextEffectMarkAttrs, expectTrackedChangeMarkAttrs, expectUnderlineMarkAttrs } from "../attrs/index.js";
6
7
  import { autospacingMatchesBase, hasAutospacingBaseSide } from "../autospacingBase.js";
8
+ import { expectBookmarkBoundaryAttrs } from "../bookmarkBoundaryAttrs.js";
7
9
  import { applyRunFormattingOverrideAttrs } from "../extensions/marks/RunFormattingOverrideExtension.js";
10
+ import { resolveNumberedRefFields } from "../numberedRefFields.js";
8
11
  import { directionToBidi } from "../paragraphDirection.js";
9
12
  import { RUN_FORMATTING_MARK_NAMES } from "../runFormattingMarkNames.js";
10
13
  import { parseShapeGeometryAdjustments } from "../shapeGeometryAdjustments.js";
@@ -198,12 +201,33 @@ function mapSuggestionStrippedNode(node) {
198
201
  function stripSuggestedProvenance(doc) {
199
202
  return mapSuggestionStrippedNode(doc) ?? doc;
200
203
  }
201
- /**
202
- * Extract block content (paragraphs, tables, block SDTs) from a ProseMirror
203
- * document.
204
- */
205
- function extractBlocks(inputDoc) {
206
- const pmDoc = stripSuggestedProvenance(inputDoc);
204
+ function materializeNumberedRefValues(doc) {
205
+ const results = resolveNumberedRefFields(doc);
206
+ if (results.size === 0) return doc;
207
+ const visit = (node) => {
208
+ if (node.type.name === "field" || node.type.name === "structuredField") {
209
+ const displayText = results.get(node);
210
+ if (displayText !== void 0) return node.type.create({
211
+ ...node.attrs,
212
+ displayText
213
+ }, node.content, node.marks);
214
+ return node;
215
+ }
216
+ if (node.childCount === 0) return node;
217
+ const children = [];
218
+ let changed = false;
219
+ node.forEach((child) => {
220
+ const mappedChild = visit(child);
221
+ children.push(mappedChild);
222
+ changed ||= mappedChild !== child;
223
+ });
224
+ return changed ? node.copy(Fragment.fromArray(children)) : node;
225
+ };
226
+ return visit(doc);
227
+ }
228
+ function extractBlocks(inputDoc, refResolution = "resolve") {
229
+ const strippedDoc = stripSuggestedProvenance(inputDoc);
230
+ const pmDoc = refResolution === "resolve" ? materializeNumberedRefValues(strippedDoc) : strippedDoc;
207
231
  const blocks = [];
208
232
  const textBoxAnchorMarkers = /* @__PURE__ */ new Map();
209
233
  const documentCounts = buildDocumentTrackedChangeCounts(pmDoc);
@@ -271,7 +295,7 @@ function convertPMBlockSdt(node) {
271
295
  if (attrs.rawEndPropertiesXml) properties.rawEndPropertiesXml = attrs.rawEndPropertiesXml;
272
296
  if (attrs.rawSdtChildrenBeforeContent) properties.rawSdtChildrenBeforeContent = attrs.rawSdtChildrenBeforeContent;
273
297
  if (attrs.rawSdtChildrenAfterContent) properties.rawSdtChildrenAfterContent = attrs.rawSdtChildrenAfterContent;
274
- const extracted = extractBlocks(node.type.schema.node("doc", null, node.content));
298
+ const extracted = extractBlocks(node.type.schema.node("doc", null, node.content), "inherit");
275
299
  return {
276
300
  type: "blockSdt",
277
301
  properties,
@@ -391,6 +415,7 @@ function editTextBoxAnchorInContent(content, marker, replacement) {
391
415
  }
392
416
  let nestedContent;
393
417
  if (item?.type === "hyperlink") nestedContent = item.children;
418
+ else if (item?.type === "simpleField") nestedContent = item.content;
394
419
  else if (item?.type === "inlineSdt" || item?.type === "insertion" || item?.type === "deletion" || item?.type === "moveFrom" || item?.type === "moveTo") nestedContent = item.content;
395
420
  if (!nestedContent) continue;
396
421
  const hadContent = nestedContent.length > 0;
@@ -640,12 +665,28 @@ function paragraphAttrsToFormatting(attrs) {
640
665
  if (attrs.suppressAutoHyphens != null) f.suppressAutoHyphens = attrs.suppressAutoHyphens;
641
666
  return f;
642
667
  }
643
- /**
644
- * Extract paragraph content (runs, hyperlinks) from ProseMirror paragraph
645
- *
646
- * Coalesces consecutive text with the same marks into single Runs
647
- * for efficient DOCX representation.
648
- */
668
+ function createTrackedRunWrapper(type, info, child) {
669
+ if (type === "insertion") return {
670
+ type,
671
+ info,
672
+ content: [child]
673
+ };
674
+ if (type === "deletion") return {
675
+ type,
676
+ info,
677
+ content: [child]
678
+ };
679
+ if (type === "moveFrom") return {
680
+ type,
681
+ info,
682
+ content: [child]
683
+ };
684
+ return {
685
+ type,
686
+ info,
687
+ content: [child]
688
+ };
689
+ }
649
690
  function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, textBoxAnchorMarkers, skipLeadingRenderedPageBreak = false) {
650
691
  const content = [];
651
692
  const inheritedFormatting = paragraph.type.name === "paragraph" ? expectParagraphAttrs(paragraph).defaultTextFormatting ?? void 0 : void 0;
@@ -659,6 +700,7 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
659
700
  let currentMarksKey = null;
660
701
  let currentHyperlink = null;
661
702
  let currentHyperlinkKey = null;
703
+ let currentTrackedChange;
662
704
  const openedComments = /* @__PURE__ */ new Set();
663
705
  const commentLastOffset = /* @__PURE__ */ new Map();
664
706
  paragraph.forEach((node, offset) => {
@@ -687,6 +729,7 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
687
729
  for (const commentId of nodeCommentIds) if (!openedComments.has(commentId)) toOpen.push(commentId);
688
730
  if (toClose.length === 0 && toOpen.length === 0) return;
689
731
  flushCurrentInline();
732
+ currentTrackedChange = void 0;
690
733
  for (const commentId of toClose.toSorted((a, b) => a - b)) {
691
734
  content.push({
692
735
  type: "commentRangeEnd",
@@ -708,6 +751,7 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
708
751
  if (!item || item.attrs.offset > offset) break;
709
752
  nextEmptyHyperlink += 1;
710
753
  flushCurrentInline();
754
+ currentTrackedChange = void 0;
711
755
  content.push(createEmptyHyperlink(item.attrs));
712
756
  }
713
757
  };
@@ -722,8 +766,10 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
722
766
  const noteRefMark = node.marks.find((m) => m.type.name === "footnoteRef");
723
767
  const insertionMark = node.marks.find((m) => m.type.name === "insertion");
724
768
  const deletionMark = node.marks.find((m) => m.type.name === "deletion");
769
+ if (!insertionMark && !deletionMark) currentTrackedChange = void 0;
725
770
  if (node.type.name === "textBoxAnchor") {
726
771
  flushCurrentInline();
772
+ currentTrackedChange = void 0;
727
773
  if (!textBoxAnchorMarkers) return;
728
774
  const { anchorId } = expectTextBoxAnchorAttrs(node);
729
775
  const marker = {
@@ -766,42 +812,51 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
766
812
  if (!changeMark) return;
767
813
  const changeAttrs = expectTrackedChangeMarkAttrs(changeMark);
768
814
  const otherMarks = node.marks.filter((m) => m.type.name !== "insertion" && m.type.name !== "deletion");
769
- const run = createTrackedChangeRun({
770
- inheritedFormatting,
771
- marks: otherMarks,
772
- node
773
- });
774
- if (!run) return;
775
- const trackedContent = linkMark ? {
776
- ...createHyperlink(linkMark),
777
- children: [run]
778
- } : run;
779
815
  const info = {
780
816
  id: changeAttrs.revisionId,
781
817
  author: changeAttrs.author || "Unknown"
782
818
  };
783
819
  if (changeAttrs.date) info.date = changeAttrs.date;
784
820
  if (changeAttrs.initials) info.initials = changeAttrs.initials;
785
- if (insertionMark) if (changeAttrs.moveKind === "moveTo") content.push({
786
- type: "moveTo",
787
- info,
788
- content: [trackedContent]
789
- });
790
- else content.push({
791
- type: "insertion",
792
- info,
793
- content: [trackedContent]
794
- });
795
- else if (changeAttrs.moveKind === "moveFrom") content.push({
796
- type: "moveFrom",
797
- info,
798
- content: [trackedContent]
799
- });
800
- else content.push({
801
- type: "deletion",
802
- info,
803
- content: [trackedContent]
821
+ let type;
822
+ if (insertionMark) type = changeAttrs.moveKind === "moveTo" ? "moveTo" : "insertion";
823
+ else type = changeAttrs.moveKind === "moveFrom" ? "moveFrom" : "deletion";
824
+ const trackedChangeKey = `${type}:${JSON.stringify(info)}`;
825
+ if (linkMark) {
826
+ const linkKey = getLinkKey(linkMark);
827
+ if (!currentTrackedChange || currentTrackedChange.key !== trackedChangeKey || currentTrackedChange.hyperlinkKey !== linkKey) {
828
+ const hyperlink = createHyperlink(linkMark);
829
+ const wrapper = createTrackedRunWrapper(type, info, hyperlink);
830
+ content.push(wrapper);
831
+ currentTrackedChange = {
832
+ key: trackedChangeKey,
833
+ hyperlink,
834
+ hyperlinkKey: linkKey
835
+ };
836
+ }
837
+ if (node.type.name === "bookmarkBoundary") {
838
+ addNodeToHyperlink({
839
+ hyperlink: currentTrackedChange.hyperlink,
840
+ inheritedFormatting,
841
+ node
842
+ });
843
+ return;
844
+ }
845
+ const run = createTrackedChangeRun({
846
+ inheritedFormatting,
847
+ marks: otherMarks,
848
+ node
849
+ });
850
+ if (run) currentTrackedChange.hyperlink.children.push(run);
851
+ return;
852
+ }
853
+ currentTrackedChange = void 0;
854
+ const run = createTrackedChangeRun({
855
+ inheritedFormatting,
856
+ marks: otherMarks,
857
+ node
804
858
  });
859
+ if (run) content.push(createTrackedRunWrapper(type, info, run));
805
860
  return;
806
861
  }
807
862
  if (noteRefMark && !linkMark) {
@@ -824,7 +879,21 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
824
879
  return;
825
880
  }
826
881
  if (currentHyperlink) flushCurrentInline();
827
- if (node.isText) {
882
+ if (node.type.name === "bookmarkBoundary") {
883
+ flushCurrentInline();
884
+ const attrs = expectBookmarkBoundaryAttrs(node);
885
+ if (attrs.type === "start") content.push({
886
+ type: "bookmarkStart",
887
+ id: attrs.id,
888
+ name: attrs.name,
889
+ ...attrs.colFirst !== void 0 ? { colFirst: attrs.colFirst } : {},
890
+ ...attrs.colLast !== void 0 ? { colLast: attrs.colLast } : {}
891
+ });
892
+ else content.push({
893
+ type: "bookmarkEnd",
894
+ id: attrs.id
895
+ });
896
+ } else if (node.isText) {
828
897
  const marksKey = getMarksKey(node.marks);
829
898
  if (currentRun && currentMarksKey === marksKey) appendTextToRun(currentRun, node.text || "");
830
899
  else {
@@ -854,9 +923,12 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
854
923
  } else if (node.type.name === "renderedPageBreak") {
855
924
  flushCurrentInline();
856
925
  content.push(createRenderedPageBreakRun());
857
- } else if (node.type.name === "field") {
926
+ } else if (node.type.name === "field" || node.type.name === "structuredField") {
858
927
  flushCurrentInline();
859
- content.push(createFieldFromNode(node, node.marks));
928
+ content.push(createFieldFromNode(node, {
929
+ marks: node.marks,
930
+ textBoxAnchorMarkers
931
+ }));
860
932
  } else if (node.type.name === "sdt") {
861
933
  flushCurrentInline();
862
934
  content.push(createInlineSdtFromNode(node, textBoxAnchorMarkers));
@@ -1005,6 +1077,21 @@ function createHyperlink(linkMark) {
1005
1077
  return hyperlink;
1006
1078
  }
1007
1079
  function addNodeToHyperlink({ hyperlink, inheritedFormatting, node }) {
1080
+ if (node.type.name === "bookmarkBoundary") {
1081
+ const attrs = expectBookmarkBoundaryAttrs(node);
1082
+ if (attrs.type === "start") hyperlink.children.push({
1083
+ type: "bookmarkStart",
1084
+ id: attrs.id,
1085
+ name: attrs.name,
1086
+ ...attrs.colFirst !== void 0 ? { colFirst: attrs.colFirst } : {},
1087
+ ...attrs.colLast !== void 0 ? { colLast: attrs.colLast } : {}
1088
+ });
1089
+ else hyperlink.children.push({
1090
+ type: "bookmarkEnd",
1091
+ id: attrs.id
1092
+ });
1093
+ return;
1094
+ }
1008
1095
  const noteRefMark = node.marks.find((m) => m.type.name === "footnoteRef");
1009
1096
  if (noteRefMark) {
1010
1097
  hyperlink.children.push(createNoteReferenceRun(noteRefMark, node.marks));
@@ -1151,13 +1238,10 @@ function createTabRun(node, marks) {
1151
1238
  if (formatting) run.formatting = formatting;
1152
1239
  return run;
1153
1240
  }
1154
- /**
1155
- * Create a SimpleField or ComplexField from a PM field node
1156
- */
1157
- function createFieldFromNode(node, marks) {
1241
+ function createFieldFromNode(node, { marks, textBoxAnchorMarkers }) {
1158
1242
  const attrs = expectFieldAttrs(node);
1159
1243
  const formatting = marks && marks.length > 0 ? marksToTextFormatting(marks) : void 0;
1160
- let displayText = attrs.displayText || "";
1244
+ let displayText = attrs.displayText ?? "";
1161
1245
  if (!displayText) switch (attrs.fieldType) {
1162
1246
  case "PAGE":
1163
1247
  displayText = "1";
@@ -1177,13 +1261,15 @@ function createFieldFromNode(node, marks) {
1177
1261
  }],
1178
1262
  ...formatting && Object.keys(formatting).length > 0 ? { formatting } : {}
1179
1263
  };
1264
+ const extractedContent = extractParagraphContent(node, void 0, void 0, textBoxAnchorMarkers).filter((content) => content.type === "run" || content.type === "hyperlink");
1265
+ const fieldContent = extractedContent.length > 0 ? synchronizeFieldDisplayText(extractedContent, displayText, displayRun) : [];
1180
1266
  if (attrs.fieldKind === "complex") {
1181
1267
  const complex = {
1182
1268
  type: "complexField",
1183
1269
  instruction: attrs.instruction,
1184
1270
  fieldType: attrs.fieldType,
1185
1271
  fieldCode: [],
1186
- fieldResult: [displayRun]
1272
+ fieldResult: fieldContent.length > 0 ? fieldContent.filter((content) => content.type === "run") : [displayRun]
1187
1273
  };
1188
1274
  if (attrs.fldLock) complex.fldLock = true;
1189
1275
  if (attrs.dirty) complex.dirty = true;
@@ -1193,12 +1279,45 @@ function createFieldFromNode(node, marks) {
1193
1279
  type: "simpleField",
1194
1280
  instruction: attrs.instruction,
1195
1281
  fieldType: attrs.fieldType,
1196
- content: [displayRun]
1282
+ content: fieldContent.length > 0 ? fieldContent : [displayRun]
1197
1283
  };
1198
1284
  if (attrs.fldLock) simple.fldLock = true;
1199
1285
  if (attrs.dirty) simple.dirty = true;
1200
1286
  return simple;
1201
1287
  }
1288
+ const synchronizeFieldDisplayText = (content, displayText, fallbackRun) => {
1289
+ let currentText = "";
1290
+ const visitRuns = (visit) => {
1291
+ for (const child of content) {
1292
+ if (child.type === "run") {
1293
+ visit(child);
1294
+ continue;
1295
+ }
1296
+ for (const hyperlinkChild of child.children) if (hyperlinkChild.type === "run") visit(hyperlinkChild);
1297
+ }
1298
+ };
1299
+ visitRuns((run) => {
1300
+ for (const runContent of run.content) if (runContent.type === "text") currentText += runContent.text;
1301
+ });
1302
+ if (currentText === displayText) return content;
1303
+ let replacedText = false;
1304
+ visitRuns((run) => {
1305
+ for (const runContent of run.content) {
1306
+ if (runContent.type !== "text") continue;
1307
+ runContent.text = replacedText ? "" : displayText;
1308
+ replacedText = true;
1309
+ }
1310
+ });
1311
+ if (replacedText) return content;
1312
+ const hyperlink = content.find((child) => child.type === "hyperlink");
1313
+ if (!hyperlink) {
1314
+ content.push(fallbackRun);
1315
+ return content;
1316
+ }
1317
+ const firstEnd = hyperlink.children.findIndex((child) => child.type === "bookmarkEnd");
1318
+ hyperlink.children.splice(firstEnd < 0 ? hyperlink.children.length : firstEnd, 0, fallbackRun);
1319
+ return content;
1320
+ };
1202
1321
  /**
1203
1322
  * Create a MathEquation from a PM math node
1204
1323
  */
@@ -1455,7 +1574,8 @@ function marksToTextFormatting(marks, options) {
1455
1574
  const attrs = expectCharacterSpacingMarkAttrs(mark);
1456
1575
  if (attrs.spacing !== void 0) formatting.spacing = attrs.spacing;
1457
1576
  if (attrs.position !== void 0) formatting.position = attrs.position;
1458
- if (attrs.scale !== void 0) formatting.scale = attrs.scale;
1577
+ const horizontalScale = normalizeHorizontalScalePercent(attrs.scale);
1578
+ if (horizontalScale !== void 0) formatting.scale = horizontalScale;
1459
1579
  if (attrs.kerning !== void 0) formatting.kerning = attrs.kerning;
1460
1580
  break;
1461
1581
  }
@@ -1896,6 +2016,7 @@ function tableCellAttrsToFormatting(attrs) {
1896
2016
  */
1897
2017
  function convertPMTextBox(node) {
1898
2018
  const attrs = expectTextBoxAttrs(node);
2019
+ const verticalAlign = normalizeShapeTextAnchor(attrs.verticalAlign);
1899
2020
  const childBlocks = [];
1900
2021
  node.forEach((child) => {
1901
2022
  if (child.type.name === "paragraph") childBlocks.push(convertPMParagraph(child));
@@ -1915,6 +2036,7 @@ function convertPMTextBox(node) {
1915
2036
  }],
1916
2037
  ...attrs.autoFit !== void 0 ? { autoFit: attrs.autoFit } : {},
1917
2038
  ...attrs.textWrap !== void 0 ? { textWrap: attrs.textWrap } : {},
2039
+ ...verticalAlign !== void 0 ? { anchor: verticalAlign } : {},
1918
2040
  margins: (() => {
1919
2041
  const m = {};
1920
2042
  if (typeof attrs.marginTop === "number") m.top = pixelsToEmu(attrs.marginTop);