@stll/folio-core 0.54.2 → 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 (199) hide show
  1. package/dist/ai-edits/apply.js +22 -1
  2. package/dist/ai-edits/headless.js +1 -0
  3. package/dist/compare/content-types.d.ts +3 -15
  4. package/dist/controller/canonicalComposition.d.ts +36 -0
  5. package/dist/controller/canonicalComposition.js +168 -0
  6. package/dist/controller/canonicalInput.d.ts +45 -0
  7. package/dist/controller/canonicalInput.js +338 -0
  8. package/dist/controller/canonicalOperations.d.ts +22 -0
  9. package/dist/controller/canonicalOperations.js +85 -0
  10. package/dist/controller/canonicalReview.d.ts +12 -0
  11. package/dist/controller/canonicalReview.js +19 -0
  12. package/dist/controller/canonicalSession.d.ts +149 -0
  13. package/dist/controller/canonicalSession.js +1038 -0
  14. package/dist/controller/canonicalStoryEditor.d.ts +34 -0
  15. package/dist/controller/canonicalStoryEditor.js +82 -0
  16. package/dist/controller/canonicalStructure.d.ts +16 -0
  17. package/dist/controller/canonicalStructure.js +269 -0
  18. package/dist/controller/folioEditor.d.ts +1 -1
  19. package/dist/controller/folioEditor.js +9 -0
  20. package/dist/controller/headerFooterEditorManager.d.ts +4 -0
  21. package/dist/controller/headerFooterEditorManager.js +71 -3
  22. package/dist/controller/hiddenEditorApi.d.ts +35 -0
  23. package/dist/controller/hiddenEditorApi.js +25 -8
  24. package/dist/controller/hiddenEditorManager.d.ts +11 -2
  25. package/dist/controller/hiddenEditorManager.js +456 -30
  26. package/dist/controller/layoutPipeline.d.ts +1 -1
  27. package/dist/controller/layoutPipeline.js +2 -0
  28. package/dist/controller/noteEditorManager.d.ts +4 -0
  29. package/dist/controller/noteEditorManager.js +113 -15
  30. package/dist/docx/attributeRemainder.js +1 -0
  31. package/dist/docx/canonicalSessionInput.d.ts +11 -0
  32. package/dist/docx/canonicalSessionInput.js +27 -0
  33. package/dist/docx/canonicalStoryRepack.d.ts +10 -0
  34. package/dist/docx/canonicalStoryRepack.js +41 -0
  35. package/dist/docx/contentTypeRegistry.d.ts +8 -0
  36. package/dist/docx/contentTypeRegistry.js +64 -0
  37. package/dist/docx/ensureParaIds.d.ts +7 -1
  38. package/dist/docx/ensureParaIds.js +163 -211
  39. package/dist/docx/foldedListNumberFields.d.ts +85 -0
  40. package/dist/docx/foldedListNumberFields.js +267 -0
  41. package/dist/docx/headerFooterVerbatim.d.ts +14 -1
  42. package/dist/docx/headerFooterVerbatim.js +95 -2
  43. package/dist/docx/noteIds.d.ts +5 -0
  44. package/dist/docx/noteIds.js +6 -2
  45. package/dist/docx/noteReferenceMark.d.ts +3 -1
  46. package/dist/docx/noteReferenceMark.js +15 -14
  47. package/dist/docx/numberingParser.d.ts +3 -1
  48. package/dist/docx/numberingParser.js +17 -3
  49. package/dist/docx/packageParts.d.ts +3 -1
  50. package/dist/docx/packageParts.js +65 -16
  51. package/dist/docx/paragraphMarkPropertyPresence.d.ts +9 -0
  52. package/dist/docx/paragraphMarkPropertyPresence.js +21 -0
  53. package/dist/docx/paragraphParser.js +101 -53
  54. package/dist/docx/paragraphPropertySource.d.ts +15 -1
  55. package/dist/docx/paragraphPropertySource.js +76 -22
  56. package/dist/docx/parser.js +2 -1
  57. package/dist/docx/reviewHistoryNamespace.d.ts +4 -0
  58. package/dist/docx/reviewHistoryNamespace.js +4 -0
  59. package/dist/docx/reviewResolutionProvenance.d.ts +25 -0
  60. package/dist/docx/reviewResolutionProvenance.js +153 -0
  61. package/dist/docx/rezip.d.ts +7 -3
  62. package/dist/docx/rezip.js +107 -45
  63. package/dist/docx/runConsolidator.d.ts +2 -58
  64. package/dist/docx/runConsolidator.js +3 -175
  65. package/dist/docx/runParser.d.ts +2 -1
  66. package/dist/docx/runParser.js +156 -116
  67. package/dist/docx/saveDiagnostics.d.ts +11 -0
  68. package/dist/docx/saveDiagnostics.js +0 -0
  69. package/dist/docx/selectiveSave.d.ts +2 -1
  70. package/dist/docx/selectiveSave.js +4 -1
  71. package/dist/docx/selectiveXmlPatch.d.ts +16 -8
  72. package/dist/docx/selectiveXmlPatch.js +74 -2
  73. package/dist/docx/serializer/headerFooterSerializer.d.ts +5 -1
  74. package/dist/docx/serializer/headerFooterSerializer.js +19 -11
  75. package/dist/docx/serializer/noteSerializer.d.ts +2 -2
  76. package/dist/docx/serializer/noteSerializer.js +24 -8
  77. package/dist/docx/serializer/paragraphSerializer.js +41 -4
  78. package/dist/docx/serializer/partNamespaces.js +2 -1
  79. package/dist/docx/serializer/runSerializer.js +3 -1
  80. package/dist/docx/settingsHeaderFooterUpdate.d.ts +5 -0
  81. package/dist/docx/settingsHeaderFooterUpdate.js +90 -0
  82. package/dist/docx/settingsParser.d.ts +1 -2
  83. package/dist/docx/settingsParser.js +5 -6
  84. package/dist/docx/storyBlockReplay.d.ts +11 -0
  85. package/dist/docx/storyBlockReplay.js +367 -0
  86. package/dist/docx/streamingXmlParser.d.ts +22 -1
  87. package/dist/docx/streamingXmlParser.js +49 -3
  88. package/dist/docx/structuralXmlPatch.js +8 -1
  89. package/dist/docx/verbatimCapture.d.ts +3 -1
  90. package/dist/docx/verbatimCapture.js +49 -6
  91. package/dist/i18n/messages/ar.gen.d.ts +5 -0
  92. package/dist/i18n/messages/ar.gen.js +656 -0
  93. package/dist/i18n/messages/cs.gen.d.ts +5 -0
  94. package/dist/i18n/messages/cs.gen.js +656 -0
  95. package/dist/i18n/messages/de.gen.d.ts +5 -0
  96. package/dist/i18n/messages/de.gen.js +656 -0
  97. package/dist/i18n/messages/en.gen.d.ts +5 -0
  98. package/dist/i18n/messages/en.gen.js +656 -0
  99. package/dist/i18n/messages/es.gen.d.ts +5 -0
  100. package/dist/i18n/messages/es.gen.js +656 -0
  101. package/dist/i18n/messages/et.gen.d.ts +5 -0
  102. package/dist/i18n/messages/et.gen.js +656 -0
  103. package/dist/i18n/messages/fr.gen.d.ts +5 -0
  104. package/dist/i18n/messages/fr.gen.js +656 -0
  105. package/dist/i18n/messages/he.gen.d.ts +5 -0
  106. package/dist/i18n/messages/he.gen.js +656 -0
  107. package/dist/i18n/messages/hi.gen.d.ts +5 -0
  108. package/dist/i18n/messages/hi.gen.js +656 -0
  109. package/dist/i18n/messages/hu.gen.d.ts +5 -0
  110. package/dist/i18n/messages/hu.gen.js +656 -0
  111. package/dist/i18n/messages/locales.d.ts +5 -0
  112. package/dist/i18n/messages/locales.js +22 -0
  113. package/dist/i18n/messages/lt.gen.d.ts +5 -0
  114. package/dist/i18n/messages/lt.gen.js +656 -0
  115. package/dist/i18n/messages/lv.gen.d.ts +5 -0
  116. package/dist/i18n/messages/lv.gen.js +656 -0
  117. package/dist/i18n/messages/pl.gen.d.ts +5 -0
  118. package/dist/i18n/messages/pl.gen.js +656 -0
  119. package/dist/i18n/messages/pt-BR.gen.d.ts +5 -0
  120. package/dist/i18n/messages/pt-BR.gen.js +656 -0
  121. package/dist/i18n/messages/sk.gen.d.ts +5 -0
  122. package/dist/i18n/messages/sk.gen.js +656 -0
  123. package/dist/i18n/messages/tr.gen.d.ts +5 -0
  124. package/dist/i18n/messages/tr.gen.js +656 -0
  125. package/dist/i18n/messages/zh-CN.gen.d.ts +5 -0
  126. package/dist/i18n/messages/zh-CN.gen.js +656 -0
  127. package/dist/i18n/messages.d.ts +2 -3
  128. package/dist/i18n/messages.js +1 -19
  129. package/dist/internal/noteMarkerAttrs.d.ts +8 -0
  130. package/dist/internal/noteMarkerAttrs.js +16 -0
  131. package/dist/internal/pageBreakRunSourceDescendantIndex.js +1 -0
  132. package/dist/internal/prosemirrorAttrBoundary.d.ts +21 -0
  133. package/dist/internal/prosemirrorAttrBoundary.js +50 -0
  134. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  135. package/dist/layout-bridge/convert/footnoteLayout.js +3 -3
  136. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  137. package/dist/layout-bridge/convert/headerFooterLayout.js +1 -0
  138. package/dist/layout-bridge/convert/noteReferences.d.ts +1 -3
  139. package/dist/layout-bridge/convert/noteReferences.js +1 -6
  140. package/dist/layout-bridge/convert/paragraphRuns.js +2 -4
  141. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +2 -2
  142. package/dist/layout-bridge/convert/toFlowBlocks.js +2 -2
  143. package/dist/managers/DocumentLoaderManager.d.ts +1 -0
  144. package/dist/managers/DocumentLoaderManager.js +8 -1
  145. package/dist/markdown/renderBlock.js +15 -1
  146. package/dist/markdown/renderParagraph.js +9 -13
  147. package/dist/markdown/renderRuns.js +3 -2
  148. package/dist/markdown/renderTable.js +2 -0
  149. package/dist/markdown/types.d.ts +3 -9
  150. package/dist/prosemirror/attrs/index.d.ts +2 -12
  151. package/dist/prosemirror/attrs/index.js +22 -48
  152. package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +2 -1
  153. package/dist/prosemirror/canonicalCommands.d.ts +97 -0
  154. package/dist/prosemirror/canonicalCommands.js +28 -0
  155. package/dist/prosemirror/commands/pageBreak.js +15 -1
  156. package/dist/prosemirror/commentReferenceAttrs.d.ts +2 -1
  157. package/dist/prosemirror/conversion/fromProseDoc.js +91 -19
  158. package/dist/prosemirror/conversion/listRenderingDefinition.d.ts +6 -0
  159. package/dist/prosemirror/conversion/listRenderingDefinition.js +97 -0
  160. package/dist/prosemirror/conversion/toProseDoc.d.ts +4 -3
  161. package/dist/prosemirror/conversion/toProseDoc.js +51 -11
  162. package/dist/prosemirror/executeEditorCommand.d.ts +11 -0
  163. package/dist/prosemirror/executeEditorCommand.js +26 -0
  164. package/dist/prosemirror/extensions/StarterKit.js +2 -0
  165. package/dist/prosemirror/extensions/core/ParagraphExtension.js +50 -19
  166. package/dist/prosemirror/extensions/features/ListExtension.js +18 -5
  167. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +5 -2
  168. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +13 -1
  169. package/dist/prosemirror/extensions/marks/TextColorExtension.js +3 -2
  170. package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +2 -0
  171. package/dist/prosemirror/extensions/marks/markUtils.js +70 -8
  172. package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.d.ts +6 -0
  173. package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.js +36 -0
  174. package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.js +4 -2
  175. package/dist/prosemirror/listMarker.d.ts +1 -0
  176. package/dist/prosemirror/listMarker.js +16 -7
  177. package/dist/prosemirror/listNumbering.js +26 -5
  178. package/dist/prosemirror/listRenderingAttrs.d.ts +1 -0
  179. package/dist/prosemirror/listRenderingAttrs.js +3 -0
  180. package/dist/prosemirror/markupViewNotes.js +3 -2
  181. package/dist/prosemirror/moveRangeBoundaryAttrs.d.ts +2 -1
  182. package/dist/prosemirror/noteReferenceReview.js +5 -3
  183. package/dist/prosemirror/plugins/suggestionMode.js +50 -2
  184. package/dist/prosemirror/rangeAnchorAttrs.d.ts +2 -1
  185. package/dist/prosemirror/runFormattingFromMarks.d.ts +4 -1
  186. package/dist/prosemirror/runFormattingFromMarks.js +15 -1
  187. package/dist/prosemirror/runFormattingInlineCarriers.d.ts +2 -1
  188. package/dist/prosemirror/runFormattingInlineCarriers.js +4 -1
  189. package/dist/prosemirror/schema/marks.d.ts +2 -0
  190. package/dist/prosemirror/schema/nodes.d.ts +10 -2
  191. package/dist/prosemirror/textBoxAnchorAttrs.d.ts +2 -1
  192. package/dist/prosemirror/textInput.js +5 -1
  193. package/dist/prosemirror/trackedRevisionPath.js +2 -1
  194. package/dist/prosemirror/trackedRunInlineAtoms.d.ts +1 -0
  195. package/dist/prosemirror/trackedRunInlineAtoms.js +1 -0
  196. package/dist/prosemirror/validation.js +4 -0
  197. package/dist/types/content.d.ts +2 -2
  198. package/dist/utils/createDocument.js +2 -2
  199. package/package.json +14 -2
