@beyondwork/docx-react-component 1.0.28 → 1.0.30

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 (92) hide show
  1. package/package.json +26 -37
  2. package/src/api/public-types.ts +531 -0
  3. package/src/api/session-state.ts +2 -0
  4. package/src/core/commands/index.ts +201 -79
  5. package/src/core/commands/table-structure-commands.ts +138 -5
  6. package/src/core/state/text-transaction.ts +370 -3
  7. package/src/index.ts +41 -0
  8. package/src/io/docx-session.ts +318 -25
  9. package/src/io/export/serialize-footnotes.ts +41 -46
  10. package/src/io/export/serialize-headers-footers.ts +36 -40
  11. package/src/io/export/serialize-main-document.ts +55 -89
  12. package/src/io/export/serialize-numbering.ts +104 -4
  13. package/src/io/export/serialize-runtime-revisions.ts +196 -2
  14. package/src/io/export/split-story-blocks-for-runtime-revisions.ts +252 -0
  15. package/src/io/export/table-properties-xml.ts +318 -0
  16. package/src/io/normalize/normalize-text.ts +34 -3
  17. package/src/io/ooxml/parse-comments.ts +6 -0
  18. package/src/io/ooxml/parse-footnotes.ts +69 -13
  19. package/src/io/ooxml/parse-headers-footers.ts +54 -11
  20. package/src/io/ooxml/parse-main-document.ts +112 -42
  21. package/src/io/ooxml/parse-numbering.ts +341 -26
  22. package/src/io/ooxml/parse-revisions.ts +118 -4
  23. package/src/io/ooxml/parse-styles.ts +176 -0
  24. package/src/io/ooxml/parse-tables.ts +34 -25
  25. package/src/io/ooxml/revision-boundaries.ts +127 -3
  26. package/src/io/ooxml/workflow-payload.ts +544 -0
  27. package/src/model/canonical-document.ts +91 -1
  28. package/src/model/snapshot.ts +112 -1
  29. package/src/preservation/store.ts +73 -3
  30. package/src/review/store/comment-store.ts +19 -1
  31. package/src/review/store/revision-actions.ts +29 -0
  32. package/src/review/store/revision-store.ts +12 -1
  33. package/src/review/store/revision-types.ts +11 -0
  34. package/src/runtime/context-analytics.ts +824 -0
  35. package/src/runtime/document-locations.ts +521 -0
  36. package/src/runtime/document-navigation.ts +14 -1
  37. package/src/runtime/document-outline.ts +440 -0
  38. package/src/runtime/document-runtime.ts +941 -45
  39. package/src/runtime/event-refresh-hints.ts +137 -0
  40. package/src/runtime/numbering-prefix.ts +67 -39
  41. package/src/runtime/page-layout-estimation.ts +100 -7
  42. package/src/runtime/resolved-numbering-geometry.ts +293 -0
  43. package/src/runtime/session-capabilities.ts +2 -2
  44. package/src/runtime/suggestions-snapshot.ts +137 -0
  45. package/src/runtime/surface-projection.ts +223 -27
  46. package/src/runtime/table-style-resolver.ts +409 -0
  47. package/src/runtime/view-state.ts +17 -1
  48. package/src/runtime/workflow-markup.ts +54 -14
  49. package/src/ui/WordReviewEditor.tsx +1269 -87
  50. package/src/ui/editor-command-bag.ts +7 -0
  51. package/src/ui/editor-runtime-boundary.ts +111 -10
  52. package/src/ui/editor-shell-view.tsx +17 -15
  53. package/src/ui/editor-surface-controller.tsx +5 -0
  54. package/src/ui/headless/selection-tool-context.ts +19 -0
  55. package/src/ui/headless/selection-tool-resolver.ts +752 -0
  56. package/src/ui/headless/selection-tool-types.ts +129 -0
  57. package/src/ui/headless/selection-toolbar-model.ts +10 -33
  58. package/src/ui/runtime-shortcut-dispatch.ts +365 -0
  59. package/src/ui-tailwind/chrome/chrome-preset-model.ts +107 -0
  60. package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +15 -0
  61. package/src/ui-tailwind/chrome/review-queue-bar.tsx +97 -0
  62. package/src/ui-tailwind/chrome/tw-context-analytics-summary.tsx +122 -0
  63. package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +1 -9
  64. package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +1 -5
  65. package/src/ui-tailwind/chrome/tw-page-ruler.tsx +8 -29
  66. package/src/ui-tailwind/chrome/tw-selection-tool-blocked.tsx +23 -0
  67. package/src/ui-tailwind/chrome/tw-selection-tool-comment.tsx +35 -0
  68. package/src/ui-tailwind/chrome/tw-selection-tool-formatting.tsx +37 -0
  69. package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +298 -0
  70. package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +116 -0
  71. package/src/ui-tailwind/chrome/tw-selection-tool-suggestion.tsx +29 -0
  72. package/src/ui-tailwind/chrome/tw-selection-tool-workflow.tsx +27 -0
  73. package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +3 -3
  74. package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +3 -3
  75. package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +86 -14
  76. package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +57 -52
  77. package/src/ui-tailwind/editor-surface/pm-decorations.ts +36 -52
  78. package/src/ui-tailwind/editor-surface/pm-schema.ts +56 -5
  79. package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +87 -24
  80. package/src/ui-tailwind/editor-surface/surface-build-keys.ts +4 -0
  81. package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +135 -32
  82. package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +74 -7
  83. package/src/ui-tailwind/review/tw-comment-sidebar.tsx +17 -17
  84. package/src/ui-tailwind/review/tw-review-rail.tsx +19 -17
  85. package/src/ui-tailwind/review/tw-revision-sidebar.tsx +10 -10
  86. package/src/ui-tailwind/status/tw-status-bar.tsx +10 -6
  87. package/src/ui-tailwind/theme/editor-theme.css +58 -40
  88. package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +4 -4
  89. package/src/ui-tailwind/toolbar/tw-toolbar.tsx +250 -181
  90. package/src/ui-tailwind/tw-review-workspace.tsx +323 -280
  91. package/src/validation/compatibility-engine.ts +246 -2
  92. package/src/validation/docx-comment-proof.ts +24 -11
