@stll/folio-core 0.35.1 → 0.37.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 (236) hide show
  1. package/README.md +59 -1
  2. package/dist/ai-edits/apply.js +878 -377
  3. package/dist/ai-edits/block-identity.d.ts +4 -1
  4. package/dist/ai-edits/block-identity.js +4 -1
  5. package/dist/ai-edits/blockRange.js +14 -14
  6. package/dist/ai-edits/clean-text.d.ts +40 -1
  7. package/dist/ai-edits/clean-text.js +52 -2
  8. package/dist/ai-edits/headless.d.ts +3 -1
  9. package/dist/ai-edits/headless.js +141 -73
  10. package/dist/ai-edits/index.d.ts +3 -3
  11. package/dist/ai-edits/index.js +2 -2
  12. package/dist/ai-edits/read.js +38 -20
  13. package/dist/ai-edits/snapshot.d.ts +14 -6
  14. package/dist/ai-edits/snapshot.js +105 -20
  15. package/dist/ai-edits/table-cell-mutations.js +1 -1
  16. package/dist/ai-edits/table-row-column-mutations.js +7 -0
  17. package/dist/ai-edits/table-template.d.ts +11 -1
  18. package/dist/ai-edits/table-template.js +49 -17
  19. package/dist/ai-edits/types.d.ts +62 -61
  20. package/dist/ai-edits/word-diff.d.ts +18 -3
  21. package/dist/ai-edits/word-diff.js +556 -67
  22. package/dist/ai-suggestions/conflict.js +1 -4
  23. package/dist/ai-suggestions/text-positions.d.ts +8 -0
  24. package/dist/ai-suggestions/text-positions.js +27 -5
  25. package/dist/compare/__fixtures__/body-sequence.js +3 -4
  26. package/dist/compare/column-alignment.d.ts +13 -13
  27. package/dist/compare/column-alignment.js +78 -39
  28. package/dist/compare/compare.d.ts +4 -3
  29. package/dist/compare/compare.js +48 -21
  30. package/dist/compare/content-alignment.d.ts +95 -0
  31. package/dist/compare/content-alignment.js +1450 -0
  32. package/dist/compare/content-types.d.ts +100 -0
  33. package/dist/compare/content-types.js +0 -0
  34. package/dist/compare/content.d.ts +209 -0
  35. package/dist/compare/content.js +885 -0
  36. package/dist/compare/formatting.d.ts +5 -5
  37. package/dist/compare/formatting.js +6 -4
  38. package/dist/compare/plan.d.ts +6 -1
  39. package/dist/compare/plan.js +171 -566
  40. package/dist/compare/scenario.d.ts +2 -2
  41. package/dist/compare/types.d.ts +3 -3
  42. package/dist/compare/verification.d.ts +8 -9
  43. package/dist/compare/verification.js +72 -50
  44. package/dist/compat/eigenpal.d.ts +5 -3
  45. package/dist/compat/eigenpal.js +3 -2
  46. package/dist/controller/headerFooterEditorManager.js +18 -10
  47. package/dist/controller/hiddenEditorApi.js +1 -1
  48. package/dist/controller/hiddenEditorManager.d.ts +7 -2
  49. package/dist/controller/hiddenEditorManager.js +15 -6
  50. package/dist/controller/layoutPipeline.js +5 -3
  51. package/dist/controller/noteEditorManager.js +12 -7
  52. package/dist/display-list/build/headerFooterPrimitives.js +1 -0
  53. package/dist/display-list/build/storyPrimitives.d.ts +5 -2
  54. package/dist/display-list/build/storyPrimitives.js +60 -3
  55. package/dist/display-list/build/tablePrimitives.js +30 -0
  56. package/dist/display-list/primitives.d.ts +1 -1
  57. package/dist/document-operations.d.ts +8 -4
  58. package/dist/document-operations.js +104 -12
  59. package/dist/docx/blockContentParser.js +6 -27
  60. package/dist/docx/commentParser.js +2 -4
  61. package/dist/docx/commentRangeIntegrity.js +2 -4
  62. package/dist/docx/documentClone.d.ts +2 -0
  63. package/dist/docx/documentClone.js +2 -0
  64. package/dist/docx/ensureParaIds.js +9 -4
  65. package/dist/docx/headerFooterParser.js +2 -4
  66. package/dist/docx/normalizeBaseDirection.js +5 -7
  67. package/dist/docx/numberingParser.d.ts +3 -1
  68. package/dist/docx/numberingParser.js +4 -1
  69. package/dist/docx/paragraphParser.js +34 -35
  70. package/dist/docx/paragraphPropertySource.d.ts +49 -0
  71. package/dist/docx/paragraphPropertySource.js +113 -0
  72. package/dist/docx/paragraphTraversal.js +30 -34
  73. package/dist/docx/rezip.d.ts +0 -8
  74. package/dist/docx/rezip.js +41 -16
  75. package/dist/docx/runConsolidator.js +2 -4
  76. package/dist/docx/runParser.js +6 -17
  77. package/dist/docx/sectionParser.js +1 -15
  78. package/dist/docx/serializer/paragraphSerializer.js +289 -30
  79. package/dist/docx/serializer/runSerializer.js +6 -12
  80. package/dist/docx/serializer/sectionPropertiesSerializer.js +2 -10
  81. package/dist/docx/serializer/tableSerializer.js +4 -23
  82. package/dist/docx/serializer/trackedChangeAttributes.d.ts +11 -0
  83. package/dist/docx/serializer/trackedChangeAttributes.js +31 -0
  84. package/dist/docx/server/build.d.ts +1 -1
  85. package/dist/docx/server/createBilingualDocument.js +8 -10
  86. package/dist/docx/server/evaluateDocxXmlPatchProposal.js +22 -13
  87. package/dist/docx/server/validateDocxConformance.js +17 -13
  88. package/dist/docx/tableParser.js +1 -37
  89. package/dist/docx/trackedChangeInfo.d.ts +11 -0
  90. package/dist/docx/trackedChangeInfo.js +38 -0
  91. package/dist/docx/verbatimCapture.d.ts +20 -9
  92. package/dist/docx/verbatimCapture.js +208 -8
  93. package/dist/docx/xmlParser.d.ts +3 -1
  94. package/dist/docx/xmlParser.js +6 -1
  95. package/dist/docx/xmlSafety.d.ts +1 -1
  96. package/dist/docx/xmlSafety.js +157 -0
  97. package/dist/headless-layout.js +5 -4
  98. package/dist/index.d.ts +5 -3
  99. package/dist/index.js +3 -2
  100. package/dist/internal/headlessRevisionResolution.d.ts +23 -0
  101. package/dist/internal/headlessRevisionResolution.js +155 -0
  102. package/dist/internal/headlessRevisionResolutionGuard.d.ts +12 -0
  103. package/dist/internal/headlessRevisionResolutionGuard.js +28 -0
  104. package/dist/internal/pageBreakRunDescendantIndex.d.ts +9 -0
  105. package/dist/internal/pageBreakRunDescendantIndex.js +27 -0
  106. package/dist/internal/pageBreakRunPartition.d.ts +26 -0
  107. package/dist/internal/pageBreakRunPartition.js +35 -0
  108. package/dist/internal/pageBreakRunSourceDescendantIndex.d.ts +15 -0
  109. package/dist/internal/pageBreakRunSourceDescendantIndex.js +126 -0
  110. package/dist/internal/sectionEndpointResolution.d.ts +32 -0
  111. package/dist/internal/sectionEndpointResolution.js +38 -0
  112. package/dist/layout-bridge/convert/footnoteLayout.js +1 -0
  113. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +16 -4
  114. package/dist/layout-bridge/convert/headerFooterLayout.js +52 -9
  115. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -0
  116. package/dist/layout-bridge/convert/toFlowBlocks.js +391 -82
  117. package/dist/layout-bridge/dom/clickToPositionDom.d.ts +8 -1
  118. package/dist/layout-bridge/dom/clickToPositionDom.js +114 -40
  119. package/dist/layout-bridge/dom/textStreamDom.d.ts +24 -0
  120. package/dist/layout-bridge/dom/textStreamDom.js +75 -0
  121. package/dist/layout-bridge/headerFooterLayout.js +16 -30
  122. package/dist/layout-engine/index.js +12 -3
  123. package/dist/layout-engine/measure/tableFragmentBorderGeometry.d.ts +17 -0
  124. package/dist/layout-engine/measure/tableFragmentBorderGeometry.js +24 -0
  125. package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
  126. package/dist/layout-engine/types.d.ts +7 -0
  127. package/dist/layout-painter/imageLayout.d.ts +1 -1
  128. package/dist/layout-painter/renderTable.js +20 -0
  129. package/dist/markdown/renderBlock.js +7 -10
  130. package/dist/model.d.ts +1 -1
  131. package/dist/paged-layout/rangeProjection.js +6 -9
  132. package/dist/paged-layout/transactionDirtyRange.d.ts +3 -1
  133. package/dist/paged-layout/transactionDirtyRange.js +23 -1
  134. package/dist/prosemirror/attrs/index.d.ts +7 -3
  135. package/dist/prosemirror/attrs/index.js +128 -7
  136. package/dist/prosemirror/bookmarkBoundaryIntegrity.d.ts +9 -0
  137. package/dist/prosemirror/bookmarkBoundaryIntegrity.js +22 -0
  138. package/dist/prosemirror/commands/comments.d.ts +10 -1
  139. package/dist/prosemirror/commands/comments.js +551 -87
  140. package/dist/prosemirror/commands/formatPainter.d.ts +45 -10
  141. package/dist/prosemirror/commands/formatPainter.js +319 -63
  142. package/dist/prosemirror/commands/index.d.ts +2 -2
  143. package/dist/prosemirror/commands/pageBreak.d.ts +5 -2
  144. package/dist/prosemirror/commands/pageBreak.js +18 -36
  145. package/dist/prosemirror/commands/propertyChangeScope.d.ts +27 -3
  146. package/dist/prosemirror/commands/propertyChangeScope.js +85 -14
  147. package/dist/prosemirror/conversion/fromProseDoc.d.ts +8 -5
  148. package/dist/prosemirror/conversion/fromProseDoc.js +935 -223
  149. package/dist/prosemirror/conversion/runShadingMark.js +2 -2
  150. package/dist/prosemirror/conversion/toProseDoc.d.ts +26 -1
  151. package/dist/prosemirror/conversion/toProseDoc.js +439 -291
  152. package/dist/prosemirror/extensions/StarterKit.js +4 -0
  153. package/dist/prosemirror/extensions/core/ParagraphExtension.js +54 -6
  154. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +7 -1
  155. package/dist/prosemirror/extensions/features/ListExtension.js +95 -123
  156. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +19 -6
  157. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +27 -1
  158. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +134 -30
  159. package/dist/prosemirror/extensions/features/pasteCleanup.js +9 -15
  160. package/dist/prosemirror/extensions/marks/BoldExtension.js +4 -3
  161. package/dist/prosemirror/extensions/marks/CharacterStyleExtension.d.ts +4 -7
  162. package/dist/prosemirror/extensions/marks/CharacterStyleExtension.js +5 -11
  163. package/dist/prosemirror/extensions/marks/FontSizeExtension.js +3 -3
  164. package/dist/prosemirror/extensions/marks/ItalicExtension.js +4 -3
  165. package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.d.ts +13 -0
  166. package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.js +39 -0
  167. package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.d.ts +7 -1
  168. package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +67 -21
  169. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +2 -0
  170. package/dist/prosemirror/extensions/marks/markUtils.d.ts +8 -1
  171. package/dist/prosemirror/extensions/marks/markUtils.js +88 -2
  172. package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +44 -3
  173. package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
  174. package/dist/prosemirror/extensions/nodes/HardBreakExtension.js +15 -4
  175. package/dist/prosemirror/extensions/nodes/PageBreakExtension.d.ts +6 -0
  176. package/dist/prosemirror/extensions/nodes/PageBreakExtension.js +6 -0
  177. package/dist/prosemirror/extensions/nodes/PageBreakRunExtension.d.ts +6 -0
  178. package/dist/prosemirror/extensions/nodes/PageBreakRunExtension.js +36 -0
  179. package/dist/prosemirror/findReplaceSelection.js +8 -3
  180. package/dist/prosemirror/index.d.ts +3 -3
  181. package/dist/prosemirror/listMarker.d.ts +26 -1
  182. package/dist/prosemirror/listMarker.js +108 -14
  183. package/dist/prosemirror/pageBreakRunProjection.d.ts +28 -0
  184. package/dist/prosemirror/pageBreakRunProjection.js +47 -0
  185. package/dist/prosemirror/paraText.js +6 -0
  186. package/dist/prosemirror/paragraphAlignment.d.ts +12 -0
  187. package/dist/prosemirror/paragraphAlignment.js +13 -0
  188. package/dist/prosemirror/paragraphSpacing.d.ts +29 -0
  189. package/dist/prosemirror/paragraphSpacing.js +125 -0
  190. package/dist/prosemirror/plugins/documentNumbering.d.ts +8 -0
  191. package/dist/prosemirror/plugins/documentNumbering.js +18 -0
  192. package/dist/prosemirror/plugins/pmTextScan.d.ts +3 -2
  193. package/dist/prosemirror/plugins/pmTextScan.js +14 -4
  194. package/dist/prosemirror/plugins/suggestionMode.js +9 -11
  195. package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +16 -0
  196. package/dist/prosemirror/rebaseParagraphRunFormatting.js +61 -0
  197. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +64 -0
  198. package/dist/prosemirror/runFormattingInlineCarriers.js +121 -0
  199. package/dist/prosemirror/runFormattingProvenance.d.ts +12 -0
  200. package/dist/prosemirror/runFormattingProvenance.js +48 -0
  201. package/dist/prosemirror/runFormattingReconciliation.d.ts +25 -0
  202. package/dist/prosemirror/runFormattingReconciliation.js +54 -0
  203. package/dist/prosemirror/runPropertyChangeResolution.d.ts +18 -0
  204. package/dist/prosemirror/runPropertyChangeResolution.js +18 -0
  205. package/dist/prosemirror/runStyleFormatting.d.ts +50 -0
  206. package/dist/prosemirror/runStyleFormatting.js +105 -0
  207. package/dist/prosemirror/schema/index.d.ts +3 -3
  208. package/dist/prosemirror/schema/marks.d.ts +84 -9
  209. package/dist/prosemirror/schema/marks.js +73 -1
  210. package/dist/prosemirror/schema/nodes.d.ts +30 -6
  211. package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +14 -2
  212. package/dist/prosemirror/styles/resolvedStyleAttrs.js +45 -23
  213. package/dist/prosemirror/styles/styleResolver.d.ts +10 -13
  214. package/dist/prosemirror/styles/styleResolver.js +3 -3
  215. package/dist/prosemirror/styles/styleToggleCascade.d.ts +8 -1
  216. package/dist/prosemirror/styles/styleToggleCascade.js +24 -1
  217. package/dist/prosemirror/tableGridMutation.d.ts +20 -0
  218. package/dist/prosemirror/tableGridMutation.js +30 -0
  219. package/dist/prosemirror/trackedRunInlineAtoms.d.ts +31 -0
  220. package/dist/prosemirror/trackedRunInlineAtoms.js +39 -0
  221. package/dist/prosemirror/utils/visualLineNavigation.js +27 -31
  222. package/dist/prosemirror/validation.js +23 -4
  223. package/dist/redline.js +4 -1
  224. package/dist/render-dom/HeaderFooterSelectionOverlay.js +20 -20
  225. package/dist/render-dom/RenderedDomContext.js +17 -34
  226. package/dist/server.d.ts +4 -4
  227. package/dist/server.js +2 -2
  228. package/dist/style-engine/styleEngine.d.ts +1 -1
  229. package/dist/utils/clipboard.js +1 -1
  230. package/dist/utils/findReplace.js +38 -21
  231. package/dist/utils/mergeDocumentContent.js +3 -3
  232. package/dist/utils/replaceText.js +2 -1
  233. package/dist/version-comparison.d.ts +38 -44
  234. package/dist/version-comparison.js +270 -399
  235. package/dist/watermark/index.js +2 -4
  236. package/package.json +8 -2
