@stll/folio-react 0.25.0 → 0.25.2

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.
@@ -1,6 +1,7 @@
1
1
  import { i as cn, n as FolioUIProvider, r as useFolioUI, t as DEFAULT_COMPONENTS } from "./folio-ui-DO95voaI.js";
2
2
  import { t as messages_exports } from "./messages.js";
3
3
  import { c } from "react-compiler-runtime";
4
+ import { CANONICAL_GAP, canonicalRefusalMessage, usesCanonicalSession } from "@stll/folio-core/types/canonicalCapabilities";
4
5
  import * as React$1 from "react";
5
6
  import React, { Component, Suspense, cloneElement, createContext, forwardRef, isValidElement, lazy, memo, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
6
7
  import { AlertCircleIcon, AlertTriangleIcon, AlignCenterIcon, AlignJustifyIcon, AlignLeftIcon, AlignRightIcon, BaselineIcon, BoldIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ClipboardCopyIcon, EyeIcon, FileIcon, GlobeIcon, ImageIcon, IndentDecreaseIcon, IndentIncreaseIcon, InfoIcon, ItalicIcon, LinkIcon, ListIcon, ListOrderedIcon, ListTreeIcon, MessageSquareTextIcon, MoreHorizontalIcon, OmegaIcon, PaintbrushIcon, PanelLeftOpenIcon, PenLineIcon, PencilIcon, PilcrowIcon, Redo2Icon, RulerIcon, SeparatorHorizontalIcon, SquarePenIcon, StickyNoteIcon, TableIcon, TableOfContentsIcon, TypeIcon, UnderlineIcon, Undo2Icon, UnlinkIcon, XIcon } from "lucide-react";
@@ -8,6 +9,7 @@ import { closeHistory, redo, undo } from "prosemirror-history";
8
9
  import { IntlProvider, useFormatter, useTranslations } from "use-intl";
9
10
  import { FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FolioPendingSuggestionRegistry, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, createFolioAIEditSnapshot, createPendingSuggestionSourceSnapshot, getCommentAnchorsFromDoc, getFolioDocumentOperationIssues, getTrackedChangesFromDoc } from "@stll/folio-core/ai-edits";
10
11
  import { resolveCanonicalReviewRange } from "@stll/folio-core/controller/canonicalReview";
12
+ import { afterCanonicalCompositionSettles } from "@stll/folio-core/controller/canonicalInputTimer";
11
13
  import { resolveActiveEditorStory } from "@stll/folio-core/controller/activeEditorStory";
12
14
  import { FOLIO_DOCX_SERIALIZATION_MODE, createFolioEditor } from "@stll/folio-core/controller/folioEditor";
13
15
  import { createNoteReferenceFollower, withoutUnreferencedNotes } from "@stll/folio-core/prosemirror/noteReferenceReview";
@@ -42,13 +44,15 @@ import { resolveColor } from "@stll/folio-core/utils/colorResolver";
42
44
  import { closestHtmlElement, htmlQueryAll, queryHtmlElement } from "@stll/folio-core/utils/domGuards";
43
45
  import { onFontsLoaded } from "@stll/folio-core/utils/fontLoader";
44
46
  import { collectHeadings } from "@stll/folio-core/utils/headingCollector";
47
+ import { DEFAULT_OUTLINE_DEPTH, filterHeadingsByDepth } from "@stll/folio-core/utils/outlineDepth";
45
48
  import { formatPx, pixelsToTwips, pointsToHalfPoints, twipsToPixels } from "@stll/folio-core/utils/units";
46
49
  import { HistoryManager, classifyHistoryShortcut } from "@stll/folio-core/managers/HistoryManager";
47
- import { createCanonicalHeaderFooterOperation, createCanonicalSectionPropertiesOperation, removeCanonicalHeaderFooterOperations } from "@stll/folio-core/controller/canonicalOperations";
48
- import { repackWithCanonicalStoryRemovals } from "@stll/folio-core/docx/canonicalStoryRepack";
50
+ import { CanonicalSaveDiagnosticError, serializeCanonicalSave } from "@stll/folio-core/docx/canonicalSave";
49
51
  import { TableSelectionManager } from "@stll/folio-core/managers/TableSelectionManager";
50
52
  import { DEFAULT_PAGE_HEIGHT_PX, getMargins, getPageSize, twipsToPixels as twipsToPixels$1 } from "@stll/folio-core/paged-layout/sectionGeometry";
53
+ import { getFootnoteText } from "@stll/folio-core/docx/storyPlainText";
51
54
  import { createPortal } from "react-dom";
55
+ import { panic } from "better-result";
52
56
  import { NodeSelection, Selection, TextSelection as TextSelection$1 } from "prosemirror-state";
53
57
  import { CellSelection } from "prosemirror-tables";
54
58
  import { createHeaderFooterEditorManager } from "@stll/folio-core/controller/headerFooterEditorManager";
@@ -65,7 +69,6 @@ import { TRANSACTION_LAYOUT_TIMING, browserClock, createLayoutScheduler } from "
65
69
  import { createLayoutSession } from "@stll/folio-core/controller/layoutSession";
66
70
  import { createHyphenationReadiness } from "@stll/folio-core/controller/hyphenationReadiness";
67
71
  import { readFontSetSignature, waitForInitialLayoutFonts, watchLayoutFontLoads } from "@stll/folio-core/controller/fontReadiness";
68
- import { getFootnoteText } from "@stll/folio-core/docx/footnoteParser";
69
72
  import { convertHeaderFooterPmDocToContent, convertHeaderFooterToContent } from "@stll/folio-core/layout-bridge/convert/headerFooterLayout";
70
73
  import { templatePreviewDirtyRange } from "@stll/folio-core/layout-bridge/convert/templatePreviewFlow";
71
74
  import { clickToPositionDom, getCaretPositionFromDom, getSelectionRectsFromDom } from "@stll/folio-core/layout-bridge/dom/clickToPositionDom";
@@ -96,7 +99,6 @@ import { findStartPosForParaId } from "@stll/folio-core/prosemirror/utils/findPa
96
99
  import { allowsDirectDrawingEdit } from "@stll/folio-core/docx/imageRawXml";
97
100
  import { commitImageFloatMove, commitImageInlineMove, commitImageResize, isFloatingImage } from "@stll/folio-core/prosemirror/imageCommit";
98
101
  import { buildEmbeddedFontFamilyMap, extractEmbeddedFonts } from "@stll/folio-core/fonts/embeddedFonts";
99
- import { panic } from "better-result";
100
102
  import { loadCollaborationModules } from "@stll/folio-core/controller/collaborationModules";
101
103
  import { createVisualLineState, handleVisualLineKeyDown } from "@stll/folio-core/prosemirror/utils/visualLineNavigation";
102
104
  import { clampRangeToDocSize, resolveFolioAIBlockRange, resolveFolioAITextRange, resolvePassageRange } from "@stll/folio-core/ai-edits/blockRange";
@@ -113,6 +115,7 @@ import { getDocumentLoadSource } from "@stll/folio-core/utils/documentLoaderBeha
113
115
  import { DISPLAY_MODES, EditorModeManager, isReadOnlyMode, isTrackChangesMode, toggledTrackChangesMode } from "@stll/folio-core/managers/EditorModeManager";
114
116
  import { FindReplaceManager } from "@stll/folio-core/managers/FindReplaceManager";
115
117
  import { createEmptyHeaderFooter, pickActiveHeaderFooterRId, removeHeaderFooter, resolveEffectiveSectionProperties, resolveHeaderFooterContent, saveHeaderFooterContent } from "@stll/folio-core/utils/headerFooter";
118
+ import { createCanonicalHeaderFooterOperation, removeCanonicalHeaderFooterOperations } from "@stll/folio-core/controller/canonicalOperations";
116
119
  import { editHyperlinkAtCursor, removeHyperlinkAtCursor } from "@stll/folio-core/prosemirror/commands/hyperlink";
117
120
  import { anchorTargetAttrs, sanitizeExternalUrl, windowFeaturesFor } from "@stll/folio-core/utils/urlSecurity";
118
121
  import { applyImagePosition, applyImageProperties, applyImageTransform, applyImageWrapType, insertImageFromFile } from "@stll/folio-core/prosemirror/commands/image";
@@ -368,7 +371,7 @@ const HiddenHeaderFooterPMs = memo(forwardRef(function HiddenHeaderFooterPMs({ d
368
371
  getTheme: () => themeRef.current,
369
372
  getCanonicalApi: () => canonicalApiRef.current?.() ?? null,
370
373
  getExperimentalSession: () => sessionRef.current,
371
- onSessionRefusal: (reason) => refusalRef.current?.(reason),
374
+ onSessionRefusal: (reason, gap, error) => refusalRef.current?.(reason, gap, error),
372
375
  onTransaction: ({ rId, kind, view, docChanged, selectionChanged }) => {
373
376
  onTransactionRef.current?.(rId, kind, view, docChanged, selectionChanged);
374
377
  }
@@ -475,14 +478,11 @@ const NoteStoryEditor = forwardRef(function NoteStoryEditor(t0, ref) {
475
478
  getTheme: () => themeRef.current,
476
479
  getCanonicalApi: () => canonicalApiRef.current?.() ?? null,
477
480
  getExperimentalSession: () => sessionRef.current,
478
- onSessionRefusal: (reason) => refusalRef.current?.(reason),
481
+ onSessionRefusal: (reason, gap, error) => refusalRef.current?.(reason, gap, error),
479
482
  onTransaction: (t2) => {
480
483
  const { docChanged, selectionChanged, view } = t2;
481
- if (docChanged) if (sessionRef.current === "canonical") {
482
- const canonical = canonicalApiRef.current?.()?.getCanonicalDocument();
483
- if (canonical) onDocumentChangeRef.current(canonical);
484
- } else {
485
- const current = documentRef.current;
484
+ if (docChanged) {
485
+ const current = canonicalApiRef.current?.()?.getCanonicalDocument() ?? documentRef.current;
486
486
  if (current) onDocumentChangeRef.current(managerRef.current?.snapshotDocument(current) ?? current);
487
487
  }
488
488
  onStoryChangeRef.current(view, docChanged, selectionChanged);
@@ -1318,7 +1318,7 @@ const HiddenProseMirror = forwardRef((props, ref) => {
1318
1318
  getExperimentalSession: () => experimentalSessionRef.current,
1319
1319
  getEditingMode: () => suggestionModeActiveRef.current ? "suggesting" : "editing",
1320
1320
  getSuggestionAuthor: () => suggestionAuthorRef.current,
1321
- onSessionRefusal: (reason) => onSessionRefusalRef.current?.(reason),
1321
+ onSessionRefusal: (reason, gap, error) => onSessionRefusalRef.current?.(reason, gap, error),
1322
1322
  getDocumentIdentity: () => documentIdentityRef.current,
1323
1323
  getDocumentContext: () => documentRef.current,
1324
1324
  onTransaction: (update) => onTransactionRef.current?.(update),
@@ -1345,10 +1345,10 @@ const HiddenProseMirror = forwardRef((props, ref) => {
1345
1345
  setCollaborationModules(modules);
1346
1346
  setCollaborationModulesError(null);
1347
1347
  }
1348
- }, (error) => {
1348
+ }, (error_0) => {
1349
1349
  if (!cancelled) {
1350
1350
  setCollaborationModules(null);
1351
- setCollaborationModulesError(error);
1351
+ setCollaborationModulesError(error_0);
1352
1352
  }
1353
1353
  });
1354
1354
  return () => {
@@ -1402,7 +1402,8 @@ const HiddenProseMirror = forwardRef((props, ref) => {
1402
1402
  }, [readOnly]);
1403
1403
  useImperativeHandle(ref, () => ({
1404
1404
  ...managerRef.current.api,
1405
- getHostElement: () => hostRef.current
1405
+ getHostElement: () => hostRef.current,
1406
+ isCanonicalComposing: () => managerRef.current?.isCanonicalComposing() ?? false
1406
1407
  }), []);
1407
1408
  if (hasCollaboration && collaborationModulesError) {
1408
1409
  let detail = "unknown error";
@@ -2900,8 +2901,8 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
2900
2901
  onActiveNoteStoryChange?.(story);
2901
2902
  }, [onActiveNoteStoryChange]);
2902
2903
  useEffect(() => {
2903
- if (readOnly || experimentalSession === "canonical") noteEditorRef.current?.close();
2904
- }, [experimentalSession, readOnly]);
2904
+ if (readOnly) noteEditorRef.current?.close();
2905
+ }, [readOnly]);
2905
2906
  const getCanonicalApi = useCallback(() => hiddenPMRef.current, []);
2906
2907
  const { handlePMKeyDown } = useVisualLineNavigation({ pagesContainerRef });
2907
2908
  const handleHiddenEditorKeyDown = useCallback((view, event) => {
@@ -2922,8 +2923,11 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
2922
2923
  onDocumentChangeRef.current = onDocumentChange;
2923
2924
  onTotalPagesChangeRef.current = onTotalPagesChange;
2924
2925
  onErrorRef.current = onError;
2925
- const handleSessionRefusal = useCallback((message) => {
2926
- onErrorRef.current?.(new CanonicalSessionRefusalError({ message }));
2926
+ const handleSessionRefusal = useCallback((message, gap, error) => {
2927
+ onErrorRef.current?.(error ?? new CanonicalSessionRefusalError({
2928
+ gap,
2929
+ message
2930
+ }));
2927
2931
  }, []);
2928
2932
  const [layout, setLayout] = useState(null);
2929
2933
  const layoutRef = useRef(layout);
@@ -3046,7 +3050,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3046
3050
  queuedInputBeforeHiddenEditorRef.current = [];
3047
3051
  for (const input of queuedInput) {
3048
3052
  if (input.type === "text") {
3049
- if (experimentalSession === "canonical") view_0.dom.dispatchEvent(new InputEvent("beforeinput", {
3053
+ if (usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting)) view_0.dom.dispatchEvent(new InputEvent("beforeinput", {
3050
3054
  inputType: "insertText",
3051
3055
  data: input.text,
3052
3056
  cancelable: true,
@@ -3171,7 +3175,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3171
3175
  runLayoutPipelineRef.current(state, { reason: "hyphenation-ready" });
3172
3176
  if (view_1) updateSelectionOverlayRef.current(view_1.state);
3173
3177
  },
3174
- onError: (error) => onErrorRef.current?.(error)
3178
+ onError: (error_0) => onErrorRef.current?.(error_0)
3175
3179
  }));
3176
3180
  useEffect(() => hyphenationReadiness.cancel, [hyphenationReadiness]);
3177
3181
  const laidOutLayoutInputSignatureRef = useRef(null);
@@ -3309,6 +3313,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3309
3313
  clock: browserClock
3310
3314
  });
3311
3315
  const documentChangeNotifyTimerRef = useRef(null);
3316
+ const compositionNotificationRetryRef = useRef(null);
3312
3317
  const [noteFollower] = useState(createNoteReferenceFollower);
3313
3318
  useEffect(() => {
3314
3319
  noteFollower.reset();
@@ -3318,14 +3323,28 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3318
3323
  window.clearTimeout(documentChangeNotifyTimerRef.current);
3319
3324
  documentChangeNotifyTimerRef.current = null;
3320
3325
  }
3326
+ if (hiddenPMRef.current?.isCanonicalComposing()) {
3327
+ const activeView = getActiveEditorStory().view ?? panic("Canonical composition requires an editor view.");
3328
+ if (compositionNotificationRetryRef.current === null) compositionNotificationRetryRef.current = afterCanonicalCompositionSettles(activeView, () => {
3329
+ compositionNotificationRetryRef.current = null;
3330
+ flushDocumentChangeNotification();
3331
+ });
3332
+ return;
3333
+ }
3334
+ compositionNotificationRetryRef.current?.();
3335
+ compositionNotificationRetryRef.current = null;
3321
3336
  let newDoc = hiddenPMRef.current?.getDocument();
3322
3337
  const body = hiddenPMRef.current?.getState()?.doc;
3323
- if (newDoc && body && experimentalSession !== "canonical") newDoc = noteFollower.reconcile(newDoc, body);
3338
+ if (newDoc && body && !usesCanonicalSession(experimentalSession, CANONICAL_GAP.save)) newDoc = noteFollower.reconcile(newDoc, body);
3324
3339
  if (newDoc) {
3325
- onDocumentChangeRef.current?.(experimentalSession === "canonical" ? cloneDocumentWithParagraphPropertySources(newDoc) : newDoc);
3326
- folioEmitterRef.current.emit("docChange", experimentalSession === "canonical" ? cloneDocumentWithParagraphPropertySources(newDoc) : newDoc);
3340
+ onDocumentChangeRef.current?.(usesCanonicalSession(experimentalSession, CANONICAL_GAP.save) ? cloneDocumentWithParagraphPropertySources(newDoc) : newDoc);
3341
+ folioEmitterRef.current.emit("docChange", usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting) ? cloneDocumentWithParagraphPropertySources(newDoc) : newDoc);
3327
3342
  }
3328
- }, [experimentalSession, noteFollower]);
3343
+ }, [
3344
+ experimentalSession,
3345
+ noteFollower,
3346
+ getActiveEditorStory
3347
+ ]);
3329
3348
  const scheduleDocumentChangeNotification = useCallback(() => {
3330
3349
  if (documentChangeNotifyTimerRef.current !== null) window.clearTimeout(documentChangeNotifyTimerRef.current);
3331
3350
  documentChangeNotifyTimerRef.current = window.setTimeout(() => {
@@ -3338,6 +3357,8 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3338
3357
  }, []);
3339
3358
  useEffect(() => () => {
3340
3359
  layoutSchedulerRef.current?.dispose();
3360
+ compositionNotificationRetryRef.current?.();
3361
+ compositionNotificationRetryRef.current = null;
3341
3362
  if (documentChangeNotifyTimerRef.current !== null) {
3342
3363
  window.clearTimeout(documentChangeNotifyTimerRef.current);
3343
3364
  documentChangeNotifyTimerRef.current = null;
@@ -3930,7 +3951,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3930
3951
  if (docChanged_0) {
3931
3952
  if (!hiddenPMRef.current?.getState() && !precomputedInitialStateRef.current) ensureHiddenEditorView({ sync: true });
3932
3953
  scheduleLayout();
3933
- if (experimentalSession === "canonical") scheduleDocumentChangeNotification();
3954
+ if (usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting)) scheduleDocumentChangeNotification();
3934
3955
  }
3935
3956
  if (docChanged_0 || selectionChanged) {
3936
3957
  const { from: from_1, to: to_1 } = view_3.state.selection;
@@ -3966,8 +3987,8 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3966
3987
  }
3967
3988
  }, [scheduleLayout]);
3968
3989
  const handleNoteDocumentChange = useCallback((updated) => {
3969
- onDocumentChangeRef.current?.(experimentalSession === "canonical" ? cloneDocumentWithParagraphPropertySources(updated) : updated);
3970
- folioEmitterRef.current.emit("docChange", experimentalSession === "canonical" ? cloneDocumentWithParagraphPropertySources(updated) : updated);
3990
+ onDocumentChangeRef.current?.(usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting) ? cloneDocumentWithParagraphPropertySources(updated) : updated);
3991
+ folioEmitterRef.current.emit("docChange", usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting) ? cloneDocumentWithParagraphPropertySources(updated) : updated);
3971
3992
  }, [experimentalSession]);
3972
3993
  useEffect(() => {
3973
3994
  if (!hfEditMode) setHfCaretSelection(null);
@@ -4833,10 +4854,6 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4833
4854
  if (story_0) {
4834
4855
  e_3.preventDefault();
4835
4856
  e_3.stopPropagation();
4836
- if (experimentalSession === "canonical") {
4837
- handleSessionRefusal("Footnote and endnote editing is unavailable in this session.");
4838
- return;
4839
- }
4840
4857
  noteEditorRef.current?.open(story_0);
4841
4858
  return;
4842
4859
  }
@@ -4980,9 +4997,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4980
4997
  }
4981
4998
  }
4982
4999
  }, [
4983
- experimentalSession,
4984
5000
  getPositionFromMouse,
4985
- handleSessionRefusal,
4986
5001
  onHeaderFooterDoubleClick,
4987
5002
  onHyperlinkClick,
4988
5003
  readOnly
@@ -5490,7 +5505,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5490
5505
  getDocument() {
5491
5506
  if (documentChangeNotifyTimerRef.current !== null) flushDocumentChangeNotification();
5492
5507
  const editorDocument = folioEditor.getDocument();
5493
- if (experimentalSession === "canonical") return editorDocument;
5508
+ if (usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting)) return editorDocument;
5494
5509
  const current_0 = editorDocument ? noteFollower.withPending(editorDocument) : null;
5495
5510
  return current_0 ? noteEditorRef.current?.snapshotDocument(current_0) ?? current_0 : null;
5496
5511
  },
@@ -5501,14 +5516,12 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5501
5516
  return folioEditor.getView();
5502
5517
  },
5503
5518
  getActiveView() {
5504
- if (experimentalSession === "canonical") return folioEditor.getView();
5505
5519
  return getActiveEditorStory().view;
5506
5520
  },
5507
5521
  closeNoteStory() {
5508
5522
  noteEditorRef.current?.close();
5509
5523
  },
5510
5524
  getHfView(rId_0) {
5511
- if (experimentalSession === "canonical") return null;
5512
5525
  return hfPMsRef.current?.getView(rId_0) ?? null;
5513
5526
  },
5514
5527
  ensureView(options_4) {
@@ -5534,7 +5547,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5534
5547
  undo() {
5535
5548
  const target_5 = getActiveEditorStory();
5536
5549
  if (target_5.type === "none") return false;
5537
- if (experimentalSession === "canonical") return hiddenPMRef.current?.applyCanonicalStoryHistory({
5550
+ if (usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting)) return hiddenPMRef.current?.applyCanonicalStoryHistory({
5538
5551
  view: target_5.view,
5539
5552
  story: getCanonicalActiveStory(),
5540
5553
  direction: "undo"
@@ -5545,7 +5558,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5545
5558
  redo() {
5546
5559
  const target_6 = getActiveEditorStory();
5547
5560
  if (target_6.type === "none") return false;
5548
- if (experimentalSession === "canonical") return hiddenPMRef.current?.applyCanonicalStoryHistory({
5561
+ if (usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting)) return hiddenPMRef.current?.applyCanonicalStoryHistory({
5549
5562
  view: target_6.view,
5550
5563
  story: getCanonicalActiveStory(),
5551
5564
  direction: "redo"
@@ -5556,12 +5569,12 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5556
5569
  canUndo() {
5557
5570
  const target_7 = getActiveEditorStory();
5558
5571
  if (target_7.type === "none") return false;
5559
- return experimentalSession === "canonical" || target_7.type === "body" ? hiddenPMRef.current?.canUndo() ?? false : undo(target_7.view.state);
5572
+ return usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting) || target_7.type === "body" ? hiddenPMRef.current?.canUndo() ?? false : undo(target_7.view.state);
5560
5573
  },
5561
5574
  canRedo() {
5562
5575
  const target_8 = getActiveEditorStory();
5563
5576
  if (target_8.type === "none") return false;
5564
- return experimentalSession === "canonical" || target_8.type === "body" ? hiddenPMRef.current?.canRedo() ?? false : redo(target_8.view.state);
5577
+ return usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting) || target_8.type === "body" ? hiddenPMRef.current?.canRedo() ?? false : redo(target_8.view.state);
5565
5578
  },
5566
5579
  setSelection(anchor_3, head_1) {
5567
5580
  folioEditor.setSelection(anchor_3, head_1);
@@ -5721,7 +5734,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5721
5734
  onTransaction: handleHfPmTransaction,
5722
5735
  getCanonicalApi,
5723
5736
  onSessionRefusal: handleSessionRefusal,
5724
- ...experimentalSession === void 0 ? {} : { experimentalSession },
5737
+ ...!usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting) ? {} : { experimentalSession },
5725
5738
  ...styles !== void 0 ? { styles } : {},
5726
5739
  ..._theme !== void 0 ? { theme: _theme } : {}
5727
5740
  }),
@@ -5731,7 +5744,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5731
5744
  onActiveChange: handleActiveNoteStoryChange,
5732
5745
  getCanonicalApi,
5733
5746
  onSessionRefusal: handleSessionRefusal,
5734
- ...experimentalSession === void 0 ? {} : { experimentalSession },
5747
+ ...!usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting) ? {} : { experimentalSession },
5735
5748
  onDocumentChange: handleNoteDocumentChange,
5736
5749
  onStoryChange: handleNoteStoryTransaction,
5737
5750
  plugins: noteStoryPlugins,
@@ -5744,7 +5757,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5744
5757
  ref: hiddenPMRef,
5745
5758
  document,
5746
5759
  documentIdentity,
5747
- ...experimentalSession === void 0 ? {} : { experimentalSession },
5760
+ ...!usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting) ? {} : { experimentalSession },
5748
5761
  onSessionRefusal: handleSessionRefusal,
5749
5762
  ...suggestionAuthor !== void 0 ? { suggestionAuthor } : {},
5750
5763
  suggestionModeActive,
@@ -7645,35 +7658,31 @@ const initialFocusTarget = (container, initial) => {
7645
7658
  if (initial === "container") return container;
7646
7659
  return container.querySelector("[aria-current=\"true\"]") ?? container.querySelector(LIST_TAB_STOP) ?? container.querySelector(FOCUSABLE) ?? container;
7647
7660
  };
7648
- /**
7649
- * While `onClose` is set, `container` is an open drawer: focus moves into it,
7650
- * Escape calls `onClose`, and once it closes focus returns to what had it
7651
- * before, if that is still in the document.
7652
- */
7653
- const useDrawerFocus = (container, onClose, t0) => {
7654
- const $ = c(8);
7655
- const initial = t0 === void 0 ? "item" : t0;
7661
+ const useDrawerFocus = (options) => {
7662
+ const $ = c(9);
7663
+ const { container, onClose, returnFocusRef } = options;
7664
+ const initial = options.initial ?? "item";
7656
7665
  const onCloseRef = useRef(onClose);
7666
+ let t0;
7657
7667
  let t1;
7658
- let t2;
7659
7668
  if ($[0] !== onClose) {
7660
- t1 = () => {
7669
+ t0 = () => {
7661
7670
  onCloseRef.current = onClose;
7662
7671
  };
7663
- t2 = [onClose];
7672
+ t1 = [onClose];
7664
7673
  $[0] = onClose;
7665
- $[1] = t1;
7666
- $[2] = t2;
7674
+ $[1] = t0;
7675
+ $[2] = t1;
7667
7676
  } else {
7668
- t1 = $[1];
7669
- t2 = $[2];
7677
+ t0 = $[1];
7678
+ t1 = $[2];
7670
7679
  }
7671
- useEffect(t1, t2);
7680
+ useEffect(t0, t1);
7672
7681
  const active = onClose !== null;
7682
+ let t2;
7673
7683
  let t3;
7674
- let t4;
7675
- if ($[3] !== active || $[4] !== container || $[5] !== initial) {
7676
- t3 = () => {
7684
+ if ($[3] !== active || $[4] !== container || $[5] !== initial || $[6] !== returnFocusRef) {
7685
+ t2 = () => {
7677
7686
  if (!active) return;
7678
7687
  const previous = document.activeElement instanceof HTMLElement ? document.activeElement : null;
7679
7688
  const element = container.current;
@@ -7686,24 +7695,28 @@ const useDrawerFocus = (container, onClose, t0) => {
7686
7695
  document.addEventListener("keydown", handleKeyDown);
7687
7696
  return () => {
7688
7697
  document.removeEventListener("keydown", handleKeyDown);
7689
- if (previous?.isConnected) previous.focus({ preventScroll: true });
7698
+ const returnTarget = returnFocusRef?.current;
7699
+ const target = returnTarget?.isConnected ? returnTarget : previous;
7700
+ if (target?.isConnected) target.focus({ preventScroll: true });
7690
7701
  };
7691
7702
  };
7692
- t4 = [
7703
+ t3 = [
7693
7704
  active,
7694
7705
  container,
7695
- initial
7706
+ initial,
7707
+ returnFocusRef
7696
7708
  ];
7697
7709
  $[3] = active;
7698
7710
  $[4] = container;
7699
7711
  $[5] = initial;
7700
- $[6] = t3;
7701
- $[7] = t4;
7712
+ $[6] = returnFocusRef;
7713
+ $[7] = t2;
7714
+ $[8] = t3;
7702
7715
  } else {
7703
- t3 = $[6];
7704
- t4 = $[7];
7716
+ t2 = $[7];
7717
+ t3 = $[8];
7705
7718
  }
7706
- useEffect(t3, t4);
7719
+ useEffect(t2, t3);
7707
7720
  };
7708
7721
  /** Dims the page under an open drawer; pressing it closes the drawer. */
7709
7722
  const PanelScrim = (t0) => {
@@ -7730,164 +7743,188 @@ const PanelScrim = (t0) => {
7730
7743
  const SURFACE_WIDTH = {
7731
7744
  column: PANEL_METRICS.outlineColumnWidth,
7732
7745
  rail: PANEL_METRICS.outlineRailWidth,
7733
- drawer: PANEL_METRICS.drawerWidth
7746
+ expanded: PANEL_METRICS.outlineColumnWidth
7734
7747
  };
7735
7748
  const DocumentOutline = (t0) => {
7736
- const $ = c(55);
7737
- const { headings, scrollContainerRef, docSize, activeId, onJump, surface, expanded, onExpand, onClose } = t0;
7749
+ const $ = c(91);
7750
+ const { headings, available, outlineDepth, onOutlineDepthChange, scrollContainerRef, docSize, activeId, onJump, surface, expanded, onExpand, onClose, width: widthOverride } = t0;
7738
7751
  const t = useTranslations("folio");
7739
7752
  const OutlineRail = useFolioUI().OutlineRail;
7740
7753
  const navRef = useRef(null);
7741
- useDrawerFocus(navRef, surface === "drawer" && onClose ? onClose : null);
7742
- let t1;
7743
- if ($[0] !== headings) {
7744
- t1 = headings.map(_temp$7);
7745
- $[0] = headings;
7746
- $[1] = t1;
7747
- } else t1 = $[1];
7748
- const items = t1;
7754
+ const expandButtonRef = useRef(null);
7755
+ const t1 = surface === "expanded" && onClose ? onClose : null;
7756
+ let t2;
7757
+ if ($[0] !== t1) {
7758
+ t2 = {
7759
+ container: navRef,
7760
+ onClose: t1,
7761
+ returnFocusRef: expandButtonRef
7762
+ };
7763
+ $[0] = t1;
7764
+ $[1] = t2;
7765
+ } else t2 = $[1];
7766
+ useDrawerFocus(t2);
7767
+ let t3;
7768
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
7769
+ t3 = {
7770
+ minWidth: PANEL_METRICS.controlMinimumSize,
7771
+ minHeight: PANEL_METRICS.controlMinimumSize
7772
+ };
7773
+ $[2] = t3;
7774
+ } else t3 = $[2];
7775
+ const controlMinimumStyle = t3;
7776
+ let t4;
7777
+ if ($[3] !== headings) {
7778
+ t4 = headings.map(_temp$7);
7779
+ $[3] = headings;
7780
+ $[4] = t4;
7781
+ } else t4 = $[4];
7782
+ const items = t4;
7749
7783
  let map;
7750
- if ($[2] !== docSize || $[3] !== headings) {
7784
+ if ($[5] !== docSize || $[6] !== headings) {
7751
7785
  map = /* @__PURE__ */ new Map();
7752
7786
  if (docSize > 0) for (const heading_0 of headings) map.set(headingId(heading_0), Math.min(99, Math.max(1, heading_0.pmPos / docSize * 100)));
7753
- $[2] = docSize;
7754
- $[3] = headings;
7755
- $[4] = map;
7756
- } else map = $[4];
7787
+ $[5] = docSize;
7788
+ $[6] = headings;
7789
+ $[7] = map;
7790
+ } else map = $[7];
7757
7791
  const pctById = map;
7758
- let t2;
7759
- if ($[5] !== onClose || $[6] !== onJump || $[7] !== surface) {
7760
- t2 = (id) => {
7792
+ let t5;
7793
+ if ($[8] !== onClose || $[9] !== onJump || $[10] !== surface) {
7794
+ t5 = (id) => {
7761
7795
  onJump(id);
7762
- if (surface === "drawer") onClose?.();
7796
+ if (surface === "expanded") onClose?.();
7763
7797
  };
7764
- $[5] = onClose;
7765
- $[6] = onJump;
7766
- $[7] = surface;
7767
- $[8] = t2;
7768
- } else t2 = $[8];
7769
- const handleJump = t2;
7770
- let t3;
7771
- if ($[9] !== pctById) {
7772
- t3 = (id_0) => pctById.get(id_0) ?? null;
7773
- $[9] = pctById;
7774
- $[10] = t3;
7775
- } else t3 = $[10];
7776
- const resolvePct = t3;
7777
- if (headings.length < 2) return null;
7778
- let t4;
7779
- if ($[11] !== t) {
7780
- t4 = t("editor.showDocumentOutline");
7781
- $[11] = t;
7782
- $[12] = t4;
7783
- } else t4 = $[12];
7784
- const outlineLabel = t4;
7785
- const width = SURFACE_WIDTH[surface];
7786
- const t5 = surface === "rail" ? "rail" : "panel";
7798
+ $[8] = onClose;
7799
+ $[9] = onJump;
7800
+ $[10] = surface;
7801
+ $[11] = t5;
7802
+ } else t5 = $[11];
7803
+ const handleJump = t5;
7787
7804
  let t6;
7788
- if ($[13] !== OutlineRail || $[14] !== activeId || $[15] !== handleJump || $[16] !== items || $[17] !== outlineLabel || $[18] !== resolvePct || $[19] !== scrollContainerRef || $[20] !== t5 || $[21] !== width) {
7789
- t6 = /* @__PURE__ */ jsx(OutlineRail, {
7805
+ if ($[12] !== pctById) {
7806
+ t6 = (id_0) => pctById.get(id_0) ?? null;
7807
+ $[12] = pctById;
7808
+ $[13] = t6;
7809
+ } else t6 = $[13];
7810
+ const resolvePct = t6;
7811
+ if (!available) return null;
7812
+ let t7;
7813
+ if ($[14] !== t) {
7814
+ t7 = t("editor.showDocumentOutline");
7815
+ $[14] = t;
7816
+ $[15] = t7;
7817
+ } else t7 = $[15];
7818
+ const outlineLabel = t7;
7819
+ const width = widthOverride ?? SURFACE_WIDTH[surface];
7820
+ const t8 = surface === "rail" ? "rail" : "panel";
7821
+ let t9;
7822
+ if ($[16] !== OutlineRail || $[17] !== activeId || $[18] !== handleJump || $[19] !== items || $[20] !== outlineLabel || $[21] !== resolvePct || $[22] !== scrollContainerRef || $[23] !== t8 || $[24] !== width) {
7823
+ t9 = /* @__PURE__ */ jsx(OutlineRail, {
7790
7824
  activeId,
7791
7825
  ariaLabel: outlineLabel,
7792
7826
  items,
7793
7827
  onJump: handleJump,
7794
7828
  panelWidth: width,
7795
- presentation: t5,
7829
+ presentation: t8,
7796
7830
  resolvePct,
7797
7831
  scrollContainerRef,
7798
7832
  topOffset: 0
7799
7833
  });
7800
- $[13] = OutlineRail;
7801
- $[14] = activeId;
7802
- $[15] = handleJump;
7803
- $[16] = items;
7804
- $[17] = outlineLabel;
7805
- $[18] = resolvePct;
7806
- $[19] = scrollContainerRef;
7807
- $[20] = t5;
7808
- $[21] = width;
7809
- $[22] = t6;
7810
- } else t6 = $[22];
7811
- const rail = t6;
7834
+ $[16] = OutlineRail;
7835
+ $[17] = activeId;
7836
+ $[18] = handleJump;
7837
+ $[19] = items;
7838
+ $[20] = outlineLabel;
7839
+ $[21] = resolvePct;
7840
+ $[22] = scrollContainerRef;
7841
+ $[23] = t8;
7842
+ $[24] = width;
7843
+ $[25] = t9;
7844
+ } else t9 = $[25];
7845
+ const rail = t9;
7812
7846
  if (surface === "rail") {
7813
- let t7;
7814
- if ($[23] !== width) {
7815
- t7 = { width };
7816
- $[23] = width;
7817
- $[24] = t7;
7818
- } else t7 = $[24];
7819
- const t8 = expanded ?? false;
7820
- let t9;
7821
- if ($[25] === Symbol.for("react.memo_cache_sentinel")) {
7822
- t9 = /* @__PURE__ */ jsx(PanelLeftOpenIcon, {
7847
+ let t10;
7848
+ if ($[26] !== width) {
7849
+ t10 = { width };
7850
+ $[26] = width;
7851
+ $[27] = t10;
7852
+ } else t10 = $[27];
7853
+ const t11 = expanded ?? false;
7854
+ let t12;
7855
+ if ($[28] === Symbol.for("react.memo_cache_sentinel")) {
7856
+ t12 = /* @__PURE__ */ jsx(PanelLeftOpenIcon, {
7823
7857
  "aria-hidden": "true",
7824
7858
  size: 16
7825
7859
  });
7826
- $[25] = t9;
7827
- } else t9 = $[25];
7828
- let t10;
7829
- if ($[26] !== onExpand || $[27] !== outlineLabel || $[28] !== t8) {
7830
- t10 = /* @__PURE__ */ jsx("button", {
7831
- "aria-expanded": t8,
7860
+ $[28] = t12;
7861
+ } else t12 = $[28];
7862
+ let t13;
7863
+ if ($[29] !== onExpand || $[30] !== outlineLabel || $[31] !== t11) {
7864
+ t13 = /* @__PURE__ */ jsx("button", {
7865
+ ref: expandButtonRef,
7866
+ "aria-expanded": t11,
7832
7867
  "aria-label": outlineLabel,
7833
7868
  className: "folio-outline-icon-button",
7834
7869
  "data-testid": "folio-outline-expand",
7835
7870
  onClick: onExpand,
7871
+ style: controlMinimumStyle,
7836
7872
  title: outlineLabel,
7837
7873
  type: "button",
7838
- children: t9
7874
+ children: t12
7839
7875
  });
7840
- $[26] = onExpand;
7841
- $[27] = outlineLabel;
7842
- $[28] = t8;
7843
- $[29] = t10;
7844
- } else t10 = $[29];
7845
- let t11;
7846
- if ($[30] !== outlineLabel || $[31] !== rail || $[32] !== t10 || $[33] !== t7) {
7847
- t11 = /* @__PURE__ */ jsxs("nav", {
7876
+ $[29] = onExpand;
7877
+ $[30] = outlineLabel;
7878
+ $[31] = t11;
7879
+ $[32] = t13;
7880
+ } else t13 = $[32];
7881
+ let t14;
7882
+ if ($[33] !== outlineLabel || $[34] !== rail || $[35] !== t10 || $[36] !== t13) {
7883
+ t14 = /* @__PURE__ */ jsxs("nav", {
7848
7884
  "aria-label": outlineLabel,
7849
7885
  className: "folio-outline folio-outline--rail",
7850
7886
  "data-testid": "folio-outline",
7851
7887
  "data-folio-outline-surface": "rail",
7852
- style: t7,
7853
- children: [t10, rail]
7888
+ style: t10,
7889
+ children: [t13, rail]
7854
7890
  });
7855
- $[30] = outlineLabel;
7856
- $[31] = rail;
7857
- $[32] = t10;
7858
- $[33] = t7;
7859
- $[34] = t11;
7860
- } else t11 = $[34];
7861
- return t11;
7891
+ $[33] = outlineLabel;
7892
+ $[34] = rail;
7893
+ $[35] = t10;
7894
+ $[36] = t13;
7895
+ $[37] = t14;
7896
+ } else t14 = $[37];
7897
+ return t14;
7862
7898
  }
7863
- const t7 = `folio-outline folio-outline--${surface}`;
7864
- let t8;
7865
- if ($[35] !== width) {
7866
- t8 = { width };
7867
- $[35] = width;
7868
- $[36] = t8;
7869
- } else t8 = $[36];
7870
- let t9;
7871
- if ($[37] !== t) {
7872
- t9 = t("editor.outlineTitle");
7873
- $[37] = t;
7874
- $[38] = t9;
7875
- } else t9 = $[38];
7876
- let t10;
7877
- if ($[39] !== t9) {
7878
- t10 = /* @__PURE__ */ jsx("span", {
7899
+ const t10 = `folio-outline folio-outline--${surface === "expanded" ? "column" : surface}`;
7900
+ let t11;
7901
+ if ($[38] !== width) {
7902
+ t11 = { width };
7903
+ $[38] = width;
7904
+ $[39] = t11;
7905
+ } else t11 = $[39];
7906
+ let t12;
7907
+ if ($[40] !== t) {
7908
+ t12 = t("editor.outlineTitle");
7909
+ $[40] = t;
7910
+ $[41] = t12;
7911
+ } else t12 = $[41];
7912
+ let t13;
7913
+ if ($[42] !== t12) {
7914
+ t13 = /* @__PURE__ */ jsx("span", {
7879
7915
  className: "folio-outline-title",
7880
- children: t9
7916
+ children: t12
7881
7917
  });
7882
- $[39] = t9;
7883
- $[40] = t10;
7884
- } else t10 = $[40];
7885
- let t11;
7886
- if ($[41] !== onClose || $[42] !== surface || $[43] !== t) {
7887
- t11 = surface === "drawer" && onClose && /* @__PURE__ */ jsx("button", {
7918
+ $[42] = t12;
7919
+ $[43] = t13;
7920
+ } else t13 = $[43];
7921
+ let t14;
7922
+ if ($[44] !== onClose || $[45] !== surface || $[46] !== t) {
7923
+ t14 = surface === "expanded" && onClose && /* @__PURE__ */ jsx("button", {
7888
7924
  "aria-label": t("common.closeDialog"),
7889
7925
  className: "folio-outline-icon-button",
7890
7926
  onClick: onClose,
7927
+ style: controlMinimumStyle,
7891
7928
  title: t("common.closeDialog"),
7892
7929
  type: "button",
7893
7930
  children: /* @__PURE__ */ jsx(XIcon, {
@@ -7895,41 +7932,157 @@ const DocumentOutline = (t0) => {
7895
7932
  size: 16
7896
7933
  })
7897
7934
  });
7898
- $[41] = onClose;
7899
- $[42] = surface;
7900
- $[43] = t;
7901
- $[44] = t11;
7902
- } else t11 = $[44];
7903
- let t12;
7904
- if ($[45] !== t10 || $[46] !== t11) {
7905
- t12 = /* @__PURE__ */ jsxs("div", {
7935
+ $[44] = onClose;
7936
+ $[45] = surface;
7937
+ $[46] = t;
7938
+ $[47] = t14;
7939
+ } else t14 = $[47];
7940
+ let t15;
7941
+ if ($[48] !== t13 || $[49] !== t14) {
7942
+ t15 = /* @__PURE__ */ jsxs("div", {
7943
+ className: "folio-outline-heading-row",
7944
+ children: [t13, t14]
7945
+ });
7946
+ $[48] = t13;
7947
+ $[49] = t14;
7948
+ $[50] = t15;
7949
+ } else t15 = $[50];
7950
+ let t16;
7951
+ if ($[51] !== t) {
7952
+ t16 = t("editor.outlineDepthLabel");
7953
+ $[51] = t;
7954
+ $[52] = t16;
7955
+ } else t16 = $[52];
7956
+ let t17;
7957
+ if ($[53] !== t16) {
7958
+ t17 = /* @__PURE__ */ jsx("span", { children: t16 });
7959
+ $[53] = t16;
7960
+ $[54] = t17;
7961
+ } else t17 = $[54];
7962
+ let t18;
7963
+ if ($[55] !== t) {
7964
+ t18 = t("editor.outlineDepthLabel");
7965
+ $[55] = t;
7966
+ $[56] = t18;
7967
+ } else t18 = $[56];
7968
+ let t19;
7969
+ if ($[57] !== onOutlineDepthChange) {
7970
+ t19 = (event) => {
7971
+ const value = event.currentTarget.value;
7972
+ if (value === "all") {
7973
+ onOutlineDepthChange("all");
7974
+ return;
7975
+ }
7976
+ onOutlineDepthChange(value === "3" ? 3 : 2);
7977
+ };
7978
+ $[57] = onOutlineDepthChange;
7979
+ $[58] = t19;
7980
+ } else t19 = $[58];
7981
+ let t20;
7982
+ if ($[59] !== t) {
7983
+ t20 = t("editor.outlineDepthTwo");
7984
+ $[59] = t;
7985
+ $[60] = t20;
7986
+ } else t20 = $[60];
7987
+ let t21;
7988
+ if ($[61] !== t20) {
7989
+ t21 = /* @__PURE__ */ jsx("option", {
7990
+ value: 2,
7991
+ children: t20
7992
+ });
7993
+ $[61] = t20;
7994
+ $[62] = t21;
7995
+ } else t21 = $[62];
7996
+ let t22;
7997
+ if ($[63] !== t) {
7998
+ t22 = t("editor.outlineDepthThree");
7999
+ $[63] = t;
8000
+ $[64] = t22;
8001
+ } else t22 = $[64];
8002
+ let t23;
8003
+ if ($[65] !== t22) {
8004
+ t23 = /* @__PURE__ */ jsx("option", {
8005
+ value: 3,
8006
+ children: t22
8007
+ });
8008
+ $[65] = t22;
8009
+ $[66] = t23;
8010
+ } else t23 = $[66];
8011
+ let t24;
8012
+ if ($[67] !== t) {
8013
+ t24 = t("editor.outlineDepthAll");
8014
+ $[67] = t;
8015
+ $[68] = t24;
8016
+ } else t24 = $[68];
8017
+ let t25;
8018
+ if ($[69] !== t24) {
8019
+ t25 = /* @__PURE__ */ jsx("option", {
8020
+ value: "all",
8021
+ children: t24
8022
+ });
8023
+ $[69] = t24;
8024
+ $[70] = t25;
8025
+ } else t25 = $[70];
8026
+ let t26;
8027
+ if ($[71] !== outlineDepth || $[72] !== t18 || $[73] !== t19 || $[74] !== t21 || $[75] !== t23 || $[76] !== t25) {
8028
+ t26 = /* @__PURE__ */ jsxs("select", {
8029
+ "aria-label": t18,
8030
+ onChange: t19,
8031
+ value: outlineDepth,
8032
+ children: [
8033
+ t21,
8034
+ t23,
8035
+ t25
8036
+ ]
8037
+ });
8038
+ $[71] = outlineDepth;
8039
+ $[72] = t18;
8040
+ $[73] = t19;
8041
+ $[74] = t21;
8042
+ $[75] = t23;
8043
+ $[76] = t25;
8044
+ $[77] = t26;
8045
+ } else t26 = $[77];
8046
+ let t27;
8047
+ if ($[78] !== t17 || $[79] !== t26) {
8048
+ t27 = /* @__PURE__ */ jsxs("label", {
8049
+ className: "folio-outline-depth-control",
8050
+ children: [t17, t26]
8051
+ });
8052
+ $[78] = t17;
8053
+ $[79] = t26;
8054
+ $[80] = t27;
8055
+ } else t27 = $[80];
8056
+ let t28;
8057
+ if ($[81] !== t15 || $[82] !== t27) {
8058
+ t28 = /* @__PURE__ */ jsxs("div", {
7906
8059
  className: "folio-outline-header",
7907
- children: [t10, t11]
8060
+ children: [t15, t27]
7908
8061
  });
7909
- $[45] = t10;
7910
- $[46] = t11;
7911
- $[47] = t12;
7912
- } else t12 = $[47];
7913
- let t13;
7914
- if ($[48] !== outlineLabel || $[49] !== rail || $[50] !== surface || $[51] !== t12 || $[52] !== t7 || $[53] !== t8) {
7915
- t13 = /* @__PURE__ */ jsxs("nav", {
8062
+ $[81] = t15;
8063
+ $[82] = t27;
8064
+ $[83] = t28;
8065
+ } else t28 = $[83];
8066
+ let t29;
8067
+ if ($[84] !== outlineLabel || $[85] !== rail || $[86] !== surface || $[87] !== t10 || $[88] !== t11 || $[89] !== t28) {
8068
+ t29 = /* @__PURE__ */ jsxs("nav", {
7916
8069
  ref: navRef,
7917
8070
  "aria-label": outlineLabel,
7918
- className: t7,
8071
+ className: t10,
7919
8072
  "data-testid": "folio-outline",
7920
8073
  "data-folio-outline-surface": surface,
7921
- style: t8,
7922
- children: [t12, rail]
8074
+ style: t11,
8075
+ children: [t28, rail]
7923
8076
  });
7924
- $[48] = outlineLabel;
7925
- $[49] = rail;
7926
- $[50] = surface;
7927
- $[51] = t12;
7928
- $[52] = t7;
7929
- $[53] = t8;
7930
- $[54] = t13;
7931
- } else t13 = $[54];
7932
- return t13;
8077
+ $[84] = outlineLabel;
8078
+ $[85] = rail;
8079
+ $[86] = surface;
8080
+ $[87] = t10;
8081
+ $[88] = t11;
8082
+ $[89] = t28;
8083
+ $[90] = t29;
8084
+ } else t29 = $[90];
8085
+ return t29;
7933
8086
  };
7934
8087
  function _temp$7(heading) {
7935
8088
  const item = {
@@ -10599,7 +10752,7 @@ const useHeaderFooterEditor = ({ history, pushDocument, getHfView, getCanonicalA
10599
10752
  setHfEditPosition(position);
10600
10753
  return;
10601
10754
  }
10602
- if (experimentalSession === "canonical") {
10755
+ if (usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting)) {
10603
10756
  const api = getCanonicalApi?.();
10604
10757
  api?.ensureView();
10605
10758
  const canonical = api?.getCanonicalDocument();
@@ -10629,7 +10782,7 @@ const useHeaderFooterEditor = ({ history, pushDocument, getHfView, getCanonicalA
10629
10782
  experimentalSession
10630
10783
  ]);
10631
10784
  const handleHeaderFooterSave = useCallback(() => {
10632
- if (experimentalSession === "canonical") {
10785
+ if (usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting)) {
10633
10786
  setHfEditPosition(null);
10634
10787
  return;
10635
10788
  }
@@ -10683,7 +10836,7 @@ const useHeaderFooterEditor = ({ history, pushDocument, getHfView, getCanonicalA
10683
10836
  return;
10684
10837
  }
10685
10838
  const activeRId_0 = pickActiveHeaderFooterRId(resolution, hfEditPosition, hfEditIsFirstPage);
10686
- if (experimentalSession === "canonical") {
10839
+ if (usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting)) {
10687
10840
  const api_0 = getCanonicalApi?.();
10688
10841
  const canonical_0 = api_0?.getCanonicalDocument();
10689
10842
  if (api_0 && canonical_0 && activeRId_0) api_0.applyCanonicalOperations(removeCanonicalHeaderFooterOperations({
@@ -11024,22 +11177,23 @@ const usePanelLayout = (t0) => {
11024
11177
  t2 = $[3];
11025
11178
  }
11026
11179
  useLayoutEffect(t1, t2);
11180
+ const requestedOutline = overlay === "outline" && outline !== "absent" ? "expanded" : outline;
11027
11181
  let t3;
11028
- if ($[4] !== availableWidth || $[5] !== comments || $[6] !== outline || $[7] !== pageWidth) {
11182
+ if ($[4] !== availableWidth || $[5] !== comments || $[6] !== pageWidth || $[7] !== requestedOutline) {
11029
11183
  t3 = computePanelLayout({
11030
11184
  availableWidth,
11031
11185
  pageWidth,
11032
- outline,
11186
+ outline: requestedOutline,
11033
11187
  comments
11034
11188
  });
11035
11189
  $[4] = availableWidth;
11036
11190
  $[5] = comments;
11037
- $[6] = outline;
11038
- $[7] = pageWidth;
11191
+ $[6] = pageWidth;
11192
+ $[7] = requestedOutline;
11039
11193
  $[8] = t3;
11040
11194
  } else t3 = $[8];
11041
11195
  const layout = t3;
11042
- const outlineDrawn = layout.outline === "rail" || layout.outline === "drawer";
11196
+ const outlineDrawn = layout.outline !== "none" && layout.outline !== "column";
11043
11197
  const commentsDrawn = layout.comments === "drawer";
11044
11198
  let t4;
11045
11199
  let t5;
@@ -11063,16 +11217,16 @@ const usePanelLayout = (t0) => {
11063
11217
  }
11064
11218
  useEffect(t4, t5);
11065
11219
  let t6;
11066
- if ($[14] !== availableWidth || $[15] !== outline || $[16] !== pageWidth) {
11220
+ if ($[14] !== availableWidth || $[15] !== pageWidth || $[16] !== requestedOutline) {
11067
11221
  t6 = () => computePanelLayout({
11068
11222
  availableWidth,
11069
11223
  pageWidth,
11070
- outline,
11224
+ outline: requestedOutline,
11071
11225
  comments: "open"
11072
11226
  });
11073
11227
  $[14] = availableWidth;
11074
- $[15] = outline;
11075
- $[16] = pageWidth;
11228
+ $[15] = pageWidth;
11229
+ $[16] = requestedOutline;
11076
11230
  $[17] = t6;
11077
11231
  } else t6 = $[17];
11078
11232
  const layoutWithCommentsOpen = t6;
@@ -12773,7 +12927,7 @@ function sanitizeControlledComments(comments) {
12773
12927
  }
12774
12928
  return sanitized;
12775
12929
  }
12776
- function useFolioComments({ doc, autoOpenReviewSidebar, anchorPositions, editorContentRef, commentsProp, onCommentsChange }) {
12930
+ function useFolioComments({ doc, autoOpenReviewSidebar, anchorPositions, editorContentRef, commentsProp, onCommentsChange, committedComments }) {
12777
12931
  const [showCommentsSidebar, setShowCommentsSidebar] = useState(false);
12778
12932
  const [visibleCommentAuthors, setVisibleCommentAuthors] = useState(null);
12779
12933
  const [activeCommentId, setActiveCommentId] = useState(null);
@@ -12810,11 +12964,10 @@ function useFolioComments({ doc, autoOpenReviewSidebar, anchorPositions, editorC
12810
12964
  const [floatingCommentBtn, setFloatingCommentBtn] = useState(null);
12811
12965
  const commentsLoadedRef = useRef(false);
12812
12966
  useEffect(() => {
12813
- if (isControlledComments || commentsLoadedRef.current) return;
12814
- if (!doc) return;
12815
- const bodyComments = doc.package.document.comments;
12967
+ if (commentsLoadedRef.current || committedComments == null && isControlledComments) return;
12968
+ const bodyComments = committedComments ?? doc?.package.document.comments;
12816
12969
  if (bodyComments && bodyComments.length > 0) {
12817
- setComments(bodyComments);
12970
+ if (committedComments == null && doc?.package.document.comments) setComments(doc.package.document.comments);
12818
12971
  setVisibleCommentAuthors(null);
12819
12972
  setActiveCommentId(null);
12820
12973
  if (autoOpenReviewSidebar && countOpenCommentThreads(bodyComments) > 0) setShowCommentsSidebar(true);
@@ -12822,14 +12975,16 @@ function useFolioComments({ doc, autoOpenReviewSidebar, anchorPositions, editorC
12822
12975
  }
12823
12976
  }, [
12824
12977
  autoOpenReviewSidebar,
12978
+ committedComments,
12825
12979
  doc,
12826
12980
  isControlledComments,
12827
12981
  setComments
12828
12982
  ]);
12983
+ const listedComments = committedComments ?? comments;
12829
12984
  const commentAuthors = useMemo(() => {
12830
12985
  const seen = /* @__PURE__ */ new Set();
12831
12986
  const authors = [];
12832
- for (const comment of comments) {
12987
+ for (const comment of listedComments) {
12833
12988
  const commentAuthor = getCommentAuthorKey(comment.author);
12834
12989
  if (!seen.has(commentAuthor)) {
12835
12990
  seen.add(commentAuthor);
@@ -12837,26 +12992,26 @@ function useFolioComments({ doc, autoOpenReviewSidebar, anchorPositions, editorC
12837
12992
  }
12838
12993
  }
12839
12994
  return authors;
12840
- }, [comments]);
12995
+ }, [listedComments]);
12841
12996
  const visibleCommentAuthorSet = useMemo(() => visibleCommentAuthors ?? new Set(commentAuthors), [visibleCommentAuthors, commentAuthors]);
12842
12997
  const visibleCommentIds = useMemo(() => {
12843
12998
  const ids = /* @__PURE__ */ new Set([-1]);
12844
- for (const comment_0 of comments) if (visibleCommentAuthorSet.has(getCommentAuthorKey(comment_0.author))) ids.add(comment_0.id);
12999
+ for (const comment_0 of listedComments) if (visibleCommentAuthorSet.has(getCommentAuthorKey(comment_0.author))) ids.add(comment_0.id);
12845
13000
  return ids;
12846
- }, [comments, visibleCommentAuthorSet]);
13001
+ }, [listedComments, visibleCommentAuthorSet]);
12847
13002
  const visibleComments = useMemo(() => {
12848
13003
  const visibleRootIds = /* @__PURE__ */ new Set();
12849
- for (const comment_1 of comments) {
13004
+ for (const comment_1 of listedComments) {
12850
13005
  const parentId_0 = getCommentParentId(comment_1);
12851
13006
  if (parentId_0 === null || parentId_0 === void 0 || !visibleCommentIds.has(comment_1.id)) continue;
12852
13007
  visibleRootIds.add(parentId_0);
12853
13008
  }
12854
- return comments.filter((comment_2) => {
13009
+ return listedComments.filter((comment_2) => {
12855
13010
  const parentId_1 = getCommentParentId(comment_2);
12856
13011
  if (parentId_1 !== null && parentId_1 !== void 0) return visibleCommentIds.has(comment_2.id);
12857
13012
  return visibleCommentIds.has(comment_2.id) || visibleRootIds.has(comment_2.id);
12858
13013
  });
12859
- }, [comments, visibleCommentIds]);
13014
+ }, [listedComments, visibleCommentIds]);
12860
13015
  const activeCommentVisible = activeCommentId !== null && visibleCommentIds.has(activeCommentId);
12861
13016
  useEffect(() => {
12862
13017
  if (!activeCommentVisible) setActiveCommentId(null);
@@ -12949,7 +13104,7 @@ function useFolioComments({ doc, autoOpenReviewSidebar, anchorPositions, editorC
12949
13104
  */
12950
13105
  /** No headings to track while the outline is not shown. */
12951
13106
  const NO_HEADINGS = [];
12952
- const CommentsSidebar = lazy(() => import("./CommentsSidebar-D9vMIMl7.js").then((m) => ({ default: m.CommentsSidebar })));
13107
+ const CommentsSidebar = lazy(() => import("./CommentsSidebar-IR9uTkkk.js").then((m) => ({ default: m.CommentsSidebar })));
12953
13108
  const TextContextMenu = lazy(() => import("./TextContextMenu-Bqth8itn.js").then((m) => ({ default: m.TextContextMenu })));
12954
13109
  const loadAttemptSelectiveSave = async () => {
12955
13110
  const { attemptSelectiveSave } = await import("@stll/folio-core/docx/selectiveSave");
@@ -13020,8 +13175,14 @@ function areActiveTrackedChangesEqual(a, b) {
13020
13175
  /**
13021
13176
  * DocxEditor - Complete DOCX editor component
13022
13177
  */
13023
- const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, document: initialDocument, onSave, author = "User", onChange, onSelectionChange, onSelectionTextChange, onError, onFontsLoaded: onFontsLoadedCallback, fontFamilies, fonts, theme, showToolbar = true, showZoomControl = true, showReviewControls = true, showHeaderFooterEditing = true, pageRenderer, showMarginGuides = false, marginGuideColor, showRuler: showRulerProp = false, rulerUnit = "inch", initialZoom = 1, enableWheelZoom = true, keyboardShortcuts = "document", hostShortcuts: hostShortcutsProp, readOnly: readOnlyProp = false, autoOpenReviewSidebar = true, components, toolbarExtra, className = "", style, placeholder, loadingIndicator, preserveDocumentWhileLoading = false, initialScrollTop, onScrollTopChange, showOutline: showOutlineProp = true, onPrint, onInsertImage, onInsertTable, showTableInsert = true, onInsertPageBreak, onInsertTOC, onCopy, onCut, onPaste, mode: modeProp, onModeChange, onReadonlyEditAttempt, onCompatibilityChange, onEditorViewReady, onAnonymizationMatchesChange, onAnonymizationTermClick, selectedAnonymizationCanonical = null, anonymizationSelectionSeq, showTemplateDirectives = false, onSlashMenuChange, onSlashMenuKeyAction, customContextMenuItems, onCustomContextAction, comments: commentsProp, onCommentsChange, collaboration, plugins, featureFlags, experimentalSession, onSelectiveSaveTripwire }, ref) {
13178
+ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, document: initialDocument, onSave, author = "User", onChange, onSelectionChange, onSelectionTextChange, onError, onFontsLoaded: onFontsLoadedCallback, fontFamilies, fonts, theme, showToolbar = true, showZoomControl = true, showReviewControls = true, showHeaderFooterEditing = true, pageRenderer, showMarginGuides = false, marginGuideColor, showRuler: showRulerProp = false, rulerUnit = "inch", initialZoom = 1, enableWheelZoom = true, keyboardShortcuts = "document", hostShortcuts: hostShortcutsProp, readOnly: readOnlyProp = false, autoOpenReviewSidebar = true, components, toolbarExtra, className = "", style, placeholder, loadingIndicator, preserveDocumentWhileLoading = false, initialScrollTop, onScrollTopChange, showOutline: showOutlineProp = true, outlineDepth: outlineDepthProp, onOutlineDepthChange, onPrint, onInsertImage, onInsertTable, showTableInsert = true, onInsertPageBreak, onInsertTOC, onCopy, onCut, onPaste, mode: modeProp, onModeChange, onReadonlyEditAttempt, onCompatibilityChange, onEditorViewReady, onAnonymizationMatchesChange, onAnonymizationTermClick, selectedAnonymizationCanonical = null, anonymizationSelectionSeq, showTemplateDirectives = false, onSlashMenuChange, onSlashMenuKeyAction, customContextMenuItems, onCustomContextAction, comments: commentsProp, onCommentsChange, collaboration, plugins, featureFlags, experimentalSession, onSelectiveSaveTripwire }, ref) {
13024
13179
  const t = useTranslations("folio");
13180
+ const [outlineDepthState, setOutlineDepthState] = useState(DEFAULT_OUTLINE_DEPTH);
13181
+ const outlineDepth = outlineDepthProp ?? outlineDepthState;
13182
+ const handleOutlineDepthChange = useCallback((depth) => {
13183
+ if (outlineDepthProp === void 0) setOutlineDepthState(depth);
13184
+ onOutlineDepthChange?.(depth);
13185
+ }, [onOutlineDepthChange, outlineDepthProp]);
13025
13186
  useEffect(() => {
13026
13187
  const onClipboardReadError = () => {
13027
13188
  toast(t("clipboardReadFailed"));
@@ -13059,25 +13220,17 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13059
13220
  const [, setTrackedChanges] = useState([]);
13060
13221
  const trackedChangesRef = useRef([]);
13061
13222
  const [anchorPositions, setAnchorPositions] = useState(EMPTY_ANCHOR_POSITIONS);
13062
- const { editingMode, readOnly, trackChangesOn, toggleTrackChanges: toggleTrackChangesUnrestricted, displayMode, setDisplayMode } = useEditorMode({
13223
+ const { editingMode, readOnly, trackChangesOn, toggleTrackChanges, displayMode, setDisplayMode } = useEditorMode({
13063
13224
  modeProp,
13064
13225
  onModeChange,
13065
13226
  readOnlyProp
13066
13227
  });
13067
- const toggleTrackChanges = useCallback(() => {
13068
- if (experimentalSession === "canonical" && !trackChangesOn) {
13069
- const error = new CanonicalSessionRefusalError({ message: "Canonical sessions do not support suggesting mode." });
13070
- toast(error.message);
13071
- onError?.(error);
13072
- return;
13073
- }
13074
- toggleTrackChangesUnrestricted();
13075
- }, [
13076
- experimentalSession,
13077
- trackChangesOn,
13078
- onError,
13079
- toggleTrackChangesUnrestricted
13080
- ]);
13228
+ useEffect(() => {
13229
+ pagedEditorRef.current?.getEditor().setCanonicalMode(editingMode === "suggesting" ? {
13230
+ type: "suggesting",
13231
+ author
13232
+ } : { type: "editing" });
13233
+ }, [editingMode, author]);
13081
13234
  const extractTrackedChangesTimerRef = useRef(null);
13082
13235
  const collectHeadingsTimerRef = useRef(null);
13083
13236
  const extractTrackedChanges = useCallback(() => {
@@ -13126,13 +13279,16 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13126
13279
  const history = useDocumentHistory(initialDocument || null, {
13127
13280
  maxEntries: 100,
13128
13281
  groupingInterval: 500,
13129
- enableKeyboardShortcuts: historyShortcuts === "editor" && experimentalSession !== "canonical"
13282
+ enableKeyboardShortcuts: historyShortcuts === "editor" && !usesCanonicalSession(experimentalSession, CANONICAL_GAP.history)
13130
13283
  });
13131
- const refuseCanonicalModelEdit = useCallback((message) => {
13132
- if (experimentalSession !== "canonical") return false;
13133
- const error_0 = new CanonicalSessionRefusalError({ message });
13134
- toast(error_0.message);
13135
- onError?.(error_0);
13284
+ const refuseCanonicalModelEdit = useCallback((gap, message) => {
13285
+ if (!usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting)) return false;
13286
+ const error = new CanonicalSessionRefusalError({
13287
+ gap,
13288
+ message: canonicalRefusalMessage(gap, message)
13289
+ });
13290
+ toast(error.message);
13291
+ onError?.(error);
13136
13292
  return true;
13137
13293
  }, [experimentalSession, onError]);
13138
13294
  const extensionManager = useMemo(() => {
@@ -13316,14 +13472,23 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13316
13472
  size: 4,
13317
13473
  color: { rgb: "000000" }
13318
13474
  });
13319
- const { comments, createComment, setComments, commentsRef, commentsDirtyRef, commentsLoadedRef, showCommentsSidebar, setShowCommentsSidebar, setVisibleCommentAuthors, activeCommentId, setActiveCommentId, isAddingComment, setIsAddingComment, commentSelectionRange, setCommentSelectionRange, addCommentYPosition, setAddCommentYPosition, floatingCommentBtn, setFloatingCommentBtn, commentAuthors, visibleCommentAuthorSet, visibleComments, syncCommentHighlightStyles } = useFolioComments({
13320
- doc: history.state,
13475
+ const canonicalCommentApi = pagedEditorRef.current?.getEditor();
13476
+ const canonicalCommentsVersion = canonicalCommentApi?.getCanonicalCommittedVersion() ?? null;
13477
+ const canonicalComments = useMemo(() => canonicalCommentsVersion === null ? null : canonicalCommentApi?.getCanonicalComments() ?? null, [canonicalCommentApi, canonicalCommentsVersion]);
13478
+ const canonicalCommentsSerialized = useMemo(() => canonicalComments === null ? null : JSON.stringify(canonicalComments), [canonicalComments]);
13479
+ const canonicalCommentsSnapshotRef = useRef(canonicalCommentsSerialized);
13480
+ const lastControlledCommentsRef = useRef(void 0);
13481
+ const { comments: legacyComments, createComment, setComments, commentsRef, commentsDirtyRef, commentsLoadedRef, showCommentsSidebar, setShowCommentsSidebar, setVisibleCommentAuthors, activeCommentId, setActiveCommentId, isAddingComment, setIsAddingComment, commentSelectionRange, setCommentSelectionRange, addCommentYPosition, setAddCommentYPosition, floatingCommentBtn, setFloatingCommentBtn, commentAuthors, visibleCommentAuthorSet, visibleComments, syncCommentHighlightStyles } = useFolioComments({
13482
+ doc: canonicalComments === null ? history.state : null,
13321
13483
  autoOpenReviewSidebar,
13322
13484
  anchorPositions,
13323
13485
  editorContentRef,
13324
13486
  commentsProp,
13325
- onCommentsChange
13487
+ onCommentsChange,
13488
+ committedComments: canonicalComments
13326
13489
  });
13490
+ const comments = canonicalComments ?? legacyComments;
13491
+ const commentDraftMode = usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting) ? "canonical" : "prosemirror";
13327
13492
  const documentOperationUndoEntriesRef = useRef([]);
13328
13493
  const pendingSuggestionRegistryRef = useRef(new FolioPendingSuggestionRegistry());
13329
13494
  const styleResolverCacheRef = useRef(null);
@@ -13372,11 +13537,12 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13372
13537
  history,
13373
13538
  pushDocument,
13374
13539
  getCanonicalApi,
13375
- ...experimentalSession === void 0 ? {} : { experimentalSession },
13540
+ ...!usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting) ? {} : { experimentalSession },
13376
13541
  getHfView: (rId) => pagedEditorRef.current?.getHfView(rId) ?? null
13377
13542
  });
13378
13543
  let activeHfRId = hfEditIsFirstPage ? activeFirstFooterRId : activeFooterRId;
13379
13544
  if (hfEditPosition === "header") activeHfRId = hfEditIsFirstPage ? activeFirstHeaderRId : activeHeaderRId;
13545
+ const visibleOutlineHeadings = useMemo(() => filterHeadingsByDepth(outlineHeadings, outlineDepth), [outlineDepth, outlineHeadings]);
13380
13546
  const panels = usePanelLayout({
13381
13547
  pageWidth: (widestLaidOutPageWidth ?? getPageSize(effectiveSectionProperties).w) * zoom,
13382
13548
  outline: showOutline && outlineHeadings.length > 1 ? "available" : "absent",
@@ -13389,7 +13555,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13389
13555
  if (panels.layout.comments === "drawer" && panelOverlay === "comments") return "drawer";
13390
13556
  return null;
13391
13557
  })();
13392
- const { activeId: activeHeadingId, markJumped: markHeadingJumped } = useActiveHeading(scrollContainerRef, panels.layout.outline === "none" ? NO_HEADINGS : outlineHeadings);
13558
+ const { activeId: activeHeadingId, markJumped: markHeadingJumped } = useActiveHeading(scrollContainerRef, panels.layout.outline === "none" ? NO_HEADINGS : visibleOutlineHeadings);
13393
13559
  const closePanelOverlay = useCallback(() => setPanelOverlay("none"), [setPanelOverlay]);
13394
13560
  const toggleOutlineOverlay = useCallback(() => setPanelOverlay(panelOverlay === "outline" ? "none" : "outline"), [panelOverlay, setPanelOverlay]);
13395
13561
  const getActiveEditorStory = useCallback(() => {
@@ -13405,7 +13571,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13405
13571
  else pagedEditorRef.current?.focus();
13406
13572
  }, [getActiveEditorStory]);
13407
13573
  const undoActiveEditor = useCallback(() => {
13408
- if (experimentalSession !== "canonical" && getActiveEditorStory().type === "headerFooter" && hfEditorRef.current) hfEditorRef.current.undo();
13574
+ if (!usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting) && getActiveEditorStory().type === "headerFooter" && hfEditorRef.current) hfEditorRef.current.undo();
13409
13575
  else {
13410
13576
  pagedEditorRef.current?.undo();
13411
13577
  requestAnimationFrame(refreshBodyHistoryAvailability);
@@ -13416,7 +13582,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13416
13582
  experimentalSession
13417
13583
  ]);
13418
13584
  const redoActiveEditor = useCallback(() => {
13419
- if (experimentalSession !== "canonical" && getActiveEditorStory().type === "headerFooter" && hfEditorRef.current) hfEditorRef.current.redo();
13585
+ if (!usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting) && getActiveEditorStory().type === "headerFooter" && hfEditorRef.current) hfEditorRef.current.redo();
13420
13586
  else {
13421
13587
  pagedEditorRef.current?.redo();
13422
13588
  requestAnimationFrame(refreshBodyHistoryAvailability);
@@ -13449,7 +13615,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13449
13615
  documentBuffer: documentBuffer ?? null,
13450
13616
  initialDocument: initialDocument ?? null,
13451
13617
  password,
13452
- ...experimentalSession === void 0 ? {} : { experimentalSession },
13618
+ ...!usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting) ? {} : { experimentalSession },
13453
13619
  history,
13454
13620
  onError,
13455
13621
  onCompatibilityChange,
@@ -13551,8 +13717,9 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13551
13717
  if (view_4) setSuggestionMode(editingMode === "suggesting", view_4.state, view_4.dispatch, author);
13552
13718
  }, [editingMode, author]);
13553
13719
  const handleDocumentChange = useCallback((newDocument) => {
13720
+ const canonical = usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting);
13554
13721
  const currentComments = commentsRef.current;
13555
- const documentWithComments = {
13722
+ const documentWithComments = canonical ? newDocument : {
13556
13723
  ...newDocument,
13557
13724
  package: {
13558
13725
  ...newDocument.package,
@@ -13563,7 +13730,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13563
13730
  }
13564
13731
  };
13565
13732
  pushDocument(documentWithComments);
13566
- onChange?.(experimentalSession === "canonical" ? cloneDocumentWithParagraphPropertySources(documentWithComments) : documentWithComments);
13733
+ onChange?.(canonical ? cloneDocumentWithParagraphPropertySources(documentWithComments) : documentWithComments);
13567
13734
  if (showOutlineRef.current) {
13568
13735
  if (collectHeadingsTimerRef.current) clearTimeout(collectHeadingsTimerRef.current);
13569
13736
  collectHeadingsTimerRef.current = setTimeout(() => {
@@ -13585,13 +13752,15 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13585
13752
  extractTrackedChanges,
13586
13753
  refreshBodyHistoryAvailability,
13587
13754
  commentsRef,
13588
- experimentalSession
13755
+ experimentalSession,
13756
+ history.state,
13757
+ onCommentsChange
13589
13758
  ]);
13590
13759
  const buildCurrentDocument = useCallback(() => {
13591
13760
  if (!history.state) return null;
13592
- const canonical = pagedEditorRef.current?.getEditor().getCanonicalDocument();
13593
- if (canonical) return canonical;
13594
- if (experimentalSession === "canonical") return null;
13761
+ const canonical_0 = pagedEditorRef.current?.getEditor().getCanonicalDocument();
13762
+ if (canonical_0) return canonical_0;
13763
+ if (usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting)) return null;
13595
13764
  let doc_0 = cloneDocumentWithParagraphPropertySources(history.state);
13596
13765
  const pmDoc = pagedEditorRef.current?.getDocument();
13597
13766
  if (pmDoc) {
@@ -13621,11 +13790,14 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13621
13790
  commentsRef,
13622
13791
  experimentalSession
13623
13792
  ]);
13793
+ const applyCanonicalComment = useCallback((request) => {
13794
+ return getCanonicalApi()?.applyCanonicalComment(request) ?? null;
13795
+ }, [getCanonicalApi]);
13624
13796
  const replaceComments = useCallback((nextComments) => {
13625
- if (experimentalSession === "canonical") {
13626
- refuseCanonicalModelEdit("Comment changes are unavailable in this session.");
13627
- return;
13628
- }
13797
+ if (applyCanonicalComment({
13798
+ type: "replace",
13799
+ comments: nextComments
13800
+ }) !== null) return;
13629
13801
  commentsDirtyRef.current = true;
13630
13802
  setComments(nextComments);
13631
13803
  const currentDocument = buildCurrentDocument();
@@ -13635,13 +13807,57 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13635
13807
  buildCurrentDocument,
13636
13808
  commentsDirtyRef,
13637
13809
  experimentalSession,
13810
+ applyCanonicalComment,
13638
13811
  onChange,
13639
- refuseCanonicalModelEdit,
13640
13812
  setComments
13641
13813
  ]);
13642
13814
  const updateComments = useCallback((updater) => {
13643
13815
  replaceComments(updater(commentsRef.current));
13644
13816
  }, [commentsRef, replaceComments]);
13817
+ const [controlledCommentsRetry, setControlledCommentsRetry] = useState(0);
13818
+ useEffect(() => {
13819
+ if (commentsProp === void 0 || canonicalComments === null) {
13820
+ lastControlledCommentsRef.current = void 0;
13821
+ return;
13822
+ }
13823
+ const requested = JSON.stringify(legacyComments);
13824
+ if (lastControlledCommentsRef.current === requested) return;
13825
+ if (canonicalCommentsSerialized === requested) {
13826
+ lastControlledCommentsRef.current = requested;
13827
+ return;
13828
+ }
13829
+ const result = applyCanonicalComment({
13830
+ type: "replace",
13831
+ comments: legacyComments
13832
+ });
13833
+ if (result?.status === "applied") {
13834
+ lastControlledCommentsRef.current = requested;
13835
+ return;
13836
+ }
13837
+ if (result?.status !== "refused" || result.retry !== "afterComposition") return;
13838
+ const view_7 = getCanonicalApi()?.getView();
13839
+ if (!view_7) return;
13840
+ return afterCanonicalCompositionSettles(view_7, () => setControlledCommentsRetry((attempt) => attempt + 1));
13841
+ }, [
13842
+ applyCanonicalComment,
13843
+ commentsProp,
13844
+ controlledCommentsRetry,
13845
+ getCanonicalApi,
13846
+ legacyComments,
13847
+ canonicalCommentsSerialized
13848
+ ]);
13849
+ useEffect(() => {
13850
+ if (canonicalComments === null) return;
13851
+ const nextComments_0 = canonicalComments;
13852
+ const serialized = canonicalCommentsSerialized;
13853
+ if (canonicalCommentsSnapshotRef.current === null) {
13854
+ canonicalCommentsSnapshotRef.current = serialized;
13855
+ return;
13856
+ }
13857
+ if (canonicalCommentsSnapshotRef.current === serialized) return;
13858
+ canonicalCommentsSnapshotRef.current = serialized;
13859
+ onCommentsChange?.(structuredClone(nextComments_0));
13860
+ }, [canonicalCommentsSerialized, onCommentsChange]);
13645
13861
  const { findResultRef, handleFind, handleFindNext, handleFindPrevious, handleReplace, handleReplaceAll } = useFindReplace({
13646
13862
  getDocumentState: buildCurrentDocument,
13647
13863
  containerRef,
@@ -13649,9 +13865,9 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13649
13865
  findReplace,
13650
13866
  selectMatch: useCallback((match) => {
13651
13867
  const editor_0 = pagedEditorRef.current;
13652
- const view_7 = editor_0?.getView();
13653
- if (!editor_0 || !view_7) return false;
13654
- const range = resolveFindMatchRange(view_7.state.doc, match);
13868
+ const view_8 = editor_0?.getView();
13869
+ if (!editor_0 || !view_8) return false;
13870
+ const range = resolveFindMatchRange(view_8.state.doc, match);
13655
13871
  if (!range) return false;
13656
13872
  editor_0.setSelection(range.from, range.to);
13657
13873
  requestAnimationFrame(() => {
@@ -13661,17 +13877,17 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13661
13877
  }, [])
13662
13878
  });
13663
13879
  const handleSelectionChange = useCallback((selectionState) => {
13664
- const view_8 = getActiveEditorView();
13665
- if (view_8) {
13666
- const { from, to } = view_8.state.selection;
13880
+ const view_9 = getActiveEditorView();
13881
+ if (view_9) {
13882
+ const { from, to } = view_9.state.selection;
13667
13883
  lastSelectionRef.current = {
13668
13884
  from,
13669
13885
  to
13670
13886
  };
13671
13887
  }
13672
13888
  let pmTableCtx = null;
13673
- if (view_8) {
13674
- pmTableCtx = getTableContext(view_8.state);
13889
+ if (view_9) {
13890
+ pmTableCtx = getTableContext(view_9.state);
13675
13891
  if (!pmTableCtx.isInTable) pmTableCtx = null;
13676
13892
  }
13677
13893
  if (pmTableCtx?.cellBorderColor) {
@@ -13683,8 +13899,8 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13683
13899
  color: { rgb }
13684
13900
  };
13685
13901
  }
13686
- const pmImageCtx = view_8 ? detectImageContext(view_8.state) : null;
13687
- const trackedChange = view_8 ? detectActiveTrackedChange(view_8.state) : null;
13902
+ const pmImageCtx = view_9 ? detectImageContext(view_9.state) : null;
13903
+ const trackedChange = view_9 ? detectActiveTrackedChange(view_9.state) : null;
13688
13904
  if (!selectionState) {
13689
13905
  setFloatingCommentBtn(null);
13690
13906
  setState((prev_1) => {
@@ -13747,10 +13963,10 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13747
13963
  activeTrackedChange: activeTrackedChange_0
13748
13964
  };
13749
13965
  });
13750
- if (view_8 && selectionState.hasSelection && !isAddingComment && !readOnly) {
13966
+ if (view_9 && selectionState.hasSelection && !isAddingComment && !readOnly) {
13751
13967
  const container = scrollContainerRef.current;
13752
13968
  const parentEl = editorContentRef.current;
13753
- const { from: selFrom } = view_8.state.selection;
13969
+ const { from: selFrom } = view_9.state.selection;
13754
13970
  const top = findSelectionYPosition(container, parentEl, selFrom);
13755
13971
  if (top !== null && container && parentEl) {
13756
13972
  const pagesEl = container.querySelector(".paged-editor__pages");
@@ -13758,7 +13974,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13758
13974
  const parentRect = parentEl.getBoundingClientRect();
13759
13975
  const rawLeft = pageEl ? pageEl.getBoundingClientRect().right - parentRect.left + 12 : parentRect.width / 2 + 408;
13760
13976
  const left = Math.max(16, Math.min(rawLeft, parentRect.width - 16));
13761
- const { from: from_0, to: to_0 } = view_8.state.selection;
13977
+ const { from: from_0, to: to_0 } = view_9.state.selection;
13762
13978
  if (from_0 !== to_0) setFloatingCommentBtn({
13763
13979
  top,
13764
13980
  left,
@@ -13889,16 +14105,15 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13889
14105
  roots: shortcutRoots
13890
14106
  });
13891
14107
  const handleApplyFootnoteProperties = useCallback((footnotePr, endnotePr) => {
13892
- if (experimentalSession === "canonical") {
13893
- const api = getCanonicalApi();
13894
- api?.ensureView();
13895
- const canonical_0 = api?.getCanonicalDocument();
13896
- if (!canonical_0 || !api?.applyCanonicalOperations([createCanonicalSectionPropertiesOperation(canonical_0, {
13897
- footnotePr,
13898
- endnotePr
13899
- })])) refuseCanonicalModelEdit("Section property changes could not be applied.");
14108
+ const api = getCanonicalApi();
14109
+ if (!api) {
14110
+ refuseCanonicalModelEdit(CANONICAL_GAP.sectionProperties, "The editor is not ready for section changes.");
13900
14111
  return;
13901
14112
  }
14113
+ if (api.applyCanonicalSectionProperties({
14114
+ footnotePr,
14115
+ endnotePr
14116
+ }) !== null) return;
13902
14117
  if (!history.state?.package) return;
13903
14118
  const newDoc = {
13904
14119
  ...history.state.package.document,
@@ -13918,103 +14133,102 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13918
14133
  }, [
13919
14134
  history,
13920
14135
  pushDocument,
13921
- experimentalSession,
13922
14136
  getCanonicalApi,
13923
14137
  refuseCanonicalModelEdit
13924
14138
  ]);
13925
14139
  const handleTableAction = useCallback((action_0) => {
13926
- const view_9 = getActiveEditorView();
13927
- if (!view_9) return;
14140
+ const view_10 = getActiveEditorView();
14141
+ if (!view_10) return;
13928
14142
  switch (action_0) {
13929
14143
  case "addRowAbove":
13930
- addRowAbove(view_9.state, view_9.dispatch);
14144
+ addRowAbove(view_10.state, view_10.dispatch);
13931
14145
  break;
13932
14146
  case "addRowBelow":
13933
- addRowBelow(view_9.state, view_9.dispatch);
14147
+ addRowBelow(view_10.state, view_10.dispatch);
13934
14148
  break;
13935
14149
  case "addColumnLeft":
13936
- addColumnLeft(view_9.state, view_9.dispatch);
14150
+ addColumnLeft(view_10.state, view_10.dispatch);
13937
14151
  break;
13938
14152
  case "addColumnRight":
13939
- addColumnRight(view_9.state, view_9.dispatch);
14153
+ addColumnRight(view_10.state, view_10.dispatch);
13940
14154
  break;
13941
14155
  case "deleteRow":
13942
- deleteRow(view_9.state, view_9.dispatch);
14156
+ deleteRow(view_10.state, view_10.dispatch);
13943
14157
  break;
13944
14158
  case "deleteColumn":
13945
- deleteColumn(view_9.state, view_9.dispatch);
14159
+ deleteColumn(view_10.state, view_10.dispatch);
13946
14160
  break;
13947
14161
  case "deleteTable":
13948
- deleteTable(view_9.state, view_9.dispatch);
14162
+ deleteTable(view_10.state, view_10.dispatch);
13949
14163
  break;
13950
14164
  case "selectTable":
13951
- selectTable(view_9.state, view_9.dispatch);
14165
+ selectTable(view_10.state, view_10.dispatch);
13952
14166
  break;
13953
14167
  case "selectRow":
13954
- selectRow(view_9.state, view_9.dispatch);
14168
+ selectRow(view_10.state, view_10.dispatch);
13955
14169
  break;
13956
14170
  case "selectColumn":
13957
- selectColumn(view_9.state, view_9.dispatch);
14171
+ selectColumn(view_10.state, view_10.dispatch);
13958
14172
  break;
13959
14173
  case "mergeCells":
13960
- mergeCells(view_9.state, view_9.dispatch);
14174
+ mergeCells(view_10.state, view_10.dispatch);
13961
14175
  break;
13962
14176
  case "splitCell":
13963
- splitCell(view_9.state, view_9.dispatch);
14177
+ splitCell(view_10.state, view_10.dispatch);
13964
14178
  break;
13965
14179
  case "borderAll":
13966
- setAllTableBorders(view_9.state, view_9.dispatch, borderSpecRef.current);
14180
+ setAllTableBorders(view_10.state, view_10.dispatch, borderSpecRef.current);
13967
14181
  break;
13968
14182
  case "borderOutside":
13969
- setOutsideTableBorders(view_9.state, view_9.dispatch, borderSpecRef.current);
14183
+ setOutsideTableBorders(view_10.state, view_10.dispatch, borderSpecRef.current);
13970
14184
  break;
13971
14185
  case "borderInside":
13972
- setInsideTableBorders(view_9.state, view_9.dispatch, borderSpecRef.current);
14186
+ setInsideTableBorders(view_10.state, view_10.dispatch, borderSpecRef.current);
13973
14187
  break;
13974
14188
  case "borderNone":
13975
- removeTableBorders(view_9.state, view_9.dispatch);
14189
+ removeTableBorders(view_10.state, view_10.dispatch);
13976
14190
  break;
13977
14191
  case "borderTop":
13978
- setCellBorder("top", borderSpecRef.current, true)(view_9.state, view_9.dispatch);
14192
+ setCellBorder("top", borderSpecRef.current, true)(view_10.state, view_10.dispatch);
13979
14193
  break;
13980
14194
  case "borderBottom":
13981
- setCellBorder("bottom", borderSpecRef.current, true)(view_9.state, view_9.dispatch);
14195
+ setCellBorder("bottom", borderSpecRef.current, true)(view_10.state, view_10.dispatch);
13982
14196
  break;
13983
14197
  case "borderLeft":
13984
- setCellBorder("left", borderSpecRef.current, true)(view_9.state, view_9.dispatch);
14198
+ setCellBorder("left", borderSpecRef.current, true)(view_10.state, view_10.dispatch);
13985
14199
  break;
13986
14200
  case "borderRight":
13987
- setCellBorder("right", borderSpecRef.current, true)(view_9.state, view_9.dispatch);
14201
+ setCellBorder("right", borderSpecRef.current, true)(view_10.state, view_10.dispatch);
13988
14202
  break;
13989
- default: if (typeof action_0 === "object") if (action_0.type === "cellFillColor") setCellFillColor(action_0.color)(view_9.state, view_9.dispatch);
14203
+ default: if (typeof action_0 === "object") if (action_0.type === "cellFillColor") setCellFillColor(action_0.color)(view_10.state, view_10.dispatch);
13990
14204
  else if (action_0.type === "borderColor") {
13991
14205
  const rgb_0 = action_0.color.replace(/^#/u, "");
13992
14206
  borderSpecRef.current = {
13993
14207
  ...borderSpecRef.current,
13994
14208
  color: { rgb: rgb_0 }
13995
14209
  };
13996
- setTableBorderColor(action_0.color)(view_9.state, view_9.dispatch);
14210
+ setTableBorderColor(action_0.color)(view_10.state, view_10.dispatch);
13997
14211
  } else if (action_0.type === "borderWidth") {
13998
14212
  borderSpecRef.current = {
13999
14213
  ...borderSpecRef.current,
14000
14214
  size: action_0.size
14001
14215
  };
14002
- setTableBorderWidth(action_0.size)(view_9.state, view_9.dispatch);
14216
+ setTableBorderWidth(action_0.size)(view_10.state, view_10.dispatch);
14003
14217
  } else if (action_0.type === "cellBorder") setCellBorder(action_0.side, {
14004
14218
  style: action_0.style,
14005
14219
  size: action_0.size,
14006
14220
  color: { rgb: action_0.color.replace(/^#/u, "") }
14007
- })(view_9.state, view_9.dispatch);
14008
- else if (action_0.type === "cellVerticalAlign") setCellVerticalAlign(action_0.align)(view_9.state, view_9.dispatch);
14009
- else if (action_0.type === "cellMargins") setCellMargins(action_0.margins)(view_9.state, view_9.dispatch);
14010
- else if (action_0.type === "cellTextDirection") setCellTextDirection(action_0.direction)(view_9.state, view_9.dispatch);
14011
- else if (action_0.type === "toggleNoWrap") toggleNoWrap()(view_9.state, view_9.dispatch);
14012
- else if (action_0.type === "rowHeight") setRowHeight(action_0.height, action_0.rule)(view_9.state, view_9.dispatch);
14013
- else if (action_0.type === "toggleHeaderRow") toggleHeaderRow()(view_9.state, view_9.dispatch);
14014
- else if (action_0.type === "distributeColumns") distributeColumns()(view_9.state, view_9.dispatch);
14015
- else if (action_0.type === "autoFitContents") autoFitContents()(view_9.state, view_9.dispatch);
14221
+ })(view_10.state, view_10.dispatch);
14222
+ else if (action_0.type === "cellVerticalAlign") setCellVerticalAlign(action_0.align)(view_10.state, view_10.dispatch);
14223
+ else if (action_0.type === "cellMargins") setCellMargins(action_0.margins)(view_10.state, view_10.dispatch);
14224
+ else if (action_0.type === "cellTextDirection") setCellTextDirection(action_0.direction)(view_10.state, view_10.dispatch);
14225
+ else if (action_0.type === "toggleNoWrap") toggleNoWrap()(view_10.state, view_10.dispatch);
14226
+ else if (action_0.type === "rowHeight") setRowHeight(action_0.height, action_0.rule)(view_10.state, view_10.dispatch);
14227
+ else if (action_0.type === "toggleHeaderRow") toggleHeaderRow()(view_10.state, view_10.dispatch);
14228
+ else if (action_0.type === "distributeColumns") distributeColumns()(view_10.state, view_10.dispatch);
14229
+ else if (action_0.type === "autoFitContents") autoFitContents()(view_10.state, view_10.dispatch);
14016
14230
  else if (action_0.type === "openTableProperties") setTablePropsOpen(true);
14017
- else if (action_0.type === "tableProperties") setTableProperties(action_0.props)(view_9.state, view_9.dispatch);
14231
+ else if (action_0.type === "tableProperties") setTableProperties(action_0.props)(view_10.state, view_10.dispatch);
14018
14232
  else {
14019
14233
  let preset = getBuiltinTableStyle(action_0.styleId);
14020
14234
  const currentDocForTable = historyStateRef.current;
@@ -14085,7 +14299,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14085
14299
  if (preset.tableBorders) styleArg.tableBorders = preset.tableBorders;
14086
14300
  if (preset.conditionals) styleArg.conditionals = preset.conditionals;
14087
14301
  if (preset.look) styleArg.look = preset.look;
14088
- applyTableStyle(styleArg)(view_9.state, view_9.dispatch);
14302
+ applyTableStyle(styleArg)(view_10.state, view_10.dispatch);
14089
14303
  }
14090
14304
  }
14091
14305
  else tableSelection.handleAction(action_0);
@@ -14106,86 +14320,86 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14106
14320
  });
14107
14321
  }, [openContextMenu]);
14108
14322
  const handleFormat = useCallback((action_1) => {
14109
- const view_10 = getActiveEditorView();
14110
- if (!view_10) return;
14111
- view_10.focus();
14112
- const isBodyEditor = view_10 === pagedEditorRef.current?.getView();
14113
- const { from: from_1, to: to_1 } = view_10.state.selection;
14323
+ const view_11 = getActiveEditorView();
14324
+ if (!view_11) return;
14325
+ view_11.focus();
14326
+ const isBodyEditor = view_11 === pagedEditorRef.current?.getView();
14327
+ const { from: from_1, to: to_1 } = view_11.state.selection;
14114
14328
  const savedSelection = lastSelectionRef.current;
14115
14329
  if (isBodyEditor && savedSelection && (from_1 !== savedSelection.from || to_1 !== savedSelection.to)) try {
14116
- const tr = view_10.state.tr.setSelection(TextSelection.create(view_10.state.doc, savedSelection.from, savedSelection.to));
14117
- view_10.dispatch(tr);
14330
+ const tr = view_11.state.tr.setSelection(TextSelection.create(view_11.state.doc, savedSelection.from, savedSelection.to));
14331
+ view_11.dispatch(tr);
14118
14332
  } catch {}
14119
14333
  if (action_1 === "bold") {
14120
- executeEditorCommand(view_10, toggleBold);
14334
+ executeEditorCommand(view_11, toggleBold);
14121
14335
  return;
14122
14336
  }
14123
14337
  if (action_1 === "italic") {
14124
- executeEditorCommand(view_10, toggleItalic);
14338
+ executeEditorCommand(view_11, toggleItalic);
14125
14339
  return;
14126
14340
  }
14127
14341
  if (action_1 === "underline") {
14128
- executeEditorCommand(view_10, toggleUnderline);
14342
+ executeEditorCommand(view_11, toggleUnderline);
14129
14343
  return;
14130
14344
  }
14131
14345
  if (action_1 === "strikethrough") {
14132
- executeEditorCommand(view_10, toggleStrike);
14346
+ executeEditorCommand(view_11, toggleStrike);
14133
14347
  return;
14134
14348
  }
14135
14349
  if (action_1 === "superscript") {
14136
- executeEditorCommand(view_10, toggleSuperscript);
14350
+ executeEditorCommand(view_11, toggleSuperscript);
14137
14351
  return;
14138
14352
  }
14139
14353
  if (action_1 === "subscript") {
14140
- executeEditorCommand(view_10, toggleSubscript);
14354
+ executeEditorCommand(view_11, toggleSubscript);
14141
14355
  return;
14142
14356
  }
14143
14357
  if (action_1 === "bulletList") {
14144
- executeEditorCommand(view_10, toggleBulletList);
14358
+ executeEditorCommand(view_11, toggleBulletList);
14145
14359
  return;
14146
14360
  }
14147
14361
  if (action_1 === "numberedList") {
14148
- executeEditorCommand(view_10, toggleNumberedList);
14362
+ executeEditorCommand(view_11, toggleNumberedList);
14149
14363
  return;
14150
14364
  }
14151
14365
  if (action_1 === "indent") {
14152
- executeFirstEditorCommand(view_10, [increaseListLevel, increaseIndent()]);
14366
+ executeFirstEditorCommand(view_11, [increaseListLevel, increaseIndent()]);
14153
14367
  return;
14154
14368
  }
14155
14369
  if (action_1 === "outdent") {
14156
- executeFirstEditorCommand(view_10, [decreaseListLevel, decreaseIndent()]);
14370
+ executeFirstEditorCommand(view_11, [decreaseListLevel, decreaseIndent()]);
14157
14371
  return;
14158
14372
  }
14159
14373
  if (action_1 === "clearFormatting") {
14160
- executeEditorCommand(view_10, clearFormatting);
14374
+ executeEditorCommand(view_11, clearFormatting);
14161
14375
  return;
14162
14376
  }
14163
14377
  if (action_1 === "setRtl") {
14164
- executeEditorCommand(view_10, setRtl);
14378
+ executeEditorCommand(view_11, setRtl);
14165
14379
  return;
14166
14380
  }
14167
14381
  if (action_1 === "setLtr") {
14168
- executeEditorCommand(view_10, setLtr);
14382
+ executeEditorCommand(view_11, setLtr);
14169
14383
  return;
14170
14384
  }
14171
14385
  if (action_1 === "insertPageBreak") {
14172
- executeEditorCommand(view_10, insertPageBreak);
14386
+ executeEditorCommand(view_11, insertPageBreak);
14173
14387
  return;
14174
14388
  }
14175
14389
  if (typeof action_1 === "object") switch (action_1.type) {
14176
14390
  case "alignment":
14177
- executeEditorCommand(view_10, setAlignment(action_1.value));
14391
+ executeEditorCommand(view_11, setAlignment(action_1.value));
14178
14392
  break;
14179
14393
  case "toggleDirection":
14180
- executeEditorCommand(view_10, toggleBidi);
14394
+ executeEditorCommand(view_11, toggleBidi);
14181
14395
  break;
14182
14396
  case "textColor": {
14183
14397
  const colorVal_0 = action_1.value;
14184
- if (typeof colorVal_0 === "string") executeEditorCommand(view_10, setTextColor({ rgb: colorVal_0.replace("#", "") }));
14185
- else if (colorVal_0.auto) executeEditorCommand(view_10, clearTextColor);
14398
+ if (typeof colorVal_0 === "string") executeEditorCommand(view_11, setTextColor({ rgb: colorVal_0.replace("#", "") }));
14399
+ else if (colorVal_0.auto) executeEditorCommand(view_11, clearTextColor);
14186
14400
  else {
14187
14401
  const themeColor = typeof colorVal_0.themeColor === "string" ? colorVal_0.themeColor : void 0;
14188
- executeEditorCommand(view_10, setTextColor({
14402
+ executeEditorCommand(view_11, setTextColor({
14189
14403
  ...colorVal_0.rgb === void 0 ? {} : { rgb: colorVal_0.rgb },
14190
14404
  ...themeColor ? { themeColor } : {},
14191
14405
  ...colorVal_0.themeTint === void 0 ? {} : { themeTint: colorVal_0.themeTint },
@@ -14195,16 +14409,16 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14195
14409
  break;
14196
14410
  }
14197
14411
  case "highlightColor":
14198
- executeEditorCommand(view_10, setHighlight((action_1.value ? mapHexToHighlightName(action_1.value) : "") || action_1.value));
14412
+ executeEditorCommand(view_11, setHighlight((action_1.value ? mapHexToHighlightName(action_1.value) : "") || action_1.value));
14199
14413
  break;
14200
14414
  case "fontSize":
14201
- executeEditorCommand(view_10, setFontSize(pointsToHalfPoints(action_1.value)));
14415
+ executeEditorCommand(view_11, setFontSize(pointsToHalfPoints(action_1.value)));
14202
14416
  break;
14203
14417
  case "fontFamily":
14204
- executeEditorCommand(view_10, setFontFamily(action_1.value));
14418
+ executeEditorCommand(view_11, setFontFamily(action_1.value));
14205
14419
  break;
14206
14420
  case "lineSpacing":
14207
- executeEditorCommand(view_10, setLineSpacing(action_1.value));
14421
+ executeEditorCommand(view_11, setLineSpacing(action_1.value));
14208
14422
  break;
14209
14423
  case "applyStyle": {
14210
14424
  const currentDoc_0 = historyStateRef.current;
@@ -14217,22 +14431,22 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14217
14431
  const styleName = styleResolver_0.getStyle(action_1.value)?.name;
14218
14432
  if (styleName) styleAttrs.styleName = styleName;
14219
14433
  styleAttrs.numbering = currentDoc_0?.package.numbering ? getCachedNumberingMap(currentDoc_0.package.numbering) : null;
14220
- executeEditorCommand(view_10, applyStyle(action_1.value, styleAttrs));
14221
- } else executeEditorCommand(view_10, applyStyle(action_1.value));
14434
+ executeEditorCommand(view_11, applyStyle(action_1.value, styleAttrs));
14435
+ } else executeEditorCommand(view_11, applyStyle(action_1.value));
14222
14436
  break;
14223
14437
  }
14224
14438
  default: break;
14225
14439
  }
14226
14440
  }, [getActiveEditorView, getCachedStyleResolver]);
14227
14441
  const captureFormatPainter = useCallback(() => {
14228
- const view_11 = getActiveEditorView();
14229
- capturedFormatMarksRef.current = view_11 ? captureFormatMarks(view_11.state) : null;
14442
+ const view_12 = getActiveEditorView();
14443
+ capturedFormatMarksRef.current = view_12 ? captureFormatMarks(view_12.state) : null;
14230
14444
  }, [getActiveEditorView]);
14231
14445
  const paintFormatToSelection = useCallback(() => {
14232
- const view_12 = getActiveEditorView();
14233
- if (!view_12) return false;
14234
- const applied = applyFormatMarks(capturedFormatMarksRef.current)(view_12.state, view_12.dispatch);
14235
- if (applied) requestAnimationFrame(() => view_12.focus());
14446
+ const view_13 = getActiveEditorView();
14447
+ if (!view_13) return false;
14448
+ const applied = applyFormatMarks(capturedFormatMarksRef.current)(view_13.state, view_13.dispatch);
14449
+ if (applied) requestAnimationFrame(() => view_13.focus());
14236
14450
  return applied;
14237
14451
  }, [getActiveEditorView]);
14238
14452
  const handleFormatPainter = useCallback((sticky) => {
@@ -14410,12 +14624,12 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14410
14624
  t
14411
14625
  ]);
14412
14626
  const handleContextMenuAction = useCallback(async (action_2) => {
14413
- const view_13 = getActiveEditorView();
14414
- if (!view_13) return;
14627
+ const view_14 = getActiveEditorView();
14628
+ if (!view_14) return;
14415
14629
  focusActiveEditor();
14416
14630
  if (readOnly && action_2 !== "copy" && action_2 !== "selectAll") return;
14417
14631
  if (action_2.startsWith("custom:")) {
14418
- const { from: from_2, to: to_2 } = contextMenu.selectionRange.from !== contextMenu.selectionRange.to ? contextMenu.selectionRange : view_13.state.selection;
14632
+ const { from: from_2, to: to_2 } = contextMenu.selectionRange.from !== contextMenu.selectionRange.to ? contextMenu.selectionRange : view_14.state.selection;
14419
14633
  onCustomContextAction?.(action_2.slice(7), {
14420
14634
  from: from_2,
14421
14635
  to: to_2
@@ -14425,16 +14639,16 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14425
14639
  switch (action_2) {
14426
14640
  case "cut": {
14427
14641
  if (readOnly) return;
14428
- const { from: from_7, to: to_7 } = view_13.state.selection;
14429
- const text_2 = view_13.state.doc.textBetween(from_7, to_7, "\n");
14642
+ const { from: from_7, to: to_7 } = view_14.state.selection;
14643
+ const text_2 = view_14.state.doc.textBetween(from_7, to_7, "\n");
14430
14644
  navigator.clipboard.writeText(text_2).catch(() => void 0);
14431
- if (!deleteSelectionAsSuggestion(view_13.state, view_13.dispatch)) view_13.dispatch(view_13.state.tr.deleteSelection());
14645
+ if (!deleteSelectionAsSuggestion(view_14.state, view_14.dispatch)) view_14.dispatch(view_14.state.tr.deleteSelection());
14432
14646
  onCut?.();
14433
14647
  break;
14434
14648
  }
14435
14649
  case "copy": {
14436
- const { from: cf, to: ct } = view_13.state.selection;
14437
- const copied = view_13.state.doc.textBetween(cf, ct, "\n");
14650
+ const { from: cf, to: ct } = view_14.state.selection;
14651
+ const copied = view_14.state.doc.textBetween(cf, ct, "\n");
14438
14652
  navigator.clipboard.writeText(copied).catch(() => void 0);
14439
14653
  onCopy?.();
14440
14654
  break;
@@ -14457,12 +14671,12 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14457
14671
  bubbles: true,
14458
14672
  cancelable: true
14459
14673
  });
14460
- view_13.dom.dispatchEvent(pasteEvent);
14674
+ view_14.dom.dispatchEvent(pasteEvent);
14461
14675
  } catch {
14462
14676
  try {
14463
14677
  const text_0 = await navigator.clipboard.readText();
14464
14678
  if (text_0) {
14465
- view_13.dispatch(view_13.state.tr.insertText(text_0));
14679
+ view_14.dispatch(view_14.state.tr.insertText(text_0));
14466
14680
  onPaste?.();
14467
14681
  }
14468
14682
  } catch {}
@@ -14471,9 +14685,9 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14471
14685
  case "pasteAsPlainText":
14472
14686
  try {
14473
14687
  const text = await navigator.clipboard.readText();
14474
- if (text && !view_13.isDestroyed) {
14475
- const slice = buildPlainTextSlice(text, view_13.state.schema);
14476
- view_13.dispatch(view_13.state.tr.replaceSelection(slice).scrollIntoView());
14688
+ if (text && !view_14.isDestroyed) {
14689
+ const slice = buildPlainTextSlice(text, view_14.state.schema);
14690
+ view_14.dispatch(view_14.state.tr.replaceSelection(slice).scrollIntoView());
14477
14691
  onPaste?.();
14478
14692
  }
14479
14693
  } catch {
@@ -14481,49 +14695,51 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14481
14695
  }
14482
14696
  break;
14483
14697
  case "delete": {
14484
- const { from: from_6, to: to_6 } = view_13.state.selection;
14485
- if (from_6 !== to_6) view_13.dispatch(view_13.state.tr.deleteRange(from_6, to_6));
14698
+ const { from: from_6, to: to_6 } = view_14.state.selection;
14699
+ if (from_6 !== to_6) view_14.dispatch(view_14.state.tr.deleteRange(from_6, to_6));
14486
14700
  break;
14487
14701
  }
14488
14702
  case "selectAll":
14489
- view_13.dispatch(view_13.state.tr.setSelection(TextSelection.create(view_13.state.doc, 0, view_13.state.doc.content.size)));
14703
+ view_14.dispatch(view_14.state.tr.setSelection(TextSelection.create(view_14.state.doc, 0, view_14.state.doc.content.size)));
14490
14704
  break;
14491
14705
  case "addRowAbove":
14492
- addRowAbove(view_13.state, view_13.dispatch);
14706
+ addRowAbove(view_14.state, view_14.dispatch);
14493
14707
  break;
14494
14708
  case "addRowBelow":
14495
- addRowBelow(view_13.state, view_13.dispatch);
14709
+ addRowBelow(view_14.state, view_14.dispatch);
14496
14710
  break;
14497
14711
  case "deleteRow":
14498
- deleteRow(view_13.state, view_13.dispatch);
14712
+ deleteRow(view_14.state, view_14.dispatch);
14499
14713
  break;
14500
14714
  case "addColumnLeft":
14501
- addColumnLeft(view_13.state, view_13.dispatch);
14715
+ addColumnLeft(view_14.state, view_14.dispatch);
14502
14716
  break;
14503
14717
  case "addColumnRight":
14504
- addColumnRight(view_13.state, view_13.dispatch);
14718
+ addColumnRight(view_14.state, view_14.dispatch);
14505
14719
  break;
14506
14720
  case "deleteColumn":
14507
- deleteColumn(view_13.state, view_13.dispatch);
14721
+ deleteColumn(view_14.state, view_14.dispatch);
14508
14722
  break;
14509
14723
  case "tableBordersAll":
14510
- setTableBorderPreset("all")(view_13.state, view_13.dispatch);
14724
+ setTableBorderPreset("all")(view_14.state, view_14.dispatch);
14511
14725
  break;
14512
14726
  case "tableBordersNone":
14513
- setTableBorderPreset("none")(view_13.state, view_13.dispatch);
14727
+ setTableBorderPreset("none")(view_14.state, view_14.dispatch);
14514
14728
  break;
14515
14729
  case "addComment": {
14516
- const { from: from_5, to: to_5 } = contextMenu.selectionRange.from !== contextMenu.selectionRange.to ? contextMenu.selectionRange : view_13.state.selection;
14730
+ const { from: from_5, to: to_5 } = contextMenu.selectionRange.from !== contextMenu.selectionRange.to ? contextMenu.selectionRange : view_14.state.selection;
14517
14731
  if (from_5 === to_5) break;
14518
14732
  const commentY = findSelectionYPosition(scrollContainerRef.current, editorContentRef.current, from_5) ?? getFallbackCommentYPosition(scrollContainerRef.current);
14519
14733
  setCommentSelectionRange({
14520
14734
  from: from_5,
14521
14735
  to: to_5
14522
14736
  });
14523
- if (!applyCommentMarkRange(view_13, {
14524
- from: from_5,
14525
- to: to_5
14526
- }, -1, { selectEnd: true })) break;
14737
+ if (commentDraftMode === "prosemirror") {
14738
+ if (!applyCommentMarkRange(view_14, {
14739
+ from: from_5,
14740
+ to: to_5
14741
+ }, -1, { selectEnd: true })) break;
14742
+ }
14527
14743
  setAddCommentYPosition(commentY);
14528
14744
  setShowCommentsSidebar(true);
14529
14745
  setIsAddingComment(true);
@@ -14531,30 +14747,30 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14531
14747
  break;
14532
14748
  }
14533
14749
  case "acceptChange": {
14534
- const { from: from_4, to: to_4 } = view_13.state.selection;
14535
- const range_1 = findChangeAtPosition(view_13.state, from_4, to_4);
14750
+ const { from: from_4, to: to_4 } = view_14.state.selection;
14751
+ const range_1 = findChangeAtPosition(view_14.state, from_4, to_4);
14536
14752
  if (resolveCanonicalReviewRange({
14537
14753
  editor: pagedEditorRef.current?.getEditor(),
14538
14754
  ...range_1,
14539
14755
  resolution: "accept"
14540
- }) === null) acceptChange(range_1.from, range_1.to)(view_13.state, view_13.dispatch);
14756
+ }) === null) acceptChange(range_1.from, range_1.to)(view_14.state, view_14.dispatch);
14541
14757
  break;
14542
14758
  }
14543
14759
  case "rejectChange": {
14544
- const { from: from_3, to: to_3 } = view_13.state.selection;
14545
- const range_0 = findChangeAtPosition(view_13.state, from_3, to_3);
14760
+ const { from: from_3, to: to_3 } = view_14.state.selection;
14761
+ const range_0 = findChangeAtPosition(view_14.state, from_3, to_3);
14546
14762
  if (resolveCanonicalReviewRange({
14547
14763
  editor: pagedEditorRef.current?.getEditor(),
14548
14764
  ...range_0,
14549
14765
  resolution: "reject"
14550
- }) === null) rejectChange(range_0.from, range_0.to)(view_13.state, view_13.dispatch);
14766
+ }) === null) rejectChange(range_0.from, range_0.to)(view_14.state, view_14.dispatch);
14551
14767
  break;
14552
14768
  }
14553
14769
  case "restartNumbering":
14554
- restartNumbering(view_13.state, view_13.dispatch);
14770
+ restartNumbering(view_14.state, view_14.dispatch);
14555
14771
  break;
14556
14772
  case "continueNumbering":
14557
- continueNumbering(view_13.state, view_13.dispatch);
14773
+ continueNumbering(view_14.state, view_14.dispatch);
14558
14774
  break;
14559
14775
  case "setNumberingValue":
14560
14776
  setNumberingValueDialogOpen(true);
@@ -14580,13 +14796,12 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14580
14796
  ]);
14581
14797
  const handlePageSetupApply = useCallback((props) => {
14582
14798
  if (readOnly) return;
14583
- if (experimentalSession === "canonical") {
14584
- const api_0 = getCanonicalApi();
14585
- api_0?.ensureView();
14586
- const canonical_1 = api_0?.getCanonicalDocument();
14587
- if (!canonical_1 || !api_0?.applyCanonicalOperations([createCanonicalSectionPropertiesOperation(canonical_1, props)])) refuseCanonicalModelEdit("Section property changes could not be applied.");
14799
+ const api_0 = getCanonicalApi();
14800
+ if (!api_0) {
14801
+ refuseCanonicalModelEdit(CANONICAL_GAP.sectionProperties, "The editor is not ready for section changes.");
14588
14802
  return;
14589
14803
  }
14804
+ if (api_0.applyCanonicalSectionProperties(props) !== null) return;
14590
14805
  if (!history.state || readOnly) return;
14591
14806
  const newDoc_0 = {
14592
14807
  ...history.state,
@@ -14606,7 +14821,6 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14606
14821
  history.state,
14607
14822
  readOnly,
14608
14823
  handleDocumentChange,
14609
- experimentalSession,
14610
14824
  getCanonicalApi,
14611
14825
  refuseCanonicalModelEdit
14612
14826
  ]);
@@ -14615,83 +14829,100 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14615
14829
  const handleTopMarginChange = useCallback((twips_1) => handlePageSetupApply({ marginTop: twips_1 }), [handlePageSetupApply]);
14616
14830
  const handleBottomMarginChange = useCallback((twips_2) => handlePageSetupApply({ marginBottom: twips_2 }), [handlePageSetupApply]);
14617
14831
  const handleIndentLeftChange = useCallback((twips_3) => {
14618
- const view_14 = getActiveEditorView();
14619
- if (!view_14) return;
14620
- setIndentLeft(twips_3)(view_14.state, view_14.dispatch);
14621
- }, [getActiveEditorView]);
14622
- const handleIndentRightChange = useCallback((twips_4) => {
14623
14832
  const view_15 = getActiveEditorView();
14624
14833
  if (!view_15) return;
14625
- setIndentRight(twips_4)(view_15.state, view_15.dispatch);
14834
+ setIndentLeft(twips_3)(view_15.state, view_15.dispatch);
14626
14835
  }, [getActiveEditorView]);
14627
- const handleFirstLineIndentChange = useCallback((twips_5) => {
14836
+ const handleIndentRightChange = useCallback((twips_4) => {
14628
14837
  const view_16 = getActiveEditorView();
14629
14838
  if (!view_16) return;
14630
- if (twips_5 < 0) setIndentFirstLine(-twips_5, true)(view_16.state, view_16.dispatch);
14631
- else setIndentFirstLine(twips_5, false)(view_16.state, view_16.dispatch);
14839
+ setIndentRight(twips_4)(view_16.state, view_16.dispatch);
14632
14840
  }, [getActiveEditorView]);
14633
- const handleTabStopRemove = useCallback((positionTwips) => {
14841
+ const handleFirstLineIndentChange = useCallback((twips_5) => {
14634
14842
  const view_17 = getActiveEditorView();
14635
14843
  if (!view_17) return;
14636
- removeTabStop(positionTwips)(view_17.state, view_17.dispatch);
14844
+ if (twips_5 < 0) setIndentFirstLine(-twips_5, true)(view_17.state, view_17.dispatch);
14845
+ else setIndentFirstLine(twips_5, false)(view_17.state, view_17.dispatch);
14846
+ }, [getActiveEditorView]);
14847
+ const handleTabStopRemove = useCallback((positionTwips) => {
14848
+ const view_18 = getActiveEditorView();
14849
+ if (!view_18) return;
14850
+ removeTabStop(positionTwips)(view_18.state, view_18.dispatch);
14637
14851
  }, [getActiveEditorView]);
14638
14852
  const serializeCurrentDocx = useCallback(async (options) => {
14639
14853
  let tripwireResult = null;
14640
14854
  let savedBuffer = null;
14641
14855
  try {
14642
- const view_18 = pagedEditorRef.current?.getView();
14643
- const editorState = view_18?.state;
14644
- const baselineBuffer = originalBufferRef.current;
14645
- const current = buildCurrentDocument();
14646
- const doc_1 = current ? withoutUnreferencedNotes(current) : null;
14647
- if (!doc_1) return null;
14648
- const { resolveSelectiveSaveFlags } = await import("@stll/folio-core/docx/selectiveSaveFlags");
14649
- const flags = resolveSelectiveSaveFlags(featureFlags);
14650
- const useSelectiveForSave = flags.selectiveSave && options?.mode !== FOLIO_DOCX_SERIALIZATION_MODE.full;
14651
- const shouldAttemptSelective = useSelectiveForSave || flags.selectiveSaveTripwire;
14652
- let selectiveBuffer = null;
14653
- if (shouldAttemptSelective && editorState && baselineBuffer) selectiveBuffer = await (await loadAttemptSelectiveSave())(doc_1, baselineBuffer, {
14654
- changedParaIds: getChangedParagraphIds(editorState),
14655
- structuralChange: hasStructuralChanges(editorState),
14656
- hasUntrackedChanges: hasUntrackedChanges(editorState),
14657
- maxBytes: flags.selectiveSaveMaxBytes
14658
- });
14659
- let buffer = useSelectiveForSave ? selectiveBuffer : null;
14660
- let fullBuffer = null;
14661
- const repackSourceDoc = baselineBuffer ? {
14662
- ...doc_1,
14663
- originalBuffer: baselineBuffer
14664
- } : doc_1;
14665
- const repackFull = async () => {
14666
- const repackDocx = await loadRepackDocx();
14667
- const repack = () => repackDocx(repackSourceDoc);
14668
- if (experimentalSession === "canonical") return repackWithCanonicalStoryRemovals({
14669
- document: repackSourceDoc,
14670
- repack
14856
+ const editor_1 = pagedEditorRef.current?.getEditor();
14857
+ const snapshot = editor_1?.captureCanonicalSave();
14858
+ if (snapshot && editor_1) {
14859
+ const view_19 = editor_1.getView();
14860
+ const editorState = view_19?.state;
14861
+ const result_2 = await serializeCanonicalSave({
14862
+ snapshot,
14863
+ options,
14864
+ featureFlags
14671
14865
  });
14672
- return editorState ? repackWithEditorSectionRemovals({
14673
- state: editorState,
14674
- document: repackSourceDoc,
14675
- repack
14676
- }) : repack();
14677
- };
14678
- if (!buffer) {
14679
- fullBuffer = await repackFull();
14680
- buffer = fullBuffer;
14681
- } else if (flags.selectiveSaveTripwire) try {
14682
- fullBuffer = await repackFull();
14683
- } catch {}
14684
- if (flags.selectiveSaveTripwire && fullBuffer && onSelectiveSaveTripwire) try {
14685
- const { compareSelectiveVsFull } = await import("@stll/folio-core/docx/selectiveSaveTripwire");
14686
- tripwireResult = await compareSelectiveVsFull(selectiveBuffer, fullBuffer);
14687
- } catch {}
14688
- if (view_18 && pagedEditorRef.current?.getView() === view_18 && view_18.state.doc === editorState?.doc) {
14689
- originalBufferRef.current = buffer;
14690
- view_18.dispatch(clearTrackedChanges(view_18.state));
14866
+ for (const diagnostic of result_2.diagnostics) if (!options?.onDiagnostic) onError?.(new CanonicalSaveDiagnosticError({
14867
+ gap: CANONICAL_GAP.save,
14868
+ diagnostic,
14869
+ message: `Canonical save used a fidelity fallback: ${diagnostic.type} (${diagnostic.part}).`
14870
+ }));
14871
+ tripwireResult = result_2.tripwireResult;
14872
+ if (view_19 && pagedEditorRef.current?.getEditor() === editor_1 && editor_1.getView() === view_19 && view_19.state.doc === editorState?.doc && editor_1.isCanonicalSaveCurrent(snapshot.version)) view_19.dispatch(clearTrackedChanges(view_19.state));
14873
+ savedBuffer = result_2.buffer;
14874
+ } else {
14875
+ if (usesCanonicalSession(experimentalSession, CANONICAL_GAP.save)) return null;
14876
+ const view_20 = pagedEditorRef.current?.getView();
14877
+ const editorState_0 = view_20?.state;
14878
+ const baselineBuffer = originalBufferRef.current;
14879
+ const current = buildCurrentDocument();
14880
+ const doc_1 = current ? withoutUnreferencedNotes(current) : null;
14881
+ if (!doc_1) return null;
14882
+ const { resolveSelectiveSaveFlags } = await import("@stll/folio-core/docx/selectiveSaveFlags");
14883
+ const flags = resolveSelectiveSaveFlags(featureFlags);
14884
+ const useSelectiveForSave = flags.selectiveSave && options?.mode !== FOLIO_DOCX_SERIALIZATION_MODE.full;
14885
+ const shouldAttemptSelective = useSelectiveForSave || flags.selectiveSaveTripwire;
14886
+ let selectiveBuffer = null;
14887
+ if (shouldAttemptSelective && editorState_0 && baselineBuffer) selectiveBuffer = await (await loadAttemptSelectiveSave())(doc_1, baselineBuffer, {
14888
+ changedParaIds: getChangedParagraphIds(editorState_0),
14889
+ structuralChange: hasStructuralChanges(editorState_0),
14890
+ hasUntrackedChanges: hasUntrackedChanges(editorState_0),
14891
+ maxBytes: flags.selectiveSaveMaxBytes
14892
+ });
14893
+ let buffer = useSelectiveForSave ? selectiveBuffer : null;
14894
+ let fullBuffer = null;
14895
+ const repackSourceDoc = baselineBuffer ? {
14896
+ ...doc_1,
14897
+ originalBuffer: baselineBuffer
14898
+ } : doc_1;
14899
+ const repackFull = async () => {
14900
+ const repackDocx = await loadRepackDocx();
14901
+ const repack = () => repackDocx(repackSourceDoc);
14902
+ return editorState_0 ? repackWithEditorSectionRemovals({
14903
+ state: editorState_0,
14904
+ document: repackSourceDoc,
14905
+ repack
14906
+ }) : repack();
14907
+ };
14908
+ if (!buffer) {
14909
+ fullBuffer = await repackFull();
14910
+ buffer = fullBuffer;
14911
+ } else if (flags.selectiveSaveTripwire) try {
14912
+ fullBuffer = await repackFull();
14913
+ } catch {}
14914
+ if (flags.selectiveSaveTripwire && fullBuffer && onSelectiveSaveTripwire) try {
14915
+ const { compareSelectiveVsFull } = await import("@stll/folio-core/docx/selectiveSaveTripwire");
14916
+ tripwireResult = await compareSelectiveVsFull(selectiveBuffer, fullBuffer);
14917
+ } catch {}
14918
+ if (view_20 && pagedEditorRef.current?.getView() === view_20 && view_20.state.doc === editorState_0?.doc) {
14919
+ originalBufferRef.current = buffer;
14920
+ view_20.dispatch(clearTrackedChanges(view_20.state));
14921
+ }
14922
+ savedBuffer = buffer;
14691
14923
  }
14692
- savedBuffer = buffer;
14693
- } catch (error_1) {
14694
- onError?.(error_1 instanceof Error ? error_1 : /* @__PURE__ */ new Error("Failed to save document"));
14924
+ } catch (error_0) {
14925
+ onError?.(error_0 instanceof Error ? error_0 : /* @__PURE__ */ new Error("Failed to save document"));
14695
14926
  return null;
14696
14927
  }
14697
14928
  if (tripwireResult && onSelectiveSaveTripwire) onSelectiveSaveTripwire(tripwireResult);
@@ -14701,12 +14932,13 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14701
14932
  onError,
14702
14933
  originalBufferRef,
14703
14934
  featureFlags,
14704
- onSelectiveSaveTripwire
14935
+ onSelectiveSaveTripwire,
14936
+ experimentalSession
14705
14937
  ]);
14706
14938
  const handleSave = useCallback(async (options_0) => {
14707
- const editor_1 = pagedEditorRef.current?.getEditor();
14939
+ const editor_2 = pagedEditorRef.current?.getEditor();
14708
14940
  const serializationOptions = { mode: options_0?.selective === false ? FOLIO_DOCX_SERIALIZATION_MODE.full : FOLIO_DOCX_SERIALIZATION_MODE.preferSelective };
14709
- const buffer_0 = editor_1 ? await editor_1.getDocx(serializationOptions) : await serializeCurrentDocx(serializationOptions);
14941
+ const buffer_0 = editor_2 ? await editor_2.getDocx(serializationOptions) : await serializeCurrentDocx(serializationOptions);
14710
14942
  if (!buffer_0) return null;
14711
14943
  commentsDirtyRef.current = false;
14712
14944
  onSave?.(buffer_0);
@@ -14725,16 +14957,16 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14725
14957
  loadParsedDocument,
14726
14958
  serializeCurrentDocx
14727
14959
  ]);
14728
- const handleEditorError = useCallback((error_2) => {
14729
- if (CanonicalSessionRefusalError.is(error_2)) toast(error_2.message);
14730
- onError?.(error_2);
14960
+ const handleEditorError = useCallback((error_1) => {
14961
+ if (CanonicalSessionRefusalError.is(error_1)) toast(error_1.message);
14962
+ onError?.(error_1);
14731
14963
  }, [onError]);
14732
14964
  useImperativeHandle(ref, () => ({
14733
14965
  getDocument: () => buildCurrentDocument(),
14734
14966
  hasPendingChanges: () => {
14735
- const view_19 = pagedEditorRef.current?.getView();
14736
- if (!view_19) return false;
14737
- return commentsDirtyRef.current || getChangedParagraphIds(view_19.state).size > 0 || hasStructuralChanges(view_19.state) || hasUntrackedChanges(view_19.state);
14967
+ const view_21 = pagedEditorRef.current?.getView();
14968
+ if (!view_21) return false;
14969
+ return commentsDirtyRef.current || getChangedParagraphIds(view_21.state).size > 0 || hasStructuralChanges(view_21.state) || hasUntrackedChanges(view_21.state);
14738
14970
  },
14739
14971
  getEditorRef: () => pagedEditorRef.current,
14740
14972
  getEditor: () => pagedEditorRef.current?.getEditor() ?? null,
@@ -14760,9 +14992,9 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14760
14992
  },
14761
14993
  loadDocument: (document_0) => {
14762
14994
  pendingSuggestionRegistryRef.current.clear();
14763
- const editor_2 = pagedEditorRef.current?.getEditor();
14764
- if (editor_2) {
14765
- editor_2.loadDocument(document_0);
14995
+ const editor_3 = pagedEditorRef.current?.getEditor();
14996
+ if (editor_3) {
14997
+ editor_3.loadDocument(document_0);
14766
14998
  return;
14767
14999
  }
14768
15000
  loadParsedDocument(document_0);
@@ -14775,13 +15007,13 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14775
15007
  pagedEditorRef.current?.ensureView(options_2);
14776
15008
  },
14777
15009
  createAIEditSnapshot: () => {
14778
- const view_20 = pagedEditorRef.current?.getView();
14779
- return view_20 ? createFolioAIEditSnapshot(view_20.state.doc) : null;
15010
+ const view_22 = pagedEditorRef.current?.getView();
15011
+ return view_22 ? createFolioAIEditSnapshot(view_22.state.doc) : null;
14780
15012
  },
14781
- applyDocumentOperations: ({ snapshot, batch, author: operationAuthor = author }) => {
15013
+ applyDocumentOperations: ({ snapshot: snapshot_0, batch, author: operationAuthor = author }) => {
14782
15014
  assertSupportedFolioDocumentOperationVersion(batch.version);
14783
- const view_21 = pagedEditorRef.current?.getView();
14784
- if (!view_21) {
15015
+ const view_23 = pagedEditorRef.current?.getView();
15016
+ if (!view_23) {
14785
15017
  let status = "committed";
14786
15018
  if (batch.dryRun === true) status = "previewed";
14787
15019
  else if (batch.atomic === true) status = "rejected";
@@ -14799,21 +15031,27 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14799
15031
  undoHandle: null
14800
15032
  };
14801
15033
  }
15034
+ const canonical_1 = getCanonicalApi()?.applyCanonicalDocumentOperations({
15035
+ snapshot: snapshot_0,
15036
+ batch,
15037
+ author: operationAuthor
15038
+ });
15039
+ if (canonical_1) return canonical_1;
14802
15040
  const existingUndoEntry = documentOperationUndoEntriesRef.current.at(-1);
14803
- if (existingUndoEntry && (!view_21.state.doc.eq(existingUndoEntry.afterState.doc) || commentsRef.current !== existingUndoEntry.commentsAfter)) documentOperationUndoEntriesRef.current.length = 0;
15041
+ if (existingUndoEntry && (!view_23.state.doc.eq(existingUndoEntry.afterState.doc) || commentsRef.current !== existingUndoEntry.commentsAfter)) documentOperationUndoEntriesRef.current.length = 0;
14804
15042
  const commentsBefore = commentsRef.current;
14805
15043
  const createdComments = [];
14806
15044
  const operationView = {
14807
- state: view_21.state,
15045
+ state: view_23.state,
14808
15046
  dispatch: (transaction) => {
14809
- view_21.dispatch(closeHistory(transaction));
14810
- operationView.state = view_21.state;
15047
+ view_23.dispatch(closeHistory(transaction));
15048
+ operationView.state = view_23.state;
14811
15049
  }
14812
15050
  };
14813
- const activeSuggestionIds = new Set(getSuggestions(view_21.state).map((s_0) => s_0.suggestionId));
14814
- const result = applyFolioDocumentOperations({
15051
+ const activeSuggestionIds = new Set(getSuggestions(view_23.state).map((s_0) => s_0.suggestionId));
15052
+ const result_3 = applyFolioDocumentOperations({
14815
15053
  view: operationView,
14816
- snapshot,
15054
+ snapshot: snapshot_0,
14817
15055
  batch,
14818
15056
  author: operationAuthor,
14819
15057
  createCommentId: (text_3) => {
@@ -14826,25 +15064,27 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14826
15064
  id: `react-${String(documentOperationUndoHandleCursor++)}`
14827
15065
  })
14828
15066
  });
14829
- if (batch.mode === "suggested" && result.status === "committed") pendingSuggestionRegistryRef.current.recordApplied({
14830
- snapshot,
15067
+ if (batch.mode === "suggested" && result_3.status === "committed") pendingSuggestionRegistryRef.current.recordApplied({
15068
+ snapshot: snapshot_0,
14831
15069
  story: { type: "main" },
14832
15070
  operations: batch.operations,
14833
- applied: result.applied,
15071
+ applied: result_3.applied,
14834
15072
  author: operationAuthor,
14835
15073
  activeSuggestionIds
14836
15074
  });
14837
- const batchComments = appliedOperationComments(createdComments, result.applied);
15075
+ const batchComments = appliedOperationComments(createdComments, result_3.applied);
14838
15076
  if (batchComments.length > 0) updateComments((currentComments_0) => [...currentComments_0, ...batchComments]);
14839
- if (result.undoHandle !== null) documentOperationUndoEntriesRef.current.push({
14840
- undoHandle: result.undoHandle,
14841
- afterState: view_21.state,
15077
+ if (result_3.undoHandle !== null) documentOperationUndoEntriesRef.current.push({
15078
+ undoHandle: result_3.undoHandle,
15079
+ afterState: view_23.state,
14842
15080
  commentsBefore,
14843
15081
  commentsAfter: commentsRef.current
14844
15082
  });
14845
- return result;
15083
+ return result_3;
14846
15084
  },
14847
15085
  undoDocumentOperations: (undoHandle) => {
15086
+ const canonical_2 = getCanonicalApi()?.undoCanonicalDocumentOperations(undoHandle);
15087
+ if (canonical_2) return canonical_2;
14848
15088
  const entries = documentOperationUndoEntriesRef.current;
14849
15089
  const entryIndex = entries.findIndex((entry_2) => entry_2.undoHandle.type === undoHandle.type && entry_2.undoHandle.id === undoHandle.id);
14850
15090
  if (entryIndex === -1) return {
@@ -14858,18 +15098,18 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14858
15098
  reason: "notLatest"
14859
15099
  };
14860
15100
  const entry_3 = entries.at(-1);
14861
- const view_22 = pagedEditorRef.current?.getView();
14862
- if (!entry_3 || !view_22) return {
15101
+ const view_24 = pagedEditorRef.current?.getView();
15102
+ if (!entry_3 || !view_24) return {
14863
15103
  status: "rejected",
14864
15104
  undoHandle,
14865
15105
  reason: "unknownHandle"
14866
15106
  };
14867
- if (!view_22.state.doc.eq(entry_3.afterState.doc) || commentsRef.current !== entry_3.commentsAfter) return {
15107
+ if (!view_24.state.doc.eq(entry_3.afterState.doc) || commentsRef.current !== entry_3.commentsAfter) return {
14868
15108
  status: "rejected",
14869
15109
  undoHandle,
14870
15110
  reason: "documentChanged"
14871
15111
  };
14872
- if (!undo(view_22.state, view_22.dispatch)) return {
15112
+ if (!undo(view_24.state, view_24.dispatch)) return {
14873
15113
  status: "rejected",
14874
15114
  undoHandle,
14875
15115
  reason: "documentChanged"
@@ -14882,20 +15122,30 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14882
15122
  undoHandle
14883
15123
  };
14884
15124
  },
14885
- applyAIEditOperations: ({ snapshot: snapshot_0, operations, mode = "tracked-changes", author: operationAuthor_0 = author }) => {
14886
- const view_23 = pagedEditorRef.current?.getView();
14887
- if (!view_23) return {
15125
+ applyAIEditOperations: ({ snapshot: snapshot_1, operations, mode = "tracked-changes", author: operationAuthor_0 = author }) => {
15126
+ const view_25 = pagedEditorRef.current?.getView();
15127
+ if (!view_25) return {
14888
15128
  applied: [],
14889
15129
  skipped: operations.map((operation_0) => ({
14890
15130
  id: operation_0.id,
14891
15131
  reason: "unsupportedBlock"
14892
15132
  }))
14893
15133
  };
15134
+ const canonical_3 = getCanonicalApi()?.applyCanonicalDocumentOperations({
15135
+ snapshot: snapshot_1,
15136
+ batch: {
15137
+ version: FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION,
15138
+ operations,
15139
+ mode
15140
+ },
15141
+ author: operationAuthor_0
15142
+ });
15143
+ if (canonical_3) return canonical_3;
14894
15144
  const createdComments_0 = [];
14895
- const activeSuggestionIds_0 = new Set(getSuggestions(view_23.state).map((s_1) => s_1.suggestionId));
15145
+ const activeSuggestionIds_0 = new Set(getSuggestions(view_25.state).map((s_1) => s_1.suggestionId));
14896
15146
  const { applied: applied_0, skipped: skipped_0 } = applyFolioDocumentOperations({
14897
- view: view_23,
14898
- snapshot: snapshot_0,
15147
+ view: view_25,
15148
+ snapshot: snapshot_1,
14899
15149
  batch: {
14900
15150
  version: FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION,
14901
15151
  operations,
@@ -14911,7 +15161,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14911
15161
  const batchComments_0 = appliedOperationComments(createdComments_0, applied_0);
14912
15162
  if (batchComments_0.length > 0) updateComments((currentComments_1) => [...currentComments_1, ...batchComments_0]);
14913
15163
  if (mode === "suggested") pendingSuggestionRegistryRef.current.recordApplied({
14914
- snapshot: snapshot_0,
15164
+ snapshot: snapshot_1,
14915
15165
  story: { type: "main" },
14916
15166
  operations,
14917
15167
  applied: applied_0,
@@ -14924,71 +15174,71 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14924
15174
  };
14925
15175
  },
14926
15176
  acceptAIEditOperation: (revisionId) => {
14927
- const view_24 = pagedEditorRef.current?.getView();
14928
- if (!view_24) return false;
14929
- const editor_3 = pagedEditorRef.current?.getEditor();
14930
- if (editor_3?.getCanonicalDocument()) return editor_3.resolveCanonicalRevisions(typeof revisionId === "number" ? [revisionId] : revisionId, "accept");
14931
- return acceptAIEditRevision(revisionId)(view_24.state, view_24.dispatch);
15177
+ const view_26 = pagedEditorRef.current?.getView();
15178
+ if (!view_26) return false;
15179
+ const editor_4 = pagedEditorRef.current?.getEditor();
15180
+ if (editor_4?.getCanonicalDocument()) return editor_4.resolveCanonicalRevisions(typeof revisionId === "number" ? [revisionId] : revisionId, "accept");
15181
+ return acceptAIEditRevision(revisionId)(view_26.state, view_26.dispatch);
14932
15182
  },
14933
15183
  rejectAIEditOperation: (revisionId_0) => {
14934
- const view_25 = pagedEditorRef.current?.getView();
14935
- if (!view_25) return false;
14936
- const editor_4 = pagedEditorRef.current?.getEditor();
14937
- if (editor_4?.getCanonicalDocument()) return editor_4.resolveCanonicalRevisions(typeof revisionId_0 === "number" ? [revisionId_0] : revisionId_0, "reject");
14938
- return rejectAIEditRevision(revisionId_0)(view_25.state, view_25.dispatch);
15184
+ const view_27 = pagedEditorRef.current?.getView();
15185
+ if (!view_27) return false;
15186
+ const editor_5 = pagedEditorRef.current?.getEditor();
15187
+ if (editor_5?.getCanonicalDocument()) return editor_5.resolveCanonicalRevisions(typeof revisionId_0 === "number" ? [revisionId_0] : revisionId_0, "reject");
15188
+ return rejectAIEditRevision(revisionId_0)(view_27.state, view_27.dispatch);
14939
15189
  },
14940
15190
  undo: () => {
14941
- if (experimentalSession !== "canonical" && getActiveEditorStory().type === "headerFooter" && hfEditorRef.current) return hfEditorRef.current.undo();
15191
+ if (!usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting) && getActiveEditorStory().type === "headerFooter" && hfEditorRef.current) return hfEditorRef.current.undo();
14942
15192
  const undone = pagedEditorRef.current?.undo() ?? false;
14943
15193
  requestAnimationFrame(refreshBodyHistoryAvailability);
14944
15194
  return undone;
14945
15195
  },
14946
15196
  redo: () => {
14947
- if (experimentalSession !== "canonical" && getActiveEditorStory().type === "headerFooter" && hfEditorRef.current) return hfEditorRef.current.redo();
15197
+ if (!usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting) && getActiveEditorStory().type === "headerFooter" && hfEditorRef.current) return hfEditorRef.current.redo();
14948
15198
  const redone = pagedEditorRef.current?.redo() ?? false;
14949
15199
  requestAnimationFrame(refreshBodyHistoryAvailability);
14950
15200
  return redone;
14951
15201
  },
14952
15202
  scrollToAIEditOperation: (revisionId_1) => {
14953
- const view_26 = pagedEditorRef.current?.getView();
14954
- if (!view_26) return false;
14955
- const range_2 = findAIEditRevisionRange(view_26.state, revisionId_1);
15203
+ const view_28 = pagedEditorRef.current?.getView();
15204
+ if (!view_28) return false;
15205
+ const range_2 = findAIEditRevisionRange(view_28.state, revisionId_1);
14956
15206
  if (!range_2) return false;
14957
- const { from: from_8, to: to_8 } = clampRangeToDocSize(view_26.state.doc.content.size, range_2);
14958
- const $from = view_26.state.doc.resolve(from_8);
14959
- const $to = view_26.state.doc.resolve(to_8);
14960
- view_26.dispatch(view_26.state.tr.setSelection(TextSelection.between($from, $to)));
15207
+ const { from: from_8, to: to_8 } = clampRangeToDocSize(view_28.state.doc.content.size, range_2);
15208
+ const $from = view_28.state.doc.resolve(from_8);
15209
+ const $to = view_28.state.doc.resolve(to_8);
15210
+ view_28.dispatch(view_28.state.tr.setSelection(TextSelection.between($from, $to)));
14961
15211
  requestAnimationFrame(() => {
14962
15212
  pagedEditorRef.current?.scrollToPosition(from_8);
14963
15213
  });
14964
15214
  return true;
14965
15215
  },
14966
- scrollToBlock: (blockId, snapshot_1) => {
14967
- const view_27 = pagedEditorRef.current?.getView();
14968
- if (!view_27) return false;
15216
+ scrollToBlock: (blockId, snapshot_2) => {
15217
+ const view_29 = pagedEditorRef.current?.getView();
15218
+ if (!view_29) return false;
14969
15219
  const range_3 = resolveFolioAIBlockRange({
14970
15220
  blockId,
14971
- doc: view_27.state.doc,
14972
- snapshot: snapshot_1
15221
+ doc: view_29.state.doc,
15222
+ snapshot: snapshot_2
14973
15223
  });
14974
15224
  if (range_3 === null) return false;
14975
15225
  const { from: from_9, to: to_9 } = range_3;
14976
- const $from_0 = view_27.state.doc.resolve(from_9);
14977
- const $to_0 = view_27.state.doc.resolve(to_9);
14978
- view_27.dispatch(view_27.state.tr.setSelection(TextSelection.between($from_0, $to_0)));
15226
+ const $from_0 = view_29.state.doc.resolve(from_9);
15227
+ const $to_0 = view_29.state.doc.resolve(to_9);
15228
+ view_29.dispatch(view_29.state.tr.setSelection(TextSelection.between($from_0, $to_0)));
14979
15229
  requestAnimationFrame(() => {
14980
15230
  pagedEditorRef.current?.scrollToPosition(from_9);
14981
15231
  });
14982
15232
  return true;
14983
15233
  },
14984
- highlightPassage: ({ blockId: blockId_0, text: text_5, snapshot: snapshot_2 }) => {
14985
- const view_28 = pagedEditorRef.current?.getView();
14986
- if (!view_28) return "none";
15234
+ highlightPassage: ({ blockId: blockId_0, text: text_5, snapshot: snapshot_3 }) => {
15235
+ const view_30 = pagedEditorRef.current?.getView();
15236
+ if (!view_30) return "none";
14987
15237
  const passageRange = resolvePassageRange({
14988
15238
  blockId: blockId_0,
14989
15239
  text: text_5,
14990
- doc: view_28.state.doc,
14991
- snapshot: snapshot_2
15240
+ doc: view_30.state.doc,
15241
+ snapshot: snapshot_3
14992
15242
  });
14993
15243
  if (passageRange !== null) {
14994
15244
  pagedEditorRef.current?.setPassageHighlight(passageRange);
@@ -15000,16 +15250,16 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15000
15250
  pagedEditorRef.current?.setPassageHighlight(null);
15001
15251
  const blockRange = resolveFolioAIBlockRange({
15002
15252
  blockId: blockId_0,
15003
- doc: view_28.state.doc,
15004
- snapshot: snapshot_2
15253
+ doc: view_30.state.doc,
15254
+ snapshot: snapshot_3
15005
15255
  });
15006
15256
  if (blockRange === null) return "none";
15007
15257
  const paraId_0 = getFolioParaIdFromBlockId(blockId_0);
15008
15258
  if (paraId_0 !== null && pagedEditorRef.current?.scrollToParaId(paraId_0, { highlight: {} })) return "block";
15009
15259
  const { from: from_10, to: to_10 } = blockRange;
15010
- const $from_1 = view_28.state.doc.resolve(from_10);
15011
- const $to_1 = view_28.state.doc.resolve(to_10);
15012
- view_28.dispatch(view_28.state.tr.setSelection(TextSelection.between($from_1, $to_1)));
15260
+ const $from_1 = view_30.state.doc.resolve(from_10);
15261
+ const $to_1 = view_30.state.doc.resolve(to_10);
15262
+ view_30.dispatch(view_30.state.tr.setSelection(TextSelection.between($from_1, $to_1)));
15013
15263
  requestAnimationFrame(() => {
15014
15264
  pagedEditorRef.current?.scrollToPosition(from_10);
15015
15265
  });
@@ -15018,60 +15268,70 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15018
15268
  clearPassageHighlight: () => {
15019
15269
  pagedEditorRef.current?.setPassageHighlight(null);
15020
15270
  },
15021
- showInDocument: (target_1, snapshot_3) => {
15022
- const view_29 = pagedEditorRef.current?.getView();
15023
- if (!view_29) return false;
15271
+ showInDocument: (target_1, snapshot_4) => {
15272
+ const view_31 = pagedEditorRef.current?.getView();
15273
+ if (!view_31) return false;
15024
15274
  const range_4 = target_1.type === "textRange" ? resolveFolioAITextRange({
15025
15275
  range: target_1,
15026
- doc: view_29.state.doc,
15027
- snapshot: snapshot_3
15276
+ doc: view_31.state.doc,
15277
+ snapshot: snapshot_4
15028
15278
  }) : resolveFolioAIBlockRange({
15029
15279
  blockId: target_1.blockId,
15030
- doc: view_29.state.doc,
15031
- snapshot: snapshot_3
15280
+ doc: view_31.state.doc,
15281
+ snapshot: snapshot_4
15032
15282
  });
15033
15283
  if (range_4 === null) return false;
15034
15284
  const { from: from_11, to: to_11 } = range_4;
15035
- const $from_2 = view_29.state.doc.resolve(from_11);
15036
- const $to_2 = view_29.state.doc.resolve(to_11);
15037
- view_29.dispatch(view_29.state.tr.setSelection(TextSelection.between($from_2, $to_2)));
15285
+ const $from_2 = view_31.state.doc.resolve(from_11);
15286
+ const $to_2 = view_31.state.doc.resolve(to_11);
15287
+ view_31.dispatch(view_31.state.tr.setSelection(TextSelection.between($from_2, $to_2)));
15038
15288
  requestAnimationFrame(() => {
15039
15289
  pagedEditorRef.current?.scrollToPosition(from_11);
15040
15290
  });
15041
15291
  return true;
15042
15292
  },
15043
15293
  getSuggestions: () => {
15044
- const view_30 = pagedEditorRef.current?.getView();
15045
- return view_30 ? getSuggestions(view_30.state) : [];
15294
+ const view_32 = pagedEditorRef.current?.getView();
15295
+ return view_32 ? getSuggestions(view_32.state) : [];
15046
15296
  },
15047
15297
  exportPendingSuggestions: () => {
15048
- const view_31 = pagedEditorRef.current?.getView();
15049
- const activeIds = new Set(view_31 ? getSuggestions(view_31.state).map((s_2) => s_2.suggestionId) : []);
15298
+ const view_33 = pagedEditorRef.current?.getView();
15299
+ const activeIds = new Set(view_33 ? getSuggestions(view_33.state).map((s_2) => s_2.suggestionId) : []);
15050
15300
  return pendingSuggestionRegistryRef.current.exportPendingSuggestions({
15051
15301
  activeSuggestionIds: activeIds,
15052
- snapshotForStory: (story_0, commentIds) => story_0.type === "main" && view_31 ? createPendingSuggestionSourceSnapshot(view_31.state, commentIds) : null
15302
+ snapshotForStory: (story_0, commentIds) => story_0.type === "main" && view_33 ? createPendingSuggestionSourceSnapshot(view_33.state, commentIds) : null
15053
15303
  });
15054
15304
  },
15055
15305
  loadPendingSuggestions: (records) => pendingSuggestionRegistryRef.current.loadPendingSuggestions({
15056
15306
  records,
15057
15307
  snapshotForStory: (story_1) => {
15058
- const view_32 = pagedEditorRef.current?.getView();
15059
- return story_1.type === "main" && view_32 ? createFolioAIEditSnapshot(view_32.state.doc) : null;
15308
+ const view_34 = pagedEditorRef.current?.getView();
15309
+ return story_1.type === "main" && view_34 ? createFolioAIEditSnapshot(view_34.state.doc) : null;
15060
15310
  },
15061
15311
  sourceSnapshotForStory: (story_2, commentIds_0) => {
15062
- const view_33 = pagedEditorRef.current?.getView();
15063
- return story_2.type === "main" && view_33 ? createPendingSuggestionSourceSnapshot(view_33.state, commentIds_0) : null;
15312
+ const view_35 = pagedEditorRef.current?.getView();
15313
+ return story_2.type === "main" && view_35 ? createPendingSuggestionSourceSnapshot(view_35.state, commentIds_0) : null;
15064
15314
  },
15065
- apply: (record, snapshot_4) => {
15066
- const view_34 = pagedEditorRef.current?.getView();
15067
- if (!view_34) return {
15315
+ apply: (record, snapshot_5) => {
15316
+ const view_36 = pagedEditorRef.current?.getView();
15317
+ if (!view_36) return {
15068
15318
  applied: [],
15069
15319
  skipped: []
15070
15320
  };
15321
+ const canonical_4 = getCanonicalApi()?.applyCanonicalDocumentOperations({
15322
+ snapshot: snapshot_5,
15323
+ batch: {
15324
+ version: FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION,
15325
+ operations: [record.operation],
15326
+ mode: "suggested"
15327
+ },
15328
+ author: record.author
15329
+ });
15330
+ if (canonical_4) return canonical_4;
15071
15331
  const createdComments_1 = [];
15072
- const result_0 = applyFolioDocumentOperations({
15073
- view: view_34,
15074
- snapshot: snapshot_4,
15332
+ const result_4 = applyFolioDocumentOperations({
15333
+ view: view_36,
15334
+ snapshot: snapshot_5,
15075
15335
  batch: {
15076
15336
  version: FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION,
15077
15337
  operations: [record.operation],
@@ -15084,78 +15344,78 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15084
15344
  return comment_1.id;
15085
15345
  }
15086
15346
  });
15087
- const appliedComments = appliedOperationComments(createdComments_1, result_0.applied);
15347
+ const appliedComments = appliedOperationComments(createdComments_1, result_4.applied);
15088
15348
  if (appliedComments.length > 0) updateComments((currentComments_2) => [...currentComments_2, ...appliedComments]);
15089
15349
  return {
15090
- applied: result_0.applied,
15091
- skipped: result_0.skipped
15350
+ applied: result_4.applied,
15351
+ skipped: result_4.skipped
15092
15352
  };
15093
15353
  },
15094
15354
  activeSuggestionIds: () => {
15095
- const view_35 = pagedEditorRef.current?.getView();
15096
- return new Set(view_35 ? getSuggestions(view_35.state).map((s_3) => s_3.suggestionId) : []);
15355
+ const view_37 = pagedEditorRef.current?.getView();
15356
+ return new Set(view_37 ? getSuggestions(view_37.state).map((s_3) => s_3.suggestionId) : []);
15097
15357
  }
15098
15358
  }),
15099
15359
  acceptSuggestion: (suggestionId, options_3) => {
15100
- const view_36 = pagedEditorRef.current?.getView();
15101
- if (!view_36) return {
15360
+ const view_38 = pagedEditorRef.current?.getView();
15361
+ if (!view_38) return {
15102
15362
  accepted: false,
15103
15363
  appliedAs: null
15104
15364
  };
15105
- const appliedAs = getSuggestions(view_36.state).find((s_4) => s_4.suggestionId === suggestionId)?.appliedAs ?? null;
15106
- const accepted = acceptSuggestion(suggestionId, { author: options_3?.author ?? author })(view_36.state, view_36.dispatch);
15365
+ const appliedAs = getSuggestions(view_38.state).find((s_4) => s_4.suggestionId === suggestionId)?.appliedAs ?? null;
15366
+ const accepted = acceptSuggestion(suggestionId, { author: options_3?.author ?? author })(view_38.state, view_38.dispatch);
15107
15367
  return {
15108
15368
  accepted,
15109
15369
  appliedAs: accepted ? appliedAs : null
15110
15370
  };
15111
15371
  },
15112
15372
  rejectSuggestion: (suggestionId_0) => {
15113
- const view_37 = pagedEditorRef.current?.getView();
15114
- if (!view_37) return false;
15115
- return rejectSuggestion(suggestionId_0)(view_37.state, view_37.dispatch);
15373
+ const view_39 = pagedEditorRef.current?.getView();
15374
+ if (!view_39) return false;
15375
+ return rejectSuggestion(suggestionId_0)(view_39.state, view_39.dispatch);
15116
15376
  },
15117
15377
  scrollToSuggestion: (suggestionId_1) => {
15118
- const view_38 = pagedEditorRef.current?.getView();
15119
- if (!view_38) return false;
15120
- const range_5 = findSuggestionRange(view_38.state, suggestionId_1);
15378
+ const view_40 = pagedEditorRef.current?.getView();
15379
+ if (!view_40) return false;
15380
+ const range_5 = findSuggestionRange(view_40.state, suggestionId_1);
15121
15381
  if (!range_5) return false;
15122
- const { from: from_12, to: to_12 } = clampRangeToDocSize(view_38.state.doc.content.size, range_5);
15123
- const $from_3 = view_38.state.doc.resolve(from_12);
15124
- const $to_3 = view_38.state.doc.resolve(to_12);
15125
- view_38.dispatch(view_38.state.tr.setSelection(TextSelection.between($from_3, $to_3)));
15382
+ const { from: from_12, to: to_12 } = clampRangeToDocSize(view_40.state.doc.content.size, range_5);
15383
+ const $from_3 = view_40.state.doc.resolve(from_12);
15384
+ const $to_3 = view_40.state.doc.resolve(to_12);
15385
+ view_40.dispatch(view_40.state.tr.setSelection(TextSelection.between($from_3, $to_3)));
15126
15386
  requestAnimationFrame(() => {
15127
15387
  pagedEditorRef.current?.scrollToPosition(from_12);
15128
15388
  });
15129
15389
  return true;
15130
15390
  },
15131
15391
  getTrackedChanges: () => {
15132
- const view_39 = pagedEditorRef.current?.getView();
15133
- return view_39 ? getTrackedChangesFromDoc(view_39.state.doc) : [];
15392
+ const view_41 = pagedEditorRef.current?.getView();
15393
+ return view_41 ? getTrackedChangesFromDoc(view_41.state.doc) : [];
15134
15394
  },
15135
15395
  getCommentAnchors: () => {
15136
- const view_40 = pagedEditorRef.current?.getView();
15137
- return view_40 ? getCommentAnchorsFromDoc(view_40.state.doc) : [];
15396
+ const view_42 = pagedEditorRef.current?.getView();
15397
+ return view_42 ? getCommentAnchorsFromDoc(view_42.state.doc) : [];
15138
15398
  },
15139
15399
  getSelectionText: () => {
15140
- const view_41 = pagedEditorRef.current?.getView();
15141
- return view_41 ? getSelectedText(view_41.state) : "";
15400
+ const view_43 = pagedEditorRef.current?.getView();
15401
+ return view_43 ? getSelectedText(view_43.state) : "";
15142
15402
  },
15143
15403
  getPageText: (page_1) => {
15144
- const view_42 = pagedEditorRef.current?.getView();
15145
- if (!view_42) return null;
15146
- return getPageTextFromLayout(pagedEditorRef.current?.getEditor()?.getLayout() ?? null, view_42.state.doc, page_1);
15404
+ const view_44 = pagedEditorRef.current?.getView();
15405
+ if (!view_44) return null;
15406
+ return getPageTextFromLayout(pagedEditorRef.current?.getEditor()?.getLayout() ?? null, view_44.state.doc, page_1);
15147
15407
  },
15148
- getTargetPage: (target_2, snapshot_5) => {
15149
- const view_43 = pagedEditorRef.current?.getView();
15150
- if (!view_43) return null;
15408
+ getTargetPage: (target_2, snapshot_6) => {
15409
+ const view_45 = pagedEditorRef.current?.getView();
15410
+ if (!view_45) return null;
15151
15411
  const range_6 = target_2.type === "textRange" ? resolveFolioAITextRange({
15152
15412
  range: target_2,
15153
- doc: view_43.state.doc,
15154
- snapshot: snapshot_5
15413
+ doc: view_45.state.doc,
15414
+ snapshot: snapshot_6
15155
15415
  }) : resolveFolioAIBlockRange({
15156
15416
  blockId: target_2.blockId,
15157
- doc: view_43.state.doc,
15158
- snapshot: snapshot_5
15417
+ doc: view_45.state.doc,
15418
+ snapshot: snapshot_6
15159
15419
  });
15160
15420
  if (range_6 === null) return null;
15161
15421
  return pagedEditorRef.current?.getPageNumberForPmPos(range_6.from) ?? null;
@@ -15165,49 +15425,49 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15165
15425
  getScrollRoot: () => pagedEditorRef.current?.getScrollRoot() ?? null,
15166
15426
  onLayoutChange: (listener) => pagedEditorRef.current?.onLayoutChange(listener) ?? (() => {}),
15167
15427
  getContentControls: (filter = {}) => {
15168
- const view_44 = pagedEditorRef.current?.getView();
15169
- if (!view_44) return [];
15170
- return findBlockSdtMatches(view_44.state.doc, filter).map((match_0) => ({
15428
+ const view_46 = pagedEditorRef.current?.getView();
15429
+ if (!view_46) return [];
15430
+ return findBlockSdtMatches(view_46.state.doc, filter).map((match_0) => ({
15171
15431
  properties: blockSdtAttrsToSdtProperties(match_0.node),
15172
15432
  path: match_0.path,
15173
15433
  pmPos: match_0.pos
15174
15434
  }));
15175
15435
  },
15176
15436
  scrollToContentControl: (filter_0) => {
15177
- const view_45 = pagedEditorRef.current?.getView();
15178
- if (!view_45) return false;
15179
- const match_1 = findBlockSdtMatch(view_45.state.doc, filter_0);
15437
+ const view_47 = pagedEditorRef.current?.getView();
15438
+ if (!view_47) return false;
15439
+ const match_1 = findBlockSdtMatch(view_47.state.doc, filter_0);
15180
15440
  if (!match_1) return false;
15181
15441
  const inside = match_1.pos + 1;
15182
- const $pos = view_45.state.doc.resolve(inside);
15183
- view_45.dispatch(view_45.state.tr.setSelection(TextSelection.near($pos)));
15442
+ const $pos = view_47.state.doc.resolve(inside);
15443
+ view_47.dispatch(view_47.state.tr.setSelection(TextSelection.near($pos)));
15184
15444
  requestAnimationFrame(() => {
15185
15445
  pagedEditorRef.current?.scrollToPosition(inside);
15186
15446
  });
15187
15447
  return true;
15188
15448
  },
15189
15449
  setContentControlContent: (filter_1, input, options_4 = {}) => {
15190
- const view_46 = pagedEditorRef.current?.getView();
15191
- if (!view_46) return false;
15192
- const tr_0 = typeof input === "string" ? setContentControlContentTr(view_46.state, filter_1, input, options_4) : setContentControlContentBlocksTr(view_46.state, filter_1, input, options_4);
15450
+ const view_48 = pagedEditorRef.current?.getView();
15451
+ if (!view_48) return false;
15452
+ const tr_0 = typeof input === "string" ? setContentControlContentTr(view_48.state, filter_1, input, options_4) : setContentControlContentBlocksTr(view_48.state, filter_1, input, options_4);
15193
15453
  if (!tr_0) return false;
15194
- view_46.dispatch(tr_0);
15454
+ view_48.dispatch(tr_0);
15195
15455
  return true;
15196
15456
  },
15197
15457
  setContentControlValue: (filter_2, input_0, options_5 = {}) => {
15198
- const view_47 = pagedEditorRef.current?.getView();
15199
- if (!view_47) return false;
15200
- const tr_1 = setContentControlValueTr(view_47.state, filter_2, input_0, options_5);
15458
+ const view_49 = pagedEditorRef.current?.getView();
15459
+ if (!view_49) return false;
15460
+ const tr_1 = setContentControlValueTr(view_49.state, filter_2, input_0, options_5);
15201
15461
  if (!tr_1) return false;
15202
- view_47.dispatch(tr_1);
15462
+ view_49.dispatch(tr_1);
15203
15463
  return true;
15204
15464
  },
15205
15465
  removeContentControl: (filter_3, options_6 = {}) => {
15206
- const view_48 = pagedEditorRef.current?.getView();
15207
- if (!view_48) return false;
15208
- const tr_2 = removeContentControlTr(view_48.state, filter_3, options_6);
15466
+ const view_50 = pagedEditorRef.current?.getView();
15467
+ if (!view_50) return false;
15468
+ const tr_2 = removeContentControlTr(view_50.state, filter_3, options_6);
15209
15469
  if (!tr_2) return false;
15210
- view_48.dispatch(tr_2);
15470
+ view_50.dispatch(tr_2);
15211
15471
  return true;
15212
15472
  }
15213
15473
  }), [
@@ -15242,7 +15502,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15242
15502
  label: t(DISPLAY_MODE_LABEL_KEYS[mode_0])
15243
15503
  })), [t]);
15244
15504
  const activeHistoryAvailability = (() => {
15245
- if (experimentalSession === "canonical") return {
15505
+ if (usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting)) return {
15246
15506
  canRedo: pagedEditorRef.current?.canRedo() ?? false,
15247
15507
  canUndo: pagedEditorRef.current?.canUndo() ?? false
15248
15508
  };
@@ -15297,47 +15557,47 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15297
15557
  if (isDisplayMode(value)) setDisplayMode(value);
15298
15558
  }, [setDisplayMode]);
15299
15559
  const handleAcceptActiveChange = useCallback(() => {
15300
- const view_49 = pagedEditorRef.current?.getView();
15301
- if (!view_49) return;
15302
- const { from: from_13, to: to_13 } = view_49.state.selection;
15303
- const range_7 = findChangeAtPosition(view_49.state, from_13, to_13);
15560
+ const view_51 = pagedEditorRef.current?.getView();
15561
+ if (!view_51) return;
15562
+ const { from: from_13, to: to_13 } = view_51.state.selection;
15563
+ const range_7 = findChangeAtPosition(view_51.state, from_13, to_13);
15304
15564
  if (resolveCanonicalReviewRange({
15305
15565
  editor: pagedEditorRef.current?.getEditor(),
15306
15566
  ...range_7,
15307
15567
  resolution: "accept"
15308
- }) === null) acceptChange(range_7.from, range_7.to)(view_49.state, view_49.dispatch);
15568
+ }) === null) acceptChange(range_7.from, range_7.to)(view_51.state, view_51.dispatch);
15309
15569
  }, []);
15310
15570
  const handleRejectActiveChange = useCallback(() => {
15311
- const view_50 = pagedEditorRef.current?.getView();
15312
- if (!view_50) return;
15313
- const { from: from_14, to: to_14 } = view_50.state.selection;
15314
- const range_8 = findChangeAtPosition(view_50.state, from_14, to_14);
15571
+ const view_52 = pagedEditorRef.current?.getView();
15572
+ if (!view_52) return;
15573
+ const { from: from_14, to: to_14 } = view_52.state.selection;
15574
+ const range_8 = findChangeAtPosition(view_52.state, from_14, to_14);
15315
15575
  if (resolveCanonicalReviewRange({
15316
15576
  editor: pagedEditorRef.current?.getEditor(),
15317
15577
  ...range_8,
15318
15578
  resolution: "reject"
15319
- }) === null) rejectChange(range_8.from, range_8.to)(view_50.state, view_50.dispatch);
15579
+ }) === null) rejectChange(range_8.from, range_8.to)(view_52.state, view_52.dispatch);
15320
15580
  }, []);
15321
15581
  const handlePreviousChange = useCallback(() => {
15322
- const view_51 = pagedEditorRef.current?.getView();
15323
- if (!view_51) return;
15324
- const { from: from_15 } = view_51.state.selection;
15325
- const change = findPreviousChange(view_51.state, from_15);
15582
+ const view_53 = pagedEditorRef.current?.getView();
15583
+ if (!view_53) return;
15584
+ const { from: from_15 } = view_53.state.selection;
15585
+ const change = findPreviousChange(view_53.state, from_15);
15326
15586
  if (!change) return;
15327
- view_51.dispatch(view_51.state.tr.setSelection(TextSelection.create(view_51.state.doc, change.from, change.to)));
15328
- view_51.focus();
15587
+ view_53.dispatch(view_53.state.tr.setSelection(TextSelection.create(view_53.state.doc, change.from, change.to)));
15588
+ view_53.focus();
15329
15589
  requestAnimationFrame(() => {
15330
15590
  pagedEditorRef.current?.scrollToPosition(change.from);
15331
15591
  });
15332
15592
  }, []);
15333
15593
  const handleNextChange = useCallback(() => {
15334
- const view_52 = pagedEditorRef.current?.getView();
15335
- if (!view_52) return;
15336
- const { to: to_15 } = view_52.state.selection;
15337
- const change_0 = findNextChange(view_52.state, to_15);
15594
+ const view_54 = pagedEditorRef.current?.getView();
15595
+ if (!view_54) return;
15596
+ const { to: to_15 } = view_54.state.selection;
15597
+ const change_0 = findNextChange(view_54.state, to_15);
15338
15598
  if (!change_0) return;
15339
- view_52.dispatch(view_52.state.tr.setSelection(TextSelection.create(view_52.state.doc, change_0.from, change_0.to)));
15340
- view_52.focus();
15599
+ view_54.dispatch(view_54.state.tr.setSelection(TextSelection.create(view_54.state.doc, change_0.from, change_0.to)));
15600
+ view_54.focus();
15341
15601
  requestAnimationFrame(() => {
15342
15602
  pagedEditorRef.current?.scrollToPosition(change_0.from);
15343
15603
  });
@@ -15507,51 +15767,94 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15507
15767
  requestAnimationFrame(syncCommentHighlightStyles);
15508
15768
  }, [onScrollTopChange, syncCommentHighlightStyles]);
15509
15769
  const handlePagedSelectionChange = useCallback((_from, _to) => {
15510
- const view_53 = getActiveEditorView() ?? pagedEditorRef.current?.getView() ?? null;
15511
- handleSelectionChange(view_53 ? extractSelectionState(view_53.state) : null);
15770
+ const view_55 = getActiveEditorView() ?? pagedEditorRef.current?.getView() ?? null;
15771
+ handleSelectionChange(view_55 ? extractSelectionState(view_55.state) : null);
15512
15772
  }, [getActiveEditorView, handleSelectionChange]);
15513
15773
  const handleTotalPagesChange = useCallback((totalPages) => {
15514
15774
  setScrollPageInfo((previous) => updateScrollPageTotal(previous, totalPages));
15515
15775
  }, [setScrollPageInfo]);
15516
15776
  const handleCommentClick = useCallback((id) => setActiveCommentId(id), [setActiveCommentId]);
15517
15777
  const handleCommentResolve = useCallback((id_0) => {
15518
- if (refuseCanonicalModelEdit("Comment changes are unavailable in this session.")) return;
15778
+ if (applyCanonicalComment({
15779
+ type: "resolve",
15780
+ id: id_0,
15781
+ status: "resolved"
15782
+ }) !== null) return;
15519
15783
  updateComments((previous_0) => previous_0.map((comment_2) => comment_2.id === id_0 ? {
15520
15784
  ...comment_2,
15521
15785
  done: true
15522
15786
  } : comment_2));
15523
- }, [refuseCanonicalModelEdit, updateComments]);
15787
+ }, [applyCanonicalComment, updateComments]);
15524
15788
  const handleCommentDelete = useCallback((id_1) => {
15525
- if (refuseCanonicalModelEdit("Comment changes are unavailable in this session.")) return;
15789
+ const result_5 = applyCanonicalComment({
15790
+ type: "delete",
15791
+ id: id_1
15792
+ });
15793
+ if (result_5 !== null) {
15794
+ if (result_5.status === "applied" && activeCommentId === id_1) setActiveCommentId(null);
15795
+ return;
15796
+ }
15526
15797
  updateComments((previous_1) => previous_1.filter((comment_3) => comment_3.id !== id_1 && comment_3.parentId !== id_1));
15527
15798
  if (activeCommentId === id_1) setActiveCommentId(null);
15528
15799
  }, [
15529
15800
  activeCommentId,
15530
- refuseCanonicalModelEdit,
15801
+ applyCanonicalComment,
15531
15802
  setActiveCommentId,
15532
15803
  updateComments
15533
15804
  ]);
15534
15805
  const handleCommentReply = useCallback((id_2, text_6) => {
15535
- if (refuseCanonicalModelEdit("Comment changes are unavailable in this session.")) return;
15806
+ if (applyCanonicalComment({
15807
+ type: "create",
15808
+ text: text_6,
15809
+ author,
15810
+ anchor: {
15811
+ kind: "reply",
15812
+ parentId: id_2
15813
+ }
15814
+ }) !== null) return;
15536
15815
  updateComments((previous_2) => [...previous_2, createComment(text_6, author, id_2)]);
15537
15816
  }, [
15817
+ applyCanonicalComment,
15538
15818
  author,
15539
15819
  createComment,
15540
- refuseCanonicalModelEdit,
15541
15820
  updateComments
15542
15821
  ]);
15543
15822
  const handleAddComment = useCallback((addText) => {
15544
- if (refuseCanonicalModelEdit("Comment changes are unavailable in this session.")) return false;
15823
+ const view_56 = pagedEditorRef.current?.getView();
15824
+ if (!view_56 || !commentSelectionRange) return false;
15825
+ const result_6 = applyCanonicalComment({
15826
+ type: "create",
15827
+ text: addText,
15828
+ author,
15829
+ anchor: {
15830
+ kind: "selection",
15831
+ ...commentSelectionRange,
15832
+ story: "main"
15833
+ }
15834
+ });
15835
+ if (result_6 !== null) {
15836
+ if (result_6?.status !== "applied") return false;
15837
+ setVisibleCommentAuthors((current_0) => {
15838
+ if (current_0 === null) return null;
15839
+ const next_1 = new Set(current_0);
15840
+ const created = result_6.comments.find(({ id: id_3 }) => id_3 === result_6.commentId);
15841
+ if (created) next_1.add(getCommentAuthorKey(created.author));
15842
+ return next_1;
15843
+ });
15844
+ if (result_6.commentId !== void 0) setActiveCommentId(result_6.commentId);
15845
+ setIsAddingComment(false);
15846
+ setCommentSelectionRange(null);
15847
+ setAddCommentYPosition(null);
15848
+ return true;
15849
+ }
15545
15850
  const comment_4 = createComment(addText, author);
15546
- const view_54 = pagedEditorRef.current?.getView();
15547
- if (!view_54 || !commentSelectionRange) return false;
15548
- if (!applyCommentMarkRange(view_54, commentSelectionRange, comment_4.id, { replacePending: true })) return false;
15851
+ if (!applyCommentMarkRange(view_56, commentSelectionRange, comment_4.id, { replacePending: true })) return false;
15549
15852
  const commentAuthor_2 = getCommentAuthorKey(comment_4.author);
15550
- setVisibleCommentAuthors((current_0) => {
15551
- if (current_0 === null) return null;
15552
- const next_1 = new Set(current_0);
15553
- next_1.add(commentAuthor_2);
15554
- return next_1;
15853
+ setVisibleCommentAuthors((current_1) => {
15854
+ if (current_1 === null) return null;
15855
+ const next_2 = new Set(current_1);
15856
+ next_2.add(commentAuthor_2);
15857
+ return next_2;
15555
15858
  });
15556
15859
  setActiveCommentId(comment_4.id);
15557
15860
  updateComments((previous_3) => [...previous_3, comment_4]);
@@ -15566,9 +15869,9 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15566
15869
  return true;
15567
15870
  }, [
15568
15871
  author,
15872
+ applyCanonicalComment,
15569
15873
  commentSelectionRange,
15570
15874
  createComment,
15571
- refuseCanonicalModelEdit,
15572
15875
  setActiveCommentId,
15573
15876
  setAddCommentYPosition,
15574
15877
  setCommentSelectionRange,
@@ -15578,22 +15881,32 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15578
15881
  updateComments
15579
15882
  ]);
15580
15883
  const handleTrackedChangeReply = useCallback((revisionId_2, text_7) => {
15581
- if (refuseCanonicalModelEdit("Comment changes are unavailable in this session.")) return;
15884
+ if (applyCanonicalComment({
15885
+ type: "create",
15886
+ text: text_7,
15887
+ author,
15888
+ anchor: {
15889
+ kind: "revision",
15890
+ story: "main",
15891
+ revisionId: revisionId_2
15892
+ }
15893
+ }) !== null) return;
15582
15894
  updateComments((previous_4) => [...previous_4, createComment(text_7, author, revisionId_2)]);
15583
15895
  }, [
15896
+ applyCanonicalComment,
15584
15897
  author,
15585
15898
  createComment,
15586
- refuseCanonicalModelEdit,
15587
15899
  updateComments
15588
15900
  ]);
15589
15901
  const handleCancelAddComment = useCallback(() => {
15590
- const view_55 = pagedEditorRef.current?.getView();
15591
- if (view_55 && commentSelectionRange) removePendingCommentMarkRange(view_55, commentSelectionRange);
15902
+ const view_57 = pagedEditorRef.current?.getView();
15903
+ if (view_57 && commentSelectionRange && commentDraftMode === "prosemirror") removePendingCommentMarkRange(view_57, commentSelectionRange);
15592
15904
  setIsAddingComment(false);
15593
15905
  setCommentSelectionRange(null);
15594
15906
  setAddCommentYPosition(null);
15595
15907
  }, [
15596
15908
  commentSelectionRange,
15909
+ commentDraftMode,
15597
15910
  setAddCommentYPosition,
15598
15911
  setCommentSelectionRange,
15599
15912
  setIsAddingComment
@@ -15604,23 +15917,23 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15604
15917
  })?.revisionId ?? null;
15605
15918
  }, []);
15606
15919
  const handleSidebarAcceptChange = useCallback((from_17, to_17) => {
15607
- const view_56 = pagedEditorRef.current?.getView();
15608
- if (!view_56) return;
15920
+ const view_58 = pagedEditorRef.current?.getView();
15921
+ if (!view_58) return;
15609
15922
  const revisionId_3 = resolveSidebarChangeRevisionId(from_17, to_17);
15610
15923
  if (revisionId_3 === null) return;
15611
- const editor_5 = pagedEditorRef.current?.getEditor();
15612
- if (editor_5?.getCanonicalDocument()) editor_5.resolveCanonicalRevisions([revisionId_3], "accept");
15613
- else acceptAIEditRevision(revisionId_3)(view_56.state, view_56.dispatch);
15924
+ const editor_6 = pagedEditorRef.current?.getEditor();
15925
+ if (editor_6?.getCanonicalDocument()) editor_6.resolveCanonicalRevisions([revisionId_3], "accept");
15926
+ else acceptAIEditRevision(revisionId_3)(view_58.state, view_58.dispatch);
15614
15927
  extractTrackedChanges();
15615
15928
  }, [extractTrackedChanges, resolveSidebarChangeRevisionId]);
15616
15929
  const handleSidebarRejectChange = useCallback((from_18, to_18) => {
15617
- const view_57 = pagedEditorRef.current?.getView();
15618
- if (!view_57) return;
15930
+ const view_59 = pagedEditorRef.current?.getView();
15931
+ if (!view_59) return;
15619
15932
  const revisionId_4 = resolveSidebarChangeRevisionId(from_18, to_18);
15620
15933
  if (revisionId_4 === null) return;
15621
- const editor_6 = pagedEditorRef.current?.getEditor();
15622
- if (editor_6?.getCanonicalDocument()) editor_6.resolveCanonicalRevisions([revisionId_4], "reject");
15623
- else rejectAIEditRevision(revisionId_4)(view_57.state, view_57.dispatch);
15934
+ const editor_7 = pagedEditorRef.current?.getEditor();
15935
+ if (editor_7?.getCanonicalDocument()) editor_7.resolveCanonicalRevisions([revisionId_4], "reject");
15936
+ else rejectAIEditRevision(revisionId_4)(view_59.state, view_59.dispatch);
15624
15937
  extractTrackedChanges();
15625
15938
  }, [extractTrackedChanges, resolveSidebarChangeRevisionId]);
15626
15939
  const commentsPageWidth = history.state?.package.document.finalSectionProperties?.pageWidth;
@@ -15668,7 +15981,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15668
15981
  ]);
15669
15982
  const openCommentThreadCount = useMemo(() => countOpenCommentThreads(comments), [comments]);
15670
15983
  const outlineToggle = (() => {
15671
- if (panels.layout.outline !== "drawer") return "absent";
15984
+ if (panels.layout.outline !== "drawer" && panels.layout.outline !== "expanded") return "absent";
15672
15985
  return panelOverlay === "outline" ? "open" : "closed";
15673
15986
  })();
15674
15987
  const panelToggles = useMemo(() => /* @__PURE__ */ jsx(PanelToggles, {
@@ -15748,9 +16061,9 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15748
16061
  };
15749
16062
  requestAnimationFrame(flash);
15750
16063
  }, []);
15751
- const handleOutlineJump = useCallback((id_3) => {
15752
- markHeadingJumped(id_3);
15753
- handleOutlineHeadingClick(Number(id_3));
16064
+ const handleOutlineJump = useCallback((id_4) => {
16065
+ markHeadingJumped(id_4);
16066
+ handleOutlineHeadingClick(Number(id_4));
15754
16067
  }, [handleOutlineHeadingClick, markHeadingJumped]);
15755
16068
  const handleTextContextAction = useCallback((action_3) => {
15756
16069
  handleContextMenuAction(action_3);
@@ -15763,8 +16076,8 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15763
16076
  }, [readOnly]);
15764
16077
  const closeTableProperties = useCallback(() => setTablePropsOpen(false), []);
15765
16078
  const applyTableProperties = useCallback((props_0) => {
15766
- const view_58 = getActiveEditorView();
15767
- if (view_58) setTableProperties(props_0)(view_58.state, view_58.dispatch);
16079
+ const view_60 = getActiveEditorView();
16080
+ if (view_60) setTableProperties(props_0)(view_60.state, view_60.dispatch);
15768
16081
  }, [getActiveEditorView]);
15769
16082
  const closeImagePosition = useCallback(() => setImagePositionOpen(false), [setImagePositionOpen]);
15770
16083
  const closeImageProperties = useCallback(() => setImagePropsOpen(false), [setImagePropsOpen]);
@@ -15772,8 +16085,8 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15772
16085
  const closeFootnoteProperties = useCallback(() => setFootnotePropsOpen(false), []);
15773
16086
  const closeInsertSymbol = useCallback(() => setShowInsertSymbol(false), []);
15774
16087
  const insertSymbol = useCallback((symbol) => {
15775
- const view_59 = getActiveEditorView();
15776
- if (view_59) view_59.dispatch(view_59.state.tr.insertText(symbol).scrollIntoView());
16088
+ const view_61 = getActiveEditorView();
16089
+ if (view_61) view_61.dispatch(view_61.state.tr.insertText(symbol).scrollIntoView());
15777
16090
  }, [getActiveEditorView]);
15778
16091
  const imagePropertiesCurrentData = useMemo(() => buildImagePropertiesData(state.pmImageContext), [state.pmImageContext]);
15779
16092
  const currentFindResult = findResultRef.current;
@@ -15856,8 +16169,8 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15856
16169
  ]);
15857
16170
  const closeNumberingValueDialog = useCallback(() => setNumberingValueDialogOpen(false), []);
15858
16171
  const applyNumberingValue = useCallback((value_0) => {
15859
- const view_60 = getActiveEditorView();
15860
- if (view_60) setNumberingValue(value_0)(view_60.state, view_60.dispatch);
16172
+ const view_62 = getActiveEditorView();
16173
+ if (view_62) setNumberingValue(value_0)(view_62.state, view_62.dispatch);
15861
16174
  }, [getActiveEditorView]);
15862
16175
  const numberingValueDialog = useMemo(() => ({
15863
16176
  isOpen: numberingValueDialogOpen,
@@ -16004,15 +16317,20 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
16004
16317
  "data-folio-outline": panels.layout.outline,
16005
16318
  "data-folio-comments": panels.layout.comments,
16006
16319
  children: [
16007
- (panels.layout.outline === "column" || panels.layout.outline === "rail") && /* @__PURE__ */ jsx(DocumentOutline, {
16008
- headings: outlineHeadings,
16320
+ panels.layout.outline !== "none" && panels.layout.outline !== "drawer" && /* @__PURE__ */ jsx(DocumentOutline, {
16321
+ headings: visibleOutlineHeadings,
16322
+ available: outlineHeadings.length > 1,
16323
+ outlineDepth,
16324
+ onOutlineDepthChange: handleOutlineDepthChange,
16009
16325
  scrollContainerRef,
16010
16326
  docSize: pagedEditorRef.current?.getView()?.state.doc.content.size ?? 0,
16011
16327
  activeId: activeHeadingId,
16012
16328
  onJump: handleOutlineJump,
16013
16329
  surface: panels.layout.outline,
16330
+ width: panels.layout.outlineTrackWidth,
16014
16331
  expanded: panelOverlay === "outline",
16015
- onExpand: toggleOutlineOverlay
16332
+ onExpand: toggleOutlineOverlay,
16333
+ ...panels.layout.outline === "expanded" ? { onClose: closePanelOverlay } : {}
16016
16334
  }),
16017
16335
  /* @__PURE__ */ jsxs("div", {
16018
16336
  ref: scrollContainerRef,
@@ -16119,7 +16437,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
16119
16437
  showMarginGuides,
16120
16438
  ...marginGuideColor !== void 0 ? { marginGuideColor } : {},
16121
16439
  readOnly,
16122
- ...experimentalSession === void 0 ? {} : { experimentalSession },
16440
+ ...!usesCanonicalSession(experimentalSession, CANONICAL_GAP.authorityRouting) ? {} : { experimentalSession },
16123
16441
  onDocumentChange: handleDocumentChange,
16124
16442
  extensionManager,
16125
16443
  suggestionModeActive: editingMode === "suggesting",
@@ -16156,8 +16474,8 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
16156
16474
  onMouseDown: (e_1) => {
16157
16475
  e_1.preventDefault();
16158
16476
  e_1.stopPropagation();
16159
- const view_61 = pagedEditorRef.current?.getView();
16160
- if (!view_61) {
16477
+ const view_63 = pagedEditorRef.current?.getView();
16478
+ if (!view_63) {
16161
16479
  setFloatingCommentBtn(null);
16162
16480
  return;
16163
16481
  }
@@ -16165,9 +16483,9 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
16165
16483
  from: floatingCommentBtn.from,
16166
16484
  to: floatingCommentBtn.to
16167
16485
  };
16168
- const currentSelection = view_61.state.selection;
16486
+ const currentSelection = view_63.state.selection;
16169
16487
  const safeRange = resolveCommentCreationRange({
16170
- docSize: view_61.state.doc.content.size,
16488
+ docSize: view_63.state.doc.content.size,
16171
16489
  capturedRange,
16172
16490
  currentRange: {
16173
16491
  from: currentSelection.from,
@@ -16181,10 +16499,12 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
16181
16499
  return;
16182
16500
  }
16183
16501
  setCommentSelectionRange(safeRange);
16184
- if (!applyCommentMarkRange(view_61, safeRange, -1, { selectEnd: true })) {
16185
- setCommentSelectionRange(null);
16186
- setFloatingCommentBtn(null);
16187
- return;
16502
+ if (commentDraftMode === "prosemirror") {
16503
+ if (!applyCommentMarkRange(view_63, safeRange, -1, { selectEnd: true })) {
16504
+ setCommentSelectionRange(null);
16505
+ setFloatingCommentBtn(null);
16506
+ return;
16507
+ }
16188
16508
  }
16189
16509
  const yPos_0 = findSelectionYPosition(scrollContainerRef.current, editorContentRef.current, safeRange.from);
16190
16510
  setAddCommentYPosition(yPos_0 ?? floatingCommentBtn.top);
@@ -16254,15 +16574,6 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
16254
16574
  })
16255
16575
  })]
16256
16576
  }),
16257
- panelOverlay === "outline" && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(PanelScrim, { onDismiss: closePanelOverlay }), /* @__PURE__ */ jsx(DocumentOutline, {
16258
- headings: outlineHeadings,
16259
- scrollContainerRef,
16260
- docSize: pagedEditorRef.current?.getView()?.state.doc.content.size ?? 0,
16261
- activeId: activeHeadingId,
16262
- onJump: handleOutlineJump,
16263
- surface: "drawer",
16264
- onClose: closePanelOverlay
16265
- })] }),
16266
16577
  commentsSurface === "drawer" && /* @__PURE__ */ jsx(PanelScrim, { onDismiss: dismissCommentsDrawer })
16267
16578
  ]
16268
16579
  }),