@beyondwork/docx-react-component 1.0.31 → 1.0.32
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 +6 -0
- package/package.json +1 -1
- package/src/api/public-types.ts +16 -1
- package/src/api/session-state.ts +2 -0
- package/src/io/docx-session.ts +16 -3
- package/src/io/ooxml/parse-footnotes.ts +23 -33
- package/src/io/ooxml/parse-headers-footers.ts +20 -21
- package/src/io/ooxml/workflow-payload.ts +311 -8
- package/src/model/snapshot.ts +113 -1
- package/src/runtime/document-runtime.ts +207 -33
- package/src/runtime/surface-projection.ts +156 -7
- package/src/ui/WordReviewEditor.tsx +13 -5
- package/src/ui/editor-surface-controller.tsx +2 -0
- package/src/ui/headless/selection-tool-resolver.ts +4 -1
- package/src/ui/headless/selection-tool-types.ts +1 -2
- package/src/ui/workflow-surface-blocked-rails.ts +19 -1
- package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +1 -2
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +1 -2
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +88 -14
- package/src/ui-tailwind/editor-surface/pm-schema.ts +29 -0
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +12 -0
- package/src/ui-tailwind/editor-surface/surface-build-keys.ts +2 -0
- package/src/ui-tailwind/editor-surface/tw-inline-token.tsx +20 -0
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +26 -0
- package/src/ui-tailwind/theme/editor-theme.css +8 -0
|
@@ -3,7 +3,6 @@ import type {
|
|
|
3
3
|
CommentSidebarThreadSnapshot,
|
|
4
4
|
FormattingStateSnapshot,
|
|
5
5
|
InteractionGuardSnapshot,
|
|
6
|
-
StyleCatalogSnapshot,
|
|
7
6
|
TableStructureContextSnapshot,
|
|
8
7
|
SuggestionsSnapshot,
|
|
9
8
|
TrackedChangeEntrySnapshot,
|
|
@@ -79,7 +78,7 @@ export type StructureContextKind = "table" | "image" | "object" | "list";
|
|
|
79
78
|
export interface StructureContextSelectionToolModel extends BaseSelectionToolModel {
|
|
80
79
|
kind: "structure-context";
|
|
81
80
|
structureKind: StructureContextKind;
|
|
82
|
-
tableStyles?:
|
|
81
|
+
tableStyles?: Array<{ styleId: string; displayName: string }>;
|
|
83
82
|
activeTable?: TableStructureContextSnapshot | null;
|
|
84
83
|
activeImage?: ActiveImageContext;
|
|
85
84
|
activeObject?: ActiveObjectContext;
|
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
RuntimeRenderSnapshot,
|
|
4
4
|
SurfaceBlockSnapshot,
|
|
5
5
|
WorkflowBlockedCommandReason,
|
|
6
|
+
WorkflowLockedZone,
|
|
6
7
|
WorkflowMarkupSnapshot,
|
|
7
8
|
} from "../api/public-types";
|
|
8
9
|
|
|
@@ -10,6 +11,21 @@ export function deriveVisibleWorkflowBlockedRails(
|
|
|
10
11
|
surface: RuntimeRenderSnapshot["surface"] | undefined,
|
|
11
12
|
markupSnapshot: WorkflowMarkupSnapshot | null,
|
|
12
13
|
): WorkflowBlockedCommandReason[] {
|
|
14
|
+
return deriveVisibleWorkflowLockedZones(surface, markupSnapshot).map((zone) => ({
|
|
15
|
+
code: zone.code,
|
|
16
|
+
message: zone.detail,
|
|
17
|
+
fragmentId: zone.fragmentId,
|
|
18
|
+
label: zone.label,
|
|
19
|
+
detail: zone.detail,
|
|
20
|
+
anchor: zone.anchor,
|
|
21
|
+
storyTarget: zone.storyTarget,
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function deriveVisibleWorkflowLockedZones(
|
|
26
|
+
surface: RuntimeRenderSnapshot["surface"] | undefined,
|
|
27
|
+
markupSnapshot: WorkflowMarkupSnapshot | null,
|
|
28
|
+
): WorkflowLockedZone[] {
|
|
13
29
|
if (!surface || !markupSnapshot) {
|
|
14
30
|
return [];
|
|
15
31
|
}
|
|
@@ -22,8 +38,10 @@ export function deriveVisibleWorkflowBlockedRails(
|
|
|
22
38
|
),
|
|
23
39
|
)
|
|
24
40
|
.map((fragment) => ({
|
|
41
|
+
fragmentId: fragment.fragmentId,
|
|
25
42
|
code: fragment.blockedReasonCode,
|
|
26
|
-
|
|
43
|
+
label: fragment.label,
|
|
44
|
+
detail: fragment.detail,
|
|
27
45
|
anchor: fragment.anchor,
|
|
28
46
|
storyTarget: fragment.storyTarget,
|
|
29
47
|
}));
|
|
@@ -52,8 +52,7 @@ export function TwSelectionToolStructure(props: TwSelectionToolStructureProps) {
|
|
|
52
52
|
return (
|
|
53
53
|
<TwTableContextToolbar
|
|
54
54
|
disabled={!props.model.canMutate}
|
|
55
|
-
tableContext={props.model.activeTable ?? null}
|
|
56
|
-
tableStyles={props.model.tableStyles ?? []}
|
|
55
|
+
tableContext={props.model.activeTable ?? null} tableStyles={props.model.tableStyles ?? []}
|
|
57
56
|
onSetTableStyle={props.onSetTableStyle}
|
|
58
57
|
onAddRowBefore={props.onAddRowBefore}
|
|
59
58
|
onAddRowAfter={props.onAddRowAfter}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
3
|
import type {
|
|
4
|
-
StyleCatalogSnapshot,
|
|
5
4
|
TableOperationCapabilitySnapshot,
|
|
6
5
|
TableStructureContextSnapshot,
|
|
7
6
|
} from "../../api/public-types";
|
|
@@ -10,7 +9,7 @@ import { preserveEditorSelectionMouseDown } from "../../ui/headless/preserve-edi
|
|
|
10
9
|
export interface TwTableContextToolbarProps {
|
|
11
10
|
disabled: boolean;
|
|
12
11
|
tableContext: TableStructureContextSnapshot | null;
|
|
13
|
-
tableStyles:
|
|
12
|
+
tableStyles: Array<{ styleId: string; displayName: string }>;
|
|
14
13
|
onSetTableStyle?: (styleId: string) => void;
|
|
15
14
|
onAddRowBefore?: () => void;
|
|
16
15
|
onAddRowAfter?: () => void;
|
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
EditorStoryTarget,
|
|
10
10
|
WorkflowBlockedCommandReason,
|
|
11
11
|
WorkflowCandidateRange,
|
|
12
|
+
WorkflowLockedZone,
|
|
12
13
|
WorkflowMetadataMarkup,
|
|
13
14
|
WorkflowScope,
|
|
14
15
|
} from "../../api/public-types";
|
|
@@ -81,16 +82,16 @@ function getWorkflowMetadataInlineClass(): string {
|
|
|
81
82
|
|
|
82
83
|
function getWorkflowBlockedInlineClass(reason: WorkflowBlockedCommandReason): string {
|
|
83
84
|
if (reason.code === "workflow_blocked_import") {
|
|
84
|
-
return "wre-workflow-inline wre-workflow-inline-blocked-import";
|
|
85
|
+
return "wre-workflow-inline wre-workflow-inline-locked-zone wre-workflow-inline-blocked-import";
|
|
85
86
|
}
|
|
86
|
-
return "wre-workflow-inline wre-workflow-inline-preserve-only";
|
|
87
|
+
return "wre-workflow-inline wre-workflow-inline-locked-zone wre-workflow-inline-preserve-only";
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
function getWorkflowBlockedRailClass(reason: WorkflowBlockedCommandReason): string {
|
|
90
91
|
if (reason.code === "workflow_blocked_import") {
|
|
91
|
-
return "wre-workflow-rail wre-workflow-rail-blocked-import";
|
|
92
|
+
return "wre-workflow-rail wre-workflow-rail-locked-zone wre-workflow-rail-blocked-import";
|
|
92
93
|
}
|
|
93
|
-
return "wre-workflow-rail wre-workflow-rail-preserve-only";
|
|
94
|
+
return "wre-workflow-rail wre-workflow-rail-locked-zone wre-workflow-rail-preserve-only";
|
|
94
95
|
}
|
|
95
96
|
|
|
96
97
|
function hasBlockChildren(node: PMNode): boolean {
|
|
@@ -172,6 +173,56 @@ function buildAnchorPmRange(
|
|
|
172
173
|
};
|
|
173
174
|
}
|
|
174
175
|
|
|
176
|
+
function collectLockedPmRanges(
|
|
177
|
+
lockedZones: readonly WorkflowLockedZone[] | undefined,
|
|
178
|
+
activeStory: EditorStoryTarget,
|
|
179
|
+
positionMap: PositionMap,
|
|
180
|
+
): Array<{ from: number; to: number; zone: WorkflowLockedZone }> {
|
|
181
|
+
if (!lockedZones || lockedZones.length === 0) {
|
|
182
|
+
return [];
|
|
183
|
+
}
|
|
184
|
+
const ranges: Array<{ from: number; to: number; zone: WorkflowLockedZone }> = [];
|
|
185
|
+
for (const zone of lockedZones) {
|
|
186
|
+
const zoneStoryTarget = zone.storyTarget ?? MAIN_STORY_TARGET;
|
|
187
|
+
if (!storyTargetsEqual(zoneStoryTarget, activeStory)) {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
const pmRange = buildAnchorPmRange(zone.anchor, positionMap);
|
|
191
|
+
if (!pmRange || !pmRange.allowInline || pmRange.from >= pmRange.to) {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
ranges.push({ from: pmRange.from, to: pmRange.to, zone });
|
|
195
|
+
}
|
|
196
|
+
return ranges;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function subtractInlineOverlaps(
|
|
200
|
+
baseRange: { from: number; to: number },
|
|
201
|
+
blockedRanges: Array<{ from: number; to: number }>,
|
|
202
|
+
): Array<{ from: number; to: number }> {
|
|
203
|
+
let segments = [baseRange];
|
|
204
|
+
for (const blockedRange of blockedRanges) {
|
|
205
|
+
const nextSegments: Array<{ from: number; to: number }> = [];
|
|
206
|
+
for (const segment of segments) {
|
|
207
|
+
if (blockedRange.to <= segment.from || blockedRange.from >= segment.to) {
|
|
208
|
+
nextSegments.push(segment);
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
if (blockedRange.from > segment.from) {
|
|
212
|
+
nextSegments.push({ from: segment.from, to: blockedRange.from });
|
|
213
|
+
}
|
|
214
|
+
if (blockedRange.to < segment.to) {
|
|
215
|
+
nextSegments.push({ from: blockedRange.to, to: segment.to });
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
segments = nextSegments;
|
|
219
|
+
if (segments.length === 0) {
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return segments.filter((segment) => segment.from < segment.to);
|
|
224
|
+
}
|
|
225
|
+
|
|
175
226
|
function pushRailDecorations(
|
|
176
227
|
decorations: Decoration[],
|
|
177
228
|
doc: PMNode,
|
|
@@ -214,6 +265,7 @@ export function buildDecorations(
|
|
|
214
265
|
activeStory: EditorStoryTarget = MAIN_STORY_TARGET,
|
|
215
266
|
workflowCandidates?: readonly WorkflowCandidateRange[],
|
|
216
267
|
workflowBlockedReasons?: readonly WorkflowBlockedCommandReason[],
|
|
268
|
+
workflowLockedZones?: readonly WorkflowLockedZone[],
|
|
217
269
|
activeWorkflowWorkItemId?: string | null,
|
|
218
270
|
activeWorkflowScopeIds?: readonly string[],
|
|
219
271
|
workflowMetadata?: readonly WorkflowMetadataMarkup[],
|
|
@@ -221,6 +273,7 @@ export function buildDecorations(
|
|
|
221
273
|
const decorations: Decoration[] = [];
|
|
222
274
|
const railRangeCache = new Map<string, Array<{ from: number; to: number }>>();
|
|
223
275
|
const activeScopeIds = new Set(activeWorkflowScopeIds ?? []);
|
|
276
|
+
const lockedPmRanges = collectLockedPmRanges(workflowLockedZones, activeStory, positionMap);
|
|
224
277
|
|
|
225
278
|
// Walk comment threads and create inline decorations
|
|
226
279
|
if (commentModel) {
|
|
@@ -307,15 +360,21 @@ export function buildDecorations(
|
|
|
307
360
|
);
|
|
308
361
|
|
|
309
362
|
if (pmRange.allowInline && pmRange.from < pmRange.to) {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
"data-workflow-scope-id": scope.scopeId,
|
|
314
|
-
"data-workflow-scope-mode": scope.mode,
|
|
315
|
-
"data-workflow-active": isActiveWorkItem ? "true" : "false",
|
|
316
|
-
...(isSelectionZone ? { "data-workflow-zone": "selection" } : {}),
|
|
317
|
-
}),
|
|
363
|
+
const visibleScopeSegments = subtractInlineOverlaps(
|
|
364
|
+
{ from: pmRange.from, to: pmRange.to },
|
|
365
|
+
lockedPmRanges.filter((range) => range.to > pmRange.from && range.from < pmRange.to),
|
|
318
366
|
);
|
|
367
|
+
for (const visibleSegment of visibleScopeSegments) {
|
|
368
|
+
decorations.push(
|
|
369
|
+
Decoration.inline(visibleSegment.from, visibleSegment.to, {
|
|
370
|
+
class: getWorkflowInlineClass(scope, isActiveWorkItem, isSelectionZone),
|
|
371
|
+
"data-workflow-scope-id": scope.scopeId,
|
|
372
|
+
"data-workflow-scope-mode": scope.mode,
|
|
373
|
+
"data-workflow-active": isActiveWorkItem ? "true" : "false",
|
|
374
|
+
...(isSelectionZone ? { "data-workflow-zone": "selection" } : {}),
|
|
375
|
+
}),
|
|
376
|
+
);
|
|
377
|
+
}
|
|
319
378
|
}
|
|
320
379
|
|
|
321
380
|
pushRailDecorations(decorations, doc, pmRange.from, pmRange.to, {
|
|
@@ -375,8 +434,19 @@ export function buildDecorations(
|
|
|
375
434
|
}
|
|
376
435
|
}
|
|
377
436
|
|
|
378
|
-
if (workflowBlockedReasons) {
|
|
379
|
-
|
|
437
|
+
if ((workflowLockedZones && workflowLockedZones.length > 0) || workflowBlockedReasons) {
|
|
438
|
+
const blockedReasonsToRender = workflowLockedZones && workflowLockedZones.length > 0
|
|
439
|
+
? workflowLockedZones.map((zone) => ({
|
|
440
|
+
code: zone.code,
|
|
441
|
+
message: zone.detail,
|
|
442
|
+
anchor: zone.anchor,
|
|
443
|
+
storyTarget: zone.storyTarget,
|
|
444
|
+
fragmentId: zone.fragmentId,
|
|
445
|
+
label: zone.label,
|
|
446
|
+
detail: zone.detail,
|
|
447
|
+
}))
|
|
448
|
+
: workflowBlockedReasons ?? [];
|
|
449
|
+
for (const reason of blockedReasonsToRender) {
|
|
380
450
|
if (
|
|
381
451
|
reason.code !== "workflow_preserve_only" &&
|
|
382
452
|
reason.code !== "workflow_blocked_import"
|
|
@@ -393,6 +463,8 @@ export function buildDecorations(
|
|
|
393
463
|
Decoration.inline(pmRange.from, pmRange.to, {
|
|
394
464
|
class: getWorkflowBlockedInlineClass(reason),
|
|
395
465
|
"data-workflow-blocked-code": reason.code,
|
|
466
|
+
...(reason.fragmentId ? { "data-workflow-fragment-id": reason.fragmentId } : {}),
|
|
467
|
+
"data-workflow-zone": "locked",
|
|
396
468
|
}),
|
|
397
469
|
);
|
|
398
470
|
}
|
|
@@ -402,6 +474,8 @@ export function buildDecorations(
|
|
|
402
474
|
className: getWorkflowBlockedRailClass(reason),
|
|
403
475
|
attrs: {
|
|
404
476
|
"data-workflow-blocked-code": reason.code,
|
|
477
|
+
...(reason.fragmentId ? { "data-workflow-fragment-id": reason.fragmentId } : {}),
|
|
478
|
+
"data-workflow-zone": "locked",
|
|
405
479
|
},
|
|
406
480
|
}, railRangeCache);
|
|
407
481
|
}
|
|
@@ -489,6 +489,7 @@ export const editorSchema = new Schema({
|
|
|
489
489
|
label: { default: "Locked" },
|
|
490
490
|
detail: { default: "" },
|
|
491
491
|
presentation: { default: "inline-chip" },
|
|
492
|
+
displayText: { default: null },
|
|
492
493
|
},
|
|
493
494
|
toDOM(node) {
|
|
494
495
|
const presentation = node.attrs.presentation as string;
|
|
@@ -505,6 +506,34 @@ export const editorSchema = new Schema({
|
|
|
505
506
|
},
|
|
506
507
|
];
|
|
507
508
|
}
|
|
509
|
+
if (presentation === "text-box") {
|
|
510
|
+
return [
|
|
511
|
+
"span",
|
|
512
|
+
{
|
|
513
|
+
class: "mx-0.5 inline-flex max-w-full whitespace-pre-wrap rounded border border-slate-300 bg-slate-50 px-2 py-1 align-top text-sm leading-snug text-slate-700 shadow-sm",
|
|
514
|
+
"data-node-type": "opaque_inline",
|
|
515
|
+
"data-inline-presentation": "text-box",
|
|
516
|
+
contenteditable: "false",
|
|
517
|
+
title: node.attrs.detail as string,
|
|
518
|
+
"aria-label": node.attrs.label as string,
|
|
519
|
+
},
|
|
520
|
+
(node.attrs.displayText as string | null) ?? (node.attrs.label as string),
|
|
521
|
+
];
|
|
522
|
+
}
|
|
523
|
+
if (presentation === "checkbox") {
|
|
524
|
+
return [
|
|
525
|
+
"span",
|
|
526
|
+
{
|
|
527
|
+
class: "mx-0.5 inline-flex h-5 min-w-[1.25rem] items-center justify-center rounded border border-slate-300 bg-white px-1 align-text-bottom text-sm leading-none text-slate-700",
|
|
528
|
+
"data-node-type": "opaque_inline",
|
|
529
|
+
"data-inline-presentation": "checkbox",
|
|
530
|
+
contenteditable: "false",
|
|
531
|
+
title: node.attrs.detail as string,
|
|
532
|
+
"aria-label": node.attrs.label as string,
|
|
533
|
+
},
|
|
534
|
+
(node.attrs.displayText as string | null) ?? "☐",
|
|
535
|
+
];
|
|
536
|
+
}
|
|
508
537
|
return [
|
|
509
538
|
"span",
|
|
510
539
|
{
|
|
@@ -508,6 +508,17 @@ function buildOpaqueInlineOrComplexAtom(
|
|
|
508
508
|
const label = segment.label;
|
|
509
509
|
const detail = segment.detail;
|
|
510
510
|
|
|
511
|
+
if (segment.presentation === "text-box" || segment.presentation === "checkbox") {
|
|
512
|
+
return editorSchema.nodes.opaque_inline.create({
|
|
513
|
+
fragmentId: segment.fragmentId,
|
|
514
|
+
warningId: segment.warningId,
|
|
515
|
+
label,
|
|
516
|
+
detail,
|
|
517
|
+
presentation: segment.presentation,
|
|
518
|
+
displayText: segment.displayText ?? null,
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
|
|
511
522
|
if (showUnsupportedObjectPreviews && label === "Embedded chart") {
|
|
512
523
|
return editorSchema.nodes.chart_atom.create({ detail });
|
|
513
524
|
}
|
|
@@ -548,6 +559,7 @@ function buildOpaqueInlineOrComplexAtom(
|
|
|
548
559
|
label,
|
|
549
560
|
detail,
|
|
550
561
|
presentation: segment.presentation ?? "inline-chip",
|
|
562
|
+
displayText: segment.displayText ?? null,
|
|
551
563
|
});
|
|
552
564
|
}
|
|
553
565
|
|
|
@@ -43,6 +43,7 @@ export function createSurfaceDecorationKey(input: {
|
|
|
43
43
|
workflowScopeSignature?: string;
|
|
44
44
|
workflowCandidateSignature?: string;
|
|
45
45
|
workflowBlockedSignature?: string;
|
|
46
|
+
workflowLockedZoneSignature?: string;
|
|
46
47
|
workflowMetadataSignature?: string;
|
|
47
48
|
activeWorkflowWorkItemId?: string | null;
|
|
48
49
|
activeWorkflowScopeIds?: readonly string[];
|
|
@@ -56,6 +57,7 @@ export function createSurfaceDecorationKey(input: {
|
|
|
56
57
|
workflowScopeSignature: input.workflowScopeSignature ?? null,
|
|
57
58
|
workflowCandidateSignature: input.workflowCandidateSignature ?? null,
|
|
58
59
|
workflowBlockedSignature: input.workflowBlockedSignature ?? null,
|
|
60
|
+
workflowLockedZoneSignature: input.workflowLockedZoneSignature ?? null,
|
|
59
61
|
workflowMetadataSignature: input.workflowMetadataSignature ?? null,
|
|
60
62
|
activeWorkflowWorkItemId: input.activeWorkflowWorkItemId ?? null,
|
|
61
63
|
activeWorkflowScopeIds: input.activeWorkflowScopeIds ?? [],
|
|
@@ -106,6 +106,26 @@ export function TwInlineToken(props: TwInlineTokenProps) {
|
|
|
106
106
|
);
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
if (segment.presentation === "checkbox") {
|
|
110
|
+
return (
|
|
111
|
+
<button
|
|
112
|
+
type="button"
|
|
113
|
+
tabIndex={-1}
|
|
114
|
+
onMouseDown={(e) => {
|
|
115
|
+
e.preventDefault();
|
|
116
|
+
props.onSelectionChange?.(createSelectionSnapshot(segment.from, segment.to));
|
|
117
|
+
}}
|
|
118
|
+
className={`inline-flex h-5 min-w-[1.25rem] items-center justify-center rounded border border-slate-300 bg-white px-1 text-sm leading-none text-slate-700 ${commentClass} ${selected ? "ring-1 ring-accent/30" : ""} ${focusRingClass}`}
|
|
119
|
+
title={segment.detail}
|
|
120
|
+
data-inline-presentation="checkbox"
|
|
121
|
+
>
|
|
122
|
+
{renderTwCaret(selection, segment.from)}
|
|
123
|
+
{segment.displayText ?? "☐"}
|
|
124
|
+
{renderTwCaret(selection, segment.to)}
|
|
125
|
+
</button>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
109
129
|
return (
|
|
110
130
|
<button
|
|
111
131
|
type="button"
|
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
SelectionSnapshot,
|
|
19
19
|
WorkflowBlockedCommandReason,
|
|
20
20
|
WorkflowCandidateRange,
|
|
21
|
+
WorkflowLockedZone,
|
|
21
22
|
WorkflowMetadataMarkup,
|
|
22
23
|
WorkflowScope,
|
|
23
24
|
} from "../../api/public-types";
|
|
@@ -101,6 +102,7 @@ export interface TwProseMirrorSurfaceProps {
|
|
|
101
102
|
workflowScopes?: readonly WorkflowScope[];
|
|
102
103
|
workflowCandidates?: readonly WorkflowCandidateRange[];
|
|
103
104
|
workflowBlockedReasons?: readonly WorkflowBlockedCommandReason[];
|
|
105
|
+
workflowLockedZones?: readonly WorkflowLockedZone[];
|
|
104
106
|
activeWorkflowWorkItemId?: string | null;
|
|
105
107
|
activeWorkflowScopeIds?: readonly string[];
|
|
106
108
|
workflowMetadata?: readonly WorkflowMetadataMarkup[];
|
|
@@ -221,6 +223,7 @@ export const TwProseMirrorSurface = forwardRef<
|
|
|
221
223
|
workflowScopeSignature: createWorkflowScopeSignature(props.workflowScopes),
|
|
222
224
|
workflowCandidateSignature: createWorkflowCandidateSignature(props.workflowCandidates),
|
|
223
225
|
workflowBlockedSignature: createWorkflowBlockedSignature(props.workflowBlockedReasons),
|
|
226
|
+
workflowLockedZoneSignature: createWorkflowLockedZoneSignature(props.workflowLockedZones),
|
|
224
227
|
workflowMetadataSignature: createWorkflowMetadataSignature(props.workflowMetadata),
|
|
225
228
|
activeWorkflowWorkItemId: props.activeWorkflowWorkItemId ?? null,
|
|
226
229
|
activeWorkflowScopeIds: props.activeWorkflowScopeIds ?? [],
|
|
@@ -231,6 +234,7 @@ export const TwProseMirrorSurface = forwardRef<
|
|
|
231
234
|
props.activeRevisionId,
|
|
232
235
|
props.workflowCandidates,
|
|
233
236
|
props.workflowBlockedReasons,
|
|
237
|
+
props.workflowLockedZones,
|
|
234
238
|
props.workflowMetadata,
|
|
235
239
|
props.activeWorkflowWorkItemId,
|
|
236
240
|
props.activeWorkflowScopeIds,
|
|
@@ -280,6 +284,7 @@ export const TwProseMirrorSurface = forwardRef<
|
|
|
280
284
|
snapshot.activeStory,
|
|
281
285
|
props.workflowCandidates,
|
|
282
286
|
props.workflowBlockedReasons,
|
|
287
|
+
props.workflowLockedZones,
|
|
283
288
|
props.activeWorkflowWorkItemId,
|
|
284
289
|
props.activeWorkflowScopeIds,
|
|
285
290
|
props.workflowMetadata,
|
|
@@ -300,6 +305,7 @@ export const TwProseMirrorSurface = forwardRef<
|
|
|
300
305
|
props.activeWorkflowScopeIds,
|
|
301
306
|
props.activeWorkflowWorkItemId,
|
|
302
307
|
props.workflowBlockedReasons,
|
|
308
|
+
props.workflowLockedZones,
|
|
303
309
|
props.workflowMetadata,
|
|
304
310
|
props.workflowCandidates,
|
|
305
311
|
props.workflowScopes,
|
|
@@ -335,6 +341,7 @@ export const TwProseMirrorSurface = forwardRef<
|
|
|
335
341
|
snapshot.activeStory,
|
|
336
342
|
props.workflowCandidates,
|
|
337
343
|
props.workflowBlockedReasons,
|
|
344
|
+
props.workflowLockedZones,
|
|
338
345
|
props.activeWorkflowWorkItemId,
|
|
339
346
|
props.activeWorkflowScopeIds,
|
|
340
347
|
props.workflowMetadata,
|
|
@@ -898,6 +905,24 @@ function createWorkflowBlockedSignature(
|
|
|
898
905
|
).join("|");
|
|
899
906
|
}
|
|
900
907
|
|
|
908
|
+
function createWorkflowLockedZoneSignature(
|
|
909
|
+
lockedZones: readonly WorkflowLockedZone[] | undefined,
|
|
910
|
+
): string {
|
|
911
|
+
if (!lockedZones || lockedZones.length === 0) {
|
|
912
|
+
return "";
|
|
913
|
+
}
|
|
914
|
+
return lockedZones.map((zone) =>
|
|
915
|
+
[
|
|
916
|
+
zone.fragmentId,
|
|
917
|
+
zone.code,
|
|
918
|
+
zone.label,
|
|
919
|
+
zone.detail,
|
|
920
|
+
serializeAnchorSignature(zone.anchor),
|
|
921
|
+
serializeStoryTargetSignature(zone.storyTarget),
|
|
922
|
+
].join(":")
|
|
923
|
+
).join("|");
|
|
924
|
+
}
|
|
925
|
+
|
|
901
926
|
function createWorkflowMetadataSignature(
|
|
902
927
|
metadata: readonly WorkflowMetadataMarkup[] | undefined,
|
|
903
928
|
): string {
|
|
@@ -922,6 +947,7 @@ function serializeAnchorSignature(
|
|
|
922
947
|
| WorkflowScope["anchor"]
|
|
923
948
|
| WorkflowCandidateRange["anchor"]
|
|
924
949
|
| WorkflowBlockedCommandReason["anchor"]
|
|
950
|
+
| WorkflowLockedZone["anchor"]
|
|
925
951
|
| WorkflowMetadataMarkup["anchor"]
|
|
926
952
|
| undefined,
|
|
927
953
|
): string {
|
|
@@ -326,6 +326,10 @@
|
|
|
326
326
|
text-underline-offset: 0.18em;
|
|
327
327
|
}
|
|
328
328
|
|
|
329
|
+
.prosemirror-surface .ProseMirror .wre-workflow-inline-locked-zone {
|
|
330
|
+
border-radius: 0.35rem;
|
|
331
|
+
}
|
|
332
|
+
|
|
329
333
|
.prosemirror-surface .ProseMirror .wre-workflow-rail {
|
|
330
334
|
position: relative;
|
|
331
335
|
padding-left: 0.875rem;
|
|
@@ -421,6 +425,10 @@
|
|
|
421
425
|
);
|
|
422
426
|
}
|
|
423
427
|
|
|
428
|
+
.prosemirror-surface .ProseMirror .wre-workflow-rail-locked-zone {
|
|
429
|
+
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--wre-workflow-rail-color, var(--color-danger)) 10%, transparent);
|
|
430
|
+
}
|
|
431
|
+
|
|
424
432
|
.prosemirror-surface .ProseMirror .wre-workflow-rail-selection-zone {
|
|
425
433
|
background: transparent;
|
|
426
434
|
}
|