@stll/folio-core 0.11.0 → 0.13.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 (263) hide show
  1. package/dist/ai-edits/apply.d.ts +2 -1
  2. package/dist/ai-edits/apply.js +693 -63
  3. package/dist/ai-edits/block-identity.d.ts +4 -0
  4. package/dist/ai-edits/block-identity.js +9 -0
  5. package/dist/ai-edits/blockRange.d.ts +28 -1
  6. package/dist/ai-edits/blockRange.js +68 -2
  7. package/dist/ai-edits/clean-text.js +2 -1
  8. package/dist/ai-edits/headless.d.ts +4 -4
  9. package/dist/ai-edits/headless.js +9 -9
  10. package/dist/ai-edits/index.d.ts +2 -2
  11. package/dist/ai-edits/index.js +2 -2
  12. package/dist/ai-edits/read.d.ts +7 -7
  13. package/dist/ai-edits/read.js +110 -3
  14. package/dist/ai-edits/snapshot.js +21 -3
  15. package/dist/ai-edits/table-cell-mutations.d.ts +48 -0
  16. package/dist/ai-edits/table-cell-mutations.js +238 -0
  17. package/dist/ai-edits/table-mutation-plan.d.ts +38 -0
  18. package/dist/ai-edits/table-mutation-plan.js +90 -0
  19. package/dist/ai-edits/table-row-column-mutations.d.ts +108 -0
  20. package/dist/ai-edits/table-row-column-mutations.js +300 -0
  21. package/dist/ai-edits/table-targets.d.ts +32 -0
  22. package/dist/ai-edits/table-targets.js +70 -0
  23. package/dist/ai-edits/types.d.ts +62 -1
  24. package/dist/ai-edits/word-diff.js +21 -0
  25. package/dist/compat/eigenpal.d.ts +3 -3
  26. package/dist/compat/eigenpal.js +3 -3
  27. package/dist/content-controls/mutateContentControls.js +1 -1
  28. package/dist/controller/activeEditorStory.d.ts +36 -0
  29. package/dist/controller/activeEditorStory.js +30 -0
  30. package/dist/controller/contentControlWidgetController.d.ts +55 -0
  31. package/dist/controller/contentControlWidgetController.js +141 -0
  32. package/dist/controller/fontReadiness.js +2 -0
  33. package/dist/controller/headerFooterEditorManager.js +2 -2
  34. package/dist/controller/hiddenEditorApi.js +2 -2
  35. package/dist/controller/hiddenEditorManager.d.ts +12 -1
  36. package/dist/controller/hiddenEditorManager.js +44 -12
  37. package/dist/controller/layoutPipeline.d.ts +2 -0
  38. package/dist/controller/layoutPipeline.js +17 -2
  39. package/dist/controller/noteEditorManager.d.ts +36 -0
  40. package/dist/controller/noteEditorManager.js +210 -0
  41. package/dist/document-operations.d.ts +43 -11
  42. package/dist/document-operations.js +186 -18
  43. package/dist/docx/blockContentParser.js +21 -7
  44. package/dist/docx/commentParser.js +6 -1
  45. package/dist/docx/commentRangeIntegrity.d.ts +6 -0
  46. package/dist/docx/commentRangeIntegrity.js +186 -0
  47. package/dist/docx/conformance.js +62 -1
  48. package/dist/docx/documentGrid.d.ts +8 -0
  49. package/dist/docx/documentGrid.js +8 -0
  50. package/dist/docx/drawingUtils.js +1 -1
  51. package/dist/docx/encryption/agileDecryption.js +12 -2
  52. package/dist/docx/encryption/compoundFile.js +6 -1
  53. package/dist/docx/encryption/encryptionInfo.d.ts +9 -1
  54. package/dist/docx/encryption/encryptionInfo.js +18 -2
  55. package/dist/docx/encryption/openEncryptedDocx.js +1 -1
  56. package/dist/docx/ensureParaIds.js +8 -7
  57. package/dist/docx/fieldParser.js +1 -1
  58. package/dist/docx/groupDrawingParser.js +10 -5
  59. package/dist/docx/hyperlinkParser.js +1 -1
  60. package/dist/docx/imageParser.js +10 -6
  61. package/dist/docx/metadataPrivacy.js +17 -3
  62. package/dist/docx/notePropertiesParser.js +1 -1
  63. package/dist/docx/numberingParser.js +1 -1
  64. package/dist/docx/paragraphParser.js +70 -61
  65. package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
  66. package/dist/docx/paragraphTextBoxEnrichment.js +67 -13
  67. package/dist/docx/paragraphTraversal.js +1 -1
  68. package/dist/docx/parser.js +3 -3
  69. package/dist/docx/rezip.js +20 -9
  70. package/dist/docx/runParser.js +17 -6
  71. package/dist/docx/sdtProperties.js +1 -1
  72. package/dist/docx/sectionParser.js +18 -5
  73. package/dist/docx/selectiveSave.js +5 -1
  74. package/dist/docx/selectiveXmlPatch.d.ts +22 -1
  75. package/dist/docx/selectiveXmlPatch.js +61 -1
  76. package/dist/docx/serializer/blockSdtSerializer.js +3 -2
  77. package/dist/docx/serializer/commentSerializer.js +5 -6
  78. package/dist/docx/serializer/documentSerializer.js +2 -2
  79. package/dist/docx/serializer/headerFooterSerializer.js +2 -2
  80. package/dist/docx/serializer/noteSerializer.js +2 -2
  81. package/dist/docx/serializer/paragraphSerializer.js +23 -15
  82. package/dist/docx/serializer/runSerializer.js +25 -21
  83. package/dist/docx/serializer/sectionPropertiesSerializer.js +2 -1
  84. package/dist/docx/serializer/stylesSerializer.js +1 -1
  85. package/dist/docx/serializer/tableSerializer.d.ts +5 -4
  86. package/dist/docx/serializer/tableSerializer.js +26 -20
  87. package/dist/docx/serializer/xmlUtils.d.ts +13 -1
  88. package/dist/docx/serializer/xmlUtils.js +27 -1
  89. package/dist/docx/server/applyDocxXmlPatchProposal.d.ts +87 -0
  90. package/dist/docx/server/applyDocxXmlPatchProposal.js +204 -0
  91. package/dist/docx/server/boundedArchive.d.ts +14 -3
  92. package/dist/docx/server/boundedArchive.js +56 -11
  93. package/dist/docx/server/evaluateDocxXmlPatchProposal.d.ts +85 -0
  94. package/dist/docx/server/evaluateDocxXmlPatchProposal.js +361 -0
  95. package/dist/docx/server/extractDocxText.js +55 -8
  96. package/dist/docx/server/inspectDocxPackage.d.ts +70 -0
  97. package/dist/docx/server/inspectDocxPackage.js +217 -0
  98. package/dist/docx/server/validateDocxConformance.d.ts +41 -0
  99. package/dist/docx/server/validateDocxConformance.js +336 -0
  100. package/dist/docx/settingsParser.js +26 -3
  101. package/dist/docx/shapeParser.js +1 -1
  102. package/dist/docx/styleParser.js +4 -2
  103. package/dist/docx/tableParser.d.ts +8 -1
  104. package/dist/docx/tableParser.js +31 -10
  105. package/dist/docx/textBoxParser.d.ts +3 -3
  106. package/dist/docx/textBoxParser.js +16 -12
  107. package/dist/docx/unzip.js +1 -0
  108. package/dist/docx/vmlImageParser.js +11 -3
  109. package/dist/docx/xmlParser.js +11 -1
  110. package/dist/docx/xmlSafety.d.ts +5 -0
  111. package/dist/docx/xmlSafety.js +9 -0
  112. package/dist/fields/resolveFieldValues.js +1 -3
  113. package/dist/fonts/embeddedFonts.d.ts +33 -5
  114. package/dist/fonts/embeddedFonts.js +37 -8
  115. package/dist/i18n/messages/catalogs.gen.d.ts +17 -0
  116. package/dist/i18n/messages/catalogs.gen.js +17 -0
  117. package/dist/i18n/messages/messages.gen.d.ts +1 -0
  118. package/dist/index.d.ts +3 -3
  119. package/dist/index.js +3 -3
  120. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  121. package/dist/layout-bridge/convert/footnoteLayout.js +47 -40
  122. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  123. package/dist/layout-bridge/convert/headerFooterLayout.js +3 -0
  124. package/dist/layout-bridge/convert/templatePreviewFlow.js +3 -3
  125. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -2
  126. package/dist/layout-bridge/convert/toFlowBlocks.js +151 -20
  127. package/dist/layout-bridge/dom/noteStoryDom.d.ts +6 -0
  128. package/dist/layout-bridge/dom/noteStoryDom.js +17 -0
  129. package/dist/layout-bridge/engine/clickToPosition.js +2 -2
  130. package/dist/layout-engine/index.d.ts +2 -2
  131. package/dist/layout-engine/index.js +58 -30
  132. package/dist/layout-engine/justificationCompatibility.d.ts +6 -0
  133. package/dist/layout-engine/justificationCompatibility.js +8 -0
  134. package/dist/layout-engine/keep-together.js +11 -1
  135. package/dist/layout-engine/measure/cache.js +23 -5
  136. package/dist/layout-engine/measure/effectiveLineBreakPolicy.js +8 -2
  137. package/dist/layout-engine/measure/lineBreakProvider.d.ts +2 -2
  138. package/dist/layout-engine/measure/lineBreakProvider.js +56 -37
  139. package/dist/layout-engine/measure/measureBlocks.js +15 -4
  140. package/dist/layout-engine/measure/measureContainer.js +1 -1
  141. package/dist/layout-engine/measure/measureHelpers.d.ts +11 -2
  142. package/dist/layout-engine/measure/measureHelpers.js +15 -4
  143. package/dist/layout-engine/measure/measureParagraph.js +85 -25
  144. package/dist/layout-engine/measure/measureProvider.js +4 -3
  145. package/dist/layout-engine/measure/tableCellFlow.js +5 -2
  146. package/dist/layout-engine/measure/textBoxParagraphLayout.d.ts +9 -7
  147. package/dist/layout-engine/measure/textBoxParagraphLayout.js +22 -6
  148. package/dist/layout-engine/measure/textMeasurementPolicy.d.ts +3 -1
  149. package/dist/layout-engine/measure/textMeasurementPolicy.js +7 -1
  150. package/dist/layout-engine/paginator.js +5 -1
  151. package/dist/layout-engine/paragraphSpacing.d.ts +28 -4
  152. package/dist/layout-engine/paragraphSpacing.js +107 -13
  153. package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
  154. package/dist/layout-engine/types.d.ts +48 -15
  155. package/dist/layout-painter/registry/modules/textBox.js +5 -1
  156. package/dist/layout-painter/renderImage.d.ts +12 -1
  157. package/dist/layout-painter/renderImage.js +21 -4
  158. package/dist/layout-painter/renderPage.d.ts +5 -2
  159. package/dist/layout-painter/renderPage.js +59 -14
  160. package/dist/layout-painter/renderParagraph.js +55 -15
  161. package/dist/layout-painter/renderTable.d.ts +5 -1
  162. package/dist/layout-painter/renderTable.js +7 -3
  163. package/dist/layout-painter/renderTextBox.d.ts +2 -1
  164. package/dist/layout-painter/renderTextBox.js +25 -14
  165. package/dist/layout-painter/renderWatermark.d.ts +1 -1
  166. package/dist/layout-painter/renderWatermark.js +2 -1
  167. package/dist/managers/DocumentLoaderManager.js +1 -1
  168. package/dist/markdown/fromMarkdown.js +1 -1
  169. package/dist/model.js +1 -1
  170. package/dist/prosemirror/attrs/index.d.ts +4 -2
  171. package/dist/prosemirror/attrs/index.js +175 -18
  172. package/dist/prosemirror/commands/comments.d.ts +79 -4
  173. package/dist/prosemirror/commands/comments.js +622 -13
  174. package/dist/prosemirror/commands/contentControls.js +1 -1
  175. package/dist/prosemirror/commands/hyperlink.js +15 -1
  176. package/dist/prosemirror/commands/image.js +7 -1
  177. package/dist/prosemirror/commands/index.d.ts +2 -2
  178. package/dist/prosemirror/commands/index.js +2 -2
  179. package/dist/prosemirror/commands/pageBreak.js +1 -1
  180. package/dist/prosemirror/commands/propertyChangeScope.d.ts +2 -2
  181. package/dist/prosemirror/commands/propertyChangeScope.js +3 -2
  182. package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +9 -0
  183. package/dist/prosemirror/commands/tableCellMergeResolution.js +181 -0
  184. package/dist/prosemirror/commentIdAllocator.js +13 -3
  185. package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -1
  186. package/dist/prosemirror/conversion/fromProseDoc.js +404 -62
  187. package/dist/prosemirror/conversion/index.js +1 -1
  188. package/dist/prosemirror/conversion/sdtAttrs.d.ts +9 -0
  189. package/dist/prosemirror/conversion/sdtAttrs.js +49 -0
  190. package/dist/prosemirror/conversion/toProseDoc.d.ts +2 -1
  191. package/dist/prosemirror/conversion/toProseDoc.js +364 -103
  192. package/dist/prosemirror/extensions/ExtensionManager.js +1 -1
  193. package/dist/prosemirror/extensions/StarterKit.js +6 -1
  194. package/dist/prosemirror/extensions/core/ParagraphExtension.js +6 -2
  195. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +1 -0
  196. package/dist/prosemirror/extensions/features/ImagePasteExtension.js +10 -2
  197. package/dist/prosemirror/extensions/features/ListExtension.js +1 -1
  198. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +10 -1
  199. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +93 -2
  200. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +2 -1
  201. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +6 -2
  202. package/dist/prosemirror/extensions/features/pasteCleanup.js +15 -2
  203. package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.js +1 -1
  204. package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +30 -4
  205. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.d.ts +9 -1
  206. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +70 -11
  207. package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
  208. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.d.ts +7 -0
  209. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.js +22 -0
  210. package/dist/prosemirror/extensions/nodes/TableExtension.d.ts +1 -1
  211. package/dist/prosemirror/extensions/nodes/TableExtension.js +14 -6
  212. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +13 -0
  213. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +41 -0
  214. package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +5 -2
  215. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +4 -1
  216. package/dist/prosemirror/index.d.ts +1 -1
  217. package/dist/prosemirror/index.js +1 -1
  218. package/dist/prosemirror/plugins/contentControlWidgets.d.ts +36 -10
  219. package/dist/prosemirror/plugins/contentControlWidgets.js +128 -94
  220. package/dist/prosemirror/plugins/revisionIds.d.ts +23 -0
  221. package/dist/prosemirror/plugins/revisionIds.js +57 -0
  222. package/dist/prosemirror/plugins/selectionTracker.js +1 -0
  223. package/dist/prosemirror/plugins/suggestionMode.js +5 -4
  224. package/dist/prosemirror/runFormattingMarkNames.d.ts +14 -0
  225. package/dist/prosemirror/runFormattingMarkNames.js +40 -0
  226. package/dist/prosemirror/schema/index.d.ts +2 -2
  227. package/dist/prosemirror/schema/marks.d.ts +30 -3
  228. package/dist/prosemirror/schema/marks.js +15 -0
  229. package/dist/prosemirror/schema/nodes.d.ts +111 -6
  230. package/dist/prosemirror/selectionState.js +1 -0
  231. package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
  232. package/dist/prosemirror/tableCellMergeRevision.d.ts +9 -0
  233. package/dist/prosemirror/tableCellMergeRevision.js +22 -0
  234. package/dist/prosemirror/textBoxAnchorAttrs.d.ts +9 -0
  235. package/dist/prosemirror/textBoxAnchorAttrs.js +33 -0
  236. package/dist/prosemirror/utils/extractTrackedChanges.d.ts +1 -1
  237. package/dist/prosemirror/utils/extractTrackedChanges.js +62 -14
  238. package/dist/prosemirror/validation.js +9 -1
  239. package/dist/render-dom/RemoteSelectionOverlay.js +2 -2
  240. package/dist/server.d.ts +7 -3
  241. package/dist/server.js +7 -3
  242. package/dist/utils/clipboard.d.ts +10 -1
  243. package/dist/utils/clipboard.js +33 -6
  244. package/dist/utils/colorResolver.d.ts +8 -1
  245. package/dist/utils/colorResolver.js +35 -5
  246. package/dist/utils/fontFamilyMerge.js +9 -11
  247. package/dist/utils/fontLoader.js +3 -2
  248. package/dist/utils/fontResolver.d.ts +2 -1
  249. package/dist/utils/fontResolver.js +31 -7
  250. package/dist/utils/fontWeights.d.ts +1 -1
  251. package/dist/utils/fontWeights.js +1 -1
  252. package/dist/utils/hexId.d.ts +11 -1
  253. package/dist/utils/hexId.js +11 -1
  254. package/dist/utils/paragraphFormattingMerge.js +1 -0
  255. package/dist/utils/sanitizeImageSrc.d.ts +21 -0
  256. package/dist/utils/sanitizeImageSrc.js +30 -0
  257. package/dist/utils/stripXmlDeclarations.d.ts +11 -0
  258. package/dist/utils/stripXmlDeclarations.js +35 -0
  259. package/dist/version-comparison.d.ts +22 -2
  260. package/dist/version-comparison.js +41 -12
  261. package/dist/watermark/index.d.ts +11 -1
  262. package/dist/watermark/index.js +22 -1
  263. package/package.json +3 -2
