@beyondwork/docx-react-component 1.0.38 → 1.0.40
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 +305 -6
- package/src/core/commands/table-structure-commands.ts +31 -2
- package/src/core/commands/text-commands.ts +122 -2
- package/src/index.ts +9 -0
- package/src/io/docx-session.ts +1 -0
- package/src/io/export/serialize-numbering.ts +42 -8
- 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/ooxml/parse-fields.ts +10 -3
- 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/xml-attr-helpers.ts +60 -0
- package/src/io/ooxml/xml-element.ts +19 -0
- package/src/model/canonical-document.ts +83 -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-runtime.ts +141 -18
- package/src/runtime/layout/docx-font-loader.ts +30 -11
- package/src/runtime/layout/index.ts +2 -0
- package/src/runtime/layout/inert-layout-facet.ts +3 -0
- package/src/runtime/layout/layout-engine-instance.ts +69 -2
- package/src/runtime/layout/layout-invalidation.ts +14 -5
- package/src/runtime/layout/page-graph.ts +36 -0
- package/src/runtime/layout/paginate-paragraph-lines.ts +128 -0
- package/src/runtime/layout/paginated-layout-engine.ts +342 -28
- package/src/runtime/layout/project-block-fragments.ts +154 -20
- package/src/runtime/layout/public-facet.ts +81 -1
- 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 +21 -1
- package/src/runtime/numbering-prefix.ts +5 -0
- package/src/runtime/paragraph-style-resolver.ts +194 -0
- package/src/runtime/render/render-kernel.ts +5 -1
- 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/workflow-rail-segments.ts +149 -1
- package/src/ui/WordReviewEditor.tsx +302 -5
- 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 +22 -0
- package/src/ui/editor-surface-controller.tsx +9 -1
- package/src/ui/headless/chrome-registry.ts +34 -5
- package/src/ui/headless/scoped-chrome-policy.ts +29 -0
- package/src/ui-tailwind/chrome/review-queue-bar.tsx +2 -14
- package/src/ui-tailwind/chrome/role-action-sets.ts +14 -8
- package/src/ui-tailwind/chrome/tw-mode-dock.tsx +80 -0
- package/src/ui-tailwind/chrome/tw-selection-anchor-resolver.ts +7 -10
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +11 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +11 -0
- package/src/ui-tailwind/chrome/tw-table-border-picker.tsx +245 -0
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +101 -21
- package/src/ui-tailwind/chrome/tw-table-grip-layer.tsx +353 -0
- package/src/ui-tailwind/chrome-overlay/chrome-overlay-projector.ts +5 -1
- package/src/ui-tailwind/chrome-overlay/index.ts +2 -6
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +82 -18
- package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +133 -0
- package/src/ui-tailwind/chrome-overlay/tw-scope-card.tsx +386 -0
- package/src/ui-tailwind/chrome-overlay/tw-scope-rail-layer.tsx +140 -69
- package/src/ui-tailwind/editor-surface/page-slice-util.ts +15 -0
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +28 -3
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +7 -2
- 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 +170 -63
- 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 -78
- 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 +6 -5
- package/src/ui-tailwind/theme/editor-theme.css +108 -15
- package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +122 -1
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +36 -3
- package/src/ui-tailwind/tw-review-workspace.tsx +207 -54
- package/src/runtime/collab-review-sync.ts +0 -254
- package/src/ui-tailwind/chrome-overlay/tw-workspace-view-switcher.tsx +0 -95
- package/src/ui-tailwind/editor-surface/pm-collab-plugins.ts +0 -40
|
@@ -408,8 +408,16 @@
|
|
|
408
408
|
box-shadow: inset -1px 0 0 color-mix(in srgb, var(--color-danger) 35%, transparent);
|
|
409
409
|
}
|
|
410
410
|
|
|
411
|
+
/*
|
|
412
|
+
* `wre-workflow-inline-active` no longer emits a visual outline. The
|
|
413
|
+
* per-run inset box-shadow produced a halo around every text fragment
|
|
414
|
+
* (one box per run, due to box-decoration-break: clone above), which
|
|
415
|
+
* fought with the overlay's flat tint. The class name is kept on the
|
|
416
|
+
* inline decoration as a data hook (no visual), and emphasis for the
|
|
417
|
+
* active scope now lives on the ChromeOverlay rail stripe + scope card.
|
|
418
|
+
*/
|
|
411
419
|
.prosemirror-surface .ProseMirror .wre-workflow-inline-active {
|
|
412
|
-
|
|
420
|
+
/* intentionally empty — visual emphasis handled by ChromeOverlay */
|
|
413
421
|
}
|
|
414
422
|
|
|
415
423
|
/*
|
|
@@ -423,9 +431,37 @@
|
|
|
423
431
|
pointer-events: none;
|
|
424
432
|
}
|
|
425
433
|
|
|
434
|
+
/*
|
|
435
|
+
* ─── Gutter lane tokens ───
|
|
436
|
+
*
|
|
437
|
+
* The scope rail and scope card chrome live in a reserved lane to the
|
|
438
|
+
* left of the page frame so they visibly read as chrome (not document
|
|
439
|
+
* content). Page surfaces use 64px, canvas surfaces 48px. Host apps
|
|
440
|
+
* can override via CSS custom property.
|
|
441
|
+
*/
|
|
442
|
+
:root {
|
|
443
|
+
--wre-gutter-lane-width: 64px;
|
|
444
|
+
--wre-gutter-lane-pad: 8px;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
.wre-canvas-surface {
|
|
448
|
+
--wre-gutter-lane-width: 48px;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/*
|
|
452
|
+
* The page-with-gutter grid shell allocates the gutter as its own
|
|
453
|
+
* column so absolute-positioned chrome overlays (which fill inset 0 of
|
|
454
|
+
* this shell) land INSIDE the gutter, not over the shell background.
|
|
455
|
+
*/
|
|
456
|
+
.wre-page-with-gutter {
|
|
457
|
+
display: grid;
|
|
458
|
+
grid-template-columns: var(--wre-gutter-lane-width) 1fr;
|
|
459
|
+
position: relative;
|
|
460
|
+
}
|
|
461
|
+
|
|
426
462
|
.wre-scope-rail-tint {
|
|
427
463
|
position: absolute;
|
|
428
|
-
border-radius: 0.
|
|
464
|
+
border-radius: 0.2rem;
|
|
429
465
|
pointer-events: none;
|
|
430
466
|
z-index: 0;
|
|
431
467
|
transition: background 140ms ease-out;
|
|
@@ -452,32 +488,89 @@
|
|
|
452
488
|
outline-offset: -1px;
|
|
453
489
|
}
|
|
454
490
|
|
|
491
|
+
/*
|
|
492
|
+
* ─── Scope rail stripe ───
|
|
493
|
+
*
|
|
494
|
+
* The rail stripe is the rest-state representation of a scope: a 4px
|
|
495
|
+
* color stripe in the gutter lane. Posture color comes from the
|
|
496
|
+
* accent/warning/insert/secondary/danger tokens. Hover widens the
|
|
497
|
+
* stripe via transform (zero layout cost) and reveals the label pill.
|
|
498
|
+
*/
|
|
499
|
+
.wre-scope-rail-stripe {
|
|
500
|
+
position: absolute;
|
|
501
|
+
width: 4px;
|
|
502
|
+
border-radius: 2px;
|
|
503
|
+
background: currentColor;
|
|
504
|
+
pointer-events: auto;
|
|
505
|
+
cursor: pointer;
|
|
506
|
+
z-index: 1;
|
|
507
|
+
transform-origin: left center;
|
|
508
|
+
transition: transform 120ms ease-out, opacity 120ms ease-out;
|
|
509
|
+
opacity: 0.75;
|
|
510
|
+
/* Reset button defaults. */
|
|
511
|
+
border: none;
|
|
512
|
+
padding: 0;
|
|
513
|
+
margin: 0;
|
|
514
|
+
font: inherit;
|
|
515
|
+
color: inherit;
|
|
516
|
+
background-clip: padding-box;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
.wre-scope-rail-stripe:hover,
|
|
520
|
+
.wre-scope-rail-stripe:focus-visible {
|
|
521
|
+
transform: scaleX(1.5);
|
|
522
|
+
opacity: 1;
|
|
523
|
+
outline: none;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
.wre-scope-rail-stripe-active {
|
|
527
|
+
opacity: 1;
|
|
528
|
+
transform: scaleX(1.75);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
.wre-scope-rail-stripe.wre-scope-rail-label-accent { color: var(--color-accent); }
|
|
532
|
+
.wre-scope-rail-stripe.wre-scope-rail-label-warning { color: var(--color-warning); }
|
|
533
|
+
.wre-scope-rail-stripe.wre-scope-rail-label-insert { color: var(--color-insert); }
|
|
534
|
+
.wre-scope-rail-stripe.wre-scope-rail-label-secondary { color: var(--color-secondary); }
|
|
535
|
+
.wre-scope-rail-stripe.wre-scope-rail-label-danger { color: var(--color-danger); }
|
|
536
|
+
|
|
537
|
+
/*
|
|
538
|
+
* ─── Scope rail label pill ───
|
|
539
|
+
*
|
|
540
|
+
* Shown only on stripe hover (CSS-driven). The pill overlays the
|
|
541
|
+
* stripe with icon + short posture label, anchored to the first line
|
|
542
|
+
* of the scope.
|
|
543
|
+
*/
|
|
455
544
|
.wre-scope-rail-label {
|
|
456
545
|
position: absolute;
|
|
457
546
|
display: flex;
|
|
458
|
-
flex-direction: column;
|
|
459
547
|
align-items: center;
|
|
460
548
|
justify-content: center;
|
|
461
|
-
gap: 0.
|
|
462
|
-
padding: 0.
|
|
463
|
-
border-radius:
|
|
549
|
+
gap: 0.2rem;
|
|
550
|
+
padding: 0.15rem 0.3rem;
|
|
551
|
+
border-radius: var(--radius-sm);
|
|
464
552
|
border: 1px solid transparent;
|
|
465
553
|
background: var(--color-canvas, #fff);
|
|
466
|
-
box-shadow:
|
|
467
|
-
font-size:
|
|
554
|
+
box-shadow: var(--shadow-sm);
|
|
555
|
+
font-size: 9.5px;
|
|
468
556
|
line-height: 1;
|
|
469
557
|
text-transform: uppercase;
|
|
470
|
-
letter-spacing: 0.
|
|
558
|
+
letter-spacing: 0.06em;
|
|
471
559
|
font-weight: 600;
|
|
472
560
|
cursor: pointer;
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
561
|
+
z-index: 2;
|
|
562
|
+
opacity: 0;
|
|
563
|
+
pointer-events: none;
|
|
564
|
+
transition: opacity 140ms ease-out, transform 140ms ease-out;
|
|
565
|
+
transform: translateX(-4px);
|
|
476
566
|
}
|
|
477
567
|
|
|
478
|
-
.wre-scope-rail-
|
|
479
|
-
|
|
480
|
-
|
|
568
|
+
.wre-scope-rail-stripe:hover + .wre-scope-rail-label,
|
|
569
|
+
.wre-scope-rail-label:hover,
|
|
570
|
+
.wre-scope-rail-stripe:focus-visible + .wre-scope-rail-label {
|
|
571
|
+
opacity: 1;
|
|
572
|
+
pointer-events: auto;
|
|
573
|
+
transform: translateX(0);
|
|
481
574
|
}
|
|
482
575
|
|
|
483
576
|
.wre-scope-rail-label-accent {
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
|
|
16
16
|
import React, { useState } from "react";
|
|
17
17
|
import * as Popover from "@radix-ui/react-popover";
|
|
18
|
+
import * as Toggle from "@radix-ui/react-toggle";
|
|
19
|
+
import * as Tooltip from "@radix-ui/react-tooltip";
|
|
18
20
|
import {
|
|
19
21
|
BookmarkCheck,
|
|
20
22
|
Check,
|
|
@@ -23,8 +25,13 @@ import {
|
|
|
23
25
|
ChevronLeft,
|
|
24
26
|
ChevronRight,
|
|
25
27
|
CircleOff,
|
|
28
|
+
Eye,
|
|
29
|
+
EyeOff,
|
|
30
|
+
FileDiff,
|
|
26
31
|
Flag,
|
|
27
32
|
Hand,
|
|
33
|
+
MessageSquare,
|
|
34
|
+
MessageSquareDot,
|
|
28
35
|
MessageSquareText,
|
|
29
36
|
Rows3,
|
|
30
37
|
SkipForward,
|
|
@@ -38,6 +45,7 @@ import type {
|
|
|
38
45
|
ReviewQueueSnapshot,
|
|
39
46
|
ScopeRailPosture,
|
|
40
47
|
} from "../../api/public-types";
|
|
48
|
+
import type { SessionCapabilities } from "../../runtime/session-capabilities";
|
|
41
49
|
import type { ScopedChromePolicy } from "../../ui/headless/scoped-chrome-policy";
|
|
42
50
|
import type { ToolbarChromeItemId } from "../../ui/headless/chrome-registry";
|
|
43
51
|
import { preserveEditorSelectionMouseDown } from "../../ui/headless/preserve-editor-selection";
|
|
@@ -68,7 +76,23 @@ export interface TwRoleActionRegionProps {
|
|
|
68
76
|
workflowItem?: WorkflowWorkItemSnapshot | null;
|
|
69
77
|
markupDisplay?: MarkupDisplayMode;
|
|
70
78
|
|
|
71
|
-
//
|
|
79
|
+
// Shared: editor + review role
|
|
80
|
+
canAddComment?: boolean;
|
|
81
|
+
showTrackedChanges?: boolean;
|
|
82
|
+
onAddComment?: () => void;
|
|
83
|
+
onShowTrackedChangesChange?: (show: boolean) => void;
|
|
84
|
+
/**
|
|
85
|
+
* Session capabilities used to gate the role-region tracked-changes
|
|
86
|
+
* toggle (mirrors the right-cluster gate at tw-toolbar.tsx). When
|
|
87
|
+
* `capabilities.trackChangesSupported` is false, the toggle is disabled.
|
|
88
|
+
*/
|
|
89
|
+
capabilities?: SessionCapabilities;
|
|
90
|
+
|
|
91
|
+
// Review sidebar panel (optional — hidden when not provided)
|
|
92
|
+
onReviewSidebarTrackedChanges?: () => void;
|
|
93
|
+
onReviewSidebarComments?: () => void;
|
|
94
|
+
|
|
95
|
+
// Workflow + review role: scope posture menu
|
|
72
96
|
onMarkScopePosture?: (posture: ScopeRailPosture) => void;
|
|
73
97
|
|
|
74
98
|
// Review role
|
|
@@ -142,7 +166,104 @@ interface RoleActionButtonProps {
|
|
|
142
166
|
|
|
143
167
|
function RoleActionButton(arg: RoleActionButtonProps): React.JSX.Element | null {
|
|
144
168
|
const { id, props } = arg;
|
|
169
|
+
const focusRingClass =
|
|
170
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-canvas";
|
|
145
171
|
switch (id) {
|
|
172
|
+
case "comment":
|
|
173
|
+
return (
|
|
174
|
+
<Tooltip.Root>
|
|
175
|
+
<Tooltip.Trigger asChild>
|
|
176
|
+
<button
|
|
177
|
+
type="button"
|
|
178
|
+
aria-label="Add comment"
|
|
179
|
+
disabled={!props.canAddComment || !props.onAddComment}
|
|
180
|
+
onMouseDown={preserveEditorSelectionMouseDown}
|
|
181
|
+
onClick={props.onAddComment}
|
|
182
|
+
className={`inline-flex h-6 w-6 items-center justify-center rounded-md text-secondary transition-colors hover:bg-surface disabled:cursor-not-allowed disabled:opacity-40 outline-none ${focusRingClass}`}
|
|
183
|
+
data-testid="role-add-comment"
|
|
184
|
+
>
|
|
185
|
+
<MessageSquare className="h-3.5 w-3.5" />
|
|
186
|
+
</button>
|
|
187
|
+
</Tooltip.Trigger>
|
|
188
|
+
<Tooltip.Portal>
|
|
189
|
+
<Tooltip.Content className="rounded-md bg-primary px-2 py-1 text-xs text-white shadow-md z-50" sideOffset={6}>
|
|
190
|
+
Add comment
|
|
191
|
+
</Tooltip.Content>
|
|
192
|
+
</Tooltip.Portal>
|
|
193
|
+
</Tooltip.Root>
|
|
194
|
+
);
|
|
195
|
+
case "tracked-changes-toggle":
|
|
196
|
+
return (
|
|
197
|
+
<Tooltip.Root>
|
|
198
|
+
<Tooltip.Trigger asChild>
|
|
199
|
+
<Toggle.Root
|
|
200
|
+
pressed={props.showTrackedChanges ?? false}
|
|
201
|
+
onPressedChange={(v) => props.onShowTrackedChangesChange?.(v)}
|
|
202
|
+
disabled={props.capabilities ? !props.capabilities.trackChangesSupported : false}
|
|
203
|
+
onMouseDown={preserveEditorSelectionMouseDown}
|
|
204
|
+
className={`inline-flex h-6 w-6 items-center justify-center rounded-md text-secondary transition-colors hover:bg-surface data-[state=on]:bg-canvas data-[state=on]:text-accent data-[state=on]:ring-1 data-[state=on]:ring-accent/30 data-[state=on]:shadow-sm outline-none disabled:opacity-40 ${focusRingClass}`}
|
|
205
|
+
data-testid="role-tracked-changes-toggle"
|
|
206
|
+
>
|
|
207
|
+
{(props.showTrackedChanges ?? false) ? (
|
|
208
|
+
<Eye className="h-3.5 w-3.5" />
|
|
209
|
+
) : (
|
|
210
|
+
<EyeOff className="h-3.5 w-3.5" />
|
|
211
|
+
)}
|
|
212
|
+
</Toggle.Root>
|
|
213
|
+
</Tooltip.Trigger>
|
|
214
|
+
<Tooltip.Portal>
|
|
215
|
+
<Tooltip.Content className="rounded-md bg-primary px-2 py-1 text-xs text-white shadow-md z-50" sideOffset={6}>
|
|
216
|
+
{(props.showTrackedChanges ?? false) ? "Hide tracked changes" : "Show tracked changes"}
|
|
217
|
+
</Tooltip.Content>
|
|
218
|
+
</Tooltip.Portal>
|
|
219
|
+
</Tooltip.Root>
|
|
220
|
+
);
|
|
221
|
+
case "review-sidebar-tracked-changes":
|
|
222
|
+
return (
|
|
223
|
+
<Tooltip.Root>
|
|
224
|
+
<Tooltip.Trigger asChild>
|
|
225
|
+
<button
|
|
226
|
+
type="button"
|
|
227
|
+
aria-label="Show tracked changes in sidebar"
|
|
228
|
+
disabled={!props.onReviewSidebarTrackedChanges}
|
|
229
|
+
onMouseDown={preserveEditorSelectionMouseDown}
|
|
230
|
+
onClick={props.onReviewSidebarTrackedChanges}
|
|
231
|
+
className={`inline-flex h-6 w-6 items-center justify-center rounded-md text-secondary transition-colors hover:bg-surface disabled:cursor-not-allowed disabled:opacity-40 outline-none ${focusRingClass}`}
|
|
232
|
+
data-testid="role-sidebar-tracked-changes"
|
|
233
|
+
>
|
|
234
|
+
<FileDiff className="h-3.5 w-3.5" />
|
|
235
|
+
</button>
|
|
236
|
+
</Tooltip.Trigger>
|
|
237
|
+
<Tooltip.Portal>
|
|
238
|
+
<Tooltip.Content className="rounded-md bg-primary px-2 py-1 text-xs text-white shadow-md z-50" sideOffset={6}>
|
|
239
|
+
Tracked changes panel
|
|
240
|
+
</Tooltip.Content>
|
|
241
|
+
</Tooltip.Portal>
|
|
242
|
+
</Tooltip.Root>
|
|
243
|
+
);
|
|
244
|
+
case "review-sidebar-comments":
|
|
245
|
+
return (
|
|
246
|
+
<Tooltip.Root>
|
|
247
|
+
<Tooltip.Trigger asChild>
|
|
248
|
+
<button
|
|
249
|
+
type="button"
|
|
250
|
+
aria-label="Show comments in sidebar"
|
|
251
|
+
disabled={!props.onReviewSidebarComments}
|
|
252
|
+
onMouseDown={preserveEditorSelectionMouseDown}
|
|
253
|
+
onClick={props.onReviewSidebarComments}
|
|
254
|
+
className={`inline-flex h-6 w-6 items-center justify-center rounded-md text-secondary transition-colors hover:bg-surface disabled:cursor-not-allowed disabled:opacity-40 outline-none ${focusRingClass}`}
|
|
255
|
+
data-testid="role-sidebar-comments"
|
|
256
|
+
>
|
|
257
|
+
<MessageSquareDot className="h-3.5 w-3.5" />
|
|
258
|
+
</button>
|
|
259
|
+
</Tooltip.Trigger>
|
|
260
|
+
<Tooltip.Portal>
|
|
261
|
+
<Tooltip.Content className="rounded-md bg-primary px-2 py-1 text-xs text-white shadow-md z-50" sideOffset={6}>
|
|
262
|
+
Comments panel
|
|
263
|
+
</Tooltip.Content>
|
|
264
|
+
</Tooltip.Portal>
|
|
265
|
+
</Tooltip.Root>
|
|
266
|
+
);
|
|
146
267
|
case "editor-scope-posture-menu":
|
|
147
268
|
return (
|
|
148
269
|
<TwScopePostureMenu
|
|
@@ -42,6 +42,8 @@ import {
|
|
|
42
42
|
|
|
43
43
|
import type {
|
|
44
44
|
ActiveListContext,
|
|
45
|
+
ChromePinSurface,
|
|
46
|
+
ChromePinsState,
|
|
45
47
|
CompatibilityPanelSnapshot,
|
|
46
48
|
EditorRole,
|
|
47
49
|
EditorStoryTarget,
|
|
@@ -49,6 +51,7 @@ import type {
|
|
|
49
51
|
FormattingStateSnapshot,
|
|
50
52
|
FormattingAlignment,
|
|
51
53
|
InsertImageOptions,
|
|
54
|
+
PinState,
|
|
52
55
|
ReviewQueueSnapshot,
|
|
53
56
|
ScopeRailPosture,
|
|
54
57
|
SectionBreakType,
|
|
@@ -61,6 +64,7 @@ import type {
|
|
|
61
64
|
import type { SessionCapabilities } from "../../runtime/session-capabilities";
|
|
62
65
|
import {
|
|
63
66
|
getToolbarChromePlacement,
|
|
67
|
+
isChromeItemOwnedByRoleRegion,
|
|
64
68
|
isToolbarChromeItemVisible,
|
|
65
69
|
resolveScopedChromePolicy,
|
|
66
70
|
type ScopedChromePolicy,
|
|
@@ -72,6 +76,7 @@ import {
|
|
|
72
76
|
type MarkupDisplayMode,
|
|
73
77
|
type WorkflowWorkItemSnapshot,
|
|
74
78
|
} from "./tw-role-action-region";
|
|
79
|
+
import { TwDetachHandle } from "../chrome/tw-detach-handle";
|
|
75
80
|
import { TwToolbarIconButton } from "./tw-toolbar-icon-button";
|
|
76
81
|
|
|
77
82
|
export interface TwToolbarProps {
|
|
@@ -144,7 +149,10 @@ export interface TwToolbarProps {
|
|
|
144
149
|
/** Markup display mode for the review role. */
|
|
145
150
|
markupDisplay?: MarkupDisplayMode;
|
|
146
151
|
|
|
147
|
-
//
|
|
152
|
+
// Shared: editor + review role (comment + TC in role region)
|
|
153
|
+
onReviewSidebarTrackedChanges?: () => void;
|
|
154
|
+
onReviewSidebarComments?: () => void;
|
|
155
|
+
// Workflow + review role: scope posture
|
|
148
156
|
onMarkScopePosture?: (posture: ScopeRailPosture) => void;
|
|
149
157
|
// Review role
|
|
150
158
|
onReviewPrev?: () => void;
|
|
@@ -162,6 +170,10 @@ export interface TwToolbarProps {
|
|
|
162
170
|
onWorkflowSkip?: () => void;
|
|
163
171
|
onWorkflowMarkBlocked?: () => void;
|
|
164
172
|
onWorkflowJumpToScope?: () => void;
|
|
173
|
+
/** Current chrome pin state; when supplied enables the topnav detach handle. */
|
|
174
|
+
chromePins?: ChromePinsState;
|
|
175
|
+
/** Called when the user detaches or re-attaches the topnav. */
|
|
176
|
+
onChromePinChange?: (surface: ChromePinSurface, pin: PinState | null) => void;
|
|
165
177
|
}
|
|
166
178
|
|
|
167
179
|
export interface ToolbarInteractionPolicy {
|
|
@@ -219,7 +231,12 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
219
231
|
const showTextColors = isToolbarChromeItemVisible(scopedChromePolicy, "text-colors");
|
|
220
232
|
const showParagraphAlignment = isToolbarChromeItemVisible(scopedChromePolicy, "paragraph-alignment");
|
|
221
233
|
const showInsertMenu = isToolbarChromeItemVisible(scopedChromePolicy, "insert-actions");
|
|
222
|
-
const showTrackedChangesToggle =
|
|
234
|
+
const showTrackedChangesToggle =
|
|
235
|
+
isToolbarChromeItemVisible(scopedChromePolicy, "tracked-changes-toggle") &&
|
|
236
|
+
!isChromeItemOwnedByRoleRegion("tracked-changes-toggle", props.role);
|
|
237
|
+
const showRightClusterComment =
|
|
238
|
+
isToolbarChromeItemVisible(scopedChromePolicy, "comment") &&
|
|
239
|
+
!isChromeItemOwnedByRoleRegion("comment", props.role);
|
|
223
240
|
const showHealth =
|
|
224
241
|
showDiagnosticsChrome &&
|
|
225
242
|
isToolbarChromeItemVisible(scopedChromePolicy, "health") &&
|
|
@@ -527,6 +544,13 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
527
544
|
reviewQueue={props.reviewQueue}
|
|
528
545
|
workflowItem={props.workflowItem}
|
|
529
546
|
markupDisplay={props.markupDisplay}
|
|
547
|
+
canAddComment={canAddComment}
|
|
548
|
+
showTrackedChanges={props.showTrackedChanges}
|
|
549
|
+
capabilities={caps}
|
|
550
|
+
onAddComment={props.onAddComment}
|
|
551
|
+
onShowTrackedChangesChange={props.onShowTrackedChangesChange}
|
|
552
|
+
onReviewSidebarTrackedChanges={props.onReviewSidebarTrackedChanges}
|
|
553
|
+
onReviewSidebarComments={props.onReviewSidebarComments}
|
|
530
554
|
onMarkScopePosture={props.onMarkScopePosture}
|
|
531
555
|
onReviewPrev={props.onReviewPrev}
|
|
532
556
|
onReviewNext={props.onReviewNext}
|
|
@@ -567,7 +591,7 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
567
591
|
</>
|
|
568
592
|
) : null}
|
|
569
593
|
|
|
570
|
-
{
|
|
594
|
+
{showRightClusterComment ? (
|
|
571
595
|
<TwToolbarIconButton
|
|
572
596
|
icon={MessageSquare}
|
|
573
597
|
label="Add comment"
|
|
@@ -809,6 +833,15 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
809
833
|
onClick={props.onExport}
|
|
810
834
|
/>
|
|
811
835
|
) : null}
|
|
836
|
+
|
|
837
|
+
{props.onChromePinChange ? (
|
|
838
|
+
<TwDetachHandle
|
|
839
|
+
surface="topnav"
|
|
840
|
+
pin={props.chromePins?.topnav}
|
|
841
|
+
onChange={props.onChromePinChange}
|
|
842
|
+
label="Detach toolbar"
|
|
843
|
+
/>
|
|
844
|
+
) : null}
|
|
812
845
|
</div>
|
|
813
846
|
</header>
|
|
814
847
|
);
|