@stll/folio-core 0.45.0 → 0.47.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 (451) hide show
  1. package/dist/ai-edits/apply.js +85 -43
  2. package/dist/ai-edits/headless.js +2 -2
  3. package/dist/ai-edits/read.d.ts +1 -0
  4. package/dist/ai-edits/read.js +1 -0
  5. package/dist/ai-edits/snapshot.js +32 -27
  6. package/dist/ai-edits/table-cell-mutations.js +15 -7
  7. package/dist/ai-edits/table-geometry.js +21 -18
  8. package/dist/ai-edits/table-template.js +2 -2
  9. package/dist/compare/compare.js +2 -5
  10. package/dist/compare/content-alignment.js +108 -12
  11. package/dist/compare/content-types.d.ts +8 -2
  12. package/dist/compare/content.js +2 -11
  13. package/dist/compare/plan.js +7 -4
  14. package/dist/compare/scenario.js +2 -5
  15. package/dist/compare/section-boundary-properties.js +1 -2
  16. package/dist/compare/types.d.ts +9 -1
  17. package/dist/compare/types.js +12 -1
  18. package/dist/compat/eigenpal.d.ts +2 -1
  19. package/dist/compat/eigenpal.js +2 -1
  20. package/dist/content-controls/checkboxDisplay.d.ts +17 -0
  21. package/dist/content-controls/checkboxDisplay.js +46 -0
  22. package/dist/content-controls/findContentControls.js +3 -1
  23. package/dist/content-controls/mutateContentControls.js +57 -43
  24. package/dist/controller/contentControlWidgetController.d.ts +1 -0
  25. package/dist/controller/contentControlWidgetController.js +3 -0
  26. package/dist/controller/hiddenEditorApi.js +3 -1
  27. package/dist/controller/hiddenEditorManager.d.ts +1 -1
  28. package/dist/controller/hiddenEditorManager.js +6 -3
  29. package/dist/controller/layoutPipeline.js +8 -3
  30. package/dist/display-list/build/buildDisplayList.js +20 -1
  31. package/dist/display-list/build/imagePrimitives.d.ts +4 -4
  32. package/dist/display-list/build/imagePrimitives.js +38 -18
  33. package/dist/display-list/build/pageBorderPrimitives.js +2 -1
  34. package/dist/display-list/build/paragraphPrimitives.js +113 -14
  35. package/dist/display-list/build/previewPrimitives.d.ts +10 -0
  36. package/dist/display-list/build/previewPrimitives.js +89 -0
  37. package/dist/display-list/build/strokes.d.ts +177 -8
  38. package/dist/display-list/build/strokes.js +167 -47
  39. package/dist/display-list/build/tablePrimitives.js +4 -2
  40. package/dist/display-list/build/textBoxPrimitives.js +6 -4
  41. package/dist/display-list/build/textDecorations.d.ts +15 -1
  42. package/dist/display-list/build/textDecorations.js +15 -1
  43. package/dist/display-list/dom/renderDisplayListToDom.js +11 -21
  44. package/dist/display-list/primitives.d.ts +13 -2
  45. package/dist/display-list/primitives.js +36 -1
  46. package/dist/display-list/types.d.ts +17 -0
  47. package/dist/document-operations.js +2 -1
  48. package/dist/docx/attributeRemainder.d.ts +76 -0
  49. package/dist/docx/attributeRemainder.js +111 -0
  50. package/dist/docx/blockContentParser.d.ts +3 -1
  51. package/dist/docx/blockContentParser.js +102 -106
  52. package/dist/docx/blockPlainText.d.ts +3 -4
  53. package/dist/docx/blockPlainText.js +3 -0
  54. package/dist/docx/borderParser.js +26 -11
  55. package/dist/docx/builtInStyles.d.ts +8 -16
  56. package/dist/docx/builtInStyles.js +54 -17
  57. package/dist/docx/commentAnchorIndex.d.ts +30 -0
  58. package/dist/docx/commentAnchorIndex.js +50 -0
  59. package/dist/docx/commentParser.d.ts +1 -1
  60. package/dist/docx/commentParser.js +56 -39
  61. package/dist/docx/commentRangeIntegrity.d.ts +16 -1
  62. package/dist/docx/commentRangeIntegrity.js +42 -1
  63. package/dist/docx/commentRangeJoin.d.ts +9 -0
  64. package/dist/docx/commentRangeJoin.js +33 -0
  65. package/dist/docx/commentReferenceCompletion.d.ts +9 -0
  66. package/dist/docx/commentReferenceCompletion.js +47 -0
  67. package/dist/docx/commentReferenceNormalization.js +3 -1
  68. package/dist/docx/commentReplyMarkers.js +11 -19
  69. package/dist/docx/compatibility.js +56 -41
  70. package/dist/docx/containerChildren.d.ts +208 -0
  71. package/dist/docx/containerChildren.gen.d.ts +43 -0
  72. package/dist/docx/containerChildren.gen.js +263 -0
  73. package/dist/docx/containerChildren.js +153 -0
  74. package/dist/docx/diagramPreview.d.ts +14 -2
  75. package/dist/docx/diagramPreview.js +81 -169
  76. package/dist/docx/documentParser.d.ts +1 -1
  77. package/dist/docx/documentParser.js +7 -4
  78. package/dist/docx/drawingAnchor.d.ts +87 -0
  79. package/dist/docx/drawingAnchor.js +201 -0
  80. package/dist/docx/drawingUtils.d.ts +43 -38
  81. package/dist/docx/drawingUtils.js +205 -118
  82. package/dist/docx/ensureParaIds.js +17 -7
  83. package/dist/docx/fieldParser.d.ts +1 -1
  84. package/dist/docx/fieldParser.js +4 -4
  85. package/dist/docx/fieldState.d.ts +26 -0
  86. package/dist/docx/fieldState.js +53 -0
  87. package/dist/docx/fontTableParser.js +102 -41
  88. package/dist/docx/footnoteParser.d.ts +1 -1
  89. package/dist/docx/footnoteParser.js +10 -6
  90. package/dist/docx/graphicFrameLocks.d.ts +16 -4
  91. package/dist/docx/graphicFrameLocks.js +19 -6
  92. package/dist/docx/groupDrawingParser.js +4 -3
  93. package/dist/docx/headerFooterParser.js +1 -1
  94. package/dist/docx/headerFooterReferenceNormalization.js +1 -0
  95. package/dist/docx/hyperlinkParser.d.ts +66 -9
  96. package/dist/docx/hyperlinkParser.js +153 -26
  97. package/dist/docx/imageParser.js +160 -115
  98. package/dist/docx/index.d.ts +2 -1
  99. package/dist/docx/index.js +2 -1
  100. package/dist/docx/inlineContentRemovals.d.ts +28 -0
  101. package/dist/docx/inlineContentRemovals.js +46 -0
  102. package/dist/docx/inlineWrapperContent.d.ts +166 -0
  103. package/dist/docx/inlineWrapperContent.js +165 -0
  104. package/dist/docx/inlineWrapperParser.d.ts +11 -0
  105. package/dist/docx/inlineWrapperParser.js +60 -0
  106. package/dist/docx/nonVisualDrawingProps.d.ts +5 -13
  107. package/dist/docx/normalizeBaseDirection.js +12 -1
  108. package/dist/docx/numberingParser.d.ts +25 -2
  109. package/dist/docx/numberingParser.js +264 -361
  110. package/dist/docx/numberingReference.d.ts +9 -16
  111. package/dist/docx/numberingReference.js +17 -16
  112. package/dist/docx/numberingReferenceNormalization.js +7 -7
  113. package/dist/docx/ooxmlCounterFormatter.d.ts +1 -1
  114. package/dist/docx/ooxmlCounterFormatter.js +4 -1
  115. package/dist/docx/paraIdAttribute.d.ts +111 -0
  116. package/dist/docx/paraIdAttribute.js +142 -0
  117. package/dist/docx/paragraphParser.d.ts +10 -25
  118. package/dist/docx/paragraphParser.js +421 -496
  119. package/dist/docx/paragraphProperties.d.ts +23 -0
  120. package/dist/docx/paragraphProperties.js +279 -0
  121. package/dist/docx/paragraphPropertySource.js +7 -1
  122. package/dist/docx/paragraphTextBoxEnrichment.d.ts +3 -2
  123. package/dist/docx/paragraphTextBoxEnrichment.js +20 -59
  124. package/dist/docx/paragraphTraversal.d.ts +14 -10
  125. package/dist/docx/paragraphTraversal.js +53 -52
  126. package/dist/docx/parseWarningMessage.js +5 -1
  127. package/dist/docx/parserEnums.d.ts +6 -8
  128. package/dist/docx/parserEnums.js +4 -6
  129. package/dist/docx/preservedRunContent.d.ts +32 -0
  130. package/dist/docx/preservedRunContent.js +96 -0
  131. package/dist/docx/previewBudget.d.ts +44 -23
  132. package/dist/docx/previewBudget.js +61 -30
  133. package/dist/docx/propertyElementAttributes.d.ts +178 -0
  134. package/dist/docx/propertyElementAttributes.js +114 -0
  135. package/dist/docx/renderedPageBreakNormalization.js +4 -6
  136. package/dist/docx/rezip.d.ts +28 -2
  137. package/dist/docx/rezip.js +152 -27
  138. package/dist/docx/runConsolidator.d.ts +42 -2
  139. package/dist/docx/runConsolidator.js +60 -6
  140. package/dist/docx/runParser.d.ts +55 -19
  141. package/dist/docx/runParser.js +394 -306
  142. package/dist/docx/runPayload.d.ts +5 -0
  143. package/dist/docx/runPayload.js +4 -0
  144. package/dist/docx/sdtProperties.d.ts +39 -5
  145. package/dist/docx/sdtProperties.js +205 -84
  146. package/dist/docx/sdtPropertiesPatch.d.ts +5 -9
  147. package/dist/docx/sdtPropertiesPatch.js +68 -112
  148. package/dist/docx/sectionParser.d.ts +1 -2
  149. package/dist/docx/sectionParser.js +241 -238
  150. package/dist/docx/selectiveSave.js +3 -2
  151. package/dist/docx/selectiveXmlPatch.d.ts +66 -3
  152. package/dist/docx/selectiveXmlPatch.js +276 -133
  153. package/dist/docx/serializer/blockSdtSerializer.js +2 -96
  154. package/dist/docx/serializer/borderSerializer.d.ts +5 -5
  155. package/dist/docx/serializer/borderSerializer.js +12 -10
  156. package/dist/docx/serializer/commentSerializer.js +5 -7
  157. package/dist/docx/serializer/documentSerializer.js +11 -11
  158. package/dist/docx/serializer/fontTableSerializer.js +31 -3
  159. package/dist/docx/serializer/headerFooterSerializer.js +10 -9
  160. package/dist/docx/serializer/markupRangeAttributes.d.ts +9 -1
  161. package/dist/docx/serializer/markupRangeAttributes.js +9 -1
  162. package/dist/docx/serializer/noteSerializer.js +11 -8
  163. package/dist/docx/serializer/numberingSerializer.d.ts +1 -6
  164. package/dist/docx/serializer/numberingSerializer.js +81 -79
  165. package/dist/docx/serializer/paragraphSerializer.d.ts +1 -9
  166. package/dist/docx/serializer/paragraphSerializer.js +156 -236
  167. package/dist/docx/serializer/runSerializer.d.ts +1 -5
  168. package/dist/docx/serializer/runSerializer.js +134 -75
  169. package/dist/docx/serializer/sdtPropertiesSerializer.d.ts +26 -0
  170. package/dist/docx/serializer/sdtPropertiesSerializer.js +111 -0
  171. package/dist/docx/serializer/sectionPropertiesSerializer.js +42 -49
  172. package/dist/docx/serializer/settingsSerializer.js +6 -4
  173. package/dist/docx/serializer/stylesSerializer.js +8 -11
  174. package/dist/docx/serializer/tableSerializer.js +283 -105
  175. package/dist/docx/serializer/textFormattingSerializer.d.ts +28 -4
  176. package/dist/docx/serializer/textFormattingSerializer.js +111 -101
  177. package/dist/docx/serializer/xmlUtils.d.ts +1 -1
  178. package/dist/docx/serializer/xmlUtils.js +1 -1
  179. package/dist/docx/server/createBilingualDocument.js +20 -16
  180. package/dist/docx/server/materializeYjsDocx.d.ts +1 -1
  181. package/dist/docx/server/materializeYjsDocx.js +9 -1
  182. package/dist/docx/server/migrateYjsAttrSchema.d.ts +55 -0
  183. package/dist/docx/server/migrateYjsAttrSchema.js +95 -0
  184. package/dist/docx/settingsParser.js +7 -4
  185. package/dist/docx/shadingParser.d.ts +2 -1
  186. package/dist/docx/shadingParser.js +43 -7
  187. package/dist/docx/shapeParser.js +13 -8
  188. package/dist/docx/strictNames.d.ts +11 -0
  189. package/dist/docx/strictNames.gen.d.ts +45 -0
  190. package/dist/docx/strictNames.gen.js +50 -0
  191. package/dist/docx/strictNames.js +43 -0
  192. package/dist/docx/strictValueEncodings.gen.js +133 -131
  193. package/dist/docx/styleParser.js +17 -349
  194. package/dist/docx/tableParser.d.ts +11 -2
  195. package/dist/docx/tableParser.js +665 -220
  196. package/dist/docx/textBoxParser.d.ts +28 -3
  197. package/dist/docx/textBoxParser.js +69 -9
  198. package/dist/docx/themeColorAttribute.d.ts +13 -0
  199. package/dist/docx/themeColorAttribute.js +24 -0
  200. package/dist/docx/trackedMoveRangeNormalization.js +2 -1
  201. package/dist/docx/unzip.js +5 -4
  202. package/dist/docx/vmlImageParser.d.ts +30 -5
  203. package/dist/docx/vmlImageParser.js +91 -32
  204. package/dist/docx/vmlPreview.js +2 -2
  205. package/dist/docx/wrapPolygon.d.ts +30 -0
  206. package/dist/docx/wrapPolygon.js +70 -0
  207. package/dist/docx/xmlEncoding.d.ts +5 -0
  208. package/dist/docx/xmlEncoding.js +12 -0
  209. package/dist/docx/xmlParser.d.ts +23 -1
  210. package/dist/docx/xmlParser.js +31 -2
  211. package/dist/fonts/embeddedFonts.js +3 -3
  212. package/dist/headless-layout.js +12 -1
  213. package/dist/i18n/messages/catalogs.gen.d.ts +68 -0
  214. package/dist/i18n/messages/catalogs.gen.js +102 -34
  215. package/dist/i18n/messages/messages.gen.d.ts +4 -0
  216. package/dist/index.d.ts +2 -1
  217. package/dist/index.js +2 -1
  218. package/dist/internal/headlessRevisionResolution.js +9 -0
  219. package/dist/internal/pageBreakRunSourceDescendantIndex.js +7 -2
  220. package/dist/internal/paragraphFormattingSerialization.d.ts +20 -9
  221. package/dist/internal/paragraphFormattingSerialization.js +118 -83
  222. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  223. package/dist/layout-bridge/convert/footnoteLayout.js +1 -0
  224. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  225. package/dist/layout-bridge/convert/headerFooterLayout.js +2 -0
  226. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +17 -12
  227. package/dist/layout-bridge/convert/toFlowBlocks.js +267 -101
  228. package/dist/layout-engine/index.d.ts +2 -2
  229. package/dist/layout-engine/index.js +53 -17
  230. package/dist/layout-engine/measure/measureBlocks.d.ts +3 -0
  231. package/dist/layout-engine/measure/measureBlocks.js +6 -10
  232. package/dist/layout-engine/measure/tableCellFloating.d.ts +2 -0
  233. package/dist/layout-engine/measure/tableCellFloating.js +2 -0
  234. package/dist/layout-engine/measure/tableCellGrid.js +2 -1
  235. package/dist/layout-engine/measure/tableFragmentBorderGeometry.js +2 -1
  236. package/dist/layout-engine/measure/tableInlinePlacement.js +2 -5
  237. package/dist/layout-engine/paragraphSequence.js +3 -2
  238. package/dist/layout-engine/renderedBreakReconciliation.js +2 -1
  239. package/dist/layout-engine/section-breaks.d.ts +49 -2
  240. package/dist/layout-engine/section-breaks.js +55 -4
  241. package/dist/layout-engine/types.d.ts +69 -17
  242. package/dist/layout-engine/types.js +16 -1
  243. package/dist/layout-painter/borderStroke.d.ts +18 -4
  244. package/dist/layout-painter/renderImage.d.ts +5 -1
  245. package/dist/layout-painter/renderImage.js +10 -3
  246. package/dist/layout-painter/renderPage.d.ts +2 -0
  247. package/dist/layout-painter/renderPage.js +10 -4
  248. package/dist/layout-painter/renderParagraph.d.ts +14 -1
  249. package/dist/layout-painter/renderParagraph.js +34 -28
  250. package/dist/layout-painter/renderTable.d.ts +4 -1
  251. package/dist/layout-painter/renderTable.js +22 -22
  252. package/dist/layout-painter/renderTextBox.js +5 -3
  253. package/dist/managers/autoSaveCodec.d.ts +9 -1
  254. package/dist/managers/autoSaveCodec.js +12 -4
  255. package/dist/markdown/renderBlock.js +3 -0
  256. package/dist/markdown/renderRuns.d.ts +1 -1
  257. package/dist/markdown/renderRuns.js +34 -6
  258. package/dist/markdown/renderTable.js +24 -6
  259. package/dist/markdown/trailers.js +4 -1
  260. package/dist/model.d.ts +3 -3
  261. package/dist/model.js +2 -2
  262. package/dist/paged-layout/sectionBlockWidths.d.ts +3 -0
  263. package/dist/paged-layout/sectionBlockWidths.js +26 -4
  264. package/dist/pdf/images.js +142 -6
  265. package/dist/prosemirror/attrs/index.d.ts +34 -5
  266. package/dist/prosemirror/attrs/index.js +639 -48
  267. package/dist/prosemirror/authoredTransformAttrs.d.ts +28 -0
  268. package/dist/prosemirror/authoredTransformAttrs.js +64 -0
  269. package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +9 -1
  270. package/dist/prosemirror/bookmarkBoundaryAttrs.js +22 -3
  271. package/dist/prosemirror/commands/comments.js +68 -53
  272. package/dist/prosemirror/commands/contentControls.js +33 -20
  273. package/dist/prosemirror/commands/image.d.ts +10 -3
  274. package/dist/prosemirror/commands/image.js +46 -29
  275. package/dist/prosemirror/commands/pageBreak.js +1 -1
  276. package/dist/prosemirror/commands/paragraph.d.ts +2 -1
  277. package/dist/prosemirror/commands/propertyChangeScope.d.ts +12 -4
  278. package/dist/prosemirror/commands/propertyChangeScope.js +22 -4
  279. package/dist/prosemirror/commands/sectionBreak.d.ts +33 -1
  280. package/dist/prosemirror/commands/sectionBreak.js +187 -11
  281. package/dist/prosemirror/commentReferenceAttrs.d.ts +8 -0
  282. package/dist/prosemirror/commentReferenceAttrs.js +33 -0
  283. package/dist/prosemirror/commentReferenceIntegrity.d.ts +47 -0
  284. package/dist/prosemirror/commentReferenceIntegrity.js +43 -0
  285. package/dist/prosemirror/conversion/fromProseDoc.d.ts +17 -12
  286. package/dist/prosemirror/conversion/fromProseDoc.js +553 -207
  287. package/dist/prosemirror/conversion/index.d.ts +2 -2
  288. package/dist/prosemirror/conversion/preservedSinkCarriers.d.ts +39 -0
  289. package/dist/prosemirror/conversion/preservedSinkCarriers.js +19 -0
  290. package/dist/prosemirror/conversion/runShadingMark.js +14 -1
  291. package/dist/prosemirror/conversion/sdtAttrs.d.ts +10 -1
  292. package/dist/prosemirror/conversion/sdtAttrs.js +19 -5
  293. package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -9
  294. package/dist/prosemirror/conversion/toProseDoc.js +801 -411
  295. package/dist/prosemirror/emptyRangeAnchor.d.ts +53 -0
  296. package/dist/prosemirror/emptyRangeAnchor.js +158 -0
  297. package/dist/prosemirror/extensions/StarterKit.js +14 -58
  298. package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
  299. package/dist/prosemirror/extensions/core/ParagraphExtension.js +21 -16
  300. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +48 -29
  301. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +3 -1
  302. package/dist/prosemirror/extensions/features/ImagePasteExtension.js +5 -3
  303. package/dist/prosemirror/extensions/features/ListExtension.js +43 -24
  304. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +1 -0
  305. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +4 -3
  306. package/dist/prosemirror/extensions/features/PasteCleanupExtension.d.ts +3 -3
  307. package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +5 -5
  308. package/dist/prosemirror/extensions/features/pasteCleanup.d.ts +3 -1
  309. package/dist/prosemirror/extensions/features/pasteCleanup.js +56 -2
  310. package/dist/prosemirror/extensions/features/pastedHeadingStyles.js +5 -4
  311. package/dist/prosemirror/extensions/markRegistry.d.ts +65 -0
  312. package/dist/prosemirror/extensions/markRegistry.js +138 -0
  313. package/dist/prosemirror/extensions/marks/InlineWrapperExtension.d.ts +18 -0
  314. package/dist/prosemirror/extensions/marks/InlineWrapperExtension.js +77 -0
  315. package/dist/prosemirror/extensions/marks/RunIdentityExtension.d.ts +26 -0
  316. package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +134 -0
  317. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +2 -1
  318. package/dist/prosemirror/extensions/marks/UnderlineExtension.js +12 -18
  319. package/dist/prosemirror/extensions/marks/markUtils.d.ts +2 -1
  320. package/dist/prosemirror/extensions/marks/markUtils.js +49 -5
  321. package/dist/prosemirror/extensions/nodes/BlockBookmarkBoundaryExtension.d.ts +29 -0
  322. package/dist/prosemirror/extensions/nodes/BlockBookmarkBoundaryExtension.js +46 -0
  323. package/dist/prosemirror/extensions/nodes/BlockSdtExtension.d.ts +4 -3
  324. package/dist/prosemirror/extensions/nodes/BlockSdtExtension.js +18 -13
  325. package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +28 -53
  326. package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.d.ts +11 -0
  327. package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +97 -0
  328. package/dist/prosemirror/extensions/nodes/FieldExtension.js +9 -7
  329. package/dist/prosemirror/extensions/nodes/ImageExtension.js +24 -1
  330. package/dist/prosemirror/extensions/nodes/MoveRangeBoundaryExtension.d.ts +11 -0
  331. package/dist/prosemirror/extensions/nodes/MoveRangeBoundaryExtension.js +43 -0
  332. package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.d.ts +32 -0
  333. package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.js +67 -0
  334. package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.d.ts +16 -0
  335. package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.js +60 -0
  336. package/dist/prosemirror/extensions/nodes/RangeAnchorExtension.d.ts +13 -0
  337. package/dist/prosemirror/extensions/nodes/RangeAnchorExtension.js +65 -0
  338. package/dist/prosemirror/extensions/nodes/SdtExtension.d.ts +3 -1
  339. package/dist/prosemirror/extensions/nodes/SdtExtension.js +22 -16
  340. package/dist/prosemirror/extensions/nodes/ShapeExtension.js +7 -0
  341. package/dist/prosemirror/extensions/nodes/TableExtension.js +142 -123
  342. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +9 -1
  343. package/dist/prosemirror/extensions/nodes/bookmarkBoundaryDom.d.ts +23 -0
  344. package/dist/prosemirror/extensions/nodes/bookmarkBoundaryDom.js +57 -0
  345. package/dist/prosemirror/extensions/types.d.ts +12 -3
  346. package/dist/prosemirror/index.d.ts +4 -2
  347. package/dist/prosemirror/index.js +2 -1
  348. package/dist/prosemirror/inlineWrapperStack.d.ts +39 -0
  349. package/dist/prosemirror/inlineWrapperStack.js +92 -0
  350. package/dist/prosemirror/listMarker.d.ts +2 -2
  351. package/dist/prosemirror/listMarker.js +7 -8
  352. package/dist/prosemirror/listRenderingAttrs.js +11 -1
  353. package/dist/prosemirror/listState.d.ts +62 -0
  354. package/dist/prosemirror/listState.js +49 -0
  355. package/dist/prosemirror/moveRangeBoundaryAttrs.d.ts +13 -0
  356. package/dist/prosemirror/moveRangeBoundaryAttrs.js +114 -0
  357. package/dist/prosemirror/numberedRefFields.js +4 -4
  358. package/dist/prosemirror/numberingAttr.d.ts +55 -0
  359. package/dist/prosemirror/numberingAttr.js +74 -0
  360. package/dist/prosemirror/outlineLevelAttr.d.ts +29 -0
  361. package/dist/prosemirror/outlineLevelAttr.js +42 -0
  362. package/dist/prosemirror/pageBreakRunProjection.d.ts +17 -7
  363. package/dist/prosemirror/pageBreakRunProjection.js +19 -9
  364. package/dist/prosemirror/paragraphFormattingProvenance.d.ts +9 -0
  365. package/dist/prosemirror/paragraphFormattingProvenance.js +4 -1
  366. package/dist/prosemirror/plugins/selectionTracker.d.ts +3 -6
  367. package/dist/prosemirror/plugins/selectionTracker.js +3 -10
  368. package/dist/prosemirror/rangeAnchorAttrs.d.ts +14 -0
  369. package/dist/prosemirror/rangeAnchorAttrs.js +101 -0
  370. package/dist/prosemirror/replacedAnnotations.d.ts +59 -0
  371. package/dist/prosemirror/replacedAnnotations.js +183 -0
  372. package/dist/prosemirror/revisionCarriers.d.ts +86 -2
  373. package/dist/prosemirror/revisionCarriers.js +86 -60
  374. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +5 -1
  375. package/dist/prosemirror/runFormattingInlineCarriers.js +7 -1
  376. package/dist/prosemirror/runIdentity.d.ts +28 -0
  377. package/dist/prosemirror/runIdentity.js +36 -0
  378. package/dist/prosemirror/runStyleFormatting.js +1 -1
  379. package/dist/prosemirror/schema/index.d.ts +3 -3
  380. package/dist/prosemirror/schema/marks.d.ts +47 -4
  381. package/dist/prosemirror/schema/nodes.d.ts +309 -26
  382. package/dist/prosemirror/schema/nodes.js +16 -1
  383. package/dist/prosemirror/sectionCarrier.d.ts +37 -0
  384. package/dist/prosemirror/sectionCarrier.js +40 -0
  385. package/dist/prosemirror/selectionState.d.ts +3 -0
  386. package/dist/prosemirror/selectionState.js +4 -1
  387. package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +5 -4
  388. package/dist/prosemirror/styles/resolvedStyleAttrs.js +15 -13
  389. package/dist/prosemirror/tableResize.js +5 -6
  390. package/dist/prosemirror/trackedRunInlineAtoms.d.ts +4 -0
  391. package/dist/prosemirror/trackedRunInlineAtoms.js +4 -0
  392. package/dist/prosemirror/utils/extractTrackedChanges.d.ts +10 -11
  393. package/dist/prosemirror/utils/extractTrackedChanges.js +109 -92
  394. package/dist/prosemirror/validation.js +31 -6
  395. package/dist/prosemirror/yjsDocumentMetadata.d.ts +73 -0
  396. package/dist/prosemirror/yjsDocumentMetadata.js +592 -0
  397. package/dist/prosemirror/zeroWidthAnchors.js +6 -0
  398. package/dist/render-dom/commentAnchorAttributes.d.ts +37 -0
  399. package/dist/render-dom/commentAnchorAttributes.js +54 -0
  400. package/dist/server.d.ts +3 -1
  401. package/dist/server.js +3 -1
  402. package/dist/style-sets/extract.js +4 -4
  403. package/dist/style-sets/stellaStyle.js +36 -23
  404. package/dist/types/colors.d.ts +2 -2
  405. package/dist/types/content.d.ts +2 -2
  406. package/dist/types/documentEnumValues.d.ts +53 -26
  407. package/dist/types/documentEnumValues.js +72 -174
  408. package/dist/types/formatting.d.ts +2 -2
  409. package/dist/types/index.d.ts +9 -2
  410. package/dist/utils/borderCss.d.ts +246 -0
  411. package/dist/utils/borderCss.js +325 -0
  412. package/dist/utils/clipboard.d.ts +9 -1
  413. package/dist/utils/clipboard.js +27 -1
  414. package/dist/utils/colorResolver.d.ts +4 -3
  415. package/dist/utils/colorResolver.js +45 -76
  416. package/dist/utils/createDocument.js +24 -6
  417. package/dist/utils/findReplace.js +52 -10
  418. package/dist/utils/formatToStyle.d.ts +84 -2
  419. package/dist/utils/formatToStyle.js +133 -52
  420. package/dist/utils/headingCollector.js +3 -2
  421. package/dist/utils/imageLuminance.d.ts +15 -0
  422. package/dist/utils/imageLuminance.js +32 -0
  423. package/dist/utils/mergeDocumentContent.js +12 -20
  424. package/dist/utils/paragraphFormattingMerge.js +27 -6
  425. package/dist/utils/replaceText.js +1 -0
  426. package/dist/utils/tableOperations.d.ts +5 -3
  427. package/dist/utils/tableOperations.js +14 -1
  428. package/dist/utils/tablePlacement.d.ts +7 -0
  429. package/dist/utils/tablePlacement.js +14 -0
  430. package/dist/utils/textDirectionFlow.d.ts +15 -0
  431. package/dist/utils/textDirectionFlow.js +38 -0
  432. package/dist/utils/textFormattingMerge.js +16 -4
  433. package/package.json +10 -10
  434. package/dist/ai-edits/__fixtures__/paragraphs.d.ts +0 -17
  435. package/dist/ai-edits/__fixtures__/paragraphs.js +0 -33
  436. package/dist/compare/__fixtures__/body-sequence.d.ts +0 -119
  437. package/dist/compare/__fixtures__/body-sequence.js +0 -225
  438. package/dist/compare/__fixtures__/nested-table.d.ts +0 -16
  439. package/dist/compare/__fixtures__/nested-table.js +0 -50
  440. package/dist/compare/__fixtures__/numbered-list.d.ts +0 -34
  441. package/dist/compare/__fixtures__/numbered-list.js +0 -85
  442. package/dist/docx/blockRangeMarkers.d.ts +0 -36
  443. package/dist/docx/blockRangeMarkers.js +0 -59
  444. package/dist/docx/bookmarkPlacement.d.ts +0 -9
  445. package/dist/docx/bookmarkPlacement.js +0 -50
  446. package/dist/fonts/embeddedFontTable.d.ts +0 -45
  447. package/dist/fonts/embeddedFontTable.js +0 -80
  448. package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.d.ts +0 -13
  449. package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.js +0 -39
  450. package/dist/prosemirror/yjsParagraphSourceContract.d.ts +0 -9
  451. package/dist/prosemirror/yjsParagraphSourceContract.js +0 -26
