@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,5 +1,97 @@
1
1
  import { createExtension } from "../create.js";
2
- import { history, redo, undo } from "prosemirror-history";
2
+ import { Plugin } from "prosemirror-state";
3
+ import { closeHistory, history, isHistoryTransaction, redo, undo } from "prosemirror-history";
4
+ //#region src/prosemirror/extensions/core/HistoryExtension.ts
5
+ /**
6
+ * History Extension — undo/redo via prosemirror-history
7
+ */
8
+ /**
9
+ * History adjacency is based on step maps, which differ for physical deletions
10
+ * and suggestion marks. Group continuous typing and same-direction deletions explicitly; each
11
+ * structural edit, paste, drop, or composition starts its own undo event.
12
+ * Capture DOM input before the shared input router or a keymap handles it.
13
+ */
14
+ const inputBoundaryPlugin = (newGroupDelay) => {
15
+ let previousKind;
16
+ let deletionGroup = 0;
17
+ let previousInputTime = 0;
18
+ let pendingDeletionGroup = null;
19
+ return new Plugin({
20
+ filterTransaction(tr) {
21
+ const pendingGroup = pendingDeletionGroup;
22
+ pendingDeletionGroup = null;
23
+ if (isHistoryTransaction(tr) || !tr.docChanged && tr.selectionSet) {
24
+ previousKind = void 0;
25
+ return true;
26
+ }
27
+ if (tr.docChanged && (previousKind === "deleteBackward" || previousKind === "deleteForward" || previousKind === "deletion")) {
28
+ if (pendingGroup !== null) tr.setMeta("composition", pendingGroup);
29
+ else if (!tr.getMeta("appendedTransaction")) previousKind = void 0;
30
+ }
31
+ return true;
32
+ },
33
+ view(view) {
34
+ const startInput = (kind) => {
35
+ const now = Date.now();
36
+ if (kind !== previousKind || kind === "structure" || kind === "paste" || kind === "drop" || now - previousInputTime > newGroupDelay) {
37
+ deletionGroup--;
38
+ view.dispatch(closeHistory(view.state.tr));
39
+ }
40
+ previousInputTime = now;
41
+ previousKind = kind;
42
+ pendingDeletionGroup = kind === "deleteBackward" || kind === "deleteForward" || kind === "deletion" ? deletionGroup : null;
43
+ };
44
+ const keydown = (event) => {
45
+ if (event.isComposing) return;
46
+ if (event.key === "Backspace" || event.key === "Delete") {
47
+ startInput(event.key === "Backspace" ? "deleteBackward" : "deleteForward");
48
+ return;
49
+ }
50
+ if (event.key === "Enter") {
51
+ startInput("structure");
52
+ return;
53
+ }
54
+ if (event.key.length === 1 && !event.metaKey && !event.ctrlKey) startInput("typing");
55
+ };
56
+ const beforeinput = (event) => {
57
+ if (event.inputType === "insertCompositionText" || event.isComposing) {
58
+ startInput("composition");
59
+ return;
60
+ }
61
+ if (event.inputType === "insertText" || event.inputType === "insertReplacementText") {
62
+ startInput("typing");
63
+ return;
64
+ }
65
+ if (event.inputType.startsWith("delete")) if (event.inputType.endsWith("Backward")) startInput("deleteBackward");
66
+ else if (event.inputType.endsWith("Forward")) startInput("deleteForward");
67
+ else startInput("deletion");
68
+ else if (event.inputType === "insertParagraph" || event.inputType === "insertLineBreak") startInput("structure");
69
+ };
70
+ const paste = () => startInput("paste");
71
+ const drop = () => startInput("drop");
72
+ const compositionstart = () => {
73
+ view.dispatch(closeHistory(view.state.tr));
74
+ previousKind = "composition";
75
+ };
76
+ view.dom.addEventListener("keydown", keydown, true);
77
+ view.dom.addEventListener("beforeinput", beforeinput, true);
78
+ view.dom.addEventListener("paste", paste, true);
79
+ view.dom.addEventListener("drop", drop, true);
80
+ view.dom.addEventListener("compositionstart", compositionstart, true);
81
+ return { destroy() {
82
+ view.dom.removeEventListener("keydown", keydown, true);
83
+ view.dom.removeEventListener("beforeinput", beforeinput, true);
84
+ view.dom.removeEventListener("paste", paste, true);
85
+ view.dom.removeEventListener("drop", drop, true);
86
+ view.dom.removeEventListener("compositionstart", compositionstart, true);
87
+ } };
88
+ }
89
+ });
90
+ };
91
+ const consumeHistoryShortcut = (command) => (state, dispatch, view) => {
92
+ command(state, dispatch, view);
93
+ return true;
94
+ };
3
95
  const HistoryExtension = createExtension({
4
96
  name: "history",
5
97
  defaultOptions: {
@@ -12,15 +104,15 @@ const HistoryExtension = createExtension({
12
104
  plugins: [history({
13
105
  depth: options.depth,
14
106
  newGroupDelay: options.newGroupDelay
15
- })],
107
+ }), inputBoundaryPlugin(options.newGroupDelay)],
16
108
  commands: {
17
109
  undo: () => undo,
18
110
  redo: () => redo
19
111
  },
20
112
  ...options.shortcuts === "editor" && { keyboardShortcuts: {
21
- "Mod-z": undo,
22
- "Mod-y": redo,
23
- "Mod-Shift-z": redo
113
+ "Mod-z": consumeHistoryShortcut(undo),
114
+ "Mod-y": consumeHistoryShortcut(redo),
115
+ "Mod-Shift-z": consumeHistoryShortcut(redo)
24
116
  } }
25
117
  };
26
118
  }