@@ -1,17 +1,34 @@
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";
8
- import { marksToTextFormatting } from "./fromProseDoc.js";
6
+ import { sdtAttrsFromProperties } from "./sdtAttrs.js";
7
+ import { mergeTextFormatting } from "../../utils/textFormattingMerge.js";
8
+ import { mergeParagraphFormatting, mergeParagraphTabStops } from "../../utils/paragraphFormattingMerge.js";
9
9
  import { createStyleEngine } from "../../style-engine/styleEngine.js";
10
10
  import { buildRunFormattingOverrideAttrs } from "../extensions/marks/RunFormattingOverrideExtension.js";
11
11
  import { schema } from "../schema/index.js";
12
12
  import { resolveEffectiveTableCellFormatting } from "./effectiveTableCellFormatting.js";
13
+ import { marksToTextFormatting } from "./fromProseDoc.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);
17
+ /**
18
+ * Build a `nextTextBoxGroupId()` generator salted with a random per-load
19
+ * nonce, so minted text-box anchor ids (`<salt>:<group>:<index>`) are unique
20
+ * across separate conversions instead of purely sequential ("0:0", "0:1",
21
+ * ...) starting fresh every load. `TextBoxAnchorExtension` parses
22
+ * `data-docx-textbox-anchor` straight off pasted DOM and `fromProseDoc`
23
+ * registers anchors first-seen-wins — without the salt, a pasted external
24
+ * span carrying a guessed/copied id could collide with and hijack a real
25
+ * text box anchored in a completely different document.
26
+ */
27
+ const createTextBoxGroupIdFactory = () => {
28
+ const salt = Math.random().toString(36).slice(2, 10);
29
+ let index = 0;
30
+ return () => `${salt}:${index++}`;
31
+ };
15
32
  /**
16
33
  * Convert a Document to a ProseMirror document
17
34
  *
@@ -23,14 +40,19 @@ function toProseDoc(document, options) {
23
40
  const nodes = [];
24
41
  const styleResolver = createStyleEngine(options?.styles ?? document.package.styles);
25
42
  const theme = options?.theme ?? document.package.theme ?? null;
26
- let textBoxGroupIndex = 0;
27
- const nextTextBoxGroupId = () => String(textBoxGroupIndex++);
43
+ const nextTextBoxGroupId = createTextBoxGroupIdFactory();
28
44
  const convertBodyBlocks = (blocks) => {
29
45
  const out = [];
30
46
  for (const block of blocks) if (block.type === "paragraph") {
31
47
  const pbPos = paragraphPageBreakPosition(block);
32
48
  if (pbPos === "before") out.push(schema.node("pageBreak"));
33
- const converted = convertParagraphWithTextBoxes(block, styleResolver, { textBoxGroupId: nextTextBoxGroupId() });
49
+ const converted = convertParagraphWithTextBoxes(block, styleResolver, {
50
+ textBoxGroupId: nextTextBoxGroupId(),
51
+ context: {
52
+ theme,
53
+ nextTextBoxGroupId
54
+ }
55
+ });
34
56
  const firstConverted = converted.at(0);
35
57
  if (pbPos === "before" && converted.length === 1 && firstConverted?.type.name === "paragraph" && firstConverted.content.size === 0 && document.package.settings?.splitPageBreakAndParagraphMark !== true) {
36
58
  const paragraph = firstConverted;
@@ -39,6 +61,14 @@ function toProseDoc(document, options) {
39
61
  _pageBreakCarrier: true
40
62
  }, paragraph.content, paragraph.marks);
41
63
  }
64
+ if (pbPos === "after") {
65
+ const paragraphIndex = converted.findIndex((node) => node.type.name === "paragraph");
66
+ const trailingParagraph = paragraphIndex >= 0 ? converted.at(paragraphIndex) : void 0;
67
+ if (trailingParagraph) converted[paragraphIndex] = trailingParagraph.type.create({
68
+ ...trailingParagraph.attrs,
69
+ _trailingPageBreak: true
70
+ }, trailingParagraph.content, trailingParagraph.marks);
71
+ }
42
72
  out.push(...converted);
43
73
  if (pbPos === "after") out.push(schema.node("pageBreak"));
44
74
  } else if (block.type === "table") out.push(convertTable(block, styleResolver, {
@@ -91,9 +121,9 @@ function convertBlockSdt(blockSdt, convertBlocks) {
91
121
  * Resolves style-based text formatting and passes it to runs so that
92
122
  * paragraph styles (like Heading1) apply their font size, color, etc.
93
123
  */