@@ -1,4 +1,6 @@
1
1
  import { resolveColorValueToHex } from "../../docx/drawingUtils.js";
2
+ import { linkProseParagraphPropertySource, recreateProseNodeWithParagraphPropertySource } from "../../docx/paragraphPropertySource.js";
3
+ import { buildPageBreakRunSourceDescendantIndex } from "../../internal/pageBreakRunSourceDescendantIndex.js";
2
4
  import { createStyleEngine } from "../../style-engine/styleEngine.js";
3
5
  import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
4
6
  import { mergeParagraphFormatting, mergeParagraphTabStops } from "../../utils/paragraphFormattingMerge.js";
@@ -8,16 +10,22 @@ import { emuToPixels } from "../../utils/units.js";
8
10
  import { setAutospacingBaseValue } from "../autospacingBase.js";
9
11
  import { buildRunFormattingOverrideAttrs } from "../extensions/marks/RunFormattingOverrideExtension.js";
10
12
  import { stampNumberedRefFieldBaselines } from "../numberedRefFields.js";
13
+ import { pageBreakRunParagraphProjectionDispositionForFeatures } from "../pageBreakRunProjection.js";
11
14
  import { directionFromBidi } from "../paragraphDirection.js";
15
+ import { lineSpacingProvenanceFromSpacing } from "../paragraphSpacing.js";
16
+ import { getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting } from "../runStyleFormatting.js";
12
17
  import { schema } from "../schema/index.js";
18
+ import { COMPLEX_SCRIPT_RUN_PROPERTY_KEYS } from "../schema/marks.js";
13
19
  import { cascadeStyleTextFormatting } from "../styles/styleToggleCascade.js";
20
+ import { canCarryTrackedRunMark, trackedRunInlineAtomDisposition } from "../trackedRunInlineAtoms.js";
14
21
  import { assertValidProseMirrorDocument } from "../validation.js";
15
22
  import { resolveEffectiveTableCellFormatting } from "./effectiveTableCellFormatting.js";
16
- import { marksToTextFormatting } from "./fromProseDoc.js";
17
23
  import { shadingToRunShadingAttrs } from "./runShadingMark.js";
18
24
  import { sdtAttrsFromProperties } from "./sdtAttrs.js";
19
- import { panic } from "better-result";
25
+ import { TaggedError, panic } from "better-result";
20
26
  //#region src/prosemirror/conversion/toProseDoc.ts
27
+ /** DOCX content that cannot be preserved by the editable ProseMirror model. */
28
+ var UnsupportedDocxToProseMirrorConversionError = class extends TaggedError("UnsupportedDocxToProseMirrorConversionError") {};
21
29
  const DETACHED_WATERMARK_HOST = Symbol.for("stll.detachedWatermarkHost");
22
30
  /**
23
31
  * Build a `nextTextBoxGroupId()` generator salted with a random per-load
@@ -105,36 +113,16 @@ function toProseDoc(document, options) {
105
113
  theme,
106
114
  nextTextBoxGroupId,
107
115
  nextHyperlinkInstanceIndex: createHyperlinkInstanceIndexAllocator(),
108
- pairedBookmarkIds: collectPairedBookmarkIds(paragraphs)
116
+ pairedBookmarkIds: collectPairedBookmarkIds(paragraphs),
117
+ pageBreakRunSourceDescendants: buildPageBreakRunSourceDescendantIndex(paragraphs)
109
118
  };
110
119
  const convertBodyBlocks = (blocks) => {
111
120
  const out = [];
112
- for (const block of blocks) if (block.type === "paragraph") {
113
- const pbPos = paragraphPageBreakPosition(block);
114
- if (pbPos === "before") out.push(schema.node("pageBreak"));
115
- const converted = convertParagraphWithTextBoxes(block, styleResolver, {
116
- textBoxGroupId: nextTextBoxGroupId(),
117
- context: conversionContext
118
- });
119
- const firstConverted = converted.at(0);
120
- if (pbPos === "before" && converted.length === 1 && firstConverted?.type.name === "paragraph" && firstConverted.content.size === 0 && document.package.settings?.splitPageBreakAndParagraphMark !== true) {
121
- const paragraph = firstConverted;
122
- converted[0] = paragraph.type.create({
123
- ...paragraph.attrs,
124
- _pageBreakCarrier: true
125
- }, paragraph.content, paragraph.marks);
126
- }
127
- if (pbPos === "after") {
128
- const paragraphIndex = converted.findIndex((node) => node.type.name === "paragraph");
129
- const trailingParagraph = paragraphIndex >= 0 ? converted.at(paragraphIndex) : void 0;
130
- if (trailingParagraph) converted[paragraphIndex] = trailingParagraph.type.create({
131
- ...trailingParagraph.attrs,
132
- _trailingPageBreak: true
133
- }, trailingParagraph.content, trailingParagraph.marks);
134
- }
135
- out.push(...converted);
136
- if (pbPos === "after") out.push(schema.node("pageBreak"));
137
- } else if (block.type === "table") out.push(convertTable(block, styleResolver, conversionContext));
121
+ for (const block of blocks) if (block.type === "paragraph") out.push(...convertParagraphWithTextBoxes(block, styleResolver, {
122
+ textBoxGroupId: nextTextBoxGroupId(),
123
+ context: conversionContext
124
+ }));
125
+ else if (block.type === "table") out.push(convertTable(block, styleResolver, conversionContext));
138
126
  else out.push(convertBlockSdt(block, convertBodyBlocks));
139
127
  return out;
140
128
  };
@@ -186,8 +174,17 @@ function convertBlockSdt(blockSdt, convertBlocks) {
186
174
  * Resolves style-based text formatting and passes it to runs so that
187
175
  * paragraph styles (like Heading1) apply their font size, color, etc.
188
176
  */
189
- function convertParagraph(paragraph, styleResolver, nextHyperlinkInstanceIndex, pairedBookmarkIds, activeCommentIds, extraRunFormatting, tableParagraphOverlay, textBoxAnchors) {
190
- const attrs = paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOverlay);
177
+ function convertParagraph(paragraph, styleResolver, context, activeCommentIds, extraRunFormatting, tableParagraphOverlay, textBoxAnchors) {
178
+ const { nextHyperlinkInstanceIndex, pairedBookmarkIds, pageBreakRunSourceDescendants } = context;
179
+ let pageBreakRunOwnerId = 0;
180
+ const nextPageBreakRunOwnerId = () => pageBreakRunOwnerId++;
181
+ const { attrs, effectiveFrame } = paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOverlay);
182
+ assertParagraphPageBreakCanBeProjected({
183
+ paragraph,
184
+ attrs,
185
+ effectiveFrame,
186
+ sourceDescendants: pageBreakRunSourceDescendants
187
+ });
191
188
  const isTocParagraph = attrs._tableOfContentsLevel !== void 0;
192
189
  const inlineNodes = [];
193
190
  let inlineOffset = 0;
@@ -215,7 +212,7 @@ function convertParagraph(paragraph, styleResolver, nextHyperlinkInstanceIndex,
215
212
  }
216
213
  const paragraphRunFormatting = resolveRunFormattingWithoutDefaults(paragraph.formatting?.runProperties, styleResolver);
217
214
  let inheritableParagraphRunFormatting;
218
- if (paragraphRunFormatting && !isTocParagraph) inheritableParagraphRunFormatting = stripParagraphMarkFormattingForBodyRuns(paragraphRunFormatting);
215
+ if (paragraphRunFormatting && !isTocParagraph && paragraph.formatting?.styleId === void 0) inheritableParagraphRunFormatting = stripParagraphMarkFormattingForBodyRuns(paragraphRunFormatting);
219
216
  const ordinaryStyleFormatting = paragraph.formatting?.styleId === void 0 ? mergeTextFormatting(styleRunFormatting, extraRunFormatting) : mergeTextFormatting(extraRunFormatting, styleRunFormatting);