@@ -1,37 +1,59 @@
1
+ import { rangedCommentIds } from "../../docx/commentAnchorIndex.js";
1
2
  import { resolveColorValueToHex } from "../../docx/drawingUtils.js";
2
- import { isNumberingReference } from "../../docx/numberingReference.js";
3
+ import { isInlineSdtContent, isTrackedChangeWrapperChild } from "../../docx/inlineWrapperContent.js";
4
+ import { mergeParagraphNumbering as mergeParagraphNumbering$1, paragraphNumberingReferenceId as paragraphNumberingReferenceId$1 } from "../../docx/numberingReference.js";
3
5
  import { PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR, createProseParagraphWithPropertySource, getDocumentParagraphPropertySourceContract, recreateProseNodeWithParagraphPropertySource, transportTableCellsWithParagraphPropertySources } from "../../docx/paragraphPropertySource.js";
4
6
  import { isBaselineVertAlign } from "../../docx/runParser.js";
5
7
  import { resolveTableLook } from "../../docx/tableLook.js";
6
8
  import { isCellMergeContinuation } from "../../docx/tableParser.js";
9
+ import { copiedWrapPolygon } from "../../docx/wrapPolygon.js";
7
10
  import { buildPageBreakRunSourceDescendantIndex } from "../../internal/pageBreakRunSourceDescendantIndex.js";
8
11
  import { createStyleEngine } from "../../style-engine/styleEngine.js";
12
+ import { outlineAttrForDash } from "../../types/documentEnumValues.js";
13
+ import { cssBorderStyleForDash } from "../../utils/borderCss.js";
9
14
  import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
10
15
  import { mergeParagraphFormatting, mergeParagraphTabStops } from "../../utils/paragraphFormattingMerge.js";
11
16
  import { tableOfContentsStyleLevel } from "../../utils/tableOfContentsStyle.js";
12
17
  import { mergeTextFormatting } from "../../utils/textFormattingMerge.js";
13
18
  import { emuToPixels, emuToStrokePixels } from "../../utils/units.js";
19
+ import { expectInlineWrapperMarkAttrs } from "../attrs/index.js";
20
+ import { authoredTransformAttrs } from "../authoredTransformAttrs.js";
14
21
  import { setAutospacingBaseValue } from "../autospacingBase.js";
22
+ import { planEmptyRanges } from "../emptyRangeAnchor.js";
23
+ import { INLINE_WRAPPER_MARK_NAME } from "../extensions/marks/InlineWrapperExtension.js";
15
24
  import { textFormattingToMarks } from "../extensions/marks/markUtils.js";
25
+ import { MOVE_RANGE_BOUNDARY_NODE_NAME } from "../extensions/nodes/MoveRangeBoundaryExtension.js";
26
+ import { RANGE_ANCHOR_NODE_NAME } from "../extensions/nodes/RangeAnchorExtension.js";
27
+ import "../extensions/nodes/SdtExtension.js";
28
+ import { inlineWrapperLayer } from "../inlineWrapperStack.js";
16
29
  import { listRenderingAttrPatch } from "../listRenderingAttrs.js";
17
30
  import { stampNumberedRefFieldBaselines } from "../numberedRefFields.js";
31
+ import { paragraphNumberingAttr } from "../numberingAttr.js";
18
32
  import { pageBreakRunParagraphProjectionDispositionForFeatures } from "../pageBreakRunProjection.js";
19
33
  import { directionFromBidi } from "../paragraphDirection.js";
20
34
  import { styleResolvedParagraphFormatting } from "../paragraphFormattingProvenance.js";
21
35
  import { lineSpacingProvenanceFromSpacing } from "../paragraphSpacing.js";
36
+ import { RUN_IDENTITY_MARK_NAME, hasRunIdentityPayload, runIdentityAttrs } from "../runIdentity.js";
22
37
  import { getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, resolveParagraphBodyRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting } from "../runStyleFormatting.js";
23
38
  import { schema } from "../schema/index.js";
39
+ import { PRESERVED_XML_LEVELS } from "../schema/nodes.js";
24
40
  import { cascadeStyleTextFormatting } from "../styles/styleToggleCascade.js";
25
41
  import { canCarryTrackedRunMark, trackedRunInlineAtomDisposition } from "../trackedRunInlineAtoms.js";
26
42
  import { assertValidProseMirrorDocument } from "../validation.js";
27
43
  import { resolveEffectiveTableCellFormatting } from "./effectiveTableCellFormatting.js";
