@stll/folio-core 0.54.1 → 0.55.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 (251) hide show
  1. package/dist/ai-edits/apply.d.ts +1 -1
  2. package/dist/ai-edits/apply.js +40 -32
  3. package/dist/ai-edits/headless.d.ts +1 -2
  4. package/dist/ai-edits/headless.js +13 -27
  5. package/dist/ai-edits/read.d.ts +1 -0
  6. package/dist/ai-edits/read.js +7 -2
  7. package/dist/ai-edits/table-mutation-plan.d.ts +2 -1
  8. package/dist/ai-edits/table-mutation-plan.js +39 -1
  9. package/dist/ai-suggestions/apply.d.ts +1 -1
  10. package/dist/ai-suggestions/apply.js +3 -2
  11. package/dist/compare/compare.js +2 -1
  12. package/dist/compare/content-types.d.ts +3 -15
  13. package/dist/controller/canonicalComposition.d.ts +36 -0
  14. package/dist/controller/canonicalComposition.js +168 -0
  15. package/dist/controller/canonicalInput.d.ts +45 -0
  16. package/dist/controller/canonicalInput.js +338 -0
  17. package/dist/controller/canonicalOperations.d.ts +22 -0
  18. package/dist/controller/canonicalOperations.js +85 -0
  19. package/dist/controller/canonicalReview.d.ts +12 -0
  20. package/dist/controller/canonicalReview.js +19 -0
  21. package/dist/controller/canonicalSession.d.ts +149 -0
  22. package/dist/controller/canonicalSession.js +1038 -0
  23. package/dist/controller/canonicalStoryEditor.d.ts +34 -0
  24. package/dist/controller/canonicalStoryEditor.js +82 -0
  25. package/dist/controller/canonicalStructure.d.ts +16 -0
  26. package/dist/controller/canonicalStructure.js +269 -0
  27. package/dist/controller/folioEditor.d.ts +1 -1
  28. package/dist/controller/folioEditor.js +9 -0
  29. package/dist/controller/headerFooterEditorManager.d.ts +4 -0
  30. package/dist/controller/headerFooterEditorManager.js +71 -3
  31. package/dist/controller/hiddenEditorApi.d.ts +35 -0
  32. package/dist/controller/hiddenEditorApi.js +25 -8
  33. package/dist/controller/hiddenEditorManager.d.ts +11 -2
  34. package/dist/controller/hiddenEditorManager.js +456 -30
  35. package/dist/controller/layoutPipeline.d.ts +1 -1
  36. package/dist/controller/layoutPipeline.js +2 -0
  37. package/dist/controller/noteEditorManager.d.ts +4 -0
  38. package/dist/controller/noteEditorManager.js +113 -15
  39. package/dist/docx/attributeRemainder.js +1 -0
  40. package/dist/docx/bookmarkIds.d.ts +11 -0
  41. package/dist/docx/bookmarkIds.js +33 -0
  42. package/dist/docx/canonicalSessionInput.d.ts +11 -0
  43. package/dist/docx/canonicalSessionInput.js +27 -0
  44. package/dist/docx/canonicalStoryRepack.d.ts +10 -0
  45. package/dist/docx/canonicalStoryRepack.js +41 -0
  46. package/dist/docx/contentTypeRegistry.d.ts +8 -0
  47. package/dist/docx/contentTypeRegistry.js +64 -0
  48. package/dist/docx/documentParser.d.ts +14 -1
  49. package/dist/docx/documentParser.js +17 -4
  50. package/dist/docx/drawingIdNormalization.js +23 -8
  51. package/dist/docx/ensureParaIds.d.ts +12 -1
  52. package/dist/docx/ensureParaIds.js +173 -213
  53. package/dist/docx/foldedListNumberFields.d.ts +85 -0
  54. package/dist/docx/foldedListNumberFields.js +267 -0
  55. package/dist/docx/headerFooterVerbatim.d.ts +14 -1
  56. package/dist/docx/headerFooterVerbatim.js +95 -2
  57. package/dist/docx/listNumberingInstances.js +11 -9
  58. package/dist/docx/noteIds.d.ts +9 -0
  59. package/dist/docx/noteIds.js +17 -0
  60. package/dist/docx/noteReferenceMark.d.ts +3 -1
  61. package/dist/docx/noteReferenceMark.js +15 -14
  62. package/dist/docx/numberingIds.d.ts +14 -0
  63. package/dist/docx/numberingIds.js +16 -0
  64. package/dist/docx/numberingParser.d.ts +3 -1
  65. package/dist/docx/numberingParser.js +17 -3
  66. package/dist/docx/numericIdAllocator.d.ts +12 -0
  67. package/dist/docx/numericIdAllocator.js +33 -0
  68. package/dist/docx/numericIdNormalization.d.ts +16 -0
  69. package/dist/docx/numericIdNormalization.js +174 -0
  70. package/dist/docx/packageParts.d.ts +3 -1
  71. package/dist/docx/packageParts.js +65 -16
  72. package/dist/docx/paragraphMarkPropertyPresence.d.ts +9 -0
  73. package/dist/docx/paragraphMarkPropertyPresence.js +21 -0
  74. package/dist/docx/paragraphParser.js +101 -53
  75. package/dist/docx/paragraphPropertySource.d.ts +15 -1
  76. package/dist/docx/paragraphPropertySource.js +76 -22
  77. package/dist/docx/paragraphTextBoxEnrichment.js +2 -1
  78. package/dist/docx/parser.js +19 -6
  79. package/dist/docx/rasterMime.d.ts +64 -0
  80. package/dist/docx/rasterMime.js +116 -0
  81. package/dist/docx/replyToComment.js +13 -6
  82. package/dist/docx/reviewHistoryNamespace.d.ts +4 -0
  83. package/dist/docx/reviewHistoryNamespace.js +4 -0
  84. package/dist/docx/reviewResolutionProvenance.d.ts +25 -0
  85. package/dist/docx/reviewResolutionProvenance.js +153 -0
  86. package/dist/docx/rezip.d.ts +7 -3
  87. package/dist/docx/rezip.js +121 -52
  88. package/dist/docx/runConsolidator.d.ts +2 -58
  89. package/dist/docx/runConsolidator.js +3 -175
  90. package/dist/docx/runParser.d.ts +2 -1
  91. package/dist/docx/runParser.js +156 -116
  92. package/dist/docx/saveDiagnostics.d.ts +11 -0
  93. package/dist/docx/saveDiagnostics.js +0 -0
  94. package/dist/docx/selectiveSave.d.ts +2 -1
  95. package/dist/docx/selectiveSave.js +14 -1
  96. package/dist/docx/selectiveXmlPatch.d.ts +16 -8
  97. package/dist/docx/selectiveXmlPatch.js +74 -2
  98. package/dist/docx/serializer/headerFooterSerializer.d.ts +5 -1
  99. package/dist/docx/serializer/headerFooterSerializer.js +19 -11
  100. package/dist/docx/serializer/noteSerializer.d.ts +2 -2
  101. package/dist/docx/serializer/noteSerializer.js +24 -8
  102. package/dist/docx/serializer/paragraphSerializer.js +41 -4
  103. package/dist/docx/serializer/partNamespaces.js +6 -3
  104. package/dist/docx/serializer/runSerializer.js +8 -5
  105. package/dist/docx/serializer/trackedChangeAttributes.js +7 -1
  106. package/dist/docx/server/build.js +14 -3
  107. package/dist/docx/server/createBilingualDocument.js +10 -9
  108. package/dist/docx/settingsHeaderFooterUpdate.d.ts +5 -0
  109. package/dist/docx/settingsHeaderFooterUpdate.js +90 -0
  110. package/dist/docx/settingsParser.d.ts +1 -2
  111. package/dist/docx/settingsParser.js +5 -6
  112. package/dist/docx/storyBlockReplay.d.ts +11 -0
  113. package/dist/docx/storyBlockReplay.js +367 -0
  114. package/dist/docx/streamingXmlParser.d.ts +31 -1
  115. package/dist/docx/streamingXmlParser.js +136 -21
  116. package/dist/docx/structuralXmlPatch.js +8 -1
  117. package/dist/docx/unzip.d.ts +3 -1
  118. package/dist/docx/unzip.js +36 -16
  119. package/dist/docx/verbatimCapture.d.ts +3 -1
  120. package/dist/docx/verbatimCapture.js +49 -6
  121. package/dist/i18n/messages/ar.gen.d.ts +5 -0
  122. package/dist/i18n/messages/ar.gen.js +656 -0
  123. package/dist/i18n/messages/cs.gen.d.ts +5 -0
  124. package/dist/i18n/messages/cs.gen.js +656 -0
  125. package/dist/i18n/messages/de.gen.d.ts +5 -0
  126. package/dist/i18n/messages/de.gen.js +656 -0
  127. package/dist/i18n/messages/en.gen.d.ts +5 -0
  128. package/dist/i18n/messages/en.gen.js +656 -0
  129. package/dist/i18n/messages/es.gen.d.ts +5 -0
  130. package/dist/i18n/messages/es.gen.js +656 -0
  131. package/dist/i18n/messages/et.gen.d.ts +5 -0
  132. package/dist/i18n/messages/et.gen.js +656 -0
  133. package/dist/i18n/messages/fr.gen.d.ts +5 -0
  134. package/dist/i18n/messages/fr.gen.js +656 -0
  135. package/dist/i18n/messages/he.gen.d.ts +5 -0
  136. package/dist/i18n/messages/he.gen.js +656 -0
  137. package/dist/i18n/messages/hi.gen.d.ts +5 -0
  138. package/dist/i18n/messages/hi.gen.js +656 -0
  139. package/dist/i18n/messages/hu.gen.d.ts +5 -0
  140. package/dist/i18n/messages/hu.gen.js +656 -0
  141. package/dist/i18n/messages/locales.d.ts +5 -0
  142. package/dist/i18n/messages/locales.js +22 -0
  143. package/dist/i18n/messages/lt.gen.d.ts +5 -0
  144. package/dist/i18n/messages/lt.gen.js +656 -0
  145. package/dist/i18n/messages/lv.gen.d.ts +5 -0
  146. package/dist/i18n/messages/lv.gen.js +656 -0
  147. package/dist/i18n/messages/pl.gen.d.ts +5 -0
  148. package/dist/i18n/messages/pl.gen.js +656 -0
  149. package/dist/i18n/messages/pt-BR.gen.d.ts +5 -0
  150. package/dist/i18n/messages/pt-BR.gen.js +656 -0
  151. package/dist/i18n/messages/sk.gen.d.ts +5 -0
  152. package/dist/i18n/messages/sk.gen.js +656 -0
  153. package/dist/i18n/messages/tr.gen.d.ts +5 -0
  154. package/dist/i18n/messages/tr.gen.js +656 -0
  155. package/dist/i18n/messages/zh-CN.gen.d.ts +5 -0
  156. package/dist/i18n/messages/zh-CN.gen.js +656 -0
  157. package/dist/i18n/messages.d.ts +2 -3
  158. package/dist/i18n/messages.js +1 -19
  159. package/dist/internal/noteMarkerAttrs.d.ts +8 -0
  160. package/dist/internal/noteMarkerAttrs.js +16 -0
  161. package/dist/internal/pageBreakRunSourceDescendantIndex.js +1 -0
  162. package/dist/internal/prosemirrorAttrBoundary.d.ts +21 -0
  163. package/dist/internal/prosemirrorAttrBoundary.js +50 -0
  164. package/dist/layout-bridge/convert/fixedTableColumnWidths.d.ts +6 -0
  165. package/dist/layout-bridge/convert/fixedTableColumnWidths.js +23 -0
  166. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  167. package/dist/layout-bridge/convert/footnoteLayout.js +3 -3
  168. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  169. package/dist/layout-bridge/convert/headerFooterLayout.js +1 -0
  170. package/dist/layout-bridge/convert/noteReferences.d.ts +1 -3
  171. package/dist/layout-bridge/convert/noteReferences.js +1 -6
  172. package/dist/layout-bridge/convert/paragraphRuns.js +2 -4
  173. package/dist/layout-bridge/convert/tableConversion.js +4 -1
  174. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +2 -2
  175. package/dist/layout-bridge/convert/toFlowBlocks.js +2 -2
  176. package/dist/layout-painter/index.js +2 -5
  177. package/dist/managers/DocumentLoaderManager.d.ts +1 -0
  178. package/dist/managers/DocumentLoaderManager.js +8 -1
  179. package/dist/markdown/renderBlock.js +15 -1
  180. package/dist/markdown/renderParagraph.js +9 -13
  181. package/dist/markdown/renderRuns.js +3 -2
  182. package/dist/markdown/renderTable.js +2 -0
  183. package/dist/markdown/types.d.ts +3 -9
  184. package/dist/paged-layout/editorScrollRoot.d.ts +15 -0
  185. package/dist/paged-layout/editorScrollRoot.js +72 -0
  186. package/dist/paged-layout/scrollToPmPosition.js +8 -22
  187. package/dist/prosemirror/attrs/index.d.ts +2 -12
  188. package/dist/prosemirror/attrs/index.js +22 -48
  189. package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +2 -1
  190. package/dist/prosemirror/canonicalCommands.d.ts +97 -0
  191. package/dist/prosemirror/canonicalCommands.js +28 -0
  192. package/dist/prosemirror/commands/clearParagraphIndent.d.ts +6 -0
  193. package/dist/prosemirror/commands/clearParagraphIndent.js +25 -0
  194. package/dist/prosemirror/commands/pageBreak.js +15 -1
  195. package/dist/prosemirror/commentIdAllocator.d.ts +15 -22
  196. package/dist/prosemirror/commentIdAllocator.js +50 -25
  197. package/dist/prosemirror/commentReferenceAttrs.d.ts +2 -1
  198. package/dist/prosemirror/conversion/fromProseDoc.js +91 -19
  199. package/dist/prosemirror/conversion/listRenderingDefinition.d.ts +6 -0
  200. package/dist/prosemirror/conversion/listRenderingDefinition.js +97 -0
  201. package/dist/prosemirror/conversion/toProseDoc.d.ts +4 -3
  202. package/dist/prosemirror/conversion/toProseDoc.js +51 -11
  203. package/dist/prosemirror/executeEditorCommand.d.ts +11 -0
  204. package/dist/prosemirror/executeEditorCommand.js +26 -0
  205. package/dist/prosemirror/extensions/StarterKit.js +2 -0
  206. package/dist/prosemirror/extensions/core/HistoryExtension.js +97 -5
  207. package/dist/prosemirror/extensions/core/ParagraphExtension.js +53 -20
  208. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +22 -28
  209. package/dist/prosemirror/extensions/features/ListExtension.js +18 -5
  210. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +5 -2
  211. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +13 -1
  212. package/dist/prosemirror/extensions/marks/TextColorExtension.js +3 -2
  213. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +2 -0
  214. package/dist/prosemirror/extensions/marks/markUtils.js +70 -8
  215. package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.d.ts +6 -0
  216. package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.js +36 -0
  217. package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.js +4 -2
  218. package/dist/prosemirror/extensions/nodes/ShapeExtension.js +8 -6
  219. package/dist/prosemirror/listMarker.d.ts +1 -0
  220. package/dist/prosemirror/listMarker.js +16 -7
  221. package/dist/prosemirror/listNumbering.js +26 -5
  222. package/dist/prosemirror/listRenderingAttrs.d.ts +1 -0
  223. package/dist/prosemirror/listRenderingAttrs.js +3 -0
  224. package/dist/prosemirror/markupViewNotes.js +3 -2
  225. package/dist/prosemirror/moveRangeBoundaryAttrs.d.ts +2 -1
  226. package/dist/prosemirror/noteReferenceReview.js +5 -3
  227. package/dist/prosemirror/plugins/revisionIds.d.ts +23 -19
  228. package/dist/prosemirror/plugins/revisionIds.js +110 -29
  229. package/dist/prosemirror/plugins/suggestionMode.d.ts +2 -2
  230. package/dist/prosemirror/plugins/suggestionMode.js +246 -42
  231. package/dist/prosemirror/rangeAnchorAttrs.d.ts +2 -1
  232. package/dist/prosemirror/runFormattingFromMarks.d.ts +4 -1
  233. package/dist/prosemirror/runFormattingFromMarks.js +15 -1
  234. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +2 -1
  235. package/dist/prosemirror/runFormattingInlineCarriers.js +4 -1
  236. package/dist/prosemirror/schema/marks.d.ts +2 -0
  237. package/dist/prosemirror/schema/nodes.d.ts +10 -2
  238. package/dist/prosemirror/storyListNumbering.js +11 -9
  239. package/dist/prosemirror/textBoxAnchorAttrs.d.ts +2 -1
  240. package/dist/prosemirror/textInput.d.ts +6 -1
  241. package/dist/prosemirror/textInput.js +14 -3
  242. package/dist/prosemirror/trackedRevisionPath.js +2 -1
  243. package/dist/prosemirror/trackedRunInlineAtoms.d.ts +1 -0
  244. package/dist/prosemirror/trackedRunInlineAtoms.js +1 -0
  245. package/dist/prosemirror/utils/visualLineNavigation.js +6 -8
  246. package/dist/prosemirror/validation.js +4 -0
  247. package/dist/types/content.d.ts +2 -2
  248. package/dist/utils/createDocument.js +2 -2
  249. package/dist/utils/mergeDocumentContent.d.ts +2 -2
  250. package/dist/utils/mergeDocumentContent.js +11 -8
  251. package/package.json +14 -2
