@stll/folio-core 0.10.0 → 0.12.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 (217) hide show
  1. package/dist/ai-edits/apply.js +602 -50
  2. package/dist/ai-edits/block-identity.d.ts +4 -0
  3. package/dist/ai-edits/block-identity.js +9 -0
  4. package/dist/ai-edits/blockRange.d.ts +28 -1
  5. package/dist/ai-edits/blockRange.js +67 -1
  6. package/dist/ai-edits/headless.d.ts +4 -4
  7. package/dist/ai-edits/headless.js +9 -9
  8. package/dist/ai-edits/index.d.ts +2 -2
  9. package/dist/ai-edits/index.js +2 -2
  10. package/dist/ai-edits/read.d.ts +7 -7
  11. package/dist/ai-edits/read.js +110 -3
  12. package/dist/ai-edits/table-cell-mutations.d.ts +48 -0
  13. package/dist/ai-edits/table-cell-mutations.js +237 -0
  14. package/dist/ai-edits/table-mutation-plan.d.ts +38 -0
  15. package/dist/ai-edits/table-mutation-plan.js +90 -0
  16. package/dist/ai-edits/table-row-column-mutations.d.ts +100 -0
  17. package/dist/ai-edits/table-row-column-mutations.js +300 -0
  18. package/dist/ai-edits/table-targets.d.ts +32 -0
  19. package/dist/ai-edits/table-targets.js +70 -0
  20. package/dist/ai-edits/types.d.ts +34 -0
  21. package/dist/compat/eigenpal.js +1 -1
  22. package/dist/content-controls/mutateContentControls.js +1 -1
  23. package/dist/controller/activeEditorStory.d.ts +36 -0
  24. package/dist/controller/activeEditorStory.js +30 -0
  25. package/dist/controller/collaborationModules.d.ts +7 -0
  26. package/dist/controller/collaborationModules.js +15 -0
  27. package/dist/controller/contentControlWidgetController.d.ts +55 -0
  28. package/dist/controller/contentControlWidgetController.js +141 -0
  29. package/dist/controller/folioEditor.d.ts +1 -1
  30. package/dist/controller/fontReadiness.js +2 -0
  31. package/dist/controller/headerFooterEditorManager.d.ts +41 -0
  32. package/dist/controller/headerFooterEditorManager.js +182 -0
  33. package/dist/controller/hiddenEditorApi.js +2 -2
  34. package/dist/controller/hiddenEditorManager.d.ts +13 -2
  35. package/dist/controller/hiddenEditorManager.js +32 -11
  36. package/dist/controller/layoutPipeline.d.ts +2 -0
  37. package/dist/controller/layoutPipeline.js +16 -1
  38. package/dist/controller/noteEditorManager.d.ts +36 -0
  39. package/dist/controller/noteEditorManager.js +210 -0
  40. package/dist/document-operations.d.ts +35 -3
  41. package/dist/document-operations.js +161 -3
  42. package/dist/docx/blockContentParser.js +2 -2
  43. package/dist/docx/commentParser.js +6 -1
  44. package/dist/docx/conformance.js +8 -1
  45. package/dist/docx/documentGrid.d.ts +8 -0
  46. package/dist/docx/documentGrid.js +8 -0
  47. package/dist/docx/drawingUtils.js +1 -1
  48. package/dist/docx/ensureParaIds.js +1 -1
  49. package/dist/docx/fieldParser.js +1 -1
  50. package/dist/docx/notePropertiesParser.js +1 -1
  51. package/dist/docx/numberingParser.js +1 -1
  52. package/dist/docx/paragraphParser.js +63 -58
  53. package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
  54. package/dist/docx/paragraphTextBoxEnrichment.js +67 -13
  55. package/dist/docx/paragraphTraversal.js +1 -1
  56. package/dist/docx/parser.js +3 -3
  57. package/dist/docx/rezip.js +1 -1
  58. package/dist/docx/runParser.js +4 -2
  59. package/dist/docx/sdtProperties.js +1 -1
  60. package/dist/docx/sectionParser.js +1 -1
  61. package/dist/docx/selectiveSave.js +1 -1
  62. package/dist/docx/serializer/commentSerializer.js +1 -2
  63. package/dist/docx/serializer/documentSerializer.js +2 -2
  64. package/dist/docx/serializer/headerFooterSerializer.js +2 -2
  65. package/dist/docx/serializer/noteSerializer.js +2 -2
  66. package/dist/docx/serializer/paragraphSerializer.js +7 -1
  67. package/dist/docx/serializer/runSerializer.js +4 -2
  68. package/dist/docx/serializer/stylesSerializer.js +1 -1
  69. package/dist/docx/serializer/tableSerializer.d.ts +5 -4
  70. package/dist/docx/serializer/tableSerializer.js +17 -13
  71. package/dist/docx/server/applyDocxXmlPatchProposal.d.ts +87 -0
  72. package/dist/docx/server/applyDocxXmlPatchProposal.js +204 -0
  73. package/dist/docx/server/boundedArchive.d.ts +14 -3
  74. package/dist/docx/server/boundedArchive.js +56 -11
  75. package/dist/docx/server/evaluateDocxXmlPatchProposal.d.ts +85 -0
  76. package/dist/docx/server/evaluateDocxXmlPatchProposal.js +361 -0
  77. package/dist/docx/server/inspectDocxPackage.d.ts +70 -0
  78. package/dist/docx/server/inspectDocxPackage.js +217 -0
  79. package/dist/docx/server/validateDocxConformance.d.ts +41 -0
  80. package/dist/docx/server/validateDocxConformance.js +336 -0
  81. package/dist/docx/settingsParser.js +11 -1
  82. package/dist/docx/shapeParser.js +1 -1
  83. package/dist/docx/styleParser.js +4 -2
  84. package/dist/docx/tableParser.js +18 -7
  85. package/dist/docx/textBoxParser.d.ts +3 -3
  86. package/dist/docx/textBoxParser.js +16 -12
  87. package/dist/docx/xmlSafety.d.ts +5 -0
  88. package/dist/docx/xmlSafety.js +9 -0
  89. package/dist/fields/resolveFieldValues.js +1 -3
  90. package/dist/i18n/messages/catalogs.gen.d.ts +17 -0
  91. package/dist/i18n/messages/catalogs.gen.js +17 -0
  92. package/dist/i18n/messages/messages.gen.d.ts +1 -0
  93. package/dist/index.js +1 -1
  94. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  95. package/dist/layout-bridge/convert/footnoteLayout.js +47 -40
  96. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  97. package/dist/layout-bridge/convert/headerFooterLayout.js +3 -0
  98. package/dist/layout-bridge/convert/templatePreviewFlow.js +3 -3
  99. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -2
  100. package/dist/layout-bridge/convert/toFlowBlocks.js +136 -20
  101. package/dist/layout-bridge/dom/noteStoryDom.d.ts +6 -0
  102. package/dist/layout-bridge/dom/noteStoryDom.js +17 -0
  103. package/dist/layout-bridge/engine/clickToPosition.js +2 -2
  104. package/dist/layout-engine/index.d.ts +2 -2
  105. package/dist/layout-engine/index.js +43 -28
  106. package/dist/layout-engine/justificationCompatibility.d.ts +6 -0
  107. package/dist/layout-engine/justificationCompatibility.js +8 -0
  108. package/dist/layout-engine/keep-together.js +11 -1
  109. package/dist/layout-engine/measure/cache.js +21 -5
  110. package/dist/layout-engine/measure/lineBreakProvider.js +53 -34
  111. package/dist/layout-engine/measure/measureBlocks.js +6 -3
  112. package/dist/layout-engine/measure/measureContainer.js +1 -1
  113. package/dist/layout-engine/measure/measureHelpers.d.ts +1 -1
  114. package/dist/layout-engine/measure/measureHelpers.js +3 -3
  115. package/dist/layout-engine/measure/measureParagraph.js +69 -25
  116. package/dist/layout-engine/measure/measureProvider.js +4 -3
  117. package/dist/layout-engine/measure/tableCellFlow.js +5 -2
  118. package/dist/layout-engine/measure/textBoxParagraphLayout.d.ts +9 -7
  119. package/dist/layout-engine/measure/textBoxParagraphLayout.js +22 -6
  120. package/dist/layout-engine/measure/textMeasurementPolicy.d.ts +3 -1
  121. package/dist/layout-engine/measure/textMeasurementPolicy.js +7 -1
  122. package/dist/layout-engine/paginator.js +5 -1
  123. package/dist/layout-engine/paragraphSpacing.d.ts +28 -4
  124. package/dist/layout-engine/paragraphSpacing.js +107 -13
  125. package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
  126. package/dist/layout-engine/types.d.ts +26 -13
  127. package/dist/layout-painter/registry/modules/textBox.js +5 -1
  128. package/dist/layout-painter/renderPage.d.ts +5 -2
  129. package/dist/layout-painter/renderPage.js +56 -12
  130. package/dist/layout-painter/renderParagraph.js +22 -6
  131. package/dist/layout-painter/renderTable.d.ts +5 -1
  132. package/dist/layout-painter/renderTable.js +5 -2
  133. package/dist/layout-painter/renderTextBox.d.ts +2 -1
  134. package/dist/layout-painter/renderTextBox.js +25 -14
  135. package/dist/managers/DocumentLoaderManager.js +1 -1
  136. package/dist/managers/FindReplaceManager.d.ts +8 -0
  137. package/dist/managers/FindReplaceManager.js +18 -0
  138. package/dist/managers/TableSelectionManager.d.ts +6 -0
  139. package/dist/managers/TableSelectionManager.js +14 -0
  140. package/dist/model.js +1 -1
  141. package/dist/prosemirror/attrs/index.d.ts +4 -2
  142. package/dist/prosemirror/attrs/index.js +154 -18
  143. package/dist/prosemirror/commands/comments.d.ts +3 -3
  144. package/dist/prosemirror/commands/comments.js +248 -12
  145. package/dist/prosemirror/commands/contentControls.js +1 -1
  146. package/dist/prosemirror/commands/index.js +1 -1
  147. package/dist/prosemirror/commands/pageBreak.js +1 -1
  148. package/dist/prosemirror/commands/propertyChangeScope.d.ts +2 -2
  149. package/dist/prosemirror/commands/propertyChangeScope.js +3 -2
  150. package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +9 -0
  151. package/dist/prosemirror/commands/tableCellMergeResolution.js +181 -0
  152. package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -1
  153. package/dist/prosemirror/conversion/fromProseDoc.js +286 -61
  154. package/dist/prosemirror/conversion/sdtAttrs.d.ts +9 -0
  155. package/dist/prosemirror/conversion/sdtAttrs.js +49 -0
  156. package/dist/prosemirror/conversion/toProseDoc.d.ts +2 -1
  157. package/dist/prosemirror/conversion/toProseDoc.js +347 -98
  158. package/dist/prosemirror/extensions/ExtensionManager.js +1 -1
  159. package/dist/prosemirror/extensions/StarterKit.js +6 -1
  160. package/dist/prosemirror/extensions/core/ParagraphExtension.js +4 -1
  161. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +1 -0
  162. package/dist/prosemirror/extensions/features/ListExtension.js +1 -1
  163. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +10 -1
  164. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +93 -2
  165. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +2 -1
  166. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +6 -2
  167. package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.js +1 -1
  168. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.d.ts +9 -1
  169. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +24 -1
  170. package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
  171. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.d.ts +7 -0
  172. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.js +22 -0
  173. package/dist/prosemirror/extensions/nodes/TableExtension.js +9 -3
  174. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +13 -0
  175. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +41 -0
  176. package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +5 -2
  177. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +4 -1
  178. package/dist/prosemirror/findReplaceSelection.d.ts +6 -1
  179. package/dist/prosemirror/findReplaceSelection.js +57 -13
  180. package/dist/prosemirror/plugins/contentControlWidgets.d.ts +34 -8
  181. package/dist/prosemirror/plugins/contentControlWidgets.js +125 -91
  182. package/dist/prosemirror/plugins/selectionTracker.js +1 -0
  183. package/dist/prosemirror/plugins/suggestionMode.js +1 -1
  184. package/dist/prosemirror/schema/index.d.ts +2 -2
  185. package/dist/prosemirror/schema/marks.d.ts +5 -1
  186. package/dist/prosemirror/schema/nodes.d.ts +64 -7
  187. package/dist/prosemirror/selectionState.js +1 -0
  188. package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
  189. package/dist/prosemirror/tableCellMergeRevision.d.ts +9 -0
  190. package/dist/prosemirror/tableCellMergeRevision.js +22 -0
  191. package/dist/prosemirror/textBoxAnchorAttrs.d.ts +9 -0
  192. package/dist/prosemirror/textBoxAnchorAttrs.js +33 -0
  193. package/dist/prosemirror/utils/extractTrackedChanges.d.ts +1 -1
  194. package/dist/prosemirror/utils/extractTrackedChanges.js +62 -14
  195. package/dist/prosemirror/validation.js +9 -1
  196. package/dist/render-dom/BodySelectionOverlay.d.ts +31 -0
  197. package/dist/render-dom/BodySelectionOverlay.js +76 -0
  198. package/dist/render-dom/HeaderFooterSelectionOverlay.d.ts +28 -0
  199. package/dist/render-dom/HeaderFooterSelectionOverlay.js +121 -0
  200. package/dist/render-dom/RemoteSelectionOverlay.d.ts +30 -0
  201. package/dist/render-dom/RemoteSelectionOverlay.js +67 -0
  202. package/dist/render-dom/RenderedDomContext.d.ts +40 -0
  203. package/dist/render-dom/RenderedDomContext.js +126 -0
  204. package/dist/render-dom/resolveSidebarItemPositions.d.ts +33 -0
  205. package/dist/render-dom/resolveSidebarItemPositions.js +45 -0
  206. package/dist/server.d.ts +6 -2
  207. package/dist/server.js +5 -1
  208. package/dist/utils/findReplace.d.ts +32 -0
  209. package/dist/utils/findReplace.js +118 -0
  210. package/dist/utils/fontFamilyMerge.js +9 -11
  211. package/dist/utils/fontLoader.js +3 -2
  212. package/dist/utils/fontResolver.js +22 -4
  213. package/dist/utils/fontWeights.d.ts +1 -1
  214. package/dist/utils/fontWeights.js +1 -1
  215. package/dist/utils/headerFooter.js +24 -1
  216. package/dist/utils/paragraphFormattingMerge.js +1 -0
  217. package/package.json +1 -1
