@stll/folio-react 0.24.1 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/{CommentsSidebar-D0TBbrpB.js → CommentsSidebar-D9vMIMl7.js} +6 -2
  2. package/dist/compat/eigenpal.d.ts +1 -1
  3. package/dist/compat/eigenpal.js +1 -1
  4. package/dist/i18n/messages/ar.d.ts +2 -0
  5. package/dist/i18n/messages/ar.js +2 -0
  6. package/dist/i18n/messages/cs.d.ts +2 -0
  7. package/dist/i18n/messages/cs.js +2 -0
  8. package/dist/i18n/messages/de.d.ts +2 -0
  9. package/dist/i18n/messages/de.js +2 -0
  10. package/dist/i18n/messages/en.d.ts +2 -0
  11. package/dist/i18n/messages/en.js +2 -0
  12. package/dist/i18n/messages/es.d.ts +2 -0
  13. package/dist/i18n/messages/es.js +2 -0
  14. package/dist/i18n/messages/et.d.ts +2 -0
  15. package/dist/i18n/messages/et.js +2 -0
  16. package/dist/i18n/messages/fr.d.ts +2 -0
  17. package/dist/i18n/messages/fr.js +2 -0
  18. package/dist/i18n/messages/he.d.ts +2 -0
  19. package/dist/i18n/messages/he.js +2 -0
  20. package/dist/i18n/messages/hi.d.ts +2 -0
  21. package/dist/i18n/messages/hi.js +2 -0
  22. package/dist/i18n/messages/hu.d.ts +2 -0
  23. package/dist/i18n/messages/hu.js +2 -0
  24. package/dist/i18n/messages/locales.d.ts +2 -0
  25. package/dist/i18n/messages/locales.js +2 -0
  26. package/dist/i18n/messages/lt.d.ts +2 -0
  27. package/dist/i18n/messages/lt.js +2 -0
  28. package/dist/i18n/messages/lv.d.ts +2 -0
  29. package/dist/i18n/messages/lv.js +2 -0
  30. package/dist/i18n/messages/pl.d.ts +2 -0
  31. package/dist/i18n/messages/pl.js +2 -0
  32. package/dist/i18n/messages/pt-BR.d.ts +2 -0
  33. package/dist/i18n/messages/pt-BR.js +2 -0
  34. package/dist/i18n/messages/sk.d.ts +2 -0
  35. package/dist/i18n/messages/sk.js +2 -0
  36. package/dist/i18n/messages/tr.d.ts +2 -0
  37. package/dist/i18n/messages/tr.js +2 -0
  38. package/dist/i18n/messages/zh-CN.d.ts +2 -0
  39. package/dist/i18n/messages/zh-CN.js +2 -0
  40. package/dist/index.d.ts +1 -1
  41. package/dist/index.js +1 -1
  42. package/dist/{renderAsync-BYZY3FVx.d.ts → renderAsync-CfXBLJ_1.d.ts} +3 -0
  43. package/dist/{renderAsync-DqldIlJu.js → renderAsync-yYZKXh6r.js} +613 -292
  44. package/package.json +6 -2
