@stll/folio-core 0.43.0 → 0.44.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 (183) hide show
  1. package/dist/ai-edits/headless.js +6 -5
  2. package/dist/ai-edits/index.d.ts +2 -2
  3. package/dist/ai-edits/index.js +2 -2
  4. package/dist/ai-edits/snapshot.js +13 -9
  5. package/dist/compare/content-alignment.js +16 -1
  6. package/dist/compare/inline-atoms.js +1 -1
  7. package/dist/compare/style-resources.js +6 -0
  8. package/dist/docx/appVersionNormalization.d.ts +0 -18
  9. package/dist/docx/blockContentParser.js +8 -0
  10. package/dist/docx/blockRangeMarkers.d.ts +36 -0
  11. package/dist/docx/blockRangeMarkers.js +59 -0
  12. package/dist/docx/bookmarkParser.d.ts +2 -20
  13. package/dist/docx/bookmarkParser.js +6 -30
  14. package/dist/docx/borderParser.d.ts +13 -0
  15. package/dist/docx/borderParser.js +71 -0
  16. package/dist/docx/builtInStyles.d.ts +165 -0
  17. package/dist/docx/builtInStyles.js +239 -0
  18. package/dist/docx/commentIdNormalization.d.ts +3 -1
  19. package/dist/docx/commentIdNormalization.js +18 -1
  20. package/dist/docx/commentParser.d.ts +2 -1
  21. package/dist/docx/commentParser.js +34 -7
  22. package/dist/docx/commentReferenceNormalization.d.ts +4 -1
  23. package/dist/docx/commentReferenceNormalization.js +23 -14
  24. package/dist/docx/danglingRelationshipReferences.d.ts +15 -0
  25. package/dist/docx/danglingRelationshipReferences.js +30 -0
  26. package/dist/docx/defaultParagraphStyle.d.ts +18 -1
  27. package/dist/docx/defaultParagraphStyle.js +23 -1
  28. package/dist/docx/documentParser.d.ts +2 -1
  29. package/dist/docx/documentParser.js +2 -2
  30. package/dist/docx/drawingUtils.d.ts +8 -1
  31. package/dist/docx/drawingUtils.js +12 -3
  32. package/dist/docx/fieldParser.js +3 -5
  33. package/dist/docx/footnoteParser.d.ts +3 -2
  34. package/dist/docx/footnoteParser.js +19 -4
  35. package/dist/docx/groupDrawingParser.js +1 -1
  36. package/dist/docx/headerFooterRefParser.d.ts +4 -3
  37. package/dist/docx/headerFooterRefParser.js +42 -12
  38. package/dist/docx/headerFooterReferenceNormalization.d.ts +4 -1
  39. package/dist/docx/headerFooterReferenceNormalization.js +5 -1
  40. package/dist/docx/hyperlinkParser.js +11 -15
  41. package/dist/docx/imageParser.d.ts +1 -1
  42. package/dist/docx/imageParser.js +22 -18
  43. package/dist/docx/imageRawXml.js +5 -5
  44. package/dist/docx/markupRangeMarker.d.ts +15 -0
  45. package/dist/docx/markupRangeMarker.js +44 -0
  46. package/dist/docx/noteReferenceStyles.d.ts +29 -0
  47. package/dist/docx/noteReferenceStyles.js +70 -0
  48. package/dist/docx/numberingReferenceNormalization.d.ts +4 -1
  49. package/dist/docx/numberingReferenceNormalization.js +20 -1
  50. package/dist/docx/paraIdRangeNormalization.d.ts +0 -19
  51. package/dist/docx/paragraphParser.js +66 -99
  52. package/dist/docx/paragraphPropertySource.js +1 -0
  53. package/dist/docx/paragraphTraversal.d.ts +37 -1
  54. package/dist/docx/paragraphTraversal.js +84 -1
  55. package/dist/docx/parseContext.d.ts +37 -0
  56. package/dist/docx/parseContext.js +67 -0
  57. package/dist/docx/parseWarningMessage.d.ts +6 -0
  58. package/dist/docx/parseWarningMessage.js +44 -0
  59. package/dist/docx/parser.js +81 -27
  60. package/dist/docx/relsParser.d.ts +28 -11
  61. package/dist/docx/relsParser.js +26 -13
  62. package/dist/docx/revisionIdNormalization.js +81 -7
  63. package/dist/docx/rezip.js +63 -22
  64. package/dist/docx/runConsolidator.js +1 -2
  65. package/dist/docx/runParser.d.ts +8 -1
  66. package/dist/docx/runParser.js +30 -48
  67. package/dist/docx/sectionParser.d.ts +2 -1
  68. package/dist/docx/sectionParser.js +21 -65
  69. package/dist/docx/serializer/borderSerializer.d.ts +1 -2
  70. package/dist/docx/serializer/commentSerializer.js +22 -9
  71. package/dist/docx/serializer/documentSerializer.d.ts +1 -5
  72. package/dist/docx/serializer/documentSerializer.js +6 -16
  73. package/dist/docx/serializer/headerFooterSerializer.js +5 -0
  74. package/dist/docx/serializer/markupRangeAttributes.d.ts +8 -0
  75. package/dist/docx/serializer/markupRangeAttributes.js +24 -0
  76. package/dist/docx/serializer/noteSerializer.js +5 -0
  77. package/dist/docx/serializer/paragraphSerializer.d.ts +1 -5
  78. package/dist/docx/serializer/paragraphSerializer.js +29 -35
  79. package/dist/docx/serializer/runSerializer.js +13 -7
  80. package/dist/docx/serializer/tableSerializer.js +28 -13
  81. package/dist/docx/serializer/textFormattingSerializer.d.ts +2 -3
  82. package/dist/docx/server/build.js +8 -1
  83. package/dist/docx/server/createBilingualDocument.js +10 -18
  84. package/dist/docx/server/extractDocxText.js +3 -4
  85. package/dist/docx/shadingParser.d.ts +6 -0
  86. package/dist/docx/shadingParser.js +32 -0
  87. package/dist/docx/shapeParser.js +3 -3
  88. package/dist/docx/styleParser.js +13 -87
  89. package/dist/docx/styleReferenceResolution.d.ts +36 -0
  90. package/dist/docx/styleReferenceResolution.js +51 -0
  91. package/dist/docx/tableLook.d.ts +57 -0
  92. package/dist/docx/tableLook.js +63 -0
  93. package/dist/docx/tableParser.d.ts +7 -9
  94. package/dist/docx/tableParser.js +64 -110
  95. package/dist/docx/textBoxParser.js +4 -4
  96. package/dist/docx/trackedMoveRangeNormalization.d.ts +3 -1
  97. package/dist/docx/trackedMoveRangeNormalization.js +11 -21
  98. package/dist/docx/transitionalSpelling.d.ts +13 -2
  99. package/dist/docx/transitionalSpelling.js +23 -1
  100. package/dist/docx/verbatimCapture.js +4 -11
  101. package/dist/docx/vmlImageParser.js +2 -2
  102. package/dist/docx/watermarkParser.js +2 -2
  103. package/dist/docx/xmlParser.d.ts +22 -32
  104. package/dist/docx/xmlParser.js +36 -21
  105. package/dist/internal/pageBreakRunSourceDescendantIndex.js +2 -1
  106. package/dist/internal/paragraphFormattingSerialization.d.ts +2 -3
  107. package/dist/internal/paragraphFormattingSerialization.js +26 -6
  108. package/dist/layout-bridge/convert/footnoteLayout.js +2 -7
  109. package/dist/layout-engine/index.d.ts +2 -2
  110. package/dist/layout-engine/index.js +2 -2
  111. package/dist/layout-engine/measure/measureBlocks.js +1 -6
  112. package/dist/layout-engine/types.d.ts +8 -2
  113. package/dist/layout-engine/types.js +35 -2
  114. package/dist/markdown/index.js +1 -1
  115. package/dist/markdown/internals.d.ts +6 -1
  116. package/dist/markdown/internals.js +14 -1
  117. package/dist/markdown/renderBlock.js +35 -21
  118. package/dist/markdown/renderParagraph.js +14 -5
  119. package/dist/markdown/renderRuns.js +4 -3
  120. package/dist/markdown/renderTable.js +4 -3
  121. package/dist/markdown/trailers.js +41 -7
  122. package/dist/markdown/types.d.ts +3 -7
  123. package/dist/prosemirror/attrs/index.js +2 -5
  124. package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +11 -1
  125. package/dist/prosemirror/bookmarkBoundaryAttrs.js +18 -3
  126. package/dist/prosemirror/commands/index.d.ts +3 -3
  127. package/dist/prosemirror/commands/index.js +2 -2
  128. package/dist/prosemirror/commands/paragraph.d.ts +3 -3
  129. package/dist/prosemirror/commands/paragraph.js +2 -2
  130. package/dist/prosemirror/commentIdAllocator.js +2 -7
  131. package/dist/prosemirror/conversion/fromProseDoc.js +129 -40
  132. package/dist/prosemirror/conversion/toProseDoc.d.ts +1 -14
  133. package/dist/prosemirror/conversion/toProseDoc.js +375 -316
  134. package/dist/prosemirror/extensions/core/ParagraphExtension.d.ts +14 -1
  135. package/dist/prosemirror/extensions/core/ParagraphExtension.js +11 -6
  136. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +3 -3
  137. package/dist/prosemirror/extensions/features/PasteCleanupExtension.d.ts +4 -1
  138. package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +6 -2
  139. package/dist/prosemirror/extensions/features/pastedHeadingStyles.d.ts +7 -0
  140. package/dist/prosemirror/extensions/features/pastedHeadingStyles.js +74 -0
  141. package/dist/prosemirror/extensions/marks/markUtils.d.ts +11 -3
  142. package/dist/prosemirror/extensions/marks/markUtils.js +98 -19
  143. package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +7 -3
  144. package/dist/prosemirror/extensions/nodes/ImageExtension.js +2 -1
  145. package/dist/prosemirror/extensions/nodes/ShapeExtension.js +1 -0
  146. package/dist/prosemirror/extensions/nodes/TableExtension.js +15 -1
  147. package/dist/prosemirror/extensions/types.d.ts +2 -2
  148. package/dist/prosemirror/index.d.ts +3 -3
  149. package/dist/prosemirror/index.js +3 -3
  150. package/dist/prosemirror/insertOperations.d.ts +9 -2
  151. package/dist/prosemirror/insertOperations.js +9 -4
  152. package/dist/prosemirror/paragraphFormattingProvenance.d.ts +159 -0
  153. package/dist/prosemirror/paragraphFormattingProvenance.js +106 -0
  154. package/dist/prosemirror/plugins/documentStyles.d.ts +9 -1
  155. package/dist/prosemirror/plugins/documentStyles.js +11 -1
  156. package/dist/prosemirror/plugins/index.d.ts +2 -2
  157. package/dist/prosemirror/plugins/index.js +2 -2
  158. package/dist/prosemirror/plugins/revisionIds.d.ts +11 -2
  159. package/dist/prosemirror/plugins/revisionIds.js +21 -6
  160. package/dist/prosemirror/runFormattingReconciliation.js +3 -2
  161. package/dist/prosemirror/runStyleFormatting.d.ts +1 -1
  162. package/dist/prosemirror/schema/nodes.d.ts +31 -0
  163. package/dist/prosemirror/styles/resolvedStyleAttrs.js +2 -0
  164. package/dist/prosemirror/styles/styleResolver.d.ts +9 -0
  165. package/dist/prosemirror/styles/styleResolver.js +12 -0
  166. package/dist/style-engine/styleEngine.d.ts +3 -0
  167. package/dist/style-engine/styleEngine.js +3 -0
  168. package/dist/style-sets/extract.js +1 -23
  169. package/dist/style-sets/stellaStyle.js +46 -39
  170. package/dist/style-sets/styleSetNormalization.d.ts +19 -0
  171. package/dist/style-sets/styleSetNormalization.js +99 -0
  172. package/dist/types/content.d.ts +2 -2
  173. package/dist/utils/createDocument.js +145 -20
  174. package/dist/utils/headingCollector.d.ts +8 -5
  175. package/dist/utils/headingCollector.js +23 -25
  176. package/dist/utils/tableOfContentsStyle.js +9 -2
  177. package/package.json +2 -2
  178. package/dist/docx/textWhitespace.d.ts +0 -4
  179. package/dist/docx/textWhitespace.js +0 -4
  180. package/dist/layout-bridge/engine/tableWidthUtils.d.ts +0 -6
  181. package/dist/layout-bridge/engine/tableWidthUtils.js +0 -25
  182. package/dist/markdown/headings.d.ts +0 -13
  183. package/dist/markdown/headings.js +0 -20
