@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
@@ -0,0 +1,129 @@
1
+ import type {
2
+ ActiveListContext,
3
+ CommentSidebarThreadSnapshot,
4
+ FormattingStateSnapshot,
5
+ InteractionGuardSnapshot,
6
+ StyleCatalogSnapshot,
7
+ TableStructureContextSnapshot,
8
+ SuggestionsSnapshot,
9
+ TrackedChangeEntrySnapshot,
10
+ WorkflowMarkupSnapshot,
11
+ WorkflowScopeSnapshot,
12
+ } from "../../api/public-types";
13
+
14
+ export interface SelectionToolBadge {
15
+ label: string;
16
+ tone?: "neutral" | "accent";
17
+ }
18
+
19
+ export interface SelectionToolAnchor {
20
+ left: number;
21
+ right: number;
22
+ top: number;
23
+ bottom: number;
24
+ }
25
+
26
+ export interface ActiveImageContext {
27
+ mediaId: string;
28
+ display: "inline" | "floating";
29
+ widthEmu?: number;
30
+ heightEmu?: number;
31
+ horizontalOffsetEmu?: number;
32
+ verticalOffsetEmu?: number;
33
+ }
34
+
35
+ export interface ActiveObjectContext {
36
+ kind: "textbox" | "shape";
37
+ display: "inline" | "floating";
38
+ }
39
+
40
+ export type SelectionToolKind =
41
+ | "formatting-inline"
42
+ | "suggestion-review"
43
+ | "comment-thread"
44
+ | "workflow-task"
45
+ | "structure-context"
46
+ | "blocked-explainer";
47
+
48
+ export interface BaseSelectionToolModel {
49
+ kind: SelectionToolKind;
50
+ badges: SelectionToolBadge[];
51
+ previewText?: string;
52
+ disabledReason?: string;
53
+ }
54
+
55
+ export interface FormattingInlineSelectionToolModel extends BaseSelectionToolModel {
56
+ kind: "formatting-inline";
57
+ previewText: string;
58
+ canToggleFormatting: boolean;
59
+ boldActive: boolean;
60
+ italicActive: boolean;
61
+ underlineActive: boolean;
62
+ canAddComment: boolean;
63
+ }
64
+
65
+ export interface SuggestionReviewSelectionToolModel extends BaseSelectionToolModel {
66
+ kind: "suggestion-review";
67
+ suggestionId: string;
68
+ changeIds: string[];
69
+ kindLabel: string;
70
+ previewText: string;
71
+ canAccept: boolean;
72
+ canReject: boolean;
73
+ canEditSuggestion: boolean;
74
+ canAddComment: boolean;
75
+ }
76
+
77
+ export type StructureContextKind = "table" | "image" | "object" | "list";
78
+
79
+ export interface StructureContextSelectionToolModel extends BaseSelectionToolModel {
80
+ kind: "structure-context";
81
+ structureKind: StructureContextKind;
82
+ tableStyles?: StyleCatalogSnapshot["tables"];
83
+ activeTable?: TableStructureContextSnapshot | null;
84
+ activeImage?: ActiveImageContext;
85
+ activeObject?: ActiveObjectContext;
86
+ activeListContext?: ActiveListContext | null;
87
+ canMutate: boolean;
88
+ }
89
+
90
+ export interface WorkflowTaskSelectionToolModel extends BaseSelectionToolModel {
91
+ kind: "workflow-task";
92
+ workflowTitle?: string;
93
+ workflowDetail?: string;
94
+ }
95
+
96
+ export interface CommentThreadSelectionToolModel extends BaseSelectionToolModel {
97
+ kind: "comment-thread";
98
+ thread?: CommentSidebarThreadSnapshot;
99
+ canAddComment: boolean;
100
+ }
101
+
102
+ export interface BlockedExplainerSelectionToolModel extends BaseSelectionToolModel {
103
+ kind: "blocked-explainer";
104
+ disabledReason: string;
105
+ }
106
+
107
+ export type ActiveSelectionToolModel =
108
+ | FormattingInlineSelectionToolModel
109
+ | SuggestionReviewSelectionToolModel
110
+ | CommentThreadSelectionToolModel
111
+ | WorkflowTaskSelectionToolModel
112
+ | StructureContextSelectionToolModel
113
+ | BlockedExplainerSelectionToolModel;
114
+
115
+ export interface SelectionToolResolverContext {
116
+ workflowScopeSnapshot?: WorkflowScopeSnapshot | null;
117
+ interactionGuardSnapshot?: InteractionGuardSnapshot;
118
+ workflowMarkupSnapshot?: WorkflowMarkupSnapshot;
119
+ suggestionsSnapshot?: SuggestionsSnapshot;
120
+ activeRevisionId?: string;
121
+ activeCommentId?: string;
122
+ activeCommentThread?: CommentSidebarThreadSnapshot;
123
+ activeTableContext?: TableStructureContextSnapshot | null;
124
+ activeImageContext?: ActiveImageContext | null;
125
+ activeObjectContext?: ActiveObjectContext | null;
126
+ activeListContext?: ActiveListContext | null;
127
+ selectedRevision?: TrackedChangeEntrySnapshot;
128
+ formattingState?: FormattingStateSnapshot;
129
+ }
@@ -1,34 +1,11 @@
1
- export interface SelectionToolbarBadge {
2
- label: string;
3
- tone?: "neutral" | "accent";
4
- }
1
+ import type {
2
+ FormattingInlineSelectionToolModel,
3
+ SelectionToolAnchor,
4
+ SelectionToolBadge,
5
+ SuggestionReviewSelectionToolModel,
6
+ } from "./selection-tool-types";
5
7
 
