@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.
- package/package.json +26 -37
- package/src/api/public-types.ts +531 -0
- package/src/api/session-state.ts +2 -0
- package/src/core/commands/index.ts +201 -79
- package/src/core/commands/table-structure-commands.ts +138 -5
- package/src/core/state/text-transaction.ts +370 -3
- package/src/index.ts +41 -0
- package/src/io/docx-session.ts +318 -25
- package/src/io/export/serialize-footnotes.ts +41 -46
- package/src/io/export/serialize-headers-footers.ts +36 -40
- package/src/io/export/serialize-main-document.ts +55 -89
- package/src/io/export/serialize-numbering.ts +104 -4
- package/src/io/export/serialize-runtime-revisions.ts +196 -2
- package/src/io/export/split-story-blocks-for-runtime-revisions.ts +252 -0
- package/src/io/export/table-properties-xml.ts +318 -0
- package/src/io/normalize/normalize-text.ts +34 -3
- package/src/io/ooxml/parse-comments.ts +6 -0
- package/src/io/ooxml/parse-footnotes.ts +69 -13
- package/src/io/ooxml/parse-headers-footers.ts +54 -11
- package/src/io/ooxml/parse-main-document.ts +112 -42
- package/src/io/ooxml/parse-numbering.ts +341 -26
- package/src/io/ooxml/parse-revisions.ts +118 -4
- package/src/io/ooxml/parse-styles.ts +176 -0
- package/src/io/ooxml/parse-tables.ts +34 -25
- package/src/io/ooxml/revision-boundaries.ts +127 -3
- package/src/io/ooxml/workflow-payload.ts +544 -0
- package/src/model/canonical-document.ts +91 -1
- package/src/model/snapshot.ts +112 -1
- package/src/preservation/store.ts +73 -3
- package/src/review/store/comment-store.ts +19 -1
- package/src/review/store/revision-actions.ts +29 -0
- package/src/review/store/revision-store.ts +12 -1
- package/src/review/store/revision-types.ts +11 -0
- package/src/runtime/context-analytics.ts +824 -0
- package/src/runtime/document-locations.ts +521 -0
- package/src/runtime/document-navigation.ts +14 -1
- package/src/runtime/document-outline.ts +440 -0
- package/src/runtime/document-runtime.ts +941 -45
- package/src/runtime/event-refresh-hints.ts +137 -0
- package/src/runtime/numbering-prefix.ts +67 -39
- package/src/runtime/page-layout-estimation.ts +100 -7
- package/src/runtime/resolved-numbering-geometry.ts +293 -0
- package/src/runtime/session-capabilities.ts +2 -2
- package/src/runtime/suggestions-snapshot.ts +137 -0
- package/src/runtime/surface-projection.ts +223 -27
- package/src/runtime/table-style-resolver.ts +409 -0
- package/src/runtime/view-state.ts +17 -1
- package/src/runtime/workflow-markup.ts +54 -14
- package/src/ui/WordReviewEditor.tsx +1269 -87
- package/src/ui/editor-command-bag.ts +7 -0
- package/src/ui/editor-runtime-boundary.ts +111 -10
- package/src/ui/editor-shell-view.tsx +17 -15
- package/src/ui/editor-surface-controller.tsx +5 -0
- package/src/ui/headless/selection-tool-context.ts +19 -0
- package/src/ui/headless/selection-tool-resolver.ts +752 -0
- package/src/ui/headless/selection-tool-types.ts +129 -0
- package/src/ui/headless/selection-toolbar-model.ts +10 -33
- package/src/ui/runtime-shortcut-dispatch.ts +365 -0
- package/src/ui-tailwind/chrome/chrome-preset-model.ts +107 -0
- package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +15 -0
- package/src/ui-tailwind/chrome/review-queue-bar.tsx +97 -0
- package/src/ui-tailwind/chrome/tw-context-analytics-summary.tsx +122 -0
- package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +1 -9
- package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +1 -5
- package/src/ui-tailwind/chrome/tw-page-ruler.tsx +8 -29
- package/src/ui-tailwind/chrome/tw-selection-tool-blocked.tsx +23 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-comment.tsx +35 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-formatting.tsx +37 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +298 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +116 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-suggestion.tsx +29 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-workflow.tsx +27 -0
- package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +3 -3
- package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +3 -3
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +86 -14
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +57 -52
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +36 -52
- package/src/ui-tailwind/editor-surface/pm-schema.ts +56 -5
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +87 -24
- package/src/ui-tailwind/editor-surface/surface-build-keys.ts +4 -0
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +135 -32
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +74 -7
- package/src/ui-tailwind/review/tw-comment-sidebar.tsx +17 -17
- package/src/ui-tailwind/review/tw-review-rail.tsx +19 -17
- package/src/ui-tailwind/review/tw-revision-sidebar.tsx +10 -10
- package/src/ui-tailwind/status/tw-status-bar.tsx +10 -6
- package/src/ui-tailwind/theme/editor-theme.css +58 -40
- package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +4 -4
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +250 -181
- package/src/ui-tailwind/tw-review-workspace.tsx +323 -280
- package/src/validation/compatibility-engine.ts +246 -2
- 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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import type {
|
|
2
|
+
FormattingInlineSelectionToolModel,
|
|
3
|
+
SelectionToolAnchor,
|
|
4
|
+
SelectionToolBadge,
|
|
5
|
+
SuggestionReviewSelectionToolModel,
|
|
6
|
+
} from "./selection-tool-types";
|
|
5
7
|
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
+
}
|