44
+ import { hasSinkChildren } from "./preservedSinkCarriers.js";
28
45
  import { sdtAttrsFromProperties } from "./sdtAttrs.js";
29
- import { TaggedError, panic } from "better-result";
30
- import { DRAWING_RAW_XML_MODES } from "@stll/docx-core/model";
46
+ import { panic } from "better-result";
47
+ import { DRAWING_RAW_XML_MODES, PARSE_WARNING_CODES } from "@stll/docx-core/model";
31
48
  //#region src/prosemirror/conversion/toProseDoc.ts
32
- /** DOCX content that cannot be preserved by the editable ProseMirror model. */
33
- var UnsupportedDocxToProseMirrorConversionError = class extends TaggedError("UnsupportedDocxToProseMirrorConversionError") {};
34
49
  const DETACHED_WATERMARK_HOST = Symbol.for("stll.detachedWatermarkHost");
50
+ const noPageBreakProjectionWarning = () => {};
51
+ const pageBreakProjectionWarn = (warn) => warn === void 0 ? noPageBreakProjectionWarning : (detail) => {
52
+ warn({
53
+ code: PARSE_WARNING_CODES.pageBreakProjectionApproximated,
54
+ detail
55
+ });
56
+ };
35
57
  /**
36
58
  * Build a `nextTextBoxGroupId()` generator salted with a random per-load
37
59
  * nonce, so minted text-box anchor ids (`<salt>:<group>:<index>`) are unique
@@ -47,6 +69,26 @@ const createTextBoxGroupIdFactory = () => {
47
69
  let index = 0;
48
70
  return () => `${salt}:${index++}`;
49
71
  };
72
+ /**
73
+ * The identity mark for one authored `w:r`, or `null` when it carries nothing
74
+ * worth a mark.
75
+ *
76
+ * The only place the mark is minted. Both run-converting paths call it — the
77
+ * paragraph's and the hyperlink's — so the next payload field is added once
78
+ * rather than to whichever site the author happened to open.
79
+ *
80
+ * Minted when the run holds a page break (the leaves it is cut into have to be
81
+ * rejoined into one `w:r` on save), an attribute remainder, or a `w:rPr` sink.
82
+ * 57.5% of corpus files hold none of the three and mint nothing.
83
+ */
84
+ const runIdentityMark = (run, nextRunIdentityId) => {
85
+ const payload = {
86
+ preservedAttributes: run.preservedAttributes,
87
+ preserved: run.formatting?.preserved
88
+ };
89
+ if (!runHasPageBreakContent(run) && !hasRunIdentityPayload(payload)) return null;
90
+ return schema.mark(RUN_IDENTITY_MARK_NAME, runIdentityAttrs(nextRunIdentityId(), payload));
91
+ };
50
92
  /** Keep imported hyperlink identity unique across every nested conversion scope. */
51
93
  const createHyperlinkInstanceIndexAllocator = () => {
52
94
  let index = 0;
@@ -89,6 +131,10 @@ const collectPairedBookmarkIds = (blocks) => {
89
131
  case "run":
90
132
  visitRun(child);
91
133
  break;
134
+ case "preservedInline": break;
135
+ case "inlineWrapper":
136
+ for (const wrapped of child.content) visitParagraphContent(wrapped);
137
+ break;
92
138
  default: panic(`Unsupported hyperlink child: ${JSON.stringify(child)}`);
93
139
  }
94
140
  };
@@ -107,8 +153,7 @@ const collectPairedBookmarkIds = (blocks) => {
107
153
  visitHyperlink(content);
108
154
  return;
109
155
  case "simpleField":
110
- for (const child of content.content) if (child.type === "hyperlink") visitHyperlink(child);
111
- else visitRun(child);
156
+ for (const child of content.content) visitParagraphContent(child);
112
157
  return;
113
158
  case "complexField":
114
159
  for (const run of [...content.fieldCode ?? [], ...content.fieldResult]) visitRun(run);
@@ -118,7 +163,7 @@ const collectPairedBookmarkIds = (blocks) => {
118
163
  case "deletion":
119
164
  case "moveFrom":
120
165
  case "moveTo":
121
- case "bidiWrapper":
166
+ case "inlineWrapper":
122
167
  for (const child of content.content) visitParagraphContent(child);
123
168
  return;
124
169
  case "commentRangeStart":
@@ -128,7 +173,8 @@ const collectPairedBookmarkIds = (blocks) => {
128
173
  case "moveFromRangeEnd":
129
174
  case "moveToRangeStart":
130
175
  case "moveToRangeEnd":
131
- case "mathEquation": return;
176
+ case "mathEquation":
177
+ case "preservedInline": return;
132
178
  default: panic(`Unsupported paragraph content: ${JSON.stringify(content)}`);
133
179
  }
134
180
  };
@@ -138,11 +184,22 @@ const collectPairedBookmarkIds = (blocks) => {
138
184
  for (const content of block.content) visitParagraphContent(content);
139
185
  break;
140
186
  case "table":
141
- for (const row of block.rows) for (const cell of row.cells) visitBlocks(cell.content);
187
+ for (const { marker } of block.bookmarks ?? []) countBoundary(marker.id, marker.type === "bookmarkStart" ? "start" : "end");
188
+ for (const row of block.rows) {
189
+ for (const { marker } of row.bookmarks ?? []) countBoundary(marker.id, marker.type === "bookmarkStart" ? "start" : "end");
190
+ for (const cell of row.cells) visitBlocks(cell.content);
191
+ }
142
192
  break;
143
193
  case "blockSdt":
144
194
  visitBlocks(block.content);
145
195
  break;
196
+ case "preservedBlock": break;
197
+ case "bookmarkStart":
198
+ countBoundary(block.id, "start");
199
+ break;
200
+ case "bookmarkEnd":
201
+ countBoundary(block.id, "end");
202
+ break;
146
203
  default: panic(`Unsupported block content: ${JSON.stringify(block)}`);
147
204
  }
148
205
  };
@@ -166,7 +223,10 @@ function toProseDoc(document, options) {
166
223
  nextTextBoxGroupId,
167
224
  nextHyperlinkInstanceIndex: createHyperlinkInstanceIndexAllocator(),
168
225
  pairedBookmarkIds: collectPairedBookmarkIds(paragraphs),
169
- pageBreakRunSourceDescendants: buildPageBreakRunSourceDescendantIndex(paragraphs)
226
+ pageBreakRunSourceDescendants: buildPageBreakRunSourceDescendantIndex(paragraphs),
227
+ storyRangedCommentIds: rangedCommentIds(paragraphs),
228
+ openCommentIds: /* @__PURE__ */ new Set(),
229
+ warnPageBreakProjection: pageBreakProjectionWarn(options?.warn)
170
230
  };
