@stll/folio-core 0.55.0 → 0.57.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 (225) hide show
  1. package/dist/ai-edits/apply.js +214 -52
  2. package/dist/ai-edits/batch-claims.d.ts +3 -1
  3. package/dist/ai-edits/batch-claims.js +25 -1
  4. package/dist/ai-edits/headless.js +2 -2
  5. package/dist/ai-edits/table-row-column-mutations.js +17 -3
  6. package/dist/ai-edits/types.d.ts +7 -1
  7. package/dist/ai-suggestions/apply.js +20 -1
  8. package/dist/compare/compare.js +1 -0
  9. package/dist/compare/inline-atoms.js +40 -16
  10. package/dist/compare/inline-provenance.js +12 -5
  11. package/dist/compare/reproducible-package.d.ts +0 -17
  12. package/dist/compare/reproducible-package.js +12 -18
  13. package/dist/compat/eigenpal.d.ts +2 -1
  14. package/dist/compat/eigenpal.js +2 -1
  15. package/dist/controller/canonicalClipboard.d.ts +23 -0
  16. package/dist/controller/canonicalClipboard.js +482 -0
  17. package/dist/controller/canonicalClipboardResources.d.ts +21 -0
  18. package/dist/controller/canonicalClipboardResources.js +382 -0
  19. package/dist/controller/canonicalComments.d.ts +41 -0
  20. package/dist/controller/canonicalComments.js +152 -0
  21. package/dist/controller/canonicalComposition.d.ts +24 -3
  22. package/dist/controller/canonicalComposition.js +208 -48
  23. package/dist/controller/canonicalInlineProjection.d.ts +118 -0
  24. package/dist/controller/canonicalInlineProjection.js +476 -0
  25. package/dist/controller/canonicalInput.d.ts +13 -4
  26. package/dist/controller/canonicalInput.js +62 -14
  27. package/dist/controller/canonicalInputTimer.d.ts +16 -0
  28. package/dist/controller/canonicalInputTimer.js +34 -0
  29. package/dist/controller/canonicalPublicOperations.d.ts +48 -0
  30. package/dist/controller/canonicalPublicOperations.js +648 -0
  31. package/dist/controller/canonicalSelection.d.ts +18 -0
  32. package/dist/controller/canonicalSelection.js +32 -0
  33. package/dist/controller/canonicalSession.d.ts +27 -6
  34. package/dist/controller/canonicalSession.js +298 -116
  35. package/dist/controller/canonicalStoryEditor.d.ts +7 -3
  36. package/dist/controller/canonicalStoryEditor.js +27 -2
  37. package/dist/controller/canonicalStructure.js +57 -4
  38. package/dist/controller/canonicalTocSelection.d.ts +11 -0
  39. package/dist/controller/canonicalTocSelection.js +43 -0
  40. package/dist/controller/folioEditor.d.ts +2 -9
  41. package/dist/controller/folioEditor.js +18 -4
  42. package/dist/controller/headerFooterEditorManager.d.ts +2 -1
  43. package/dist/controller/headerFooterEditorManager.js +26 -11
  44. package/dist/controller/hiddenEditorApi.d.ts +24 -3
  45. package/dist/controller/hiddenEditorApi.js +8 -0
  46. package/dist/controller/hiddenEditorManager.d.ts +5 -1
  47. package/dist/controller/hiddenEditorManager.js +378 -43
  48. package/dist/controller/noteEditorManager.d.ts +2 -1
  49. package/dist/controller/noteEditorManager.js +29 -13
  50. package/dist/document-operations.d.ts +8 -1
  51. package/dist/document-operations.js +6 -4
  52. package/dist/docx/blockPlainText.d.ts +1 -1
  53. package/dist/docx/blockPlainText.js +11 -3
  54. package/dist/docx/builtInStyles.js +13 -6
  55. package/dist/docx/canonicalResourceSave.d.ts +16 -0
  56. package/dist/docx/canonicalResourceSave.js +27 -0
  57. package/dist/docx/canonicalSave.d.ts +29 -0
  58. package/dist/docx/canonicalSave.js +101 -0
  59. package/dist/docx/canonicalStoryRepack.d.ts +1 -1
  60. package/dist/docx/canonicalStoryRepack.js +38 -5
  61. package/dist/docx/containerChildren.gen.d.ts +3 -1
  62. package/dist/docx/containerChildren.gen.js +33 -1
  63. package/dist/docx/documentParser.d.ts +1 -13
  64. package/dist/docx/documentParser.js +1 -47
  65. package/dist/docx/ensureParaIds.js +10 -4
  66. package/dist/docx/fieldParser.js +14 -2
  67. package/dist/docx/footnoteParser.d.ts +1 -11
  68. package/dist/docx/footnoteParser.js +1 -16
  69. package/dist/docx/headerFooterParser.d.ts +1 -9
  70. package/dist/docx/headerFooterParser.js +1 -12
  71. package/dist/docx/headerFooterVerbatim.d.ts +26 -1
  72. package/dist/docx/headerFooterVerbatim.js +81 -3
  73. package/dist/docx/hyperlinkParser.d.ts +1 -1
  74. package/dist/docx/hyperlinkParser.js +20 -1
  75. package/dist/docx/imageParser.d.ts +13 -1
  76. package/dist/docx/imageParser.js +20 -11
  77. package/dist/docx/inlineWrapperContent.d.ts +4 -4
  78. package/dist/docx/inlineWrapperContent.js +4 -4
  79. package/dist/docx/linkedSdtPreservation.d.ts +10 -0
  80. package/dist/docx/linkedSdtPreservation.js +37 -0
  81. package/dist/docx/metadataPrivacy.js +6 -1
  82. package/dist/docx/packageParts.js +9 -3
  83. package/dist/docx/paragraphParser.js +88 -67
  84. package/dist/docx/paragraphPropertySource.d.ts +22 -1
  85. package/dist/docx/paragraphPropertySource.js +109 -2
  86. package/dist/docx/parser.js +2 -1
  87. package/dist/docx/preservedRunContent.js +2 -1
  88. package/dist/docx/relsParser.js +26 -2
  89. package/dist/docx/removeHeaderFooterParts.js +17 -6
  90. package/dist/docx/rezip.d.ts +49 -5
  91. package/dist/docx/rezip.js +754 -235
  92. package/dist/docx/saveDiagnostics.d.ts +11 -0
  93. package/dist/docx/selectiveSave.d.ts +2 -1
  94. package/dist/docx/selectiveSave.js +42 -11
  95. package/dist/docx/selectiveXmlPatch.js +7 -5
  96. package/dist/docx/serializer/commentSerializer.d.ts +4 -1
  97. package/dist/docx/serializer/commentSerializer.js +7 -3
  98. package/dist/docx/serializer/documentSerializer.d.ts +9 -2
  99. package/dist/docx/serializer/documentSerializer.js +29 -10
  100. package/dist/docx/serializer/paragraphSerializer.js +207 -94
  101. package/dist/docx/server/applyDocxXmlPatchProposal.js +14 -9
  102. package/dist/docx/server/materializeYjsDocx.js +14 -6
  103. package/dist/docx/server/migrateYjsAttrSchema.js +17 -5
  104. package/dist/docx/storyBlockReplay.d.ts +21 -1
  105. package/dist/docx/storyBlockReplay.js +113 -9
  106. package/dist/docx/storyPlainText.d.ts +20 -0
  107. package/dist/docx/storyPlainText.js +23 -0
  108. package/dist/docx/structuralXmlPatch.js +10 -22
  109. package/dist/docx/styleParser.d.ts +5 -1
  110. package/dist/docx/styleParser.js +1 -1
  111. package/dist/docx/tableParser.d.ts +1 -8
  112. package/dist/docx/tableParser.js +1 -28
  113. package/dist/docx/textBoxParser.d.ts +1 -5
  114. package/dist/docx/textBoxParser.js +1 -20
  115. package/dist/docx/unzip.js +6 -1
  116. package/dist/i18n/messages/ar.gen.js +4 -0
  117. package/dist/i18n/messages/catalogs.gen.d.ts +68 -0
  118. package/dist/i18n/messages/catalogs.gen.js +68 -0
  119. package/dist/i18n/messages/cs.gen.js +4 -0
  120. package/dist/i18n/messages/de.gen.js +4 -0
  121. package/dist/i18n/messages/en.gen.js +4 -0
  122. package/dist/i18n/messages/es.gen.js +4 -0
  123. package/dist/i18n/messages/et.gen.js +4 -0
  124. package/dist/i18n/messages/fr.gen.js +4 -0
  125. package/dist/i18n/messages/he.gen.js +4 -0
  126. package/dist/i18n/messages/hi.gen.js +4 -0
  127. package/dist/i18n/messages/hu.gen.js +4 -0
  128. package/dist/i18n/messages/lt.gen.js +4 -0
  129. package/dist/i18n/messages/lv.gen.js +4 -0
  130. package/dist/i18n/messages/messages.gen.d.ts +4 -0
  131. package/dist/i18n/messages/pl.gen.js +4 -0
  132. package/dist/i18n/messages/pt-BR.gen.js +4 -0
  133. package/dist/i18n/messages/sk.gen.js +4 -0
  134. package/dist/i18n/messages/tr.gen.js +4 -0
  135. package/dist/i18n/messages/zh-CN.gen.js +4 -0
  136. package/dist/index.d.ts +2 -1
  137. package/dist/index.js +2 -1
  138. package/dist/internal/acceptedBlockProjection.d.ts +12 -0
  139. package/dist/internal/acceptedBlockProjection.js +45 -0
  140. package/dist/internal/revisionResolutionInline.js +25 -3
  141. package/dist/managers/DocumentLoaderManager.js +2 -1
  142. package/dist/markdown/escape.d.ts +3 -1
  143. package/dist/markdown/escape.js +9 -2
  144. package/dist/markdown/renderBlock.js +5 -120
  145. package/dist/markdown/renderParagraph.js +4 -2
  146. package/dist/markdown/renderRuns.d.ts +7 -1
  147. package/dist/markdown/renderRuns.js +33 -24
  148. package/dist/panel-layout.d.ts +11 -9
  149. package/dist/panel-layout.js +13 -9
  150. package/dist/prosemirror/addTrackedDeletionMark.d.ts +18 -0
  151. package/dist/prosemirror/addTrackedDeletionMark.js +87 -0
  152. package/dist/prosemirror/attrs/index.js +5 -0
  153. package/dist/prosemirror/canonicalCommands.d.ts +28 -4
  154. package/dist/prosemirror/canonicalCommands.js +11 -4
  155. package/dist/prosemirror/canonicalSelectionRange.d.ts +9 -0
  156. package/dist/prosemirror/canonicalSelectionRange.js +15 -0
  157. package/dist/prosemirror/clipboardIntent.d.ts +7 -0
  158. package/dist/prosemirror/clipboardIntent.js +9 -0
  159. package/dist/prosemirror/commands/comments.js +60 -35
  160. package/dist/prosemirror/commands/pageBreak.js +2 -2
  161. package/dist/prosemirror/commands/pastePlainText.js +2 -1
  162. package/dist/prosemirror/commands/propertyChangeScope.js +3 -6
  163. package/dist/prosemirror/commands/resolveParagraphProperties.js +22 -13
  164. package/dist/prosemirror/commentOps.js +15 -1
  165. package/dist/prosemirror/conversion/fromProseDoc.js +22 -3
  166. package/dist/prosemirror/conversion/hyphenTextCarriers.d.ts +8 -0
  167. package/dist/prosemirror/conversion/hyphenTextCarriers.js +8 -0
  168. package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -1
  169. package/dist/prosemirror/conversion/toProseDoc.js +124 -22
  170. package/dist/prosemirror/extensions/core/ParagraphExtension.js +61 -35
  171. package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +74 -25
  172. package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +11 -0
  173. package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +65 -29
  174. package/dist/prosemirror/extensions/marks/markUtils.js +11 -8
  175. package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +5 -2
  176. package/dist/prosemirror/fieldRepresentation.d.ts +8 -0
  177. package/dist/prosemirror/fieldRepresentation.js +18 -0
  178. package/dist/prosemirror/hyperlinkRemoval.d.ts +13 -1
  179. package/dist/prosemirror/hyperlinkRemoval.js +28 -9
  180. package/dist/prosemirror/insertOperations.js +2 -1
  181. package/dist/prosemirror/listNumbering.js +11 -5
  182. package/dist/prosemirror/noteReferenceOccurrenceId.d.ts +5 -0
  183. package/dist/prosemirror/noteReferenceOccurrenceId.js +5 -0
  184. package/dist/prosemirror/noteReferenceOccurrences.d.ts +21 -0
  185. package/dist/prosemirror/noteReferenceOccurrences.js +185 -0
  186. package/dist/prosemirror/noteReferenceReview.js +14 -1
  187. package/dist/prosemirror/paragraphPropertyCarry.d.ts +7 -1
  188. package/dist/prosemirror/paragraphPropertyCarry.js +8 -3
  189. package/dist/prosemirror/plugins/documentStyles.d.ts +4 -1
  190. package/dist/prosemirror/plugins/documentStyles.js +17 -10
  191. package/dist/prosemirror/plugins/suggestionMode.js +48 -48
  192. package/dist/prosemirror/preservedXmlReview.d.ts +6 -0
  193. package/dist/prosemirror/preservedXmlReview.js +35 -0
  194. package/dist/prosemirror/runFormattingFromMarks.js +2 -2
  195. package/dist/prosemirror/runFormattingReconciliation.js +5 -4
  196. package/dist/prosemirror/runPropertyChangeResolution.d.ts +8 -1
  197. package/dist/prosemirror/runPropertyChangeResolution.js +24 -2
  198. package/dist/prosemirror/runStyleFormatting.d.ts +3 -1
  199. package/dist/prosemirror/runStyleFormatting.js +3 -1
  200. package/dist/prosemirror/schema/marks.d.ts +1 -0
  201. package/dist/prosemirror/schema/nodes.d.ts +2 -0
  202. package/dist/prosemirror/styles/paragraphStyleCascade.js +4 -1
  203. package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +15 -15
  204. package/dist/prosemirror/styles/resolvedStyleAttrs.js +69 -28
  205. package/dist/prosemirror/textInput.d.ts +5 -1
  206. package/dist/prosemirror/textInput.js +3 -3
  207. package/dist/prosemirror/trackedRevisionPath.d.ts +5 -1
  208. package/dist/prosemirror/trackedRevisionPath.js +39 -1
  209. package/dist/prosemirror/validation.js +3 -5
  210. package/dist/prosemirror/yjsDocumentMetadata.d.ts +9 -3
  211. package/dist/prosemirror/yjsDocumentMetadata.js +37 -8
  212. package/dist/types/canonicalCapabilities.d.ts +201 -0
  213. package/dist/types/canonicalCapabilities.js +198 -0
  214. package/dist/types/canonicalComments.d.ts +51 -0
  215. package/dist/types/canonicalComments.js +0 -0
  216. package/dist/types/canonicalSave.d.ts +11 -0
  217. package/dist/types/canonicalSave.js +0 -0
  218. package/dist/types/canonicalSections.d.ts +12 -0
  219. package/dist/types/canonicalSections.js +0 -0
  220. package/dist/types/docxSerialization.d.ts +14 -0
  221. package/dist/types/docxSerialization.js +7 -0
  222. package/dist/utils/headingCollector.js +45 -4
  223. package/dist/utils/outlineDepth.d.ts +9 -0
  224. package/dist/utils/outlineDepth.js +9 -0
  225. package/package.json +4 -4