@@ -1,4 +1,5 @@
1
1
  import { expectParagraphAttrs, expectTrackedChangeMarkAttrs } from "../attrs/index.js";
2
+ import { clearIndentOnBackspace } from "../commands/clearParagraphIndent.js";
2
3
  import { paragraphPropertiesSnapshot } from "../commands/propertyChangeScope.js";
3
4
  import { paragraphEndsItsContainer } from "../containerFinalParagraph.js";
4
5
  import { encloseWholeControls } from "../contentControlRevisions.js";
@@ -10,14 +11,16 @@ import { rebaseParagraphRuns } from "../rebaseParagraphRunFormatting.js";
10
11
  import { RUN_FORMATTING_MARK_NAMES } from "../runFormattingMarkNames.js";
11
12
  import { paragraphRunStyleContext } from "../runStyleFormatting.js";
12
13
  import { cellPasteRange, pasteTableCells } from "../tableCellPaste.js";
13
- import { handleEditorBeforeInput } from "../textInput.js";
14
+ import { afterNativeCompositionFlush, handleEditorBeforeInput } from "../textInput.js";
14
15
  import { canCarryTrackedRunMark } from "../trackedRunInlineAtoms.js";
15
16
  import { getDocumentNumbering } from "./documentNumbering.js";
16
- import { getDocumentStyleResolver } from "./documentStyleState.js";
17
+ import { documentStylesKey, getDocumentStyleResolver } from "./documentStyleState.js";
17
18
  import { mintRevisionId, seedRevisionIdsFromDoc } from "./revisionIds.js";
