@stll/folio-core 0.36.0 → 0.37.1

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 (200) hide show
  1. package/README.md +59 -1
  2. package/dist/ai-edits/apply.js +689 -367
  3. package/dist/ai-edits/block-identity.d.ts +4 -1
  4. package/dist/ai-edits/block-identity.js +4 -1
  5. package/dist/ai-edits/blockRange.js +14 -14
  6. package/dist/ai-edits/clean-text.d.ts +40 -1
  7. package/dist/ai-edits/clean-text.js +52 -2
  8. package/dist/ai-edits/headless.d.ts +3 -1
  9. package/dist/ai-edits/headless.js +133 -71
  10. package/dist/ai-edits/index.d.ts +3 -3
  11. package/dist/ai-edits/index.js +2 -2
  12. package/dist/ai-edits/read.js +38 -20
  13. package/dist/ai-edits/snapshot.d.ts +14 -6
  14. package/dist/ai-edits/snapshot.js +99 -19
  15. package/dist/ai-edits/table-cell-mutations.js +1 -1
  16. package/dist/ai-edits/table-row-column-mutations.js +7 -0
  17. package/dist/ai-edits/table-template.d.ts +11 -1
  18. package/dist/ai-edits/table-template.js +49 -17
  19. package/dist/ai-edits/types.d.ts +60 -57
  20. package/dist/ai-suggestions/conflict.js +1 -4
  21. package/dist/ai-suggestions/text-positions.d.ts +8 -0
  22. package/dist/ai-suggestions/text-positions.js +27 -5
  23. package/dist/compare/__fixtures__/body-sequence.js +3 -4
  24. package/dist/compare/column-alignment.d.ts +13 -13
  25. package/dist/compare/column-alignment.js +78 -39
  26. package/dist/compare/compare.d.ts +4 -3
  27. package/dist/compare/compare.js +41 -5
  28. package/dist/compare/content-alignment.d.ts +95 -0
  29. package/dist/compare/content-alignment.js +1450 -0
  30. package/dist/compare/content-types.d.ts +100 -0
  31. package/dist/compare/content-types.js +0 -0
  32. package/dist/compare/content.d.ts +209 -0
  33. package/dist/compare/content.js +885 -0
  34. package/dist/compare/formatting.d.ts +5 -5
  35. package/dist/compare/formatting.js +6 -4
  36. package/dist/compare/plan.d.ts +6 -1
  37. package/dist/compare/plan.js +201 -569
  38. package/dist/compare/scenario.d.ts +2 -2
  39. package/dist/compare/types.d.ts +3 -3
  40. package/dist/compare/verification.d.ts +2 -2
  41. package/dist/compare/verification.js +25 -8
  42. package/dist/compat/eigenpal.d.ts +5 -3
  43. package/dist/compat/eigenpal.js +3 -2
  44. package/dist/controller/headerFooterEditorManager.js +14 -6
  45. package/dist/controller/hiddenEditorManager.d.ts +7 -2
  46. package/dist/controller/hiddenEditorManager.js +15 -6
  47. package/dist/controller/layoutPipeline.js +5 -3
  48. package/dist/controller/noteEditorManager.js +12 -7
  49. package/dist/display-list/build/headerFooterPrimitives.js +1 -0
  50. package/dist/display-list/build/storyPrimitives.d.ts +5 -2
  51. package/dist/display-list/build/storyPrimitives.js +60 -3
  52. package/dist/display-list/build/tablePrimitives.js +30 -0
  53. package/dist/display-list/primitives.d.ts +1 -1
  54. package/dist/document-operations.d.ts +8 -6
  55. package/dist/document-operations.js +121 -26
  56. package/dist/docx/blockContentParser.js +6 -27
  57. package/dist/docx/ensureParaIds.js +9 -4
  58. package/dist/docx/numberingParser.d.ts +3 -1
  59. package/dist/docx/numberingParser.js +4 -1
  60. package/dist/docx/paragraphParser.js +7 -6
  61. package/dist/docx/paragraphTraversal.js +30 -34
  62. package/dist/docx/rezip.d.ts +0 -8
  63. package/dist/docx/rezip.js +41 -16
  64. package/dist/docx/runParser.js +4 -2
  65. package/dist/docx/serializer/paragraphSerializer.js +2 -0
  66. package/dist/docx/serializer/runSerializer.js +5 -3
  67. package/dist/docx/serializer/trackedChangeAttributes.d.ts +3 -1
  68. package/dist/docx/serializer/trackedChangeAttributes.js +11 -1
  69. package/dist/docx/server/build.d.ts +1 -1
  70. package/dist/headless-layout.js +5 -4
  71. package/dist/index.d.ts +5 -3
  72. package/dist/index.js +3 -2
  73. package/dist/internal/headlessRevisionResolution.d.ts +23 -0
  74. package/dist/internal/headlessRevisionResolution.js +176 -0
  75. package/dist/internal/headlessRevisionResolutionGuard.d.ts +12 -0
  76. package/dist/internal/headlessRevisionResolutionGuard.js +28 -0
  77. package/dist/internal/pageBreakRunDescendantIndex.d.ts +9 -0
  78. package/dist/internal/pageBreakRunDescendantIndex.js +27 -0
  79. package/dist/internal/pageBreakRunPartition.d.ts +26 -0
  80. package/dist/internal/pageBreakRunPartition.js +35 -0
  81. package/dist/internal/pageBreakRunSourceDescendantIndex.d.ts +15 -0
  82. package/dist/internal/pageBreakRunSourceDescendantIndex.js +126 -0
  83. package/dist/internal/sectionEndpointResolution.d.ts +32 -0
  84. package/dist/internal/sectionEndpointResolution.js +38 -0
  85. package/dist/layout-bridge/convert/footnoteLayout.js +1 -0
  86. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +16 -4
  87. package/dist/layout-bridge/convert/headerFooterLayout.js +48 -5
  88. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -0
  89. package/dist/layout-bridge/convert/toFlowBlocks.js +379 -75
  90. package/dist/layout-bridge/dom/clickToPositionDom.d.ts +8 -1
  91. package/dist/layout-bridge/dom/clickToPositionDom.js +114 -40
  92. package/dist/layout-bridge/dom/textStreamDom.d.ts +24 -0
  93. package/dist/layout-bridge/dom/textStreamDom.js +75 -0
  94. package/dist/layout-bridge/headerFooterLayout.js +16 -30
  95. package/dist/layout-engine/index.js +12 -3
  96. package/dist/layout-engine/measure/tableFragmentBorderGeometry.d.ts +17 -0
  97. package/dist/layout-engine/measure/tableFragmentBorderGeometry.js +24 -0
  98. package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
  99. package/dist/layout-engine/types.d.ts +7 -0
  100. package/dist/layout-painter/imageLayout.d.ts +1 -1
  101. package/dist/layout-painter/renderTable.js +20 -0
  102. package/dist/model.d.ts +1 -1
  103. package/dist/paged-layout/rangeProjection.js +6 -9
  104. package/dist/paged-layout/transactionDirtyRange.d.ts +3 -1
  105. package/dist/paged-layout/transactionDirtyRange.js +23 -1
  106. package/dist/prosemirror/attrs/index.d.ts +7 -3
  107. package/dist/prosemirror/attrs/index.js +113 -7
  108. package/dist/prosemirror/bookmarkBoundaryIntegrity.d.ts +9 -0
  109. package/dist/prosemirror/bookmarkBoundaryIntegrity.js +22 -0
  110. package/dist/prosemirror/commands/comments.d.ts +10 -1
  111. package/dist/prosemirror/commands/comments.js +167 -59
  112. package/dist/prosemirror/commands/formatPainter.d.ts +45 -10
  113. package/dist/prosemirror/commands/formatPainter.js +319 -63
  114. package/dist/prosemirror/commands/index.d.ts +2 -2
  115. package/dist/prosemirror/commands/pageBreak.d.ts +5 -2
  116. package/dist/prosemirror/commands/pageBreak.js +18 -36
  117. package/dist/prosemirror/commands/propertyChangeScope.d.ts +7 -5
  118. package/dist/prosemirror/commands/propertyChangeScope.js +27 -18
  119. package/dist/prosemirror/conversion/fromProseDoc.d.ts +7 -2
  120. package/dist/prosemirror/conversion/fromProseDoc.js +809 -209
  121. package/dist/prosemirror/conversion/runShadingMark.js +2 -2
  122. package/dist/prosemirror/conversion/toProseDoc.d.ts +26 -1
  123. package/dist/prosemirror/conversion/toProseDoc.js +416 -283
  124. package/dist/prosemirror/extensions/StarterKit.js +4 -0
  125. package/dist/prosemirror/extensions/core/ParagraphExtension.js +12 -8
  126. package/dist/prosemirror/extensions/features/ListExtension.js +95 -123
  127. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +1 -1
  128. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +27 -1
  129. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +134 -30
  130. package/dist/prosemirror/extensions/features/pasteCleanup.js +9 -15
  131. package/dist/prosemirror/extensions/marks/BoldExtension.js +4 -3
  132. package/dist/prosemirror/extensions/marks/CharacterStyleExtension.d.ts +4 -7
  133. package/dist/prosemirror/extensions/marks/CharacterStyleExtension.js +5 -11
  134. package/dist/prosemirror/extensions/marks/FontSizeExtension.js +3 -3
  135. package/dist/prosemirror/extensions/marks/ItalicExtension.js +4 -3
  136. package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.d.ts +13 -0
  137. package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.js +39 -0
  138. package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.d.ts +7 -1
  139. package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +67 -21
  140. package/dist/prosemirror/extensions/marks/markUtils.d.ts +8 -1
  141. package/dist/prosemirror/extensions/marks/markUtils.js +88 -2
  142. package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +44 -3
  143. package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
  144. package/dist/prosemirror/extensions/nodes/HardBreakExtension.js +15 -4
  145. package/dist/prosemirror/extensions/nodes/PageBreakExtension.d.ts +6 -0
  146. package/dist/prosemirror/extensions/nodes/PageBreakExtension.js +6 -0
  147. package/dist/prosemirror/extensions/nodes/PageBreakRunExtension.d.ts +6 -0
  148. package/dist/prosemirror/extensions/nodes/PageBreakRunExtension.js +36 -0
  149. package/dist/prosemirror/findReplaceSelection.js +8 -3
  150. package/dist/prosemirror/index.d.ts +3 -3
  151. package/dist/prosemirror/listMarker.d.ts +26 -1
  152. package/dist/prosemirror/listMarker.js +108 -14
  153. package/dist/prosemirror/pageBreakRunProjection.d.ts +28 -0
  154. package/dist/prosemirror/pageBreakRunProjection.js +47 -0
  155. package/dist/prosemirror/paraText.js +6 -0
  156. package/dist/prosemirror/paragraphSpacing.d.ts +29 -0
  157. package/dist/prosemirror/paragraphSpacing.js +125 -0
  158. package/dist/prosemirror/plugins/documentNumbering.d.ts +8 -0
  159. package/dist/prosemirror/plugins/documentNumbering.js +18 -0
  160. package/dist/prosemirror/plugins/pmTextScan.d.ts +3 -2
  161. package/dist/prosemirror/plugins/pmTextScan.js +14 -4
  162. package/dist/prosemirror/plugins/suggestionMode.js +8 -10
  163. package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +16 -0
  164. package/dist/prosemirror/rebaseParagraphRunFormatting.js +61 -0
  165. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +64 -0
  166. package/dist/prosemirror/runFormattingInlineCarriers.js +121 -0
  167. package/dist/prosemirror/runFormattingProvenance.d.ts +12 -0
  168. package/dist/prosemirror/runFormattingProvenance.js +48 -0
  169. package/dist/prosemirror/runFormattingReconciliation.d.ts +25 -0
  170. package/dist/prosemirror/runFormattingReconciliation.js +54 -0
  171. package/dist/prosemirror/runPropertyChangeResolution.d.ts +18 -0
  172. package/dist/prosemirror/runPropertyChangeResolution.js +18 -0
  173. package/dist/prosemirror/runStyleFormatting.d.ts +50 -0
  174. package/dist/prosemirror/runStyleFormatting.js +105 -0
  175. package/dist/prosemirror/schema/index.d.ts +3 -3
  176. package/dist/prosemirror/schema/marks.d.ts +82 -9
  177. package/dist/prosemirror/schema/marks.js +73 -1
  178. package/dist/prosemirror/schema/nodes.d.ts +18 -5
  179. package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +14 -2
  180. package/dist/prosemirror/styles/resolvedStyleAttrs.js +44 -23
  181. package/dist/prosemirror/styles/styleResolver.d.ts +10 -13
  182. package/dist/prosemirror/styles/styleResolver.js +3 -3
  183. package/dist/prosemirror/styles/styleToggleCascade.d.ts +8 -1
  184. package/dist/prosemirror/styles/styleToggleCascade.js +24 -1
  185. package/dist/prosemirror/tableGridMutation.d.ts +20 -0
  186. package/dist/prosemirror/tableGridMutation.js +30 -0
  187. package/dist/prosemirror/trackedRunInlineAtoms.d.ts +31 -0
  188. package/dist/prosemirror/trackedRunInlineAtoms.js +39 -0
  189. package/dist/prosemirror/utils/visualLineNavigation.js +27 -31
  190. package/dist/prosemirror/validation.js +23 -4
  191. package/dist/render-dom/HeaderFooterSelectionOverlay.js +20 -20
  192. package/dist/render-dom/RenderedDomContext.js +17 -34
  193. package/dist/server.d.ts +4 -4
  194. package/dist/server.js +2 -2
  195. package/dist/style-engine/styleEngine.d.ts +1 -1
  196. package/dist/utils/clipboard.js +1 -1
  197. package/dist/utils/findReplace.js +38 -21
  198. package/dist/version-comparison.d.ts +38 -44
  199. package/dist/version-comparison.js +270 -401
  200. package/package.json +3 -2