@@ -37,6 +37,8 @@ export interface EditorCommandBag {
37
37
  onSetTextColor?(color: string): void;
38
38
  onSetHighlightColor?(color: string | null): void;
39
39
  onSetAlignment?(alignment: FormattingAlignment): void;
40
+ onToggleBulletedList?(): void;
41
+ onToggleNumberedList?(): void;
40
42
  onOutdent?(): void;
41
43
  onIndent?(): void;
42
44
  onAddComment(): void;
@@ -98,6 +100,11 @@ export interface EditorCommandBag {
98
100
  ): void;
99
101
  onRestartNumbering?(): void;
100
102
  onContinueNumbering?(): void;
103
+ onUpdateFields?(): void;
104
+ onUpdateTableOfContents?(): void;
105
+ onGoToPreviousReviewItem?(): void;
106
+ onGoToNextReviewItem?(): void;
107
+ onMarkSectionForReview?(): string | null;
101
108
  onNavigateHeading?(headingId: string): void;
102
109
  }
103
110
 
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useMemo, useRef, useState } from "react";
1
+ import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
2
2
 
3
3
  import type {
4
4
  AutosaveState,
@@ -15,6 +15,7 @@ import type {
15
15
  FieldSnapshot,
16
16
  PersistedEditorSnapshot,
17
17
  RuntimeRenderSnapshot,
18
+ SuggestionsSnapshot,
18
19
  TocRefreshResult,
19
20
  UpdateFieldsResult,
20
21
  ViewMode as EditorViewMode,
@@ -30,6 +31,7 @@ import {
30
31
  import { createCanonicalDocumentId } from "../core/state/editor-state.ts";
31
32
  import {
32
33
  createDocumentRuntime,
34
+ type DocumentRuntimeEvent,
33
35
  type DocumentRuntime,
34
36
  } from "../runtime/document-runtime.ts";
35
37
  import { loadDocxEditorSession } from "../io/docx-session.ts";
@@ -80,6 +82,7 @@ export interface WordReviewEditorRuntime extends DocumentRuntime {
80
82
  getFatalError?(): EditorError | undefined;
81
83
  dispose?(): void;
82
84
  setDefaultAuthorId?(authorId?: string): void;
85
+ drainBootstrapEvents?(): DocumentRuntimeEvent[];
83
86
  emitBlockedCommand(
84
87
  command: string,
85
88
  reasons: Extract<WordReviewEditorEvent, { type: "command_blocked" }>["reasons"],
@@ -267,6 +270,7 @@ export function useEditorRuntimeBoundary(
267
270
  const [runtime, setRuntime] = useState<WordReviewEditorRuntime | null>(null);
268
271
  const [loadError, setLoadError] = useState<EditorError | null>(null);
269
272
  const runtimeRef = useRef<WordReviewEditorRuntime | null>(null);
273
+ const pendingReadySourceRef = useRef<"docx" | "session" | "snapshot" | null>(null);
270
274
  const autosaveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
271
275
  const lastSavedRevisionTokenRef = useRef<string | null>(null);
272
276
  const hostAdapterRef = useRef(hostAdapter);
@@ -274,6 +278,7 @@ export function useEditorRuntimeBoundary(
274
278
  const onEventRef = useRef(onEvent);
275
279
  const onWarningRef = useRef(onWarning);
276
280
  const onErrorRef = useRef(onError);
281
+ const currentUserIdRef = useRef(currentUser.userId);
277
282
  const runtimeViewStateSeedRef = useRef<{
278
283
  workspaceMode: WorkspaceMode;
279
284
  zoomLevel: ZoomLevel;
@@ -299,6 +304,8 @@ export function useEditorRuntimeBoundary(
299
304
  };
300
305
  }
301
306
 
307
+ currentUserIdRef.current = currentUser.userId;
308
+
302
309
  const stableInitialSource = initialSourceRef.current;
303
310
  const sourceReloadKey = externalDocSource
304
311
  ? `external:${externalDocSource.kind}:${externalDocumentRevision ?? "static"}`
@@ -320,7 +327,7 @@ export function useEditorRuntimeBoundary(
320
327
  onErrorRef.current = onError;
321
328
  }, [datastore, hostAdapter, onError, onEvent, onWarning]);
322
329
 
323
- useEffect(() => {
330
+ useLayoutEffect(() => {
324
331
  runtimeRef.current?.setDefaultAuthorId?.(currentUser.userId);
325
332
  }, [currentUser.userId]);
326
333
 
@@ -329,6 +336,15 @@ export function useEditorRuntimeBoundary(
329
336
 
330
337
  async function loadRuntime(): Promise<void> {
331
338
  setLoadError(null);
339
+ pendingReadySourceRef.current = null;
340
+ if (autosaveTimerRef.current) {
341
+ clearTimeout(autosaveTimerRef.current);
342
+ autosaveTimerRef.current = null;
343
+ }
344
+ lastSavedRevisionTokenRef.current = null;
345
+ runtimeRef.current?.dispose?.();
346
+ runtimeRef.current = null;
347
+ setRuntime(null);
332
348
 
333
349
  try {
334
350
  const source = await __resolveWordReviewEditorSource({
@@ -348,7 +364,6 @@ export function useEditorRuntimeBoundary(
348
364
  return;
349
365
  }
350
366
 
351
- runtimeRef.current?.dispose?.();
352
367
  const nextRuntime = createRuntime(
353
368
  {
354
369
  documentId,
@@ -357,7 +372,7 @@ export function useEditorRuntimeBoundary(
357
372
  initialViewState: runtimeViewStateSeedRef.current,
358
373
  hostAdapter: hostAdapterRef.current,
359
374
  datastore: datastoreRef.current,
360
- currentUserId: currentUser.userId,
375
+ currentUserId: currentUserIdRef.current,
361
376
  },
362
377
  {
363
378
  onWarning: onWarningRef.current,
@@ -366,13 +381,8 @@ export function useEditorRuntimeBoundary(
366
381
  },
367
382
  );
368
383
  recordPerfSample("runtime.create");
369
- emitEditorEvent({
370
- hostAdapter: hostAdapterRef.current,
371
- datastore: datastoreRef.current,
372
- onEvent: onEventRef.current,
373
- event: createReadyEvent(nextRuntime, source.source),
374
- });
375
384
  runtimeRef.current = nextRuntime;
385
+ pendingReadySourceRef.current = source.source;
376
386
  setRuntime(nextRuntime);
377
387
  } catch (error) {
378
388
  if (cancelled) {
@@ -406,6 +416,32 @@ export function useEditorRuntimeBoundary(
406
416
  sourceReloadKey,
407
417
  ]);
408
418
 
419
+ useEffect(() => {
420
+ if (!runtime || !pendingReadySourceRef.current) {
421
+ return;
422
+ }
423
+
424
+ emitEditorEvent({
425
+ hostAdapter: hostAdapterRef.current,
426
+ datastore: datastoreRef.current,
427
+ onEvent: onEventRef.current,
428
+ event: createReadyEvent(runtime, pendingReadySourceRef.current),
429
+ });
430
+ for (const event of runtime.drainBootstrapEvents?.() ?? []) {
431
+ if (event.type === "ready") {
432
+ continue;
433
+ }
434
+ const hostEvent = event as Exclude<WordReviewEditorEvent, { type: "ready" }>;
435
+ emitEditorEvent({
436
+ hostAdapter: hostAdapterRef.current,
437
+ datastore: datastoreRef.current,
438
+ onEvent: onEventRef.current,
439
+ event: hostEvent,
440
+ });
441
+ }
442
+ pendingReadySourceRef.current = null;
443
+ }, [runtime]);
444
+
409
445
  useEffect(() => {
410
446
  if (!runtime?.subscribeToEvents) {
411
447
  return;
@@ -518,6 +554,7 @@ function createRuntime(
518
554
  args: CreateRuntimeArgs,
519
555
  handlers: RuntimeLifecycleHandlers = {},
520
556
  ): WordReviewEditorRuntime {
557
+ const bootstrapEvents: DocumentRuntimeEvent[] = [];
521
558
  const docxSession = args.source.initialDocx
522
559
  ? loadDocxEditorSession({
523
560
  documentId: args.documentId,
@@ -574,8 +611,12 @@ function createRuntime(
574
611
  },
575
612
  onWarning: handlers.onWarning,
576
613
  onError: handlers.onError,
614
+ onEvent: (event) => {
615
+ bootstrapEvents.push(event);
616
+ },
577
617
  defaultAuthorId: args.currentUserId,
578
618
  }), {
619
+ drainBootstrapEvents: () => bootstrapEvents.splice(0, bootstrapEvents.length),
579
620
  emitBlockedCommand: (
580
621
  command: string,
581
622
  reasons: Extract<WordReviewEditorEvent, { type: "command_blocked" }>["reasons"],
@@ -712,6 +753,16 @@ function createLoadingRuntimeBridge(input: {
712
753
  entryCount: 0,
713
754
  entries: [],
714
755
  };
756
+ const emptySuggestions: SuggestionsSnapshot = {
757
+ totalCount: 0,
758
+ actionableSuggestionIds: [],
759
+ preserveOnlySuggestionIds: [],
760
+ activeSuggestionIds: [],
761
+ acceptedSuggestionIds: [],
762
+ rejectedSuggestionIds: [],
763
+ detachedSuggestionIds: [],
764
+ suggestions: [],
765
+ };
715
766
 
716
767
  return {
717
768
  subscribe: () => () => undefined,
@@ -750,6 +801,25 @@ function createLoadingRuntimeBridge(input: {
750
801
  setZoom: () => undefined,
751
802
  getPageLayoutSnapshot: () => null,
752
803
  getDocumentNavigationSnapshot: () => input.navigation,
804
+ getCurrentLocation: () => null,
805
+ getLocationForSelection: () => null,
806
+ getLocationForAnchor: () => null,
807
+ captureRestorePoint: () => null,
808
+ restoreToPoint: () => ({
809
+ status: "detached",
810
+ reasons: ["loading"],
811
+ }),
812
+ getOutlineSnapshot: () => ({
813
+ headings: [],
814
+ }),
815
+ getTocSnapshot: () => null,
816
+ getSections: () => [],
817
+ getSectionSnapshot: () => null,
818
+ describeEventImpact: () => ({
819
+ invalidate: ["render"],
820
+ staleTargets: ["none"],
821
+ changeKinds: ["content"],
822
+ }),
753
823
  getFieldSnapshot: () => emptyFieldSnapshot,
754
824
  updateFields: () => emptyFieldResult,
755
825
  updateTableOfContents: () => emptyTocResult,
@@ -768,6 +838,7 @@ function createLoadingRuntimeBridge(input: {
768
838
  errors: input.snapshot.fatalError ? [input.snapshot.fatalError] : [],
769
839
  }),
770
840
  getWarnings: () => input.snapshot.warnings,
841
+ getSuggestionsSnapshot: () => emptySuggestions,
771
842
  exportDocx: () =>
772
843
  Promise.reject(createLoadingBoundaryError(input.snapshot.documentId, "export")),
773
844
  setWorkflowOverlay: () => undefined,
@@ -778,12 +849,21 @@ function createLoadingRuntimeBridge(input: {
778
849
  totalCount: 0,
779
850
  items: [],
780
851
  highlights: [],
852
+ metadata: [],
781
853
  comments: [],
782
854
  revisions: [],
783
855
  fields: [],
784
856
  protectedRanges: [],
785
857
  opaqueFragments: [],
786
858
  }),
859
+ setWorkflowMetadataDefinitions: () => undefined,
860
+ clearWorkflowMetadataDefinitions: () => undefined,
861
+ setWorkflowMetadataEntries: () => undefined,
862
+ clearWorkflowMetadataEntries: () => undefined,
863
+ getWorkflowMetadataSnapshot: () => ({
864
+ definitions: [],
865
+ entries: [],
866
+ }),
787
867
  setHostAnnotationOverlay: () => undefined,
788
868
  clearHostAnnotationOverlay: () => undefined,
789
869
  getHostAnnotationSnapshot: () => ({
@@ -792,6 +872,16 @@ function createLoadingRuntimeBridge(input: {
792
872
  }),
793
873
  getWorkflowCandidateRanges: () => [],
794
874
  replaceWorkflowMarkupText: () => undefined,
875
+ getDocumentTextStream: () => [],
876
+ getStoryTextStream: () => null,
877
+ getDocumentChunks: () => [],
878
+ getWorkflowChunks: () => [],
879
+ getReviewWorkSnapshot: () => ({
880
+ openCommentCount: 0,
881
+ actionableRevisionCount: 0,
882
+ items: [],
883
+ }),
884
+ getRuntimeContextAnalytics: () => null,
795
885
  };
796
886
  }
797
887
 
@@ -851,6 +941,10 @@ export async function persistAndExport(input: {
851
941
  input.autosaveTimerRef.current = null;
852
942
  }
853
943
 
944
+ const revisionToken = input.runtime.getRenderSnapshot().revisionToken;
945
+ const previousSavedRevisionToken = input.lastSavedRevisionTokenRef.current;
946
+ input.lastSavedRevisionTokenRef.current = revisionToken;
947
+
854
948
  await persistSession({
855
949
  hostAdapter: input.hostAdapter,
856
950
  datastore: input.datastore,
@@ -860,6 +954,9 @@ export async function persistAndExport(input: {
860
954
  onError: input.onError,
861
955
  onEvent: input.onEvent,
862
956
  lastSavedRevisionTokenRef: input.lastSavedRevisionTokenRef,
957
+ }).catch((error) => {
958
+ input.lastSavedRevisionTokenRef.current = previousSavedRevisionToken;
959
+ throw error;
863
960
  });
864
961
 
865
962
  let result: ExportResult;
@@ -993,6 +1090,10 @@ export async function persistSession(input: {
993
1090
  const snapshot = input.runtime.getPersistedSnapshot();
994
1091
  const revisionToken = input.runtime.getRenderSnapshot().revisionToken;
995
1092
 
1093
+ if (input.isAutosave && input.lastSavedRevisionTokenRef.current === revisionToken) {
1094
+ return;
1095
+ }
1096
+
996
1097
  if (input.isAutosave) {
997
1098
  emitEditorEvent({
998
1099
  hostAdapter: input.hostAdapter,
@@ -1,12 +1,17 @@
1
1
  import React, { type CSSProperties, type ReactNode } from "react";
2
2
 
3
3
  import type {
4
+ ActiveListContext,
4
5
  DocumentNavigationSnapshot,
5
6
  EditorError,
6
7
  FormattingStateSnapshot,
7
8
  InteractionGuardSnapshot,
9
+ ReviewQueueSnapshot,
10
+ RuntimeContextAnalyticsSnapshot,
8
11
  RuntimeRenderSnapshot,
9
12
  StyleCatalogSnapshot,
13
+ WordReviewEditorChromeOptions,
14
+ WordReviewEditorChromePreset,
10
15
  WordReviewEditorChromeVisibility,
11
16
  WorkflowScopeSnapshot,
12
17
  WorkspaceMode,
@@ -15,19 +20,12 @@ import type {
15
20
  import type { SessionCapabilities } from "../runtime/session-capabilities.ts";
16
21
  import type { MarkupDisplay } from "./headless/comment-decoration-model.ts";
17
22
  import type {
18
- SelectionToolbarAnchor,
19
- SelectionToolbarModel,
20
- SuggestionCardModel,
21
- } from "./headless/selection-toolbar-model.ts";
23
+ ActiveSelectionToolModel,
24
+ SelectionToolAnchor,
25
+ } from "./headless/selection-tool-types.ts";
22
26
  import type { EditorCommandBag } from "./editor-command-bag.ts";
23
27
  import type { ReviewRailTab } from "../ui-tailwind/review/tw-review-rail.tsx";
24
28
  import { TwReviewWorkspace } from "../ui-tailwind/tw-review-workspace.tsx";
25
- import type {
26
- ActiveImageContext,
27
- } from "../ui-tailwind/chrome/tw-image-context-toolbar.tsx";
28
- import type {
29
- ActiveObjectContext,
30
- } from "../ui-tailwind/chrome/tw-object-context-toolbar.tsx";
31
29
  import type { EditorViewStateSnapshot } from "../api/public-types.ts";
32
30
 
33
31
  export interface EditorShellViewProps {
@@ -50,6 +48,7 @@ export interface EditorShellViewProps {
50
48
  workspaceMode: WorkspaceMode;
51
49
  zoomLevel?: ZoomLevel;
52
50
  formattingState?: FormattingStateSnapshot;
51
+ activeListContext?: ActiveListContext | null;
53
52
  styleCatalog?: StyleCatalogSnapshot;
54
53
  activeRailTab: ReviewRailTab;
55
54
  activeCommentId?: string;
@@ -57,9 +56,14 @@ export interface EditorShellViewProps {
57
56
  showTrackedChanges: boolean;
58
57
  workflowScopeSnapshot?: WorkflowScopeSnapshot | null;
59
58
  interactionGuardSnapshot?: InteractionGuardSnapshot;
60
- selectionToolbar?: SelectionToolbarModel | null;
61
- suggestionCard?: SuggestionCardModel | null;
62
- selectionToolbarAnchor?: SelectionToolbarAnchor | null;
59
+ chromePreset?: WordReviewEditorChromePreset;
60
+ chromeOptions?: Partial<WordReviewEditorChromeOptions>;
61
+ reviewQueue?: ReviewQueueSnapshot;
62
+ documentContextAnalytics?: RuntimeContextAnalyticsSnapshot | null;
63
+ selectionContextAnalytics?: RuntimeContextAnalyticsSnapshot | null;
64
+ currentScopeContextAnalytics?: RuntimeContextAnalyticsSnapshot | null;
65
+ activeSelectionTool?: ActiveSelectionToolModel | null;
66
+ selectionToolAnchor?: SelectionToolAnchor | null;
63
67
  documentNavigation?: DocumentNavigationSnapshot;
64
68
  commands: EditorCommandBag;
65
69
  document: ReactNode;
@@ -72,8 +76,6 @@ export interface EditorShellViewProps {
72
76
  onSelectionToolbarFocusCapture?: React.FocusEventHandler<HTMLDivElement>;
73
77
  onSelectionToolbarBlurCapture?: React.FocusEventHandler<HTMLDivElement>;
74
78
  selectionToolbarRef?: React.Ref<HTMLDivElement>;
75
- activeImageContext?: ActiveImageContext | null;
76
- activeObjectContext?: ActiveObjectContext | null;
77
79
  chromeVisibility?: Partial<WordReviewEditorChromeVisibility>;
78
80
  }
79
81
 
@@ -7,11 +7,13 @@ import type {
7
7
  SelectionSnapshot,
8
8
  WorkflowBlockedCommandReason,
9
9
  WorkflowCandidateRange,
10
+ WorkflowMetadataMarkup,
10
11
  WorkflowScope,
11
12
  } from "../api/public-types.ts";
12
13
  import type { CanonicalDocumentEnvelope } from "../core/state/editor-state.ts";
13
14
  import type { MarkupDisplay } from "./headless/comment-decoration-model.ts";
14
15
  import type { SelectionToolbarAnchor } from "./headless/selection-toolbar-model.ts";
16
+ import type { ActiveSelectionToolModel } from "./headless/selection-tool-types.ts";
15
17
  import {
16
18
  TwProseMirrorSurface,
17
19
  type TwProseMirrorSurfaceRef,
@@ -25,7 +27,9 @@ export interface EditorSurfaceControllerProps {
25
27
  documentNavigation: DocumentNavigationSnapshot;
26
28
  reviewMode: "editing" | "review";
27
29
  markupDisplay: MarkupDisplay;
30
+ showUnsupportedObjectPreviews?: boolean;
28
31
  activeRevisionId?: string;
32
+ activeSelectionToolKind?: ActiveSelectionToolModel["kind"] | null;
29
33
  showTrackedChanges?: boolean;
30
34
  suggestionsEnabled?: boolean;
31
35
  mediaPreviews?: Record<string, MediaPreviewDescriptor>;
@@ -51,6 +55,7 @@ export interface EditorSurfaceControllerProps {
51
55
  workflowBlockedReasons?: readonly WorkflowBlockedCommandReason[];
52
56
  activeWorkflowWorkItemId?: string | null;
53
57
  activeWorkflowScopeIds?: readonly string[];
58
+ workflowMetadata?: readonly WorkflowMetadataMarkup[];
54
59
  }
55
60
 
56
61
  export const EditorSurfaceController = forwardRef<
@@ -0,0 +1,19 @@
1
+ import type {
2
+ DocumentNavigationSnapshot,
3
+ EditorViewStateSnapshot,
4
+ RuntimeRenderSnapshot,
5
+ StyleCatalogSnapshot,
6
+ } from "../../api/public-types";
7
+ import type { SessionCapabilities } from "../../runtime/session-capabilities";
8
+ import type { SelectionToolResolverContext } from "./selection-tool-types";
9
+
10
+ export interface SelectionToolResolverInput extends SelectionToolResolverContext {
11
+ snapshot: RuntimeRenderSnapshot;
12
+ viewState: EditorViewStateSnapshot;
13
+ capabilities: SessionCapabilities;
14
+ documentNavigation: DocumentNavigationSnapshot;
15
+ styleCatalog: StyleCatalogSnapshot;
16
+ preferListStructureContext?: boolean;
17
+ addCommentDisabledReason?: string;
18
+ suppressedSuggestionRevisionId?: string | null;
19
+ }