@stll/folio-core 0.45.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 (207) hide show
  1. package/dist/ai-edits/apply.js +59 -19
  2. package/dist/ai-edits/headless.js +1 -1
  3. package/dist/compare/compare.js +2 -5
  4. package/dist/compare/scenario.js +2 -5
  5. package/dist/compare/types.d.ts +9 -1
  6. package/dist/compare/types.js +12 -1
  7. package/dist/compat/eigenpal.d.ts +2 -1
  8. package/dist/compat/eigenpal.js +2 -1
  9. package/dist/content-controls/checkboxDisplay.d.ts +11 -0
  10. package/dist/content-controls/checkboxDisplay.js +40 -0
  11. package/dist/content-controls/findContentControls.js +3 -1
  12. package/dist/content-controls/mutateContentControls.js +17 -2
  13. package/dist/controller/contentControlWidgetController.d.ts +1 -0
  14. package/dist/controller/contentControlWidgetController.js +3 -0
  15. package/dist/controller/hiddenEditorApi.js +3 -1
  16. package/dist/controller/hiddenEditorManager.d.ts +1 -1
  17. package/dist/controller/hiddenEditorManager.js +6 -3
  18. package/dist/display-list/build/buildDisplayList.js +20 -1
  19. package/dist/display-list/build/imagePrimitives.d.ts +1 -1
  20. package/dist/display-list/build/imagePrimitives.js +3 -1
  21. package/dist/display-list/build/paragraphPrimitives.js +21 -2
  22. package/dist/display-list/dom/renderDisplayListToDom.js +10 -2
  23. package/dist/display-list/types.d.ts +17 -0
  24. package/dist/docx/attributeRemainder.d.ts +43 -0
  25. package/dist/docx/attributeRemainder.js +65 -0
  26. package/dist/docx/blockContentParser.d.ts +1 -1
  27. package/dist/docx/blockContentParser.js +87 -63
  28. package/dist/docx/blockPlainText.d.ts +3 -4
  29. package/dist/docx/blockPlainText.js +1 -0
  30. package/dist/docx/bookmarkPlacement.js +2 -0
  31. package/dist/docx/commentAnchorIndex.d.ts +30 -0
  32. package/dist/docx/commentAnchorIndex.js +50 -0
  33. package/dist/docx/commentParser.d.ts +1 -1
  34. package/dist/docx/commentParser.js +54 -37
  35. package/dist/docx/commentRangeIntegrity.d.ts +16 -1
  36. package/dist/docx/commentRangeIntegrity.js +42 -1
  37. package/dist/docx/commentRangeJoin.d.ts +9 -0
  38. package/dist/docx/commentRangeJoin.js +33 -0
  39. package/dist/docx/commentReferenceCompletion.d.ts +9 -0
  40. package/dist/docx/commentReferenceCompletion.js +47 -0
  41. package/dist/docx/commentReferenceNormalization.js +1 -0
  42. package/dist/docx/commentReplyMarkers.js +11 -19
  43. package/dist/docx/compatibility.js +1 -0
  44. package/dist/docx/containerChildren.d.ts +111 -0
  45. package/dist/docx/containerChildren.gen.d.ts +28 -0
  46. package/dist/docx/containerChildren.gen.js +246 -0
  47. package/dist/docx/containerChildren.js +103 -0
  48. package/dist/docx/documentParser.d.ts +1 -1
  49. package/dist/docx/documentParser.js +3 -3
  50. package/dist/docx/ensureParaIds.js +17 -7
  51. package/dist/docx/fieldParser.d.ts +1 -1
  52. package/dist/docx/fieldParser.js +4 -4
  53. package/dist/docx/fieldState.d.ts +26 -0
  54. package/dist/docx/fieldState.js +53 -0
  55. package/dist/docx/footnoteParser.d.ts +1 -1
  56. package/dist/docx/graphicFrameLocks.d.ts +16 -4
  57. package/dist/docx/graphicFrameLocks.js +19 -6
  58. package/dist/docx/headerFooterParser.js +1 -1
  59. package/dist/docx/headerFooterReferenceNormalization.js +1 -0
  60. package/dist/docx/hyperlinkParser.d.ts +27 -8
  61. package/dist/docx/hyperlinkParser.js +76 -18
  62. package/dist/docx/imageParser.js +33 -8
  63. package/dist/docx/inlineWrapperContent.d.ts +85 -0
  64. package/dist/docx/inlineWrapperContent.js +84 -0
  65. package/dist/docx/normalizeBaseDirection.js +10 -1
  66. package/dist/docx/paraIdAttribute.d.ts +21 -0
  67. package/dist/docx/paraIdAttribute.js +64 -0
  68. package/dist/docx/paragraphParser.d.ts +1 -1
  69. package/dist/docx/paragraphParser.js +277 -168
  70. package/dist/docx/paragraphPropertySource.js +5 -1
  71. package/dist/docx/paragraphTextBoxEnrichment.d.ts +1 -1
  72. package/dist/docx/paragraphTextBoxEnrichment.js +6 -52
  73. package/dist/docx/paragraphTraversal.js +7 -4
  74. package/dist/docx/parseWarningMessage.js +2 -1
  75. package/dist/docx/preservedRunContent.d.ts +32 -0
  76. package/dist/docx/preservedRunContent.js +86 -0
  77. package/dist/docx/renderedPageBreakNormalization.js +2 -4
  78. package/dist/docx/rezip.js +74 -18
  79. package/dist/docx/runParser.d.ts +1 -1
  80. package/dist/docx/runParser.js +16 -12
  81. package/dist/docx/sectionParser.js +8 -1
  82. package/dist/docx/selectiveXmlPatch.d.ts +46 -2
  83. package/dist/docx/selectiveXmlPatch.js +86 -39
  84. package/dist/docx/serializer/borderSerializer.js +2 -2
  85. package/dist/docx/serializer/commentSerializer.js +5 -7
  86. package/dist/docx/serializer/documentSerializer.js +8 -11
  87. package/dist/docx/serializer/headerFooterSerializer.js +7 -9
  88. package/dist/docx/serializer/noteSerializer.js +8 -8
  89. package/dist/docx/serializer/paragraphSerializer.js +76 -56
  90. package/dist/docx/serializer/runSerializer.js +25 -16
  91. package/dist/docx/serializer/sectionPropertiesSerializer.js +8 -4
  92. package/dist/docx/serializer/tableSerializer.js +18 -8
  93. package/dist/docx/server/createBilingualDocument.js +3 -1
  94. package/dist/docx/server/materializeYjsDocx.d.ts +1 -1
  95. package/dist/docx/server/materializeYjsDocx.js +9 -1
  96. package/dist/docx/server/migrateYjsAttrSchema.d.ts +55 -0
  97. package/dist/docx/server/migrateYjsAttrSchema.js +95 -0
  98. package/dist/docx/shapeParser.js +5 -5
  99. package/dist/docx/tableParser.d.ts +1 -1
  100. package/dist/docx/tableParser.js +206 -85
  101. package/dist/docx/textBoxParser.d.ts +25 -2
  102. package/dist/docx/textBoxParser.js +52 -2
  103. package/dist/docx/unzip.js +5 -4
  104. package/dist/docx/vmlImageParser.d.ts +17 -1
  105. package/dist/docx/vmlImageParser.js +17 -1
  106. package/dist/docx/xmlEncoding.d.ts +5 -0
  107. package/dist/docx/xmlEncoding.js +12 -0
  108. package/dist/docx/xmlParser.d.ts +10 -1
  109. package/dist/docx/xmlParser.js +14 -1
  110. package/dist/headless-layout.js +10 -1
  111. package/dist/index.d.ts +2 -1
  112. package/dist/index.js +2 -1
  113. package/dist/internal/pageBreakRunSourceDescendantIndex.js +5 -2
  114. package/dist/layout-bridge/convert/toFlowBlocks.js +102 -12
  115. package/dist/layout-engine/measure/tableCellFloating.d.ts +2 -0
  116. package/dist/layout-engine/measure/tableCellFloating.js +2 -0
  117. package/dist/layout-engine/types.d.ts +23 -1
  118. package/dist/layout-painter/renderImage.d.ts +5 -1
  119. package/dist/layout-painter/renderImage.js +10 -3
  120. package/dist/layout-painter/renderPage.d.ts +2 -0
  121. package/dist/layout-painter/renderPage.js +4 -0
  122. package/dist/layout-painter/renderParagraph.d.ts +13 -1
  123. package/dist/layout-painter/renderParagraph.js +22 -3
  124. package/dist/managers/autoSaveCodec.d.ts +9 -1
  125. package/dist/managers/autoSaveCodec.js +12 -4
  126. package/dist/markdown/renderBlock.js +1 -0
  127. package/dist/markdown/renderRuns.d.ts +1 -1
  128. package/dist/markdown/renderRuns.js +28 -5
  129. package/dist/markdown/renderTable.js +22 -5
  130. package/dist/markdown/trailers.js +4 -1
  131. package/dist/pdf/images.js +142 -6
  132. package/dist/prosemirror/attrs/index.d.ts +14 -3
  133. package/dist/prosemirror/attrs/index.js +155 -2
  134. package/dist/prosemirror/authoredTransformAttrs.d.ts +28 -0
  135. package/dist/prosemirror/authoredTransformAttrs.js +64 -0
  136. package/dist/prosemirror/commands/contentControls.js +10 -2
  137. package/dist/prosemirror/commands/image.d.ts +9 -2
  138. package/dist/prosemirror/commands/image.js +42 -28
  139. package/dist/prosemirror/commands/pageBreak.js +1 -1
  140. package/dist/prosemirror/commentReferenceAttrs.d.ts +8 -0
  141. package/dist/prosemirror/commentReferenceAttrs.js +33 -0
  142. package/dist/prosemirror/commentReferenceIntegrity.d.ts +47 -0
  143. package/dist/prosemirror/commentReferenceIntegrity.js +43 -0
  144. package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -13
  145. package/dist/prosemirror/conversion/fromProseDoc.js +269 -70
  146. package/dist/prosemirror/conversion/index.d.ts +2 -2
  147. package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -9
  148. package/dist/prosemirror/conversion/toProseDoc.js +468 -308
  149. package/dist/prosemirror/extensions/StarterKit.js +8 -58
  150. package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
  151. package/dist/prosemirror/extensions/core/ParagraphExtension.js +2 -1
  152. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +45 -27
  153. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +3 -1
  154. package/dist/prosemirror/extensions/features/ImagePasteExtension.js +5 -3
  155. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +1 -0
  156. package/dist/prosemirror/extensions/markRegistry.d.ts +41 -0
  157. package/dist/prosemirror/extensions/markRegistry.js +75 -0
  158. package/dist/prosemirror/extensions/marks/InlineWrapperExtension.d.ts +18 -0
  159. package/dist/prosemirror/extensions/marks/InlineWrapperExtension.js +63 -0
  160. package/dist/prosemirror/extensions/marks/markUtils.d.ts +2 -1
  161. package/dist/prosemirror/extensions/marks/markUtils.js +47 -4
  162. package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.d.ts +11 -0
  163. package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +87 -0
  164. package/dist/prosemirror/extensions/nodes/FieldExtension.js +9 -7
  165. package/dist/prosemirror/extensions/nodes/ImageExtension.js +16 -0
  166. package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.d.ts +32 -0
  167. package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.js +67 -0
  168. package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.d.ts +16 -0
  169. package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.js +60 -0
  170. package/dist/prosemirror/extensions/nodes/ShapeExtension.js +3 -0
  171. package/dist/prosemirror/extensions/nodes/TableExtension.js +3 -2
  172. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +5 -1
  173. package/dist/prosemirror/inlineWrapperStack.d.ts +39 -0
  174. package/dist/prosemirror/inlineWrapperStack.js +75 -0
  175. package/dist/prosemirror/pageBreakRunProjection.d.ts +17 -7
  176. package/dist/prosemirror/pageBreakRunProjection.js +19 -9
  177. package/dist/prosemirror/replacedAnnotations.d.ts +59 -0
  178. package/dist/prosemirror/replacedAnnotations.js +165 -0
  179. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +3 -1
  180. package/dist/prosemirror/runFormattingInlineCarriers.js +5 -1
  181. package/dist/prosemirror/schema/index.d.ts +3 -3
  182. package/dist/prosemirror/schema/marks.d.ts +25 -1
  183. package/dist/prosemirror/schema/nodes.d.ts +90 -3
  184. package/dist/prosemirror/schema/nodes.js +16 -1
  185. package/dist/prosemirror/trackedRunInlineAtoms.d.ts +2 -0
  186. package/dist/prosemirror/trackedRunInlineAtoms.js +2 -0
  187. package/dist/prosemirror/validation.js +16 -2
  188. package/dist/prosemirror/yjsDocumentMetadata.d.ts +73 -0
  189. package/dist/prosemirror/yjsDocumentMetadata.js +171 -0
  190. package/dist/prosemirror/zeroWidthAnchors.js +2 -0
  191. package/dist/render-dom/commentAnchorAttributes.d.ts +37 -0
  192. package/dist/render-dom/commentAnchorAttributes.js +54 -0
  193. package/dist/server.d.ts +3 -1
  194. package/dist/server.js +3 -1
  195. package/dist/types/content.d.ts +2 -2
  196. package/dist/utils/clipboard.d.ts +9 -1
  197. package/dist/utils/clipboard.js +27 -1
  198. package/dist/utils/findReplace.js +1 -1
  199. package/dist/utils/imageLuminance.d.ts +15 -0
  200. package/dist/utils/imageLuminance.js +32 -0
  201. package/dist/utils/mergeDocumentContent.js +7 -17
  202. package/dist/utils/replaceText.js +1 -0
  203. package/package.json +2 -2
  204. package/dist/docx/blockRangeMarkers.d.ts +0 -36
  205. package/dist/docx/blockRangeMarkers.js +0 -59
  206. package/dist/prosemirror/yjsParagraphSourceContract.d.ts +0 -9
  207. 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";