@@ -1,17 +1,19 @@
1
+ import { directionFromBidi } from "../paragraphDirection.js";
1
2
  import { emuToPixels } from "../../utils/units.js";
2
- import { mergeTextFormatting } from "../../utils/textFormattingMerge.js";
3
- import { mergeParagraphFormatting, mergeParagraphTabStops } from "../../utils/paragraphFormattingMerge.js";
4
3
  import { setAutospacingBaseValue } from "../autospacingBase.js";
5
- import { directionFromBidi } from "../paragraphDirection.js";
6
4
  import { assertValidProseMirrorDocument } from "../validation.js";
7
5
  import { shadingToRunShadingAttrs } from "./runShadingMark.js";
6
+ import { sdtAttrsFromProperties } from "./sdtAttrs.js";
8
7
  import { marksToTextFormatting } from "./fromProseDoc.js";
8
+ import { mergeTextFormatting } from "../../utils/textFormattingMerge.js";
9
+ import { mergeParagraphFormatting, mergeParagraphTabStops } from "../../utils/paragraphFormattingMerge.js";
9
10
  import { createStyleEngine } from "../../style-engine/styleEngine.js";
10
11
  import { buildRunFormattingOverrideAttrs } from "../extensions/marks/RunFormattingOverrideExtension.js";
11
12
  import { schema } from "../schema/index.js";
12
13
  import { resolveEffectiveTableCellFormatting } from "./effectiveTableCellFormatting.js";
13
14
  //#region src/prosemirror/conversion/toProseDoc.ts
14
15
  const TOC_STYLE_ID = /^TOC\d*$/iu;