@@ -1,6 +1,9 @@
1
1
  import { resolveColorValueToHex } from "../../docx/drawingUtils.js";
2
2
  import { isNumberingReference } from "../../docx/numberingReference.js";
3
3
  import { PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR, createProseParagraphWithPropertySource, getDocumentParagraphPropertySourceContract, recreateProseNodeWithParagraphPropertySource, transportTableCellsWithParagraphPropertySources } from "../../docx/paragraphPropertySource.js";
4
+ import { isBaselineVertAlign } from "../../docx/runParser.js";
5
+ import { resolveTableLook } from "../../docx/tableLook.js";
6
+ import { isCellMergeContinuation } from "../../docx/tableParser.js";
4
7
  import { buildPageBreakRunSourceDescendantIndex } from "../../internal/pageBreakRunSourceDescendantIndex.js";
5
8
  import { createStyleEngine } from "../../style-engine/styleEngine.js";
6
9
  import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
@@ -9,20 +12,19 @@ import { tableOfContentsStyleLevel } from "../../utils/tableOfContentsStyle.js";
9
12
  import { mergeTextFormatting } from "../../utils/textFormattingMerge.js";
10
13
  import { emuToPixels } from "../../utils/units.js";
11
14
  import { setAutospacingBaseValue } from "../autospacingBase.js";
12
- import { buildRunFormattingOverrideAttrs } from "../extensions/marks/RunFormattingOverrideExtension.js";
15
+ import { textFormattingToMarks } from "../extensions/marks/markUtils.js";
13
16
  import { listRenderingAttrPatch } from "../listRenderingAttrs.js";
14
17
  import { stampNumberedRefFieldBaselines } from "../numberedRefFields.js";
15
18
  import { pageBreakRunParagraphProjectionDispositionForFeatures } from "../pageBreakRunProjection.js";
16
19
  import { directionFromBidi } from "../paragraphDirection.js";
20
+ import { styleResolvedParagraphFormatting } from "../paragraphFormattingProvenance.js";
17
21
  import { lineSpacingProvenanceFromSpacing } from "../paragraphSpacing.js";
18
22
  import { getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, resolveParagraphBodyRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting } from "../runStyleFormatting.js";
19
23
  import { schema } from "../schema/index.js";
20
- import { COMPLEX_SCRIPT_RUN_PROPERTY_KEYS } from "../schema/marks.js";
21
24
  import { cascadeStyleTextFormatting } from "../styles/styleToggleCascade.js";
22
25
  import { canCarryTrackedRunMark, trackedRunInlineAtomDisposition } from "../trackedRunInlineAtoms.js";
23
26
  import { assertValidProseMirrorDocument } from "../validation.js";
24
27
  import { resolveEffectiveTableCellFormatting } from "./effectiveTableCellFormatting.js";
25
- import { shadingToRunShadingAttrs } from "./runShadingMark.js";
26
28
  import { sdtAttrsFromProperties } from "./sdtAttrs.js";
27
29
  import { TaggedError, panic } from "better-result";
28
30
  import { DRAWING_RAW_XML_MODES } from "@stll/docx-core/model";
@@ -77,25 +79,72 @@ const collectPairedBookmarkIds = (blocks) => {
77
79
  for (const content of run.content) if (content.type === "shape" && content.shape.textBody) visitBlocks(content.shape.textBody.content);
78
80
  };
79
81
  const visitHyperlink = (hyperlink) => {
80
- for (const child of hyperlink.children) if (child.type === "bookmarkStart") countBoundary(child.id, "start");
81
- else if (child.type === "bookmarkEnd") countBoundary(child.id, "end");
82
- else visitRun(child);
82
+ for (const child of hyperlink.children) switch (child.type) {
83
+ case "bookmarkStart":
84
+ countBoundary(child.id, "start");
85
+ break;
86
+ case "bookmarkEnd":
87
+ countBoundary(child.id, "end");
88
+ break;
89
+ case "run":
90
+ visitRun(child);
91
+ break;
92
+ default: panic(`Unsupported hyperlink child: ${JSON.stringify(child)}`);
93
+ }
83
94
  };
