@stll/folio-core 0.36.0 → 0.37.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 (200) hide show
  1. package/README.md +59 -1
  2. package/dist/ai-edits/apply.js +545 -296
  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 +45 -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 +169 -567
  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 +6 -4
  55. package/dist/document-operations.js +77 -12
  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 +155 -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 +190 -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";
@@ -44,6 +50,7 @@ function removeCommentMark(commentId) {
44
50
  return true;
45
51
  };
46
52
  }
53
+ const BULK_INLINE_RESOLUTION_THRESHOLD = 256;
47
54
  /**
48
55
  * Resolve a tracked change: accept or reject.
49
56
  * - Accept: keep insertions (remove mark), delete deletions (remove text)
@@ -56,7 +63,7 @@ function removeCommentMark(commentId) {
56
63
  * the operation matches every revision mark or property-change entry in the
57
64
  * range (the bulk accept-all/reject-all path).
58
65
  */
59
- function resolveChange(from, to, mode, revisionIds) {
66
+ function resolveChange(from, to, mode, revisionIds, execution = "legacy") {
60
67
  return (state, dispatch) => {
61
68
  const insertionType = state.schema.marks["insertion"];
62
69
  const deletionType = state.schema.marks["deletion"];
@@ -65,6 +72,7 @@ function resolveChange(from, to, mode, revisionIds) {
65
72
  const removeType = mode === "accept" ? deletionType : insertionType;
66
73
  const revisionSet = revisionIds === void 0 ? null : new Set(revisionIds);
67
74
  const removeKeptMarksInBulk = revisionSet === null && keepType !== void 0;
75
+ const canBulkInlineResolution = execution === "headless-bulk-inline" && revisionSet === null && from === 0 && to === state.doc.content.size && stateAllowsHeadlessRevisionResolution(state);
68
76
  const matchesRevision = (mark) => revisionSet === null || typeof mark.attrs["revisionId"] === "number" && revisionSet.has(mark.attrs["revisionId"]);
69
77
  if (dispatch) {
70
78
  const tr = state.tr;
@@ -72,6 +80,10 @@ function resolveChange(from, to, mode, revisionIds) {
72
80
  const pPrMarkOps = [];
73
81
  const tableRowStructuralOps = [];
74
82
  const tableCellStructuralOps = [];
83
+ const deferredRunPropertyChanges = [];
84
+ let bulkInlineCarrierCount = 0;
85
+ let removedSectionEndpointCount = 0;
86
+ const removedSectionReferences = [];
75
87
  state.doc.nodesBetween(from, to, (node, pos) => {
76
88
  if (node.type.name === "paragraph") {
77
89
  const op = collectPPrMarkOp(node, pos, from, to, mode, revisionSet);
@@ -92,9 +104,14 @@ function resolveChange(from, to, mode, revisionIds) {
92
104
  _propertyChanges: remaining.length > 0 ? remaining : null
93
105
  };
94
106
  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"]);
107
+ const inheritedAlignment = expectParagraphAttrs(node).alignmentFromStyle;
108
+ let previousFormattingFromStyle;
109
+ if (styleResolver) previousFormattingFromStyle = styleResolver.resolveParagraphStyle(rejection.previousFormatting?.styleId).paragraphFormatting;
110
+ else if (inheritedAlignment !== void 0) previousFormattingFromStyle = { alignment: inheritedAlignment };
111
+ Object.assign(nextAttrs, paragraphRejectAttrPatch(rejection.previousFormatting, previousFormattingFromStyle));
112
+ const restoredFormatting = paragraphRejectOriginalFormatting(rejection.previousFormatting, node.attrs["_originalFormatting"]);
113
+ nextAttrs["_originalFormatting"] = restoredFormatting;
114
+ if (styleResolver) nextAttrs["defaultTextFormatting"] = resolveParagraphDefaultTextFormatting(rejection.previousFormatting?.styleId, restoredFormatting ?? void 0, styleResolver) ?? null;
98
115
  }
99
116
  }
100
117
  }
@@ -113,7 +130,13 @@ function resolveChange(from, to, mode, revisionIds) {
113
130
  nextAttrs["sectionBreakType"] = sectionBreakTypeFromSectionStart(restored.sectionStart);
114
131
  }
115
132
  }
116
- if (nextAttrs) tr.setNodeMarkup(pos, void 0, nextAttrs);
133
+ if (nextAttrs) if (nextAttrs["styleId"] !== node.attrs["styleId"] && styleResolver) setParagraphAttrsWithRebasedRunFormatting({
134
+ nextAttrs,
135
+ paragraphPosition: pos,
136
+ styleResolver,
137
+ tr
138
+ });
139
+ else tr.setNodeMarkup(pos, void 0, nextAttrs);
117
140
  return true;
118
141
  }
119
142
  if (node.type.name === "tableRow" && rangeCoversNode(from, to, pos, node)) {
@@ -125,7 +148,10 @@ function resolveChange(from, to, mode, revisionIds) {
125
148
  if (tableChangeAttrName !== void 0) {
126
149
  if (rangeCoversNode(from, to, pos, node)) {
127
150
  const nextAttrs = resolveTablePropertyChangeAttrs(node, tableChangeAttrName, mode, revisionSet);
128
- if (nextAttrs) tr.setNodeMarkup(pos, void 0, nextAttrs);
151
+ if (nextAttrs) {
152
+ tr.setNodeMarkup(pos, void 0, nextAttrs);
153
+ markStructuralChange(tr);
154
+ }
129
155
  }
130
156
  return true;
131
157
  }
@@ -134,6 +160,27 @@ function resolveChange(from, to, mode, revisionIds) {
134
160
  const rangeFrom = Math.max(from, pos);
135
161
  const rangeTo = Math.min(to, nodeEnd);
136
162
  const runPropertyChangeMark = node.marks.find((mark) => mark.type.name === "runPropertyChange");
163
+ const resolvesRunPropertyChange = runPropertyChangeMark !== void 0 && expectRunPropertyChangeMarkAttrs(runPropertyChangeMark).changes.length > 0;
164
+ const removesNode = removeType !== void 0 && node.marks.some((mark) => mark.type === removeType && matchesRevision(mark));
165
+ const removesKeptMark = keepType !== void 0 && node.marks.some((mark) => mark.type === keepType && matchesRevision(mark));
166
+ if (canBulkInlineResolution) {
167
+ if (resolvesRunPropertyChange) deferredRunPropertyChanges.push({
168
+ tr,
169
+ node,
170
+ from: rangeFrom,
171
+ to: rangeTo,
172
+ mark: runPropertyChangeMark,
173
+ mode,
174
+ revisionSet,
175
+ styleResolver
176
+ });
177
+ if (removesNode) deleteRanges.push({
178
+ from: rangeFrom,
179
+ to: rangeTo
180
+ });
181
+ if (resolvesRunPropertyChange || removesNode || removesKeptMark) bulkInlineCarrierCount++;
182
+ return true;
183
+ }
137
184
  if (runPropertyChangeMark) resolveRunPropertyChange({
138
185
  tr,
139
186
  node,
@@ -141,9 +188,10 @@ function resolveChange(from, to, mode, revisionIds) {
141
188
  to: rangeTo,
142
189
  mark: runPropertyChangeMark,
143
190
  mode,
144
- revisionSet
191
+ revisionSet,
192
+ styleResolver
145
193
  });
146
- if (removeType && node.marks.some((m) => m.type === removeType && matchesRevision(m))) deleteRanges.push({
194
+ if (removesNode) deleteRanges.push({
147
195
  from: rangeFrom,
148
196
  to: rangeTo
149
197
  });
@@ -152,24 +200,35 @@ function resolveChange(from, to, mode, revisionIds) {
152
200
  }
153
201
  return true;
154
202
  });
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;
203
+ let bulkInlineChangeTracking = null;
204
+ if (canBulkInlineResolution && bulkInlineCarrierCount >= BULK_INLINE_RESOLUTION_THRESHOLD) bulkInlineChangeTracking = appendHeadlessInlineResolution({
205
+ tr,
206
+ mode,
207
+ keepType,
208
+ removeType,
209
+ styleResolver
210
+ });
211
+ else {
212
+ for (const deferred of deferredRunPropertyChanges) resolveRunPropertyChange(deferred);
213
+ if (removeKeptMarksInBulk) tr.removeMark(from, to, keepType);
214
+ let rangesToDelete = deleteRanges;
215
+ if (revisionSet === null) {
216
+ const coalescedDeleteRanges = [];
217
+ for (const range of deleteRanges) {
218
+ const previous = coalescedDeleteRanges.at(-1);
219
+ if (previous && range.from <= previous.to) {
220
+ previous.to = Math.max(previous.to, range.to);
221
+ continue;
222
+ }
223
+ coalescedDeleteRanges.push({
224
+ from: range.from,
225
+ to: range.to
226
+ });
164
227
  }
165
- coalescedDeleteRanges.push({
166
- from: range.from,
167
- to: range.to
168
- });
228
+ rangesToDelete = coalescedDeleteRanges;
169
229
  }
170
- rangesToDelete = coalescedDeleteRanges;
230
+ for (const range of rangesToDelete.toReversed()) tr.delete(range.from, range.to);
171
231
  }
172
- for (const range of rangesToDelete.toReversed()) tr.delete(range.from, range.to);
173
232
  pPrMarkOps.sort((a, b) => b.paragraphPos - a.paragraphPos);
174
233
  for (const op of pPrMarkOps) {
175
234
  const mappedPos = tr.mapping.map(op.paragraphPos);
@@ -181,35 +240,34 @@ function resolveChange(from, to, mode, revisionIds) {
181
240
  }
182
241
  const joinPos = mappedPos + paragraph.nodeSize;
183
242
  const nextNode = joinPos < tr.doc.content.size ? tr.doc.nodeAt(joinPos) : null;
184
- if (!(nextNode?.type.name === paragraph.type.name && !(carriesSection(paragraph) && carriesSection(nextNode)))) {
243
+ if (!(nextNode?.type.name === paragraph.type.name)) {
185
244
  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
245
  const endsItsContainer = paragraphEndsItsContainer(resolved, paragraph.type.name);
189
246
  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
- });
247
+ if (holdsNoContent(paragraph) && canGo && resolved.parent.childCount > 1) {
248
+ if (ownsSectionEndpoint(paragraph)) {
249
+ removedSectionEndpointCount++;
250
+ removedSectionReferences.push(...sectionReferencesOf(paragraph));
251
+ }
196
252
  tr.delete(mappedPos, mappedPos + paragraph.nodeSize);
197
253
  continue;
198
254
  }
199
255
  tr.setNodeAttribute(mappedPos, "pPrMark", null);
200
256
  continue;
201
257
  }
202
- const formattingOwner = holdsNoContent(paragraph) ? nextNode : paragraph;
203
- const sectionOwner = carriesSection(paragraph) ? paragraph : nextNode;
204
258
  const joinedAttrs = {
205
- ...formattingOwner.attrs,
259
+ ...(holdsNoContent(paragraph) ? nextNode : paragraph).attrs,
206
260
  pPrMark: nextNode.attrs["pPrMark"],
207
- sectionBreakType: sectionOwner.attrs["sectionBreakType"],
208
- _sectionProperties: sectionOwner.attrs["_sectionProperties"]
261
+ sectionBreakType: nextNode.attrs["sectionBreakType"],
262
+ _sectionProperties: nextNode.attrs["_sectionProperties"]
209
263
  };
210
264
  try {
211
265
  tr.join(joinPos);
212
266
  tr.setNodeMarkup(mappedPos, void 0, joinedAttrs);
267
+ if (ownsSectionEndpoint(paragraph)) {
268
+ removedSectionEndpointCount++;
269
+ removedSectionReferences.push(...sectionReferencesOf(paragraph));
270
+ }
213
271
  } catch {}
214
272
  }
215
273
  tableRowStructuralOps.sort((left, right) => right.rowPos - left.rowPos);
@@ -259,12 +317,18 @@ function resolveChange(from, to, mode, revisionIds) {
259
317
  }
260
318
  if (failedTableCellMergeResolution) return false;
261
319
  if (resolvedTableCellStructure) markStructuralChange(tr);
320
+ if (bulkInlineChangeTracking) markChangedParagraphRanges(tr, bulkInlineChangeTracking);
321
+ if (removedSectionEndpointCount > 0) markTrackedSectionEndpointRemoval(tr, {
322
+ sourceDoc: state.doc,
323
+ removedEndpointCount: removedSectionEndpointCount,
324
+ removedReferences: removedSectionReferences
325
+ });
262
326
  if (tr.steps.length > 0) dispatch(tr);
263
327
  }
264
328
  return true;
265
329
  };
266
330
  }
267
- const resolveRunPropertyChange = ({ tr, node, from, to, mark, mode, revisionSet }) => {
331
+ const resolveRunPropertyChange = ({ tr, node, from, to, mark, mode, revisionSet, styleResolver }) => {
268
332
  const { changes } = expectRunPropertyChangeMarkAttrs(mark);
269
333
  const matches = changes.filter((change) => revisionSet === null || revisionSet.has(change.info.id));
270
334
  if (matches.length === 0) return;
@@ -273,15 +337,18 @@ const resolveRunPropertyChange = ({ tr, node, from, to, mark, mode, revisionSet
273
337
  if (remaining.length > 0) tr.addMark(from, to, mark.type.create({ changes: remaining }));
274
338
  if (mode === "accept") return;
275
339
  const previousFormatting = matches.at(0)?.previousFormatting;
340
+ const styleContext = paragraphRunStyleContextAt({
341
+ doc: tr.doc,
342
+ pos: from,
343
+ styleResolver
344
+ });
276
345
  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
- }
346
+ for (const previousMark of reconstructRejectedRunFormattingMarks({
347
+ node,
348
+ paragraphContext: styleContext,
349
+ previousFormatting,
350
+ styleResolver
351
+ })) tr.addMark(from, to, previousMark);
285
352
  };
286
353
  function collectTableRowStructuralOp(node, rowPos, mode, revisionSet) {
287
354
  for (const attrName of ["trIns", "trDel"]) {
@@ -376,11 +443,33 @@ function deleteTableCellAt(tr, cellPos) {
376
443
  const resolved = tr.doc.resolve(cellPos);
377
444
  const row = resolved.parent;
378
445
  if (row.type.spec["tableRole"] !== "row") return;
446
+ const tableDepth = resolved.depth - 1;
447
+ const table = resolved.node(tableDepth);
448
+ if (table.type.spec["tableRole"] !== "table") return;
449
+ const tablePosition = resolved.before(tableDepth);
450
+ const cellOffset = cellPos - resolved.start(tableDepth);
451
+ const removedColumn = TableMap.get(table).findCell(cellOffset).left;
379
452
  if (row.childCount > 1) {
380
453
  tr.delete(cellPos, cellPos + cell.nodeSize);
454
+ reconcileTableGridAfterColumnRemoval({
455
+ tr,
456
+ tablePosition,
457
+ previousTable: table,
458
+ removedColumn
459
+ });
460
+ return;
461
+ }
462
+ if (table.childCount === 1) {
463
+ deleteTableRowAt(tr, resolved.start() - 1);
381
464
  return;
382
465
  }
383
466
  deleteTableRowAt(tr, resolved.start() - 1);
467
+ reconcileTableGridAfterColumnRemoval({
468
+ tr,
469
+ tablePosition,
470
+ previousTable: table,
471
+ removedColumn
472
+ });
384
473
  }
385
474
  function deleteTableRowAt(tr, rowPos) {
386
475
  const resolved = tr.doc.resolve(rowPos);
@@ -487,16 +576,24 @@ function isPPrMarkAttr(value) {
487
576
  * the two ends belong together, not because they resolve differently.
488
577
  */
489
578
  const paragraphMarkWasAdded = (kind) => kind === "ins" || kind === "moveTo";
579
+ const ownsSectionEndpoint = (paragraph) => {
580
+ const attrs = expectParagraphAttrs(paragraph);
581
+ return attrs._sectionProperties !== void 0 || attrs.sectionBreakType !== void 0;
582
+ };
583
+ const sectionReferencesOf = (paragraph) => {
584
+ const sectionProperties = expectParagraphAttrs(paragraph)._sectionProperties;
585
+ if (!sectionProperties) return [];
586
+ return [...(sectionProperties.headerReferences ?? []).map(({ type, rId }) => ({
587
+ part: "header",
588
+ type,
589
+ relationshipId: rId
590
+ })), ...(sectionProperties.footerReferences ?? []).map(({ type, rId }) => ({
591
+ part: "footer",
592
+ type,
593
+ relationshipId: rId
594
+ }))];
595
+ };
490
596
  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
597
  function readRevisionInfo(info) {
501
598
  const revision = {};
502
599
  if (typeof info?.author === "string") revision.author = info.author;
@@ -574,6 +671,20 @@ function rejectAllChanges() {
574
671
  return (state, dispatch) => rejectChange(0, state.doc.content.size)(state, dispatch);
575
672
  }
576
673
  /**
674
+ * Resolve a complete state synchronously for a headless reader or writer.
675
+ *
676
+ * @internal The replacement transaction is consumed here and never exposed:
677
+ * it is deliberately not an editor command and must not be transported or
678
+ * mapped through concurrent edits.
679
+ */
680
+ function resolveAllChangesInHeadlessState(state, mode) {
681
+ let resolvedState = state;
682
+ resolveChange(0, state.doc.content.size, mode, void 0, "headless-bulk-inline")(state, (transaction) => {
683
+ resolvedState = state.apply(transaction);
684
+ });
685
+ return resolvedState;
686
+ }
687
+ /**
577
688
  * Find the document range covered by all revision carriers with any of the
578
689
  * given ids. Returns null when none are present (already accepted/rejected, or
579
690
  * never existed). A replace operation typically passes two ids; standalone
@@ -965,12 +1076,31 @@ const reauthorParagraphPropertySuggestions = ({ node, matchesSuggestion, author,
965
1076
  });
966
1077
  return changed ? next : null;
967
1078
  };
1079
+ const canReauthorParagraphPropertySuggestions = (doc, matchesSuggestion) => {
1080
+ let valid = true;
1081
+ doc.descendants((node) => {
1082
+ if (!valid || node.type.name !== "paragraph") return;
1083
+ const propertyChanges = expectParagraphAttrs(node)._propertyChanges;
1084
+ if (!Array.isArray(propertyChanges)) return;
1085
+ let serializableCount = 0;
1086
+ for (const change of propertyChanges) {
1087
+ const suggested = readSuggestedParagraphPropertyChange(change);
1088
+ if (!suggested || matchesSuggestion(suggested.suggestionId)) serializableCount++;
1089
+ }
1090
+ if (serializableCount > 1) {
1091
+ valid = false;
1092
+ return false;
1093
+ }
1094
+ });
1095
+ return valid;
1096
+ };
968
1097
  const appendRotatedParagraphPropertyChange = ({ tr, currentPosition, previous, mark, fallbackAuthor }) => {
969
1098
  const current = tr.doc.nodeAt(currentPosition);
970
1099
  if (!current || current.type.name !== "paragraph") return false;
971
1100
  const author = typeof mark.info.author === "string" ? mark.info.author : fallbackAuthor;
972
1101
  if (author === void 0) return false;
973
1102
  const existing = expectParagraphAttrs(current)._propertyChanges;
1103
+ if (hasSerializableParagraphPropertyChange(existing)) return false;
974
1104
  tr.setNodeMarkup(currentPosition, void 0, {
975
1105
  ...current.attrs,
976
1106
  _propertyChanges: [...Array.isArray(existing) ? existing : [], {
@@ -1194,6 +1324,7 @@ const removeSuggestedInsertNodes = ({ tr, positions, resolvedRevisionIds }) => {
1194
1324
  */
1195
1325
  const acceptSuggestions = (matchesSuggestion, options) => {
1196
1326
  return (state, dispatch) => {
1327
+ if (!canReauthorParagraphPropertySuggestions(state.doc, matchesSuggestion)) return false;
1197
1328
  const insertionType = state.schema.marks["insertion"];
1198
1329
  const deletionType = state.schema.marks["deletion"];
1199
1330
  const runPropertyChangeType = state.schema.marks["runPropertyChange"];
@@ -1547,4 +1678,4 @@ function findPreviousChange(state, startPos) {
1547
1678
  return result.value;
1548
1679
  }
1549
1680
  //#endregion
1550
- export { acceptAIEditRevision, acceptAllChanges, acceptAllSuggestions, acceptChange, acceptSuggestion, addCommentMark, findAIEditRevisionRange, findChangeAtPosition, findNextChange, findParagraphBoundaryChangeAtPosition, findPreviousChange, findSuggestionRange, getSuggestions, rejectAIEditRevision, rejectAllChanges, rejectAllSuggestions, rejectChange, rejectSuggestion, removeCommentMark };
1681
+ 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 };