@stll/folio-core 0.52.0 → 0.53.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 (307) hide show
  1. package/README.md +23 -0
  2. package/dist/ai-edits/apply.d.ts +26 -1
  3. package/dist/ai-edits/apply.js +1519 -105
  4. package/dist/ai-edits/batch-claims.d.ts +130 -0
  5. package/dist/ai-edits/batch-claims.js +244 -0
  6. package/dist/ai-edits/blockRange.js +9 -3
  7. package/dist/ai-edits/character-boundaries.d.ts +43 -0
  8. package/dist/ai-edits/character-boundaries.js +95 -0
  9. package/dist/ai-edits/clean-text.d.ts +33 -3
  10. package/dist/ai-edits/clean-text.js +52 -6
  11. package/dist/ai-edits/comment-lifecycle.d.ts +18 -0
  12. package/dist/ai-edits/comment-lifecycle.js +52 -0
  13. package/dist/ai-edits/headless.d.ts +71 -7
  14. package/dist/ai-edits/headless.js +381 -41
  15. package/dist/ai-edits/index.d.ts +2 -1
  16. package/dist/ai-edits/index.js +2 -1
  17. package/dist/ai-edits/minimal-replacement.d.ts +21 -6
  18. package/dist/ai-edits/minimal-replacement.js +134 -15
  19. package/dist/ai-edits/newListNumbering.d.ts +23 -0
  20. package/dist/ai-edits/newListNumbering.js +94 -0
  21. package/dist/ai-edits/note-references.d.ts +96 -0
  22. package/dist/ai-edits/note-references.js +139 -0
  23. package/dist/ai-edits/pending-suggestions.d.ts +79 -0
  24. package/dist/ai-edits/pending-suggestions.js +306 -0
  25. package/dist/ai-edits/read.d.ts +1 -1
  26. package/dist/ai-edits/read.js +56 -43
  27. package/dist/ai-edits/result-validation.d.ts +29 -0
  28. package/dist/ai-edits/result-validation.js +164 -0
  29. package/dist/ai-edits/snapshot.d.ts +36 -3
  30. package/dist/ai-edits/snapshot.js +177 -23
  31. package/dist/ai-edits/table-cell-mutations.d.ts +1 -1
  32. package/dist/ai-edits/table-cell-mutations.js +4 -1
  33. package/dist/ai-edits/table-geometry.d.ts +1 -1
  34. package/dist/ai-edits/table-row-column-mutations.d.ts +38 -16
  35. package/dist/ai-edits/table-row-column-mutations.js +61 -26
  36. package/dist/ai-edits/types.d.ts +155 -16
  37. package/dist/compare/compare.d.ts +1 -1
  38. package/dist/compare/compare.js +65 -16
  39. package/dist/compare/content-alignment.js +13 -2
  40. package/dist/compare/content-types.d.ts +7 -0
  41. package/dist/compare/content.d.ts +4 -1
  42. package/dist/compare/content.js +6 -1
  43. package/dist/compare/formatting.js +2 -1
  44. package/dist/compare/inline-atoms.d.ts +21 -4
  45. package/dist/compare/inline-atoms.js +138 -16
  46. package/dist/compare/plan.js +10 -5
  47. package/dist/compare/scenario.js +14 -3
  48. package/dist/compare/section-boundary-properties.js +1 -1
  49. package/dist/compare/types.d.ts +4 -2
  50. package/dist/compare/types.js +2 -1
  51. package/dist/compare/verification.d.ts +1 -1
  52. package/dist/compare/verification.js +15 -3
  53. package/dist/controller/committedLayoutDiff.d.ts +25 -0
  54. package/dist/controller/committedLayoutDiff.js +71 -0
  55. package/dist/controller/contentControlWidgetController.d.ts +1 -1
  56. package/dist/controller/folioEditor.d.ts +1 -1
  57. package/dist/controller/fontReadiness.d.ts +70 -3
  58. package/dist/controller/fontReadiness.js +100 -10
  59. package/dist/controller/headerFooterEditorManager.js +6 -1
  60. package/dist/controller/layoutPipeline.d.ts +12 -10
  61. package/dist/controller/layoutPipeline.js +62 -9
  62. package/dist/controller/layoutRunOptions.d.ts +24 -0
  63. package/dist/controller/layoutRunOptions.js +17 -0
  64. package/dist/controller/layoutScheduler.d.ts +19 -14
  65. package/dist/controller/layoutScheduler.js +15 -12
  66. package/dist/controller/layoutSession.d.ts +26 -2
  67. package/dist/controller/layoutSession.js +1 -1
  68. package/dist/controller/noteEditorManager.js +8 -3
  69. package/dist/document-operations.d.ts +11 -2
  70. package/dist/document-operations.js +230 -21
  71. package/dist/docx/altChunk.d.ts +8 -0
  72. package/dist/docx/altChunk.js +17 -0
  73. package/dist/docx/attributeRemainder.d.ts +1 -1
  74. package/dist/docx/blockContentParser.d.ts +64 -1
  75. package/dist/docx/blockContentParser.js +17 -4
  76. package/dist/docx/blockCustomXmlShell.d.ts +7 -0
  77. package/dist/docx/blockCustomXmlShell.js +14 -0
  78. package/dist/docx/blockPlainText.js +7 -0
  79. package/dist/docx/commentAnchorIndex.js +1 -1
  80. package/dist/docx/commentRangeIntegrity.js +8 -3
  81. package/dist/docx/commentReferenceNormalization.js +1 -1
  82. package/dist/docx/commentReplyMarkers.js +20 -1
  83. package/dist/docx/compatibility.d.ts +1 -1
  84. package/dist/docx/compatibility.js +34 -13
  85. package/dist/docx/containerChildren.gen.d.ts +1 -1
  86. package/dist/docx/containerChildren.gen.js +1 -0
  87. package/dist/docx/documentParser.js +12 -12
  88. package/dist/docx/drawingIdNormalization.d.ts +3 -1
  89. package/dist/docx/drawingIdNormalization.js +6 -1
  90. package/dist/docx/ensureParaIds.js +119 -97
  91. package/dist/docx/footnoteParser.js +8 -4
  92. package/dist/docx/headerFooterParser.js +3 -3
  93. package/dist/docx/headerFooterReferenceNormalization.d.ts +20 -1
  94. package/dist/docx/headerFooterReferenceNormalization.js +52 -27
  95. package/dist/docx/hyperlinkParser.d.ts +1 -1
  96. package/dist/docx/index.d.ts +1 -1
  97. package/dist/docx/listNumberingInstances.d.ts +59 -0
  98. package/dist/docx/listNumberingInstances.js +249 -0
  99. package/dist/docx/normalizeBaseDirection.js +2 -1
  100. package/dist/docx/opaqueCarrier.d.ts +7 -0
  101. package/dist/docx/opaqueCarrier.js +38 -0
  102. package/dist/docx/packageParts.js +4 -1
  103. package/dist/docx/paragraphParser.js +91 -24
  104. package/dist/docx/paragraphPropertySource.d.ts +4 -2
  105. package/dist/docx/paragraphPropertySource.js +7 -1
  106. package/dist/docx/paragraphTraversal.js +1 -0
  107. package/dist/docx/parseWarningMessage.js +4 -1
  108. package/dist/docx/parser.js +173 -20
  109. package/dist/docx/rezip.js +27 -5
  110. package/dist/docx/sdtProperties.js +1 -1
  111. package/dist/docx/sdtPropertiesPatch.js +3 -0
  112. package/dist/docx/selectiveSave.js +16 -9
  113. package/dist/docx/selectiveXmlPatch.js +106 -37
  114. package/dist/docx/serializer/blockCustomXmlSerializer.d.ts +5 -0
  115. package/dist/docx/serializer/blockCustomXmlSerializer.js +4 -0
  116. package/dist/docx/serializer/documentSerializer.js +2 -0
  117. package/dist/docx/serializer/headerFooterSerializer.js +2 -0
  118. package/dist/docx/serializer/noteSerializer.js +3 -1
  119. package/dist/docx/serializer/paragraphSerializer.js +33 -9
  120. package/dist/docx/serializer/tableSerializer.js +25 -38
  121. package/dist/docx/server/createBilingualDocument.js +3 -3
  122. package/dist/docx/tableParser.d.ts +157 -1
  123. package/dist/docx/tableParser.js +89 -10
  124. package/dist/docx/textBoxParser.js +1 -1
  125. package/dist/docx/unzip.d.ts +2 -1
  126. package/dist/docx/unzip.js +1 -1
  127. package/dist/docx/wordprocessingPrefixes.d.ts +78 -0
  128. package/dist/docx/wordprocessingPrefixes.js +286 -0
  129. package/dist/i18n/messages/catalogs.gen.d.ts +136 -0
  130. package/dist/i18n/messages/catalogs.gen.js +153 -17
  131. package/dist/i18n/messages/messages.gen.d.ts +8 -0
  132. package/dist/internal/compare/inline-presentation.d.ts +2 -1
  133. package/dist/internal/compare/inline-presentation.js +11 -10
  134. package/dist/internal/headlessRevisionResolutionGuard.d.ts +2 -8
  135. package/dist/internal/headlessRevisionResolutionGuard.js +2 -11
  136. package/dist/internal/indexedPositionMap.d.ts +11 -0
  137. package/dist/internal/indexedPositionMap.js +42 -0
  138. package/dist/internal/pageBreakRunSourceDescendantIndex.js +2 -1
  139. package/dist/internal/revisionResolutionEdits.d.ts +13 -0
  140. package/dist/internal/revisionResolutionEdits.js +19 -0
  141. package/dist/internal/revisionResolutionInline.d.ts +24 -0
  142. package/dist/internal/{headlessRevisionResolution.js → revisionResolutionInline.js} +61 -43
  143. package/dist/internal/revisionResolutionStep.d.ts +34 -0
  144. package/dist/internal/revisionResolutionStep.js +282 -0
  145. package/dist/internal/revisionResolutionTracking.d.ts +11 -0
  146. package/dist/internal/revisionResolutionTracking.js +124 -0
  147. package/dist/internal/wholeStoryRevisionResolution.d.ts +56 -0
  148. package/dist/internal/wholeStoryRevisionResolution.js +530 -0
  149. package/dist/layout-bridge/convert/markupViewFlow.d.ts +20 -0
  150. package/dist/layout-bridge/convert/markupViewFlow.js +123 -0
  151. package/dist/layout-bridge/convert/tableConversion.js +1 -1
  152. package/dist/layout-bridge/convert/toFlowBlocks.js +10 -1
  153. package/dist/layout-engine/layoutInstrumentation.d.ts +9 -1
  154. package/dist/layout-engine/layoutInstrumentation.js +4 -1
  155. package/dist/layout-engine/measure/cache.d.ts +18 -1
  156. package/dist/layout-engine/measure/cache.js +31 -1
  157. package/dist/layout-engine/measure/font-metrics.worker.js +3 -7
  158. package/dist/layout-engine/measure/measureContainer.js +7 -47
  159. package/dist/layout-engine/measure/measureHelpers.d.ts +6 -1
  160. package/dist/layout-engine/measure/measureHelpers.js +22 -2
  161. package/dist/layout-engine/measure/measureWorker.js +2 -3
  162. package/dist/layout-engine/measure/measureWorkerProtocol.d.ts +6 -7
  163. package/dist/layout-engine/measure/measureWorkerProtocol.js +1 -2
  164. package/dist/layout-engine/types.d.ts +6 -0
  165. package/dist/layout-painter/renderPage.js +1 -0
  166. package/dist/layout-painter/renderParagraph.js +1 -1
  167. package/dist/managers/ContextMenuManager.js +5 -2
  168. package/dist/managers/types.d.ts +3 -0
  169. package/dist/markdown/fromMarkdown.js +2 -1
  170. package/dist/markdown/internals.d.ts +11 -1
  171. package/dist/markdown/internals.js +24 -3
  172. package/dist/markdown/renderBlock.js +39 -9
  173. package/dist/markdown/renderParagraph.d.ts +13 -1
  174. package/dist/markdown/renderParagraph.js +85 -38
  175. package/dist/markdown/renderRuns.js +3 -10
  176. package/dist/markdown/renderTable.js +24 -12
  177. package/dist/markdown/trailers.js +2 -2
  178. package/dist/markdown/types.d.ts +29 -7
  179. package/dist/paged-layout/incrementalMeasure.d.ts +1 -2
  180. package/dist/paged-layout/incrementalMeasure.js +1 -9
  181. package/dist/paged-layout/transactionDirtyRange.d.ts +1 -3
  182. package/dist/paged-layout/transactionDirtyRange.js +29 -41
  183. package/dist/panel-layout.d.ts +83 -0
  184. package/dist/panel-layout.js +96 -0
  185. package/dist/prosemirror/anchoredTextBoxes.d.ts +37 -0
  186. package/dist/prosemirror/anchoredTextBoxes.js +156 -0
  187. package/dist/prosemirror/attrs/index.d.ts +6 -2
  188. package/dist/prosemirror/attrs/index.js +172 -1
  189. package/dist/prosemirror/commands/comments.d.ts +7 -8
  190. package/dist/prosemirror/commands/comments.js +241 -207
  191. package/dist/prosemirror/commands/contentControls.d.ts +1 -1
  192. package/dist/prosemirror/commands/formatPainter.d.ts +1 -1
  193. package/dist/prosemirror/commands/formatting.d.ts +1 -1
  194. package/dist/prosemirror/commands/index.d.ts +2 -2
  195. package/dist/prosemirror/commands/index.js +2 -2
  196. package/dist/prosemirror/commands/paragraph.d.ts +7 -1
  197. package/dist/prosemirror/commands/paragraph.js +9 -1
  198. package/dist/prosemirror/commands/paragraphBookmarkJoin.d.ts +13 -0
  199. package/dist/prosemirror/commands/paragraphBookmarkJoin.js +22 -0
  200. package/dist/prosemirror/commands/pastePlainText.d.ts +1 -1
  201. package/dist/prosemirror/commands/resolveAllTableChanges.d.ts +40 -0
  202. package/dist/prosemirror/commands/resolveAllTableChanges.js +615 -0
  203. package/dist/prosemirror/commands/resolveNodePropertyChangeAttrs.d.ts +15 -0
  204. package/dist/prosemirror/commands/resolveNodePropertyChangeAttrs.js +46 -0
  205. package/dist/prosemirror/commands/resolveParagraphProperties.d.ts +16 -0
  206. package/dist/prosemirror/commands/resolveParagraphProperties.js +59 -0
  207. package/dist/prosemirror/commands/sectionBreak.js +2 -1
  208. package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +8 -2
  209. package/dist/prosemirror/commands/tableCellMergeResolution.js +1 -1
  210. package/dist/prosemirror/contentControlRevisions.d.ts +1 -1
  211. package/dist/prosemirror/conversion/fromProseDoc.js +181 -31
  212. package/dist/prosemirror/conversion/toProseDoc.js +39 -4
  213. package/dist/prosemirror/emptyFieldResultRuns.d.ts +18 -0
  214. package/dist/prosemirror/emptyFieldResultRuns.js +33 -0
  215. package/dist/prosemirror/extensions/ExtensionManager.d.ts +1 -1
  216. package/dist/prosemirror/extensions/ExtensionManager.js +3 -1
  217. package/dist/prosemirror/extensions/StarterKit.js +3 -1
  218. package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
  219. package/dist/prosemirror/extensions/core/ParagraphExtension.js +12 -0
  220. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +3 -0
  221. package/dist/prosemirror/extensions/features/ListExtension.js +161 -123
  222. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +19 -2
  223. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +33 -20
  224. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +31 -2
  225. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +270 -99
  226. package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +3 -2
  227. package/dist/prosemirror/extensions/features/pasteCleanup.js +2 -1
  228. package/dist/prosemirror/extensions/features/pastedHtmlLists.d.ts +12 -0
  229. package/dist/prosemirror/extensions/features/pastedHtmlLists.js +126 -0
  230. package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +21 -5
  231. package/dist/prosemirror/extensions/marks/RunIdentityExtension.d.ts +21 -18
  232. package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +37 -17
  233. package/dist/prosemirror/extensions/marks/markUtils.d.ts +7 -2
  234. package/dist/prosemirror/extensions/marks/markUtils.js +8 -2
  235. package/dist/prosemirror/extensions/marks/noteReferenceDeletion.d.ts +10 -0
  236. package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +35 -0
  237. package/dist/prosemirror/extensions/nodes/BlockCustomXmlExtension.d.ts +6 -0
  238. package/dist/prosemirror/extensions/nodes/BlockCustomXmlExtension.js +52 -0
  239. package/dist/prosemirror/extensions/nodes/FieldExtension.d.ts +3 -3
  240. package/dist/prosemirror/extensions/nodes/FieldExtension.js +50 -15
  241. package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.js +4 -1
  242. package/dist/prosemirror/extensions/nodes/TableExtension.d.ts +1 -1
  243. package/dist/prosemirror/extensions/nodes/TableExtension.js +19 -18
  244. package/dist/prosemirror/extensions/types.d.ts +4 -1
  245. package/dist/prosemirror/findReplaceSelection.js +1 -1
  246. package/dist/prosemirror/index.d.ts +3 -2
  247. package/dist/prosemirror/index.js +3 -2
  248. package/dist/prosemirror/indexedNodeLookup.d.ts +17 -0
  249. package/dist/prosemirror/indexedNodeLookup.js +103 -0
  250. package/dist/prosemirror/listAutoformatMarkers.d.ts +19 -0
  251. package/dist/prosemirror/listAutoformatMarkers.js +98 -0
  252. package/dist/prosemirror/listInstanceReferences.d.ts +12 -0
  253. package/dist/prosemirror/listInstanceReferences.js +72 -0
  254. package/dist/prosemirror/listLabels.d.ts +24 -0
  255. package/dist/prosemirror/listLabels.js +111 -0
  256. package/dist/prosemirror/listNumbering.d.ts +110 -0
  257. package/dist/prosemirror/listNumbering.js +345 -0
  258. package/dist/prosemirror/listRenderingAttrs.d.ts +11 -2
  259. package/dist/prosemirror/listRenderingAttrs.js +8 -1
  260. package/dist/prosemirror/markupViewProjection.d.ts +95 -0
  261. package/dist/prosemirror/markupViewProjection.js +83 -0
  262. package/dist/prosemirror/numberingAttr.d.ts +9 -1
  263. package/dist/prosemirror/numberingAttr.js +9 -1
  264. package/dist/prosemirror/outlineLevelAttr.js +1 -1
  265. package/dist/prosemirror/paragraphIndentation.d.ts +10 -1
  266. package/dist/prosemirror/paragraphIndentation.js +29 -7
  267. package/dist/prosemirror/paragraphMarkJoin.d.ts +19 -0
  268. package/dist/prosemirror/paragraphMarkJoin.js +24 -0
  269. package/dist/prosemirror/plugins/createDocScanPlugin.d.ts +1 -1
  270. package/dist/prosemirror/plugins/documentNumbering.d.ts +27 -1
  271. package/dist/prosemirror/plugins/documentNumbering.js +97 -11
  272. package/dist/prosemirror/plugins/documentStyles.d.ts +10 -1
  273. package/dist/prosemirror/plugins/documentStyles.js +14 -1
  274. package/dist/prosemirror/plugins/suggestionMode.d.ts +16 -2
  275. package/dist/prosemirror/plugins/suggestionMode.js +116 -52
  276. package/dist/prosemirror/plugins/templateDirectives.d.ts +1 -1
  277. package/dist/prosemirror/plugins/transactionInvariants.d.ts +32 -0
  278. package/dist/prosemirror/plugins/transactionInvariants.js +86 -0
  279. package/dist/prosemirror/positionSweep.d.ts +24 -0
  280. package/dist/prosemirror/positionSweep.js +222 -0
  281. package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +1 -1
  282. package/dist/prosemirror/rejoinRunCarriers.d.ts +1 -1
  283. package/dist/prosemirror/replacedAnnotations.d.ts +33 -1
  284. package/dist/prosemirror/replacedAnnotations.js +170 -1
  285. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +1 -1
  286. package/dist/prosemirror/schema/index.d.ts +2 -2
  287. package/dist/prosemirror/schema/index.js +3 -0
  288. package/dist/prosemirror/schema/nodes.d.ts +42 -11
  289. package/dist/prosemirror/sectionMarkEdits.d.ts +20 -0
  290. package/dist/prosemirror/sectionMarkEdits.js +59 -0
  291. package/dist/prosemirror/storyListNumbering.d.ts +17 -0
  292. package/dist/prosemirror/storyListNumbering.js +102 -0
  293. package/dist/prosemirror/tableGridMutation.d.ts +48 -2
  294. package/dist/prosemirror/tableGridMutation.js +106 -1
  295. package/dist/prosemirror/validation.js +5 -1
  296. package/dist/redline.js +93 -9
  297. package/dist/render-dom/BodySelectionOverlay.d.ts +4 -1
  298. package/dist/render-dom/BodySelectionOverlay.js +3 -2
  299. package/dist/utils/findReplace.js +2 -2
  300. package/dist/utils/mergeDocumentContent.js +1 -1
  301. package/dist/utils/noteReferenceLabels.d.ts +36 -0
  302. package/dist/utils/noteReferenceLabels.js +32 -0
  303. package/dist/utils/replaceText.js +1 -1
  304. package/dist/version-comparison.d.ts +1 -0
  305. package/dist/version-comparison.js +1 -0
  306. package/package.json +3 -2
  307. package/dist/internal/headlessRevisionResolution.d.ts +0 -23