16
+ const isTocStyleId = (styleId) => styleId !== void 0 && TOC_STYLE_ID.test(styleId);
15
17
  /**
16
18
  * Convert a Document to a ProseMirror document
17
19
  *
@@ -30,7 +32,13 @@ function toProseDoc(document, options) {
30
32
  for (const block of blocks) if (block.type === "paragraph") {
31
33
  const pbPos = paragraphPageBreakPosition(block);
32
34
  if (pbPos === "before") out.push(schema.node("pageBreak"));
33
- const converted = convertParagraphWithTextBoxes(block, styleResolver, { textBoxGroupId: nextTextBoxGroupId() });
35
+ const converted = convertParagraphWithTextBoxes(block, styleResolver, {
36
+ textBoxGroupId: nextTextBoxGroupId(),
37
+ context: {
38
+ theme,
39
+ nextTextBoxGroupId
40
+ }
41
+ });
34
42
  const firstConverted = converted.at(0);
35
43
  if (pbPos === "before" && converted.length === 1 && firstConverted?.type.name === "paragraph" && firstConverted.content.size === 0 && document.package.settings?.splitPageBreakAndParagraphMark !== true) {
36
44
  const paragraph = firstConverted;
@@ -39,6 +47,14 @@ function toProseDoc(document, options) {
39
47
  _pageBreakCarrier: true
40
48
  }, paragraph.content, paragraph.marks);
41
49
  }
50
+ if (pbPos === "after") {
51
+ const paragraphIndex = converted.findIndex((node) => node.type.name === "paragraph");
52
+ const trailingParagraph = paragraphIndex >= 0 ? converted.at(paragraphIndex) : void 0;
53
+ if (trailingParagraph) converted[paragraphIndex] = trailingParagraph.type.create({
54
+ ...trailingParagraph.attrs,
55
+ _trailingPageBreak: true
56
+ }, trailingParagraph.content, trailingParagraph.marks);
57
+ }
42
58
  out.push(...converted);
43
59
  if (pbPos === "after") out.push(schema.node("pageBreak"));
44
60
  } else if (block.type === "table") out.push(convertTable(block, styleResolver, {
@@ -91,9 +107,9 @@ function convertBlockSdt(blockSdt, convertBlocks) {
91
107
  * Resolves style-based text formatting and passes it to runs so that
92
108
  * paragraph styles (like Heading1) apply their font size, color, etc.
93
109
  */
