@stll/folio-core 0.44.0 → 0.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/dist/ai-edits/__fixtures__/paragraphs.js +2 -2
  2. package/dist/ai-edits/apply.js +59 -19
  3. package/dist/ai-edits/headless.js +2 -1
  4. package/dist/compare/compare.js +2 -5
  5. package/dist/compare/content-alignment.js +78 -53
  6. package/dist/compare/inline-atoms.js +34 -20
  7. package/dist/compare/scenario.js +2 -5
  8. package/dist/compare/types.d.ts +9 -1
  9. package/dist/compare/types.js +12 -1
  10. package/dist/compat/eigenpal.d.ts +2 -1
  11. package/dist/compat/eigenpal.js +2 -1
  12. package/dist/content-controls/checkboxDisplay.d.ts +11 -0
  13. package/dist/content-controls/checkboxDisplay.js +40 -0
  14. package/dist/content-controls/findContentControls.js +3 -1
  15. package/dist/content-controls/mutateContentControls.js +21 -4
  16. package/dist/controller/contentControlWidgetController.d.ts +1 -0
  17. package/dist/controller/contentControlWidgetController.js +3 -0
  18. package/dist/controller/hiddenEditorApi.js +3 -1
  19. package/dist/controller/hiddenEditorManager.d.ts +1 -1
  20. package/dist/controller/hiddenEditorManager.js +6 -3
  21. package/dist/display-list/build/buildDisplayList.js +20 -1
  22. package/dist/display-list/build/imagePrimitives.d.ts +1 -1
  23. package/dist/display-list/build/imagePrimitives.js +3 -1
  24. package/dist/display-list/build/paragraphPrimitives.js +21 -2
  25. package/dist/display-list/dom/renderDisplayListToDom.js +18 -10
  26. package/dist/display-list/types.d.ts +17 -0
  27. package/dist/document-operations.js +14 -3
  28. package/dist/docx/attributeRemainder.d.ts +43 -0
  29. package/dist/docx/attributeRemainder.js +65 -0
  30. package/dist/docx/blockContentParser.d.ts +1 -1
  31. package/dist/docx/blockContentParser.js +87 -63
  32. package/dist/docx/blockPlainText.d.ts +3 -4
  33. package/dist/docx/blockPlainText.js +1 -0
  34. package/dist/docx/bookmarkPlacement.js +2 -0
  35. package/dist/docx/borderParser.js +5 -5
  36. package/dist/docx/commentAnchorIndex.d.ts +30 -0
  37. package/dist/docx/commentAnchorIndex.js +50 -0
  38. package/dist/docx/commentParser.d.ts +1 -1
  39. package/dist/docx/commentParser.js +78 -50
  40. package/dist/docx/commentRangeIntegrity.d.ts +16 -1
  41. package/dist/docx/commentRangeIntegrity.js +42 -1
  42. package/dist/docx/commentRangeJoin.d.ts +9 -0
  43. package/dist/docx/commentRangeJoin.js +33 -0
  44. package/dist/docx/commentReferenceCompletion.d.ts +9 -0
  45. package/dist/docx/commentReferenceCompletion.js +47 -0
  46. package/dist/docx/commentReferenceNormalization.js +1 -0
  47. package/dist/docx/commentReplyMarkers.js +11 -19
  48. package/dist/docx/commentThreadKey.d.ts +18 -0
  49. package/dist/docx/commentThreadKey.js +22 -0
  50. package/dist/docx/compatibility.js +1 -0
  51. package/dist/docx/containerChildren.d.ts +111 -0
  52. package/dist/docx/containerChildren.gen.d.ts +28 -0
  53. package/dist/docx/containerChildren.gen.js +246 -0
  54. package/dist/docx/containerChildren.js +103 -0
  55. package/dist/docx/diagramPreview.js +87 -27
  56. package/dist/docx/documentParser.d.ts +1 -1
  57. package/dist/docx/documentParser.js +3 -3
  58. package/dist/docx/ensureParaIds.js +17 -7
  59. package/dist/docx/fieldParser.d.ts +1 -1
  60. package/dist/docx/fieldParser.js +4 -4
  61. package/dist/docx/fieldState.d.ts +26 -0
  62. package/dist/docx/fieldState.js +53 -0
  63. package/dist/docx/footnoteParser.d.ts +1 -1
  64. package/dist/docx/graphicFrameLocks.d.ts +16 -4
  65. package/dist/docx/graphicFrameLocks.js +19 -6
  66. package/dist/docx/groupDrawingParser.js +3 -3
  67. package/dist/docx/headerFooterParser.js +1 -1
  68. package/dist/docx/headerFooterReferenceNormalization.js +1 -0
  69. package/dist/docx/hyperlinkParser.d.ts +27 -8
  70. package/dist/docx/hyperlinkParser.js +78 -20
  71. package/dist/docx/imageParser.d.ts +9 -1
  72. package/dist/docx/imageParser.js +91 -20
  73. package/dist/docx/imageRawXml.d.ts +14 -1
  74. package/dist/docx/imageRawXml.js +30 -6
  75. package/dist/docx/inlineWrapperContent.d.ts +85 -0
  76. package/dist/docx/inlineWrapperContent.js +84 -0
  77. package/dist/docx/mathToMathml.js +12 -14
  78. package/dist/docx/nonVisualDrawingProps.d.ts +34 -0
  79. package/dist/docx/nonVisualDrawingProps.js +46 -0
  80. package/dist/docx/normalizeBaseDirection.js +10 -1
  81. package/dist/docx/paraIdAttribute.d.ts +21 -0
  82. package/dist/docx/paraIdAttribute.js +64 -0
  83. package/dist/docx/paragraphParser.d.ts +1 -1
  84. package/dist/docx/paragraphParser.js +277 -168
  85. package/dist/docx/paragraphPropertySource.js +5 -1
  86. package/dist/docx/paragraphTextBoxEnrichment.d.ts +1 -1
  87. package/dist/docx/paragraphTextBoxEnrichment.js +9 -52
  88. package/dist/docx/paragraphTraversal.js +7 -4
  89. package/dist/docx/parseWarningMessage.js +2 -1
  90. package/dist/docx/parser.js +2 -2
  91. package/dist/docx/preservedRunContent.d.ts +32 -0
  92. package/dist/docx/preservedRunContent.js +86 -0
  93. package/dist/docx/previewBudget.d.ts +64 -0
  94. package/dist/docx/previewBudget.js +88 -0
  95. package/dist/docx/renderedPageBreakNormalization.js +2 -4
  96. package/dist/docx/revisionIdNormalization.js +17 -5
  97. package/dist/docx/rezip.js +91 -36
  98. package/dist/docx/runParser.d.ts +1 -1
  99. package/dist/docx/runParser.js +16 -12
  100. package/dist/docx/sdtPropertiesPatch.js +24 -18
  101. package/dist/docx/sectionParser.js +8 -1
  102. package/dist/docx/sectionReferenceHistory.js +2 -2
  103. package/dist/docx/selectiveSave.js +6 -6
  104. package/dist/docx/selectiveXmlPatch.d.ts +46 -2
  105. package/dist/docx/selectiveXmlPatch.js +86 -39
  106. package/dist/docx/serializer/blockSdtSerializer.js +38 -26
  107. package/dist/docx/serializer/borderSerializer.d.ts +1 -1
  108. package/dist/docx/serializer/borderSerializer.js +15 -14
  109. package/dist/docx/serializer/commentSerializer.d.ts +41 -16
  110. package/dist/docx/serializer/commentSerializer.js +87 -92
  111. package/dist/docx/serializer/documentSerializer.js +8 -11
  112. package/dist/docx/serializer/fontTableSerializer.js +6 -6
  113. package/dist/docx/serializer/headerFooterSerializer.js +12 -14
  114. package/dist/docx/serializer/markupRangeAttributes.js +2 -2
  115. package/dist/docx/serializer/noteSerializer.js +8 -8
  116. package/dist/docx/serializer/numberingSerializer.js +7 -6
  117. package/dist/docx/serializer/paragraphSerializer.js +93 -72
  118. package/dist/docx/serializer/partNamespaces.js +2 -2
  119. package/dist/docx/serializer/runSerializer.js +73 -44
  120. package/dist/docx/serializer/sectionPropertiesSerializer.js +19 -14
  121. package/dist/docx/serializer/settingsSerializer.js +4 -3
  122. package/dist/docx/serializer/stylesSerializer.js +6 -6
  123. package/dist/docx/serializer/tableSerializer.js +28 -17
  124. package/dist/docx/serializer/textFormattingSerializer.js +29 -28
  125. package/dist/docx/serializer/themeSerializer.js +6 -6
  126. package/dist/docx/serializer/trackedChangeAttributes.js +2 -2
  127. package/dist/docx/serializer/xmlUtils.d.ts +1 -2
  128. package/dist/docx/serializer/xmlUtils.js +1 -13
  129. package/dist/docx/server/boundedArchive.d.ts +12 -0
  130. package/dist/docx/server/boundedArchive.js +20 -1
  131. package/dist/docx/server/createBilingualDocument.js +3 -1
  132. package/dist/docx/server/materializeYjsDocx.d.ts +1 -1
  133. package/dist/docx/server/materializeYjsDocx.js +9 -1
  134. package/dist/docx/server/migrateYjsAttrSchema.d.ts +55 -0
  135. package/dist/docx/server/migrateYjsAttrSchema.js +95 -0
  136. package/dist/docx/server/validateDocxConformance.js +22 -1
  137. package/dist/docx/shapeParser.js +12 -10
  138. package/dist/docx/tableParser.d.ts +1 -1
  139. package/dist/docx/tableParser.js +206 -85
  140. package/dist/docx/textBoxParser.d.ts +25 -2
  141. package/dist/docx/textBoxParser.js +59 -4
  142. package/dist/docx/unzip.d.ts +23 -0
  143. package/dist/docx/unzip.js +37 -26
  144. package/dist/docx/verbatimCapture.js +1 -1
  145. package/dist/docx/vmlImageParser.d.ts +17 -1
  146. package/dist/docx/vmlImageParser.js +20 -3
  147. package/dist/docx/vmlPreview.d.ts +1 -3
  148. package/dist/docx/vmlPreview.js +2 -30
  149. package/dist/docx/xmlEncoding.d.ts +5 -0
  150. package/dist/docx/xmlEncoding.js +12 -0
  151. package/dist/docx/xmlParser.d.ts +26 -2
  152. package/dist/docx/xmlParser.js +70 -27
  153. package/dist/docx/xmlResourceLimits.d.ts +89 -9
  154. package/dist/docx/xmlResourceLimits.js +105 -24
  155. package/dist/headless-layout.js +10 -1
  156. package/dist/index.d.ts +2 -1
  157. package/dist/index.js +2 -1
  158. package/dist/internal/pageBreakRunSourceDescendantIndex.js +5 -2
  159. package/dist/internal/paragraphFormattingSerialization.js +3 -2
  160. package/dist/layout-bridge/convert/toFlowBlocks.js +102 -12
  161. package/dist/layout-engine/measure/tableCellFloating.d.ts +2 -0
  162. package/dist/layout-engine/measure/tableCellFloating.js +2 -0
  163. package/dist/layout-engine/types.d.ts +23 -1
  164. package/dist/layout-painter/renderImage.d.ts +5 -1
  165. package/dist/layout-painter/renderImage.js +14 -6
  166. package/dist/layout-painter/renderPage.d.ts +2 -0
  167. package/dist/layout-painter/renderPage.js +4 -0
  168. package/dist/layout-painter/renderParagraph.d.ts +13 -1
  169. package/dist/layout-painter/renderParagraph.js +26 -6
  170. package/dist/managers/autoSaveCodec.d.ts +9 -1
  171. package/dist/managers/autoSaveCodec.js +14 -12
  172. package/dist/markdown/images.js +1 -4
  173. package/dist/markdown/renderBlock.js +1 -0
  174. package/dist/markdown/renderRuns.d.ts +1 -1
  175. package/dist/markdown/renderRuns.js +28 -5
  176. package/dist/markdown/renderTable.js +22 -5
  177. package/dist/markdown/trailers.js +4 -1
  178. package/dist/pdf/images.js +142 -6
  179. package/dist/prosemirror/attrs/index.d.ts +14 -3
  180. package/dist/prosemirror/attrs/index.js +224 -2
  181. package/dist/prosemirror/authoredTransformAttrs.d.ts +28 -0
  182. package/dist/prosemirror/authoredTransformAttrs.js +64 -0
  183. package/dist/prosemirror/commands/contentControls.js +10 -2
  184. package/dist/prosemirror/commands/image.d.ts +9 -2
  185. package/dist/prosemirror/commands/image.js +43 -28
  186. package/dist/prosemirror/commands/pageBreak.js +1 -1
  187. package/dist/prosemirror/commentReferenceAttrs.d.ts +8 -0
  188. package/dist/prosemirror/commentReferenceAttrs.js +33 -0
  189. package/dist/prosemirror/commentReferenceIntegrity.d.ts +47 -0
  190. package/dist/prosemirror/commentReferenceIntegrity.js +43 -0
  191. package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -13
  192. package/dist/prosemirror/conversion/fromProseDoc.js +338 -99
  193. package/dist/prosemirror/conversion/index.d.ts +2 -2
  194. package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -9
  195. package/dist/prosemirror/conversion/toProseDoc.js +551 -327
  196. package/dist/prosemirror/extensions/StarterKit.js +8 -58
  197. package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
  198. package/dist/prosemirror/extensions/core/ParagraphExtension.js +2 -1
  199. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +45 -27
  200. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +3 -1
  201. package/dist/prosemirror/extensions/features/ImagePasteExtension.js +5 -3
  202. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +1 -0
  203. package/dist/prosemirror/extensions/markRegistry.d.ts +41 -0
  204. package/dist/prosemirror/extensions/markRegistry.js +75 -0
  205. package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +2 -3
  206. package/dist/prosemirror/extensions/marks/InlineWrapperExtension.d.ts +18 -0
  207. package/dist/prosemirror/extensions/marks/InlineWrapperExtension.js +63 -0
  208. package/dist/prosemirror/extensions/marks/markUtils.d.ts +2 -1
  209. package/dist/prosemirror/extensions/marks/markUtils.js +47 -4
  210. package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.d.ts +11 -0
  211. package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +87 -0
  212. package/dist/prosemirror/extensions/nodes/FieldExtension.js +9 -7
  213. package/dist/prosemirror/extensions/nodes/ImageExtension.js +20 -0
  214. package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.d.ts +32 -0
  215. package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.js +67 -0
  216. package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.d.ts +16 -0
  217. package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.js +60 -0
  218. package/dist/prosemirror/extensions/nodes/ShapeExtension.js +10 -2
  219. package/dist/prosemirror/extensions/nodes/TableExtension.js +3 -2
  220. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +13 -5
  221. package/dist/prosemirror/inlineWrapperStack.d.ts +39 -0
  222. package/dist/prosemirror/inlineWrapperStack.js +75 -0
  223. package/dist/prosemirror/pageBreakRunProjection.d.ts +17 -7
  224. package/dist/prosemirror/pageBreakRunProjection.js +19 -9
  225. package/dist/prosemirror/paragraphFormattingProvenance.d.ts +6 -3
  226. package/dist/prosemirror/paragraphFormattingProvenance.js +12 -3
  227. package/dist/prosemirror/replacedAnnotations.d.ts +59 -0
  228. package/dist/prosemirror/replacedAnnotations.js +165 -0
  229. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +3 -1
  230. package/dist/prosemirror/runFormattingInlineCarriers.js +5 -1
  231. package/dist/prosemirror/schema/index.d.ts +3 -3
  232. package/dist/prosemirror/schema/marks.d.ts +25 -1
  233. package/dist/prosemirror/schema/nodes.d.ts +139 -3
  234. package/dist/prosemirror/schema/nodes.js +16 -1
  235. package/dist/prosemirror/trackedRunInlineAtoms.d.ts +2 -0
  236. package/dist/prosemirror/trackedRunInlineAtoms.js +2 -0
  237. package/dist/prosemirror/validation.js +16 -2
  238. package/dist/prosemirror/yjsDocumentMetadata.d.ts +73 -0
  239. package/dist/prosemirror/yjsDocumentMetadata.js +171 -0
  240. package/dist/prosemirror/zeroWidthAnchors.js +2 -0
  241. package/dist/render-dom/commentAnchorAttributes.d.ts +37 -0
  242. package/dist/render-dom/commentAnchorAttributes.js +54 -0
  243. package/dist/server.d.ts +3 -1
  244. package/dist/server.js +3 -1
  245. package/dist/types/content.d.ts +2 -2
  246. package/dist/utils/base64.d.ts +36 -0
  247. package/dist/utils/base64.js +40 -0
  248. package/dist/utils/clipboard.d.ts +9 -1
  249. package/dist/utils/clipboard.js +29 -2
  250. package/dist/utils/findReplace.js +1 -1
  251. package/dist/utils/imageLuminance.d.ts +15 -0
  252. package/dist/utils/imageLuminance.js +32 -0
  253. package/dist/utils/mergeDocumentContent.js +7 -17
  254. package/dist/utils/replaceText.js +1 -0
  255. package/dist/utils/units.d.ts +10 -1
  256. package/dist/utils/units.js +12 -1
  257. package/dist/utils/urlSecurity.d.ts +8 -2
  258. package/dist/utils/urlSecurity.js +21 -3
  259. package/package.json +2 -2
  260. package/dist/docx/blockRangeMarkers.d.ts +0 -36
  261. package/dist/docx/blockRangeMarkers.js +0 -59
  262. package/dist/prosemirror/yjsParagraphSourceContract.d.ts +0 -9
  263. package/dist/prosemirror/yjsParagraphSourceContract.js +0 -26