@@ -11,12 +14,16 @@ import { canonicalJson } from "../../utils/canonicalJson.js";
11
14
  import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
12
15
  import { mergeTextFormatting } from "../../utils/textFormattingMerge.js";
13
16
  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";
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;
@@ -236,6 +231,8 @@ function fromProseDoc(pmDoc, baseDocument) {
236
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.");
237
232
  const tokenSources = baseContract && proseContract && baseDocument ? validateParagraphPropertySourceTokens(pmDoc, baseDocument, baseContract) : null;
238
233
  const blocks = extractBlocks(pmDoc, "resolve", baseDocument?.package.styles ? createStyleEngine(baseDocument.package.styles) : null);
234
+ joinCommentRangesAcrossParagraphs(blocks);
235
+ completeCommentReferences(blocks);
239
236
  const linkedSources = restoreLinkedParagraphPropertySources(blocks);
240
237
  if (tokenSources) restoreParagraphPropertySourcesByToken(blocks, tokenSources);
241
238
  else if (baseDocument) restoreParagraphPropertySources(blocks, baseDocument.package.document.content, linkedSources.targets, linkedSources.sources);
@@ -452,42 +449,9 @@ function materializeNumberedRefValues(doc) {
452
449
  };
453
450
  return visit(doc);
454
451
  }
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") {
452
+ function extractBlocks(inputDoc, refResolution = "resolve", styleResolver = null) {
488
453
  const strippedDoc = stripSuggestedProvenance(inputDoc, styleResolver);
489
- const refResolvedDoc = refResolution === "resolve" ? materializeNumberedRefValues(strippedDoc) : strippedDoc;
490
- const pmDoc = emptyFieldResult === "serializerFallback" ? materializeSerializerFieldFallbacks(refResolvedDoc) : refResolvedDoc;
454
+ const pmDoc = refResolution === "resolve" ? materializeNumberedRefValues(strippedDoc) : strippedDoc;
491
455
  const blocks = [];
492
456
  const textBoxAnchorMarkers = /* @__PURE__ */ new Map();
493
457
  const documentCounts = buildDocumentTrackedChangeCounts(pmDoc);
@@ -530,15 +494,69 @@ function extractBlocks(inputDoc, refResolution = "resolve", styleResolver = null
530
494
  pendingPageBreaks = 0;
531
495
  } else if (node.type.name === "blockSdt") {
532
496
  if (pendingPageBreaks > 0 && !appendPendingPageBreaksToPreviousParagraph()) flushPendingPageBreaks();
533
- 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
+ });
534
504
  previousStandaloneTextBox = null;