@@ -1,30 +1,28 @@
1
1
  import { recordHiddenEditorPhase, recordHiddenEditorStateCreate } from "../layout-engine/layoutInstrumentation.js";
2
2
  import { suppressHiddenEditorScrollToSelection } from "../paged-layout/hiddenEditorScroll.js";
3
3
  import { isReadOnlyEditKey } from "../paged-layout/readOnlyEditAttempt.js";
4
+ import { getCanonicalCommandIntents } from "../prosemirror/canonicalCommands.js";
4
5
  import { createEmptyDoc, toProseDoc } from "../prosemirror/conversion/toProseDoc.js";
6
+ import { registerEditorCommandOwner } from "../prosemirror/executeEditorCommand.js";
5
7
  import { ensureBaseDirectionInState } from "../prosemirror/extensions/features/AutoBidiDetectionExtension.js";
6
8
  import { ensureParaIdsInDoc, ensureParaIdsInState } from "../prosemirror/extensions/features/ParaIdAllocatorExtension.js";
9
+ import { createParagraphChangeTrackerPlugin, markPackageChange } from "../prosemirror/extensions/features/ParagraphChangeTrackerExtension.js";
10
+ import { toggleMarkForAllScripts, toggleUnderlineMark } from "../prosemirror/extensions/marks/markUtils.js";
7
11
  import { createDocumentNumberingPlugin } from "../prosemirror/plugins/documentNumbering.js";
