@stll/folio-core 0.10.0 → 0.12.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 (217) hide show
  1. package/dist/ai-edits/apply.js +602 -50
  2. package/dist/ai-edits/block-identity.d.ts +4 -0
  3. package/dist/ai-edits/block-identity.js +9 -0
  4. package/dist/ai-edits/blockRange.d.ts +28 -1
  5. package/dist/ai-edits/blockRange.js +67 -1
  6. package/dist/ai-edits/headless.d.ts +4 -4
  7. package/dist/ai-edits/headless.js +9 -9
  8. package/dist/ai-edits/index.d.ts +2 -2
  9. package/dist/ai-edits/index.js +2 -2
  10. package/dist/ai-edits/read.d.ts +7 -7
  11. package/dist/ai-edits/read.js +110 -3
  12. package/dist/ai-edits/table-cell-mutations.d.ts +48 -0
  13. package/dist/ai-edits/table-cell-mutations.js +237 -0
  14. package/dist/ai-edits/table-mutation-plan.d.ts +38 -0
  15. package/dist/ai-edits/table-mutation-plan.js +90 -0
  16. package/dist/ai-edits/table-row-column-mutations.d.ts +100 -0
  17. package/dist/ai-edits/table-row-column-mutations.js +300 -0
  18. package/dist/ai-edits/table-targets.d.ts +32 -0
  19. package/dist/ai-edits/table-targets.js +70 -0
  20. package/dist/ai-edits/types.d.ts +34 -0
  21. package/dist/compat/eigenpal.js +1 -1
  22. package/dist/content-controls/mutateContentControls.js +1 -1
  23. package/dist/controller/activeEditorStory.d.ts +36 -0
  24. package/dist/controller/activeEditorStory.js +30 -0
  25. package/dist/controller/collaborationModules.d.ts +7 -0
  26. package/dist/controller/collaborationModules.js +15 -0
  27. package/dist/controller/contentControlWidgetController.d.ts +55 -0
  28. package/dist/controller/contentControlWidgetController.js +141 -0
  29. package/dist/controller/folioEditor.d.ts +1 -1
  30. package/dist/controller/fontReadiness.js +2 -0
  31. package/dist/controller/headerFooterEditorManager.d.ts +41 -0
  32. package/dist/controller/headerFooterEditorManager.js +182 -0
  33. package/dist/controller/hiddenEditorApi.js +2 -2
  34. package/dist/controller/hiddenEditorManager.d.ts +13 -2
  35. package/dist/controller/hiddenEditorManager.js +32 -11
  36. package/dist/controller/layoutPipeline.d.ts +2 -0
  37. package/dist/controller/layoutPipeline.js +16 -1
  38. package/dist/controller/noteEditorManager.d.ts +36 -0
  39. package/dist/controller/noteEditorManager.js +210 -0
  40. package/dist/document-operations.d.ts +35 -3
  41. package/dist/document-operations.js +161 -3
  42. package/dist/docx/blockContentParser.js +2 -2
  43. package/dist/docx/commentParser.js +6 -1
  44. package/dist/docx/conformance.js +8 -1
  45. package/dist/docx/documentGrid.d.ts +8 -0
  46. package/dist/docx/documentGrid.js +8 -0
  47. package/dist/docx/drawingUtils.js +1 -1
  48. package/dist/docx/ensureParaIds.js +1 -1
  49. package/dist/docx/fieldParser.js +1 -1
  50. package/dist/docx/notePropertiesParser.js +1 -1
  51. package/dist/docx/numberingParser.js +1 -1
  52. package/dist/docx/paragraphParser.js +63 -58
  53. package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
  54. package/dist/docx/paragraphTextBoxEnrichment.js +67 -13
  55. package/dist/docx/paragraphTraversal.js +1 -1
  56. package/dist/docx/parser.js +3 -3
  57. package/dist/docx/rezip.js +1 -1
  58. package/dist/docx/runParser.js +4 -2
  59. package/dist/docx/sdtProperties.js +1 -1
  60. package/dist/docx/sectionParser.js +1 -1
  61. package/dist/docx/selectiveSave.js +1 -1
  62. package/dist/docx/serializer/commentSerializer.js +1 -2
  63. package/dist/docx/serializer/documentSerializer.js +2 -2
  64. package/dist/docx/serializer/headerFooterSerializer.js +2 -2
  65. package/dist/docx/serializer/noteSerializer.js +2 -2
  66. package/dist/docx/serializer/paragraphSerializer.js +7 -1
  67. package/dist/docx/serializer/runSerializer.js +4 -2
  68. package/dist/docx/serializer/stylesSerializer.js +1 -1
  69. package/dist/docx/serializer/tableSerializer.d.ts +5 -4
  70. package/dist/docx/serializer/tableSerializer.js +17 -13
  71. package/dist/docx/server/applyDocxXmlPatchProposal.d.ts +87 -0
  72. package/dist/docx/server/applyDocxXmlPatchProposal.js +204 -0
  73. package/dist/docx/server/boundedArchive.d.ts +14 -3
  74. package/dist/docx/server/boundedArchive.js +56 -11
  75. package/dist/docx/server/evaluateDocxXmlPatchProposal.d.ts +85 -0
  76. package/dist/docx/server/evaluateDocxXmlPatchProposal.js +361 -0
  77. package/dist/docx/server/inspectDocxPackage.d.ts +70 -0
  78. package/dist/docx/server/inspectDocxPackage.js +217 -0
  79. package/dist/docx/server/validateDocxConformance.d.ts +41 -0
  80. package/dist/docx/server/validateDocxConformance.js +336 -0
  81. package/dist/docx/settingsParser.js +11 -1
  82. package/dist/docx/shapeParser.js +1 -1
  83. package/dist/docx/styleParser.js +4 -2
  84. package/dist/docx/tableParser.js +18 -7
  85. package/dist/docx/textBoxParser.d.ts +3 -3
  86. package/dist/docx/textBoxParser.js +16 -12
  87. package/dist/docx/xmlSafety.d.ts +5 -0
  88. package/dist/docx/xmlSafety.js +9 -0
  89. package/dist/fields/resolveFieldValues.js +1 -3
  90. package/dist/i18n/messages/catalogs.gen.d.ts +17 -0
  91. package/dist/i18n/messages/catalogs.gen.js +17 -0
  92. package/dist/i18n/messages/messages.gen.d.ts +1 -0
  93. package/dist/index.js +1 -1
  94. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  95. package/dist/layout-bridge/convert/footnoteLayout.js +47 -40
  96. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  97. package/dist/layout-bridge/convert/headerFooterLayout.js +3 -0
  98. package/dist/layout-bridge/convert/templatePreviewFlow.js +3 -3
  99. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -2
  100. package/dist/layout-bridge/convert/toFlowBlocks.js +136 -20
  101. package/dist/layout-bridge/dom/noteStoryDom.d.ts +6 -0
  102. package/dist/layout-bridge/dom/noteStoryDom.js +17 -0
  103. package/dist/layout-bridge/engine/clickToPosition.js +2 -2
  104. package/dist/layout-engine/index.d.ts +2 -2
  105. package/dist/layout-engine/index.js +43 -28
  106. package/dist/layout-engine/justificationCompatibility.d.ts +6 -0
  107. package/dist/layout-engine/justificationCompatibility.js +8 -0
  108. package/dist/layout-engine/keep-together.js +11 -1
  109. package/dist/layout-engine/measure/cache.js +21 -5
  110. package/dist/layout-engine/measure/lineBreakProvider.js +53 -34
  111. package/dist/layout-engine/measure/measureBlocks.js +6 -3
  112. package/dist/layout-engine/measure/measureContainer.js +1 -1
  113. package/dist/layout-engine/measure/measureHelpers.d.ts +1 -1
  114. package/dist/layout-engine/measure/measureHelpers.js +3 -3
  115. package/dist/layout-engine/measure/measureParagraph.js +69 -25
  116. package/dist/layout-engine/measure/measureProvider.js +4 -3
  117. package/dist/layout-engine/measure/tableCellFlow.js +5 -2
  118. package/dist/layout-engine/measure/textBoxParagraphLayout.d.ts +9 -7
  119. package/dist/layout-engine/measure/textBoxParagraphLayout.js +22 -6
  120. package/dist/layout-engine/measure/textMeasurementPolicy.d.ts +3 -1
  121. package/dist/layout-engine/measure/textMeasurementPolicy.js +7 -1
  122. package/dist/layout-engine/paginator.js +5 -1
  123. package/dist/layout-engine/paragraphSpacing.d.ts +28 -4
  124. package/dist/layout-engine/paragraphSpacing.js +107 -13
  125. package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
  126. package/dist/layout-engine/types.d.ts +26 -13
  127. package/dist/layout-painter/registry/modules/textBox.js +5 -1
  128. package/dist/layout-painter/renderPage.d.ts +5 -2
  129. package/dist/layout-painter/renderPage.js +56 -12
  130. package/dist/layout-painter/renderParagraph.js +22 -6
  131. package/dist/layout-painter/renderTable.d.ts +5 -1
  132. package/dist/layout-painter/renderTable.js +5 -2
  133. package/dist/layout-painter/renderTextBox.d.ts +2 -1
  134. package/dist/layout-painter/renderTextBox.js +25 -14
  135. package/dist/managers/DocumentLoaderManager.js +1 -1
  136. package/dist/managers/FindReplaceManager.d.ts +8 -0
  137. package/dist/managers/FindReplaceManager.js +18 -0
  138. package/dist/managers/TableSelectionManager.d.ts +6 -0
  139. package/dist/managers/TableSelectionManager.js +14 -0
  140. package/dist/model.js +1 -1
  141. package/dist/prosemirror/attrs/index.d.ts +4 -2
  142. package/dist/prosemirror/attrs/index.js +154 -18
  143. package/dist/prosemirror/commands/comments.d.ts +3 -3
  144. package/dist/prosemirror/commands/comments.js +248 -12
  145. package/dist/prosemirror/commands/contentControls.js +1 -1
  146. package/dist/prosemirror/commands/index.js +1 -1
  147. package/dist/prosemirror/commands/pageBreak.js +1 -1
  148. package/dist/prosemirror/commands/propertyChangeScope.d.ts +2 -2
  149. package/dist/prosemirror/commands/propertyChangeScope.js +3 -2
  150. package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +9 -0
  151. package/dist/prosemirror/commands/tableCellMergeResolution.js +181 -0
  152. package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -1
  153. package/dist/prosemirror/conversion/fromProseDoc.js +286 -61
  154. package/dist/prosemirror/conversion/sdtAttrs.d.ts +9 -0
  155. package/dist/prosemirror/conversion/sdtAttrs.js +49 -0
  156. package/dist/prosemirror/conversion/toProseDoc.d.ts +2 -1
  157. package/dist/prosemirror/conversion/toProseDoc.js +347 -98
  158. package/dist/prosemirror/extensions/ExtensionManager.js +1 -1
  159. package/dist/prosemirror/extensions/StarterKit.js +6 -1
  160. package/dist/prosemirror/extensions/core/ParagraphExtension.js +4 -1
  161. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +1 -0
  162. package/dist/prosemirror/extensions/features/ListExtension.js +1 -1
  163. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +10 -1
  164. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +93 -2
  165. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +2 -1
  166. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +6 -2
  167. package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.js +1 -1
  168. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.d.ts +9 -1
  169. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +24 -1
  170. package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
  171. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.d.ts +7 -0
  172. package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.js +22 -0
  173. package/dist/prosemirror/extensions/nodes/TableExtension.js +9 -3
  174. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +13 -0
  175. package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +41 -0
  176. package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +5 -2
  177. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +4 -1
  178. package/dist/prosemirror/findReplaceSelection.d.ts +6 -1
  179. package/dist/prosemirror/findReplaceSelection.js +57 -13
  180. package/dist/prosemirror/plugins/contentControlWidgets.d.ts +34 -8
  181. package/dist/prosemirror/plugins/contentControlWidgets.js +125 -91
  182. package/dist/prosemirror/plugins/selectionTracker.js +1 -0
  183. package/dist/prosemirror/plugins/suggestionMode.js +1 -1
  184. package/dist/prosemirror/schema/index.d.ts +2 -2
  185. package/dist/prosemirror/schema/marks.d.ts +5 -1
  186. package/dist/prosemirror/schema/nodes.d.ts +64 -7
  187. package/dist/prosemirror/selectionState.js +1 -0
  188. package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
  189. package/dist/prosemirror/tableCellMergeRevision.d.ts +9 -0
  190. package/dist/prosemirror/tableCellMergeRevision.js +22 -0
  191. package/dist/prosemirror/textBoxAnchorAttrs.d.ts +9 -0
  192. package/dist/prosemirror/textBoxAnchorAttrs.js +33 -0
  193. package/dist/prosemirror/utils/extractTrackedChanges.d.ts +1 -1
  194. package/dist/prosemirror/utils/extractTrackedChanges.js +62 -14
  195. package/dist/prosemirror/validation.js +9 -1
  196. package/dist/render-dom/BodySelectionOverlay.d.ts +31 -0
  197. package/dist/render-dom/BodySelectionOverlay.js +76 -0
  198. package/dist/render-dom/HeaderFooterSelectionOverlay.d.ts +28 -0
  199. package/dist/render-dom/HeaderFooterSelectionOverlay.js +121 -0
  200. package/dist/render-dom/RemoteSelectionOverlay.d.ts +30 -0
  201. package/dist/render-dom/RemoteSelectionOverlay.js +67 -0
  202. package/dist/render-dom/RenderedDomContext.d.ts +40 -0
  203. package/dist/render-dom/RenderedDomContext.js +126 -0
  204. package/dist/render-dom/resolveSidebarItemPositions.d.ts +33 -0
  205. package/dist/render-dom/resolveSidebarItemPositions.js +45 -0
  206. package/dist/server.d.ts +6 -2
  207. package/dist/server.js +5 -1
  208. package/dist/utils/findReplace.d.ts +32 -0
  209. package/dist/utils/findReplace.js +118 -0
  210. package/dist/utils/fontFamilyMerge.js +9 -11
  211. package/dist/utils/fontLoader.js +3 -2
  212. package/dist/utils/fontResolver.js +22 -4
  213. package/dist/utils/fontWeights.d.ts +1 -1
  214. package/dist/utils/fontWeights.js +1 -1
  215. package/dist/utils/headerFooter.js +24 -1
  216. package/dist/utils/paragraphFormattingMerge.js +1 -0
  217. package/package.json +1 -1