94
- function convertParagraph(paragraph, styleResolver, activeCommentIds, extraRunFormatting, tableParagraphOverlay) {
124
+ function convertParagraph(paragraph, styleResolver, activeCommentIds, extraRunFormatting, tableParagraphOverlay, textBoxAnchors) {
95
125
  const attrs = paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOverlay);
96
- const isTocParagraph = TOC_STYLE_ID.test(paragraph.formatting?.styleId ?? "");
126
+ const isTocParagraph = isTocStyleId(paragraph.formatting?.styleId);
97
127
  const inlineNodes = [];
98
128
  let inlineOffset = 0;
99
129
  let bookmarksArr;
@@ -111,11 +141,16 @@ function convertParagraph(paragraph, styleResolver, activeCommentIds, extraRunFo
111
141
  emitInlineNodes([node]);
112
142
  };
113
143
  let styleRunFormatting;
114
- if (styleResolver) styleRunFormatting = styleResolver.resolveParagraphStyle(paragraph.formatting?.styleId).runFormatting;
115
- const paragraphRunFormatting = resolveParagraphMarkRunFormatting(paragraph.formatting?.runProperties, styleResolver);
144
+ let paragraphStyleFontFamily;
145
+ if (styleResolver) {
146
+ styleRunFormatting = styleResolver.resolveParagraphStyle(paragraph.formatting?.styleId).runFormatting;
147
+ paragraphStyleFontFamily = resolveParagraphStyleFontFamily(paragraph.formatting?.styleId, styleResolver);
148
+ }
149
+ const paragraphRunFormatting = resolveRunFormattingWithoutDefaults(paragraph.formatting?.runProperties, styleResolver);
116
150
  let inheritableParagraphRunFormatting;
117
151
  if (paragraphRunFormatting && !isTocParagraph) inheritableParagraphRunFormatting = stripParagraphMarkFormattingForBodyRuns(paragraphRunFormatting);
118
- const baseRunFormatting = mergeTextFormatting(styleRunFormatting, extraRunFormatting);
152
+ let baseRunFormatting = mergeTextFormatting(styleRunFormatting, extraRunFormatting);
153
+ if (paragraphStyleFontFamily) baseRunFormatting = mergeTextFormatting(baseRunFormatting, { fontFamily: paragraphStyleFontFamily });
119
154
  const paragraphMarkPrecedesStyle = paragraph.formatting?.styleId !== void 0;
120
155
  const defaultRunFormatting = paragraphMarkPrecedesStyle ? mergeTextFormatting(inheritableParagraphRunFormatting, baseRunFormatting) : mergeTextFormatting(baseRunFormatting, inheritableParagraphRunFormatting);
121
156
  const getInheritedRunFormatting = (formatting, fieldType) => {
@@ -124,17 +159,22 @@ function convertParagraph(paragraph, styleResolver, activeCommentIds, extraRunFo
124
159
  return suppressParagraphMarkFormatting(baseRunFormatting, inheritableParagraphRunFormatting, formatting, paragraphMarkPrecedesStyle);
125
160
  };
126
161
  const emitTrackedChange = (change, markType, moveKind) => {
127
- emitInlineNodes(convertTrackedChange(change, markType, getInheritedRunFormatting, styleResolver, moveKind));
162
+ emitInlineNodes(convertTrackedChange(change, markType, getInheritedRunFormatting, styleResolver, moveKind, textBoxAnchors));
128
163
  };
129
164
  for (const content of paragraph.content) {
130
165
  if (content.type === "commentRangeStart") commentIds.add(content.id);
131
166
  else if (content.type === "commentRangeEnd") commentIds.delete(content.id);
132
167
  else if (content.type === "commentReference") anchorPointComment(inlineNodes, content.id);
133
- else if (content.type === "run") emitInlineNodes(convertRun(content, getInheritedRunFormatting(content.formatting), styleResolver));
168
+ else if (content.type === "run") emitInlineNodes(convertRun(content, getInheritedRunFormatting(content.formatting), styleResolver, textBoxAnchors));
134
169
  else if (content.type === "hyperlink") {
135
170
  const currentHyperlinkIndex = hyperlinkIndex;
136
171
  hyperlinkIndex += 1;
137
- const linkNodes = convertHyperlink(content, getInheritedRunFormatting, styleResolver, currentHyperlinkIndex);
172
+ const linkNodes = convertHyperlink(content, {
173
+ getInheritedRunFormatting,
174
+ styleResolver,
175
+ hyperlinkIndex: currentHyperlinkIndex,
176
+ textBoxAnchors
177
+ });
138
178
  if (linkNodes.length === 0) {
139
179
  emptyHyperlinks ??= [];
140
180
  emptyHyperlinks.push({
@@ -148,7 +188,7 @@ function convertParagraph(paragraph, styleResolver, activeCommentIds, extraRunFo
148
188
  }
149
189
  emitInlineNodes(linkNodes);
150
190
  } else if (content.type === "simpleField" || content.type === "complexField") emitInlineNode(convertField(content, getInheritedRunFormatting, styleResolver));
151
- else if (content.type === "inlineSdt") emitInlineNode(convertInlineSdt(content, getInheritedRunFormatting, styleResolver));
191
+ else if (content.type === "inlineSdt") emitInlineNode(convertInlineSdt(content, getInheritedRunFormatting, styleResolver, textBoxAnchors));
152
192
  else if (content.type === "insertion" || content.type === "moveTo") emitTrackedChange(content, "insertion", content.type === "moveTo" ? "moveTo" : null);
153
193
  else if (content.type === "deletion" || content.type === "moveFrom") emitTrackedChange(content, "deletion", content.type === "moveFrom" ? "moveFrom" : null);
154
194
  else if (content.type === "mathEquation") emitInlineNode(convertMathEquation(content));
@@ -164,6 +204,15 @@ function convertParagraph(paragraph, styleResolver, activeCommentIds, extraRunFo
164
204
  if (emptyHyperlinks) attrs._emptyHyperlinks = emptyHyperlinks;
165
205
  return schema.node("paragraph", attrs, inlineNodes);
166
206
  }
207
+ const resolveParagraphStyleFontFamily = (styleId, styleResolver) => {
208
+ let style = styleId ? styleResolver.getStyle(styleId) : styleResolver.getDefaultParagraphStyle();
209
+ const visited = /* @__PURE__ */ new Set();
210
+ while (style?.type === "paragraph" && !visited.has(style.styleId)) {
211
+ visited.add(style.styleId);
212
+ if (style.rPr?.fontFamily) return style.rPr.fontFamily;
213
+ style = style.basedOn ? styleResolver.getStyle(style.basedOn) : void 0;
214
+ }
215
+ };
167
216
  /**
168
217
  * Apply comment marks to PM nodes within a comment range.
169
218
  * Only the first active comment ID is used (comments don't overlap visually).
@@ -191,19 +240,25 @@ function anchorPointComment(nodes, commentId) {
191
240
  * Convert tracked change (insertion or deletion) content to PM nodes with
192
241
  * an insertion/deletion mark applied.
193
242
  */
194
- function convertTrackedChange(change, markType, getInheritedRunFormatting, styleResolver, moveKind = null) {
243
+ function convertTrackedChange(change, markType, getInheritedRunFormatting, styleResolver, moveKind = null, textBoxAnchors) {
195
244
  const nodes = [];
196
245
  let hyperlinkIndex = 0;
197
- for (const item of change.content) if (item.type === "run") nodes.push(...convertRun(item, getInheritedRunFormatting(item.formatting), styleResolver));
246
+ for (const item of change.content) if (item.type === "run") nodes.push(...convertRun(item, getInheritedRunFormatting(item.formatting), styleResolver, textBoxAnchors));
198
247
  else {
199
248
  const currentHyperlinkIndex = hyperlinkIndex;
200
249
  hyperlinkIndex += 1;
201
- nodes.push(...convertHyperlink(item, getInheritedRunFormatting, styleResolver, currentHyperlinkIndex));
250
+ nodes.push(...convertHyperlink(item, {
251
+ getInheritedRunFormatting,
252
+ styleResolver,
253
+ hyperlinkIndex: currentHyperlinkIndex,
254
+ textBoxAnchors
255
+ }));
202
256
  }
203
257
  const mark = schema.marks[markType].create({
204
258
  revisionId: change.info.id,
205
259
  author: change.info.author,
206
260
  date: change.info.date ?? null,
261
+ initials: change.info.initials ?? null,
207
262
  moveKind
208
263
  });
209
264
  return nodes.map((node) => {
@@ -212,7 +267,7 @@ function convertTrackedChange(change, markType, getInheritedRunFormatting, style
212
267
  });
213
268
  }
214
269
  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");
270
+ 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
271
  }
217
272
  /**
218
273
  * Convert ParagraphFormatting to ProseMirror paragraph attrs
@@ -263,9 +318,14 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
263
318
  set("spaceAfter", formatting?.spaceAfter ?? stylePpr?.spaceAfter);
264
319
  set("lineSpacing", formatting?.lineSpacing ?? stylePpr?.lineSpacing);
265
320
  set("lineSpacingRule", formatting?.lineSpacingRule ?? stylePpr?.lineSpacingRule);
321
+ set("snapToGrid", formatting?.snapToGrid ?? stylePpr?.snapToGrid);
266
322
  set("spacingExplicit", formatting?.spacingExplicit);
267
323
  const paragraphStyle = styleId ? styleResolver.getStyle(styleId) ?? styleResolver.getDefaultParagraphStyle() : styleResolver.getDefaultParagraphStyle();
268
324
  const docDefaultSpacing = styleResolver.getDocDefaults()?.pPr;
325
+ const spacingFromImplicitDefaultStyle = {};
326
+ if (!styleId && formatting?.spaceBefore === void 0 && paragraphStyle?.pPr?.spaceBefore !== void 0) spacingFromImplicitDefaultStyle.before = true;
327
+ if (!styleId && formatting?.spaceAfter === void 0 && paragraphStyle?.pPr?.spaceAfter !== void 0) spacingFromImplicitDefaultStyle.after = true;
328
+ if (spacingFromImplicitDefaultStyle.before || spacingFromImplicitDefaultStyle.after) attrs.spacingFromImplicitDefaultStyle = spacingFromImplicitDefaultStyle;
269
329
  const spacingFromDocDefaults = {};
270
330
  if (formatting?.spaceBefore === void 0 && tableParagraphOverlay?.spaceBefore === void 0 && paragraphStyle?.pPr?.spaceBefore === void 0 && docDefaultSpacing?.spaceBefore !== void 0) spacingFromDocDefaults.before = true;
271
331
  if (formatting?.spaceAfter === void 0 && tableParagraphOverlay?.spaceAfter === void 0 && paragraphStyle?.pPr?.spaceAfter === void 0 && docDefaultSpacing?.spaceAfter !== void 0) spacingFromDocDefaults.after = true;
@@ -289,7 +349,7 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
289
349
  set("runInWithNext", formatting?.runInWithNext ?? stylePpr?.runInWithNext);
290
350
  set("outlineLevel", formatting?.outlineLevel ?? stylePpr?.outlineLevel);
291
351
  set("direction", directionFromBidi(formatting?.bidi ?? stylePpr?.bidi));
292
- set("defaultTextFormatting", resolveParagraphDefaultTextFormatting(styleId, formatting, styleResolver, { includeParagraphMarkRunProperties: !TOC_STYLE_ID.test(styleId ?? "") }));
352
+ set("defaultTextFormatting", resolveParagraphDefaultTextFormatting(styleId, formatting, styleResolver, { includeParagraphMarkRunProperties: !isTocStyleId(styleId) }));
293
353
  if (!formatting?.numPr && stylePpr?.numPr && stylePpr.numPr.numId !== 0) {
294
354
  attrs.numPr = stylePpr.numPr;
295
355
  attrs.numPrFromStyle = stylePpr.numPr;
@@ -300,6 +360,7 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
300
360
  set("spaceAfter", formatting?.spaceAfter);
301
361
  set("lineSpacing", formatting?.lineSpacing);
302
362
  set("lineSpacingRule", formatting?.lineSpacingRule);
363
+ set("snapToGrid", formatting?.snapToGrid);
303
364
  set("spacingExplicit", formatting?.spacingExplicit);
304
365
  set("indentLeft", formatting?.indentLeft);
305
366
  set("indentRight", formatting?.indentRight);
@@ -361,7 +422,7 @@ function resolveTableStyleConditional(styleResolver, tableStyleId, conditionType
361
422
  if (!style?.tblStylePr) return;
362
423
  const conditional = style.tblStylePr.find((p) => p.type === conditionType);
363
424
  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);
425
+ const mergedRunProps = mergeTextFormatting(conditional.pPr?.runProperties ? resolveRunFormattingWithoutDefaults(conditional.pPr.runProperties, styleResolver) : void 0, conditional.rPr ? resolveRunFormattingWithoutDefaults(conditional.rPr, styleResolver) : void 0);
365
426
  const paragraphSpacingOverlay = extractTableParagraphSpacingOverlay(conditional.pPr);
366
427
  const result = {};
367
428
  if (conditional.tcPr) result.tcPr = conditional.tcPr;
@@ -373,7 +434,7 @@ function resolveTableBaseStyle(styleResolver, tableStyleId) {
373
434
  if (!styleResolver || !tableStyleId) return;
374
435
  const style = styleResolver.getStyle(tableStyleId);
375
436
  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);
437
+ const mergedRunProps = mergeTextFormatting(style.pPr?.runProperties ? resolveRunFormattingWithoutDefaults(style.pPr.runProperties, styleResolver) : void 0, style.rPr ? resolveRunFormattingWithoutDefaults(style.rPr, styleResolver) : void 0);
377
438
  const paragraphSpacingOverlay = extractTableParagraphSpacingOverlay(style.pPr);
378
439
  const result = {};
379
440
  if (style.tcPr) result.tcPr = style.tcPr;
@@ -415,7 +476,12 @@ function mergeConditionalStyles(base, override) {
415
476
  }
416
477
  function hasDirectRunFormatting(formatting) {
417
478
  if (!formatting) return false;
418
- return Object.entries(formatting).some(([key, value]) => key !== "styleId" && value !== void 0);
479
+ for (const key in formatting) {
480
+ if (!Object.hasOwn(formatting, key)) continue;
481
+ const value = Reflect.get(formatting, key);
482
+ if (key !== "styleId" && value !== void 0) return true;
483
+ }
484
+ return false;
419
485
  }
420
486
  function stripParagraphMarkOnlyFormatting(formatting) {
421
487
  const { allCaps: _ac, highlight: _h, shading: _s, smallCaps: _sc, vertAlign: _va, ...rest } = formatting;
@@ -457,7 +523,12 @@ function resolveTextFormatting(formatting, styleResolver) {
457
523
  if (!styleResolver) return formatting;
458
524
  return mergeTextFormatting(styleResolver.resolveRunStyle(formatting.styleId), formatting);
459
525
  }
460
- function resolveParagraphMarkRunFormatting(formatting, styleResolver) {
526
+ /**
527
+ * Resolve an embedded character-style reference without importing
528
+ * `docDefaults`. The caller already has the paragraph cascade, including
529
+ * document defaults, and will layer these own properties over it.
530
+ */
531
+ function resolveRunFormattingWithoutDefaults(formatting, styleResolver) {
461
532
  if (!formatting || !styleResolver) return formatting;
462
533
  return mergeTextFormatting(formatting.styleId ? styleResolver.getRunStyleOwnProperties(formatting.styleId) : void 0, formatting);
463
534
  }
@@ -465,7 +536,7 @@ function resolveParagraphDefaultTextFormatting(styleId, formatting, styleResolve
465
536
  const style = styleId ? styleResolver.getStyle(styleId) ?? styleResolver.getDefaultParagraphStyle() : styleResolver.getDefaultParagraphStyle();
466
537
  const paragraphStyleRpr = style?.type === "paragraph" ? style.rPr : void 0;
467
538
  const rawParagraphMarkRpr = options.includeParagraphMarkRunProperties === false ? void 0 : formatting?.runProperties;
468
- const paragraphRunProperties = rawParagraphMarkRpr ? stripParagraphMarkOnlyFormatting(resolveParagraphMarkRunFormatting(rawParagraphMarkRpr, styleResolver) ?? {}) : void 0;
539
+ const paragraphRunProperties = rawParagraphMarkRpr ? stripParagraphMarkOnlyFormatting(resolveRunFormattingWithoutDefaults(rawParagraphMarkRpr, styleResolver) ?? {}) : void 0;
469
540
  const bodyRunDefaults = mergeTextFormatting(mergeTextFormatting(styleResolver.getDocDefaults()?.rPr, styleResolver.getDefaultCharacterStyle()?.rPr), paragraphStyleRpr);
470
541
  return styleId === void 0 ? mergeTextFormatting(bodyRunDefaults, paragraphRunProperties) : mergeTextFormatting(paragraphRunProperties, bodyRunDefaults);
471
542
  }
@@ -650,12 +721,29 @@ function countTableColumns(rows) {
650
721
  * Convert a TableRow to a ProseMirror table row node
651
722
  */
652
723
  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];
724
+ const attrsWithoutStructuralChange = { isHeader: !!row.formatting?.header };
725
+ if (row.formatting?.height?.value !== void 0) attrsWithoutStructuralChange.height = row.formatting.height.value;
726
+ if (row.formatting?.heightRule) attrsWithoutStructuralChange.heightRule = row.formatting.heightRule;
727
+ if (row.formatting?.hidden) attrsWithoutStructuralChange.hidden = true;
728
+ if (row.formatting) attrsWithoutStructuralChange._originalFormatting = row.formatting;
729
+ if (row.propertyChanges && row.propertyChanges.length > 0) attrsWithoutStructuralChange.trPrChange = [...row.propertyChanges];
730
+ let attrs = attrsWithoutStructuralChange;
731
+ if (row.structuralChange?.type === "tableRowInsertion") attrs = {
732
+ ...attrsWithoutStructuralChange,
733
+ trIns: {
734
+ revisionId: row.structuralChange.info.id,
735
+ author: row.structuralChange.info.author,
736
+ date: row.structuralChange.info.date ?? null
737
+ }
738
+ };
739
+ else if (row.structuralChange?.type === "tableRowDeletion") attrs = {
740
+ ...attrsWithoutStructuralChange,
741
+ trDel: {
742
+ revisionId: row.structuralChange.info.id,
743
+ author: row.structuralChange.info.author,
744
+ date: row.structuralChange.info.date ?? null
745
+ }
746
+ };
659
747
  const numCells = row.cells.length;
660
748
  const isFirstRow = rowIndex === 0;
661
749
  const isLastRow = rowIndex === (totalRows ?? 1) - 1;
@@ -776,15 +864,44 @@ function convertTableCell({ cell, styleResolver, context, isHeader, gridWidthPer
776
864
  }
777
865
  if (formatting?.textDirection) attrs.textDirection = formatting.textDirection;
778
866
  if (formatting?.noWrap !== void 0) attrs.noWrap = formatting.noWrap;
867
+ const hideMark = formatting?.hideMark ?? conditionalStyle?.tcPr?.hideMark;
868
+ if (hideMark !== void 0) attrs.hideMark = hideMark;
779
869
  if (effectiveFormatting.borders) attrs.borders = effectiveFormatting.borders;
780
870
  if (effectiveFormatting.margins) attrs.margins = effectiveFormatting.margins;
781
871
  if (formatting) attrs._originalFormatting = formatting;
782
872
  if (cell.propertyChanges && cell.propertyChanges.length > 0) attrs.tcPrChange = [...cell.propertyChanges];
873
+ if (cell.structuralChange?.type === "tableCellInsertion") attrs.cellMarker = {
874
+ kind: "ins",
875
+ info: {
876
+ revisionId: cell.structuralChange.info.id,
877
+ author: cell.structuralChange.info.author,
878
+ date: cell.structuralChange.info.date ?? null
879
+ }
880
+ };
881
+ else if (cell.structuralChange?.type === "tableCellDeletion") attrs.cellMarker = {
882
+ kind: "del",
883
+ info: {
884
+ revisionId: cell.structuralChange.info.id,
885
+ author: cell.structuralChange.info.author,
886
+ date: cell.structuralChange.info.date ?? null
887
+ }
888
+ };
889
+ else if (cell.structuralChange?.type === "tableCellMerge") attrs.cellMarker = {
890
+ kind: "merge",
891
+ info: {
892
+ revisionId: cell.structuralChange.info.id,
893
+ author: cell.structuralChange.info.author,
894
+ date: cell.structuralChange.info.date ?? null
895
+ },
896
+ ...cell.structuralChange.verticalMerge !== void 0 ? { verticalMerge: cell.structuralChange.verticalMerge } : {},
897
+ ...cell.structuralChange.verticalMergeOriginal !== void 0 ? { verticalMergeOriginal: cell.structuralChange.verticalMergeOriginal } : {}
898
+ };
783
899
  if (preserveVMergeRestart) attrs._preserveVMergeRestart = true;
784
900
  if (vMergeContinuationCells && vMergeContinuationCells.length > 0) attrs._docxVMergeContinuationCells = vMergeContinuationCells;
785
901
  const contentNodes = [];
786
902
  for (const content of cell.content) if (content.type === "paragraph") contentNodes.push(...convertParagraphWithTextBoxes(content, styleResolver, {
787
903
  textBoxGroupId: context.nextTextBoxGroupId(),
904
+ context,
788
905
  ...conditionalStyle?.rPr !== void 0 ? { extraRunFormatting: conditionalStyle.rPr } : {},
789
906
  ...conditionalStyle?.pPr !== void 0 ? { tableParagraphOverlay: conditionalStyle.pPr } : {}
790
907
  }));
@@ -793,6 +910,25 @@ function convertTableCell({ cell, styleResolver, context, isHeader, gridWidthPer
793
910
  const nodeType = isHeader ? "tableHeader" : "tableCell";
794
911
  return schema.node(nodeType, attrs, contentNodes);
795
912
  }
913
+ function standaloneTableCellToProseMirror(cell, nodeType) {
914
+ return convertTableCell({
915
+ cell,
916
+ styleResolver: null,
917
+ context: {
918
+ theme: null,
919
+ nextTextBoxGroupId: createTextBoxGroupIdFactory()
920
+ },
921
+ isHeader: nodeType === "tableHeader",
922
+ gridWidthPercent: void 0,
923
+ conditionalStyle: void 0,
924
+ tableBorders: void 0,
925
+ position: {},
926
+ calculatedRowSpan: 1,
927
+ preserveVMergeRestart: void 0,
928
+ vMergeContinuationCells: void 0,
929
+ defaultCellMargins: void 0
930
+ });
931
+ }
796
932
  /**
797
933
  * Convert a SimpleField or ComplexField to a ProseMirror field node.
798
934
  * Preserves run formatting (bold, fontSize, color, etc.) as PM marks.
@@ -832,46 +968,38 @@ function convertMathEquation(math) {
832
968
  /**
833
969
  * Convert an InlineSdt to a ProseMirror sdt node with inline content.
834
970
  */
835
- function convertInlineSdt(sdt, getInheritedRunFormatting, styleResolver) {
971
+ function convertInlineSdt(sdt, getInheritedRunFormatting, styleResolver, textBoxAnchors) {
836
972
  const props = sdt.properties;
837
973
  const inlineNodes = [];
838
974
  let hyperlinkIndex = 0;
839
975
  for (const content of sdt.content) if (content.type === "run") {
840
- const runNodes = convertRun(content, getInheritedRunFormatting(content.formatting), styleResolver);
976
+ const runNodes = convertRun(content, getInheritedRunFormatting(content.formatting), styleResolver, textBoxAnchors);
841
977
  inlineNodes.push(...runNodes);
842
978
  } else if (content.type === "hyperlink") {
843
979
  const currentHyperlinkIndex = hyperlinkIndex;
844
980
  hyperlinkIndex += 1;
845
- const linkNodes = convertHyperlink(content, getInheritedRunFormatting, styleResolver, currentHyperlinkIndex);
981
+ const linkNodes = convertHyperlink(content, {
982
+ getInheritedRunFormatting,
983
+ styleResolver,
984
+ hyperlinkIndex: currentHyperlinkIndex,
985
+ textBoxAnchors
986
+ });
846
987
  inlineNodes.push(...linkNodes);
847
988
  } else if (content.type === "simpleField" || content.type === "complexField") {
848
989
  const fieldNode = convertField(content, getInheritedRunFormatting, styleResolver);
849
990
  if (fieldNode) inlineNodes.push(fieldNode);
850
991
  } else if (content.type === "inlineSdt") {
851
- const nestedSdt = convertInlineSdt(content, getInheritedRunFormatting, styleResolver);
992
+ const nestedSdt = convertInlineSdt(content, getInheritedRunFormatting, styleResolver, textBoxAnchors);
852
993
  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));
994
+ } else if (content.type === "insertion") inlineNodes.push(...convertTrackedChange(content, "insertion", getInheritedRunFormatting, styleResolver, null, textBoxAnchors));
995
+ else if (content.type === "deletion") inlineNodes.push(...convertTrackedChange(content, "deletion", getInheritedRunFormatting, styleResolver, null, textBoxAnchors));
996
+ else if (content.type === "moveTo") inlineNodes.push(...convertTrackedChange(content, "insertion", getInheritedRunFormatting, styleResolver, "moveTo", textBoxAnchors));
997
+ else if (content.type === "moveFrom") inlineNodes.push(...convertTrackedChange(content, "deletion", getInheritedRunFormatting, styleResolver, "moveFrom", textBoxAnchors));
855
998
  else {
856
999
  const mathNode = convertMathEquation(content);
857
1000
  if (mathNode) inlineNodes.push(mathNode);
858
1001
  }
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);
1002
+ return schema.node("sdt", sdtAttrsFromProperties(props), inlineNodes.length > 0 ? inlineNodes : void 0);
875
1003
  }
876
1004
  /**
877
1005
  * Convert a Run to ProseMirror text nodes with marks
@@ -879,11 +1007,12 @@ function convertInlineSdt(sdt, getInheritedRunFormatting, styleResolver) {
879
1007
  * @param run - The run to convert
880
1008
  * @param styleFormatting - Text formatting from the paragraph's style (e.g., Heading1's font size/color)
881
1009
  */
882
- function convertRun(run, styleFormatting, styleResolver) {
1010
+ function convertRun(run, styleFormatting, styleResolver, textBoxAnchors) {
883
1011
  const nodes = [];
884
1012
  const { marks, mergedFormatting } = buildRunMarks(run.formatting, styleFormatting, styleResolver);
1013
+ if (run.propertyChanges && run.propertyChanges.length > 0) marks.push(schema.mark("runPropertyChange", { changes: [...run.propertyChanges] }));
885
1014
  for (const content of run.content) {
886
- const contentNodes = convertRunContent(content, marks, mergedFormatting);
1015
+ const contentNodes = convertRunContent(content, marks, mergedFormatting, textBoxAnchors);
887
1016
  nodes.push(...contentNodes);
888
1017
  }
889
1018
  return nodes;
@@ -908,7 +1037,7 @@ function buildRunMarks(runFormatting, inheritedFormatting, styleResolver) {
908
1037
  /**
909
1038
  * Convert RunContent to ProseMirror nodes
910
1039
  */
911
- function convertRunContent(content, marks, formatting) {
1040
+ function convertRunContent(content, marks, formatting, textBoxAnchors) {
912
1041
  switch (content.type) {
913
1042
  case "text":
914
1043
  if (content.text) return [schema.text(content.text, marks)];
@@ -917,11 +1046,15 @@ function convertRunContent(content, marks, formatting) {
917
1046
  if (content.breakType === "textWrapping" || !content.breakType) return [withHyperlinkBoundaryMarks(schema.node("hardBreak"), marks)];
918
1047
  if (content.breakType === "column") return [withHyperlinkBoundaryMarks(schema.node("hardBreak", { breakType: "column" }), marks)];
919
1048
  return [];
1049
+ case "renderedPageBreak": return [schema.node("renderedPageBreak").mark(marks)];
920
1050
  case "tab": return [schema.node("tab").mark(marks)];
921
1051
  case "drawing": return [withHyperlinkBoundaryMarks(convertImage(content.image, content.rawXml), marks)];
922
1052
  case "shape": {
923
1053
  const shp = content.shape;
924
- if (shp.textBody) return [];
1054
+ if (shp.textBody) {
1055
+ const anchorId = textBoxAnchors?.get(shp);
1056
+ return anchorId ? [schema.node("textBoxAnchor", { anchorId }).mark(marks)] : [];
1057
+ }
925
1058
  return [withHyperlinkBoundaryMarks(convertShape(shp), marks)];
926
1059
  }
927
1060
  case "footnoteRef": {
@@ -1053,13 +1186,7 @@ function convertImage(image, rawXml) {
1053
1186
  _docxObjectPreview: rawXml !== void 0 && /<(?:[A-Za-z_][\w.-]*:)?object(?:\s|>)/u.test(rawXml)
1054
1187
  });
1055
1188
  }
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) {
1189
+ function convertHyperlink(hyperlink, { getInheritedRunFormatting, styleResolver, hyperlinkIndex, textBoxAnchors }) {
1063
1190
  const nodes = [];
1064
1191
  const href = hyperlink.href || (hyperlink.anchor ? `#${hyperlink.anchor}` : "");
1065
1192
  const linkMark = schema.mark("hyperlink", {
@@ -1072,7 +1199,7 @@ function convertHyperlink(hyperlink, getInheritedRunFormatting, styleResolver, h
1072
1199
  const inheritedFormatting = getInheritedRunFormatting(child.formatting);
1073
1200
  const { marks: runMarks, mergedFormatting } = buildRunMarks(child.formatting, inheritedFormatting, styleResolver);
1074
1201
  const allMarks = [...runMarks, linkMark];
1075
- for (const content of child.content) nodes.push(...convertRunContent(content, allMarks, mergedFormatting));
1202
+ for (const content of child.content) nodes.push(...convertRunContent(content, allMarks, mergedFormatting, textBoxAnchors));
1076
1203
  }
1077
1204
  return nodes;
1078
1205
  }
@@ -1230,57 +1357,159 @@ function convertShape(shape) {
1230
1357
  position
1231
1358
  });
1232
1359
  }
1233
- function convertParagraphWithTextBoxes(block, styleResolver, { textBoxGroupId, extraRunFormatting, tableParagraphOverlay }) {
1234
- const textBoxes = extractTextBoxesFromParagraph(block);
1235
- const pmParagraph = convertParagraph(block, styleResolver, void 0, extraRunFormatting, tableParagraphOverlay);
1360
+ function convertParagraphWithTextBoxes(block, styleResolver, { textBoxGroupId, context, extraRunFormatting, tableParagraphOverlay }) {
1361
+ const { textBoxes, textBoxAnchors } = extractTextBoxesFromParagraph(block, textBoxGroupId);
1362
+ const pmParagraph = convertParagraph(block, styleResolver, void 0, extraRunFormatting, tableParagraphOverlay, textBoxAnchors);
1236
1363
  const nodes = [];
1237
- const isEmptyAfterExtraction = textBoxes.length > 0 && pmParagraph.content.size === 0;
1364
+ const isEmptyAfterExtraction = textBoxes.length > 0 && !hasContentBesidesTextBoxAnchors(pmParagraph);
1238
1365
  const keepWrapperParagraph = isEmptyAfterExtraction && hasParagraphBoundaryPayload(block, pmParagraph);
1239
1366
  if (!isEmptyAfterExtraction || keepWrapperParagraph) nodes.push(pmParagraph);
1240
- for (const tb of textBoxes) nodes.push(convertTextBox(tb, styleResolver, {
1367
+ for (const { textBox, anchorId, trackedChange, inlineSdts } of textBoxes) nodes.push(convertTextBox(textBox, styleResolver, {
1241
1368
  placement: isEmptyAfterExtraction && !keepWrapperParagraph ? "standalone" : "inlineWithPrevious",
1242
- groupId: textBoxGroupId
1369
+ groupId: textBoxGroupId,
1370
+ anchorId,
1371
+ context,
1372
+ trackedChange,
1373
+ inlineSdts
1243
1374
  }));
1244
1375
  return nodes;
1245
1376
  }
1377
+ function hasContentBesidesTextBoxAnchors(paragraph) {
1378
+ let hasContent = false;
1379
+ paragraph.descendants((node) => {
1380
+ if (node.type.name === "textBoxAnchor") return false;
1381
+ if (node.type.name === "sdt") {
1382
+ if (node.childCount === 0) hasContent = true;
1383
+ return !hasContent;
1384
+ }
1385
+ hasContent = true;
1386
+ return false;
1387
+ });
1388
+ return hasContent;
1389
+ }
1246
1390
  function hasParagraphBoundaryPayload(block, pmParagraph) {
1247
1391
  const bookmarks = pmParagraph.attrs["bookmarks"];
1248
1392
  const emptyHyperlinks = pmParagraph.attrs["_emptyHyperlinks"];
1249
1393
  return Boolean(block.sectionProperties || block.propertyChanges?.length || Array.isArray(bookmarks) && bookmarks.length > 0 || Array.isArray(emptyHyperlinks) && emptyHyperlinks.length > 0);
1250
1394
  }
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) {
1395
+ const NO_EXTRACTED_TEXT_BOXES = {
1396
+ textBoxes: [],
1397
+ textBoxAnchors: /* @__PURE__ */ new Map()
1398
+ };
1399
+ function extractTextBoxesFromParagraph(paragraph, textBoxGroupId) {
1400
+ if (!mayContainTextBox(paragraph)) return NO_EXTRACTED_TEXT_BOXES;
1401
+ return extractTextBoxes(paragraph, textBoxGroupId);
1402
+ }
1403
+ function mayContainTextBox(paragraph) {
1404
+ for (const item of paragraph.content) {
1405
+ if (item.type !== "run") {
1406
+ if (item.type === "inlineSdt" || item.type === "hyperlink" || item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") return true;
1407
+ continue;
1408
+ }
1409
+ for (const content of item.content) if (content.type === "shape" && content.shape.textBody) return true;
1410
+ }
1411
+ return false;
1412
+ }
1413
+ function extractTextBoxes(paragraph, textBoxGroupId) {
1257
1414
  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);
1415
+ const textBoxAnchors = /* @__PURE__ */ new Map();
1416
+ const visitRun = (run, context) => {
1417
+ for (const runContent of run.content) {
1418
+ if (runContent.type !== "shape" || !runContent.shape.textBody) continue;
1419
+ const anchorId = `${textBoxGroupId}:${textBoxes.length}`;
1420
+ textBoxAnchors.set(runContent.shape, anchorId);
1421
+ textBoxes.push({
1422
+ textBox: textBoxFromShape(runContent.shape, runContent.shape.textBody),
1423
+ anchorId,
1424
+ trackedChange: context.trackedChange,
1425
+ inlineSdts: context.inlineSdts
1426
+ });
1427
+ }
1428
+ };
1429
+ const visitHyperlink = (hyperlink, context) => {
1430
+ for (const child of hyperlink.children) if (child.type === "run") visitRun(child, context);
1431
+ };
1432
+ const visitTrackedChange = (change, context) => {
1433
+ const trackedChange = {
1434
+ type: change.type,
1435
+ info: change.info
1436
+ };
1437
+ for (const item of change.content) {
1438
+ if (item.type === "run") {
1439
+ visitRun(item, {
1440
+ ...context,
1441
+ trackedChange
1442
+ });
1443
+ continue;
1444
+ }
1445
+ visitHyperlink(item, {
1446
+ ...context,
1447
+ trackedChange
1448
+ });
1449
+ }
1450
+ };
1451
+ const visitInlineSdt = (sdt, context) => {
1452
+ const inlineSdts = [...context.inlineSdts, sdtAttrsFromProperties(sdt.properties)];
1453
+ const nestedContext = {
1454
+ ...context,
1455
+ inlineSdts
1456
+ };
1457
+ for (const item of sdt.content) {
1458
+ if (item.type === "run") {
1459
+ visitRun(item, nestedContext);
1460
+ continue;
1275
1461
  }
1462
+ if (item.type === "inlineSdt") {
1463
+ visitInlineSdt(item, nestedContext);
1464
+ continue;
1465
+ }
1466
+ if (item.type === "hyperlink") {
1467
+ visitHyperlink(item, nestedContext);
1468
+ continue;
1469
+ }
1470
+ if (item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") visitTrackedChange(item, nestedContext);
1471
+ }
1472
+ };
1473
+ const rootContext = { inlineSdts: [] };
1474
+ for (const item of paragraph.content) {
1475
+ if (item.type === "run") {
1476
+ visitRun(item, rootContext);
1477
+ continue;
1276
1478
  }
1479
+ if (item.type === "inlineSdt") {
1480
+ visitInlineSdt(item, rootContext);
1481
+ continue;
1482
+ }
1483
+ if (item.type === "hyperlink") {
1484
+ visitHyperlink(item, rootContext);
1485
+ continue;
1486
+ }
1487
+ if (item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") visitTrackedChange(item, rootContext);
1277
1488
  }
1278
- return textBoxes;
1489
+ return {
1490
+ textBoxes,
1491
+ textBoxAnchors
1492
+ };
1493
+ }
1494
+ function textBoxFromShape(shape, textBody) {
1495
+ const textBox = {
1496
+ type: "textBox",
1497
+ size: shape.size,
1498
+ content: textBody.content
1499
+ };
1500
+ if (shape.id) textBox.id = shape.id;
1501
+ if (shape.position) textBox.position = shape.position;
1502
+ if (shape.wrap) textBox.wrap = shape.wrap;
1503
+ if (shape.fill) textBox.fill = shape.fill;
1504
+ if (shape.outline) textBox.outline = shape.outline;
1505
+ if (textBody.margins) textBox.margins = textBody.margins;
1506
+ if (textBody.autoFit) textBox.autoFit = textBody.autoFit;
1507
+ return textBox;
1279
1508
  }
1280
1509
  /**
1281
1510
  * Convert a TextBox to a ProseMirror textBox node
1282
1511
  */
1283
- function convertTextBox(textBox, styleResolver, options = {}) {
1512
+ function convertTextBox(textBox, styleResolver, options) {
1284
1513
  const textBoxSize = textBox.size;
1285
1514
  const widthPx = textBoxSize?.width ? emuToPixels(textBoxSize.width) : 200;
1286
1515
  const heightPx = textBoxSize?.height ? emuToPixels(textBoxSize.height) : void 0;
@@ -1299,7 +1528,16 @@ function convertTextBox(textBox, styleResolver, options = {}) {
1299
1528
  const marginLeft = textBox.margins?.left !== void 0 ? emuToPixels(textBox.margins.left) : 7;
1300
1529
  const marginRight = textBox.margins?.right !== void 0 ? emuToPixels(textBox.margins.right) : 7;
1301
1530
  const contentNodes = [];
1302
- for (const para of textBox.content) contentNodes.push(convertParagraph(para, styleResolver));
1531
+ for (const block of textBox.content) {
1532
+ if (block.type === "paragraph") {
1533
+ contentNodes.push(...convertParagraphWithTextBoxes(block, styleResolver, {
1534
+ textBoxGroupId: options.context.nextTextBoxGroupId(),
1535
+ context: options.context
1536
+ }));
1537
+ continue;
1538
+ }
1539
+ contentNodes.push(convertTable(block, styleResolver, options.context));
1540
+ }
1303
1541
  if (contentNodes.length === 0) contentNodes.push(schema.node("paragraph", {}, []));
1304
1542
  const wrapType = textBox.wrap?.type;
1305
1543
  const wrapText = textBox.wrap?.wrapText;
@@ -1359,7 +1597,10 @@ function convertTextBox(textBox, styleResolver, options = {}) {
1359
1597
  distRight,
1360
1598
  position,
1361
1599
  _docxPlacement: options.placement,
1362
- _docxGroupId: options.groupId
1600
+ _docxGroupId: options.groupId,
1601
+ _docxAnchorId: options.anchorId,
1602
+ _docxTrackedChange: options.trackedChange,
1603
+ _docxInlineSdts: options.inlineSdts.length > 0 ? options.inlineSdts : void 0
1363
1604
  }, contentNodes);
1364
1605
  }
1365
1606
  /**
@@ -1374,11 +1615,16 @@ function headerFooterToProseDoc(content, options) {
1374
1615
  const nodes = [];
1375
1616
  const styleResolver = options?.styles ? createStyleEngine(options.styles) : null;
1376
1617
  const theme = options?.theme ?? null;
1377
- let textBoxGroupIndex = 0;
1378
- const nextTextBoxGroupId = () => String(textBoxGroupIndex++);
1618
+ const nextTextBoxGroupId = createTextBoxGroupIdFactory();
1379
1619
  const convertBlocks = (blocks) => {
1380
1620
  const out = [];
1381
- for (const block of blocks) if (block.type === "paragraph") out.push(...convertParagraphWithTextBoxes(block, styleResolver, { textBoxGroupId: nextTextBoxGroupId() }));
1621
+ for (const block of blocks) if (block.type === "paragraph") out.push(...convertParagraphWithTextBoxes(block, styleResolver, {
1622
+ textBoxGroupId: nextTextBoxGroupId(),
1623
+ context: {
1624
+ theme,
1625
+ nextTextBoxGroupId
1626
+ }
1627
+ }));
1382
1628
  else if (block.type === "table") out.push(convertTable(block, styleResolver, {
1383
1629
  theme,
1384
1630
  nextTextBoxGroupId
@@ -1414,6 +1660,21 @@ function footnoteToProseDoc(content, options) {
1414
1660
  * null — no page break found.
1415
1661
  */
1416
1662
  function paragraphPageBreakPosition(paragraph) {
1663
+ if (!mayContainPageBreak(paragraph)) return null;
1664
+ return findParagraphPageBreakPosition(paragraph);
1665
+ }
1666
+ function mayContainPageBreak(paragraph) {
1667
+ for (const item of paragraph.content) {
1668
+ if (item.type === "run") {
1669
+ for (const content of item.content) if (content.type === "break" && content.breakType === "page") return true;
1670
+ continue;
1671
+ }
1672
+ 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;
1673
+ 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;
1674
+ }
1675
+ return false;
1676
+ }
1677
+ function findParagraphPageBreakPosition(paragraph) {
1417
1678
  const state = { seenVisibleContent: false };
1418
1679
  function isPageBreak(content) {
1419
1680
  return content.type === "break" && content.breakType === "page";
@@ -1468,4 +1729,4 @@ function createEmptyDoc() {
1468
1729
  return schema.node("doc", null, [schema.node("paragraph", {}, [])]);
1469
1730
  }
1470
1731
  //#endregion
1471
- export { createEmptyDoc, footnoteToProseDoc, headerFooterToProseDoc, textFormattingToMarks, toProseDoc };
1732
+ export { createEmptyDoc, footnoteToProseDoc, headerFooterToProseDoc, standaloneTableCellToProseMirror, textFormattingToMarks, toProseDoc };