@@ -7,6 +7,7 @@ import { AlertCircleIcon, AlertTriangleIcon, AlignCenterIcon, AlignJustifyIcon,
7
7
  import { closeHistory, redo, undo } from "prosemirror-history";
8
8
  import { IntlProvider, useFormatter, useTranslations } from "use-intl";
9
9
  import { FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FolioPendingSuggestionRegistry, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, createFolioAIEditSnapshot, createPendingSuggestionSourceSnapshot, getCommentAnchorsFromDoc, getFolioDocumentOperationIssues, getTrackedChangesFromDoc } from "@stll/folio-core/ai-edits";
10
+ import { resolveCanonicalReviewRange } from "@stll/folio-core/controller/canonicalReview";
10
11
  import { resolveActiveEditorStory } from "@stll/folio-core/controller/activeEditorStory";
11
12
  import { FOLIO_DOCX_SERIALIZATION_MODE, createFolioEditor } from "@stll/folio-core/controller/folioEditor";
12
13
  import { createNoteReferenceFollower, withoutUnreferencedNotes } from "@stll/folio-core/prosemirror/noteReferenceReview";
@@ -14,6 +15,7 @@ import { cloneDocumentWithParagraphPropertySources } from "@stll/folio-core/docx
14
15
  import { normalizeBaseDirection } from "@stll/folio-core/docx/normalizeBaseDirection";
15
16
  import { getCachedNumberingMap } from "@stll/folio-core/docx/numberingParser";
16
17
  import { classifyEditorKeydown, deleteSelectedTable, historyShortcutOwner, isFocusInInputLike, isKeydownInShortcutScope, isMacPlatform } from "@stll/folio-core/managers/editorShortcuts";
18
+ import { getEditorScrollRoot, scrollEditorBy, scrollEditorElementIntoView, scrollEditorTo } from "@stll/folio-core/paged-layout/editorScrollRoot";
17
19
  import { computeScrollPageInfo, updateScrollPageTotal } from "@stll/folio-core/paged-layout/scrollPageInfo";
18
20
  import { NO_LIST_STATE, TextSelection, addColumnLeft, addColumnRight, addRowAbove, addRowBelow, applyFormatMarks, applyStyle, applyTableStyle, autoFitContents, captureFormatMarks, clearFormatting, clearTextColor, continueNumbering, createStyleResolver, decreaseIndent, decreaseListLevel, deleteColumn, deleteRow, deleteTable, distributeColumns, extractSelectionState, getDocumentBuiltInStyles, getSelectedText, getTableContext, increaseIndent, increaseListLevel, listStateLevel, mergeCells, removeTabStop, removeTableBorders, restartNumbering, sameListState, schema, selectColumn, selectRow, selectTable, setAlignment, setAllTableBorders, setCellBorder, setCellFillColor, setCellMargins, setCellTextDirection, setCellVerticalAlign, setFontFamily, setFontSize, setHighlight, setIndentFirstLine, setIndentLeft, setIndentRight, setInsideTableBorders, setLineSpacing, setLtr, setNumberingValue, setOutsideTableBorders, setRowHeight, setRtl, setTableBorderColor, setTableBorderPreset, setTableBorderWidth, setTableProperties, setTextColor, splitCell, toggleBidi, toggleBold, toggleBulletList, toggleHeaderRow, toggleItalic, toggleNoWrap, toggleNumberedList, toggleStrike, toggleSubscript, toggleSuperscript, toggleUnderline } from "@stll/folio-core/prosemirror";
19
21
  import { acceptAIEditRevision, acceptChange, acceptSuggestion, findAIEditRevisionRange, findChangeAtPosition, findNextChange, findParagraphBoundaryChangeAtPosition, findPreviousChange, findSuggestionRange, getSuggestions, rejectAIEditRevision, rejectChange, rejectSuggestion } from "@stll/folio-core/prosemirror/commands/comments";
@@ -22,6 +24,8 @@ import { setContentControlContentBlocksTr } from "@stll/folio-core/prosemirror/c
22
24
  import { CLIPBOARD_READ_ERROR_EVENT, buildPlainTextSlice } from "@stll/folio-core/prosemirror/commands/pastePlainText";
23
25
  import { proseDocToBlocks } from "@stll/folio-core/prosemirror/conversion/fromProseDoc";
24
26
  import { ExtensionManager } from "@stll/folio-core/prosemirror/extensions/ExtensionManager";
27
+ import { executeEditorCommand, executeFirstEditorCommand } from "@stll/folio-core/prosemirror/executeEditorCommand";
28
+ import { insertPageBreak } from "@stll/folio-core/prosemirror/commands/pageBreak";
25
29
  import { clearTrackedChanges, getChangedParagraphIds, hasStructuralChanges, hasUntrackedChanges, repackWithEditorSectionRemovals } from "@stll/folio-core/prosemirror/extensions/features/ParagraphChangeTrackerExtension";
26
30
  import { createStarterKit } from "@stll/folio-core/prosemirror/extensions/StarterKit";
27
31
  import { resolveFindMatchRange } from "@stll/folio-core/prosemirror/findReplaceSelection";
@@ -40,6 +44,8 @@ import { onFontsLoaded } from "@stll/folio-core/utils/fontLoader";
40
44
  import { collectHeadings } from "@stll/folio-core/utils/headingCollector";
41
45
  import { formatPx, pixelsToTwips, pointsToHalfPoints, twipsToPixels } from "@stll/folio-core/utils/units";
42
46
  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";
43
49
  import { TableSelectionManager } from "@stll/folio-core/managers/TableSelectionManager";
44
50
  import { DEFAULT_PAGE_HEIGHT_PX, getMargins, getPageSize, twipsToPixels as twipsToPixels$1 } from "@stll/folio-core/paged-layout/sectionGeometry";
45
51
  import { createPortal } from "react-dom";
@@ -51,6 +57,7 @@ import { createNoteEditorManager } from "@stll/folio-core/controller/noteEditorM
51
57
  import { projectMarkupView, visibleCaretPosition } from "@stll/folio-core/prosemirror/markupViewProjection";
52
58
  import { createFolioAIEditSnapshot as createFolioAIEditSnapshot$1 } from "@stll/folio-core/ai-edits/snapshot";
53
59
  import { createFolioEditorEmitter } from "@stll/folio-core/controller/folioEditorEvents";
60
+ import { CanonicalSessionRefusalError, collectRemoteSelections, createHiddenEditorManager, createHiddenEditorState } from "@stll/folio-core/controller/hiddenEditorManager";
54
61
  import { dispatchEditorTextInput } from "@stll/folio-core/prosemirror/textInput";
55
62
  import { createLatestRequestGate } from "@stll/folio-core/controller/latestRequestGate";
56
63
  import { runLayoutPipeline } from "@stll/folio-core/controller/layoutPipeline";
@@ -80,7 +87,7 @@ import { onPaintedLayoutChange, readBlockRects } from "@stll/folio-core/paged-la
80
87
  import { LayoutSelectionGate } from "@stll/folio-core/paged-layout/LayoutSelectionGate";
81
88
  import { collectRunFontsAtPmPositions, measureDirectiveGutter, projectRangesToRects } from "@stll/folio-core/paged-layout/rangeProjection";
82
89
  import { isReadOnlyEditKey } from "@stll/folio-core/paged-layout/readOnlyEditAttempt";
83
- import { getPageScrollTarget, prefersReducedMotionBehavior } from "@stll/folio-core/paged-layout/scrollNavigation";
90
+ import { getPageScrollTarget } from "@stll/folio-core/paged-layout/scrollNavigation";
84
91
  import { PAGES_CONTAINER_CLASS, scrollPagesToPmPosition } from "@stll/folio-core/paged-layout/scrollToPmPosition";
85
92
  import { flashParagraphFragmentsByParaId } from "@stll/folio-core/paged-layout/paragraphFlash";
86
93
  import { resizeColumnPair } from "@stll/folio-core/paged-layout/tableColumnResize";
@@ -90,12 +97,12 @@ import { allowsDirectDrawingEdit } from "@stll/folio-core/docx/imageRawXml";
90
97
  import { commitImageFloatMove, commitImageInlineMove, commitImageResize, isFloatingImage } from "@stll/folio-core/prosemirror/imageCommit";
91
98
  import { buildEmbeddedFontFamilyMap, extractEmbeddedFonts } from "@stll/folio-core/fonts/embeddedFonts";
92
99
  import { panic } from "better-result";
93
- import { collectRemoteSelections, createHiddenEditorManager, createHiddenEditorState } from "@stll/folio-core/controller/hiddenEditorManager";
94
100
  import { loadCollaborationModules } from "@stll/folio-core/controller/collaborationModules";
95
101
  import { createVisualLineState, handleVisualLineKeyDown } from "@stll/folio-core/prosemirror/utils/visualLineNavigation";
96
102
  import { clampRangeToDocSize, resolveFolioAIBlockRange, resolveFolioAITextRange, resolvePassageRange } from "@stll/folio-core/ai-edits/blockRange";
97
103
  import { getFolioParaIdFromBlockId } from "@stll/folio-core/types/block-id";
98
104
  import { getPageTextFromLayout } from "@stll/folio-core/paged-layout/pageText";
105
+ import { allocateCommentId, seedCommentIdAbove } from "@stll/folio-core/prosemirror/commentIdAllocator";
99
106
  import { ContentControlWidgetController } from "@stll/folio-core/controller/contentControlWidgetController";
100
107
  import { createDefaultFindOptions, findInDocument } from "@stll/folio-core/utils/findReplace";
101
108
  import { PANEL_METRICS, computePanelLayout } from "@stll/folio-core/panel-layout";
@@ -337,22 +344,31 @@ const HOST_STYLES = {
337
344
  zIndex: -1,
338
345
  pointerEvents: "none"
339
346
  };
340
- const HiddenHeaderFooterPMs = memo(forwardRef(function HiddenHeaderFooterPMs({ document, styles, theme, onTransaction }, ref) {
347
+ const HiddenHeaderFooterPMs = memo(forwardRef(function HiddenHeaderFooterPMs({ document, styles, theme, onTransaction, experimentalSession, getCanonicalApi, onSessionRefusal }, ref) {
341
348
  const hostRef = useRef(null);
342
349
  const documentRef = useRef(document);
343
350
  const stylesRef = useRef(styles);
344
351
  const themeRef = useRef(theme);
345
352
  const onTransactionRef = useRef(onTransaction);
353
+ const canonicalApiRef = useRef(getCanonicalApi);
354
+ const sessionRef = useRef(experimentalSession);
355
+ const refusalRef = useRef(onSessionRefusal);
346
356
  documentRef.current = document;
347
357
  stylesRef.current = styles;
348
358
  themeRef.current = theme;
349
359
  onTransactionRef.current = onTransaction;
360
+ canonicalApiRef.current = getCanonicalApi;
361
+ sessionRef.current = experimentalSession;
362
+ refusalRef.current = onSessionRefusal;
350
363
  const managerRef = useRef(null);
351
364
  managerRef.current ??= createHeaderFooterEditorManager({
352
365
  getHost: () => hostRef.current,
353
366
  getDocument: () => documentRef.current,
354
367
  getStyles: () => stylesRef.current,
355
368
  getTheme: () => themeRef.current,
369
+ getCanonicalApi: () => canonicalApiRef.current?.() ?? null,
370
+ getExperimentalSession: () => sessionRef.current,
371
+ onSessionRefusal: (reason) => refusalRef.current?.(reason),
356
372
  onTransaction: ({ rId, kind, view, docChanged, selectionChanged }) => {
357
373
  onTransactionRef.current?.(rId, kind, view, docChanged, selectionChanged);
358
374
  }
@@ -418,13 +434,16 @@ const hostStyle = {
418
434
  };
419
435
  const EMPTY_PLUGINS$1 = [];
420
436
  const NoteStoryEditor = forwardRef(function NoteStoryEditor(t0, ref) {
421
- const $ = c(51);
422
- const { document, onActiveChange, onDocumentChange, onStoryChange, plugins, styles, suggestionAuthor, suggestionModeActive, theme } = t0;
437
+ const $ = c(57);
438
+ const { document, experimentalSession, getCanonicalApi, onSessionRefusal, onActiveChange, onDocumentChange, onStoryChange, plugins, styles, suggestionAuthor, suggestionModeActive, theme } = t0;
423
439
  const t = useTranslations("folio");
424
440
  const resolvedPlugins = plugins ?? EMPTY_PLUGINS$1;
425
441
  const isSuggestionModeActive = suggestionModeActive ?? false;
426
442
  const hostRef = useRef(null);
427
443
  const documentRef = useRef(document);
444
+ const canonicalApiRef = useRef(getCanonicalApi);
445
+ const sessionRef = useRef(experimentalSession);
446
+ const refusalRef = useRef(onSessionRefusal);
428
447
  const stylesRef = useRef(styles);
429
448
  const themeRef = useRef(theme);
430
449
  const pluginsRef = useRef(resolvedPlugins);
@@ -436,9 +455,12 @@ const NoteStoryEditor = forwardRef(function NoteStoryEditor(t0, ref) {
436
455
  const footnotes = document?.package.footnotes;
437
456
  const endnotes = document?.package.endnotes;
438
457
  let t1;
439
- if ($[0] !== active || $[1] !== document || $[2] !== onActiveChange || $[3] !== onDocumentChange || $[4] !== onStoryChange || $[5] !== resolvedPlugins || $[6] !== styles || $[7] !== theme) {
458
+ if ($[0] !== active || $[1] !== document || $[2] !== experimentalSession || $[3] !== getCanonicalApi || $[4] !== onActiveChange || $[5] !== onDocumentChange || $[6] !== onSessionRefusal || $[7] !== onStoryChange || $[8] !== resolvedPlugins || $[9] !== styles || $[10] !== theme) {
440
459
  t1 = () => {
441
460
  documentRef.current = document;
461
+ canonicalApiRef.current = getCanonicalApi;
462
+ sessionRef.current = experimentalSession;
463
+ refusalRef.current = onSessionRefusal;
442
464
  stylesRef.current = styles;
443
465
  themeRef.current = theme;
444
466
  pluginsRef.current = resolvedPlugins;
@@ -451,9 +473,15 @@ const NoteStoryEditor = forwardRef(function NoteStoryEditor(t0, ref) {
451
473
  getPlugins: () => pluginsRef.current,
452
474
  getStyles: () => stylesRef.current,
453
475
  getTheme: () => themeRef.current,
476
+ getCanonicalApi: () => canonicalApiRef.current?.() ?? null,
477
+ getExperimentalSession: () => sessionRef.current,
478
+ onSessionRefusal: (reason) => refusalRef.current?.(reason),
454
479
  onTransaction: (t2) => {
455
480
  const { docChanged, selectionChanged, view } = t2;
456
- if (docChanged) {
481
+ if (docChanged) if (sessionRef.current === "canonical") {
482
+ const canonical = canonicalApiRef.current?.()?.getCanonicalDocument();
483
+ if (canonical) onDocumentChangeRef.current(canonical);
484
+ } else {
457
485
  const current = documentRef.current;
458
486
  if (current) onDocumentChangeRef.current(managerRef.current?.snapshotDocument(current) ?? current);
459
487
  }
@@ -469,44 +497,53 @@ const NoteStoryEditor = forwardRef(function NoteStoryEditor(t0, ref) {
469
497
  };
470
498
  $[0] = active;
471
499
  $[1] = document;
472
- $[2] = onActiveChange;
473
- $[3] = onDocumentChange;
474
- $[4] = onStoryChange;
475
- $[5] = resolvedPlugins;
476
- $[6] = styles;
477
- $[7] = theme;
478
- $[8] = t1;
479
- } else t1 = $[8];
500
+ $[2] = experimentalSession;
501
+ $[3] = getCanonicalApi;
502
+ $[4] = onActiveChange;
503
+ $[5] = onDocumentChange;
504
+ $[6] = onSessionRefusal;
505
+ $[7] = onStoryChange;
506
+ $[8] = resolvedPlugins;
507
+ $[9] = styles;
508
+ $[10] = theme;
509
+ $[11] = t1;
510
+ } else t1 = $[11];
480
511
  let t2;
481
- if ($[9] !== active || $[10] !== document || $[11] !== endnotes || $[12] !== footnotes || $[13] !== onActiveChange || $[14] !== onDocumentChange || $[15] !== onStoryChange || $[16] !== resolvedPlugins || $[17] !== styles || $[18] !== theme) {
512
+ if ($[12] !== active || $[13] !== document || $[14] !== endnotes || $[15] !== experimentalSession || $[16] !== footnotes || $[17] !== getCanonicalApi || $[18] !== onActiveChange || $[19] !== onDocumentChange || $[20] !== onSessionRefusal || $[21] !== onStoryChange || $[22] !== resolvedPlugins || $[23] !== styles || $[24] !== theme) {
482
513
  t2 = [
483
514
  active,
484
515
  document,
485
516
  endnotes,
517
+ experimentalSession,
486
518
  footnotes,
519
+ getCanonicalApi,
487
520
  onActiveChange,
488
521
  onDocumentChange,
522
+ onSessionRefusal,
489
523
  onStoryChange,
490
524
  resolvedPlugins,
491
525
  styles,
492
526
  theme
493
527
  ];
494
- $[9] = active;
495
- $[10] = document;
496
- $[11] = endnotes;
497
- $[12] = footnotes;
498
- $[13] = onActiveChange;
499
- $[14] = onDocumentChange;
500
- $[15] = onStoryChange;
501
- $[16] = resolvedPlugins;
502
- $[17] = styles;
503
- $[18] = theme;
504
- $[19] = t2;
505
- } else t2 = $[19];
528
+ $[12] = active;
529
+ $[13] = document;
530
+ $[14] = endnotes;
531
+ $[15] = experimentalSession;
532
+ $[16] = footnotes;
533
+ $[17] = getCanonicalApi;
534
+ $[18] = onActiveChange;
535
+ $[19] = onDocumentChange;
536
+ $[20] = onSessionRefusal;
537
+ $[21] = onStoryChange;
538
+ $[22] = resolvedPlugins;
539
+ $[23] = styles;
540
+ $[24] = theme;
541
+ $[25] = t2;
542
+ } else t2 = $[25];
506
543
  useEffect(t1, t2);
507
544
  let t3;
508
545
  let t4;
509
- if ($[20] !== isSuggestionModeActive || $[21] !== suggestionAuthor) {
546
+ if ($[26] !== isSuggestionModeActive || $[27] !== suggestionAuthor) {
510
547
  t3 = () => {
511
548
  const manager_0 = managerRef.current;
512
549
  if (!manager_0) return;
@@ -516,41 +553,41 @@ const NoteStoryEditor = forwardRef(function NoteStoryEditor(t0, ref) {
516
553
  }
517
554
  };
518
555
  t4 = [isSuggestionModeActive, suggestionAuthor];
519
- $[20] = isSuggestionModeActive;
520
- $[21] = suggestionAuthor;
521
- $[22] = t3;
522
- $[23] = t4;
556
+ $[26] = isSuggestionModeActive;
557
+ $[27] = suggestionAuthor;
558
+ $[28] = t3;
559
+ $[29] = t4;
523
560
  } else {
524
- t3 = $[22];
525
- t4 = $[23];
561
+ t3 = $[28];
562
+ t4 = $[29];
526
563
  }
527
564
  useEffect(t3, t4);
528
565
  let t5;
529
566
  let t6;
530
- if ($[24] === Symbol.for("react.memo_cache_sentinel")) {
567
+ if ($[30] === Symbol.for("react.memo_cache_sentinel")) {
531
568
  t5 = () => () => {
532
569
  managerRef.current?.destroy();
533
570
  };
534
571
  t6 = [];
535
- $[24] = t5;
536
- $[25] = t6;
572
+ $[30] = t5;
573
+ $[31] = t6;
537
574
  } else {
538
- t5 = $[24];
539
- t6 = $[25];
575
+ t5 = $[30];
576
+ t6 = $[31];
540
577
  }
541
578
  useEffect(t5, t6);
542
579
  let t7;
543
- if ($[26] === Symbol.for("react.memo_cache_sentinel")) {
580
+ if ($[32] === Symbol.for("react.memo_cache_sentinel")) {
544
581
  t7 = () => {
545
582
  managerRef.current?.activate(null);
546
583
  setActive(null);
547
584
  onActiveChangeRef.current(null);
548
585
  };
549
- $[26] = t7;
550
- } else t7 = $[26];
586
+ $[32] = t7;
587
+ } else t7 = $[32];
551
588
  const closeEditor = t7;
552
589
  let t8;
553
- if ($[27] !== isSuggestionModeActive || $[28] !== suggestionAuthor) {
590
+ if ($[33] !== isSuggestionModeActive || $[34] !== suggestionAuthor) {
554
591
  t8 = () => ({
555
592
  close: closeEditor,
556
593
  getActiveView: () => {
@@ -567,63 +604,63 @@ const NoteStoryEditor = forwardRef(function NoteStoryEditor(t0, ref) {
567
604
  },
568
605
  snapshotDocument: (current_0) => managerRef.current?.snapshotDocument(current_0) ?? current_0
569
606
  });
570
- $[27] = isSuggestionModeActive;
571
- $[28] = suggestionAuthor;
572
- $[29] = t8;
573
- } else t8 = $[29];
607
+ $[33] = isSuggestionModeActive;
608
+ $[34] = suggestionAuthor;
609
+ $[35] = t8;
610
+ } else t8 = $[35];
574
611
  useImperativeHandle(ref, t8);
575
612
  let t9;
576
- if ($[30] !== active || $[31] !== t) {
613
+ if ($[36] !== active || $[37] !== t) {
577
614
  t9 = active ? t(active.kind === "footnote" ? "dialogs.footnoteProperties.footnotes" : "dialogs.footnoteProperties.endnotes") : "";
578
- $[30] = active;
579
- $[31] = t;
580
- $[32] = t9;
581
- } else t9 = $[32];
615
+ $[36] = active;
616
+ $[37] = t;
617
+ $[38] = t9;
618
+ } else t9 = $[38];
582
619
  const title = t9;
583
620
  const t10 = active ? "block" : "none";
584
621
  let t11;
585
- if ($[33] !== t10) {
622
+ if ($[39] !== t10) {
586
623
  t11 = {
587
624
  ...panelStyle,
588
625
  display: t10
589
626
  };
590
- $[33] = t10;
591
- $[34] = t11;
592
- } else t11 = $[34];
627
+ $[39] = t10;
628
+ $[40] = t11;
629
+ } else t11 = $[40];
593
630
  let t12;
594
- if ($[35] === Symbol.for("react.memo_cache_sentinel")) {
631
+ if ($[41] === Symbol.for("react.memo_cache_sentinel")) {
595
632
  t12 = (event) => {
596
633
  if (event.key !== "Escape") return;
597
634
  event.preventDefault();
598
635
  event.stopPropagation();
599
636
  closeEditor();
600
637
  };
601
- $[35] = t12;
602
- } else t12 = $[35];
638
+ $[41] = t12;
639
+ } else t12 = $[41];
603
640
  let t13;
604
- if ($[36] !== title) {
641
+ if ($[42] !== title) {
605
642
  t13 = /* @__PURE__ */ jsx("span", { children: title });
606
- $[36] = title;
607
- $[37] = t13;
608
- } else t13 = $[37];
643
+ $[42] = title;
644
+ $[43] = t13;
645
+ } else t13 = $[43];
609
646
  let t14;
610
- if ($[38] !== t) {
647
+ if ($[44] !== t) {
611
648
  t14 = t("common.closeDialog");
612
- $[38] = t;
613
- $[39] = t14;
614
- } else t14 = $[39];
649
+ $[44] = t;
650
+ $[45] = t14;
651
+ } else t14 = $[45];
615
652
  let t15;
616
- if ($[40] === Symbol.for("react.memo_cache_sentinel")) {
653
+ if ($[46] === Symbol.for("react.memo_cache_sentinel")) {
617
654
  t15 = {
618
655
  border: 0,
619
656
  background: "transparent",
620
657
  color: "inherit",
621
658
  cursor: "pointer"
622
659
  };
623
- $[40] = t15;
624
- } else t15 = $[40];
660
+ $[46] = t15;
661
+ } else t15 = $[46];
625
662
  let t16;
626
- if ($[41] !== t14) {
663
+ if ($[47] !== t14) {
627
664
  t16 = /* @__PURE__ */ jsx("button", {
628
665
  type: "button",
629
666
  "aria-label": t14,
@@ -631,40 +668,40 @@ const NoteStoryEditor = forwardRef(function NoteStoryEditor(t0, ref) {
631
668
  style: t15,
632
669
  children: "×"
633
670
  });
634
- $[41] = t14;
635
- $[42] = t16;
636
- } else t16 = $[42];
671
+ $[47] = t14;
672
+ $[48] = t16;
673
+ } else t16 = $[48];
637
674
  let t17;
638
- if ($[43] !== t13 || $[44] !== t16) {
675
+ if ($[49] !== t13 || $[50] !== t16) {
639
676
  t17 = /* @__PURE__ */ jsxs("div", {
640
677
  style: headerStyle,
641
678
  children: [t13, t16]
642
679
  });
643
- $[43] = t13;
644
- $[44] = t16;
645
- $[45] = t17;
646
- } else t17 = $[45];
680
+ $[49] = t13;
681
+ $[50] = t16;
682
+ $[51] = t17;
683
+ } else t17 = $[51];
647
684
  let t18;
648
- if ($[46] === Symbol.for("react.memo_cache_sentinel")) {
685
+ if ($[52] === Symbol.for("react.memo_cache_sentinel")) {
649
686
  t18 = /* @__PURE__ */ jsx("div", {
650
687
  ref: hostRef,
651
688
  style: hostStyle
652
689
  });
653
- $[46] = t18;
654
- } else t18 = $[46];
690
+ $[52] = t18;
691
+ } else t18 = $[52];
655
692
  let t19;
656
- if ($[47] !== t11 || $[48] !== t17 || $[49] !== title) {
693
+ if ($[53] !== t11 || $[54] !== t17 || $[55] !== title) {
657
694
  t19 = /* @__PURE__ */ jsxs("aside", {
658
695
  style: t11,
659
696
  "aria-label": title,
660
697
  onKeyDown: t12,
661
698
  children: [t17, t18]
662
699
  });
663
- $[47] = t11;
664
- $[48] = t17;
665
- $[49] = title;
666
- $[50] = t19;
667
- } else t19 = $[50];
700
+ $[53] = t11;
701
+ $[54] = t17;
702
+ $[55] = title;
703
+ $[56] = t19;
704
+ } else t19 = $[56];
668
705
  return t19;
669
706
  });
670
707
  NoteStoryEditor.displayName = "NoteStoryEditor";
@@ -853,10 +890,7 @@ const AnonymizationRectsOverlay = ({ groups, onTermClick, selectedCanonical = nu
853
890
  index: nextIndex
854
891
  };
855
892
  const el = spans[nextIndex];
856
- if (el) el.scrollIntoView({
857
- block: "center",
858
- behavior: prefersReducedMotionBehavior()
859
- });
893
+ if (el) scrollEditorElementIntoView(el);
860
894
  }, [selectedCanonical, selectionSeq]);
861
895
  const overlayRef = useRef(null);
862
896
  useEffect(() => {
@@ -1219,12 +1253,16 @@ const HIDDEN_HOST_STYLES = {
1219
1253
  * HiddenProseMirror - Off-screen ProseMirror editor for keyboard input
1220
1254
  */
1221
1255
  const HiddenProseMirror = forwardRef((props, ref) => {
1222
- const { document, documentIdentity, styles, theme: _theme, widthPx = 612, readOnly = false, onTransaction, onSelectionChange, externalPlugins = EMPTY_EXTERNAL_PLUGINS, collaboration, extensionManager, onEditorViewReady, onEditorViewDestroy, onKeyDown, onCopy, onCut, onPaste, onReadOnlyEditAttempt, onRemoteSelectionsChange, precomputedInitialState } = props;
1256
+ const { document, documentIdentity, experimentalSession, suggestionModeActive = false, suggestionAuthor = "User", onSessionRefusal, styles, theme: _theme, widthPx = 612, readOnly = false, onTransaction, onSelectionChange, externalPlugins = EMPTY_EXTERNAL_PLUGINS, collaboration, extensionManager, onEditorViewReady, onEditorViewDestroy, onKeyDown, onCopy, onCut, onPaste, onReadOnlyEditAttempt, onRemoteSelectionsChange, precomputedInitialState } = props;
1223
1257
  const [collaborationModules, setCollaborationModules] = useState(null);
1224
1258
  const [collaborationModulesError, setCollaborationModulesError] = useState(null);
1225
1259
  const hasCollaboration = collaboration !== void 0;
1226
1260
  const hostRef = useRef(null);
1227
1261
  const readOnlyRef = useRef(readOnly);
1262
+ const experimentalSessionRef = useRef(experimentalSession);
1263
+ const suggestionModeActiveRef = useRef(suggestionModeActive);
1264
+ const suggestionAuthorRef = useRef(suggestionAuthor);
1265
+ const onSessionRefusalRef = useRef(onSessionRefusal);
1228
1266
  const documentRef = useRef(document);
1229
1267
  const documentIdentityRef = useRef(documentIdentity);
1230
1268
  const stylesRef = useRef(styles);
@@ -1244,6 +1282,10 @@ const HiddenProseMirror = forwardRef((props, ref) => {
1244
1282
  const onReadOnlyEditAttemptRef = useRef(onReadOnlyEditAttempt);
1245
1283
  const onRemoteSelectionsChangeRef = useRef(onRemoteSelectionsChange);
1246
1284
  readOnlyRef.current = readOnly;
1285
+ experimentalSessionRef.current = experimentalSession;
1286
+ suggestionModeActiveRef.current = suggestionModeActive;
1287
+ suggestionAuthorRef.current = suggestionAuthor;
1288
+ onSessionRefusalRef.current = onSessionRefusal;
1247
1289
  stylesRef.current = styles;
1248
1290
  extensionManagerRef.current = extensionManager;
1249
1291
  externalPluginsRef.current = externalPlugins;
@@ -1273,6 +1315,10 @@ const HiddenProseMirror = forwardRef((props, ref) => {
1273
1315
  getCollaborationModules: () => collaborationModulesRef.current,
1274
1316
  getPrecomputedInitialState: () => precomputedInitialStateRef.current,
1275
1317
  getReadOnly: () => readOnlyRef.current,
1318
+ getExperimentalSession: () => experimentalSessionRef.current,
1319
+ getEditingMode: () => suggestionModeActiveRef.current ? "suggesting" : "editing",
1320
+ getSuggestionAuthor: () => suggestionAuthorRef.current,
1321
+ onSessionRefusal: (reason) => onSessionRefusalRef.current?.(reason),
1276
1322
  getDocumentIdentity: () => documentIdentityRef.current,
1277
1323
  getDocumentContext: () => documentRef.current,
1278
1324
  onTransaction: (update) => onTransactionRef.current?.(update),
@@ -1332,13 +1378,19 @@ const HiddenProseMirror = forwardRef((props, ref) => {
1332
1378
  }, []);
1333
1379
  useLayoutEffect(() => {
1334
1380
  managerRef.current?.retryViewCreation();
1335
- }, [collaboration, collaborationModules]);
1381
+ }, [
1382
+ collaboration,
1383
+ collaborationModules,
1384
+ experimentalSession
1385
+ ]);
1336
1386
  useEffect(() => () => destroyView(), [destroyView]);
1337
1387
  useEffect(() => {
1338
1388
  managerRef.current?.syncExternalDocument();
1339
1389
  }, [
1340
1390
  document,
1341
1391
  documentIdentity,
1392
+ experimentalSession,
1393
+ suggestionModeActive,
1342
1394
  styles,
1343
1395
  extensionManager,
1344
1396
  externalPlugins,
@@ -2170,18 +2222,6 @@ const TemplateDirectivesOverlay = (t0) => {
2170
2222
  const EDGE_ZONE = 40;
2171
2223
  /** Maximum scroll speed in pixels per frame (~60fps). */
2172
2224
  const MAX_SPEED = 12;
2173
- /**
2174
- * Find the nearest scrollable ancestor.
2175
- */
2176
- function findScrollParent(el) {
2177
- let parent = el.parentElement;
2178
- while (parent && parent !== document.documentElement) {
2179
- const { overflowY } = getComputedStyle(parent);
2180
- if ((overflowY === "auto" || overflowY === "scroll") && parent.scrollHeight > parent.clientHeight) return parent;
2181
- parent = parent.parentElement;
2182
- }
2183
- return null;
2184
- }
2185
2225
  function useDragAutoScroll({ pagesContainerRef, onScrollExtendSelection }) {
2186
2226
  const rafIdRef = useRef(null);
2187
2227
  const lastMouseRef = useRef({
@@ -2189,14 +2229,7 @@ function useDragAutoScroll({ pagesContainerRef, onScrollExtendSelection }) {
2189
2229
  y: 0
2190
2230
  });
2191
2231
  const activeRef = useRef(false);
2192
- const scrollParentRef = useRef(null);
2193
- const getScrollParent = useCallback(() => {
2194
- if (scrollParentRef.current) return scrollParentRef.current;
2195
- const pages = pagesContainerRef.current;
2196
- if (!pages) return null;
2197
- scrollParentRef.current = findScrollParent(pages);
2198
- return scrollParentRef.current;
2199
- }, [pagesContainerRef]);
2232
+ const getScrollParent = useCallback(() => getEditorScrollRoot(pagesContainerRef.current), [pagesContainerRef]);
2200
2233
  const stopAutoScroll = useCallback(() => {
2201
2234
  activeRef.current = false;
2202
2235
  if (rafIdRef.current !== null) {
@@ -2219,7 +2252,7 @@ function useDragAutoScroll({ pagesContainerRef, onScrollExtendSelection }) {
2219
2252
  scrollDelta = Math.min(MAX_SPEED, proximity_0 / EDGE_ZONE * MAX_SPEED);
2220
2253
  }
2221
2254
  if (scrollDelta !== 0) {
2222
- container.scrollTop += scrollDelta;
2255
+ scrollEditorBy(container, scrollDelta);
2223
2256
  onScrollExtendSelection(mx, my);
2224
2257
  }
2225
2258
  rafIdRef.current = requestAnimationFrame(tick);
@@ -2839,27 +2872,37 @@ function buildFootnoteRenderItems(pageFootnoteMap, footnoteContentMap, doc) {
2839
2872
  * PagedEditor - Main paginated editing component.
2840
2873
  */
2841
2874
  const PagedEditor = forwardRef(function PagedEditor(props, ref) {
2842
- const { document, documentIO, documentIdentity, fonts: hostFonts, styles, theme: _theme, sectionProperties, headerContent, footerContent, firstPageHeaderContent, firstPageFooterContent, headerContentRId, footerContentRId, firstPageHeaderContentRId, firstPageFooterContentRId, readOnly = false, pageGap = 24, zoom = 1, pageRenderer, markupView, showMarginGuides = false, marginGuideColor, onDocumentChange, onReadOnlyEditAttempt, onCopy, onCut, onPaste, onSelectionChange, onSelectionTextChange, onEditorViewReady, externalPlugins = EMPTY_PLUGINS, showTemplateDirectives = true, collaboration, extensionManager, suggestionModeActive = false, suggestionAuthor, onActiveNoteStoryChange, onHeaderFooterDoubleClick, hfEditMode, activeHeaderFooterRId, onBodyClick, className, style, pageEndGutter = 0, sidebarOverlay, scrollContainerRef: scrollContainerRefProp, onHyperlinkClick, onContextMenu, onAnchorPositionsChange, onTotalPagesChange, onError, anchorPositionMode = "comments-and-revisions", onAnonymizationTermClick, selectedAnonymizationCanonical = null, anonymizationSelectionSeq } = props;
2875
+ const { document, documentIO, documentIdentity, experimentalSession, fonts: hostFonts, styles, theme: _theme, sectionProperties, headerContent, footerContent, firstPageHeaderContent, firstPageFooterContent, headerContentRId, footerContentRId, firstPageHeaderContentRId, firstPageFooterContentRId, readOnly = false, pageGap = 24, zoom = 1, pageRenderer, markupView, showMarginGuides = false, marginGuideColor, onDocumentChange, onReadOnlyEditAttempt, onCopy, onCut, onPaste, onSelectionChange, onSelectionTextChange, onEditorViewReady, externalPlugins = EMPTY_PLUGINS, showTemplateDirectives = true, collaboration, extensionManager, suggestionModeActive = false, suggestionAuthor, onActiveNoteStoryChange, onHeaderFooterDoubleClick, hfEditMode, activeHeaderFooterRId, onBodyClick, className, style, pageEndGutter = 0, sidebarOverlay, scrollContainerRef: scrollContainerRefProp, onHyperlinkClick, onContextMenu, onAnchorPositionsChange, onTotalPagesChange, onError, anchorPositionMode = "comments-and-revisions", onAnonymizationTermClick, selectedAnonymizationCanonical = null, anonymizationSelectionSeq } = props;
2843
2876
  const getScrollContainer = useCallback(() => {
2844
- if (scrollContainerRefProp && typeof scrollContainerRefProp === "object") return scrollContainerRefProp.current;
2845
- return containerRef.current;
2877
+ if (scrollContainerRefProp && typeof scrollContainerRefProp === "object") return getEditorScrollRoot(scrollContainerRefProp.current);
2878
+ return getEditorScrollRoot(containerRef.current);
2846
2879
  }, [scrollContainerRefProp]);
2847
2880
  const containerRef = useRef(null);
2848
2881
  const pagesContainerRef = useRef(null);
2882
+ useLayoutEffect(() => {
2883
+ if (!scrollContainerRefProp || typeof scrollContainerRefProp !== "object") return;
2884
+ const root = scrollContainerRefProp.current;
2885
+ if (!root || root.hasAttribute("data-folio-scroll")) return;
2886
+ root.setAttribute("data-folio-scroll", "");
2887
+ return () => root.removeAttribute("data-folio-scroll");
2888
+ }, [scrollContainerRefProp]);
2849
2889
  const folioEmitterRef = useRef(createFolioEditorEmitter());
2850
2890
  const hiddenPMRef = useRef(null);
2851
2891
  const hfPMsRef = useRef(null);
2852
2892
  const noteEditorRef = useRef(null);
2893
+ const activeNoteStoryRef = useRef(null);
2853
2894
  const [noteStoryActive, setNoteStoryActive] = useState(false);
2854
2895
  const painterRef = useRef(null);
2855
2896
  const noteStoryPlugins = useMemo(() => externalPlugins.filter(({ spec }) => spec.key === suggestionModeKey), [externalPlugins]);
2856
2897
  const handleActiveNoteStoryChange = useCallback((story) => {
2898
+ activeNoteStoryRef.current = story;
2857
2899
  setNoteStoryActive(story !== null);
2858
2900
  onActiveNoteStoryChange?.(story);
2859
2901
  }, [onActiveNoteStoryChange]);
2860
2902
  useEffect(() => {
2861
- if (readOnly) noteEditorRef.current?.close();
2862
- }, [readOnly]);
2903
+ if (readOnly || experimentalSession === "canonical") noteEditorRef.current?.close();
2904
+ }, [experimentalSession, readOnly]);
2905
+ const getCanonicalApi = useCallback(() => hiddenPMRef.current, []);
2863
2906
  const { handlePMKeyDown } = useVisualLineNavigation({ pagesContainerRef });
2864
2907
  const handleHiddenEditorKeyDown = useCallback((view, event) => {
2865
2908
  if (getTemplateSlashMenu(view.state).active) return false;
@@ -2879,6 +2922,9 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
2879
2922
  onDocumentChangeRef.current = onDocumentChange;
2880
2923
  onTotalPagesChangeRef.current = onTotalPagesChange;
2881
2924
  onErrorRef.current = onError;
2925
+ const handleSessionRefusal = useCallback((message) => {
2926
+ onErrorRef.current?.(new CanonicalSessionRefusalError({ message }));
2927
+ }, []);
2882
2928
  const [layout, setLayout] = useState(null);
2883
2929
  const layoutRef = useRef(layout);
2884
2930
  layoutRef.current = layout;
@@ -3000,12 +3046,18 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3000
3046
  queuedInputBeforeHiddenEditorRef.current = [];
3001
3047
  for (const input of queuedInput) {
3002
3048
  if (input.type === "text") {
3003
- dispatchEditorTextInput(view_0, input.text);
3049
+ if (experimentalSession === "canonical") view_0.dom.dispatchEvent(new InputEvent("beforeinput", {
3050
+ inputType: "insertText",
3051
+ data: input.text,
3052
+ cancelable: true,
3053
+ bubbles: true
3054
+ }));
3055
+ else dispatchEditorTextInput(view_0, input.text);
3004
3056
  continue;
3005
3057
  }
3006
3058
  replayDeferredKeyDown(view_0, input.eventInit);
3007
3059
  }
3008
- }, []);
3060
+ }, [experimentalSession]);
3009
3061
  useEffect(() => {
3010
3062
  if (collaboration !== void 0) ensureHiddenEditorView();
3011
3063
  }, [collaboration, ensureHiddenEditorView]);
@@ -3224,6 +3276,18 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3224
3276
  folioEditor,
3225
3277
  hfEditMode
3226
3278
  ]);
3279
+ const getCanonicalActiveStory = useCallback(() => {
3280
+ const note = activeNoteStoryRef.current;
3281
+ if (note) return {
3282
+ kind: note.kind,
3283
+ id: note.noteId
3284
+ };
3285
+ if (hfEditMode && activeHeaderFooterRId) return {
3286
+ kind: hfEditMode,
3287
+ rId: activeHeaderFooterRId
3288
+ };
3289
+ return "main";
3290
+ }, [hfEditMode, activeHeaderFooterRId]);
3227
3291
  const paintSettingsInitializedRef = useRef(false);
3228
3292
  useEffect(() => {
3229
3293
  if (!paintSettingsInitializedRef.current) {
@@ -3256,12 +3320,12 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3256
3320
  }
3257
3321
  let newDoc = hiddenPMRef.current?.getDocument();
3258
3322
  const body = hiddenPMRef.current?.getState()?.doc;
3259
- if (newDoc && body) newDoc = noteFollower.reconcile(newDoc, body);
3323
+ if (newDoc && body && experimentalSession !== "canonical") newDoc = noteFollower.reconcile(newDoc, body);
3260
3324
  if (newDoc) {
3261
- onDocumentChangeRef.current?.(newDoc);
3262
- folioEmitterRef.current.emit("docChange", newDoc);
3325
+ onDocumentChangeRef.current?.(experimentalSession === "canonical" ? cloneDocumentWithParagraphPropertySources(newDoc) : newDoc);
3326
+ folioEmitterRef.current.emit("docChange", experimentalSession === "canonical" ? cloneDocumentWithParagraphPropertySources(newDoc) : newDoc);
3263
3327
  }
3264
- }, [noteFollower]);
3328
+ }, [experimentalSession, noteFollower]);
3265
3329
  const scheduleDocumentChangeNotification = useCallback(() => {
3266
3330
  if (documentChangeNotifyTimerRef.current !== null) window.clearTimeout(documentChangeNotifyTimerRef.current);
3267
3331
  documentChangeNotifyTimerRef.current = window.setTimeout(() => {
@@ -3866,6 +3930,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3866
3930
  if (docChanged_0) {
3867
3931
  if (!hiddenPMRef.current?.getState() && !precomputedInitialStateRef.current) ensureHiddenEditorView({ sync: true });
3868
3932
  scheduleLayout();
3933
+ if (experimentalSession === "canonical") scheduleDocumentChangeNotification();
3869
3934
  }
3870
3935
  if (docChanged_0 || selectionChanged) {
3871
3936
  const { from: from_1, to: to_1 } = view_3.state.selection;
@@ -3883,7 +3948,12 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3883
3948
  to: to_1
3884
3949
  });
3885
3950
  }
3886
- }, [scheduleLayout, ensureHiddenEditorView]);
3951
+ }, [
3952
+ scheduleLayout,
3953
+ ensureHiddenEditorView,
3954
+ experimentalSession,
3955
+ scheduleDocumentChangeNotification
3956
+ ]);
3887
3957
  const handleNoteStoryTransaction = useCallback((view_4, docChanged_1, selectionChanged_0) => {
3888
3958
  if (docChanged_1) scheduleLayout();
3889
3959
  if (docChanged_1 || selectionChanged_0) {
@@ -3896,9 +3966,9 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
3896
3966
  }
3897
3967
  }, [scheduleLayout]);
3898
3968
  const handleNoteDocumentChange = useCallback((updated) => {
3899
- onDocumentChangeRef.current?.(updated);
3900
- folioEmitterRef.current.emit("docChange", updated);
3901
- }, []);
3969
+ onDocumentChangeRef.current?.(experimentalSession === "canonical" ? cloneDocumentWithParagraphPropertySources(updated) : updated);
3970
+ folioEmitterRef.current.emit("docChange", experimentalSession === "canonical" ? cloneDocumentWithParagraphPropertySources(updated) : updated);
3971
+ }, [experimentalSession]);
3902
3972
  useEffect(() => {
3903
3973
  if (!hfEditMode) setHfCaretSelection(null);
3904
3974
  dragAnchorRef.current = null;
@@ -4029,10 +4099,8 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4029
4099
  scrollToPositionImpl(target_0.pmPos);
4030
4100
  return;
4031
4101
  }
4032
- (pagesContainerRef.current?.querySelector(`[data-page-number="${String(target_0.pageIndex + 1)}"]`))?.scrollIntoView({
4033
- block: "center",
4034
- inline: "nearest"
4035
- });
4102
+ const shell = pagesContainerRef.current?.querySelector(`[data-page-number="${String(target_0.pageIndex + 1)}"]`);
4103
+ scrollEditorElementIntoView(shell ?? null);
4036
4104
  }, [layout, scrollToPositionImpl]);
4037
4105
  const scrollToParaIdImpl = useCallback((paraId, options_2) => {
4038
4106
  const state_7 = hiddenPMRef.current?.getState();
@@ -4765,6 +4833,10 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4765
4833
  if (story_0) {
4766
4834
  e_3.preventDefault();
4767
4835
  e_3.stopPropagation();
4836
+ if (experimentalSession === "canonical") {
4837
+ handleSessionRefusal("Footnote and endnote editing is unavailable in this session.");
4838
+ return;
4839
+ }
4768
4840
  noteEditorRef.current?.open(story_0);
4769
4841
  return;
4770
4842
  }
@@ -4908,7 +4980,9 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
4908
4980
  }
4909
4981
  }
4910
4982
  }, [
4983
+ experimentalSession,
4911
4984
  getPositionFromMouse,
4985
+ handleSessionRefusal,
4912
4986
  onHeaderFooterDoubleClick,
4913
4987
  onHyperlinkClick,
4914
4988
  readOnly
@@ -5100,11 +5174,17 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5100
5174
  if (["PageUp", "PageDown"].includes(e_7.key) && !e_7.metaKey && !e_7.ctrlKey) {}
5101
5175
  if (e_7.key === "Home" && (e_7.metaKey || e_7.ctrlKey)) {
5102
5176
  const sc = getScrollContainer();
5103
- if (sc) sc.scrollTop = 0;
5177
+ if (sc) scrollEditorTo(sc, {
5178
+ top: 0,
5179
+ behavior: "instant"
5180
+ });
5104
5181
  }
5105
5182
  if (e_7.key === "End" && (e_7.metaKey || e_7.ctrlKey)) {
5106
5183
  const sc_0 = getScrollContainer();
5107
- if (sc_0) sc_0.scrollTop = sc_0.scrollHeight;
5184
+ if (sc_0) scrollEditorTo(sc_0, {
5185
+ top: sc_0.scrollHeight,
5186
+ behavior: "instant"
5187
+ });
5108
5188
  }
5109
5189
  }, [
5110
5190
  copySelectionText,
@@ -5410,6 +5490,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5410
5490
  getDocument() {
5411
5491
  if (documentChangeNotifyTimerRef.current !== null) flushDocumentChangeNotification();
5412
5492
  const editorDocument = folioEditor.getDocument();
5493
+ if (experimentalSession === "canonical") return editorDocument;
5413
5494
  const current_0 = editorDocument ? noteFollower.withPending(editorDocument) : null;
5414
5495
  return current_0 ? noteEditorRef.current?.snapshotDocument(current_0) ?? current_0 : null;
5415
5496
  },
@@ -5420,12 +5501,14 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5420
5501
  return folioEditor.getView();
5421
5502
  },
5422
5503
  getActiveView() {
5504
+ if (experimentalSession === "canonical") return folioEditor.getView();
5423
5505
  return getActiveEditorStory().view;
5424
5506
  },
5425
5507
  closeNoteStory() {
5426
5508
  noteEditorRef.current?.close();
5427
5509
  },
5428
5510
  getHfView(rId_0) {
5511
+ if (experimentalSession === "canonical") return null;
5429
5512
  return hfPMsRef.current?.getView(rId_0) ?? null;
5430
5513
  },
5431
5514
  ensureView(options_4) {
@@ -5451,20 +5534,34 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5451
5534
  undo() {
5452
5535
  const target_5 = getActiveEditorStory();
5453
5536
  if (target_5.type === "none") return false;
5537
+ if (experimentalSession === "canonical") return hiddenPMRef.current?.applyCanonicalStoryHistory({
5538
+ view: target_5.view,
5539
+ story: getCanonicalActiveStory(),
5540
+ direction: "undo"
5541
+ }) ?? false;
5542
+ if (target_5.type === "body") return hiddenPMRef.current?.undo() ?? false;
5454
5543
  return undo(target_5.view.state, target_5.view.dispatch);
5455
5544
  },
5456
5545
  redo() {
5457
5546
  const target_6 = getActiveEditorStory();
5458
5547
  if (target_6.type === "none") return false;
5548
+ if (experimentalSession === "canonical") return hiddenPMRef.current?.applyCanonicalStoryHistory({
5549
+ view: target_6.view,
5550
+ story: getCanonicalActiveStory(),
5551
+ direction: "redo"
5552
+ }) ?? false;
5553
+ if (target_6.type === "body") return hiddenPMRef.current?.redo() ?? false;
5459
5554
  return redo(target_6.view.state, target_6.view.dispatch);
5460
5555
  },
5461
5556
  canUndo() {
5462
5557
  const target_7 = getActiveEditorStory();
5463
- return target_7.type === "none" ? false : undo(target_7.view.state);
5558
+ if (target_7.type === "none") return false;
5559
+ return experimentalSession === "canonical" || target_7.type === "body" ? hiddenPMRef.current?.canUndo() ?? false : undo(target_7.view.state);
5464
5560
  },
5465
5561
  canRedo() {
5466
5562
  const target_8 = getActiveEditorStory();
5467
- return target_8.type === "none" ? false : redo(target_8.view.state);
5563
+ if (target_8.type === "none") return false;
5564
+ return experimentalSession === "canonical" || target_8.type === "body" ? hiddenPMRef.current?.canRedo() ?? false : redo(target_8.view.state);
5468
5565
  },
5469
5566
  setSelection(anchor_3, head_1) {
5470
5567
  folioEditor.setSelection(anchor_3, head_1);
@@ -5548,6 +5645,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5548
5645
  flushDocumentChangeNotification,
5549
5646
  folioEditor,
5550
5647
  getActiveEditorStory,
5648
+ getCanonicalActiveStory,
5551
5649
  noteFollower,
5552
5650
  getScrollContainer,
5553
5651
  refreshBodyImeCaretAnchor,
@@ -5603,6 +5701,7 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5603
5701
  };
5604
5702
  return /* @__PURE__ */ jsxs("div", {
5605
5703
  ref: containerRef,
5704
+ "data-folio-scroll": scrollContainerRefProp && typeof scrollContainerRefProp === "object" ? void 0 : "",
5606
5705
  className: `folio-root paged-editor ${className ?? ""}`,
5607
5706
  style: {
5608
5707
  ...containerStyles,
@@ -5620,6 +5719,9 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5620
5719
  ref: hfPMsRef,
5621
5720
  document,
5622
5721
  onTransaction: handleHfPmTransaction,
5722
+ getCanonicalApi,
5723
+ onSessionRefusal: handleSessionRefusal,
5724
+ ...experimentalSession === void 0 ? {} : { experimentalSession },
5623
5725
  ...styles !== void 0 ? { styles } : {},
5624
5726
  ..._theme !== void 0 ? { theme: _theme } : {}
5625
5727
  }),
@@ -5627,6 +5729,9 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5627
5729
  ref: noteEditorRef,
5628
5730
  document,
5629
5731
  onActiveChange: handleActiveNoteStoryChange,
5732
+ getCanonicalApi,
5733
+ onSessionRefusal: handleSessionRefusal,
5734
+ ...experimentalSession === void 0 ? {} : { experimentalSession },
5630
5735
  onDocumentChange: handleNoteDocumentChange,
5631
5736
  onStoryChange: handleNoteStoryTransaction,
5632
5737
  plugins: noteStoryPlugins,
@@ -5639,6 +5744,10 @@ const PagedEditor = forwardRef(function PagedEditor(props, ref) {
5639
5744
  ref: hiddenPMRef,
5640
5745
  document,
5641
5746
  documentIdentity,
5747
+ ...experimentalSession === void 0 ? {} : { experimentalSession },
5748
+ onSessionRefusal: handleSessionRefusal,
5749
+ ...suggestionAuthor !== void 0 ? { suggestionAuthor } : {},
5750
+ suggestionModeActive,
5642
5751
  widthPx: contentWidth,
5643
5752
  precomputedInitialState: validPrecomputedInitialState,
5644
5753
  readOnly,
@@ -6804,20 +6913,6 @@ const toast = (msg) => {
6804
6913
  };
6805
6914
  /** Stable empty anchor positions Map used as the initial state. */
6806
6915
  const EMPTY_ANCHOR_POSITIONS = /* @__PURE__ */ new Map();
6807
- let nextCommentId = Date.now();
6808
- function allocateCommentId() {
6809
- return nextCommentId++;
6810
- }
6811
- /**
6812
- * Bump the in-process comment-id counter above `id` so a later
6813
- * `allocateCommentId()` can never re-mint an id that was adopted from an
6814
- * external source-of-truth model. No-op when `id` is already below the
6815
- * current counter. Mirrors the allocator-seeding behaviour of upstream
6816
- * docx-editor's `CommentIdAllocator.seedAbove` (05f2ab84).
6817
- */
6818
- function seedCommentIdAbove(id) {
6819
- if (id >= nextCommentId) nextCommentId = id + 1;
6820
- }
6821
6916
  function getCommentAuthorKey(author) {
6822
6917
  const trimmed = author?.trim();
6823
6918
  return trimmed && trimmed.length > 0 ? trimmed : "Unknown";
@@ -7176,10 +7271,7 @@ const readFindSelectionSeed = () => {
7176
7271
  //#region src/components/dialogs/findReplaceUtils.ts
7177
7272
  const scrollToMatch = (containerElement, match) => {
7178
7273
  if (!containerElement) return;
7179
- (containerElement.querySelector(`[data-paragraph-index="${match.paragraphIndex}"]`) ?? containerElement.querySelector(`.layout-paragraph[data-block-id="block-${match.paragraphIndex + 1}"]`) ?? containerElement.querySelectorAll(".layout-paragraph").item(match.paragraphIndex)).scrollIntoView({
7180
- behavior: prefersReducedMotionBehavior(),
7181
- block: "center"
7182
- });
7274
+ scrollEditorElementIntoView(containerElement.querySelector(`[data-paragraph-index="${match.paragraphIndex}"]`) ?? containerElement.querySelector(`.layout-paragraph[data-block-id="block-${match.paragraphIndex + 1}"]`) ?? containerElement.querySelectorAll(".layout-paragraph").item(match.paragraphIndex));
7183
7275
  };
7184
7276
  //#endregion
7185
7277
  //#region src/components/dialogs/useFindReplace.ts
@@ -10083,15 +10175,17 @@ function useContextMenu(t0) {
10083
10175
  * callbacks each render.
10084
10176
  */
10085
10177
  const useDocumentLoader = (t0) => {
10086
- const $ = c(21);
10087
- const { documentBuffer, initialDocument, password, history, onError, onCompatibilityChange, onReset, setDocumentLoadState } = t0;
10178
+ const $ = c(28);
10179
+ const { documentBuffer, initialDocument, password, experimentalSession, history, onError, onCompatibilityChange, onReset, setDocumentLoadState } = t0;
10088
10180
  const originalBufferRef = useRef(null);
10181
+ const originalBufferIdentityRef = useRef(null);
10089
10182
  const [loadedDocumentIdentity, setLoadedDocumentIdentity] = useState("0");
10090
10183
  let t1;
10091
- if ($[0] !== history || $[1] !== onCompatibilityChange || $[2] !== onError || $[3] !== onReset || $[4] !== setDocumentLoadState) {
10184
+ if ($[0] !== experimentalSession || $[1] !== history || $[2] !== onCompatibilityChange || $[3] !== onError || $[4] !== onReset || $[5] !== setDocumentLoadState) {
10092
10185
  t1 = () => {
10093
10186
  const instance = new DocumentLoaderManager({
10094
10187
  history,
10188
+ getExperimentalSession: () => experimentalSession,
10095
10189
  onError,
10096
10190
  onCompatibilityChange,
10097
10191
  onReset,
@@ -10107,17 +10201,19 @@ const useDocumentLoader = (t0) => {
10107
10201
  }
10108
10202
  };
10109
10203
  };
10110
- $[0] = history;
10111
- $[1] = onCompatibilityChange;
10112
- $[2] = onError;
10113
- $[3] = onReset;
10114
- $[4] = setDocumentLoadState;
10115
- $[5] = t1;
10116
- } else t1 = $[5];
10204
+ $[0] = experimentalSession;
10205
+ $[1] = history;
10206
+ $[2] = onCompatibilityChange;
10207
+ $[3] = onError;
10208
+ $[4] = onReset;
10209
+ $[5] = setDocumentLoadState;
10210
+ $[6] = t1;
10211
+ } else t1 = $[6];
10117
10212
  const [t2] = useState(t1);
10118
10213
  const { manager, api } = t2;
10119
10214
  manager.setCallbacks({
10120
10215
  history,
10216
+ getExperimentalSession: () => experimentalSession,
10121
10217
  onError,
10122
10218
  onCompatibilityChange,
10123
10219
  onReset,
@@ -10125,8 +10221,7 @@ const useDocumentLoader = (t0) => {
10125
10221
  setLoadedDocumentIdentity
10126
10222
  });
10127
10223
  let t3;
10128
- let t4;
10129
- if ($[6] !== api || $[7] !== documentBuffer || $[8] !== initialDocument || $[9] !== password) {
10224
+ if ($[7] !== api || $[8] !== documentBuffer || $[9] !== initialDocument || $[10] !== password) {
10130
10225
  t3 = () => {
10131
10226
  const source = getDocumentLoadSource({
10132
10227
  documentBuffer,
@@ -10139,45 +10234,58 @@ const useDocumentLoader = (t0) => {
10139
10234
  }
10140
10235
  api.loadBuffer(source.buffer, { password });
10141
10236
  };
10237
+ $[7] = api;
10238
+ $[8] = documentBuffer;
10239
+ $[9] = initialDocument;
10240
+ $[10] = password;
10241
+ $[11] = t3;
10242
+ } else t3 = $[11];
10243
+ let t4;
10244
+ if ($[12] !== api || $[13] !== documentBuffer || $[14] !== experimentalSession || $[15] !== initialDocument || $[16] !== password) {
10142
10245
  t4 = [
10143
10246
  documentBuffer,
10144
10247
  initialDocument,
10145
10248
  password,
10249
+ experimentalSession,
10146
10250
  api
10147
10251
  ];
10148
- $[6] = api;
10149
- $[7] = documentBuffer;
10150
- $[8] = initialDocument;
10151
- $[9] = password;
10152
- $[10] = t3;
10153
- $[11] = t4;
10154
- } else {
10155
- t3 = $[10];
10156
- t4 = $[11];
10157
- }
10252
+ $[12] = api;
10253
+ $[13] = documentBuffer;
10254
+ $[14] = experimentalSession;
10255
+ $[15] = initialDocument;
10256
+ $[16] = password;
10257
+ $[17] = t4;
10258
+ } else t4 = $[17];
10158
10259
  useEffect(t3, t4);
10159
10260
  let t5;
10160
10261
  let t6;
10161
- if ($[12] !== documentBuffer || $[13] !== history.state) {
10262
+ if ($[18] !== documentBuffer || $[19] !== history.state || $[20] !== loadedDocumentIdentity) {
10162
10263
  t5 = () => {
10264
+ if (originalBufferIdentityRef.current === loadedDocumentIdentity) return;
10265
+ originalBufferIdentityRef.current = loadedDocumentIdentity;
10163
10266
  if (history.state?.originalBuffer) {
10164
10267
  originalBufferRef.current = history.state.originalBuffer;
10165
10268
  return;
10166
10269
  }
10167
- if (documentBuffer instanceof ArrayBuffer) originalBufferRef.current = documentBuffer;
10270
+ originalBufferRef.current = documentBuffer instanceof ArrayBuffer ? documentBuffer : null;
10168
10271
  };
10169
- t6 = [history.state, documentBuffer];
10170
- $[12] = documentBuffer;
10171
- $[13] = history.state;
10172
- $[14] = t5;
10173
- $[15] = t6;
10272
+ t6 = [
10273
+ history.state,
10274
+ documentBuffer,
10275
+ loadedDocumentIdentity
10276
+ ];
10277
+ $[18] = documentBuffer;
10278
+ $[19] = history.state;
10279
+ $[20] = loadedDocumentIdentity;
10280
+ $[21] = t5;
10281
+ $[22] = t6;
10174
10282
  } else {
10175
- t5 = $[14];
10176
- t6 = $[15];
10283
+ t5 = $[21];
10284
+ t6 = $[22];
10177
10285
  }
10178
10286
  useEffect(t5, t6);
10179
10287
  let t7;
10180
- if ($[16] !== api.loadBuffer || $[17] !== api.loadParsedDocument || $[18] !== api.resetForNewDocument || $[19] !== loadedDocumentIdentity) {
10288
+ if ($[23] !== api.loadBuffer || $[24] !== api.loadParsedDocument || $[25] !== api.resetForNewDocument || $[26] !== loadedDocumentIdentity) {
10181
10289
  t7 = {
10182
10290
  loadBuffer: api.loadBuffer,
10183
10291
  loadParsedDocument: api.loadParsedDocument,
@@ -10185,12 +10293,12 @@ const useDocumentLoader = (t0) => {
10185
10293
  originalBufferRef,
10186
10294
  loadedDocumentIdentity
10187
10295
  };
10188
- $[16] = api.loadBuffer;
10189
- $[17] = api.loadParsedDocument;
10190
- $[18] = api.resetForNewDocument;
10191
- $[19] = loadedDocumentIdentity;
10192
- $[20] = t7;
10193
- } else t7 = $[20];
10296
+ $[23] = api.loadBuffer;
10297
+ $[24] = api.loadParsedDocument;
10298
+ $[25] = api.resetForNewDocument;
10299
+ $[26] = loadedDocumentIdentity;
10300
+ $[27] = t7;
10301
+ } else t7 = $[27];
10194
10302
  return t7;
10195
10303
  };
10196
10304
  //#endregion
@@ -10473,7 +10581,7 @@ const saveAndCloseHeaderFooterEdit = ({ activeRId, document, editPosition, isFir
10473
10581
  if (newDocument) pushDocument(newDocument);
10474
10582
  setEditPosition(null);
10475
10583
  };
10476
- const useHeaderFooterEditor = ({ history, pushDocument, getHfView }) => {
10584
+ const useHeaderFooterEditor = ({ history, pushDocument, getHfView, getCanonicalApi, experimentalSession }) => {
10477
10585
  const [hfEditPosition, setHfEditPosition] = useState(null);
10478
10586
  const [hfEditIsFirstPage, setHfEditIsFirstPage] = useState(false);
10479
10587
  const rawResolution = useMemo(() => resolveHeaderFooterContent(history.state?.package), [history.state]);
@@ -10491,6 +10599,19 @@ const useHeaderFooterEditor = ({ history, pushDocument, getHfView }) => {
10491
10599
  setHfEditPosition(position);
10492
10600
  return;
10493
10601
  }
10602
+ if (experimentalSession === "canonical") {
10603
+ const api = getCanonicalApi?.();
10604
+ api?.ensureView();
10605
+ const canonical = api?.getCanonicalDocument();
10606
+ if (!canonical || !api) return;
10607
+ const operation = createCanonicalHeaderFooterOperation({
10608
+ document: canonical,
10609
+ position,
10610
+ referenceType: isFirstPage ? "first" : "default"
10611
+ });
10612
+ if (api.applyCanonicalOperations([operation])) setHfEditPosition(position);
10613
+ return;
10614
+ }
10494
10615
  if (!history.state) return;
10495
10616
  const newDoc = createEmptyHeaderFooter(history.state, position, isFirstPage);
10496
10617
  if (!newDoc) return;
@@ -10503,9 +10624,15 @@ const useHeaderFooterEditor = ({ history, pushDocument, getHfView }) => {
10503
10624
  firstPageFooterContent,
10504
10625
  hasTitlePg,
10505
10626
  history,
10506
- pushDocument
10627
+ pushDocument,
10628
+ getCanonicalApi,
10629
+ experimentalSession
10507
10630
  ]);
10508
10631
  const handleHeaderFooterSave = useCallback(() => {
10632
+ if (experimentalSession === "canonical") {
10633
+ setHfEditPosition(null);
10634
+ return;
10635
+ }
10509
10636
  if (!hfEditPosition || !history.state?.package) {
10510
10637
  setHfEditPosition(null);
10511
10638
  return;
@@ -10527,7 +10654,8 @@ const useHeaderFooterEditor = ({ history, pushDocument, getHfView }) => {
10527
10654
  resolution,
10528
10655
  history,
10529
10656
  pushDocument,
10530
- getHfView
10657
+ getHfView,
10658
+ experimentalSession
10531
10659
  ]);
10532
10660
  return {
10533
10661
  hfEditPosition,
@@ -10555,6 +10683,17 @@ const useHeaderFooterEditor = ({ history, pushDocument, getHfView }) => {
10555
10683
  return;
10556
10684
  }
10557
10685
  const activeRId_0 = pickActiveHeaderFooterRId(resolution, hfEditPosition, hfEditIsFirstPage);
10686
+ if (experimentalSession === "canonical") {
10687
+ const api_0 = getCanonicalApi?.();
10688
+ const canonical_0 = api_0?.getCanonicalDocument();
10689
+ if (api_0 && canonical_0 && activeRId_0) api_0.applyCanonicalOperations(removeCanonicalHeaderFooterOperations({
10690
+ document: canonical_0,
10691
+ position: hfEditPosition,
10692
+ rId: activeRId_0
10693
+ }));
10694
+ setHfEditPosition(null);
10695
+ return;
10696
+ }
10558
10697
  if (activeRId_0) pushDocument(removeHeaderFooter({
10559
10698
  document: history.state,
10560
10699
  position: hfEditPosition,
@@ -10566,7 +10705,9 @@ const useHeaderFooterEditor = ({ history, pushDocument, getHfView }) => {
10566
10705
  hfEditIsFirstPage,
10567
10706
  resolution,
10568
10707
  history,
10569
- pushDocument
10708
+ pushDocument,
10709
+ getCanonicalApi,
10710
+ experimentalSession
10570
10711
  ])
10571
10712
  };
10572
10713
  };
@@ -11019,7 +11160,10 @@ function useZoomAndPageInfo({ scrollContainerRef, pagedEditorRef, initialZoom })
11019
11160
  if (anchor.zoom === zoom) return;
11020
11161
  const scrollContainer_1 = scrollContainerRef.current;
11021
11162
  if (!scrollContainer_1) return;
11022
- scrollContainer_1.scrollTop = getScrollTopForZoomAnchor(anchor, zoom);
11163
+ scrollEditorTo(scrollContainer_1, {
11164
+ top: getScrollTopForZoomAnchor(anchor, zoom),
11165
+ behavior: "instant"
11166
+ });
11023
11167
  updateScrollPageInfo(scrollContainer_1);
11024
11168
  scheduleScrollPageInfoFade();
11025
11169
  }, [
@@ -12637,15 +12781,25 @@ function useFolioComments({ doc, autoOpenReviewSidebar, anchorPositions, editorC
12637
12781
  const sanitizedCommentsProp = useMemo(() => commentsProp !== void 0 ? sanitizeControlledComments(commentsProp) : void 0, [commentsProp]);
12638
12782
  const isControlledComments = sanitizedCommentsProp !== void 0;
12639
12783
  const comments = isControlledComments ? sanitizedCommentsProp : internalComments;
12784
+ useLayoutEffect(() => {
12785
+ for (const { id } of doc?.package.document.comments ?? []) seedCommentIdAbove(id);
12786
+ for (const { id: id_0 } of comments) seedCommentIdAbove(id_0);
12787
+ }, [comments, doc]);
12640
12788
  const commentsDirtyRef = useRef(false);
12641
12789
  const commentsRef = useRef(comments);
12642
12790
  commentsRef.current = comments;
12643
12791
  const readonlyCommentsRef = commentsRef;
12644
12792
  const onCommentsChangeRef = useRef(onCommentsChange);
12645
12793
  onCommentsChangeRef.current = onCommentsChange;
12794
+ const createComment$1 = useCallback((text, author, parentId) => {
12795
+ for (const { id: id_1 } of doc?.package.document.comments ?? []) seedCommentIdAbove(id_1);
12796
+ for (const { id: id_2 } of commentsRef.current) seedCommentIdAbove(id_2);
12797
+ return createComment(text, author, parentId);
12798
+ }, [doc]);
12646
12799
  const setComments = useCallback((next) => {
12647
12800
  const resolved = typeof next === "function" ? next(commentsRef.current) : next;
12648
12801
  if (resolved === commentsRef.current) return;
12802
+ for (const { id: id_3 } of resolved) seedCommentIdAbove(id_3);
12649
12803
  commentsRef.current = resolved;
12650
12804
  if (!isControlledComments) setInternalComments(resolved);
12651
12805
  onCommentsChangeRef.current?.(resolved);
@@ -12693,13 +12847,13 @@ function useFolioComments({ doc, autoOpenReviewSidebar, anchorPositions, editorC
12693
12847
  const visibleComments = useMemo(() => {
12694
12848
  const visibleRootIds = /* @__PURE__ */ new Set();
12695
12849
  for (const comment_1 of comments) {
12696
- const parentId = getCommentParentId(comment_1);
12697
- if (parentId === null || parentId === void 0 || !visibleCommentIds.has(comment_1.id)) continue;
12698
- visibleRootIds.add(parentId);
12850
+ const parentId_0 = getCommentParentId(comment_1);
12851
+ if (parentId_0 === null || parentId_0 === void 0 || !visibleCommentIds.has(comment_1.id)) continue;
12852
+ visibleRootIds.add(parentId_0);
12699
12853
  }
12700
12854
  return comments.filter((comment_2) => {
12701
- const parentId_0 = getCommentParentId(comment_2);
12702
- if (parentId_0 !== null && parentId_0 !== void 0) return visibleCommentIds.has(comment_2.id);
12855
+ const parentId_1 = getCommentParentId(comment_2);
12856
+ if (parentId_1 !== null && parentId_1 !== void 0) return visibleCommentIds.has(comment_2.id);
12703
12857
  return visibleCommentIds.has(comment_2.id) || visibleRootIds.has(comment_2.id);
12704
12858
  });
12705
12859
  }, [comments, visibleCommentIds]);
@@ -12712,7 +12866,7 @@ function useFolioComments({ doc, autoOpenReviewSidebar, anchorPositions, editorC
12712
12866
  if (!root) return;
12713
12867
  const nodes = root.querySelectorAll(`.layout-run-text${COMMENT_ANCHOR_SELECTOR}`);
12714
12868
  for (const node of nodes) {
12715
- const commentIds = commentAnchorIds(node).map((id) => Number.parseInt(id, 10));
12869
+ const commentIds = commentAnchorIds(node).map((id_4) => Number.parseInt(id_4, 10));
12716
12870
  if (!commentIds.some((commentId) => commentId === -1 || visibleCommentIds.has(commentId))) {
12717
12871
  node.style.backgroundColor = "transparent";
12718
12872
  node.style.borderBottom = "2px solid transparent";
@@ -12757,6 +12911,7 @@ function useFolioComments({ doc, autoOpenReviewSidebar, anchorPositions, editorC
12757
12911
  return {
12758
12912
  comments,
12759
12913
  setComments,
12914
+ createComment: createComment$1,
12760
12915
  isControlledComments,
12761
12916
  commentsRef: readonlyCommentsRef,
12762
12917
  commentsDirtyRef,
@@ -12794,7 +12949,7 @@ function useFolioComments({ doc, autoOpenReviewSidebar, anchorPositions, editorC
12794
12949
  */
12795
12950
  /** No headings to track while the outline is not shown. */
12796
12951
  const NO_HEADINGS = [];
12797
- const CommentsSidebar = lazy(() => import("./CommentsSidebar-D0TBbrpB.js").then((m) => ({ default: m.CommentsSidebar })));
12952
+ const CommentsSidebar = lazy(() => import("./CommentsSidebar-D9vMIMl7.js").then((m) => ({ default: m.CommentsSidebar })));
12798
12953
  const TextContextMenu = lazy(() => import("./TextContextMenu-Bqth8itn.js").then((m) => ({ default: m.TextContextMenu })));
12799
12954
  const loadAttemptSelectiveSave = async () => {
12800
12955
  const { attemptSelectiveSave } = await import("@stll/folio-core/docx/selectiveSave");
@@ -12865,7 +13020,7 @@ function areActiveTrackedChangesEqual(a, b) {
12865
13020
  /**
12866
13021
  * DocxEditor - Complete DOCX editor component
12867
13022
  */
12868
- 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, onSelectiveSaveTripwire }, ref) {
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) {
12869
13024
  const t = useTranslations("folio");
12870
13025
  useEffect(() => {
12871
13026
  const onClipboardReadError = () => {
@@ -12904,11 +13059,25 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
12904
13059
  const [, setTrackedChanges] = useState([]);
12905
13060
  const trackedChangesRef = useRef([]);
12906
13061
  const [anchorPositions, setAnchorPositions] = useState(EMPTY_ANCHOR_POSITIONS);
12907
- const { editingMode, readOnly, trackChangesOn, toggleTrackChanges, displayMode, setDisplayMode } = useEditorMode({
13062
+ const { editingMode, readOnly, trackChangesOn, toggleTrackChanges: toggleTrackChangesUnrestricted, displayMode, setDisplayMode } = useEditorMode({
12908
13063
  modeProp,
12909
13064
  onModeChange,
12910
13065
  readOnlyProp
12911
13066
  });
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
+ ]);
12912
13081
  const extractTrackedChangesTimerRef = useRef(null);
12913
13082
  const collectHeadingsTimerRef = useRef(null);
12914
13083
  const extractTrackedChanges = useCallback(() => {
@@ -12957,8 +13126,15 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
12957
13126
  const history = useDocumentHistory(initialDocument || null, {
12958
13127
  maxEntries: 100,
12959
13128
  groupingInterval: 500,
12960
- enableKeyboardShortcuts: historyShortcuts === "editor"
13129
+ enableKeyboardShortcuts: historyShortcuts === "editor" && experimentalSession !== "canonical"
12961
13130
  });
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);
13136
+ return true;
13137
+ }, [experimentalSession, onError]);
12962
13138
  const extensionManager = useMemo(() => {
12963
13139
  const mgr = new ExtensionManager(createStarterKit({ historyShortcuts }));
12964
13140
  mgr.buildSchema();
@@ -13017,8 +13193,30 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13017
13193
  if (!onEditorViewReady) return;
13018
13194
  if (lastReportedViewRef.current === view_0) return;
13019
13195
  lastReportedViewRef.current = view_0;
13196
+ if (view_0 && initialScrollTop !== void 0) {
13197
+ const initialScroll = initialScrollRef.current;
13198
+ switch (initialScroll.status) {
13199
+ case "scheduled":
13200
+ cancelAnimationFrame(initialScroll.frame);
13201
+ scrollEditorTo(scrollContainerRef.current, {
13202
+ top: initialScrollTop,
13203
+ behavior: "instant"
13204
+ });
13205
+ initialScrollRef.current = { status: "applied" };
13206
+ break;
13207
+ case "waiting":
13208
+ scrollEditorTo(scrollContainerRef.current, {
13209
+ top: initialScrollTop,
13210
+ behavior: "instant"
13211
+ });
13212
+ initialScrollRef.current = { status: "applied" };
13213
+ break;
13214
+ case "applied": break;
13215
+ default: return initialScroll;
13216
+ }
13217
+ }
13020
13218
  onEditorViewReady(view_0);
13021
- }, [onEditorViewReady]);
13219
+ }, [onEditorViewReady, initialScrollTop]);
13022
13220
  useLayoutEffect(() => {
13023
13221
  if (!onEditorViewReady) return;
13024
13222
  const view_1 = pagedEditorRef.current?.getView() ?? null;
@@ -13077,7 +13275,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13077
13275
  const imageInputRef = useRef(null);
13078
13276
  const editorContentRef = useRef(null);
13079
13277
  const scrollContainerRef = useRef(null);
13080
- const initialScrollAppliedRef = useRef(false);
13278
+ const initialScrollRef = useRef({ status: "waiting" });
13081
13279
  const [widestLaidOutPageWidth, setWidestLaidOutPageWidth] = useState(null);
13082
13280
  const hasDocument = history.state !== null;
13083
13281
  useEffect(() => {
@@ -13118,7 +13316,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13118
13316
  size: 4,
13119
13317
  color: { rgb: "000000" }
13120
13318
  });
13121
- const { comments, setComments, commentsRef, commentsDirtyRef, commentsLoadedRef, showCommentsSidebar, setShowCommentsSidebar, setVisibleCommentAuthors, activeCommentId, setActiveCommentId, isAddingComment, setIsAddingComment, commentSelectionRange, setCommentSelectionRange, addCommentYPosition, setAddCommentYPosition, floatingCommentBtn, setFloatingCommentBtn, commentAuthors, visibleCommentAuthorSet, visibleComments, syncCommentHighlightStyles } = useFolioComments({
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({
13122
13320
  doc: history.state,
13123
13321
  autoOpenReviewSidebar,
13124
13322
  anchorPositions,
@@ -13156,6 +13354,8 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13156
13354
  canUndo: false
13157
13355
  });
13158
13356
  const [activeNoteStory, setActiveNoteStory] = useState(null);
13357
+ const canEditHeaderFooter = showHeaderFooterEditing;
13358
+ const getCanonicalApi = useCallback(() => pagedEditorRef.current?.getEditor() ?? null, []);
13159
13359
  const pushDocument = useCallback((document) => {
13160
13360
  history.push(document);
13161
13361
  return document;
@@ -13171,6 +13371,8 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13171
13371
  const { hfEditPosition, setHfEditPosition, hfEditIsFirstPage, headerContent, footerContent, firstPageHeaderContent, firstPageFooterContent, activeHeaderRId, activeFooterRId, activeFirstHeaderRId, activeFirstFooterRId, effectiveSectionProperties, handleHeaderFooterDoubleClick, handleBodyClick, handleRemoveHeaderFooter } = useHeaderFooterEditor({
13172
13372
  history,
13173
13373
  pushDocument,
13374
+ getCanonicalApi,
13375
+ ...experimentalSession === void 0 ? {} : { experimentalSession },
13174
13376
  getHfView: (rId) => pagedEditorRef.current?.getHfView(rId) ?? null
13175
13377
  });
13176
13378
  let activeHfRId = hfEditIsFirstPage ? activeFirstFooterRId : activeFooterRId;
@@ -13203,19 +13405,27 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13203
13405
  else pagedEditorRef.current?.focus();
13204
13406
  }, [getActiveEditorStory]);
13205
13407
  const undoActiveEditor = useCallback(() => {
13206
- if (getActiveEditorStory().type === "headerFooter" && hfEditorRef.current) hfEditorRef.current.undo();
13408
+ if (experimentalSession !== "canonical" && getActiveEditorStory().type === "headerFooter" && hfEditorRef.current) hfEditorRef.current.undo();
13207
13409
  else {
13208
13410
  pagedEditorRef.current?.undo();
13209
13411
  requestAnimationFrame(refreshBodyHistoryAvailability);
13210
13412
  }
13211
- }, [getActiveEditorStory, refreshBodyHistoryAvailability]);
13413
+ }, [
13414
+ getActiveEditorStory,
13415
+ refreshBodyHistoryAvailability,
13416
+ experimentalSession
13417
+ ]);
13212
13418
  const redoActiveEditor = useCallback(() => {
13213
- if (getActiveEditorStory().type === "headerFooter" && hfEditorRef.current) hfEditorRef.current.redo();
13419
+ if (experimentalSession !== "canonical" && getActiveEditorStory().type === "headerFooter" && hfEditorRef.current) hfEditorRef.current.redo();
13214
13420
  else {
13215
13421
  pagedEditorRef.current?.redo();
13216
13422
  requestAnimationFrame(refreshBodyHistoryAvailability);
13217
13423
  }
13218
- }, [getActiveEditorStory, refreshBodyHistoryAvailability]);
13424
+ }, [
13425
+ getActiveEditorStory,
13426
+ refreshBodyHistoryAvailability,
13427
+ experimentalSession
13428
+ ]);
13219
13429
  const handleActiveNoteStoryChange = useCallback((story) => {
13220
13430
  setActiveNoteStory(story);
13221
13431
  if (story && hfEditPosition) handleBodyClick();
@@ -13239,15 +13449,19 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13239
13449
  documentBuffer: documentBuffer ?? null,
13240
13450
  initialDocument: initialDocument ?? null,
13241
13451
  password,
13452
+ ...experimentalSession === void 0 ? {} : { experimentalSession },
13242
13453
  history,
13243
13454
  onError,
13244
13455
  onCompatibilityChange,
13245
13456
  onReset: useCallback(() => {
13246
- initialScrollAppliedRef.current = false;
13247
- if (scrollContainerRef.current) {
13248
- scrollContainerRef.current.scrollTop = 0;
13249
- scrollContainerRef.current.scrollLeft = 0;
13250
- }
13457
+ const initialScroll_0 = initialScrollRef.current;
13458
+ if (initialScroll_0.status === "scheduled") cancelAnimationFrame(initialScroll_0.frame);
13459
+ initialScrollRef.current = { status: "waiting" };
13460
+ if (scrollContainerRef.current) scrollEditorTo(scrollContainerRef.current, {
13461
+ top: 0,
13462
+ left: 0,
13463
+ behavior: "instant"
13464
+ });
13251
13465
  commentsDirtyRef.current = false;
13252
13466
  commentsLoadedRef.current = false;
13253
13467
  setComments([]);
@@ -13303,13 +13517,24 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13303
13517
  extractTrackedChanges
13304
13518
  ]);
13305
13519
  useEffect(() => {
13306
- if (initialScrollTop === void 0 || state.documentLoad.status !== "ready" || initialScrollAppliedRef.current) return;
13307
- initialScrollAppliedRef.current = true;
13520
+ if (initialScrollTop === void 0 || state.documentLoad.status !== "ready" || initialScrollRef.current.status !== "waiting") return;
13308
13521
  const frame = requestAnimationFrame(() => {
13309
- if (scrollContainerRef.current) scrollContainerRef.current.scrollTop = initialScrollTop;
13522
+ initialScrollRef.current = { status: "applied" };
13523
+ scrollEditorTo(scrollContainerRef.current, {
13524
+ top: initialScrollTop,
13525
+ behavior: "instant"
13526
+ });
13310
13527
  });
13528
+ initialScrollRef.current = {
13529
+ status: "scheduled",
13530
+ frame
13531
+ };
13311
13532
  return () => {
13312
- cancelAnimationFrame(frame);
13533
+ const initialScroll_1 = initialScrollRef.current;
13534
+ if (initialScroll_1.status === "scheduled" && initialScroll_1.frame === frame) {
13535
+ cancelAnimationFrame(frame);
13536
+ initialScrollRef.current = { status: "waiting" };
13537
+ }
13313
13538
  };
13314
13539
  }, [
13315
13540
  initialScrollTop,
@@ -13338,7 +13563,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13338
13563
  }
13339
13564
  };
13340
13565
  pushDocument(documentWithComments);
13341
- onChange?.(documentWithComments);
13566
+ onChange?.(experimentalSession === "canonical" ? cloneDocumentWithParagraphPropertySources(documentWithComments) : documentWithComments);
13342
13567
  if (showOutlineRef.current) {
13343
13568
  if (collectHeadingsTimerRef.current) clearTimeout(collectHeadingsTimerRef.current);
13344
13569
  collectHeadingsTimerRef.current = setTimeout(() => {
@@ -13359,10 +13584,14 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13359
13584
  pushDocument,
13360
13585
  extractTrackedChanges,
13361
13586
  refreshBodyHistoryAvailability,
13362
- commentsRef
13587
+ commentsRef,
13588
+ experimentalSession
13363
13589
  ]);
13364
13590
  const buildCurrentDocument = useCallback(() => {
13365
13591
  if (!history.state) return null;
13592
+ const canonical = pagedEditorRef.current?.getEditor().getCanonicalDocument();
13593
+ if (canonical) return canonical;
13594
+ if (experimentalSession === "canonical") return null;
13366
13595
  let doc_0 = cloneDocumentWithParagraphPropertySources(history.state);
13367
13596
  const pmDoc = pagedEditorRef.current?.getDocument();
13368
13597
  if (pmDoc) {
@@ -13387,8 +13616,16 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13387
13616
  const referencedCommentIds = collectCommentIdsFromSources(doc_0.package.document.content, doc_0.package.headers, doc_0.package.footers, doc_0.package.footnotes, doc_0.package.endnotes);
13388
13617
  doc_0.package.document.comments = pruneOrphanedComments(commentsRef.current, referencedCommentIds);
13389
13618
  return doc_0;
13390
- }, [history.state, commentsRef]);
13619
+ }, [
13620
+ history.state,
13621
+ commentsRef,
13622
+ experimentalSession
13623
+ ]);
13391
13624
  const replaceComments = useCallback((nextComments) => {
13625
+ if (experimentalSession === "canonical") {
13626
+ refuseCanonicalModelEdit("Comment changes are unavailable in this session.");
13627
+ return;
13628
+ }
13392
13629
  commentsDirtyRef.current = true;
13393
13630
  setComments(nextComments);
13394
13631
  const currentDocument = buildCurrentDocument();
@@ -13397,7 +13634,9 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13397
13634
  }, [
13398
13635
  buildCurrentDocument,
13399
13636
  commentsDirtyRef,
13637
+ experimentalSession,
13400
13638
  onChange,
13639
+ refuseCanonicalModelEdit,
13401
13640
  setComments
13402
13641
  ]);
13403
13642
  const updateComments = useCallback((updater) => {
@@ -13650,6 +13889,16 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13650
13889
  roots: shortcutRoots
13651
13890
  });
13652
13891
  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.");
13900
+ return;
13901
+ }
13653
13902
  if (!history.state?.package) return;
13654
13903
  const newDoc = {
13655
13904
  ...history.state.package.document,
@@ -13666,7 +13915,13 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13666
13915
  document: newDoc
13667
13916
  }
13668
13917
  });
13669
- }, [history, pushDocument]);
13918
+ }, [
13919
+ history,
13920
+ pushDocument,
13921
+ experimentalSession,
13922
+ getCanonicalApi,
13923
+ refuseCanonicalModelEdit
13924
+ ]);
13670
13925
  const handleTableAction = useCallback((action_0) => {
13671
13926
  const view_9 = getActiveEditorView();
13672
13927
  if (!view_9) return;
@@ -13861,92 +14116,95 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13861
14116
  const tr = view_10.state.tr.setSelection(TextSelection.create(view_10.state.doc, savedSelection.from, savedSelection.to));
13862
14117
  view_10.dispatch(tr);
13863
14118
  } catch {}
13864
- const commandState = view_10.state;
13865
14119
  if (action_1 === "bold") {
13866
- toggleBold(commandState, view_10.dispatch);
14120
+ executeEditorCommand(view_10, toggleBold);
13867
14121
  return;
13868
14122
  }
13869
14123
  if (action_1 === "italic") {
13870
- toggleItalic(commandState, view_10.dispatch);
14124
+ executeEditorCommand(view_10, toggleItalic);
13871
14125
  return;
13872
14126
  }
13873
14127
  if (action_1 === "underline") {
13874
- toggleUnderline(commandState, view_10.dispatch);
14128
+ executeEditorCommand(view_10, toggleUnderline);
13875
14129
  return;
13876
14130
  }
13877
14131
  if (action_1 === "strikethrough") {
13878
- toggleStrike(commandState, view_10.dispatch);
14132
+ executeEditorCommand(view_10, toggleStrike);
13879
14133
  return;
13880
14134
  }
13881
14135
  if (action_1 === "superscript") {
13882
- toggleSuperscript(commandState, view_10.dispatch);
14136
+ executeEditorCommand(view_10, toggleSuperscript);
13883
14137
  return;
13884
14138
  }
13885
14139
  if (action_1 === "subscript") {
13886
- toggleSubscript(commandState, view_10.dispatch);
14140
+ executeEditorCommand(view_10, toggleSubscript);
13887
14141
  return;
13888
14142
  }
13889
14143
  if (action_1 === "bulletList") {
13890
- toggleBulletList(commandState, view_10.dispatch);
14144
+ executeEditorCommand(view_10, toggleBulletList);
13891
14145
  return;
13892
14146
  }
13893
14147
  if (action_1 === "numberedList") {
13894
- toggleNumberedList(commandState, view_10.dispatch);
14148
+ executeEditorCommand(view_10, toggleNumberedList);
13895
14149
  return;
13896
14150
  }
13897
14151
  if (action_1 === "indent") {
13898
- if (!increaseListLevel(commandState, view_10.dispatch)) increaseIndent()(commandState, view_10.dispatch);
14152
+ executeFirstEditorCommand(view_10, [increaseListLevel, increaseIndent()]);
13899
14153
  return;
13900
14154
  }
13901
14155
  if (action_1 === "outdent") {
13902
- if (!decreaseListLevel(commandState, view_10.dispatch)) decreaseIndent()(commandState, view_10.dispatch);
14156
+ executeFirstEditorCommand(view_10, [decreaseListLevel, decreaseIndent()]);
13903
14157
  return;
13904
14158
  }
13905
14159
  if (action_1 === "clearFormatting") {
13906
- clearFormatting(commandState, view_10.dispatch);
14160
+ executeEditorCommand(view_10, clearFormatting);
13907
14161
  return;
13908
14162
  }
13909
14163
  if (action_1 === "setRtl") {
13910
- setRtl(commandState, view_10.dispatch);
14164
+ executeEditorCommand(view_10, setRtl);
13911
14165
  return;
13912
14166
  }
13913
14167
  if (action_1 === "setLtr") {
13914
- setLtr(commandState, view_10.dispatch);
14168
+ executeEditorCommand(view_10, setLtr);
14169
+ return;
14170
+ }
14171
+ if (action_1 === "insertPageBreak") {
14172
+ executeEditorCommand(view_10, insertPageBreak);
13915
14173
  return;
13916
14174
  }
13917
14175
  if (typeof action_1 === "object") switch (action_1.type) {
13918
14176
  case "alignment":
13919
- setAlignment(action_1.value)(commandState, view_10.dispatch);
14177
+ executeEditorCommand(view_10, setAlignment(action_1.value));
13920
14178
  break;
13921
14179
  case "toggleDirection":
13922
- toggleBidi(commandState, view_10.dispatch);
14180
+ executeEditorCommand(view_10, toggleBidi);
13923
14181
  break;
13924
14182
  case "textColor": {
13925
14183
  const colorVal_0 = action_1.value;
13926
- if (typeof colorVal_0 === "string") setTextColor({ rgb: colorVal_0.replace("#", "") })(commandState, view_10.dispatch);
13927
- else if (colorVal_0.auto) clearTextColor(commandState, view_10.dispatch);
14184
+ if (typeof colorVal_0 === "string") executeEditorCommand(view_10, setTextColor({ rgb: colorVal_0.replace("#", "") }));
14185
+ else if (colorVal_0.auto) executeEditorCommand(view_10, clearTextColor);
13928
14186
  else {
13929
14187
  const themeColor = typeof colorVal_0.themeColor === "string" ? colorVal_0.themeColor : void 0;
13930
- setTextColor({
14188
+ executeEditorCommand(view_10, setTextColor({
13931
14189
  ...colorVal_0.rgb === void 0 ? {} : { rgb: colorVal_0.rgb },
13932
14190
  ...themeColor ? { themeColor } : {},
13933
14191
  ...colorVal_0.themeTint === void 0 ? {} : { themeTint: colorVal_0.themeTint },
13934
14192
  ...colorVal_0.themeShade === void 0 ? {} : { themeShade: colorVal_0.themeShade }
13935
- })(commandState, view_10.dispatch);
14193
+ }));
13936
14194
  }
13937
14195
  break;
13938
14196
  }
13939
14197
  case "highlightColor":
13940
- setHighlight((action_1.value ? mapHexToHighlightName(action_1.value) : "") || action_1.value)(commandState, view_10.dispatch);
14198
+ executeEditorCommand(view_10, setHighlight((action_1.value ? mapHexToHighlightName(action_1.value) : "") || action_1.value));
13941
14199
  break;
13942
14200
  case "fontSize":
13943
- setFontSize(pointsToHalfPoints(action_1.value))(commandState, view_10.dispatch);
14201
+ executeEditorCommand(view_10, setFontSize(pointsToHalfPoints(action_1.value)));
13944
14202
  break;
13945
14203
  case "fontFamily":
13946
- setFontFamily(action_1.value)(commandState, view_10.dispatch);
14204
+ executeEditorCommand(view_10, setFontFamily(action_1.value));
13947
14205
  break;
13948
14206
  case "lineSpacing":
13949
- setLineSpacing(action_1.value)(commandState, view_10.dispatch);
14207
+ executeEditorCommand(view_10, setLineSpacing(action_1.value));
13950
14208
  break;
13951
14209
  case "applyStyle": {
13952
14210
  const currentDoc_0 = historyStateRef.current;
@@ -13959,8 +14217,8 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
13959
14217
  const styleName = styleResolver_0.getStyle(action_1.value)?.name;
13960
14218
  if (styleName) styleAttrs.styleName = styleName;
13961
14219
  styleAttrs.numbering = currentDoc_0?.package.numbering ? getCachedNumberingMap(currentDoc_0.package.numbering) : null;
13962
- applyStyle(action_1.value, styleAttrs)(commandState, view_10.dispatch);
13963
- } else applyStyle(action_1.value)(commandState, view_10.dispatch);
14220
+ executeEditorCommand(view_10, applyStyle(action_1.value, styleAttrs));
14221
+ } else executeEditorCommand(view_10, applyStyle(action_1.value));
13964
14222
  break;
13965
14223
  }
13966
14224
  default: break;
@@ -14275,13 +14533,21 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14275
14533
  case "acceptChange": {
14276
14534
  const { from: from_4, to: to_4 } = view_13.state.selection;
14277
14535
  const range_1 = findChangeAtPosition(view_13.state, from_4, to_4);
14278
- acceptChange(range_1.from, range_1.to)(view_13.state, view_13.dispatch);
14536
+ if (resolveCanonicalReviewRange({
14537
+ editor: pagedEditorRef.current?.getEditor(),
14538
+ ...range_1,
14539
+ resolution: "accept"
14540
+ }) === null) acceptChange(range_1.from, range_1.to)(view_13.state, view_13.dispatch);
14279
14541
  break;
14280
14542
  }
14281
14543
  case "rejectChange": {
14282
14544
  const { from: from_3, to: to_3 } = view_13.state.selection;
14283
14545
  const range_0 = findChangeAtPosition(view_13.state, from_3, to_3);
14284
- rejectChange(range_0.from, range_0.to)(view_13.state, view_13.dispatch);
14546
+ if (resolveCanonicalReviewRange({
14547
+ editor: pagedEditorRef.current?.getEditor(),
14548
+ ...range_0,
14549
+ resolution: "reject"
14550
+ }) === null) rejectChange(range_0.from, range_0.to)(view_13.state, view_13.dispatch);
14285
14551
  break;
14286
14552
  }
14287
14553
  case "restartNumbering":
@@ -14313,6 +14579,14 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14313
14579
  t
14314
14580
  ]);
14315
14581
  const handlePageSetupApply = useCallback((props) => {
14582
+ 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.");
14588
+ return;
14589
+ }
14316
14590
  if (!history.state || readOnly) return;
14317
14591
  const newDoc_0 = {
14318
14592
  ...history.state,
@@ -14331,7 +14605,10 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14331
14605
  }, [
14332
14606
  history.state,
14333
14607
  readOnly,
14334
- handleDocumentChange
14608
+ handleDocumentChange,
14609
+ experimentalSession,
14610
+ getCanonicalApi,
14611
+ refuseCanonicalModelEdit
14335
14612
  ]);
14336
14613
  const handleLeftMarginChange = useCallback((twips) => handlePageSetupApply({ marginLeft: twips }), [handlePageSetupApply]);
14337
14614
  const handleRightMarginChange = useCallback((twips_0) => handlePageSetupApply({ marginRight: twips_0 }), [handlePageSetupApply]);
@@ -14362,6 +14639,9 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14362
14639
  let tripwireResult = null;
14363
14640
  let savedBuffer = null;
14364
14641
  try {
14642
+ const view_18 = pagedEditorRef.current?.getView();
14643
+ const editorState = view_18?.state;
14644
+ const baselineBuffer = originalBufferRef.current;
14365
14645
  const current = buildCurrentDocument();
14366
14646
  const doc_1 = current ? withoutUnreferencedNotes(current) : null;
14367
14647
  if (!doc_1) return null;
@@ -14369,18 +14649,13 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14369
14649
  const flags = resolveSelectiveSaveFlags(featureFlags);
14370
14650
  const useSelectiveForSave = flags.selectiveSave && options?.mode !== FOLIO_DOCX_SERIALIZATION_MODE.full;
14371
14651
  const shouldAttemptSelective = useSelectiveForSave || flags.selectiveSaveTripwire;
14372
- const view_18 = pagedEditorRef.current?.getView();
14373
- const baselineBuffer = originalBufferRef.current;
14374
14652
  let selectiveBuffer = null;
14375
- if (shouldAttemptSelective && view_18 && baselineBuffer) {
14376
- const editorState = view_18.state;
14377
- selectiveBuffer = await (await loadAttemptSelectiveSave())(doc_1, baselineBuffer, {
14378
- changedParaIds: getChangedParagraphIds(editorState),
14379
- structuralChange: hasStructuralChanges(editorState),
14380
- hasUntrackedChanges: hasUntrackedChanges(editorState),
14381
- maxBytes: flags.selectiveSaveMaxBytes
14382
- });
14383
- }
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
+ });
14384
14659
  let buffer = useSelectiveForSave ? selectiveBuffer : null;
14385
14660
  let fullBuffer = null;
14386
14661
  const repackSourceDoc = baselineBuffer ? {
@@ -14390,8 +14665,12 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14390
14665
  const repackFull = async () => {
14391
14666
  const repackDocx = await loadRepackDocx();
14392
14667
  const repack = () => repackDocx(repackSourceDoc);
14393
- return view_18 ? repackWithEditorSectionRemovals({
14394
- state: view_18.state,
14668
+ if (experimentalSession === "canonical") return repackWithCanonicalStoryRemovals({
14669
+ document: repackSourceDoc,
14670
+ repack
14671
+ });
14672
+ return editorState ? repackWithEditorSectionRemovals({
14673
+ state: editorState,
14395
14674
  document: repackSourceDoc,
14396
14675
  repack
14397
14676
  }) : repack();
@@ -14406,13 +14685,13 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14406
14685
  const { compareSelectiveVsFull } = await import("@stll/folio-core/docx/selectiveSaveTripwire");
14407
14686
  tripwireResult = await compareSelectiveVsFull(selectiveBuffer, fullBuffer);
14408
14687
  } catch {}
14409
- if (view_18) {
14688
+ if (view_18 && pagedEditorRef.current?.getView() === view_18 && view_18.state.doc === editorState?.doc) {
14410
14689
  originalBufferRef.current = buffer;
14411
14690
  view_18.dispatch(clearTrackedChanges(view_18.state));
14412
14691
  }
14413
14692
  savedBuffer = buffer;
14414
- } catch (error) {
14415
- onError?.(error instanceof Error ? error : /* @__PURE__ */ new Error("Failed to save document"));
14693
+ } catch (error_1) {
14694
+ onError?.(error_1 instanceof Error ? error_1 : /* @__PURE__ */ new Error("Failed to save document"));
14416
14695
  return null;
14417
14696
  }
14418
14697
  if (tripwireResult && onSelectiveSaveTripwire) onSelectiveSaveTripwire(tripwireResult);
@@ -14446,8 +14725,9 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14446
14725
  loadParsedDocument,
14447
14726
  serializeCurrentDocx
14448
14727
  ]);
14449
- const handleEditorError = useCallback((error_0) => {
14450
- onError?.(error_0);
14728
+ const handleEditorError = useCallback((error_2) => {
14729
+ if (CanonicalSessionRefusalError.is(error_2)) toast(error_2.message);
14730
+ onError?.(error_2);
14451
14731
  }, [onError]);
14452
14732
  useImperativeHandle(ref, () => ({
14453
14733
  getDocument: () => buildCurrentDocument(),
@@ -14646,21 +14926,25 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14646
14926
  acceptAIEditOperation: (revisionId) => {
14647
14927
  const view_24 = pagedEditorRef.current?.getView();
14648
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");
14649
14931
  return acceptAIEditRevision(revisionId)(view_24.state, view_24.dispatch);
14650
14932
  },
14651
14933
  rejectAIEditOperation: (revisionId_0) => {
14652
14934
  const view_25 = pagedEditorRef.current?.getView();
14653
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");
14654
14938
  return rejectAIEditRevision(revisionId_0)(view_25.state, view_25.dispatch);
14655
14939
  },
14656
14940
  undo: () => {
14657
- if (getActiveEditorStory().type === "headerFooter" && hfEditorRef.current) return hfEditorRef.current.undo();
14941
+ if (experimentalSession !== "canonical" && getActiveEditorStory().type === "headerFooter" && hfEditorRef.current) return hfEditorRef.current.undo();
14658
14942
  const undone = pagedEditorRef.current?.undo() ?? false;
14659
14943
  requestAnimationFrame(refreshBodyHistoryAvailability);
14660
14944
  return undone;
14661
14945
  },
14662
14946
  redo: () => {
14663
- if (getActiveEditorStory().type === "headerFooter" && hfEditorRef.current) return hfEditorRef.current.redo();
14947
+ if (experimentalSession !== "canonical" && getActiveEditorStory().type === "headerFooter" && hfEditorRef.current) return hfEditorRef.current.redo();
14664
14948
  const redone = pagedEditorRef.current?.redo() ?? false;
14665
14949
  requestAnimationFrame(refreshBodyHistoryAvailability);
14666
14950
  return redone;
@@ -14940,10 +15224,12 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14940
15224
  loadBuffer,
14941
15225
  updateComments,
14942
15226
  replaceComments,
15227
+ createComment,
14943
15228
  commentsRef,
14944
15229
  commentsDirtyRef,
14945
15230
  getActiveEditorStory,
14946
- refreshBodyHistoryAvailability
15231
+ refreshBodyHistoryAvailability,
15232
+ experimentalSession
14947
15233
  ]);
14948
15234
  const getHfTargetElement = useCallback((pos_0) => {
14949
15235
  const pagesContainer = containerRef.current?.querySelector(".paged-editor__pages");
@@ -14956,6 +15242,10 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
14956
15242
  label: t(DISPLAY_MODE_LABEL_KEYS[mode_0])
14957
15243
  })), [t]);
14958
15244
  const activeHistoryAvailability = (() => {
15245
+ if (experimentalSession === "canonical") return {
15246
+ canRedo: pagedEditorRef.current?.canRedo() ?? false,
15247
+ canUndo: pagedEditorRef.current?.canUndo() ?? false
15248
+ };
14959
15249
  if (activeNoteStory) return {
14960
15250
  canRedo: pagedEditorRef.current?.canRedo() ?? false,
14961
15251
  canUndo: pagedEditorRef.current?.canUndo() ?? false
@@ -15011,14 +15301,22 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15011
15301
  if (!view_49) return;
15012
15302
  const { from: from_13, to: to_13 } = view_49.state.selection;
15013
15303
  const range_7 = findChangeAtPosition(view_49.state, from_13, to_13);
15014
- acceptChange(range_7.from, range_7.to)(view_49.state, view_49.dispatch);
15304
+ if (resolveCanonicalReviewRange({
15305
+ editor: pagedEditorRef.current?.getEditor(),
15306
+ ...range_7,
15307
+ resolution: "accept"
15308
+ }) === null) acceptChange(range_7.from, range_7.to)(view_49.state, view_49.dispatch);
15015
15309
  }, []);
15016
15310
  const handleRejectActiveChange = useCallback(() => {
15017
15311
  const view_50 = pagedEditorRef.current?.getView();
15018
15312
  if (!view_50) return;
15019
15313
  const { from: from_14, to: to_14 } = view_50.state.selection;
15020
15314
  const range_8 = findChangeAtPosition(view_50.state, from_14, to_14);
15021
- rejectChange(range_8.from, range_8.to)(view_50.state, view_50.dispatch);
15315
+ if (resolveCanonicalReviewRange({
15316
+ editor: pagedEditorRef.current?.getEditor(),
15317
+ ...range_8,
15318
+ resolution: "reject"
15319
+ }) === null) rejectChange(range_8.from, range_8.to)(view_50.state, view_50.dispatch);
15022
15320
  }, []);
15023
15321
  const handlePreviousChange = useCallback(() => {
15024
15322
  const view_51 = pagedEditorRef.current?.getView();
@@ -15217,23 +15515,33 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15217
15515
  }, [setScrollPageInfo]);
15218
15516
  const handleCommentClick = useCallback((id) => setActiveCommentId(id), [setActiveCommentId]);
15219
15517
  const handleCommentResolve = useCallback((id_0) => {
15518
+ if (refuseCanonicalModelEdit("Comment changes are unavailable in this session.")) return;
15220
15519
  updateComments((previous_0) => previous_0.map((comment_2) => comment_2.id === id_0 ? {
15221
15520
  ...comment_2,
15222
15521
  done: true
15223
15522
  } : comment_2));
15224
- }, [updateComments]);
15523
+ }, [refuseCanonicalModelEdit, updateComments]);
15225
15524
  const handleCommentDelete = useCallback((id_1) => {
15525
+ if (refuseCanonicalModelEdit("Comment changes are unavailable in this session.")) return;
15226
15526
  updateComments((previous_1) => previous_1.filter((comment_3) => comment_3.id !== id_1 && comment_3.parentId !== id_1));
15227
15527
  if (activeCommentId === id_1) setActiveCommentId(null);
15228
15528
  }, [
15229
15529
  activeCommentId,
15530
+ refuseCanonicalModelEdit,
15230
15531
  setActiveCommentId,
15231
15532
  updateComments
15232
15533
  ]);
15233
15534
  const handleCommentReply = useCallback((id_2, text_6) => {
15535
+ if (refuseCanonicalModelEdit("Comment changes are unavailable in this session.")) return;
15234
15536
  updateComments((previous_2) => [...previous_2, createComment(text_6, author, id_2)]);
15235
- }, [author, updateComments]);
15537
+ }, [
15538
+ author,
15539
+ createComment,
15540
+ refuseCanonicalModelEdit,
15541
+ updateComments
15542
+ ]);
15236
15543
  const handleAddComment = useCallback((addText) => {
15544
+ if (refuseCanonicalModelEdit("Comment changes are unavailable in this session.")) return false;
15237
15545
  const comment_4 = createComment(addText, author);
15238
15546
  const view_54 = pagedEditorRef.current?.getView();
15239
15547
  if (!view_54 || !commentSelectionRange) return false;
@@ -15259,6 +15567,8 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15259
15567
  }, [
15260
15568
  author,
15261
15569
  commentSelectionRange,
15570
+ createComment,
15571
+ refuseCanonicalModelEdit,
15262
15572
  setActiveCommentId,
15263
15573
  setAddCommentYPosition,
15264
15574
  setCommentSelectionRange,
@@ -15268,8 +15578,14 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15268
15578
  updateComments
15269
15579
  ]);
15270
15580
  const handleTrackedChangeReply = useCallback((revisionId_2, text_7) => {
15581
+ if (refuseCanonicalModelEdit("Comment changes are unavailable in this session.")) return;
15271
15582
  updateComments((previous_4) => [...previous_4, createComment(text_7, author, revisionId_2)]);
15272
- }, [author, updateComments]);
15583
+ }, [
15584
+ author,
15585
+ createComment,
15586
+ refuseCanonicalModelEdit,
15587
+ updateComments
15588
+ ]);
15273
15589
  const handleCancelAddComment = useCallback(() => {
15274
15590
  const view_55 = pagedEditorRef.current?.getView();
15275
15591
  if (view_55 && commentSelectionRange) removePendingCommentMarkRange(view_55, commentSelectionRange);
@@ -15292,7 +15608,9 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15292
15608
  if (!view_56) return;
15293
15609
  const revisionId_3 = resolveSidebarChangeRevisionId(from_17, to_17);
15294
15610
  if (revisionId_3 === null) return;
15295
- acceptAIEditRevision(revisionId_3)(view_56.state, view_56.dispatch);
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);
15296
15614
  extractTrackedChanges();
15297
15615
  }, [extractTrackedChanges, resolveSidebarChangeRevisionId]);
15298
15616
  const handleSidebarRejectChange = useCallback((from_18, to_18) => {
@@ -15300,7 +15618,9 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15300
15618
  if (!view_57) return;
15301
15619
  const revisionId_4 = resolveSidebarChangeRevisionId(from_18, to_18);
15302
15620
  if (revisionId_4 === null) return;
15303
- rejectAIEditRevision(revisionId_4)(view_57.state, view_57.dispatch);
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);
15304
15624
  extractTrackedChanges();
15305
15625
  }, [extractTrackedChanges, resolveSidebarChangeRevisionId]);
15306
15626
  const commentsPageWidth = history.state?.package.document.finalSectionProperties?.pageWidth;
@@ -15619,7 +15939,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15619
15939
  onError: handleEditorError,
15620
15940
  children: /* @__PURE__ */ jsxs("div", {
15621
15941
  ref: containerRef,
15622
- className: `folio-root folio-editor${displayMode !== "all-markup" ? ` folio-root--${displayMode}` : ""}${showHeaderFooterEditing ? "" : " folio-no-hf-edit"} ${className}`,
15942
+ className: `folio-root folio-editor${displayMode !== "all-markup" ? ` folio-root--${displayMode}` : ""}${canEditHeaderFooter ? "" : " folio-no-hf-edit"} ${className}`,
15623
15943
  style: containerStyle,
15624
15944
  "data-testid": "folio-editor",
15625
15945
  "data-folio-format-painter": formatPainterMode !== "off" ? "armed" : void 0,
@@ -15789,9 +16109,9 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15789
16109
  firstPageHeaderContentRId: activeFirstHeaderRId,
15790
16110
  firstPageFooterContentRId: activeFirstFooterRId,
15791
16111
  ...history.state.package.styles ? { styles: history.state.package.styles } : {},
15792
- onHeaderFooterDoubleClick: showHeaderFooterEditing ? handleHeaderFooterStoryOpen : void 0,
15793
- hfEditMode: hfEditPosition,
15794
- activeHeaderFooterRId: activeHfRId,
16112
+ onHeaderFooterDoubleClick: handleHeaderFooterStoryOpen,
16113
+ hfEditMode: canEditHeaderFooter ? hfEditPosition : null,
16114
+ activeHeaderFooterRId: canEditHeaderFooter ? activeHfRId : null,
15795
16115
  onBodyClick: handleBodyClick,
15796
16116
  onActiveNoteStoryChange: handleActiveNoteStoryChange,
15797
16117
  zoom,
@@ -15799,6 +16119,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15799
16119
  showMarginGuides,
15800
16120
  ...marginGuideColor !== void 0 ? { marginGuideColor } : {},
15801
16121
  readOnly,
16122
+ ...experimentalSession === void 0 ? {} : { experimentalSession },
15802
16123
  onDocumentChange: handleDocumentChange,
15803
16124
  extensionManager,
15804
16125
  suggestionModeActive: editingMode === "suggesting",
@@ -15907,7 +16228,7 @@ const DocxEditor = forwardRef(function DocxEditor({ documentBuffer, password, do
15907
16228
  children: /* @__PURE__ */ jsx(SquarePenIcon, { size: 16 })
15908
16229
  })
15909
16230
  }),
15910
- hfEditPosition && (() => {
16231
+ canEditHeaderFooter && hfEditPosition && (() => {
15911
16232
  if (!(() => {
15912
16233
  if (hfEditIsFirstPage) return (() => {
15913
16234
  if (hfEditPosition === "header") return firstPageHeaderContent;