@@ -1,4 +1,10 @@
1
+ import { expectRunPropertyChangeMarkAttrs } from "../attrs/index.js";
2
+ import { markStructuralChange } from "../extensions/features/ParagraphChangeTrackerExtension.js";
1
3
  import { paragraphRejectAttrPatch, paragraphRejectOriginalFormatting, sectionRejectProperties, tableCellRejectAttrPatch, tableRejectAttrPatch, tableRowRejectAttrPatch } from "./propertyChangeScope.js";
4
+ import { textFormattingToMarks } from "../conversion/toProseDoc.js";
5
+ import { getTableCellMergeChange } from "../tableCellMergeRevision.js";
6
+ import { hasMatchingCollapsedTableCellMerge, resolveCollapsedTableCellMerge, resolveVisibleTableCellMerge } from "./tableCellMergeResolution.js";
7
+ import { TableMap, removeRow } from "prosemirror-tables";
2
8
  //#region src/prosemirror/commands/comments.ts
3
9
  /**
4
10
  * Add a comment mark to the current selection.
@@ -36,18 +42,18 @@ function removeCommentMark(commentId) {
36
42
  * Resolve a tracked change: accept or reject.
37
43
  * - Accept: keep insertions (remove mark), delete deletions (remove text)
38
44
  * - Reject: keep deletions (remove mark), delete insertions (remove text)
45
+ * - Run formatting: accept the current formatting, or restore the previous formatting
39
46
  *
40
47
  * Pass `revisionId` to scope the operation to one specific
41
48
  * revision — otherwise overlapping marks for other revisions get
42
49
  * processed too, silently consuming pending work. Without an id
43
- * the operation matches every insertion/deletion mark in the
50
+ * the operation matches every revision mark or property-change entry in the
44
51
  * range (the bulk accept-all/reject-all path).
45
52
  */