18
19
  import { Slice } from "prosemirror-model";
20
+ import { CellSelection } from "prosemirror-tables";
19
21
  import { Mapping, ReplaceStep } from "prosemirror-transform";
20
- import { AllSelection, Plugin, PluginKey, Selection, TextSelection } from "prosemirror-state";
22
+ import { AllSelection, EditorState, Plugin, PluginKey, Selection, TextSelection } from "prosemirror-state";
23
+ import { joinBackward, joinForward, selectNodeBackward, selectNodeForward } from "prosemirror-commands";
21
24
  import { isHistoryTransaction } from "prosemirror-history";
22
25
  import { undoInputRule } from "prosemirror-inputrules";
23
26
  //#region src/prosemirror/plugins/suggestionMode.ts
@@ -241,10 +244,44 @@ function markRangeAsInserted(tr, doc, from, to, insertionType, deletionType, att
241
244
  function handleSuggestionPaste(view, slice, pluginState) {
242
245
  const { selection } = view.state;
243
246
  const selectsAll = selection instanceof AllSelection;
244
- if (!(selection instanceof TextSelection || selectsAll) || selection.empty) return false;
247
+ if (!(selection instanceof TextSelection || selectsAll)) return false;
245
248
  const insertionType = view.state.schema.marks["insertion"];
246
249
  const deletionType = view.state.schema.marks["deletion"];
247
250
  if (!insertionType || !deletionType) return false;
251
+ if (selection.empty) {
252
+ const { $from } = selection;
253
+ const closedTable = slice.openStart === 0 && slice.openEnd === 0 && slice.content.firstChild?.type.name === "table" && slice.content.lastChild?.type.name === "table";
254
+ const prefix = $from.parent.content.cut(0, $from.parentOffset);
255
+ let deletedPrefix = prefix.size > 0;
256
+ prefix.forEach((node) => {
257
+ if (!node.marks.some((mark) => mark.type === deletionType)) deletedPrefix = false;
258
+ });
259
+ if (!closedTable || $from.parent.type.name !== "paragraph" || !deletedPrefix) return false;
260
+ const suffix = $from.parent.content.cut($from.parentOffset);
261
+ let deletedSuffix = true;
262
+ suffix.forEach((node) => {
263
+ if (!node.marks.some((mark) => mark.type === deletionType)) deletedSuffix = false;
264
+ });
265
+ const tr = view.state.tr.setMeta(SUGGESTION_META, true).setMeta("paste", true);
266
+ const at = $from.before();
267
+ tr.replaceRange(at, at, slice);
268
+ const revision = makeMarkAttrs(pluginState);
269
+ const end = tr.mapping.map(at, 1);
270
+ enclosePastedRunRevisions({
271
+ tr,
272
+ from: at,
273
+ to: end,
274
+ revision
275
+ });
276
+ markRangeAsInserted(tr, tr.doc, at, end, insertionType, deletionType, revision);
277
+ if (deletedSuffix && $from.parent.attrs["pPrMark"] == null && !paragraphEndsItsContainer($from.doc.resolve($from.before()), "paragraph")) tr.setNodeAttribute(tr.mapping.map($from.before()), "pPrMark", {
278
+ kind: "del",
279
+ info: makeParagraphMarkInfo(pluginState)
280
+ });
281
+ tr.setSelection(TextSelection.create(tr.doc, tr.mapping.map(selection.from)));
282
+ view.dispatch(tr.scrollIntoView());
283
+ return true;
284
+ }
248
285
  if (selectsAll && (slice.openStart > 0 || slice.openEnd > 0)) slice = new Slice(view.state.tr.replaceSelection(slice).doc.content, 0, 0);
249
286
  const { from, to } = selectsAll ? {
250
287
  from: Selection.atStart(view.state.doc).from,
@@ -372,16 +409,54 @@ function handleSuggestionTableCellPaste(view, slice, pluginState) {
372
409
  const insertFrom = tr.mapping.slice(mapFrom).map(to);
373
410
  const sizeBefore = tr.doc.content.size;
374
411
  tr.replaceRange(insertFrom, insertFrom, content);
375
- const insertTo = insertFrom + (tr.doc.content.size - sizeBefore);
412
+ let insertTo = insertFrom + (tr.doc.content.size - sizeBefore);
413
+ let pastedFrom = insertFrom;
414
+ const finalParagraph = cell.lastChild;
415
+ const $pasteFrom = tr.doc.resolve(pastedFrom);
416
+ const $pasteTo = tr.doc.resolve(insertTo);
417
+ if (content.openStart > 0 && content.openEnd > 0 && finalParagraph?.type.name === "paragraph" && $pasteFrom.parent.type.name === "paragraph" && $pasteTo.parent.type.name === "paragraph" && $pasteFrom.before() !== $pasteTo.before()) {
418
+ tr.setNodeAttribute($pasteFrom.before(), "pPrMark", {
419
+ kind: "ins",
420
+ info: {
421
+ id: revision.revisionId,
422
+ author: revision.author,
423
+ date: revision.date
424
+ }
425
+ });
426
+ tr.setNodeAttribute($pasteTo.before(), "pPrMark", finalParagraph.attrs["pPrMark"]);
427
+ recordReplacedParagraphProperties({
428
+ tr,
429
+ position: $pasteTo.before(),
430
+ replaced: finalParagraph,
431
+ revision: {
432
+ id: revision.revisionId,
433
+ author: revision.author,
434
+ date: revision.date
435
+ }
436
+ });
437
+ }
438
+ const emptyInsertions = [];
439
+ tr.doc.nodeAt(cellPos)?.forEach((node, offset) => {
440
+ const pos = cellPos + 1 + offset;
441
+ if (pos < pastedFrom && node.type.name === "paragraph" && node.content.size === 0 && isCurrentAuthorParagraphInsertion(node.attrs["pPrMark"], pluginState.author)) emptyInsertions.push({
442
+ from: pos,
443
+ to: pos + node.nodeSize
444
+ });
445
+ });
446
+ const retraction = tr.mapping.maps.length;
447
+ for (const range of emptyInsertions.toReversed()) tr.delete(range.from, range.to);
448
+ const retracted = tr.mapping.slice(retraction);
449
+ pastedFrom = retracted.map(pastedFrom);
450
+ insertTo = retracted.map(insertTo);
376
451
  enclosePastedRunRevisions({
377
452
  tr,
378
- from: insertFrom,
453
+ from: pastedFrom,
379
454
  to: insertTo,
380
455
  revision
381
456
  });
382
- markRangeAsInserted(tr, tr.doc, insertFrom, insertTo, insertionType, deletionType, revision);
383
- tr.doc.nodesBetween(insertFrom, insertTo, (node, pos) => {
384
- if (node.type.name === "paragraph" && pos >= insertFrom && pos + node.nodeSize <= insertTo && node.attrs["pPrMark"] == null) tr.setNodeAttribute(pos, "pPrMark", {
457
+ markRangeAsInserted(tr, tr.doc, pastedFrom, insertTo, insertionType, deletionType, revision);
458
+ tr.doc.nodesBetween(pastedFrom, insertTo, (node, pos) => {
459
+ if (node.type.name === "paragraph" && pos >= pastedFrom && pos + node.nodeSize <= insertTo && node.attrs["pPrMark"] == null) tr.setNodeAttribute(pos, "pPrMark", {
385
460
  kind: "ins",
386
461
  info: {
387
462
  id: revision.revisionId,
@@ -452,7 +527,9 @@ function applySuggestionInsert(view, from, to, text, pluginState) {
452
527
  const tr = view.state.tr;
453
528
  tr.setMeta(SUGGESTION_META, true);
454
529
  tr.setMeta(SUGGESTED_TEXT_INPUT_META, text);
455
- const selectsAll = view.state.selection instanceof AllSelection;
530
+ const { selection } = view.state;
531
+ const typesOverSelection = !selection.empty && selection.from === from && selection.to === to;
532
+ const selectsAll = selection instanceof AllSelection;
456
533
  if (selectsAll) {
457
534
  from = Math.max(from, Selection.atStart(view.state.doc).from);
458
535
  to = Math.min(to, Selection.atEnd(view.state.doc).to);
@@ -473,7 +550,7 @@ function applySuggestionInsert(view, from, to, text, pluginState) {
473
550
  for (const mark of replacedFormatting) tr.addMark(insertAt, insertAt + text.length, mark);
474
551
  }
475
552
  separateSplitStretch(tr, insertAt, insertAt + text.length, insertAttrs.revisionId);
476
- if (view.state.selection instanceof AllSelection) tr.setSelection(TextSelection.create(tr.doc, insertAt + text.length));
553
+ if (typesOverSelection) tr.setSelection(TextSelection.create(tr.doc, insertAt + text.length));
477
554
  view.dispatch(tr.scrollIntoView());
478
555
  return true;
479
556
  }
@@ -533,15 +610,38 @@ function suggestRangeDeletion(state, tr, from, to) {
533
610
  * prior author's revision must not be silently overwritten.
534
611
  */
535
612
  function handleSuggestionEnter(view, pluginState) {
536
- const { $from } = view.state.selection;
537
- if ($from.parent.type.name !== "paragraph") return false;
613
+ const state = view.state;
614
+ if (state.selection.$from.parent.type.name !== "paragraph") return false;
615
+ const replacement = { tr: null };
616
+ let splitState = state;
617
+ if (state.selection instanceof TextSelection && !state.selection.empty) {
618
+ if (!handleSuggestionDelete(state, (tr) => {
619
+ replacement.tr = tr;
620
+ const styles = documentStylesKey.get(state);
621
+ const plugins = [];
622
+ if (styles) {
623
+ const spec = { ...styles.spec };
624
+ delete spec.appendTransaction;
625
+ delete spec.filterTransaction;
626
+ plugins.push(new Plugin(spec));
627
+ }
628
+ splitState = state.reconfigure({ plugins }).apply(tr);
629
+ }, "forward")) return false;
630
+ }
631
+ const { $from } = splitState.selection;
538
632
  const sourcePos = $from.before();
539
633
  const sourceAttrs = $from.parent.attrs;
540
634
  const captured = { tr: null };
541
- if (!splitBlockClearBorders(view.state, (tr) => {
635
+ if (!splitBlockClearBorders(splitState, (tr) => {
542
636
  captured.tr = tr;
543
637
  }, view) || !captured.tr) return false;
544
- const tr = captured.tr;
638
+ const tr = replacement.tr ?? captured.tr;
639
+ if (replacement.tr) {
640
+ for (const step of captured.tr.steps) tr.step(step);
641
+ tr.setSelection(captured.tr.selection.getBookmark().resolve(tr.doc));
642
+ tr.setStoredMarks(captured.tr.storedMarks);
643
+ }
644
+ tr.setMeta(SUGGESTION_META, true);
545
645
  if (sourceAttrs["pPrMark"] == null) {
546
646
  if (tr.doc.nodeAt(sourcePos)?.type.name === "paragraph") {
547
647
  const markInfo = {
@@ -561,6 +661,24 @@ function handleSuggestionEnter(view, pluginState) {
561
661
  view.dispatch(tr.scrollIntoView());
562
662
  return true;
563
663
  }
664
+ /** Find the adjacent visible unit without consuming a bookmark range marker. */
665
+ function caretDeleteTarget(state, direction) {
666
+ const { $from } = state.selection;
667
+ const backward = direction === "backward";
668
+ let from = backward ? $from.pos - 1 : $from.pos;
669
+ let to = backward ? $from.pos : $from.pos + 1;
670
+ while (from >= $from.start() && to <= $from.end()) {
671
+ const adjacent = state.doc.resolve(from).nodeAfter;
672
+ if (adjacent?.type.name !== "bookmarkBoundary") return {
673
+ type: "inlineUnit",
674
+ from,
675
+ to
676
+ };
677
+ from += backward ? -adjacent.nodeSize : adjacent.nodeSize;
678
+ to += backward ? -adjacent.nodeSize : adjacent.nodeSize;
679
+ }
680
+ return { type: "paragraphEdge" };
681
+ }
564
682
  /**
565
683
  * Detect a caret-at-paragraph-boundary scenario where Backspace/Delete should
566
684
  * record a tracked paragraph-mark deletion instead of joining paragraphs.
@@ -572,8 +690,8 @@ function handleSuggestionEnter(view, pluginState) {
572
690
  * - Delete-at-paragraph-end → current paragraph.
573
691
  *
574
692
  * Returns `null` when there is no adjacent sibling paragraph (the join would
575
- * not produce paragraph-mark merging — e.g. doc start, doc end, or sibling
576
- * is a table). The default merge path then runs unchanged.
693
+ * not produce paragraph-mark merging, e.g. doc start, doc end, or a table).
694
+ * Bookmark markers at an edge do not hide the adjacent paragraph break.
577
695
  */
578
696
  function paragraphBoundaryTarget(state, direction) {
579
697
  const { $from, empty } = state.selection;
@@ -581,14 +699,13 @@ function paragraphBoundaryTarget(state, direction) {
581
699
  if ($from.parent.type.name !== "paragraph") return null;
582
700
  const paragraphStart = $from.before();
583
701
  const paragraphEnd = $from.after();
702
+ if (caretDeleteTarget(state, direction).type !== "paragraphEdge") return null;
584
703
  if (direction === "backward") {
585
- if ($from.parentOffset !== 0) return null;
586
704
  if (paragraphStart === 0) return null;
587
705
  const prev = state.doc.resolve(paragraphStart).nodeBefore;
588
706
  if (!prev || prev.type.name !== "paragraph") return null;
589
707
  return paragraphStart - prev.nodeSize;
590
708
  }
591
- if ($from.parentOffset !== $from.parent.content.size) return null;
592
709
  if (paragraphEnd >= state.doc.content.size) return null;
593
710
  const next = state.doc.resolve(paragraphEnd).nodeAfter;
594
711
  if (!next || next.type.name !== "paragraph") return null;
@@ -612,7 +729,13 @@ function applyPPrDel(view, targetParagraphPos, pluginState) {
612
729
  const joined = view.state.doc.nodeAt(joinPos);
613
730
  try {
614
731
  tr.join(joinPos);
615
- tr.setNodeAttribute(targetParagraphPos, "pPrMark", null);
732
+ tr.setNodeAttribute(targetParagraphPos, "pPrMark", joined?.type === targetNode.type ? expectParagraphAttrs(joined).pPrMark : null);
733
+ if (joined?.type === targetNode.type) recordReplacedParagraphProperties({
734
+ tr,
735
+ position: targetParagraphPos,
736
+ replaced: joined,
737
+ revision: existingMark.info
738
+ });
616
739
  const styleResolver = getDocumentStyleResolver(view.state);
617
740
  if (styleResolver && joined?.type === targetNode.type && joined.content.size > 0) rebaseParagraphRuns({
618
741
  previousContext: paragraphRunStyleContext(joined, styleResolver),
@@ -671,15 +794,28 @@ function handleSuggestionDelete(state, dispatch, direction) {
671
794
  to: rangeTo.pos
672
795
  }).sort((a, b) => b.from - a.from);
673
796
  for (const { from, to } of ranges) markRangeAsDeleted(tr, state.doc, from, to, insertionType, deletionType, pluginState, state);
674
- const cursorPos = tr.mapping.map($to.pos);
675
- tr.setSelection(TextSelection.near(tr.doc.resolve(cursorPos)));
797
+ if (state.selection instanceof CellSelection) tr.setSelection(state.selection.map(tr.doc, tr.mapping));
798
+ else {
799
+ const cursorPos = tr.mapping.map($to.pos);
800
+ tr.setSelection(TextSelection.near(tr.doc.resolve(cursorPos)));
801
+ }
676
802
  dispatch(tr.scrollIntoView());
677
803
  return true;
678
804
  }
679
805
  const isBackward = direction === "backward";
680
- const deletePos = isBackward ? $from.pos - 1 : $from.pos;
681
- const deleteEnd = isBackward ? $from.pos : $from.pos + 1;
682
- if (deletePos < 0 || deleteEnd > state.doc.content.size) return true;
806
+ const target = caretDeleteTarget(state, direction);
807
+ if (target.type === "paragraphEdge") {
808
+ const edge = isBackward ? $from.start() : $from.end();
809
+ if ($from.pos === edge) return false;
810
+ const virtual = EditorState.create({
811
+ doc: state.doc,
812
+ selection: TextSelection.create(state.doc, edge)
813
+ });
814
+ if ((isBackward ? joinBackward : joinForward)(virtual, dispatch)) return true;
815
+ return (isBackward ? selectNodeBackward : selectNodeForward)(virtual, dispatch);
816
+ }
817
+ const deletePos = target.from;
818
+ const deleteEnd = target.to;
683
819
  const noteRange = expandNoteReferenceDeletionRange(state.doc, deletePos, deleteEnd);
684
820
  const rangeFrom = noteRange?.from ?? deletePos;
685
821
  const rangeTo = noteRange?.to ?? deleteEnd;
@@ -701,19 +837,7 @@ function handleSuggestionDelete(state, dispatch, direction) {
701
837
  }
702
838
  /** Apply the editor's selected-content deletion path for a host cut action. */
703
839
  const deleteSelectionAsSuggestion = (state, dispatch) => state.selection.empty ? false : handleSuggestionDelete(state, dispatch, "forward");
704
- /**
705
- * Mark the text committed by an IME composition as a tracked insertion.
706
- *
707
- * Invoked from `compositionend` (deferred to a microtask) rather than from the
708
- * `appendTransaction` catch-all. ProseMirror commits composed text as part of
709
- * its own composition-end flush; adding the insertion mark *synchronously*
710
- * during that flush re-wraps the very text node the IME just finalized, which
711
- * corrupts CJK (Japanese / Chinese / Korean) input — characters duplicate or
712
- * garble. Running one tick later, after the composition has settled, wraps the
713
- * committed range safely. `markRangeAsInserted` skips nodes that already carry a
714
- * tracked-change mark, so this is idempotent. eigenpal/docx-editor#938.
715
- */
716
- function markComposedAsInsertion(view, from, pluginState, replaced) {
840
+ function markComposedAsInsertion({ view, from, pluginState, replaced, compositionId }) {
717
841
  const insertionType = view.state.schema.marks["insertion"];
718
842
  const deletionType = view.state.schema.marks["deletion"];
719
843
  if (!insertionType || !deletionType) return;
@@ -721,9 +845,16 @@ function markComposedAsInsertion(view, from, pluginState, replaced) {
721
845
  if (to <= from && !replaced) return;
722
846
  const tr = view.state.tr;
723
847
  tr.setMeta(SUGGESTION_META, true);
848
+ if (compositionId !== null) tr.setMeta("composition", compositionId);
724
849
  if (replaced) {
725
- tr.insert(from, replaced.content);
726
- markRangeAsDeleted(tr, tr.doc, from, from + replaced.content.size, insertionType, deletionType, pluginState);
850
+ tr.replaceRange(from, from, replaced);
851
+ markRangeAsDeleted(tr, tr.doc, from, tr.mapping.map(from, 1), insertionType, deletionType, pluginState);
852
+ const restoredEnd = tr.doc.resolve(tr.mapping.map(from, 1));
853
+ const restoredStart = tr.doc.resolve(from);
854
+ if (restoredStart.parent.type.name === "paragraph" && restoredEnd.parent.type.name === "paragraph" && restoredStart.parent !== restoredEnd.parent) {
855
+ const mark = expectParagraphAttrs(restoredStart.parent).pPrMark;
856
+ if (mark?.kind === "del") carryIntoParagraphLeft(view.state, tr, view.state.doc.resolve(from).parent, restoredEnd.before(), mark.info);
857
+ }
727
858
  }
728
859
  const insertionFrom = tr.mapping.map(from, 1);
729
860
  const insertionTo = tr.mapping.map(to, 1);
@@ -766,6 +897,38 @@ function recordSplitParagraph(tr, before, step, insertedFrom, insertedTo, attrs)
766
897
  });
767
898
  }
768
899
  /**
900
+ * The inline content a step removed from within one textblock, and where it
901
+ * started: the node a node selection held (an image, a field, a note
902
+ * reference) or a range of runs. Null for a step that removed nothing, or removed paragraph or table
903
+ * structure the catch-all cannot put back.
904
+ */
905
+ function replacedInline(before, step) {
906
+ if (!(step instanceof ReplaceStep) || !before || step.from === step.to) return null;
907
+ const $from = before.resolve(step.from);
908
+ if (!$from.parent.inlineContent || !$from.sameParent(before.resolve(step.to))) return null;
909
+ return {
910
+ from: step.from,
911
+ content: $from.parent.content.cut($from.parentOffset, step.to - $from.start())
912
+ };
913
+ }
914
+ /**
915
+ * A transaction the plugin did not build (a command, a default paste, a
916
+ * keymap) replaced inline content directly. Put it back in front of what
917
+ * replaced it as a tracked deletion, as typing over a selection does, so
918
+ * rejecting restores it and accepting removes it. The author's own
919
+ * insertions are retracted instead.
920
+ */
921
+ function restoreReplacedInline({ tr, replaced, insertionType, deletionType, pluginState }) {
922
+ for (const { at, content } of replaced) {
923
+ const pos = tr.mapping.map(at, -1);
924
+ const $pos = tr.doc.resolve(pos);
925
+ const index = $pos.index();
926
+ if (!$pos.parent.canReplace(index, index, content)) continue;
927
+ tr.insert(pos, content);
928
+ markRangeAsDeleted(tr, tr.doc, pos, pos + content.size, insertionType, deletionType, pluginState);
929
+ }
930
+ }
931
+ /**
769
932
  * Create the suggestion mode plugin.
770
933
  * When active, text edits become tracked changes.
771
934
  */
@@ -773,6 +936,7 @@ function createSuggestionModePlugin(initialActive = false, author = "User") {
773
936
  let composing = false;
774
937
  let compositionFrom = null;
775
938
  let compositionReplaced = null;
939
+ let compositionId = null;
776
940
  return new Plugin({
777
941
  key: suggestionModeKey,
778
942
  state: {
@@ -784,6 +948,8 @@ function createSuggestionModePlugin(initialActive = false, author = "User") {
784
948
  };
785
949
  },
786
950
  apply(tr, state) {
951
+ const nativeCompositionId = tr.getMeta("composition");
952
+ if (composing && tr.docChanged && typeof nativeCompositionId === "number") compositionId = nativeCompositionId;
787
953
  const meta = tr.getMeta(suggestionModeKey);
788
954
  if (meta) return {
789
955
  ...state,
@@ -809,6 +975,7 @@ function createSuggestionModePlugin(initialActive = false, author = "User") {
809
975
  if (!suggestionModeKey.getState(view.state)?.active) return false;
810
976
  if (composing) return false;
811
977
  composing = true;
978
+ compositionId = null;
812
979
  const { from, to } = view.state.selection;
813
980
  compositionFrom = from;
814
981
  compositionReplaced = from === to ? null : view.state.doc.slice(from, to);
@@ -822,14 +989,23 @@ function createSuggestionModePlugin(initialActive = false, author = "User") {
822
989
  compositionReplaced = null;
823
990
  if (!pluginState?.active || from == null) {
824
991
  composing = false;
992
+ compositionId = null;
825
993
  return false;
826
994
  }
827
- queueMicrotask(() => {
995
+ afterNativeCompositionFlush(() => {
828
996
  try {
829
997
  const current = suggestionModeKey.getState(view.state);
830
- if (current?.active) markComposedAsInsertion(view, from, current, replaced);
998
+ const nativeCompositionId = compositionId;
999
+ if (current?.active) markComposedAsInsertion({
1000
+ view,
1001
+ from,
1002
+ pluginState: current,
1003
+ replaced,
1004
+ compositionId: nativeCompositionId
1005
+ });
831
1006
  } finally {
832
1007
  composing = false;
1008
+ compositionId = null;
833
1009
  }
834
1010
  });
835
1011
  return false;
@@ -851,6 +1027,20 @@ function createSuggestionModePlugin(initialActive = false, author = "User") {
851
1027
  if (event.key === "Backspace" || event.key === "Delete") {
852
1028
  const { $from, empty } = view.state.selection;
853
1029
  if (event.key === "Backspace" && empty && $from.parentOffset === 0 && $from.parent.type.name === "paragraph" && expectParagraphAttrs($from.parent).numPr?.kind === "reference") return false;
1030
+ if (event.key === "Backspace" && clearIndentOnBackspace(view.state, (tr) => {
1031
+ const revision = makeMarkAttrs(pluginState);
1032
+ recordReplacedParagraphProperties({
1033
+ tr,
1034
+ position: $from.before(),
1035
+ replaced: $from.parent,
1036
+ revision: {
1037
+ id: revision.revisionId,
1038
+ author: revision.author,
1039
+ date: revision.date
1040
+ }
1041
+ });
1042
+ view.dispatch(tr.setMeta("suggestionModeApplied", true));
1043
+ })) return true;
854
1044
  const boundaryTarget = paragraphBoundaryTarget(view.state, event.key === "Backspace" ? "backward" : "forward");
855
1045
  if (boundaryTarget !== null) return applyPPrDel(view, boundaryTarget, pluginState);
856
1046
  const direction = event.key === "Backspace" ? "backward" : "forward";
@@ -883,9 +1073,16 @@ function createSuggestionModePlugin(initialActive = false, author = "User") {
883
1073
  tr.setMeta(SUGGESTION_META, true);
884
1074
  const deletionType = newState.schema.marks["deletion"];
885
1075
  const laterMaps = transactions.slice(transactions.indexOf(userTr) + 1).flatMap((transaction) => transaction.mapping.maps);
1076
+ const restoresReplaced = userTr.getMeta("appendedTransaction") === void 0;
1077
+ const replaced = [];
886
1078
  for (const [stepIndex, step] of userTr.steps.entries()) {
887
1079
  const stepMap = step.getMap();
888
1080
  const following = new Mapping([...userTr.mapping.maps.slice(stepIndex + 1), ...laterMaps]);
1081
+ const removed = restoresReplaced ? replacedInline(userTr.docs[stepIndex], step) : null;
1082
+ if (removed) replaced.push({
1083
+ at: following.map(removed.from, -1),
1084
+ content: removed.content
1085
+ });
889
1086
  stepMap.forEach((_oldFrom, _oldTo, stepFrom, stepTo) => {
890
1087
  const newFrom = following.map(stepFrom, -1);
891
1088
  const newTo = following.map(stepTo, 1);
@@ -901,6 +1098,13 @@ function createSuggestionModePlugin(initialActive = false, author = "User") {
901
1098
  }
902
1099
  });
903
1100
  }
1101
+ if (deletionType) restoreReplacedInline({
1102
+ tr,
1103
+ replaced,
1104
+ insertionType,
1105
+ deletionType,
1106
+ pluginState
1107
+ });
904
1108
  return tr.steps.length > 0 ? tr : null;
905
1109
  }
906
1110
  });
@@ -1,4 +1,5 @@
1
- import { ReadProseMirrorAttrsResult } from "./attrs/index.js";
1
+ import { ReadProseMirrorAttrsResult } from "../internal/prosemirrorAttrBoundary.js";
2
+ import "./attrs/index.js";
2
3
  import { RangeAnchorAttrs } from "./emptyRangeAnchor.js";
3
4
  import { Node } from "prosemirror-model";
4
5
  //#region src/prosemirror/rangeAnchorAttrs.d.ts
@@ -1,6 +1,7 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
2
  import { RunStyleResolver } from "./runStyleFormatting.js";
3
3
  import { Mark } from "prosemirror-model";
4
+ import { RunPropsPatch } from "@stll/docx-core/ops";
4
5
  //#region src/prosemirror/runFormattingFromMarks.d.ts
5
6
  /**
6
7
  * Convert ProseMirror marks to TextFormatting
@@ -12,7 +13,9 @@ type MarksToTextFormattingOptions = {
12
13
  paragraphMarkPrecedesStyle?: boolean | undefined;
13
14
  styleResolver?: RunStyleResolver | null | undefined;
14
15
  };
16
+ /** Overlay only changed visual marks; private authored properties stay with the run. */
17
+ declare const runFormattingPatchFromMarks: (beforeMarks: readonly Mark[], afterMarks: readonly Mark[]) => RunPropsPatch;
15
18
  declare const sameFormattingValue: (left: unknown, right: unknown) => boolean;
16
19
  declare function marksToTextFormatting(marks: readonly Mark[], options?: MarksToTextFormattingOptions): document_d_exports.TextFormatting;
17
20
  //#endregion
18
- export { MarksToTextFormattingOptions, marksToTextFormatting, sameFormattingValue };
21
+ export { MarksToTextFormattingOptions, marksToTextFormatting, runFormattingPatchFromMarks, sameFormattingValue };
@@ -203,6 +203,20 @@ const changedVisualFormattingGroups = (observedFormatting, expectedFormatting) =
203
203
  }
204
204
  return changed;
205
205
  };
206
+ /** Overlay only changed visual marks; private authored properties stay with the run. */
207
+ const runFormattingPatchFromMarks = (beforeMarks, afterMarks) => {
208
+ const observedMarks = (marks) => marks.filter(({ type }) => type.name !== "runFormattingOverride");
209
+ const before = marksToTextFormatting(observedMarks(beforeMarks));
210
+ const after = marksToTextFormatting(observedMarks(afterMarks));
211
+ const changed = changedVisualFormattingGroups(after, before);
212
+ const patch = before.styleId === after.styleId ? {} : { styleId: after.styleId ?? null };
213
+ const isFormattingKey = (key) => Object.hasOwn(RUN_FORMATTING_VISUAL_GROUPS, key);
214
+ for (const [key, group] of Object.entries(RUN_FORMATTING_VISUAL_GROUPS)) {
215
+ if (!isFormattingKey(key) || group === null || !changed.has(group)) continue;
216
+ Reflect.set(patch, key, after[key] ?? null);
217
+ }
218
+ return patch;
219
+ };
206
220
  const VISUAL_BOOLEAN_FORMATTING_PROPERTIES = /* @__PURE__ */ new Set([
207
221
  "allCaps",
208
222
  "bold",
@@ -564,4 +578,4 @@ function marksToTextFormatting(marks, options) {
564
578
  };
565
579
  }
566
580
  //#endregion
567
- export { marksToTextFormatting, sameFormattingValue };
581
+ export { marksToTextFormatting, runFormattingPatchFromMarks, sameFormattingValue };
@@ -1,7 +1,7 @@
1
1
  import { Mark, Node } from "prosemirror-model";
2
2
  import { Transaction } from "prosemirror-state";
3
3
  //#region src/prosemirror/runFormattingInlineCarriers.d.ts
4
- type RunFormattingInlineAtomDisposition = "break-run" | "field-run" | "not-a-run" | "page-break-carrier" | "preserved-xml-run" | "structured-field" | "symbol-run" | "tab-run" | "text-run";
4
+ type RunFormattingInlineAtomDisposition = "break-run" | "field-run" | "not-a-run" | "note-marker-run" | "page-break-carrier" | "preserved-xml-run" | "structured-field" | "symbol-run" | "tab-run" | "text-run";
5
5
  /**
6
6
  * How every inline atom maps to a serialized run-formatting carrier.
7
7
  *
@@ -18,6 +18,7 @@ declare const RUN_FORMATTING_INLINE_ATOM_DISPOSITIONS: Readonly<{
18
18
  readonly image: "not-a-run";
19
19
  readonly math: "not-a-run";
20
20
  readonly moveRangeBoundary: "not-a-run";
21
+ readonly noteMarker: "note-marker-run";
21
22
  readonly pageBreakRun: "page-break-carrier";
22
23
  readonly preservedXml: "preserved-xml-run";
23
24
  readonly rangeAnchor: "not-a-run";
@@ -20,6 +20,7 @@ const RUN_FORMATTING_INLINE_ATOM_DISPOSITIONS = Object.freeze({
20
20
  image: "not-a-run",
21
21
  math: "not-a-run",
22
22
  moveRangeBoundary: "not-a-run",
23
+ noteMarker: "note-marker-run",
23
24
  pageBreakRun: "page-break-carrier",
24
25
  preservedXml: "preserved-xml-run",
25
26
  rangeAnchor: "not-a-run",
@@ -52,6 +53,7 @@ const CONTROL_CHARACTER_BY_DISPOSITION = Object.freeze({
52
53
  "break-run": "\n",
53
54
  "field-run": null,
54
55
  "not-a-run": null,
56
+ "note-marker-run": null,
55
57
  "page-break-carrier": null,
56
58
  "preserved-xml-run": null,
57
59
  "structured-field": null,
@@ -179,7 +181,8 @@ const runFormattingCarrierReviewText = (carrier) => {
179
181
  case "tab-run":
180
182
  case "break-run": return CONTROL_CHARACTER_BY_DISPOSITION[carrier.disposition];
181
183
  case "text-run": return carrier.node.text ?? "";
182
- case "page-break-carrier": return "";
184
+ case "page-break-carrier":
185
+ case "note-marker-run": return "";
183
186
  case "symbol-run": {
184
187
  const { char } = expectSymbolAttrs(carrier.node);
185
188
  return decodeOoxmlSymbolCharacter(char) ?? "�";
@@ -107,6 +107,7 @@ type TrackedRevisionAncestor = {
107
107
  utcDate?: string;
108
108
  initials?: string;
109
109
  outerWrapperCount: number;
110
+ resolutionJoins?: document_d_exports.Insertion["resolutionJoins"];
110
111
  };
111
112
  type TrackedChangeMarkAttrs = {
112
113
  revisionId: number;
@@ -119,6 +120,7 @@ type TrackedChangeMarkAttrs = {
119
120
  moveKind?: "moveTo" | "moveFrom";
120
121
  /** Number of inline-wrapper layers authored outside this revision. */
121
122
  _docxOuterWrapperCount?: number;
123
+ _docxResolutionJoins?: document_d_exports.Insertion["resolutionJoins"];
122
124
  /** Outer revisions, in authored order, that ProseMirror cannot hold as nested marks. */
123
125
  _docxRevisionAncestors?: readonly TrackedRevisionAncestor[];
124
126
  /** Defaults to `"user"`; `"suggested"` for AI-proposed, non-serialized edits. */
@@ -44,6 +44,10 @@ declare const PRESERVED_XML_LEVELS: {
44
44
  readonly inline: "inline";
45
45
  };
46
46
  type PreservedXmlLevel = (typeof PRESERVED_XML_LEVELS)[keyof typeof PRESERVED_XML_LEVELS];
47
+ /** The automatic number mark authored inside a note story, with no reader text. */
48
+ type NoteMarkerAttrs = {
49
+ kind: "footnote" | "endnote";
50
+ };
47
51
  /** A run or inline child folio does not model, carried through the editor untouched. */
48
52
  type PreservedXmlAttrs = {
49
53
  /** Replayable markup, as `captureVerbatimXml` wrote it. */
@@ -51,6 +55,8 @@ type PreservedXmlAttrs = {
51
55
  /** The visible text the markup puts on the line, empty when it shows none. */
52
56
  text: string;
53
57
  level: PreservedXmlLevel;
58
+ /** `PreservedInline.foldedListNumber`, for a capture the list marker stands in for. */
59
+ foldedListNumber?: document_d_exports.FoldedListNumber;
54
60
  };
55
61
  /** A block child folio does not model, carried through the editor untouched. */
56
62
  type PreservedBlockAttrs = {
@@ -166,6 +172,8 @@ type ParagraphAttrs = {
166
172
  * next marker letter.
167
173
  */
168
174
  listImplicitChildLevelAdvances?: number;
175
+ /** Cached inline LISTNUM display text appended after the resolved list template. */
176
+ listFoldedMarkerSuffix?: string;
169
177
  /**
170
178
  * When the marker text contains a TAB separator, this column offset (in
171
179
  * twips) is where the slot after the tab should land — used to align an
@@ -338,7 +346,7 @@ type ParagraphPropertyChangeAttrs = Omit<document_d_exports.ParagraphPropertyCha
338
346
  };
339
347
  previousFormatting?: Omit<document_d_exports.ParagraphFormatting, "numPr"> & {
340
348
  numPr?: ParagraphAttrs["numPr"] | null;
341
- } & Partial<Pick<ParagraphAttrs, "listIsBullet" | "listIsLegal" | "listNumFmt" | "listMarker" | "listMarkerTemplate" | "listMarkerHidden" | "listMarkerFormatting" | "listMarkerAlignment" | "listMarkerSuffix" | "listMarkerAllCaps" | "listImplicitChildLevelAdvances" | "listMarkerSecondSlotOffsetTwips" | "listLevelNumFmts" | "listLevelStarts" | "listLevelTabs" | "listAbstractNumId" | "listStartOverride" | "lineSpacingExplicit" | "direction" | "_autospacingBase">>;
349
+ } & Partial<Pick<ParagraphAttrs, "listIsBullet" | "listIsLegal" | "listNumFmt" | "listMarker" | "listMarkerTemplate" | "listMarkerHidden" | "listMarkerFormatting" | "listMarkerAlignment" | "listMarkerSuffix" | "listMarkerAllCaps" | "listImplicitChildLevelAdvances" | "listFoldedMarkerSuffix" | "listMarkerSecondSlotOffsetTwips" | "listLevelNumFmts" | "listLevelStarts" | "listLevelTabs" | "listAbstractNumId" | "listStartOverride" | "lineSpacingExplicit" | "direction" | "_autospacingBase">>;
342
350
  currentFormatting?: document_d_exports.ParagraphFormatting;
343
351
  };
344
352
  /**
@@ -1258,4 +1266,4 @@ type TableCellAttrs = {
1258
1266
  _docxVMergeContinuationCells?: unknown;
1259
1267
  };
1260
1268
  //#endregion
1261
- export { AlternateContentAttrs, AuthoredEmuAttrs, BlockCustomXmlAttrs, BlockSdtAttrs, BookmarkBoundaryAttrs, CommentReferenceAttrs, FieldAttrs, HardBreakAttrs, ImageAttrs, ImagePositionAttrs, MathAttrs, PRESERVED_XML_LEVELS, PageBreakRunAttrs, ParagraphAttrs, ParagraphAttrsPatch, ParagraphPropertyChangeAttrs, PreservedBlockAttrs, PreservedXmlAttrs, PreservedXmlLevel, SdtAttrs, ShapeAttrs, SuggestedStructuralMarker, SymbolAttrs, TEXT_BOX_TEXT_BODY_CONTENT_STATE_TYPES, TabAttrs, TableAttrs, TableCellAttrs, TableRowAttrs, TextBoxAnchorAttrs, TextBoxAttrs, TextBoxTextBodyContentState };
1269
+ export { AlternateContentAttrs, AuthoredEmuAttrs, BlockCustomXmlAttrs, BlockSdtAttrs, BookmarkBoundaryAttrs, CommentReferenceAttrs, FieldAttrs, HardBreakAttrs, ImageAttrs, ImagePositionAttrs, MathAttrs, NoteMarkerAttrs, PRESERVED_XML_LEVELS, PageBreakRunAttrs, ParagraphAttrs, ParagraphAttrsPatch, ParagraphPropertyChangeAttrs, PreservedBlockAttrs, PreservedXmlAttrs, PreservedXmlLevel, SdtAttrs, ShapeAttrs, SuggestedStructuralMarker, SymbolAttrs, TEXT_BOX_TEXT_BODY_CONTENT_STATE_TYPES, TabAttrs, TableAttrs, TableCellAttrs, TableRowAttrs, TextBoxAnchorAttrs, TextBoxAttrs, TextBoxTextBodyContentState };