@@ -1,4 +1,7 @@
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";
4
+ import { isInlineSdtContent } from "../../docx/inlineWrapperContent.js";
2
5
  import { isNumberingReference } 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
7
  import { visitDocxParagraphs } from "../../docx/paragraphTraversal.js";
@@ -10,13 +13,17 @@ import { OUTLINE_STYLE_CSS_ALIASES, normalizeShapeTextAnchor } from "../../types
10
13
  import { canonicalJson } from "../../utils/canonicalJson.js";
11
14
  import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
12
15
  import { mergeTextFormatting } from "../../utils/textFormattingMerge.js";
13
- import { 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";
16
+ import { emuToPixels, emuToStrokePixels, pixelsToEmu } from "../../utils/units.js";
17
+ import { expectBlockSdtAttrs, expectCharacterSpacingMarkAttrs, expectCharacterStyleMarkAttrs, expectCommentMarkAttrs, expectEmphasisMarkAttrs, expectFieldAttrs, expectFontFamilyMarkAttrs, expectFontSizeMarkAttrs, expectFootnoteRefMarkAttrs, expectHardBreakAttrs, expectHighlightMarkAttrs, expectHyperlinkMarkAttrs, expectImageAttrs, expectInlineWrapperMarkAttrs, expectLanguageMarkAttrs, expectMathAttrs, expectPageBreakRunAttrs, expectPageBreakRunOwnerMarkAttrs, expectParagraphAttrs, expectPreservedBlockAttrs, expectPreservedXmlAttrs, expectRunFormattingOverrideMarkAttrs, expectRunPropertyChangeMarkAttrs, expectRunShadingMarkAttrs, expectSdtAttrs, expectShapeAttrs, expectStrikeMarkAttrs, expectSymbolAttrs, expectTabAttrs, expectTableAttrs, expectTableCellAttrs, expectTableRowAttrs, expectTextBoxAttrs, expectTextColorMarkAttrs, expectTextEffectMarkAttrs, expectTrackedChangeMarkAttrs, expectUnderlineMarkAttrs } from "../attrs/index.js";
18
+ import { readAuthoredTransform } from "../authoredTransformAttrs.js";
15
19
  import { autospacingMatchesBase, hasAutospacingBaseSide } from "../autospacingBase.js";
16
20
  import { bookmarkBoundaryDisplacement, expectBookmarkBoundaryAttrs } from "../bookmarkBoundaryAttrs.js";
17
21
  import { paragraphRejectAttrPatch, paragraphRejectOriginalFormatting, removeParagraphPropertyChanges } from "../commands/propertyChangeScope.js";
22
+ import { expectCommentReferenceAttrs } from "../commentReferenceAttrs.js";
23
+ import { INLINE_WRAPPER_MARK_NAME } from "../extensions/marks/InlineWrapperExtension.js";
18
24
  import { applyRunFormattingOverrideAttrs, buildRunFormattingOverrideAttrs } from "../extensions/marks/RunFormattingOverrideExtension.js";
19
25
  import { textFormattingToMarks } from "../extensions/marks/markUtils.js";
26
+ import { inlineWrapperMember, inlineWrapperStackKey } from "../inlineWrapperStack.js";
20
27
  import { listRenderingFromAttrs as listRenderingFromAttrs$1 } from "../listRenderingAttrs.js";
21
28
  import { resolveNumberedRefFields } from "../numberedRefFields.js";
22
29
  import { directParagraphAlignment } from "../paragraphAlignment.js";
@@ -26,6 +33,7 @@ import { RUN_FORMATTING_MARK_NAMES } from "../runFormattingMarkNames.js";
26
33
  import { authoredRunFormattingFromAttrs, hasAuthoredRunFormattingProvenance } from "../runFormattingProvenance.js";
27
34
  import { paragraphFormattingForRun, paragraphRunStyleContext, resolveEffectiveRunStyleFormatting, suppressParagraphMarkFormatting } from "../runStyleFormatting.js";
28
35
  import { schema } from "../schema/index.js";
36
+ import { PRESERVED_XML_LEVELS } from "../schema/nodes.js";
29
37
  import { parseShapeGeometryAdjustments } from "../shapeGeometryAdjustments.js";
30
38
  import { expectTextBoxAnchorAttrs } from "../textBoxAnchorAttrs.js";
31
39
  import { assertValidProseMirrorDocument } from "../validation.js";
@@ -51,19 +59,6 @@ function normalizeShapeOutlineStyle(style) {
51
59
  if (style in OUTLINE_STYLE_CSS_ALIASES) return OUTLINE_STYLE_CSS_ALIASES[style];
52
60
  return narrowEnum(style, ShapeOutlineStyleSchema);
53
61
  }
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;
66
- }
67
62
  function imagePositionFromAttrs(attrs) {
68
63
  const horizontalPosition = attrs?.horizontal;
69
64
  const verticalPosition = attrs?.vertical;
@@ -79,14 +74,35 @@ function imagePositionFromAttrs(attrs) {
79
74
  vertical
80
75
  };
81
76
  }