@@ -1,3 +1,4 @@
1
+ import { mintBookmarkId, reserveProseBookmarkIds } from "../../../docx/bookmarkIds.js";
1
2
  import { BUILT_IN_STYLE_NAME } from "../../../docx/builtInStyles.js";
2
3
  import { PROSE_PARAGRAPH_SOURCE_TOKEN_ATTR } from "../../../docx/paragraphPropertySource.js";
3
4
  import { isStyleSourcedParagraphNumbering } from "../../../internal/paragraphFormattingSerialization.js";
@@ -7,6 +8,7 @@ import { collectHeadings } from "../../../utils/headingCollector.js";
7
8
  import { tableOfContentsStyleLevel } from "../../../utils/tableOfContentsStyle.js";
8
9
  import { expectParagraphAttrs } from "../../attrs/index.js";
9
10
  import { autospacingMatchesBase } from "../../autospacingBase.js";
11
+ import { withCanonicalParagraphFormatting } from "../../canonicalCommands.js";
10
12
  import { removeSectionBreakAtSelection, setSectionBreakType } from "../../commands/sectionBreak.js";
11
13
  import { CLEARED_LIST_RENDERING_ATTRS } from "../../listMarker.js";
12
14
  import { directParagraphAlignment } from "../../paragraphAlignment.js";
