@beyondwork/docx-react-component 1.0.37 → 1.0.39
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 +41 -31
- package/src/api/public-types.ts +496 -1
- package/src/core/commands/section-layout-commands.ts +58 -0
- package/src/core/commands/table-grid.ts +431 -0
- package/src/core/commands/table-structure-commands.ts +845 -56
- package/src/core/commands/text-commands.ts +122 -2
- package/src/io/docx-session.ts +1 -0
- package/src/io/export/serialize-main-document.ts +2 -11
- package/src/io/export/serialize-numbering.ts +43 -10
- package/src/io/export/serialize-paragraph-formatting.ts +152 -0
- package/src/io/export/serialize-run-formatting.ts +90 -0
- package/src/io/export/serialize-styles.ts +212 -0
- package/src/io/export/serialize-tables.ts +74 -0
- package/src/io/export/table-properties-xml.ts +139 -4
- package/src/io/normalize/normalize-text.ts +15 -0
- package/src/io/ooxml/parse-fields.ts +10 -3
- package/src/io/ooxml/parse-footnotes.ts +60 -0
- package/src/io/ooxml/parse-headers-footers.ts +60 -0
- package/src/io/ooxml/parse-main-document.ts +137 -0
- package/src/io/ooxml/parse-numbering.ts +41 -1
- package/src/io/ooxml/parse-paragraph-formatting.ts +188 -0
- package/src/io/ooxml/parse-run-formatting.ts +129 -0
- package/src/io/ooxml/parse-styles.ts +31 -0
- package/src/io/ooxml/parse-tables.ts +249 -0
- package/src/io/ooxml/xml-attr-helpers.ts +60 -0
- package/src/io/ooxml/xml-element.ts +19 -0
- package/src/model/canonical-document.ts +117 -3
- package/src/runtime/collab/event-types.ts +165 -0
- package/src/runtime/collab/index.ts +22 -0
- package/src/runtime/collab/remote-cursor-awareness.ts +93 -0
- package/src/runtime/collab/runtime-collab-sync.ts +273 -0
- package/src/runtime/document-layout.ts +4 -2
- package/src/runtime/document-navigation.ts +1 -1
- package/src/runtime/document-runtime.ts +248 -18
- package/src/runtime/layout/default-page-format.ts +96 -0
- package/src/runtime/layout/index.ts +47 -0
- package/src/runtime/layout/inert-layout-facet.ts +16 -0
- package/src/runtime/layout/layout-engine-instance.ts +100 -23
- package/src/runtime/layout/layout-invalidation.ts +14 -5
- package/src/runtime/layout/margin-preset-catalog.ts +178 -0
- package/src/runtime/layout/page-format-catalog.ts +233 -0
- package/src/runtime/layout/page-graph.ts +55 -0
- package/src/runtime/layout/paginate-paragraph-lines.ts +128 -0
- package/src/runtime/layout/paginated-layout-engine.ts +484 -37
- package/src/runtime/layout/project-block-fragments.ts +225 -0
- package/src/runtime/layout/public-facet.ts +748 -16
- package/src/runtime/layout/resolve-page-fields.ts +70 -0
- package/src/runtime/layout/resolve-page-previews.ts +185 -0
- package/src/runtime/layout/resolved-formatting-state.ts +30 -26
- package/src/runtime/layout/table-render-plan.ts +249 -0
- package/src/runtime/numbering-prefix.ts +5 -0
- package/src/runtime/paragraph-style-resolver.ts +194 -0
- package/src/runtime/render/block-fragment-projection.ts +35 -0
- package/src/runtime/render/decoration-resolver.ts +189 -0
- package/src/runtime/render/index.ts +57 -0
- package/src/runtime/render/pending-op-delta-reader.ts +129 -0
- package/src/runtime/render/render-frame-types.ts +317 -0
- package/src/runtime/render/render-kernel.ts +759 -0
- package/src/runtime/resolved-numbering-geometry.ts +9 -1
- package/src/runtime/surface-projection.ts +129 -9
- package/src/runtime/table-schema.ts +11 -0
- package/src/runtime/view-state.ts +67 -0
- package/src/runtime/workflow-markup.ts +1 -5
- package/src/runtime/workflow-rail-segments.ts +280 -0
- package/src/ui/WordReviewEditor.tsx +368 -19
- package/src/ui/editor-command-bag.ts +4 -0
- package/src/ui/editor-runtime-boundary.ts +16 -0
- package/src/ui/editor-shell-view.tsx +10 -0
- package/src/ui/editor-surface-controller.tsx +9 -1
- package/src/ui/headless/chrome-registry.ts +310 -15
- package/src/ui/headless/scoped-chrome-policy.ts +49 -1
- package/src/ui/headless/selection-tool-types.ts +10 -0
- package/src/ui-tailwind/chrome/chrome-preset-model.ts +23 -2
- package/src/ui-tailwind/chrome/review-queue-bar.tsx +2 -14
- package/src/ui-tailwind/chrome/role-action-sets.ts +80 -0
- package/src/ui-tailwind/chrome/tw-detach-handle.tsx +147 -0
- package/src/ui-tailwind/chrome/tw-selection-anchor-resolver.ts +160 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +68 -92
- package/src/ui-tailwind/chrome/tw-selection-tool-placement.ts +149 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +11 -0
- package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +15 -4
- package/src/ui-tailwind/chrome/tw-table-border-picker.tsx +245 -0
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +356 -140
- package/src/ui-tailwind/chrome/tw-table-grip-layer.tsx +284 -0
- package/src/ui-tailwind/chrome-overlay/chrome-overlay-projector.ts +94 -0
- package/src/ui-tailwind/chrome-overlay/index.ts +16 -0
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +96 -0
- package/src/ui-tailwind/chrome-overlay/tw-scope-rail-layer.tsx +178 -0
- package/src/ui-tailwind/editor-surface/fast-text-edit-lane.ts +4 -0
- package/src/ui-tailwind/editor-surface/local-edit-session-state.ts +11 -0
- package/src/ui-tailwind/editor-surface/page-slice-util.ts +15 -0
- package/src/ui-tailwind/editor-surface/perf-probe.ts +7 -1
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +40 -4
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +22 -12
- package/src/ui-tailwind/editor-surface/pm-page-break-decorations.ts +389 -0
- package/src/ui-tailwind/editor-surface/pm-schema.ts +40 -2
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +144 -62
- package/src/ui-tailwind/editor-surface/remote-cursor-plugin.ts +179 -0
- package/src/ui-tailwind/editor-surface/tw-page-block-view.tsx +559 -0
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +224 -75
- package/src/ui-tailwind/editor-surface/tw-table-bands.css +61 -0
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +19 -0
- package/src/ui-tailwind/index.ts +29 -0
- package/src/ui-tailwind/review/tw-comment-sidebar.tsx +2 -2
- package/src/ui-tailwind/review/tw-rail-card.tsx +150 -0
- package/src/ui-tailwind/review/tw-review-rail-footer.tsx +52 -0
- package/src/ui-tailwind/review/tw-review-rail.tsx +166 -11
- package/src/ui-tailwind/review/tw-workflow-tab.tsx +108 -0
- package/src/ui-tailwind/theme/editor-theme.css +498 -163
- package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +680 -0
- package/src/ui-tailwind/toolbar/tw-scope-posture-menu.tsx +182 -0
- package/src/ui-tailwind/toolbar/tw-shell-header.tsx +162 -0
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +104 -2
- package/src/ui-tailwind/tw-review-workspace.tsx +234 -21
- package/src/runtime/collab-review-sync.ts +0 -254
- package/src/ui-tailwind/editor-surface/pm-collab-plugins.ts +0 -40
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
EditorRole,
|
|
3
|
+
WordReviewEditorChromePreset,
|
|
4
|
+
} from "../../api/public-types";
|
|
2
5
|
import type { SelectionToolKind } from "./selection-tool-types";
|
|
3
6
|
|
|
4
7
|
export type ChromeSurface = "top-toolbar" | "selection-tool";
|
|
@@ -6,6 +9,7 @@ export type ChromeDensity = "compact";
|
|
|
6
9
|
export type ToolbarChromePlacement = "inline" | "overflow" | "hidden";
|
|
7
10
|
|
|
8
11
|
export type ToolbarChromeItemId =
|
|
12
|
+
// Universal formatting + history
|
|
9
13
|
| "history"
|
|
10
14
|
| "text-style-selectors"
|
|
11
15
|
| "inline-formatting"
|
|
@@ -24,7 +28,27 @@ export type ToolbarChromeItemId =
|
|
|
24
28
|
| "workspace-mode"
|
|
25
29
|
| "zoom"
|
|
26
30
|
| "health"
|
|
27
|
-
| "export"
|
|
31
|
+
| "export"
|
|
32
|
+
// R1: role-scoped action region entries
|
|
33
|
+
| "editor-scope-posture-menu"
|
|
34
|
+
| "review-sidebar-tracked-changes"
|
|
35
|
+
| "review-sidebar-comments"
|
|
36
|
+
| "review-queue-prev"
|
|
37
|
+
| "review-queue-next"
|
|
38
|
+
| "review-queue-counts"
|
|
39
|
+
| "review-queue-active-label"
|
|
40
|
+
| "review-accept"
|
|
41
|
+
| "review-reject"
|
|
42
|
+
| "review-accept-all"
|
|
43
|
+
| "review-reject-all"
|
|
44
|
+
| "review-markup-mode"
|
|
45
|
+
| "workflow-prev"
|
|
46
|
+
| "workflow-next"
|
|
47
|
+
| "workflow-mark-complete"
|
|
48
|
+
| "workflow-claim"
|
|
49
|
+
| "workflow-skip"
|
|
50
|
+
| "workflow-mark-blocked"
|
|
51
|
+
| "workflow-jump-to-scope";
|
|
28
52
|
|
|
29
53
|
export interface ChromeRegistryEntryBase {
|
|
30
54
|
id: string;
|
|
@@ -42,12 +66,33 @@ export interface ToolbarChromeRegistryEntry extends ChromeRegistryEntryBase {
|
|
|
42
66
|
id: ToolbarChromeItemId;
|
|
43
67
|
surfaces: ["top-toolbar"];
|
|
44
68
|
presets: ReadonlyArray<WordReviewEditorChromePreset>;
|
|
69
|
+
/**
|
|
70
|
+
* Roles in which this entry appears. Empty = appears in every role.
|
|
71
|
+
* R1 uses this to filter the inline action set down to the per-role
|
|
72
|
+
* matrix described in the chrome-phase plan.
|
|
73
|
+
*/
|
|
74
|
+
roles: ReadonlyArray<EditorRole>;
|
|
45
75
|
fullPlacement: Exclude<ToolbarChromePlacement, "hidden">;
|
|
46
76
|
compactPlacement: ToolbarChromePlacement;
|
|
47
|
-
runtimeBehavior: "always" | "formatting" | "structure" | "comment";
|
|
77
|
+
runtimeBehavior: "always" | "formatting" | "structure" | "comment" | "sidebar-panel";
|
|
48
78
|
scopeBehavior?: "default" | "scoped-only" | "hidden-when-scoped";
|
|
79
|
+
/**
|
|
80
|
+
* Optional per-role placement override. When a role overrides the
|
|
81
|
+
* placement (for instance, "text-style-selectors" is `inline` in editor
|
|
82
|
+
* but `overflow` in review/workflow), list the role-specific placement
|
|
83
|
+
* here. Missing roles inherit `fullPlacement` / `compactPlacement`.
|
|
84
|
+
*/
|
|
85
|
+
rolePlacement?: Partial<
|
|
86
|
+
Record<EditorRole, Exclude<ToolbarChromePlacement, "hidden">>
|
|
87
|
+
>;
|
|
49
88
|
}
|
|
50
89
|
|
|
90
|
+
const ALL_ROLES: ReadonlyArray<EditorRole> = ["editor", "review", "workflow"];
|
|
91
|
+
const EDITOR_ONLY: ReadonlyArray<EditorRole> = ["editor"];
|
|
92
|
+
const REVIEW_ONLY: ReadonlyArray<EditorRole> = ["review"];
|
|
93
|
+
const WORKFLOW_ONLY: ReadonlyArray<EditorRole> = ["workflow"];
|
|
94
|
+
const EDITOR_AND_REVIEW: ReadonlyArray<EditorRole> = ["editor", "review"];
|
|
95
|
+
|
|
51
96
|
export const SELECTION_TOOL_REGISTRY: ReadonlyArray<SelectionToolRegistryEntry> = [
|
|
52
97
|
{ id: "suggestion-review", surfaces: ["selection-tool"], group: "review", precedence: 10 },
|
|
53
98
|
{ id: "comment-thread", surfaces: ["selection-tool"], group: "review", precedence: 20 },
|
|
@@ -62,7 +107,8 @@ export const TOOLBAR_CHROME_REGISTRY: ReadonlyArray<ToolbarChromeRegistryEntry>
|
|
|
62
107
|
id: "history",
|
|
63
108
|
surfaces: ["top-toolbar"],
|
|
64
109
|
group: "history",
|
|
65
|
-
presets: ["simple", "advanced", "review"],
|
|
110
|
+
presets: ["simple", "advanced", "review", "workflow"],
|
|
111
|
+
roles: ALL_ROLES,
|
|
66
112
|
fullPlacement: "inline",
|
|
67
113
|
compactPlacement: "inline",
|
|
68
114
|
runtimeBehavior: "always",
|
|
@@ -71,61 +117,94 @@ export const TOOLBAR_CHROME_REGISTRY: ReadonlyArray<ToolbarChromeRegistryEntry>
|
|
|
71
117
|
id: "text-style-selectors",
|
|
72
118
|
surfaces: ["top-toolbar"],
|
|
73
119
|
group: "text",
|
|
74
|
-
presets: ["advanced"],
|
|
120
|
+
presets: ["advanced", "workflow"],
|
|
121
|
+
roles: ALL_ROLES,
|
|
75
122
|
fullPlacement: "inline",
|
|
76
123
|
compactPlacement: "overflow",
|
|
77
124
|
runtimeBehavior: "formatting",
|
|
125
|
+
rolePlacement: {
|
|
126
|
+
editor: "inline",
|
|
127
|
+
review: "overflow",
|
|
128
|
+
workflow: "overflow",
|
|
129
|
+
},
|
|
78
130
|
},
|
|
79
131
|
{
|
|
80
132
|
id: "inline-formatting",
|
|
81
133
|
surfaces: ["top-toolbar"],
|
|
82
134
|
group: "text",
|
|
83
|
-
presets: ["simple", "advanced", "review"],
|
|
135
|
+
presets: ["simple", "advanced", "review", "workflow"],
|
|
136
|
+
roles: ALL_ROLES,
|
|
84
137
|
fullPlacement: "inline",
|
|
85
138
|
compactPlacement: "inline",
|
|
86
139
|
runtimeBehavior: "formatting",
|
|
140
|
+
rolePlacement: {
|
|
141
|
+
editor: "inline",
|
|
142
|
+
review: "overflow",
|
|
143
|
+
workflow: "overflow",
|
|
144
|
+
},
|
|
87
145
|
},
|
|
88
146
|
{
|
|
89
147
|
id: "text-colors",
|
|
90
148
|
surfaces: ["top-toolbar"],
|
|
91
149
|
group: "text",
|
|
92
150
|
presets: ["simple", "advanced"],
|
|
151
|
+
roles: EDITOR_AND_REVIEW,
|
|
93
152
|
fullPlacement: "inline",
|
|
94
153
|
compactPlacement: "inline",
|
|
95
154
|
runtimeBehavior: "formatting",
|
|
155
|
+
rolePlacement: {
|
|
156
|
+
editor: "inline",
|
|
157
|
+
review: "overflow",
|
|
158
|
+
},
|
|
96
159
|
},
|
|
97
160
|
{
|
|
98
161
|
id: "paragraph-alignment",
|
|
99
162
|
surfaces: ["top-toolbar"],
|
|
100
163
|
group: "paragraph",
|
|
101
164
|
presets: ["simple", "advanced"],
|
|
165
|
+
roles: EDITOR_AND_REVIEW,
|
|
102
166
|
fullPlacement: "inline",
|
|
103
167
|
compactPlacement: "inline",
|
|
104
168
|
runtimeBehavior: "formatting",
|
|
169
|
+
rolePlacement: {
|
|
170
|
+
editor: "inline",
|
|
171
|
+
review: "overflow",
|
|
172
|
+
},
|
|
105
173
|
},
|
|
106
174
|
{
|
|
107
175
|
id: "list-actions",
|
|
108
176
|
surfaces: ["top-toolbar"],
|
|
109
177
|
group: "paragraph",
|
|
110
178
|
presets: ["simple", "advanced"],
|
|
179
|
+
roles: EDITOR_AND_REVIEW,
|
|
111
180
|
fullPlacement: "inline",
|
|
112
181
|
compactPlacement: "overflow",
|
|
113
182
|
runtimeBehavior: "formatting",
|
|
183
|
+
rolePlacement: {
|
|
184
|
+
editor: "inline",
|
|
185
|
+
review: "overflow",
|
|
186
|
+
},
|
|
114
187
|
},
|
|
115
188
|
{
|
|
116
189
|
id: "indentation",
|
|
117
190
|
surfaces: ["top-toolbar"],
|
|
118
191
|
group: "paragraph",
|
|
119
192
|
presets: ["simple", "advanced"],
|
|
193
|
+
roles: EDITOR_AND_REVIEW,
|
|
120
194
|
fullPlacement: "inline",
|
|
121
195
|
compactPlacement: "overflow",
|
|
122
196
|
runtimeBehavior: "formatting",
|
|
197
|
+
rolePlacement: {
|
|
198
|
+
editor: "inline",
|
|
199
|
+
review: "overflow",
|
|
200
|
+
},
|
|
123
201
|
},
|
|
124
202
|
{
|
|
125
203
|
id: "list-continuation",
|
|
126
204
|
surfaces: ["top-toolbar"],
|
|
127
205
|
group: "paragraph",
|
|
128
206
|
presets: ["simple", "advanced"],
|
|
207
|
+
roles: EDITOR_ONLY,
|
|
129
208
|
fullPlacement: "inline",
|
|
130
209
|
compactPlacement: "overflow",
|
|
131
210
|
runtimeBehavior: "formatting",
|
|
@@ -135,6 +214,7 @@ export const TOOLBAR_CHROME_REGISTRY: ReadonlyArray<ToolbarChromeRegistryEntry>
|
|
|
135
214
|
surfaces: ["top-toolbar"],
|
|
136
215
|
group: "document",
|
|
137
216
|
presets: ["simple", "advanced"],
|
|
217
|
+
roles: EDITOR_ONLY,
|
|
138
218
|
fullPlacement: "inline",
|
|
139
219
|
compactPlacement: "overflow",
|
|
140
220
|
runtimeBehavior: "structure",
|
|
@@ -145,6 +225,7 @@ export const TOOLBAR_CHROME_REGISTRY: ReadonlyArray<ToolbarChromeRegistryEntry>
|
|
|
145
225
|
surfaces: ["top-toolbar"],
|
|
146
226
|
group: "document",
|
|
147
227
|
presets: ["advanced"],
|
|
228
|
+
roles: EDITOR_ONLY,
|
|
148
229
|
fullPlacement: "inline",
|
|
149
230
|
compactPlacement: "overflow",
|
|
150
231
|
runtimeBehavior: "structure",
|
|
@@ -154,7 +235,8 @@ export const TOOLBAR_CHROME_REGISTRY: ReadonlyArray<ToolbarChromeRegistryEntry>
|
|
|
154
235
|
id: "scope-status",
|
|
155
236
|
surfaces: ["top-toolbar"],
|
|
156
237
|
group: "scope",
|
|
157
|
-
presets: ["simple", "advanced", "review"],
|
|
238
|
+
presets: ["simple", "advanced", "review", "workflow"],
|
|
239
|
+
roles: ALL_ROLES,
|
|
158
240
|
fullPlacement: "inline",
|
|
159
241
|
compactPlacement: "inline",
|
|
160
242
|
runtimeBehavior: "always",
|
|
@@ -164,7 +246,8 @@ export const TOOLBAR_CHROME_REGISTRY: ReadonlyArray<ToolbarChromeRegistryEntry>
|
|
|
164
246
|
id: "story-breadcrumb",
|
|
165
247
|
surfaces: ["top-toolbar"],
|
|
166
248
|
group: "scope",
|
|
167
|
-
presets: ["simple", "advanced", "review"],
|
|
249
|
+
presets: ["simple", "advanced", "review", "workflow"],
|
|
250
|
+
roles: ALL_ROLES,
|
|
168
251
|
fullPlacement: "inline",
|
|
169
252
|
compactPlacement: "inline",
|
|
170
253
|
runtimeBehavior: "always",
|
|
@@ -173,7 +256,8 @@ export const TOOLBAR_CHROME_REGISTRY: ReadonlyArray<ToolbarChromeRegistryEntry>
|
|
|
173
256
|
id: "sidebar-toggle",
|
|
174
257
|
surfaces: ["top-toolbar"],
|
|
175
258
|
group: "review",
|
|
176
|
-
presets: ["simple", "advanced", "review"],
|
|
259
|
+
presets: ["simple", "advanced", "review", "workflow"],
|
|
260
|
+
roles: ALL_ROLES,
|
|
177
261
|
fullPlacement: "inline",
|
|
178
262
|
compactPlacement: "inline",
|
|
179
263
|
runtimeBehavior: "always",
|
|
@@ -182,7 +266,11 @@ export const TOOLBAR_CHROME_REGISTRY: ReadonlyArray<ToolbarChromeRegistryEntry>
|
|
|
182
266
|
id: "comment",
|
|
183
267
|
surfaces: ["top-toolbar"],
|
|
184
268
|
group: "review",
|
|
185
|
-
presets: ["simple", "advanced", "review"],
|
|
269
|
+
presets: ["simple", "advanced", "review", "workflow"],
|
|
270
|
+
// Visible in every role, but editor/review roles render it inside the
|
|
271
|
+
// role action region (see ROLE_ACTION_SETS) and the right cluster
|
|
272
|
+
// suppresses it via `isChromeItemOwnedByRoleRegion` to avoid duplication.
|
|
273
|
+
roles: ALL_ROLES,
|
|
186
274
|
fullPlacement: "inline",
|
|
187
275
|
compactPlacement: "inline",
|
|
188
276
|
runtimeBehavior: "comment",
|
|
@@ -191,7 +279,9 @@ export const TOOLBAR_CHROME_REGISTRY: ReadonlyArray<ToolbarChromeRegistryEntry>
|
|
|
191
279
|
id: "tracked-changes-toggle",
|
|
192
280
|
surfaces: ["top-toolbar"],
|
|
193
281
|
group: "review",
|
|
194
|
-
presets: ["advanced", "review"],
|
|
282
|
+
presets: ["simple", "advanced", "review", "workflow"],
|
|
283
|
+
// Same ownership rule as `comment` — editor/review role regions own it.
|
|
284
|
+
roles: ALL_ROLES,
|
|
195
285
|
fullPlacement: "inline",
|
|
196
286
|
compactPlacement: "inline",
|
|
197
287
|
runtimeBehavior: "always",
|
|
@@ -200,7 +290,8 @@ export const TOOLBAR_CHROME_REGISTRY: ReadonlyArray<ToolbarChromeRegistryEntry>
|
|
|
200
290
|
id: "workspace-mode",
|
|
201
291
|
surfaces: ["top-toolbar"],
|
|
202
292
|
group: "view",
|
|
203
|
-
presets: ["simple", "advanced", "review"],
|
|
293
|
+
presets: ["simple", "advanced", "review", "workflow"],
|
|
294
|
+
roles: ALL_ROLES,
|
|
204
295
|
fullPlacement: "inline",
|
|
205
296
|
compactPlacement: "inline",
|
|
206
297
|
runtimeBehavior: "always",
|
|
@@ -209,7 +300,8 @@ export const TOOLBAR_CHROME_REGISTRY: ReadonlyArray<ToolbarChromeRegistryEntry>
|
|
|
209
300
|
id: "zoom",
|
|
210
301
|
surfaces: ["top-toolbar"],
|
|
211
302
|
group: "view",
|
|
212
|
-
presets: ["simple", "advanced", "review"],
|
|
303
|
+
presets: ["simple", "advanced", "review", "workflow"],
|
|
304
|
+
roles: ALL_ROLES,
|
|
213
305
|
fullPlacement: "inline",
|
|
214
306
|
compactPlacement: "inline",
|
|
215
307
|
runtimeBehavior: "always",
|
|
@@ -218,7 +310,8 @@ export const TOOLBAR_CHROME_REGISTRY: ReadonlyArray<ToolbarChromeRegistryEntry>
|
|
|
218
310
|
id: "health",
|
|
219
311
|
surfaces: ["top-toolbar"],
|
|
220
312
|
group: "status",
|
|
221
|
-
presets: ["simple", "advanced", "review"],
|
|
313
|
+
presets: ["simple", "advanced", "review", "workflow"],
|
|
314
|
+
roles: ALL_ROLES,
|
|
222
315
|
fullPlacement: "inline",
|
|
223
316
|
compactPlacement: "inline",
|
|
224
317
|
runtimeBehavior: "always",
|
|
@@ -227,9 +320,211 @@ export const TOOLBAR_CHROME_REGISTRY: ReadonlyArray<ToolbarChromeRegistryEntry>
|
|
|
227
320
|
id: "export",
|
|
228
321
|
surfaces: ["top-toolbar"],
|
|
229
322
|
group: "status",
|
|
230
|
-
presets: ["simple", "advanced", "review"],
|
|
323
|
+
presets: ["simple", "advanced", "review", "workflow"],
|
|
324
|
+
roles: ALL_ROLES,
|
|
325
|
+
fullPlacement: "inline",
|
|
326
|
+
compactPlacement: "inline",
|
|
327
|
+
runtimeBehavior: "always",
|
|
328
|
+
},
|
|
329
|
+
|
|
330
|
+
// ───── R1: Workflow-role scope posture menu ───────────────────────────
|
|
331
|
+
{
|
|
332
|
+
id: "editor-scope-posture-menu",
|
|
333
|
+
surfaces: ["top-toolbar"],
|
|
334
|
+
group: "scope",
|
|
335
|
+
presets: ["advanced", "review", "workflow"],
|
|
336
|
+
// Scoping/tagging is a workflow-primary action; moved from editor role.
|
|
337
|
+
roles: WORKFLOW_ONLY,
|
|
338
|
+
fullPlacement: "inline",
|
|
339
|
+
compactPlacement: "overflow",
|
|
340
|
+
runtimeBehavior: "always",
|
|
341
|
+
},
|
|
342
|
+
|
|
343
|
+
// ───── R1: Review-role sidebar panel toggles (optional, host-provided) ─
|
|
344
|
+
{
|
|
345
|
+
id: "review-sidebar-tracked-changes",
|
|
346
|
+
surfaces: ["top-toolbar"],
|
|
347
|
+
group: "review-sidebar",
|
|
348
|
+
presets: ["review"],
|
|
349
|
+
roles: REVIEW_ONLY,
|
|
350
|
+
fullPlacement: "inline",
|
|
351
|
+
compactPlacement: "inline",
|
|
352
|
+
// Hidden unless the host provides the sidebar panel callback via
|
|
353
|
+
// hasSidebarPanelAccess in ResolveScopedChromePolicyInput.
|
|
354
|
+
runtimeBehavior: "sidebar-panel",
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
id: "review-sidebar-comments",
|
|
358
|
+
surfaces: ["top-toolbar"],
|
|
359
|
+
group: "review-sidebar",
|
|
360
|
+
presets: ["review"],
|
|
361
|
+
roles: REVIEW_ONLY,
|
|
362
|
+
fullPlacement: "inline",
|
|
363
|
+
compactPlacement: "inline",
|
|
364
|
+
runtimeBehavior: "sidebar-panel",
|
|
365
|
+
},
|
|
366
|
+
|
|
367
|
+
// ───── R1: Review-role primaries ──────────────────────────────────────
|
|
368
|
+
{
|
|
369
|
+
id: "review-queue-prev",
|
|
370
|
+
surfaces: ["top-toolbar"],
|
|
371
|
+
group: "review-queue",
|
|
372
|
+
presets: ["review", "workflow"],
|
|
373
|
+
roles: REVIEW_ONLY,
|
|
374
|
+
fullPlacement: "inline",
|
|
375
|
+
compactPlacement: "inline",
|
|
376
|
+
runtimeBehavior: "always",
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
id: "review-queue-next",
|
|
380
|
+
surfaces: ["top-toolbar"],
|
|
381
|
+
group: "review-queue",
|
|
382
|
+
presets: ["review", "workflow"],
|
|
383
|
+
roles: REVIEW_ONLY,
|
|
384
|
+
fullPlacement: "inline",
|
|
385
|
+
compactPlacement: "inline",
|
|
386
|
+
runtimeBehavior: "always",
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
id: "review-queue-counts",
|
|
390
|
+
surfaces: ["top-toolbar"],
|
|
391
|
+
group: "review-queue",
|
|
392
|
+
presets: ["review"],
|
|
393
|
+
roles: REVIEW_ONLY,
|
|
394
|
+
fullPlacement: "inline",
|
|
395
|
+
compactPlacement: "overflow",
|
|
396
|
+
runtimeBehavior: "always",
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
id: "review-queue-active-label",
|
|
400
|
+
surfaces: ["top-toolbar"],
|
|
401
|
+
group: "review-queue",
|
|
402
|
+
presets: ["review"],
|
|
403
|
+
roles: REVIEW_ONLY,
|
|
404
|
+
fullPlacement: "inline",
|
|
405
|
+
compactPlacement: "overflow",
|
|
406
|
+
runtimeBehavior: "always",
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
id: "review-accept",
|
|
410
|
+
surfaces: ["top-toolbar"],
|
|
411
|
+
group: "review-action",
|
|
412
|
+
presets: ["review"],
|
|
413
|
+
roles: REVIEW_ONLY,
|
|
231
414
|
fullPlacement: "inline",
|
|
232
415
|
compactPlacement: "inline",
|
|
233
416
|
runtimeBehavior: "always",
|
|
234
417
|
},
|
|
418
|
+
{
|
|
419
|
+
id: "review-reject",
|
|
420
|
+
surfaces: ["top-toolbar"],
|
|
421
|
+
group: "review-action",
|
|
422
|
+
presets: ["review"],
|
|
423
|
+
roles: REVIEW_ONLY,
|
|
424
|
+
fullPlacement: "inline",
|
|
425
|
+
compactPlacement: "inline",
|
|
426
|
+
runtimeBehavior: "always",
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
id: "review-accept-all",
|
|
430
|
+
surfaces: ["top-toolbar"],
|
|
431
|
+
group: "review-action",
|
|
432
|
+
presets: ["review"],
|
|
433
|
+
roles: REVIEW_ONLY,
|
|
434
|
+
fullPlacement: "inline",
|
|
435
|
+
compactPlacement: "overflow",
|
|
436
|
+
runtimeBehavior: "always",
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
id: "review-reject-all",
|
|
440
|
+
surfaces: ["top-toolbar"],
|
|
441
|
+
group: "review-action",
|
|
442
|
+
presets: ["review"],
|
|
443
|
+
roles: REVIEW_ONLY,
|
|
444
|
+
fullPlacement: "inline",
|
|
445
|
+
compactPlacement: "overflow",
|
|
446
|
+
runtimeBehavior: "always",
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
id: "review-markup-mode",
|
|
450
|
+
surfaces: ["top-toolbar"],
|
|
451
|
+
group: "review-action",
|
|
452
|
+
presets: ["review"],
|
|
453
|
+
roles: REVIEW_ONLY,
|
|
454
|
+
fullPlacement: "inline",
|
|
455
|
+
compactPlacement: "inline",
|
|
456
|
+
runtimeBehavior: "always",
|
|
457
|
+
},
|
|
458
|
+
|
|
459
|
+
// ───── R1: Workflow-role primaries ────────────────────────────────────
|
|
460
|
+
{
|
|
461
|
+
id: "workflow-prev",
|
|
462
|
+
surfaces: ["top-toolbar"],
|
|
463
|
+
group: "workflow-queue",
|
|
464
|
+
presets: ["workflow"],
|
|
465
|
+
roles: WORKFLOW_ONLY,
|
|
466
|
+
fullPlacement: "inline",
|
|
467
|
+
compactPlacement: "inline",
|
|
468
|
+
runtimeBehavior: "always",
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
id: "workflow-next",
|
|
472
|
+
surfaces: ["top-toolbar"],
|
|
473
|
+
group: "workflow-queue",
|
|
474
|
+
presets: ["workflow"],
|
|
475
|
+
roles: WORKFLOW_ONLY,
|
|
476
|
+
fullPlacement: "inline",
|
|
477
|
+
compactPlacement: "inline",
|
|
478
|
+
runtimeBehavior: "always",
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
id: "workflow-mark-complete",
|
|
482
|
+
surfaces: ["top-toolbar"],
|
|
483
|
+
group: "workflow-action",
|
|
484
|
+
presets: ["workflow"],
|
|
485
|
+
roles: WORKFLOW_ONLY,
|
|
486
|
+
fullPlacement: "inline",
|
|
487
|
+
compactPlacement: "inline",
|
|
488
|
+
runtimeBehavior: "always",
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
id: "workflow-claim",
|
|
492
|
+
surfaces: ["top-toolbar"],
|
|
493
|
+
group: "workflow-action",
|
|
494
|
+
presets: ["workflow"],
|
|
495
|
+
roles: WORKFLOW_ONLY,
|
|
496
|
+
fullPlacement: "inline",
|
|
497
|
+
compactPlacement: "inline",
|
|
498
|
+
runtimeBehavior: "always",
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
id: "workflow-skip",
|
|
502
|
+
surfaces: ["top-toolbar"],
|
|
503
|
+
group: "workflow-action",
|
|
504
|
+
presets: ["workflow"],
|
|
505
|
+
roles: WORKFLOW_ONLY,
|
|
506
|
+
fullPlacement: "inline",
|
|
507
|
+
compactPlacement: "overflow",
|
|
508
|
+
runtimeBehavior: "always",
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
id: "workflow-mark-blocked",
|
|
512
|
+
surfaces: ["top-toolbar"],
|
|
513
|
+
group: "workflow-action",
|
|
514
|
+
presets: ["workflow"],
|
|
515
|
+
roles: WORKFLOW_ONLY,
|
|
516
|
+
fullPlacement: "inline",
|
|
517
|
+
compactPlacement: "overflow",
|
|
518
|
+
runtimeBehavior: "always",
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
id: "workflow-jump-to-scope",
|
|
522
|
+
surfaces: ["top-toolbar"],
|
|
523
|
+
group: "workflow-action",
|
|
524
|
+
presets: ["workflow"],
|
|
525
|
+
roles: WORKFLOW_ONLY,
|
|
526
|
+
fullPlacement: "inline",
|
|
527
|
+
compactPlacement: "overflow",
|
|
528
|
+
runtimeBehavior: "always",
|
|
529
|
+
},
|
|
235
530
|
];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ActiveListContext,
|
|
3
|
+
EditorRole,
|
|
3
4
|
InteractionGuardSnapshot,
|
|
4
5
|
WorkflowScopeSnapshot,
|
|
5
6
|
WordReviewEditorChromePreset,
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
type ToolbarChromeItemId,
|
|
11
12
|
type ToolbarChromePlacement,
|
|
12
13
|
} from "./chrome-registry";
|
|
14
|
+
import { ROLE_ACTION_SETS } from "../../ui-tailwind/chrome/role-action-sets";
|
|
13
15
|
import type { SelectionToolKind } from "./selection-tool-types";
|
|
14
16
|
|
|
15
17
|
export interface ToolbarChromeItemPolicy {
|
|
@@ -36,6 +38,20 @@ export interface ResolveScopedChromePolicyInput {
|
|
|
36
38
|
interactionGuardSnapshot?: InteractionGuardSnapshot;
|
|
37
39
|
workflowScopeSnapshot?: WorkflowScopeSnapshot | null;
|
|
38
40
|
activeListContext?: ActiveListContext | null;
|
|
41
|
+
/**
|
|
42
|
+
* Active chrome role (spec §6.4). When supplied, the policy filters
|
|
43
|
+
* registry entries whose `roles` array excludes the active role. When
|
|
44
|
+
* omitted, the preset filter alone drives visibility (back-compat for
|
|
45
|
+
* callers that haven't adopted the role model yet).
|
|
46
|
+
*/
|
|
47
|
+
role?: EditorRole;
|
|
48
|
+
/**
|
|
49
|
+
* Whether the host has wired sidebar-panel callbacks
|
|
50
|
+
* (`onReviewSidebarTrackedChanges` / `onReviewSidebarComments`).
|
|
51
|
+
* Defaults to `false` — sidebar panel buttons are hidden unless the host
|
|
52
|
+
* explicitly opts in (typically the harness).
|
|
53
|
+
*/
|
|
54
|
+
hasSidebarPanelAccess?: boolean;
|
|
39
55
|
}
|
|
40
56
|
|
|
41
57
|
export function resolveScopedChromePolicy(
|
|
@@ -62,6 +78,13 @@ export function resolveScopedChromePolicy(
|
|
|
62
78
|
TOOLBAR_CHROME_REGISTRY.map((entry) => {
|
|
63
79
|
let visible = entry.presets.includes(input.preset);
|
|
64
80
|
|
|
81
|
+
// Role filter — apply only when the caller supplied a role so existing
|
|
82
|
+
// host apps that haven't adopted the role model keep the pre-R1
|
|
83
|
+
// behavior (preset + capability only).
|
|
84
|
+
if (visible && input.role !== undefined) {
|
|
85
|
+
visible = entry.roles.includes(input.role);
|
|
86
|
+
}
|
|
87
|
+
|
|
65
88
|
if (visible) {
|
|
66
89
|
switch (entry.runtimeBehavior) {
|
|
67
90
|
case "formatting":
|
|
@@ -73,6 +96,9 @@ export function resolveScopedChromePolicy(
|
|
|
73
96
|
case "comment":
|
|
74
97
|
visible = canAddComment;
|
|
75
98
|
break;
|
|
99
|
+
case "sidebar-panel":
|
|
100
|
+
visible = Boolean(input.hasSidebarPanelAccess);
|
|
101
|
+
break;
|
|
76
102
|
default:
|
|
77
103
|
visible = true;
|
|
78
104
|
break;
|
|
@@ -93,8 +119,12 @@ export function resolveScopedChromePolicy(
|
|
|
93
119
|
visible = !hasScopedContext;
|
|
94
120
|
}
|
|
95
121
|
|
|
122
|
+
// Resolve placement: when the entry overrides placement for the
|
|
123
|
+
// active role, that wins over the preset-density default.
|
|
124
|
+
const fullPlacement =
|
|
125
|
+
(input.role && entry.rolePlacement?.[input.role]) ?? entry.fullPlacement;
|
|
96
126
|
const placement = visible
|
|
97
|
-
? (input.compactMode ? entry.compactPlacement :
|
|
127
|
+
? (input.compactMode ? entry.compactPlacement : fullPlacement)
|
|
98
128
|
: "hidden";
|
|
99
129
|
const enabled =
|
|
100
130
|
visible &&
|
|
@@ -133,6 +163,24 @@ export function isToolbarChromeItemVisible(
|
|
|
133
163
|
return policy.toolbar[itemId]?.visible ?? false;
|
|
134
164
|
}
|
|
135
165
|
|
|
166
|
+
/**
|
|
167
|
+
* Returns true when the given chrome item is owned by the active role's
|
|
168
|
+
* inline role-action region (i.e. it appears in `ROLE_ACTION_SETS[role]`).
|
|
169
|
+
* The right-cluster render path uses this to suppress its own copy so we
|
|
170
|
+
* don't render the same button twice.
|
|
171
|
+
*
|
|
172
|
+
* When `role` is undefined (legacy host, no role model adopted) this
|
|
173
|
+
* returns `false` — the right cluster keeps ownership per the pre-R1
|
|
174
|
+
* layout.
|
|
175
|
+
*/
|
|
176
|
+
export function isChromeItemOwnedByRoleRegion(
|
|
177
|
+
itemId: ToolbarChromeItemId,
|
|
178
|
+
role: EditorRole | undefined,
|
|
179
|
+
): boolean {
|
|
180
|
+
if (!role) return false;
|
|
181
|
+
return ROLE_ACTION_SETS[role].includes(itemId);
|
|
182
|
+
}
|
|
183
|
+
|
|
136
184
|
export function getToolbarChromePlacement(
|
|
137
185
|
policy: ScopedChromePolicy,
|
|
138
186
|
itemId: ToolbarChromeItemId,
|
|
@@ -59,6 +59,16 @@ export interface FormattingInlineSelectionToolModel extends BaseSelectionToolMod
|
|
|
59
59
|
italicActive: boolean;
|
|
60
60
|
underlineActive: boolean;
|
|
61
61
|
canAddComment: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* One-click "apply" color for the text-color affordance. R2.5 plumbs
|
|
64
|
+
* the current `formattingState.textColor` (or the user's most recent
|
|
65
|
+
* pick) here so the mini-toolbar reflects the active color instead of
|
|
66
|
+
* a hardcoded blue. Consumers fall back to a fixed default when
|
|
67
|
+
* absent.
|
|
68
|
+
*/
|
|
69
|
+
textColorDefault?: string;
|
|
70
|
+
/** Matching one-click highlight color. See `textColorDefault`. */
|
|
71
|
+
highlightColorDefault?: string;
|
|
62
72
|
}
|
|
63
73
|
|
|
64
74
|
export interface SuggestionReviewSelectionToolModel extends BaseSelectionToolModel {
|
|
@@ -7,12 +7,15 @@ import type {
|
|
|
7
7
|
|
|
8
8
|
export function resolveChromePreset(
|
|
9
9
|
chromePreset: WordReviewEditorProps["chromePreset"],
|
|
10
|
-
|
|
10
|
+
reviewMode: WordReviewEditorProps["reviewMode"] = "review",
|
|
11
11
|
): WordReviewEditorChromePreset {
|
|
12
12
|
if (chromePreset) {
|
|
13
13
|
return chromePreset;
|
|
14
14
|
}
|
|
15
|
-
|
|
15
|
+
// When the host does not set an explicit preset, pick one from the
|
|
16
|
+
// review-mode signal so review sessions get the review strip inline
|
|
17
|
+
// with the toolbar (rather than the density default "advanced").
|
|
18
|
+
return reviewMode === "review" ? "review" : "advanced";
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
export function resolveChromePresetOptions(
|
|
@@ -40,6 +43,14 @@ export function resolveChromePresetOptions(
|
|
|
40
43
|
showSectionTagAction: true,
|
|
41
44
|
showReviewRail: true,
|
|
42
45
|
},
|
|
46
|
+
workflow: {
|
|
47
|
+
// Workflow role consolidates prev/next + mark-section into the top
|
|
48
|
+
// toolbar via the role-action region, so the separate queue bar
|
|
49
|
+
// strip is suppressed.
|
|
50
|
+
showReviewQueueBar: false,
|
|
51
|
+
showSectionTagAction: false,
|
|
52
|
+
showReviewRail: true,
|
|
53
|
+
},
|
|
43
54
|
};
|
|
44
55
|
|
|
45
56
|
return {
|
|
@@ -95,6 +106,16 @@ export function resolveChromeVisibilityForPreset(input: {
|
|
|
95
106
|
statusBar: true,
|
|
96
107
|
reviewRail: options.showReviewRail,
|
|
97
108
|
},
|
|
109
|
+
workflow: {
|
|
110
|
+
toolbar: true,
|
|
111
|
+
alerts: true,
|
|
112
|
+
selectionOverlay: true,
|
|
113
|
+
contextToolbars: true,
|
|
114
|
+
contextAnalytics: true,
|
|
115
|
+
pageChrome: true,
|
|
116
|
+
statusBar: true,
|
|
117
|
+
reviewRail: options.showReviewRail,
|
|
118
|
+
},
|
|
98
119
|
};
|
|
99
120
|
|
|
100
121
|
return {
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { ChevronLeft, ChevronRight, MessageSquareText, Rows3 } from "lucide-react";
|
|
4
4
|
|
|
5
5
|
import type { ReviewQueueSnapshot } from "../../api/public-types";
|
|
6
6
|
import { preserveEditorSelectionMouseDown } from "../../ui/headless/preserve-editor-selection";
|
|
7
7
|
|
|
8
|
+
/** @deprecated Use the role action region (TwRoleActionRegion) for queue navigation. */
|
|
8
9
|
export interface TwReviewQueueBarProps {
|
|
9
10
|
queue: ReviewQueueSnapshot;
|
|
10
11
|
onPrevious?: () => void;
|
|
11
12
|
onNext?: () => void;
|
|
12
|
-
onMarkSection?: () => void;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
const buttonClass =
|
|
@@ -47,18 +47,6 @@ export function TwReviewQueueBar(props: TwReviewQueueBarProps) {
|
|
|
47
47
|
Next
|
|
48
48
|
<ChevronRight className="h-3.5 w-3.5" />
|
|
49
49
|
</button>
|
|
50
|
-
{props.onMarkSection ? (
|
|
51
|
-
<button
|
|
52
|
-
type="button"
|
|
53
|
-
aria-label="Mark section for review"
|
|
54
|
-
className={buttonClass}
|
|
55
|
-
onMouseDown={preserveEditorSelectionMouseDown}
|
|
56
|
-
onClick={props.onMarkSection}
|
|
57
|
-
>
|
|
58
|
-
<BookmarkPlus className="h-3.5 w-3.5" />
|
|
59
|
-
Mark section
|
|
60
|
-
</button>
|
|
61
|
-
) : null}
|
|
62
50
|
<div className="ml-auto flex flex-wrap items-center gap-2 text-xs text-secondary">
|
|
63
51
|
<span className="inline-flex items-center gap-1 rounded-full bg-canvas px-2.5 py-1 font-medium text-primary">
|
|
64
52
|
<MessageSquareText className="h-3.5 w-3.5 text-comment" />
|