77
+ /**
78
+ * The EMUs behind one pixel attribute of a drawing.
79
+ *
80
+ * `toProseDoc` carries the authored EMU beside every pixel value it derived,
81
+ * because EMU → px → EMU does not land back on the same number. While the
82
+ * pixel attribute still projects from the authored EMU nothing has moved it,
83
+ * so the document gets its own value back; once an editor command has, the
84
+ * pixel attribute is the truth and converts.
85
+ */
86
+ const emuFromPixels = (px, key, authored, project) => {
87
+ const emu = authored?.[key];
88
+ return emu !== void 0 && project(emu) === px ? emu : pixelsToEmu(px);
89
+ };
90
+ /**
91
+ * Copy the wrap insets onto a wrap. Shared by the image, shape and text-box
92
+ * paths so one rule decides when an inset keeps its authored EMU.
93
+ */
94
+ const assignWrapDistances = (wrap, attrs) => {
95
+ const authored = attrs._docxAuthoredEmu;
96
+ if (attrs.distTop !== void 0) wrap.distT = emuFromPixels(attrs.distTop, "distTop", authored, emuToPixels);
97
+ if (attrs.distBottom !== void 0) wrap.distB = emuFromPixels(attrs.distBottom, "distBottom", authored, emuToPixels);
98
+ if (attrs.distLeft !== void 0) wrap.distL = emuFromPixels(attrs.distLeft, "distLeft", authored, emuToPixels);
99
+ if (attrs.distRight !== void 0) wrap.distR = emuFromPixels(attrs.distRight, "distRight", authored, emuToPixels);
100
+ };
82
101
  function textBoxWrapFromAttrs(attrs) {
83
102
  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;
84
103
  const wrap = { type: attrs.wrapType ?? "inline" };
85
104
  if (attrs.wrapText !== void 0) wrap.wrapText = attrs.wrapText;
86
- if (attrs.distTop !== void 0) wrap.distT = pixelsToEmu(attrs.distTop);
87
- if (attrs.distBottom !== void 0) wrap.distB = pixelsToEmu(attrs.distBottom);
88
- if (attrs.distLeft !== void 0) wrap.distL = pixelsToEmu(attrs.distLeft);
89
- if (attrs.distRight !== void 0) wrap.distR = pixelsToEmu(attrs.distRight);
105
+ assignWrapDistances(wrap, attrs);
90
106
  return wrap;
91
107
  }