84
95
  const visitParagraphContent = (content) => {
85
- if (content.type === "bookmarkStart") countBoundary(content.id, "start");
86
- else if (content.type === "bookmarkEnd") countBoundary(content.id, "end");
87
- else if (content.type === "run") visitRun(content);
88
- else if (content.type === "hyperlink") visitHyperlink(content);
89
- else if (content.type === "simpleField") for (const child of content.content) if (child.type === "hyperlink") visitHyperlink(child);
90
- else visitRun(child);
91
- else if (content.type === "complexField") for (const run of [...content.fieldCode ?? [], ...content.fieldResult]) visitRun(run);
92
- else if (content.type === "inlineSdt") for (const child of content.content) visitParagraphContent(child);
93
- else if (content.type === "insertion" || content.type === "deletion" || content.type === "moveFrom" || content.type === "moveTo") for (const child of content.content) visitParagraphContent(child);
96
+ switch (content.type) {
97
+ case "bookmarkStart":
98
+ countBoundary(content.id, "start");
99
+ return;
100
+ case "bookmarkEnd":
101
+ countBoundary(content.id, "end");
102
+ return;
103
+ case "run":
104
+ visitRun(content);
105
+ return;
106
+ case "hyperlink":
107
+ visitHyperlink(content);
108
+ return;
109
+ case "simpleField":
110
+ for (const child of content.content) if (child.type === "hyperlink") visitHyperlink(child);
111
+ else visitRun(child);
112
+ return;
113
+ case "complexField":
114
+ for (const run of [...content.fieldCode ?? [], ...content.fieldResult]) visitRun(run);
115
+ return;
116
+ case "inlineSdt":
117
+ case "insertion":
118
+ case "deletion":
119
+ case "moveFrom":
120
+ case "moveTo":
121
+ case "bidiWrapper":
122
+ for (const child of content.content) visitParagraphContent(child);
123
+ return;
124
+ case "commentRangeStart":
125
+ case "commentRangeEnd":
126
+ case "commentReference":
127
+ case "moveFromRangeStart":
128
+ case "moveFromRangeEnd":
129
+ case "moveToRangeStart":
130
+ case "moveToRangeEnd":
131
+ case "mathEquation": return;
132
+ default: panic(`Unsupported paragraph content: ${JSON.stringify(content)}`);
133
+ }
94
134
  };
95
135
  const visitBlocks = (nestedBlocks) => {
96
- for (const block of nestedBlocks) if (block.type === "paragraph") for (const content of block.content) visitParagraphContent(content);
97
- else if (block.type === "table") for (const row of block.rows) for (const cell of row.cells) visitBlocks(cell.content);
98
- else visitBlocks(block.content);
136
+ for (const block of nestedBlocks) switch (block.type) {
137
+ case "paragraph":
138
+ for (const content of block.content) visitParagraphContent(content);
139
+ break;
140
+ case "table":
141
+ for (const row of block.rows) for (const cell of row.cells) visitBlocks(cell.content);
142
+ break;
143
+ case "blockSdt":
144
+ visitBlocks(block.content);
145
+ break;
146
+ default: panic(`Unsupported block content: ${JSON.stringify(block)}`);
147
+ }
99
148
  };
100
149
  visitBlocks(blocks);
101
150
  return new Set([...counts].flatMap(([id, count]) => count.starts === 1 && count.ends === 1 && count.firstStart !== void 0 && count.firstEnd !== void 0 && count.firstStart < count.firstEnd ? [id] : []));
@@ -121,12 +170,21 @@ function toProseDoc(document, options) {
121
170
  };
122
171
  const convertBodyBlocks = (blocks) => {
123
172
  const out = [];
124
- for (const block of blocks) if (block.type === "paragraph") out.push(...convertParagraphWithTextBoxes(block, styleResolver, {
125
- textBoxGroupId: nextTextBoxGroupId(),
126
- context: conversionContext
127
- }));
128
- else if (block.type === "table") out.push(convertTable(block, styleResolver, conversionContext));
129
- else out.push(convertBlockSdt(block, convertBodyBlocks));
173
+ for (const block of blocks) switch (block.type) {
174
+ case "paragraph":
175
+ out.push(...convertParagraphWithTextBoxes(block, styleResolver, {
176
+ textBoxGroupId: nextTextBoxGroupId(),
177
+ context: conversionContext
178
+ }));
179
+ break;
180
+ case "table":
181
+ out.push(convertTable(block, styleResolver, conversionContext));
182
+ break;
183
+ case "blockSdt":
184
+ out.push(convertBlockSdt(block, convertBodyBlocks));
185
+ break;
186
+ default: panic(`Unsupported block content: ${JSON.stringify(block)}`);
187
+ }
130
188
  return out;
131
189
  };
132
190
  nodes.push(...convertBodyBlocks(paragraphs));
@@ -265,58 +323,95 @@ function convertParagraph(paragraph, styleResolver, context, activeCommentIds, e
265
323
  const emitTrackedChange = (change, markType, moveKind) => {
266
324
  emitInlineNodes(convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, moveKind, textBoxAnchors));
267
325
  };