@@ -1,13 +1,19 @@
1
+ import { appendHeadlessInlineResolution } from "../../internal/headlessRevisionResolution.js";
2
+ import { stateAllowsHeadlessRevisionResolution } from "../../internal/headlessRevisionResolutionGuard.js";
1
3
  import { expectParagraphAttrs, expectRunPropertyChangeMarkAttrs } from "../attrs/index.js";
2
4
  import { addedBreakCarrierBefore, finalParagraphsOf, paragraphEndsItsContainer } from "../containerFinalParagraph.js";
3
- import { textFormattingToMarks } from "../conversion/toProseDoc.js";
4
- import { markStructuralChange } from "../extensions/features/ParagraphChangeTrackerExtension.js";
5
+ import { resolveParagraphDefaultTextFormatting } from "../conversion/toProseDoc.js";
6
+ import { markChangedParagraphRanges, markStructuralChange, markTrackedSectionEndpointRemoval } from "../extensions/features/ParagraphChangeTrackerExtension.js";
5
7
  import { getDocumentStyleResolver } from "../plugins/documentStyles.js";
8
+ import { setParagraphAttrsWithRebasedRunFormatting } from "../rebaseParagraphRunFormatting.js";
6
9
  import { getFolioNodeRevisionCarriers } from "../revisionCarriers.js";