92
108
  const assignUniqueParagraph = (paragraphs, paraId, paragraph) => {
@@ -215,6 +231,8 @@ function fromProseDoc(pmDoc, baseDocument) {
215
231
  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.");
216
232
  const tokenSources = baseContract && proseContract && baseDocument ? validateParagraphPropertySourceTokens(pmDoc, baseDocument, baseContract) : null;
217
233
  const blocks = extractBlocks(pmDoc, "resolve", baseDocument?.package.styles ? createStyleEngine(baseDocument.package.styles) : null);
234
+ joinCommentRangesAcrossParagraphs(blocks);
235
+ completeCommentReferences(blocks);
218
236
  const linkedSources = restoreLinkedParagraphPropertySources(blocks);
219
237
  if (tokenSources) restoreParagraphPropertySourcesByToken(blocks, tokenSources);
220
238
  else if (baseDocument) restoreParagraphPropertySources(blocks, baseDocument.package.document.content, linkedSources.targets, linkedSources.sources);
@@ -431,42 +449,9 @@ function materializeNumberedRefValues(doc) {
431
449
  };
432
450
  return visit(doc);
433
451
  }
434
- const SERIALIZER_EMPTY_PAGE_FIELD_RESULT = "1";
435
- const fieldResultHasExplicitPageBreak = (node) => extractParagraphContent(node, void 0, void 0, /* @__PURE__ */ new Map(), false).filter((content) => content.type === "run" || content.type === "hyperlink").some((content) => {
436
- return (content.type === "run" ? [content] : content.children).some((run) => run.type === "run" && run.content.some((runContent) => runContent.type === "break" && runContent.breakType === "page"));
437
- });
438
- /**
439
- * PAGE and NUMPAGES have a stable visible fallback. Other empty fields may
440
- * intentionally have no result (for example an empty TOC); inventing a space
441
- * changes their authored result on every save/reopen cycle. A field whose
442
- * result already carries an explicit page break owns that break's run, so the
443
- * fallback would displace it.
444
- */
445
- function materializeSerializerFieldFallbacks(doc) {
446
- const visit = (node) => {
447
- if (node.type.name === "field" || node.type.name === "structuredField") {
448
- const attrs = expectFieldAttrs(node);
449
- return (attrs.fieldType === "PAGE" || attrs.fieldType === "NUMPAGES") && !attrs.displayText && !fieldResultHasExplicitPageBreak(node) ? recreateProseNodeWithParagraphPropertySource(node, { attrs: {
450
- ...node.attrs,
451
- displayText: SERIALIZER_EMPTY_PAGE_FIELD_RESULT
452
- } }) : node;
453
- }
454
- if (node.childCount === 0) return node;
455
- const children = [];
456
- let changed = false;
457
- node.forEach((child) => {
458
- const mappedChild = visit(child);
459
- children.push(mappedChild);
460
- changed ||= mappedChild !== child;
461
- });
462
- return changed ? recreateProseNodeWithParagraphPropertySource(node, { content: Fragment.fromArray(children) }) : node;
463
- };
464
- return visit(doc);
465
- }
466
- function extractBlocks(inputDoc, refResolution = "resolve", styleResolver = null, emptyFieldResult = "serializerFallback") {
452
+ function extractBlocks(inputDoc, refResolution = "resolve", styleResolver = null) {
467
453
  const strippedDoc = stripSuggestedProvenance(inputDoc, styleResolver);
468
- const refResolvedDoc = refResolution === "resolve" ? materializeNumberedRefValues(strippedDoc) : strippedDoc;
469
- const pmDoc = emptyFieldResult === "serializerFallback" ? materializeSerializerFieldFallbacks(refResolvedDoc) : refResolvedDoc;
454
+ const pmDoc = refResolution === "resolve" ? materializeNumberedRefValues(strippedDoc) : strippedDoc;
470
455
  const blocks = [];
471
456
  const textBoxAnchorMarkers = /* @__PURE__ */ new Map();
472
457
  const documentCounts = buildDocumentTrackedChangeCounts(pmDoc);
@@ -509,15 +494,69 @@ function extractBlocks(inputDoc, refResolution = "resolve", styleResolver = null
509
494
  pendingPageBreaks = 0;
510
495
  } else if (node.type.name === "blockSdt") {
511
496
  if (pendingPageBreaks > 0 && !appendPendingPageBreaksToPreviousParagraph()) flushPendingPageBreaks();
512
- blocks.push(convertPMBlockSdt(node, styleResolver, emptyFieldResult));
497
+ blocks.push(convertPMBlockSdt(node, styleResolver));
498
+ previousStandaloneTextBox = null;
499
+ } else if (node.type.name === "preservedBlock") {
500
+ blocks.push({
501
+ type: "preservedBlock",
502
+ xml: expectPreservedBlockAttrs(node).xml
503
+ });
513
504
  previousStandaloneTextBox = null;
514
505
  }
515
506
  });
516
507
  if (pendingPageBreaks > 0 && !appendPendingPageBreaksToPreviousParagraph()) flushPendingPageBreaks();
517
508
  removeUnresolvedTextBoxAnchors(blocks, textBoxAnchorMarkers);
509
+ keepOneAttributeRemainderPerRecord(blocks);
518
510
  return blocks;
519
511
  }