220
217
  const orderedToggleFormatting = cascadeStyleTextFormatting([
221
218
  {
@@ -233,53 +230,75 @@ function convertParagraph(paragraph, styleResolver, nextHyperlinkInstanceIndex,
233
230
  ], { ordinaryFormatting: ordinaryStyleFormatting });
234
231
  let baseRunFormatting = orderedToggleFormatting.formatting;
235
232
  if (paragraphStyleFontFamily) baseRunFormatting = mergeTextFormatting(baseRunFormatting, { fontFamily: paragraphStyleFontFamily });
236
- const paragraphMarkPrecedesStyle = paragraph.formatting?.styleId !== void 0;
237
- const ordinaryDefaultRunFormatting = paragraphMarkPrecedesStyle ? mergeTextFormatting(inheritableParagraphRunFormatting, baseRunFormatting) : mergeTextFormatting(baseRunFormatting, inheritableParagraphRunFormatting);
238
- const defaultToggleCascade = paragraphMarkPrecedesStyle ? cascadeStyleTextFormatting([{
233
+ const defaultCharacterFormatting = styleResolver?.getDefaultCharacterStyle()?.rPr;
234
+ const ordinaryBaseWithDefaultCharacter = mergeTextFormatting(defaultCharacterFormatting, baseRunFormatting);
235
+ const defaultCharacterStyleCascade = cascadeStyleTextFormatting([{
239
236
  cascade: orderedToggleFormatting,
240
237
  type: "carried"
241
- }], { ordinaryFormatting: ordinaryDefaultRunFormatting }) : cascadeStyleTextFormatting([{
242
- cascade: orderedToggleFormatting,
238
+ }, {
239
+ formatting: defaultCharacterFormatting,
240
+ type: "style"
241
+ }], { ordinaryFormatting: ordinaryBaseWithDefaultCharacter });
242
+ const ordinaryDefaultRunFormatting = mergeTextFormatting(ordinaryBaseWithDefaultCharacter, inheritableParagraphRunFormatting);
243
+ const defaultToggleCascade = cascadeStyleTextFormatting([{
244
+ cascade: defaultCharacterStyleCascade,
243
245
  type: "carried"
244
246
  }, {
245
247
  formatting: inheritableParagraphRunFormatting,
246
248
  type: "direct"
247
249
  }], { ordinaryFormatting: ordinaryDefaultRunFormatting });
248
250
  const defaultRunFormatting = defaultToggleCascade.formatting;
251
+ if (extraRunFormatting !== void 0) if (defaultRunFormatting) attrs.defaultTextFormatting = defaultRunFormatting;
252
+ else delete attrs.defaultTextFormatting;
249
253
  const getInheritedRunFormatting = (formatting, fieldType) => {
254
+ const hasCharacterStyle = formatting?.styleId !== void 0;
255
+ const inheritedBaseFormatting = hasCharacterStyle ? baseRunFormatting : ordinaryBaseWithDefaultCharacter;
256
+ const inheritedToggleCascade = hasCharacterStyle ? orderedToggleFormatting : defaultCharacterStyleCascade;
250
257
  if (fieldType === "TOC") return {
251
- formatting: hasDirectRunFormatting(formatting) ? suppressParagraphMarkFormatting(baseRunFormatting, void 0, formatting) : baseRunFormatting,
252
- toggleCascade: orderedToggleFormatting
258
+ formatting: hasDirectRunFormatting(formatting) ? suppressParagraphMarkFormatting({
259
+ baseFormatting: inheritedBaseFormatting,
260
+ directFormatting: formatting,
261
+ paragraphMarkFormatting: void 0
262
+ }) : inheritedBaseFormatting,
263
+ ...!hasCharacterStyle ? { implicitCharacterStyleApplied: true } : {},
264
+ toggleCascade: inheritedToggleCascade
253
265
  };
254
266
  if (!(hasDirectRunFormatting(formatting) || formatting?.styleId !== void 0)) return {
255
267
  formatting: defaultRunFormatting,
268
+ implicitCharacterStyleApplied: true,
256
269
  toggleCascade: defaultToggleCascade
257
270
  };
258
- const suppressedFormatting = suppressParagraphMarkFormatting(baseRunFormatting, inheritableParagraphRunFormatting, formatting, paragraphMarkPrecedesStyle);
271
+ const suppressedFormatting = suppressParagraphMarkFormatting({
272
+ baseFormatting: inheritedBaseFormatting,
273
+ directFormatting: formatting,
274
+ paragraphMarkFormatting: inheritableParagraphRunFormatting
275
+ });
259
276
  const paragraphMarkOverrides = getParagraphMarkSuppressionOverrides({
260
277
  directFormatting: formatting,
261
278
  paragraphMarkFormatting: inheritableParagraphRunFormatting,
262
279
  suppressedFormatting
263
- });
280
+ }) ?? (inheritableParagraphRunFormatting ? {} : void 0);
264
281
  return {
265
282
  formatting: suppressedFormatting,
283
+ ...!hasCharacterStyle ? { implicitCharacterStyleApplied: true } : {},
266
284
  ...paragraphMarkOverrides ? { paragraphMarkOverrides } : {},
267
- toggleCascade: orderedToggleFormatting
285
+ toggleCascade: inheritedToggleCascade
268
286
  };
269
287
  };
270
288
  const emitTrackedChange = (change, markType, moveKind) => {
271
- emitInlineNodes(convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, moveKind, textBoxAnchors));
289
+ emitInlineNodes(convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, moveKind, textBoxAnchors));
272
290
  };
273
291
  for (const content of paragraph.content) if (content.type === "commentRangeStart") commentIds.add(content.id);
274
292
  else if (content.type === "commentRangeEnd") commentIds.delete(content.id);
275
293
  else if (content.type === "commentReference") anchorPointComment(inlineNodes, content.id);
276
- else if (content.type === "run") emitInlineNodes(convertRun(content, getInheritedRunFormatting(content.formatting), styleResolver, textBoxAnchors));
294
+ else if (content.type === "run") emitInlineNodes(convertRun(content, getInheritedRunFormatting(content.formatting), nextPageBreakRunOwnerId, styleResolver, textBoxAnchors));
277
295
  else if (content.type === "hyperlink") {
278
296
  const linkNodes = convertHyperlink(content, {
279
297
  getInheritedRunFormatting,
280
298
  styleResolver,
281
299
  hyperlinkIndex: nextHyperlinkInstanceIndex(),
282
- textBoxAnchors
300
+ textBoxAnchors,
301
+ nextPageBreakRunOwnerId
283
302
  });
284
303
  if (linkNodes.length === 0) {
285
304
  emptyHyperlinks ??= [];
@@ -297,9 +316,10 @@ function convertParagraph(paragraph, styleResolver, nextHyperlinkInstanceIndex,
297
316
  getInheritedRunFormatting,
298
317
  styleResolver,
299
318
  nextHyperlinkInstanceIndex,
319
+ nextPageBreakRunOwnerId,
300
320
  textBoxAnchors
301
321
  }));
302
- else if (content.type === "inlineSdt") emitInlineNode(convertInlineSdt(content, nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, textBoxAnchors));
322
+ else if (content.type === "inlineSdt") emitInlineNode(convertInlineSdt(content, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, textBoxAnchors));
303
323
  else if (content.type === "insertion" || content.type === "moveTo") emitTrackedChange(content, "insertion", content.type === "moveTo" ? "moveTo" : null);
304
324
  else if (content.type === "deletion" || content.type === "moveFrom") emitTrackedChange(content, "deletion", content.type === "moveFrom" ? "moveFrom" : null);
305
325
  else if (content.type === "mathEquation") emitInlineNode(convertMathEquation(content));
@@ -323,7 +343,9 @@ function convertParagraph(paragraph, styleResolver, nextHyperlinkInstanceIndex,
323
343
  }
324
344
  if (bookmarksArr) attrs.bookmarks = bookmarksArr;
325
345
  if (emptyHyperlinks) attrs._emptyHyperlinks = emptyHyperlinks;
326
- return schema.node("paragraph", attrs, inlineNodes);
346
+ const proseParagraph = schema.node("paragraph", attrs, inlineNodes);
347
+ linkProseParagraphPropertySource(proseParagraph, paragraph);
348
+ return proseParagraph;
327
349
  }