@@ -1,3 +1,4 @@
1
+ import { CanonicalGap } from "../types/canonicalCapabilities.js";
1
2
  import { HiddenEditorApi } from "./hiddenEditorApi.js";
2
3
  import { Transaction } from "prosemirror-state";
3
4
  import { EditorView } from "prosemirror-view";
@@ -9,7 +10,7 @@ type CanonicalStoryEditorOptions = {
9
10
  getApi: () => HiddenEditorApi | null;
10
11
  enabled: () => boolean;
11
12
  onSelectionChange: () => void;
12
- onRefusal: ((reason: string) => void) | undefined;
13
+ onRefusal: ((reason: string, gap: CanonicalGap) => void) | undefined;
13
14
  };
14
15
  /** Secondary views compile classified native input into the shared Document journal. */
15
16
  declare const createCanonicalStoryEditor: ({ story, getView, getApi, enabled, onRefusal, onSelectionChange }: CanonicalStoryEditorOptions) => {
@@ -18,14 +19,17 @@ declare const createCanonicalStoryEditor: ({ story, getView, getApi, enabled, on
18
19
  handleKeyDown: (view: EditorView, event: KeyboardEvent) => boolean;
19
20
  handleTextInput: (view: EditorView, from: number, to: number, text: string) => boolean;
20
21
  handleDOMEvents: {
22
+ keydown: (view: EditorView, event: KeyboardEvent) => boolean;
23
+ keyup: (view: EditorView, event: KeyboardEvent) => boolean;
24
+ mouseup: (view: EditorView) => boolean;
21
25
  beforeinput: (view: EditorView, event: InputEvent) => boolean;
22
26
  mousedown: (view: EditorView) => boolean;
23
27
  compositionstart: (view: EditorView) => boolean;
24
28
  compositionend: (view: EditorView) => boolean;
25
29
  input: (view: EditorView) => boolean;
26
30
  blur: (view: EditorView) => boolean;
27
- paste: (view: EditorView, event: Event) => boolean;
28
- cut: (view: EditorView, event: Event) => boolean;
31
+ paste: (view: EditorView, event: ClipboardEvent) => boolean;
32
+ cut: (view: EditorView, event: ClipboardEvent) => boolean;
29
33
  drop: (view: EditorView, event: Event) => boolean;
30
34
  };
31
35
  };
@@ -1,11 +1,16 @@
1
+ import { CANONICAL_GAP } from "../types/canonicalCapabilities.js";
1
2
  import { createCanonicalInputBoundary } from "./canonicalInput.js";
2
3
  import { CanonicalSessionError } from "./canonicalSession.js";
4
+ import { AllSelection, TextSelection } from "prosemirror-state";
3
5
  //#region src/controller/canonicalStoryEditor.ts
4
6
  /** Secondary views compile classified native input into the shared Document journal. */
5
7
  const createCanonicalStoryEditor = ({ story, getView, getApi, enabled, onRefusal, onSelectionChange }) => {
6
- const refuse = (message) => {
7
- if (onRefusal) onRefusal(message);
8
+ const refuse = (reason) => {
9
+ const gap = CANONICAL_GAP.dispatch;
10
+ const message = reason;
11
+ if (onRefusal) onRefusal(message, gap);
8
12
  else throw new CanonicalSessionError({
13
+ gap,
9
14
  message,
10
15
  reason: "refused"
11
16
  });
@@ -20,6 +25,17 @@ const createCanonicalStoryEditor = ({ story, getView, getApi, enabled, onRefusal
20
25
  if (accepted && !view.isDestroyed) onSelectionChange();
21
26
  return accepted;
22
27
  };
28
+ const syncNativeSelection = (view) => {
29
+ if (boundary.isComposing || view.composing) return;
30
+ const selection = view.dom.ownerDocument.getSelection();
31
+ if (!selection?.anchorNode || !selection.focusNode || !view.dom.contains(selection.anchorNode) || !view.dom.contains(selection.focusNode)) return;
32
+ const anchor = view.posAtDOM(selection.anchorNode, selection.anchorOffset);
33
+ const head = view.posAtDOM(selection.focusNode, selection.focusOffset);
34
+ if (view.state.selection instanceof AllSelection && Math.min(anchor, head) === 0 && Math.max(anchor, head) === view.state.doc.content.size) return;
35
+ if (anchor === view.state.selection.anchor && head === view.state.selection.head) return;
36
+ if (!view.state.doc.resolve(anchor).parent.inlineContent || !view.state.doc.resolve(head).parent.inlineContent) return;
37
+ view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, anchor, head)));
38
+ };
23
39
  const boundary = createCanonicalInputBoundary({
24
40
  breakUndoGroup: () => {
25
41
  getApi()?.updateCanonicalInputLifecycle("breakUndoGroup");
@@ -65,6 +81,15 @@ const createCanonicalStoryEditor = ({ story, getView, getApi, enabled, onRefusal
65
81
  handleKeyDown: (view, event) => enabled() && boundary.handleKeyDown(view, event),
66
82
  handleTextInput: (view, from, to, text) => enabled() && boundary.handleTextInput(view, from, to, text),
67
83
  handleDOMEvents: {
84
+ keydown: (view, event) => enabled() && boundary.handleDOMEvents.keydown(view, event),
85
+ keyup: (view, event) => {
86
+ if (enabled() && /^(?:Arrow|Home$|End$|Page)/u.test(event.key)) syncNativeSelection(view);
87
+ return false;
88
+ },
89
+ mouseup: (view) => {
90
+ if (enabled()) syncNativeSelection(view);
91
+ return false;
92
+ },
68
93
  beforeinput: (view, event) => enabled() && boundary.handleDOMEvents.beforeinput(view, event),
69
94
  mousedown: (view) => enabled() && boundary.handleDOMEvents.mousedown(view),
70
95
  compositionstart: (view) => enabled() && boundary.handleDOMEvents.compositionstart(view),
@@ -1,11 +1,17 @@
1
+ import { BUILT_IN_STYLE_NAME, createBuiltInStyleIndex } from "../docx/builtInStyles.js";
1
2
  import { getCachedNumberingMap, numberingLevelUsesBulletMarker } from "../docx/numberingParser.js";
2
3
  import { listRequestsForMarker } from "../prosemirror/listAutoformatMarkers.js";
4
+ import { CANONICAL_GAP } from "../types/canonicalCapabilities.js";
5
+ import { collectHeadings } from "../utils/headingCollector.js";
3
6
  import { CanonicalSessionError } from "./canonicalSession.js";
4
7
  import { Result } from "better-result";
5
- import { paragraphNumberingReference } from "@stll/docx-core/model";
8
+ import { headingOutlineLevel, paragraphNumberingReference } from "@stll/docx-core/model";
6
9
  import { OP_STORIES } from "@stll/docx-core/ops";
7
10
  //#region src/controller/canonicalStructure.ts
11
+ const DEFAULT_TOC_PAGE_WIDTH_TWIPS = 12240;
12
+ const DEFAULT_TOC_MARGIN_TWIPS = 1440;
8
13
  const refuse = (message) => Result.err(new CanonicalSessionError({
14
+ gap: CANONICAL_GAP.commands,
9
15
  message,
10
16
  reason: "refused"
11
17
  }));
@@ -84,6 +90,53 @@ const prepareCanonicalCommands = (session, state, commands) => {
84
90
  const intents = [];
85
91
  const paragraphs = selectedParagraphs(session, state);
86
92
  for (const command of commands) switch (command.type) {
93
+ case "generateTOC": {
94
+ const at = session.projection.addressAt(command.at);
95
+ if (at.isErr()) return at;
96
+ const definitions = session.document.package.styles;
97
+ const styles = createBuiltInStyleIndex(definitions?.styles ?? [], definitions?.docDefaults);
98
+ const headings = [];
99
+ for (const heading of collectHeadings(session.projection.doc, styles)) {
100
+ const address = session.projection.addressAt(heading.pmPos + 1);
101
+ if (address.isErr()) return address;
102
+ const outline = headingOutlineLevel(heading.level);
103
+ if (outline?.kind !== "heading") return refuse("A TOC heading has an invalid outline level.");
104
+ const styleId = styles.styleIdForTableOfContentsLevel(outline.level + 1);
105
+ headings.push({
106
+ blockId: address.value.blockId,
107
+ text: heading.text,
108
+ level: outline.level,
109
+ ...styleId === void 0 ? {} : { styleId }
110
+ });
111
+ }
112
+ if (headings.length === 0) break;
113
+ const titleStyleId = styles.styleIdForBuiltInName(BUILT_IN_STYLE_NAME.tocHeading);
114
+ const section = session.document.package.document.content.find((item) => item.type === "paragraph" && (item.sectionProperties?.pageWidth ?? 0) > 0);
115
+ const properties = section?.type === "paragraph" ? section.sectionProperties : void 0;
116
+ intents.push({
117
+ type: "generateTOC",
118
+ at: at.value,
119
+ title: command.title,
120
+ headings,
121
+ tabPosition: (properties?.pageWidth ?? DEFAULT_TOC_PAGE_WIDTH_TWIPS) - (properties?.marginLeft ?? DEFAULT_TOC_MARGIN_TWIPS) - (properties?.marginRight ?? DEFAULT_TOC_MARGIN_TWIPS),
122
+ ...titleStyleId === void 0 ? {} : { titleStyleId }
123
+ });
124
+ break;
125
+ }
126
+ case "setHyperlink":
127
+ case "removeHyperlink":
128
+ case "insertHyperlink": {
129
+ const from = session.projection.addressAt(command.from);
130
+ if (from.isErr()) return from;
131
+ const to = session.projection.addressAt(command.to);
132
+ if (to.isErr()) return to;
133
+ intents.push({
134
+ ...command,
135
+ from: from.value,
136
+ to: to.value
137
+ });
138
+ break;
139
+ }
87
140
  case "insertBreak": {
88
141
  const from = session.projection.addressAt(command.from);
89
142
  if (from.isErr()) return from;
@@ -233,7 +286,7 @@ const prepareCanonicalCommands = (session, state, commands) => {
233
286
  }
234
287
  default: return command;
235
288
  }
236
- return session.prepareIntents(state, intents);
289
+ return session.prepareIntents(state, { intents });
237
290
  };
238
291
  /** Rules compile their replacement and paragraph change as one atomic edit. */
239
292
  const prepareCanonicalAutoformat = (session, state, { from, to, text }) => {
@@ -254,7 +307,7 @@ const prepareCanonicalAutoformat = (session, state, { from, to, text }) => {
254
307
  const request = requests?.at(0);
255
308
  const styleId = `Heading${heading?.length ?? 1}`;
256
309
  if (request === void 0 && !session.hasStyle(styleId)) return void 0;
257
- return session.prepareIntents(state, [{
310
+ return session.prepareIntents(state, { intents: [{
258
311
  type: "replaceText",
259
312
  from: start,
260
313
  to: at.value,
@@ -263,7 +316,7 @@ const prepareCanonicalAutoformat = (session, state, { from, to, text }) => {
263
316
  type: "formatParagraph",
264
317
  at: start,
265
318
  patch: { styleId }
266
- } : numberingIntent(session, [source], request)]);
319
+ } : numberingIntent(session, [source], request)] });
267
320
  };
268
321
  //#endregion
269
322
  export { prepareCanonicalAutoformat, prepareCanonicalCommands };
@@ -0,0 +1,11 @@
1
+ import { DocumentOp, TextPosition } from "@stll/docx-core/ops";
2
+ //#region src/controller/canonicalTocSelection.d.ts
3
+ type TocSelectionMapping = {
4
+ at: TextPosition;
5
+ after: TextPosition;
6
+ ops: readonly DocumentOp[];
7
+ };
8
+ /** TOC insertion retains the selected text and maps its endpoints through the canonical split. */
9
+ declare const mapTocSelection: (point: TextPosition, { at, after, ops }: TocSelectionMapping) => TextPosition;
10
+ //#endregion
11
+ export { mapTocSelection };
@@ -0,0 +1,43 @@
1
+ import { panic } from "better-result";
2
+ import { DOCUMENT_OP_TYPES, SPLIT_HALVES, compareGaps, idKey, mapTocBookmarkPosition, sameStory } from "@stll/docx-core/ops";
3
+ //#region src/controller/canonicalTocSelection.ts
4
+ /** TOC insertion retains the selected text and maps its endpoints through the canonical split. */
5
+ const mapTocSelection = (point, { at, after, ops }) => {
6
+ if (!sameStory(point.story, at.story)) return point;
7
+ point = mapTocBookmarkPosition({
8
+ ...point,
9
+ zeroWidthBefore: point.zeroWidthBefore ?? 0
10
+ }, ops);
11
+ at = mapTocBookmarkPosition({
12
+ ...at,
13
+ zeroWidthBefore: at.zeroWidthBefore ?? 0
14
+ }, ops);
15
+ if (idKey(point.blockId) !== idKey(at.blockId)) return point;
16
+ const split = ops.find((op) => op.type === DOCUMENT_OP_TYPES.SPLIT_BLOCK);
17
+ if (split === void 0) return point;
18
+ if (point.offset === at.offset && (point.zeroWidthBefore ?? 0) === (at.zeroWidthBefore ?? 0)) return after;
19
+ if (split.type !== DOCUMENT_OP_TYPES.SPLIT_BLOCK || split.newHalf !== SPLIT_HALVES.FIRST) return panic("TOC insertion must retain its following paragraph identity.");
20
+ const pointGap = {
21
+ offset: point.offset,
22
+ zeroWidthBefore: point.zeroWidthBefore ?? 0
23
+ };
24
+ const splitGap = {
25
+ offset: split.at.offset,
26
+ zeroWidthBefore: split.at.zeroWidthBefore ?? 0
27
+ };
28
+ if (compareGaps(pointGap, splitGap) < 0) return {
29
+ ...point,
30
+ blockId: split.newBlockId
31
+ };
32
+ if (point.offset === split.at.offset) return {
33
+ ...point,
34
+ offset: 0,
35
+ zeroWidthBefore: pointGap.zeroWidthBefore - splitGap.zeroWidthBefore
36
+ };
37
+ return {
38
+ ...point,
39
+ offset: point.offset - split.at.offset
40
+ };
41
+ };
42
+ //#endregion
43
+ export { mapTocSelection };
@@ -1,5 +1,6 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
2
  import { DocxInput } from "../utils/docxInput.js";
3
+ import { FOLIO_DOCX_SERIALIZATION_MODE, FolioDocxSerializationMode, FolioGetDocxOptions } from "../types/docxSerialization.js";
3
4
  import { Layout } from "../layout-engine/types.js";
4
5
  import { FolioEditorEmitter } from "./folioEditorEvents.js";
5
6
  import { HiddenEditorApi } from "./hiddenEditorApi.js";
@@ -14,14 +15,6 @@ type FolioEditorDeps = {
14
15
  getDocumentIO?: () => FolioEditorDocumentIO;
15
16
  emitter: FolioEditorEmitter;
16
17
  };
17
- declare const FOLIO_DOCX_SERIALIZATION_MODE: Readonly<{
18
- readonly full: "full";
19
- readonly preferSelective: "prefer-selective";
20
- }>;
21
- type FolioDocxSerializationMode = (typeof FOLIO_DOCX_SERIALIZATION_MODE)[keyof typeof FOLIO_DOCX_SERIALIZATION_MODE];
22
- type FolioGetDocxOptions = {
23
- mode?: FolioDocxSerializationMode;
24
- };
25
18
  /**
26
19
  * Document lifecycle operations supplied by a host integration.
27
20
  *
@@ -45,4 +38,4 @@ type FolioEditor = HiddenEditorApi & {
45
38
  };
46
39
  declare const createFolioEditor: (deps: FolioEditorDeps) => FolioEditor;
47
40
  //#endregion
48
- export { FOLIO_DOCX_SERIALIZATION_MODE, FolioDocxSerializationMode, FolioEditor, FolioEditorDeps, FolioEditorDocumentIO, FolioGetDocxOptions, createFolioEditor };
41
+ export { FOLIO_DOCX_SERIALIZATION_MODE, type FolioDocxSerializationMode, FolioEditor, FolioEditorDeps, FolioEditorDocumentIO, type FolioGetDocxOptions, createFolioEditor };
@@ -1,9 +1,7 @@
1
+ import { CANONICAL_GAP } from "../types/canonicalCapabilities.js";
2
+ import { FOLIO_DOCX_SERIALIZATION_MODE } from "../types/docxSerialization.js";
1
3
  import { panic } from "better-result";
2
4
  //#region src/controller/folioEditor.ts
3
- const FOLIO_DOCX_SERIALIZATION_MODE = Object.freeze({
4
- full: "full",
5
- preferSelective: "prefer-selective"
6
- });
7
5
  const createFolioEditor = (deps) => {
8
6
  const getDocumentIO = () => deps.getDocumentIO?.() ?? panic("FolioEditor document I/O requires a getDocumentIO dependency");
9
7
  return {
@@ -17,10 +15,26 @@ const createFolioEditor = (deps) => {
17
15
  getDocument: () => deps.getEditorApi()?.getDocument() ?? null,
18
16
  updateCanonicalInputLifecycle: (action) => deps.getEditorApi()?.updateCanonicalInputLifecycle(action) ?? false,
19
17
  applyCanonicalStoryHistory: (options) => deps.getEditorApi()?.applyCanonicalStoryHistory(options) ?? false,
18
+ applyCanonicalComment: (request) => deps.getEditorApi()?.applyCanonicalComment(request) ?? null,
19
+ applyCanonicalSectionProperties: (patch) => {
20
+ const api = deps.getEditorApi();
21
+ if (!api) return {
22
+ status: "refused",
23
+ gap: CANONICAL_GAP.sectionProperties,
24
+ message: "The editor is not ready for section changes."
25
+ };
26
+ return api.applyCanonicalSectionProperties(patch);
27
+ },
20
28
  applyCanonicalOperations: (ops) => deps.getEditorApi()?.applyCanonicalOperations(ops) ?? false,
21
29
  getCanonicalStorySelection: (story) => deps.getEditorApi()?.getCanonicalStorySelection(story) ?? null,
22
30
  getCanonicalStoryProjection: (story) => deps.getEditorApi()?.getCanonicalStoryProjection(story) ?? null,
23
31
  replaceCanonicalStoryText: (options) => deps.getEditorApi()?.replaceCanonicalStoryText(options) ?? false,
32
+ isCanonicalSaveCurrent: (version) => deps.getEditorApi()?.isCanonicalSaveCurrent(version) ?? false,
33
+ captureCanonicalSave: () => deps.getEditorApi()?.captureCanonicalSave() ?? null,
34
+ applyCanonicalDocumentOperations: (options) => deps.getEditorApi()?.applyCanonicalDocumentOperations(options) ?? null,
35
+ undoCanonicalDocumentOperations: (handle) => deps.getEditorApi()?.undoCanonicalDocumentOperations(handle) ?? null,
36
+ getCanonicalComments: () => deps.getEditorApi()?.getCanonicalComments() ?? null,
37
+ getCanonicalCommittedVersion: () => deps.getEditorApi()?.getCanonicalCommittedVersion() ?? null,
24
38
  getCanonicalDocument: () => deps.getEditorApi()?.getCanonicalDocument() ?? null,
25
39
  setCanonicalMode: (mode) => deps.getEditorApi()?.setCanonicalMode(mode) ?? false,
26
40
  resolveCanonicalRevisions: (revisionIds, resolution) => deps.getEditorApi()?.resolveCanonicalRevisions(revisionIds, resolution) ?? false,
@@ -1,4 +1,5 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
+ import { CanonicalGap } from "../types/canonicalCapabilities.js";
2
3
  import { HiddenEditorApi } from "./hiddenEditorApi.js";
3
4
  import { DirectEditorProps, EditorView } from "prosemirror-view";
4
5
  //#region src/controller/headerFooterEditorManager.d.ts
@@ -19,7 +20,7 @@ type HeaderFooterEditorManagerDeps = {
19
20
  getDocument: () => document_d_exports.Document | null;
20
21
  getCanonicalApi?: (() => HiddenEditorApi | null) | undefined;
21
22
  getExperimentalSession?: (() => "canonical" | undefined) | undefined;
22
- onSessionRefusal?: ((reason: string) => void) | undefined;
23
+ onSessionRefusal?: ((reason: string, gap: CanonicalGap, error?: Error) => void) | undefined;
23
24
  getHost: () => HTMLElement | null;
24
25
  getStyles: () => document_d_exports.StyleDefinitions | null | undefined;
25
26
  getTheme: () => document_d_exports.Theme | null | undefined;
@@ -6,10 +6,13 @@ import { ExtensionManager } from "../prosemirror/extensions/ExtensionManager.js"
6
6
  import { createStarterKit } from "../prosemirror/extensions/StarterKit.js";
7
7
  import { ensureBaseDirectionInState } from "../prosemirror/extensions/features/AutoBidiDetectionExtension.js";
8
8
  import { ensureParaIdsInState } from "../prosemirror/extensions/features/ParaIdAllocatorExtension.js";
9
+ import { noteReferenceTransactionIssue } from "../prosemirror/noteReferenceOccurrences.js";
9
10
  import { createDocumentNumberingPlugin } from "../prosemirror/plugins/documentNumbering.js";
10
- import { createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
11
+ import { createDocumentStyleContextPlugin, createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
11
12
  import { schema } from "../prosemirror/schema/index.js";
12
13
  import { storyListNumbering } from "../prosemirror/storyListNumbering.js";
14
+ import { CANONICAL_GAP, usesCanonicalSession } from "../types/canonicalCapabilities.js";
15
+ import { CanonicalSessionError } from "./canonicalSession.js";
13
16
  import { createCanonicalStoryEditor } from "./canonicalStoryEditor.js";
14
17
  import { OP_STORIES } from "@stll/docx-core/ops";
15
18
  import { EditorState, TextSelection } from "prosemirror-state";
@@ -84,11 +87,12 @@ const createHeaderFooterEditorManager = (deps) => {
84
87
  for (const part of mounted.values()) destroyMounted(part);
85
88
  mounted.clear();
86
89
  };
90
+ const getOwnedDocument = () => usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting) ? deps.getCanonicalApi?.()?.getCanonicalDocument() ?? null : deps.getDocument();
87
91
  const sync = () => {
88
92
  const host = deps.getHost();
89
93
  if (!host) return;
90
- if (deps.getExperimentalSession?.() === "canonical" && !deps.getCanonicalApi?.()?.getCanonicalStoryProjection(OP_STORIES.MAIN)) return;
91
- const document = deps.getExperimentalSession?.() === "canonical" ? deps.getCanonicalApi?.()?.getCanonicalDocument() ?? deps.getDocument() : deps.getDocument();
94
+ if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting) && !deps.getCanonicalApi?.()?.getCanonicalStoryProjection(OP_STORIES.MAIN)) return;
95
+ const document = getOwnedDocument();
92
96
  const styles = deps.getStyles();
93
97
  const theme = deps.getTheme();
94
98
  const numbering = document?.package.numbering;
@@ -104,7 +108,7 @@ const createHeaderFooterEditorManager = (deps) => {
104
108
  const existing = mounted.get(part.rId);
105
109
  if (existing) {
106
110
  if (existing.mountNode.parentElement !== host) host.append(existing.mountNode);
107
- if (deps.getExperimentalSession?.() === "canonical") {
111
+ if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) {
108
112
  const projected = deps.getCanonicalApi?.()?.getCanonicalStoryProjection({
109
113
  kind: part.kind,
110
114
  rId: part.rId
@@ -154,7 +158,7 @@ const createHeaderFooterEditorManager = (deps) => {
154
158
  },
155
159
  getView: () => view,
156
160
  getApi: () => deps.getCanonicalApi?.() ?? null,
157
- enabled: () => deps.getExperimentalSession?.() === "canonical",
161
+ enabled: () => usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting),
158
162
  onRefusal: deps.onSessionRefusal,
159
163
  onSelectionChange: () => deps.onTransaction?.({
160
164
  kind: part.kind,
@@ -164,11 +168,11 @@ const createHeaderFooterEditorManager = (deps) => {
164
168
  selectionChanged: true
165
169
  })
166
170
  });
167
- const canonicalProjection = deps.getExperimentalSession?.() === "canonical" ? deps.getCanonicalApi?.()?.getCanonicalStoryProjection({
171
+ const canonicalProjection = usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting) ? deps.getCanonicalApi?.()?.getCanonicalStoryProjection({
168
172
  kind: part.kind,
169
173
  rId: part.rId
170
174
  }) : null;
171
- if (deps.getExperimentalSession?.() === "canonical" && !canonicalProjection) {
175
+ if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting) && !canonicalProjection) {
172
176
  manager.destroy();
173
177
  mountNode.remove();
174
178
  continue;
@@ -177,16 +181,19 @@ const createHeaderFooterEditorManager = (deps) => {
177
181
  ...canonical.props,
178
182
  state: canonicalProjection ? EditorState.create({
179
183
  doc: canonicalProjection,
180
- plugins: [createDocumentStylesPlugin(styles), createDocumentNumberingPlugin(numbering)]
184
+ plugins: [createDocumentStyleContextPlugin(styles), createDocumentNumberingPlugin(numbering)]
181
185
  }) : buildInitialState(headerFooter, styles, theme, numbering, manager),
182
186
  dispatchTransaction(transaction) {
183
187
  if (canonical.dispatch(transaction)) return;
184
188
  const nextState = view.state.apply(transaction);
189
+ const docChanged = !nextState.doc.eq(view.state.doc);
190
+ const noteIssue = noteReferenceTransactionIssue(transaction);
191
+ if (noteIssue) deps.onSessionRefusal?.(noteIssue.message, CANONICAL_GAP.dispatch, noteIssue);
185
192
  view.updateState(nextState);
186
193
  const mountedPart = mounted.get(part.rId);
187
- if (mountedPart && transaction.docChanged) mountedPart.dirty = true;
194
+ if (mountedPart && docChanged) mountedPart.dirty = true;
188
195
  deps.onTransaction?.({
189
- docChanged: transaction.docChanged,
196
+ docChanged,
190
197
  kind: part.kind,
191
198
  rId: part.rId,
192
199
  selectionChanged: transaction.selectionSet,
@@ -217,7 +224,15 @@ const createHeaderFooterEditorManager = (deps) => {
217
224
  rId
218
225
  })),
219
226
  snapshotDocument: (document) => {
220
- if (deps.getExperimentalSession?.() === "canonical") return deps.getCanonicalApi?.()?.getCanonicalDocument() ?? document;
227
+ if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) {
228
+ const canonical = deps.getCanonicalApi?.()?.getCanonicalDocument();
229
+ if (canonical) return canonical;
230
+ throw new CanonicalSessionError({
231
+ gap: CANONICAL_GAP.authorityRouting,
232
+ reason: "refused",
233
+ message: "Canonical story snapshot is unavailable."
234
+ });
235
+ }
221
236
  let headers = document.package.headers;
222
237
  let footers = document.package.footers;
223
238
  let headersChanged = false;
@@ -1,10 +1,16 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
- import { createCanonicalInputBoundary } from "./canonicalInput.js";
2
+ import { FolioDocumentOperationResult, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult } from "../document-operations.js";
3
+ import { Comment } from "../types/content.js";
4
+ import { CanonicalSaveSnapshot } from "../types/canonicalSave.js";
3
5
  import { CanonicalSessionMode } from "./canonicalSession.js";
6
+ import { createCanonicalInputBoundary } from "./canonicalInput.js";
7
+ import { CanonicalPublicOperationOptions } from "./canonicalPublicOperations.js";
8
+ import { CanonicalSectionPropertiesResult } from "../types/canonicalSections.js";
9
+ import { CanonicalCommentRequest, CanonicalCommentResult } from "../types/canonicalComments.js";
4
10
  import { Node } from "prosemirror-model";
5
11
  import { Command, EditorState, Transaction } from "prosemirror-state";
6
12
  import { EditorView } from "prosemirror-view";
7
- import { DocumentOp, OpStory } from "@stll/docx-core/ops";
13
+ import { DocumentOp, FormattingPatch, OpStory } from "@stll/docx-core/ops";
8
14
  //#region src/controller/hiddenEditorApi.d.ts
9
15
  type CanonicalStoryHistoryOptions = {
10
16
  view: EditorView;
@@ -28,7 +34,13 @@ type HiddenEditorApi = {
28
34
  /** Get the current Document from PM state */
29
35
  getDocument: () => document_d_exports.Document | null;
30
36
  /** Canonical snapshot, or null in the default session. */
37
+ getCanonicalComments: () => Comment[] | null;
38
+ /** Committed session/version identity; safe during provisional composition. */
39
+ getCanonicalCommittedVersion: () => string | null;
31
40
  getCanonicalDocument: () => document_d_exports.Document | null;
41
+ captureCanonicalSave: () => CanonicalSaveSnapshot | null;
42
+ /** A save cannot acknowledge newer edits or an unfinished composition. */
43
+ isCanonicalSaveCurrent: (version: number) => boolean;
32
44
  /** Set the explicit mode for an active canonical session. */
33
45
  setCanonicalMode: (mode: CanonicalSessionMode) => boolean;
34
46
  /** Resolve canonical revisions as one batch and journal its exact inverse. */
@@ -36,12 +48,17 @@ type HiddenEditorApi = {
36
48
  updateCanonicalInputLifecycle: (action: "beginComposition" | "endComposition" | "breakUndoGroup") => boolean;
37
49
  applyCanonicalStoryHistory: (options: CanonicalStoryHistoryOptions) => boolean;
38
50
  applyCanonicalOperations: (ops: readonly DocumentOp[]) => boolean;
51
+ applyCanonicalComment: (request: CanonicalCommentRequest) => CanonicalCommentResult | null;
52
+ /** Apply a final-section patch; null is reserved for default sessions. */
53
+ applyCanonicalSectionProperties: (patch: FormattingPatch<document_d_exports.SectionProperties>) => CanonicalSectionPropertiesResult | null;
39
54
  getCanonicalStorySelection: (story: OpStory) => {
40
55
  anchor: number;
41
56
  head: number;
42
57
  } | null;
43
58
  getCanonicalStoryProjection: (story: OpStory) => Node | null;
44
59
  replaceCanonicalStoryText: (options: CanonicalStoryTextOptions) => boolean;
60
+ applyCanonicalDocumentOperations: (options: CanonicalPublicOperationOptions) => FolioDocumentOperationResult | null;
61
+ undoCanonicalDocumentOperations: (handle: FolioDocumentOperationUndoHandle) => FolioDocumentOperationUndoResult | null;
45
62
  /** Focus the hidden editor */
46
63
  focus: () => void;
47
64
  /** Blur the hidden editor */
@@ -72,12 +89,16 @@ type HiddenEditorApi = {
72
89
  type HiddenEditorApiDeps = {
73
90
  getView: () => EditorView | null;
74
91
  getDocumentContext: () => document_d_exports.Document | null;
92
+ getCanonicalComments?: () => Comment[] | null;
93
+ getCanonicalCommittedVersion?: HiddenEditorApi["getCanonicalCommittedVersion"];
75
94
  getCanonicalDocument?: () => document_d_exports.Document | null;
95
+ captureCanonicalSave?: HiddenEditorApi["captureCanonicalSave"];
96
+ isCanonicalSaveCurrent?: HiddenEditorApi["isCanonicalSaveCurrent"];
76
97
  setCanonicalMode?: HiddenEditorApi["setCanonicalMode"];
77
98
  resolveCanonicalRevisions?: HiddenEditorApi["resolveCanonicalRevisions"];
78
99
  executeCanonicalCommand?: (command: Command) => boolean | undefined;
79
100
  getCanonicalHistory?: () => Pick<HiddenEditorApi, "undo" | "redo" | "canUndo" | "canRedo"> | null;
80
- canonicalOperations?: Pick<HiddenEditorApi, "updateCanonicalInputLifecycle" | "applyCanonicalOperations" | "getCanonicalStoryProjection" | "replaceCanonicalStoryText" | "applyCanonicalStoryHistory" | "getCanonicalStorySelection">;
101
+ canonicalOperations?: Pick<HiddenEditorApi, "updateCanonicalInputLifecycle" | "applyCanonicalOperations" | "applyCanonicalComment" | "applyCanonicalSectionProperties" | "getCanonicalStoryProjection" | "replaceCanonicalStoryText" | "applyCanonicalStoryHistory" | "getCanonicalStorySelection" | "applyCanonicalDocumentOperations" | "undoCanonicalDocumentOperations">;
81
102
  isDestroying: () => boolean;
82
103
  ensureView: () => void;
83
104
  isViewRequested: () => boolean;
@@ -34,6 +34,10 @@ const createHiddenEditorApi = (deps) => {
34
34
  getView: () => deps.getView() ?? null,
35
35
  setCanonicalMode: (mode) => !deps.isDestroying() && (deps.setCanonicalMode?.(mode) ?? false),
36
36
  resolveCanonicalRevisions: (revisionIds, resolution) => !deps.isDestroying() && (deps.resolveCanonicalRevisions?.(revisionIds, resolution) ?? false),
37
+ getCanonicalComments: () => deps.getCanonicalComments?.() ?? null,
38
+ getCanonicalCommittedVersion: () => deps.getCanonicalCommittedVersion?.() ?? null,
39
+ captureCanonicalSave: () => deps.captureCanonicalSave?.() ?? null,
40
+ isCanonicalSaveCurrent: (version) => deps.isCanonicalSaveCurrent?.(version) ?? false,
37
41
  getCanonicalDocument: () => {
38
42
  const canonical = deps.getCanonicalDocument?.();
39
43
  return canonical ? cloneDocumentWithParagraphPropertySources(canonical) : null;
@@ -47,10 +51,14 @@ const createHiddenEditorApi = (deps) => {
47
51
  },
48
52
  updateCanonicalInputLifecycle: (action) => deps.canonicalOperations?.updateCanonicalInputLifecycle(action) ?? false,
49
53
  applyCanonicalStoryHistory: (options) => deps.canonicalOperations?.applyCanonicalStoryHistory(options) ?? false,
54
+ applyCanonicalComment: (request) => deps.canonicalOperations?.applyCanonicalComment(request) ?? null,
55
+ applyCanonicalSectionProperties: (patch) => deps.canonicalOperations?.applyCanonicalSectionProperties(patch) ?? null,
50
56
  applyCanonicalOperations: (ops) => deps.canonicalOperations?.applyCanonicalOperations(ops) ?? false,
51
57
  getCanonicalStorySelection: (story) => deps.canonicalOperations?.getCanonicalStorySelection(story) ?? null,
52
58
  getCanonicalStoryProjection: (story) => deps.canonicalOperations?.getCanonicalStoryProjection(story) ?? null,
53
59
  replaceCanonicalStoryText: (options) => deps.canonicalOperations?.replaceCanonicalStoryText(options) ?? false,
60
+ applyCanonicalDocumentOperations: (options) => deps.canonicalOperations?.applyCanonicalDocumentOperations(options) ?? null,
61
+ undoCanonicalDocumentOperations: (handle) => deps.canonicalOperations?.undoCanonicalDocumentOperations(handle) ?? null,
54
62
  focus: () => {
55
63
  const view = deps.getView();
56
64
  if (!view || view.hasFocus()) return;
@@ -1,4 +1,5 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
+ import { CanonicalGap } from "../types/canonicalCapabilities.js";
2
3
  import { HiddenEditorApi } from "./hiddenEditorApi.js";
3
4
  import { HiddenEditorStateReason } from "../layout-engine/layoutInstrumentation.js";
4
5
  import { ExtensionManager } from "../prosemirror/extensions/ExtensionManager.js";
@@ -12,6 +13,7 @@ import * as YProseMirror from "y-prosemirror";
12
13
  //#region src/controller/hiddenEditorManager.d.ts
13
14
  declare const CanonicalSessionRefusalError_base: import("better-result").TaggedErrorClass<"CanonicalSessionRefusalError">;
14
15
  declare class CanonicalSessionRefusalError extends CanonicalSessionRefusalError_base<{
16
+ gap: CanonicalGap;
15
17
  message: string;
16
18
  }> {}
17
19
  type YProseMirrorModule = typeof YProseMirror;
@@ -63,7 +65,7 @@ type HiddenEditorManagerDeps = {
63
65
  getExperimentalSession?: () => "canonical" | undefined;
64
66
  getEditingMode?: () => EditorMode;
65
67
  getSuggestionAuthor?: () => string;
66
- onSessionRefusal?: (reason: string) => void;
68
+ onSessionRefusal?: (reason: string, gap: CanonicalGap, error?: Error) => void;
67
69
  /**
68
70
  * Identity of the loaded document as tracked by the adapter's loader: the
69
71
  * same value across internal edits (so typing does not trigger an external
@@ -97,6 +99,8 @@ declare const createHiddenEditorClipboardHandlers: (deps: Pick<HiddenEditorManag
97
99
  paste: (_view: unknown, event: PreventableDomEvent) => boolean;
98
100
  };
99
101
  type HiddenEditorManager = {
102
+ /** Whether the canonical owner still holds a provisional composition. */
103
+ isCanonicalComposing: () => boolean;
100
104
  /** Request the view (sets the requested flag, then attempts creation). */
101
105
  ensureView: () => void;
102
106
  /** Re-attempt a previously-requested-but-deferred creation (no-op otherwise). */