520
- function convertPMBlockSdt(node, styleResolver, emptyFieldResult) {
512
+ /**
513
+ * The attribute remainder follows the record it was authored on, and only it.
514
+ *
515
+ * ProseMirror copies a node's attrs when a command splits it, so pressing
516
+ * Enter in the middle of a paragraph produces two nodes holding the *same*
517
+ * remainder array. Writing it back on both would give the new half a
518
+ * revision-session id nobody assigned to it: `w:rsidR` says which editing
519
+ * session wrote this paragraph, and a copy of it is a claim about history the
520
+ * author did not make. The rule is that the half that comes first in document
521
+ * order keeps the authored identity, and the other half is a new record with
522
+ * no remainder — the same answer a paragraph the editor created from scratch
523
+ * gets, which is none.
524
+ *
525
+ * Reference identity is what tells the two cases apart, and it is exact: two
526
+ * records that each parsed their own attributes hold different arrays however
527
+ * equal their contents, and only a copy made by the editor shares one.
528
+ */
529
+ const keepOneAttributeRemainderPerRecord = (blocks) => {
530
+ const seen = /* @__PURE__ */ new WeakSet();
531
+ const keepFirst = (record) => {
532
+ const remainder = record.preservedAttributes;
533
+ if (remainder === void 0) return;
534
+ if (seen.has(remainder)) {
535
+ delete record.preservedAttributes;
536
+ return;
537
+ }
538
+ seen.add(remainder);
539
+ };
540
+ const walk = (content) => {
541
+ for (const block of content) switch (block.type) {
542
+ case "paragraph":
543
+ keepFirst(block);
544
+ break;
545
+ case "table":
546
+ for (const row of block.rows) {
547
+ keepFirst(row);
548
+ for (const cell of row.cells) walk(cell.content);
549
+ }
550
+ break;
551
+ case "blockSdt":
552
+ walk(block.content);
553
+ break;
554
+ default: break;
555
+ }
556
+ };
557
+ walk(blocks);
558
+ };
559
+ function convertPMBlockSdt(node, styleResolver) {
521
560
  const attrs = expectBlockSdtAttrs(node);
522
561
  const properties = { sdtType: attrs.sdtType };
523
562
  if (attrs.alias) properties.alias = attrs.alias;
@@ -535,7 +574,7 @@ function convertPMBlockSdt(node, styleResolver, emptyFieldResult) {
535
574
  if (attrs.rawEndPropertiesXml) properties.rawEndPropertiesXml = attrs.rawEndPropertiesXml;
536
575
  if (attrs.rawSdtChildrenBeforeContent) properties.rawSdtChildrenBeforeContent = attrs.rawSdtChildrenBeforeContent;
537
576
  if (attrs.rawSdtChildrenAfterContent) properties.rawSdtChildrenAfterContent = attrs.rawSdtChildrenAfterContent;
538
- const extracted = extractBlocks(node.type.schema.node("doc", null, node.content), "inherit", styleResolver, emptyFieldResult);
577
+ const extracted = extractBlocks(node.type.schema.node("doc", null, node.content), "inherit", styleResolver);
539
578
  return {
540
579
  type: "blockSdt",
541
580
  properties,
@@ -573,6 +612,7 @@ function appendTextBoxBlock(blocks, node, options) {
573
612
  if (!mergeTextBoxIntoTrailingInlineSdts(options.previousStandaloneTextBox.paragraph, paragraph, attrs._docxInlineSdts ?? [])) options.previousStandaloneTextBox.paragraph.content.push(...paragraph.content);
574
613
  return options.previousStandaloneTextBox;
575
614
  }
615
+ if (attrs._docxPlacement === "standalone" && attrs._preservedAttributes?.length) paragraph.preservedAttributes = attrs._preservedAttributes;
576
616
  prependPageBreaks(paragraph, options.pendingPageBreaks);
577
617
  blocks.push(paragraph);
578
618
  return attrs._docxPlacement === "standalone" && attrs._docxGroupId ? {
@@ -626,7 +666,7 @@ function findTextBoxShapeRun(content) {
626
666
  if (item.content.some((runContent) => runContent.type === "shape" && runContent.shape.shapeType === "textBox")) return item;
627
667
  continue;
628
668
  }
629
- if (item.type === "inlineSdt" || item.type === "hyperlink" || item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") {
669
+ if (item.type === "inlineSdt" || item.type === "hyperlink" || item.type === "inlineWrapper" || item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") {
630
670
  const run = findTextBoxShapeRun(item.type === "hyperlink" ? item.children : item.content);
631
671
  if (run) return run;
632
672
  }
@@ -642,6 +682,7 @@ function replaceTextBoxAnchorInBlocks(blocks, marker, textBoxRun) {
642
682
  for (const row of block.rows) for (const cell of row.cells) if (replaceTextBoxAnchorInBlocks(cell.content, marker, textBoxRun)) return true;
643
683
  continue;
644
684
  }
685
+ if (block.type === "preservedBlock") continue;
645
686
  if (replaceTextBoxAnchorInBlocks(block.content, marker, textBoxRun)) return true;
646
687
  }
647
688
  return false;
@@ -664,7 +705,7 @@ const textBoxAnchorHost = (item) => {
664
705
  case "deletion":
665
706
  case "moveFrom":
666
707
  case "moveTo":
667
- case "bidiWrapper": return item.content;
708
+ case "inlineWrapper": return item.content;
668
709
  case "run":
669
710
  case "complexField":
670
711
  case "bookmarkStart":
@@ -676,7 +717,8 @@ const textBoxAnchorHost = (item) => {
676
717
  case "moveFromRangeEnd":
677
718
  case "moveToRangeStart":
678
719
  case "moveToRangeEnd":
679
- case "mathEquation": return;
720
+ case "mathEquation":
721
+ case "preservedInline": return;
680
722
  default: panic(`Unsupported paragraph content: ${JSON.stringify(item)}`);
681
723
  }
682
724
  };
@@ -709,6 +751,7 @@ function removeTextBoxAnchorFromBlocks(blocks, marker) {
709
751
  for (const row of block.rows) for (const cell of row.cells) if (removeTextBoxAnchorFromBlocks(cell.content, marker)) return true;
710
752
  continue;
711
753
  }
754
+ if (block.type === "preservedBlock") continue;
712
755
  if (removeTextBoxAnchorFromBlocks(block.content, marker)) return true;
713
756
  }
714
757
  return false;
@@ -804,6 +847,7 @@ function convertPMParagraph(node, documentCounts, textBoxAnchorMarkers, styleRes
804
847
  else if (attrs.sectionBreakType) paragraph.sectionProperties = { sectionStart: attrs.sectionBreakType };
805
848
  if (attrs._propertyChanges && attrs._propertyChanges.length > 0) paragraph.propertyChanges = attrs._propertyChanges.map(propertyChangeFromAttrs);
806
849
  if (attrs.pPrMark) paragraph.pPrMark = attrs.pPrMark;
850
+ if (attrs._preservedAttributes && attrs._preservedAttributes.length > 0) paragraph.preservedAttributes = attrs._preservedAttributes;
807
851
  linkParagraphPropertySourceCandidate(paragraph, node);
808
852
  return paragraph;
809
853
  }
@@ -906,6 +950,9 @@ function paragraphAttrsToFormatting(attrs) {
906
950
  else delete result.styleId;
907
951
  assignBooleanToggle(result, attrs, orig, "pageBreakBefore");
908
952
  assignBooleanToggle(result, attrs, orig, "widowControl");
953
+ assignBooleanToggle(result, attrs, orig, "keepNext");
954
+ assignBooleanToggle(result, attrs, orig, "keepLines");
955
+ assignBooleanToggle(result, attrs, orig, "runInWithNext");
909
956
  assignBooleanToggle(result, attrs, orig, "snapToGrid");
910
957
  assignBooleanToggle(result, attrs, orig, "kinsoku");
911
958
  assignBooleanToggle(result, attrs, orig, "overflowPunctuation");
@@ -931,10 +978,13 @@ function paragraphAttrsToFormatting(attrs) {
931
978
  const contextualSpacing = authored("contextualSpacing", attrs.contextualSpacing);
932
979
  const pageBreakBefore = authored("pageBreakBefore", attrs.pageBreakBefore);
933
980
  const widowControl = authored("widowControl", attrs.widowControl);
981
+ const keepNext = authored("keepNext", attrs.keepNext);
982
+ const keepLines = authored("keepLines", attrs.keepLines);
983
+ const runInWithNext = authored("runInWithNext", attrs.runInWithNext);
934
984
  const kinsoku = authored("kinsoku", attrs.kinsoku);
935
985
  const overflowPunctuation = authored("overflowPunctuation", attrs.overflowPunctuation);
936
986
  const suppressAutoHyphens = authored("suppressAutoHyphens", attrs.suppressAutoHyphens);
937
- 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 || kinsoku != null || overflowPunctuation != null || suppressAutoHyphens != null)) return;
987
+ 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;
938
988
  const f = {};
939
989
  if (directAlignment !== void 0) f.alignment = directAlignment;
940
990
  if (shouldSerializeSpaceBefore) f.spaceBefore = spaceBefore;
@@ -959,6 +1009,9 @@ function paragraphAttrsToFormatting(attrs) {
959
1009
  if (bidi != null) f.bidi = bidi;
960
1010
  if (pageBreakBefore != null) f.pageBreakBefore = pageBreakBefore;
961
1011
  if (widowControl != null) f.widowControl = widowControl;
1012
+ if (keepNext != null) f.keepNext = keepNext;
1013
+ if (keepLines != null) f.keepLines = keepLines;
1014
+ if (runInWithNext != null) f.runInWithNext = runInWithNext;
962
1015
  if (kinsoku != null) f.kinsoku = kinsoku;
963
1016
  if (overflowPunctuation != null) f.overflowPunctuation = overflowPunctuation;
964
1017
  if (suppressAutoHyphens != null) f.suppressAutoHyphens = suppressAutoHyphens;
@@ -987,6 +1040,70 @@ function createTrackedRunWrapper(type, info, child) {
987
1040
  content
988
1041
  };
989
1042
  }
1043
+ /**
1044
+ * Comment ids in the order their markers are written at a shared boundary.
1045
+ *
1046
+ * Two ranges that begin or end at the same position have no order in the
1047
+ * editor, where each is a mark, so every emission site orders them by id: a
1048
+ * boundary written in the order the marks happened to open is a different
1049
+ * document each time the same one is saved.
1050
+ */
1051
+ const byCommentId = (ids) => [...ids].toSorted((a, b) => a - b);
1052
+ /** The wrappers `node` sits inside, outermost first; empty when it sits in none. */
1053
+ const inlineWrapperStackOf = (node) => {
1054
+ const mark = node.marks.find((candidate) => candidate.type.name === INLINE_WRAPPER_MARK_NAME);
1055
+ return mark ? expectInlineWrapperMarkAttrs(mark).stack : [];
1056
+ };
1057
+ const isRevisionWrapper = (item) => item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo";
1058
+ /** `stack` closed around `content`, outermost layer first. */
1059
+ const nestInlineWrappers = (stack, content) => {
1060
+ const innermost = stack.at(-1);
1061
+ if (innermost === void 0) panic("An inline wrapper group carries no layer");
1062
+ let wrapper = inlineWrapperMember(innermost, content);
1063
+ for (const layer of stack.slice(0, -1).toReversed()) wrapper = inlineWrapperMember(layer, [wrapper]);
1064
+ return wrapper;
1065
+ };
1066
+ /**
1067
+ * The emitted sequence with each wrapper group nested back into the wrappers
1068
+ * `toProseDoc` lifted off it.
1069
+ *
1070
+ * The revision stays outermost. folio already writes a revision outside the
1071
+ * hyperlink it spans, the parse leg is revision-owned, and accepting or
1072
+ * rejecting one is a range operation over the revision's own content; a
1073
+ * wrapper placed outside two revisions would also have to mint one revision id
1074
+ * per wrapper. So a revision in the group keeps its place and takes the nest
1075
+ * inside it, and the items around it share a nest of their own.
1076
+ *
1077
+ * A group with nothing in it writes no wrapper: an authored wrapper whose
1078
+ * content was deleted or rejected is gone, and an empty one says nothing.
1079
+ */
1080
+ const nestInlineWrapperGroups = (items, groups) => {
1081
+ const nested = [];
1082
+ for (const [index, group] of groups.entries()) {
1083
+ const slice = items.slice(group.start, groups[index + 1]?.start ?? items.length);
1084
+ if (group.stack.length === 0) {
1085
+ nested.push(...slice);
1086
+ continue;
1087
+ }
1088
+ let pending = [];
1089
+ const closeNest = () => {
1090
+ if (pending.length === 0) return;
1091
+ nested.push(nestInlineWrappers(group.stack, pending));
1092
+ pending = [];
1093
+ };
1094
+ for (const item of slice) {
1095
+ if (!isRevisionWrapper(item)) {
1096
+ pending.push(item);
1097
+ continue;
1098
+ }
1099
+ closeNest();
1100
+ if (item.content.length > 0) item.content = [nestInlineWrappers(group.stack, item.content)];
1101
+ nested.push(item);
1102
+ }
1103
+ closeNest();
1104
+ }
1105
+ return nested;
1106
+ };
990
1107
  function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, textBoxAnchorMarkers, skipLeadingRenderedPageBreak = false, inheritedFormattingOverride) {
991
1108
  const content = [];
992
1109
  const paragraphStyleContext = paragraph.type.name === "paragraph" ? paragraphRunStyleContext(paragraph) : void 0;
@@ -1003,6 +1120,11 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1003
1120
  })).toSorted((left, right) => left.attrs.offset - right.attrs.offset || left.order - right.order);
1004
1121
  let nextEmptyHyperlink = 0;
1005
1122
  let leadingRenderedPageBreakPending = skipLeadingRenderedPageBreak;
1123
+ const wrapperGroups = [{
1124
+ start: 0,
1125
+ stack: []
1126
+ }];
1127
+ let wrapperGroupKey = "";
1006
1128
  let currentRun = null;
1007
1129
  let currentMarksKey = null;
1008
1130
  let currentHyperlink = null;
@@ -1056,14 +1178,14 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1056
1178
  if (toClose.length === 0 && toOpen.length === 0) return;
1057
1179
  flushCurrentInline();
1058
1180
  currentTrackedChange = void 0;
1059
- for (const commentId of toClose.toSorted((a, b) => a - b)) {
1181
+ for (const commentId of byCommentId(toClose)) {
1060
1182
  content.push({
1061
1183
  type: "commentRangeEnd",
1062
1184
  id: commentId
1063
1185
  });
1064
1186
  openedComments.delete(commentId);
1065
1187
  }
1066
- for (const commentId of toOpen.toSorted((a, b) => a - b)) {
1188
+ for (const commentId of byCommentId(toOpen)) {
1067
1189
  content.push({
1068
1190
  type: "commentRangeStart",
1069
1191
  id: commentId
@@ -1081,13 +1203,45 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1081
1203
  content.push(createEmptyHyperlink(item.attrs));
1082
1204
  }
1083
1205
  };
1206
+ /**
1207
+ * Cut the emitted sequence where the wrapper the nodes sit inside changes.
1208
+ *
1209
+ * Nothing that spans nodes may span the cut: a run, a hyperlink and a
1210
+ * revision each sit inside one wrapper or outside it, never half in. The
1211
+ * comment ranges `syncCommentRanges` writes are cut with the rest, which
1212
+ * puts a range that opens or closes inside a wrapper inside it, as Word
1213
+ * writes it; a range marker says the same thing at either level, because the
1214
+ * wrapper is transparent and the position is unchanged.
1215
+ */
1216
+ const enterWrapperGroup = (node) => {
1217
+ const stack = inlineWrapperStackOf(node);
1218
+ const key = inlineWrapperStackKey(stack);
1219
+ if (key === wrapperGroupKey) return;
1220
+ flushCurrentInline();
1221
+ currentTrackedChange = void 0;
1222
+ wrapperGroupKey = key;
1223
+ wrapperGroups.push({
1224
+ start: content.length,
1225
+ stack
1226
+ });
1227
+ };
1084
1228
  const processInlineNode = (node, offset) => {
1085
1229
  if (node.type.name === "renderedPageBreak" && leadingRenderedPageBreakPending) {
1086
1230
  leadingRenderedPageBreakPending = false;
1087
1231
  return;
1088
1232
  }
1089
1233
  leadingRenderedPageBreakPending = false;
1234
+ enterWrapperGroup(node);
1090
1235
  syncCommentRanges(node, offset);
1236
+ if (node.type.name === "commentReference") {
1237
+ flushCurrentInline();
1238
+ currentTrackedChange = void 0;
1239
+ content.push({
1240
+ type: "commentReference",
1241
+ id: expectCommentReferenceAttrs(node).commentId
1242
+ });
1243
+ return;
1244
+ }
1091
1245
  const linkMark = node.marks.find((m) => m.type.name === "hyperlink");
1092
1246
  const noteRefMark = node.marks.find((m) => m.type.name === "footnoteRef");
1093
1247
  const insertionMark = node.marks.find((m) => m.type.name === "insertion");
@@ -1180,6 +1334,10 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1180
1334
  });
1181
1335
  return;
1182
1336
  }
1337
+ if (isInlineLevelPreservedXml(node)) {
1338
+ currentTrackedChange.hyperlink.children.push(createPreservedInline(node));
1339
+ return;
1340
+ }
1183
1341
  const run = createTrackedChangeRun({
1184
1342
  ...formattingContext,
1185
1343
  marks: otherMarks,
@@ -1226,6 +1384,10 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1226
1384
  currentTrackedChange.wrapper.content.push(createMathFromNode(node));
1227
1385
  return;
1228
1386
  }
1387
+ if (isInlineLevelPreservedXml(node)) {
1388
+ currentTrackedChange.wrapper.content.push(createPreservedInline(node));
1389
+ return;
1390
+ }
1229
1391
  const run = createTrackedChangeRun({
1230
1392
  ...formattingContext,
1231
1393
  marks: otherMarks,
@@ -1295,6 +1457,9 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1295
1457
  } else if (node.type.name === "symbol") {
1296
1458
  flushCurrentInline();
1297
1459
  content.push(createSymbolRun(node, node.marks, formattingContext));
1460
+ } else if (node.type.name === "preservedXml") {
1461
+ flushCurrentInline();
1462
+ content.push(isInlineLevelPreservedXml(node) ? createPreservedInline(node) : createPreservedXmlRun(node, node.marks, formattingContext));
1298
1463
  } else if (node.type.name === "hardBreak") {
1299
1464
  flushCurrentInline();
1300
1465
  content.push(createBreakRun(expectHardBreakAttrs(node), node.marks, formattingContext));
@@ -1349,11 +1514,11 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1349
1514
  });
1350
1515
  flushEmptyHyperlinksThroughOffset(Number.POSITIVE_INFINITY);
1351
1516
  flushCurrentInline();
1352
- for (const commentId of openedComments) content.push({
1517
+ for (const commentId of byCommentId(openedComments)) content.push({
1353
1518
  type: "commentRangeEnd",
1354
1519
  id: commentId
1355
1520
  });
1356
- return content;
1521
+ return nestInlineWrapperGroups(content, wrapperGroups);
1357
1522
  }
1358
1523
  function createTrackedChangeRun({ baseParagraphFormatting, inheritedFormatting, marks, node, paragraphMarkFormatting, paragraphMarkPrecedesStyle, styleResolver }) {
1359
1524
  const formattingContext = {
@@ -1378,6 +1543,7 @@ function createTrackedChangeRun({ baseParagraphFormatting, inheritedFormatting,
1378
1543
  };
1379
1544
  restoreRunPropertyChanges(run, marks);
1380
1545
  } else if (node.type.name === "symbol") run = createSymbolRun(node, marks, formattingContext);
1546
+ else if (node.type.name === "preservedXml") run = createPreservedXmlRun(node, marks, formattingContext);
1381
1547
  else if (node.type.name === "hardBreak") run = createBreakRun(expectHardBreakAttrs(node), marks, formattingContext);
1382
1548
  else if (node.type.name === "pageBreakRun") {
1383
1549
  const { clear } = expectPageBreakRunAttrs(node);
@@ -1552,6 +1718,16 @@ function addNodeToHyperlink({ baseParagraphFormatting, hyperlink, inheritedForma
1552
1718
  }));
1553
1719
  return;
1554
1720
  }
1721
+ if (node.type.name === "preservedXml") {
1722
+ hyperlink.children.push(isInlineLevelPreservedXml(node) ? createPreservedInline(node) : createPreservedXmlRun(node, nonLinkMarks, {
1723
+ baseParagraphFormatting,
1724
+ inheritedFormatting,
1725
+ paragraphMarkFormatting,
1726
+ paragraphMarkPrecedesStyle,
1727
+ styleResolver
1728
+ }));
1729
+ return;
1730
+ }
1555
1731
  if (node.type.name === "hardBreak") {
1556
1732
  hyperlink.children.push(createBreakRun(expectHardBreakAttrs(node), nonLinkMarks, {
1557
1733
  baseParagraphFormatting,
@@ -1649,6 +1825,44 @@ function createSymbolRun(node, marks, formattingContext) {
1649
1825
  restoreRunPropertyChanges(run, marks);
1650
1826
  return run;
1651
1827
  }
1828
+ /**
1829
+ * Whether the atom's markup is a paragraph child rather than a run child.
1830
+ *
1831
+ * The two are the same node in the editor and different elements in the file:
1832
+ * `w:ruby` has to go back inside a `w:r` and `w:permStart` may not, because
1833
+ * the schema admits no such child of a run and Word reports the package as
1834
+ * unreadable content.
1835
+ */
1836
+ const isInlineLevelPreservedXml = (node) => node.type.name === "preservedXml" && expectPreservedXmlAttrs(node).level === PRESERVED_XML_LEVELS.inline;
1837
+ /** The paragraph-level capture an inline-level atom writes back. */
1838
+ const createPreservedInline = (node) => {
1839
+ const { xml, text } = expectPreservedXmlAttrs(node);
1840
+ return {
1841
+ type: "preservedInline",
1842
+ xml,
1843
+ text
1844
+ };
1845
+ };
1846
+ /**
1847
+ * Rebuild the run around a preserved child. The markup is opaque and comes
1848
+ * back byte for byte; only the run properties around it are rebuilt from the
1849
+ * atom's marks, exactly as for a symbol.
1850
+ */
1851
+ function createPreservedXmlRun(node, marks, formattingContext) {
1852
+ const { xml, text } = expectPreservedXmlAttrs(node);
1853
+ const run = {
1854
+ type: "run",
1855
+ content: [{
1856
+ type: "preservedXml",
1857
+ xml,
1858
+ text
1859
+ }]
1860
+ };
1861
+ const formatting = getAtomRunFormattingFromMarks(marks, formattingContext);
1862
+ if (formatting) run.formatting = formatting;
1863
+ restoreRunPropertyChanges(run, marks);
1864
+ return run;
1865
+ }
1652
1866
  function restoreRunPropertyChanges(run, marks) {
1653
1867
  const changeMark = marks.find((mark) => mark.type.name === "runPropertyChange");
1654
1868
  if (!changeMark) return;
@@ -1791,7 +2005,7 @@ function createFieldFromNode(node, { baseParagraphFormatting, inheritedFormattin
1791
2005
  paragraphMarkFormatting,
1792
2006
  paragraphMarkPrecedesStyle: paragraphMarkPrecedesStyle ?? false,
1793
2007
  styleResolver: styleResolver ?? null
1794
- }).filter((content) => content.type === "run" || content.type === "hyperlink");
2008
+ }).filter((content) => content.type === "run" || content.type === "hyperlink" || content.type === "preservedInline");
1795
2009
  const displayText = attrs.displayText ?? "";
1796
2010
  const displayRun = {
1797
2011
  type: "run",
@@ -1812,8 +2026,8 @@ function createFieldFromNode(node, { baseParagraphFormatting, inheritedFormattin
1812
2026
  fieldCode: [],
1813
2027
  fieldResult: fieldContent.length > 0 ? fieldContent.filter((content) => content.type === "run") : fallbackFieldContent
1814
2028
  };
1815
- if (attrs.fldLock) complex.fldLock = true;
1816
- if (attrs.dirty) complex.dirty = true;
2029
+ if (attrs.fldLock !== void 0) complex.fldLock = attrs.fldLock;
2030
+ if (attrs.dirty !== void 0) complex.dirty = attrs.dirty;
1817
2031
  return complex;
1818
2032
  }
1819
2033
  const simple = {
@@ -1822,8 +2036,8 @@ function createFieldFromNode(node, { baseParagraphFormatting, inheritedFormattin
1822
2036
  fieldType: attrs.fieldType,
1823
2037
  content: fieldContent.length > 0 ? fieldContent : fallbackFieldContent
1824
2038
  };
1825
- if (attrs.fldLock) simple.fldLock = true;
1826
- if (attrs.dirty) simple.dirty = true;
2039
+ if (attrs.fldLock !== void 0) simple.fldLock = attrs.fldLock;
2040
+ if (attrs.dirty !== void 0) simple.dirty = attrs.dirty;
1827
2041
  return simple;
1828
2042
  }
1829
2043
  const synchronizeFieldDisplayText = (content, displayText, fallbackRun) => {
@@ -1834,6 +2048,7 @@ const synchronizeFieldDisplayText = (content, displayText, fallbackRun) => {
1834
2048
  visit(child);
1835
2049
  continue;
1836
2050
  }
2051
+ if (child.type !== "hyperlink") continue;
1837
2052
  for (const hyperlinkChild of child.children) if (hyperlinkChild.type === "run") visit(hyperlinkChild);
1838
2053
  }
1839
2054
  };
@@ -1879,7 +2094,7 @@ function createInlineSdtFromNode(node, textBoxAnchorMarkers, formattingContext)
1879
2094
  return {
1880
2095
  type: "inlineSdt",
1881
2096
  properties: sdtPropertiesFromAttrs(expectSdtAttrs(node)),
1882
- 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")
2097
+ content: extractParagraphContent(node, void 0, void 0, textBoxAnchorMarkers, false, formattingContext).filter(isInlineSdtContent)
1883
2098
  };
1884
2099
  }
1885
2100
  /**
@@ -1896,34 +2111,39 @@ const carriedRunFormatting = (formatting) => formatting && Object.keys(formattin
1896
2111
  function createImageRun(node) {
1897
2112
  const attrs = expectImageAttrs(node);
1898
2113
  const wrap = { type: attrs.wrapType || "inline" };
1899
- if (attrs.distTop !== void 0) wrap.distT = pixelsToEmu(attrs.distTop);
1900
- if (attrs.distBottom !== void 0) wrap.distB = pixelsToEmu(attrs.distBottom);
1901
- if (attrs.distLeft !== void 0) wrap.distL = pixelsToEmu(attrs.distLeft);
1902
- if (attrs.distRight !== void 0) wrap.distR = pixelsToEmu(attrs.distRight);
2114
+ assignWrapDistances(wrap, attrs);
1903
2115
  if (attrs.wrapText) wrap.wrapText = attrs.wrapText;
2116
+ const authoredEmu = attrs._docxAuthoredEmu;
1904
2117
  const image = {
1905
2118
  type: "image",
1906
2119
  rId: attrs.rId || "",
1907
2120
  src: attrs.src,
1908
2121
  size: {
1909
- width: pixelsToEmu(attrs.width || 0),
1910
- height: pixelsToEmu(attrs.height || 0)
2122
+ width: emuFromPixels(attrs.width || 0, "width", authoredEmu, emuToPixels),
2123
+ height: emuFromPixels(attrs.height || 0, "height", authoredEmu, emuToPixels)
1911
2124
  },
1912
2125
  wrap
1913
2126
  };
1914
2127
  if (attrs.docPrName != null) image.docPrName = attrs.docPrName;
1915
2128
  if (attrs.alt != null) image.alt = attrs.alt;
1916
2129
  if (attrs.title != null) image.title = attrs.title;
1917
- const imageTransform = parseTransformAttr(attrs.transform);
2130
+ const imageTransform = readAuthoredTransform(attrs);
1918
2131
  if (imageTransform) image.transform = imageTransform;
1919
2132
  if (attrs.opacity != null) image.opacity = attrs.opacity;
2133
+ if (attrs.brightness != null || attrs.contrast != null) image.effects = {
2134
+ ...attrs.brightness == null ? {} : { brightness: attrs.brightness },
2135
+ ...attrs.contrast == null ? {} : { contrast: attrs.contrast }
2136
+ };
1920
2137
  const imagePosition = imagePositionFromAttrs(attrs.position);
1921
2138
  if (imagePosition) image.position = imagePosition;
1922
2139
  if (attrs.layoutInCell !== void 0) image.layoutInCell = attrs.layoutInCell;
2140
+ if (attrs.decorative !== void 0) image.decorative = attrs.decorative;
2141
+ if (attrs.hidden !== void 0) image.hidden = attrs.hidden;
2142
+ if (attrs.docPrExtensions !== void 0) image.docPrExtensions = [...attrs.docPrExtensions];
1923
2143
  if (attrs.frameLocks !== void 0) image.frameLocks = { ...attrs.frameLocks };
1924
2144
  if (attrs.borderWidth && attrs.borderWidth > 0) {
1925
2145
  const outline = {
1926
- width: pixelsToEmu(attrs.borderWidth),
2146
+ width: emuFromPixels(attrs.borderWidth, "borderWidth", authoredEmu, emuToStrokePixels),
1927
2147
  style: attrs.borderStyle ? {
1928
2148
  solid: "solid",
1929
2149
  dotted: "dot",
@@ -2003,24 +2223,25 @@ const drawingFromImageAttrs = (image, attrs) => {
2003
2223
  */
2004
2224
  function createShapeRun(node) {
2005
2225
  const attrs = expectShapeAttrs(node);
2226
+ const authoredEmu = attrs._docxAuthoredEmu;
2006
2227
  const shape = {
2007
2228
  type: "shape",
2008
2229
  shapeType: attrs.shapeType || "rect",
2009
2230
  size: {
2010
- width: attrs.width ? pixelsToEmu(attrs.width) : 0,
2011
- height: attrs.height ? pixelsToEmu(attrs.height) : 0
2231
+ width: attrs.width ? emuFromPixels(attrs.width, "width", authoredEmu, emuToPixels) : 0,
2232
+ height: attrs.height ? emuFromPixels(attrs.height, "height", authoredEmu, emuToPixels) : 0
2012
2233
  }
2013
2234
  };
2014
2235
  if (attrs.shapeId) shape.id = attrs.shapeId;
2236
+ if (attrs.shapeName !== void 0) shape.name = attrs.shapeName;
2237
+ if (attrs.alt !== void 0) shape.alt = attrs.alt;
2238
+ if (attrs.title !== void 0) shape.title = attrs.title;
2015
2239
  const geometryAdjustments = parseShapeGeometryAdjustments(attrs.geometryAdjustments);
2016
2240
  if (geometryAdjustments !== void 0) shape.geometryAdjustments = geometryAdjustments;
2017
- const shapeTransform = parseTransformAttr(attrs.transform);
2241
+ const shapeTransform = readAuthoredTransform(attrs);
2018
2242
  if (shapeTransform) shape.transform = shapeTransform;
2019
2243
  const wrap = { type: attrs.wrapType || "inline" };
2020
- if (attrs.distTop !== void 0) wrap.distT = pixelsToEmu(attrs.distTop);
2021
- if (attrs.distBottom !== void 0) wrap.distB = pixelsToEmu(attrs.distBottom);
2022
- if (attrs.distLeft !== void 0) wrap.distL = pixelsToEmu(attrs.distLeft);
2023
- if (attrs.distRight !== void 0) wrap.distR = pixelsToEmu(attrs.distRight);
2244
+ assignWrapDistances(wrap, attrs);
2024
2245
  if (attrs.wrapText) wrap.wrapText = attrs.wrapText;
2025
2246
  shape.wrap = wrap;
2026
2247
  const shapePosition = imagePositionFromAttrs(attrs.position);
@@ -2050,11 +2271,15 @@ function createShapeRun(node) {
2050
2271
  color: attrs.fillColorValue ?? { rgb: attrs.fillColor.replace("#", "") }
2051
2272
  };
2052
2273
  else if (attrs.fillType === "none") shape.fill = { type: "none" };
2053
- if (attrs.outlineStyle !== "none" && (attrs.outlineWidth !== void 0 && attrs.outlineWidth > 0 || attrs.outlineColor || attrs.outlineStyle || attrs.outlineCap || attrs.outlineHeadEnd || attrs.outlineTailEnd)) {
2274
+ if (attrs.outlineStyle !== "none" && (attrs.outlineWidth !== void 0 && attrs.outlineWidth > 0 || attrs.outlineColor || attrs.outlineStyle || attrs.outlineCap || attrs.outlineJoin || attrs.outlineHeadEnd || attrs.outlineTailEnd)) {
2054
2275
  const shapeOutline = {};
2055
- if (attrs.outlineWidth !== void 0 && attrs.outlineWidth > 0) shapeOutline.width = pixelsToEmu(attrs.outlineWidth);
2056
- if (attrs.outlineStyle) shapeOutline.style = normalizeShapeOutlineStyle(attrs.outlineStyle) ?? "solid";
2276
+ if (attrs.outlineWidth !== void 0 && attrs.outlineWidth > 0) shapeOutline.width = emuFromPixels(attrs.outlineWidth, "outlineWidth", authoredEmu, emuToStrokePixels);
2277
+ if (attrs.outlineStyle) {
2278
+ const style = normalizeShapeOutlineStyle(attrs.outlineStyle);
2279
+ if (style !== void 0) shapeOutline.style = style;
2280
+ }
2057
2281
  if (attrs.outlineCap) shapeOutline.cap = attrs.outlineCap;
2282
+ if (attrs.outlineJoin) shapeOutline.join = attrs.outlineJoin;
2058
2283
  if (attrs.outlineHeadEnd) shapeOutline.headEnd = attrs.outlineHeadEnd;
2059
2284
  if (attrs.outlineTailEnd) shapeOutline.tailEnd = attrs.outlineTailEnd;
2060
2285
  if (attrs.outlineColor) shapeOutline.color = attrs.outlineColorValue ?? { rgb: attrs.outlineColor.replace("#", "") };
@@ -2824,6 +3049,7 @@ function convertPMTableRow(node, documentCounts, activeVerticalMerges, styleReso
2824
3049
  const rowFormatting = tableRowAttrsToFormatting(attrs);
2825
3050
  if (rowFormatting) row.formatting = rowFormatting;
2826
3051
  if (Array.isArray(attrs.trPrChange) && attrs.trPrChange.length > 0) row.propertyChanges = [...attrs.trPrChange];
3052
+ if (attrs._preservedAttributes && attrs._preservedAttributes.length > 0) row.preservedAttributes = attrs._preservedAttributes;
2827
3053
  if (attrs.trIns) row.structuralChange = {
2828
3054
  type: "tableRowInsertion",
2829
3055
  info: {
@@ -2916,6 +3142,13 @@ function convertPMTableCell(node, documentCounts, styleResolver = null) {
2916
3142
  textBoxAnchorMarkers,
2917
3143
  styleResolver
2918
3144
  });
3145
+ else if (contentNode.type.name === "preservedBlock") {
3146
+ content.push({
3147
+ type: "preservedBlock",
3148
+ xml: expectPreservedBlockAttrs(contentNode).xml
3149
+ });
3150
+ previousStandaloneTextBox = null;
3151
+ }
2919
3152
  });
2920
3153
  removeUnresolvedTextBoxAnchors(content, textBoxAnchorMarkers);
2921
3154
  const cell = {
@@ -3015,6 +3248,7 @@ const projectTextBoxBodyContent = (state, blocks) => {
3015
3248
  */
3016
3249
  function convertPMTextBox(node, styleResolver = null) {
3017
3250
  const attrs = expectTextBoxAttrs(node);
3251
+ const authoredEmu = attrs._docxAuthoredEmu;
3018
3252
  const verticalAlign = normalizeShapeTextAnchor(attrs.verticalAlign);
3019
3253
  const childBlocks = [];
3020
3254
  node.forEach((child) => {
@@ -3026,8 +3260,8 @@ function convertPMTextBox(node, styleResolver = null) {
3026
3260
  type: "shape",
3027
3261
  shapeType: "textBox",
3028
3262
  size: {
3029
- width: attrs.width ? pixelsToEmu(attrs.width) : 0,
3030
- height: attrs.height ? pixelsToEmu(attrs.height) : 0
3263
+ width: attrs.width ? emuFromPixels(attrs.width, "width", authoredEmu, emuToPixels) : 0,
3264
+ height: attrs.height ? emuFromPixels(attrs.height, "height", authoredEmu, emuToPixels) : 0
3031
3265
  },
3032
3266
  textBody: {
3033
3267
  content: textBodyContent.type === "source-empty" ? [] : textBodyContent.content,
@@ -3037,16 +3271,19 @@ function convertPMTextBox(node, styleResolver = null) {
3037
3271
  ...verticalAlign !== void 0 ? { anchor: verticalAlign } : {},
3038
3272
  margins: (() => {
3039
3273
  const m = {};
3040
- if (typeof attrs.marginTop === "number") m.top = pixelsToEmu(attrs.marginTop);
3041
- if (typeof attrs.marginBottom === "number") m.bottom = pixelsToEmu(attrs.marginBottom);
3042
- if (typeof attrs.marginLeft === "number") m.left = pixelsToEmu(attrs.marginLeft);
3043
- if (typeof attrs.marginRight === "number") m.right = pixelsToEmu(attrs.marginRight);
3274
+ if (typeof attrs.marginTop === "number") m.top = emuFromPixels(attrs.marginTop, "marginTop", authoredEmu, emuToPixels);
3275
+ if (typeof attrs.marginBottom === "number") m.bottom = emuFromPixels(attrs.marginBottom, "marginBottom", authoredEmu, emuToPixels);
3276
+ if (typeof attrs.marginLeft === "number") m.left = emuFromPixels(attrs.marginLeft, "marginLeft", authoredEmu, emuToPixels);
3277
+ if (typeof attrs.marginRight === "number") m.right = emuFromPixels(attrs.marginRight, "marginRight", authoredEmu, emuToPixels);
3044
3278
  return m;
3045
3279
  })()
3046
3280
  }
3047
3281
  };
3048
3282
  if (attrs.textBoxId) shape.id = attrs.textBoxId;
3049
- const transform = parseTransformAttr(attrs.transform);
3283
+ if (attrs.textBoxName !== void 0) shape.name = attrs.textBoxName;
3284
+ if (attrs.alt !== void 0) shape.alt = attrs.alt;
3285
+ if (attrs.title !== void 0) shape.title = attrs.title;
3286
+ const transform = readAuthoredTransform(attrs);
3050
3287
  if (transform) shape.transform = transform;
3051
3288
  if (attrs.fillColor) shape.fill = {
3052
3289
  type: "solid",
@@ -3054,7 +3291,7 @@ function convertPMTextBox(node, styleResolver = null) {
3054
3291
  };
3055
3292
  if (attrs.outlineStyle !== "none" && attrs.outlineWidth && attrs.outlineWidth > 0) {
3056
3293
  const tbOutline = {
3057
- width: pixelsToEmu(attrs.outlineWidth),
3294
+ width: emuFromPixels(attrs.outlineWidth, "outlineWidth", authoredEmu, emuToStrokePixels),
3058
3295
  style: normalizeShapeOutlineStyle(attrs.outlineStyle) ?? "solid"
3059
3296
  };
3060
3297
  if (attrs.outlineColor) tbOutline.color = { rgb: attrs.outlineColor.replace("#", "") };
@@ -3116,8 +3353,10 @@ function updateDocumentContent(originalDocument, pmDoc) {
3116
3353
  * Used for converting edited header/footer PM content back to the document
3117
3354
  * model.
3118
3355
  */
3119
- function proseDocToBlocks(pmDoc, baseContent, styles, options) {
3120
- const blocks = extractBlocks(pmDoc, "resolve", styles ? createStyleEngine(styles) : null, options?.emptyFieldResult ?? "serializerFallback");
3356
+ function proseDocToBlocks(pmDoc, baseContent, styles) {
3357
+ const blocks = extractBlocks(pmDoc, "resolve", styles ? createStyleEngine(styles) : null);
3358
+ joinCommentRangesAcrossParagraphs(blocks);
3359
+ completeCommentReferences(blocks);
3121
3360
  const linkedSources = restoreLinkedParagraphPropertySources(blocks);
3122
3361
  if (baseContent) restoreParagraphPropertySources(blocks, baseContent, linkedSources.targets, linkedSources.sources);
3123
3362
  return blocks;