535
505
  }
536
506
  });
537
507
  if (pendingPageBreaks > 0 && !appendPendingPageBreaksToPreviousParagraph()) flushPendingPageBreaks();
538
508
  removeUnresolvedTextBoxAnchors(blocks, textBoxAnchorMarkers);
509
+ keepOneAttributeRemainderPerRecord(blocks);
539
510
  return blocks;
540
511
  }
541
- 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) {
542
560
  const attrs = expectBlockSdtAttrs(node);
543
561
  const properties = { sdtType: attrs.sdtType };
544
562
  if (attrs.alias) properties.alias = attrs.alias;
@@ -556,7 +574,7 @@ function convertPMBlockSdt(node, styleResolver, emptyFieldResult) {
556
574
  if (attrs.rawEndPropertiesXml) properties.rawEndPropertiesXml = attrs.rawEndPropertiesXml;
557
575
  if (attrs.rawSdtChildrenBeforeContent) properties.rawSdtChildrenBeforeContent = attrs.rawSdtChildrenBeforeContent;
558
576
  if (attrs.rawSdtChildrenAfterContent) properties.rawSdtChildrenAfterContent = attrs.rawSdtChildrenAfterContent;
559
- 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);
560
578
  return {
561
579
  type: "blockSdt",
562
580
  properties,
@@ -594,6 +612,7 @@ function appendTextBoxBlock(blocks, node, options) {
594
612
  if (!mergeTextBoxIntoTrailingInlineSdts(options.previousStandaloneTextBox.paragraph, paragraph, attrs._docxInlineSdts ?? [])) options.previousStandaloneTextBox.paragraph.content.push(...paragraph.content);
595
613
  return options.previousStandaloneTextBox;
596
614
  }
615
+ if (attrs._docxPlacement === "standalone" && attrs._preservedAttributes?.length) paragraph.preservedAttributes = attrs._preservedAttributes;
597
616
  prependPageBreaks(paragraph, options.pendingPageBreaks);
598
617
  blocks.push(paragraph);
599
618
  return attrs._docxPlacement === "standalone" && attrs._docxGroupId ? {
@@ -647,7 +666,7 @@ function findTextBoxShapeRun(content) {
647
666
  if (item.content.some((runContent) => runContent.type === "shape" && runContent.shape.shapeType === "textBox")) return item;
648
667
  continue;
649
668
  }
650
- 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") {
651
670
  const run = findTextBoxShapeRun(item.type === "hyperlink" ? item.children : item.content);
652
671
  if (run) return run;
653
672
  }
@@ -663,6 +682,7 @@ function replaceTextBoxAnchorInBlocks(blocks, marker, textBoxRun) {
663
682
  for (const row of block.rows) for (const cell of row.cells) if (replaceTextBoxAnchorInBlocks(cell.content, marker, textBoxRun)) return true;
664
683
  continue;
665
684
  }
685
+ if (block.type === "preservedBlock") continue;
666
686
  if (replaceTextBoxAnchorInBlocks(block.content, marker, textBoxRun)) return true;
667
687
  }
668
688
  return false;
@@ -685,7 +705,7 @@ const textBoxAnchorHost = (item) => {
685
705
  case "deletion":
686
706
  case "moveFrom":
687
707
  case "moveTo":
688
- case "bidiWrapper": return item.content;
708
+ case "inlineWrapper": return item.content;
689
709
  case "run":
690
710
  case "complexField":
691
711
  case "bookmarkStart":
@@ -697,7 +717,8 @@ const textBoxAnchorHost = (item) => {
697
717
  case "moveFromRangeEnd":
698
718
  case "moveToRangeStart":
699
719
  case "moveToRangeEnd":
700
- case "mathEquation": return;
720
+ case "mathEquation":
721
+ case "preservedInline": return;
701
722
  default: panic(`Unsupported paragraph content: ${JSON.stringify(item)}`);
702
723
  }
703
724
  };
@@ -730,6 +751,7 @@ function removeTextBoxAnchorFromBlocks(blocks, marker) {
730
751
  for (const row of block.rows) for (const cell of row.cells) if (removeTextBoxAnchorFromBlocks(cell.content, marker)) return true;
731
752
  continue;
732
753
  }
754
+ if (block.type === "preservedBlock") continue;
733
755
  if (removeTextBoxAnchorFromBlocks(block.content, marker)) return true;
734
756
  }