7
10
  import { RUN_FORMATTING_MARK_NAMES } from "../runFormattingMarkNames.js";
11
+ import { reconstructRejectedRunFormattingMarks } from "../runPropertyChangeResolution.js";
12
+ import { paragraphRunStyleContextAt } from "../runStyleFormatting.js";
8
13
  import { getTableCellMergeChange } from "../tableCellMergeRevision.js";
14
+ import { reconcileTableGridAfterColumnRemoval } from "../tableGridMutation.js";
9
15
  import { holdsNoContent } from "../zeroWidthAnchors.js";
10
- import { paragraphPropertiesSnapshot, paragraphRejectAttrPatch, paragraphRejectOriginalFormatting, removeParagraphPropertyChanges, sectionRejectProperties, tableCellRejectAttrPatch, tableRejectAttrPatch, tableRowRejectAttrPatch } from "./propertyChangeScope.js";
16
+ import { hasSerializableParagraphPropertyChange, paragraphPropertiesSnapshot, paragraphRejectAttrPatch, paragraphRejectOriginalFormatting, removeParagraphPropertyChanges, sectionRejectProperties, tableCellRejectAttrPatch, tableRejectAttrPatch, tableRowRejectAttrPatch } from "./propertyChangeScope.js";
11
17
  import { hasMatchingCollapsedTableCellMerge, resolveCollapsedTableCellMerge, resolveVisibleTableCellMerge } from "./tableCellMergeResolution.js";