94
- function convertParagraph(paragraph, styleResolver, activeCommentIds, extraRunFormatting, tableParagraphOverlay) {
110
+ function convertParagraph(paragraph, styleResolver, activeCommentIds, extraRunFormatting, tableParagraphOverlay, textBoxAnchors) {
95
111
  const attrs = paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOverlay);
96
- const isTocParagraph = TOC_STYLE_ID.test(paragraph.formatting?.styleId ?? "");
112
+ const isTocParagraph = isTocStyleId(paragraph.formatting?.styleId);
97
113
  const inlineNodes = [];
98
114
  let inlineOffset = 0;
99
115
  let bookmarksArr;
@@ -111,11 +127,16 @@ function convertParagraph(paragraph, styleResolver, activeCommentIds, extraRunFo
111
127
  emitInlineNodes([node]);
112
128
  };
113
129
  let styleRunFormatting;
114
- if (styleResolver) styleRunFormatting = styleResolver.resolveParagraphStyle(paragraph.formatting?.styleId).runFormatting;
115
- const paragraphRunFormatting = resolveParagraphMarkRunFormatting(paragraph.formatting?.runProperties, styleResolver);
130
+ let paragraphStyleFontFamily;
131
+ if (styleResolver) {
132
+ styleRunFormatting = styleResolver.resolveParagraphStyle(paragraph.formatting?.styleId).runFormatting;
133
+ paragraphStyleFontFamily = resolveParagraphStyleFontFamily(paragraph.formatting?.styleId, styleResolver);
134
+ }
135
+ const paragraphRunFormatting = resolveRunFormattingWithoutDefaults(paragraph.formatting?.runProperties, styleResolver);
116
136
  let inheritableParagraphRunFormatting;
117
137
  if (paragraphRunFormatting && !isTocParagraph) inheritableParagraphRunFormatting = stripParagraphMarkFormattingForBodyRuns(paragraphRunFormatting);
118
- const baseRunFormatting = mergeTextFormatting(styleRunFormatting, extraRunFormatting);
138
+ let baseRunFormatting = mergeTextFormatting(styleRunFormatting, extraRunFormatting);
139
+ if (paragraphStyleFontFamily) baseRunFormatting = mergeTextFormatting(baseRunFormatting, { fontFamily: paragraphStyleFontFamily });
119
140
  const paragraphMarkPrecedesStyle = paragraph.formatting?.styleId !== void 0;
120
141
  const defaultRunFormatting = paragraphMarkPrecedesStyle ? mergeTextFormatting(inheritableParagraphRunFormatting, baseRunFormatting) : mergeTextFormatting(baseRunFormatting, inheritableParagraphRunFormatting);
121
142
  const getInheritedRunFormatting = (formatting, fieldType) => {
@@ -124,17 +145,22 @@ function convertParagraph(paragraph, styleResolver, activeCommentIds, extraRunFo
124
145
  return suppressParagraphMarkFormatting(baseRunFormatting, inheritableParagraphRunFormatting, formatting, paragraphMarkPrecedesStyle);
125
146
  };
126
147
  const emitTrackedChange = (change, markType, moveKind) => {
127
- emitInlineNodes(convertTrackedChange(change, markType, getInheritedRunFormatting, styleResolver, moveKind));
148
+ emitInlineNodes(convertTrackedChange(change, markType, getInheritedRunFormatting, styleResolver, moveKind, textBoxAnchors));
128
149
  };
129
150
  for (const content of paragraph.content) {
130
151
  if (content.type === "commentRangeStart") commentIds.add(content.id);
131
152
  else if (content.type === "commentRangeEnd") commentIds.delete(content.id);
132
153
  else if (content.type === "commentReference") anchorPointComment(inlineNodes, content.id);
133
- else if (content.type === "run") emitInlineNodes(convertRun(content, getInheritedRunFormatting(content.formatting), styleResolver));
154
+ else if (content.type === "run") emitInlineNodes(convertRun(content, getInheritedRunFormatting(content.formatting), styleResolver, textBoxAnchors));
134
155
  else if (content.type === "hyperlink") {
135
156
  const currentHyperlinkIndex = hyperlinkIndex;
136
157
  hyperlinkIndex += 1;
137
- const linkNodes = convertHyperlink(content, getInheritedRunFormatting, styleResolver, currentHyperlinkIndex);
158
+ const linkNodes = convertHyperlink(content, {
159
+ getInheritedRunFormatting,
160
+ styleResolver,
161
+ hyperlinkIndex: currentHyperlinkIndex,
162
+ textBoxAnchors
163
+ });
138
164
  if (linkNodes.length === 0) {
139
165
  emptyHyperlinks ??= [];
140
166
  emptyHyperlinks.push({
@@ -148,7 +174,7 @@ function convertParagraph(paragraph, styleResolver, activeCommentIds, extraRunFo
148
174
  }
149
175
  emitInlineNodes(linkNodes);
150
176
  } else if (content.type === "simpleField" || content.type === "complexField") emitInlineNode(convertField(content, getInheritedRunFormatting, styleResolver));
151
- else if (content.type === "inlineSdt") emitInlineNode(convertInlineSdt(content, getInheritedRunFormatting, styleResolver));
177
+ else if (content.type === "inlineSdt") emitInlineNode(convertInlineSdt(content, getInheritedRunFormatting, styleResolver, textBoxAnchors));
152
178
  else if (content.type === "insertion" || content.type === "moveTo") emitTrackedChange(content, "insertion", content.type === "moveTo" ? "moveTo" : null);
153
179
  else if (content.type === "deletion" || content.type === "moveFrom") emitTrackedChange(content, "deletion", content.type === "moveFrom" ? "moveFrom" : null);
154
180
  else if (content.type === "mathEquation") emitInlineNode(convertMathEquation(content));
@@ -164,6 +190,15 @@ function convertParagraph(paragraph, styleResolver, activeCommentIds, extraRunFo
164
190
  if (emptyHyperlinks) attrs._emptyHyperlinks = emptyHyperlinks;
165
191
  return schema.node("paragraph", attrs, inlineNodes);
166
192
  }
193
+ const resolveParagraphStyleFontFamily = (styleId, styleResolver) => {
194
+ let style = styleId ? styleResolver.getStyle(styleId) : styleResolver.getDefaultParagraphStyle();
195
+ const visited = /* @__PURE__ */ new Set();
196
+ while (style?.type === "paragraph" && !visited.has(style.styleId)) {
197
+ visited.add(style.styleId);
198
+ if (style.rPr?.fontFamily) return style.rPr.fontFamily;
199
+ style = style.basedOn ? styleResolver.getStyle(style.basedOn) : void 0;
200
+ }
201
+ };
167
202
  /**
168
203
  * Apply comment marks to PM nodes within a comment range.
169
204
  * Only the first active comment ID is used (comments don't overlap visually).
@@ -191,14 +226,19 @@ function anchorPointComment(nodes, commentId) {
191
226
  * Convert tracked change (insertion or deletion) content to PM nodes with
192
227
  * an insertion/deletion mark applied.
193
228
  */
194
- function convertTrackedChange(change, markType, getInheritedRunFormatting, styleResolver, moveKind = null) {
229
+ function convertTrackedChange(change, markType, getInheritedRunFormatting, styleResolver, moveKind = null, textBoxAnchors) {
195
230
  const nodes = [];
196
231
  let hyperlinkIndex = 0;
197
- for (const item of change.content) if (item.type === "run") nodes.push(...convertRun(item, getInheritedRunFormatting(item.formatting), styleResolver));
232
+ for (const item of change.content) if (item.type === "run") nodes.push(...convertRun(item, getInheritedRunFormatting(item.formatting), styleResolver, textBoxAnchors));
198
233
  else {
199
234
  const currentHyperlinkIndex = hyperlinkIndex;
200
235
  hyperlinkIndex += 1;
201
- nodes.push(...convertHyperlink(item, getInheritedRunFormatting, styleResolver, currentHyperlinkIndex));
236
+ nodes.push(...convertHyperlink(item, {
237
+ getInheritedRunFormatting,
238
+ styleResolver,
239
+ hyperlinkIndex: currentHyperlinkIndex,
240
+ textBoxAnchors
241
+ }));
202
242
  }
203
243
  const mark = schema.marks[markType].create({
204
244
  revisionId: change.info.id,
@@ -212,7 +252,7 @@ function convertTrackedChange(change, markType, getInheritedRunFormatting, style
212
252
  });
213
253
  }
214
254
  function canCarryTrackedRunMark(node, markType) {
215
- return node.isText || node.isInline && node.type.allowsMarkType(markType) && (node.type.name === "image" || node.type.name === "shape" || node.type.name === "hardBreak" || node.type.name === "tab");
255
+ return node.isText || node.isInline && node.type.allowsMarkType(markType) && (node.type.name === "image" || node.type.name === "shape" || node.type.name === "hardBreak" || node.type.name === "tab" || node.type.name === "textBoxAnchor");
216
256
  }
217
257
  /**
218
258
  * Convert ParagraphFormatting to ProseMirror paragraph attrs
@@ -263,9 +303,14 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
263
303
  set("spaceAfter", formatting?.spaceAfter ?? stylePpr?.spaceAfter);
264
304
  set("lineSpacing", formatting?.lineSpacing ?? stylePpr?.lineSpacing);
265
305
  set("lineSpacingRule", formatting?.lineSpacingRule ?? stylePpr?.lineSpacingRule);
306
+ set("snapToGrid", formatting?.snapToGrid ?? stylePpr?.snapToGrid);
266
307
  set("spacingExplicit", formatting?.spacingExplicit);
267
308
  const paragraphStyle = styleId ? styleResolver.getStyle(styleId) ?? styleResolver.getDefaultParagraphStyle() : styleResolver.getDefaultParagraphStyle();
268
309
  const docDefaultSpacing = styleResolver.getDocDefaults()?.pPr;
310
+ const spacingFromImplicitDefaultStyle = {};
311
+ if (!styleId && formatting?.spaceBefore === void 0 && paragraphStyle?.pPr?.spaceBefore !== void 0) spacingFromImplicitDefaultStyle.before = true;
312
+ if (!styleId && formatting?.spaceAfter === void 0 && paragraphStyle?.pPr?.spaceAfter !== void 0) spacingFromImplicitDefaultStyle.after = true;
313
+ if (spacingFromImplicitDefaultStyle.before || spacingFromImplicitDefaultStyle.after) attrs.spacingFromImplicitDefaultStyle = spacingFromImplicitDefaultStyle;
269
314
  const spacingFromDocDefaults = {};
270
315
  if (formatting?.spaceBefore === void 0 && tableParagraphOverlay?.spaceBefore === void 0 && paragraphStyle?.pPr?.spaceBefore === void 0 && docDefaultSpacing?.spaceBefore !== void 0) spacingFromDocDefaults.before = true;
271
316
  if (formatting?.spaceAfter === void 0 && tableParagraphOverlay?.spaceAfter === void 0 && paragraphStyle?.pPr?.spaceAfter === void 0 && docDefaultSpacing?.spaceAfter !== void 0) spacingFromDocDefaults.after = true;
@@ -289,7 +334,7 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
289
334
  set("runInWithNext", formatting?.runInWithNext ?? stylePpr?.runInWithNext);
290
335
  set("outlineLevel", formatting?.outlineLevel ?? stylePpr?.outlineLevel);
291
336
  set("direction", directionFromBidi(formatting?.bidi ?? stylePpr?.bidi));
292
- set("defaultTextFormatting", resolveParagraphDefaultTextFormatting(styleId, formatting, styleResolver, { includeParagraphMarkRunProperties: !TOC_STYLE_ID.test(styleId ?? "") }));
337
+ set("defaultTextFormatting", resolveParagraphDefaultTextFormatting(styleId, formatting, styleResolver, { includeParagraphMarkRunProperties: !isTocStyleId(styleId) }));
293
338
  if (!formatting?.numPr && stylePpr?.numPr && stylePpr.numPr.numId !== 0) {
294
339
  attrs.numPr = stylePpr.numPr;
295
340
  attrs.numPrFromStyle = stylePpr.numPr;
@@ -300,6 +345,7 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
300
345
  set("spaceAfter", formatting?.spaceAfter);
301
346
  set("lineSpacing", formatting?.lineSpacing);
302
347
  set("lineSpacingRule", formatting?.lineSpacingRule);
348
+ set("snapToGrid", formatting?.snapToGrid);
303
349
  set("spacingExplicit", formatting?.spacingExplicit);
304
350
  set("indentLeft", formatting?.indentLeft);
305
351
  set("indentRight", formatting?.indentRight);
@@ -361,7 +407,7 @@ function resolveTableStyleConditional(styleResolver, tableStyleId, conditionType
361
407
  if (!style?.tblStylePr) return;
362
408
  const conditional = style.tblStylePr.find((p) => p.type === conditionType);
363
409
  if (!conditional) return;
364
- const mergedRunProps = mergeTextFormatting(conditional.pPr?.runProperties ? resolveTextFormatting(conditional.pPr.runProperties, styleResolver) : void 0, conditional.rPr ? resolveTextFormatting(conditional.rPr, styleResolver) : void 0);
410
+ const mergedRunProps = mergeTextFormatting(conditional.pPr?.runProperties ? resolveRunFormattingWithoutDefaults(conditional.pPr.runProperties, styleResolver) : void 0, conditional.rPr ? resolveRunFormattingWithoutDefaults(conditional.rPr, styleResolver) : void 0);
365
411
  const paragraphSpacingOverlay = extractTableParagraphSpacingOverlay(conditional.pPr);
366
412
  const result = {};
367
413
  if (conditional.tcPr) result.tcPr = conditional.tcPr;
@@ -373,7 +419,7 @@ function resolveTableBaseStyle(styleResolver, tableStyleId) {
373
419
  if (!styleResolver || !tableStyleId) return;
374
420
  const style = styleResolver.getStyle(tableStyleId);
375
421
  if (!style) return;
376
- const mergedRunProps = mergeTextFormatting(style.pPr?.runProperties ? resolveTextFormatting(style.pPr.runProperties, styleResolver) : void 0, style.rPr ? resolveTextFormatting(style.rPr, styleResolver) : void 0);
422
+ const mergedRunProps = mergeTextFormatting(style.pPr?.runProperties ? resolveRunFormattingWithoutDefaults(style.pPr.runProperties, styleResolver) : void 0, style.rPr ? resolveRunFormattingWithoutDefaults(style.rPr, styleResolver) : void 0);
377
423
  const paragraphSpacingOverlay = extractTableParagraphSpacingOverlay(style.pPr);
378
424
  const result = {};
379
425
  if (style.tcPr) result.tcPr = style.tcPr;
@@ -415,7 +461,12 @@ function mergeConditionalStyles(base, override) {
415
461
  }
416
462
  function hasDirectRunFormatting(formatting) {
417
463
  if (!formatting) return false;
418
- return Object.entries(formatting).some(([key, value]) => key !== "styleId" && value !== void 0);
464
+ for (const key in formatting) {
465
+ if (!Object.hasOwn(formatting, key)) continue;
466
+ const value = Reflect.get(formatting, key);
467
+ if (key !== "styleId" && value !== void 0) return true;
468
+ }
469
+ return false;
419
470
  }
420
471
  function stripParagraphMarkOnlyFormatting(formatting) {
421
472
  const { allCaps: _ac, highlight: _h, shading: _s, smallCaps: _sc, vertAlign: _va, ...rest } = formatting;
@@ -457,7 +508,12 @@ function resolveTextFormatting(formatting, styleResolver) {
457
508
  if (!styleResolver) return formatting;
458
509
  return mergeTextFormatting(styleResolver.resolveRunStyle(formatting.styleId), formatting);
459
510
  }
460
- function resolveParagraphMarkRunFormatting(formatting, styleResolver) {
511
+ /**
512
+ * Resolve an embedded character-style reference without importing
513
+ * `docDefaults`. The caller already has the paragraph cascade, including
514
+ * document defaults, and will layer these own properties over it.
515
+ */
516
+ function resolveRunFormattingWithoutDefaults(formatting, styleResolver) {
461
517
  if (!formatting || !styleResolver) return formatting;
462
518
  return mergeTextFormatting(formatting.styleId ? styleResolver.getRunStyleOwnProperties(formatting.styleId) : void 0, formatting);
463
519
  }
@@ -465,7 +521,7 @@ function resolveParagraphDefaultTextFormatting(styleId, formatting, styleResolve
465
521
  const style = styleId ? styleResolver.getStyle(styleId) ?? styleResolver.getDefaultParagraphStyle() : styleResolver.getDefaultParagraphStyle();
466
522
  const paragraphStyleRpr = style?.type === "paragraph" ? style.rPr : void 0;
467
523
  const rawParagraphMarkRpr = options.includeParagraphMarkRunProperties === false ? void 0 : formatting?.runProperties;
468
- const paragraphRunProperties = rawParagraphMarkRpr ? stripParagraphMarkOnlyFormatting(resolveParagraphMarkRunFormatting(rawParagraphMarkRpr, styleResolver) ?? {}) : void 0;
524
+ const paragraphRunProperties = rawParagraphMarkRpr ? stripParagraphMarkOnlyFormatting(resolveRunFormattingWithoutDefaults(rawParagraphMarkRpr, styleResolver) ?? {}) : void 0;
469
525
  const bodyRunDefaults = mergeTextFormatting(mergeTextFormatting(styleResolver.getDocDefaults()?.rPr, styleResolver.getDefaultCharacterStyle()?.rPr), paragraphStyleRpr);
470
526
  return styleId === void 0 ? mergeTextFormatting(bodyRunDefaults, paragraphRunProperties) : mergeTextFormatting(paragraphRunProperties, bodyRunDefaults);
471
527
  }
@@ -650,12 +706,29 @@ function countTableColumns(rows) {
650
706
  * Convert a TableRow to a ProseMirror table row node
651
707
  */
652
708
  function convertTableRow(row, styleResolver, context, isHeaderRow, columnWidths, totalWidth, conditionalStyles, rowBandStyle, bandingEnabledV, tableLook, tableBorders, rowIndex, totalRows, totalColumns, rowSpanMap, defaultCellMargins) {
653
- const attrs = { isHeader: !!row.formatting?.header };
654
- if (row.formatting?.height?.value !== void 0) attrs.height = row.formatting.height.value;
655
- if (row.formatting?.heightRule) attrs.heightRule = row.formatting.heightRule;
656
- if (row.formatting?.hidden) attrs.hidden = true;
657
- if (row.formatting) attrs._originalFormatting = row.formatting;
658
- if (row.propertyChanges && row.propertyChanges.length > 0) attrs.trPrChange = [...row.propertyChanges];
709
+ const attrsWithoutStructuralChange = { isHeader: !!row.formatting?.header };
710
+ if (row.formatting?.height?.value !== void 0) attrsWithoutStructuralChange.height = row.formatting.height.value;
711
+ if (row.formatting?.heightRule) attrsWithoutStructuralChange.heightRule = row.formatting.heightRule;
712
+ if (row.formatting?.hidden) attrsWithoutStructuralChange.hidden = true;
713
+ if (row.formatting) attrsWithoutStructuralChange._originalFormatting = row.formatting;
714
+ if (row.propertyChanges && row.propertyChanges.length > 0) attrsWithoutStructuralChange.trPrChange = [...row.propertyChanges];
715
+ let attrs = attrsWithoutStructuralChange;
716
+ if (row.structuralChange?.type === "tableRowInsertion") attrs = {
717
+ ...attrsWithoutStructuralChange,
718
+ trIns: {
719
+ revisionId: row.structuralChange.info.id,
720
+ author: row.structuralChange.info.author,
721
+ date: row.structuralChange.info.date ?? null
722
+ }
723
+ };
724
+ else if (row.structuralChange?.type === "tableRowDeletion") attrs = {
725
+ ...attrsWithoutStructuralChange,
726
+ trDel: {
727
+ revisionId: row.structuralChange.info.id,
728
+ author: row.structuralChange.info.author,
729
+ date: row.structuralChange.info.date ?? null
730
+ }
731
+ };
659
732
  const numCells = row.cells.length;
660
733
  const isFirstRow = rowIndex === 0;
661
734
  const isLastRow = rowIndex === (totalRows ?? 1) - 1;
@@ -776,15 +849,44 @@ function convertTableCell({ cell, styleResolver, context, isHeader, gridWidthPer
776
849
  }
777
850
  if (formatting?.textDirection) attrs.textDirection = formatting.textDirection;
778
851
  if (formatting?.noWrap !== void 0) attrs.noWrap = formatting.noWrap;
852
+ const hideMark = formatting?.hideMark ?? conditionalStyle?.tcPr?.hideMark;
853
+ if (hideMark !== void 0) attrs.hideMark = hideMark;
779
854
  if (effectiveFormatting.borders) attrs.borders = effectiveFormatting.borders;
780
855
  if (effectiveFormatting.margins) attrs.margins = effectiveFormatting.margins;
781
856
  if (formatting) attrs._originalFormatting = formatting;
782
857
  if (cell.propertyChanges && cell.propertyChanges.length > 0) attrs.tcPrChange = [...cell.propertyChanges];
858
+ if (cell.structuralChange?.type === "tableCellInsertion") attrs.cellMarker = {
859
+ kind: "ins",
860
+ info: {
861
+ revisionId: cell.structuralChange.info.id,
862
+ author: cell.structuralChange.info.author,
863
+ date: cell.structuralChange.info.date ?? null
864
+ }
865
+ };
866
+ else if (cell.structuralChange?.type === "tableCellDeletion") attrs.cellMarker = {
867
+ kind: "del",
868
+ info: {
869
+ revisionId: cell.structuralChange.info.id,
870
+ author: cell.structuralChange.info.author,
871
+ date: cell.structuralChange.info.date ?? null
872
+ }
873
+ };
874
+ else if (cell.structuralChange?.type === "tableCellMerge") attrs.cellMarker = {
875
+ kind: "merge",
876
+ info: {
877
+ revisionId: cell.structuralChange.info.id,
878
+ author: cell.structuralChange.info.author,
879
+ date: cell.structuralChange.info.date ?? null
880
+ },
881
+ ...cell.structuralChange.verticalMerge !== void 0 ? { verticalMerge: cell.structuralChange.verticalMerge } : {},
882
+ ...cell.structuralChange.verticalMergeOriginal !== void 0 ? { verticalMergeOriginal: cell.structuralChange.verticalMergeOriginal } : {}
883
+ };
783
884
  if (preserveVMergeRestart) attrs._preserveVMergeRestart = true;
784
885
  if (vMergeContinuationCells && vMergeContinuationCells.length > 0) attrs._docxVMergeContinuationCells = vMergeContinuationCells;
785
886
  const contentNodes = [];
786
887
  for (const content of cell.content) if (content.type === "paragraph") contentNodes.push(...convertParagraphWithTextBoxes(content, styleResolver, {
787
888
  textBoxGroupId: context.nextTextBoxGroupId(),
889
+ context,
788
890
  ...conditionalStyle?.rPr !== void 0 ? { extraRunFormatting: conditionalStyle.rPr } : {},
789
891
  ...conditionalStyle?.pPr !== void 0 ? { tableParagraphOverlay: conditionalStyle.pPr } : {}
790
892
  }));
@@ -793,6 +895,27 @@ function convertTableCell({ cell, styleResolver, context, isHeader, gridWidthPer
793
895
  const nodeType = isHeader ? "tableHeader" : "tableCell";
794
896
  return schema.node(nodeType, attrs, contentNodes);
795
897
  }
898
+ function standaloneTableCellToProseMirror(cell, nodeType) {
899
+ let textBoxGroupIndex = 0;
900
+ const nextTextBoxGroupId = () => String(textBoxGroupIndex++);
901
+ return convertTableCell({
902
+ cell,
903
+ styleResolver: null,
904
+ context: {
905
+ theme: null,
906
+ nextTextBoxGroupId
907
+ },
908
+ isHeader: nodeType === "tableHeader",
909
+ gridWidthPercent: void 0,
910
+ conditionalStyle: void 0,
911
+ tableBorders: void 0,
912
+ position: {},
913
+ calculatedRowSpan: 1,
914
+ preserveVMergeRestart: void 0,
915
+ vMergeContinuationCells: void 0,
916
+ defaultCellMargins: void 0
917
+ });
918
+ }
796
919
  /**
797
920
  * Convert a SimpleField or ComplexField to a ProseMirror field node.
798
921
  * Preserves run formatting (bold, fontSize, color, etc.) as PM marks.
@@ -832,46 +955,38 @@ function convertMathEquation(math) {
832
955
  /**
833
956
  * Convert an InlineSdt to a ProseMirror sdt node with inline content.
834
957
  */
835
- function convertInlineSdt(sdt, getInheritedRunFormatting, styleResolver) {
958
+ function convertInlineSdt(sdt, getInheritedRunFormatting, styleResolver, textBoxAnchors) {
836
959
  const props = sdt.properties;
837
960
  const inlineNodes = [];
838
961
  let hyperlinkIndex = 0;
839
962
  for (const content of sdt.content) if (content.type === "run") {
840
- const runNodes = convertRun(content, getInheritedRunFormatting(content.formatting), styleResolver);
963
+ const runNodes = convertRun(content, getInheritedRunFormatting(content.formatting), styleResolver, textBoxAnchors);
841
964
  inlineNodes.push(...runNodes);
842
965
  } else if (content.type === "hyperlink") {
843
966
  const currentHyperlinkIndex = hyperlinkIndex;
844
967
  hyperlinkIndex += 1;
845
- const linkNodes = convertHyperlink(content, getInheritedRunFormatting, styleResolver, currentHyperlinkIndex);
968
+ const linkNodes = convertHyperlink(content, {
969
+ getInheritedRunFormatting,
970
+ styleResolver,
971
+ hyperlinkIndex: currentHyperlinkIndex,
972
+ textBoxAnchors
973
+ });
846
974
  inlineNodes.push(...linkNodes);
847
975
  } else if (content.type === "simpleField" || content.type === "complexField") {
848
976
  const fieldNode = convertField(content, getInheritedRunFormatting, styleResolver);
849
977
  if (fieldNode) inlineNodes.push(fieldNode);
850
978
  } else if (content.type === "inlineSdt") {
851
- const nestedSdt = convertInlineSdt(content, getInheritedRunFormatting, styleResolver);
979
+ const nestedSdt = convertInlineSdt(content, getInheritedRunFormatting, styleResolver, textBoxAnchors);
852
980
  if (nestedSdt) inlineNodes.push(nestedSdt);
853
- } else if (content.type === "insertion") inlineNodes.push(...convertTrackedChange(content, "insertion", getInheritedRunFormatting, styleResolver));
854
- else if (content.type === "deletion") inlineNodes.push(...convertTrackedChange(content, "deletion", getInheritedRunFormatting, styleResolver));
981
+ } else if (content.type === "insertion") inlineNodes.push(...convertTrackedChange(content, "insertion", getInheritedRunFormatting, styleResolver, null, textBoxAnchors));
982
+ else if (content.type === "deletion") inlineNodes.push(...convertTrackedChange(content, "deletion", getInheritedRunFormatting, styleResolver, null, textBoxAnchors));
983
+ else if (content.type === "moveTo") inlineNodes.push(...convertTrackedChange(content, "insertion", getInheritedRunFormatting, styleResolver, "moveTo", textBoxAnchors));
984
+ else if (content.type === "moveFrom") inlineNodes.push(...convertTrackedChange(content, "deletion", getInheritedRunFormatting, styleResolver, "moveFrom", textBoxAnchors));
855
985
  else {
856
986
  const mathNode = convertMathEquation(content);
857
987
  if (mathNode) inlineNodes.push(mathNode);
858
988
  }
859
- return schema.node("sdt", {
860
- sdtType: props.sdtType,
861
- alias: props.alias ?? null,
862
- tag: props.tag ?? null,
863
- id: props.id ?? null,
864
- lock: props.lock ?? null,
865
- placeholder: props.placeholder ?? null,
866
- showingPlaceholder: props.showingPlaceholder ?? false,
867
- dateFormat: props.dateFormat ?? null,
868
- dateValueISO: props.dateValueISO ?? null,
869
- listItems: props.listItems ? JSON.stringify(props.listItems) : null,
870
- dropdownLastValue: props.dropdownLastValue ?? null,
871
- checked: props.checked ?? null,
872
- rawPropertiesXml: props.rawPropertiesXml ?? null,
873
- rawEndPropertiesXml: props.rawEndPropertiesXml ?? null
874
- }, inlineNodes.length > 0 ? inlineNodes : void 0);
989
+ return schema.node("sdt", sdtAttrsFromProperties(props), inlineNodes.length > 0 ? inlineNodes : void 0);
875
990
  }
876
991
  /**
877
992
  * Convert a Run to ProseMirror text nodes with marks
@@ -879,11 +994,12 @@ function convertInlineSdt(sdt, getInheritedRunFormatting, styleResolver) {
879
994
  * @param run - The run to convert
880
995
  * @param styleFormatting - Text formatting from the paragraph's style (e.g., Heading1's font size/color)
881
996
  */
882
- function convertRun(run, styleFormatting, styleResolver) {
997
+ function convertRun(run, styleFormatting, styleResolver, textBoxAnchors) {
883
998
  const nodes = [];
884
999
  const { marks, mergedFormatting } = buildRunMarks(run.formatting, styleFormatting, styleResolver);
1000
+ if (run.propertyChanges && run.propertyChanges.length > 0) marks.push(schema.mark("runPropertyChange", { changes: [...run.propertyChanges] }));
885
1001
  for (const content of run.content) {
886
- const contentNodes = convertRunContent(content, marks, mergedFormatting);
1002
+ const contentNodes = convertRunContent(content, marks, mergedFormatting, textBoxAnchors);
887
1003
  nodes.push(...contentNodes);
888
1004
  }
889
1005
  return nodes;
@@ -908,7 +1024,7 @@ function buildRunMarks(runFormatting, inheritedFormatting, styleResolver) {
908
1024
  /**
909
1025
  * Convert RunContent to ProseMirror nodes
910
1026
  */
911
- function convertRunContent(content, marks, formatting) {
1027
+ function convertRunContent(content, marks, formatting, textBoxAnchors) {
912
1028
  switch (content.type) {
913
1029
  case "text":
914
1030
  if (content.text) return [schema.text(content.text, marks)];
@@ -917,11 +1033,15 @@ function convertRunContent(content, marks, formatting) {
917
1033
  if (content.breakType === "textWrapping" || !content.breakType) return [withHyperlinkBoundaryMarks(schema.node("hardBreak"), marks)];
918
1034
  if (content.breakType === "column") return [withHyperlinkBoundaryMarks(schema.node("hardBreak", { breakType: "column" }), marks)];
919
1035
  return [];
1036
+ case "renderedPageBreak": return [schema.node("renderedPageBreak").mark(marks)];
920
1037
  case "tab": return [schema.node("tab").mark(marks)];
921
1038
  case "drawing": return [withHyperlinkBoundaryMarks(convertImage(content.image, content.rawXml), marks)];
922
1039
  case "shape": {
923
1040
  const shp = content.shape;
924
- if (shp.textBody) return [];
1041
+ if (shp.textBody) {
1042
+ const anchorId = textBoxAnchors?.get(shp);
1043
+ return anchorId ? [schema.node("textBoxAnchor", { anchorId }).mark(marks)] : [];
1044
+ }
925
1045
  return [withHyperlinkBoundaryMarks(convertShape(shp), marks)];
926
1046
  }
927
1047
  case "footnoteRef": {
@@ -1053,13 +1173,7 @@ function convertImage(image, rawXml) {
1053
1173
  _docxObjectPreview: rawXml !== void 0 && /<(?:[A-Za-z_][\w.-]*:)?object(?:\s|>)/u.test(rawXml)
1054
1174
  });
1055
1175
  }
1056
- /**
1057
- * Convert a Hyperlink to ProseMirror nodes with link mark
1058
- *
1059
- * @param hyperlink - The hyperlink to convert
1060
- * @param getInheritedRunFormatting - Formatting inherited by each child run
1061
- */
1062
- function convertHyperlink(hyperlink, getInheritedRunFormatting, styleResolver, hyperlinkIndex) {
1176
+ function convertHyperlink(hyperlink, { getInheritedRunFormatting, styleResolver, hyperlinkIndex, textBoxAnchors }) {
1063
1177
  const nodes = [];
1064
1178
  const href = hyperlink.href || (hyperlink.anchor ? `#${hyperlink.anchor}` : "");
1065
1179
  const linkMark = schema.mark("hyperlink", {
@@ -1072,7 +1186,7 @@ function convertHyperlink(hyperlink, getInheritedRunFormatting, styleResolver, h
1072
1186
  const inheritedFormatting = getInheritedRunFormatting(child.formatting);
1073
1187
  const { marks: runMarks, mergedFormatting } = buildRunMarks(child.formatting, inheritedFormatting, styleResolver);
1074
1188
  const allMarks = [...runMarks, linkMark];
1075
- for (const content of child.content) nodes.push(...convertRunContent(content, allMarks, mergedFormatting));
1189
+ for (const content of child.content) nodes.push(...convertRunContent(content, allMarks, mergedFormatting, textBoxAnchors));
1076
1190
  }
1077
1191
  return nodes;
1078
1192
  }
@@ -1230,57 +1344,159 @@ function convertShape(shape) {
1230
1344
  position
1231
1345
  });
1232
1346
  }
1233
- function convertParagraphWithTextBoxes(block, styleResolver, { textBoxGroupId, extraRunFormatting, tableParagraphOverlay }) {
1234
- const textBoxes = extractTextBoxesFromParagraph(block);
1235
- const pmParagraph = convertParagraph(block, styleResolver, void 0, extraRunFormatting, tableParagraphOverlay);
1347
+ function convertParagraphWithTextBoxes(block, styleResolver, { textBoxGroupId, context, extraRunFormatting, tableParagraphOverlay }) {
1348
+ const { textBoxes, textBoxAnchors } = extractTextBoxesFromParagraph(block, textBoxGroupId);
1349
+ const pmParagraph = convertParagraph(block, styleResolver, void 0, extraRunFormatting, tableParagraphOverlay, textBoxAnchors);
1236
1350
  const nodes = [];
1237
- const isEmptyAfterExtraction = textBoxes.length > 0 && pmParagraph.content.size === 0;
1351
+ const isEmptyAfterExtraction = textBoxes.length > 0 && !hasContentBesidesTextBoxAnchors(pmParagraph);
1238
1352
  const keepWrapperParagraph = isEmptyAfterExtraction && hasParagraphBoundaryPayload(block, pmParagraph);
1239
1353
  if (!isEmptyAfterExtraction || keepWrapperParagraph) nodes.push(pmParagraph);
1240
- for (const tb of textBoxes) nodes.push(convertTextBox(tb, styleResolver, {
1354
+ for (const { textBox, anchorId, trackedChange, inlineSdts } of textBoxes) nodes.push(convertTextBox(textBox, styleResolver, {
1241
1355
  placement: isEmptyAfterExtraction && !keepWrapperParagraph ? "standalone" : "inlineWithPrevious",
1242
- groupId: textBoxGroupId
1356
+ groupId: textBoxGroupId,
1357
+ anchorId,
1358
+ context,
1359
+ trackedChange,
1360
+ inlineSdts
1243
1361
  }));
1244
1362
  return nodes;
1245
1363
  }
1364
+ function hasContentBesidesTextBoxAnchors(paragraph) {
1365
+ let hasContent = false;
1366
+ paragraph.descendants((node) => {
1367
+ if (node.type.name === "textBoxAnchor") return false;
1368
+ if (node.type.name === "sdt") {
1369
+ if (node.childCount === 0) hasContent = true;
1370
+ return !hasContent;
1371
+ }
1372
+ hasContent = true;
1373
+ return false;
1374
+ });
1375
+ return hasContent;
1376
+ }
1246
1377
  function hasParagraphBoundaryPayload(block, pmParagraph) {
1247
1378
  const bookmarks = pmParagraph.attrs["bookmarks"];
1248
1379
  const emptyHyperlinks = pmParagraph.attrs["_emptyHyperlinks"];
1249
1380
  return Boolean(block.sectionProperties || block.propertyChanges?.length || Array.isArray(bookmarks) && bookmarks.length > 0 || Array.isArray(emptyHyperlinks) && emptyHyperlinks.length > 0);
1250
1381
  }
1251
- /**
1252
- * Extract text boxes from paragraph runs.
1253
- * Text boxes appear as ShapeContent where the shape has textBody,
1254
- * or as DrawingContent that contains a text box instead of an image.
1255
- */
1256
- function extractTextBoxesFromParagraph(paragraph) {
1382
+ const NO_EXTRACTED_TEXT_BOXES = {
1383
+ textBoxes: [],
1384
+ textBoxAnchors: /* @__PURE__ */ new Map()
1385
+ };
1386
+ function extractTextBoxesFromParagraph(paragraph, textBoxGroupId) {
1387
+ if (!mayContainTextBox(paragraph)) return NO_EXTRACTED_TEXT_BOXES;
1388
+ return extractTextBoxes(paragraph, textBoxGroupId);
1389
+ }
1390
+ function mayContainTextBox(paragraph) {
1391
+ for (const item of paragraph.content) {
1392
+ if (item.type !== "run") {
1393
+ if (item.type === "inlineSdt" || item.type === "hyperlink" || item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") return true;
1394
+ continue;
1395
+ }
1396
+ for (const content of item.content) if (content.type === "shape" && content.shape.textBody) return true;
1397
+ }
1398
+ return false;
1399
+ }
1400
+ function extractTextBoxes(paragraph, textBoxGroupId) {
1257
1401
  const textBoxes = [];
1258
- for (const content of paragraph.content) if (content.type === "run") {
1259
- for (const rc of content.content) if (rc.type === "shape") {
1260
- const shape = rc.shape;
1261
- if (shape.textBody) {
1262
- const textBox = {
1263
- type: "textBox",
1264
- size: shape.size,
1265
- content: shape.textBody.content
1266
- };
1267
- if (shape.id) textBox.id = shape.id;
1268
- if (shape.position) textBox.position = shape.position;
1269
- if (shape.wrap) textBox.wrap = shape.wrap;
1270
- if (shape.fill) textBox.fill = shape.fill;
1271
- if (shape.outline) textBox.outline = shape.outline;
1272
- if (shape.textBody.margins) textBox.margins = shape.textBody.margins;
1273
- if (shape.textBody.autoFit) textBox.autoFit = shape.textBody.autoFit;
1274
- textBoxes.push(textBox);
1402
+ const textBoxAnchors = /* @__PURE__ */ new Map();
1403
+ const visitRun = (run, context) => {
1404
+ for (const runContent of run.content) {
1405
+ if (runContent.type !== "shape" || !runContent.shape.textBody) continue;
1406
+ const anchorId = `${textBoxGroupId}:${textBoxes.length}`;
1407
+ textBoxAnchors.set(runContent.shape, anchorId);
1408
+ textBoxes.push({
1409
+ textBox: textBoxFromShape(runContent.shape, runContent.shape.textBody),
1410
+ anchorId,
1411
+ trackedChange: context.trackedChange,
1412
+ inlineSdts: context.inlineSdts
1413
+ });
1414
+ }
1415
+ };
1416
+ const visitHyperlink = (hyperlink, context) => {
1417
+ for (const child of hyperlink.children) if (child.type === "run") visitRun(child, context);
1418
+ };
1419
+ const visitTrackedChange = (change, context) => {
1420
+ const trackedChange = {
1421
+ type: change.type,
1422
+ info: change.info
1423
+ };
1424
+ for (const item of change.content) {
1425
+ if (item.type === "run") {
1426
+ visitRun(item, {
1427
+ ...context,
1428
+ trackedChange
1429
+ });
1430
+ continue;
1275
1431
  }
1432
+ visitHyperlink(item, {
1433
+ ...context,
1434
+ trackedChange
1435
+ });
1276
1436
  }
1437
+ };
1438
+ const visitInlineSdt = (sdt, context) => {
1439
+ const inlineSdts = [...context.inlineSdts, sdtAttrsFromProperties(sdt.properties)];
1440
+ const nestedContext = {
1441
+ ...context,
1442
+ inlineSdts
1443
+ };
1444
+ for (const item of sdt.content) {
1445
+ if (item.type === "run") {
1446
+ visitRun(item, nestedContext);
1447
+ continue;
1448
+ }
1449
+ if (item.type === "inlineSdt") {
1450
+ visitInlineSdt(item, nestedContext);
1451
+ continue;
1452
+ }
1453
+ if (item.type === "hyperlink") {
1454
+ visitHyperlink(item, nestedContext);
1455
+ continue;
1456
+ }
1457
+ if (item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") visitTrackedChange(item, nestedContext);
1458
+ }
1459
+ };
1460
+ const rootContext = { inlineSdts: [] };
1461
+ for (const item of paragraph.content) {
1462
+ if (item.type === "run") {
1463
+ visitRun(item, rootContext);
1464
+ continue;
1465
+ }
1466
+ if (item.type === "inlineSdt") {
1467
+ visitInlineSdt(item, rootContext);
1468
+ continue;
1469
+ }
1470
+ if (item.type === "hyperlink") {
1471
+ visitHyperlink(item, rootContext);
1472
+ continue;
1473
+ }
1474
+ if (item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") visitTrackedChange(item, rootContext);
1277
1475
  }
1278
- return textBoxes;
1476
+ return {
1477
+ textBoxes,
1478
+ textBoxAnchors
1479
+ };
1480
+ }
1481
+ function textBoxFromShape(shape, textBody) {
1482
+ const textBox = {
1483
+ type: "textBox",
1484
+ size: shape.size,
1485
+ content: textBody.content
1486
+ };
1487
+ if (shape.id) textBox.id = shape.id;
1488
+ if (shape.position) textBox.position = shape.position;
1489
+ if (shape.wrap) textBox.wrap = shape.wrap;
1490
+ if (shape.fill) textBox.fill = shape.fill;
1491
+ if (shape.outline) textBox.outline = shape.outline;
1492
+ if (textBody.margins) textBox.margins = textBody.margins;
1493
+ if (textBody.autoFit) textBox.autoFit = textBody.autoFit;
1494
+ return textBox;
1279
1495
  }
1280
1496
  /**
1281
1497
  * Convert a TextBox to a ProseMirror textBox node
1282
1498
  */
1283
- function convertTextBox(textBox, styleResolver, options = {}) {
1499
+ function convertTextBox(textBox, styleResolver, options) {
1284
1500
  const textBoxSize = textBox.size;
1285
1501
  const widthPx = textBoxSize?.width ? emuToPixels(textBoxSize.width) : 200;
1286
1502
  const heightPx = textBoxSize?.height ? emuToPixels(textBoxSize.height) : void 0;
@@ -1299,7 +1515,16 @@ function convertTextBox(textBox, styleResolver, options = {}) {
1299
1515
  const marginLeft = textBox.margins?.left !== void 0 ? emuToPixels(textBox.margins.left) : 7;
1300
1516
  const marginRight = textBox.margins?.right !== void 0 ? emuToPixels(textBox.margins.right) : 7;
1301
1517
  const contentNodes = [];
1302
- for (const para of textBox.content) contentNodes.push(convertParagraph(para, styleResolver));
1518
+ for (const block of textBox.content) {
1519
+ if (block.type === "paragraph") {
1520
+ contentNodes.push(...convertParagraphWithTextBoxes(block, styleResolver, {
1521
+ textBoxGroupId: options.context.nextTextBoxGroupId(),
1522
+ context: options.context
1523
+ }));
1524
+ continue;
1525
+ }
1526
+ contentNodes.push(convertTable(block, styleResolver, options.context));
1527
+ }
1303
1528
  if (contentNodes.length === 0) contentNodes.push(schema.node("paragraph", {}, []));
1304
1529
  const wrapType = textBox.wrap?.type;
1305
1530
  const wrapText = textBox.wrap?.wrapText;
@@ -1359,7 +1584,10 @@ function convertTextBox(textBox, styleResolver, options = {}) {
1359
1584
  distRight,
1360
1585
  position,
1361
1586
  _docxPlacement: options.placement,
1362
- _docxGroupId: options.groupId
1587
+ _docxGroupId: options.groupId,
1588
+ _docxAnchorId: options.anchorId,
1589
+ _docxTrackedChange: options.trackedChange,
1590
+ _docxInlineSdts: options.inlineSdts.length > 0 ? options.inlineSdts : void 0
1363
1591
  }, contentNodes);
1364
1592
  }
1365
1593
  /**
@@ -1378,7 +1606,13 @@ function headerFooterToProseDoc(content, options) {
1378
1606
  const nextTextBoxGroupId = () => String(textBoxGroupIndex++);
1379
1607
  const convertBlocks = (blocks) => {
1380
1608
  const out = [];
1381
- for (const block of blocks) if (block.type === "paragraph") out.push(...convertParagraphWithTextBoxes(block, styleResolver, { textBoxGroupId: nextTextBoxGroupId() }));
1609
+ for (const block of blocks) if (block.type === "paragraph") out.push(...convertParagraphWithTextBoxes(block, styleResolver, {
1610
+ textBoxGroupId: nextTextBoxGroupId(),
1611
+ context: {
1612
+ theme,
1613
+ nextTextBoxGroupId
1614
+ }
1615
+ }));
1382
1616
  else if (block.type === "table") out.push(convertTable(block, styleResolver, {
1383
1617
  theme,
1384
1618
  nextTextBoxGroupId
@@ -1414,6 +1648,21 @@ function footnoteToProseDoc(content, options) {
1414
1648
  * null — no page break found.
1415
1649
  */
1416
1650
  function paragraphPageBreakPosition(paragraph) {
1651
+ if (!mayContainPageBreak(paragraph)) return null;
1652
+ return findParagraphPageBreakPosition(paragraph);
1653
+ }
1654
+ function mayContainPageBreak(paragraph) {
1655
+ for (const item of paragraph.content) {
1656
+ if (item.type === "run") {
1657
+ for (const content of item.content) if (content.type === "break" && content.breakType === "page") return true;
1658
+ continue;
1659
+ }
1660
+ if (item.type === "hyperlink" || item.type === "simpleField" || item.type === "complexField" || item.type === "inlineSdt" || item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") return true;
1661
+ if (item.type === "bookmarkStart" || item.type === "bookmarkEnd" || item.type === "commentRangeStart" || item.type === "commentRangeEnd" || item.type === "commentReference" || item.type === "moveFromRangeStart" || item.type === "moveFromRangeEnd" || item.type === "moveToRangeStart" || item.type === "moveToRangeEnd" || item.type === "mathEquation") continue;
1662
+ }
1663
+ return false;
1664
+ }
1665
+ function findParagraphPageBreakPosition(paragraph) {
1417
1666
  const state = { seenVisibleContent: false };
1418
1667
  function isPageBreak(content) {
1419
1668
  return content.type === "break" && content.breakType === "page";
@@ -1468,4 +1717,4 @@ function createEmptyDoc() {
1468
1717
  return schema.node("doc", null, [schema.node("paragraph", {}, [])]);
1469
1718
  }
1470
1719
  //#endregion
1471
- export { createEmptyDoc, footnoteToProseDoc, headerFooterToProseDoc, textFormattingToMarks, toProseDoc };
1720
+ export { createEmptyDoc, footnoteToProseDoc, headerFooterToProseDoc, standaloneTableCellToProseMirror, textFormattingToMarks, toProseDoc };