735
757
  return false;
@@ -825,6 +847,7 @@ function convertPMParagraph(node, documentCounts, textBoxAnchorMarkers, styleRes
825
847
  else if (attrs.sectionBreakType) paragraph.sectionProperties = { sectionStart: attrs.sectionBreakType };
826
848
  if (attrs._propertyChanges && attrs._propertyChanges.length > 0) paragraph.propertyChanges = attrs._propertyChanges.map(propertyChangeFromAttrs);
827
849
  if (attrs.pPrMark) paragraph.pPrMark = attrs.pPrMark;
850
+ if (attrs._preservedAttributes && attrs._preservedAttributes.length > 0) paragraph.preservedAttributes = attrs._preservedAttributes;
828
851
  linkParagraphPropertySourceCandidate(paragraph, node);
829
852
  return paragraph;
830
853
  }
@@ -1017,6 +1040,70 @@ function createTrackedRunWrapper(type, info, child) {
1017
1040
  content
1018
1041
  };
1019
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
+ };
1020
1107
  function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, textBoxAnchorMarkers, skipLeadingRenderedPageBreak = false, inheritedFormattingOverride) {
1021
1108
  const content = [];
1022
1109
  const paragraphStyleContext = paragraph.type.name === "paragraph" ? paragraphRunStyleContext(paragraph) : void 0;
@@ -1033,6 +1120,11 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1033
1120
  })).toSorted((left, right) => left.attrs.offset - right.attrs.offset || left.order - right.order);
