@beyondwork/docx-react-component 1.0.36 → 1.0.38
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/README.md +103 -13
- package/package.json +1 -1
- package/src/api/package-version.ts +13 -0
- package/src/api/public-types.ts +402 -1
- package/src/core/commands/index.ts +18 -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 +815 -55
- package/src/core/selection/mapping.ts +6 -0
- package/src/io/docx-session.ts +24 -9
- package/src/io/export/build-app-properties-xml.ts +88 -0
- package/src/io/export/serialize-comments.ts +6 -1
- package/src/io/export/serialize-footnotes.ts +10 -9
- package/src/io/export/serialize-headers-footers.ts +11 -10
- package/src/io/export/serialize-main-document.ts +328 -50
- package/src/io/export/serialize-numbering.ts +114 -24
- package/src/io/export/serialize-tables.ts +87 -11
- package/src/io/export/table-properties-xml.ts +174 -20
- package/src/io/export/twip.ts +66 -0
- package/src/io/normalize/normalize-text.ts +20 -0
- package/src/io/ooxml/parse-footnotes.ts +62 -1
- package/src/io/ooxml/parse-headers-footers.ts +62 -1
- package/src/io/ooxml/parse-main-document.ts +158 -1
- package/src/io/ooxml/parse-tables.ts +249 -0
- package/src/legal/bookmarks.ts +78 -0
- package/src/model/canonical-document.ts +45 -0
- package/src/review/store/scope-tag-diff.ts +130 -0
- package/src/runtime/document-layout.ts +4 -2
- package/src/runtime/document-navigation.ts +2 -306
- package/src/runtime/document-runtime.ts +287 -11
- package/src/runtime/layout/default-page-format.ts +96 -0
- package/src/runtime/layout/docx-font-loader.ts +143 -0
- package/src/runtime/layout/index.ts +233 -0
- package/src/runtime/layout/inert-layout-facet.ts +59 -0
- package/src/runtime/layout/layout-engine-instance.ts +628 -0
- package/src/runtime/layout/layout-invalidation.ts +257 -0
- package/src/runtime/layout/layout-measurement-provider.ts +175 -0
- package/src/runtime/layout/margin-preset-catalog.ts +178 -0
- package/src/runtime/layout/measurement-backend-canvas.ts +307 -0
- package/src/runtime/layout/measurement-backend-empirical.ts +208 -0
- package/src/runtime/layout/page-format-catalog.ts +233 -0
- package/src/runtime/layout/page-fragment-mapper.ts +179 -0
- package/src/runtime/layout/page-graph.ts +452 -0
- package/src/runtime/layout/page-layout-snapshot-adapter.ts +70 -0
- package/src/runtime/layout/page-story-resolver.ts +195 -0
- package/src/runtime/layout/paginated-layout-engine.ts +921 -0
- package/src/runtime/layout/project-block-fragments.ts +91 -0
- package/src/runtime/layout/public-facet.ts +1398 -0
- package/src/runtime/layout/resolved-formatting-document.ts +317 -0
- package/src/runtime/layout/resolved-formatting-state.ts +430 -0
- package/src/runtime/layout/table-render-plan.ts +229 -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 +755 -0
- package/src/runtime/scope-tag-registry.ts +95 -0
- package/src/runtime/surface-projection.ts +1 -0
- package/src/runtime/text-ack-range.ts +49 -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 +99 -15
- package/src/ui/editor-runtime-boundary.ts +10 -1
- package/src/ui/editor-shell-view.tsx +6 -0
- package/src/ui/editor-surface-controller.tsx +3 -0
- package/src/ui/headless/chrome-registry.ts +501 -0
- package/src/ui/headless/scoped-chrome-policy.ts +183 -0
- package/src/ui/headless/selection-tool-context.ts +2 -0
- package/src/ui/headless/selection-tool-resolver.ts +36 -17
- 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/role-action-sets.ts +74 -0
- package/src/ui-tailwind/chrome/tw-detach-handle.tsx +147 -0
- package/src/ui-tailwind/chrome/tw-selection-anchor-resolver.ts +163 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +57 -92
- package/src/ui-tailwind/chrome/tw-selection-tool-placement.ts +149 -0
- package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +15 -4
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +274 -138
- package/src/ui-tailwind/chrome-overlay/chrome-overlay-projector.ts +90 -0
- package/src/ui-tailwind/chrome-overlay/index.ts +22 -0
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +86 -0
- package/src/ui-tailwind/chrome-overlay/tw-scope-rail-layer.tsx +178 -0
- package/src/ui-tailwind/chrome-overlay/tw-workspace-view-switcher.tsx +95 -0
- package/src/ui-tailwind/editor-surface/fast-text-edit-lane.ts +337 -0
- package/src/ui-tailwind/editor-surface/local-edit-session-state.ts +100 -0
- package/src/ui-tailwind/editor-surface/perf-probe.ts +27 -1
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +20 -2
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +93 -23
- package/src/ui-tailwind/editor-surface/predicted-position-map.ts +78 -0
- package/src/ui-tailwind/editor-surface/predicted-tag-preflight.ts +63 -0
- package/src/ui-tailwind/editor-surface/predicted-tx-gate.ts +39 -0
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +176 -6
- package/src/ui-tailwind/index.ts +33 -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 +505 -144
- package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +559 -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-icon-button.tsx +2 -2
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +304 -166
- package/src/ui-tailwind/tw-review-workspace.tsx +163 -2
|
@@ -43,11 +43,14 @@ import {
|
|
|
43
43
|
import type {
|
|
44
44
|
ActiveListContext,
|
|
45
45
|
CompatibilityPanelSnapshot,
|
|
46
|
+
EditorRole,
|
|
46
47
|
EditorStoryTarget,
|
|
47
48
|
EditorWarning,
|
|
48
49
|
FormattingStateSnapshot,
|
|
49
50
|
FormattingAlignment,
|
|
50
51
|
InsertImageOptions,
|
|
52
|
+
ReviewQueueSnapshot,
|
|
53
|
+
ScopeRailPosture,
|
|
51
54
|
SectionBreakType,
|
|
52
55
|
StyleCatalogSnapshot,
|
|
53
56
|
WorkflowBlockedCommandReason,
|
|
@@ -56,9 +59,19 @@ import type {
|
|
|
56
59
|
ZoomLevel,
|
|
57
60
|
} from "../../api/public-types";
|
|
58
61
|
import type { SessionCapabilities } from "../../runtime/session-capabilities";
|
|
62
|
+
import {
|
|
63
|
+
getToolbarChromePlacement,
|
|
64
|
+
isToolbarChromeItemVisible,
|
|
65
|
+
resolveScopedChromePolicy,
|
|
66
|
+
type ScopedChromePolicy,
|
|
67
|
+
} from "../../ui/headless/scoped-chrome-policy";
|
|
59
68
|
import { preserveEditorSelectionMouseDown } from "../../ui/headless/preserve-editor-selection";
|
|
60
69
|
import { TwHealthPanel } from "../review/tw-health-panel";
|
|
61
|
-
import {
|
|
70
|
+
import {
|
|
71
|
+
TwRoleActionRegion,
|
|
72
|
+
type MarkupDisplayMode,
|
|
73
|
+
type WorkflowWorkItemSnapshot,
|
|
74
|
+
} from "./tw-role-action-region";
|
|
62
75
|
import { TwToolbarIconButton } from "./tw-toolbar-icon-button";
|
|
63
76
|
|
|
64
77
|
export interface TwToolbarProps {
|
|
@@ -68,6 +81,7 @@ export interface TwToolbarProps {
|
|
|
68
81
|
blockedReasons?: WorkflowBlockedCommandReason[];
|
|
69
82
|
showDiagnosticsChrome?: boolean;
|
|
70
83
|
interactionPolicy?: ToolbarInteractionPolicy;
|
|
84
|
+
scopedChromePolicy?: ScopedChromePolicy;
|
|
71
85
|
preset?: WordReviewEditorChromePreset;
|
|
72
86
|
compactMode?: boolean;
|
|
73
87
|
workspaceMode: WorkspaceMode;
|
|
@@ -115,6 +129,39 @@ export interface TwToolbarProps {
|
|
|
115
129
|
onContinueNumbering?: () => void;
|
|
116
130
|
onUpdateFields?: () => void;
|
|
117
131
|
onUpdateTableOfContents?: () => void;
|
|
132
|
+
|
|
133
|
+
// ───── R1: role-scoped inline action region (spec §6.4) ──────────────
|
|
134
|
+
/**
|
|
135
|
+
* Active editor role. When supplied, the toolbar renders the inline
|
|
136
|
+
* `TwRoleActionRegion` between the left formatting cluster and the
|
|
137
|
+
* right view cluster. Omit to keep the pre-R1 layout.
|
|
138
|
+
*/
|
|
139
|
+
role?: EditorRole;
|
|
140
|
+
/** Review-queue snapshot for the review role's inline prev/next/counts. */
|
|
141
|
+
reviewQueue?: ReviewQueueSnapshot;
|
|
142
|
+
/** Active work item for the workflow role's inline queue. */
|
|
143
|
+
workflowItem?: WorkflowWorkItemSnapshot | null;
|
|
144
|
+
/** Markup display mode for the review role. */
|
|
145
|
+
markupDisplay?: MarkupDisplayMode;
|
|
146
|
+
|
|
147
|
+
// Editor role
|
|
148
|
+
onMarkScopePosture?: (posture: ScopeRailPosture) => void;
|
|
149
|
+
// Review role
|
|
150
|
+
onReviewPrev?: () => void;
|
|
151
|
+
onReviewNext?: () => void;
|
|
152
|
+
onReviewAccept?: () => void;
|
|
153
|
+
onReviewReject?: () => void;
|
|
154
|
+
onReviewAcceptAll?: () => void;
|
|
155
|
+
onReviewRejectAll?: () => void;
|
|
156
|
+
onReviewMarkupMode?: (mode: MarkupDisplayMode) => void;
|
|
157
|
+
// Workflow role
|
|
158
|
+
onWorkflowPrev?: () => void;
|
|
159
|
+
onWorkflowNext?: () => void;
|
|
160
|
+
onWorkflowMarkComplete?: () => void;
|
|
161
|
+
onWorkflowClaim?: () => void;
|
|
162
|
+
onWorkflowSkip?: () => void;
|
|
163
|
+
onWorkflowMarkBlocked?: () => void;
|
|
164
|
+
onWorkflowJumpToScope?: () => void;
|
|
118
165
|
}
|
|
119
166
|
|
|
120
167
|
export interface ToolbarInteractionPolicy {
|
|
@@ -152,27 +199,56 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
152
199
|
const canEdit = props.interactionPolicy?.canFormatText ?? (caps ? caps.canEdit : false);
|
|
153
200
|
const canInsertStructural = props.interactionPolicy?.canInsertStructural ?? canEdit;
|
|
154
201
|
const canAddComment = props.interactionPolicy?.canAddComment ?? (caps ? caps.canAddComment : false);
|
|
155
|
-
const showStyleSelectors = preset === "advanced";
|
|
156
|
-
const showAdvancedFormatting = preset === "advanced";
|
|
157
|
-
const showFormattingColors = preset !== "review";
|
|
158
|
-
const showInsertMenu = preset === "simple" || preset === "advanced";
|
|
159
|
-
const showTrackedChangesToggle = preset !== "simple";
|
|
160
202
|
const showDiagnosticsChrome = props.showDiagnosticsChrome ?? true;
|
|
161
|
-
const
|
|
162
|
-
const showListActions = preset === "simple" || preset === "advanced";
|
|
163
|
-
const showUpdateActions = preset === "advanced";
|
|
164
|
-
const showSidebarToggle = props.showSidebarToggle ?? false;
|
|
165
|
-
const layoutModel = resolveToolbarLayoutModel({
|
|
166
|
-
compactMode: isCompact,
|
|
203
|
+
const scopedChromePolicy = props.scopedChromePolicy ?? resolveScopedChromePolicy({
|
|
167
204
|
preset,
|
|
168
|
-
|
|
205
|
+
compactMode: isCompact,
|
|
206
|
+
capabilities: caps,
|
|
207
|
+
interactionGuardSnapshot: props.interactionPolicy
|
|
208
|
+
? ({
|
|
209
|
+
effectiveMode: props.interactionPolicy.mode,
|
|
210
|
+
blockedReasons: props.blockedReasons ?? [],
|
|
211
|
+
} as any)
|
|
212
|
+
: undefined,
|
|
213
|
+
activeListContext: props.activeListContext,
|
|
214
|
+
...(props.role ? { role: props.role } : {}),
|
|
169
215
|
});
|
|
216
|
+
const showStyleSelectors = isToolbarChromeItemVisible(scopedChromePolicy, "text-style-selectors");
|
|
217
|
+
const showInlineFormatting = isToolbarChromeItemVisible(scopedChromePolicy, "inline-formatting");
|
|
218
|
+
const showAdvancedFormatting = preset === "advanced" && showInlineFormatting;
|
|
219
|
+
const showTextColors = isToolbarChromeItemVisible(scopedChromePolicy, "text-colors");
|
|
220
|
+
const showParagraphAlignment = isToolbarChromeItemVisible(scopedChromePolicy, "paragraph-alignment");
|
|
221
|
+
const showInsertMenu = isToolbarChromeItemVisible(scopedChromePolicy, "insert-actions");
|
|
222
|
+
const showTrackedChangesToggle = isToolbarChromeItemVisible(scopedChromePolicy, "tracked-changes-toggle");
|
|
223
|
+
const showHealth =
|
|
224
|
+
showDiagnosticsChrome &&
|
|
225
|
+
isToolbarChromeItemVisible(scopedChromePolicy, "health") &&
|
|
226
|
+
Boolean(props.compatibility && props.warnings);
|
|
227
|
+
const showListActions = isToolbarChromeItemVisible(scopedChromePolicy, "list-actions");
|
|
228
|
+
const showUpdateActions = isToolbarChromeItemVisible(scopedChromePolicy, "update-actions");
|
|
229
|
+
const showSidebarToggle =
|
|
230
|
+
(props.showSidebarToggle ?? false) &&
|
|
231
|
+
isToolbarChromeItemVisible(scopedChromePolicy, "sidebar-toggle");
|
|
232
|
+
const showStyleSelectorsInRow = getToolbarChromePlacement(scopedChromePolicy, "text-style-selectors") === "inline";
|
|
233
|
+
const showListActionsInRow = getToolbarChromePlacement(scopedChromePolicy, "list-actions") === "inline";
|
|
234
|
+
const showSpacingActionsInRow = getToolbarChromePlacement(scopedChromePolicy, "indentation") === "inline";
|
|
235
|
+
const showListContinuationInRow =
|
|
236
|
+
getToolbarChromePlacement(scopedChromePolicy, "list-continuation") === "inline";
|
|
237
|
+
const showInsertActionsInRow = getToolbarChromePlacement(scopedChromePolicy, "insert-actions") === "inline";
|
|
238
|
+
const showUpdateActionsInRow = getToolbarChromePlacement(scopedChromePolicy, "update-actions") === "inline";
|
|
239
|
+
const showCompactOverflow =
|
|
240
|
+
getToolbarChromePlacement(scopedChromePolicy, "text-style-selectors") === "overflow" ||
|
|
241
|
+
getToolbarChromePlacement(scopedChromePolicy, "list-actions") === "overflow" ||
|
|
242
|
+
getToolbarChromePlacement(scopedChromePolicy, "indentation") === "overflow" ||
|
|
243
|
+
getToolbarChromePlacement(scopedChromePolicy, "list-continuation") === "overflow" ||
|
|
244
|
+
getToolbarChromePlacement(scopedChromePolicy, "insert-actions") === "overflow" ||
|
|
245
|
+
getToolbarChromePlacement(scopedChromePolicy, "update-actions") === "overflow";
|
|
170
246
|
const showPostFormattingDivider =
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
247
|
+
showListActionsInRow ||
|
|
248
|
+
showSpacingActionsInRow ||
|
|
249
|
+
showInsertActionsInRow ||
|
|
250
|
+
showUpdateActionsInRow ||
|
|
251
|
+
showCompactOverflow;
|
|
176
252
|
const zoomLabel =
|
|
177
253
|
typeof zoomLevel === "number"
|
|
178
254
|
? `${zoomLevel}%`
|
|
@@ -185,8 +261,8 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
185
261
|
className={[
|
|
186
262
|
"shrink-0 rounded-xl border border-border/70 bg-canvas/92 px-2.5 shadow-[0_8px_20px_-18px_var(--color-shadow-strong)] backdrop-blur-sm",
|
|
187
263
|
isCompact
|
|
188
|
-
? "flex min-h-
|
|
189
|
-
: "flex h-
|
|
264
|
+
? "flex min-h-10 flex-wrap items-center gap-1.5 py-1.5"
|
|
265
|
+
: "flex h-10 items-center gap-1",
|
|
190
266
|
].join(" ")}
|
|
191
267
|
>
|
|
192
268
|
{/* Left cluster: undo/redo + formatting */}
|
|
@@ -205,7 +281,7 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
205
281
|
/>
|
|
206
282
|
<div className="mx-1 h-4 w-px bg-border" />
|
|
207
283
|
|
|
208
|
-
{showStyleSelectors &&
|
|
284
|
+
{showStyleSelectors && showStyleSelectorsInRow ? (
|
|
209
285
|
<>
|
|
210
286
|
<ToolbarParagraphStyleSelect
|
|
211
287
|
disabled={!canEdit || paragraphStyles.length === 0 || !props.onSetParagraphStyle}
|
|
@@ -229,69 +305,79 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
229
305
|
</>
|
|
230
306
|
) : null}
|
|
231
307
|
|
|
232
|
-
|
|
233
|
-
icon={Bold}
|
|
234
|
-
label="Bold"
|
|
235
|
-
active={props.formattingState?.bold ?? false}
|
|
236
|
-
disabled={!canEdit}
|
|
237
|
-
onClick={props.onToggleBold}
|
|
238
|
-
/>
|
|
239
|
-
<TwToolbarIconButton
|
|
240
|
-
icon={Italic}
|
|
241
|
-
label="Italic"
|
|
242
|
-
active={props.formattingState?.italic ?? false}
|
|
243
|
-
disabled={!canEdit}
|
|
244
|
-
onClick={props.onToggleItalic}
|
|
245
|
-
/>
|
|
246
|
-
<TwToolbarIconButton
|
|
247
|
-
icon={Underline}
|
|
248
|
-
label="Underline"
|
|
249
|
-
active={props.formattingState?.underline ?? false}
|
|
250
|
-
disabled={!canEdit}
|
|
251
|
-
onClick={props.onToggleUnderline}
|
|
252
|
-
/>
|
|
253
|
-
{showAdvancedFormatting ? (
|
|
254
|
-
<ToolbarFormattingOverflow
|
|
255
|
-
disabled={!canEdit}
|
|
256
|
-
formattingState={props.formattingState}
|
|
257
|
-
onToggleStrikethrough={props.onToggleStrikethrough}
|
|
258
|
-
onToggleSuperscript={props.onToggleSuperscript}
|
|
259
|
-
onToggleSubscript={props.onToggleSubscript}
|
|
260
|
-
/>
|
|
261
|
-
) : null}
|
|
262
|
-
{showFormattingColors ? (
|
|
308
|
+
{showInlineFormatting ? (
|
|
263
309
|
<>
|
|
264
|
-
<
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
if (value) {
|
|
271
|
-
props.onSetTextColor?.(value);
|
|
272
|
-
}
|
|
273
|
-
}}
|
|
274
|
-
title="Text color"
|
|
310
|
+
<TwToolbarIconButton
|
|
311
|
+
icon={Bold}
|
|
312
|
+
label="Bold"
|
|
313
|
+
active={props.formattingState?.bold ?? false}
|
|
314
|
+
disabled={!canEdit}
|
|
315
|
+
onClick={props.onToggleBold}
|
|
275
316
|
/>
|
|
276
|
-
<
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
title="Highlight color"
|
|
317
|
+
<TwToolbarIconButton
|
|
318
|
+
icon={Italic}
|
|
319
|
+
label="Italic"
|
|
320
|
+
active={props.formattingState?.italic ?? false}
|
|
321
|
+
disabled={!canEdit}
|
|
322
|
+
onClick={props.onToggleItalic}
|
|
283
323
|
/>
|
|
284
|
-
<
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
324
|
+
<TwToolbarIconButton
|
|
325
|
+
icon={Underline}
|
|
326
|
+
label="Underline"
|
|
327
|
+
active={props.formattingState?.underline ?? false}
|
|
328
|
+
disabled={!canEdit}
|
|
329
|
+
onClick={props.onToggleUnderline}
|
|
288
330
|
/>
|
|
331
|
+
{showAdvancedFormatting ? (
|
|
332
|
+
<ToolbarFormattingOverflow
|
|
333
|
+
disabled={!canEdit}
|
|
334
|
+
formattingState={props.formattingState}
|
|
335
|
+
onToggleStrikethrough={props.onToggleStrikethrough}
|
|
336
|
+
onToggleSuperscript={props.onToggleSuperscript}
|
|
337
|
+
onToggleSubscript={props.onToggleSubscript}
|
|
338
|
+
/>
|
|
339
|
+
) : null}
|
|
340
|
+
</>
|
|
341
|
+
) : null}
|
|
342
|
+
{showTextColors || showParagraphAlignment ? (
|
|
343
|
+
<>
|
|
344
|
+
{showTextColors ? (
|
|
345
|
+
<>
|
|
346
|
+
<ToolbarColorPopover
|
|
347
|
+
ariaLabel="Text color"
|
|
348
|
+
colors={TEXT_COLORS.map((value) => ({ value, label: value }))}
|
|
349
|
+
disabled={!canEdit || !props.onSetTextColor}
|
|
350
|
+
icon={<Baseline className="h-3.5 w-3.5" />}
|
|
351
|
+
onSelect={(value) => {
|
|
352
|
+
if (value) {
|
|
353
|
+
props.onSetTextColor?.(value);
|
|
354
|
+
}
|
|
355
|
+
}}
|
|
356
|
+
title="Text color"
|
|
357
|
+
/>
|
|
358
|
+
<ToolbarColorPopover
|
|
359
|
+
ariaLabel="Highlight color"
|
|
360
|
+
colors={HIGHLIGHT_COLORS.map((entry) => ({ value: entry.value, label: entry.label }))}
|
|
361
|
+
disabled={!canEdit || !props.onSetHighlightColor}
|
|
362
|
+
icon={<Highlighter className="h-3.5 w-3.5" />}
|
|
363
|
+
onSelect={(value) => props.onSetHighlightColor?.(value)}
|
|
364
|
+
title="Highlight color"
|
|
365
|
+
/>
|
|
366
|
+
</>
|
|
367
|
+
) : null}
|
|
368
|
+
{showParagraphAlignment ? (
|
|
369
|
+
<ToolbarAlignmentPopover
|
|
370
|
+
activeAlignment={props.formattingState?.alignment}
|
|
371
|
+
disabled={!canEdit || !props.onSetAlignment}
|
|
372
|
+
onSelect={(alignment) => props.onSetAlignment?.(alignment)}
|
|
373
|
+
/>
|
|
374
|
+
) : null}
|
|
289
375
|
</>
|
|
290
376
|
) : null}
|
|
291
377
|
|
|
292
378
|
{showPostFormattingDivider ? <div className="mx-1 h-4 w-px bg-border" /> : null}
|
|
293
379
|
|
|
294
|
-
{showListActions &&
|
|
380
|
+
{showListActions && showListActionsInRow ? (
|
|
295
381
|
<>
|
|
296
382
|
<TwToolbarIconButton
|
|
297
383
|
icon={List}
|
|
@@ -309,7 +395,7 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
309
395
|
/>
|
|
310
396
|
</>
|
|
311
397
|
) : null}
|
|
312
|
-
{
|
|
398
|
+
{showSpacingActionsInRow ? (
|
|
313
399
|
<>
|
|
314
400
|
<TwToolbarIconButton
|
|
315
401
|
icon={Outdent}
|
|
@@ -325,7 +411,7 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
325
411
|
/>
|
|
326
412
|
</>
|
|
327
413
|
) : null}
|
|
328
|
-
{
|
|
414
|
+
{showListContinuationInRow ? (
|
|
329
415
|
<>
|
|
330
416
|
<button
|
|
331
417
|
type="button"
|
|
@@ -333,7 +419,7 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
333
419
|
disabled={!canEdit || !props.onRestartNumbering}
|
|
334
420
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
335
421
|
onClick={props.onRestartNumbering}
|
|
336
|
-
className={`inline-flex h-
|
|
422
|
+
className={`inline-flex h-6 items-center rounded-md px-2 text-[11px] font-medium text-secondary transition-colors hover:bg-surface outline-none disabled:cursor-not-allowed disabled:opacity-40 ${focusRingClass}`}
|
|
337
423
|
>
|
|
338
424
|
Restart
|
|
339
425
|
</button>
|
|
@@ -343,13 +429,13 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
343
429
|
disabled={!canEdit || !props.onContinueNumbering}
|
|
344
430
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
345
431
|
onClick={props.onContinueNumbering}
|
|
346
|
-
className={`inline-flex h-
|
|
432
|
+
className={`inline-flex h-6 items-center rounded-md px-2 text-[11px] font-medium text-secondary transition-colors hover:bg-surface outline-none disabled:cursor-not-allowed disabled:opacity-40 ${focusRingClass}`}
|
|
347
433
|
>
|
|
348
434
|
Continue
|
|
349
435
|
</button>
|
|
350
436
|
</>
|
|
351
437
|
) : null}
|
|
352
|
-
{showInsertMenu &&
|
|
438
|
+
{showInsertMenu && showInsertActionsInRow ? (
|
|
353
439
|
<ToolbarInsertMenu
|
|
354
440
|
disabled={!canInsertStructural}
|
|
355
441
|
onInsertImage={props.onInsertImage}
|
|
@@ -358,7 +444,7 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
358
444
|
onInsertTable={props.onInsertTable}
|
|
359
445
|
/>
|
|
360
446
|
) : null}
|
|
361
|
-
{showUpdateActions &&
|
|
447
|
+
{showUpdateActions && showUpdateActionsInRow ? (
|
|
362
448
|
<>
|
|
363
449
|
<button
|
|
364
450
|
type="button"
|
|
@@ -366,7 +452,7 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
366
452
|
disabled={!canEdit || !props.onUpdateFields}
|
|
367
453
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
368
454
|
onClick={props.onUpdateFields}
|
|
369
|
-
className={`inline-flex h-
|
|
455
|
+
className={`inline-flex h-6 items-center rounded-md px-2 text-[11px] font-medium text-secondary transition-colors hover:bg-surface outline-none disabled:cursor-not-allowed disabled:opacity-40 ${focusRingClass}`}
|
|
370
456
|
>
|
|
371
457
|
Fields
|
|
372
458
|
</button>
|
|
@@ -376,23 +462,25 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
376
462
|
disabled={!canEdit || !props.onUpdateTableOfContents}
|
|
377
463
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
378
464
|
onClick={props.onUpdateTableOfContents}
|
|
379
|
-
className={`inline-flex h-
|
|
465
|
+
className={`inline-flex h-6 items-center rounded-md px-2 text-[11px] font-medium text-secondary transition-colors hover:bg-surface outline-none disabled:cursor-not-allowed disabled:opacity-40 ${focusRingClass}`}
|
|
380
466
|
>
|
|
381
467
|
TOC
|
|
382
468
|
</button>
|
|
383
469
|
</>
|
|
384
470
|
) : null}
|
|
385
|
-
{
|
|
471
|
+
{showCompactOverflow ? (
|
|
386
472
|
<ToolbarCompactOverflow
|
|
387
473
|
activeListContext={props.activeListContext}
|
|
388
474
|
canEdit={canEdit}
|
|
389
475
|
canInsertStructural={canInsertStructural}
|
|
390
476
|
formattingState={props.formattingState}
|
|
391
477
|
paragraphStyles={paragraphStyles}
|
|
392
|
-
showInsertMenu={
|
|
393
|
-
showListActions={
|
|
394
|
-
|
|
395
|
-
|
|
478
|
+
showInsertMenu={getToolbarChromePlacement(scopedChromePolicy, "insert-actions") === "overflow"}
|
|
479
|
+
showListActions={getToolbarChromePlacement(scopedChromePolicy, "list-actions") === "overflow"}
|
|
480
|
+
showParagraphActions={getToolbarChromePlacement(scopedChromePolicy, "indentation") === "overflow"}
|
|
481
|
+
showListContinuation={getToolbarChromePlacement(scopedChromePolicy, "list-continuation") === "overflow"}
|
|
482
|
+
showStyleSelectors={getToolbarChromePlacement(scopedChromePolicy, "text-style-selectors") === "overflow"}
|
|
483
|
+
showUpdateActions={getToolbarChromePlacement(scopedChromePolicy, "update-actions") === "overflow"}
|
|
396
484
|
onSetParagraphStyle={props.onSetParagraphStyle}
|
|
397
485
|
onSetFontFamily={props.onSetFontFamily}
|
|
398
486
|
onSetFontSize={props.onSetFontSize}
|
|
@@ -412,14 +500,15 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
412
500
|
) : null}
|
|
413
501
|
|
|
414
502
|
{/* Story focus breadcrumb — visible when editing a secondary story */}
|
|
415
|
-
{props.activeStory && props.activeStory.kind !== "main"
|
|
503
|
+
{props.activeStory && props.activeStory.kind !== "main" &&
|
|
504
|
+
isToolbarChromeItemVisible(scopedChromePolicy, "story-breadcrumb") ? (
|
|
416
505
|
<>
|
|
417
506
|
<div className="mx-1 h-4 w-px bg-border" />
|
|
418
507
|
<button
|
|
419
508
|
type="button"
|
|
420
509
|
onClick={props.onCloseStory}
|
|
421
510
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
422
|
-
className={`inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 text-
|
|
511
|
+
className={`inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 text-[11px] font-medium text-accent hover:bg-surface transition-colors outline-none ${focusRingClass}`}
|
|
423
512
|
aria-label={`Editing ${storyLabel(props.activeStory)} — click to return to main body`}
|
|
424
513
|
>
|
|
425
514
|
<span className="text-secondary">←</span>
|
|
@@ -429,8 +518,43 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
429
518
|
) : null}
|
|
430
519
|
</div>
|
|
431
520
|
|
|
521
|
+
{/* R1: role-scoped inline action region (spec §6.4) */}
|
|
522
|
+
{props.role ? (
|
|
523
|
+
<TwRoleActionRegion
|
|
524
|
+
role={props.role}
|
|
525
|
+
policy={scopedChromePolicy}
|
|
526
|
+
compactMode={isCompact}
|
|
527
|
+
reviewQueue={props.reviewQueue}
|
|
528
|
+
workflowItem={props.workflowItem}
|
|
529
|
+
markupDisplay={props.markupDisplay}
|
|
530
|
+
onMarkScopePosture={props.onMarkScopePosture}
|
|
531
|
+
onReviewPrev={props.onReviewPrev}
|
|
532
|
+
onReviewNext={props.onReviewNext}
|
|
533
|
+
onReviewAccept={props.onReviewAccept}
|
|
534
|
+
onReviewReject={props.onReviewReject}
|
|
535
|
+
onReviewAcceptAll={props.onReviewAcceptAll}
|
|
536
|
+
onReviewRejectAll={props.onReviewRejectAll}
|
|
537
|
+
onReviewMarkupMode={props.onReviewMarkupMode}
|
|
538
|
+
onWorkflowPrev={props.onWorkflowPrev}
|
|
539
|
+
onWorkflowNext={props.onWorkflowNext}
|
|
540
|
+
onWorkflowMarkComplete={props.onWorkflowMarkComplete}
|
|
541
|
+
onWorkflowClaim={props.onWorkflowClaim}
|
|
542
|
+
onWorkflowSkip={props.onWorkflowSkip}
|
|
543
|
+
onWorkflowMarkBlocked={props.onWorkflowMarkBlocked}
|
|
544
|
+
onWorkflowJumpToScope={props.onWorkflowJumpToScope}
|
|
545
|
+
/>
|
|
546
|
+
) : null}
|
|
547
|
+
|
|
432
548
|
{/* Right cluster: comment, track changes, markup, view, export */}
|
|
433
549
|
<div className={`flex items-center gap-0.5 ${isCompact ? "ml-auto flex-wrap justify-end" : ""}`}>
|
|
550
|
+
{scopedChromePolicy.scopeStatusLabel ? (
|
|
551
|
+
<>
|
|
552
|
+
<span className="inline-flex h-6 items-center rounded-full bg-surface px-2 text-[10px] font-medium text-secondary ring-1 ring-border/50">
|
|
553
|
+
{scopedChromePolicy.scopeStatusLabel}
|
|
554
|
+
</span>
|
|
555
|
+
<div className="mx-1 h-4 w-px bg-border" />
|
|
556
|
+
</>
|
|
557
|
+
) : null}
|
|
434
558
|
{showSidebarToggle ? (
|
|
435
559
|
<>
|
|
436
560
|
<TwToolbarIconButton
|
|
@@ -443,13 +567,15 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
443
567
|
</>
|
|
444
568
|
) : null}
|
|
445
569
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
570
|
+
{isToolbarChromeItemVisible(scopedChromePolicy, "comment") ? (
|
|
571
|
+
<TwToolbarIconButton
|
|
572
|
+
icon={MessageSquare}
|
|
573
|
+
label="Add comment"
|
|
574
|
+
disabled={!canAddComment}
|
|
575
|
+
emphasis
|
|
576
|
+
onClick={props.onAddComment}
|
|
577
|
+
/>
|
|
578
|
+
) : null}
|
|
453
579
|
|
|
454
580
|
{showTrackedChangesToggle ? (
|
|
455
581
|
<>
|
|
@@ -460,9 +586,9 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
460
586
|
onPressedChange={props.onShowTrackedChangesChange}
|
|
461
587
|
disabled={caps ? !caps.trackChangesSupported : false}
|
|
462
588
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
463
|
-
className={`inline-flex h-
|
|
589
|
+
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}`}
|
|
464
590
|
>
|
|
465
|
-
{props.showTrackedChanges ? <Eye className="h-
|
|
591
|
+
{props.showTrackedChanges ? <Eye className="h-3.5 w-3.5" /> : <EyeOff className="h-3.5 w-3.5" />}
|
|
466
592
|
</Toggle.Root>
|
|
467
593
|
</Tooltip.Trigger>
|
|
468
594
|
<Tooltip.Portal>
|
|
@@ -480,21 +606,22 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
480
606
|
) : null}
|
|
481
607
|
|
|
482
608
|
{/* View mode toggle group: Canvas (clean, flowing) / Page (layout-sensitive) */}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
609
|
+
{isToolbarChromeItemVisible(scopedChromePolicy, "workspace-mode") ? (
|
|
610
|
+
<ToggleGroup.Root
|
|
611
|
+
type="single"
|
|
612
|
+
value={workspaceMode}
|
|
613
|
+
onValueChange={(v: string) => {
|
|
614
|
+
if (v) props.onWorkspaceModeChange(v as WorkspaceMode);
|
|
615
|
+
}}
|
|
616
|
+
className="flex items-center gap-0.5"
|
|
617
|
+
>
|
|
491
618
|
<Tooltip.Root>
|
|
492
619
|
<Tooltip.Trigger asChild>
|
|
493
620
|
<ToggleGroup.Item
|
|
494
621
|
value="canvas"
|
|
495
622
|
aria-label="Canvas workspace"
|
|
496
623
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
497
|
-
className={`inline-flex h-
|
|
624
|
+
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 ${focusRingClass}`}
|
|
498
625
|
>
|
|
499
626
|
<Monitor className="h-3.5 w-3.5" />
|
|
500
627
|
</ToggleGroup.Item>
|
|
@@ -511,7 +638,7 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
511
638
|
value="page"
|
|
512
639
|
aria-label="Page workspace"
|
|
513
640
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
514
|
-
className={`inline-flex h-
|
|
641
|
+
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 ${focusRingClass}`}
|
|
515
642
|
>
|
|
516
643
|
<FileText className="h-3.5 w-3.5" />
|
|
517
644
|
</ToggleGroup.Item>
|
|
@@ -522,10 +649,11 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
522
649
|
</Tooltip.Content>
|
|
523
650
|
</Tooltip.Portal>
|
|
524
651
|
</Tooltip.Root>
|
|
525
|
-
|
|
652
|
+
</ToggleGroup.Root>
|
|
653
|
+
) : null}
|
|
526
654
|
|
|
527
655
|
{/* Zoom controls — available in all workspace modes */}
|
|
528
|
-
{props.onZoomChange ? (
|
|
656
|
+
{isToolbarChromeItemVisible(scopedChromePolicy, "zoom") && props.onZoomChange ? (
|
|
529
657
|
<>
|
|
530
658
|
<div className="mx-1 h-4 w-px bg-border" />
|
|
531
659
|
<div className="flex items-center gap-0.5">
|
|
@@ -534,7 +662,7 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
534
662
|
<button
|
|
535
663
|
type="button"
|
|
536
664
|
aria-label="Zoom out"
|
|
537
|
-
className={`inline-flex h-
|
|
665
|
+
className={`inline-flex h-6 w-6 items-center justify-center rounded-md text-secondary transition-colors hover:bg-surface outline-none ${focusRingClass}`}
|
|
538
666
|
disabled={typeof zoomLevel === "number" && zoomLevel <= 50}
|
|
539
667
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
540
668
|
onClick={() => {
|
|
@@ -560,7 +688,7 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
560
688
|
type="button"
|
|
561
689
|
aria-label={`Zoom: ${zoomLabel}`}
|
|
562
690
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
563
|
-
className={`inline-flex h-
|
|
691
|
+
className={`inline-flex h-6 items-center justify-center rounded-md px-1.5 text-[10px] font-medium text-secondary transition-colors hover:bg-surface outline-none ${focusRingClass}`}
|
|
564
692
|
>
|
|
565
693
|
{zoomLabel}
|
|
566
694
|
</button>
|
|
@@ -604,7 +732,7 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
604
732
|
<button
|
|
605
733
|
type="button"
|
|
606
734
|
aria-label="Zoom in"
|
|
607
|
-
className={`inline-flex h-
|
|
735
|
+
className={`inline-flex h-6 w-6 items-center justify-center rounded-md text-secondary transition-colors hover:bg-surface outline-none ${focusRingClass}`}
|
|
608
736
|
disabled={typeof zoomLevel === "number" && zoomLevel >= 200}
|
|
609
737
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
610
738
|
onClick={() => {
|
|
@@ -635,9 +763,9 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
635
763
|
type="button"
|
|
636
764
|
aria-label="Document health"
|
|
637
765
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
638
|
-
className={`relative inline-flex h-
|
|
766
|
+
className={`relative inline-flex h-6 w-6 items-center justify-center rounded-md text-secondary transition-colors hover:bg-surface hover:text-primary outline-none ${focusRingClass}`}
|
|
639
767
|
>
|
|
640
|
-
<AlertCircle className="h-
|
|
768
|
+
<AlertCircle className="h-3.5 w-3.5" />
|
|
641
769
|
{(caps?.healthIssueCount ?? 0) > 0 ? (
|
|
642
770
|
<span className="absolute -top-0.5 -right-0.5 flex h-3 min-w-[12px] items-center justify-center rounded-full bg-tertiary text-[8px] font-medium text-white">
|
|
643
771
|
{caps?.healthIssueCount}
|
|
@@ -672,13 +800,15 @@ export function TwToolbar(props: TwToolbarProps) {
|
|
|
672
800
|
</>
|
|
673
801
|
) : null}
|
|
674
802
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
803
|
+
{isToolbarChromeItemVisible(scopedChromePolicy, "export") ? (
|
|
804
|
+
<TwToolbarIconButton
|
|
805
|
+
icon={Download}
|
|
806
|
+
label={caps?.exportBlocked ? "Export blocked" : "Download document"}
|
|
807
|
+
disabled={caps ? !caps.canExport : true}
|
|
808
|
+
emphasis
|
|
809
|
+
onClick={props.onExport}
|
|
810
|
+
/>
|
|
811
|
+
) : null}
|
|
682
812
|
</div>
|
|
683
813
|
</header>
|
|
684
814
|
);
|
|
@@ -706,7 +836,7 @@ function ToolbarParagraphStyleSelect(props: {
|
|
|
706
836
|
aria-disabled={props.disabled || undefined}
|
|
707
837
|
data-disabled={props.disabled ? "" : undefined}
|
|
708
838
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
709
|
-
className={`inline-flex h-
|
|
839
|
+
className={`inline-flex h-6 min-w-[7.5rem] items-center justify-between gap-2 rounded-md border border-border bg-canvas px-2 text-[11px] font-medium text-primary transition-colors hover:bg-surface outline-none disabled:cursor-not-allowed disabled:opacity-40 ${focusRingClass}`}
|
|
710
840
|
>
|
|
711
841
|
<Select.Value placeholder="Style" />
|
|
712
842
|
<Select.Icon>
|
|
@@ -723,7 +853,7 @@ function ToolbarParagraphStyleSelect(props: {
|
|
|
723
853
|
<Select.Viewport className="p-1">
|
|
724
854
|
{props.styles.map((style) => (
|
|
725
855
|
<Select.Item
|
|
726
|
-
className={`flex cursor-pointer items-center rounded-md px-2
|
|
856
|
+
className={`flex cursor-pointer items-center rounded-md px-2 py-1 text-[11px] text-primary outline-none data-[highlighted]:bg-surface data-[state=checked]:bg-canvas data-[state=checked]:text-accent data-[state=checked]:ring-1 data-[state=checked]:ring-accent/20 ${focusRingClass}`}
|
|
727
857
|
key={style.styleId}
|
|
728
858
|
value={style.styleId}
|
|
729
859
|
>
|
|
@@ -755,7 +885,7 @@ function ToolbarFontFamilySelect(props: {
|
|
|
755
885
|
aria-disabled={props.disabled || undefined}
|
|
756
886
|
data-disabled={props.disabled ? "" : undefined}
|
|
757
887
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
758
|
-
className={`inline-flex h-
|
|
888
|
+
className={`inline-flex h-6 min-w-[6.5rem] items-center justify-between gap-2 rounded-md border border-border bg-canvas px-2 text-[11px] font-medium text-primary transition-colors hover:bg-surface outline-none disabled:cursor-not-allowed disabled:opacity-40 ${focusRingClass}`}
|
|
759
889
|
>
|
|
760
890
|
<Select.Value placeholder="Font" />
|
|
761
891
|
<Select.Icon>
|
|
@@ -772,7 +902,7 @@ function ToolbarFontFamilySelect(props: {
|
|
|
772
902
|
<Select.Viewport className="p-1">
|
|
773
903
|
{FONT_FAMILIES.map((font) => (
|
|
774
904
|
<Select.Item
|
|
775
|
-
className={`flex cursor-pointer items-center rounded-md px-2
|
|
905
|
+
className={`flex cursor-pointer items-center rounded-md px-2 py-1 text-[11px] text-primary outline-none data-[highlighted]:bg-surface data-[state=checked]:bg-canvas data-[state=checked]:text-accent data-[state=checked]:ring-1 data-[state=checked]:ring-accent/20 ${focusRingClass}`}
|
|
776
906
|
key={font}
|
|
777
907
|
value={font}
|
|
778
908
|
>
|
|
@@ -805,7 +935,7 @@ function ToolbarFontSizeSelect(props: {
|
|
|
805
935
|
aria-disabled={props.disabled || undefined}
|
|
806
936
|
data-disabled={props.disabled ? "" : undefined}
|
|
807
937
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
808
|
-
className={`inline-flex h-
|
|
938
|
+
className={`inline-flex h-6 min-w-[3.5rem] items-center justify-between gap-2 rounded-md border border-border bg-canvas px-2 text-[11px] font-medium text-primary transition-colors hover:bg-surface outline-none disabled:cursor-not-allowed disabled:opacity-40 ${focusRingClass}`}
|
|
809
939
|
>
|
|
810
940
|
<Select.Value placeholder="Size" />
|
|
811
941
|
<Select.Icon>
|
|
@@ -822,7 +952,7 @@ function ToolbarFontSizeSelect(props: {
|
|
|
822
952
|
<Select.Viewport className="p-1">
|
|
823
953
|
{FONT_SIZES.map((size) => (
|
|
824
954
|
<Select.Item
|
|
825
|
-
className={`flex cursor-pointer items-center rounded-md px-2
|
|
955
|
+
className={`flex cursor-pointer items-center rounded-md px-2 py-1 text-[11px] text-primary outline-none data-[highlighted]:bg-surface data-[state=checked]:bg-canvas data-[state=checked]:text-accent data-[state=checked]:ring-1 data-[state=checked]:ring-accent/20 ${focusRingClass}`}
|
|
826
956
|
key={size}
|
|
827
957
|
value={String(size)}
|
|
828
958
|
>
|
|
@@ -844,6 +974,8 @@ function ToolbarCompactOverflow(props: {
|
|
|
844
974
|
paragraphStyles: StyleCatalogSnapshot["paragraphs"];
|
|
845
975
|
showInsertMenu: boolean;
|
|
846
976
|
showListActions: boolean;
|
|
977
|
+
showParagraphActions: boolean;
|
|
978
|
+
showListContinuation: boolean;
|
|
847
979
|
showStyleSelectors: boolean;
|
|
848
980
|
showUpdateActions: boolean;
|
|
849
981
|
onSetParagraphStyle?: (styleId: string) => void;
|
|
@@ -891,7 +1023,7 @@ function ToolbarCompactOverflow(props: {
|
|
|
891
1023
|
aria-expanded={open}
|
|
892
1024
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
893
1025
|
onClick={() => setOpen((value) => !value)}
|
|
894
|
-
className={`inline-flex h-
|
|
1026
|
+
className={`inline-flex h-6 items-center gap-1 rounded-md border border-border bg-canvas px-2 text-[11px] font-medium text-primary transition-colors hover:bg-surface outline-none ${focusRingClass}`}
|
|
895
1027
|
>
|
|
896
1028
|
More
|
|
897
1029
|
<ChevronDown className="h-3.5 w-3.5 text-tertiary" />
|
|
@@ -971,31 +1103,36 @@ function ToolbarCompactOverflow(props: {
|
|
|
971
1103
|
</div>
|
|
972
1104
|
) : null}
|
|
973
1105
|
|
|
974
|
-
|
|
975
|
-
<div className="
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1106
|
+
{props.showParagraphActions || (props.showListContinuation && props.activeListContext) ? (
|
|
1107
|
+
<div className="space-y-1">
|
|
1108
|
+
<div className="px-1 text-[10px] font-semibold uppercase tracking-[0.12em] text-tertiary">
|
|
1109
|
+
Paragraph
|
|
1110
|
+
</div>
|
|
1111
|
+
{props.showParagraphActions ? (
|
|
1112
|
+
<>
|
|
1113
|
+
<ToolbarMenuButton
|
|
1114
|
+
ariaLabel="Outdent"
|
|
1115
|
+
disabled={!props.canEdit || !props.onOutdent}
|
|
1116
|
+
icon={<Outdent className="h-3.5 w-3.5" />}
|
|
1117
|
+
label="Outdent"
|
|
1118
|
+
onClick={() => {
|
|
1119
|
+
props.onOutdent?.();
|
|
1120
|
+
setOpen(false);
|
|
1121
|
+
}}
|
|
1122
|
+
/>
|
|
1123
|
+
<ToolbarMenuButton
|
|
1124
|
+
ariaLabel="Indent"
|
|
1125
|
+
disabled={!props.canEdit || !props.onIndent}
|
|
1126
|
+
icon={<Indent className="h-3.5 w-3.5" />}
|
|
1127
|
+
label="Indent"
|
|
1128
|
+
onClick={() => {
|
|
1129
|
+
props.onIndent?.();
|
|
1130
|
+
setOpen(false);
|
|
1131
|
+
}}
|
|
1132
|
+
/>
|
|
1133
|
+
</>
|
|
1134
|
+
) : null}
|
|
1135
|
+
{props.showListContinuation && props.activeListContext ? (
|
|
999
1136
|
<>
|
|
1000
1137
|
<ToolbarMenuButton
|
|
1001
1138
|
ariaLabel="Restart numbering"
|
|
@@ -1018,8 +1155,9 @@ function ToolbarCompactOverflow(props: {
|
|
|
1018
1155
|
}}
|
|
1019
1156
|
/>
|
|
1020
1157
|
</>
|
|
1021
|
-
|
|
1022
|
-
|
|
1158
|
+
) : null}
|
|
1159
|
+
</div>
|
|
1160
|
+
) : null}
|
|
1023
1161
|
|
|
1024
1162
|
{props.showInsertMenu ? (
|
|
1025
1163
|
<div className="space-y-1">
|
|
@@ -1047,7 +1185,7 @@ function ToolbarCompactOverflow(props: {
|
|
|
1047
1185
|
}}
|
|
1048
1186
|
/>
|
|
1049
1187
|
<label
|
|
1050
|
-
className={`flex h-
|
|
1188
|
+
className={`flex h-7 cursor-pointer items-center gap-2 rounded-md px-2 text-left text-[11px] font-medium text-primary transition-colors hover:bg-surface ${
|
|
1051
1189
|
!props.canInsertStructural || !props.onInsertImage ? "pointer-events-none opacity-40" : ""
|
|
1052
1190
|
}`}
|
|
1053
1191
|
>
|
|
@@ -1131,7 +1269,7 @@ function ToolbarFormattingOverflow(props: {
|
|
|
1131
1269
|
disabled={props.disabled}
|
|
1132
1270
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
1133
1271
|
onClick={() => setOpen((value) => !value)}
|
|
1134
|
-
className={`inline-flex h-
|
|
1272
|
+
className={`inline-flex h-6 w-6 items-center justify-center rounded-md text-secondary transition-colors hover:bg-surface outline-none disabled:cursor-not-allowed disabled:opacity-40 ${focusRingClass}`}
|
|
1135
1273
|
>
|
|
1136
1274
|
<MoreHorizontal className="h-3.5 w-3.5" />
|
|
1137
1275
|
</button>
|
|
@@ -1206,7 +1344,7 @@ function ToolbarColorPopover(props: {
|
|
|
1206
1344
|
disabled={props.disabled}
|
|
1207
1345
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
1208
1346
|
onClick={() => setOpen((value) => !value)}
|
|
1209
|
-
className={`inline-flex h-
|
|
1347
|
+
className={`inline-flex h-6 w-6 items-center justify-center rounded-md text-secondary transition-colors hover:bg-surface outline-none disabled:cursor-not-allowed disabled:opacity-40 ${focusRingClass}`}
|
|
1210
1348
|
>
|
|
1211
1349
|
{props.icon}
|
|
1212
1350
|
</button>
|
|
@@ -1234,7 +1372,7 @@ function ToolbarColorPopover(props: {
|
|
|
1234
1372
|
props.onSelect(color.value);
|
|
1235
1373
|
setOpen(false);
|
|
1236
1374
|
}}
|
|
1237
|
-
className={`inline-flex h-
|
|
1375
|
+
className={`inline-flex h-7 items-center justify-center rounded-md border border-border text-[10px] font-medium text-primary transition-transform hover:scale-[1.04] disabled:cursor-not-allowed disabled:opacity-40 ${
|
|
1238
1376
|
color.value ? "" : "bg-surface"
|
|
1239
1377
|
} ${focusRingClass}`}
|
|
1240
1378
|
style={color.value ? { backgroundColor: color.value } : undefined}
|
|
@@ -1273,7 +1411,7 @@ function ToolbarAlignmentPopover(props: {
|
|
|
1273
1411
|
disabled={props.disabled}
|
|
1274
1412
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
1275
1413
|
onClick={() => setOpen((value) => !value)}
|
|
1276
|
-
className={`inline-flex h-
|
|
1414
|
+
className={`inline-flex h-6 w-6 items-center justify-center rounded-md text-secondary transition-colors hover:bg-surface outline-none disabled:cursor-not-allowed disabled:opacity-40 ${focusRingClass}`}
|
|
1277
1415
|
>
|
|
1278
1416
|
{(alignments.find((entry) => entry.value === props.activeAlignment) ?? alignments[0])?.icon}
|
|
1279
1417
|
</button>
|
|
@@ -1346,7 +1484,7 @@ function ToolbarInsertMenu(props: {
|
|
|
1346
1484
|
disabled={props.disabled}
|
|
1347
1485
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
1348
1486
|
onClick={() => setOpen((value) => !value)}
|
|
1349
|
-
className={`inline-flex h-
|
|
1487
|
+
className={`inline-flex h-6 items-center gap-1 rounded-md border border-border bg-canvas px-2 text-[11px] font-medium text-primary transition-colors hover:bg-surface outline-none disabled:cursor-not-allowed disabled:opacity-40 ${focusRingClass}`}
|
|
1350
1488
|
>
|
|
1351
1489
|
Insert
|
|
1352
1490
|
<ChevronDown className="h-3.5 w-3.5 text-tertiary" />
|
|
@@ -1382,7 +1520,7 @@ function ToolbarInsertMenu(props: {
|
|
|
1382
1520
|
}}
|
|
1383
1521
|
/>
|
|
1384
1522
|
<label
|
|
1385
|
-
className={`flex h-
|
|
1523
|
+
className={`flex h-7 cursor-pointer items-center gap-2 rounded-md px-2 text-[11px] font-medium text-primary transition-colors hover:bg-surface ${
|
|
1386
1524
|
props.disabled || !props.onInsertImage ? "pointer-events-none opacity-40" : ""
|
|
1387
1525
|
}`}
|
|
1388
1526
|
>
|
|
@@ -1431,7 +1569,7 @@ function ToolbarPopoverActionButton(props: {
|
|
|
1431
1569
|
disabled={props.disabled}
|
|
1432
1570
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
1433
1571
|
onClick={props.onClick}
|
|
1434
|
-
className={`inline-flex h-
|
|
1572
|
+
className={`inline-flex h-7 items-center justify-center rounded-md border border-border transition-colors disabled:cursor-not-allowed disabled:opacity-40 ${
|
|
1435
1573
|
props.active ? "bg-canvas text-accent ring-1 ring-accent/30 shadow-sm" : "bg-canvas text-secondary hover:bg-surface"
|
|
1436
1574
|
} ${focusRingClass}`}
|
|
1437
1575
|
>
|
|
@@ -1454,7 +1592,7 @@ function ToolbarMenuButton(props: {
|
|
|
1454
1592
|
disabled={props.disabled}
|
|
1455
1593
|
onMouseDown={preserveEditorSelectionMouseDown}
|
|
1456
1594
|
onClick={props.onClick}
|
|
1457
|
-
className={`flex h-
|
|
1595
|
+
className={`flex h-7 w-full items-center gap-2 rounded-md px-2 text-left text-[11px] font-medium text-primary transition-colors hover:bg-surface disabled:cursor-not-allowed disabled:opacity-40 ${focusRingClass}`}
|
|
1458
1596
|
>
|
|
1459
1597
|
<span className="text-secondary">{props.icon}</span>
|
|
1460
1598
|
<span>{props.label}</span>
|