@@ -231,6 +233,7 @@ const paragraphNodeSpec = {
231
233
  listMarkerSuffix: { default: null },
232
234
  listMarkerAllCaps: { default: null },
233
235
  listImplicitChildLevelAdvances: { default: null },
236
+ listFoldedMarkerSuffix: { default: void 0 },
234
237
  listMarkerSecondSlotOffsetTwips: { default: null },
235
238
  listLevelNumFmts: { default: null },
236
239
  listLevelStarts: { default: null },
@@ -630,27 +633,56 @@ const ParagraphExtension = createNodeExtension({
630
633
  onSchemaReady() {
631
634
  const applyStyleFn = makeApplyStyle();
632
635
  return { commands: {
633
- setAlignment: (alignment) => makeSetAlignment(alignment),
634
- alignLeft: () => makeSetAlignment("left"),
635
- alignCenter: () => makeSetAlignment("center"),
636
- alignRight: () => makeSetAlignment("right"),
637
- alignJustify: () => makeSetAlignment("both"),
638
- setLineSpacing: (value, rule) => makeSetLineSpacing(value, rule),
639
- singleSpacing: () => makeSetLineSpacing(240),
640
- oneAndHalfSpacing: () => makeSetLineSpacing(360),
641
- doubleSpacing: () => makeSetLineSpacing(480),
642
- setSpaceBefore: (twips) => setParagraphSpacingAttr("before", twips),
643
- setSpaceAfter: (twips) => setParagraphSpacingAttr("after", twips),
644
- increaseIndent: (amount) => makeIncreaseIndent(amount),
645
- decreaseIndent: (amount) => makeDecreaseIndent(amount),
646
- setIndentLeft: (twips) => setParagraphAttr("indentLeft", twips > 0 ? twips : null),
647
- setIndentRight: (twips) => setParagraphAttr("indentRight", twips > 0 ? twips : null),
648
- setIndentFirstLine: (twips, hanging) => setParagraphAttrsCmd({
636
+ setAlignment: (alignment) => withCanonicalParagraphFormatting(makeSetAlignment(alignment), { alignment }),
637
+ alignLeft: () => withCanonicalParagraphFormatting(makeSetAlignment("left"), { alignment: "left" }),
638
+ alignCenter: () => withCanonicalParagraphFormatting(makeSetAlignment("center"), { alignment: "center" }),
639
+ alignRight: () => withCanonicalParagraphFormatting(makeSetAlignment("right"), { alignment: "right" }),
640
+ alignJustify: () => withCanonicalParagraphFormatting(makeSetAlignment("both"), { alignment: "both" }),
641
+ setLineSpacing: (value, rule) => withCanonicalParagraphFormatting(makeSetLineSpacing(value, rule), {
642
+ lineSpacing: value,
643
+ lineSpacingRule: rule ?? "auto"
644
+ }),
645
+ singleSpacing: () => withCanonicalParagraphFormatting(makeSetLineSpacing(240), {
646
+ lineSpacing: 240,
647
+ lineSpacingRule: "auto"
648
+ }),
649
+ oneAndHalfSpacing: () => withCanonicalParagraphFormatting(makeSetLineSpacing(360), {
650
+ lineSpacing: 360,
651
+ lineSpacingRule: "auto"
652
+ }),
653
+ doubleSpacing: () => withCanonicalParagraphFormatting(makeSetLineSpacing(480), {
654
+ lineSpacing: 480,
655
+ lineSpacingRule: "auto"
656
+ }),
657
+ setSpaceBefore: (twips) => withCanonicalParagraphFormatting(setParagraphSpacingAttr("before", twips), { spaceBefore: twips }),
658
+ setSpaceAfter: (twips) => withCanonicalParagraphFormatting(setParagraphSpacingAttr("after", twips), { spaceAfter: twips }),
659
+ increaseIndent: (amount) => withCanonicalParagraphFormatting(makeIncreaseIndent(amount), (node) => ({ indentLeft: (expectParagraphAttrs(node).indentLeft ?? 0) + (amount ?? 720) })),
660
+ decreaseIndent: (amount) => withCanonicalParagraphFormatting(makeDecreaseIndent(amount), (node) => {
661
+ const attrs = expectParagraphAttrs(node);
662
+ const indentLeft = Math.max(0, (attrs.indentLeft ?? 0) - (amount ?? 720));
663
+ return { indentLeft: indentLeft > 0 || paragraphNumberingReferenceId(attrs.numPr ?? void 0) !== void 0 ? indentLeft : null };
664
+ }),
665
+ setIndentLeft: (twips) => withCanonicalParagraphFormatting(setParagraphAttr("indentLeft", twips > 0 ? twips : null), { indentLeft: twips > 0 ? twips : null }),
666
+ setIndentRight: (twips) => withCanonicalParagraphFormatting(setParagraphAttr("indentRight", twips > 0 ? twips : null), { indentRight: twips > 0 ? twips : null }),
667
+ setIndentFirstLine: (twips, hanging) => withCanonicalParagraphFormatting(setParagraphAttrsCmd({
668
+ indentFirstLine: twips > 0 ? twips : null,
669
+ hangingIndent: hanging ?? false
670
+ }), {
649
671
  indentFirstLine: twips > 0 ? twips : null,
650
672
  hangingIndent: hanging ?? false
651
673
  }),
652
- applyStyle: (styleId, resolvedAttrs) => applyStyleFn(styleId, resolvedAttrs),
653
- clearStyle: () => (state, dispatch) => {
674
+ applyStyle: (styleId, resolvedAttrs) => withCanonicalParagraphFormatting(applyStyleFn(styleId, resolvedAttrs), {
675
+ styleId,
676
+ ...resolvedAttrs ? {
677
+ alignment: null,
678
+ outlineLevel: null,
679
+ spaceBefore: null,
680
+ spaceAfter: null,
681
+ lineSpacing: null,
682
+ lineSpacingRule: null
683
+ } : {}
684
+ }),
685
+ clearStyle: () => withCanonicalParagraphFormatting((state, dispatch) => {
654
686
  const resolver = getDocumentStyleResolver(state);
655
687
  if (!resolver) return applyStyleFn(null)(state, dispatch);
656
688
  const resolved = resolver.resolveParagraphStyle(null);
@@ -661,7 +693,7 @@ const ParagraphExtension = createNodeExtension({
661
693
  ...styleName && { styleName },
662
694
  numbering: getDocumentNumbering(state)
663
695
  })(state, dispatch);
664
- },
696
+ }, { styleId: null }),
665
697
  insertSectionBreak: (breakType) => setSectionBreakType(breakType),
666
698
  removeSectionBreak: () => removeSectionBreakAtSelection,
667
699
  generateTOC: ({ title }) => (state, dispatch) => {
@@ -671,6 +703,7 @@ const ParagraphExtension = createNodeExtension({
671
703
  if (!dispatch) return true;
672
704
  const { schema: s } = state;
673
705
  const tr = state.tr;
706
+ reserveProseBookmarkIds(state.doc);
674
707
  const bookmarkEntries = [];
675
708
  for (const h of headings) {
676
709
  const bookmarkName = `_Toc${Math.floor(1e8 + Math.random() * 9e8)}`;
@@ -683,7 +716,7 @@ const ParagraphExtension = createNodeExtension({
683
716
  const paragraphNode = tr.doc.resolve(mappedPos).nodeAfter;
684
717
  if (paragraphNode && paragraphNode.type.name === "paragraph") {
685
718
  const newBookmarks = [...(paragraphNode.attrs["bookmarks"] ?? []).filter((b) => !b.name.startsWith("_Toc")), {
686
- id: Math.floor(Math.random() * 2147483647),
719
+ id: mintBookmarkId(),
687
720
  name: bookmarkName
688
721
  }];
689
722
  tr.setNodeMarkup(mappedPos, void 0, {
@@ -1,5 +1,6 @@
1
1
  import { mergeTextFormatting } from "../../../utils/textFormattingMerge.js";
2
2
  import { expectCharacterStyleMarkAttrs, expectRunFormattingOverrideMarkAttrs } from "../../attrs/index.js";
3
+ import { clearIndentOnBackspace } from "../../commands/clearParagraphIndent.js";
3
4
  import { keepSectionBreaksOnSurvivingMarks } from "../../commands/sectionBreak.js";
4
5
  import { getDocumentStyleResolver } from "../../plugins/documentStyleState.js";
5
6
  import { RUN_FORMATTING_MARK_NAMES } from "../../runFormattingMarkNames.js";
@@ -8,6 +9,7 @@ import { paragraphAttrsFromResolvedStyle } from "../../styles/resolvedStyleAttrs
8
9
  import { createExtension } from "../create.js";
9
10
  import { marksToTextFormatting, textFormattingToMarks } from "../marks/markUtils.js";
10
11
  import { Priority } from "../types.js";
12
+ import { EditorState, TextSelection } from "prosemirror-state";
11
13
  import { baseKeymap, deleteSelection, joinBackward, joinForward, selectAll, selectParentNode, splitBlock } from "prosemirror-commands";
12
14
  //#region src/prosemirror/extensions/features/BaseKeymapExtension.ts
13
15
  /**
@@ -22,31 +24,6 @@ function chainCommands(...commands) {
22
24
  };
23
25
  }
24
26
  /**
25
- * Backspace at the start of a paragraph clears first-line indent / hanging indent
26
- * before joining with the previous paragraph (matches Word behavior).
27
- */
28
- const clearIndentOnBackspace = (state, dispatch) => {
29
- const { $cursor } = state.selection;
30
- if (!$cursor) return false;
31
- if ($cursor.parentOffset !== 0) return false;
32
- if ($cursor.parent.type.name !== "paragraph") return false;
33
- const attrs = $cursor.parent.attrs;
34
- const hasFirstLine = attrs["indentFirstLine"] !== null && attrs["indentFirstLine"] > 0;
35
- const hasHanging = !!attrs["hangingIndent"];
36
- const hasIndentLeft = attrs["indentLeft"] !== null && attrs["indentLeft"] > 0;
37
- if (!hasFirstLine && !hasHanging && !hasIndentLeft) return false;
38
- if (dispatch) {
39
- const pos = $cursor.before();
40
- dispatch(state.tr.setNodeMarkup(pos, void 0, {
41
- ...attrs,
42
- indentFirstLine: null,
43
- hangingIndent: null,
44
- indentLeft: null
45
- }).scrollIntoView());
46
- }
47
- return true;
48
- };
49
- /**
50
27
  * Custom Enter handler: splits the block, inherits style-related attrs,
51
28
  * clears paragraph borders, and preserves run formatting on the new paragraph.
52
29
  *
@@ -117,16 +94,33 @@ function applyNextParagraphStyle(tr, sourcePara, newPara, resolver) {
117
94
  tr.setStoredMarks(resolved.runFormatting ? textFormattingToMarks(resolved.runFormatting, tr.doc.type.schema) : []);
118
95
  return true;
119
96
  }
97
+ const blockBoundaryDeletion = (state) => {
98
+ if (!(state.selection instanceof TextSelection) || state.selection.empty) return null;
99
+ const tr = state.tr.deleteSelection();
100
+ return tr.doc.resolve(tr.mapping.map(state.selection.from)).parent.isTextblock ? null : tr;
101
+ };
120
102
  const splitBlockClearBorders = (state, dispatch, view) => {
121
- const { $from: preSplitFrom } = state.selection;
103
+ const deletion = blockBoundaryDeletion(state);
104
+ const splitState = deletion ? EditorState.create({
105
+ doc: deletion.doc,
106
+ selection: deletion.selection,
107
+ storedMarks: deletion.storedMarks
108
+ }) : state;
109
+ const { $from: preSplitFrom } = splitState.selection;
122
110
  const sourcePara = preSplitFrom.parent.type.name === "paragraph" ? preSplitFrom.parent : null;
123
- const caretFormattingMarks = (state.storedMarks || preSplitFrom.marks()).filter((mark) => RUN_FORMATTING_MARK_NAMES.has(mark.type.name));
111
+ const caretFormattingMarks = (splitState.storedMarks || preSplitFrom.marks()).filter((mark) => RUN_FORMATTING_MARK_NAMES.has(mark.type.name));
124
112
  const resolver = getDocumentStyleResolver(state);
125
113
  const splitResult = { tr: null };
126
- if (!splitBlock(state, dispatch ? (tr) => {
114
+ if (!splitBlock(splitState, dispatch ? (tr) => {
127
115
  splitResult.tr = tr;
128
116
  } : void 0, view)) return false;
129
117
  if (dispatch && splitResult.tr !== null) {
118
+ if (deletion) {
119
+ for (const step of splitResult.tr.steps) deletion.step(step);
120
+ deletion.setSelection(splitResult.tr.selection.getBookmark().resolve(deletion.doc));
121
+ deletion.setStoredMarks(splitResult.tr.storedMarks);
122
+ splitResult.tr = deletion;
123
+ }
130
124
  const tr = splitResult.tr;
131
125
  const { $from } = tr.selection;
132
126
  const newPara = $from.parent;
@@ -1,5 +1,6 @@
1
1
  import { paragraphNumberingLevel, paragraphNumberingReferenceId } from "../../../docx/numberingReference.js";
2
2
  import { expectParagraphAttrs } from "../../attrs/index.js";
3
+ import { withCanonicalCommand } from "../../canonicalCommands.js";
3
4
  import { LIST_MARKER_PATTERN, listRequestsForMarker } from "../../listAutoformatMarkers.js";
4
5
  import { CLEARED_LIST_RENDERING_ATTRS } from "../../listMarker.js";
5
6
  import { applyParagraphUpdates, continueNumbering, listItemAttrs, resolveListTarget, restartNumbering, setNumberingValue } from "../../listNumbering.js";
@@ -107,8 +108,14 @@ function toggleList(intent) {
107
108
  return true;
108
109
  };
109
110
  }
110
- const toggleBulletList = (state, dispatch) => toggleList("bullet")(state, dispatch);
111
- const toggleNumberedList = (state, dispatch) => toggleList("numbered")(state, dispatch);
111
+ const toggleBulletList = withCanonicalCommand((state, dispatch) => toggleList("bullet")(state, dispatch), () => [{
112
+ type: "toggleList",
113
+ kind: "bullet"
114
+ }]);
115
+ const toggleNumberedList = withCanonicalCommand((state, dispatch) => toggleList("numbered")(state, dispatch), () => [{
116
+ type: "toggleList",
117
+ kind: "decimal"
118
+ }]);
112
119
  const attrsForListLevel = (state, attrs, level) => {
113
120
  if (!hasActiveListNumbering(attrs)) panic("Cannot change the level of a list without a numbering id");
114
121
  return {
@@ -394,9 +401,15 @@ const ListExtension = createExtension({
394
401
  commands: {
395
402
  toggleBulletList: () => toggleBulletList,
396
403
  toggleNumberedList: () => toggleNumberedList,
397
- increaseListLevel: () => increaseListLevel,
398
- decreaseListLevel: () => decreaseListLevel,
399
- removeList: () => removeList,
404
+ increaseListLevel: () => withCanonicalCommand(increaseListLevel, () => [{
405
+ type: "changeListLevel",
406
+ direction: "increase"
407
+ }]),
408
+ decreaseListLevel: () => withCanonicalCommand(decreaseListLevel, () => [{
409
+ type: "changeListLevel",
410
+ direction: "decrease"
411
+ }]),
412
+ removeList: () => withCanonicalCommand(removeList, () => [{ type: "removeList" }]),
400
413
  restartNumbering: () => restartNumbering,
401
414
  continueNumbering: () => continueNumbering,
402
415
  setNumberingValue: (value) => setNumberingValue(value)
@@ -2,7 +2,7 @@ import { document_d_exports } from "../../../types/document.js";
2
2
  import { Extension } from "../types.js";
3
3
  import { RemovedSectionReference, TrackedSectionEndpointRemoval } from "../../../internal/sectionEndpointResolution.js";
4
4
  import { Node } from "prosemirror-model";
5
- import { EditorState, PluginKey, Transaction } from "prosemirror-state";
5
+ import { EditorState, Plugin, PluginKey, Transaction } from "prosemirror-state";
6
6
  //#region src/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts
7
7
  declare const paragraphChangeTrackerKey: PluginKey<InternalParagraphChangeTrackerState>;
8
8
  type ParagraphChangeTrackerState = {
@@ -30,6 +30,7 @@ type InternalParagraphChangeTrackerState = ParagraphChangeTrackerState & {
30
30
  /** The section records themselves, by identity. */
31
31
  sectionRecords: ReadonlySet<document_d_exports.SectionProperties>;
32
32
  };
33
+ declare function createParagraphChangeTrackerPlugin(): Plugin<InternalParagraphChangeTrackerState>;
33
34
  /**
34
35
  * Get the change tracker state from an EditorState
35
36
  */
@@ -85,6 +86,8 @@ declare function markSectionBreakRemoval(tr: Transaction, sourceDoc: Node): Tran
85
86
  */
86
87
  declare function clearTrackedChanges(state: EditorState): Transaction;
87
88
  declare function ignoreTrackedChanges(tr: Transaction): Transaction;
89
+ /** A committed package-story/property edit requires the full package serializer. */
90
+ declare const markPackageChange: (tr: Transaction) => Transaction;
88
91
  declare function markStructuralChange(tr: Transaction): Transaction;
89
92
  type MarkChangedParagraphRangesOptions = {
90
93
  ranges: readonly {
@@ -98,4 +101,4 @@ type MarkChangedParagraphRangesOptions = {
98
101
  declare function markChangedParagraphRanges(tr: Transaction, batch: MarkChangedParagraphRangesOptions): Transaction;
99
102
  declare const ParagraphChangeTrackerExtension: (options?: Partial<{}> | undefined) => Extension;
100
103
  //#endregion
101
- export { ParagraphChangeTrackerExtension, ParagraphChangeTrackerState, clearTrackedChanges, getChangeTrackerState, getChangedParagraphIds, getTrackedSectionEndpointRemoval, hasStructuralChanges, hasUntrackedChanges, ignoreTrackedChanges, markChangedParagraphRanges, markSectionBreakRemoval, markStructuralChange, markTrackedSectionEndpointRemoval, paragraphChangeTrackerKey, repackWithEditorSectionRemovals };
104
+ export { ParagraphChangeTrackerExtension, ParagraphChangeTrackerState, clearTrackedChanges, createParagraphChangeTrackerPlugin, getChangeTrackerState, getChangedParagraphIds, getTrackedSectionEndpointRemoval, hasStructuralChanges, hasUntrackedChanges, ignoreTrackedChanges, markChangedParagraphRanges, markPackageChange, markSectionBreakRemoval, markStructuralChange, markTrackedSectionEndpointRemoval, paragraphChangeTrackerKey, repackWithEditorSectionRemovals };
@@ -13,6 +13,7 @@ const paragraphChangeTrackerKey = new PluginKey("paragraphChangeTracker");
13
13
  const CLEAR_META = "clear";
14
14
  const IGNORE_META = "ignore";
15
15
  const STRUCTURAL_META = "structural";
16
+ const PACKAGE_CHANGE_META = "package-change";
16
17
  const CHANGED_PARAGRAPH_RANGES_META = "folioChangedParagraphRanges";
17
18
  const SECTION_ENDPOINT_REMOVAL_META = "folioSectionEndpointRemoval";
18
19
  const SECTION_EDIT_META = "folioSectionEdit";
@@ -258,6 +259,11 @@ function createParagraphChangeTrackerPlugin() {
258
259
  sectionRecords: counts.sectionRecords
259
260
  };
260
261
  }
262
+ if (meta === PACKAGE_CHANGE_META && !tr.docChanged) return {
263
+ ...prevState,
264
+ hasUntrackedSourceChanges: true,
265
+ hasUntrackedChanges: true
266
+ };
261
267
  if (!tr.docChanged) return isSectionEditMeta(sectionEditMeta) && sectionEditMeta.expectedEndpointFingerprint === prevState.sectionEndpointFingerprint ? {
262
268
  ...prevState,
263
269
  sectionEndpointRemoval: sectionEditMeta.authorization
@@ -326,6 +332,10 @@ function createParagraphChangeTrackerPlugin() {
326
332
  newState.hasUntrackedChanges = true;
327
333
  }
328
334
  }
335
+ if (meta === PACKAGE_CHANGE_META) {
336
+ newState.hasUntrackedSourceChanges = true;
337
+ newState.hasUntrackedChanges = true;
338
+ }
329
339
  return newState;
330
340
  }
331
341
  },
@@ -503,6 +513,8 @@ function clearTrackedChanges(state) {
503
513
  function ignoreTrackedChanges(tr) {
504
514
  return tr.setMeta(paragraphChangeTrackerKey, IGNORE_META);
505
515
  }
516
+ /** A committed package-story/property edit requires the full package serializer. */
517
+ const markPackageChange = (tr) => tr.setMeta(paragraphChangeTrackerKey, PACKAGE_CHANGE_META);
506
518
  function markStructuralChange(tr) {
507
519
  return tr.setMeta(paragraphChangeTrackerKey, STRUCTURAL_META);
508
520
  }
@@ -523,4 +535,4 @@ const ParagraphChangeTrackerExtension = createExtension({
523
535
  }
524
536
  });
525
537
  //#endregion
526
- export { ParagraphChangeTrackerExtension, clearTrackedChanges, getChangeTrackerState, getChangedParagraphIds, getTrackedSectionEndpointRemoval, hasStructuralChanges, hasUntrackedChanges, ignoreTrackedChanges, markChangedParagraphRanges, markSectionBreakRemoval, markStructuralChange, markTrackedSectionEndpointRemoval, paragraphChangeTrackerKey, repackWithEditorSectionRemovals };
538
+ export { ParagraphChangeTrackerExtension, clearTrackedChanges, createParagraphChangeTrackerPlugin, getChangeTrackerState, getChangedParagraphIds, getTrackedSectionEndpointRemoval, hasStructuralChanges, hasUntrackedChanges, ignoreTrackedChanges, markChangedParagraphRanges, markPackageChange, markSectionBreakRemoval, markStructuralChange, markTrackedSectionEndpointRemoval, paragraphChangeTrackerKey, repackWithEditorSectionRemovals };
@@ -1,5 +1,6 @@
1
1
  import { textToStyle } from "../../../utils/formatToStyle.js";
2
2
  import { expectTextColorMarkAttrs } from "../../attrs/index.js";
3
+ import { canonicalRunFormatting, withCanonicalCommand } from "../../canonicalCommands.js";
3
4
  import { clearRunColor } from "../../clearRunColor.js";
4
5
  import { createMarkExtension } from "../create.js";
5
6
  import { setMark } from "./markUtils.js";
@@ -40,10 +41,10 @@ const TextColorExtension = createMarkExtension({
40
41
  if (!textColorType) panic("Missing mark type: textColor");
41
42
  return { commands: {
42
43
  setTextColor: (attrs) => {
43
- if (!attrs.rgb && !attrs.themeColor) return clearRunColor();
44
+ if (!attrs.rgb && !attrs.themeColor) return withCanonicalCommand(clearRunColor(), (state) => canonicalRunFormatting(state, { color: null }));
44
45
  return setMark(textColorType, attrs);
45
46
  },
46
- clearTextColor: () => clearRunColor()
47
+ clearTextColor: () => withCanonicalCommand(clearRunColor(), (state) => canonicalRunFormatting(state, { color: null }))
47
48
  } };
48
49
  }
49
50
  });
@@ -58,6 +58,7 @@ const InsertionExtension = createMarkExtension({
58
58
  provenance: { default: "user" },
59
59
  suggestionId: { default: null },
60
60
  _docxOuterWrapperCount: { default: null },
61
+ _docxResolutionJoins: { default: null },
61
62
  _docxRevisionAncestors: { default: null }
62
63
  },
63
64
  inclusive: false,
@@ -120,6 +121,7 @@ const DeletionExtension = createMarkExtension({
120
121
  suggestionId: { default: null },
121
122
  _historicalFormatting: { default: null },
122
123
  _docxOuterWrapperCount: { default: null },
124
+ _docxResolutionJoins: { default: null },
123
125
  _docxRevisionAncestors: { default: null }
124
126
  },
125
127
  inclusive: false,
@@ -2,6 +2,7 @@ import { FONT_THEME_VALUES } from "../../../types/documentEnumValues.js";
2
2
  import { mergeFontFamily } from "../../../utils/fontFamilyMerge.js";
3
3
  import { normalizeHorizontalScalePercent } from "../../../utils/horizontalScale.js";
4
4
  import { expectCharacterSpacingMarkAttrs, expectCharacterStyleMarkAttrs, expectEmphasisMarkAttrs, expectFontFamilyMarkAttrs, expectRunFormattingOverrideMarkAttrs, expectRunShadingMarkAttrs, expectStrikeMarkAttrs, expectTextEffectMarkAttrs } from "../../attrs/index.js";
5
+ import { canonicalRunFormatting, withCanonicalCommand } from "../../canonicalCommands.js";
5
6
  import { runShadingAttrsToShading, shadingToRunShadingAttrs } from "../../conversion/runShadingMark.js";
6
7
  import { documentMarkType } from "../../documentSchema.js";
7
8
  import { selectRunFormattingCarrierRepresentations } from "../../runFormattingInlineCarriers.js";
@@ -12,6 +13,12 @@ import { applyRunFormattingOverrideMark, buildRunFormattingOverrideAttrs } from
12
13
  import { readThemeColor } from "@stll/docx-core/model";
13
14
  import { toggleMark } from "prosemirror-commands";
14
15
  //#region src/prosemirror/extensions/marks/markUtils.ts
16
+ /**
17
+ * Shared mark utility functions
18
+ *
19
+ * setMark, removeMark, isMarkActive, getMarkAttr, marksToTextFormatting,
20
+ * textFormattingToMarks, clearFormatting
21
+ */
15
22
  const isFontTheme = (value) => value !== void 0 && FONT_THEME_VALUES.some((theme) => theme === value);
16
23
  const fontFamilyAttrsToFormatting = ({ ascii, hAnsi, eastAsia, cs, hint, asciiTheme, hAnsiTheme, eastAsiaTheme, csTheme }) => ({
17
24
  ...ascii !== void 0 ? { ascii } : {},
@@ -179,8 +186,23 @@ function createMarkWithMergedAttrs(markType, currentMark, nextAttrs) {
179
186
  if (!markRequiresAttrMerge(markType)) return markType.create(nextAttrs);
180
187
  return markType.create(mergeMarkAttrs(markType, currentMark, nextAttrs));
181
188
  }
189
+ const canonicalSetMarkFormatting = ({ state, type, attrs }) => {
190
+ const markType = documentMarkType(state, type);
191
+ const { from, to, empty } = state.selection;
192
+ if (empty) return canonicalRunFormatting(state, marksToTextFormatting([createMarkWithMergedAttrs(markType, markType.isInSet(state.storedMarks ?? state.selection.$from.marks()), attrs)]));
193
+ return selectRunFormattingCarrierRepresentations({
194
+ doc: state.doc,
195
+ from,
196
+ to
197
+ }).map((representation) => ({
198
+ type: "formatRun",
199
+ from: representation.from,
200
+ to: representation.to,
201
+ patch: marksToTextFormatting([createMarkWithMergedAttrs(markType, markType.isInSet(representation.node.marks), attrs)])
202
+ }));
203
+ };
182
204
  function setMark(type, attrs) {
183
- return (state, dispatch) => {
205
+ const command = (state, dispatch) => {
184
206
  const markType = documentMarkType(state, type);
185
207
  const { from, to, empty } = state.selection;
186
208
  if (empty) {
@@ -211,6 +233,12 @@ function setMark(type, attrs) {
211
233
  }
212
234
  return true;
213
235
  };
236
+ if (!RUN_FORMATTING_MARK_NAMES.has(type.name)) return command;
237
+ return withCanonicalCommand(command, (state) => canonicalSetMarkFormatting({
238
+ state,
239
+ type,
240
+ attrs
241
+ }));
214
242
  }
215
243
  const DIRECT_FONT_PROPERTIES = [
216
244
  "color",
@@ -287,17 +315,42 @@ const withRunFormattingOverride = (command, update) => (state, dispatch) => comm
287
315
  dispatch(updateRunFormattingOverride(state, tr, update));
288
316
  } : void 0);
289
317
  /** `toggleMark` for the document's own counterpart of `type`. */
290
- const toggleDocumentMark = (type) => (state, dispatch, view) => toggleMark(documentMarkType(state, type))(state, dispatch, view);
318
+ const toggleDocumentMark = (type) => {
319
+ const command = (state, dispatch, view) => toggleMark(documentMarkType(state, type))(state, dispatch, view);
320
+ if (!RUN_FORMATTING_MARK_NAMES.has(type.name)) return command;
321
+ return withCanonicalCommand(command, (state) => {
322
+ const markType = documentMarkType(state, type);
323
+ const formatting = marksToTextFormatting([markType.create()]);
324
+ if (!isMarkActive(state, markType)) return canonicalRunFormatting(state, formatting);
325
+ const keys = markType.name === "strike" ? ["strike", "doubleStrike"] : Object.keys(formatting);
326
+ return canonicalRunFormatting(state, Object.fromEntries(keys.map((key) => [key, null])));
327
+ });
328
+ };
291
329
  /** UI toggle whose direct-formatting contract explicitly targets both script families. */
292
- const toggleMarkForAllScripts = (type, property) => (state, dispatch) => {
330
+ const toggleMarkForAllScripts = (type, property) => withCanonicalCommand((state, dispatch) => {
293
331
  const markType = documentMarkType(state, type);
294
332
  const enabled = !isMarkActive(state, markType);
295
333
  return withRunFormattingOverride(toggleMark(markType), (attrs) => updatePairedToggleAttrs(attrs, property, enabled))(state, dispatch);
296
- };
334
+ }, (state) => {
335
+ const enabled = !isMarkActive(state, documentMarkType(state, type));
336
+ return canonicalRunFormatting(state, property === "bold" ? {
337
+ bold: enabled,
338
+ boldCs: enabled
339
+ } : {
340
+ italic: enabled,
341
+ italicCs: enabled
342
+ });
343
+ });
297
344
  /** UI size command whose direct-formatting contract explicitly targets both script families. */
298
- const setFontSizeForAllScripts = (markType, size) => withRunFormattingOverride(setMark(markType, { size }), (attrs) => updateFontSizeCompanionAttrs(attrs, size));
345
+ const setFontSizeForAllScripts = (markType, size) => withCanonicalCommand(withRunFormattingOverride(setMark(markType, { size }), (attrs) => updateFontSizeCompanionAttrs(attrs, size)), (state) => canonicalRunFormatting(state, {
346
+ fontSize: size,
347
+ fontSizeCs: size
348
+ }));
299
349
  /** Clears both ordinary and complex-script direct size through the UI command boundary. */
300
- const clearFontSizeForAllScripts = (markType) => withRunFormattingOverride(removeMark(markType), (attrs) => updateFontSizeCompanionAttrs(attrs, void 0));
350
+ const clearFontSizeForAllScripts = (markType) => withCanonicalCommand(withRunFormattingOverride(removeMark(markType), (attrs) => updateFontSizeCompanionAttrs(attrs, void 0)), (state) => canonicalRunFormatting(state, {
351
+ fontSize: null,
352
+ fontSizeCs: null
353
+ }));
301
354
  function selectionHasVisibleUnderline(state, markType) {
302
355
  const { from, to, empty, $from } = state.selection;
303
356
  if (empty) {
@@ -317,10 +370,14 @@ function selectionHasVisibleUnderline(state, markType) {
317
370
  return hasVisibleUnderline;
318
371
  }
319
372
  function toggleUnderlineMark(markType) {
320
- return (state, dispatch) => setMark(markType, { style: selectionHasVisibleUnderline(state, documentMarkType(state, markType)) ? "none" : "single" })(state, dispatch);
373
+ return withCanonicalCommand((state, dispatch) => setMark(markType, { style: selectionHasVisibleUnderline(state, documentMarkType(state, markType)) ? "none" : "single" })(state, dispatch), (state) => canonicalSetMarkFormatting({
374
+ state,
375
+ type: markType,
376
+ attrs: { style: selectionHasVisibleUnderline(state, documentMarkType(state, markType)) ? "none" : "single" }
377
+ }));
321
378
  }
322
379
  function removeMark(type) {
323
- return (state, dispatch) => {
380
+ const command = (state, dispatch) => {
324
381
  const markType = documentMarkType(state, type);
325
382
  const { from, to, empty } = state.selection;
326
383
  if (empty) {
@@ -330,6 +387,11 @@ function removeMark(type) {
330
387
  if (dispatch) dispatch(state.tr.removeMark(from, to, markType).scrollIntoView());
331
388
  return true;
332
389
  };
390
+ if (!RUN_FORMATTING_MARK_NAMES.has(type.name)) return command;
391
+ return withCanonicalCommand(command, (state) => {
392
+ const formatting = marksToTextFormatting([documentMarkType(state, type).create()]);
393
+ return canonicalRunFormatting(state, Object.fromEntries(Object.keys(formatting).map((key) => [key, null])));
394
+ });
333
395
  }
334
396
  /**
335
397
  * Check if a mark is active in the current selection
@@ -0,0 +1,6 @@
1
+ import { NodeExtension } from "../types.js";
2
+ //#region src/prosemirror/extensions/nodes/NoteMarkerExtension.d.ts
3
+ declare const NOTE_MARKER_NODE_NAME = "noteMarker";
4
+ declare const NoteMarkerExtension: (options?: Partial<Record<string, unknown>> | undefined) => NodeExtension;
5
+ //#endregion
6
+ export { NOTE_MARKER_NODE_NAME, NoteMarkerExtension };