46
53
  function resolveChange(from, to, mode, revisionIds) {
47
54
  return (state, dispatch) => {
48
55
  const insertionType = state.schema.marks["insertion"];
49
56
  const deletionType = state.schema.marks["deletion"];
50
- if (!insertionType && !deletionType) return false;
51
57
  const keepType = mode === "accept" ? insertionType : deletionType;
52
58
  const removeType = mode === "accept" ? deletionType : insertionType;
53
59
  const revisionSet = revisionIds === void 0 ? null : new Set(revisionIds);
@@ -56,6 +62,8 @@ function resolveChange(from, to, mode, revisionIds) {
56
62
  const tr = state.tr;
57
63
  const deleteRanges = [];
58
64
  const pPrMarkOps = [];
65
+ const tableRowStructuralOps = [];
66
+ const tableCellStructuralOps = [];
59
67
  state.doc.nodesBetween(from, to, (node, pos) => {
60
68
  if (node.type.name === "paragraph") {
61
69
  const op = collectPPrMarkOp(node, pos, from, to, mode, revisionSet);
@@ -95,6 +103,11 @@ function resolveChange(from, to, mode, revisionIds) {
95
103
  if (nextAttrs) tr.setNodeMarkup(pos, void 0, nextAttrs);
96
104
  return true;
97
105
  }
106
+ if (node.type.name === "tableRow" && rangeCoversNode(from, to, pos, node)) {
107
+ const op = collectTableRowStructuralOp(node, pos, mode, revisionSet);
108
+ if (op) tableRowStructuralOps.push(op);
109
+ }
110
+ if ((node.type.name === "tableCell" || node.type.name === "tableHeader") && rangeCoversNode(from, to, pos, node)) tableCellStructuralOps.push(...collectTableCellStructuralOps(node, pos, mode, revisionSet));
98
111
  const tableChangeAttrName = TABLE_PROPERTY_CHANGE_ATTR_BY_NODE[node.type.name];
99
112
  if (tableChangeAttrName !== void 0) {
100
113
  if (rangeCoversNode(from, to, pos, node)) {
@@ -107,6 +120,16 @@ function resolveChange(from, to, mode, revisionIds) {
107
120
  const nodeEnd = pos + node.nodeSize;
108
121
  const rangeFrom = Math.max(from, pos);
109
122
  const rangeTo = Math.min(to, nodeEnd);
123
+ const runPropertyChangeMark = node.marks.find((mark) => mark.type.name === "runPropertyChange");
124
+ if (runPropertyChangeMark) resolveRunPropertyChange({
125
+ tr,
126
+ node,
127
+ from: rangeFrom,
128
+ to: rangeTo,
129
+ mark: runPropertyChangeMark,
130
+ mode,
131
+ revisionSet
132
+ });
110
133
  if (removeType && node.marks.some((m) => m.type === removeType && matchesRevision(m))) deleteRanges.push({
111
134
  from: rangeFrom,
112
135
  to: rangeTo
@@ -131,11 +154,189 @@ function resolveChange(from, to, mode, revisionIds) {
131
154
  tr.setNodeAttribute(mappedPos, "pPrMark", null);
132
155
  } catch {}
133
156
  }
157
+ tableRowStructuralOps.sort((left, right) => right.rowPos - left.rowPos);
158
+ let resolvedTableRowStructure = false;
159
+ for (const op of tableRowStructuralOps) {
160
+ const mappedPos = tr.mapping.map(op.rowPos);
161
+ const row = tr.doc.nodeAt(mappedPos);
162
+ if (!row || row.type.name !== "tableRow") continue;
163
+ if (op.action === "clear") {
164
+ tr.setNodeAttribute(mappedPos, op.attrName, null);
165
+ resolvedTableRowStructure = true;
166
+ continue;
167
+ }
168
+ deleteTableRowAt(tr, mappedPos);
169
+ resolvedTableRowStructure = true;
170
+ }
171
+ if (resolvedTableRowStructure) markStructuralChange(tr);
172
+ tableCellStructuralOps.sort((left, right) => right.cellPos - left.cellPos);
173
+ let resolvedTableCellStructure = false;
174
+ let failedTableCellMergeResolution = false;
175
+ for (const op of tableCellStructuralOps) {
176
+ const mappedPos = tr.mapping.map(op.cellPos);
177
+ const cell = tr.doc.nodeAt(mappedPos);
178
+ if (!cell || cell.type.name !== "tableCell" && cell.type.name !== "tableHeader") continue;
179
+ if (op.type === "merge") {
180
+ const resolved = op.source === "collapsed" ? resolveCollapsedTableCellMerge(tr, mappedPos, op.mode, op.revisionSet) : resolveVisibleTableCellMerge(tr, mappedPos, op.mode);
181
+ if (!resolved) {
182
+ failedTableCellMergeResolution = true;
183
+ break;
184
+ }
185
+ resolvedTableCellStructure ||= resolved;
186
+ continue;
187
+ }
188
+ if (op.action === "clear") {
189
+ tr.setNodeAttribute(mappedPos, "cellMarker", null);
190
+ resolvedTableCellStructure = true;
191
+ continue;
192
+ }
193
+ deleteTableCellAt(tr, mappedPos);
194
+ resolvedTableCellStructure = true;
195
+ }
196
+ if (failedTableCellMergeResolution) return false;
197
+ if (resolvedTableCellStructure) markStructuralChange(tr);
134
198
  if (tr.steps.length > 0) dispatch(tr);
135
199
  }
136
200
  return true;
137
201
  };
138
202
  }
203
+ const RUN_FORMATTING_MARK_NAMES = /* @__PURE__ */ new Set([
204
+ "bold",
205
+ "italic",
206
+ "underline",
207
+ "strike",
208
+ "textColor",
209
+ "highlight",
210
+ "runShading",
211
+ "fontSize",
212
+ "fontFamily",
213
+ "language",
214
+ "superscript",
215
+ "subscript",
216
+ "allCaps",
217
+ "smallCaps",
218
+ "characterSpacing",
219
+ "emboss",
220
+ "imprint",
221
+ "hidden",
222
+ "textShadow",
223
+ "emphasisMark",
224
+ "textOutline",
225
+ "rtl",
226
+ "textEffect",
227
+ "runFormattingOverride",
228
+ "characterStyle"
229
+ ]);
230
+ const resolveRunPropertyChange = ({ tr, node, from, to, mark, mode, revisionSet }) => {
231
+ const { changes } = expectRunPropertyChangeMarkAttrs(mark);
232
+ const matches = changes.filter((change) => revisionSet === null || revisionSet.has(change.info.id));
233
+ if (matches.length === 0) return;
234
+ tr.removeMark(from, to, mark);
235
+ const remaining = changes.filter((change) => revisionSet !== null && !revisionSet.has(change.info.id));
236
+ if (remaining.length > 0) tr.addMark(from, to, mark.type.create({ changes: remaining }));
237
+ if (mode === "accept") return;
238
+ const previousFormatting = matches.at(0)?.previousFormatting;
239
+ for (const currentMark of node.marks) if (RUN_FORMATTING_MARK_NAMES.has(currentMark.type.name)) tr.removeMark(from, to, currentMark.type);
240
+ for (const previousMark of textFormattingToMarks(previousFormatting)) tr.addMark(from, to, previousMark);
241
+ if (previousFormatting?.styleId) {
242
+ const characterStyle = node.type.schema.marks["characterStyle"];
243
+ if (characterStyle) tr.addMark(from, to, characterStyle.create({
244
+ styleId: previousFormatting.styleId,
245
+ _styleRPr: null
246
+ }));
247
+ }
248
+ };
249
+ function collectTableRowStructuralOp(node, rowPos, mode, revisionSet) {
250
+ for (const attrName of ["trIns", "trDel"]) {
251
+ const marker = node.attrs[attrName];
252
+ if (!isTableRowRevisionAttr(marker)) continue;
253
+ if (revisionSet !== null && !revisionSet.has(marker.revisionId)) continue;
254
+ return {
255
+ rowPos,
256
+ attrName,
257
+ action: attrName === "trIns" === (mode === "accept") ? "clear" : "remove"
258
+ };
259
+ }
260
+ return null;
261
+ }
262
+ function isTableRowRevisionAttr(value) {
263
+ return typeof value === "object" && value !== null && "revisionId" in value && typeof value.revisionId === "number";
264
+ }
265
+ function collectTableCellStructuralOps(node, cellPos, mode, revisionSet) {
266
+ const operations = [];
267
+ const marker = node.attrs["cellMarker"];
268
+ if (isTableCellRevisionAttr(marker) && (revisionSet === null || revisionSet.has(marker.info.revisionId))) if (marker.kind === "merge") operations.push({
269
+ type: "merge",
270
+ cellPos,
271
+ source: "visible",
272
+ mode,
273
+ revisionSet
274
+ });
275
+ else {
276
+ const keepsCell = marker.kind === "ins" === (mode === "accept");
277
+ operations.push({
278
+ type: "membership",
279
+ cellPos,
280
+ action: keepsCell ? "clear" : "remove"
281
+ });
282
+ }
283
+ if (hasMatchingCollapsedTableCellMerge(node, revisionSet)) operations.push({
284
+ type: "merge",
285
+ cellPos,
286
+ source: "collapsed",
287
+ mode,
288
+ revisionSet
289
+ });
290
+ return operations;
291
+ }
292
+ function isTableCellRevisionAttr(value) {
293
+ if (typeof value !== "object" || value === null || !("kind" in value) || !("info" in value)) return false;
294
+ if (value.kind !== "ins" && value.kind !== "del" && value.kind !== "merge") return false;
295
+ const info = value.info;
296
+ return typeof info === "object" && info !== null && "revisionId" in info && typeof info.revisionId === "number";
297
+ }
298
+ function deleteTableCellAt(tr, cellPos) {
299
+ const cell = tr.doc.nodeAt(cellPos);
300
+ if (!cell || cell.type.name !== "tableCell" && cell.type.name !== "tableHeader") return;
301
+ const resolved = tr.doc.resolve(cellPos);
302
+ const row = resolved.parent;
303
+ if (row.type.spec["tableRole"] !== "row") return;
304
+ if (row.childCount > 1) {
305
+ tr.delete(cellPos, cellPos + cell.nodeSize);
306
+ return;
307
+ }
308
+ deleteTableRowAt(tr, resolved.start() - 1);
309
+ }
310
+ function deleteTableRowAt(tr, rowPos) {
311
+ const resolved = tr.doc.resolve(rowPos);
312
+ const table = resolved.parent;
313
+ if (table.type.spec["tableRole"] !== "table") return;
314
+ const rowIndex = resolved.index();
315
+ if (table.childCount > 1) {
316
+ const map = TableMap.get(table);
317
+ removeRow(tr, {
318
+ map,
319
+ table,
320
+ tableStart: resolved.start(),
321
+ left: 0,
322
+ top: rowIndex,
323
+ right: map.width,
324
+ bottom: rowIndex + 1
325
+ }, rowIndex);
326
+ return;
327
+ }
328
+ const tablePosition = resolved.start() - 1;
329
+ const tableEnd = tablePosition + table.nodeSize;
330
+ const outerResolved = tr.doc.resolve(tablePosition);
331
+ const parent = outerResolved.parent;
332
+ const tableIndex = outerResolved.index();
333
+ if (parent.canReplace(tableIndex, tableIndex + 1)) {
334
+ tr.delete(tablePosition, tableEnd);
335
+ return;
336
+ }
337
+ const emptyParagraph = tr.doc.type.schema.nodes["paragraph"]?.createAndFill();
338
+ if (emptyParagraph && parent.canReplaceWith(tableIndex, tableIndex + 1, emptyParagraph.type, emptyParagraph.marks)) tr.replaceWith(tablePosition, tableEnd, emptyParagraph);
339
+ }
139
340
  function collectPPrMarkOp(node, pos, from, to, mode, revisionSet) {
140
341
  if (!rangeCoversParagraphBoundary(from, to, pos, node)) return null;
141
342
  const pPrMark = node.attrs["pPrMark"];
@@ -279,30 +480,65 @@ function rejectAllChanges() {
279
480
  return (state, dispatch) => rejectChange(0, state.doc.content.size)(state, dispatch);
280
481
  }
281
482
  /**
282
- * Find the document range covered by all insertion/deletion marks
483
+ * Find the document range covered by all inline revision marks
283
484
  * carrying any of the given AI-edit `revisionIds`. Returns null when
284
485
  * none of those marks are present (already accepted/rejected, or
285
486
  * never existed). A replace operation typically passes two ids (one
286
487
  * for its deletion side, one for its insertion side); inserts and
287
- * standalone deletions pass a single id.
488
+ * standalone deletions and formatting changes pass a single id.
288
489
  */
289
490
  function findAIEditRevisionRange(state, revisionIds) {
290
491
  const insertionType = state.schema.marks["insertion"];
291
492
  const deletionType = state.schema.marks["deletion"];
292
- if (!insertionType && !deletionType) return null;
493
+ const runPropertyChangeType = state.schema.marks["runPropertyChange"];
293
494
  const idSet = new Set(typeof revisionIds === "number" ? [revisionIds] : revisionIds);
294
495
  const range = {
295
496
  from: null,
296
497
  to: null
297
498
  };
298
499
  state.doc.descendants((node, pos) => {
500
+ if (node.type.name === "tableRow") for (const attrName of ["trIns", "trDel"]) {
501
+ const marker = node.attrs[attrName];
502
+ if (isTableRowRevisionAttr(marker) && idSet.has(marker.revisionId)) {
503
+ const start = pos;
504
+ const end = pos + node.nodeSize;
505
+ if (range.from === null || start < range.from) range.from = start;
506
+ if (range.to === null || end > range.to) range.to = end;
507
+ return false;
508
+ }
509
+ }
510
+ if (node.type.name === "tableCell" || node.type.name === "tableHeader") {
511
+ const marker = node.attrs["cellMarker"];
512
+ const hasDirectRevision = isTableCellRevisionAttr(marker) && idSet.has(marker.info.revisionId);
513
+ const continuationCells = node.attrs["_docxVMergeContinuationCells"];
514
+ const hasCollapsedRevision = Array.isArray(continuationCells) && continuationCells.some((cell) => {
515
+ const change = getTableCellMergeChange(cell);
516
+ return change !== null && idSet.has(change.info.id);
517
+ });
518
+ if (hasDirectRevision || hasCollapsedRevision) {
519
+ const start = pos;
520
+ const end = pos + node.nodeSize;
521
+ if (range.from === null || start < range.from) range.from = start;
522
+ if (range.to === null || end > range.to) range.to = end;
523
+ return false;
524
+ }
525
+ }
299
526
  if (!node.isInline) return;
300
- for (const mark of node.marks) if ((mark.type === insertionType || mark.type === deletionType) && typeof mark.attrs["revisionId"] === "number" && idSet.has(mark.attrs["revisionId"])) {
301
- const start = pos;
302
- const end = pos + node.nodeSize;
303
- if (range.from === null || start < range.from) range.from = start;
304
- if (range.to === null || end > range.to) range.to = end;
305
- break;
527
+ for (const mark of node.marks) {
528
+ if (mark.type === runPropertyChangeType && expectRunPropertyChangeMarkAttrs(mark).changes.some((change) => idSet.has(change.info.id))) {
529
+ const start = pos;
530
+ const end = pos + node.nodeSize;
531
+ if (range.from === null || start < range.from) range.from = start;
532
+ if (range.to === null || end > range.to) range.to = end;
533
+ break;
534
+ }
535
+ if ((mark.type === insertionType || mark.type === deletionType) && typeof mark.attrs["revisionId"] === "number" && idSet.has(mark.attrs["revisionId"])) {
536
+ const start = pos;
537
+ const end = pos + node.nodeSize;
538
+ if (range.from === null || start < range.from) range.from = start;
539
+ if (range.to === null || end > range.to) range.to = end;
540
+ break;
541
+ }
306
542
  }
307
543
  });
308
544
  if (range.from === null || range.to === null) return null;
@@ -313,7 +549,7 @@ function findAIEditRevisionRange(state, revisionIds) {
313
549
  }
314
550
  /**
315
551
  * Accept the tracked-change marks belonging to an AI-edit operation.
316
- * Pass a single revisionId for inserts/standalone deletions, or the
552
+ * Pass a single revisionId for inserts, standalone deletions, or formatting changes; or the
317
553
  * full id list for a replace (one id per side). Returns false when
318
554
  * none of the ids match anything in the doc.
319
555
  */
@@ -1,6 +1,6 @@
1
- import { formatDate } from "../../docx/fieldParser.js";
2
1
  import { expectBlockSdtAttrs } from "../attrs/index.js";
3
2
  import { ContentControlBoundError, ContentControlLockedError, ContentControlTypeError } from "../../content-controls/errors.js";
3
+ import { formatDate } from "../../docx/fieldParser.js";
4
4
  import { SUGGESTION_BYPASS_META } from "../plugins/suggestionMode.js";
5
5
  //#region src/prosemirror/commands/contentControls.ts
6
6
  function nodeMatchesFilter(node, pos, filter) {
@@ -1,10 +1,10 @@
1
- import { acceptAIEditRevision, acceptAllChanges, acceptChange, addCommentMark, findAIEditRevisionRange, findNextChange, findPreviousChange, rejectAIEditRevision, rejectAllChanges, rejectChange, removeCommentMark } from "./comments.js";
2
1
  import { getParagraphAlignment, getParagraphBidi, getStyleId } from "../extensions/core/ParagraphExtension.js";
3
2
  import { clearFormatting, createRemoveMarkCommand, createSetMarkCommand, getMarkAttr, isMarkActive } from "../extensions/marks/markUtils.js";
4
3
  import { getTableContext, isInTable as isInTableCell } from "../extensions/nodes/TableExtension.js";
5
4
  import { getListInfo, isInList } from "../extensions/features/ListExtension.js";
6
5
  import { CLIPBOARD_READ_ERROR_EVENT, buildPlainTextSlice, pasteWithoutFormatting } from "./pastePlainText.js";
7
6
  import { getHyperlinkAttrs, getSelectedText, isHyperlinkActive } from "../extensions/marks/HyperlinkExtension.js";
7
+ import { acceptAIEditRevision, acceptAllChanges, acceptChange, addCommentMark, findAIEditRevisionRange, findNextChange, findPreviousChange, rejectAIEditRevision, rejectAllChanges, rejectChange, removeCommentMark } from "./comments.js";
8
8
  import { addColumnLeft, addColumnRight, addRowAbove, addRowBelow, applyTableStyle, autoFitContents, deleteColumn, deleteRow, deleteTable, distributeColumns, insertTable, mergeCells, removeTableBorders, selectColumn, selectRow, selectTable, setAllTableBorders, setCellBorder, setCellFillColor, setCellMargins, setCellTextDirection, setCellVerticalAlign, setInsideTableBorders, setOutsideTableBorders, setRowHeight, setTableBorderColor, setTableBorderPreset, setTableBorderWidth, setTableBorders, setTableProperties, splitCell, toggleHeaderRow, toggleNoWrap } from "./table.js";
9
9
  import { clearFontFamily, clearFontSize, clearHighlight, clearTextColor, insertHyperlink, removeHyperlink, setFontFamily, setFontSize, setHighlight, setHyperlink, setTextColor, setUnderlineStyle, toggleBold, toggleItalic, toggleStrike, toggleSubscript, toggleSuperscript, toggleUnderline } from "./formatting.js";
10
10
  import { addTabStop, alignCenter, alignJustify, alignLeft, alignRight, applyStyle, clearStyle, decreaseIndent, decreaseListLevel, doubleSpacing, generateTOC, increaseIndent, increaseListLevel, oneAndHalfSpacing, removeList, removeTabStop, setAlignment, setIndentFirstLine, setIndentLeft, setIndentRight, setLineSpacing, setLtr, setRtl, setSpaceAfter, setSpaceBefore, singleSpacing, toggleBidi, toggleBulletList, toggleNumberedList } from "./paragraph.js";
@@ -1,5 +1,5 @@
1
- import { TextSelection } from "prosemirror-state";
2
1
  import { Fragment } from "prosemirror-model";
2
+ import { TextSelection } from "prosemirror-state";
3
3
  //#region src/prosemirror/commands/pageBreak.ts
4
4
  /**
5
5
  * Page Break Commands
@@ -18,9 +18,9 @@ type AttrPatch = Record<string, unknown>;
18
18
  * `runInWithNext` (`w:specVanish` lives in that rPr)
19
19
  * - load-time style/numbering bookkeeping the command layer cannot recompute
20
20
  * without a style resolver: `numPrFromStyle`, the `list*` rendering attrs,
21
- * `spacingFromDocDefaults`
21
+ * `spacingFromDocDefaults`, `spacingFromImplicitDefaultStyle`
22
22
  */
23
- declare const PPR_CHANGE_SCOPED_ATTR_KEYS: readonly ["styleId", "numPr", "alignment", "spaceBefore", "spaceAfter", "lineSpacing", "lineSpacingRule", "spacingExplicit", "indentLeft", "indentRight", "indentFirstLine", "hangingIndent", "borders", "shading", "tabs", "pageBreakBefore", "keepNext", "keepLines", "widowControl", "contextualSpacing", "outlineLevel", "direction", "_autospacingBase"];
23
+ declare const PPR_CHANGE_SCOPED_ATTR_KEYS: readonly ["styleId", "numPr", "alignment", "spaceBefore", "spaceAfter", "lineSpacing", "lineSpacingRule", "snapToGrid", "spacingExplicit", "indentLeft", "indentRight", "indentFirstLine", "hangingIndent", "borders", "shading", "tabs", "pageBreakBefore", "keepNext", "keepLines", "widowControl", "contextualSpacing", "outlineLevel", "direction", "_autospacingBase"];
24
24
  /**
25
25
  * Build the attr patch that rejecting one pPrChange applies to a paragraph:
26
26
  * every in-scope key set to the stored previous value, or reset to `null`
@@ -1,5 +1,5 @@
1
- import { setAutospacingBaseValue } from "../autospacingBase.js";
2
1
  import { directionFromBidi } from "../paragraphDirection.js";
2
+ import { setAutospacingBaseValue } from "../autospacingBase.js";
3
3
  //#region src/prosemirror/commands/propertyChangeScope.ts
4
4
  /**
5
5
  * Paragraph attrs governed by a `w:pPrChange` — the attrs
@@ -17,7 +17,7 @@ import { directionFromBidi } from "../paragraphDirection.js";
17
17
  * `runInWithNext` (`w:specVanish` lives in that rPr)
18
18
  * - load-time style/numbering bookkeeping the command layer cannot recompute
19
19
  * without a style resolver: `numPrFromStyle`, the `list*` rendering attrs,
20
- * `spacingFromDocDefaults`
20
+ * `spacingFromDocDefaults`, `spacingFromImplicitDefaultStyle`
21
21
  */
22
22
  const PPR_CHANGE_SCOPED_ATTR_KEYS = [
23
23
  "styleId",
@@ -27,6 +27,7 @@ const PPR_CHANGE_SCOPED_ATTR_KEYS = [
27
27
  "spaceAfter",
28
28
  "lineSpacing",
29
29
  "lineSpacingRule",
30
+ "snapToGrid",
30
31
  "spacingExplicit",
31
32
  "indentLeft",
32
33
  "indentRight",
@@ -0,0 +1,9 @@
1
+ import { Transaction } from "prosemirror-state";
2
+ import { Node } from "prosemirror-model";
3
+
4
+ //#region src/prosemirror/commands/tableCellMergeResolution.d.ts
5
+ declare const hasMatchingCollapsedTableCellMerge: (node: Node, revisionSet: Set<number> | null) => boolean;
6
+ declare const resolveVisibleTableCellMerge: (tr: Transaction, cellPos: number, mode: "accept" | "reject") => boolean;
7
+ declare const resolveCollapsedTableCellMerge: (tr: Transaction, cellPos: number, mode: "accept" | "reject", revisionSet: Set<number> | null) => boolean;
8
+ //#endregion
9
+ export { hasMatchingCollapsedTableCellMerge, resolveCollapsedTableCellMerge, resolveVisibleTableCellMerge };
@@ -0,0 +1,181 @@
1
+ import { standaloneTableCellFromProseMirror } from "../conversion/fromProseDoc.js";
2
+ import { standaloneTableCellToProseMirror } from "../conversion/toProseDoc.js";
3
+ import { getTableCellMergeChange } from "../tableCellMergeRevision.js";
4
+ import { Result } from "better-result";
5
+ import { TableMap } from "prosemirror-tables";
6
+ //#region src/prosemirror/commands/tableCellMergeResolution.ts
7
+ const hasMatchingCollapsedTableCellMerge = (node, revisionSet) => {
8
+ const continuationCells = node.attrs["_docxVMergeContinuationCells"];
9
+ if (!Array.isArray(continuationCells)) return false;
10
+ return continuationCells.some((cell) => {
11
+ const change = getTableCellMergeChange(cell);
12
+ return change !== null && (revisionSet === null || revisionSet.has(change.info.id));
13
+ });
14
+ };
15
+ const isTableCellMergeRevisionAttr = (value) => {
16
+ if (typeof value !== "object" || value === null || !("kind" in value) || value.kind !== "merge" || !("info" in value)) return false;
17
+ const info = value.info;
18
+ return typeof info === "object" && info !== null && "revisionId" in info && typeof info.revisionId === "number";
19
+ };
20
+ const tableCellContext = (doc, cellPos) => {
21
+ const resolved = doc.resolve(cellPos);
22
+ for (let depth = resolved.depth; depth > 0; depth -= 1) {
23
+ const node = resolved.node(depth);
24
+ if (node.type.spec["tableRole"] !== "table") continue;
25
+ const tablePos = resolved.before(depth);
26
+ return {
27
+ table: node,
28
+ tableStart: tablePos + 1,
29
+ relativeCellPos: cellPos - tablePos - 1
30
+ };
31
+ }
32
+ return null;
33
+ };
34
+ const resolveVisibleTableCellMerge = (tr, cellPos, mode) => {
35
+ const cell = tr.doc.nodeAt(cellPos);
36
+ const marker = cell?.attrs["cellMarker"];
37
+ if (!cell || !isTableCellMergeRevisionAttr(marker)) return false;
38
+ if (mode === "accept") {
39
+ tr.setNodeAttribute(cellPos, "cellMarker", null);
40
+ return true;
41
+ }
42
+ if ((marker.verticalMergeOriginal ?? "rest") === "continue") return mergeTableCellWithCellAbove(tr, cellPos);
43
+ const originalFormatting = cell.attrs["_originalFormatting"];
44
+ let nextOriginalFormatting = originalFormatting;
45
+ if (typeof originalFormatting === "object" && originalFormatting !== null) {
46
+ nextOriginalFormatting = { ...originalFormatting };
47
+ delete nextOriginalFormatting.vMerge;
48
+ }
49
+ tr.setNodeMarkup(cellPos, void 0, {
50
+ ...cell.attrs,
51
+ cellMarker: null,
52
+ _originalFormatting: nextOriginalFormatting
53
+ });
54
+ return true;
55
+ };
56
+ const mergeTableCellWithCellAbove = (tr, cellPos) => {
57
+ const context = tableCellContext(tr.doc, cellPos);
58
+ const cell = tr.doc.nodeAt(cellPos);
59
+ if (!context || !cell) return false;
60
+ const map = TableMap.get(context.table);
61
+ const rectangle = map.findCell(context.relativeCellPos);
62
+ if (rectangle.top === 0) return false;
63
+ const aboveRelativePos = map.map[(rectangle.top - 1) * map.width + rectangle.left];
64
+ if (aboveRelativePos === void 0 || aboveRelativePos === context.relativeCellPos) return false;
65
+ const aboveRectangle = map.findCell(aboveRelativePos);
66
+ if (aboveRectangle.left !== rectangle.left || aboveRectangle.right !== rectangle.right || aboveRectangle.bottom !== rectangle.top) return false;
67
+ const abovePos = context.tableStart + aboveRelativePos;
68
+ const aboveCell = tr.doc.nodeAt(abovePos);
69
+ const aboveRowspan = aboveCell?.attrs["rowspan"];
70
+ const cellRowspan = cell.attrs["rowspan"];
71
+ if (!aboveCell || typeof aboveRowspan !== "number" || typeof cellRowspan !== "number" || aboveRowspan < 1 || cellRowspan < 1) return false;
72
+ const continuationCells = tableCellContinuationCells(aboveCell, aboveRowspan);
73
+ continuationCells.push(tableCellContinuationFromNode(cell));
74
+ const nestedContinuations = cell.attrs["_docxVMergeContinuationCells"];
75
+ if (Array.isArray(nestedContinuations)) continuationCells.push(...nestedContinuations);
76
+ tr.delete(cellPos, cellPos + cell.nodeSize);
77
+ tr.setNodeMarkup(abovePos, void 0, {
78
+ ...aboveCell.attrs,
79
+ rowspan: aboveRowspan + cellRowspan,
80
+ _docxVMergeContinuationCells: continuationCells
81
+ });
82
+ return true;
83
+ };
84
+ const tableCellContinuationCells = (cell, rowspan) => {
85
+ const stored = cell.attrs["_docxVMergeContinuationCells"];
86
+ const cells = Array.isArray(stored) ? [...stored] : [];
87
+ while (cells.length < rowspan - 1) cells.push(emptyVerticalMergeContinuation());
88
+ return cells;
89
+ };
90
+ const tableCellContinuationFromNode = (cell) => {
91
+ const continuation = standaloneTableCellFromProseMirror(cell);
92
+ const formatting = {
93
+ ...continuation.formatting,
94
+ vMerge: "continue"
95
+ };
96
+ const colspan = cell.attrs["colspan"];
97
+ if (typeof colspan === "number" && colspan > 1) formatting.gridSpan = colspan;
98
+ continuation.formatting = formatting;
99
+ delete continuation.structuralChange;
100
+ return continuation;
101
+ };
102
+ const emptyVerticalMergeContinuation = () => ({
103
+ type: "tableCell",
104
+ formatting: { vMerge: "continue" },
105
+ content: [{
106
+ type: "paragraph",
107
+ content: []
108
+ }]
109
+ });
110
+ const resolveCollapsedTableCellMerge = (tr, cellPos, mode, revisionSet) => {
111
+ const cell = tr.doc.nodeAt(cellPos);
112
+ const stored = cell?.attrs["_docxVMergeContinuationCells"];
113
+ if (!cell || !Array.isArray(stored)) return false;
114
+ const matchingIndices = [];
115
+ const nextCells = stored.map((continuationCell, index) => {
116
+ const change = getTableCellMergeChange(continuationCell);
117
+ if (!change || revisionSet !== null && !revisionSet.has(change.info.id)) return continuationCell;
118
+ matchingIndices.push(index);
119
+ const nextCell = { ...continuationCell };
120
+ delete nextCell.structuralChange;
121
+ return nextCell;
122
+ });
123
+ if (matchingIndices.length === 0) return false;
124
+ if (mode === "accept") {
125
+ tr.setNodeAttribute(cellPos, "_docxVMergeContinuationCells", nextCells);
126
+ return true;
127
+ }
128
+ const splitIndices = matchingIndices.filter((index) => {
129
+ const change = getTableCellMergeChange(stored[index]);
130
+ return change?.verticalMerge === "continue" && (change.verticalMergeOriginal ?? "rest") === "rest";
131
+ });
132
+ if (splitIndices.length === 0) {
133
+ tr.setNodeAttribute(cellPos, "_docxVMergeContinuationCells", nextCells);
134
+ return true;
135
+ }
136
+ const firstSplitIndex = splitIndices.at(0);
137
+ if (firstSplitIndex === void 0 || splitIndices.length !== stored.length - firstSplitIndex || splitIndices.some((index, offset) => index !== firstSplitIndex + offset)) return false;
138
+ const context = tableCellContext(tr.doc, cellPos);
139
+ if (!context) return false;
140
+ const map = TableMap.get(context.table);
141
+ const rectangle = map.findCell(context.relativeCellPos);
142
+ const rowspan = cell.attrs["rowspan"];
143
+ if (typeof rowspan !== "number" || rowspan !== stored.length + 1 || rectangle.bottom - rectangle.top !== rowspan) return false;
144
+ const restorations = [];
145
+ for (const index of splitIndices) {
146
+ const source = nextCells[index];
147
+ if (!source) return false;
148
+ const restoredCell = createRestoredTableCell(cell, source);
149
+ if (!restoredCell) return false;
150
+ restorations.push({
151
+ index,
152
+ cell: restoredCell
153
+ });
154
+ }
155
+ const mapFrom = tr.mapping.maps.length;
156
+ for (const restoration of restorations) {
157
+ const row = rectangle.top + restoration.index + 1;
158
+ const insertionPos = context.tableStart + map.positionAt(row, rectangle.left, context.table);
159
+ tr.insert(tr.mapping.slice(mapFrom).map(insertionPos, 1), restoration.cell);
160
+ }
161
+ const remainingCells = nextCells.slice(0, firstSplitIndex);
162
+ tr.setNodeMarkup(cellPos, void 0, {
163
+ ...cell.attrs,
164
+ rowspan: firstSplitIndex + 1,
165
+ _docxVMergeContinuationCells: remainingCells.length > 0 ? remainingCells : null
166
+ });
167
+ return true;
168
+ };
169
+ const createRestoredTableCell = (origin, source) => {
170
+ const formatting = source.formatting ? { ...source.formatting } : void 0;
171
+ if (formatting) delete formatting.vMerge;
172
+ const restored = standaloneTableCellToProseMirror({
173
+ type: "tableCell",
174
+ ...formatting ? { formatting } : {},
175
+ ...source.propertyChanges ? { propertyChanges: source.propertyChanges } : {},
176
+ content: source.content
177
+ }, origin.type.name === "tableHeader" ? "tableHeader" : "tableCell");
178
+ return Result.try(() => origin.type.schema.nodeFromJSON(restored.toJSON())).unwrapOr(null);
179
+ };
180
+ //#endregion
181
+ export { hasMatchingCollapsedTableCellMerge, resolveCollapsedTableCellMerge, resolveVisibleTableCellMerge };
@@ -10,6 +10,7 @@ declare function fromProseDoc(pmDoc: Node, baseDocument?: document_d_exports.Doc
10
10
  * Convert ProseMirror marks to TextFormatting
11
11
  */
12
12
  declare function marksToTextFormatting(marks: readonly Mark[]): document_d_exports.TextFormatting;
13
+ declare const standaloneTableCellFromProseMirror: (node: Node) => document_d_exports.TableCell;
13
14
  /**
14
15
  * Update a Document with content from a ProseMirror document
15
16
  * Preserves all non-content parts of the original document
@@ -24,4 +25,4 @@ declare function updateDocumentContent(originalDocument: document_d_exports.Docu
24
25
  */
25
26
  declare function proseDocToBlocks(pmDoc: Node): document_d_exports.BlockContent[];
26
27
  //#endregion
27
- export { fromProseDoc, marksToTextFormatting, proseDocToBlocks, updateDocumentContent };
28
+ export { fromProseDoc, marksToTextFormatting, proseDocToBlocks, standaloneTableCellFromProseMirror, updateDocumentContent };