@@ -0,0 +1,59 @@
1
+ import { sectionPropertiesOf } from "./sectionCarrier.js";
2
+ import { Mapping, ReplaceStep } from "prosemirror-transform";
3
+ //#region src/prosemirror/sectionMarkEdits.ts
4
+ const isParagraph = (node) => node.type.name === "paragraph";
5
+ /** Read `transactions`, applied in order and ending at `finalDoc`. */
6
+ const sectionMarkEditsOf = (transactions, finalDoc) => {
7
+ const deletedMarks = /* @__PURE__ */ new Set();
8
+ const carriers = [];
9
+ const replacements = [];
10
+ const mapping = new Mapping();
11
+ for (const transaction of transactions) for (const [index, step] of transaction.steps.entries()) {
12
+ const doc = transaction.docs[index];
13
+ if (step instanceof ReplaceStep && step.from < step.to && doc) replacements.push({
14
+ step,
15
+ doc,
16
+ mapIndex: mapping.maps.length
17
+ });
18
+ const map = transaction.mapping.maps[index];
19
+ if (map) mapping.appendMap(map);
20
+ }
21
+ for (const { step, doc, mapIndex } of replacements) {
22
+ const { from, to } = step;
23
+ doc.nodesBetween(from, to, (node, position) => {
24
+ if (!isParagraph(node)) return true;
25
+ const record = sectionPropertiesOf(node);
26
+ const markFrom = position + node.nodeSize - 1;
27
+ if (record && markFrom >= from && markFrom + 1 <= to) deletedMarks.add(record);
28
+ return false;
29
+ });
30
+ const $from = doc.resolve(from);
31
+ const $to = doc.resolve(to);
32
+ if (!isParagraph($from.parent) || !isParagraph($to.parent) || $from.start() === $to.start()) continue;
33
+ const leftRecord = sectionPropertiesOf($from.parent);
34
+ const rightRecord = sectionPropertiesOf($to.parent);
35
+ if (leftRecord === null && rightRecord === null) continue;
36
+ const after = mapping.slice(mapIndex);
37
+ const left = after.mapResult(from, -1);
38
+ const right = after.mapResult(to, 1);
39
+ if (right.deleted) continue;
40
+ const $right = finalDoc.resolve(right.pos);
41
+ if (!isParagraph($right.parent)) continue;
42
+ carriers.push({
43
+ position: $right.before(),
44
+ record: rightRecord
45
+ });
46
+ if (left.deleted) continue;
47
+ const $left = finalDoc.resolve(left.pos);
48
+ if (isParagraph($left.parent) && $left.start() !== $right.start()) carriers.push({
49
+ position: $left.before(),
50
+ record: null
51
+ });
52
+ }
53
+ return {
54
+ deletedMarks,
55
+ carriers
56
+ };
57
+ };
58
+ //#endregion
59
+ export { sectionMarkEditsOf };
@@ -0,0 +1,17 @@
1
+ import { document_d_exports } from "../types/document.js";
2
+ import { Node } from "prosemirror-model";
3
+ import { EditorState } from "prosemirror-state";
4
+ //#region src/prosemirror/storyListNumbering.d.ts
5
+ type StoryListNumbering = {
6
+ /** The story with every colliding list moved to its own ids. */
7
+ doc: Node;
8
+ /** `numbering` plus the lists the story defines. */
9
+ numbering: document_d_exports.NumberingDefinitions | undefined;
10
+ };
11
+ /**
12
+ * The story in `state` as it should be written into a package whose numbering
13
+ * is now `numbering`, and that numbering completed with the story's lists.
14
+ */
15
+ declare const storyListNumbering: (state: EditorState, numbering: document_d_exports.NumberingDefinitions | undefined) => StoryListNumbering;
16
+ //#endregion
17
+ export { storyListNumbering };
@@ -0,0 +1,102 @@
1
+ import { getCachedNumberingMap, isBulletLevel } from "../docx/numberingParser.js";
2
+ import { paragraphNumberingLevel, paragraphNumberingReference, paragraphNumberingReferenceId } from "../docx/numberingReference.js";
3
+ import { expectParagraphAttrs } from "./attrs/index.js";
4
+ import { completeNumberingForDoc, paragraphListReferences } from "./listInstanceReferences.js";
5
+ import { paragraphNumberingAttr } from "./numberingAttr.js";
6
+ import { getPackageNumberingDefinitions } from "./plugins/documentNumbering.js";
7
+ import { Transform } from "prosemirror-transform";
8
+ //#region src/prosemirror/storyListNumbering.ts
9
+ const remappedNumPr = (numPr, numIds) => {
10
+ const numId = paragraphNumberingReferenceId(numPr ?? void 0);
11
+ const next = numId === void 0 ? void 0 : numIds.get(numId);
12
+ if (next === void 0) return numPr;
13
+ const ilvl = paragraphNumberingLevel(numPr ?? void 0);
14
+ return paragraphNumberingAttr(paragraphNumberingReference(ilvl === void 0 ? { numId: next } : {
15
+ numId: next,
16
+ ilvl
17
+ }));
18
+ };
19
+ const remappedAbstractNumId = (abstractNumId, remap) => {
20
+ if (abstractNumId === null || abstractNumId === void 0 || remap.baseAbstractNumIds.has(abstractNumId)) return abstractNumId;
21
+ let next = remap.abstractNumIds.get(abstractNumId);
22
+ if (next === void 0) {
23
+ next = remap.nextAbstractNumId++;
24
+ remap.abstractNumIds.set(abstractNumId, next);
25
+ }
26
+ return next;
27
+ };
28
+ const maxOf = (ids, floor) => {
29
+ let max = floor;
30
+ for (const id of ids) max = Math.max(max, id);
31
+ return max;
32
+ };
33
+ /**
34
+ * The story in `state` as it should be written into a package whose numbering
35
+ * is now `numbering`, and that numbering completed with the story's lists.
36
+ */
37
+ const storyListNumbering = (state, numbering) => {
38
+ const packageDefinitions = getPackageNumberingDefinitions(state);
39
+ const storyBase = new Set((packageDefinitions?.nums ?? []).map(({ numId }) => numId));
40
+ const defined = new Set((numbering?.nums ?? []).map(({ numId }) => numId));
41
+ const definedMap = numbering ? getCachedNumberingMap(numbering) : null;
42
+ const referenced = /* @__PURE__ */ new Set();
43
+ const colliding = /* @__PURE__ */ new Set();
44
+ state.doc.descendants((node) => {
45
+ if (node.type.name !== "paragraph") return true;
46
+ for (const numId of paragraphListReferences(node)) referenced.add(numId);
47
+ const attrs = expectParagraphAttrs(node);
48
+ const numId = paragraphNumberingReferenceId(attrs.numPr);
49
+ if (numId !== void 0 && !storyBase.has(numId) && definedMap?.hasNumbering(numId)) {
50
+ const level = definedMap.getLevel(numId, paragraphNumberingLevel(attrs.numPr) ?? 0);
51
+ if (!(level !== null && isBulletLevel(level) === (attrs.listIsBullet === true) && (attrs.listAbstractNumId ?? void 0) === (definedMap.getAbstractNumId(numId) ?? void 0))) colliding.add(numId);
52
+ }
53
+ return false;
54
+ });
55
+ if (colliding.size === 0) return {
56
+ doc: state.doc,
57
+ numbering: completeNumberingForDoc(numbering, state.doc)
58
+ };
59
+ let nextNumId = maxOf([...defined, ...referenced], 0) + 1;
60
+ const remap = {
61
+ numIds: new Map([...colliding].map((numId) => [numId, nextNumId++])),
62
+ baseAbstractNumIds: new Set((packageDefinitions?.abstractNums ?? []).map(({ abstractNumId }) => abstractNumId)),
63
+ abstractNumIds: /* @__PURE__ */ new Map(),
64
+ nextAbstractNumId: maxOf((numbering?.abstractNums ?? []).map(({ abstractNumId }) => abstractNumId), -1) + 1
65
+ };
66
+ const tr = new Transform(state.doc);
67
+ state.doc.descendants((node, pos) => {
68
+ if (node.type.name !== "paragraph") return true;
69
+ const attrs = expectParagraphAttrs(node);
70
+ const numId = paragraphNumberingReferenceId(attrs.numPr);
71
+ const moves = numId !== void 0 && remap.numIds.has(numId);
72
+ const changes = attrs._propertyChanges?.map((change) => {
73
+ const previous = change.previousFormatting;
74
+ const previousNumId = paragraphNumberingReferenceId(previous?.numPr ?? void 0);
75
+ if (!previous || previousNumId === void 0 || !remap.numIds.has(previousNumId)) return change;
76
+ return {
77
+ ...change,
78
+ previousFormatting: {
79
+ ...previous,
80
+ numPr: remappedNumPr(previous.numPr, remap.numIds),
81
+ listAbstractNumId: remappedAbstractNumId(previous.listAbstractNumId, remap) ?? void 0
82
+ }
83
+ };
84
+ });
85
+ const changesMoved = changes?.some((change, index) => change !== attrs._propertyChanges?.[index]);
86
+ if (moves || changesMoved) tr.setNodeMarkup(pos, void 0, {
87
+ ...node.attrs,
88
+ ...moves ? {
89
+ numPr: remappedNumPr(attrs.numPr, remap.numIds),
90
+ listAbstractNumId: remappedAbstractNumId(attrs.listAbstractNumId, remap) ?? null
91
+ } : {},
92
+ ...changesMoved ? { _propertyChanges: changes } : {}
93
+ });
94
+ return false;
95
+ });
96
+ return {
97
+ doc: tr.doc,
98
+ numbering: completeNumberingForDoc(numbering, tr.doc)
99
+ };
100
+ };
101
+ //#endregion
102
+ export { storyListNumbering };
@@ -1,6 +1,38 @@
1
- import { Transaction } from "prosemirror-state";
2
1
  import { Node } from "prosemirror-model";