328
350
  const resolveParagraphStyleFontFamily = (styleId, styleResolver) => {
329
351
  let style = styleId ? styleResolver.getStyle(styleId) : styleResolver.getDefaultParagraphStyle();
@@ -363,29 +385,31 @@ function anchorPointComment(nodes, commentId) {
363
385
  * Convert tracked change (insertion or deletion) content to PM nodes with
364
386
  * an insertion/deletion mark applied.
365
387
  */
366
- function convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, moveKind = null, textBoxAnchors) {
388
+ function convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, moveKind = null, textBoxAnchors) {
367
389
  const nodes = [];
368
- for (const item of change.content) if (item.type === "run") nodes.push(...convertRun(item, getInheritedRunFormatting(item.formatting), styleResolver, textBoxAnchors));
390
+ for (const item of change.content) if (item.type === "run") nodes.push(...convertRun(item, getInheritedRunFormatting(item.formatting), nextPageBreakRunOwnerId, styleResolver, textBoxAnchors));
369
391
  else if (item.type === "hyperlink") {
370
392
  const currentHyperlinkIndex = nextHyperlinkInstanceIndex();
371
393
  nodes.push(...convertHyperlink(item, {
372
394
  getInheritedRunFormatting,
373
395
  styleResolver,
374
396
  hyperlinkIndex: currentHyperlinkIndex,
375
- textBoxAnchors
397
+ textBoxAnchors,
398
+ nextPageBreakRunOwnerId
376
399
  }));
377
400
  } else if (item.type === "simpleField" || item.type === "complexField") {
378
401
  const fieldNode = convertField(item, {
379
402
  getInheritedRunFormatting,
380
403
  styleResolver,
381
404
  nextHyperlinkInstanceIndex,
405
+ nextPageBreakRunOwnerId,
382
406
  textBoxAnchors
383
407
  });
384
408
  if (fieldNode) nodes.push(fieldNode);
385
409
  } else if (item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") {
386
410
  const nestedMarkType = item.type === "insertion" || item.type === "moveTo" ? "insertion" : "deletion";
387
411
  const nestedMoveKind = item.type === "moveFrom" || item.type === "moveTo" ? item.type : null;
388
- nodes.push(...convertTrackedChange(item, nestedMarkType, nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, nestedMoveKind, textBoxAnchors));
412
+ nodes.push(...convertTrackedChange(item, nestedMarkType, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, nestedMoveKind, textBoxAnchors));
389
413
  } else if (item.type === "bookmarkStart") nodes.push(schema.node("bookmarkBoundary", {
390
414
  type: "start",
391
415
  id: item.id,
@@ -402,27 +426,17 @@ function convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, getI
402
426
  revisionId: change.info.id,
403
427
  author: change.info.author,
404
428
  date: change.info.date ?? null,
429
+ utcDate: change.info.utcDate?.value ?? null,
405
430
  initials: change.info.initials ?? null,
406
431
  moveKind
407
432
  });
408
433
  return nodes.map((node) => {
409
434
  if (node.marks.some(({ type }) => type.name === "insertion" || type.name === "deletion")) return node;
410
- if (canCarryTrackedRunMark(node, mark.type)) return node.mark(mark.addToSet(node.marks));
435
+ if (trackedRunInlineAtomDisposition(node) === "outside-wrapper") panic(`Inline atom ${JSON.stringify(node.type.name)} cannot occur in a tracked-run wrapper`);
436
+ if (canCarryTrackedRunMark(node)) return node.mark(mark.addToSet(node.marks));
411
437
  return node;
412
438
  });
413
439
  }
414
- function canCarryTrackedRunMark(node, markType) {
415
- if (node.isText) return true;
416
- if (!node.isInline) return false;
417
- if (node.type.name === "field" || node.type.name === "structuredField") return true;
418
- return node.type.allowsMarkType(markType) && (node.type.name === "image" || node.type.name === "shape" || node.type.name === "hardBreak" || node.type.name === "tab" || node.type.name === "symbol" || node.type.name === "bookmarkBoundary" || node.type.name === "textBoxAnchor");
419
- }
420
- /**
421
- * Convert ParagraphFormatting to ProseMirror paragraph attrs
422
- *
423
- * If a styleResolver is provided, resolves style-based formatting and merges
424
- * with inline formatting. Inline formatting takes precedence.
425
- */
426
440
  function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOverlay) {
427
441
  const formatting = paragraph.formatting;
428
442
  const styleId = formatting?.styleId;
@@ -442,6 +456,7 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
442
456
  if (paragraph.listRendering?.isBullet) attrs.listIsBullet = paragraph.listRendering.isBullet;
443
457
  if (paragraph.listRendering?.isLegal) attrs.listIsLegal = paragraph.listRendering.isLegal;
444
458
  if (paragraph.listRendering?.marker) attrs.listMarker = paragraph.listRendering.marker;
459
+ if (paragraph.listRendering?.markerTemplate) attrs.listMarkerTemplate = paragraph.listRendering.markerTemplate;
445
460
  if (paragraph.listRendering?.markerHidden) attrs.listMarkerHidden = paragraph.listRendering.markerHidden;
446
461
  if (paragraph.listRendering?.markerFormatting) attrs.listMarkerFormatting = paragraph.listRendering.markerFormatting;
447
462
  if (paragraph.listRendering?.markerAlignment) attrs.listMarkerAlignment = paragraph.listRendering.markerAlignment;
@@ -466,19 +481,20 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
466
481
  if (styleResolver) {
467
482
  stylePpr = styleResolver.resolveParagraphStyleInTable(styleId, tableParagraphOverlay).paragraphFormatting;
468
483
  set("alignment", formatting?.alignment ?? stylePpr?.alignment);
484
+ set("alignmentFromStyle", stylePpr?.alignment);
469
485
  set("spaceBefore", formatting?.spaceBefore ?? stylePpr?.spaceBefore);
470
486
  set("spaceAfter", formatting?.spaceAfter ?? stylePpr?.spaceAfter);
471
487
  set("lineSpacing", formatting?.lineSpacing ?? stylePpr?.lineSpacing);
472
488
  set("lineSpacingRule", formatting?.lineSpacingRule ?? stylePpr?.lineSpacingRule);
473
- set("lineSpacingExplicit", formatting?.lineSpacing !== void 0 || formatting?.lineSpacingRule !== void 0 ? true : void 0);
489
+ set("lineSpacingExplicit", lineSpacingProvenanceFromSpacing(formatting));
474
490
  set("snapToGrid", formatting?.snapToGrid ?? stylePpr?.snapToGrid);
475
491
  set("spacingExplicit", formatting?.spacingExplicit);
476
492
  const paragraphStyle = styleId ? styleResolver.getStyle(styleId) ?? styleResolver.getDefaultParagraphStyle() : styleResolver.getDefaultParagraphStyle();
477
493
  const docDefaultSpacing = styleResolver.getDocDefaults()?.pPr;
478
- const spacingFromImplicitDefaultStyle = {};
479
- if (!styleId && formatting?.spaceBefore === void 0 && paragraphStyle?.pPr?.spaceBefore !== void 0) spacingFromImplicitDefaultStyle.before = true;
480
- if (!styleId && formatting?.spaceAfter === void 0 && paragraphStyle?.pPr?.spaceAfter !== void 0) spacingFromImplicitDefaultStyle.after = true;
481
- if (spacingFromImplicitDefaultStyle.before || spacingFromImplicitDefaultStyle.after) attrs.spacingFromImplicitDefaultStyle = spacingFromImplicitDefaultStyle;
494
+ const spacingFromStyle = {};
495
+ if (formatting?.spaceBefore === void 0 && stylePpr?.spaceBefore !== void 0) spacingFromStyle.before = true;
496
+ if (formatting?.spaceAfter === void 0 && stylePpr?.spaceAfter !== void 0) spacingFromStyle.after = true;
497
+ if (spacingFromStyle.before || spacingFromStyle.after) attrs.spacingFromImplicitDefaultStyle = spacingFromStyle;
482
498
  const spacingFromDocDefaults = {};
483
499
  if (formatting?.spaceBefore === void 0 && tableParagraphOverlay?.spaceBefore === void 0 && paragraphStyle?.pPr?.spaceBefore === void 0 && docDefaultSpacing?.spaceBefore !== void 0) spacingFromDocDefaults.before = true;
484
500
  if (formatting?.spaceAfter === void 0 && tableParagraphOverlay?.spaceAfter === void 0 && paragraphStyle?.pPr?.spaceAfter === void 0 && docDefaultSpacing?.spaceAfter !== void 0) spacingFromDocDefaults.after = true;
@@ -502,9 +518,12 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
502
518
  set("runInWithNext", formatting?.runInWithNext ?? stylePpr?.runInWithNext);
503
519
  set("outlineLevel", formatting?.outlineLevel ?? stylePpr?.outlineLevel);
504
520
  set("direction", directionFromBidi(formatting?.bidi ?? stylePpr?.bidi));
505
- set("defaultTextFormatting", resolveParagraphDefaultTextFormatting(styleId, formatting, styleResolver, { includeParagraphMarkRunProperties: tableOfContentsLevel === void 0 }));
506
- if (!formatting?.numPr && stylePpr?.numPr && stylePpr.numPr.numId !== 0) {
507
- attrs.numPr = stylePpr.numPr;
521
+ set("defaultTextFormatting", resolveParagraphDefaultTextFormatting(styleId, formatting, styleResolver, { includeParagraphMarkRunProperties: tableOfContentsLevel === void 0 && (styleId === void 0 || paragraph.content.length === 0) }));
522
+ if (stylePpr?.numPr && formatting?.numPr?.numId === void 0 && stylePpr.numPr.numId !== 0) {
523
+ attrs.numPr = {
524
+ ...stylePpr.numPr,
525
+ ...formatting?.numPr
526
+ };
508
527
  attrs.numPrFromStyle = stylePpr.numPr;
509
528
  }
510
529
  } else {
@@ -513,6 +532,7 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
513
532
  set("spaceAfter", formatting?.spaceAfter);
514
533
  set("lineSpacing", formatting?.lineSpacing);
515
534
  set("lineSpacingRule", formatting?.lineSpacingRule);
535
+ set("lineSpacingExplicit", lineSpacingProvenanceFromSpacing(formatting));
516
536
  set("snapToGrid", formatting?.snapToGrid);
517
537
  set("spacingExplicit", formatting?.spacingExplicit);
518
538
  set("indentLeft", formatting?.indentLeft);
@@ -548,15 +568,19 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
548
568
  if (afterAutospacing) setAutospacingBaseValue(base, "after", attrs.spaceAfter);
549
569
  attrs._autospacingBase = base;
550
570
  }
551
- return attrs;
571
+ return {
572
+ attrs,
573
+ effectiveFrame: formatting?.frame === void 0 ? stylePpr?.frame : {
574
+ ...stylePpr?.frame,
575
+ ...formatting.frame
576
+ }
577
+ };
552
578
  }
553
579
  /**
554
- * Pick the paragraph-spacing fields out of a table style's (or conditional
555
- * region's) `w:pPr` for use as the cell-paragraph cascade overlay. Narrower
556
- * than the full `ParagraphFormatting` bag — see
557
- * {@link TableCellParagraphSpacingOverlay}.
580
+ * Pick the modeled paragraph fields out of a table style's (or conditional
581
+ * region's) `w:pPr` for use as the cell-paragraph cascade overlay.
558
582
  */
559
- function extractTableParagraphSpacingOverlay(pPr) {
583
+ function extractTableParagraphOverlay(pPr) {
560
584
  if (!pPr) return;
561
585
  const overlay = {};
562
586
  if (pPr.spaceBefore !== void 0) overlay.spaceBefore = pPr.spaceBefore;
@@ -564,6 +588,7 @@ function extractTableParagraphSpacingOverlay(pPr) {
564
588
  if (pPr.lineSpacing !== void 0) overlay.lineSpacing = pPr.lineSpacing;
565
589
  if (pPr.lineSpacingRule !== void 0) overlay.lineSpacingRule = pPr.lineSpacingRule;
566
590
  if (pPr.contextualSpacing !== void 0) overlay.contextualSpacing = pPr.contextualSpacing;
591
+ if (pPr.frame !== void 0) overlay.frame = pPr.frame;
567
592
  return Object.keys(overlay).length > 0 ? overlay : void 0;
568
593
  }
569
594
  /**
@@ -576,11 +601,11 @@ function resolveTableStyleConditional(styleResolver, tableStyleId, conditionType
576
601
  const conditional = style.tblStylePr.find((p) => p.type === conditionType);
577
602
  if (!conditional) return;
578
603
  const mergedRunProps = mergeTextFormatting(conditional.pPr?.runProperties ? resolveRunFormattingWithoutDefaults(conditional.pPr.runProperties, styleResolver) : void 0, conditional.rPr ? resolveRunFormattingWithoutDefaults(conditional.rPr, styleResolver) : void 0);
579
- const paragraphSpacingOverlay = extractTableParagraphSpacingOverlay(conditional.pPr);
604
+ const paragraphOverlay = extractTableParagraphOverlay(conditional.pPr);
580
605
  const result = {};
581
606
  if (conditional.tcPr) result.tcPr = conditional.tcPr;
582
607
  if (mergedRunProps) result.rPr = mergedRunProps;
583
- if (paragraphSpacingOverlay) result.pPr = paragraphSpacingOverlay;
608
+ if (paragraphOverlay) result.pPr = paragraphOverlay;
584
609
  return result;
585
610
  }
586
611
  function resolveTableBaseStyle(styleResolver, tableStyleId) {
@@ -588,11 +613,11 @@ function resolveTableBaseStyle(styleResolver, tableStyleId) {
588
613
  const style = styleResolver.getStyle(tableStyleId);
589
614
  if (!style) return;
590
615
  const mergedRunProps = mergeTextFormatting(style.pPr?.runProperties ? resolveRunFormattingWithoutDefaults(style.pPr.runProperties, styleResolver) : void 0, style.rPr ? resolveRunFormattingWithoutDefaults(style.rPr, styleResolver) : void 0);
591
- const paragraphSpacingOverlay = extractTableParagraphSpacingOverlay(style.pPr);
616
+ const paragraphOverlay = extractTableParagraphOverlay(style.pPr);
592
617
  const result = {};
593
618
  if (style.tcPr) result.tcPr = style.tcPr;
594
619
  if (mergedRunProps) result.rPr = mergedRunProps;
595
- if (paragraphSpacingOverlay) result.pPr = paragraphSpacingOverlay;
620
+ if (paragraphOverlay) result.pPr = paragraphOverlay;
596
621
  return result.tcPr || result.rPr || result.pPr ? result : void 0;
597
622
  }
598
623
  function mergeConditionalStyles(base, override) {
@@ -627,70 +652,11 @@ function mergeConditionalStyles(base, override) {
627
652
  if (mergedPPr) merged.pPr = mergedPPr;
628
653
  return merged;
629
654
  }
630
- function hasDirectRunFormatting(formatting) {
631
- if (!formatting) return false;
632
- for (const key in formatting) {
633
- if (!Object.hasOwn(formatting, key)) continue;
634
- const value = Reflect.get(formatting, key);
635
- if (key !== "styleId" && value !== void 0) return true;
636
- }
637
- return false;
638
- }
639
- function stripParagraphMarkOnlyFormatting(formatting) {
640
- const { allCaps: _ac, highlight: _h, shading: _s, smallCaps: _sc, vertAlign: _va, ...rest } = formatting;
641
- return Object.keys(rest).length > 0 ? rest : void 0;
642
- }
643
- function stripParagraphMarkFormattingForBodyRuns(formatting) {
644
- const paragraphMarkFormatting = stripParagraphMarkOnlyFormatting(formatting);
645
- if (!paragraphMarkFormatting) return;
646
- const { fontFamily: _fontFamily, ...bodyRunFormatting } = paragraphMarkFormatting;
647
- return Object.keys(bodyRunFormatting).length > 0 ? bodyRunFormatting : void 0;
648
- }
649
- const PARAGRAPH_MARK_BOOLEAN_KEYS = [
650
- "bold",
651
- "italic",
652
- "strike",
653
- "doubleStrike",
654
- "allCaps",
655
- "smallCaps",
656
- "hidden",
657
- "emboss",
658
- "imprint",
659
- "shadow",
660
- "outline",
661
- "rtl"
662
- ];
663
- function suppressParagraphMarkFormatting(base, paragraphMark, direct, paragraphMarkPrecedesStyle = false) {
664
- if (!paragraphMark) return base;
665
- const result = (paragraphMarkPrecedesStyle ? mergeTextFormatting(paragraphMark, base) : mergeTextFormatting(base, paragraphMark)) ?? {};
666
- for (const key of PARAGRAPH_MARK_BOOLEAN_KEYS) suppressBooleanParagraphMark(result, base, paragraphMark, direct, key);
667
- if (paragraphMark.fontSize !== void 0 && direct?.fontSize === void 0 && base?.fontSize !== void 0) result.fontSize = base.fontSize;
668
- if (paragraphMark.fontSizeCs !== void 0 && direct?.fontSizeCs === void 0 && base?.fontSizeCs !== void 0) result.fontSizeCs = base.fontSizeCs;
669
- if (paragraphMark.underline !== void 0 && direct?.underline === void 0) result.underline = { style: "none" };
670
- if (paragraphMark.spacing !== void 0 && direct?.spacing === void 0) result.spacing = 0;
671
- return Object.keys(result).length > 0 ? result : void 0;
672
- }
673
- function getParagraphMarkSuppressionOverrides({ directFormatting, paragraphMarkFormatting, suppressedFormatting }) {
674
- if (!paragraphMarkFormatting) return;
675
- const overrides = {};
676
- for (const key of PARAGRAPH_MARK_BOOLEAN_KEYS) if (paragraphMarkFormatting[key] !== void 0 && directFormatting?.[key] === void 0 && suppressedFormatting?.[key] === false) overrides[key] = false;
677
- if (paragraphMarkFormatting.underline !== void 0 && directFormatting?.underline === void 0 && suppressedFormatting?.underline?.style === "none") overrides.underline = { style: "none" };
678
- return Object.keys(overrides).length > 0 ? overrides : void 0;
679
- }
680
- function suppressBooleanParagraphMark(result, base, paragraphMark, direct, key) {
681
- if (paragraphMark[key] === void 0 || direct?.[key] !== void 0) return;
682
- result[key] = base?.[key] ?? false;
683
- }
684
655
  function resolveTextFormatting(formatting, styleResolver) {
685
656
  if (!formatting) return styleResolver?.resolveRunStyle(null);
686
657
  if (!styleResolver) return formatting;
687
658
  return mergeTextFormatting(styleResolver.resolveRunStyle(formatting.styleId), formatting);
688
659
  }
689
- /**
690
- * Resolve an embedded character-style reference without importing
691
- * `docDefaults`. The caller already has the paragraph cascade, including
692
- * document defaults, and will layer these own properties over it.
693
- */
694
660
  function resolveRunFormattingWithoutDefaults(formatting, styleResolver) {
695
661
  if (!formatting || !styleResolver) return formatting;
696
662
  return cascadeStyleTextFormatting([{
@@ -701,6 +667,7 @@ function resolveRunFormattingWithoutDefaults(formatting, styleResolver) {
701
667
  type: "direct"
702
668
  }]).formatting;
703
669
  }
670
+ /** @internal Recompute a paragraph's inherited run defaults from authored package state. */
704
671
  function resolveParagraphDefaultTextFormatting(styleId, formatting, styleResolver, options = {}) {
705
672
  const style = styleId ? styleResolver.getStyle(styleId) ?? styleResolver.getDefaultParagraphStyle() : styleResolver.getDefaultParagraphStyle();
706
673
  const paragraphStyleRpr = style?.type === "paragraph" ? style.rPr : void 0;
@@ -721,10 +688,6 @@ function resolveParagraphDefaultTextFormatting(styleId, formatting, styleResolve
721
688
  }
722
689
  ], { ordinaryFormatting: mergeTextFormatting(mergeTextFormatting(styleResolver.getDocDefaults()?.rPr, styleResolver.getDefaultCharacterStyle()?.rPr), paragraphStyleRpr) });
723
690
  const bodyRunDefaults = orderedBodyToggleFormatting.formatting;
724
- if (styleId !== void 0) return cascadeStyleTextFormatting([{
725
- cascade: orderedBodyToggleFormatting,
726
- type: "carried"
727
- }], { ordinaryFormatting: mergeTextFormatting(paragraphRunProperties, bodyRunDefaults) }).formatting;
728
691
  return cascadeStyleTextFormatting([{
729
692
  cascade: orderedBodyToggleFormatting,
730
693
  type: "carried"
@@ -826,6 +789,7 @@ function paragraphContentHasMeaningfulContent(content) {
826
789
  return true;
827
790
  }
828
791
  function convertTable(table, styleResolver, context) {
792
+ for (const row of table.rows) for (const cell of row.cells) assertSourceContainerHasNoPageBreakRun(cell.content, "table-cell", context.pageBreakRunSourceDescendants);
829
793
  const rowSpanMap = calculateRowSpans(table);
830
794
  const columnWidths = table.columnWidths;
831
795
  const totalWidth = columnWidths?.reduce((sum, w) => sum + w, 0) ?? 0;
@@ -936,7 +900,9 @@ function convertTableRow(row, styleResolver, context, isHeaderRow, columnWidths,
936
900
  trIns: {
937
901
  revisionId: row.structuralChange.info.id,
938
902
  author: row.structuralChange.info.author,
939
- date: row.structuralChange.info.date ?? null
903
+ date: row.structuralChange.info.date ?? null,
904
+ ...row.structuralChange.info.utcDate ? { utcDate: row.structuralChange.info.utcDate.value } : {},
905
+ ...row.structuralChange.info.initials ? { initials: row.structuralChange.info.initials } : {}
940
906
  }
941
907
  };
942
908
  else if (row.structuralChange?.type === "tableRowDeletion") attrs = {
@@ -944,7 +910,9 @@ function convertTableRow(row, styleResolver, context, isHeaderRow, columnWidths,
944
910
  trDel: {
945
911
  revisionId: row.structuralChange.info.id,
946
912
  author: row.structuralChange.info.author,
947
- date: row.structuralChange.info.date ?? null
913
+ date: row.structuralChange.info.date ?? null,
914
+ ...row.structuralChange.info.utcDate ? { utcDate: row.structuralChange.info.utcDate.value } : {},
915
+ ...row.structuralChange.info.initials ? { initials: row.structuralChange.info.initials } : {}
948
916
  }
949
917
  };
950
918
  const numCells = row.cells.length;
@@ -958,10 +926,7 @@ function convertTableRow(row, styleResolver, context, isHeaderRow, columnWidths,
958
926
  if (effectiveCells.length === 0) {
959
927
  const fallback = {
960
928
  type: "tableCell",
961
- content: [{
962
- type: "paragraph",
963
- content: []
964
- }]
929
+ content: []
965
930
  };
966
931
  if (totalCols > 1) fallback.formatting = { gridSpan: totalCols };
967
932
  effectiveCells = [fallback];
@@ -1084,7 +1049,9 @@ function convertTableCell({ cell, styleResolver, context, isHeader, gridWidthPer
1084
1049
  info: {
1085
1050
  revisionId: cell.structuralChange.info.id,
1086
1051
  author: cell.structuralChange.info.author,
1087
- date: cell.structuralChange.info.date ?? null
1052
+ date: cell.structuralChange.info.date ?? null,
1053
+ ...cell.structuralChange.info.utcDate ? { utcDate: cell.structuralChange.info.utcDate.value } : {},
1054
+ ...cell.structuralChange.info.initials ? { initials: cell.structuralChange.info.initials } : {}
1088
1055
  }
1089
1056
  };
1090
1057
  else if (cell.structuralChange?.type === "tableCellDeletion") attrs.cellMarker = {
@@ -1092,7 +1059,9 @@ function convertTableCell({ cell, styleResolver, context, isHeader, gridWidthPer
1092
1059
  info: {
1093
1060
  revisionId: cell.structuralChange.info.id,
1094
1061
  author: cell.structuralChange.info.author,
1095
- date: cell.structuralChange.info.date ?? null
1062
+ date: cell.structuralChange.info.date ?? null,
1063
+ ...cell.structuralChange.info.utcDate ? { utcDate: cell.structuralChange.info.utcDate.value } : {},
1064
+ ...cell.structuralChange.info.initials ? { initials: cell.structuralChange.info.initials } : {}
1096
1065
  }
1097
1066
  };
1098
1067
  else if (cell.structuralChange?.type === "tableCellMerge") attrs.cellMarker = {
@@ -1100,7 +1069,9 @@ function convertTableCell({ cell, styleResolver, context, isHeader, gridWidthPer
1100
1069
  info: {
1101
1070
  revisionId: cell.structuralChange.info.id,
1102
1071
  author: cell.structuralChange.info.author,
1103
- date: cell.structuralChange.info.date ?? null
1072
+ date: cell.structuralChange.info.date ?? null,
1073
+ ...cell.structuralChange.info.utcDate ? { utcDate: cell.structuralChange.info.utcDate.value } : {},
1074
+ ...cell.structuralChange.info.initials ? { initials: cell.structuralChange.info.initials } : {}
1104
1075
  },
1105
1076
  ...cell.structuralChange.verticalMerge !== void 0 ? { verticalMerge: cell.structuralChange.verticalMerge } : {},
1106
1077
  ...cell.structuralChange.verticalMergeOriginal !== void 0 ? { verticalMergeOriginal: cell.structuralChange.verticalMergeOriginal } : {}
@@ -1120,14 +1091,19 @@ function convertTableCell({ cell, styleResolver, context, isHeader, gridWidthPer
1120
1091
  return schema.node(nodeType, attrs, contentNodes);
1121
1092
  }
1122
1093
  function standaloneTableCellToProseMirror(cell, nodeType) {
1094
+ const nextTextBoxGroupId = createTextBoxGroupIdFactory();
1095
+ const nextHyperlinkInstanceIndex = createHyperlinkInstanceIndexAllocator();
1096
+ const pageBreakRunSourceDescendants = buildPageBreakRunSourceDescendantIndex(cell.content);
1097
+ assertSourceContainerHasNoPageBreakRun(cell.content, "table-cell", pageBreakRunSourceDescendants);
1123
1098
  return convertTableCell({
1124
1099
  cell,
1125
1100
  styleResolver: null,
1126
1101
  context: {
1127
1102
  theme: null,
1128
- nextTextBoxGroupId: createTextBoxGroupIdFactory(),
1129
- nextHyperlinkInstanceIndex: createHyperlinkInstanceIndexAllocator(),
1130
- pairedBookmarkIds: collectPairedBookmarkIds(cell.content)
1103
+ nextTextBoxGroupId,
1104
+ nextHyperlinkInstanceIndex,
1105
+ pairedBookmarkIds: collectPairedBookmarkIds(cell.content),
1106
+ pageBreakRunSourceDescendants
1131
1107
  },
1132
1108
  isHeader: nodeType === "tableHeader",
1133
1109
  gridWidthPercent: void 0,
@@ -1140,16 +1116,26 @@ function standaloneTableCellToProseMirror(cell, nodeType) {
1140
1116
  defaultCellMargins: void 0
1141
1117
  });
1142
1118
  }
1143
- function convertField(field, { getInheritedRunFormatting, styleResolver, nextHyperlinkInstanceIndex, textBoxAnchors }) {
1119
+ function convertField(field, { getInheritedRunFormatting, styleResolver, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, textBoxAnchors }) {
1144
1120
  let displayText = "";
1145
1121
  let fieldFormatting;
1122
+ let fieldPropertyChanges;
1146
1123
  const inlineNodes = [];
1147
- const hasStructuredSourceContent = field.type === "simpleField" && field.content.some((content) => content.type === "hyperlink");
1124
+ const runHasPageBreak = (run) => run.content.some((content) => content.type === "break" && content.breakType === "page");
1125
+ if (field.type === "complexField" && field.fieldCode.some(runHasPageBreak)) throw new UnsupportedDocxToProseMirrorConversionError({
1126
+ message: "A complex-field instruction containing an explicit page break cannot be represented in the editor model",
1127
+ owner: "complex-field-instruction",
1128
+ contentType: "break"
1129
+ });
1130
+ const hasPageBreakContent = field.type === "simpleField" ? field.content.some((content) => content.type === "run" ? runHasPageBreak(content) : content.children.some((child) => child.type === "run" && runHasPageBreak(child))) : field.fieldResult.some(runHasPageBreak);
1131
+ if (hasPageBreakContent) assertPageBreakFieldResultIsRepresentable(field);
1132
+ const hasStructuredSourceContent = hasPageBreakContent || field.type === "simpleField" && field.content.some((content) => content.type === "hyperlink");
1148
1133
  const appendRun = (run) => {
1149
1134
  for (const content of run.content) if (content.type === "text") displayText += content.text;
1150
1135
  fieldFormatting ??= run.formatting;
1136
+ fieldPropertyChanges ??= run.propertyChanges;
1151
1137
  if (!hasStructuredSourceContent) return;
1152
- inlineNodes.push(...convertRun(run, getInheritedRunFormatting(run.formatting, field.fieldType), styleResolver, textBoxAnchors));
1138
+ inlineNodes.push(...convertRun(run, getInheritedRunFormatting(run.formatting, field.fieldType), nextPageBreakRunOwnerId, styleResolver, textBoxAnchors));
1153
1139
  };
1154
1140
  if (field.type === "simpleField") for (const content of field.content) {
1155
1141
  if (content.type === "run") {
@@ -1159,12 +1145,14 @@ function convertField(field, { getInheritedRunFormatting, styleResolver, nextHyp
1159
1145
  for (const child of content.children) if (child.type === "run") {
1160
1146
  for (const runContent of child.content) if (runContent.type === "text") displayText += runContent.text;
1161
1147
  fieldFormatting ??= child.formatting;
1148
+ fieldPropertyChanges ??= child.propertyChanges;
1162
1149
  }
1163
1150
  inlineNodes.push(...convertHyperlink(content, {
1164
1151
  getInheritedRunFormatting: (formatting) => getInheritedRunFormatting(formatting, field.fieldType),
1165
1152
  styleResolver,
1166
1153
  hyperlinkIndex: nextHyperlinkInstanceIndex(),
1167
- textBoxAnchors
1154
+ textBoxAnchors,
1155
+ nextPageBreakRunOwnerId
1168
1156
  }));
1169
1157
  }
1170
1158
  else for (const run of field.fieldResult) appendRun(run);
@@ -1172,7 +1160,8 @@ function convertField(field, { getInheritedRunFormatting, styleResolver, nextHyp
1172
1160
  const inheritedFormatting = getInheritedRunFormatting(fieldFormatting, field.fieldType);
1173
1161
  const { marks } = buildRunMarks(fieldFormatting, inheritedFormatting, styleResolver);
1174
1162
  const hasConvertedHyperlinkContent = inlineNodes.some((node) => node.marks.some((mark) => mark.type.name === "hyperlink"));
1175
- const createStructuredField = hasStructuredSourceContent && hasConvertedHyperlinkContent;
1163
+ const createStructuredField = inlineNodes.some((node) => node.type.name === "pageBreakRun") || hasStructuredSourceContent && hasConvertedHyperlinkContent;
1164
+ if (!createStructuredField && fieldPropertyChanges && fieldPropertyChanges.length > 0) marks.push(schema.mark("runPropertyChange", { changes: [...fieldPropertyChanges] }));
1176
1165
  return schema.node(createStructuredField ? "structuredField" : "field", {
1177
1166
  fieldType: field.fieldType,
1178
1167
  instruction: field.instruction,
@@ -1195,18 +1184,19 @@ function convertMathEquation(math) {
1195
1184
  /**
1196
1185
  * Convert an InlineSdt to a ProseMirror sdt node with inline content.
1197
1186
  */
1198
- function convertInlineSdt(sdt, nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, textBoxAnchors) {
1187
+ function convertInlineSdt(sdt, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, textBoxAnchors) {
1199
1188
  const props = sdt.properties;
1200
1189
  const inlineNodes = [];
1201
1190
  for (const content of sdt.content) if (content.type === "run") {
1202
- const runNodes = convertRun(content, getInheritedRunFormatting(content.formatting), styleResolver, textBoxAnchors);
1191
+ const runNodes = convertRun(content, getInheritedRunFormatting(content.formatting), nextPageBreakRunOwnerId, styleResolver, textBoxAnchors);
1203
1192
  inlineNodes.push(...runNodes);
1204
1193
  } else if (content.type === "hyperlink") {
1205
1194
  const linkNodes = convertHyperlink(content, {
1206
1195
  getInheritedRunFormatting,
1207
1196
  styleResolver,
1208
1197
  hyperlinkIndex: nextHyperlinkInstanceIndex(),
1209
- textBoxAnchors
1198
+ textBoxAnchors,
1199
+ nextPageBreakRunOwnerId
1210
1200
  });
1211
1201
  inlineNodes.push(...linkNodes);
1212
1202
  } else if (content.type === "simpleField" || content.type === "complexField") {
@@ -1214,16 +1204,17 @@ function convertInlineSdt(sdt, nextHyperlinkInstanceIndex, getInheritedRunFormat
1214
1204
  getInheritedRunFormatting,
1215
1205
  styleResolver,
1216
1206
  nextHyperlinkInstanceIndex,
1207
+ nextPageBreakRunOwnerId,
1217
1208
  textBoxAnchors
1218
1209
  });
1219
1210
  if (fieldNode) inlineNodes.push(fieldNode);
1220
1211
  } else if (content.type === "inlineSdt") {
1221
- const nestedSdt = convertInlineSdt(content, nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, textBoxAnchors);
1212
+ const nestedSdt = convertInlineSdt(content, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, textBoxAnchors);
1222
1213
  if (nestedSdt) inlineNodes.push(nestedSdt);
1223
- } else if (content.type === "insertion") inlineNodes.push(...convertTrackedChange(content, "insertion", nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, null, textBoxAnchors));
1224
- else if (content.type === "deletion") inlineNodes.push(...convertTrackedChange(content, "deletion", nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, null, textBoxAnchors));
1225
- else if (content.type === "moveTo") inlineNodes.push(...convertTrackedChange(content, "insertion", nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, "moveTo", textBoxAnchors));
1226
- else if (content.type === "moveFrom") inlineNodes.push(...convertTrackedChange(content, "deletion", nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, "moveFrom", textBoxAnchors));
1214
+ } else if (content.type === "insertion") inlineNodes.push(...convertTrackedChange(content, "insertion", nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, null, textBoxAnchors));
1215
+ else if (content.type === "deletion") inlineNodes.push(...convertTrackedChange(content, "deletion", nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, null, textBoxAnchors));
1216
+ else if (content.type === "moveTo") inlineNodes.push(...convertTrackedChange(content, "insertion", nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, "moveTo", textBoxAnchors));
1217
+ else if (content.type === "moveFrom") inlineNodes.push(...convertTrackedChange(content, "deletion", nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, "moveFrom", textBoxAnchors));
1227
1218
  else {
1228
1219
  const mathNode = convertMathEquation(content);
1229
1220
  if (mathNode) inlineNodes.push(mathNode);
@@ -1236,19 +1227,208 @@ function convertInlineSdt(sdt, nextHyperlinkInstanceIndex, getInheritedRunFormat
1236
1227
  * @param run - The run to convert
1237
1228
  * @param resolvedStyleFormatting - Paragraph formatting and its explicit style-toggle state
1238
1229
  */
1239
- function convertRun(run, resolvedStyleFormatting, styleResolver, textBoxAnchors) {
1230
+ function convertRun(run, resolvedStyleFormatting, nextPageBreakRunOwnerId, styleResolver, textBoxAnchors) {
1231
+ assertPageBreakSourceRunIsRepresentable(run);
1240
1232
  const nodes = [];
1241
1233
  const { marks, mergedFormatting } = buildRunMarks(run.formatting, resolvedStyleFormatting, styleResolver);
1242
1234
  if (run.propertyChanges && run.propertyChanges.length > 0) marks.push(schema.mark("runPropertyChange", { changes: [...run.propertyChanges] }));
1235
+ if (run.content.some((content) => content.type === "break" && content.breakType === "page")) marks.push(schema.mark("pageBreakRunOwner", { id: nextPageBreakRunOwnerId() }));
1243
1236
  for (const content of run.content) {
1244
1237
  const contentNodes = convertRunContent(content, marks, mergedFormatting, textBoxAnchors);
1245
1238
  nodes.push(...contentNodes);
1246
1239
  }
1247
1240
  return nodes;
1248
1241
  }
1242
+ function assertPageBreakSourceRunIsRepresentable(run) {
1243
+ if (!run.content.some((content) => content.type === "break" && content.breakType === "page")) return;
1244
+ assertRunContentIsRepresentableBesidePageBreak(run, "page-break-bearing-run");
1245
+ }
1246
+ const PAGE_BREAK_CONTAINER_DESCRIPTIONS = {
1247
+ "table-cell": "A table cell containing an explicit page break",
1248
+ "text-box": "A text box containing an explicit page break"
1249
+ };
1250
+ const PAGE_BREAK_PARAGRAPH_OWNERS = {
1251
+ borders: "paragraph-borders",
1252
+ frame: "paragraph-frame",
1253
+ outline: "paragraph-outline",
1254
+ textBoxAnchor: "paragraph-text-box-anchor"
1255
+ };
1256
+ function assertSourceContainerHasNoPageBreakRun(content, owner, sourceDescendants) {
1257
+ if (!sourceDescendants.containsPageBreakRun(content)) return;
1258
+ throw new UnsupportedDocxToProseMirrorConversionError({
1259
+ message: `${PAGE_BREAK_CONTAINER_DESCRIPTIONS[owner]} cannot be represented in the editor model`,
1260
+ owner,
1261
+ contentType: "break"
1262
+ });
1263
+ }
1264
+ function assertParagraphPageBreakCanBeProjected({ paragraph, attrs, effectiveFrame, sourceDescendants }) {
1265
+ const sourceFeatures = sourceDescendants.paragraphFeatures(paragraph);
1266
+ if (!sourceFeatures.hasPageBreakRun) return;
1267
+ const disposition = pageBreakRunParagraphProjectionDispositionForFeatures({
1268
+ attrs,
1269
+ effectiveFrame,
1270
+ hasTextBoxAnchor: sourceFeatures.hasTextBoxShape && !sourceFeatures.pageBreakSharesTextBoxShape
1271
+ });
1272
+ if (disposition.status === "supported") return;
1273
+ throw new UnsupportedDocxToProseMirrorConversionError({
1274
+ message: disposition.message,
1275
+ owner: PAGE_BREAK_PARAGRAPH_OWNERS[disposition.reason],
1276
+ contentType: "break"
1277
+ });
1278
+ }
1279
+ function assertPageBreakFieldResultIsRepresentable(field) {
1280
+ if (field.type === "complexField") {
1281
+ for (const run of field.fieldResult) assertRunContentIsRepresentableBesidePageBreak(run, "field-result");
1282
+ return;
1283
+ }
1284
+ for (const content of field.content) {
1285
+ if (content.type === "run") {
1286
+ assertRunContentIsRepresentableBesidePageBreak(content, "field-result");
1287
+ continue;
1288
+ }
1289
+ for (const child of content.children) if (child.type === "run") assertRunContentIsRepresentableBesidePageBreak(child, "field-result");
1290
+ }
1291
+ }
1292
+ const PAGE_BREAK_OWNER_DESCRIPTIONS = {
1293
+ "field-result": "A field result with an explicit page break",
1294
+ "page-break-bearing-run": "A page-break-bearing run"
1295
+ };
1296
+ const unsupportedPageBreakContent = (owner, contentType) => {
1297
+ const description = contentType === "shape" ? "a text-box shape" : contentType;
1298
+ throw new UnsupportedDocxToProseMirrorConversionError({
1299
+ message: `${PAGE_BREAK_OWNER_DESCRIPTIONS[owner]} containing ${description} cannot be represented in the editor model`,
1300
+ owner,
1301
+ contentType
1302
+ });
1303
+ };
1304
+ function assertRunContentIsRepresentableBesidePageBreak(run, owner) {
1305
+ for (const content of run.content) switch (content.type) {
1306
+ case "break":
1307
+ case "drawing":
1308
+ case "endnoteRef":
1309
+ case "footnoteRef":
1310
+ case "renderedPageBreak":
1311
+ case "symbol":
1312
+ case "tab":
1313
+ case "text": continue;
1314
+ case "shape":
1315
+ if (content.shape.textBody) unsupportedPageBreakContent(owner, content.type);
1316
+ continue;
1317
+ case "fieldChar":
1318
+ case "instrText":
1319
+ case "noBreakHyphen":
1320
+ case "softHyphen": return unsupportedPageBreakContent(owner, content.type);
1321
+ default: panic(`Unsupported page-break-bearing run content: ${JSON.stringify(content)}`);
1322
+ }
1323
+ }
1324
+ const RUN_FORMATTING_INFERENCE = {
1325
+ bold: "ordinary-toggle",
1326
+ boldCs: "structural",
1327
+ italic: "ordinary-toggle",
1328
+ italicCs: "structural",
1329
+ underline: "underline",
1330
+ strike: "visible-boolean",
1331
+ doubleStrike: "double-strike",
1332
+ vertAlign: "visible-value",
1333
+ smallCaps: "visible-boolean",
1334
+ allCaps: "visible-boolean",
1335
+ hidden: "visible-boolean",
1336
+ color: "color",
1337
+ highlight: "visible-value",
1338
+ shading: "preserve",
1339
+ fontSize: "font-size",
1340
+ fontSizeCs: "structural",
1341
+ fontFamily: "font-family",
1342
+ language: "nested-visible-value",
1343
+ spacing: "visible-value",
1344
+ position: "visible-value",
1345
+ scale: "scale",
1346
+ kerning: "visible-value",
1347
+ effect: "visible-value",
1348
+ emphasisMark: "visible-value",
1349
+ emboss: "visible-boolean",
1350
+ imprint: "visible-boolean",
1351
+ outline: "visible-boolean",
1352
+ shadow: "visible-boolean",
1353
+ rtl: "visible-boolean",
1354
+ cs: "structural",
1355
+ styleId: "structural"
1356
+ };
1357
+ const sameFormattingValue = (left, right) => {
1358
+ if (left === right) return true;
1359
+ if (typeof left !== "object" || left === null || typeof right !== "object" || right === null) return false;
1360
+ if (Array.isArray(left) || Array.isArray(right)) {
1361
+ if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) return false;
1362
+ return left.every((value, index) => sameFormattingValue(value, right.at(index)));
1363
+ }
1364
+ const leftEntries = Object.entries(left).filter(([, value]) => value !== void 0);
1365
+ const rightEntries = Object.entries(right).filter(([, value]) => value !== void 0);
1366
+ if (leftEntries.length !== rightEntries.length) return false;
1367
+ return leftEntries.every(([property, value]) => Object.hasOwn(right, property) && sameFormattingValue(value, Reflect.get(right, property)));
1368
+ };
1369
+ const isReconstructibleFontFamily = (directValue, effectiveValue) => {
1370
+ if (typeof directValue !== "object" || directValue === null || !sameFormattingValue(directValue, effectiveValue)) return false;
1371
+ const properties = Object.keys(directValue).filter((property) => Reflect.get(directValue, property) !== void 0);
1372
+ return properties.length === 2 && properties.includes("ascii") && properties.includes("hAnsi") && typeof Reflect.get(directValue, "ascii") === "string" && typeof Reflect.get(directValue, "hAnsi") === "string";
1373
+ };
1374
+ const canReconstructAuthoredRunFormatting = ({ directFormatting, effectiveFormatting, inheritedFormatting, paragraphMarkOverrides }) => {
1375
+ if (paragraphMarkOverrides !== void 0) return false;
1376
+ for (const property of Object.keys(directFormatting ?? {})) {
1377
+ const directValue = directFormatting?.[property];
1378
+ if (directValue === void 0 || property === "styleId") continue;
1379
+ const inheritedValue = inheritedFormatting?.[property];
1380
+ const effectiveValue = effectiveFormatting?.[property];
1381
+ switch (RUN_FORMATTING_INFERENCE[property]) {
1382
+ case "structural": continue;
1383
+ case "ordinary-toggle":
1384
+ if (directValue !== true || inheritedValue !== true) continue;
1385
+ return false;
1386
+ case "visible-boolean":
1387
+ if (directValue === false || directValue === true && inheritedValue !== true) continue;
1388
+ return false;
1389
+ case "font-size":
1390
+ if (typeof directValue === "number" && Number.isFinite(directValue) && directValue > 0) continue;
1391
+ return false;
1392
+ case "font-family":
1393
+ if (isReconstructibleFontFamily(directValue, effectiveValue)) continue;
1394
+ return false;
1395
+ case "color":
1396
+ if (typeof directValue === "object" && directValue !== null && Reflect.get(directValue, "auto") !== true && Reflect.get(directValue, "themeColor") === void 0 && sameFormattingValue(directValue, effectiveValue)) continue;
1397
+ return false;
1398
+ case "underline":
1399
+ if (typeof directValue === "object" && directValue !== null && Reflect.get(directValue, "style") !== "none" && Reflect.get(directValue, "color") === void 0 && sameFormattingValue(directValue, effectiveValue) && !sameFormattingValue(directValue, inheritedValue)) continue;
1400
+ return false;
1401
+ case "double-strike":
1402
+ if (directValue === false) continue;
1403
+ if (directValue === true && inheritedFormatting?.strike !== true && inheritedFormatting?.doubleStrike !== true) continue;
1404
+ return false;
1405
+ case "scale":
1406
+ if (normalizeHorizontalScalePercent(typeof directValue === "number" ? directValue : void 0) === directValue && directValue !== inheritedValue) continue;
1407
+ return false;
1408
+ case "nested-visible-value":
1409
+ if (sameFormattingValue(directValue, effectiveValue) && !sameFormattingValue(directValue, inheritedValue)) continue;
1410
+ return false;
1411
+ case "visible-value":
1412
+ if (directValue !== "none" && directValue !== "baseline" && sameFormattingValue(directValue, effectiveValue) && !sameFormattingValue(directValue, inheritedValue)) continue;
1413
+ return false;
1414
+ case "preserve": return false;
1415
+ }
1416
+ }
1417
+ return true;
1418
+ };
1249
1419
  function buildRunMarks(runFormatting, inherited, styleResolver) {
1420
+ if (runFormatting === void 0 && inherited.implicitCharacterStyleApplied === true && inherited.paragraphMarkOverrides === void 0) return {
1421
+ marks: textFormattingToMarks(inherited.formatting, {
1422
+ overrideFormatting: void 0,
1423
+ directFormatting: void 0,
1424
+ authoredCarrier: "reconstruct"
1425
+ }),
1426
+ mergedFormatting: inherited.formatting
1427
+ };
1250
1428
  const styleId = runFormatting?.styleId;
1251
- const characterStyleFormatting = styleId ? styleResolver?.getRunStyleOwnProperties(styleId) : styleResolver?.getDefaultCharacterStyle()?.rPr;
1429
+ let characterStyleFormatting;
1430
+ if (styleId) characterStyleFormatting = styleResolver?.getRunStyleOwnProperties(styleId);
1431
+ else if (!inherited.implicitCharacterStyleApplied) characterStyleFormatting = styleResolver?.getDefaultCharacterStyle()?.rPr;
1252
1432
  let ordinaryRunStyleFormatting = inherited.formatting ? { ...inherited.formatting } : {};
1253
1433
  if (styleId) ordinaryRunStyleFormatting = mergeTextFormatting(inherited.formatting, characterStyleFormatting) ?? {};
1254
1434
  const cascadedStyleFormatting = cascadeStyleTextFormatting([{
@@ -1266,20 +1446,28 @@ function buildRunMarks(runFormatting, inherited, styleResolver) {
1266
1446
  formatting: runFormatting,
1267
1447
  type: "direct"
1268
1448
  }], { ordinaryFormatting: mergeTextFormatting(runStyleFormatting, runFormatting) }).formatting;
1269
- const marks = textFormattingToMarks(mergedFormatting, { overrideFormatting: getRunFormattingOverrides({
1449
+ const authoredCarrier = canReconstructAuthoredRunFormatting({
1450
+ directFormatting: runFormatting,
1451
+ effectiveFormatting: mergedFormatting,
1452
+ inheritedFormatting: runStyleFormatting,
1453
+ paragraphMarkOverrides: inherited.paragraphMarkOverrides
1454
+ }) ? "reconstruct" : "preserve";
1455
+ const overrideFormatting = getRunFormattingOverrides({
1270
1456
  directFormatting: runFormatting,
1271
1457
  effectiveStyleFormatting: runStyleFormatting,
1272
1458
  hasCharacterStyle: styleId !== void 0,
1273
1459
  paragraphMarkOverrides: inherited.paragraphMarkOverrides
1274
- }) });
1275
- addDirectFontProvenance(marks, runFormatting);
1276
- if (styleId) {
1277
- const styleRPr = characterStyleFormatting ? marksToTextFormatting(textFormattingToMarks(characterStyleFormatting)) : void 0;
1278
- marks.push(schema.mark("characterStyle", {
1279
- styleId,
1280
- _styleRPr: styleRPr && Object.keys(styleRPr).length > 0 ? styleRPr : null
1281
- }));
1460
+ });
1461
+ if (authoredCarrier === "reconstruct") {
1462
+ if (overrideFormatting?.bold === true) delete overrideFormatting.bold;
1463
+ if (overrideFormatting?.italic === true) delete overrideFormatting.italic;
1282
1464
  }
1465
+ const marks = textFormattingToMarks(mergedFormatting, {
1466
+ overrideFormatting,
1467
+ directFormatting: runFormatting,
1468
+ authoredCarrier
1469
+ });
1470
+ if (styleId) marks.push(schema.mark("characterStyle", { styleId }));
1283
1471
  return {
1284
1472
  marks,
1285
1473
  mergedFormatting
@@ -1290,12 +1478,43 @@ const addDirectFontProvenance = (marks, directFormatting) => {
1290
1478
  if (directFormatting?.fontFamily !== void 0) directFontProperties.push("fontFamily");
1291
1479
  if (directFormatting?.fontSize !== void 0) directFontProperties.push("fontSize");
1292
1480
  if (directFormatting?.color !== void 0) directFontProperties.push("color");
1293
- if (!directFormatting || !Object.keys(directFormatting).some((property) => property !== "styleId")) return;
1481
+ if (directFontProperties.length === 0) return;
1294
1482
  const index = marks.findIndex(({ type }) => type.name === "runFormattingOverride");
1295
1483
  const existing = index >= 0 ? marks.at(index) : void 0;
1296
1484
  const override = schema.mark("runFormattingOverride", {
1297
1485
  ...existing?.attrs,
1298
- ...directFontProperties.length > 0 && { directFontProperties }
1486
+ directFontProperties
1487
+ });
1488
+ if (index >= 0) {
1489
+ marks[index] = override;
1490
+ return;
1491
+ }
1492
+ marks.push(override);
1493
+ };
1494
+ const COMPLEX_SCRIPT_MIRRORS = [
1495
+ {
1496
+ ordinary: "bold",
1497
+ complex: "boldCs"
1498
+ },
1499
+ {
1500
+ ordinary: "italic",
1501
+ complex: "italicCs"
1502
+ },
1503
+ {
1504
+ ordinary: "fontSize",
1505
+ complex: "fontSizeCs"
1506
+ }
1507
+ ];
1508
+ const addComplexScriptAbsenceProvenance = (marks, directFormatting) => {
1509
+ const absent = COMPLEX_SCRIPT_MIRRORS.filter(({ ordinary, complex }) => directFormatting?.[ordinary] !== void 0 && directFormatting[complex] === void 0).map(({ complex }) => complex);
1510
+ if (absent.length === 0) return;
1511
+ const index = marks.findIndex(({ type }) => type.name === "runFormattingOverride");
1512
+ const existing = index >= 0 ? marks.at(index) : void 0;
1513
+ const existingAbsences = new Set(existing?.attrs["complexScriptPropertyAbsences"] ?? []);
1514
+ for (const property of absent) existingAbsences.add(property);
1515
+ const override = schema.mark("runFormattingOverride", {
1516
+ ...existing?.attrs,
1517
+ complexScriptPropertyAbsences: COMPLEX_SCRIPT_RUN_PROPERTY_KEYS.filter((property) => existingAbsences.has(property))
1299
1518
  });
1300
1519
  if (index >= 0) {
1301
1520
  marks[index] = override;
@@ -1304,8 +1523,6 @@ const addDirectFontProvenance = (marks, directFormatting) => {
1304
1523
  marks.push(override);
1305
1524
  };
1306
1525
  const ORDINARY_STYLE_TOGGLE_KEYS = [
1307
- "bold",
1308
- "italic",
1309
1526
  "strike",
1310
1527
  "allCaps",
1311
1528
  "smallCaps",
@@ -1319,8 +1536,6 @@ function getRunFormattingOverrides({ directFormatting, effectiveStyleFormatting,
1319
1536
  const overrides = mergeTextFormatting(paragraphMarkOverrides, directFormatting);
1320
1537
  if (!overrides || !directFormatting) return overrides;
1321
1538
  for (const key of ORDINARY_STYLE_TOGGLE_KEYS) if (directFormatting[key] === true && (!hasCharacterStyle || effectiveStyleFormatting?.[key] !== true)) Reflect.deleteProperty(overrides, key);
1322
- if (directFormatting.boldCs === true && directFormatting.boldCs === directFormatting.bold && (!hasCharacterStyle || effectiveStyleFormatting?.boldCs === void 0)) Reflect.deleteProperty(overrides, "boldCs");
1323
- if (directFormatting.italicCs === true && directFormatting.italicCs === directFormatting.italic && (!hasCharacterStyle || effectiveStyleFormatting?.italicCs === void 0)) Reflect.deleteProperty(overrides, "italicCs");
1324
1539
  return overrides;
1325
1540
  }
1326
1541
  /**
@@ -1332,12 +1547,21 @@ function convertRunContent(content, marks, formatting, textBoxAnchors) {
1332
1547
  if (content.text) return [schema.text(content.text, marks)];
1333
1548
  return [];
1334
1549
  case "break":
1335
- if (content.breakType === "textWrapping" || !content.breakType) return [withHyperlinkBoundaryMarks(schema.node("hardBreak"), marks)];
1336
- if (content.breakType === "column") return [withHyperlinkBoundaryMarks(schema.node("hardBreak", { breakType: "column" }), marks)];
1337
- return [];
1550
+ if (content.breakType === "textWrapping" || !content.breakType) {
1551
+ const attrs = {
1552
+ ...content.breakType !== void 0 ? { breakType: content.breakType } : {},
1553
+ ...content.clear !== void 0 ? { clear: content.clear } : {}
1554
+ };
1555
+ return [schema.node("hardBreak", attrs).mark(marks)];
1556
+ }
1557
+ if (content.breakType === "column") return [schema.node("hardBreak", {
1558
+ breakType: "column",
1559
+ ...content.clear !== void 0 ? { clear: content.clear } : {}
1560
+ }).mark(marks)];
1561
+ return [schema.node("pageBreakRun", content.clear === void 0 ? void 0 : { clear: content.clear }).mark(marks)];
1338
1562
  case "renderedPageBreak": return [schema.node("renderedPageBreak").mark(marks)];
1339
1563
  case "tab": return [schema.node("tab", content.positional ? { positional: content.positional } : void 0).mark(marks)];
1340
- case "drawing": return [withHyperlinkBoundaryMarks(convertImage({
1564
+ case "drawing": return [withRunBoundaryMarks(convertImage({
1341
1565
  image: content.image,
1342
1566
  rawXml: content.rawXml,
1343
1567
  rawXmlMode: content.rawXmlMode
@@ -1348,7 +1572,7 @@ function convertRunContent(content, marks, formatting, textBoxAnchors) {
1348
1572
  const anchorId = textBoxAnchors?.get(shp);
1349
1573
  return anchorId ? [schema.node("textBoxAnchor", { anchorId }).mark(marks)] : [];
1350
1574
  }
1351
- return [withHyperlinkBoundaryMarks(convertShape(shp), marks)];
1575
+ return [withRunBoundaryMarks(convertShape(shp), marks)];
1352
1576
  }
1353
1577
  case "footnoteRef": {
1354
1578
  const footnoteMark = schema.mark("footnoteRef", {
@@ -1376,8 +1600,8 @@ function convertRunContent(content, marks, formatting, textBoxAnchors) {
1376
1600
  }).mark(marks)];
1377
1601
  }
1378
1602
  }
1379
- function withHyperlinkBoundaryMarks(node, marks) {
1380
- if (!marks.some((mark) => mark.type.name === "hyperlink")) return node;
1603
+ function withRunBoundaryMarks(node, marks) {
1604
+ if (!marks.some(({ type }) => type.name === "hyperlink" || type.name === "pageBreakRunOwner")) return node;
1381
1605
  return node.mark(marks);
1382
1606
  }
1383
1607
  function convertImage({ image, rawXml, rawXmlMode }) {
@@ -1485,7 +1709,7 @@ function convertImage({ image, rawXml, rawXmlMode }) {
1485
1709
  _docxObjectPreview: rawXml !== void 0 && /<(?:[A-Za-z_][\w.-]*:)?object(?:\s|>)/u.test(rawXml)
1486
1710
  });
1487
1711
  }
1488
- function convertHyperlink(hyperlink, { getInheritedRunFormatting, styleResolver, hyperlinkIndex, textBoxAnchors }) {
1712
+ function convertHyperlink(hyperlink, { getInheritedRunFormatting, styleResolver, hyperlinkIndex, textBoxAnchors, nextPageBreakRunOwnerId }) {
1489
1713
  const nodes = [];
1490
1714
  const href = hyperlink.href || (hyperlink.anchor ? `#${hyperlink.anchor}` : "");
1491
1715
  const linkMark = schema.mark("hyperlink", {
@@ -1513,8 +1737,11 @@ function convertHyperlink(hyperlink, { getInheritedRunFormatting, styleResolver,
1513
1737
  continue;
1514
1738
  }
1515
1739
  if (child.type === "run") {
1740
+ assertPageBreakSourceRunIsRepresentable(child);
1516
1741
  const inheritedFormatting = getInheritedRunFormatting(child.formatting);
1517
1742
  const { marks: runMarks, mergedFormatting } = buildRunMarks(child.formatting, inheritedFormatting, styleResolver);
1743
+ if (child.propertyChanges && child.propertyChanges.length > 0) runMarks.push(schema.mark("runPropertyChange", { changes: [...child.propertyChanges] }));
1744
+ if (child.content.some((content) => content.type === "break" && content.breakType === "page")) runMarks.push(schema.mark("pageBreakRunOwner", { id: nextPageBreakRunOwnerId() }));
1518
1745
  const allMarks = [...runMarks, linkMark];
1519
1746
  for (const content of child.content) nodes.push(...convertRunContent(content, allMarks, mergedFormatting, textBoxAnchors));
1520
1747
  }
@@ -1524,7 +1751,14 @@ function convertHyperlink(hyperlink, { getInheritedRunFormatting, styleResolver,
1524
1751
  function textFormattingToMarks(formatting, options) {
1525
1752
  if (!formatting) return [];
1526
1753
  const marks = [];
1527
- const overrideAttrs = buildRunFormattingOverrideAttrs(options ? options.overrideFormatting : formatting);
1754
+ const overrideFormatting = options ? options.overrideFormatting : formatting;
1755
+ let overrideAttrs;
1756
+ if (options?.authoredCarrier === "reconstruct") overrideAttrs = buildRunFormattingOverrideAttrs(overrideFormatting, { type: "structural-only" });
1757
+ else if (options) overrideAttrs = buildRunFormattingOverrideAttrs(overrideFormatting, {
1758
+ type: "authored-baseline",
1759
+ formatting: options.directFormatting
1760
+ });
1761
+ else overrideAttrs = buildRunFormattingOverrideAttrs(overrideFormatting);
1528
1762
  if (overrideAttrs) marks.push(schema.mark("runFormattingOverride", overrideAttrs));
1529
1763
  if (formatting.bold) marks.push(schema.mark("bold"));
1530
1764
  if (formatting.italic) marks.push(schema.mark("italic"));
@@ -1577,6 +1811,8 @@ function textFormattingToMarks(formatting, options) {
1577
1811
  if (formatting.outline) marks.push(schema.mark("textOutline"));
1578
1812
  if (formatting.rtl) marks.push(schema.mark("rtl"));
1579
1813
  if (formatting.effect && formatting.effect !== "none") marks.push(schema.mark("textEffect", { effect: formatting.effect }));
1814
+ addDirectFontProvenance(marks, options?.directFormatting);
1815
+ if (options?.authoredCarrier === "preserve") addComplexScriptAbsenceProvenance(marks, options.directFormatting);
1580
1816
  return marks;
1581
1817
  }
1582
1818
  /**
@@ -1686,7 +1922,7 @@ function convertShape(shape) {
1686
1922
  }
1687
1923
  function convertParagraphWithTextBoxes(block, styleResolver, { textBoxGroupId, context, extraRunFormatting, preserveEmptyWrapper, tableParagraphOverlay }) {
1688
1924
  const { textBoxes, textBoxAnchors } = extractTextBoxesFromParagraph(block, textBoxGroupId);
1689
- const pmParagraph = convertParagraph(block, styleResolver, context.nextHyperlinkInstanceIndex, context.pairedBookmarkIds, void 0, extraRunFormatting, tableParagraphOverlay, textBoxAnchors);
1925
+ const pmParagraph = convertParagraph(block, styleResolver, context, void 0, extraRunFormatting, tableParagraphOverlay, textBoxAnchors);
1690
1926
  const nodes = [];
1691
1927
  const isEmptyAfterExtraction = textBoxes.length > 0 && !hasContentBesidesTextBoxAnchors(pmParagraph);
1692
1928
  const keepWrapperParagraph = isEmptyAfterExtraction && (preserveEmptyWrapper === true || hasParagraphBoundaryPayload(block, pmParagraph));
@@ -1839,6 +2075,7 @@ function textBoxFromShape(shape, textBody) {
1839
2075
  * Convert a TextBox to a ProseMirror textBox node
1840
2076
  */
1841
2077
  function convertTextBox(textBox, styleResolver, options) {
2078
+ assertSourceContainerHasNoPageBreakRun(textBox.content, "text-box", options.context.pageBreakRunSourceDescendants);
1842
2079
  const textBoxSize = textBox.size;
1843
2080
  const widthPx = textBoxSize?.width ? emuToPixels(textBoxSize.width) : 200;
1844
2081
  const heightPx = textBoxSize?.height ? emuToPixels(textBoxSize.height) : void 0;
@@ -1951,7 +2188,8 @@ function headerFooterToProseDoc(content, options) {
1951
2188
  theme,
1952
2189
  nextTextBoxGroupId,
1953
2190
  nextHyperlinkInstanceIndex: createHyperlinkInstanceIndexAllocator(),
1954
- pairedBookmarkIds: collectPairedBookmarkIds(content)
2191
+ pairedBookmarkIds: collectPairedBookmarkIds(content),
2192
+ pageBreakRunSourceDescendants: buildPageBreakRunSourceDescendantIndex(content)
1955
2193
  };
1956
2194
  const convertBlocks = (blocks) => {
1957
2195
  const out = [];
@@ -1965,10 +2203,10 @@ function headerFooterToProseDoc(content, options) {
1965
2203
  if (isDetachedWatermarkHost) {
1966
2204
  const paragraphNodeIndex = paragraphNodes.findIndex(({ type }) => type.name === "paragraph");
1967
2205
  const paragraphNode = paragraphNodes[paragraphNodeIndex];
1968
- if (paragraphNode) paragraphNodes[paragraphNodeIndex] = paragraphNode.type.create({
2206
+ if (paragraphNode) paragraphNodes[paragraphNodeIndex] = recreateProseNodeWithParagraphPropertySource(paragraphNode, { attrs: {
1969
2207
  ...paragraphNode.attrs,
1970
2208
  _detachedWatermarkHost: true
1971
- }, paragraphNode.content, paragraphNode.marks);
2209
+ } });
1972
2210
  }
1973
2211
  out.push(...paragraphNodes);
1974
2212
  } else if (block.type === "table") out.push(convertTable(block, styleResolver, conversionContext));
@@ -1985,100 +2223,10 @@ function footnoteToProseDoc(content, options) {
1985
2223
  return headerFooterToProseDoc(content, options);
1986
2224
  }
1987
2225
  /**
1988
- * Determine where a page break appears inside a paragraph.
1989
- *
1990
- * Per ECMA-376 §17.3.3.1, `<w:br w:type="page"/>` is always a forced break,
1991
- * including in a paragraph whose only content is the break itself. We previously
1992
- * searched only top-level runs and missed breaks nested in hyperlinks, tracked
1993
- * changes, or fields — so those paragraphs silently dropped their forced break
1994
- * and the following content collapsed onto the previous page (common on legal
1995
- * signature pages and exhibit covers).
1996
- * See eigenpal docx-editor #409 (break-only page break sub-fix).
1997
- *
1998
- * Returns:
1999
- * "before" — the break appears before any visible content; the paragraph's
2000
- * content belongs on the NEXT page.
2001
- * "after" — the break follows some visible content; the paragraph stays
2002
- * on the current page and the next block starts a new page.
2003
- * null — no page break found.
2004
- */
2005
- function paragraphPageBreakPosition(paragraph) {
2006
- if (!mayContainPageBreak(paragraph)) return null;
2007
- return findParagraphPageBreakPosition(paragraph);
2008
- }
2009
- function mayContainPageBreak(paragraph) {
2010
- for (const item of paragraph.content) {
2011
- if (item.type === "run") {
2012
- for (const content of item.content) if (content.type === "break" && content.breakType === "page") return true;
2013
- continue;
2014
- }
2015
- 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;
2016
- 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;
2017
- }
2018
- return false;
2019
- }
2020
- function findParagraphPageBreakPosition(paragraph) {
2021
- const state = { seenVisibleContent: false };
2022
- function isPageBreak(content) {
2023
- return content.type === "break" && content.breakType === "page";
2024
- }
2025
- function isVisibleRunContent(content) {
2026
- return content.type === "text" && content.text.length > 0 || content.type === "tab" || content.type === "drawing" || content.type === "shape" || content.type === "symbol" || content.type === "fieldChar" || content.type === "instrText" || content.type === "footnoteRef" || content.type === "endnoteRef" || content.type === "noBreakHyphen" || content.type === "softHyphen";
2027
- }
2028
- function visitRun(run) {
2029
- for (const content of run.content) {
2030
- if (isPageBreak(content)) return true;
2031
- if (isVisibleRunContent(content)) state.seenVisibleContent = true;
2032
- }
2033
- return false;
2034
- }
2035
- function visitHyperlinkChildren(hyperlink) {
2036
- for (const child of hyperlink.children) if (child.type === "run" && visitRun(child)) return true;
2037
- return false;
2038
- }
2039
- function visitRunOrHyperlinkList(children) {
2040
- for (const child of children) {
2041
- if (child.type === "run" && visitRun(child)) return true;
2042
- if (child.type === "hyperlink" && visitHyperlinkChildren(child)) return true;
2043
- if (child.type === "simpleField") for (const fieldChild of child.content) {
2044
- if (fieldChild.type === "run" && visitRun(fieldChild)) return true;
2045
- if (fieldChild.type === "hyperlink" && visitHyperlinkChildren(fieldChild)) return true;
2046
- }
2047
- if (child.type === "complexField") {
2048
- for (const run of child.fieldCode) if (visitRun(run)) return true;
2049
- for (const run of child.fieldResult) if (visitRun(run)) return true;
2050
- }
2051
- if ((child.type === "insertion" || child.type === "deletion" || child.type === "moveFrom" || child.type === "moveTo") && visitRunOrHyperlinkList(child.content)) return true;
2052
- }
2053
- return false;
2054
- }
2055
- function visitItem(item) {
2056
- if (item.type === "run") return visitRun(item);
2057
- if (item.type === "hyperlink") return visitHyperlinkChildren(item);
2058
- if (item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") return visitRunOrHyperlinkList(item.content);
2059
- if (item.type === "simpleField") return visitRunOrHyperlinkList(item.content);
2060
- if (item.type === "complexField") {
2061
- for (const run of item.fieldResult) if (visitRun(run)) return true;
2062
- return false;
2063
- }
2064
- if (item.type === "inlineSdt") {
2065
- for (const child of item.content) if (visitItem(child)) return true;
2066
- return false;
2067
- }
2068
- if (item.type === "mathEquation") {
2069
- state.seenVisibleContent = true;
2070
- return false;
2071
- }
2072
- return false;
2073
- }
2074
- for (const item of paragraph.content) if (visitItem(item)) return state.seenVisibleContent ? "after" : "before";
2075
- return null;
2076
- }
2077
- /**
2078
2226
  * Create an empty ProseMirror document
2079
2227
  */
2080
2228
  function createEmptyDoc() {
2081
2229
  return schema.node("doc", null, [schema.node("paragraph", {}, [])]);
2082
2230
  }
2083
2231
  //#endregion
2084
- export { createEmptyDoc, footnoteToProseDoc, headerFooterToProseDoc, standaloneTableCellToProseMirror, textFormattingToMarks, toProseDoc };
2232
+ export { UnsupportedDocxToProseMirrorConversionError, createEmptyDoc, footnoteToProseDoc, headerFooterToProseDoc, resolveParagraphDefaultTextFormatting, standaloneTableCellToProseMirror, textFormattingToMarks, toProseDoc };