@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,39 +1,54 @@
1
+ import { joinCommentRangesAcrossParagraphs } from "../../docx/commentRangeJoin.js";
2
+ import { completeCommentReferences } from "../../docx/commentReferenceCompletion.js";
1
3
  import { EDITED_PREVIEW_FINGERPRINT, imageRawXmlFingerprint } from "../../docx/imageRawXml.js";
2
- import { isNumberingReference } from "../../docx/numberingReference.js";
4
+ import { isInlineSdtContent, isSimpleFieldContent } from "../../docx/inlineWrapperContent.js";
5
+ import { paragraphNumberingReferenceId as paragraphNumberingReferenceId$1, sameStatedParagraphNumbering as sameStatedParagraphNumbering$1 } from "../../docx/numberingReference.js";
3
6
  import { PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR, ParagraphPropertySourceValidationError, copyDocumentParagraphPropertySourceContract, copyDocumentParagraphPropertySources, copyParagraphPropertyCapture, copyParagraphPropertySource, decodeTableCellParagraphSourcePayload, getDocumentParagraphPropertySourceContract, getParagraphPropertySource, getParagraphPropertySourceCandidate, getParagraphPropertySourceToken, getParagraphPropertySourceTransferId, getProseDocumentParagraphPropertySourceContract, getProseParagraphPropertySourceToken, isParagraphPropertySourceToken, linkParagraphPropertySourceCandidate, paragraphPropertySourceBelongsToDocument, paragraphPropertySourceTokenMatchesContract, recreateProseNodeWithParagraphPropertySource, restoreTableCellsWithParagraphPropertySources, visitDocumentStoryParagraphs, visitTableCellParagraphPropertySourceBindings } from "../../docx/paragraphPropertySource.js";
4
- import { visitDocxParagraphs } from "../../docx/paragraphTraversal.js";
5
- import { ShapeOutlineStyleSchema, narrowEnum } from "../../docx/parserEnums.js";
7
+ import { BLOCK_TREE_DESCENT, visitBlockTreeRecords, visitDocxParagraphs } from "../../docx/paragraphTraversal.js";
6
8
  import { DATE_UTC_ATTRIBUTE } from "../../docx/trackedChangeInfo.js";
7
- import { isStyleSourcedParagraphNumbering, modelParagraphFormattingEmission, sameAuthoredParagraphNumberingReference } from "../../internal/paragraphFormattingSerialization.js";
9
+ import { copiedWrapPolygon } from "../../docx/wrapPolygon.js";
10
+ import { isStyleSourcedParagraphNumbering, modelParagraphFormattingEmission } from "../../internal/paragraphFormattingSerialization.js";
8
11
  import { createStyleEngine } from "../../style-engine/styleEngine.js";
9
- import { OUTLINE_STYLE_CSS_ALIASES, normalizeShapeTextAnchor } from "../../types/documentEnumValues.js";
12
+ import { normalizeShapeTextAnchor, presetDashForOutlineAttr } from "../../types/documentEnumValues.js";
13
+ import { presetDashForCssBorderStyle } from "../../utils/borderCss.js";
10
14
  import { canonicalJson } from "../../utils/canonicalJson.js";
11
15
  import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
12
16
  import { mergeTextFormatting } from "../../utils/textFormattingMerge.js";
13
17
  import { emuToPixels, emuToStrokePixels, pixelsToEmu } from "../../utils/units.js";
14
- import { expectBlockSdtAttrs, expectCharacterSpacingMarkAttrs, expectCharacterStyleMarkAttrs, expectCommentMarkAttrs, expectEmphasisMarkAttrs, expectFieldAttrs, expectFontFamilyMarkAttrs, expectFontSizeMarkAttrs, expectFootnoteRefMarkAttrs, expectHardBreakAttrs, expectHighlightMarkAttrs, expectHyperlinkMarkAttrs, expectImageAttrs, expectLanguageMarkAttrs, expectMathAttrs, expectPageBreakRunAttrs, expectPageBreakRunOwnerMarkAttrs, expectParagraphAttrs, expectRunFormattingOverrideMarkAttrs, expectRunPropertyChangeMarkAttrs, expectRunShadingMarkAttrs, expectSdtAttrs, expectShapeAttrs, expectStrikeMarkAttrs, expectSymbolAttrs, expectTabAttrs, expectTableAttrs, expectTableCellAttrs, expectTableRowAttrs, expectTextBoxAttrs, expectTextColorMarkAttrs, expectTextEffectMarkAttrs, expectTrackedChangeMarkAttrs, expectUnderlineMarkAttrs } from "../attrs/index.js";
18
+ import { expectBlockSdtAttrs, expectCharacterSpacingMarkAttrs, expectCharacterStyleMarkAttrs, expectCommentMarkAttrs, expectEmphasisMarkAttrs, expectFieldAttrs, expectFontFamilyMarkAttrs, expectFontSizeMarkAttrs, expectFootnoteRefMarkAttrs, expectHardBreakAttrs, expectHighlightMarkAttrs, expectHyperlinkMarkAttrs, expectImageAttrs, expectInlineWrapperMarkAttrs, expectLanguageMarkAttrs, expectMathAttrs, expectPageBreakRunAttrs, expectParagraphAttrs, expectPreservedBlockAttrs, expectPreservedXmlAttrs, expectRunFormattingOverrideMarkAttrs, expectRunIdentityMarkAttrs, expectRunPropertyChangeMarkAttrs, expectRunShadingMarkAttrs, expectSdtAttrs, expectShapeAttrs, expectStrikeMarkAttrs, expectSymbolAttrs, expectTabAttrs, expectTableAttrs, expectTableCellAttrs, expectTableRowAttrs, expectTextBoxAttrs, expectTextColorMarkAttrs, expectTextEffectMarkAttrs, expectTrackedChangeMarkAttrs, expectUnderlineMarkAttrs } from "../attrs/index.js";
19
+ import { readAuthoredTransform } from "../authoredTransformAttrs.js";
15
20
  import { autospacingMatchesBase, hasAutospacingBaseSide } from "../autospacingBase.js";
16
- import { bookmarkBoundaryDisplacement, expectBookmarkBoundaryAttrs } from "../bookmarkBoundaryAttrs.js";
21
+ import { bookmarkMarkerFromAttrs, expectBookmarkBoundaryAttrs } from "../bookmarkBoundaryAttrs.js";
17
22
  import { paragraphRejectAttrPatch, paragraphRejectOriginalFormatting, removeParagraphPropertyChanges } from "../commands/propertyChangeScope.js";
23
+ import { expectCommentReferenceAttrs } from "../commentReferenceAttrs.js";
24
+ import { INLINE_WRAPPER_MARK_NAME } from "../extensions/marks/InlineWrapperExtension.js";
18
25
  import { applyRunFormattingOverrideAttrs, buildRunFormattingOverrideAttrs } from "../extensions/marks/RunFormattingOverrideExtension.js";
19
26
  import { textFormattingToMarks } from "../extensions/marks/markUtils.js";
27
+ import "../extensions/nodes/MoveRangeBoundaryExtension.js";
28
+ import "../extensions/nodes/RangeAnchorExtension.js";
29
+ import { inlineWrapperMember, inlineWrapperStackKey } from "../inlineWrapperStack.js";
20
30
  import { listRenderingFromAttrs as listRenderingFromAttrs$1 } from "../listRenderingAttrs.js";
31
+ import { expectMoveRangeBoundaryAttrs } from "../moveRangeBoundaryAttrs.js";
21
32
  import { resolveNumberedRefFields } from "../numberedRefFields.js";
22
33
  import { directParagraphAlignment } from "../paragraphAlignment.js";
23
34
  import { directionToBidi } from "../paragraphDirection.js";
24
35
  import { directParagraphSpacing } from "../paragraphSpacing.js";
36
+ import { expectRangeAnchorAttrs } from "../rangeAnchorAttrs.js";
25
37
  import { RUN_FORMATTING_MARK_NAMES } from "../runFormattingMarkNames.js";
26
38
  import { authoredRunFormattingFromAttrs, hasAuthoredRunFormattingProvenance } from "../runFormattingProvenance.js";
39
+ import { RUN_IDENTITY_MARK_NAME } from "../runIdentity.js";
27
40
  import { paragraphFormattingForRun, paragraphRunStyleContext, resolveEffectiveRunStyleFormatting, suppressParagraphMarkFormatting } from "../runStyleFormatting.js";
28
41
  import { schema } from "../schema/index.js";
42
+ import { PRESERVED_XML_LEVELS } from "../schema/nodes.js";
29
43
  import { parseShapeGeometryAdjustments } from "../shapeGeometryAdjustments.js";
30
44
  import { expectTextBoxAnchorAttrs } from "../textBoxAnchorAttrs.js";
31
45
  import { assertValidProseMirrorDocument } from "../validation.js";
46
+ import { hasSinkChildren } from "./preservedSinkCarriers.js";
32
47
  import { runShadingAttrsToShading, shadingToRunShadingAttrs } from "./runShadingMark.js";
33
48
  import { decodeSdtListItems, sdtPropertiesFromAttrs, sdtPropertiesMatchAttrs } from "./sdtAttrs.js";
34
49
  import { panic } from "better-result";
50
+ import { DRAWING_RAW_XML_MODES, relationshipIdOf } from "@stll/docx-core/model";
35
51
  import { Fragment } from "prosemirror-model";
36
- import { DRAWING_RAW_XML_MODES } from "@stll/docx-core/model";
37
52
  //#region src/prosemirror/conversion/fromProseDoc.ts
38
53
  /**
39
54
  * ProseMirror to Document Conversion
@@ -46,23 +61,16 @@ import { DRAWING_RAW_XML_MODES } from "@stll/docx-core/model";
46
61
  * - Preserve paragraph attributes (paraId, textId, formatting)
47
62
  * - Handle marks -> TextFormatting conversion
48
63
  */