8
12
  import { createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
9
13
  import { schema } from "../prosemirror/schema/index.js";
10
14
  import { createTextInputPlugin } from "../prosemirror/textInput.js";
11
15
  import { applyAttrSchemaMigrations, proseDocumentParagraphSourceContract, readYjsAttrSchemaVersion, readYjsParagraphSourceContract, withParagraphSourceContract, writeYjsDocumentMetadata } from "../prosemirror/yjsDocumentMetadata.js";
16
+ import { createCanonicalInputBoundary } from "./canonicalInput.js";
17
+ import { createCanonicalSession, publishCanonicalProjection } from "./canonicalSession.js";
18
+ import { prepareCanonicalAutoformat, prepareCanonicalCommands } from "./canonicalStructure.js";
12
19
  import { createHiddenEditorApi } from "./hiddenEditorApi.js";
13
- import { panic } from "better-result";
20
+ import { Result, TaggedError, panic } from "better-result";
21
+ import { OP_STORIES } from "@stll/docx-core/ops";
14
22
  import { EditorState } from "prosemirror-state";
15
23
  import { EditorView } from "prosemirror-view";
16
24
  //#region src/controller/hiddenEditorManager.ts
17
- /**
18
- * Hidden-editor view lifecycle manager
19
- *
20
- * Framework-agnostic owner of the off-screen ProseMirror EditorView. Holds the
21
- * view plus the bookkeeping that decides when an incoming document is a truly
22
- * external change (vs. an internal edit echoed back through props), builds the
23
- * editor state and `editorProps`, and composes the slice-2a imperative API so
24
- * the API and the lifecycle share one view owner. The React adapter
25
- * (`HiddenProseMirror`) keeps the input refs and its effects (which decide
26
- * *when* to act) and drives this manager through the methods below.
27
- */
25
+ var CanonicalSessionRefusalError = class extends TaggedError("CanonicalSessionRefusalError") {};
28
26
  const normalizeSeedState = (state) => ensureBaseDirectionInState(ensureParaIdsInState(state));
29
27
  const normalizeLocalSeedState = (state) => ensureBaseDirectionInState(state);
30
28
  const isObjectRecord = (value) => typeof value === "object" && value !== null;
@@ -201,6 +199,260 @@ const createHiddenEditorClipboardHandlers = (deps) => ({
201
199
  });
202
200
  const createHiddenEditorManager = (deps) => {
203
201
  let view = null;
202
+ let releaseCommandOwner;
203
+ let editorSession = { type: "prosemirror" };
204
+ let modeOverride = null;
205
+ const syncCanonicalMode = () => {
206
+ if (editorSession.type !== "canonical") return;
207
+ editorSession.session.setMode(modeOverride ?? (deps.getEditingMode?.() === "suggesting" ? {
208
+ type: "suggesting",
209
+ author: deps.getSuggestionAuthor?.() ?? "User"
210
+ } : { type: "editing" }));
211
+ };
212
+ const refuse = (reason) => {
213
+ if (deps.onSessionRefusal) deps.onSessionRefusal(reason);
214
+ else throw new CanonicalSessionRefusalError({ message: reason });
215
+ };
216
+ const seedSession = (document) => {
217
+ if (deps.getExperimentalSession?.() !== "canonical") {
218
+ editorSession = { type: "prosemirror" };
219
+ return true;
220
+ }
221
+ const documentIdentity = deps.getDocumentIdentity();
222
+ if (editorSession.type === "refused" && editorSession.documentIdentity === documentIdentity) return false;
223
+ if (deps.getCollaboration() || !document) {
224
+ const reason = deps.getCollaboration() ? "Canonical sessions do not support collaboration." : "Canonical sessions require a loaded Document.";
225
+ editorSession = {
226
+ type: "refused",
227
+ reason,
228
+ documentIdentity
229
+ };
230
+ refuse(reason);
231
+ return false;
232
+ }
233
+ const result = createCanonicalSession(document, deps.getStyles());
234
+ if (result.isErr()) {
235
+ editorSession = {
236
+ type: "refused",
237
+ reason: result.error.message,
238
+ documentIdentity
239
+ };
240
+ refuse(result.error.message);
241
+ return false;
242
+ }
243
+ editorSession = {
244
+ type: "canonical",
245
+ session: result.value
246
+ };
247
+ modeOverride = null;
248
+ syncCanonicalMode();
249
+ return true;
250
+ };
251
+ const canonicalState = (session) => EditorState.create({
252
+ doc: session.projection.doc,
253
+ plugins: [
254
+ createParagraphChangeTrackerPlugin(),
255
+ createDocumentStylesPlugin(deps.getStyles() ?? session.document.package.styles),
256
+ createDocumentNumberingPlugin(session.document.package.numbering)
257
+ ]
258
+ });
259
+ const publishCommit = (commit) => {
260
+ if (!view || deps.getReadOnly() || editorSession.type !== "canonical") return false;
261
+ const session = editorSession.session;
262
+ const result = publishCanonicalProjection({
263
+ state: view.state,
264
+ commit,
265
+ session
266
+ });
267
+ if (result.isErr()) {
268
+ refuse(result.error.message);
269
+ return false;
270
+ }
271
+ const staged = result.value;
272
+ view.updateState(staged.state);
273
+ deps.onTransaction({
274
+ transactions: staged.transactions,
275
+ newState: staged.state,
276
+ docChanged: true
277
+ });
278
+ deps.onSelectionChange(staged.state);
279
+ return true;
280
+ };
281
+ const history = (direction) => {
282
+ if (!view || deps.getReadOnly() || editorSession.type !== "canonical") return false;
283
+ const session = editorSession.session;
284
+ if (direction === "undo" ? !session.canUndo : !session.canRedo) return false;
285
+ const prepared = direction === "undo" ? session.prepareUndo(view.state) : session.prepareRedo(view.state);
286
+ if (prepared.isErr()) {
287
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
288
+ return false;
289
+ }
290
+ return publishCommit(prepared.value);
291
+ };
292
+ const executeCanonicalCommand = (command) => {
293
+ if (!view || editorSession.type !== "canonical") return void 0;
294
+ if (deps.getReadOnly()) return false;
295
+ if (editorSession.session.isComposing) {
296
+ refuse("Composition must finish before formatting.");
297
+ return false;
298
+ }
299
+ const intents = getCanonicalCommandIntents(command, view.state);
300
+ if (intents === void 0) return void 0;
301
+ syncCanonicalMode();
302
+ editorSession.session.breakUndoGroup();
303
+ if (intents.length > 0 && intents.every((intent) => intent.type === "formatRun" && intent.from === intent.to)) return command(view.state, (transaction) => {
304
+ if (view !== null) view.dispatch(view.state.tr.setStoredMarks(transaction.storedMarks));
305
+ }, view);
306
+ const prepared = prepareCanonicalCommands(editorSession.session, view.state, intents);
307
+ if (prepared.isErr()) {
308
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
309
+ return false;
310
+ }
311
+ return publishCommit(prepared.value);
312
+ };
313
+ let lastInputRule;
314
+ const canonicalStructuralInput = {
315
+ command: (name) => {
316
+ if (!view) return;
317
+ let command = deps.getExtensionManager()?.getCommand(name)?.();
318
+ if (command === void 0) {
319
+ const mark = view.state.schema.marks[{
320
+ toggleBold: "bold",
321
+ toggleItalic: "italic",
322
+ toggleUnderline: "underline"
323
+ }[name]];
324
+ if (mark !== void 0) command = name === "toggleUnderline" ? toggleUnderlineMark(mark) : toggleMarkForAllScripts(mark, name === "toggleBold" ? "bold" : "italic");
325
+ }
326
+ if (command === void 0) {
327
+ refuse("The formatting command is unavailable.");
328
+ return;
329
+ }
330
+ if (executeCanonicalCommand(command) === void 0) command(view.state, (transaction) => view?.dispatch(transaction), view);
331
+ },
332
+ structure: (type) => {
333
+ if (!view || deps.getReadOnly() || editorSession.type !== "canonical") return;
334
+ syncCanonicalMode();
335
+ const session = editorSession.session;
336
+ const state = view.state;
337
+ const selection = session.projection.selectionAt(state);
338
+ if (selection.isErr()) {
339
+ refuse(selection.error.message);
340
+ return;
341
+ }
342
+ let prepared;
343
+ switch (type) {
344
+ case "split":
345
+ prepared = (session.projection.paragraph(selection.value.head.blockId)?.source)?.formatting?.numPr?.kind === "reference" && state.selection.$from.parent.content.size === 0 ? prepareCanonicalCommands(session, state, [{ type: "removeList" }]) : session.prepareSplit(state);
346
+ break;
347
+ case "joinBackward": {
348
+ if (lastInputRule?.session === session && lastInputRule.version === session.version && lastInputRule.caret === state.selection.head) {
349
+ lastInputRule = void 0;
350
+ history("undo");
351
+ return;
352
+ }
353
+ const paragraph = session.projection.paragraph(selection.value.head.blockId)?.source;
354
+ if (paragraph?.formatting?.numPr?.kind === "reference") {
355
+ prepared = prepareCanonicalCommands(session, state, [{ type: "removeList" }]);
356
+ break;
357
+ }
358
+ if ((paragraph?.formatting?.indentLeft ?? 0) > 0 || (paragraph?.formatting?.indentFirstLine ?? 0) > 0) {
359
+ prepared = session.prepareIntent(state, {
360
+ type: "formatParagraph",
361
+ at: selection.value.head,
362
+ patch: {
363
+ indentLeft: null,
364
+ indentFirstLine: null,
365
+ hangingIndent: null
366
+ }
367
+ });
368
+ break;
369
+ }
370
+ prepared = session.prepareJoin(state, "backward");
371
+ break;
372
+ }
373
+ case "joinForward":
374
+ prepared = session.prepareJoin(state, "forward");
375
+ break;
376
+ case "indent":
377
+ case "outdent":
378
+ prepared = prepareCanonicalCommands(session, state, [{
379
+ type: "changeListLevel",
380
+ direction: type === "indent" ? "increase" : "decrease"
381
+ }]);
382
+ break;
383
+ case "tab":
384
+ case "lineBreak":
385
+ case "pageBreak": {
386
+ const from = session.projection.addressAt(state.selection.from);
387
+ const to = session.projection.addressAt(state.selection.to);
388
+ if (from.isErr()) {
389
+ refuse(from.error.message);
390
+ return;
391
+ }
392
+ if (to.isErr()) {
393
+ refuse(to.error.message);
394
+ return;
395
+ }
396
+ prepared = session.prepareIntent(state, {
397
+ type: "insertAtom",
398
+ from: from.value,
399
+ to: to.value,
400
+ atom: type === "tab" ? { type: "tab" } : {
401
+ type: "break",
402
+ breakType: type === "pageBreak" ? "page" : "textWrapping"
403
+ }
404
+ });
405
+ break;
406
+ }
407
+ default: return type;
408
+ }
409
+ if (prepared.isErr()) {
410
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
411
+ return;
412
+ }
413
+ publishCommit(prepared.value);
414
+ }
415
+ };
416
+ const canonicalInputLifecycle = {
417
+ breakUndoGroup: () => {
418
+ if (editorSession.type === "canonical") editorSession.session.breakUndoGroup();
419
+ },
420
+ beginComposition: () => {
421
+ if (deps.getReadOnly() || editorSession.type !== "canonical") return false;
422
+ const begun = editorSession.session.beginComposition();
423
+ if (begun.isErr()) {
424
+ refuse(begun.error.message);
425
+ return false;
426
+ }
427
+ return true;
428
+ },
429
+ endComposition: () => {
430
+ if (editorSession.type === "canonical") editorSession.session.endComposition();
431
+ }
432
+ };
433
+ const input = createCanonicalInputBoundary({
434
+ ...canonicalInputLifecycle,
435
+ ...canonicalStructuralInput,
436
+ replace: (intent) => {
437
+ if (!view || deps.getReadOnly() || editorSession.type !== "canonical") return;
438
+ syncCanonicalMode();
439
+ const rule = prepareCanonicalAutoformat(editorSession.session, view.state, intent);
440
+ const prepared = rule ?? editorSession.session.prepareReplace(view.state, intent);
441
+ if (prepared.isErr()) {
442
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
443
+ return;
444
+ }
445
+ const session = editorSession.session;
446
+ if (publishCommit(prepared.value) && rule !== void 0 && view !== null) lastInputRule = {
447
+ session,
448
+ version: session.version,
449
+ caret: view.state.selection.head
450
+ };
451
+ },
452
+ undo: () => history("undo"),
453
+ redo: () => history("redo"),
454
+ refuse
455
+ });
204
456
  let isDestroying = false;
205
457
  let requested = false;
206
458
  let isInitialized = false;
@@ -212,31 +464,52 @@ const createHiddenEditorManager = (deps) => {
212
464
  if (!host) return;
213
465
  const collaboration = deps.getCollaboration();
214
466
  const collaborationModules = deps.getCollaborationModules();
215
- if (collaboration && !collaborationModules) return;
467
+ if (collaboration && !collaborationModules && deps.getExperimentalSession?.() !== "canonical") return;
216
468
  const precomputedInitialState = deps.getPrecomputedInitialState();
217
469
  const document = deps.getDocument();
218
470
  const styles = deps.getStyles();
219
471
  const extensionManager = deps.getExtensionManager();
220
472
  const externalPlugins = deps.getExternalPlugins();
473
+ if (!seedSession(document)) return;
474
+ input.reset();
221
475
  const editorProps = {
222
- state: precomputedInitialState && !collaboration ? precomputedInitialState : createHiddenEditorState({
223
- document,
224
- styles,
225
- manager: extensionManager,
226
- externalPlugins,
227
- collaboration,
228
- collaborationModules,
229
- reason: "mount"
230
- }),
476
+ state: (() => {
477
+ if (editorSession.type === "canonical") return canonicalState(editorSession.session);
478
+ if (precomputedInitialState && !collaboration) return precomputedInitialState;
479
+ return createHiddenEditorState({
480
+ document,
481
+ styles,
482
+ manager: extensionManager,
483
+ externalPlugins,
484
+ collaboration,
485
+ collaborationModules,
486
+ reason: "mount"
487
+ });
488
+ })(),
231
489
  attributes: HIDDEN_EDITOR_ATTRIBUTES,
232
- editable: () => !deps.getReadOnly(),
490
+ editable: () => !deps.getReadOnly() && editorSession.type !== "refused",
233
491
  dispatchTransaction: (transaction) => {
234
492
  if (!view || isDestroying) return;
235
493
  if (deps.getReadOnly() && transaction.docChanged) {
236
494
  deps.onReadOnlyEditAttempt();
237
495
  return;
238
496
  }
497
+ if (editorSession.type === "refused") return;
498
+ if (editorSession.type === "canonical" && transaction.docChanged) {
499
+ if (input.acceptComposition(view, transaction)) return;
500
+ if (!input.commitNativeProposal(view, transaction)) input.refuseNativeMutation(view);
501
+ view.updateState(view.state);
502
+ return;
503
+ }
504
+ if (editorSession.type === "canonical" && transaction.selectionSet && !input.isComposing) {
505
+ lastInputRule = void 0;
506
+ editorSession.session.breakUndoGroup();
507
+ }
239
508
  const applied = view.state.applyTransaction(transaction);
509
+ if (editorSession.type === "canonical" && !applied.state.doc.eq(view.state.doc)) {
510
+ refuse("A plugin attempted an unclassified canonical document mutation.");
511
+ return;
512
+ }
240
513
  view.updateState(applied.state);
241
514
  const docChanged = applied.transactions.some((appliedTransaction) => appliedTransaction.docChanged);
242
515
  const selectionChanged = applied.transactions.some((appliedTransaction) => appliedTransaction.selectionSet || appliedTransaction.docChanged);
@@ -256,20 +529,30 @@ const createHiddenEditorManager = (deps) => {
256
529
  event.preventDefault();
257
530
  return true;
258
531
  }
532
+ if (editorSession.type === "canonical" && input.handleKeyDown(pmView, event)) return true;
259
533
  return deps.onKeyDown(pmView, event);
260
534
  },
535
+ handleTextInput: (pmView, from, to, text) => editorSession.type === "canonical" ? input.handleTextInput(pmView, from, to, text) : false,
261
536
  handleScrollToSelection: suppressHiddenEditorScrollToSelection,
262
537
  handleDOMEvents: {
263
538
  focus: () => false,
264
- blur: () => false,
539
+ blur: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.blur(pmView) : false,
265
540
  ...createHiddenEditorClipboardHandlers(deps),
541
+ mousedown: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.mousedown(pmView) : false,
542
+ compositionstart: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.compositionstart(pmView) : false,
543
+ compositionend: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.compositionend(pmView) : false,
544
+ input: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.input(pmView) : false,
545
+ paste: (pmView, event) => editorSession.type === "canonical" ? input.handleDOMEvents.paste(pmView, event) : createHiddenEditorClipboardHandlers(deps).paste(pmView, event),
546
+ cut: (pmView, event) => editorSession.type === "canonical" ? input.handleDOMEvents.cut(pmView, event) : createHiddenEditorClipboardHandlers(deps).cut(pmView, event),
266
547
  beforeinput: (_view, event) => {
548
+ if (editorSession.type === "canonical" && !deps.getReadOnly()) return input.handleDOMEvents.beforeinput(_view, event);
267
549
  if (!deps.getReadOnly()) return false;
268
550
  deps.onReadOnlyEditAttempt();
269
551
  event.preventDefault();
270
552
  return true;
271
553
  },
272
554
  drop: (_view, event) => {
555
+ if (editorSession.type === "canonical") return input.handleDOMEvents.drop(_view, event);
273
556
  if (!deps.getReadOnly()) return false;
274
557
  deps.onReadOnlyEditAttempt();
275
558
  event.preventDefault();
@@ -279,6 +562,7 @@ const createHiddenEditorManager = (deps) => {
279
562
  };
280
563
  const viewStartedAt = performance.now();
281
564
  view = new EditorView(host, editorProps);
565
+ releaseCommandOwner = registerEditorCommandOwner(view, executeCanonicalCommand);
282
566
  recordHiddenEditorPhase("mount", "editor-view", performance.now() - viewStartedAt);
283
567
  syncHiddenEditorAccessibility(view, deps.getReadOnly());
284
568
  isInitialized = true;
@@ -298,8 +582,11 @@ const createHiddenEditorManager = (deps) => {
298
582
  if (view && !isDestroying) {
299
583
  isDestroying = true;
300
584
  deps.onEditorViewDestroy();
585
+ releaseCommandOwner?.();
586
+ releaseCommandOwner = void 0;
301
587
  view.destroy();
302
588
  view = null;
589
+ input.reset();
303
590
  isDestroying = false;
304
591
  }
305
592
  };
@@ -307,17 +594,23 @@ const createHiddenEditorManager = (deps) => {
307
594
  if (!view || isDestroying) return;
308
595
  const collaboration = deps.getCollaboration();
309
596
  const collaborationModules = deps.getCollaborationModules();
310
- if (collaboration && !collaborationModules) return;
597
+ if (collaboration && !collaborationModules && deps.getExperimentalSession?.() !== "canonical") return;
311
598
  const document = deps.getDocument();
312
599
  const currentDocId = deps.getDocumentIdentity();
313
600
  const currentCollaborationFragment = collaboration?.yXmlFragment ?? null;
314
601
  const collaborationSourceChanged = currentCollaborationFragment !== lastCollaborationFragment;
315
- if (collaboration && !collaborationSourceChanged) return;
316
- if (isInitialized && currentDocId === lastDocumentId && !collaborationSourceChanged) return;
602
+ const sessionChanged = editorSession.type !== "prosemirror" !== (deps.getExperimentalSession?.() === "canonical");
603
+ if (collaboration && !collaborationSourceChanged && !sessionChanged) return;
604
+ if (isInitialized && currentDocId === lastDocumentId && !collaborationSourceChanged && !sessionChanged) return;
605
+ if (!seedSession(document)) {
606
+ destroyView();
607
+ return;
608
+ }
609
+ input.reset();
317
610
  isInitialized = true;
318
611
  lastDocumentId = currentDocId;
319
612
  lastCollaborationFragment = currentCollaborationFragment;
320
- const newState = createHiddenEditorState({
613
+ const newState = editorSession.type === "canonical" ? canonicalState(editorSession.session) : createHiddenEditorState({
321
614
  document,
322
615
  styles: deps.getStyles(),
323
616
  manager: deps.getExtensionManager(),
@@ -336,6 +629,41 @@ const createHiddenEditorManager = (deps) => {
336
629
  if (!view) return;
337
630
  syncHiddenEditorAccessibility(view, deps.getReadOnly());
338
631
  };
632
+ const publishStoryCommit = (storyView, commit) => {
633
+ if (!view || editorSession.type !== "canonical") return false;
634
+ if (deps.getEditingMode?.() === "suggesting") {
635
+ refuse("Suggesting is unavailable in the experimental canonical session.");
636
+ return false;
637
+ }
638
+ const session = editorSession.session;
639
+ const bodyTransaction = view.state.tr;
640
+ if (!bodyTransaction.doc.eq(commit.bodyProjection.doc)) bodyTransaction.replaceWith(0, bodyTransaction.doc.content.size, commit.bodyProjection.doc.content);
641
+ markPackageChange(bodyTransaction);
642
+ bodyTransaction.setMeta("addToHistory", false);
643
+ const bodyStaged = Result.try(() => view?.state.applyTransaction(bodyTransaction));
644
+ if (bodyStaged.isErr() || !bodyStaged.value || !bodyStaged.value.transactions.includes(bodyTransaction) || !bodyStaged.value.state.doc.eq(commit.bodyProjection.doc) || bodyStaged.value.transactions.some((transaction) => transaction !== bodyTransaction && transaction.docChanged)) {
645
+ refuse("A plugin refused or changed the canonical body projection.");
646
+ return false;
647
+ }
648
+ const staged = publishCanonicalProjection({
649
+ state: storyView.state,
650
+ commit,
651
+ session
652
+ });
653
+ if (staged.isErr()) {
654
+ refuse(staged.error.message);
655
+ return false;
656
+ }
657
+ storyView.updateState(staged.value.state);
658
+ view.updateState(bodyStaged.value.state);
659
+ deps.onTransaction({
660
+ transactions: staged.value.transactions,
661
+ newState: view.state,
662
+ docChanged: true
663
+ });
664
+ deps.onSelectionChange(view.state);
665
+ return true;
666
+ };
339
667
  return {
340
668
  ensureView,
341
669
  retryViewCreation,
@@ -347,7 +675,105 @@ const createHiddenEditorManager = (deps) => {
347
675
  isInitialized: () => isInitialized,
348
676
  api: createHiddenEditorApi({
349
677
  getView: () => view,
350
- getDocumentContext: deps.getDocumentContext,
678
+ getDocumentContext: () => editorSession.type === "refused" ? null : deps.getDocumentContext(),
679
+ getCanonicalDocument: () => editorSession.type === "canonical" ? editorSession.session.document : null,
680
+ setCanonicalMode: (mode) => {
681
+ if (editorSession.type !== "canonical") return false;
682
+ modeOverride = mode;
683
+ syncCanonicalMode();
684
+ return true;
685
+ },
686
+ resolveCanonicalRevisions: (revisionIds, resolution) => {
687
+ if (!view || deps.getReadOnly() || editorSession.type !== "canonical") return false;
688
+ const prepared = editorSession.session.prepareResolve(view.state, {
689
+ revisionIds,
690
+ resolution
691
+ });
692
+ if (prepared.isErr()) {
693
+ if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
694
+ return false;
695
+ }
696
+ return publishCommit(prepared.value);
697
+ },
698
+ executeCanonicalCommand,
699
+ getCanonicalHistory: () => editorSession.type === "canonical" ? {
700
+ undo: () => history("undo"),
701
+ redo: () => history("redo"),
702
+ canUndo: () => editorSession.type === "canonical" && editorSession.session.canUndo,
703
+ canRedo: () => editorSession.type === "canonical" && editorSession.session.canRedo
704
+ } : null,
705
+ canonicalOperations: {
706
+ updateCanonicalInputLifecycle: (action) => {
707
+ if (editorSession.type !== "canonical") return false;
708
+ switch (action) {
709
+ case "beginComposition": return canonicalInputLifecycle.beginComposition();
710
+ case "endComposition":
711
+ canonicalInputLifecycle.endComposition();
712
+ return true;
713
+ case "breakUndoGroup":
714
+ canonicalInputLifecycle.breakUndoGroup();
715
+ return true;
716
+ }
717
+ },
718
+ getCanonicalStorySelection: (story) => {
719
+ if (editorSession.type !== "canonical") return null;
720
+ const session = editorSession.session;
721
+ const selection = session.selection;
722
+ if (!selection) return null;
723
+ const projection = session.projectStory(story);
724
+ if (projection.isErr()) return null;
725
+ const anchor = projection.value.positionAt(selection.anchor);
726
+ const head = projection.value.positionAt(selection.head);
727
+ return anchor.isOk() && head.isOk() ? {
728
+ anchor: anchor.value,
729
+ head: head.value
730
+ } : null;
731
+ },
732
+ applyCanonicalStoryHistory: ({ view: storyView, story, direction }) => {
733
+ if (story === OP_STORIES.MAIN && storyView === view) return history(direction);
734
+ if (!view || editorSession.type !== "canonical" || deps.getReadOnly()) return false;
735
+ const session = editorSession.session;
736
+ if (direction === "undo" ? !session.canUndo : !session.canRedo) return false;
737
+ const prepared = direction === "undo" ? session.prepareUndo(storyView.state, story) : session.prepareRedo(storyView.state, story);
738
+ if (prepared.isErr()) {
739
+ refuse(prepared.error.message);
740
+ return false;
741
+ }
742
+ return publishStoryCommit(storyView, prepared.value);
743
+ },
744
+ applyCanonicalOperations: (ops) => {
745
+ ensureView();
746
+ if (!view || editorSession.type !== "canonical" || deps.getReadOnly()) return false;
747
+ const prepared = editorSession.session.prepareOperations(view.state, ops);
748
+ if (prepared.isErr()) {
749
+ refuse(prepared.error.message);
750
+ return false;
751
+ }
752
+ return publishCommit(prepared.value);
753
+ },
754
+ getCanonicalStoryProjection: (story) => {
755
+ if (deps.getExperimentalSession?.() === "canonical") ensureView();
756
+ if (editorSession.type !== "canonical" || editorSession.session.isComposing) return null;
757
+ const result = editorSession.session.projectStory(story);
758
+ if (result.isErr()) {
759
+ refuse(result.error.message);
760
+ return null;
761
+ }
762
+ return result.value.doc;
763
+ },
764
+ replaceCanonicalStoryText: ({ view: storyView, story, intent }) => {
765
+ if (!view || editorSession.type !== "canonical" || deps.getReadOnly()) return false;
766
+ const prepared = editorSession.session.prepareReplace(storyView.state, {
767
+ ...intent,
768
+ story
769
+ });
770
+ if (prepared.isErr()) {
771
+ refuse(prepared.error.message);
772
+ return false;
773
+ }
774
+ return publishStoryCommit(storyView, prepared.value);
775
+ }
776
+ },
351
777
  isDestroying: () => isDestroying,
352
778
  ensureView,
353
779
  isViewRequested
@@ -355,4 +781,4 @@ const createHiddenEditorManager = (deps) => {
355
781
  };
356
782
  };
357
783
  //#endregion
358
- export { collectRemoteSelections, createHiddenEditorClipboardHandlers, createHiddenEditorManager, createHiddenEditorState };
784
+ export { CanonicalSessionRefusalError, collectRemoteSelections, createHiddenEditorClipboardHandlers, createHiddenEditorManager, createHiddenEditorState };
@@ -1,9 +1,9 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
2
  import { TemplatePreviewEntry, TemplatePreviewHiddenRange } from "../prosemirror/plugins/templatePreviewValues.js";
3
3
  import { ColumnLayout, FlowBlock, FootnoteContent, HeaderFooterContent, Layout, Measure, PageHeaderFooterRefs, PageMargins } from "../layout-engine/types.js";
4
+ import { LayoutRunOptions } from "./layoutRunOptions.js";
4
5
  import { DisplayMode } from "../managers/EditorModeManager.js";
5
6
  import { LayoutSession } from "./layoutSession.js";
6
- import { LayoutRunOptions } from "./layoutRunOptions.js";
7
7
  import { HyphenationReadiness } from "./hyphenationReadiness.js";
8
8
  import { ConvertHeaderFooterOptions, HeaderFooterMetrics } from "../layout-bridge/convert/headerFooterLayout.js";
9
9
  import "../layout-engine/index.js";
@@ -244,6 +244,7 @@ function runLayoutPipelineMeasured(deps, state, options) {
244
244
  const hfMeasureBlocks = (hfBlocks, hfWidth) => measureBlocks(hfBlocks, hfWidth, void 0, void 0, buildHeaderFooterFieldValues(hfBlocks, pageCount, hfClock, fieldInputs), { allowEndTabOverflow: true });
245
245
  return {
246
246
  ...flowOpts.styles ? { styles: flowOpts.styles } : {},
247
+ ...document?.package.numbering === void 0 ? {} : { numbering: document.package.numbering },
247
248
  ...flowOpts.defaultSize === void 0 ? {} : { defaultSize: flowOpts.defaultSize },
248
249
  ..._theme !== void 0 ? { theme: _theme } : {},
249
250
  fontAlternates,
@@ -377,6 +378,7 @@ function runLayoutPipelineMeasured(deps, state, options) {
377
378
  if (flowOpts.styles) noteOptions.styles = flowOpts.styles;
378
379
  if (flowOpts.defaultSize !== void 0) noteOptions.defaultSize = flowOpts.defaultSize;
379
380
  if (_theme !== void 0) noteOptions.theme = _theme;
381
+ if (document?.package.numbering !== void 0) noteOptions.numbering = document.package.numbering;
380
382
  noteOptions.fontAlternates = fontAlternates;
381
383
  if (defaultTabStop !== void 0) noteOptions.defaultTabStopTwips = defaultTabStop;
382
384
  if (flowOpts.lineBreakRules) noteOptions.lineBreakRules = flowOpts.lineBreakRules;
@@ -1,4 +1,5 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
+ import { HiddenEditorApi } from "./hiddenEditorApi.js";
2
3
  import { NoteStoryKey } from "../types/editor-story.js";
3
4
  import { Plugin } from "prosemirror-state";
4
5
  import { DirectEditorProps, EditorView } from "prosemirror-view";
@@ -12,6 +13,9 @@ type NoteEditorTransaction = NoteStoryKey & {
12
13
  type NoteEditorManagerDeps = {
13
14
  createView?: ((mountNode: HTMLElement, props: DirectEditorProps) => EditorView) | undefined;
14
15
  getDocument: () => document_d_exports.Document | null;
16
+ getCanonicalApi?: (() => HiddenEditorApi | null) | undefined;
17
+ getExperimentalSession?: (() => "canonical" | undefined) | undefined;
18
+ onSessionRefusal?: ((reason: string) => void) | undefined;
15
19
  getHost: () => HTMLElement | null;
16
20
  getPlugins?: (() => Plugin[]) | undefined;
17
21
  getStyles: () => document_d_exports.StyleDefinitions | null | undefined;