1034
1121
  let nextEmptyHyperlink = 0;
1035
1122
  let leadingRenderedPageBreakPending = skipLeadingRenderedPageBreak;
1123
+ const wrapperGroups = [{
1124
+ start: 0,
1125
+ stack: []
1126
+ }];
1127
+ let wrapperGroupKey = "";
1036
1128
  let currentRun = null;
1037
1129
  let currentMarksKey = null;
1038
1130
  let currentHyperlink = null;
@@ -1086,14 +1178,14 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1086
1178
  if (toClose.length === 0 && toOpen.length === 0) return;
1087
1179
  flushCurrentInline();
1088
1180
  currentTrackedChange = void 0;
1089
- for (const commentId of toClose.toSorted((a, b) => a - b)) {
1181
+ for (const commentId of byCommentId(toClose)) {
1090
1182
  content.push({
1091
1183
  type: "commentRangeEnd",
1092
1184
  id: commentId
1093
1185
  });
1094
1186
  openedComments.delete(commentId);
1095
1187
  }
1096
- for (const commentId of toOpen.toSorted((a, b) => a - b)) {
1188
+ for (const commentId of byCommentId(toOpen)) {
1097
1189
  content.push({
1098
1190
  type: "commentRangeStart",
1099
1191
  id: commentId
@@ -1111,13 +1203,45 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1111
1203
  content.push(createEmptyHyperlink(item.attrs));
1112
1204
  }
1113
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
+ };
1114
1228
  const processInlineNode = (node, offset) => {
1115
1229
  if (node.type.name === "renderedPageBreak" && leadingRenderedPageBreakPending) {
1116
1230
  leadingRenderedPageBreakPending = false;
1117
1231
  return;
1118
1232
  }
1119
1233
  leadingRenderedPageBreakPending = false;
1234
+ enterWrapperGroup(node);
1120
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
+ }
1121
1245
  const linkMark = node.marks.find((m) => m.type.name === "hyperlink");
1122
1246
  const noteRefMark = node.marks.find((m) => m.type.name === "footnoteRef");
1123
1247
  const insertionMark = node.marks.find((m) => m.type.name === "insertion");
@@ -1210,6 +1334,10 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1210
1334
  });
1211
1335
  return;
1212
1336
  }
