@beyondwork/docx-react-component 1.0.81 → 1.0.83
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 +1 -1
- package/src/api/public-types.ts +2 -1
- package/src/api/v3/_runtime-handle.ts +4 -0
- package/src/api/v3/runtime/document.ts +61 -3
- package/src/api/v3/runtime/review.ts +55 -2
- package/src/io/normalize/normalize-text.ts +4 -1
- package/src/io/ooxml/parse-drawing.ts +4 -0
- package/src/model/canonical-document.ts +2 -0
- package/src/ui/WordReviewEditor.tsx +243 -2
- package/src/ui-tailwind/chrome/editor-action-registry.ts +220 -0
- package/src/ui-tailwind/chrome/editor-actions-to-palette.ts +59 -35
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +1 -0
- package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +256 -37
- package/src/ui-tailwind/editor-surface/pm-schema.ts +54 -1
- package/src/ui-tailwind/editor-surface/tw-page-block-view.helpers.ts +31 -1
- package/src/ui-tailwind/editor-surface/tw-page-block-view.tsx +15 -0
- package/src/ui-tailwind/page-stack/tw-floating-image-layer.tsx +24 -5
- package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +35 -6
- package/src/ui-tailwind/page-stack/use-visible-block-range.ts +333 -43
- package/src/ui-tailwind/review-workspace/use-chrome-policy.ts +32 -6
- package/src/ui-tailwind/review-workspace/use-page-markers.ts +273 -24
- package/src/ui-tailwind/theme/editor-theme.css +3 -5
- package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +21 -0
- package/src/ui-tailwind/tw-review-workspace.tsx +4 -0
|
@@ -24,6 +24,8 @@ import type { EditorChromeMode } from "../../api/v3/ui/chrome-composition";
|
|
|
24
24
|
import type { ContextMenuGroupId } from "./tw-context-menu";
|
|
25
25
|
import type { ShortcutKey } from "./tw-shortcut-hint";
|
|
26
26
|
|
|
27
|
+
type ProductSectionBreakType = "nextPage" | "continuous" | "evenPage" | "oddPage";
|
|
28
|
+
|
|
27
29
|
/**
|
|
28
30
|
* Target kinds roughly mirror DESIGN-EDITOR.md §4 "Local context" cells.
|
|
29
31
|
* A contextmenu event resolves its target to one (or more) of these
|
|
@@ -80,6 +82,11 @@ export interface EditorActionHostCallbacks {
|
|
|
80
82
|
readonly onToggleItalic?: () => void;
|
|
81
83
|
readonly onToggleUnderline?: () => void;
|
|
82
84
|
readonly onToggleStrikethrough?: () => void;
|
|
85
|
+
readonly onSetParagraphStyle?: (styleId: string) => void;
|
|
86
|
+
readonly onSetFontFamily?: (fontFamily: string) => void;
|
|
87
|
+
readonly onSetFontSize?: (fontSize: number) => void;
|
|
88
|
+
readonly onSetTextColor?: (color: string) => void;
|
|
89
|
+
readonly onSetHighlightColor?: (color: string | null) => void;
|
|
83
90
|
readonly onToggleBulletedList?: () => void;
|
|
84
91
|
readonly onToggleNumberedList?: () => void;
|
|
85
92
|
readonly onOutdent?: () => void;
|
|
@@ -87,9 +94,18 @@ export interface EditorActionHostCallbacks {
|
|
|
87
94
|
readonly onSetAlignment?: (
|
|
88
95
|
alignment: "left" | "center" | "right" | "justify",
|
|
89
96
|
) => void;
|
|
97
|
+
readonly onInsertPageBreak?: () => void;
|
|
98
|
+
readonly onInsertSectionBreak?: (type: ProductSectionBreakType) => void;
|
|
90
99
|
readonly onInsertTable?: () => void;
|
|
100
|
+
readonly onInsertImage?: () => void;
|
|
91
101
|
readonly onAddComment?: () => void;
|
|
92
102
|
|
|
103
|
+
// Search / app-level host-delegated commands
|
|
104
|
+
readonly onFindRequested?: () => void;
|
|
105
|
+
readonly onReplaceRequested?: () => void;
|
|
106
|
+
readonly onPrintRequested?: () => void;
|
|
107
|
+
readonly onGoToRequested?: () => void;
|
|
108
|
+
|
|
93
109
|
// Tracked-change operations (suggestion target)
|
|
94
110
|
readonly onAcceptSuggestion?: () => void;
|
|
95
111
|
readonly onRejectSuggestion?: () => void;
|
|
@@ -134,6 +150,7 @@ export interface EditorActionHostCallbacks {
|
|
|
134
150
|
export interface EditorAction {
|
|
135
151
|
readonly id: string;
|
|
136
152
|
readonly label: string;
|
|
153
|
+
readonly description?: string;
|
|
137
154
|
readonly shortcut?: readonly ShortcutKey[];
|
|
138
155
|
readonly group: ContextMenuGroupId;
|
|
139
156
|
/** Targets for which this action is relevant. */
|
|
@@ -167,6 +184,7 @@ export interface EditorAction {
|
|
|
167
184
|
function mk<K extends keyof EditorActionHostCallbacks>(opts: {
|
|
168
185
|
id: string;
|
|
169
186
|
label: string;
|
|
187
|
+
description?: string;
|
|
170
188
|
shortcut?: readonly ShortcutKey[];
|
|
171
189
|
group: ContextMenuGroupId;
|
|
172
190
|
targetKinds: readonly TargetKind[];
|
|
@@ -178,6 +196,7 @@ function mk<K extends keyof EditorActionHostCallbacks>(opts: {
|
|
|
178
196
|
return {
|
|
179
197
|
id: opts.id,
|
|
180
198
|
label: opts.label,
|
|
199
|
+
...(opts.description ? { description: opts.description } : {}),
|
|
181
200
|
...(opts.shortcut ? { shortcut: opts.shortcut } : {}),
|
|
182
201
|
group: opts.group,
|
|
183
202
|
targetKinds: new Set(opts.targetKinds),
|
|
@@ -211,6 +230,7 @@ function mk<K extends keyof EditorActionHostCallbacks>(opts: {
|
|
|
211
230
|
function mkArg<A, K extends keyof EditorActionHostCallbacks>(opts: {
|
|
212
231
|
id: string;
|
|
213
232
|
label: string;
|
|
233
|
+
description?: string;
|
|
214
234
|
shortcut?: readonly ShortcutKey[];
|
|
215
235
|
group: ContextMenuGroupId;
|
|
216
236
|
targetKinds: readonly TargetKind[];
|
|
@@ -222,6 +242,7 @@ function mkArg<A, K extends keyof EditorActionHostCallbacks>(opts: {
|
|
|
222
242
|
return {
|
|
223
243
|
id: opts.id,
|
|
224
244
|
label: opts.label,
|
|
245
|
+
...(opts.description ? { description: opts.description } : {}),
|
|
225
246
|
...(opts.shortcut ? { shortcut: opts.shortcut } : {}),
|
|
226
247
|
group: opts.group,
|
|
227
248
|
targetKinds: new Set(opts.targetKinds),
|
|
@@ -239,6 +260,41 @@ function mkArg<A, K extends keyof EditorActionHostCallbacks>(opts: {
|
|
|
239
260
|
};
|
|
240
261
|
}
|
|
241
262
|
|
|
263
|
+
/**
|
|
264
|
+
* Build an important command that should remain visible as a disabled
|
|
265
|
+
* row when the host/runtime has not wired the implementation yet. Use
|
|
266
|
+
* sparingly for product-signpost commands such as Insert Image or
|
|
267
|
+
* Replace; most callback-less registry rows should stay hidden.
|
|
268
|
+
*/
|
|
269
|
+
function mkImportant<K extends keyof EditorActionHostCallbacks>(opts: {
|
|
270
|
+
id: string;
|
|
271
|
+
label: string;
|
|
272
|
+
description: string;
|
|
273
|
+
shortcut?: readonly ShortcutKey[];
|
|
274
|
+
group: ContextMenuGroupId;
|
|
275
|
+
targetKinds: readonly TargetKind[];
|
|
276
|
+
modes?: readonly EditorChromeMode[];
|
|
277
|
+
callback: K;
|
|
278
|
+
}): EditorAction {
|
|
279
|
+
return {
|
|
280
|
+
id: opts.id,
|
|
281
|
+
label: opts.label,
|
|
282
|
+
description: opts.description,
|
|
283
|
+
...(opts.shortcut ? { shortcut: opts.shortcut } : {}),
|
|
284
|
+
group: opts.group,
|
|
285
|
+
targetKinds: new Set(opts.targetKinds),
|
|
286
|
+
...(opts.modes ? { modes: new Set(opts.modes) } : {}),
|
|
287
|
+
when: (ctx) =>
|
|
288
|
+
typeof ctx.host[opts.callback] === "function" ? true : "disabled",
|
|
289
|
+
run: (ctx) => {
|
|
290
|
+
const fn = ctx.host[opts.callback] as (() => void) | undefined;
|
|
291
|
+
if (!fn) return;
|
|
292
|
+
fn();
|
|
293
|
+
ctx.dismiss();
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
242
298
|
export const EDITOR_ACTION_REGISTRY: readonly EditorAction[] = [
|
|
243
299
|
// -------- History --------
|
|
244
300
|
mk({
|
|
@@ -341,6 +397,105 @@ export const EDITOR_ACTION_REGISTRY: readonly EditorAction[] = [
|
|
|
341
397
|
targetKinds: ["plain-text", "table-cell"],
|
|
342
398
|
callback: "onToggleStrikethrough",
|
|
343
399
|
}),
|
|
400
|
+
mkArg<string, "onSetParagraphStyle">({
|
|
401
|
+
id: "style-normal",
|
|
402
|
+
label: "Normal text",
|
|
403
|
+
group: "formatting",
|
|
404
|
+
targetKinds: ["plain-text", "table-cell"],
|
|
405
|
+
callback: "onSetParagraphStyle",
|
|
406
|
+
payload: "Normal",
|
|
407
|
+
}),
|
|
408
|
+
mkArg<string, "onSetParagraphStyle">({
|
|
409
|
+
id: "style-heading-1",
|
|
410
|
+
label: "Heading 1",
|
|
411
|
+
shortcut: ["Mod", "Alt", "1"],
|
|
412
|
+
group: "formatting",
|
|
413
|
+
targetKinds: ["plain-text", "table-cell"],
|
|
414
|
+
callback: "onSetParagraphStyle",
|
|
415
|
+
payload: "Heading1",
|
|
416
|
+
}),
|
|
417
|
+
mkArg<string, "onSetParagraphStyle">({
|
|
418
|
+
id: "style-heading-2",
|
|
419
|
+
label: "Heading 2",
|
|
420
|
+
shortcut: ["Mod", "Alt", "2"],
|
|
421
|
+
group: "formatting",
|
|
422
|
+
targetKinds: ["plain-text", "table-cell"],
|
|
423
|
+
callback: "onSetParagraphStyle",
|
|
424
|
+
payload: "Heading2",
|
|
425
|
+
}),
|
|
426
|
+
mkArg<string, "onSetParagraphStyle">({
|
|
427
|
+
id: "style-heading-3",
|
|
428
|
+
label: "Heading 3",
|
|
429
|
+
shortcut: ["Mod", "Alt", "3"],
|
|
430
|
+
group: "formatting",
|
|
431
|
+
targetKinds: ["plain-text", "table-cell"],
|
|
432
|
+
callback: "onSetParagraphStyle",
|
|
433
|
+
payload: "Heading3",
|
|
434
|
+
}),
|
|
435
|
+
mkArg<string, "onSetFontFamily">({
|
|
436
|
+
id: "font-family-aptos",
|
|
437
|
+
label: "Font: Aptos",
|
|
438
|
+
group: "formatting",
|
|
439
|
+
targetKinds: ["plain-text", "table-cell"],
|
|
440
|
+
callback: "onSetFontFamily",
|
|
441
|
+
payload: "Aptos",
|
|
442
|
+
}),
|
|
443
|
+
mkArg<string, "onSetFontFamily">({
|
|
444
|
+
id: "font-family-calibri",
|
|
445
|
+
label: "Font: Calibri",
|
|
446
|
+
group: "formatting",
|
|
447
|
+
targetKinds: ["plain-text", "table-cell"],
|
|
448
|
+
callback: "onSetFontFamily",
|
|
449
|
+
payload: "Calibri",
|
|
450
|
+
}),
|
|
451
|
+
mkArg<number, "onSetFontSize">({
|
|
452
|
+
id: "font-size-11",
|
|
453
|
+
label: "Font size: 11",
|
|
454
|
+
group: "formatting",
|
|
455
|
+
targetKinds: ["plain-text", "table-cell"],
|
|
456
|
+
callback: "onSetFontSize",
|
|
457
|
+
payload: 11,
|
|
458
|
+
}),
|
|
459
|
+
mkArg<number, "onSetFontSize">({
|
|
460
|
+
id: "font-size-12",
|
|
461
|
+
label: "Font size: 12",
|
|
462
|
+
group: "formatting",
|
|
463
|
+
targetKinds: ["plain-text", "table-cell"],
|
|
464
|
+
callback: "onSetFontSize",
|
|
465
|
+
payload: 12,
|
|
466
|
+
}),
|
|
467
|
+
mkArg<string, "onSetTextColor">({
|
|
468
|
+
id: "text-color-black",
|
|
469
|
+
label: "Text color: Black",
|
|
470
|
+
group: "formatting",
|
|
471
|
+
targetKinds: ["plain-text", "table-cell"],
|
|
472
|
+
callback: "onSetTextColor",
|
|
473
|
+
payload: "#000000",
|
|
474
|
+
}),
|
|
475
|
+
mkArg<string, "onSetTextColor">({
|
|
476
|
+
id: "text-color-accent",
|
|
477
|
+
label: "Text color: Accent",
|
|
478
|
+
group: "formatting",
|
|
479
|
+
targetKinds: ["plain-text", "table-cell"],
|
|
480
|
+
callback: "onSetTextColor",
|
|
481
|
+
payload: "#1F6B4F",
|
|
482
|
+
}),
|
|
483
|
+
mkArg<string | null, "onSetHighlightColor">({
|
|
484
|
+
id: "highlight-yellow",
|
|
485
|
+
label: "Highlight: Yellow",
|
|
486
|
+
group: "formatting",
|
|
487
|
+
targetKinds: ["plain-text", "table-cell"],
|
|
488
|
+
callback: "onSetHighlightColor",
|
|
489
|
+
payload: "#FFF2A8",
|
|
490
|
+
}),
|
|
491
|
+
mkArg<string | null, "onSetHighlightColor">({
|
|
492
|
+
id: "highlight-clear",
|
|
493
|
+
label: "Clear highlight",
|
|
494
|
+
group: "formatting",
|
|
495
|
+
targetKinds: ["plain-text", "table-cell"],
|
|
496
|
+
callback: "onSetHighlightColor",
|
|
497
|
+
payload: null,
|
|
498
|
+
}),
|
|
344
499
|
mk({
|
|
345
500
|
id: "list-bulleted",
|
|
346
501
|
label: "Bulleted list",
|
|
@@ -401,6 +556,31 @@ export const EDITOR_ACTION_REGISTRY: readonly EditorAction[] = [
|
|
|
401
556
|
callback: "onSetAlignment",
|
|
402
557
|
payload: "justify",
|
|
403
558
|
}),
|
|
559
|
+
mk({
|
|
560
|
+
id: "insert-page-break",
|
|
561
|
+
label: "Insert page break",
|
|
562
|
+
shortcut: ["Mod", "Enter"],
|
|
563
|
+
group: "misc",
|
|
564
|
+
targetKinds: ["plain-text", "table-cell"],
|
|
565
|
+
callback: "onInsertPageBreak",
|
|
566
|
+
}),
|
|
567
|
+
mkArg<ProductSectionBreakType, "onInsertSectionBreak">({
|
|
568
|
+
id: "insert-section-break-next-page",
|
|
569
|
+
label: "Insert section break",
|
|
570
|
+
description: "Next page section break",
|
|
571
|
+
group: "misc",
|
|
572
|
+
targetKinds: ["plain-text", "table-cell"],
|
|
573
|
+
callback: "onInsertSectionBreak",
|
|
574
|
+
payload: "nextPage",
|
|
575
|
+
}),
|
|
576
|
+
mkImportant({
|
|
577
|
+
id: "insert-image",
|
|
578
|
+
label: "Insert image…",
|
|
579
|
+
description: "Needs a host file picker before it can run.",
|
|
580
|
+
group: "misc",
|
|
581
|
+
targetKinds: [],
|
|
582
|
+
callback: "onInsertImage",
|
|
583
|
+
}),
|
|
404
584
|
mk({
|
|
405
585
|
id: "insert-table",
|
|
406
586
|
label: "Insert table",
|
|
@@ -416,6 +596,46 @@ export const EDITOR_ACTION_REGISTRY: readonly EditorAction[] = [
|
|
|
416
596
|
callback: "onAddComment",
|
|
417
597
|
}),
|
|
418
598
|
|
|
599
|
+
// -------- Search / navigation / app-level commands --------
|
|
600
|
+
// Empty targetKinds keeps these out of right-click local menus. The
|
|
601
|
+
// global command palette still projects them from the shared registry.
|
|
602
|
+
mkImportant({
|
|
603
|
+
id: "find",
|
|
604
|
+
label: "Find…",
|
|
605
|
+
description: "Host search panel is not wired.",
|
|
606
|
+
shortcut: ["Mod", "F"],
|
|
607
|
+
group: "misc",
|
|
608
|
+
targetKinds: [],
|
|
609
|
+
callback: "onFindRequested",
|
|
610
|
+
}),
|
|
611
|
+
mkImportant({
|
|
612
|
+
id: "replace",
|
|
613
|
+
label: "Replace…",
|
|
614
|
+
description: "Host replace panel is not wired.",
|
|
615
|
+
shortcut: ["Ctrl", "H"],
|
|
616
|
+
group: "misc",
|
|
617
|
+
targetKinds: [],
|
|
618
|
+
callback: "onReplaceRequested",
|
|
619
|
+
}),
|
|
620
|
+
mkImportant({
|
|
621
|
+
id: "go-to",
|
|
622
|
+
label: "Go to…",
|
|
623
|
+
description: "Host navigation panel is not wired.",
|
|
624
|
+
shortcut: ["Ctrl", "G"],
|
|
625
|
+
group: "misc",
|
|
626
|
+
targetKinds: [],
|
|
627
|
+
callback: "onGoToRequested",
|
|
628
|
+
}),
|
|
629
|
+
mkImportant({
|
|
630
|
+
id: "print",
|
|
631
|
+
label: "Print…",
|
|
632
|
+
description: "Host print/export flow is not wired.",
|
|
633
|
+
shortcut: ["Mod", "P"],
|
|
634
|
+
group: "misc",
|
|
635
|
+
targetKinds: [],
|
|
636
|
+
callback: "onPrintRequested",
|
|
637
|
+
}),
|
|
638
|
+
|
|
419
639
|
// -------- Suggestion / tracked change --------
|
|
420
640
|
mk({
|
|
421
641
|
id: "accept-suggestion",
|
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Progressive-disclosure discipline (designsystem.md §2.1 principle 4):
|
|
14
14
|
* - Actions without a wired callback are hidden, not rendered
|
|
15
|
-
* disabled
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* disabled unless the registry marks them as important signposts
|
|
16
|
+
* by returning `"disabled"` from `when()`. Those rows stay visible
|
|
17
|
+
* with an explanation so users can see that the product recognizes
|
|
18
|
+
* the workflow even when the host has not wired it yet.
|
|
18
19
|
* - Mode-filtered actions (e.g. `scope-open-card` is
|
|
19
20
|
* workflow/review-only) only appear when the composition mode
|
|
20
21
|
* allows them.
|
|
@@ -33,7 +34,6 @@ import type {
|
|
|
33
34
|
CommandPaletteGroup,
|
|
34
35
|
CommandPaletteItem,
|
|
35
36
|
} from "./tw-command-palette";
|
|
36
|
-
import type { ContextMenuGroupId } from "./tw-context-menu";
|
|
37
37
|
import type { ShortcutKey } from "./tw-shortcut-hint";
|
|
38
38
|
|
|
39
39
|
/**
|
|
@@ -90,43 +90,63 @@ export function formatShortcutForPalette(
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
/**
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
93
|
+
* Product-facing command palette buckets. These are intentionally not
|
|
94
|
+
* the context-menu `ContextMenuGroupId`s: right-click menus group by
|
|
95
|
+
* local action family, while the palette groups by user intent.
|
|
96
96
|
*/
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
97
|
+
type ProductPaletteGroupId =
|
|
98
|
+
| "commands"
|
|
99
|
+
| "search"
|
|
100
|
+
| "navigation"
|
|
101
|
+
| "mode"
|
|
102
|
+
| "diagnostics";
|
|
103
|
+
|
|
104
|
+
const GROUP_LABELS: Record<ProductPaletteGroupId, string> = {
|
|
105
|
+
commands: "Commands",
|
|
106
|
+
search: "Search",
|
|
107
|
+
navigation: "Navigation",
|
|
108
|
+
mode: "Mode",
|
|
109
|
+
diagnostics: "Diagnostics",
|
|
104
110
|
};
|
|
105
111
|
|
|
106
112
|
/**
|
|
107
|
-
* Stable group order
|
|
108
|
-
* designsystem.md §2.1 (clipboard first because it's always available,
|
|
109
|
-
* review + comment next because they're the primary legal-review
|
|
110
|
-
* actions, table + formatting after, misc last).
|
|
113
|
+
* Stable product group order per editor-product Slice 3.
|
|
111
114
|
*/
|
|
112
|
-
const GROUP_ORDER: readonly
|
|
113
|
-
"
|
|
114
|
-
"
|
|
115
|
-
"
|
|
116
|
-
"
|
|
117
|
-
"
|
|
118
|
-
"misc",
|
|
115
|
+
const GROUP_ORDER: readonly ProductPaletteGroupId[] = [
|
|
116
|
+
"commands",
|
|
117
|
+
"search",
|
|
118
|
+
"navigation",
|
|
119
|
+
"mode",
|
|
120
|
+
"diagnostics",
|
|
119
121
|
];
|
|
120
122
|
|
|
121
|
-
function
|
|
123
|
+
function actionAvailability(
|
|
122
124
|
action: EditorAction,
|
|
123
125
|
ctx: EditorActionDispatchContext,
|
|
124
|
-
):
|
|
126
|
+
): false | "enabled" | "disabled" {
|
|
125
127
|
const verdict = action.when ? action.when(ctx) : true;
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
if (verdict === false) return false;
|
|
129
|
+
return verdict === "disabled" ? "disabled" : "enabled";
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function paletteGroupForAction(action: EditorAction): ProductPaletteGroupId {
|
|
133
|
+
switch (action.id) {
|
|
134
|
+
case "find":
|
|
135
|
+
case "replace":
|
|
136
|
+
return "search";
|
|
137
|
+
case "go-to":
|
|
138
|
+
case "jump-to-comment-in-rail":
|
|
139
|
+
case "scope-jump-in-rail":
|
|
140
|
+
case "scope-open-card":
|
|
141
|
+
return "navigation";
|
|
142
|
+
case "scope-mark-resolved":
|
|
143
|
+
return "mode";
|
|
144
|
+
case "object-info":
|
|
145
|
+
case "print":
|
|
146
|
+
return "diagnostics";
|
|
147
|
+
default:
|
|
148
|
+
return "commands";
|
|
149
|
+
}
|
|
130
150
|
}
|
|
131
151
|
|
|
132
152
|
export interface BuildPaletteGroupsInput {
|
|
@@ -145,15 +165,18 @@ export function buildPaletteGroupsFromRegistry(
|
|
|
145
165
|
dismiss: input.dismiss,
|
|
146
166
|
};
|
|
147
167
|
|
|
148
|
-
const byGroup = new Map<
|
|
168
|
+
const byGroup = new Map<ProductPaletteGroupId, CommandPaletteItem[]>();
|
|
149
169
|
|
|
150
170
|
for (const action of EDITOR_ACTION_REGISTRY) {
|
|
151
171
|
if (action.modes && !action.modes.has(input.mode)) continue;
|
|
152
|
-
|
|
172
|
+
const availability = actionAvailability(action, ctx);
|
|
173
|
+
if (availability === false) continue;
|
|
153
174
|
|
|
154
175
|
const item: CommandPaletteItem = {
|
|
155
176
|
id: action.id,
|
|
156
177
|
label: action.label,
|
|
178
|
+
...(action.description ? { description: action.description } : {}),
|
|
179
|
+
...(availability === "disabled" ? { disabled: true } : {}),
|
|
157
180
|
// Chrome Closure Pass · Task 4 (designsystem.md §6.25) —
|
|
158
181
|
// preserve the registry shortcut so the palette row shows
|
|
159
182
|
// the same hint as the matching context-menu / tooltip.
|
|
@@ -163,9 +186,10 @@ export function buildPaletteGroupsFromRegistry(
|
|
|
163
186
|
onInvoke: () => action.run(ctx),
|
|
164
187
|
};
|
|
165
188
|
|
|
166
|
-
const
|
|
189
|
+
const groupId = paletteGroupForAction(action);
|
|
190
|
+
const bucket = byGroup.get(groupId) ?? [];
|
|
167
191
|
bucket.push(item);
|
|
168
|
-
byGroup.set(
|
|
192
|
+
byGroup.set(groupId, bucket);
|
|
169
193
|
}
|
|
170
194
|
|
|
171
195
|
const groups: CommandPaletteGroup[] = [];
|
|
@@ -251,6 +251,7 @@ export const TwChromeOverlay: React.FC<TwChromeOverlayProps> = ({
|
|
|
251
251
|
{pageStackScrollRoot !== undefined ? (
|
|
252
252
|
<TwPageStackChromeLayer
|
|
253
253
|
facet={facet}
|
|
254
|
+
geometryFacet={geometryFacet}
|
|
254
255
|
scrollRoot={pageStackScrollRoot}
|
|
255
256
|
renderFrameRevision={renderFrameRevision ?? 0}
|
|
256
257
|
activeStory={activeStory ?? { kind: "main" }}
|