49
- function normalizeShapeOutlineStyle(style) {
50
- if (!style) return;
51
- if (style in OUTLINE_STYLE_CSS_ALIASES) return OUTLINE_STYLE_CSS_ALIASES[style];
52
- return narrowEnum(style, ShapeOutlineStyleSchema);
53
- }
54
- function parseTransformAttr(transformStr) {
55
- if (!transformStr) return;
56
- const transform = {};
57
- const rotateMatch = /rotate\((?<deg>[-\d.]+)deg\)/u.exec(transformStr);
58
- if (rotateMatch) {
59
- const rotation = Number.parseFloat(rotateMatch.groups["deg"]);
60
- if (Number.isFinite(rotation)) transform.rotation = rotation;
61
- }
62
- if (transformStr.includes("scaleX(-1)")) transform.flipH = true;
63
- if (transformStr.includes("scaleY(-1)")) transform.flipV = true;
64
- if (transform.rotation === void 0 && !transform.flipH && !transform.flipV) return;
65
- return transform;
64
+ /**
65
+ * The dash an `outlineStyle` attribute names.
66
+ *
67
+ * `"none"` is the explicit no-outline sentinel rather than a dash, so it
68
+ * returns undefined here: the serializer's no-outline guard drops the `<a:ln>`
69
+ * before this is called.
70
+ */
71
+ function normalizeShapeOutlineDash(style) {
72
+ const dash = presetDashForOutlineAttr(style);
73
+ return dash === void 0 || dash === "none" ? void 0 : dash;
66
74
  }
67
75
  function imagePositionFromAttrs(attrs) {
68
76
  const horizontalPosition = attrs?.horizontal;
@@ -93,8 +101,9 @@ const emuFromPixels = (px, key, authored, project) => {
93
101
  return emu !== void 0 && project(emu) === px ? emu : pixelsToEmu(px);
94
102
  };
95
103
  /**
96
- * Copy the wrap insets onto a wrap. Shared by the image, shape and text-box
97
- * paths so one rule decides when an inset keeps its authored EMU.
104
+ * Copy the wrap insets, the slot each was authored on, and the wrap polygon
105
+ * onto a wrap. Shared by the image, shape and text-box paths so one rule
106
+ * decides when an inset keeps its authored EMU.
98
107
  */
99
108
  const assignWrapDistances = (wrap, attrs) => {
100
109
  const authored = attrs._docxAuthoredEmu;
@@ -102,6 +111,22 @@ const assignWrapDistances = (wrap, attrs) => {
102
111
  if (attrs.distBottom !== void 0) wrap.distB = emuFromPixels(attrs.distBottom, "distBottom", authored, emuToPixels);
103
112
  if (attrs.distLeft !== void 0) wrap.distL = emuFromPixels(attrs.distLeft, "distLeft", authored, emuToPixels);
104
113
  if (attrs.distRight !== void 0) wrap.distR = emuFromPixels(attrs.distRight, "distRight", authored, emuToPixels);
114
+ const slots = copiedWrapDistanceSlots(attrs.wrapDistanceSlots);
115
+ if (slots !== void 0) wrap.distanceSlots = slots;
116
+ const extents = copiedEffectExtentSlots(attrs.wrapEffectExtentSlots);
117
+ if (extents !== void 0) wrap.effectExtentSlots = extents;
118
+ const polygon = copiedWrapPolygon(attrs.wrapPolygon);
119
+ if (polygon !== void 0) wrap.polygon = polygon;
120
+ };
121
+ /** A copy, so the model cannot share a slot record with a ProseMirror attr. */
122
+ const copiedWrapDistanceSlots = (slots) => slots === void 0 ? void 0 : {
123
+ ...slots.drawing === void 0 ? {} : { drawing: { ...slots.drawing } },
124
+ ...slots.wrapChild === void 0 ? {} : { wrapChild: { ...slots.wrapChild } }
125
+ };
126
+ /** The same copy, one carrier over. */
127
+ const copiedEffectExtentSlots = (slots) => slots === void 0 ? void 0 : {
128
+ ...slots.drawing === void 0 ? {} : { drawing: { ...slots.drawing } },
129
+ ...slots.wrapChild === void 0 ? {} : { wrapChild: { ...slots.wrapChild } }
105
130
  };
106
131
  function textBoxWrapFromAttrs(attrs) {
107
132
  if (!(attrs.wrapType !== void 0 && attrs.wrapType !== "inline" || attrs.wrapText !== void 0 || attrs.distTop !== void 0 || attrs.distBottom !== void 0 || attrs.distLeft !== void 0 || attrs.distRight !== void 0)) return;
@@ -228,7 +253,12 @@ const restoreLinkedParagraphPropertySources = (content) => {
228
253
  };
229
254
  };
230
255
  /** Convert a ProseMirror document to the document model. */
231
- function fromProseDoc(pmDoc, baseDocument) {
256
+ function fromProseDoc(pmDoc, baseDocument, { reuse = "none" } = {}) {
257
+ switch (reuse) {
258
+ case "none": break;
259
+ case "matched": panic("fromProseDoc: reuse \"matched\" is not implemented");
260
+ default: panic(`fromProseDoc: unhandled reuse ${String(reuse)}`);
261
+ }
232
262
  assertValidProseMirrorDocument(pmDoc, "Cannot convert invalid ProseMirror document to DOCX model");
233
263
  const baseContract = baseDocument ? getDocumentParagraphPropertySourceContract(baseDocument) : void 0;
234
264
  const proseContractAttribute = pmDoc.attrs[PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR];
@@ -236,6 +266,8 @@ function fromProseDoc(pmDoc, baseDocument) {
236
266
  if (proseContractAttribute !== null && proseContractAttribute !== void 0 && proseContract === null || (baseContract ?? null) !== proseContract) throw sourceValidationError("contract_mismatch", "The ProseMirror document does not match its paragraph-property source document.");
237
267
  const tokenSources = baseContract && proseContract && baseDocument ? validateParagraphPropertySourceTokens(pmDoc, baseDocument, baseContract) : null;
238
268
  const blocks = extractBlocks(pmDoc, "resolve", baseDocument?.package.styles ? createStyleEngine(baseDocument.package.styles) : null);
269
+ joinCommentRangesAcrossParagraphs(blocks);
270
+ completeCommentReferences(blocks);
239
271
  const linkedSources = restoreLinkedParagraphPropertySources(blocks);
240
272
  if (tokenSources) restoreParagraphPropertySourcesByToken(blocks, tokenSources);
241
273
  else if (baseDocument) restoreParagraphPropertySources(blocks, baseDocument.package.document.content, linkedSources.targets, linkedSources.sources);
@@ -452,42 +484,9 @@ function materializeNumberedRefValues(doc) {
452
484
  };
453
485
  return visit(doc);
454
486
  }
455
- const SERIALIZER_EMPTY_PAGE_FIELD_RESULT = "1";
456
- const fieldResultHasExplicitPageBreak = (node) => extractParagraphContent(node, void 0, void 0, /* @__PURE__ */ new Map(), false).filter((content) => content.type === "run" || content.type === "hyperlink").some((content) => {
457
- return (content.type === "run" ? [content] : content.children).some((run) => run.type === "run" && run.content.some((runContent) => runContent.type === "break" && runContent.breakType === "page"));
458
- });
459
- /**
460
- * PAGE and NUMPAGES have a stable visible fallback. Other empty fields may
461
- * intentionally have no result (for example an empty TOC); inventing a space
462
- * changes their authored result on every save/reopen cycle. A field whose
463
- * result already carries an explicit page break owns that break's run, so the
464
- * fallback would displace it.
465
- */
466
- function materializeSerializerFieldFallbacks(doc) {
467
- const visit = (node) => {
468
- if (node.type.name === "field" || node.type.name === "structuredField") {
469
- const attrs = expectFieldAttrs(node);
470
- return (attrs.fieldType === "PAGE" || attrs.fieldType === "NUMPAGES") && !attrs.displayText && !fieldResultHasExplicitPageBreak(node) ? recreateProseNodeWithParagraphPropertySource(node, { attrs: {
471
- ...node.attrs,
472
- displayText: SERIALIZER_EMPTY_PAGE_FIELD_RESULT
473
- } }) : node;
474
- }
475
- if (node.childCount === 0) return node;
476
- const children = [];
477
- let changed = false;
478
- node.forEach((child) => {
479
- const mappedChild = visit(child);
480
- children.push(mappedChild);
481
- changed ||= mappedChild !== child;
482
- });
483
- return changed ? recreateProseNodeWithParagraphPropertySource(node, { content: Fragment.fromArray(children) }) : node;
484
- };
485
- return visit(doc);
486
- }
487
- function extractBlocks(inputDoc, refResolution = "resolve", styleResolver = null, emptyFieldResult = "serializerFallback") {
487
+ function extractBlocks(inputDoc, refResolution = "resolve", styleResolver = null) {
488
488
  const strippedDoc = stripSuggestedProvenance(inputDoc, styleResolver);
489
- const refResolvedDoc = refResolution === "resolve" ? materializeNumberedRefValues(strippedDoc) : strippedDoc;
490
- const pmDoc = emptyFieldResult === "serializerFallback" ? materializeSerializerFieldFallbacks(refResolvedDoc) : refResolvedDoc;
489
+ const pmDoc = refResolution === "resolve" ? materializeNumberedRefValues(strippedDoc) : strippedDoc;
491
490
  const blocks = [];
492
491
  const textBoxAnchorMarkers = /* @__PURE__ */ new Map();
493
492
  const documentCounts = buildDocumentTrackedChangeCounts(pmDoc);
@@ -530,15 +529,116 @@ function extractBlocks(inputDoc, refResolution = "resolve", styleResolver = null
530
529
  pendingPageBreaks = 0;
531
530
  } else if (node.type.name === "blockSdt") {
532
531
  if (pendingPageBreaks > 0 && !appendPendingPageBreaksToPreviousParagraph()) flushPendingPageBreaks();
533
- blocks.push(convertPMBlockSdt(node, styleResolver, emptyFieldResult));
532
+ blocks.push(convertPMBlockSdt(node, styleResolver));
533
+ previousStandaloneTextBox = null;
534
+ } else if (node.type.name === "preservedBlock") {
535
+ blocks.push({
536
+ type: "preservedBlock",
537
+ xml: expectPreservedBlockAttrs(node).xml
538
+ });
539
+ previousStandaloneTextBox = null;
540
+ } else if (node.type.name === "blockBookmarkBoundary") {
541
+ blocks.push(blockBookmarkMarker(node));
534
542
  previousStandaloneTextBox = null;
535
543
  }
536
544
  });
537
545
  if (pendingPageBreaks > 0 && !appendPendingPageBreaksToPreviousParagraph()) flushPendingPageBreaks();
538
546
  removeUnresolvedTextBoxAnchors(blocks, textBoxAnchorMarkers);
547
+ keepOneRecordCarriedByIdentity(blocks);
548
+ keepTheSectionBreakOnTheLastParagraphThatCarriesIt(blocks);
539
549
  return blocks;
540
550
  }
541
- function convertPMBlockSdt(node, styleResolver, emptyFieldResult) {
551
+ /**
552
+ * What an authored element carried follows its record, and only it.
553
+ *
554
+ * Two things ride a node's attrs by reference rather than by value: the
555
+ * attribute remainder (`w:rsidR` and its family) and the ordered verbatim sink
556
+ * (the markup a container held beside its modelled children). ProseMirror
557
+ * copies a node's attrs when a command splits or duplicates it, so pressing
558
+ * Enter in the middle of a paragraph produces two nodes holding the *same*
559
+ * remainder array, and copying a table produces two tables holding the same
560
+ * sink. Writing either back on both is a claim the author did not make:
561
+ * `w:rsidR` says which editing session wrote this paragraph, and a second copy
562
+ * of a `w:bookmarkEnd` is a bookmark boundary nobody wrote. The rule is that
563
+ * the record that comes first in document order keeps what was authored, and
564
+ * the other is a new record with none — the same answer a record the editor
565
+ * created from scratch gets.
566
+ *
567
+ * Reference identity is what tells the two cases apart, and it is exact: two
568
+ * records that each parsed their own children and attributes hold different
569
+ * objects however equal their contents, and only a copy made by the editor
570
+ * shares one.
571
+ *
572
+ * The rule holds per block container or it does not hold: a walk that reaches
573
+ * the body, a cell and an `w:sdt` but not a text box leaves the records inside
574
+ * one free to claim an authored revision session each. `visitBlockTreeRecords`
575
+ * is the one traversal, and it is exhaustive over the block union.
576
+ */
577
+ const keepOneRecordCarriedByIdentity = (blocks) => {
578
+ const seen = /* @__PURE__ */ new WeakSet();
579
+ /** Whether this object is the authored one rather than a copy's reference. */
580
+ const isAuthored = (value) => {
581
+ if (value === void 0) return true;
582
+ if (seen.has(value)) return false;
583
+ seen.add(value);
584
+ return true;
585
+ };
586
+ const keepFirst = (record) => {
587
+ if (!isAuthored(record.preservedAttributes)) delete record.preservedAttributes;
588
+ if (!isAuthored(record.bookmarks)) delete record.bookmarks;
589
+ if (!isAuthored(record.preserved)) delete record.preserved;
590
+ };
591
+ visitBlockTreeRecords(blocks, (record) => {
592
+ keepFirst(record);
593
+ return BLOCK_TREE_DESCENT.descend;
594
+ });
595
+ };
596
+ /**
597
+ * The section break belongs to the last paragraph that carries it.
598
+ *
599
+ * A `w:sectPr` inside a `w:pPr` says "the section ends at this paragraph's
600
+ * mark". ProseMirror copies a node's attrs when a command splits it, so
601
+ * pressing Enter inside a section-ending paragraph produces two nodes over the
602
+ * *same* `_sectionProperties` object; writing it back on both ends the section
603
+ * twice. The document gains a section nobody added, and its `w:sectPr` repeats
604
+ * the `w:rsidSect` of the real one, so the copy also claims that section's
605
+ * revision history. On a split the trailing half is the half that still ends
606
+ * the section, and the leading half becomes an ordinary paragraph — Word's own
607
+ * rule, and the exact opposite of the remainder's, which stays with the
608
+ * authored half above.
609
+ *
610
+ * The rule lives on the from-leg rather than in the split commands because the
611
+ * commands cannot be enumerated: Enter, a paste that lands several paragraphs
612
+ * in a section-ending one, an AI edit and a tracked-change resolution each
613
+ * split a paragraph by their own route, and a split merged in from another
614
+ * client reaches no local command at all. Every route arrives here.
615
+ *
616
+ * Reference identity is what tells a copy from a second authored break, and it
617
+ * is exact: two paragraphs that each parsed their own `w:sectPr` hold
618
+ * different objects however equal their contents, and only a copy made by the
619
+ * editor shares one. The projection passes the object through by reference and
620
+ * never clones it, which is what keeps that signal alive.
621
+ */
622
+ const keepTheSectionBreakOnTheLastParagraphThatCarriesIt = (blocks) => {
623
+ const lastCarrier = /* @__PURE__ */ new Map();
624
+ visitBlockTreeRecords(blocks, (record) => {
625
+ if (record.type !== "paragraph" || record.sectionProperties === void 0) return BLOCK_TREE_DESCENT.descend;
626
+ const earlier = lastCarrier.get(record.sectionProperties);
627
+ if (earlier) delete earlier.sectionProperties;
628
+ lastCarrier.set(record.sectionProperties, record);
629
+ return BLOCK_TREE_DESCENT.descend;
630
+ });
631
+ };
632
+ /**
633
+ * A bookmark marker standing between two blocks, back in the model.
634
+ *
635
+ * The node's place in the document is the whole of its position, so nothing is
636
+ * read off it but the marker's own attributes.
637
+ */
638
+ function blockBookmarkMarker(node) {
639
+ return bookmarkMarkerFromAttrs(expectBookmarkBoundaryAttrs(node));
640
+ }
641
+ function convertPMBlockSdt(node, styleResolver) {
542
642
  const attrs = expectBlockSdtAttrs(node);
543
643
  const properties = { sdtType: attrs.sdtType };
544
644
  if (attrs.alias) properties.alias = attrs.alias;
@@ -552,11 +652,12 @@ function convertPMBlockSdt(node, styleResolver, emptyFieldResult) {
552
652
  if (attrs.listItems) properties.listItems = decodeSdtListItems(attrs.listItems);
553
653
  if (typeof attrs.dropdownLastValue === "string") properties.dropdownLastValue = attrs.dropdownLastValue;
554
654
  if (typeof attrs.checked === "boolean") properties.checked = attrs.checked;
555
- if (attrs.rawPropertiesXml) properties.rawPropertiesXml = attrs.rawPropertiesXml;
655
+ if (attrs._preserved) properties.preserved = attrs._preserved;
556
656
  if (attrs.rawEndPropertiesXml) properties.rawEndPropertiesXml = attrs.rawEndPropertiesXml;
657
+ if (attrs.endProperties) properties.endProperties = attrs.endProperties;
557
658
  if (attrs.rawSdtChildrenBeforeContent) properties.rawSdtChildrenBeforeContent = attrs.rawSdtChildrenBeforeContent;
558
659
  if (attrs.rawSdtChildrenAfterContent) properties.rawSdtChildrenAfterContent = attrs.rawSdtChildrenAfterContent;
559
- const extracted = extractBlocks(node.type.schema.node("doc", null, node.content), "inherit", styleResolver, emptyFieldResult);
660
+ const extracted = extractBlocks(node.type.schema.node("doc", null, node.content), "inherit", styleResolver);
560
661
  return {
561
662
  type: "blockSdt",
562
663
  properties,
@@ -594,6 +695,7 @@ function appendTextBoxBlock(blocks, node, options) {
594
695
  if (!mergeTextBoxIntoTrailingInlineSdts(options.previousStandaloneTextBox.paragraph, paragraph, attrs._docxInlineSdts ?? [])) options.previousStandaloneTextBox.paragraph.content.push(...paragraph.content);
595
696
  return options.previousStandaloneTextBox;
596
697
  }
698
+ if (attrs._docxPlacement === "standalone" && attrs._preservedAttributes?.length) paragraph.preservedAttributes = attrs._preservedAttributes;
597
699
  prependPageBreaks(paragraph, options.pendingPageBreaks);
598
700
  blocks.push(paragraph);
599
701
  return attrs._docxPlacement === "standalone" && attrs._docxGroupId ? {
@@ -647,7 +749,7 @@ function findTextBoxShapeRun(content) {
647
749
  if (item.content.some((runContent) => runContent.type === "shape" && runContent.shape.shapeType === "textBox")) return item;
648
750
  continue;
649
751
  }
650
- if (item.type === "inlineSdt" || item.type === "hyperlink" || item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") {
752
+ if (item.type === "inlineSdt" || item.type === "hyperlink" || item.type === "inlineWrapper" || item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") {
651
753
  const run = findTextBoxShapeRun(item.type === "hyperlink" ? item.children : item.content);
652
754
  if (run) return run;
653
755
  }
@@ -663,6 +765,7 @@ function replaceTextBoxAnchorInBlocks(blocks, marker, textBoxRun) {
663
765
  for (const row of block.rows) for (const cell of row.cells) if (replaceTextBoxAnchorInBlocks(cell.content, marker, textBoxRun)) return true;
664
766
  continue;
665
767
  }
768
+ if (block.type !== "blockSdt") continue;
666
769
  if (replaceTextBoxAnchorInBlocks(block.content, marker, textBoxRun)) return true;
667
770
  }
668
771
  return false;
@@ -685,7 +788,7 @@ const textBoxAnchorHost = (item) => {
685
788
  case "deletion":
686
789
  case "moveFrom":
687
790
  case "moveTo":
688
- case "bidiWrapper": return item.content;
791
+ case "inlineWrapper": return item.content;
689
792
  case "run":
690
793
  case "complexField":
691
794
  case "bookmarkStart":
@@ -697,7 +800,8 @@ const textBoxAnchorHost = (item) => {
697
800
  case "moveFromRangeEnd":
698
801
  case "moveToRangeStart":
699
802
  case "moveToRangeEnd":
700
- case "mathEquation": return;
803
+ case "mathEquation":
804
+ case "preservedInline": return;
701
805
  default: panic(`Unsupported paragraph content: ${JSON.stringify(item)}`);
702
806
  }
703
807
  };
@@ -730,6 +834,7 @@ function removeTextBoxAnchorFromBlocks(blocks, marker) {
730
834
  for (const row of block.rows) for (const cell of row.cells) if (removeTextBoxAnchorFromBlocks(cell.content, marker)) return true;
731
835
  continue;
732
836
  }
837
+ if (block.type !== "blockSdt") continue;
733
838
  if (removeTextBoxAnchorFromBlocks(block.content, marker)) return true;
734
839
  }
735
840
  return false;
@@ -741,8 +846,8 @@ function removeTextBoxAnchorFromBlocks(blocks, marker) {
741
846
  * list markers on the way out of the editor.
742
847
  */
743
848
  function listRenderingFromAttrs(attrs) {
744
- const numId = attrs.numPr?.numId;
745
- if (!isNumberingReference(numId)) return;
849
+ const numId = paragraphNumberingReferenceId$1(attrs.numPr);
850
+ if (numId === void 0) return;
746
851
  if (!(attrs.listMarker != null || attrs.listIsBullet || attrs.listNumFmt != null)) return;
747
852
  return listRenderingFromAttrs$1({
748
853
  attrs,
@@ -822,9 +927,9 @@ function convertPMParagraph(node, documentCounts, textBoxAnchorMarkers, styleRes
822
927
  if (listRendering) paragraph.listRendering = listRendering;
823
928
  if (attrs.renderedPageBreakBefore) paragraph.renderedPageBreakBefore = true;
824
929
  if (attrs._sectionProperties) paragraph.sectionProperties = attrs._sectionProperties;
825
- else if (attrs.sectionBreakType) paragraph.sectionProperties = { sectionStart: attrs.sectionBreakType };
826
930
  if (attrs._propertyChanges && attrs._propertyChanges.length > 0) paragraph.propertyChanges = attrs._propertyChanges.map(propertyChangeFromAttrs);
827
931
  if (attrs.pPrMark) paragraph.pPrMark = attrs.pPrMark;
932
+ if (attrs._preservedAttributes && attrs._preservedAttributes.length > 0) paragraph.preservedAttributes = attrs._preservedAttributes;
828
933
  linkParagraphPropertySourceCandidate(paragraph, node);
829
934
  return paragraph;
830
935
  }
@@ -842,7 +947,7 @@ const propertyChangeFromAttrs = (change) => {
842
947
  currentFormatting
843
948
  };
844
949
  const { numPr, ...previousWithoutNumPr } = previousFormatting;
845
- const normalizedPrevious = numPr === null || numPr === void 0 ? previousWithoutNumPr : {
950
+ const normalizedPrevious = numPr == null ? previousWithoutNumPr : {
846
951
  ...previousWithoutNumPr,
847
952
  numPr
848
953
  };
@@ -915,11 +1020,12 @@ function paragraphAttrsToFormatting(attrs) {
915
1020
  else Reflect.deleteProperty(result, "lineSpacingRule");
916
1021
  if (directAlignment === void 0) Reflect.deleteProperty(result, "alignment");
917
1022
  else result.alignment = directAlignment;
918
- if (isStyleSourcedParagraphNumbering(attrs.numPr, attrs.numPrFromStyle)) {
1023
+ const statedNumbering = attrs.numPr;
1024
+ if (isStyleSourcedParagraphNumbering(statedNumbering, attrs.numPrFromStyle)) {
919
1025
  delete result.numPr;
920
1026
  delete result.numPrFromStyle;
921
- } else if (attrs.numPr !== orig.numPr && !sameAuthoredParagraphNumberingReference(attrs.numPr, orig.numPr)) {
922
- if (attrs.numPr) result.numPr = attrs.numPr;
1027
+ } else if (!sameStatedParagraphNumbering$1(statedNumbering, orig.numPr)) {
1028
+ if (statedNumbering !== void 0) result.numPr = statedNumbering;
923
1029
  else delete result.numPr;
924
1030
  delete result.numPrFromStyle;
925
1031
  }
@@ -961,7 +1067,7 @@ function paragraphAttrsToFormatting(attrs) {
961
1067
  const kinsoku = authored("kinsoku", attrs.kinsoku);
962
1068
  const overflowPunctuation = authored("overflowPunctuation", attrs.overflowPunctuation);
963
1069
  const suppressAutoHyphens = authored("suppressAutoHyphens", attrs.suppressAutoHyphens);
964
- if (!(directAlignment !== void 0 || shouldSerializeSpaceBefore || shouldSerializeSpaceAfter || beforeAutospacingEdited || afterAutospacingEdited || hasDirectLineSpacing || hasDirectLineSpacingRule || snapToGrid != null || indentLeft || indentRight || indentFirstLine || attrs.numPr || attrs.styleId || borders || shading || tabs || typeof outlineLevel === "number" || contextualSpacing || attrs.spacingExplicit || bidi != null || pageBreakBefore != null || widowControl != null || keepNext != null || keepLines != null || runInWithNext != null || kinsoku != null || overflowPunctuation != null || suppressAutoHyphens != null)) return;
1070
+ if (!(directAlignment !== void 0 || shouldSerializeSpaceBefore || shouldSerializeSpaceAfter || beforeAutospacingEdited || afterAutospacingEdited || hasDirectLineSpacing || hasDirectLineSpacingRule || snapToGrid != null || indentLeft || indentRight || indentFirstLine || attrs.numPr || attrs.styleId || borders || shading || tabs || outlineLevel !== void 0 || contextualSpacing || attrs.spacingExplicit || bidi != null || pageBreakBefore != null || widowControl != null || keepNext != null || keepLines != null || runInWithNext != null || kinsoku != null || overflowPunctuation != null || suppressAutoHyphens != null)) return;
965
1071
  const f = {};
966
1072
  if (directAlignment !== void 0) f.alignment = directAlignment;
967
1073
  if (shouldSerializeSpaceBefore) f.spaceBefore = spaceBefore;
@@ -976,12 +1082,12 @@ function paragraphAttrsToFormatting(attrs) {
976
1082
  if (indentRight) f.indentRight = indentRight;
977
1083
  if (indentFirstLine) f.indentFirstLine = indentFirstLine;
978
1084
  if (attrs.hangingIndent && indentFirstLine) f.hangingIndent = attrs.hangingIndent;
979
- if (attrs.numPr && !isStyleSourcedParagraphNumbering(attrs.numPr, attrs.numPrFromStyle)) f.numPr = attrs.numPr;
1085
+ if (attrs.numPr !== void 0 && !isStyleSourcedParagraphNumbering(attrs.numPr, attrs.numPrFromStyle)) f.numPr = attrs.numPr;
980
1086
  if (attrs.styleId) f.styleId = attrs.styleId;
981
1087
  if (borders) f.borders = borders;
982
1088
  if (shading) f.shading = shading;
983
1089
  if (tabs) f.tabs = tabs;
984
- if (typeof outlineLevel === "number") f.outlineLevel = outlineLevel;
1090
+ if (outlineLevel !== void 0) f.outlineLevel = outlineLevel;
985
1091
  if (contextualSpacing) f.contextualSpacing = contextualSpacing;
986
1092
  if (bidi != null) f.bidi = bidi;
987
1093
  if (pageBreakBefore != null) f.pageBreakBefore = pageBreakBefore;
@@ -1017,6 +1123,70 @@ function createTrackedRunWrapper(type, info, child) {
1017
1123
  content
1018
1124
  };
1019
1125
  }
1126
+ /**
1127
+ * Comment ids in the order their markers are written at a shared boundary.
1128
+ *
1129
+ * Two ranges that begin or end at the same position have no order in the
1130
+ * editor, where each is a mark, so every emission site orders them by id: a
1131
+ * boundary written in the order the marks happened to open is a different
1132
+ * document each time the same one is saved.
1133
+ */
1134
+ const byCommentId = (ids) => [...ids].toSorted((a, b) => a - b);
1135
+ /** The wrappers `node` sits inside, outermost first; empty when it sits in none. */
1136
+ const inlineWrapperStackOf = (node) => {
1137
+ const mark = node.marks.find((candidate) => candidate.type.name === INLINE_WRAPPER_MARK_NAME);
1138
+ return mark ? expectInlineWrapperMarkAttrs(mark).stack : [];
1139
+ };
1140
+ const isRevisionWrapper = (item) => item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo";
1141
+ /** `stack` closed around `content`, outermost layer first. */
1142
+ const nestInlineWrappers = (stack, content) => {
1143
+ const innermost = stack.at(-1);
1144
+ if (innermost === void 0) panic("An inline wrapper group carries no layer");
1145
+ let wrapper = inlineWrapperMember(innermost, content);
1146
+ for (const layer of stack.slice(0, -1).toReversed()) wrapper = inlineWrapperMember(layer, [wrapper]);
1147
+ return wrapper;
1148
+ };
1149
+ /**
1150
+ * The emitted sequence with each wrapper group nested back into the wrappers
1151
+ * `toProseDoc` lifted off it.
1152
+ *
1153
+ * The revision stays outermost. folio already writes a revision outside the
1154
+ * hyperlink it spans, the parse leg is revision-owned, and accepting or
1155
+ * rejecting one is a range operation over the revision's own content; a
1156
+ * wrapper placed outside two revisions would also have to mint one revision id
1157
+ * per wrapper. So a revision in the group keeps its place and takes the nest
1158
+ * inside it, and the items around it share a nest of their own.
1159
+ *
1160
+ * A group with nothing in it writes no wrapper: an authored wrapper whose
1161
+ * content was deleted or rejected is gone, and an empty one says nothing.
1162
+ */
1163
+ const nestInlineWrapperGroups = (items, groups) => {
1164
+ const nested = [];
1165
+ for (const [index, group] of groups.entries()) {
1166
+ const slice = items.slice(group.start, groups[index + 1]?.start ?? items.length);
1167
+ if (group.stack.length === 0) {
1168
+ nested.push(...slice);
1169
+ continue;
1170
+ }
1171
+ let pending = [];
1172
+ const closeNest = () => {
1173
+ if (pending.length === 0) return;
1174
+ nested.push(nestInlineWrappers(group.stack, pending));
1175
+ pending = [];
1176
+ };
1177
+ for (const item of slice) {
1178
+ if (!isRevisionWrapper(item)) {
1179
+ pending.push(item);
1180
+ continue;
1181
+ }
1182
+ closeNest();
1183
+ if (item.content.length > 0) item.content = [nestInlineWrappers(group.stack, item.content)];
1184
+ nested.push(item);
1185
+ }
1186
+ closeNest();
1187
+ }
1188
+ return nested;
1189
+ };
1020
1190
  function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, textBoxAnchorMarkers, skipLeadingRenderedPageBreak = false, inheritedFormattingOverride) {
1021
1191
  const content = [];
1022
1192
  const paragraphStyleContext = paragraph.type.name === "paragraph" ? paragraphRunStyleContext(paragraph) : void 0;
@@ -1033,6 +1203,11 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1033
1203
  })).toSorted((left, right) => left.attrs.offset - right.attrs.offset || left.order - right.order);
1034
1204
  let nextEmptyHyperlink = 0;
1035
1205
  let leadingRenderedPageBreakPending = skipLeadingRenderedPageBreak;
1206
+ const wrapperGroups = [{
1207
+ start: 0,
1208
+ stack: []
1209
+ }];
1210
+ let wrapperGroupKey = "";
1036
1211
  let currentRun = null;
1037
1212
  let currentMarksKey = null;
1038
1213
  let currentHyperlink = null;
@@ -1058,7 +1233,7 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1058
1233
  };
1059
1234
  const appendDirectRun = (node, run, coalescePlainText = false) => {
1060
1235
  const marksKey = getMarksKey(node.marks);
1061
- const ownerId = pageBreakRunOwnerId(node);
1236
+ const ownerId = runIdentityId(node);
1062
1237
  const currentOwnerId = currentRun ? sourceRunOwners.get(currentRun) : void 0;
1063
1238
  const currentRunIsPlainText = currentRun?.content.every((runContent) => runContent.type === "text");
1064
1239
  const joinsOwnedSourceRun = ownerId !== void 0 && ownerId === currentOwnerId && currentRun !== null && runsShareProperties(currentRun, run);
@@ -1086,14 +1261,14 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1086
1261
  if (toClose.length === 0 && toOpen.length === 0) return;
1087
1262
  flushCurrentInline();
1088
1263
  currentTrackedChange = void 0;
1089
- for (const commentId of toClose.toSorted((a, b) => a - b)) {
1264
+ for (const commentId of byCommentId(toClose)) {
1090
1265
  content.push({
1091
1266
  type: "commentRangeEnd",
1092
1267
  id: commentId
1093
1268
  });
1094
1269
  openedComments.delete(commentId);
1095
1270
  }
1096
- for (const commentId of toOpen.toSorted((a, b) => a - b)) {
1271
+ for (const commentId of byCommentId(toOpen)) {
1097
1272
  content.push({
1098
1273
  type: "commentRangeStart",
1099
1274
  id: commentId
@@ -1111,13 +1286,58 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1111
1286
  content.push(createEmptyHyperlink(item.attrs));
1112
1287
  }
1113
1288
  };
1289
+ /**
1290
+ * Cut the emitted sequence where the wrapper the nodes sit inside changes.
1291
+ *
1292
+ * Nothing that spans nodes may span the cut: a run, a hyperlink and a
1293
+ * revision each sit inside one wrapper or outside it, never half in. The
1294
+ * comment ranges `syncCommentRanges` writes are cut with the rest, which
1295
+ * puts a range that opens or closes inside a wrapper inside it, as Word
1296
+ * writes it; a range marker says the same thing at either level, because the
1297
+ * wrapper is transparent and the position is unchanged.
1298
+ */
1299
+ const enterWrapperGroup = (node) => {
1300
+ const stack = inlineWrapperStackOf(node);
1301
+ const key = inlineWrapperStackKey(stack);
1302
+ if (key === wrapperGroupKey) return;
1303
+ flushCurrentInline();
1304
+ currentTrackedChange = void 0;
1305
+ wrapperGroupKey = key;
1306
+ wrapperGroups.push({
1307
+ start: content.length,
1308
+ stack
1309
+ });
1310
+ };
1114
1311
  const processInlineNode = (node, offset) => {
1115
1312
  if (node.type.name === "renderedPageBreak" && leadingRenderedPageBreakPending) {
1116
1313
  leadingRenderedPageBreakPending = false;
1117
1314
  return;
1118
1315
  }
1119
1316
  leadingRenderedPageBreakPending = false;
1317
+ enterWrapperGroup(node);
1120
1318
  syncCommentRanges(node, offset);
1319
+ if (node.type.name === "commentReference") {
1320
+ flushCurrentInline();
1321
+ currentTrackedChange = void 0;
1322
+ content.push({
1323
+ type: "commentReference",
1324
+ id: expectCommentReferenceAttrs(node).commentId
1325
+ });
1326
+ return;
1327
+ }
1328
+ if (node.type.name === "rangeAnchor") {
1329
+ flushCurrentInline();
1330
+ currentTrackedChange = void 0;
1331
+ const { start, end } = expectRangeAnchorAttrs(node);
1332
+ content.push({ ...start }, { ...end });
1333
+ return;
1334
+ }
1335
+ if (node.type.name === "moveRangeBoundary") {
1336
+ flushCurrentInline();
1337
+ currentTrackedChange = void 0;
1338
+ content.push({ ...expectMoveRangeBoundaryAttrs(node) });
1339
+ return;
1340
+ }
1121
1341
  const linkMark = node.marks.find((m) => m.type.name === "hyperlink");
1122
1342
  const noteRefMark = node.marks.find((m) => m.type.name === "footnoteRef");
1123
1343
  const insertionMark = node.marks.find((m) => m.type.name === "insertion");
@@ -1210,6 +1430,10 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1210
1430
  });
1211
1431
  return;
1212
1432
  }
1433
+ if (isInlineLevelPreservedXml(node)) {
1434
+ currentTrackedChange.hyperlink.children.push(createPreservedInline(node));
1435
+ return;
1436
+ }
1213
1437
  const run = createTrackedChangeRun({
1214
1438
  ...formattingContext,
1215
1439
  marks: otherMarks,
@@ -1228,20 +1452,7 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1228
1452
  };
1229
1453
  }
1230
1454
  if (node.type.name === "bookmarkBoundary") {
1231
- const attrs = expectBookmarkBoundaryAttrs(node);
1232
- const boundary = attrs.type === "start" ? {
1233
- type: "bookmarkStart",
1234
- id: attrs.id,
1235
- name: attrs.name,
1236
- ...attrs.colFirst !== void 0 ? { colFirst: attrs.colFirst } : {},
1237
- ...attrs.colLast !== void 0 ? { colLast: attrs.colLast } : {},
1238
- ...bookmarkBoundaryDisplacement(attrs)
1239
- } : {
1240
- type: "bookmarkEnd",
1241
- id: attrs.id,
1242
- ...bookmarkBoundaryDisplacement(attrs)
1243
- };
1244
- currentTrackedChange.wrapper.content.push(boundary);
1455
+ currentTrackedChange.wrapper.content.push(bookmarkMarkerFromAttrs(expectBookmarkBoundaryAttrs(node)));
1245
1456
  return;
1246
1457
  }
1247
1458
  if (node.type.name === "field" || node.type.name === "structuredField") {
@@ -1256,6 +1467,10 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1256
1467
  currentTrackedChange.wrapper.content.push(createMathFromNode(node));
1257
1468
  return;
1258
1469
  }
1470
+ if (isInlineLevelPreservedXml(node)) {
1471
+ currentTrackedChange.wrapper.content.push(createPreservedInline(node));
1472
+ return;
1473
+ }
1259
1474
  const run = createTrackedChangeRun({
1260
1475
  ...formattingContext,
1261
1476
  marks: otherMarks,
@@ -1264,7 +1479,7 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1264
1479
  if (run) appendRunToTrackedWrapper(currentTrackedChange.wrapper, run, node, sourceRunOwners);
1265
1480
  return;
1266
1481
  }
1267
- const ownedRun = linkMark || pageBreakRunOwnerId(node) === void 0 ? null : createTrackedChangeRun({
1482
+ const ownedRun = linkMark || runIdentityId(node) === void 0 ? null : createTrackedChangeRun({
1268
1483
  ...formattingContext,
1269
1484
  marks: node.marks,
1270
1485
  node
@@ -1296,20 +1511,7 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1296
1511
  if (currentHyperlink) flushCurrentInline();
1297
1512
  if (node.type.name === "bookmarkBoundary") {
1298
1513
  flushCurrentInline();
1299
- const attrs = expectBookmarkBoundaryAttrs(node);
1300
- if (attrs.type === "start") content.push({
1301
- type: "bookmarkStart",
1302
- id: attrs.id,
1303
- name: attrs.name,
1304
- ...attrs.colFirst !== void 0 ? { colFirst: attrs.colFirst } : {},
1305
- ...attrs.colLast !== void 0 ? { colLast: attrs.colLast } : {},
1306
- ...bookmarkBoundaryDisplacement(attrs)
1307
- });
1308
- else content.push({
1309
- type: "bookmarkEnd",
1310
- id: attrs.id,
1311
- ...bookmarkBoundaryDisplacement(attrs)
1312
- });
1514
+ content.push(bookmarkMarkerFromAttrs(expectBookmarkBoundaryAttrs(node)));
1313
1515
  } else if (node.isText) appendDirectRun(node, createRunFromText({
1314
1516
  ...formattingContext,
1315
1517
  marks: node.marks,
@@ -1325,6 +1527,9 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1325
1527
  } else if (node.type.name === "symbol") {
1326
1528
  flushCurrentInline();
1327
1529
  content.push(createSymbolRun(node, node.marks, formattingContext));
1530
+ } else if (node.type.name === "preservedXml") {
1531
+ flushCurrentInline();
1532
+ content.push(isInlineLevelPreservedXml(node) ? createPreservedInline(node) : createPreservedXmlRun(node, node.marks, formattingContext));
1328
1533
  } else if (node.type.name === "hardBreak") {
1329
1534
  flushCurrentInline();
1330
1535
  content.push(createBreakRun(expectHardBreakAttrs(node), node.marks, formattingContext));
@@ -1379,11 +1584,11 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1379
1584
  });
1380
1585
  flushEmptyHyperlinksThroughOffset(Number.POSITIVE_INFINITY);
1381
1586
  flushCurrentInline();
1382
- for (const commentId of openedComments) content.push({
1587
+ for (const commentId of byCommentId(openedComments)) content.push({
1383
1588
  type: "commentRangeEnd",
1384
1589
  id: commentId
1385
1590
  });
1386
- return content;
1591
+ return nestInlineWrapperGroups(content, wrapperGroups);
1387
1592
  }
1388
1593
  function createTrackedChangeRun({ baseParagraphFormatting, inheritedFormatting, marks, node, paragraphMarkFormatting, paragraphMarkPrecedesStyle, styleResolver }) {
1389
1594
  const formattingContext = {
@@ -1406,8 +1611,9 @@ function createTrackedChangeRun({ baseParagraphFormatting, inheritedFormatting,
1406
1611
  }] : [],
1407
1612
  ...Object.keys(formatting).length > 0 ? { formatting } : {}
1408
1613
  };
1409
- restoreRunPropertyChanges(run, marks);
1614
+ restoreRunRecord(run, marks);
1410
1615
  } else if (node.type.name === "symbol") run = createSymbolRun(node, marks, formattingContext);
1616
+ else if (node.type.name === "preservedXml") run = createPreservedXmlRun(node, marks, formattingContext);
1411
1617
  else if (node.type.name === "hardBreak") run = createBreakRun(expectHardBreakAttrs(node), marks, formattingContext);
1412
1618
  else if (node.type.name === "pageBreakRun") {
1413
1619
  const { clear } = expectPageBreakRunAttrs(node);
@@ -1420,11 +1626,11 @@ function createTrackedChangeRun({ baseParagraphFormatting, inheritedFormatting,
1420
1626
  else if (node.type.name === "shape") run = createShapeRun(node);
1421
1627
  else if (node.type.name === "tab") run = createTabRun(node, marks, formattingContext);
1422
1628
  else if (node.type.name === "renderedPageBreak") run = createRenderedPageBreakRun();
1423
- if (!run || pageBreakRunOwnerId(node) === void 0) return run;
1629
+ if (!run || runIdentityId(node) === void 0) return run;
1424
1630
  if (node.type.name === "image" || node.type.name === "shape" || node.type.name === "renderedPageBreak") {
1425
1631
  const formatting = getRunFormattingFromMarks(marks, formattingContext);
1426
1632
  if (formatting) run.formatting = formatting;
1427
- restoreRunPropertyChanges(run, marks);
1633
+ restoreRunRecord(run, marks);
1428
1634
  }
1429
1635
  return run;
1430
1636
  }
@@ -1515,20 +1721,7 @@ function createHyperlink(linkMark) {
1515
1721
  }
1516
1722
  function addNodeToHyperlink({ baseParagraphFormatting, hyperlink, inheritedFormatting, node, paragraphMarkFormatting, paragraphMarkPrecedesStyle, sourceRunOwners, styleResolver }) {
1517
1723
  if (node.type.name === "bookmarkBoundary") {
1518
- const attrs = expectBookmarkBoundaryAttrs(node);
1519
- if (attrs.type === "start") hyperlink.children.push({
1520
- type: "bookmarkStart",
1521
- id: attrs.id,
1522
- name: attrs.name,
1523
- ...attrs.colFirst !== void 0 ? { colFirst: attrs.colFirst } : {},
1524
- ...attrs.colLast !== void 0 ? { colLast: attrs.colLast } : {},
1525
- ...bookmarkBoundaryDisplacement(attrs)
1526
- });
1527
- else hyperlink.children.push({
1528
- type: "bookmarkEnd",
1529
- id: attrs.id,
1530
- ...bookmarkBoundaryDisplacement(attrs)
1531
- });
1724
+ hyperlink.children.push(bookmarkMarkerFromAttrs(expectBookmarkBoundaryAttrs(node)));
1532
1725
  return;
1533
1726
  }
1534
1727
  const formattingContext = {
@@ -1539,7 +1732,7 @@ function addNodeToHyperlink({ baseParagraphFormatting, hyperlink, inheritedForma
1539
1732
  styleResolver
1540
1733
  };
1541
1734
  const nonLinkMarks = node.marks.filter((mark) => mark.type.name !== "hyperlink");
1542
- const ownedRun = pageBreakRunOwnerId(node) === void 0 ? null : createTrackedChangeRun({
1735
+ const ownedRun = runIdentityId(node) === void 0 ? null : createTrackedChangeRun({
1543
1736
  ...formattingContext,
1544
1737
  marks: nonLinkMarks,
1545
1738
  node
@@ -1582,6 +1775,16 @@ function addNodeToHyperlink({ baseParagraphFormatting, hyperlink, inheritedForma
1582
1775
  }));
1583
1776
  return;
1584
1777
  }
1778
+ if (node.type.name === "preservedXml") {
1779
+ hyperlink.children.push(isInlineLevelPreservedXml(node) ? createPreservedInline(node) : createPreservedXmlRun(node, nonLinkMarks, {
1780
+ baseParagraphFormatting,
1781
+ inheritedFormatting,
1782
+ paragraphMarkFormatting,
1783
+ paragraphMarkPrecedesStyle,
1784
+ styleResolver
1785
+ }));
1786
+ return;
1787
+ }
1585
1788
  if (node.type.name === "hardBreak") {
1586
1789
  hyperlink.children.push(createBreakRun(expectHardBreakAttrs(node), nonLinkMarks, {
1587
1790
  baseParagraphFormatting,
@@ -1642,7 +1845,7 @@ function createNoteReferenceRun(noteRefMark, marks, formattingContext) {
1642
1845
  ...formatting,
1643
1846
  vertAlign
1644
1847
  };
1645
- restoreRunPropertyChanges(run, marks);
1848
+ restoreRunRecord(run, marks);
1646
1849
  return run;
1647
1850
  }
1648
1851
  function createRunFromText({ baseParagraphFormatting, inheritedFormatting, marks, paragraphMarkFormatting, paragraphMarkPrecedesStyle, styleResolver, text }) {
@@ -1661,7 +1864,7 @@ function createRunFromText({ baseParagraphFormatting, inheritedFormatting, marks
1661
1864
  }]
1662
1865
  };
1663
1866
  if (formatting) run.formatting = formatting;
1664
- restoreRunPropertyChanges(run, marks);
1867
+ restoreRunRecord(run, marks);
1665
1868
  return run;
1666
1869
  }
1667
1870
  function createSymbolRun(node, marks, formattingContext) {
@@ -1676,15 +1879,77 @@ function createSymbolRun(node, marks, formattingContext) {
1676
1879
  };
1677
1880
  const formatting = getAtomRunFormattingFromMarks(marks, formattingContext);
1678
1881
  if (formatting) run.formatting = formatting;
1679
- restoreRunPropertyChanges(run, marks);
1882
+ restoreRunRecord(run, marks);
1680
1883
  return run;
1681
1884
  }
1682
- function restoreRunPropertyChanges(run, marks) {
1885
+ /**
1886
+ * Whether the atom's markup is a paragraph child rather than a run child.
1887
+ *
1888
+ * The two are the same node in the editor and different elements in the file:
1889
+ * `w:ruby` has to go back inside a `w:r` and `w:permStart` may not, because
1890
+ * the schema admits no such child of a run and Word reports the package as
1891
+ * unreadable content.
1892
+ */
1893
+ const isInlineLevelPreservedXml = (node) => node.type.name === "preservedXml" && expectPreservedXmlAttrs(node).level === PRESERVED_XML_LEVELS.inline;
1894
+ /** The paragraph-level capture an inline-level atom writes back. */
1895
+ const createPreservedInline = (node) => {
1896
+ const { xml, text } = expectPreservedXmlAttrs(node);
1897
+ return {
1898
+ type: "preservedInline",
1899
+ xml,
1900
+ text
1901
+ };
1902
+ };
1903
+ /**
1904
+ * Rebuild the run around a preserved child. The markup is opaque and comes
1905
+ * back byte for byte; only the run properties around it are rebuilt from the
1906
+ * atom's marks, exactly as for a symbol.
1907
+ */
1908
+ function createPreservedXmlRun(node, marks, formattingContext) {
1909
+ const { xml, text } = expectPreservedXmlAttrs(node);
1910
+ const run = {
1911
+ type: "run",
1912
+ content: [{
1913
+ type: "preservedXml",
1914
+ xml,
1915
+ text
1916
+ }]
1917
+ };
1918
+ const formatting = getAtomRunFormattingFromMarks(marks, formattingContext);
1919
+ if (formatting) run.formatting = formatting;
1920
+ restoreRunRecord(run, marks);
1921
+ return run;
1922
+ }
1923
+ /**
1924
+ * Put back everything about the authored `w:r` that the marks still carry:
1925
+ * its property revision, its attribute remainder and its `w:rPr` sink.
1926
+ *
1927
+ * One helper for the three, called at every site that builds a run, because a
1928
+ * site that restored two of them would write a `w:r` that has lost the third
1929
+ * without anything saying so. A leaf with no identity mark produces a run with
1930
+ * neither remainder nor sink, which is what typed text is.
1931
+ */
1932
+ function restoreRunRecord(run, marks) {
1683
1933
  const changeMark = marks.find((mark) => mark.type.name === "runPropertyChange");
1684
- if (!changeMark) return;
1685
- const { changes } = expectRunPropertyChangeMarkAttrs(changeMark);
1686
- if (changes.length === 0) return;
1687
- run.propertyChanges = [...changes];
1934
+ if (changeMark) {
1935
+ const { changes } = expectRunPropertyChangeMarkAttrs(changeMark);
1936
+ if (changes.length > 0) run.propertyChanges = [...changes];
1937
+ }
1938
+ const identityMark = marks.find((mark) => mark.type.name === RUN_IDENTITY_MARK_NAME);
1939
+ if (!identityMark) return;
1940
+ const { preservedAttributes, preserved } = expectRunIdentityMarkAttrs(identityMark);
1941
+ if (preservedAttributes && preservedAttributes.length > 0) run.preservedAttributes = preservedAttributes.map(({ namespace, name, value }) => namespace === void 0 ? {
1942
+ name,
1943
+ value
1944
+ } : {
1945
+ namespace,
1946
+ name,
1947
+ value
1948
+ });
1949
+ if (preserved && (preserved.children?.length ?? 0) > 0) run.formatting = {
1950
+ ...run.formatting,
1951
+ preserved
1952
+ };
1688
1953
  }
1689
1954
  function getRunFormattingFromMarks(marks, options) {
1690
1955
  if (!marks || marks.length === 0 && !options) return;
@@ -1715,17 +1980,25 @@ function runsShareProperties(left, right) {
1715
1980
  propertyChanges: right.propertyChanges
1716
1981
  });
1717
1982
  }
1718
- function pageBreakRunOwnerId(node) {
1719
- const mark = node.marks.find(({ type }) => type.name === "pageBreakRunOwner");
1720
- return mark ? expectPageBreakRunOwnerMarkAttrs(mark).id : void 0;
1983
+ /**
1984
+ * The authored `w:r` this leaf came from, when it names one.
1985
+ *
1986
+ * Two leaves that share an id are two pieces of one authored run — the cut a
1987
+ * page-break atom makes — and the save leg rejoins them. Two leaves with
1988
+ * different ids are two runs however alike their formatting, which is what
1989
+ * keeps both sides' `w:rsid*` alive across a paragraph the editor rebuilt.
1990
+ */
1991
+ function runIdentityId(node) {
1992
+ const mark = node.marks.find(({ type }) => type.name === RUN_IDENTITY_MARK_NAME);
1993
+ return mark ? expectRunIdentityMarkAttrs(mark).id : void 0;
1721
1994
  }
1722
1995
  function canJoinOwnedRuns(previous, run, node, sourceRunOwners) {
1723
1996
  if (!previous || !runsShareProperties(previous, run)) return false;
1724
- const ownerId = pageBreakRunOwnerId(node);
1997
+ const ownerId = runIdentityId(node);
1725
1998
  return ownerId !== void 0 && sourceRunOwners.get(previous) === ownerId;
1726
1999
  }
1727
2000
  function rememberSourceRunOwner(run, node, sourceRunOwners) {
1728
- const ownerId = pageBreakRunOwnerId(node);
2001
+ const ownerId = runIdentityId(node);
1729
2002
  if (ownerId !== void 0) sourceRunOwners.set(run, ownerId);
1730
2003
  }
1731
2004
  function appendRunToTrackedWrapper(wrapper, run, node, sourceRunOwners) {
@@ -1763,7 +2036,7 @@ function createPageBreakCarrierRun({ baseParagraphFormatting, clear, inheritedFo
1763
2036
  styleResolver
1764
2037
  });
1765
2038
  if (formatting) run.formatting = formatting;
1766
- if (marks) restoreRunPropertyChanges(run, marks);
2039
+ if (marks) restoreRunRecord(run, marks);
1767
2040
  return run;
1768
2041
  }
1769
2042
  /**
@@ -1780,7 +2053,7 @@ function createBreakRun(attrs, marks, formattingContext) {
1780
2053
  };
1781
2054
  const formatting = getAtomRunFormattingFromMarks(marks, formattingContext);
1782
2055
  if (formatting) run.formatting = formatting;
1783
- if (marks) restoreRunPropertyChanges(run, marks);
2056
+ if (marks) restoreRunRecord(run, marks);
1784
2057
  return run;
1785
2058
  }
1786
2059
  function createRenderedPageBreakRun() {
@@ -1803,7 +2076,7 @@ function createTabRun(node, marks, formattingContext) {
1803
2076
  };
1804
2077
  const formatting = getAtomRunFormattingFromMarks(marks, formattingContext);
1805
2078
  if (formatting) run.formatting = formatting;
1806
- if (marks) restoreRunPropertyChanges(run, marks);
2079
+ if (marks) restoreRunRecord(run, marks);
1807
2080
  return run;
1808
2081
  }
1809
2082
  function createFieldFromNode(node, { baseParagraphFormatting, inheritedFormatting, marks, paragraphMarkFormatting, paragraphMarkPrecedesStyle, styleResolver, textBoxAnchorMarkers }) {
@@ -1821,7 +2094,7 @@ function createFieldFromNode(node, { baseParagraphFormatting, inheritedFormattin
1821
2094
  paragraphMarkFormatting,
1822
2095
  paragraphMarkPrecedesStyle: paragraphMarkPrecedesStyle ?? false,
1823
2096
  styleResolver: styleResolver ?? null
1824
- }).filter((content) => content.type === "run" || content.type === "hyperlink");
2097
+ }).filter(isSimpleFieldContent);
1825
2098
  const displayText = attrs.displayText ?? "";
1826
2099
  const displayRun = {
1827
2100
  type: "run",
@@ -1831,7 +2104,7 @@ function createFieldFromNode(node, { baseParagraphFormatting, inheritedFormattin
1831
2104
  }],
1832
2105
  ...formatting && Object.keys(formatting).length > 0 ? { formatting } : {}
1833
2106
  };
1834
- if (marks && node.type.name === "field") restoreRunPropertyChanges(displayRun, marks);
2107
+ if (marks && node.type.name === "field") restoreRunRecord(displayRun, marks);
1835
2108
  const fieldContent = extractedContent.length > 0 ? synchronizeFieldDisplayText(extractedContent, displayText, displayRun) : [];
1836
2109
  const fallbackFieldContent = displayText ? [displayRun] : [];
1837
2110
  if (attrs.fieldKind === "complex") {
@@ -1842,8 +2115,8 @@ function createFieldFromNode(node, { baseParagraphFormatting, inheritedFormattin
1842
2115
  fieldCode: [],
1843
2116
  fieldResult: fieldContent.length > 0 ? fieldContent.filter((content) => content.type === "run") : fallbackFieldContent
1844
2117
  };
1845
- if (attrs.fldLock) complex.fldLock = true;
1846
- if (attrs.dirty) complex.dirty = true;
2118
+ if (attrs.fldLock !== void 0) complex.fldLock = attrs.fldLock;
2119
+ if (attrs.dirty !== void 0) complex.dirty = attrs.dirty;
1847
2120
  return complex;
1848
2121
  }
1849
2122
  const simple = {
@@ -1852,21 +2125,24 @@ function createFieldFromNode(node, { baseParagraphFormatting, inheritedFormattin
1852
2125
  fieldType: attrs.fieldType,
1853
2126
  content: fieldContent.length > 0 ? fieldContent : fallbackFieldContent
1854
2127
  };
1855
- if (attrs.fldLock) simple.fldLock = true;
1856
- if (attrs.dirty) simple.dirty = true;
2128
+ if (attrs.fldLock !== void 0) simple.fldLock = attrs.fldLock;
2129
+ if (attrs.dirty !== void 0) simple.dirty = attrs.dirty;
1857
2130
  return simple;
1858
2131
  }
1859
2132
  const synchronizeFieldDisplayText = (content, displayText, fallbackRun) => {
1860
2133
  let currentText = "";
1861
- const visitRuns = (visit) => {
1862
- for (const child of content) {
2134
+ const visitRunsIn = (items, visit) => {
2135
+ for (const child of items) {
1863
2136
  if (child.type === "run") {
1864
2137
  visit(child);
1865
2138
  continue;
1866
2139
  }
1867
- for (const hyperlinkChild of child.children) if (hyperlinkChild.type === "run") visit(hyperlinkChild);
2140
+ if (child.type === "hyperlink" || child.type === "inlineWrapper") visitRunsIn(child.type === "hyperlink" ? child.children : child.content, visit);
1868
2141
  }
1869
2142
  };
2143
+ const visitRuns = (visit) => {
2144
+ visitRunsIn(content, visit);
2145
+ };
1870
2146
  visitRuns((run) => {
1871
2147
  for (const runContent of run.content) if (runContent.type === "text") currentText += runContent.text;
1872
2148
  });
@@ -1903,14 +2179,42 @@ function createMathFromNode(node) {
1903
2179
  return math;
1904
2180
  }
1905
2181
  /**
2182
+ * A revision covering every child of a control, written around the control.
2183
+ *
2184
+ * `w:ins > w:sdt` and `w:sdt > w:ins` reach the editor as the same revision
2185
+ * mark on the same leaves, so the save leg has to pick one and writes the
2186
+ * canonical order: the revision outermost, as it already is around a hyperlink
2187
+ * and around a transparent wrapper. Outermost is also the only form in which
2188
+ * accepting or rejecting the change is an operation over the whole control —
2189
+ * the reader who inserted a bound field inserted the field, not its text.
2190
+ *
2191
+ * A revision that covers only part of the content has no such form and stays
2192
+ * where the editor holds it, per child.
2193
+ */
2194
+ const hoistUniformRevision = (sdt) => {
2195
+ const only = sdt.content.length === 1 ? sdt.content.at(0) : void 0;
2196
+ if (only === void 0 || !isRevisionWrapper(only)) return sdt;
2197
+ const admitted = only.content.filter(isInlineSdtContent);
2198
+ if (admitted.length !== only.content.length) return sdt;
2199
+ return {
2200
+ ...only,
2201
+ content: [{
2202
+ ...sdt,
2203
+ content: admitted
2204
+ }]
2205
+ };
2206
+ };
2207
+ /**
1906
2208
  * Create an InlineSdt from a PM sdt node
1907
2209
  */
1908
2210
  function createInlineSdtFromNode(node, textBoxAnchorMarkers, formattingContext) {
1909
- return {
2211
+ const properties = sdtPropertiesFromAttrs(expectSdtAttrs(node));
2212
+ const content = extractParagraphContent(node, void 0, void 0, textBoxAnchorMarkers, false, formattingContext).filter(isInlineSdtContent);
2213
+ return hoistUniformRevision({
1910
2214
  type: "inlineSdt",
1911
- properties: sdtPropertiesFromAttrs(expectSdtAttrs(node)),
1912
- content: extractParagraphContent(node, void 0, void 0, textBoxAnchorMarkers, false, formattingContext).filter((c) => c.type === "run" || c.type === "hyperlink" || c.type === "simpleField" || c.type === "complexField" || c.type === "inlineSdt" || c.type === "insertion" || c.type === "deletion" || c.type === "moveFrom" || c.type === "moveTo" || c.type === "mathEquation")
1913
- };
2215
+ properties,
2216
+ content
2217
+ });
1914
2218
  }
1915
2219
  /**
1916
2220
  * Create a Run containing an image
@@ -1923,15 +2227,24 @@ function createInlineSdtFromNode(node, textBoxAnchorMarkers, formattingContext)
1923
2227
  * around one has no other record of the properties it was authored with.
1924
2228
  */
1925
2229
  const carriedRunFormatting = (formatting) => formatting && Object.keys(formatting).length > 0 ? { formatting } : {};
2230
+ /**
2231
+ * The anchor record off a node's attrs, copied so the model never aliases a
2232
+ * ProseMirror attribute object.
2233
+ */
2234
+ const restoredDrawingAnchor = (anchor) => anchor === void 0 ? void 0 : {
2235
+ ...anchor,
2236
+ ...anchor.simplePosition === void 0 ? {} : { simplePosition: { ...anchor.simplePosition } }
2237
+ };
1926
2238
  function createImageRun(node) {
1927
2239
  const attrs = expectImageAttrs(node);
1928
2240
  const wrap = { type: attrs.wrapType || "inline" };
1929
2241
  assignWrapDistances(wrap, attrs);
1930
2242
  if (attrs.wrapText) wrap.wrapText = attrs.wrapText;
1931
2243
  const authoredEmu = attrs._docxAuthoredEmu;
2244
+ const rId = relationshipIdOf(attrs.rId);
1932
2245
  const image = {
1933
2246
  type: "image",
1934
- rId: attrs.rId || "",
2247
+ ...rId === void 0 ? {} : { rId },
1935
2248
  src: attrs.src,
1936
2249
  size: {
1937
2250
  width: emuFromPixels(attrs.width || 0, "width", authoredEmu, emuToPixels),
@@ -1942,12 +2255,17 @@ function createImageRun(node) {
1942
2255
  if (attrs.docPrName != null) image.docPrName = attrs.docPrName;
1943
2256
  if (attrs.alt != null) image.alt = attrs.alt;
1944
2257
  if (attrs.title != null) image.title = attrs.title;
1945
- const imageTransform = parseTransformAttr(attrs.transform);
2258
+ const imageTransform = readAuthoredTransform(attrs);
1946
2259
  if (imageTransform) image.transform = imageTransform;
1947
2260
  if (attrs.opacity != null) image.opacity = attrs.opacity;
2261
+ if (attrs.brightness != null || attrs.contrast != null) image.effects = {
2262
+ ...attrs.brightness == null ? {} : { brightness: attrs.brightness },
2263
+ ...attrs.contrast == null ? {} : { contrast: attrs.contrast }
2264
+ };
1948
2265
  const imagePosition = imagePositionFromAttrs(attrs.position);
1949
2266
  if (imagePosition) image.position = imagePosition;
1950
- if (attrs.layoutInCell !== void 0) image.layoutInCell = attrs.layoutInCell;
2267
+ const imageAnchor = restoredDrawingAnchor(attrs.anchor);
2268
+ if (imageAnchor) image.anchor = imageAnchor;
1951
2269
  if (attrs.decorative !== void 0) image.decorative = attrs.decorative;
1952
2270
  if (attrs.hidden !== void 0) image.hidden = attrs.hidden;
1953
2271
  if (attrs.docPrExtensions !== void 0) image.docPrExtensions = [...attrs.docPrExtensions];
@@ -1955,21 +2273,15 @@ function createImageRun(node) {
1955
2273
  if (attrs.borderWidth && attrs.borderWidth > 0) {
1956
2274
  const outline = {
1957
2275
  width: emuFromPixels(attrs.borderWidth, "borderWidth", authoredEmu, emuToStrokePixels),
1958
- style: attrs.borderStyle ? {
1959
- solid: "solid",
1960
- dotted: "dot",
1961
- dashed: "dash",
1962
- double: "solid",
1963
- groove: "solid",
1964
- ridge: "solid",
1965
- inset: "solid",
1966
- outset: "solid"
1967
- }[attrs.borderStyle] || "solid" : "solid"
2276
+ dash: presetDashForCssBorderStyle(attrs.borderStyle)
1968
2277
  };
1969
2278
  if (attrs.borderColor) outline.color = { rgb: attrs.borderColor.replace("#", "") };
1970
2279
  image.outline = outline;
1971
2280
  }
1972
2281
  if (attrs.hlinkHref) image.hlinkHref = attrs.hlinkHref;
2282
+ if (attrs.docPrId !== void 0) image.id = attrs.docPrId;
2283
+ if (attrs.hlinkClickSource !== void 0) image.hlinkClickSource = { ...attrs.hlinkClickSource };
2284
+ if (attrs.hlinkHoverXml !== void 0) image.hlinkHoverXml = attrs.hlinkHoverXml;
1973
2285
  if (attrs.hlinkRId) image.hlinkRId = attrs.hlinkRId;
1974
2286
  const cropTop = attrs.cropTop != null && attrs.cropTop > 0 ? attrs.cropTop : void 0;
1975
2287
  const cropRight = attrs.cropRight != null && attrs.cropRight > 0 ? attrs.cropRight : void 0;
@@ -1992,11 +2304,13 @@ function createImageRun(node) {
1992
2304
  if (paddingLeft !== void 0) padding.left = paddingLeft;
1993
2305
  image.padding = padding;
1994
2306
  }
1995
- return {
2307
+ const run = {
1996
2308
  type: "run",
1997
2309
  ...carriedRunFormatting(attrs._docxRunFormatting),
1998
2310
  content: [drawingFromImageAttrs(image, attrs)]
1999
2311
  };
2312
+ restoreRunRecord(run, node.marks);
2313
+ return run;
2000
2314
  }
2001
2315
  /**
2002
2316
  * Rebuild the `DrawingContent` union member the image node came from.
@@ -2049,7 +2363,7 @@ function createShapeRun(node) {
2049
2363
  if (attrs.title !== void 0) shape.title = attrs.title;
2050
2364
  const geometryAdjustments = parseShapeGeometryAdjustments(attrs.geometryAdjustments);
2051
2365
  if (geometryAdjustments !== void 0) shape.geometryAdjustments = geometryAdjustments;
2052
- const shapeTransform = parseTransformAttr(attrs.transform);
2366
+ const shapeTransform = readAuthoredTransform(attrs);
2053
2367
  if (shapeTransform) shape.transform = shapeTransform;
2054
2368
  const wrap = { type: attrs.wrapType || "inline" };
2055
2369
  assignWrapDistances(wrap, attrs);
@@ -2057,6 +2371,8 @@ function createShapeRun(node) {
2057
2371
  shape.wrap = wrap;
2058
2372
  const shapePosition = imagePositionFromAttrs(attrs.position);
2059
2373
  if (shapePosition) shape.position = shapePosition;
2374
+ const shapeAnchor = restoredDrawingAnchor(attrs.anchor);
2375
+ if (shapeAnchor) shape.anchor = shapeAnchor;
2060
2376
  if (attrs.fillType === "gradient" && attrs.gradientStops) try {
2061
2377
  const parsed = JSON.parse(attrs.gradientStops);
2062
2378
  const gradient = {
@@ -2086,8 +2402,8 @@ function createShapeRun(node) {
2086
2402
  const shapeOutline = {};
2087
2403
  if (attrs.outlineWidth !== void 0 && attrs.outlineWidth > 0) shapeOutline.width = emuFromPixels(attrs.outlineWidth, "outlineWidth", authoredEmu, emuToStrokePixels);
2088
2404
  if (attrs.outlineStyle) {
2089
- const style = normalizeShapeOutlineStyle(attrs.outlineStyle);
2090
- if (style !== void 0) shapeOutline.style = style;
2405
+ const dash = normalizeShapeOutlineDash(attrs.outlineStyle);
2406
+ if (dash !== void 0) shapeOutline.dash = dash;
2091
2407
  }
2092
2408
  if (attrs.outlineCap) shapeOutline.cap = attrs.outlineCap;
2093
2409
  if (attrs.outlineJoin) shapeOutline.join = attrs.outlineJoin;
@@ -2100,11 +2416,13 @@ function createShapeRun(node) {
2100
2416
  type: "shape",
2101
2417
  shape
2102
2418
  };
2103
- return {
2419
+ const run = {
2104
2420
  type: "run",
2105
2421
  ...carriedRunFormatting(attrs._docxRunFormatting),
2106
2422
  content: [shapeContent]
2107
2423
  };
2424
+ restoreRunRecord(run, node.marks);
2425
+ return run;
2108
2426
  }
2109
2427
  const RUN_FORMATTING_VISUAL_GROUPS = {
2110
2428
  bold: "bold",
@@ -2138,7 +2456,8 @@ const RUN_FORMATTING_VISUAL_GROUPS = {
2138
2456
  shadow: "shadow",
2139
2457
  rtl: "rtl",
2140
2458
  cs: null,
2141
- styleId: null
2459
+ styleId: null,
2460
+ preserved: null
2142
2461
  };
2143
2462
  const RUN_FORMATTING_FAST_PATH_DISPOSITION = {
2144
2463
  bold: "visual",
@@ -2172,7 +2491,8 @@ const RUN_FORMATTING_FAST_PATH_DISPOSITION = {
2172
2491
  shadow: "visual",
2173
2492
  rtl: "visual",
2174
2493
  cs: "structural",
2175
- styleId: "character-style"
2494
+ styleId: "character-style",
2495
+ preserved: "structural"
2176
2496
  };
2177
2497
  const hasOnlyCarrierlessVisualFormatting = (formatting) => {
2178
2498
  for (const property of Object.keys(formatting)) if (RUN_FORMATTING_FAST_PATH_DISPOSITION[property] !== "visual") return false;
@@ -2706,7 +3026,7 @@ function convertPMTable(node, documentCounts, styleResolver = null) {
2706
3026
  rows
2707
3027
  };
2708
3028
  if (attrs.columnWidths) minTable.columnWidths = attrs.columnWidths;
2709
- restoreTablePropertyChanges(minTable, attrs);
3029
+ restoreCarriedTableAttrs(minTable, attrs);
2710
3030
  return minTable;
2711
3031
  }
2712
3032
  }
@@ -2716,16 +3036,22 @@ function convertPMTable(node, documentCounts, styleResolver = null) {
2716
3036
  };
2717
3037
  if (attrs.columnWidths) table.columnWidths = attrs.columnWidths;
2718
3038
  if (formatting && Object.keys(formatting).length > 0) table.formatting = formatting;
2719
- restoreTablePropertyChanges(table, attrs);
3039
+ restoreCarriedTableAttrs(table, attrs);
2720
3040
  return table;
2721
3041
  }
2722
3042
  /**
2723
- * Restore `w:tblPrChange` entries that PM carried opaquely on the table attrs
2724
- * (same rationale as the paragraph `_propertyChanges` attr): they must survive
2725
- * an edit so the saved DOCX keeps the tracked property-change history.
3043
+ * Restore what PM carried opaquely on the table attrs, on both paths out of
3044
+ * {@link convertPMTable}.
3045
+ *
3046
+ * `w:tblPrChange` (same rationale as the paragraph `_propertyChanges` attr)
3047
+ * must survive an edit so the saved DOCX keeps the tracked property-change
3048
+ * history, and the child sink must survive it so the markup the table held
3049
+ * beside its rows comes back between the same two.
2726
3050
  */
2727
- function restoreTablePropertyChanges(table, attrs) {
3051
+ function restoreCarriedTableAttrs(table, attrs) {
2728
3052
  if (Array.isArray(attrs.tblPrChange) && attrs.tblPrChange.length > 0) table.propertyChanges = [...attrs.tblPrChange];
3053
+ if (attrs._bookmarks && attrs._bookmarks.length > 0) table.bookmarks = attrs._bookmarks;
3054
+ if (hasSinkChildren(attrs._preserved)) table.preserved = attrs._preserved;
2729
3055
  }
2730
3056
  function convertPMTableRows(node, documentCounts, styleResolver = null) {
2731
3057
  const rows = [];
@@ -2836,10 +3162,15 @@ function convertPMTableRow(node, documentCounts, activeVerticalMerges, styleReso
2836
3162
  }
2837
3163
  };
2838
3164
  node.forEach((cellNode) => {
2839
- appendActiveVerticalMerges();
2840
3165
  if (cellNode.type.name === "tableCell" || cellNode.type.name === "tableHeader") {
2841
3166
  const cellAttrs = expectTableCellAttrs(cellNode);
2842
3167
  const colspan = Math.max(cellAttrs.colspan, 1);
3168
+ if (cellAttrs._omittedGridSlot) {
3169
+ if (!(cellNode.childCount === 1 && cellNode.child(0).type.name === "paragraph" && cellNode.child(0).content.size === 0)) panic("An omitted table grid slot acquired authored content");
3170
+ gridColumn += colspan;
3171
+ return;
3172
+ }
3173
+ appendActiveVerticalMerges();
2843
3174
  cells.push(convertPMTableCell(cellNode, documentCounts, styleResolver));
2844
3175
  if (cellAttrs.rowspan > 1) {
2845
3176
  const continuationCells = cellAttrs._docxVMergeContinuationCells !== void 0 && cellAttrs._docxVMergeContinuationCells !== null ? restoreTableCellsWithParagraphPropertySources(decodeTableCellParagraphSourcePayload(cellAttrs._docxVMergeContinuationCells)) : void 0;
@@ -2859,7 +3190,13 @@ function convertPMTableRow(node, documentCounts, activeVerticalMerges, styleReso
2859
3190
  };
2860
3191
  const rowFormatting = tableRowAttrsToFormatting(attrs);
2861
3192
  if (rowFormatting) row.formatting = rowFormatting;
3193
+ if (attrs._tablePropertyExceptions) row.tablePropertyExceptions = attrs._tablePropertyExceptions;
3194
+ if (Array.isArray(attrs.tblPrExChange) && attrs.tblPrExChange.length > 0) row.tablePropertyExceptionChanges = [...attrs.tblPrExChange];
2862
3195
  if (Array.isArray(attrs.trPrChange) && attrs.trPrChange.length > 0) row.propertyChanges = [...attrs.trPrChange];
3196
+ if (attrs._preservedAttributes && attrs._preservedAttributes.length > 0) row.preservedAttributes = attrs._preservedAttributes;
3197
+ if (attrs._bookmarks && attrs._bookmarks.length > 0) row.bookmarks = attrs._bookmarks;
3198
+ if (attrs.contentControls && attrs.contentControls.length > 0) row.contentControls = attrs.contentControls;
3199
+ if (hasSinkChildren(attrs._preserved)) row.preserved = attrs._preserved;
2863
3200
  if (attrs.trIns) row.structuralChange = {
2864
3201
  type: "tableRowInsertion",
2865
3202
  info: {
@@ -2916,11 +3253,11 @@ function tableRowAttrsToFormatting(attrs) {
2916
3253
  else delete result.heightRule;
2917
3254
  if (attrs.isHeader !== (orig.header ?? void 0)) if (attrs.isHeader) result.header = attrs.isHeader;
2918
3255
  else delete result.header;
2919
- if (attrs.hidden !== (orig.hidden ?? void 0)) if (attrs.hidden) result.hidden = attrs.hidden;
2920
- else delete result.hidden;
3256
+ if (attrs.hidden !== orig.hidden) if (attrs.hidden === void 0) delete result.hidden;
3257
+ else result.hidden = attrs.hidden;
2921
3258
  return result;
2922
3259
  }
2923
- if (!(attrs.height || attrs.isHeader || attrs.hidden)) return;
3260
+ if (!(attrs.height || attrs.isHeader || attrs.hidden !== void 0)) return;
2924
3261
  const f = {};
2925
3262
  if (attrs.height) f.height = {
2926
3263
  value: attrs.height,
@@ -2928,7 +3265,7 @@ function tableRowAttrsToFormatting(attrs) {
2928
3265
  };
2929
3266
  if (attrs.heightRule) f.heightRule = attrs.heightRule;
2930
3267
  if (attrs.isHeader) f.header = attrs.isHeader;
2931
- if (attrs.hidden) f.hidden = attrs.hidden;
3268
+ if (attrs.hidden !== void 0) f.hidden = attrs.hidden;
2932
3269
  return f;
2933
3270
  }
2934
3271
  /**
@@ -2952,6 +3289,16 @@ function convertPMTableCell(node, documentCounts, styleResolver = null) {
2952
3289
  textBoxAnchorMarkers,
2953
3290
  styleResolver
2954
3291
  });
3292
+ else if (contentNode.type.name === "preservedBlock") {
3293
+ content.push({
3294
+ type: "preservedBlock",
3295
+ xml: expectPreservedBlockAttrs(contentNode).xml
3296
+ });
3297
+ previousStandaloneTextBox = null;
3298
+ } else if (contentNode.type.name === "blockBookmarkBoundary") {
3299
+ content.push(blockBookmarkMarker(contentNode));
3300
+ previousStandaloneTextBox = null;
3301
+ }
2955
3302
  });
2956
3303
  removeUnresolvedTextBoxAnchors(content, textBoxAnchorMarkers);
2957
3304
  const cell = {
@@ -2961,6 +3308,7 @@ function convertPMTableCell(node, documentCounts, styleResolver = null) {
2961
3308
  const cellFormatting = tableCellAttrsToFormatting(attrs);
2962
3309
  if (cellFormatting) cell.formatting = cellFormatting;
2963
3310
  if (Array.isArray(attrs.tcPrChange) && attrs.tcPrChange.length > 0) cell.propertyChanges = [...attrs.tcPrChange];
3311
+ if (attrs.contentControls && attrs.contentControls.length > 0) cell.contentControls = attrs.contentControls;
2964
3312
  if (attrs.cellMarker) {
2965
3313
  const info = {
2966
3314
  id: attrs.cellMarker.info.revisionId,
@@ -2996,11 +3344,8 @@ function tableCellAttrsToFormatting(attrs) {
2996
3344
  else delete result.gridSpan;
2997
3345
  if (attrs.rowspan > 1) result.vMerge = "restart";
2998
3346
  else if (result.vMerge === "restart" && !attrs._preserveVMergeRestart) delete result.vMerge;
2999
- const cellWidth = attrs.width;
3000
- if (typeof cellWidth === "number") result.width = {
3001
- value: cellWidth,
3002
- type: attrs.widthType ?? "dxa"
3003
- };
3347
+ const authoredWidth = attrs._authoredWidth;
3348
+ if (authoredWidth) result.width = authoredWidth;
3004
3349
  else delete result.width;
3005
3350
  if (attrs.verticalAlign !== (orig.verticalAlign ?? void 0)) if (attrs.verticalAlign) result.verticalAlign = attrs.verticalAlign;
3006
3351
  else delete result.verticalAlign;
@@ -3011,15 +3356,12 @@ function tableCellAttrsToFormatting(attrs) {
3011
3356
  else delete result.textDirection;
3012
3357
  return result;
3013
3358
  }
3014
- const cellWidth = attrs.width;
3015
- if (!(attrs.colspan > 1 || attrs.rowspan > 1 || typeof cellWidth === "number" || attrs.verticalAlign || backgroundChanged || attrs.borders || attrs.margins || attrs.textDirection)) return;
3359
+ const authoredWidth = attrs._authoredWidth;
3360
+ if (!(attrs.colspan > 1 || attrs.rowspan > 1 || authoredWidth !== void 0 || attrs.verticalAlign || backgroundChanged || attrs.borders || attrs.margins || attrs.textDirection)) return;
3016
3361
  const f = {};
3017
3362
  if (attrs.colspan > 1) f.gridSpan = attrs.colspan;
3018
3363
  if (attrs.rowspan > 1) f.vMerge = "restart";
3019
- if (typeof cellWidth === "number") f.width = {
3020
- value: cellWidth,
3021
- type: attrs.widthType ?? "dxa"
3022
- };
3364
+ if (authoredWidth) f.width = authoredWidth;
3023
3365
  if (attrs.verticalAlign) f.verticalAlign = attrs.verticalAlign;
3024
3366
  if (attrs.textDirection) f.textDirection = attrs.textDirection;
3025
3367
  if (backgroundChanged) f.shading = cellShadingFromAttrs(attrs);
@@ -3086,7 +3428,7 @@ function convertPMTextBox(node, styleResolver = null) {
3086
3428
  if (attrs.textBoxName !== void 0) shape.name = attrs.textBoxName;
3087
3429
  if (attrs.alt !== void 0) shape.alt = attrs.alt;
3088
3430
  if (attrs.title !== void 0) shape.title = attrs.title;
3089
- const transform = parseTransformAttr(attrs.transform);
3431
+ const transform = readAuthoredTransform(attrs);
3090
3432
  if (transform) shape.transform = transform;
3091
3433
  if (attrs.fillColor) shape.fill = {
3092
3434
  type: "solid",
@@ -3095,7 +3437,7 @@ function convertPMTextBox(node, styleResolver = null) {
3095
3437
  if (attrs.outlineStyle !== "none" && attrs.outlineWidth && attrs.outlineWidth > 0) {
3096
3438
  const tbOutline = {
3097
3439
  width: emuFromPixels(attrs.outlineWidth, "outlineWidth", authoredEmu, emuToStrokePixels),
3098
- style: normalizeShapeOutlineStyle(attrs.outlineStyle) ?? "solid"
3440
+ dash: normalizeShapeOutlineDash(attrs.outlineStyle) ?? "solid"
3099
3441
  };
3100
3442
  if (attrs.outlineColor) tbOutline.color = { rgb: attrs.outlineColor.replace("#", "") };
3101
3443
  shape.outline = tbOutline;
@@ -3104,6 +3446,8 @@ function convertPMTextBox(node, styleResolver = null) {
3104
3446
  if (wrap) shape.wrap = wrap;
3105
3447
  const position = imagePositionFromAttrs(attrs.position);
3106
3448
  if (position) shape.position = position;
3449
+ const anchor = restoredDrawingAnchor(attrs.anchor);
3450
+ if (anchor) shape.anchor = anchor;
3107
3451
  const run = {
3108
3452
  type: "run",
3109
3453
  content: [{
@@ -3156,8 +3500,10 @@ function updateDocumentContent(originalDocument, pmDoc) {
3156
3500
  * Used for converting edited header/footer PM content back to the document
3157
3501
  * model.
3158
3502
  */
3159
- function proseDocToBlocks(pmDoc, baseContent, styles, options) {
3160
- const blocks = extractBlocks(pmDoc, "resolve", styles ? createStyleEngine(styles) : null, options?.emptyFieldResult ?? "serializerFallback");
3503
+ function proseDocToBlocks(pmDoc, baseContent, styles) {
3504
+ const blocks = extractBlocks(pmDoc, "resolve", styles ? createStyleEngine(styles) : null);
3505
+ joinCommentRangesAcrossParagraphs(blocks);
3506
+ completeCommentReferences(blocks);
3161
3507
  const linkedSources = restoreLinkedParagraphPropertySources(blocks);
3162
3508
  if (baseContent) restoreParagraphPropertySources(blocks, baseContent, linkedSources.targets, linkedSources.sources);
3163
3509
  return blocks;