1337
+ if (isInlineLevelPreservedXml(node)) {
1338
+ currentTrackedChange.hyperlink.children.push(createPreservedInline(node));
1339
+ return;
1340
+ }
1213
1341
  const run = createTrackedChangeRun({
1214
1342
  ...formattingContext,
1215
1343
  marks: otherMarks,
@@ -1256,6 +1384,10 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1256
1384
  currentTrackedChange.wrapper.content.push(createMathFromNode(node));
1257
1385
  return;
1258
1386
  }
1387
+ if (isInlineLevelPreservedXml(node)) {
1388
+ currentTrackedChange.wrapper.content.push(createPreservedInline(node));
1389
+ return;
1390
+ }
1259
1391
  const run = createTrackedChangeRun({
1260
1392
  ...formattingContext,
1261
1393
  marks: otherMarks,
@@ -1325,6 +1457,9 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1325
1457
  } else if (node.type.name === "symbol") {
1326
1458
  flushCurrentInline();
1327
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));
1328
1463
  } else if (node.type.name === "hardBreak") {
1329
1464
  flushCurrentInline();
1330
1465
  content.push(createBreakRun(expectHardBreakAttrs(node), node.marks, formattingContext));
@@ -1379,11 +1514,11 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
1379
1514
  });
1380
1515
  flushEmptyHyperlinksThroughOffset(Number.POSITIVE_INFINITY);
1381
1516
  flushCurrentInline();