6
- export interface SelectionToolbarModel {
7
- previewText: string;
8
- badges: SelectionToolbarBadge[];
9
- canToggleFormatting: boolean;
10
- boldActive: boolean;
11
- italicActive: boolean;
12
- underlineActive: boolean;
13
- canAddComment: boolean;
14
- disabledReason?: string;
15
- }
16
-
17
- export interface SuggestionCardModel {
18
- revisionId: string;
19
- kindLabel: string;
20
- previewText: string;
21
- badges: SelectionToolbarBadge[];
22
- canAccept: boolean;
23
- canReject: boolean;
24
- canEditSuggestion: boolean;
25
- canAddComment: boolean;
26
- disabledReason?: string;
27
- }
28
-
29
- export interface SelectionToolbarAnchor {
30
- left: number;
31
- right: number;
32
- top: number;
33
- bottom: number;
34
- }
8
+ export type SelectionToolbarBadge = SelectionToolBadge;
9
+ export type SelectionToolbarAnchor = SelectionToolAnchor;
10
+ export type SelectionToolbarModel = FormattingInlineSelectionToolModel;
11
+ export type SuggestionCardModel = SuggestionReviewSelectionToolModel;
@@ -0,0 +1,365 @@
1
+ import type {
2
+ StyleCatalogSnapshot,
3
+ WorkflowBlockedCommandReason,
4
+ } from "../api/public-types.ts";
5
+
6
+ export interface ShortcutKeyInput {
7
+ key: string;
8
+ ctrlKey?: boolean;
9
+ metaKey?: boolean;
10
+ altKey?: boolean;
11
+ shiftKey?: boolean;
12
+ }
13
+
14
+ export interface ShellShortcutContext {
15
+ target: "document" | "selection-toolbar" | "shell";
16
+ selectionToolbarVisible: boolean;
17
+ }
18
+
19
+ export interface SurfaceShortcutContext {
20
+ inTable: boolean;
21
+ }
22
+
23
+ export type ShellShortcutResolution =
24
+ | { kind: "none" }
25
+ | { kind: "delegate"; shortcut: "find" | "print" | "zoom-in" | "zoom-out" | "zoom-reset" }
26
+ | { kind: "block"; command: string; reason: WorkflowBlockedCommandReason }
27
+ | { kind: "history"; history: "undo" | "redo" }
28
+ | { kind: "focus-region"; direction: 1 | -1 }
29
+ | { kind: "dismiss-selection-toolbar" }
30
+ | { kind: "toggle-formatting"; mark: "bold" | "italic" | "underline" }
31
+ | { kind: "add-comment" }
32
+ | { kind: "set-heading-level"; level: 1 | 2 | 3 };
33
+
34
+ export type SurfaceShortcutResolution =
35
+ | { kind: "none" }
36
+ | { kind: "delete-backward" }
37
+ | { kind: "delete-forward" }
38
+ | { kind: "split-paragraph" }
39
+ | { kind: "insert-hard-break" }
40
+ | { kind: "insert-tab" }
41
+ | { kind: "outdent-tab" }
42
+ | { kind: "navigate-table-cell"; direction: 1 | -1 }
43
+ | { kind: "history"; history: "undo" | "redo" };
44
+
45
+ export function resolveShellShortcut(
46
+ input: ShortcutKeyInput,
47
+ context: ShellShortcutContext,
48
+ ): ShellShortcutResolution {
49
+ const key = normalizeKey(input.key);
50
+ const editorTarget = context.target === "document" || context.target === "selection-toolbar";
51
+
52
+ if (key === "f6") {
53
+ return { kind: "focus-region", direction: input.shiftKey ? -1 : 1 };
54
+ }
55
+
56
+ if (
57
+ key === "escape" &&
58
+ context.selectionToolbarVisible &&
59
+ editorTarget
60
+ ) {
61
+ return { kind: "dismiss-selection-toolbar" };
62
+ }
63
+
64
+ if (!editorTarget) {
65
+ return { kind: "none" };
66
+ }
67
+
68
+ if (isUndoShortcut(input, key)) {
69
+ return { kind: "history", history: "undo" };
70
+ }
71
+
72
+ if (isRedoShortcut(input, key)) {
73
+ return { kind: "history", history: "redo" };
74
+ }
75
+
76
+ if (isModShortcut(input, key, "b")) {
77
+ return { kind: "toggle-formatting", mark: "bold" };
78
+ }
79
+
80
+ if (isModShortcut(input, key, "i")) {
81
+ return { kind: "toggle-formatting", mark: "italic" };
82
+ }
83
+
84
+ if (isModShortcut(input, key, "u")) {
85
+ return { kind: "toggle-formatting", mark: "underline" };
86
+ }
87
+
88
+ if (isWindowsCommentShortcut(input, key) || isMacCommentShortcut(input, key)) {
89
+ return { kind: "add-comment" };
90
+ }
91
+
92
+ if (isWindowsHeadingShortcut(input, key) || isMacHeadingShortcut(input, key)) {
93
+ return { kind: "set-heading-level", level: Number.parseInt(key, 10) as 1 | 2 | 3 };
94
+ }
95
+
96
+ if (isModShortcut(input, key, "f")) {
97
+ return { kind: "delegate", shortcut: "find" };
98
+ }
99
+
100
+ if (isModShortcut(input, key, "p")) {
101
+ return { kind: "delegate", shortcut: "print" };
102
+ }
103
+
104
+ if (isZoomInShortcut(input, key)) {
105
+ return { kind: "delegate", shortcut: "zoom-in" };
106
+ }
107
+
108
+ if (isZoomOutShortcut(input, key)) {
109
+ return { kind: "delegate", shortcut: "zoom-out" };
110
+ }
111
+
112
+ if (isModShortcut(input, key, "0")) {
113
+ return { kind: "delegate", shortcut: "zoom-reset" };
114
+ }
115
+
116
+ if (isPasteTextOnlyShortcut(input, key)) {
117
+ return {
118
+ kind: "block",
119
+ command: "pasteTextOnly",
120
+ reason: createUnsupportedShortcutReason(
121
+ "Plain-text paste is not supported in the mounted editor yet.",
122
+ ),
123
+ };
124
+ }
125
+
126
+ if (isReplaceShortcut(input, key)) {
127
+ return {
128
+ kind: "block",
129
+ command: "replaceText",
130
+ reason: createUnsupportedShortcutReason(
131
+ "Replace shortcuts are not supported in the mounted editor yet.",
132
+ ),
133
+ };
134
+ }
135
+
136
+ if (
137
+ isGoToShortcut(input, key) ||
138
+ (key === "f5" && !input.shiftKey)
139
+ ) {
140
+ return {
141
+ kind: "block",
142
+ command: "goTo",
143
+ reason: createUnsupportedShortcutReason(
144
+ "Go To shortcuts are not supported in the mounted editor yet.",
145
+ ),
146
+ };
147
+ }
148
+
149
+ if (isModShiftShortcut(input, key, "e")) {
150
+ return {
151
+ kind: "block",
152
+ command: "toggleTrackChanges",
153
+ reason: createUnsupportedShortcutReason(
154
+ "Track changes authoring shortcuts are not supported in the mounted editor.",
155
+ ),
156
+ };
157
+ }
158
+
159
+ if (key === "f7" && !input.shiftKey) {
160
+ return {
161
+ kind: "block",
162
+ command: "checkSpelling",
163
+ reason: createUnsupportedShortcutReason(
164
+ "Spelling shortcuts are not supported in the mounted editor.",
165
+ ),
166
+ };
167
+ }
168
+
169
+ if (key === "f7" && input.shiftKey) {
170
+ return {
171
+ kind: "block",
172
+ command: "openThesaurus",
173
+ reason: createUnsupportedShortcutReason(
174
+ "Thesaurus shortcuts are not supported in the mounted editor.",
175
+ ),
176
+ };
177
+ }
178
+
179
+ if (key === "f8") {
180
+ return {
181
+ kind: "block",
182
+ command: "extendSelection",
183
+ reason: createUnsupportedShortcutReason(
184
+ "Extend-selection shortcuts are not supported in the mounted editor.",
185
+ ),
186
+ };
187
+ }
188
+
189
+ if (key === "f5" && input.shiftKey) {
190
+ return {
191
+ kind: "block",
192
+ command: "lastEdit",
193
+ reason: createUnsupportedShortcutReason(
194
+ "Last-edit shortcuts are not supported in the mounted editor.",
195
+ ),
196
+ };
197
+ }
198
+
199
+ return { kind: "none" };
200
+ }
201
+
202
+ export function resolveSurfaceShortcut(
203
+ input: ShortcutKeyInput,
204
+ context: SurfaceShortcutContext,
205
+ ): SurfaceShortcutResolution {
206
+ const key = normalizeKey(input.key);
207
+
208
+ if (isUndoShortcut(input, key)) {
209
+ return { kind: "history", history: "undo" };
210
+ }
211
+
212
+ if (isRedoShortcut(input, key)) {
213
+ return { kind: "history", history: "redo" };
214
+ }
215
+
216
+ if (key === "backspace" && !hasAnyModifiers(input)) {
217
+ return { kind: "delete-backward" };
218
+ }
219
+
220
+ if (key === "delete" && !hasAnyModifiers(input)) {
221
+ return { kind: "delete-forward" };
222
+ }
223
+
224
+ if (key === "enter" && input.shiftKey && !input.ctrlKey && !input.metaKey && !input.altKey) {
225
+ return { kind: "insert-hard-break" };
226
+ }
227
+
228
+ if (key === "enter" && !hasAnyModifiers(input)) {
229
+ return { kind: "split-paragraph" };
230
+ }
231
+
232
+ if (key === "tab" && input.shiftKey && !input.ctrlKey && !input.metaKey && !input.altKey) {
233
+ return context.inTable
234
+ ? { kind: "navigate-table-cell", direction: -1 }
235
+ : { kind: "outdent-tab" };
236
+ }
237
+
238
+ if (key === "tab" && !hasAnyModifiers(input)) {
239
+ return context.inTable
240
+ ? { kind: "navigate-table-cell", direction: 1 }
241
+ : { kind: "insert-tab" };
242
+ }
243
+
244
+ return { kind: "none" };
245
+ }
246
+
247
+ export function resolveHeadingShortcutStyleId(
248
+ styleCatalog: StyleCatalogSnapshot,
249
+ level: 1 | 2 | 3,
250
+ ): string | null {
251
+ const headingToken = `heading${level}`;
252
+ for (const entry of styleCatalog.paragraphs) {
253
+ if (normalizeStyleToken(entry.styleId) === headingToken) {
254
+ return entry.styleId;
255
+ }
256
+ }
257
+ for (const entry of styleCatalog.paragraphs) {
258
+ if (normalizeStyleToken(entry.displayName) === headingToken) {
259
+ return entry.styleId;
260
+ }
261
+ }
262
+ return null;
263
+ }
264
+
265
+ function createUnsupportedShortcutReason(message: string): WorkflowBlockedCommandReason {
266
+ return {
267
+ code: "unsupported_surface",
268
+ message,
269
+ };
270
+ }
271
+
272
+ function normalizeKey(key: string): string {
273
+ return key.toLowerCase();
274
+ }
275
+
276
+ function normalizeStyleToken(value: string): string {
277
+ return value.toLowerCase().replace(/[^a-z0-9]/g, "");
278
+ }
279
+
280
+ function hasAnyModifiers(input: ShortcutKeyInput): boolean {
281
+ return Boolean(input.ctrlKey || input.metaKey || input.altKey || input.shiftKey);
282
+ }
283
+
284
+ function isModShortcut(input: ShortcutKeyInput, key: string, expectedKey: string): boolean {
285
+ return (
286
+ key === expectedKey &&
287
+ Boolean(input.ctrlKey || input.metaKey) &&
288
+ !input.altKey &&
289
+ !input.shiftKey
290
+ );
291
+ }
292
+
293
+ function isModShiftShortcut(input: ShortcutKeyInput, key: string, expectedKey: string): boolean {
294
+ return (
295
+ key === expectedKey &&
296
+ Boolean(input.ctrlKey || input.metaKey) &&
297
+ !input.altKey &&
298
+ Boolean(input.shiftKey)
299
+ );
300
+ }
301
+
302
+ function isUndoShortcut(input: ShortcutKeyInput, key: string): boolean {
303
+ return isModShortcut(input, key, "z");
304
+ }
305
+
306
+ function isRedoShortcut(input: ShortcutKeyInput, key: string): boolean {
307
+ return (
308
+ (isModShiftShortcut(input, key, "z")) ||
309
+ (key === "y" && Boolean(input.ctrlKey || input.metaKey) && !input.altKey && !input.shiftKey)
310
+ );
311
+ }
312
+
313
+ function isReplaceShortcut(input: ShortcutKeyInput, key: string): boolean {
314
+ return key === "h" && Boolean(input.ctrlKey) && !input.metaKey && !input.altKey && !input.shiftKey;
315
+ }
316
+
317
+ function isGoToShortcut(input: ShortcutKeyInput, key: string): boolean {
318
+ return (
319
+ (key === "g" && Boolean(input.ctrlKey) && !input.metaKey && !input.altKey && !input.shiftKey) ||
320
+ (key === "g" && Boolean(input.metaKey) && !input.ctrlKey && Boolean(input.altKey) && !input.shiftKey)
321
+ );
322
+ }
323
+
324
+ function isWindowsCommentShortcut(input: ShortcutKeyInput, key: string): boolean {
325
+ return key === "m" && Boolean(input.ctrlKey) && Boolean(input.altKey) && !input.metaKey && !input.shiftKey;
326
+ }
327
+
328
+ function isMacCommentShortcut(input: ShortcutKeyInput, key: string): boolean {
329
+ return key === "a" && Boolean(input.metaKey) && Boolean(input.altKey) && !input.ctrlKey && !input.shiftKey;
330
+ }
331
+
332
+ function isWindowsHeadingShortcut(input: ShortcutKeyInput, key: string): boolean {
333
+ return ["1", "2", "3"].includes(key) &&
334
+ Boolean(input.ctrlKey) &&
335
+ Boolean(input.altKey) &&
336
+ !input.metaKey &&
337
+ !input.shiftKey;
338
+ }
339
+
340
+ function isMacHeadingShortcut(input: ShortcutKeyInput, key: string): boolean {
341
+ return ["1", "2", "3"].includes(key) &&
342
+ Boolean(input.metaKey) &&
343
+ Boolean(input.altKey) &&
344
+ !input.ctrlKey &&
345
+ !input.shiftKey;
346
+ }
347
+
348
+ function isZoomInShortcut(input: ShortcutKeyInput, key: string): boolean {
349
+ return Boolean(input.ctrlKey || input.metaKey) &&
350
+ !input.altKey &&
351
+ (key === "+" || key === "=" || key === "add");
352
+ }
353
+
354
+ function isZoomOutShortcut(input: ShortcutKeyInput, key: string): boolean {
355
+ return Boolean(input.ctrlKey || input.metaKey) &&
356
+ !input.altKey &&
357
+ (key === "-" || key === "_" || key === "subtract");
358
+ }
359
+
360
+ function isPasteTextOnlyShortcut(input: ShortcutKeyInput, key: string): boolean {
361
+ return key === "v" &&
362
+ Boolean(input.ctrlKey || input.metaKey) &&
363
+ !input.altKey &&
364
+ Boolean(input.shiftKey);
365
+ }
@@ -0,0 +1,107 @@
1
+ import type {
2
+ WordReviewEditorChromeOptions,
3
+ WordReviewEditorChromePreset,
4
+ WordReviewEditorChromeVisibility,
5
+ WordReviewEditorProps,
6
+ } from "../../api/public-types";
7
+
8
+ export function resolveChromePreset(
9
+ chromePreset: WordReviewEditorProps["chromePreset"],
10
+ _reviewMode: WordReviewEditorProps["reviewMode"] = "review",
11
+ ): WordReviewEditorChromePreset {
12
+ if (chromePreset) {
13
+ return chromePreset;
14
+ }
15
+ return "advanced";
16
+ }
17
+
18
+ export function resolveChromePresetOptions(
19
+ chromePreset: WordReviewEditorChromePreset,
20
+ overrides?: Partial<WordReviewEditorChromeOptions>,
21
+ ): WordReviewEditorChromeOptions {
22
+ const defaults: Record<WordReviewEditorChromePreset, WordReviewEditorChromeOptions> = {
23
+ selection: {
24
+ showReviewQueueBar: false,
25
+ showSectionTagAction: false,
26
+ showReviewRail: false,
27
+ },
28
+ simple: {
29
+ showReviewQueueBar: false,
30
+ showSectionTagAction: false,
31
+ showReviewRail: false,
32
+ },
33
+ advanced: {
34
+ showReviewQueueBar: false,
35
+ showSectionTagAction: false,
36
+ showReviewRail: true,
37
+ },
38
+ review: {
39
+ showReviewQueueBar: true,
40
+ showSectionTagAction: true,
41
+ showReviewRail: true,
42
+ },
43
+ };
44
+
45
+ return {
46
+ ...defaults[chromePreset],
47
+ ...overrides,
48
+ };
49
+ }
50
+
51
+ export function resolveChromeVisibilityForPreset(input: {
52
+ chromePreset: WordReviewEditorChromePreset;
53
+ chromeOptions?: Partial<WordReviewEditorChromeOptions>;
54
+ chromeVisibility?: Partial<WordReviewEditorChromeVisibility>;
55
+ }): WordReviewEditorChromeVisibility {
56
+ const options = resolveChromePresetOptions(input.chromePreset, input.chromeOptions);
57
+ const defaults: Record<WordReviewEditorChromePreset, WordReviewEditorChromeVisibility> = {
58
+ selection: {
59
+ toolbar: false,
60
+ alerts: true,
61
+ selectionOverlay: true,
62
+ contextToolbars: true,
63
+ contextAnalytics: true,
64
+ pageChrome: true,
65
+ statusBar: true,
66
+ reviewRail: false,
67
+ },
68
+ simple: {
69
+ toolbar: true,
70
+ alerts: true,
71
+ selectionOverlay: true,
72
+ contextToolbars: true,
73
+ contextAnalytics: true,
74
+ pageChrome: true,
75
+ statusBar: true,
76
+ reviewRail: false,
77
+ },
78
+ advanced: {
79
+ toolbar: true,
80
+ alerts: true,
81
+ selectionOverlay: true,
82
+ contextToolbars: true,
83
+ contextAnalytics: true,
84
+ pageChrome: true,
85
+ statusBar: true,
86
+ reviewRail: true,
87
+ },
88
+ review: {
89
+ toolbar: true,
90
+ alerts: true,
91
+ selectionOverlay: true,
92
+ contextToolbars: true,
93
+ contextAnalytics: true,
94
+ pageChrome: true,
95
+ statusBar: true,
96
+ reviewRail: options.showReviewRail,
97
+ },
98
+ };
99
+
100
+ return {
101
+ ...defaults[input.chromePreset],
102
+ ...(input.chromeOptions?.showReviewRail === undefined
103
+ ? {}
104
+ : { reviewRail: input.chromeOptions.showReviewRail }),
105
+ ...input.chromeVisibility,
106
+ };
107
+ }
@@ -0,0 +1,15 @@
1
+ import React from "react";
2
+
3
+ import type { WordReviewEditorChromePreset } from "../../api/public-types";
4
+ import {
5
+ TwToolbar,
6
+ type TwToolbarProps,
7
+ } from "../toolbar/tw-toolbar";
8
+
9
+ export interface ChromePresetToolbarProps extends TwToolbarProps {
10
+ chromePreset: WordReviewEditorChromePreset;
11
+ }
12
+
13
+ export function ChromePresetToolbar(props: ChromePresetToolbarProps) {
14
+ return <TwToolbar {...props} preset={props.chromePreset} />;
15
+ }