171
231
  const convertBodyBlocks = (blocks) => {
172
232
  const out = [];
@@ -183,6 +243,13 @@ function toProseDoc(document, options) {
183
243
  case "blockSdt":
184
244
  out.push(convertBlockSdt(block, convertBodyBlocks));
185
245
  break;
246
+ case "preservedBlock":
247
+ out.push(convertPreservedBlock(block));
248
+ break;
249
+ case "bookmarkStart":
250
+ case "bookmarkEnd":
251
+ out.push(convertBlockBookmarkBoundary(block));
252
+ break;
186
253
  default: panic(`Unsupported block content: ${JSON.stringify(block)}`);
187
254
  }
188
255
  return out;
@@ -200,10 +267,57 @@ function toProseDoc(document, options) {
200
267
  return pmDoc;
201
268
  }
202
269
  /**
270
+ * Carry a block folio does not model into the editor as a zero-width node.
271
+ *
272
+ * The node's place in the document is the whole of its position, so it needs
273
+ * no index and nothing has to keep one honest as the blocks around it change.
274
+ */
275
+ function convertPreservedBlock(block) {
276
+ return schema.node("preservedBlock", { xml: block.xml });
277
+ }
278
+ /**
279
+ * Carry a bookmark marker that stands between two blocks into the editor.
280
+ *
281
+ * Unconditional, unlike the inline atom: an unpaired inline boundary falls
282
+ * back to the paragraph's `bookmarks` attribute, and a marker between blocks
283
+ * has no paragraph to fall back to. Dropping it is the loss this node exists
284
+ * to prevent, and the integrity pass removes a boundary whose partner really
285
+ * has gone.
286
+ */
287
+ function convertBlockBookmarkBoundary(block) {
288
+ return schema.node("blockBookmarkBoundary", block.type === "bookmarkStart" ? {
289
+ type: "start",
290
+ id: block.id,
291
+ name: block.name,
292
+ colFirst: block.colFirst,
293
+ colLast: block.colLast,
294
+ displacedByCustomXml: block.displacedByCustomXml
295
+ } : {
296
+ type: "end",
297
+ id: block.id,
298
+ displacedByCustomXml: block.displacedByCustomXml
299
+ });
300
+ }
301
+ /**
302
+ * Carry an inline child folio does not model into the editor as an opaque atom.
303
+ *
304
+ * The same atom the run level uses, tagged with the level it came from: the
305
+ * markup is a paragraph child and the save path must not put it back inside a
306
+ * `w:r`. It carries whatever marks surround it, so a capture inside a
307
+ * `w:ins` keeps the insertion and is accepted or rejected with it.
308
+ */
309
+ function preservedInlineNode(content) {
310
+ return schema.node("preservedXml", {
311
+ xml: content.xml,
312
+ text: content.text,
313
+ level: PRESERVED_XML_LEVELS.inline
314
+ });
315
+ }
316
+ /**
203
317
  * Convert a `BlockSdt` model node into a `blockSdt` PM node, recursively
204
318
  * converting its children with the caller-supplied block converter. Pass
205
- * `rawPropertiesXml` / `rawEndPropertiesXml` through as attrs so the
206
- * serializer can replay them verbatim after a save.
319
+ * the preserved `w:sdtPr` children and the verbatim `<w:sdtEndPr>` through
320
+ * as attrs so the serializer can put them back after a save.
207
321
  */
208
322
  function convertBlockSdt(blockSdt, convertBlocks) {
209
323
  const props = blockSdt.properties;
@@ -214,15 +328,16 @@ function convertBlockSdt(blockSdt, convertBlocks) {
214
328
  id: props.id ?? null,
215
329
  lock: props.lock ?? null,
216
330
  placeholder: props.placeholder ?? null,
217
- showingPlaceholder: props.showingPlaceholder ?? false,
331
+ showingPlaceholder: props.showingPlaceholder ?? null,
218
332
  dateFormat: props.dateFormat ?? null,
219
333
  dateValueISO: props.dateValueISO ?? null,
220
334
  listItems: props.listItems ? JSON.stringify(props.listItems) : null,
221
335
  dropdownLastValue: props.dropdownLastValue ?? null,
222
336
  checked: props.checked ?? null,
223
337
  _originallyEmpty: blockSdt.content.length === 0,
224
- rawPropertiesXml: props.rawPropertiesXml ?? null,
338
+ _preserved: props.preserved ?? null,
225
339
  rawEndPropertiesXml: props.rawEndPropertiesXml ?? null,
340
+ endProperties: props.endProperties ?? null,
226
341
  rawSdtChildrenBeforeContent: props.rawSdtChildrenBeforeContent ?? null,
227
342
  rawSdtChildrenAfterContent: props.rawSdtChildrenAfterContent ?? null
228
343
  };
@@ -236,26 +351,27 @@ function convertBlockSdt(blockSdt, convertBlocks) {
236
351
  * Resolves style-based text formatting and passes it to runs so that
237
352
  * paragraph styles (like Heading1) apply their font size, color, etc.
238
353
  */
239
- function convertParagraph(paragraph, styleResolver, context, activeCommentIds, extraRunFormatting, tableParagraphOverlay, textBoxAnchors) {
240
- const { nextHyperlinkInstanceIndex, pairedBookmarkIds, pageBreakRunSourceDescendants } = context;
241
- let pageBreakRunOwnerId = 0;
242
- const nextPageBreakRunOwnerId = () => pageBreakRunOwnerId++;
354
+ function convertParagraph(paragraph, styleResolver, context, extraRunFormatting, tableParagraphOverlay, textBoxAnchors) {
355
+ const { nextHyperlinkInstanceIndex, pairedBookmarkIds, pageBreakRunSourceDescendants, storyRangedCommentIds, openCommentIds } = context;
356
+ let runIdentityId = 0;
357
+ const nextRunIdentityId = () => runIdentityId++;
243
358
  const { attrs, effectiveFrame } = paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOverlay);
244
- assertParagraphPageBreakCanBeProjected({
359
+ reportParagraphPageBreakProjection({
245
360
  paragraph,
246
361
  attrs,
247
362
  effectiveFrame,
248
- sourceDescendants: pageBreakRunSourceDescendants
363
+ sourceDescendants: pageBreakRunSourceDescendants,
364
+ warn: context.warnPageBreakProjection
249
365
  });
250
366
  const isTocParagraph = attrs._tableOfContentsLevel !== void 0;
251
367
  const inlineNodes = [];
252
368
  let inlineOffset = 0;
253
369
  let bookmarksArr;
254
370
  let emptyHyperlinks;
255
- const commentIds = activeCommentIds ?? /* @__PURE__ */ new Set();
371
+ let wrapperStack = [];
256
372
  const emitInlineNodes = (nodes) => {
257
373
  if (nodes.length === 0) return;
258
- const markedNodes = applyCommentMarks(nodes, commentIds);
374
+ const markedNodes = applyCommentMarks(withInlineWrapperMark(nodes, wrapperStack), openCommentIds);
259
375
  inlineNodes.push(...markedNodes);
260
376
  for (const node of markedNodes) inlineOffset += node.nodeSize;
261
377
  };
@@ -320,98 +436,129 @@ function convertParagraph(paragraph, styleResolver, context, activeCommentIds, e
320
436
  toggleCascade: inheritedToggleCascade
321
437
  };
322
438
  };
439
+ const getHistoricalRunFormatting = (formatting) => {
440
+ const hasCharacterStyle = formatting?.styleId !== void 0;
441
+ const inheritedBaseFormatting = hasCharacterStyle ? baseRunFormatting : ordinaryBaseWithDefaultCharacter;
442
+ const inheritedToggleCascade = hasCharacterStyle ? orderedToggleFormatting : defaultCharacterStyleCascade;
443
+ return {
444
+ formatting: inheritedBaseFormatting,
445
+ ...!hasCharacterStyle ? { implicitCharacterStyleApplied: true } : {},
446
+ toggleCascade: inheritedToggleCascade
447
+ };
448
+ };
449
+ const trackedRunFormattingResolvers = {
450
+ current: getInheritedRunFormatting,
451
+ historical: getHistoricalRunFormatting
452
+ };
323
453
  const emitTrackedChange = (change, markType, moveKind) => {
324
- emitInlineNodes(convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, moveKind, textBoxAnchors));
454
+ emitInlineNodes(convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, nextRunIdentityId, trackedRunFormattingResolvers, styleResolver, moveKind, textBoxAnchors, wrapperStack));
325
455
  };
326
- for (const content of withoutBidiWrappers(paragraph.content)) switch (content.type) {
327
- case "commentRangeStart":
328
- commentIds.add(content.id);
329
- break;
330
- case "commentRangeEnd":
331
- commentIds.delete(content.id);
332
- break;
333
- case "commentReference":
334
- anchorPointComment(inlineNodes, content.id);
335
- break;
336
- case "run":
337
- emitInlineNodes(convertRun(content, getInheritedRunFormatting(content.formatting), nextPageBreakRunOwnerId, styleResolver, textBoxAnchors));
338
- break;
339
- case "hyperlink": {
340
- const linkNodes = convertHyperlink(content, {
341
- getInheritedRunFormatting,
342
- styleResolver,
343
- hyperlinkIndex: nextHyperlinkInstanceIndex(),
344
- textBoxAnchors,
345
- nextPageBreakRunOwnerId
346
- });
347
- if (linkNodes.length === 0) {
348
- emptyHyperlinks ??= [];
349
- emptyHyperlinks.push({
350
- offset: inlineOffset,
351
- ...content.href !== void 0 ? { href: content.href } : {},
352
- ...content.anchor !== void 0 ? { anchor: content.anchor } : {},
353
- ...content.tooltip !== void 0 ? { tooltip: content.tooltip } : {},
354
- ...content.rId !== void 0 ? { rId: content.rId } : {}
456
+ const stacked = withInlineWrapperStacks(paragraph.content);
457
+ const emptyRanges = planEmptyRanges(stacked.map((item) => item.content));
458
+ for (const [index, { content, stack }] of stacked.entries()) {
459
+ wrapperStack = stack;
460
+ const anchored = emptyRanges.anchorAt.get(index);
461
+ if (anchored) {
462
+ emitInlineNode(schema.node(RANGE_ANCHOR_NODE_NAME, anchored));
463
+ continue;
464
+ }
465
+ if (emptyRanges.closedAt.has(index)) continue;
466
+ switch (content.type) {
467
+ case "commentRangeStart":
468
+ openCommentIds.add(content.id);
469
+ break;
470
+ case "commentRangeEnd":
471
+ openCommentIds.delete(content.id);
472
+ break;
473
+ case "commentReference":
474
+ if (!storyRangedCommentIds.has(content.id)) anchorPointComment(inlineNodes, content.id);
475
+ emitInlineNode(schema.node("commentReference", { commentId: content.id }));
476
+ break;
477
+ case "run":
478
+ emitInlineNodes(convertRun(content, getInheritedRunFormatting(content.formatting), nextRunIdentityId, styleResolver, textBoxAnchors));
479
+ break;
480
+ case "hyperlink": {
481
+ const linkNodes = convertHyperlink(content, {
482
+ getInheritedRunFormatting,
483
+ styleResolver,
484
+ hyperlinkIndex: nextHyperlinkInstanceIndex(),
485
+ textBoxAnchors,
486
+ nextRunIdentityId
355
487
  });
488
+ if (linkNodes.length === 0) {
489
+ emptyHyperlinks ??= [];
490
+ emptyHyperlinks.push({
491
+ offset: inlineOffset,
492
+ ...content.href !== void 0 ? { href: content.href } : {},
493
+ ...content.anchor !== void 0 ? { anchor: content.anchor } : {},
494
+ ...content.tooltip !== void 0 ? { tooltip: content.tooltip } : {},
495
+ ...content.rId !== void 0 ? { rId: content.rId } : {}
496
+ });
497
+ break;
498
+ }
499
+ emitInlineNodes(linkNodes);
356
500
  break;
357
501
  }
358
- emitInlineNodes(linkNodes);
359
- break;
360
- }
361
- case "simpleField":
362
- case "complexField":
363
- emitInlineNode(convertField(content, {
364
- getInheritedRunFormatting,
365
- styleResolver,
366
- nextHyperlinkInstanceIndex,
367
- nextPageBreakRunOwnerId,
368
- textBoxAnchors
369
- }));
370
- break;
371
- case "inlineSdt":
372
- emitInlineNode(convertInlineSdt(content, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, textBoxAnchors));
373
- break;
374
- case "insertion":
375
- case "moveTo":
376
- emitTrackedChange(content, "insertion", content.type === "moveTo" ? "moveTo" : null);
377
- break;
378
- case "deletion":
379
- case "moveFrom":
380
- emitTrackedChange(content, "deletion", content.type === "moveFrom" ? "moveFrom" : null);
381
- break;
382
- case "mathEquation":
383
- emitInlineNode(convertMathEquation(content));
384
- break;
385
- case "bookmarkStart":
386
- if (pairedBookmarkIds.has(content.id)) {
387
- emitInlineNode(schema.node("bookmarkBoundary", {
388
- type: "start",
502
+ case "simpleField":
503
+ case "complexField":
504
+ emitInlineNode(convertField(content, {
505
+ getInheritedRunFormatting,
506
+ styleResolver,
507
+ nextHyperlinkInstanceIndex,
508
+ nextRunIdentityId,
509
+ textBoxAnchors
510
+ }));
511
+ break;
512
+ case "inlineSdt":
513
+ emitInlineNode(convertInlineSdt(content, nextHyperlinkInstanceIndex, nextRunIdentityId, getInheritedRunFormatting, trackedRunFormattingResolvers, styleResolver, textBoxAnchors, stack));
514
+ break;
515
+ case "insertion":
516
+ case "moveTo":
517
+ emitTrackedChange(content, "insertion", content.type === "moveTo" ? "moveTo" : null);
518
+ break;
519
+ case "deletion":
520
+ case "moveFrom":
521
+ emitTrackedChange(content, "deletion", content.type === "moveFrom" ? "moveFrom" : null);
522
+ break;
523
+ case "mathEquation":
524
+ emitInlineNode(convertMathEquation(content));
525
+ break;
526
+ case "bookmarkStart":
527
+ if (pairedBookmarkIds.has(content.id)) {
528
+ emitInlineNode(schema.node("bookmarkBoundary", {
529
+ type: "start",
530
+ id: content.id,
531
+ name: content.name,
532
+ colFirst: content.colFirst,
533
+ colLast: content.colLast,
534
+ displacedByCustomXml: content.displacedByCustomXml
535
+ }));
536
+ break;
537
+ }
538
+ if (!bookmarksArr) bookmarksArr = [];
539
+ bookmarksArr.push({
540
+ id: content.id,
541
+ name: content.name
542
+ });
543
+ break;
544
+ case "bookmarkEnd":
545
+ if (pairedBookmarkIds.has(content.id)) emitInlineNode(schema.node("bookmarkBoundary", {
546
+ type: "end",
389
547
  id: content.id,
390
- name: content.name,
391
- colFirst: content.colFirst,
392
- colLast: content.colLast,
393
548
  displacedByCustomXml: content.displacedByCustomXml
394
549
  }));
395
550
  break;
396
- }
397
- if (!bookmarksArr) bookmarksArr = [];
398
- bookmarksArr.push({
399
- id: content.id,
400
- name: content.name
401
- });
402
- break;
403
- case "bookmarkEnd":
404
- if (pairedBookmarkIds.has(content.id)) emitInlineNode(schema.node("bookmarkBoundary", {
405
- type: "end",
406
- id: content.id,
407
- displacedByCustomXml: content.displacedByCustomXml
408
- }));
409
- break;
410
- case "moveFromRangeStart":
411
- case "moveFromRangeEnd":
412
- case "moveToRangeStart":
413
- case "moveToRangeEnd": break;
414
- default: panic(`Unsupported paragraph content: ${JSON.stringify(content)}`);
551
+ case "moveFromRangeStart":
552
+ case "moveFromRangeEnd":
553
+ case "moveToRangeStart":
554
+ case "moveToRangeEnd":
555
+ emitInlineNode(schema.node(MOVE_RANGE_BOUNDARY_NODE_NAME, { marker: content }));
556
+ break;
557
+ case "preservedInline":
558
+ emitInlineNode(preservedInlineNode(content));
559
+ break;
560
+ default: panic(`Unsupported paragraph content: ${JSON.stringify(content)}`);
561
+ }
415
562
  }
416
563
  if (bookmarksArr) attrs.bookmarks = bookmarksArr;
417
564
  if (emptyHyperlinks) attrs._emptyHyperlinks = emptyHyperlinks;
@@ -446,65 +593,91 @@ function anchorPointComment(nodes, commentId) {
446
593
  }
447
594
  }
448
595
  /**
596
+ * One node of a revision's content with the revision recorded on it.
597
+ *
598
+ * An inline content control is an `inline*` node rather than an atom, so it is
599
+ * not a run carrier: the revision goes on the leaves it holds. That is what
600
+ * makes `w:ins > w:sdt` and `w:sdt > w:ins` the same marks on the same leaves,
601
+ * and it is what lets the save leg hoist a revision covering all of them back
602
+ * around the control instead of losing it.
603
+ */
604
+ const withTrackedRunMark = (node, mark) => {
605
+ if (node.marks.some(({ type }) => type.name === "insertion" || type.name === "deletion")) return node;
606
+ if (node.type.name === "sdt") {
607
+ const marked = [];
608
+ for (let index = 0; index < node.childCount; index += 1) marked.push(withTrackedRunMark(node.child(index), mark));
609
+ return recreateProseNodeWithParagraphPropertySource(node, { content: marked });
610
+ }
611
+ if (trackedRunInlineAtomDisposition(node) === "outside-wrapper") panic(`Inline atom ${JSON.stringify(node.type.name)} cannot occur in a tracked-run wrapper`);
612
+ if (canCarryTrackedRunMark(node)) return node.mark(mark.addToSet(node.marks));
613
+ return node;
614
+ };
615
+ /**
449
616
  * Convert tracked change (insertion or deletion) content to PM nodes with
450
617
  * an insertion/deletion mark applied.
451
618
  */
452
- function convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, moveKind = null, textBoxAnchors) {
619
+ function convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, nextRunIdentityId, runFormattingResolvers, styleResolver, moveKind = null, textBoxAnchors, wrappedBy = []) {
453
620
  const nodes = [];
454
- for (const item of change.content) if (item.type === "run") nodes.push(...convertRun(item, getInheritedRunFormatting(item.formatting), nextPageBreakRunOwnerId, styleResolver, textBoxAnchors));
455
- else if (item.type === "hyperlink") {
456
- const currentHyperlinkIndex = nextHyperlinkInstanceIndex();
457
- nodes.push(...convertHyperlink(item, {
458
- getInheritedRunFormatting,
459
- styleResolver,
460
- hyperlinkIndex: currentHyperlinkIndex,
461
- textBoxAnchors,
462
- nextPageBreakRunOwnerId
621
+ const getTrackedRunFormatting = markType === "deletion" ? runFormattingResolvers.historical : runFormattingResolvers.current;
622
+ for (const { content: item, stack } of withInlineWrapperStacks(change.content)) {
623
+ if (!isTrackedChangeWrapperChild(item)) continue;
624
+ const itemNodes = [];
625
+ if (item.type === "run") itemNodes.push(...convertRun(item, getTrackedRunFormatting(item.formatting), nextRunIdentityId, styleResolver, textBoxAnchors));
626
+ else if (item.type === "hyperlink") {
627
+ const currentHyperlinkIndex = nextHyperlinkInstanceIndex();
628
+ itemNodes.push(...convertHyperlink(item, {
629
+ getInheritedRunFormatting: getTrackedRunFormatting,
630
+ styleResolver,
631
+ hyperlinkIndex: currentHyperlinkIndex,
632
+ textBoxAnchors,
633
+ nextRunIdentityId
634
+ }));
635
+ } else if (item.type === "simpleField" || item.type === "complexField") {
636
+ const fieldNode = convertField(item, {
637
+ getInheritedRunFormatting: getTrackedRunFormatting,
638
+ styleResolver,
639
+ nextHyperlinkInstanceIndex,
640
+ nextRunIdentityId,
641
+ textBoxAnchors
642
+ });
643
+ if (fieldNode) itemNodes.push(fieldNode);
644
+ } else if (item.type === "mathEquation") {
645
+ const mathNode = convertMathEquation(item);
646
+ if (mathNode) itemNodes.push(mathNode);
647
+ } else if (item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") {
648
+ const nestedMarkType = item.type === "insertion" || item.type === "moveTo" ? "insertion" : "deletion";
649
+ const nestedMoveKind = item.type === "moveFrom" || item.type === "moveTo" ? item.type : null;
650
+ itemNodes.push(...convertTrackedChange(item, nestedMarkType, nextHyperlinkInstanceIndex, nextRunIdentityId, runFormattingResolvers, styleResolver, nestedMoveKind, textBoxAnchors));
651
+ } else if (item.type === "inlineSdt") {
652
+ const sdtNode = convertInlineSdt(item, nextHyperlinkInstanceIndex, nextRunIdentityId, getTrackedRunFormatting, runFormattingResolvers, styleResolver, textBoxAnchors, [...wrappedBy, ...stack]);
653
+ if (sdtNode) itemNodes.push(sdtNode);
654
+ } else if (item.type === "bookmarkStart") itemNodes.push(schema.node("bookmarkBoundary", {
655
+ type: "start",
656
+ id: item.id,
657
+ name: item.name,
658
+ colFirst: item.colFirst,
659
+ colLast: item.colLast,
660
+ displacedByCustomXml: item.displacedByCustomXml
463
661
  }));
464
- } else if (item.type === "simpleField" || item.type === "complexField") {
465
- const fieldNode = convertField(item, {
466
- getInheritedRunFormatting,
467
- styleResolver,
468
- nextHyperlinkInstanceIndex,
469
- nextPageBreakRunOwnerId,
470
- textBoxAnchors
471
- });
472
- if (fieldNode) nodes.push(fieldNode);
473
- } else if (item.type === "mathEquation") {
474
- const mathNode = convertMathEquation(item);
475
- if (mathNode) nodes.push(mathNode);
476
- } else if (item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") {
477
- const nestedMarkType = item.type === "insertion" || item.type === "moveTo" ? "insertion" : "deletion";
478
- const nestedMoveKind = item.type === "moveFrom" || item.type === "moveTo" ? item.type : null;
479
- nodes.push(...convertTrackedChange(item, nestedMarkType, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, nestedMoveKind, textBoxAnchors));
480
- } else if (item.type === "bookmarkStart") nodes.push(schema.node("bookmarkBoundary", {
481
- type: "start",
482
- id: item.id,
483
- name: item.name,
484
- colFirst: item.colFirst,
485
- colLast: item.colLast,
486
- displacedByCustomXml: item.displacedByCustomXml
487
- }));
488
- else if (item.type === "bookmarkEnd") nodes.push(schema.node("bookmarkBoundary", {
489
- type: "end",
490
- id: item.id,
491
- displacedByCustomXml: item.displacedByCustomXml
492
- }));
493
- else panic(`Unsupported tracked-run content: ${JSON.stringify(item)}`);
662
+ else if (item.type === "bookmarkEnd") itemNodes.push(schema.node("bookmarkBoundary", {
663
+ type: "end",
664
+ id: item.id,
665
+ displacedByCustomXml: item.displacedByCustomXml
666
+ }));
667
+ else if (item.type === "preservedInline") itemNodes.push(preservedInlineNode(item));
668
+ else panic(`Unsupported tracked-run content: ${JSON.stringify(item)}`);
669
+ nodes.push(...withInlineWrapperMark(itemNodes, stack));
670
+ }
494
671
  const mark = schema.marks[markType].create({
495
672
  revisionId: change.info.id,
496
673
  author: change.info.author,
497
674
  date: change.info.date ?? null,
498
675
  utcDate: change.info.utcDate?.value ?? null,
499
676
  initials: change.info.initials ?? null,
500
- moveKind
501
- });
502
- return nodes.map((node) => {
503
- if (node.marks.some(({ type }) => type.name === "insertion" || type.name === "deletion")) return node;
504
- if (trackedRunInlineAtomDisposition(node) === "outside-wrapper") panic(`Inline atom ${JSON.stringify(node.type.name)} cannot occur in a tracked-run wrapper`);
505
- if (canCarryTrackedRunMark(node)) return node.mark(mark.addToSet(node.marks));
506
- return node;
677
+ moveKind,
678
+ ...markType === "deletion" ? { _historicalFormatting: true } : {}
507
679
  });
680
+ return nodes.map((node) => withTrackedRunMark(node, mark));
508
681
  }
509
682
  function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOverlay) {
510
683
  const formatting = paragraph.formatting;
@@ -520,11 +693,22 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
520
693
  if (paragraph.reviewCarrier) attrs.reviewCarrier = paragraph.reviewCarrier;
521
694
  if (styleId) attrs.styleId = styleId;
522
695
  if (tableOfContentsLevel !== void 0) attrs._tableOfContentsLevel = tableOfContentsLevel;
523
- if (formatting?.numPr) attrs.numPr = formatting.numPr;
524
- if (formatting?.numPrFromStyle) attrs.numPrFromStyle = formatting.numPrFromStyle;
696
+ if (formatting?.numPr) attrs.numPr = paragraphNumberingAttr(formatting.numPr);
697
+ if (formatting?.numPrFromStyle) attrs.numPrFromStyle = paragraphNumberingAttr(formatting.numPrFromStyle);
525
698
  if (paragraph.listRendering) Object.assign(attrs, listRenderingAttrPatch(paragraph.listRendering));
526
699
  if (formatting) attrs._originalFormatting = formatting;
527
- if (paragraph.propertyChanges && paragraph.propertyChanges.length > 0) attrs._propertyChanges = [...paragraph.propertyChanges];
700
+ if (paragraph.propertyChanges && paragraph.propertyChanges.length > 0) attrs._propertyChanges = paragraph.propertyChanges.map(({ previousFormatting, ...change }) => {
701
+ if (previousFormatting === void 0) return change;
702
+ const { numPr, ...rest } = previousFormatting;
703
+ return {
704
+ ...change,
705
+ previousFormatting: numPr === void 0 ? rest : {
706
+ ...rest,
707
+ numPr: paragraphNumberingAttr(numPr)
708
+ }
709
+ };
710
+ });
711
+ if (paragraph.preservedAttributes && paragraph.preservedAttributes.length > 0) attrs._preservedAttributes = paragraph.preservedAttributes;
528
712
  if (paragraph.pPrMark) attrs.pPrMark = paragraph.pPrMark;
529
713
  const set = (key, val) => {
530
714
  if (val !== void 0) attrs[key] = val;
@@ -553,7 +737,7 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
553
737
  if (formatting?.spaceBefore === void 0 && tableParagraphOverlay?.spaceBefore === void 0 && paragraphStyle?.pPr?.spaceBefore === void 0 && docDefaultSpacing?.spaceBefore !== void 0) spacingFromDocDefaults.before = true;
554
738
  if (formatting?.spaceAfter === void 0 && tableParagraphOverlay?.spaceAfter === void 0 && paragraphStyle?.pPr?.spaceAfter === void 0 && docDefaultSpacing?.spaceAfter !== void 0) spacingFromDocDefaults.after = true;
555
739
  if (spacingFromDocDefaults.before || spacingFromDocDefaults.after) attrs.spacingFromDocDefaults = spacingFromDocDefaults;
556
- const effectiveIndent = mergeParagraphFormatting(formatting?.numPr?.numId === 0 && isNumberingReference(stylePpr?.numPr?.numId) ? void 0 : stylePpr, formatting);
740
+ const effectiveIndent = mergeParagraphFormatting(formatting?.numPr?.kind === "none" && paragraphNumberingReferenceId$1(stylePpr?.numPr) !== void 0 ? void 0 : stylePpr, formatting);
557
741
  set("indentLeft", effectiveIndent?.indentLeft);
558
742
  set("indentRight", formatting?.indentRight ?? stylePpr?.indentRight);
559
743
  set("indentFirstLine", effectiveIndent?.indentFirstLine);
@@ -573,12 +757,11 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
573
757
  set("outlineLevel", formatting?.outlineLevel ?? stylePpr?.outlineLevel);
574
758
  set("direction", directionFromBidi(formatting?.bidi ?? stylePpr?.bidi));
575
759
  set("defaultTextFormatting", resolveParagraphDefaultTextFormatting(styleId, formatting, styleResolver, { includeParagraphMarkRunProperties: tableOfContentsLevel === void 0 && (styleId === void 0 || paragraph.content.length === 0) }));
576
- if (stylePpr?.numPr && formatting?.numPr?.numId === void 0 && isNumberingReference(stylePpr.numPr.numId)) {
577
- attrs.numPr = {
578
- ...stylePpr.numPr,
579
- ...formatting?.numPr
580
- };
581
- attrs.numPrFromStyle = stylePpr.numPr;
760
+ const styleNumbering = stylePpr?.numPr;
761
+ if (styleNumbering?.kind === "reference" && (formatting?.numPr === void 0 || formatting.numPr.kind === "levelOnly")) {
762
+ const merged = mergeParagraphNumbering$1(styleNumbering, formatting?.numPr);
763
+ if (merged !== void 0) attrs.numPr = paragraphNumberingAttr(merged);
764
+ attrs.numPrFromStyle = paragraphNumberingAttr(styleNumbering);
582
765
  }
583
766
  } else {
584
767
  set("alignment", formatting?.alignment);
@@ -608,11 +791,7 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
608
791
  set("direction", directionFromBidi(formatting?.bidi));
609
792
  set("defaultTextFormatting", stripParagraphMarkOnlyFormatting(resolveTextFormatting(formatting?.runProperties, styleResolver) ?? {}));
610
793
  }
611
- if (paragraph.sectionProperties) {
612
- attrs._sectionProperties = paragraph.sectionProperties;
613
- const st = paragraph.sectionProperties.sectionStart;
614
- if (st === "nextPage" || st === "continuous" || st === "oddPage" || st === "evenPage") attrs.sectionBreakType = st;
615
- }
794
+ if (paragraph.sectionProperties) attrs._sectionProperties = paragraph.sectionProperties;
616
795
  if (paragraph.renderedPageBreakBefore) attrs.renderedPageBreakBefore = true;
617
796
  const beforeAutospacing = formatting?.beforeAutospacing ?? stylePpr?.beforeAutospacing;
618
797
  const afterAutospacing = formatting?.afterAutospacing ?? stylePpr?.afterAutospacing;
@@ -850,6 +1029,8 @@ function tableCellHasMeaningfulContent(cell) {
850
1029
  return cell.content.some(blockHasMeaningfulContent);
851
1030
  }
852
1031
  function blockHasMeaningfulContent(block) {
1032
+ if (block.type === "preservedBlock") return true;
1033
+ if (block.type === "bookmarkStart" || block.type === "bookmarkEnd") return true;
853
1034
  if (block.type === "table") return block.rows.some((row) => row.cells.some((cell) => tableCellHasMeaningfulContent(cell)));
854
1035
  return block.content.some(paragraphContentHasMeaningfulContent);
855
1036
  }
@@ -861,12 +1042,11 @@ function paragraphContentHasMeaningfulContent(content) {
861
1042
  }
862
1043
  function convertTable(table, styleResolver, context) {
863
1044
  for (const row of table.rows) for (const cell of row.cells) {
864
- if (isCellMergeContinuation(cell) && context.pageBreakRunSourceDescendants.containsPageBreakRun(cell.content)) throw new UnsupportedDocxToProseMirrorConversionError({
865
- message: `${PAGE_BREAK_CONTAINER_DESCRIPTIONS["table-cell"]} cannot be represented in the editor model`,
866
- owner: "table-cell",
867
- contentType: "break"
868
- });
869
- assertSourceContainerHasNoPageBreakRun(cell.content, "table-cell", context.pageBreakRunSourceDescendants);
1045
+ if (isCellMergeContinuation(cell) && context.pageBreakRunSourceDescendants.containsPageBreakRun(cell.content)) {
1046
+ context.warnPageBreakProjection("A page break inside a vertically merged table cell paginates with the merged row");
1047
+ continue;
1048
+ }
1049
+ reportSourceContainerPageBreakRun(cell.content, "table-cell", context.pageBreakRunSourceDescendants, context.warnPageBreakProjection);
870
1050
  }
871
1051
  const rowSpanMap = calculateRowSpans(table);
872
1052
  const columnWidths = table.columnWidths;
@@ -910,6 +1090,8 @@ function convertTable(table, styleResolver, context) {
910
1090
  if (resolvedTableBidi !== void 0) attrs._resolvedBidi = resolvedTableBidi;
911
1091
  attrs._originalFormatting = table.formatting ?? {};
912
1092
  if (table.propertyChanges && table.propertyChanges.length > 0) attrs.tblPrChange = [...table.propertyChanges];
1093
+ if (table.bookmarks && table.bookmarks.length > 0) attrs._bookmarks = table.bookmarks;
1094
+ if (hasSinkChildren(table.preserved)) attrs._preserved = table.preserved;
913
1095
  const conditionalStyles = {};
914
1096
  const setCS = (key, type) => {
915
1097
  const val = resolveTableStyleConditional(styleResolver, conditionalTableStyleId, type);
@@ -961,6 +1143,19 @@ function countTableColumns(rows) {
961
1143
  }
962
1144
  return maxColumns;
963
1145
  }
1146
+ function createOmittedGridSlotCell({ colspan, slot, columnWidths, totalWidth, startColumn }) {
1147
+ const attrs = {
1148
+ colspan,
1149
+ rowspan: 1,
1150
+ _omittedGridSlot: slot
1151
+ };
1152
+ if (columnWidths && totalWidth && totalWidth > 0) {
1153
+ const slotWidth = columnWidths.slice(startColumn, startColumn + colspan).reduce((sum, width) => sum + width, 0);
1154
+ attrs.width = Math.round(slotWidth / totalWidth * 100);
1155
+ attrs.widthType = "pct";
1156
+ }
1157
+ return schema.node("tableCell", attrs, [schema.node("paragraph")]);
1158
+ }
964
1159
  /**
965
1160
  * Convert a TableRow to a ProseMirror table row node
966
1161
  */
@@ -968,10 +1163,16 @@ function convertTableRow(row, styleResolver, context, isHeaderRow, columnWidths,
968
1163
  const attrsWithoutStructuralChange = { isHeader: !!row.formatting?.header };
969
1164
  if (row.formatting?.height?.value !== void 0) attrsWithoutStructuralChange.height = row.formatting.height.value;
970
1165
  if (row.formatting?.heightRule) attrsWithoutStructuralChange.heightRule = row.formatting.heightRule;
971
- if (row.formatting?.hidden) attrsWithoutStructuralChange.hidden = true;
1166
+ if (row.formatting?.hidden !== void 0) attrsWithoutStructuralChange.hidden = row.formatting.hidden;
972
1167
  if (resolvedJustification) attrsWithoutStructuralChange._resolvedJustification = resolvedJustification;
973
1168
  if (row.formatting) attrsWithoutStructuralChange._originalFormatting = row.formatting;
1169
+ if (row.tablePropertyExceptions) attrsWithoutStructuralChange._tablePropertyExceptions = row.tablePropertyExceptions;
1170
+ if (row.tablePropertyExceptionChanges && row.tablePropertyExceptionChanges.length > 0) attrsWithoutStructuralChange.tblPrExChange = [...row.tablePropertyExceptionChanges];
974
1171
  if (row.propertyChanges && row.propertyChanges.length > 0) attrsWithoutStructuralChange.trPrChange = [...row.propertyChanges];
1172
+ if (row.preservedAttributes && row.preservedAttributes.length > 0) attrsWithoutStructuralChange._preservedAttributes = row.preservedAttributes;
1173
+ if (row.bookmarks && row.bookmarks.length > 0) attrsWithoutStructuralChange._bookmarks = row.bookmarks;
1174
+ if (row.contentControls && row.contentControls.length > 0) attrsWithoutStructuralChange.contentControls = row.contentControls;
1175
+ if (hasSinkChildren(row.preserved)) attrsWithoutStructuralChange._preserved = row.preserved;
975
1176
  let attrs = attrsWithoutStructuralChange;
976
1177
  const rowStructuralChange = row.structuralChange;
977
1178
  if (rowStructuralChange) {
@@ -1002,6 +1203,8 @@ function convertTableRow(row, styleResolver, context, isHeaderRow, columnWidths,
1002
1203
  }
1003
1204
  }
1004
1205
  const numCells = row.cells.length;
1206
+ const gridBefore = row.formatting?.gridBefore ?? 0;
1207
+ const gridAfter = row.formatting?.gridAfter ?? 0;
1005
1208
  const isFirstRow = rowIndex === 0;
1006
1209
  const isLastRow = rowIndex === (totalRows ?? 1) - 1;
1007
1210
  const rowCnf = row.formatting?.conditionalFormat;
@@ -1009,16 +1212,24 @@ function convertTableRow(row, styleResolver, context, isHeaderRow, columnWidths,
1009
1212
  const rowIsLastRow = rowCnf?.lastRow ?? isLastRow;
1010
1213
  const totalCols = totalColumns != null && totalColumns > 0 ? totalColumns : Math.max(numCells, 1);
1011
1214
  let effectiveCells = row.cells;
1012
- if (effectiveCells.length === 0) {
1215
+ const uncoveredColumns = Math.max(0, totalCols - gridBefore - gridAfter);
1216
+ if (effectiveCells.length === 0 && uncoveredColumns > 0) {
1013
1217
  const fallback = {
1014
1218
  type: "tableCell",
1015
1219
  content: []
1016
1220
  };
1017
- if (totalCols > 1) fallback.formatting = { gridSpan: totalCols };
1221
+ if (uncoveredColumns > 1) fallback.formatting = { gridSpan: uncoveredColumns };
1018
1222
  effectiveCells = [fallback];
1019
1223
  }
1020
- let colIndex = row.formatting?.gridBefore ?? 0;
1224
+ let colIndex = gridBefore;
1021
1225
  const cells = [];
1226
+ if (gridBefore > 0) cells.push(createOmittedGridSlotCell({
1227
+ colspan: gridBefore,
1228
+ slot: "before",
1229
+ columnWidths,
1230
+ totalWidth,
1231
+ startColumn: 0
1232
+ }));
1022
1233
  for (const cellIndex_item of effectiveCells) {
1023
1234
  const cell = cellIndex_item;
1024
1235
  const colspan = cell.formatting?.gridSpan ?? 1;
@@ -1086,6 +1297,13 @@ function convertTableRow(row, styleResolver, context, isHeaderRow, columnWidths,
1086
1297
  defaultCellMargins
1087
1298
  }));
1088
1299
  }
1300
+ if (gridAfter > 0) cells.push(createOmittedGridSlotCell({
1301
+ colspan: gridAfter,
1302
+ slot: "after",
1303
+ columnWidths,
1304
+ totalWidth,
1305
+ startColumn: colIndex
1306
+ }));
1089
1307
  return schema.node("tableRow", attrs, cells);
1090
1308
  }
1091
1309
  /**
@@ -1110,6 +1328,10 @@ function convertTableCell({ cell, styleResolver, context, isHeader, gridWidthPer
1110
1328
  if (effectiveFormatting.width.type === "value") {
1111
1329
  attrs.width = effectiveFormatting.width.value;
1112
1330
  if (effectiveFormatting.width.widthType) attrs.widthType = effectiveFormatting.width.widthType;
1331
+ if (effectiveFormatting.width.source === "direct") attrs._authoredWidth = {
1332
+ value: effectiveFormatting.width.value,
1333
+ type: effectiveFormatting.width.widthType
1334
+ };
1113
1335
  }
1114
1336
  if (formatting?.verticalAlign) attrs.verticalAlign = formatting.verticalAlign;
1115
1337
  if (effectiveFormatting.background.type === "color") {
@@ -1130,6 +1352,7 @@ function convertTableCell({ cell, styleResolver, context, isHeader, gridWidthPer
1130
1352
  }
1131
1353
  if (formatting) attrs._originalFormatting = formatting;
1132
1354
  if (cell.propertyChanges && cell.propertyChanges.length > 0) attrs.tcPrChange = [...cell.propertyChanges];
1355
+ if (cell.contentControls && cell.contentControls.length > 0) attrs.contentControls = cell.contentControls;
1133
1356
  const cellStructuralChange = cell.structuralChange;
1134
1357
  if (cellStructuralChange) {
1135
1358
  const info = {
@@ -1168,13 +1391,27 @@ function convertTableCell({ cell, styleResolver, context, isHeader, gridWidthPer
1168
1391
  if (preserveVMergeRestart) attrs._preserveVMergeRestart = true;
1169
1392
  if (vMergeContinuationCells && vMergeContinuationCells.length > 0) attrs._docxVMergeContinuationCells = transportTableCellsWithParagraphPropertySources(vMergeContinuationCells);
1170
1393
  const contentNodes = [];
1171
- for (const content of cell.content) if (content.type === "paragraph") contentNodes.push(...convertParagraphWithTextBoxes(content, styleResolver, {
1172
- textBoxGroupId: context.nextTextBoxGroupId(),
1173
- context,
1174
- ...conditionalStyle?.rPr !== void 0 ? { extraRunFormatting: conditionalStyle.rPr } : {},
1175
- ...conditionalStyle?.pPr !== void 0 ? { tableParagraphOverlay: conditionalStyle.pPr } : {}
1176
- }));
1177
- else contentNodes.push(convertTable(content, styleResolver, context));
1394
+ for (const content of cell.content) switch (content.type) {
1395
+ case "paragraph":
1396
+ contentNodes.push(...convertParagraphWithTextBoxes(content, styleResolver, {
1397
+ textBoxGroupId: context.nextTextBoxGroupId(),
1398
+ context,
1399
+ ...conditionalStyle?.rPr !== void 0 ? { extraRunFormatting: conditionalStyle.rPr } : {},
1400
+ ...conditionalStyle?.pPr !== void 0 ? { tableParagraphOverlay: conditionalStyle.pPr } : {}
1401
+ }));
1402
+ break;
1403
+ case "table":
1404
+ contentNodes.push(convertTable(content, styleResolver, context));
1405
+ break;
1406
+ case "preservedBlock":
1407
+ contentNodes.push(convertPreservedBlock(content));
1408
+ break;
1409
+ case "bookmarkStart":
1410
+ case "bookmarkEnd":
1411
+ contentNodes.push(convertBlockBookmarkBoundary(content));
1412
+ break;
1413
+ default: panic(`Unsupported table cell content: ${JSON.stringify(content)}`);
1414
+ }
1178
1415
  if (contentNodes.length === 0) contentNodes.push(schema.node("paragraph", {}, []));
1179
1416
  const nodeType = isHeader ? "tableHeader" : "tableCell";
1180
1417
  return schema.node(nodeType, attrs, contentNodes);
@@ -1183,7 +1420,7 @@ function standaloneTableCellToProseMirror(cell, nodeType) {
1183
1420
  const nextTextBoxGroupId = createTextBoxGroupIdFactory();
1184
1421
  const nextHyperlinkInstanceIndex = createHyperlinkInstanceIndexAllocator();
1185
1422
  const pageBreakRunSourceDescendants = buildPageBreakRunSourceDescendantIndex(cell.content);
1186
- assertSourceContainerHasNoPageBreakRun(cell.content, "table-cell", pageBreakRunSourceDescendants);
1423
+ reportSourceContainerPageBreakRun(cell.content, "table-cell", pageBreakRunSourceDescendants, noPageBreakProjectionWarning);
1187
1424
  return convertTableCell({
1188
1425
  cell,
1189
1426
  styleResolver: null,
@@ -1192,7 +1429,10 @@ function standaloneTableCellToProseMirror(cell, nodeType) {
1192
1429
  nextTextBoxGroupId,
1193
1430
  nextHyperlinkInstanceIndex,
1194
1431
  pairedBookmarkIds: collectPairedBookmarkIds(cell.content),
1195
- pageBreakRunSourceDescendants
1432
+ pageBreakRunSourceDescendants,
1433
+ storyRangedCommentIds: rangedCommentIds(cell.content),
1434
+ openCommentIds: /* @__PURE__ */ new Set(),
1435
+ warnPageBreakProjection: noPageBreakProjectionWarning
1196
1436
  },
1197
1437
  isHeader: nodeType === "tableHeader",
1198
1438
  gridWidthPercent: void 0,
@@ -1205,80 +1445,110 @@ function standaloneTableCellToProseMirror(cell, nodeType) {
1205
1445
  defaultCellMargins: void 0
1206
1446
  });
1207
1447
  }
1208
- function convertField(field, { getInheritedRunFormatting, styleResolver, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, textBoxAnchors }) {
1448
+ function convertField(field, { getInheritedRunFormatting, styleResolver, nextHyperlinkInstanceIndex, nextRunIdentityId, textBoxAnchors }) {
1209
1449
  let displayText = "";
1210
1450
  let fieldFormatting;
1211
1451
  let fieldPropertyChanges;
1212
1452
  const inlineNodes = [];
1213
- const runHasPageBreak = (run) => run.content.some((content) => content.type === "break" && content.breakType === "page");
1214
- if (field.type === "complexField" && field.fieldCode.some(runHasPageBreak)) throw new UnsupportedDocxToProseMirrorConversionError({
1215
- message: "A complex-field instruction containing an explicit page break cannot be represented in the editor model",
1216
- owner: "complex-field-instruction",
1217
- contentType: "break"
1218
- });
1219
- 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);
1220
- if (hasPageBreakContent) assertPageBreakFieldResultIsRepresentable(field);
1221
- const hasStructuredSourceContent = hasPageBreakContent || field.type === "simpleField" && field.content.some((content) => content.type === "hyperlink");
1222
- const appendRun = (run) => {
1453
+ const hasStructuredSourceContent = fieldResultHasPageBreakContent(field) || field.type === "simpleField" && field.content.some((content) => content.type === "hyperlink" || content.type === "preservedInline" || content.type === "inlineWrapper");
1454
+ const appendRun = (run, into) => {
1223
1455
  for (const content of run.content) if (content.type === "text") displayText += content.text;
1224
1456
  fieldFormatting ??= run.formatting;
1225
1457
  fieldPropertyChanges ??= run.propertyChanges;
1226
1458
  if (!hasStructuredSourceContent) return;
1227
- inlineNodes.push(...convertRun(run, getInheritedRunFormatting(run.formatting, field.fieldType), nextPageBreakRunOwnerId, styleResolver, textBoxAnchors));
1459
+ into.push(...convertRun(run, getInheritedRunFormatting(run.formatting, field.fieldType), nextRunIdentityId, styleResolver, textBoxAnchors));
1228
1460
  };
1229
- if (field.type === "simpleField") for (const content of field.content) {
1230
- if (content.type === "run") {
1231
- appendRun(content);
1232
- continue;
1233
- }
1234
- for (const child of content.children) if (child.type === "run") {
1235
- for (const runContent of child.content) if (runContent.type === "text") displayText += runContent.text;
1236
- fieldFormatting ??= child.formatting;
1237
- fieldPropertyChanges ??= child.propertyChanges;
1461
+ if (field.type === "simpleField") for (const { content, stack } of withInlineWrapperStacks(field.content)) {
1462
+ const itemNodes = [];
1463
+ switch (content.type) {
1464
+ case "run":
1465
+ appendRun(content, itemNodes);
1466
+ break;
1467
+ case "preservedInline":
1468
+ itemNodes.push(preservedInlineNode(content));
1469
+ break;
1470
+ case "hyperlink":
1471
+ for (const { content: child } of withInlineWrapperStacks(content.children)) if (child.type === "run") {
1472
+ for (const runContent of child.content) if (runContent.type === "text") displayText += runContent.text;
1473
+ fieldFormatting ??= child.formatting;
1474
+ fieldPropertyChanges ??= child.propertyChanges;
1475
+ }
1476
+ itemNodes.push(...convertHyperlink(content, {
1477
+ getInheritedRunFormatting: (formatting) => getInheritedRunFormatting(formatting, field.fieldType),
1478
+ styleResolver,
1479
+ hyperlinkIndex: nextHyperlinkInstanceIndex(),
1480
+ textBoxAnchors,
1481
+ nextRunIdentityId
1482
+ }));
1483
+ break;
1484
+ default: break;
1238
1485
  }
1239
- inlineNodes.push(...convertHyperlink(content, {
1240
- getInheritedRunFormatting: (formatting) => getInheritedRunFormatting(formatting, field.fieldType),
1241
- styleResolver,
1242
- hyperlinkIndex: nextHyperlinkInstanceIndex(),
1243
- textBoxAnchors,
1244
- nextPageBreakRunOwnerId
1245
- }));
1486
+ inlineNodes.push(...withInlineWrapperMark(itemNodes, stack));
1246
1487
  }
1247
- else for (const run of field.fieldResult) appendRun(run);
1488
+ else for (const run of field.fieldResult) appendRun(run, inlineNodes);
1248
1489
  if (!fieldFormatting && field.type === "complexField" && field.fieldResult.length === 0) fieldFormatting = field.formatting;
1249
1490
  const inheritedFormatting = getInheritedRunFormatting(fieldFormatting, field.fieldType);
1250
1491
  const { marks } = buildRunMarks(fieldFormatting, inheritedFormatting, styleResolver);
1251
1492
  const hasConvertedHyperlinkContent = inlineNodes.some((node) => node.marks.some((mark) => mark.type.name === "hyperlink"));
1252
- const createStructuredField = inlineNodes.some((node) => node.type.name === "pageBreakRun") || hasStructuredSourceContent && hasConvertedHyperlinkContent;
1493
+ const hasConvertedPageBreakContent = inlineNodes.some((node) => node.type.name === "pageBreakRun");
1494
+ const hasConvertedPreservedContent = inlineNodes.some((node) => node.type.name === "preservedXml");
1495
+ const hasConvertedWrapperContent = inlineNodes.some((node) => node.marks.some((mark) => mark.type.name === INLINE_WRAPPER_MARK_NAME));
1496
+ const createStructuredField = hasConvertedPageBreakContent || hasConvertedPreservedContent || hasStructuredSourceContent && (hasConvertedHyperlinkContent || hasConvertedWrapperContent);
1253
1497
  if (!createStructuredField && fieldPropertyChanges && fieldPropertyChanges.length > 0) marks.push(schema.mark("runPropertyChange", { changes: [...fieldPropertyChanges] }));
1254
1498
  return schema.node(createStructuredField ? "structuredField" : "field", {
1255
1499
  fieldType: field.fieldType,
1256
1500
  instruction: field.instruction,
1257
1501
  displayText,
1258
1502
  fieldKind: field.type === "simpleField" ? "simple" : "complex",
1259
- fldLock: field.fldLock ?? false,
1260
- dirty: field.dirty ?? false
1503
+ fldLock: field.fldLock ?? null,
1504
+ dirty: field.dirty ?? null
1261
1505
  }, createStructuredField ? inlineNodes : void 0, marks);
1262
1506
  }
1263
1507
  /**
1264
- * Convert a MathEquation to a ProseMirror math node.
1508
+ * Lift the transparent wrappers out of an inline content list, remembering for
1509
+ * each item which wrappers it sat inside.
1510
+ *
1511
+ * The tree becomes one sequence because every inline loop below narrows by a
1512
+ * chain of `else if` rather than by exhaustion, and a wrapper left in it would
1513
+ * reach whichever branch happens to be last. What the wrapper said is not lost
1514
+ * with the tree: it rides the `inlineWrapper` mark on the leaves it held, and
1515
+ * ProseMirror maintains that range across edits instead of an index.
1516
+ *
1517
+ * It is applied to the content of whatever holds the wrapper, never around it:
1518
+ * a wrapper inside a revision or a content control is lifted inside that
1519
+ * wrapper, so its runs keep the revision mark or the control they were
1520
+ * authored under.
1265
1521
  */
1522
+ const withInlineWrapperStacks = (content, stack = []) => content.flatMap((item) => item.type === "inlineWrapper" ? withInlineWrapperStacks(item.content, [...stack, inlineWrapperLayer(item)]) : [{
1523
+ content: item,
1524
+ stack
1525
+ }]);
1266
1526
  /**
1267
- * Flatten `w:bdo`/`w:dir` out of an inline content list.
1527
+ * `nodes` with `stack` recorded outside whatever wrapper they already carry.
1268
1528
  *
1269
- * The editor has no projection for a bidirectional wrapper yet, and the
1270
- * alternative to flattening it is worse than losing the direction: every
1271
- * inline loop below narrows by a chain of `else if` rather than by
1272
- * exhaustion, so an unhandled member reaches whichever branch happens to be
1273
- * last and is read as that. Flattening keeps the wrapper's content and loses
1274
- * only its direction, which the survival census records as an
1275
- * editor-projection loss until the mark that carries it exists.
1529
+ * A revision converts its own content first, so a node that arrives here
1530
+ * already marked sat inside the item this stack wraps: the two stacks
1531
+ * concatenate, outermost first. Concatenating is what the schema forces — the
1532
+ * mark excludes itself, so a second one replaces the first, and the inner
1533
+ * wrapper would be the one lost.
1276
1534
  *
1277
- * The save path is unaffected: a document opened and saved without being
1278
- * edited replays its markup, and one that is edited keeps the wrapper because
1279
- * `fromProseDoc` rebuilds from the source paragraph.
1535
+ * A node that holds its own leaves, a content control, is marked here as the
1536
+ * one node it is; its leaves were marked with the whole enclosing stack when
1537
+ * it was built, because the painter reads the wrapper off the leaf.
1538
+ */
1539
+ const withInlineWrapperMark = (nodes, stack) => {
1540
+ const markType = schema.marks["inlineWrapper"];
1541
+ if (stack.length === 0 || !markType) return nodes;
1542
+ return nodes.map((node) => {
1543
+ if (!node.isText && (!node.isInline || !node.type.allowsMarkType(markType))) return node;
1544
+ const inner = node.marks.find((mark) => mark.type === markType);
1545
+ const layers = inner === void 0 ? stack : [...stack, ...expectInlineWrapperMarkAttrs(inner).stack];
1546
+ return node.mark(markType.create({ stack: layers }).addToSet(node.marks));
1547
+ });
1548
+ };
1549
+ /**
1550
+ * Convert a MathEquation to a ProseMirror math node.
1280
1551
  */
1281
- const withoutBidiWrappers = (content) => content.flatMap((item) => item.type === "bidiWrapper" ? withoutBidiWrappers(item.content) : [item]);
1282
1552
  function convertMathEquation(math) {
1283
1553
  return schema.node("math", {
1284
1554
  display: math.display,
@@ -1288,54 +1558,83 @@ function convertMathEquation(math) {
1288
1558
  }
1289
1559
  /**
1290
1560
  * Convert an InlineSdt to a ProseMirror sdt node with inline content.
1561
+ *
1562
+ * `wrappedBy` is the stack the control itself sits inside. The control holds
1563
+ * its own leaves, so nothing outside can mark them afterwards: the caller's
1564
+ * stack has to reach them here, under the wrappers written inside the control.
1291
1565
  */
1292
- function convertInlineSdt(sdt, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, textBoxAnchors) {
1566
+ function convertInlineSdt(sdt, nextHyperlinkInstanceIndex, nextRunIdentityId, getInheritedRunFormatting, trackedRunFormattingResolvers, styleResolver, textBoxAnchors, wrappedBy = []) {
1293
1567
  const props = sdt.properties;
1294
1568
  const inlineNodes = [];
1295
- for (const content of sdt.content) switch (content.type) {
1296
- case "run":
1297
- inlineNodes.push(...convertRun(content, getInheritedRunFormatting(content.formatting), nextPageBreakRunOwnerId, styleResolver, textBoxAnchors));
1298
- break;
1299
- case "hyperlink": {
1300
- const currentHyperlinkIndex = nextHyperlinkInstanceIndex();
1301
- inlineNodes.push(...convertHyperlink(content, {
1302
- getInheritedRunFormatting,
1303
- styleResolver,
1304
- hyperlinkIndex: currentHyperlinkIndex,
1305
- textBoxAnchors,
1306
- nextPageBreakRunOwnerId
1307
- }));
1308
- break;
1309
- }
1310
- case "simpleField":
1311
- case "complexField": {
1312
- const fieldNode = convertField(content, {
1313
- getInheritedRunFormatting,
1314
- styleResolver,
1315
- nextHyperlinkInstanceIndex,
1316
- nextPageBreakRunOwnerId,
1317
- textBoxAnchors
1318
- });
1319
- if (fieldNode) inlineNodes.push(fieldNode);
1320
- break;
1321
- }
1322
- case "inlineSdt": {
1323
- const nestedSdt = convertInlineSdt(content, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, textBoxAnchors);
1324
- if (nestedSdt) inlineNodes.push(nestedSdt);
1325
- break;
1326
- }
1327
- case "insertion":
1328
- case "deletion":
1329
- case "moveTo":
1330
- case "moveFrom":
1331
- inlineNodes.push(...convertTrackedChange(content, content.type === "insertion" || content.type === "moveTo" ? "insertion" : "deletion", nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, content.type === "moveTo" || content.type === "moveFrom" ? content.type : null, textBoxAnchors));
1332
- break;
1333
- case "mathEquation": {
1334
- const mathNode = convertMathEquation(content);
1335
- if (mathNode) inlineNodes.push(mathNode);
1336
- break;
1569
+ for (const { content, stack } of withInlineWrapperStacks(sdt.content, wrappedBy)) {
1570
+ if (!isInlineSdtContent(content)) continue;
1571
+ const itemNodes = [];
1572
+ switch (content.type) {
1573
+ case "run":
1574
+ itemNodes.push(...convertRun(content, getInheritedRunFormatting(content.formatting), nextRunIdentityId, styleResolver, textBoxAnchors));
1575
+ break;
1576
+ case "hyperlink": {
1577
+ const currentHyperlinkIndex = nextHyperlinkInstanceIndex();
1578
+ itemNodes.push(...convertHyperlink(content, {
1579
+ getInheritedRunFormatting,
1580
+ styleResolver,
1581
+ hyperlinkIndex: currentHyperlinkIndex,
1582
+ textBoxAnchors,
1583
+ nextRunIdentityId
1584
+ }));
1585
+ break;
1586
+ }
1587
+ case "simpleField":
1588
+ case "complexField": {
1589
+ const fieldNode = convertField(content, {
1590
+ getInheritedRunFormatting,
1591
+ styleResolver,
1592
+ nextHyperlinkInstanceIndex,
1593
+ nextRunIdentityId,
1594
+ textBoxAnchors
1595
+ });
1596
+ if (fieldNode) itemNodes.push(fieldNode);
1597
+ break;
1598
+ }
1599
+ case "inlineSdt": {
1600
+ const nestedSdt = convertInlineSdt(content, nextHyperlinkInstanceIndex, nextRunIdentityId, getInheritedRunFormatting, trackedRunFormattingResolvers, styleResolver, textBoxAnchors, stack);
1601
+ if (nestedSdt) itemNodes.push(nestedSdt);
1602
+ break;
1603
+ }
1604
+ case "insertion":
1605
+ case "deletion":
1606
+ case "moveTo":
1607
+ case "moveFrom":
1608
+ itemNodes.push(...convertTrackedChange(content, content.type === "insertion" || content.type === "moveTo" ? "insertion" : "deletion", nextHyperlinkInstanceIndex, nextRunIdentityId, trackedRunFormattingResolvers, styleResolver, content.type === "moveTo" || content.type === "moveFrom" ? content.type : null, textBoxAnchors));
1609
+ break;
1610
+ case "mathEquation": {
1611
+ const mathNode = convertMathEquation(content);
1612
+ if (mathNode) itemNodes.push(mathNode);
1613
+ break;
1614
+ }
1615
+ case "bookmarkStart":
1616
+ itemNodes.push(schema.node("bookmarkBoundary", {
1617
+ type: "start",
1618
+ id: content.id,
1619
+ name: content.name,
1620
+ colFirst: content.colFirst,
1621
+ colLast: content.colLast,
1622
+ displacedByCustomXml: content.displacedByCustomXml
1623
+ }));
1624
+ break;
1625
+ case "bookmarkEnd":
1626
+ itemNodes.push(schema.node("bookmarkBoundary", {
1627
+ type: "end",
1628
+ id: content.id,
1629
+ displacedByCustomXml: content.displacedByCustomXml
1630
+ }));
1631
+ break;
1632
+ case "preservedInline":
1633
+ itemNodes.push(preservedInlineNode(content));
1634
+ break;
1635
+ default: panic(`Unsupported inline SDT content: ${JSON.stringify(content)}`);
1337
1636
  }
1338
- default: panic(`Unsupported inline SDT content: ${JSON.stringify(content)}`);
1637
+ inlineNodes.push(...withInlineWrapperMark(itemNodes, stack));
1339
1638
  }
1340
1639
  return schema.node("sdt", sdtAttrsFromProperties(props), inlineNodes.length > 0 ? inlineNodes : void 0);
1341
1640
  }
@@ -1345,40 +1644,48 @@ function convertInlineSdt(sdt, nextHyperlinkInstanceIndex, nextPageBreakRunOwner
1345
1644
  * @param run - The run to convert
1346
1645
  * @param resolvedStyleFormatting - Paragraph formatting and its explicit style-toggle state
1347
1646
  */
1348
- function convertRun(run, resolvedStyleFormatting, nextPageBreakRunOwnerId, styleResolver, textBoxAnchors) {
1349
- assertPageBreakSourceRunIsRepresentable(run);
1647
+ function convertRun(run, resolvedStyleFormatting, nextRunIdentityId, styleResolver, textBoxAnchors) {
1350
1648
  const nodes = [];
1351
1649
  const { marks, mergedFormatting } = buildRunMarks(run.formatting, resolvedStyleFormatting, styleResolver);
1352
1650
  if (run.propertyChanges && run.propertyChanges.length > 0) marks.push(schema.mark("runPropertyChange", { changes: [...run.propertyChanges] }));
1353
- if (run.content.some((content) => content.type === "break" && content.breakType === "page")) marks.push(schema.mark("pageBreakRunOwner", { id: nextPageBreakRunOwnerId() }));
1651
+ const identity = runIdentityMark(run, nextRunIdentityId);
1652
+ if (identity) marks.push(identity);
1354
1653
  for (const content of run.content) {
1355
1654
  const contentNodes = convertRunContent(content, marks, mergedFormatting, textBoxAnchors, run.formatting);
1356
1655
  nodes.push(...contentNodes);
1357
1656
  }
1358
1657
  return nodes;
1359
1658
  }
1360
- function assertPageBreakSourceRunIsRepresentable(run) {
1361
- if (!run.content.some((content) => content.type === "break" && content.breakType === "page")) return;
1362
- assertRunContentIsRepresentableBesidePageBreak(run, "page-break-bearing-run");
1659
+ const runHasPageBreakContent = (run) => run.content.some((content) => content.type === "break" && content.breakType === "page");
1660
+ /**
1661
+ * Whether a field's result holds an explicit page break.
1662
+ *
1663
+ * `convertField` re-cuts the whole result into a structured field when it
1664
+ * does, so this answers both who gets re-cut and who gets reported. One
1665
+ * predicate for the two, because a reporter that disagreed with the converter
1666
+ * would name a loss nobody suffered.
1667
+ */
1668
+ const inlineHasPageBreakContent = (items) => items.some((content) => {
1669
+ switch (content.type) {
1670
+ case "run": return runHasPageBreakContent(content);
1671
+ case "hyperlink": return inlineHasPageBreakContent(content.children);
1672
+ case "inlineWrapper": return inlineHasPageBreakContent(content.content);
1673
+ default: return false;
1674
+ }
1675
+ });
1676
+ const fieldResultHasPageBreakContent = (field) => field.type === "simpleField" ? inlineHasPageBreakContent(field.content) : field.fieldResult.some(runHasPageBreakContent);
1677
+ function reportPageBreakSourceRunContent(run, warn) {
1678
+ if (!runHasPageBreakContent(run)) return;
1679
+ reportRunContentBesidePageBreak(run, "page-break-bearing-run", warn);
1363
1680
  }
1364
1681
  const PAGE_BREAK_CONTAINER_DESCRIPTIONS = {
1365
- "table-cell": "A table cell containing an explicit page break",
1366
- "text-box": "A text box containing an explicit page break"
1682
+ "table-cell": "An interior page break in a table cell does not paginate the cell; its row moves as a unit",
1683
+ "text-box": "A page break inside a text box does not paginate the text box"
1367
1684
  };
1368
- const PAGE_BREAK_PARAGRAPH_OWNERS = {
1369
- borders: "paragraph-borders",
1370
- frame: "paragraph-frame",
1371
- outline: "paragraph-outline",
1372
- textBoxAnchor: "paragraph-text-box-anchor"
1373
- };
1374
- function assertSourceContainerHasNoPageBreakRun(content, owner, sourceDescendants) {
1685
+ function reportSourceContainerPageBreakRun(content, owner, sourceDescendants, warn) {
1375
1686
  if (!sourceDescendants.containsPageBreakRun(content)) return;
1376
1687
  if (owner === "table-cell" && hasSingleLeadingTableCellPageBreak(content, sourceDescendants)) return;
1377
- throw new UnsupportedDocxToProseMirrorConversionError({
1378
- message: `${PAGE_BREAK_CONTAINER_DESCRIPTIONS[owner]} cannot be represented in the editor model`,
1379
- owner,
1380
- contentType: "break"
1381
- });
1688
+ warn(PAGE_BREAK_CONTAINER_DESCRIPTIONS[owner]);
1382
1689
  }
1383
1690
  /**
1384
1691
  * A page break opening a cell advances the whole row during pagination.
@@ -1419,7 +1726,7 @@ const scanLeadingPageBreakContent = (content, scan) => {
1419
1726
  case "moveFrom":
1420
1727
  case "moveTo":
1421
1728
  case "inlineSdt":
1422
- case "bidiWrapper":
1729
+ case "inlineWrapper":
1423
1730
  for (const child of content.content) scanLeadingPageBreakContent(child, scan);
1424
1731
  return;
1425
1732
  case "simpleField":
@@ -1438,6 +1745,7 @@ const scanLeadingPageBreakContent = (content, scan) => {
1438
1745
  case "moveToRangeEnd": return;
1439
1746
  case "commentReference":
1440
1747
  case "mathEquation":
1748
+ case "preservedInline":
1441
1749
  if (scan.pageBreaks === 0) scan.contentBeforeBreak = true;
1442
1750
  return;
1443
1751
  default: return content;
@@ -1456,64 +1764,103 @@ const hasSingleLeadingParagraphPageBreak = (paragraph) => {
1456
1764
  const scan = scanParagraphPageBreaks(paragraph);
1457
1765
  return !scan.contentBeforeBreak && scan.pageBreaks === 1;
1458
1766
  };
1459
- function assertParagraphPageBreakCanBeProjected({ paragraph, attrs, effectiveFrame, sourceDescendants }) {
1767
+ function reportParagraphPageBreakProjection({ paragraph, attrs, effectiveFrame, sourceDescendants, warn }) {
1460
1768
  const sourceFeatures = sourceDescendants.paragraphFeatures(paragraph);
1461
1769
  if (!sourceFeatures.hasPageBreakRun) return;
1770
+ reportParagraphPageBreakRunContent(paragraph, warn);
1462
1771
  const disposition = pageBreakRunParagraphProjectionDispositionForFeatures({
1463
1772
  attrs,
1464
1773
  effectiveFrame,
1465
1774
  textBoxAnchorAfterPageBreak: sourceFeatures.hasTextBoxShape && !sourceFeatures.pageBreakSharesTextBoxShape && scanParagraphPageBreaks(paragraph).textBoxShapeAfterBreak
1466
1775
  });
1467
- if (disposition.status === "supported") return;
1776
+ if (disposition.status === "exact") return;
1468
1777
  if (disposition.reason !== "textBoxAnchor" && hasSingleLeadingParagraphPageBreak(paragraph)) return;
1469
- throw new UnsupportedDocxToProseMirrorConversionError({
1470
- message: disposition.message,
1471
- owner: PAGE_BREAK_PARAGRAPH_OWNERS[disposition.reason],
1472
- contentType: "break"
1473
- });
1778
+ warn(disposition.message);
1474
1779
  }
1475
- function assertPageBreakFieldResultIsRepresentable(field) {
1476
- if (field.type === "complexField") {
1477
- for (const run of field.fieldResult) assertRunContentIsRepresentableBesidePageBreak(run, "field-result");
1478
- return;
1479
- }
1480
- for (const content of field.content) {
1481
- if (content.type === "run") {
1482
- assertRunContentIsRepresentableBesidePageBreak(content, "field-result");
1483
- continue;
1780
+ /**
1781
+ * Report every run-level loss a paragraph's page breaks bring with them.
1782
+ *
1783
+ * One walk of the paragraph rather than a check at each `convertRun` and
1784
+ * `convertField`: the reporter is a conversion-wide fact, and a per-call-site
1785
+ * check would have to be threaded through every nested converter to reach it.
1786
+ */
1787
+ function reportParagraphPageBreakRunContent(paragraph, warn) {
1788
+ const visitField = (field) => {
1789
+ if (field.type === "complexField") {
1790
+ if (field.fieldCode.some(runHasPageBreakContent)) warn("A complex-field instruction holds an explicit page break");
1791
+ if (!fieldResultHasPageBreakContent(field)) return;
1792
+ for (const run of field.fieldResult) reportRunContentBesidePageBreak(run, "field-result", warn);
1793
+ return;
1484
1794
  }
1485
- for (const child of content.children) if (child.type === "run") assertRunContentIsRepresentableBesidePageBreak(child, "field-result");
1486
- }
1795
+ if (!fieldResultHasPageBreakContent(field)) return;
1796
+ for (const content of field.content) {
1797
+ if (content.type === "run") {
1798
+ reportRunContentBesidePageBreak(content, "field-result", warn);
1799
+ continue;
1800
+ }
1801
+ if (content.type !== "hyperlink") continue;
1802
+ for (const child of content.children) if (child.type === "run") reportRunContentBesidePageBreak(child, "field-result", warn);
1803
+ }
1804
+ };
1805
+ const visitContent = (content) => {
1806
+ switch (content.type) {
1807
+ case "run":
1808
+ reportPageBreakSourceRunContent(content, warn);
1809
+ return;
1810
+ case "hyperlink":
1811
+ for (const child of content.children) if (child.type === "run") reportPageBreakSourceRunContent(child, warn);
1812
+ return;
1813
+ case "simpleField":
1814
+ case "complexField":
1815
+ visitField(content);
1816
+ return;
1817
+ case "insertion":
1818
+ case "deletion":
1819
+ case "moveFrom":
1820
+ case "moveTo":
1821
+ case "inlineSdt":
1822
+ case "inlineWrapper":
1823
+ for (const child of content.content) visitContent(child);
1824
+ return;
1825
+ default: return;
1826
+ }
1827
+ };
1828
+ for (const content of paragraph.content) visitContent(content);
1487
1829
  }
1488
1830
  const PAGE_BREAK_OWNER_DESCRIPTIONS = {
1489
1831
  "field-result": "A field result with an explicit page break",
1490
1832
  "page-break-bearing-run": "A page-break-bearing run"
1491
1833
  };
1492
- const unsupportedPageBreakContent = (owner, contentType) => {
1493
- const description = contentType === "shape" ? "a text-box shape" : contentType;
1494
- throw new UnsupportedDocxToProseMirrorConversionError({
1495
- message: `${PAGE_BREAK_OWNER_DESCRIPTIONS[owner]} containing ${description} cannot be represented in the editor model`,
1496
- owner,
1497
- contentType
1498
- });
1499
- };
1500
- function assertRunContentIsRepresentableBesidePageBreak(run, owner) {
1834
+ /**
1835
+ * Record what a page-break-bearing run loses when the editor re-cuts it.
1836
+ *
1837
+ * The run is split into one node per inline atom and rebuilt from the
1838
+ * `runIdentity` mark, and the kinds below have no node of their own:
1839
+ * a hyphen returns as its character, a field character or instruction leaves
1840
+ * no trace, and a text-box shape is hoisted to its own block. Every one of
1841
+ * those losses is what the same run suffers with no page break in it, so
1842
+ * refusing the document here declined to open a file folio otherwise reads.
1843
+ */
1844
+ function reportRunContentBesidePageBreak(run, owner, warn) {
1501
1845
  for (const content of run.content) switch (content.type) {
1502
1846
  case "break":
1503
1847
  case "drawing":
1504
1848
  case "endnoteRef":
1505
1849
  case "footnoteRef":
1850
+ case "preservedXml":
1506
1851
  case "renderedPageBreak":
1507
1852
  case "symbol":
1508
1853
  case "tab":
1509
1854
  case "text": continue;
1510
1855
  case "shape":
1511
- if (content.shape.textBody) unsupportedPageBreakContent(owner, content.type);
1856
+ if (content.shape.textBody) warn(`${PAGE_BREAK_OWNER_DESCRIPTIONS[owner]} also holds a text-box shape`);
1512
1857
  continue;
1513
1858
  case "fieldChar":
1514
1859
  case "instrText":
1515
1860
  case "noBreakHyphen":
1516
- case "softHyphen": return unsupportedPageBreakContent(owner, content.type);
1861
+ case "softHyphen":
1862
+ warn(`${PAGE_BREAK_OWNER_DESCRIPTIONS[owner]} also holds ${content.type}`);
1863
+ continue;
1517
1864
  default: panic(`Unsupported page-break-bearing run content: ${JSON.stringify(content)}`);
1518
1865
  }
1519
1866
  }
@@ -1549,7 +1896,8 @@ const RUN_FORMATTING_INFERENCE = {
1549
1896
  shadow: "visible-boolean",
1550
1897
  rtl: "visible-boolean",
1551
1898
  cs: "structural",
1552
- styleId: "structural"
1899
+ styleId: "structural",
1900
+ preserved: "structural"
1553
1901
  };
1554
1902
  const sameFormattingValue = (left, right) => {
1555
1903
  if (left === right) return true;
@@ -1761,6 +2109,11 @@ function convertRunContent(content, marks, formatting, textBoxAnchors, authoredF
1761
2109
  }
1762
2110
  case "fieldChar":
1763
2111
  case "instrText": return [];
2112
+ case "preservedXml": return [schema.node("preservedXml", {
2113
+ xml: content.xml,
2114
+ text: content.text,
2115
+ level: PRESERVED_XML_LEVELS.run
2116
+ }).mark(marks)];
1764
2117
  case "noBreakHyphen": return [schema.text("‑", marks)];
1765
2118
  case "softHyphen": return [schema.text("­", marks)];
1766
2119
  case "symbol": return [schema.node("symbol", {
@@ -1769,8 +2122,14 @@ function convertRunContent(content, marks, formatting, textBoxAnchors, authoredF
1769
2122
  }).mark(marks)];
1770
2123
  }
1771
2124
  }
2125
+ /**
2126
+ * The marks that name an element the atom has to stay inside: a `w:hyperlink`
2127
+ * and the authored `w:r` itself. A leaf that carries one has to hold the whole
2128
+ * mark set, because the save leg rebuilds those elements around it.
2129
+ */
2130
+ const RUN_BOUNDARY_MARK_NAMES = /* @__PURE__ */ new Set(["hyperlink", RUN_IDENTITY_MARK_NAME]);
1772
2131
  function withRunBoundaryMarks(node, marks) {
1773
- if (!marks.some(({ type }) => type.name === "hyperlink" || type.name === "pageBreakRunOwner")) return node;
2132
+ if (!marks.some(({ type }) => RUN_BOUNDARY_MARK_NAMES.has(type.name))) return node;
1774
2133
  return node.mark(marks);
1775
2134
  }
1776
2135
  /**
@@ -1778,6 +2137,28 @@ function withRunBoundaryMarks(node, marks) {
1778
2137
  * none of these values and there is accordingly nothing to carry.
1779
2138
  */
1780
2139
  const authoredEmuAttrs = (values) => Object.values(values).some((value) => value !== void 0) ? values : void 0;
2140
+ /**
2141
+ * A copy of the anchor record: ProseMirror keeps object-valued attrs by
2142
+ * reference, so sharing it with the source would let a mutation of either reach
2143
+ * the other outside a transaction.
2144
+ */
2145
+ const copiedDrawingAnchor = (anchor) => anchor === void 0 ? void 0 : {
2146
+ ...anchor,
2147
+ ...anchor.simplePosition === void 0 ? {} : { simplePosition: { ...anchor.simplePosition } }
2148
+ };
2149
+ /**
2150
+ * A copy of the inset-slot record, for the reason {@link copiedDrawingAnchor}
2151
+ * is copied: ProseMirror keeps object-valued attrs by reference.
2152
+ */
2153
+ const copiedWrapDistanceSlots = (slots) => slots === void 0 ? void 0 : {
2154
+ ...slots.drawing === void 0 ? {} : { drawing: { ...slots.drawing } },
2155
+ ...slots.wrapChild === void 0 ? {} : { wrapChild: { ...slots.wrapChild } }
2156
+ };
2157
+ /** A copy of the effect-extent slots, for {@link copiedWrapDistanceSlots}'s reason. */
2158
+ const copiedEffectExtentSlots = (slots) => slots === void 0 ? void 0 : {
2159
+ ...slots.drawing === void 0 ? {} : { drawing: { ...slots.drawing } },
2160
+ ...slots.wrapChild === void 0 ? {} : { wrapChild: { ...slots.wrapChild } }
2161
+ };
1781
2162
  /** The wrap insets of a drawing, keyed by the pixel attribute each becomes. */
1782
2163
  const wrapDistanceEmu = (wrap) => ({
1783
2164
  distTop: wrap?.distT,
@@ -1808,14 +2189,7 @@ function convertImage({ image, rawXml, rawXmlMode, rawImageFingerprint, runForma
1808
2189
  else if (wrapType === "behind" || wrapType === "inFront") displayMode = "float";
1809
2190
  else if (cssFloat !== "none") displayMode = "float";
1810
2191
  else displayMode = "block";
1811
- let transform;
1812
- if (image.transform) {
1813
- const transforms = [];
1814
- if (image.transform.rotation) transforms.push(`rotate(${image.transform.rotation}deg)`);
1815
- if (image.transform.flipH) transforms.push("scaleX(-1)");
1816
- if (image.transform.flipV) transforms.push("scaleY(-1)");
1817
- if (transforms.length > 0) transform = transforms.join(" ");
1818
- }
2192
+ const transformAttrs = authoredTransformAttrs(image.transform);
1819
2193
  const distTop = image.wrap.distT != null ? emuToPixels(image.wrap.distT) : void 0;
1820
2194
  const distBottom = image.wrap.distB != null ? emuToPixels(image.wrap.distB) : void 0;
1821
2195
  const distLeft = image.wrap.distL != null ? emuToPixels(image.wrap.distL) : void 0;
@@ -1842,22 +2216,11 @@ function convertImage({ image, rawXml, rawXmlMode, rawImageFingerprint, runForma
1842
2216
  if (image.outline && image.outline.width) {
1843
2217
  borderWidth = emuToStrokePixels(image.outline.width);
1844
2218
  if (image.outline.color?.rgb) borderColor = `#${image.outline.color.rgb}`;
1845
- borderStyle = image.outline.style ? {
1846
- solid: "solid",
1847
- dot: "dotted",
1848
- dash: "dashed",
1849
- lgDash: "dashed",
1850
- dashDot: "dashed",
1851
- lgDashDot: "dashed",
1852
- lgDashDotDot: "dashed",
1853
- sysDot: "dotted",
1854
- sysDash: "dashed",
1855
- sysDashDot: "dashed",
1856
- sysDashDotDot: "dashed"
1857
- }[image.outline.style] || "solid" : "solid";
2219
+ borderStyle = cssBorderStyleForDash(image.outline.dash);
1858
2220
  }
1859
2221
  return schema.node("image", {
1860
2222
  src: image.src || "",
2223
+ preview: image.preview,
1861
2224
  docPrName: image.docPrName,
1862
2225
  alt: image.alt,
1863
2226
  title: image.title,
@@ -1867,8 +2230,10 @@ function convertImage({ image, rawXml, rawXmlMode, rawImageFingerprint, runForma
1867
2230
  wrapType,
1868
2231
  displayMode,
1869
2232
  cssFloat,
1870
- transform,
2233
+ ...transformAttrs,
1871
2234
  opacity: image.opacity,
2235
+ brightness: image.effects?.brightness,
2236
+ contrast: image.effects?.contrast,
1872
2237
  distTop,
1873
2238
  distBottom,
1874
2239
  distLeft,
@@ -1882,7 +2247,10 @@ function convertImage({ image, rawXml, rawXmlMode, rawImageFingerprint, runForma
1882
2247
  paddingBottom: image.padding?.bottom,
1883
2248
  paddingLeft: image.padding?.left,
1884
2249
  position,
1885
- layoutInCell: image.layoutInCell,
2250
+ anchor: copiedDrawingAnchor(image.anchor),
2251
+ wrapDistanceSlots: copiedWrapDistanceSlots(image.wrap.distanceSlots),
2252
+ wrapEffectExtentSlots: copiedEffectExtentSlots(image.wrap.effectExtentSlots),
2253
+ wrapPolygon: copiedWrapPolygon(image.wrap.polygon),
1886
2254
  decorative: image.decorative,
1887
2255
  hidden: image.hidden,
1888
2256
  docPrExtensions: image.docPrExtensions ? [...image.docPrExtensions] : void 0,
@@ -1899,6 +2267,9 @@ function convertImage({ image, rawXml, rawXmlMode, rawImageFingerprint, runForma
1899
2267
  wrapText,
1900
2268
  hlinkHref: image.hlinkHref,
1901
2269
  hlinkRId: image.hlinkRId,
2270
+ hlinkClickSource: image.hlinkClickSource ? { ...image.hlinkClickSource } : void 0,
2271
+ hlinkHoverXml: image.hlinkHoverXml,
2272
+ docPrId: image.id,
1902
2273
  _docxRawXml: rawXml,
1903
2274
  _docxRawXmlMode: rawXmlMode,
1904
2275
  _docxRawImageFingerprint: rawImageFingerprint,
@@ -1906,7 +2277,7 @@ function convertImage({ image, rawXml, rawXmlMode, rawImageFingerprint, runForma
1906
2277
  _docxRunFormatting: runFormatting
1907
2278
  });
1908
2279
  }
1909
- function convertHyperlink(hyperlink, { getInheritedRunFormatting, styleResolver, hyperlinkIndex, textBoxAnchors, nextPageBreakRunOwnerId }) {
2280
+ function convertHyperlink(hyperlink, { getInheritedRunFormatting, styleResolver, hyperlinkIndex, textBoxAnchors, nextRunIdentityId }) {
1910
2281
  const nodes = [];
1911
2282
  const href = hyperlink.href || (hyperlink.anchor ? `#${hyperlink.anchor}` : "");
1912
2283
  const linkMark = schema.mark("hyperlink", {
@@ -1915,35 +2286,42 @@ function convertHyperlink(hyperlink, { getInheritedRunFormatting, styleResolver,
1915
2286
  rId: hyperlink.rId,
1916
2287
  _docxHyperlinkIndex: hyperlinkIndex
1917
2288
  });
1918
- for (const child of hyperlink.children) {
1919
- if (child.type === "bookmarkStart") {
1920
- nodes.push(schema.node("bookmarkBoundary", {
1921
- type: "start",
1922
- id: child.id,
1923
- name: child.name,
1924
- colFirst: child.colFirst,
1925
- colLast: child.colLast,
1926
- displacedByCustomXml: child.displacedByCustomXml
1927
- }, void 0, [linkMark]));
1928
- continue;
1929
- }
1930
- if (child.type === "bookmarkEnd") {
1931
- nodes.push(schema.node("bookmarkBoundary", {
1932
- type: "end",
1933
- id: child.id,
1934
- displacedByCustomXml: child.displacedByCustomXml
1935
- }, void 0, [linkMark]));
1936
- continue;
1937
- }
1938
- if (child.type === "run") {
1939
- assertPageBreakSourceRunIsRepresentable(child);
1940
- const inheritedFormatting = getInheritedRunFormatting(child.formatting);
1941
- const { marks: runMarks, mergedFormatting } = buildRunMarks(child.formatting, inheritedFormatting, styleResolver);
1942
- if (child.propertyChanges && child.propertyChanges.length > 0) runMarks.push(schema.mark("runPropertyChange", { changes: [...child.propertyChanges] }));
1943
- if (child.content.some((content) => content.type === "break" && content.breakType === "page")) runMarks.push(schema.mark("pageBreakRunOwner", { id: nextPageBreakRunOwnerId() }));
1944
- const allMarks = [...runMarks, linkMark];
1945
- for (const content of child.content) nodes.push(...convertRunContent(content, allMarks, mergedFormatting, textBoxAnchors, child.formatting));
2289
+ for (const { content: child, stack } of withInlineWrapperStacks(hyperlink.children)) {
2290
+ const childNodes = [];
2291
+ switch (child.type) {
2292
+ case "bookmarkStart":
2293
+ childNodes.push(schema.node("bookmarkBoundary", {
2294
+ type: "start",
2295
+ id: child.id,
2296
+ name: child.name,
2297
+ colFirst: child.colFirst,
2298
+ colLast: child.colLast,
2299
+ displacedByCustomXml: child.displacedByCustomXml
2300
+ }, void 0, [linkMark]));
2301
+ break;
2302
+ case "bookmarkEnd":
2303
+ childNodes.push(schema.node("bookmarkBoundary", {
2304
+ type: "end",
2305
+ id: child.id,
2306
+ displacedByCustomXml: child.displacedByCustomXml
2307
+ }, void 0, [linkMark]));
2308
+ break;
2309
+ case "preservedInline":
2310
+ childNodes.push(preservedInlineNode(child).mark([linkMark]));
2311
+ break;
2312
+ case "run": {
2313
+ const inheritedFormatting = getInheritedRunFormatting(child.formatting);
2314
+ const { marks: runMarks, mergedFormatting } = buildRunMarks(child.formatting, inheritedFormatting, styleResolver);
2315
+ if (child.propertyChanges && child.propertyChanges.length > 0) runMarks.push(schema.mark("runPropertyChange", { changes: [...child.propertyChanges] }));
2316
+ const identity = runIdentityMark(child, nextRunIdentityId);
2317
+ if (identity) runMarks.push(identity);
2318
+ const allMarks = [...runMarks, linkMark];
2319
+ for (const content of child.content) childNodes.push(...convertRunContent(content, allMarks, mergedFormatting, textBoxAnchors, child.formatting));
2320
+ break;
2321
+ }
2322
+ default: break;
1946
2323
  }
2324
+ nodes.push(...withInlineWrapperMark(childNodes, stack));
1947
2325
  }
1948
2326
  return nodes;
1949
2327
  }
@@ -1991,20 +2369,13 @@ function convertShape(shape, runFormatting) {
1991
2369
  outlineColorValue = shape.outline.color;
1992
2370
  outlineColor = resolveColorValueToHex(shape.outline.color);
1993
2371
  }
1994
- outlineStyle = shape.outline.style;
2372
+ outlineStyle = outlineAttrForDash(shape.outline.dash);
1995
2373
  outlineCap = shape.outline.cap;
1996
2374
  outlineJoin = shape.outline.join;
1997
2375
  outlineHeadEnd = shape.outline.headEnd;
1998
2376
  outlineTailEnd = shape.outline.tailEnd;
1999
2377
  } else outlineWidth = 0;
2000
- let transform;
2001
- if (shape.transform) {
2002
- const transforms = [];
2003
- if (shape.transform.rotation) transforms.push(`rotate(${shape.transform.rotation}deg)`);
2004
- if (shape.transform.flipH) transforms.push("scaleX(-1)");
2005
- if (shape.transform.flipV) transforms.push("scaleY(-1)");
2006
- if (transforms.length > 0) transform = transforms.join(" ");
2007
- }
2378
+ const transformAttrs = authoredTransformAttrs(shape.transform);
2008
2379
  const wrapType = shape.wrap?.type ?? "inline";
2009
2380
  const displayMode = wrapType === "inline" ? "inline" : "float";
2010
2381
  let cssFloat = "none";
@@ -2029,6 +2400,10 @@ function convertShape(shape, runFormatting) {
2029
2400
  geometryAdjustments: shape.geometryAdjustments === void 0 ? void 0 : JSON.stringify(shape.geometryAdjustments),
2030
2401
  shapeId: shape.id,
2031
2402
  shapeName: shape.name,
2403
+ anchor: copiedDrawingAnchor(shape.anchor),
2404
+ wrapDistanceSlots: copiedWrapDistanceSlots(shape.wrap?.distanceSlots),
2405
+ wrapEffectExtentSlots: copiedEffectExtentSlots(shape.wrap?.effectExtentSlots),
2406
+ wrapPolygon: copiedWrapPolygon(shape.wrap?.polygon),
2032
2407
  alt: shape.alt,
2033
2408
  title: shape.title,
2034
2409
  width: widthPx,
@@ -2053,7 +2428,7 @@ function convertShape(shape, runFormatting) {
2053
2428
  outlineJoin,
2054
2429
  outlineHeadEnd,
2055
2430
  outlineTailEnd,
2056
- transform,
2431
+ ...transformAttrs,
2057
2432
  displayMode,
2058
2433
  cssFloat,
2059
2434
  wrapType,
@@ -2067,18 +2442,20 @@ function convertShape(shape, runFormatting) {
2067
2442
  }
2068
2443
  function convertParagraphWithTextBoxes(block, styleResolver, { textBoxGroupId, context, extraRunFormatting, preserveEmptyWrapper, tableParagraphOverlay }) {
2069
2444
  const { textBoxes, textBoxAnchors } = extractTextBoxesFromParagraph(block, textBoxGroupId);
2070
- const pmParagraph = convertParagraph(block, styleResolver, context, void 0, extraRunFormatting, tableParagraphOverlay, textBoxAnchors);
2445
+ const pmParagraph = convertParagraph(block, styleResolver, context, extraRunFormatting, tableParagraphOverlay, textBoxAnchors);
2071
2446
  const nodes = [];
2072
2447
  const isEmptyAfterExtraction = textBoxes.length > 0 && !hasContentBesidesTextBoxAnchors(pmParagraph);
2073
2448
  const keepWrapperParagraph = isEmptyAfterExtraction && (preserveEmptyWrapper === true || hasParagraphBoundaryPayload(block, pmParagraph));
2074
2449
  if (!isEmptyAfterExtraction || keepWrapperParagraph) nodes.push(pmParagraph);
2075
- for (const { textBox, anchorId, trackedChange, inlineSdts } of textBoxes) nodes.push(convertTextBox(textBox, styleResolver, {
2076
- placement: isEmptyAfterExtraction && !keepWrapperParagraph ? "standalone" : "inlineWithPrevious",
2450
+ const standalone = isEmptyAfterExtraction && !keepWrapperParagraph;
2451
+ for (const [index, { textBox, anchorId, trackedChange, inlineSdts }] of textBoxes.entries()) nodes.push(convertTextBox(textBox, styleResolver, {
2452
+ placement: standalone ? "standalone" : "inlineWithPrevious",
2077
2453
  groupId: textBoxGroupId,
2078
2454
  anchorId,
2079
2455
  context,
2080
2456
  trackedChange,
2081
- inlineSdts
2457
+ inlineSdts,
2458
+ ...standalone && index === 0 && block.preservedAttributes ? { hostPreservedAttributes: block.preservedAttributes } : {}
2082
2459
  }));
2083
2460
  return nodes;
2084
2461
  }
@@ -2211,6 +2588,7 @@ function textBoxFromShape(shape, textBody) {
2211
2588
  if (shape.title !== void 0) textBox.title = shape.title;
2212
2589
  if (shape.position) textBox.position = shape.position;
2213
2590
  if (shape.wrap) textBox.wrap = shape.wrap;
2591
+ if (shape.anchor) textBox.anchor = shape.anchor;
2214
2592
  if (shape.fill) textBox.fill = shape.fill;
2215
2593
  if (shape.outline) textBox.outline = shape.outline;
2216
2594
  if (shape.transform) textBox.transform = shape.transform;
@@ -2225,7 +2603,7 @@ function textBoxFromShape(shape, textBody) {
2225
2603
  * Convert a TextBox to a ProseMirror textBox node
2226
2604
  */
2227
2605
  function convertTextBox(textBox, styleResolver, options) {
2228
- assertSourceContainerHasNoPageBreakRun(textBox.content, "text-box", options.context.pageBreakRunSourceDescendants);
2606
+ reportSourceContainerPageBreakRun(textBox.content, "text-box", options.context.pageBreakRunSourceDescendants, options.context.warnPageBreakProjection);
2229
2607
  const textBoxSize = textBox.size;
2230
2608
  const widthPx = textBoxSize?.width ? emuToPixels(textBoxSize.width) : 200;
2231
2609
  const heightPx = textBoxSize?.height ? emuToPixels(textBoxSize.height) : void 0;
@@ -2237,30 +2615,27 @@ function convertTextBox(textBox, styleResolver, options) {
2237
2615
  if (textBox.outline && textBox.outline.width) {
2238
2616
  outlineWidth = emuToStrokePixels(textBox.outline.width);
2239
2617
  if (textBox.outline.color?.rgb) outlineColor = `#${textBox.outline.color.rgb}`;
2240
- outlineStyle = textBox.outline.style || "solid";
2241
- }
2242
- let transform;
2243
- if (textBox.transform) {
2244
- const transforms = [];
2245
- if (textBox.transform.rotation) transforms.push(`rotate(${textBox.transform.rotation}deg)`);
2246
- if (textBox.transform.flipH) transforms.push("scaleX(-1)");
2247
- if (textBox.transform.flipV) transforms.push("scaleY(-1)");
2248
- if (transforms.length > 0) transform = transforms.join(" ");
2618
+ outlineStyle = outlineAttrForDash(textBox.outline.dash) ?? "solid";
2249
2619
  }
2620
+ const transformAttrs = authoredTransformAttrs(textBox.transform);
2250
2621
  const marginTop = textBox.margins?.top !== void 0 ? emuToPixels(textBox.margins.top) : void 0;
2251
2622
  const marginBottom = textBox.margins?.bottom !== void 0 ? emuToPixels(textBox.margins.bottom) : void 0;
2252
2623
  const marginLeft = textBox.margins?.left !== void 0 ? emuToPixels(textBox.margins.left) : void 0;
2253
2624
  const marginRight = textBox.margins?.right !== void 0 ? emuToPixels(textBox.margins.right) : void 0;
2625
+ const textBoxContext = {
2626
+ ...options.context,
2627
+ openCommentIds: /* @__PURE__ */ new Set()
2628
+ };
2254
2629
  const contentNodes = [];
2255
2630
  for (const block of textBox.content) {
2256
2631
  if (block.type === "paragraph") {
2257
2632
  contentNodes.push(...convertParagraphWithTextBoxes(block, styleResolver, {
2258
- textBoxGroupId: options.context.nextTextBoxGroupId(),
2259
- context: options.context
2633
+ textBoxGroupId: textBoxContext.nextTextBoxGroupId(),
2634
+ context: textBoxContext
2260
2635
  }));
2261
2636
  continue;
2262
2637
  }
2263
- contentNodes.push(convertTable(block, styleResolver, options.context));
2638
+ contentNodes.push(convertTable(block, styleResolver, textBoxContext));
2264
2639
  }
2265
2640
  if (contentNodes.length === 0) contentNodes.push(schema.node("paragraph", {}, []));
2266
2641
  const wrapType = textBox.wrap?.type;
@@ -2311,6 +2686,10 @@ function convertTextBox(textBox, styleResolver, options) {
2311
2686
  marginRight: textBox.margins?.right,
2312
2687
  ...wrapDistanceEmu(textBox.wrap)
2313
2688
  }),
2689
+ anchor: copiedDrawingAnchor(textBox.anchor),
2690
+ wrapDistanceSlots: copiedWrapDistanceSlots(textBox.wrap?.distanceSlots),
2691
+ wrapEffectExtentSlots: copiedEffectExtentSlots(textBox.wrap?.effectExtentSlots),
2692
+ wrapPolygon: copiedWrapPolygon(textBox.wrap?.polygon),
2314
2693
  autoFit: textBox.autoFit,
2315
2694
  wordArt: textBox.wordArt,
2316
2695
  textWrap: textBox.textWrap,
@@ -2323,7 +2702,7 @@ function convertTextBox(textBox, styleResolver, options) {
2323
2702
  outlineWidth,
2324
2703
  outlineColor,
2325
2704
  outlineStyle,
2326
- transform,
2705
+ ...transformAttrs,
2327
2706
  marginTop,
2328
2707
  marginBottom,
2329
2708
  marginLeft,
@@ -2342,7 +2721,8 @@ function convertTextBox(textBox, styleResolver, options) {
2342
2721
  _docxAnchorId: options.anchorId,
2343
2722
  _docxTextBodyContentState: textBox.content.length === 0 ? { type: "source-empty" } : { type: "authored" },
2344
2723
  _docxTrackedChange: options.trackedChange,
2345
- _docxInlineSdts: options.inlineSdts.length > 0 ? options.inlineSdts : void 0
2724
+ _docxInlineSdts: options.inlineSdts.length > 0 ? options.inlineSdts : void 0,
2725
+ _preservedAttributes: options.hostPreservedAttributes
2346
2726
  }, contentNodes);
2347
2727
  }
2348
2728
  /**
@@ -2363,7 +2743,10 @@ function headerFooterToProseDoc(content, options) {
2363
2743
  nextTextBoxGroupId,
2364
2744
  nextHyperlinkInstanceIndex: createHyperlinkInstanceIndexAllocator(),
2365
2745
  pairedBookmarkIds: collectPairedBookmarkIds(content),
2366
- pageBreakRunSourceDescendants: buildPageBreakRunSourceDescendantIndex(content)
2746
+ pageBreakRunSourceDescendants: buildPageBreakRunSourceDescendantIndex(content),
2747
+ storyRangedCommentIds: rangedCommentIds(content),
2748
+ openCommentIds: /* @__PURE__ */ new Set(),
2749
+ warnPageBreakProjection: pageBreakProjectionWarn(options?.warn)
2367
2750
  };
2368
2751
  const convertBlocks = (blocks) => {
2369
2752
  const out = [];
@@ -2392,6 +2775,13 @@ function headerFooterToProseDoc(content, options) {
2392
2775
  case "blockSdt":
2393
2776
  out.push(convertBlockSdt(block, convertBlocks));
2394
2777
  break;
2778
+ case "preservedBlock":
2779
+ out.push(convertPreservedBlock(block));
2780
+ break;
2781
+ case "bookmarkStart":
2782
+ case "bookmarkEnd":
2783
+ out.push(convertBlockBookmarkBoundary(block));
2784
+ break;
2395
2785
  default: panic(`Unsupported block content: ${JSON.stringify(block)}`);
2396
2786
  }
2397
2787
  return out;
@@ -2412,4 +2802,4 @@ function createEmptyDoc() {
2412
2802
  return schema.node("doc", null, [schema.node("paragraph", {}, [])]);
2413
2803
  }
2414
2804
  //#endregion
2415
- export { UnsupportedDocxToProseMirrorConversionError, createEmptyDoc, footnoteToProseDoc, headerFooterToProseDoc, resolveParagraphDefaultTextFormatting, standaloneTableCellToProseMirror, toProseDoc };
2805
+ export { createEmptyDoc, footnoteToProseDoc, headerFooterToProseDoc, resolveParagraphDefaultTextFormatting, standaloneTableCellToProseMirror, toProseDoc };