1382
- for (const commentId of openedComments) content.push({
1517
+ for (const commentId of byCommentId(openedComments)) content.push({
1383
1518
  type: "commentRangeEnd",
1384
1519
  id: commentId
1385
1520
  });
1386
- return content;
1521
+ return nestInlineWrapperGroups(content, wrapperGroups);
1387
1522
  }
1388
1523
  function createTrackedChangeRun({ baseParagraphFormatting, inheritedFormatting, marks, node, paragraphMarkFormatting, paragraphMarkPrecedesStyle, styleResolver }) {
1389
1524
  const formattingContext = {
@@ -1408,6 +1543,7 @@ function createTrackedChangeRun({ baseParagraphFormatting, inheritedFormatting,
1408
1543
  };
1409
1544
  restoreRunPropertyChanges(run, marks);
1410
1545
  } else if (node.type.name === "symbol") run = createSymbolRun(node, marks, formattingContext);
1546
+ else if (node.type.name === "preservedXml") run = createPreservedXmlRun(node, marks, formattingContext);
1411
1547
  else if (node.type.name === "hardBreak") run = createBreakRun(expectHardBreakAttrs(node), marks, formattingContext);
1412
1548
  else if (node.type.name === "pageBreakRun") {
1413
1549
  const { clear } = expectPageBreakRunAttrs(node);
@@ -1582,6 +1718,16 @@ function addNodeToHyperlink({ baseParagraphFormatting, hyperlink, inheritedForma
1582
1718
  }));
1583
1719
  return;
1584
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
+ }
1585
1731
  if (node.type.name === "hardBreak") {
1586
1732
  hyperlink.children.push(createBreakRun(expectHardBreakAttrs(node), nonLinkMarks, {
1587
1733
  baseParagraphFormatting,
@@ -1679,6 +1825,44 @@ function createSymbolRun(node, marks, formattingContext) {
1679
1825
  restoreRunPropertyChanges(run, marks);
1680
1826
  return run;
1681
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
+ }
1682
1866
  function restoreRunPropertyChanges(run, marks) {
1683
1867
  const changeMark = marks.find((mark) => mark.type.name === "runPropertyChange");
1684
1868
  if (!changeMark) return;
@@ -1821,7 +2005,7 @@ function createFieldFromNode(node, { baseParagraphFormatting, inheritedFormattin
1821
2005
  paragraphMarkFormatting,
1822
2006
  paragraphMarkPrecedesStyle: paragraphMarkPrecedesStyle ?? false,
1823
2007
  styleResolver: styleResolver ?? null
1824
- }).filter((content) => content.type === "run" || content.type === "hyperlink");
2008
+ }).filter((content) => content.type === "run" || content.type === "hyperlink" || content.type === "preservedInline");
1825
2009
  const displayText = attrs.displayText ?? "";
1826
2010
  const displayRun = {
1827
2011
  type: "run",
@@ -1842,8 +2026,8 @@ function createFieldFromNode(node, { baseParagraphFormatting, inheritedFormattin
1842
2026
  fieldCode: [],
1843
2027
  fieldResult: fieldContent.length > 0 ? fieldContent.filter((content) => content.type === "run") : fallbackFieldContent
1844
2028
  };
1845
- if (attrs.fldLock) complex.fldLock = true;
1846
- 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;
1847
2031
  return complex;
1848
2032
  }
1849
2033
  const simple = {
@@ -1852,8 +2036,8 @@ function createFieldFromNode(node, { baseParagraphFormatting, inheritedFormattin
1852
2036
  fieldType: attrs.fieldType,
1853
2037
  content: fieldContent.length > 0 ? fieldContent : fallbackFieldContent
1854
2038
  };
1855
- if (attrs.fldLock) simple.fldLock = true;
1856
- 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;
1857
2041
  return simple;
1858
2042
  }
1859
2043
  const synchronizeFieldDisplayText = (content, displayText, fallbackRun) => {
@@ -1864,6 +2048,7 @@ const synchronizeFieldDisplayText = (content, displayText, fallbackRun) => {
1864
2048
  visit(child);
1865
2049
  continue;
1866
2050
  }
2051
+ if (child.type !== "hyperlink") continue;
1867
2052
  for (const hyperlinkChild of child.children) if (hyperlinkChild.type === "run") visit(hyperlinkChild);
1868
2053
  }
1869
2054
  };
@@ -1909,7 +2094,7 @@ function createInlineSdtFromNode(node, textBoxAnchorMarkers, formattingContext)
1909
2094
  return {
1910
2095
  type: "inlineSdt",
1911
2096
  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")
2097
+ content: extractParagraphContent(node, void 0, void 0, textBoxAnchorMarkers, false, formattingContext).filter(isInlineSdtContent)
1913
2098
  };
1914
2099
  }
1915
2100
  /**
@@ -1942,9 +2127,13 @@ function createImageRun(node) {
1942
2127
  if (attrs.docPrName != null) image.docPrName = attrs.docPrName;
1943
2128
  if (attrs.alt != null) image.alt = attrs.alt;
1944
2129
  if (attrs.title != null) image.title = attrs.title;
1945
- const imageTransform = parseTransformAttr(attrs.transform);
2130
+ const imageTransform = readAuthoredTransform(attrs);
1946
2131
  if (imageTransform) image.transform = imageTransform;
1947
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
+ };
1948
2137
  const imagePosition = imagePositionFromAttrs(attrs.position);
1949
2138
  if (imagePosition) image.position = imagePosition;
1950
2139
  if (attrs.layoutInCell !== void 0) image.layoutInCell = attrs.layoutInCell;
@@ -2049,7 +2238,7 @@ function createShapeRun(node) {
2049
2238
  if (attrs.title !== void 0) shape.title = attrs.title;
2050
2239
  const geometryAdjustments = parseShapeGeometryAdjustments(attrs.geometryAdjustments);
2051
2240
  if (geometryAdjustments !== void 0) shape.geometryAdjustments = geometryAdjustments;
2052
- const shapeTransform = parseTransformAttr(attrs.transform);
2241
+ const shapeTransform = readAuthoredTransform(attrs);
2053
2242
  if (shapeTransform) shape.transform = shapeTransform;
2054
2243
  const wrap = { type: attrs.wrapType || "inline" };
2055
2244
  assignWrapDistances(wrap, attrs);
@@ -2860,6 +3049,7 @@ function convertPMTableRow(node, documentCounts, activeVerticalMerges, styleReso
2860
3049
  const rowFormatting = tableRowAttrsToFormatting(attrs);
2861
3050
  if (rowFormatting) row.formatting = rowFormatting;
2862
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;
2863
3053
  if (attrs.trIns) row.structuralChange = {
2864
3054
  type: "tableRowInsertion",
2865
3055
  info: {
@@ -2952,6 +3142,13 @@ function convertPMTableCell(node, documentCounts, styleResolver = null) {
2952
3142
  textBoxAnchorMarkers,
2953
3143
  styleResolver
2954
3144
  });
3145
+ else if (contentNode.type.name === "preservedBlock") {
3146
+ content.push({
3147
+ type: "preservedBlock",
3148
+ xml: expectPreservedBlockAttrs(contentNode).xml
3149
+ });
3150
+ previousStandaloneTextBox = null;
3151
+ }
2955
3152
  });
2956
3153
  removeUnresolvedTextBoxAnchors(content, textBoxAnchorMarkers);
2957
3154
  const cell = {
@@ -3086,7 +3283,7 @@ function convertPMTextBox(node, styleResolver = null) {
3086
3283
  if (attrs.textBoxName !== void 0) shape.name = attrs.textBoxName;
3087
3284
  if (attrs.alt !== void 0) shape.alt = attrs.alt;
3088
3285
  if (attrs.title !== void 0) shape.title = attrs.title;
3089
- const transform = parseTransformAttr(attrs.transform);
3286
+ const transform = readAuthoredTransform(attrs);
3090
3287
  if (transform) shape.transform = transform;
3091
3288
  if (attrs.fillColor) shape.fill = {
3092
3289
  type: "solid",
@@ -3156,8 +3353,10 @@ function updateDocumentContent(originalDocument, pmDoc) {
3156
3353
  * Used for converting edited header/footer PM content back to the document
3157
3354
  * model.
3158
3355
  */
3159
- function proseDocToBlocks(pmDoc, baseContent, styles, options) {
3160
- 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);
3161
3360
  const linkedSources = restoreLinkedParagraphPropertySources(blocks);
3162
3361
  if (baseContent) restoreParagraphPropertySources(blocks, baseContent, linkedSources.targets, linkedSources.sources);
3163
3362
  return blocks;
@@ -1,4 +1,4 @@
1
- import { EmptyFieldResultMode, ProseDocToBlocksOptions, fromProseDoc, proseDocToBlocks, updateDocumentContent } from "./fromProseDoc.js";
1
+ import { fromProseDoc, proseDocToBlocks, updateDocumentContent } from "./fromProseDoc.js";
2
2
  import { ToProseDocOptions, createEmptyDoc, headerFooterToProseDoc, toProseDoc } from "./toProseDoc.js";
3
3
  import { ProseMirrorDocumentValidationIssue, ValidateProseMirrorDocumentResult, assertValidProseMirrorDocument, formatProseMirrorDocumentIssues, validateProseMirrorDocument } from "../validation.js";
4
- export { type EmptyFieldResultMode, type ProseDocToBlocksOptions, type ProseMirrorDocumentValidationIssue, type ToProseDocOptions, type ValidateProseMirrorDocumentResult, assertValidProseMirrorDocument, createEmptyDoc, formatProseMirrorDocumentIssues, fromProseDoc, headerFooterToProseDoc, proseDocToBlocks, toProseDoc, updateDocumentContent, validateProseMirrorDocument };
4
+ export { type ProseMirrorDocumentValidationIssue, type ToProseDocOptions, type ValidateProseMirrorDocumentResult, assertValidProseMirrorDocument, createEmptyDoc, formatProseMirrorDocumentIssues, fromProseDoc, headerFooterToProseDoc, proseDocToBlocks, toProseDoc, updateDocumentContent, validateProseMirrorDocument };
@@ -1,16 +1,9 @@
1
1
  import { document_d_exports } from "../../types/document.js";
2
2
  import { StyleEngine } from "../../style-engine/styleEngine.js";
3
3
  import "../../style-engine/index.js";
4
+ import { ParseContext } from "../../docx/parseContext.js";
4
5
  import { Node } from "prosemirror-model";
5
6
  //#region src/prosemirror/conversion/toProseDoc.d.ts
6
- type UnsupportedDocxToProseMirrorOwner = "complex-field-instruction" | "field-result" | "page-break-bearing-run" | "paragraph-borders" | "paragraph-frame" | "paragraph-outline" | "paragraph-text-box-anchor" | "table-cell" | "text-box";
7
- declare const UnsupportedDocxToProseMirrorConversionError_base: import("better-result").TaggedErrorClass<"UnsupportedDocxToProseMirrorConversionError">;
8
- /** DOCX content that cannot be preserved by the editable ProseMirror model. */
9
- declare class UnsupportedDocxToProseMirrorConversionError extends UnsupportedDocxToProseMirrorConversionError_base<{
10
- message: string;
11
- owner: UnsupportedDocxToProseMirrorOwner;
12
- contentType: document_d_exports.RunContent["type"];
13
- }> {}
14
7
  /**
15
8
  * Options for document conversion
16
9
  */
@@ -19,6 +12,11 @@ type ToProseDocOptions = {
19
12
  styles?: document_d_exports.StyleDefinitions;
20
13
  /** Theme used when converting themed table/cell values in nested content. */
21
14
  theme?: document_d_exports.Theme | null;
15
+ /**
16
+ * Where a projection approximation is reported, on the channel the parsers
17
+ * already use. Absent means nobody is listening, not that nothing happened.
18
+ */
19
+ warn?: ParseContext["warn"];
22
20
  };
23
21
  /**
24
22
  * Convert a Document to a ProseMirror document
@@ -53,4 +51,4 @@ declare function footnoteToProseDoc(content: document_d_exports.BlockContent[],
53
51
  */
54
52
  declare function createEmptyDoc(): Node;
55
53
  //#endregion
56
- export { ToProseDocOptions, UnsupportedDocxToProseMirrorConversionError, createEmptyDoc, footnoteToProseDoc, headerFooterToProseDoc, resolveParagraphDefaultTextFormatting, standaloneTableCellToProseMirror, toProseDoc };
54
+ export { ToProseDocOptions, createEmptyDoc, footnoteToProseDoc, headerFooterToProseDoc, resolveParagraphDefaultTextFormatting, standaloneTableCellToProseMirror, toProseDoc };