268
- for (const content of paragraph.content) if (content.type === "commentRangeStart") commentIds.add(content.id);
269
- else if (content.type === "commentRangeEnd") commentIds.delete(content.id);
270
- else if (content.type === "commentReference") anchorPointComment(inlineNodes, content.id);
271
- else if (content.type === "run") emitInlineNodes(convertRun(content, getInheritedRunFormatting(content.formatting), nextPageBreakRunOwnerId, styleResolver, textBoxAnchors));
272
- else if (content.type === "hyperlink") {
273
- const linkNodes = convertHyperlink(content, {
274
- getInheritedRunFormatting,
275
- styleResolver,
276
- hyperlinkIndex: nextHyperlinkInstanceIndex(),
277
- textBoxAnchors,
278
- nextPageBreakRunOwnerId
279
- });
280
- if (linkNodes.length === 0) {
281
- emptyHyperlinks ??= [];
282
- emptyHyperlinks.push({
283
- offset: inlineOffset,
284
- ...content.href !== void 0 ? { href: content.href } : {},
285
- ...content.anchor !== void 0 ? { anchor: content.anchor } : {},
286
- ...content.tooltip !== void 0 ? { tooltip: content.tooltip } : {},
287
- ...content.rId !== void 0 ? { rId: content.rId } : {}
326
+ for (const content of withoutBidiWrappers(paragraph.content)) switch (content.type) {
327
+ case "commentRangeStart":
328
+ commentIds.add(content.id);
329
+ break;
330
+ case "commentRangeEnd":
331
+ commentIds.delete(content.id);
332
+ break;
333
+ case "commentReference":
334
+ anchorPointComment(inlineNodes, content.id);
335
+ break;
336
+ case "run":
337
+ emitInlineNodes(convertRun(content, getInheritedRunFormatting(content.formatting), nextPageBreakRunOwnerId, styleResolver, textBoxAnchors));
338
+ break;
339
+ case "hyperlink": {
340
+ const linkNodes = convertHyperlink(content, {
341
+ getInheritedRunFormatting,
342
+ styleResolver,
343
+ hyperlinkIndex: nextHyperlinkInstanceIndex(),
344
+ textBoxAnchors,
345
+ nextPageBreakRunOwnerId
288
346
  });
289
- continue;
347
+ if (linkNodes.length === 0) {
348
+ emptyHyperlinks ??= [];
349
+ emptyHyperlinks.push({
350
+ offset: inlineOffset,
351
+ ...content.href !== void 0 ? { href: content.href } : {},
352
+ ...content.anchor !== void 0 ? { anchor: content.anchor } : {},
353
+ ...content.tooltip !== void 0 ? { tooltip: content.tooltip } : {},
354
+ ...content.rId !== void 0 ? { rId: content.rId } : {}
355
+ });
356
+ break;
357
+ }
358
+ emitInlineNodes(linkNodes);
359
+ break;
290
360
  }
291
- emitInlineNodes(linkNodes);
292
- } else if (content.type === "simpleField" || content.type === "complexField") emitInlineNode(convertField(content, {
293
- getInheritedRunFormatting,
294
- styleResolver,
295
- nextHyperlinkInstanceIndex,
296
- nextPageBreakRunOwnerId,
297
- textBoxAnchors
298
- }));
299
- else if (content.type === "inlineSdt") emitInlineNode(convertInlineSdt(content, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, textBoxAnchors));
300
- else if (content.type === "insertion" || content.type === "moveTo") emitTrackedChange(content, "insertion", content.type === "moveTo" ? "moveTo" : null);
301
- else if (content.type === "deletion" || content.type === "moveFrom") emitTrackedChange(content, "deletion", content.type === "moveFrom" ? "moveFrom" : null);
302
- else if (content.type === "mathEquation") emitInlineNode(convertMathEquation(content));
303
- else if (content.type === "bookmarkStart" && pairedBookmarkIds.has(content.id)) emitInlineNode(schema.node("bookmarkBoundary", {
304
- type: "start",
305
- id: content.id,
306
- name: content.name,
307
- colFirst: content.colFirst,
308
- colLast: content.colLast
309
- }));
310
- else if (content.type === "bookmarkEnd" && pairedBookmarkIds.has(content.id)) emitInlineNode(schema.node("bookmarkBoundary", {
311
- type: "end",
312
- id: content.id
313
- }));
314
- else if (content.type === "bookmarkStart") {
315
- if (!bookmarksArr) bookmarksArr = [];
316
- bookmarksArr.push({
317
- id: content.id,
318
- name: content.name
319
- });
361
+ case "simpleField":
362
+ case "complexField":
363
+ emitInlineNode(convertField(content, {
364
+ getInheritedRunFormatting,
365
+ styleResolver,
366
+ nextHyperlinkInstanceIndex,
367
+ nextPageBreakRunOwnerId,
368
+ textBoxAnchors
369
+ }));
370
+ break;
371
+ case "inlineSdt":
372
+ emitInlineNode(convertInlineSdt(content, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, textBoxAnchors));
373
+ break;
374
+ case "insertion":
375
+ case "moveTo":
376
+ emitTrackedChange(content, "insertion", content.type === "moveTo" ? "moveTo" : null);
377
+ break;
378
+ case "deletion":
379
+ case "moveFrom":
380
+ emitTrackedChange(content, "deletion", content.type === "moveFrom" ? "moveFrom" : null);
381
+ break;
382
+ case "mathEquation":
383
+ emitInlineNode(convertMathEquation(content));
384
+ break;
385
+ case "bookmarkStart":
386
+ if (pairedBookmarkIds.has(content.id)) {
387
+ emitInlineNode(schema.node("bookmarkBoundary", {
388
+ type: "start",
389
+ id: content.id,
390
+ name: content.name,
391
+ colFirst: content.colFirst,
392
+ colLast: content.colLast,
393
+ displacedByCustomXml: content.displacedByCustomXml
394
+ }));
395
+ break;
396
+ }
397
+ if (!bookmarksArr) bookmarksArr = [];
398
+ bookmarksArr.push({
399
+ id: content.id,
400
+ name: content.name
401
+ });
402
+ break;
403
+ case "bookmarkEnd":
404
+ if (pairedBookmarkIds.has(content.id)) emitInlineNode(schema.node("bookmarkBoundary", {
405
+ type: "end",
406
+ id: content.id,
407
+ displacedByCustomXml: content.displacedByCustomXml
408
+ }));
409
+ break;
410
+ case "moveFromRangeStart":
411
+ case "moveFromRangeEnd":
412
+ case "moveToRangeStart":
413
+ case "moveToRangeEnd": break;
414
+ default: panic(`Unsupported paragraph content: ${JSON.stringify(content)}`);
320
415
  }
321
416
  if (bookmarksArr) attrs.bookmarks = bookmarksArr;
322
417
  if (emptyHyperlinks) attrs._emptyHyperlinks = emptyHyperlinks;
@@ -387,11 +482,13 @@ function convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, next
387
482
  id: item.id,
388
483
  name: item.name,
389
484
  colFirst: item.colFirst,
390
- colLast: item.colLast
485
+ colLast: item.colLast,
486
+ displacedByCustomXml: item.displacedByCustomXml
391
487
  }));
392
488
  else if (item.type === "bookmarkEnd") nodes.push(schema.node("bookmarkBoundary", {
393
489
  type: "end",
394
- id: item.id
490
+ id: item.id,
491
+ displacedByCustomXml: item.displacedByCustomXml
395
492
  }));
396
493
  else panic(`Unsupported tracked-run content: ${JSON.stringify(item)}`);
397
494
  const mark = schema.marks[markType].create({
@@ -435,6 +532,8 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
435
532
  let stylePpr;
436
533
  if (styleResolver) {
437
534
  stylePpr = styleResolver.resolveParagraphStyleInTable(styleId, tableParagraphOverlay).paragraphFormatting;
535
+ const resolvedFormatting = styleResolvedParagraphFormatting(stylePpr);
536
+ if (resolvedFormatting) attrs._resolvedFormatting = resolvedFormatting;
438
537
  set("alignment", formatting?.alignment ?? stylePpr?.alignment);
439
538
  set("alignmentFromStyle", stylePpr?.alignment);
440
539
  set("spaceBefore", formatting?.spaceBefore ?? stylePpr?.spaceBefore);
@@ -665,22 +764,24 @@ function calculateRowSpans(table) {
665
764
  const rowCells = row.cells.map((cell) => {
666
765
  const colspan = cell.formatting?.gridSpan ?? 1;
667
766
  const vMerge = cell.formatting?.vMerge;
668
- const startRow = vMerge === "continue" ? activeMerges.get(colIndex) : void 0;
767
+ const isMergeContinuation = isCellMergeContinuation(cell);
768
+ const startRow = isMergeContinuation ? activeMerges.get(colIndex) : void 0;
669
769
  const info = {
670
770
  cell,
671
771
  colIndex,
672
772
  colspan,
673
773
  vMerge,
774
+ isMergeContinuation,
674
775
  startRow,
675
776
  hasMeaningfulContent: tableCellHasMeaningfulContent(cell),
676
- shouldSkip: vMerge === "continue" && startRow !== void 0
777
+ shouldSkip: isMergeContinuation && startRow !== void 0
677
778
  };
678
779
  colIndex += colspan;
679
780
  return info;
680
781
  });
681
782
  const rowWouldBeEmpty = rowCells.length > 0 && rowCells.every((cell) => cell.shouldSkip);
682
783
  for (const cellInfo of rowCells) {
683
- const { colIndex: cellColIndex, vMerge, startRow, hasMeaningfulContent } = cellInfo;
784
+ const { colIndex: cellColIndex, vMerge, isMergeContinuation, startRow, hasMeaningfulContent } = cellInfo;
684
785
  const key = `${rowIndex}-${cellColIndex}`;
685
786
  if (vMerge === "restart") {
686
787
  activeMerges.set(cellColIndex, rowIndex);
@@ -688,7 +789,7 @@ function calculateRowSpans(table) {
688
789
  rowSpan: 1,
689
790
  skip: false
690
791
  });
691
- } else if (vMerge === "continue") {
792
+ } else if (isMergeContinuation) {
692
793
  if (startRow === void 0 || rowWouldBeEmpty || hasMeaningfulContent) {
693
794
  result.set(key, {
694
795
  rowSpan: 1,
@@ -745,7 +846,7 @@ function paragraphContentHasMeaningfulContent(content) {
745
846
  }
746
847
  function convertTable(table, styleResolver, context) {
747
848
  for (const row of table.rows) for (const cell of row.cells) {
748
- if (cell.formatting?.vMerge === "continue" && context.pageBreakRunSourceDescendants.containsPageBreakRun(cell.content)) throw new UnsupportedDocxToProseMirrorConversionError({
849
+ if (isCellMergeContinuation(cell) && context.pageBreakRunSourceDescendants.containsPageBreakRun(cell.content)) throw new UnsupportedDocxToProseMirrorConversionError({
749
850
  message: `${PAGE_BREAK_CONTAINER_DESCRIPTIONS["table-cell"]} cannot be represented in the editor model`,
750
851
  owner: "table-cell",
751
852
  contentType: "break"
@@ -756,7 +857,7 @@ function convertTable(table, styleResolver, context) {
756
857
  const columnWidths = table.columnWidths;
757
858
  const totalWidth = columnWidths?.reduce((sum, w) => sum + w, 0) ?? 0;
758
859
  const tableStyleId = table.formatting?.styleId;
759
- const look = table.formatting?.look;
860
+ const look = resolveTableLook(table.formatting?.look);
760
861
  const tableStyle = tableStyleId ? styleResolver?.getStyle(tableStyleId) : void 0;
761
862
  const defaultTableStyle = styleResolver?.getDefaultTableStyle();
762
863
  const fallbackTableStyle = tableStyleId ? void 0 : defaultTableStyle;
@@ -792,7 +893,7 @@ function convertTable(table, styleResolver, context) {
792
893
  if (resolvedTableIndent) attrs._resolvedIndent = resolvedTableIndent;
793
894
  if (resolvedTableJustification) attrs._resolvedJustification = resolvedTableJustification;
794
895
  if (resolvedTableBidi !== void 0) attrs._resolvedBidi = resolvedTableBidi;
795
- if (table.formatting) attrs._originalFormatting = table.formatting;
896
+ attrs._originalFormatting = table.formatting ?? {};
796
897
  if (table.propertyChanges && table.propertyChanges.length > 0) attrs.tblPrChange = [...table.propertyChanges];
797
898
  const conditionalStyles = {};
798
899
  const setCS = (key, type) => {
@@ -814,15 +915,15 @@ function convertTable(table, styleResolver, context) {
814
915
  setCS("neCell", "neCell");
815
916
  setCS("swCell", "swCell");
816
917
  setCS("seCell", "seCell");
817
- const bandingEnabledH = look?.noHBand !== true;
818
- const bandingEnabledV = look?.noVBand !== true;
918
+ const bandingEnabledH = !look.noHBand;
919
+ const bandingEnabledV = !look.noVBand;
819
920
  let dataRowIndex = 0;
820
921
  const totalRows = table.rows.length;
821
922
  const gridColumnCount = columnWidths?.length ?? 0;
822
923
  const totalColumns = gridColumnCount > 0 ? gridColumnCount : countTableColumns(table.rows);
823
924
  const rows = table.rows.map((row, rowIndex) => {
824
- const isFirstRowStyled = rowIndex === 0 && !!look?.firstRow;
825
- const isLastRow = rowIndex === totalRows - 1 && !!look?.lastRow;
925
+ const isFirstRowStyled = rowIndex === 0 && look.firstRow;
926
+ const isLastRow = rowIndex === totalRows - 1 && look.lastRow;
826
927
  const rowBandStyle = (() => {
827
928
  if (bandingEnabledH && !isFirstRowStyled && !isLastRow) return (() => {
828
929
  if (dataRowIndex % 2 === 0) return conditionalStyles.band1Horz;
@@ -857,26 +958,34 @@ function convertTableRow(row, styleResolver, context, isHeaderRow, columnWidths,
857
958
  if (row.formatting) attrsWithoutStructuralChange._originalFormatting = row.formatting;
858
959
  if (row.propertyChanges && row.propertyChanges.length > 0) attrsWithoutStructuralChange.trPrChange = [...row.propertyChanges];
859
960
  let attrs = attrsWithoutStructuralChange;
860
- if (row.structuralChange?.type === "tableRowInsertion") attrs = {
861
- ...attrsWithoutStructuralChange,
862
- trIns: {
863
- revisionId: row.structuralChange.info.id,
864
- author: row.structuralChange.info.author,
865
- date: row.structuralChange.info.date ?? null,
866
- ...row.structuralChange.info.utcDate ? { utcDate: row.structuralChange.info.utcDate.value } : {},
867
- ...row.structuralChange.info.initials ? { initials: row.structuralChange.info.initials } : {}
868
- }
869
- };
870
- else if (row.structuralChange?.type === "tableRowDeletion") attrs = {
871
- ...attrsWithoutStructuralChange,
872
- trDel: {
873
- revisionId: row.structuralChange.info.id,
874
- author: row.structuralChange.info.author,
875
- date: row.structuralChange.info.date ?? null,
876
- ...row.structuralChange.info.utcDate ? { utcDate: row.structuralChange.info.utcDate.value } : {},
877
- ...row.structuralChange.info.initials ? { initials: row.structuralChange.info.initials } : {}
961
+ const rowStructuralChange = row.structuralChange;
962
+ if (rowStructuralChange) {
963
+ const revision = {
964
+ revisionId: rowStructuralChange.info.id,
965
+ author: rowStructuralChange.info.author,
966
+ date: rowStructuralChange.info.date ?? null,
967
+ ...rowStructuralChange.info.utcDate ? { utcDate: rowStructuralChange.info.utcDate.value } : {},
968
+ ...rowStructuralChange.info.initials ? { initials: rowStructuralChange.info.initials } : {}
969
+ };
970
+ switch (rowStructuralChange.type) {
971
+ case "tableRowInsertion":
972
+ attrs = {
973
+ ...attrsWithoutStructuralChange,
974
+ trIns: revision
975
+ };
976
+ break;
977
+ case "tableRowDeletion":
978
+ attrs = {
979
+ ...attrsWithoutStructuralChange,
980
+ trDel: revision
981
+ };
982
+ break;
983
+ case "tableCellInsertion":
984
+ case "tableCellDeletion":
985
+ case "tableCellMerge": break;
986
+ default: panic(`Unsupported table row structural change: ${JSON.stringify(rowStructuralChange)}`);
878
987
  }
879
- };
988
+ }
880
989
  const numCells = row.cells.length;
881
990
  const isFirstRow = rowIndex === 0;
882
991
  const isLastRow = rowIndex === (totalRows ?? 1) - 1;
@@ -1006,38 +1115,41 @@ function convertTableCell({ cell, styleResolver, context, isHeader, gridWidthPer
1006
1115
  }
1007
1116
  if (formatting) attrs._originalFormatting = formatting;
1008
1117
  if (cell.propertyChanges && cell.propertyChanges.length > 0) attrs.tcPrChange = [...cell.propertyChanges];
1009
- if (cell.structuralChange?.type === "tableCellInsertion") attrs.cellMarker = {
1010
- kind: "ins",
1011
- info: {
1012
- revisionId: cell.structuralChange.info.id,
1013
- author: cell.structuralChange.info.author,
1014
- date: cell.structuralChange.info.date ?? null,
1015
- ...cell.structuralChange.info.utcDate ? { utcDate: cell.structuralChange.info.utcDate.value } : {},
1016
- ...cell.structuralChange.info.initials ? { initials: cell.structuralChange.info.initials } : {}
1017
- }
1018
- };
1019
- else if (cell.structuralChange?.type === "tableCellDeletion") attrs.cellMarker = {
1020
- kind: "del",
1021
- info: {
1022
- revisionId: cell.structuralChange.info.id,
1023
- author: cell.structuralChange.info.author,
1024
- date: cell.structuralChange.info.date ?? null,
1025
- ...cell.structuralChange.info.utcDate ? { utcDate: cell.structuralChange.info.utcDate.value } : {},
1026
- ...cell.structuralChange.info.initials ? { initials: cell.structuralChange.info.initials } : {}
1118
+ const cellStructuralChange = cell.structuralChange;
1119
+ if (cellStructuralChange) {
1120
+ const info = {
1121
+ revisionId: cellStructuralChange.info.id,
1122
+ author: cellStructuralChange.info.author,
1123
+ date: cellStructuralChange.info.date ?? null,
1124
+ ...cellStructuralChange.info.utcDate ? { utcDate: cellStructuralChange.info.utcDate.value } : {},
1125
+ ...cellStructuralChange.info.initials ? { initials: cellStructuralChange.info.initials } : {}
1126
+ };
1127
+ switch (cellStructuralChange.type) {
1128
+ case "tableCellInsertion":
1129
+ attrs.cellMarker = {
1130
+ kind: "ins",
1131
+ info
1132
+ };
1133
+ break;
1134
+ case "tableCellDeletion":
1135
+ attrs.cellMarker = {
1136
+ kind: "del",
1137
+ info
1138
+ };
1139
+ break;
1140
+ case "tableCellMerge":
1141
+ attrs.cellMarker = {
1142
+ kind: "merge",
1143
+ info,
1144
+ ...cellStructuralChange.verticalMerge !== void 0 ? { verticalMerge: cellStructuralChange.verticalMerge } : {},
1145
+ ...cellStructuralChange.verticalMergeOriginal !== void 0 ? { verticalMergeOriginal: cellStructuralChange.verticalMergeOriginal } : {}
1146
+ };
1147
+ break;
1148
+ case "tableRowInsertion":
1149
+ case "tableRowDeletion": break;
1150
+ default: panic(`Unsupported table cell structural change: ${JSON.stringify(cellStructuralChange)}`);
1027
1151
  }
1028
- };
1029
- else if (cell.structuralChange?.type === "tableCellMerge") attrs.cellMarker = {
1030
- kind: "merge",
1031
- info: {
1032
- revisionId: cell.structuralChange.info.id,
1033
- author: cell.structuralChange.info.author,
1034
- date: cell.structuralChange.info.date ?? null,
1035
- ...cell.structuralChange.info.utcDate ? { utcDate: cell.structuralChange.info.utcDate.value } : {},
1036
- ...cell.structuralChange.info.initials ? { initials: cell.structuralChange.info.initials } : {}
1037
- },
1038
- ...cell.structuralChange.verticalMerge !== void 0 ? { verticalMerge: cell.structuralChange.verticalMerge } : {},
1039
- ...cell.structuralChange.verticalMergeOriginal !== void 0 ? { verticalMergeOriginal: cell.structuralChange.verticalMergeOriginal } : {}
1040
- };
1152
+ }
1041
1153
  if (preserveVMergeRestart) attrs._preserveVMergeRestart = true;
1042
1154
  if (vMergeContinuationCells && vMergeContinuationCells.length > 0) attrs._docxVMergeContinuationCells = transportTableCellsWithParagraphPropertySources(vMergeContinuationCells);
1043
1155
  const contentNodes = [];
@@ -1136,6 +1248,22 @@ function convertField(field, { getInheritedRunFormatting, styleResolver, nextHyp
1136
1248
  /**
1137
1249
  * Convert a MathEquation to a ProseMirror math node.
1138
1250
  */
1251
+ /**
1252
+ * Flatten `w:bdo`/`w:dir` out of an inline content list.
1253
+ *
1254
+ * The editor has no projection for a bidirectional wrapper yet, and the
1255
+ * alternative to flattening it is worse than losing the direction: every
1256
+ * inline loop below narrows by a chain of `else if` rather than by
1257
+ * exhaustion, so an unhandled member reaches whichever branch happens to be
1258
+ * last and is read as that. Flattening keeps the wrapper's content and loses
1259
+ * only its direction, which the survival census records as an
1260
+ * editor-projection loss until the mark that carries it exists.
1261
+ *
1262
+ * The save path is unaffected: a document opened and saved without being
1263
+ * edited replays its markup, and one that is edited keeps the wrapper because
1264
+ * `fromProseDoc` rebuilds from the source paragraph.
1265
+ */
1266
+ const withoutBidiWrappers = (content) => content.flatMap((item) => item.type === "bidiWrapper" ? withoutBidiWrappers(item.content) : [item]);
1139
1267
  function convertMathEquation(math) {
1140
1268
  return schema.node("math", {
1141
1269
  display: math.display,
@@ -1149,37 +1277,50 @@ function convertMathEquation(math) {
1149
1277
  function convertInlineSdt(sdt, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, textBoxAnchors) {
1150
1278
  const props = sdt.properties;
1151
1279
  const inlineNodes = [];
1152
- for (const content of sdt.content) if (content.type === "run") {
1153
- const runNodes = convertRun(content, getInheritedRunFormatting(content.formatting), nextPageBreakRunOwnerId, styleResolver, textBoxAnchors);
1154
- inlineNodes.push(...runNodes);
1155
- } else if (content.type === "hyperlink") {
1156
- const linkNodes = convertHyperlink(content, {
1157
- getInheritedRunFormatting,
1158
- styleResolver,
1159
- hyperlinkIndex: nextHyperlinkInstanceIndex(),
1160
- textBoxAnchors,
1161
- nextPageBreakRunOwnerId
1162
- });
1163
- inlineNodes.push(...linkNodes);
1164
- } else if (content.type === "simpleField" || content.type === "complexField") {
1165
- const fieldNode = convertField(content, {
1166
- getInheritedRunFormatting,
1167
- styleResolver,
1168
- nextHyperlinkInstanceIndex,
1169
- nextPageBreakRunOwnerId,
1170
- textBoxAnchors
1171
- });
1172
- if (fieldNode) inlineNodes.push(fieldNode);
1173
- } else if (content.type === "inlineSdt") {
1174
- const nestedSdt = convertInlineSdt(content, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, textBoxAnchors);
1175
- if (nestedSdt) inlineNodes.push(nestedSdt);
1176
- } else if (content.type === "insertion") inlineNodes.push(...convertTrackedChange(content, "insertion", nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, null, textBoxAnchors));
1177
- else if (content.type === "deletion") inlineNodes.push(...convertTrackedChange(content, "deletion", nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, null, textBoxAnchors));
1178
- else if (content.type === "moveTo") inlineNodes.push(...convertTrackedChange(content, "insertion", nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, "moveTo", textBoxAnchors));
1179
- else if (content.type === "moveFrom") inlineNodes.push(...convertTrackedChange(content, "deletion", nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, "moveFrom", textBoxAnchors));
1180
- else {
1181
- const mathNode = convertMathEquation(content);
1182
- if (mathNode) inlineNodes.push(mathNode);
1280
+ for (const content of sdt.content) switch (content.type) {
1281
+ case "run":
1282
+ inlineNodes.push(...convertRun(content, getInheritedRunFormatting(content.formatting), nextPageBreakRunOwnerId, styleResolver, textBoxAnchors));
1283
+ break;
1284
+ case "hyperlink": {
1285
+ const currentHyperlinkIndex = nextHyperlinkInstanceIndex();
1286
+ inlineNodes.push(...convertHyperlink(content, {
1287
+ getInheritedRunFormatting,
1288
+ styleResolver,
1289
+ hyperlinkIndex: currentHyperlinkIndex,
1290
+ textBoxAnchors,
1291
+ nextPageBreakRunOwnerId
1292
+ }));
1293
+ break;
1294
+ }
1295
+ case "simpleField":
1296
+ case "complexField": {
1297
+ const fieldNode = convertField(content, {
1298
+ getInheritedRunFormatting,
1299
+ styleResolver,
1300
+ nextHyperlinkInstanceIndex,
1301
+ nextPageBreakRunOwnerId,
1302
+ textBoxAnchors
1303
+ });
1304
+ if (fieldNode) inlineNodes.push(fieldNode);
1305
+ break;
1306
+ }
1307
+ case "inlineSdt": {
1308
+ const nestedSdt = convertInlineSdt(content, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, textBoxAnchors);
1309
+ if (nestedSdt) inlineNodes.push(nestedSdt);
1310
+ break;
1311
+ }
1312
+ case "insertion":
1313
+ case "deletion":
1314
+ case "moveTo":
1315
+ case "moveFrom":
1316
+ inlineNodes.push(...convertTrackedChange(content, content.type === "insertion" || content.type === "moveTo" ? "insertion" : "deletion", nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, content.type === "moveTo" || content.type === "moveFrom" ? content.type : null, textBoxAnchors));
1317
+ break;
1318
+ case "mathEquation": {
1319
+ const mathNode = convertMathEquation(content);
1320
+ if (mathNode) inlineNodes.push(mathNode);
1321
+ break;
1322
+ }
1323
+ default: panic(`Unsupported inline SDT content: ${JSON.stringify(content)}`);
1183
1324
  }
1184
1325
  return schema.node("sdt", sdtAttrsFromProperties(props), inlineNodes.length > 0 ? inlineNodes : void 0);
1185
1326
  }
@@ -1196,7 +1337,7 @@ function convertRun(run, resolvedStyleFormatting, nextPageBreakRunOwnerId, style
1196
1337
  if (run.propertyChanges && run.propertyChanges.length > 0) marks.push(schema.mark("runPropertyChange", { changes: [...run.propertyChanges] }));
1197
1338
  if (run.content.some((content) => content.type === "break" && content.breakType === "page")) marks.push(schema.mark("pageBreakRunOwner", { id: nextPageBreakRunOwnerId() }));
1198
1339
  for (const content of run.content) {
1199
- const contentNodes = convertRunContent(content, marks, mergedFormatting, textBoxAnchors);
1340
+ const contentNodes = convertRunContent(content, marks, mergedFormatting, textBoxAnchors, run.formatting);
1200
1341
  nodes.push(...contentNodes);
1201
1342
  }
1202
1343
  return nodes;
@@ -1263,6 +1404,7 @@ const scanLeadingPageBreakContent = (content, scan) => {
1263
1404
  case "moveFrom":
1264
1405
  case "moveTo":
1265
1406
  case "inlineSdt":
1407
+ case "bidiWrapper":
1266
1408
  for (const child of content.content) scanLeadingPageBreakContent(child, scan);
1267
1409
  return;
1268
1410
  case "simpleField":
@@ -1458,7 +1600,7 @@ const canReconstructAuthoredRunFormatting = ({ directFormatting, effectiveFormat
1458
1600
  };
1459
1601
  function buildRunMarks(runFormatting, inherited, styleResolver) {
1460
1602
  if (runFormatting === void 0 && inherited.implicitCharacterStyleApplied === true && inherited.paragraphMarkOverrides === void 0) return {
1461
- marks: textFormattingToMarks(inherited.formatting, {
1603
+ marks: textFormattingToMarks(inherited.formatting, schema, {
1462
1604
  overrideFormatting: void 0,
1463
1605
  directFormatting: void 0,
1464
1606
  authoredCarrier: "reconstruct"
@@ -1502,7 +1644,7 @@ function buildRunMarks(runFormatting, inherited, styleResolver) {
1502
1644
  if (overrideFormatting?.bold === true) delete overrideFormatting.bold;
1503
1645
  if (overrideFormatting?.italic === true) delete overrideFormatting.italic;
1504
1646
  }
1505
- const marks = textFormattingToMarks(mergedFormatting, {
1647
+ const marks = textFormattingToMarks(mergedFormatting, schema, {
1506
1648
  overrideFormatting,
1507
1649
  directFormatting: runFormatting,
1508
1650
  authoredCarrier
@@ -1513,55 +1655,6 @@ function buildRunMarks(runFormatting, inherited, styleResolver) {
1513
1655
  mergedFormatting
1514
1656
  };
1515
1657
  }
1516
- const addDirectFontProvenance = (marks, directFormatting) => {
1517
- const directFontProperties = [];
1518
- if (directFormatting?.fontFamily !== void 0) directFontProperties.push("fontFamily");
1519
- if (directFormatting?.fontSize !== void 0) directFontProperties.push("fontSize");
1520
- if (directFormatting?.color !== void 0) directFontProperties.push("color");
1521
- if (directFontProperties.length === 0) return;
1522
- const index = marks.findIndex(({ type }) => type.name === "runFormattingOverride");
1523
- const existing = index >= 0 ? marks.at(index) : void 0;
1524
- const override = schema.mark("runFormattingOverride", {
1525
- ...existing?.attrs,
1526
- directFontProperties
1527
- });
1528
- if (index >= 0) {
1529
- marks[index] = override;
1530
- return;
1531
- }
1532
- marks.push(override);
1533
- };
1534
- const COMPLEX_SCRIPT_MIRRORS = [
1535
- {
1536
- ordinary: "bold",
1537
- complex: "boldCs"
1538
- },
1539
- {
1540
- ordinary: "italic",
1541
- complex: "italicCs"
1542
- },
1543
- {
1544
- ordinary: "fontSize",
1545
- complex: "fontSizeCs"
1546
- }
1547
- ];
1548
- const addComplexScriptAbsenceProvenance = (marks, directFormatting) => {
1549
- const absent = COMPLEX_SCRIPT_MIRRORS.filter(({ ordinary, complex }) => directFormatting?.[ordinary] !== void 0 && directFormatting[complex] === void 0).map(({ complex }) => complex);
1550
- if (absent.length === 0) return;
1551
- const index = marks.findIndex(({ type }) => type.name === "runFormattingOverride");
1552
- const existing = index >= 0 ? marks.at(index) : void 0;
1553
- const existingAbsences = new Set(existing?.attrs["complexScriptPropertyAbsences"] ?? []);
1554
- for (const property of absent) existingAbsences.add(property);
1555
- const override = schema.mark("runFormattingOverride", {
1556
- ...existing?.attrs,
1557
- complexScriptPropertyAbsences: COMPLEX_SCRIPT_RUN_PROPERTY_KEYS.filter((property) => existingAbsences.has(property))
1558
- });
1559
- if (index >= 0) {
1560
- marks[index] = override;
1561
- return;
1562
- }
1563
- marks.push(override);
1564
- };
1565
1658
  const ORDINARY_STYLE_TOGGLE_KEYS = [
1566
1659
  "strike",
1567
1660
  "allCaps",
@@ -1579,9 +1672,28 @@ function getRunFormattingOverrides({ directFormatting, effectiveStyleFormatting,
1579
1672
  return overrides;
1580
1673
  }
1581
1674
  /**
1675
+ * The vertical alignment a note reference mark carries.
1676
+ *
1677
+ * The mark models the two alignments a reference can sit at; `subscript` is not
1678
+ * one of them and drops to `null`. `baseline` is read through its owner, since
1679
+ * it is the reserved "no offset" value rather than an offset of its own.
1680
+ */
1681
+ const noteReferenceVertAlign = (vertAlign) => {
1682
+ if (isBaselineVertAlign(vertAlign)) return "baseline";
1683
+ return vertAlign === "superscript" ? "superscript" : null;
1684
+ };
1685
+ /**
1686
+ * The run properties an inline atom has to carry itself.
1687
+ *
1688
+ * `withRunBoundaryMarks` keeps the run's formatting marks off an image or
1689
+ * shape node, so the node is the only place left to record the `w:rPr` the
1690
+ * run was authored with.
1691
+ */
1692
+ const carriedRunFormatting = (formatting) => formatting && Object.keys(formatting).length > 0 ? formatting : void 0;
1693
+ /**
1582
1694
  * Convert RunContent to ProseMirror nodes
1583
1695
  */
1584
- function convertRunContent(content, marks, formatting, textBoxAnchors) {
1696
+ function convertRunContent(content, marks, formatting, textBoxAnchors, authoredFormatting) {
1585
1697
  switch (content.type) {
1586
1698
  case "text":
1587
1699
  if (content.text) return [schema.text(content.text, marks)];
@@ -1605,7 +1717,8 @@ function convertRunContent(content, marks, formatting, textBoxAnchors) {
1605
1717
  image: content.image,
1606
1718
  rawXml: content.rawXml,
1607
1719
  rawXmlMode: content.rawXmlMode,
1608
- rawImageFingerprint: content.rawXmlMode === DRAWING_RAW_XML_MODES.PRESERVE_ONLY ? void 0 : content.rawImageFingerprint
1720
+ rawImageFingerprint: content.rawXmlMode === DRAWING_RAW_XML_MODES.PRESERVE_ONLY ? void 0 : content.rawImageFingerprint,
1721
+ runFormatting: carriedRunFormatting(authoredFormatting)
1609
1722
  }), marks)];
1610
1723
  case "shape": {
1611
1724
  const shp = content.shape;
@@ -1613,13 +1726,13 @@ function convertRunContent(content, marks, formatting, textBoxAnchors) {
1613
1726
  const anchorId = textBoxAnchors?.get(shp);
1614
1727
  return anchorId ? [schema.node("textBoxAnchor", { anchorId }).mark(marks)] : [];
1615
1728
  }
1616
- return [withRunBoundaryMarks(convertShape(shp), marks)];
1729
+ return [withRunBoundaryMarks(convertShape(shp, carriedRunFormatting(authoredFormatting)), marks)];
1617
1730
  }
1618
1731
  case "footnoteRef": {
1619
1732
  const footnoteMark = schema.mark("footnoteRef", {
1620
1733
  id: content.id.toString(),
1621
1734
  noteType: "footnote",
1622
- vertAlign: formatting?.vertAlign === "baseline" || formatting?.vertAlign === "superscript" ? formatting.vertAlign : null
1735
+ vertAlign: noteReferenceVertAlign(formatting?.vertAlign)
1623
1736
  });
1624
1737
  return [schema.text(content.id.toString(), [...marks, footnoteMark])];
1625
1738
  }
@@ -1627,7 +1740,7 @@ function convertRunContent(content, marks, formatting, textBoxAnchors) {
1627
1740
  const endnoteMark = schema.mark("footnoteRef", {
1628
1741
  id: content.id.toString(),
1629
1742
  noteType: "endnote",
1630
- vertAlign: formatting?.vertAlign === "baseline" || formatting?.vertAlign === "superscript" ? formatting.vertAlign : null
1743
+ vertAlign: noteReferenceVertAlign(formatting?.vertAlign)
1631
1744
  });
1632
1745
  return [schema.text(content.id.toString(), [...marks, endnoteMark])];
1633
1746
  }
@@ -1645,7 +1758,7 @@ function withRunBoundaryMarks(node, marks) {
1645
1758
  if (!marks.some(({ type }) => type.name === "hyperlink" || type.name === "pageBreakRunOwner")) return node;
1646
1759
  return node.mark(marks);
1647
1760
  }
1648
- function convertImage({ image, rawXml, rawXmlMode, rawImageFingerprint }) {
1761
+ function convertImage({ image, rawXml, rawXmlMode, rawImageFingerprint, runFormatting }) {
1649
1762
  const imageSize = image.size;
1650
1763
  const widthPx = imageSize?.width ? emuToPixels(imageSize.width) : void 0;
1651
1764
  const heightPx = imageSize?.height ? emuToPixels(imageSize.height) : void 0;
@@ -1753,7 +1866,8 @@ function convertImage({ image, rawXml, rawXmlMode, rawImageFingerprint }) {
1753
1866
  _docxRawXml: rawXml,
1754
1867
  _docxRawXmlMode: rawXmlMode,
1755
1868
  _docxRawImageFingerprint: rawImageFingerprint,
1756
- _docxObjectPreview: rawXml !== void 0 && /<(?:[A-Za-z_][\w.-]*:)?object(?:\s|>)/u.test(rawXml)
1869
+ _docxObjectPreview: rawXml !== void 0 && /<(?:[A-Za-z_][\w.-]*:)?object(?:\s|>)/u.test(rawXml),
1870
+ _docxRunFormatting: runFormatting
1757
1871
  });
1758
1872
  }
1759
1873
  function convertHyperlink(hyperlink, { getInheritedRunFormatting, styleResolver, hyperlinkIndex, textBoxAnchors, nextPageBreakRunOwnerId }) {
@@ -1772,14 +1886,16 @@ function convertHyperlink(hyperlink, { getInheritedRunFormatting, styleResolver,
1772
1886
  id: child.id,
1773
1887
  name: child.name,
1774
1888
  colFirst: child.colFirst,
1775
- colLast: child.colLast
1889
+ colLast: child.colLast,
1890
+ displacedByCustomXml: child.displacedByCustomXml
1776
1891
  }, void 0, [linkMark]));
1777
1892
  continue;
1778
1893
  }
1779
1894
  if (child.type === "bookmarkEnd") {
1780
1895
  nodes.push(schema.node("bookmarkBoundary", {
1781
1896
  type: "end",
1782
- id: child.id
1897
+ id: child.id,
1898
+ displacedByCustomXml: child.displacedByCustomXml
1783
1899
  }, void 0, [linkMark]));
1784
1900
  continue;
1785
1901
  }
@@ -1790,82 +1906,15 @@ function convertHyperlink(hyperlink, { getInheritedRunFormatting, styleResolver,
1790
1906
  if (child.propertyChanges && child.propertyChanges.length > 0) runMarks.push(schema.mark("runPropertyChange", { changes: [...child.propertyChanges] }));
1791
1907
  if (child.content.some((content) => content.type === "break" && content.breakType === "page")) runMarks.push(schema.mark("pageBreakRunOwner", { id: nextPageBreakRunOwnerId() }));
1792
1908
  const allMarks = [...runMarks, linkMark];
1793
- for (const content of child.content) nodes.push(...convertRunContent(content, allMarks, mergedFormatting, textBoxAnchors));
1909
+ for (const content of child.content) nodes.push(...convertRunContent(content, allMarks, mergedFormatting, textBoxAnchors, child.formatting));
1794
1910
  }
1795
1911
  }
1796
1912
  return nodes;
1797
1913
  }
1798
- function textFormattingToMarks(formatting, options) {
1799
- if (!formatting) return [];
1800
- const marks = [];
1801
- const overrideFormatting = options ? options.overrideFormatting : formatting;
1802
- let overrideAttrs;
1803
- if (options?.authoredCarrier === "reconstruct") overrideAttrs = buildRunFormattingOverrideAttrs(overrideFormatting, { type: "structural-only" });
1804
- else if (options) overrideAttrs = buildRunFormattingOverrideAttrs(overrideFormatting, {
1805
- type: "authored-baseline",
1806
- formatting: options.directFormatting
1807
- });
1808
- else overrideAttrs = buildRunFormattingOverrideAttrs(overrideFormatting);
1809
- if (overrideAttrs) marks.push(schema.mark("runFormattingOverride", overrideAttrs));
1810
- if (formatting.bold) marks.push(schema.mark("bold"));
1811
- if (formatting.italic) marks.push(schema.mark("italic"));
1812
- if (formatting.underline && formatting.underline.style !== "none") marks.push(schema.mark("underline", {
1813
- style: formatting.underline.style,
1814
- color: formatting.underline.color
1815
- }));
1816
- if (formatting.strike || formatting.doubleStrike) marks.push(schema.mark("strike", { double: formatting.doubleStrike || false }));
1817
- if (formatting.color && !formatting.color.auto) marks.push(schema.mark("textColor", {
1818
- rgb: formatting.color.rgb,
1819
- themeColor: formatting.color.themeColor,
1820
- themeTint: formatting.color.themeTint,
1821
- themeShade: formatting.color.themeShade
1822
- }));
1823
- if (formatting.highlight && formatting.highlight !== "none") marks.push(schema.mark("highlight", { color: formatting.highlight }));
1824
- const runShadingMarkAttrs = shadingToRunShadingAttrs(formatting.shading);
1825
- if (runShadingMarkAttrs) marks.push(schema.mark("runShading", runShadingMarkAttrs));
1826
- if (formatting.fontSize) marks.push(schema.mark("fontSize", { size: formatting.fontSize }));
1827
- if (formatting.fontFamily) marks.push(schema.mark("fontFamily", {
1828
- ascii: formatting.fontFamily.ascii,
1829
- hAnsi: formatting.fontFamily.hAnsi,
1830
- eastAsia: formatting.fontFamily.eastAsia,
1831
- cs: formatting.fontFamily.cs,
1832
- hint: formatting.fontFamily.hint,
1833
- asciiTheme: formatting.fontFamily.asciiTheme,
1834
- hAnsiTheme: formatting.fontFamily.hAnsiTheme,
1835
- eastAsiaTheme: formatting.fontFamily.eastAsiaTheme,
1836
- csTheme: formatting.fontFamily.csTheme
1837
- }));
1838
- if (formatting.language) marks.push(schema.mark("language", formatting.language));
1839
- if (formatting.vertAlign === "superscript") marks.push(schema.mark("superscript"));
1840
- else if (formatting.vertAlign === "subscript") marks.push(schema.mark("subscript"));
1841
- if (formatting.allCaps) marks.push(schema.mark("allCaps"));
1842
- if (formatting.smallCaps) marks.push(schema.mark("smallCaps"));
1843
- const spacing = typeof formatting.spacing === "number" ? formatting.spacing : null;
1844
- const position = typeof formatting.position === "number" ? formatting.position : null;
1845
- const scale = normalizeHorizontalScalePercent(formatting.scale) ?? null;
1846
- const kerning = typeof formatting.kerning === "number" ? formatting.kerning : null;
1847
- if (spacing !== null || position !== null || scale !== null || kerning !== null) marks.push(schema.mark("characterSpacing", {
1848
- spacing,
1849
- position,
1850
- scale,
1851
- kerning
1852
- }));
1853
- if (formatting.hidden === true) marks.push(schema.mark("hidden"));
1854
- if (formatting.emboss) marks.push(schema.mark("emboss"));
1855
- if (formatting.imprint) marks.push(schema.mark("imprint"));
1856
- if (formatting.shadow) marks.push(schema.mark("textShadow"));
1857
- if (formatting.emphasisMark && formatting.emphasisMark !== "none") marks.push(schema.mark("emphasisMark", { type: formatting.emphasisMark }));
1858
- if (formatting.outline) marks.push(schema.mark("textOutline"));
1859
- if (formatting.rtl) marks.push(schema.mark("rtl"));
1860
- if (formatting.effect && formatting.effect !== "none") marks.push(schema.mark("textEffect", { effect: formatting.effect }));
1861
- addDirectFontProvenance(marks, options?.directFormatting);
1862
- if (options?.authoredCarrier === "preserve") addComplexScriptAbsenceProvenance(marks, options.directFormatting);
1863
- return marks;
1864
- }
1865
1914
  /**
1866
1915
  * Convert a Shape to a ProseMirror shape node (inline SVG)
1867
1916
  */
1868
- function convertShape(shape) {
1917
+ function convertShape(shape, runFormatting) {
1869
1918
  const shapeSize = shape.size;
1870
1919
  const widthPx = shapeSize?.width ? emuToPixels(shapeSize.width) : 100;
1871
1920
  const heightPx = shapeSize?.height ? emuToPixels(shapeSize.height) : 80;
@@ -1937,6 +1986,7 @@ function convertShape(shape) {
1937
1986
  }
1938
1987
  };
1939
1988
  return schema.node("shape", {
1989
+ _docxRunFormatting: runFormatting,
1940
1990
  shapeType: shapeAttrs.shapeType ?? "rect",
1941
1991
  geometryAdjustments: shape.geometryAdjustments === void 0 ? void 0 : JSON.stringify(shape.geometryAdjustments),
1942
1992
  shapeId: shape.id,
@@ -2253,24 +2303,33 @@ function headerFooterToProseDoc(content, options) {
2253
2303
  };
2254
2304
  const convertBlocks = (blocks) => {
2255
2305
  const out = [];
2256
- for (const block of blocks) if (block.type === "paragraph") {
2257
- const isDetachedWatermarkHost = Reflect.get(block, DETACHED_WATERMARK_HOST) === true;
2258
- const paragraphNodes = convertParagraphWithTextBoxes(block, styleResolver, {
2259
- textBoxGroupId: nextTextBoxGroupId(),
2260
- context: conversionContext,
2261
- preserveEmptyWrapper: isDetachedWatermarkHost
2262
- });
2263
- if (isDetachedWatermarkHost) {
2264
- const paragraphNodeIndex = paragraphNodes.findIndex(({ type }) => type.name === "paragraph");
2265
- const paragraphNode = paragraphNodes[paragraphNodeIndex];
2266
- if (paragraphNode) paragraphNodes[paragraphNodeIndex] = recreateProseNodeWithParagraphPropertySource(paragraphNode, { attrs: {
2267
- ...paragraphNode.attrs,
2268
- _detachedWatermarkHost: true
2269
- } });
2306
+ for (const block of blocks) switch (block.type) {
2307
+ case "paragraph": {
2308
+ const isDetachedWatermarkHost = Reflect.get(block, DETACHED_WATERMARK_HOST) === true;
2309
+ const paragraphNodes = convertParagraphWithTextBoxes(block, styleResolver, {
2310
+ textBoxGroupId: nextTextBoxGroupId(),
2311
+ context: conversionContext,
2312
+ preserveEmptyWrapper: isDetachedWatermarkHost
2313
+ });
2314
+ if (isDetachedWatermarkHost) {
2315
+ const paragraphNodeIndex = paragraphNodes.findIndex(({ type }) => type.name === "paragraph");
2316
+ const paragraphNode = paragraphNodes[paragraphNodeIndex];
2317
+ if (paragraphNode) paragraphNodes[paragraphNodeIndex] = recreateProseNodeWithParagraphPropertySource(paragraphNode, { attrs: {
2318
+ ...paragraphNode.attrs,
2319
+ _detachedWatermarkHost: true
2320
+ } });
2321
+ }
2322
+ out.push(...paragraphNodes);
2323
+ break;
2270
2324
  }
2271
- out.push(...paragraphNodes);
2272
- } else if (block.type === "table") out.push(convertTable(block, styleResolver, conversionContext));
2273
- else out.push(convertBlockSdt(block, convertBlocks));
2325
+ case "table":
2326
+ out.push(convertTable(block, styleResolver, conversionContext));
2327
+ break;
2328
+ case "blockSdt":
2329
+ out.push(convertBlockSdt(block, convertBlocks));
2330
+ break;
2331
+ default: panic(`Unsupported block content: ${JSON.stringify(block)}`);
2332
+ }
2274
2333
  return out;
2275
2334
  };
2276
2335
  nodes.push(...convertBlocks(content));
@@ -2289,4 +2348,4 @@ function createEmptyDoc() {
2289
2348
  return schema.node("doc", null, [schema.node("paragraph", {}, [])]);
2290
2349
  }
2291
2350
  //#endregion
2292
- export { UnsupportedDocxToProseMirrorConversionError, createEmptyDoc, footnoteToProseDoc, headerFooterToProseDoc, resolveParagraphDefaultTextFormatting, standaloneTableCellToProseMirror, textFormattingToMarks, toProseDoc };
2351
+ export { UnsupportedDocxToProseMirrorConversionError, createEmptyDoc, footnoteToProseDoc, headerFooterToProseDoc, resolveParagraphDefaultTextFormatting, standaloneTableCellToProseMirror, toProseDoc };