12
18
  import { TableMap, removeRow } from "prosemirror-tables";
13
19
  import { PARAGRAPH_MARK_CHANGE_KINDS } from "@stll/docx-core/model";
@@ -56,7 +62,7 @@ function removeCommentMark(commentId) {
56
62
  * the operation matches every revision mark or property-change entry in the
57
63
  * range (the bulk accept-all/reject-all path).
58
64
  */
59
- function resolveChange(from, to, mode, revisionIds) {
65
+ function resolveChange(from, to, mode, revisionIds, execution = "legacy") {
60
66
  return (state, dispatch) => {
61
67
  const insertionType = state.schema.marks["insertion"];
62
68
  const deletionType = state.schema.marks["deletion"];
@@ -65,6 +71,7 @@ function resolveChange(from, to, mode, revisionIds) {
65
71
  const removeType = mode === "accept" ? deletionType : insertionType;
66
72
  const revisionSet = revisionIds === void 0 ? null : new Set(revisionIds);
67
73
  const removeKeptMarksInBulk = revisionSet === null && keepType !== void 0;
74
+ const canBulkInlineResolution = execution === "headless-bulk-inline" && revisionSet === null && from === 0 && to === state.doc.content.size && stateAllowsHeadlessRevisionResolution(state);
68
75
  const matchesRevision = (mark) => revisionSet === null || typeof mark.attrs["revisionId"] === "number" && revisionSet.has(mark.attrs["revisionId"]);
69
76
  if (dispatch) {
70
77
  const tr = state.tr;
@@ -72,6 +79,8 @@ function resolveChange(from, to, mode, revisionIds) {
72
79
  const pPrMarkOps = [];
73
80
  const tableRowStructuralOps = [];
74
81
  const tableCellStructuralOps = [];
82
+ let removedSectionEndpointCount = 0;
83
+ const removedSectionReferences = [];
75
84
  state.doc.nodesBetween(from, to, (node, pos) => {
76
85
  if (node.type.name === "paragraph") {
77
86
  const op = collectPPrMarkOp(node, pos, from, to, mode, revisionSet);
@@ -92,9 +101,14 @@ function resolveChange(from, to, mode, revisionIds) {
92
101
  _propertyChanges: remaining.length > 0 ? remaining : null
93
102
  };
94
103
  if (rejection?.type === "restore-previous") {
95
- const previousAlignmentFromStyle = styleResolver ? styleResolver.resolveParagraphStyle(rejection.previousFormatting?.styleId).paragraphFormatting?.alignment : expectParagraphAttrs(node).alignmentFromStyle;
96
- Object.assign(nextAttrs, paragraphRejectAttrPatch(rejection.previousFormatting, previousAlignmentFromStyle));
97
- nextAttrs["_originalFormatting"] = paragraphRejectOriginalFormatting(rejection.previousFormatting, node.attrs["_originalFormatting"]);
104
+ const inheritedAlignment = expectParagraphAttrs(node).alignmentFromStyle;
105
+ let previousFormattingFromStyle;
106
+ if (styleResolver) previousFormattingFromStyle = styleResolver.resolveParagraphStyle(rejection.previousFormatting?.styleId).paragraphFormatting;
107
+ else if (inheritedAlignment !== void 0) previousFormattingFromStyle = { alignment: inheritedAlignment };
108
+ Object.assign(nextAttrs, paragraphRejectAttrPatch(rejection.previousFormatting, previousFormattingFromStyle));
109
+ const restoredFormatting = paragraphRejectOriginalFormatting(rejection.previousFormatting, node.attrs["_originalFormatting"]);
110
+ nextAttrs["_originalFormatting"] = restoredFormatting;
111
+ if (styleResolver) nextAttrs["defaultTextFormatting"] = resolveParagraphDefaultTextFormatting(rejection.previousFormatting?.styleId, restoredFormatting ?? void 0, styleResolver) ?? null;
98
112
  }
99
113
  }
100
114
  }
@@ -113,7 +127,13 @@ function resolveChange(from, to, mode, revisionIds) {
113
127
  nextAttrs["sectionBreakType"] = sectionBreakTypeFromSectionStart(restored.sectionStart);
114
128
  }
115
129
  }
116
- if (nextAttrs) tr.setNodeMarkup(pos, void 0, nextAttrs);
130
+ if (nextAttrs) if (nextAttrs["styleId"] !== node.attrs["styleId"] && styleResolver) setParagraphAttrsWithRebasedRunFormatting({
131
+ nextAttrs,
132
+ paragraphPosition: pos,
133
+ styleResolver,
134
+ tr
135
+ });
136
+ else tr.setNodeMarkup(pos, void 0, nextAttrs);
117
137
  return true;
118
138
  }
119
139
  if (node.type.name === "tableRow" && rangeCoversNode(from, to, pos, node)) {
@@ -125,15 +145,20 @@ function resolveChange(from, to, mode, revisionIds) {
125
145
  if (tableChangeAttrName !== void 0) {
126
146
  if (rangeCoversNode(from, to, pos, node)) {
127
147
  const nextAttrs = resolveTablePropertyChangeAttrs(node, tableChangeAttrName, mode, revisionSet);
128
- if (nextAttrs) tr.setNodeMarkup(pos, void 0, nextAttrs);
148
+ if (nextAttrs) {
149
+ tr.setNodeMarkup(pos, void 0, nextAttrs);
150
+ markStructuralChange(tr);
151
+ }
129
152
  }
130
153
  return true;
131
154
  }
132
155
  if (!node.isInline) return true;
156
+ if (canBulkInlineResolution) return true;
133
157
  const nodeEnd = pos + node.nodeSize;
134
158
  const rangeFrom = Math.max(from, pos);
135
159
  const rangeTo = Math.min(to, nodeEnd);
136
160
  const runPropertyChangeMark = node.marks.find((mark) => mark.type.name === "runPropertyChange");
161
+ const removesNode = removeType !== void 0 && node.marks.some((mark) => mark.type === removeType && matchesRevision(mark));
137
162
  if (runPropertyChangeMark) resolveRunPropertyChange({
138
163
  tr,
139
164
  node,
@@ -141,9 +166,10 @@ function resolveChange(from, to, mode, revisionIds) {
141
166
  to: rangeTo,
142
167
  mark: runPropertyChangeMark,
143
168
  mode,
144
- revisionSet
169
+ revisionSet,
170
+ styleResolver
145
171
  });
146
- if (removeType && node.marks.some((m) => m.type === removeType && matchesRevision(m))) deleteRanges.push({
172
+ if (removesNode) deleteRanges.push({
147
173
  from: rangeFrom,
148
174
  to: rangeTo
149
175
  });
@@ -152,24 +178,34 @@ function resolveChange(from, to, mode, revisionIds) {
152
178
  }
153
179
  return true;
154
180
  });
155
- if (removeKeptMarksInBulk) tr.removeMark(from, to, keepType);
156
- let rangesToDelete = deleteRanges;
157
- if (revisionSet === null) {
158
- const coalescedDeleteRanges = [];
159
- for (const range of deleteRanges) {
160
- const previous = coalescedDeleteRanges.at(-1);
161
- if (previous && range.from <= previous.to) {
162
- previous.to = Math.max(previous.to, range.to);
163
- continue;
181
+ let bulkInlineChangeTracking = null;
182
+ if (canBulkInlineResolution) bulkInlineChangeTracking = appendHeadlessInlineResolution({
183
+ tr,
184
+ mode,
185
+ keepType,
186
+ removeType,
187
+ styleResolver
188
+ });
189
+ else {
190
+ if (removeKeptMarksInBulk) tr.removeMark(from, to, keepType);
191
+ let rangesToDelete = deleteRanges;
192
+ if (revisionSet === null) {
193
+ const coalescedDeleteRanges = [];
194
+ for (const range of deleteRanges) {
195
+ const previous = coalescedDeleteRanges.at(-1);
196
+ if (previous && range.from <= previous.to) {
197
+ previous.to = Math.max(previous.to, range.to);
198
+ continue;
199
+ }
200
+ coalescedDeleteRanges.push({
201
+ from: range.from,
202
+ to: range.to
203
+ });
164
204
  }
165
- coalescedDeleteRanges.push({
166
- from: range.from,
167
- to: range.to
168
- });
205
+ rangesToDelete = coalescedDeleteRanges;
169
206
  }
170
- rangesToDelete = coalescedDeleteRanges;
207
+ for (const range of rangesToDelete.toReversed()) tr.delete(range.from, range.to);
171
208
  }
172
- for (const range of rangesToDelete.toReversed()) tr.delete(range.from, range.to);
173
209
  pPrMarkOps.sort((a, b) => b.paragraphPos - a.paragraphPos);
174
210
  for (const op of pPrMarkOps) {
175
211
  const mappedPos = tr.mapping.map(op.paragraphPos);
@@ -181,35 +217,34 @@ function resolveChange(from, to, mode, revisionIds) {
181
217
  }
182
218
  const joinPos = mappedPos + paragraph.nodeSize;
183
219
  const nextNode = joinPos < tr.doc.content.size ? tr.doc.nodeAt(joinPos) : null;
184
- if (!(nextNode?.type.name === paragraph.type.name && !(carriesSection(paragraph) && carriesSection(nextNode)))) {
220
+ if (!(nextNode?.type.name === paragraph.type.name)) {
185
221
  const resolved = tr.doc.resolve(mappedPos);
186
- const previous = resolved.nodeBefore;
187
- const sectionCanMoveBack = !carriesSection(paragraph) || previous?.type.name === paragraph.type.name && !carriesSection(previous);
188
222
  const endsItsContainer = paragraphEndsItsContainer(resolved, paragraph.type.name);
189
223
  const canGo = op.markWasAdded || !endsItsContainer;
190
- if (sectionCanMoveBack && holdsNoContent(paragraph) && canGo && resolved.parent.childCount > 1) {
191
- if (carriesSection(paragraph) && previous) tr.setNodeMarkup(mappedPos - previous.nodeSize, void 0, {
192
- ...previous.attrs,
193
- sectionBreakType: paragraph.attrs["sectionBreakType"],
194
- _sectionProperties: paragraph.attrs["_sectionProperties"]
195
- });
224
+ if (holdsNoContent(paragraph) && canGo && resolved.parent.childCount > 1) {
225
+ if (ownsSectionEndpoint(paragraph)) {
226
+ removedSectionEndpointCount++;
227
+ removedSectionReferences.push(...sectionReferencesOf(paragraph));
228
+ }
196
229
  tr.delete(mappedPos, mappedPos + paragraph.nodeSize);
197
230
  continue;
198
231
  }
199
232
  tr.setNodeAttribute(mappedPos, "pPrMark", null);
200
233
  continue;
201
234
  }
202
- const formattingOwner = holdsNoContent(paragraph) ? nextNode : paragraph;
203
- const sectionOwner = carriesSection(paragraph) ? paragraph : nextNode;
204
235
  const joinedAttrs = {
205
- ...formattingOwner.attrs,
236
+ ...(holdsNoContent(paragraph) ? nextNode : paragraph).attrs,
206
237
  pPrMark: nextNode.attrs["pPrMark"],
207
- sectionBreakType: sectionOwner.attrs["sectionBreakType"],
208
- _sectionProperties: sectionOwner.attrs["_sectionProperties"]
238
+ sectionBreakType: nextNode.attrs["sectionBreakType"],
239
+ _sectionProperties: nextNode.attrs["_sectionProperties"]
209
240
  };
210
241
  try {
211
242
  tr.join(joinPos);
212
243
  tr.setNodeMarkup(mappedPos, void 0, joinedAttrs);
244
+ if (ownsSectionEndpoint(paragraph)) {
245
+ removedSectionEndpointCount++;
246
+ removedSectionReferences.push(...sectionReferencesOf(paragraph));
247
+ }
213
248
  } catch {}
214
249
  }
215
250
  tableRowStructuralOps.sort((left, right) => right.rowPos - left.rowPos);
@@ -259,12 +294,18 @@ function resolveChange(from, to, mode, revisionIds) {
259
294
  }
260
295
  if (failedTableCellMergeResolution) return false;
261
296
  if (resolvedTableCellStructure) markStructuralChange(tr);
297
+ if (bulkInlineChangeTracking) markChangedParagraphRanges(tr, bulkInlineChangeTracking);
298
+ if (removedSectionEndpointCount > 0) markTrackedSectionEndpointRemoval(tr, {
299
+ sourceDoc: state.doc,
300
+ removedEndpointCount: removedSectionEndpointCount,
301
+ removedReferences: removedSectionReferences
302
+ });
262
303
  if (tr.steps.length > 0) dispatch(tr);
263
304
  }
264
305
  return true;
265
306
  };
266
307
  }
267
- const resolveRunPropertyChange = ({ tr, node, from, to, mark, mode, revisionSet }) => {
308
+ const resolveRunPropertyChange = ({ tr, node, from, to, mark, mode, revisionSet, styleResolver }) => {
268
309
  const { changes } = expectRunPropertyChangeMarkAttrs(mark);
269
310
  const matches = changes.filter((change) => revisionSet === null || revisionSet.has(change.info.id));
270
311
  if (matches.length === 0) return;
@@ -273,15 +314,18 @@ const resolveRunPropertyChange = ({ tr, node, from, to, mark, mode, revisionSet
273
314
  if (remaining.length > 0) tr.addMark(from, to, mark.type.create({ changes: remaining }));
274
315
  if (mode === "accept") return;
275
316
  const previousFormatting = matches.at(0)?.previousFormatting;
317
+ const styleContext = paragraphRunStyleContextAt({
318
+ doc: tr.doc,
319
+ pos: from,
320
+ styleResolver
321
+ });
276
322
  for (const currentMark of node.marks) if (RUN_FORMATTING_MARK_NAMES.has(currentMark.type.name)) tr.removeMark(from, to, currentMark.type);
277
- for (const previousMark of textFormattingToMarks(previousFormatting)) tr.addMark(from, to, previousMark);
278
- if (previousFormatting?.styleId) {
279
- const characterStyle = node.type.schema.marks["characterStyle"];
280
- if (characterStyle) tr.addMark(from, to, characterStyle.create({
281
- styleId: previousFormatting.styleId,
282
- _styleRPr: null
283
- }));
284
- }
323
+ for (const previousMark of reconstructRejectedRunFormattingMarks({
324
+ node,
325
+ paragraphContext: styleContext,
326
+ previousFormatting,
327
+ styleResolver
328
+ })) tr.addMark(from, to, previousMark);
285
329
  };
286
330
  function collectTableRowStructuralOp(node, rowPos, mode, revisionSet) {
287
331
  for (const attrName of ["trIns", "trDel"]) {
@@ -376,11 +420,33 @@ function deleteTableCellAt(tr, cellPos) {
376
420
  const resolved = tr.doc.resolve(cellPos);
377
421
  const row = resolved.parent;
378
422
  if (row.type.spec["tableRole"] !== "row") return;
423
+ const tableDepth = resolved.depth - 1;
424
+ const table = resolved.node(tableDepth);
425
+ if (table.type.spec["tableRole"] !== "table") return;
426
+ const tablePosition = resolved.before(tableDepth);
427
+ const cellOffset = cellPos - resolved.start(tableDepth);
428
+ const removedColumn = TableMap.get(table).findCell(cellOffset).left;
379
429
  if (row.childCount > 1) {
380
430
  tr.delete(cellPos, cellPos + cell.nodeSize);
431
+ reconcileTableGridAfterColumnRemoval({
432
+ tr,
433
+ tablePosition,
434
+ previousTable: table,
435
+ removedColumn
436
+ });
437
+ return;
438
+ }
439
+ if (table.childCount === 1) {
440
+ deleteTableRowAt(tr, resolved.start() - 1);
381
441
  return;
382
442
  }
383
443
  deleteTableRowAt(tr, resolved.start() - 1);
444
+ reconcileTableGridAfterColumnRemoval({
445
+ tr,
446
+ tablePosition,
447
+ previousTable: table,
448
+ removedColumn
449
+ });
384
450
  }
385
451
  function deleteTableRowAt(tr, rowPos) {
386
452
  const resolved = tr.doc.resolve(rowPos);
@@ -487,16 +553,24 @@ function isPPrMarkAttr(value) {
487
553
  * the two ends belong together, not because they resolve differently.
488
554
  */
489
555
  const paragraphMarkWasAdded = (kind) => kind === "ins" || kind === "moveTo";
556
+ const ownsSectionEndpoint = (paragraph) => {
557
+ const attrs = expectParagraphAttrs(paragraph);
558
+ return attrs._sectionProperties !== void 0 || attrs.sectionBreakType !== void 0;
559
+ };
560
+ const sectionReferencesOf = (paragraph) => {
561
+ const sectionProperties = expectParagraphAttrs(paragraph)._sectionProperties;
562
+ if (!sectionProperties) return [];
563
+ return [...(sectionProperties.headerReferences ?? []).map(({ type, rId }) => ({
564
+ part: "header",
565
+ type,
566
+ relationshipId: rId
567
+ })), ...(sectionProperties.footerReferences ?? []).map(({ type, rId }) => ({
568
+ part: "footer",
569
+ type,
570
+ relationshipId: rId
571
+ }))];
572
+ };
490
573
  const isAddedPPrMarkAttr = (value) => isPPrMarkAttr(value) && (value.kind === "ins" || value.kind === "moveTo");
491
- /**
492
- * Whether the paragraph's mark carries a section's properties.
493
- *
494
- * A section break lives on a paragraph mark, so the paragraph is where the
495
- * section ends. Removing it removes the section: a document that had two ends
496
- * up with one, and every setting the dropped section carried — page size,
497
- * margins, its header and footer references — goes with it.
498
- */
499
- const carriesSection = (paragraph) => paragraph.attrs["sectionBreakType"] != null || paragraph.attrs["_sectionProperties"] != null;
500
574
  function readRevisionInfo(info) {
501
575
  const revision = {};
502
576
  if (typeof info?.author === "string") revision.author = info.author;
@@ -574,6 +648,20 @@ function rejectAllChanges() {
574
648
  return (state, dispatch) => rejectChange(0, state.doc.content.size)(state, dispatch);
575
649
  }
576
650
  /**
651
+ * Resolve a complete state synchronously for a headless reader or writer.
652
+ *
653
+ * @internal The replacement transaction is consumed here and never exposed:
654
+ * it is deliberately not an editor command and must not be transported or
655
+ * mapped through concurrent edits.
656
+ */
657
+ function resolveAllChangesInHeadlessState(state, mode) {
658
+ let resolvedState = state;
659
+ resolveChange(0, state.doc.content.size, mode, void 0, "headless-bulk-inline")(state, (transaction) => {
660
+ resolvedState = state.apply(transaction);
661
+ });
662
+ return resolvedState;
663
+ }
664
+ /**
577
665
  * Find the document range covered by all revision carriers with any of the
578
666
  * given ids. Returns null when none are present (already accepted/rejected, or
579
667
  * never existed). A replace operation typically passes two ids; standalone
@@ -965,12 +1053,31 @@ const reauthorParagraphPropertySuggestions = ({ node, matchesSuggestion, author,
965
1053
  });
966
1054
  return changed ? next : null;
967
1055
  };
1056
+ const canReauthorParagraphPropertySuggestions = (doc, matchesSuggestion) => {
1057
+ let valid = true;
1058
+ doc.descendants((node) => {
1059
+ if (!valid || node.type.name !== "paragraph") return;
1060
+ const propertyChanges = expectParagraphAttrs(node)._propertyChanges;
1061
+ if (!Array.isArray(propertyChanges)) return;
1062
+ let serializableCount = 0;
1063
+ for (const change of propertyChanges) {
1064
+ const suggested = readSuggestedParagraphPropertyChange(change);
1065
+ if (!suggested || matchesSuggestion(suggested.suggestionId)) serializableCount++;
1066
+ }
1067
+ if (serializableCount > 1) {
1068
+ valid = false;
1069
+ return false;
1070
+ }
1071
+ });
1072
+ return valid;
1073
+ };
968
1074
  const appendRotatedParagraphPropertyChange = ({ tr, currentPosition, previous, mark, fallbackAuthor }) => {
969
1075
  const current = tr.doc.nodeAt(currentPosition);
970
1076
  if (!current || current.type.name !== "paragraph") return false;
971
1077
  const author = typeof mark.info.author === "string" ? mark.info.author : fallbackAuthor;
972
1078
  if (author === void 0) return false;
973
1079
  const existing = expectParagraphAttrs(current)._propertyChanges;
1080
+ if (hasSerializableParagraphPropertyChange(existing)) return false;
974
1081
  tr.setNodeMarkup(currentPosition, void 0, {
975
1082
  ...current.attrs,
976
1083
  _propertyChanges: [...Array.isArray(existing) ? existing : [], {
@@ -1194,6 +1301,7 @@ const removeSuggestedInsertNodes = ({ tr, positions, resolvedRevisionIds }) => {
1194
1301
  */
1195
1302
  const acceptSuggestions = (matchesSuggestion, options) => {
1196
1303
  return (state, dispatch) => {
1304
+ if (!canReauthorParagraphPropertySuggestions(state.doc, matchesSuggestion)) return false;
1197
1305
  const insertionType = state.schema.marks["insertion"];
1198
1306
  const deletionType = state.schema.marks["deletion"];
1199
1307
  const runPropertyChangeType = state.schema.marks["runPropertyChange"];
@@ -1547,4 +1655,4 @@ function findPreviousChange(state, startPos) {
1547
1655
  return result.value;
1548
1656
  }
1549
1657
  //#endregion
1550
- export { acceptAIEditRevision, acceptAllChanges, acceptAllSuggestions, acceptChange, acceptSuggestion, addCommentMark, findAIEditRevisionRange, findChangeAtPosition, findNextChange, findParagraphBoundaryChangeAtPosition, findPreviousChange, findSuggestionRange, getSuggestions, rejectAIEditRevision, rejectAllChanges, rejectAllSuggestions, rejectChange, rejectSuggestion, removeCommentMark };
1658
+ export { acceptAIEditRevision, acceptAllChanges, acceptAllSuggestions, acceptChange, acceptSuggestion, addCommentMark, findAIEditRevisionRange, findChangeAtPosition, findNextChange, findParagraphBoundaryChangeAtPosition, findPreviousChange, findSuggestionRange, getSuggestions, rejectAIEditRevision, rejectAllChanges, rejectAllSuggestions, rejectChange, rejectSuggestion, removeCommentMark, resolveAllChangesInHeadlessState };
@@ -1,3 +1,4 @@
1
+ import { document_d_exports } from "../../types/document.js";
1
2
  import { Command, EditorState } from "prosemirror-state";
2
3
  import { Mark } from "prosemirror-model";
3
4
  //#region src/prosemirror/commands/formatPainter.d.ts
@@ -9,22 +10,56 @@ import { Mark } from "prosemirror-model";
9
10
  * text direction or hide content, which is surprising for a formatting brush.
10
11
  */
11
12
  declare const PAINTABLE_MARK_NAMES: ReadonlySet<string>;
13
+ type PaintableFormatting = {
14
+ allCaps?: document_d_exports.TextFormatting["allCaps"];
15
+ bold?: document_d_exports.TextFormatting["bold"];
16
+ boldCs?: document_d_exports.TextFormatting["boldCs"];
17
+ color?: document_d_exports.TextFormatting["color"];
18
+ cs?: document_d_exports.TextFormatting["cs"];
19
+ doubleStrike?: document_d_exports.TextFormatting["doubleStrike"];
20
+ effect?: document_d_exports.TextFormatting["effect"];
21
+ emboss?: document_d_exports.TextFormatting["emboss"];
22
+ emphasisMark?: document_d_exports.TextFormatting["emphasisMark"];
23
+ fontFamily?: document_d_exports.TextFormatting["fontFamily"];
24
+ fontSize?: document_d_exports.TextFormatting["fontSize"];
25
+ fontSizeCs?: document_d_exports.TextFormatting["fontSizeCs"];
26
+ highlight?: document_d_exports.TextFormatting["highlight"];
27
+ imprint?: document_d_exports.TextFormatting["imprint"];
28
+ italic?: document_d_exports.TextFormatting["italic"];
29
+ italicCs?: document_d_exports.TextFormatting["italicCs"];
30
+ kerning?: document_d_exports.TextFormatting["kerning"];
31
+ outline?: document_d_exports.TextFormatting["outline"];
32
+ position?: document_d_exports.TextFormatting["position"];
33
+ scale?: document_d_exports.TextFormatting["scale"];
34
+ shading?: document_d_exports.TextFormatting["shading"];
35
+ shadow?: document_d_exports.TextFormatting["shadow"];
36
+ smallCaps?: document_d_exports.TextFormatting["smallCaps"];
37
+ spacing?: document_d_exports.TextFormatting["spacing"];
38
+ strike?: document_d_exports.TextFormatting["strike"];
39
+ underline?: document_d_exports.TextFormatting["underline"];
40
+ vertAlign?: document_d_exports.TextFormatting["vertAlign"];
41
+ };
42
+ type CapturedTextFormatting = Readonly<{
43
+ effectiveFormatting: Readonly<PaintableFormatting>;
44
+ marks: readonly Mark[];
45
+ type: "capturedTextFormatting";
46
+ }>;
12
47
  /**
13
- * Capture the paintable character marks active over the current selection.
14
- * Returns the marks (with their attrs) to hand to `applyFormatMarks`. An empty
15
- * selection reads the stored/insertion marks; a range reads its leading run.
16
- * Returns an empty array when the source carries no direct character formatting.
48
+ * Capture the paintable character formatting active over the current selection.
49
+ * An empty selection reads the stored/insertion marks; a range reads its leading
50
+ * run. The discriminated result deliberately represents an effectively plain run:
51
+ * `null` belongs to the host's “nothing captured” state, not this command.
17
52
  */
18
- declare function captureFormatMarks(state: EditorState): Mark[];
53
+ declare function captureFormatMarks(state: EditorState): CapturedTextFormatting;
19
54
  /**
20
55
  * Apply captured marks onto the current selection's range: clear every paintable
21
56
  * mark type first (replace, not merge — so painting Georgia-12-bold onto
22
57
  * Arial-10 leaves only Georgia-12-bold), then lay down the captured marks.
23
58
  *
24
- * Best-effort: a collapsed selection or an empty capture is a no-op (returns
25
- * false so a keymap binding stays unclaimed and the keystroke passes through).
26
- * Never throws.
59
+ * Best-effort: a collapsed selection, no capture, or a target-relative delta
60
+ * that cannot be represented without guessing document defaults is a no-op.
61
+ * Returns false so a keymap binding stays unclaimed; never partially mutates.
27
62
  */
28
- declare function applyFormatMarks(marks: readonly Mark[]): Command;
63
+ declare function applyFormatMarks(captured: CapturedTextFormatting | null): Command;
29
64
  //#endregion
30
- export { PAINTABLE_MARK_NAMES, applyFormatMarks, captureFormatMarks };
65
+ export { CapturedTextFormatting, PAINTABLE_MARK_NAMES, applyFormatMarks, captureFormatMarks };