2
+ import { Transaction } from "prosemirror-state";
3
+ import { TableMap } from "prosemirror-tables";
3
4
  //#region src/prosemirror/tableGridMutation.d.ts
5
+ type RemoveTableRowOptions = {
6
+ map: TableMap;
7
+ table: Node;
8
+ tableStart: number;
9
+ };
10
+ /**
11
+ * Remove one row, keeping every vertical merge that touches it whole: a merge
12
+ * reaching through the row from above closes one row sooner, and a cell that
13
+ * starts in the row and spans down moves into the row below, one row shorter.
14
+ *
15
+ * `prosemirror-tables` exports the same operation as `removeRow`, but its walk
16
+ * across the row skips a cell's extra columns without moving its map index
17
+ * along with them, so after a cell wider than one column it reads the wrong
18
+ * slots: a merge reaching through the row further right is never shortened,
19
+ * and the table is left one row shorter than that merge.
20
+ */
21
+ declare const removeTableRow: (tr: Transaction, { map, table, tableStart }: RemoveTableRowOptions, row: number) => void;
22
+ /**
23
+ * Remove every row a structural edit left without a cell of its own, closing
24
+ * the vertical merges that reached through it over one row fewer.
25
+ *
26
+ * Deleting the only column a row still had a cell in, or merging whole rows
27
+ * together, leaves a row holding nothing but the merges from above. The
28
+ * editable model can carry such a row, but nothing else agrees with it: a
29
+ * package spells it as a row of `w:vMerge` continuations, which the reader
30
+ * gives a cell of its own by splitting the merge apart, so the reopened table
31
+ * differs from the one the operation reported. Accepting the same deletion
32
+ * tracked removes the cells one at a time and the row with its last one,
33
+ * which is this result; the two modes have to leave the same table.
34
+ */
35
+ declare const removeRowsWithoutCells: (tr: Transaction, tablePosition: number) => void;
4
36
  type ReconcileTableGridAfterColumnRemovalOptions = {
5
37
  tr: Transaction;
6
38
  tablePosition: number;
@@ -16,5 +48,19 @@ type ReconcileTableGridAfterColumnRemovalOptions = {
16
48
  * the old grid; reopening then has to interpret surviving cells as spans.
17
49
  */
18
50
  declare const reconcileTableGridAfterColumnRemoval: ({ tr, tablePosition, previousTable, removedColumn }: ReconcileTableGridAfterColumnRemovalOptions) => void;
51
+ type ReconcileTableGridAfterColumnInsertionOptions = {
52
+ tr: Transaction;
53
+ tablePosition: number;
54
+ previousTable: Node;
55
+ insertedColumn: number;
56
+ };
57
+ /**
58
+ * The same for a physical column insertion: the new grid column takes the
59
+ * width of the column beside it, and the table grows by it.
60
+ *
61
+ * Without it the table keeps the grid it had, so every row spans one column
62
+ * more than `w:tblGrid` declares.
63
+ */
64
+ declare const reconcileTableGridAfterColumnInsertion: ({ tr, tablePosition, previousTable, insertedColumn }: ReconcileTableGridAfterColumnInsertionOptions) => void;
19
65
  //#endregion
20
- export { reconcileTableGridAfterColumnRemoval };
66
+ export { reconcileTableGridAfterColumnInsertion, reconcileTableGridAfterColumnRemoval, removeRowsWithoutCells, removeTableRow };
@@ -2,6 +2,77 @@ import { expectTableAttrs, mergeTableAttrs } from "./attrs/index.js";
2
2
  import { TableMap } from "prosemirror-tables";
3
3
  //#region src/prosemirror/tableGridMutation.ts
4
4
  /**
5
+ * Remove one row, keeping every vertical merge that touches it whole: a merge
6
+ * reaching through the row from above closes one row sooner, and a cell that
7
+ * starts in the row and spans down moves into the row below, one row shorter.
8
+ *
9
+ * `prosemirror-tables` exports the same operation as `removeRow`, but its walk
10
+ * across the row skips a cell's extra columns without moving its map index
11
+ * along with them, so after a cell wider than one column it reads the wrong
12
+ * slots: a merge reaching through the row further right is never shortened,
13
+ * and the table is left one row shorter than that merge.
14
+ */
15
+ const removeTableRow = (tr, { map, table, tableStart }, row) => {
16
+ let rowPosition = 0;
17
+ for (let index = 0; index < row; index++) rowPosition += table.child(index).nodeSize;
18
+ const nextRow = rowPosition + table.child(row).nodeSize;
19
+ const mapFrom = tr.mapping.maps.length;
20
+ tr.delete(tableStart + rowPosition, tableStart + nextRow);
21
+ for (let column = 0; column < map.width;) {
22
+ const index = row * map.width + column;
23
+ const position = map.map[index];
24
+ const cell = position === void 0 ? null : table.nodeAt(position);
25
+ if (position === void 0 || !cell) {
26
+ column += 1;
27
+ continue;
28
+ }
29
+ const colspan = Math.max(1, Number(cell.attrs["colspan"]) || 1);
30
+ const rowspan = Math.max(1, Number(cell.attrs["rowspan"]) || 1);
31
+ if (row > 0 && position === map.map[index - map.width]) tr.setNodeMarkup(tr.mapping.slice(mapFrom).map(tableStart + position), null, {
32
+ ...cell.attrs,
33
+ rowspan: rowspan - 1
34
+ });
35
+ else if (row + 1 < map.height && position === map.map[index + map.width]) {
36
+ const moved = cell.type.create({
37
+ ...cell.attrs,
38
+ rowspan: rowspan - 1
39
+ }, cell.content);
40
+ const below = map.positionAt(row + 1, column, table);
41
+ tr.insert(tr.mapping.slice(mapFrom).map(tableStart + below), moved);
42
+ }
43
+ column += colspan;
44
+ }
45
+ };
46
+ /**
47
+ * Remove every row a structural edit left without a cell of its own, closing
48
+ * the vertical merges that reached through it over one row fewer.
49
+ *
50
+ * Deleting the only column a row still had a cell in, or merging whole rows
51
+ * together, leaves a row holding nothing but the merges from above. The
52
+ * editable model can carry such a row, but nothing else agrees with it: a
53
+ * package spells it as a row of `w:vMerge` continuations, which the reader
54
+ * gives a cell of its own by splitting the merge apart, so the reopened table
55
+ * differs from the one the operation reported. Accepting the same deletion
56
+ * tracked removes the cells one at a time and the row with its last one,
57
+ * which is this result; the two modes have to leave the same table.
58
+ */
59
+ const removeRowsWithoutCells = (tr, tablePosition) => {
60
+ for (;;) {
61
+ const table = tr.doc.nodeAt(tablePosition);
62
+ if (!table || table.type.spec["tableRole"] !== "table" || table.childCount < 2) return;
63
+ let emptyRow = -1;
64
+ table.forEach((row, _offset, index) => {
65
+ if (emptyRow === -1 && row.childCount === 0) emptyRow = index;
66
+ });
67
+ if (emptyRow === -1) return;
68
+ removeTableRow(tr, {
69
+ map: TableMap.get(table),
70
+ table,
71
+ tableStart: tablePosition + 1
72
+ }, emptyRow);
73
+ }
74
+ };
75
+ /**
5
76
  * Keep the editable table grid aligned with a physical column removal.
6
77
  *
7
78
  * `prosemirror-tables` owns cell topology, but Folio separately retains the
@@ -18,6 +89,40 @@ const reconcileTableGridAfterColumnRemoval = ({ tr, tablePosition, previousTable
18
89
  const removedColumnCount = previousColumnCount - columnCount;
19
90
  const previousWidths = expectTableAttrs(previousTable).columnWidths;
20
91
  const columnWidths = previousWidths?.length === previousColumnCount ? previousWidths.toSpliced(removedColumn, removedColumnCount) : void 0;
92
+ setTableGrid({
93
+ tr,
94
+ tablePosition,
95
+ table,
96
+ columnWidths,
97
+ columnCount
98
+ });
99
+ };
100
+ /**
101
+ * The same for a physical column insertion: the new grid column takes the
102
+ * width of the column beside it, and the table grows by it.
103
+ *
104
+ * Without it the table keeps the grid it had, so every row spans one column
105
+ * more than `w:tblGrid` declares.
106
+ */
107
+ const reconcileTableGridAfterColumnInsertion = ({ tr, tablePosition, previousTable, insertedColumn }) => {
108
+ const previousColumnCount = TableMap.get(previousTable).width;
109
+ const table = tr.doc.nodeAt(tablePosition);
110
+ if (!table || table.type.spec["tableRole"] !== "table") return;
111
+ const columnCount = TableMap.get(table).width;
112
+ if (columnCount <= previousColumnCount) return;
113
+ const insertedColumnCount = columnCount - previousColumnCount;
114
+ const previousWidths = expectTableAttrs(previousTable).columnWidths;
115
+ const neighbourWidth = previousWidths?.[Math.max(0, Math.min(insertedColumn, previousColumnCount) - 1)] ?? previousWidths?.[0];
116
+ const columnWidths = previousWidths?.length === previousColumnCount && neighbourWidth !== void 0 ? previousWidths.toSpliced(insertedColumn, 0, ...Array.from({ length: insertedColumnCount }, () => neighbourWidth)) : void 0;
117
+ setTableGrid({
118
+ tr,
119
+ tablePosition,
120
+ table,
121
+ columnWidths,
122
+ columnCount
123
+ });
124
+ };
125
+ const setTableGrid = ({ tr, tablePosition, table, columnWidths, columnCount }) => {
21
126
  const formatting = expectTableAttrs(table)._originalFormatting;
22
127
  const originalFormatting = formatting ? { ...formatting } : void 0;
23
128
  if (originalFormatting) delete originalFormatting.gridSourceXml;
@@ -27,4 +132,4 @@ const reconcileTableGridAfterColumnRemoval = ({ tr, tablePosition, previousTable
27
132
  }));
28
133
  };
29
134
  //#endregion
30
- export { reconcileTableGridAfterColumnRemoval };
135
+ export { reconcileTableGridAfterColumnInsertion, reconcileTableGridAfterColumnRemoval, removeRowsWithoutCells, removeTableRow };
@@ -1,4 +1,4 @@
1
- import { readBlockSdtAttrs, readCharacterSpacingMarkAttrs, readCharacterStyleMarkAttrs, readCommentMarkAttrs, readEmphasisMarkAttrs, readFieldAttrs, readFontFamilyMarkAttrs, readFontSizeMarkAttrs, readFootnoteRefMarkAttrs, readHardBreakAttrs, readHighlightMarkAttrs, readHyperlinkMarkAttrs, readImageAttrs, readInlineWrapperMarkAttrs, readLanguageMarkAttrs, readMathAttrs, readPageBreakRunAttrs, readParagraphAttrs, readPreservedBlockAttrs, readPreservedXmlAttrs, readRunFormattingOverrideMarkAttrs, readRunIdentityMarkAttrs, readRunPropertyChangeMarkAttrs, readRunShadingMarkAttrs, readSdtAttrs, readShapeAttrs, readStrikeMarkAttrs, readSymbolAttrs, readTabAttrs, readTableAttrs, readTableCellAttrs, readTableRowAttrs, readTextBoxAttrs, readTextColorMarkAttrs, readTextEffectMarkAttrs, readTrackedChangeMarkAttrs, readUnderlineMarkAttrs } from "./attrs/index.js";
1
+ import { readBlockCustomXmlAttrs, readBlockSdtAttrs, readCharacterSpacingMarkAttrs, readCharacterStyleMarkAttrs, readCommentMarkAttrs, readEmphasisMarkAttrs, readFieldAttrs, readFontFamilyMarkAttrs, readFontSizeMarkAttrs, readFootnoteRefMarkAttrs, readHardBreakAttrs, readHighlightMarkAttrs, readHyperlinkMarkAttrs, readImageAttrs, readInlineWrapperMarkAttrs, readLanguageMarkAttrs, readMathAttrs, readPageBreakRunAttrs, readParagraphAttrs, readPreservedBlockAttrs, readPreservedXmlAttrs, readRunFormattingOverrideMarkAttrs, readRunIdentityMarkAttrs, readRunPropertyChangeMarkAttrs, readRunShadingMarkAttrs, readSdtAttrs, readShapeAttrs, readStrikeMarkAttrs, readSymbolAttrs, readTabAttrs, readTableAttrs, readTableCellAttrs, readTableRowAttrs, readTextBoxAttrs, readTextColorMarkAttrs, readTextEffectMarkAttrs, readTrackedChangeMarkAttrs, readUnderlineMarkAttrs } from "./attrs/index.js";
2
2
  import { readBookmarkBoundaryAttrs } from "./bookmarkBoundaryAttrs.js";
3
3
  import { readCommentReferenceAttrs } from "./commentReferenceAttrs.js";
4
4
  import { INLINE_WRAPPER_MARK_NAME } from "./extensions/marks/InlineWrapperExtension.js";
@@ -288,6 +288,10 @@ const validateNodeAttrs = (node, path, issues) => {
288
288
  appendAttrIssues(path, readBlockSdtAttrs(node), issues);
289
289
  for (let i = 0; i < node.childCount; i += 1) validateNode(node.child(i), `${path}.content[${i}]`, issues);
290
290
  return;
291
+ case "blockCustomXml":
292
+ appendAttrIssues(path, readBlockCustomXmlAttrs(node), issues);
293
+ for (let i = 0; i < node.childCount; i += 1) validateNode(node.child(i), `${path}.content[${i}]`, issues);
294
+ return;
291
295
  case "shape":
292
296
  appendAttrIssues(path, readShapeAttrs(node), issues);
293
297
  return;
package/dist/redline.js CHANGED
@@ -1,4 +1,4 @@
1
- import { FolioDocxReviewer, isFolioResolvedReviewedView } from "./ai-edits/headless.js";
1
+ import { FolioDocxReviewer, getFolioDocxComparisonAccess, isFolioResolvedReviewedView } from "./ai-edits/headless.js";
2
2
  import { createFolioAITextRangeHandle, trailingBodyBlockId } from "./ai-edits/snapshot.js";
3
3
  import { createScopedWordDiffOptions } from "./ai-edits/word-diff.js";
4
4
  import { FolioContentInlinePresentationProjectionError } from "./compare/content.js";
@@ -77,6 +77,7 @@ const buildRedlineOperations = ({ baseSnapshot, revisedBlocks, nextOperationId }
77
77
  const operations = [];
78
78
  const trailingAdditions = [];
79
79
  const lastBaseBlockId = trailingBodyBlockId(baseSnapshot);
80
+ const baseBlocksById = new Map(baseSnapshot.blocks.map((block) => [block.id, block]));
80
81
  events.forEach((event, eventIndex) => {
81
82
  if (event.type === "pair") {
82
83
  if (event.baseBlock.text !== event.revisedBlock.text) operations.push({
@@ -102,10 +103,7 @@ const buildRedlineOperations = ({ baseSnapshot, revisedBlocks, nextOperationId }
102
103
  }
103
104
  const anchorId = anchorIds[eventIndex] ?? null;
104
105
  if (anchorId === null) {
105
- trailingAdditions.push({
106
- text: event.block.text,
107
- ...event.block.styleId !== void 0 && { styleId: event.block.styleId }
108
- });
106
+ trailingAdditions.push(event.block);
109
107
  return;
110
108
  }
111
109
  operations.push({
@@ -113,7 +111,7 @@ const buildRedlineOperations = ({ baseSnapshot, revisedBlocks, nextOperationId }
113
111
  type: "insertBeforeBlock",
114
112
  blockId: anchorId,
115
113
  text: event.block.text,
116
- ...event.block.styleId !== void 0 && { styleId: event.block.styleId }
114
+ ...insertedParagraphProperties(event.block, baseBlocksById.get(anchorId))
117
115
  });
118
116
  });
119
117
  for (const addition of trailingAdditions) operations.push({
@@ -121,10 +119,85 @@ const buildRedlineOperations = ({ baseSnapshot, revisedBlocks, nextOperationId }
121
119
  type: "insertAfterBlock",
122
120
  blockId: lastBaseBlockId ?? "redline-unanchored",
123
121
  text: addition.text,
124
- ...addition.styleId !== void 0 && { styleId: addition.styleId }
122
+ ...insertedParagraphProperties(addition, lastBaseBlockId === null ? void 0 : baseBlocksById.get(lastBaseBlockId))
125
123
  });
126
124
  return operations;
127
125
  };
126
+ /**
127
+ * The revised value, or `null` to clear one the anchor would pass on, or
128
+ * `undefined` when neither has one: an explicit `null` costs a restyle pass.
129
+ */
130
+ const statedOrCleared = (revised, anchor) => revised ?? (anchor === void 0 ? void 0 : null);
131
+ /**
132
+ * The paragraph properties an inserted block states. An insertion that says
133
+ * nothing takes the properties of its anchor, which is whichever base block
134
+ * happens to follow it, so whatever the anchor states and the revised block
135
+ * does not is cleared: a list item keeps its numbering, and a plain paragraph
136
+ * beside a list item stays plain.
137
+ */
138
+ const insertedParagraphProperties = (block, anchor) => {
139
+ const properties = {};
140
+ const styleId = statedOrCleared(block.styleId, anchor?.styleId);
141
+ if (styleId !== void 0) properties.styleId = styleId;
142
+ const alignment = statedOrCleared(block.directAlignment, anchor?.directAlignment);
143
+ if (alignment !== void 0) properties.alignment = alignment;
144
+ const spacing = statedOrCleared(block.directSpacing, anchor?.directSpacing);
145
+ if (spacing !== void 0) properties.spacing = spacing;
146
+ const indentation = statedOrCleared(block.directIndentation, anchor?.directIndentation);
147
+ if (indentation !== void 0) properties.indentation = indentation;
148
+ if (block.listReference !== void 0 || anchor?.listReference !== void 0 || anchor?.listLevel !== void 0) {
149
+ properties.numbering = block.listReference ?? null;
150
+ properties.listLevel = block.listLevel ?? null;
151
+ } else if (block.listLevel !== void 0) properties.listLevel = block.listLevel;
152
+ return properties;
153
+ };
154
+ const insertedNumbering = (operation) => {
155
+ if (operation.type !== "insertBeforeBlock" && operation.type !== "insertAfterBlock") return null;
156
+ const numbering = operation.numbering;
157
+ return numbering && !("start" in numbering) ? numbering : null;
158
+ };
159
+ /** The `w:numId`s whose `w:num` and abstract definition both exist. */
160
+ const definedNumIds = (numbering) => {
161
+ const abstractIds = new Set(numbering?.abstractNums.map((entry) => entry.abstractNumId));
162
+ return new Set((numbering?.nums ?? []).filter((entry) => abstractIds.has(entry.abstractNumId)).map((entry) => entry.numId));
163
+ };
164
+ /**
165
+ * Rebind every inserted list item to numbering the redline package defines.
166
+ * The redline is the base package, where the revised version's `w:numId` may
167
+ * name nothing, or another list: the referenced definitions are copied in,
168
+ * under a fresh id wherever the base uses that one for different numbering.
169
+ * A reference the revised package cannot resolve shows no number there
170
+ * either, and is inserted without one.
171
+ */
172
+ const bindInsertedNumbering = (baseReviewer, revisedReviewer, operationsByStory) => {
173
+ const baseAccess = getFolioDocxComparisonAccess(baseReviewer);
174
+ const revisedNumbering = getFolioDocxComparisonAccess(revisedReviewer).numberingDefinitions();
175
+ const resolvable = definedNumIds(revisedNumbering);
176
+ const references = operationsByStory.flatMap((operations) => operations.flatMap((operation) => {
177
+ const numbering = insertedNumbering(operation);
178
+ return numbering && resolvable.has(numbering.numId) ? [numbering] : [];
179
+ }));
180
+ const remapped = baseAccess.planTargetNumberingReferences(revisedNumbering, references) ?? panic("Resolvable revised numbering references could not be planned");
181
+ baseAccess.stageTargetNumbering(revisedNumbering, references, remapped);
182
+ const defined = definedNumIds(baseAccess.numberingDefinitions());
183
+ return operationsByStory.map((operations) => operations.map((operation) => {
184
+ const numbering = insertedNumbering(operation);
185
+ if (numbering === null) return operation;
186
+ const numId = remapped.get(numbering.numId) ?? numbering.numId;
187
+ if (!resolvable.has(numbering.numId) || !defined.has(numId)) return {
188
+ ...operation,
189
+ numbering: null,
190
+ listLevel: null
191
+ };
192
+ return {
193
+ ...operation,
194
+ numbering: {
195
+ numId,
196
+ level: numbering.level
197
+ }
198
+ };
199
+ }));
200
+ };
128
201
  const resolveInputView = (value, option) => {
129
202
  if (value === void 0) return "final";
130
203
  if (!isFolioResolvedReviewedView(value)) throw new InvalidGenerateRedlineDocxOptionsError({
@@ -155,6 +228,7 @@ const generateRedlineDocx = async (base, revised, options = {}) => {
155
228
  if (operationSequence >= 1e4) throw new GenerateRedlineDocxOperationLimitError({ message: "The document comparison exceeds the generated operation limit." });
156
229
  return `redline-${++operationSequence}`;
157
230
  };
231
+ const plannedStories = [];
158
232
  for (const pair of pairFolioDocumentStories(baseStories, revisedStories)) {
159
233
  if (!pair.baseStory) {
160
234
  unprocessedStories.push({
@@ -182,15 +256,25 @@ const generateRedlineDocx = async (base, revised, options = {}) => {
182
256
  nextOperationId
183
257
  });
184
258
  if (operations.length === 0) continue;
185
- const result = baseReviewer.applyDocumentOperationsToStory({
259
+ plannedStories.push({
186
260
  story: pair.baseStory,
187
261
  snapshot: baseSnapshot,
262
+ operations
263
+ });
264
+ }
265
+ const boundOperations = bindInsertedNumbering(baseReviewer, revisedReviewer, plannedStories.map(({ operations }) => operations));
266
+ for (const [index, { story, snapshot }] of plannedStories.entries()) {
267
+ const operations = boundOperations[index] ?? panic("A planned story lost its operations");
268
+ const result = baseReviewer.applyDocumentOperationsToStory({
269
+ story,
270
+ snapshot,
188
271
  batch: {
189
272
  version: 1,
190
273
  mode: "tracked-changes",
191
274
  operations
192
275
  },
193
- wordDiff
276
+ wordDiff,
277
+ undefinedStyles: "keep"
194
278
  });
195
279
  applied.push(...result.applied);
196
280
  skipped.push(...result.skipped);
@@ -1,3 +1,4 @@
1
+ import { DisplayMode } from "../managers/EditorModeManager.js";
1
2
  import { EditorState } from "prosemirror-state";
2
3
  //#region src/render-dom/BodySelectionOverlay.d.ts
3
4
  type BodySelectionOverlayResult = {
@@ -10,6 +11,8 @@ type BodySelectionOverlayResult = {
10
11
  type SyncBodySelectionOverlayOptions = {
11
12
  pagesContainer: HTMLElement;
12
13
  state: EditorState;
14
+ /** The review view the pages were laid out for; a caret in text it hides paints at its edge. */
15
+ markupView: DisplayMode;
13
16
  zoom: number;
14
17
  zIndex?: number;
15
18
  caretColor?: string;
@@ -17,7 +20,7 @@ type SyncBodySelectionOverlayOptions = {
17
20
  };
18
21
  declare class BodySelectionOverlay {
19
22
  clear(pagesContainer: HTMLElement): void;
20
- sync({ pagesContainer, state, zoom, zIndex, caretColor, selectionColor }: SyncBodySelectionOverlayOptions): BodySelectionOverlayResult;
23
+ sync({ pagesContainer, state, markupView, zoom, zIndex, caretColor, selectionColor }: SyncBodySelectionOverlayOptions): BodySelectionOverlayResult;
21
24
  }
22
25
  //#endregion
23
26
  export { BodySelectionOverlay, BodySelectionOverlayResult, SyncBodySelectionOverlayOptions };
@@ -2,6 +2,7 @@ import { applyCellSelectionHighlight } from "../layout-bridge/cellSelectionHighl
2
2
  import { getCaretPositionFromDom, getSelectionRectsFromDom } from "../layout-bridge/dom/clickToPositionDom.js";
3
3
  import { findBodyPmAnchor } from "../layout-bridge/dom/findBodyPmSpans.js";
4
4
  import { findImageElement } from "../layout-painter/imageLayout.js";
5
+ import { projectMarkupView, visibleCaretPosition } from "../prosemirror/markupViewProjection.js";
5
6
  import { NodeSelection } from "prosemirror-state";
6
7
  //#region src/render-dom/BodySelectionOverlay.ts
7
8
  /**
@@ -23,7 +24,7 @@ var BodySelectionOverlay = class {
23
24
  clear(pagesContainer) {
24
25
  for (const element of pagesContainer.querySelectorAll(OWNED_OVERLAY_SELECTOR)) element.remove();
25
26
  }
26
- sync({ pagesContainer, state, zoom, zIndex = 10, caretColor = "var(--doc-caret, #000)", selectionColor = "var(--doc-selection, rgba(66, 133, 244, 0.3))" }) {
27
+ sync({ pagesContainer, state, markupView, zoom, zIndex = 10, caretColor = "var(--doc-caret, #000)", selectionColor = "var(--doc-selection, rgba(66, 133, 244, 0.3))" }) {
27
28
  this.clear(pagesContainer);
28
29
  applyCellSelectionHighlight(pagesContainer, state);
29
30
  const { selection } = state;
@@ -37,7 +38,7 @@ var BodySelectionOverlay = class {
37
38
  };
38
39
  }
39
40
  if (selection.empty) {
40
- const caret = getCaretPositionFromDom(pagesContainer, selection.from, pagesContainer.getBoundingClientRect());
41
+ const caret = getCaretPositionFromDom(pagesContainer, visibleCaretPosition(projectMarkupView(state, markupView), selection.from), pagesContainer.getBoundingClientRect());
41
42
  if (!caret) return { type: "text" };
42
43
  const element = pagesContainer.ownerDocument.createElement("div");
43
44
  element.className = CARET_CLASS;
@@ -66,7 +66,7 @@ const forEachParagraph = (blocks, visit) => {
66
66
  walkTable(block);
67
67
  continue;
68
68
  }
69
- if (isBlockSdt(block)) walkBlocks(block.content);
69
+ if (isBlockContainer(block)) walkBlocks(block.content);
70
70
  }
71
71
  };
72
72
  const walkTable = (table) => {
@@ -172,6 +172,6 @@ const isParagraph = (value) => isRecord(value) && value["type"] === "paragraph"
172
172
  const isTable = (value) => isRecord(value) && value["type"] === "table" && Array.isArray(value["rows"]);
173
173
  const isTableRow = (value) => isRecord(value) && Array.isArray(value["cells"]);
174
174
  const isTableCell = (value) => isRecord(value) && Array.isArray(value["content"]);
175
- const isBlockSdt = (value) => isRecord(value) && value["type"] === "blockSdt" && Array.isArray(value["content"]);
175
+ const isBlockContainer = (value) => isRecord(value) && (value["type"] === "blockSdt" || value["type"] === "blockCustomXml") && Array.isArray(value["content"]);
176
176
  //#endregion
177
177
  export { createDefaultFindOptions, createSearchPattern, escapeRegexString, findAllMatches, findInDocument, findInParagraph };
@@ -86,7 +86,7 @@ function mergeDocumentContent(target, source) {
86
86
  function remapBlock(block, numIdRemap, abstractNumIdRemap) {
87
87
  if (block.type === "paragraph") return remapParagraph(block, numIdRemap, abstractNumIdRemap);
88
88
  if (block.type === "table") return remapTable(block, numIdRemap, abstractNumIdRemap);
89
- if (block.type === "blockSdt" && Array.isArray(block.content)) return {
89
+ if ((block.type === "blockSdt" || block.type === "blockCustomXml") && Array.isArray(block.content)) return {
90
90
  ...block,
91
91
  content: block.content.map((child) => remapBlock(child, numIdRemap, abstractNumIdRemap))
92
92
  };
@@ -0,0 +1,36 @@
1
+ //#region src/utils/noteReferenceLabels.d.ts
2
+ /**
3
+ * How a reader shows a footnote or endnote reference.
4
+ *
5
+ * A reference's `w:id` is a package key, not something a reader sees: the
6
+ * rendered document numbers notes by the order they are first referenced
7
+ * (1, 2, 3 …), whatever ids the package gave them. Every reader that puts a reference in a line of
8
+ * text — the Markdown export, `getContent()`, the AI snapshot and the agent
9
+ * tools built on it — numbers through {@link createNoteReferenceNumbering}, so
10
+ * the same reference reads as the same marker everywhere.
11
+ *
12
+ * Footnotes and endnotes are numbered in separate sequences; an
13
+ * endnote's token carries an `e` so the two sequences never collide
14
+ * (`[^1]` is footnote 1, `[^e1]` is endnote 1).
15
+ */
16
+ type NoteReferenceKind = "footnote" | "endnote";
17
+ /** The bare token: `1` for footnote 1, `e1` for endnote 1. */
18
+ declare const noteReferenceToken: (kind: NoteReferenceKind, displayNumber: number) => string;
19
+ /** The marker a text reader shows in the line: `[^1]`, `[^e1]`. */
20
+ declare const noteReferenceMarker: (kind: NoteReferenceKind, displayNumber: number) => string;
21
+ type NoteReferenceNumber = {
22
+ displayNumber: number;
23
+ /** Whether this is the note's first reference in reading order. */
24
+ first: boolean;
25
+ };
26
+ type NoteReferenceNumbering = {
27
+ /** Number one reference, in reading order. */
28
+ next: (kind: NoteReferenceKind, noteId: string | number) => NoteReferenceNumber;
29
+ };
30
+ /**
31
+ * A reading-order numbering: each note takes the next number of its kind the
32
+ * first time it is referenced, and a repeated reference reuses it.
33
+ */
34
+ declare const createNoteReferenceNumbering: () => NoteReferenceNumbering;
35
+ //#endregion
36
+ export { NoteReferenceKind, NoteReferenceNumber, NoteReferenceNumbering, createNoteReferenceNumbering, noteReferenceMarker, noteReferenceToken };