@beyondwork/docx-react-component 1.0.19 → 1.0.21
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 +44 -25
- package/src/api/public-types.ts +336 -0
- package/src/api/session-state.ts +2 -0
- package/src/core/commands/formatting-commands.ts +1 -1
- package/src/core/commands/index.ts +14 -2
- package/src/core/search/search-text.ts +28 -0
- package/src/core/state/editor-state.ts +3 -0
- package/src/index.ts +21 -0
- package/src/io/docx-session.ts +363 -17
- package/src/io/export/serialize-comments.ts +104 -34
- package/src/io/export/serialize-footnotes.ts +198 -1
- package/src/io/export/serialize-headers-footers.ts +203 -10
- package/src/io/export/serialize-main-document.ts +83 -3
- package/src/io/export/split-review-boundaries.ts +181 -19
- package/src/io/normalize/normalize-text.ts +82 -8
- package/src/io/ooxml/highlight-colors.ts +39 -0
- package/src/io/ooxml/parse-comments.ts +85 -19
- package/src/io/ooxml/parse-fields.ts +396 -0
- package/src/io/ooxml/parse-footnotes.ts +240 -2
- package/src/io/ooxml/parse-headers-footers.ts +431 -7
- package/src/io/ooxml/parse-inline-media.ts +15 -1
- package/src/io/ooxml/parse-main-document.ts +396 -14
- package/src/io/ooxml/parse-revisions.ts +317 -38
- package/src/legal/bookmarks.ts +44 -0
- package/src/legal/cross-references.ts +59 -1
- package/src/model/canonical-document.ts +117 -1
- package/src/model/snapshot.ts +85 -1
- package/src/review/store/revision-store.ts +6 -0
- package/src/review/store/revision-types.ts +1 -0
- package/src/runtime/document-navigation.ts +52 -13
- package/src/runtime/document-runtime.ts +1521 -75
- package/src/runtime/read-only-diagnostics-runtime.ts +8 -0
- package/src/runtime/session-capabilities.ts +33 -3
- package/src/runtime/surface-projection.ts +86 -25
- package/src/runtime/table-schema.ts +2 -2
- package/src/runtime/view-state.ts +24 -6
- package/src/runtime/workflow-markup.ts +349 -0
- package/src/ui/WordReviewEditor.tsx +915 -1314
- package/src/ui/editor-command-bag.ts +120 -0
- package/src/ui/editor-runtime-boundary.ts +1448 -0
- package/src/ui/editor-shell-view.tsx +134 -0
- package/src/ui/editor-surface-controller.tsx +55 -0
- package/src/ui/headless/revision-decoration-model.ts +4 -4
- package/src/ui/runtime-snapshot-selectors.ts +197 -0
- package/src/ui/workflow-surface-blocked-rails.ts +94 -0
- package/src/ui-tailwind/chrome/tw-alert-banner.tsx +18 -2
- package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +129 -0
- package/src/ui-tailwind/chrome/tw-layout-panel.tsx +114 -0
- package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +34 -0
- package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +27 -2
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +128 -0
- package/src/ui-tailwind/editor-surface/perf-probe.ts +86 -14
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +2 -2
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +237 -0
- package/src/ui-tailwind/editor-surface/pm-position-map.ts +1 -1
- package/src/ui-tailwind/editor-surface/pm-schema.ts +139 -8
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +98 -48
- package/src/ui-tailwind/editor-surface/surface-build-keys.ts +55 -0
- package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +7 -1
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +190 -48
- package/src/ui-tailwind/page-chrome-model.ts +27 -0
- package/src/ui-tailwind/review/tw-comment-sidebar.tsx +7 -7
- package/src/ui-tailwind/review/tw-health-panel.tsx +31 -2
- package/src/ui-tailwind/review/tw-review-rail.tsx +3 -3
- package/src/ui-tailwind/review/tw-revision-sidebar.tsx +15 -15
- package/src/ui-tailwind/theme/editor-theme.css +130 -0
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +543 -5
- package/src/ui-tailwind/tw-review-workspace.tsx +316 -19
- package/src/validation/compatibility-engine.ts +27 -4
- package/src/validation/compatibility-report.ts +1 -0
- package/src/validation/docx-comment-proof.ts +220 -0
|
@@ -17,6 +17,12 @@ export interface PMStateResult {
|
|
|
17
17
|
positionMap: PositionMap;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
export interface MediaPreviewDescriptor {
|
|
21
|
+
src: string;
|
|
22
|
+
widthEmu?: number;
|
|
23
|
+
heightEmu?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
20
26
|
/**
|
|
21
27
|
* Create a ProseMirror EditorState from a runtime surface snapshot.
|
|
22
28
|
*
|
|
@@ -27,8 +33,9 @@ export function createPMStateFromSnapshot(
|
|
|
27
33
|
surface: EditorSurfaceSnapshot,
|
|
28
34
|
selection: SelectionSnapshot,
|
|
29
35
|
plugins: Plugin[],
|
|
36
|
+
mediaPreviews: Record<string, MediaPreviewDescriptor> = {},
|
|
30
37
|
): PMStateResult {
|
|
31
|
-
const doc = buildPMDoc(surface);
|
|
38
|
+
const doc = buildPMDoc(surface, mediaPreviews);
|
|
32
39
|
const positionMap = buildPositionMap(surface);
|
|
33
40
|
const pmSelection = createPMSelectionFromSnapshot(doc, positionMap, selection);
|
|
34
41
|
|
|
@@ -50,7 +57,8 @@ export function createPMSelectionFromSnapshot(
|
|
|
50
57
|
const pmHead = clamp(positionMap.runtimeToPm(selection.head), 1, positionMap.pmDocSize - 1);
|
|
51
58
|
try {
|
|
52
59
|
if (selection.activeRange.kind === "node") {
|
|
53
|
-
|
|
60
|
+
const pmNodePos = clamp(pmAnchor - 1, 0, positionMap.pmDocSize - 2);
|
|
61
|
+
return NodeSelection.create(doc, pmNodePos);
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
const forward = selection.head >= selection.anchor;
|
|
@@ -98,31 +106,52 @@ function resolveInlineBoundary(
|
|
|
98
106
|
return null;
|
|
99
107
|
}
|
|
100
108
|
|
|
101
|
-
function buildPMDoc(
|
|
102
|
-
|
|
109
|
+
function buildPMDoc(
|
|
110
|
+
surface: EditorSurfaceSnapshot,
|
|
111
|
+
mediaPreviews: Record<string, MediaPreviewDescriptor>,
|
|
112
|
+
): PMNode {
|
|
113
|
+
const blocks = buildPMBlocks(surface.blocks, mediaPreviews);
|
|
114
|
+
|
|
115
|
+
// Ensure at least one block (PM requires non-empty doc)
|
|
116
|
+
if (blocks.length === 0) {
|
|
117
|
+
blocks.push(editorSchema.nodes.paragraph.create());
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return editorSchema.nodes.doc.create(null, Fragment.from(blocks));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function buildPMBlocks(
|
|
124
|
+
blocks: SurfaceBlockSnapshot[],
|
|
125
|
+
mediaPreviews: Record<string, MediaPreviewDescriptor>,
|
|
126
|
+
): PMNode[] {
|
|
127
|
+
const nodes: PMNode[] = [];
|
|
128
|
+
|
|
129
|
+
for (let index = 0; index < blocks.length; index += 1) {
|
|
130
|
+
const block = blocks[index];
|
|
131
|
+
const previousBlock = index > 0 ? blocks[index - 1] : null;
|
|
132
|
+
const nextBlock = blocks[index + 1];
|
|
133
|
+
const previousParagraph = previousBlock?.kind === "paragraph" ? previousBlock : null;
|
|
134
|
+
const nextParagraph = nextBlock?.kind === "paragraph" ? nextBlock : null;
|
|
103
135
|
|
|
104
|
-
for (const block of surface.blocks) {
|
|
105
136
|
if (block.kind === "paragraph") {
|
|
106
|
-
|
|
137
|
+
nodes.push(buildParagraph(block, previousParagraph, nextParagraph, mediaPreviews));
|
|
107
138
|
} else if (block.kind === "table") {
|
|
108
|
-
|
|
139
|
+
nodes.push(buildTable(block, mediaPreviews));
|
|
109
140
|
} else if (block.kind === "sdt_block") {
|
|
110
|
-
|
|
141
|
+
nodes.push(buildSdtBlock(block, mediaPreviews));
|
|
111
142
|
} else {
|
|
112
|
-
|
|
143
|
+
nodes.push(buildOpaqueBlock(block));
|
|
113
144
|
}
|
|
114
145
|
}
|
|
115
146
|
|
|
116
|
-
|
|
117
|
-
if (blocks.length === 0) {
|
|
118
|
-
blocks.push(editorSchema.nodes.paragraph.create());
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return editorSchema.nodes.doc.create(null, Fragment.from(blocks));
|
|
147
|
+
return nodes;
|
|
122
148
|
}
|
|
123
149
|
|
|
124
150
|
function buildParagraph(
|
|
125
151
|
block: Extract<SurfaceBlockSnapshot, { kind: "paragraph" }>,
|
|
152
|
+
previousParagraph: Extract<SurfaceBlockSnapshot, { kind: "paragraph" }> | null,
|
|
153
|
+
nextParagraph: Extract<SurfaceBlockSnapshot, { kind: "paragraph" }> | null,
|
|
154
|
+
mediaPreviews: Record<string, MediaPreviewDescriptor>,
|
|
126
155
|
): PMNode {
|
|
127
156
|
const content: PMNode[] = [];
|
|
128
157
|
const tabStops = block.tabStops ?? [];
|
|
@@ -148,11 +177,28 @@ function buildParagraph(
|
|
|
148
177
|
);
|
|
149
178
|
tabIndex++;
|
|
150
179
|
} else {
|
|
151
|
-
const nodes = buildInlineContent(segment);
|
|
180
|
+
const nodes = buildInlineContent(segment, mediaPreviews);
|
|
152
181
|
content.push(...nodes);
|
|
153
182
|
}
|
|
154
183
|
}
|
|
155
184
|
|
|
185
|
+
const listContinuation = Boolean(
|
|
186
|
+
block.numbering &&
|
|
187
|
+
nextParagraph?.numbering &&
|
|
188
|
+
nextParagraph.numbering.numberingInstanceId === block.numbering.numberingInstanceId &&
|
|
189
|
+
nextParagraph.numbering.level === block.numbering.level,
|
|
190
|
+
);
|
|
191
|
+
const contextualSpacingAfter = Boolean(
|
|
192
|
+
block.contextualSpacing &&
|
|
193
|
+
nextParagraph?.contextualSpacing &&
|
|
194
|
+
(nextParagraph.styleId ?? "__default__") === (block.styleId ?? "__default__"),
|
|
195
|
+
);
|
|
196
|
+
const contextualSpacingBefore = Boolean(
|
|
197
|
+
block.contextualSpacing &&
|
|
198
|
+
previousParagraph?.contextualSpacing &&
|
|
199
|
+
(previousParagraph.styleId ?? "__default__") === (block.styleId ?? "__default__"),
|
|
200
|
+
);
|
|
201
|
+
|
|
156
202
|
return editorSchema.nodes.paragraph.create(
|
|
157
203
|
{
|
|
158
204
|
styleId: block.styleId ?? null,
|
|
@@ -169,9 +215,14 @@ function buildParagraph(
|
|
|
169
215
|
spacingAfter: block.spacing?.after ?? null,
|
|
170
216
|
lineSpacing: block.spacing?.line ?? null,
|
|
171
217
|
lineRule: block.spacing?.lineRule ?? null,
|
|
218
|
+
contextualSpacing: block.contextualSpacing ?? null,
|
|
219
|
+
listContinuation: listContinuation || null,
|
|
220
|
+
contextualSpacingBefore: contextualSpacingBefore || null,
|
|
221
|
+
contextualSpacingAfter: contextualSpacingAfter || null,
|
|
172
222
|
indentLeft: block.indentation?.left ?? null,
|
|
173
223
|
indentRight: block.indentation?.right ?? null,
|
|
174
224
|
indentFirstLine: block.indentation?.firstLine ?? null,
|
|
225
|
+
indentHanging: block.indentation?.hanging ?? null,
|
|
175
226
|
shadingFill: block.shading?.fill ?? null,
|
|
176
227
|
borderTop: (block.borders as Record<string, unknown>)?.top ?? null,
|
|
177
228
|
borderBottom: (block.borders as Record<string, unknown>)?.bottom ?? null,
|
|
@@ -185,7 +236,10 @@ function buildParagraph(
|
|
|
185
236
|
);
|
|
186
237
|
}
|
|
187
238
|
|
|
188
|
-
function buildInlineContent(
|
|
239
|
+
function buildInlineContent(
|
|
240
|
+
segment: SurfaceInlineSegment,
|
|
241
|
+
mediaPreviews: Record<string, MediaPreviewDescriptor>,
|
|
242
|
+
): PMNode[] {
|
|
189
243
|
switch (segment.kind) {
|
|
190
244
|
case "text": {
|
|
191
245
|
if (!segment.text) return [];
|
|
@@ -253,6 +307,8 @@ function buildInlineContent(segment: SurfaceInlineSegment): PMNode[] {
|
|
|
253
307
|
return [editorSchema.nodes.tab_char.create()];
|
|
254
308
|
|
|
255
309
|
case "image":
|
|
310
|
+
{
|
|
311
|
+
const preview = mediaPreviews[segment.mediaId];
|
|
256
312
|
return [
|
|
257
313
|
editorSchema.nodes.image_atom.create({
|
|
258
314
|
mediaId: segment.mediaId,
|
|
@@ -260,8 +316,12 @@ function buildInlineContent(segment: SurfaceInlineSegment): PMNode[] {
|
|
|
260
316
|
state: segment.state,
|
|
261
317
|
display: segment.display ?? "inline",
|
|
262
318
|
detail: segment.detail ?? null,
|
|
319
|
+
src: preview?.src ?? null,
|
|
320
|
+
widthEmu: preview?.widthEmu ?? null,
|
|
321
|
+
heightEmu: preview?.heightEmu ?? null,
|
|
263
322
|
}),
|
|
264
323
|
];
|
|
324
|
+
}
|
|
265
325
|
|
|
266
326
|
case "opaque_inline":
|
|
267
327
|
return [buildOpaqueInlineOrComplexAtom(segment)];
|
|
@@ -274,6 +334,17 @@ function buildInlineContent(segment: SurfaceInlineSegment): PMNode[] {
|
|
|
274
334
|
return [text];
|
|
275
335
|
}
|
|
276
336
|
|
|
337
|
+
case "field_ref":
|
|
338
|
+
return [
|
|
339
|
+
editorSchema.nodes.field_ref_atom.create({
|
|
340
|
+
fieldFamily: segment.fieldFamily,
|
|
341
|
+
fieldTarget: segment.fieldTarget ?? null,
|
|
342
|
+
instruction: segment.instruction,
|
|
343
|
+
refreshStatus: segment.refreshStatus,
|
|
344
|
+
label: segment.label,
|
|
345
|
+
}),
|
|
346
|
+
];
|
|
347
|
+
|
|
277
348
|
default:
|
|
278
349
|
return [];
|
|
279
350
|
}
|
|
@@ -281,23 +352,13 @@ function buildInlineContent(segment: SurfaceInlineSegment): PMNode[] {
|
|
|
281
352
|
|
|
282
353
|
function buildTable(
|
|
283
354
|
block: Extract<SurfaceBlockSnapshot, { kind: "table" }>,
|
|
355
|
+
mediaPreviews: Record<string, MediaPreviewDescriptor>,
|
|
284
356
|
): PMNode {
|
|
285
357
|
const rows: PMNode[] = [];
|
|
286
358
|
for (const row of block.rows) {
|
|
287
359
|
const cells: PMNode[] = [];
|
|
288
360
|
for (const cell of row.cells) {
|
|
289
|
-
const cellContent
|
|
290
|
-
for (const child of cell.content) {
|
|
291
|
-
if (child.kind === "paragraph") {
|
|
292
|
-
cellContent.push(buildParagraph(child as Extract<SurfaceBlockSnapshot, { kind: "paragraph" }>));
|
|
293
|
-
} else if (child.kind === "table") {
|
|
294
|
-
cellContent.push(buildTable(child as Extract<SurfaceBlockSnapshot, { kind: "table" }>));
|
|
295
|
-
} else if (child.kind === "sdt_block") {
|
|
296
|
-
cellContent.push(buildSdtBlock(child as Extract<SurfaceBlockSnapshot, { kind: "sdt_block" }>));
|
|
297
|
-
} else if (child.kind === "opaque_block") {
|
|
298
|
-
cellContent.push(buildOpaqueBlock(child as Extract<SurfaceBlockSnapshot, { kind: "opaque_block" }>));
|
|
299
|
-
}
|
|
300
|
-
}
|
|
361
|
+
const cellContent = buildPMBlocks(cell.content, mediaPreviews);
|
|
301
362
|
// Ensure at least one paragraph in cell (PM requires non-empty)
|
|
302
363
|
if (cellContent.length === 0) {
|
|
303
364
|
cellContent.push(editorSchema.nodes.paragraph.create());
|
|
@@ -347,19 +408,9 @@ function buildTable(
|
|
|
347
408
|
|
|
348
409
|
function buildSdtBlock(
|
|
349
410
|
block: Extract<SurfaceBlockSnapshot, { kind: "sdt_block" }>,
|
|
411
|
+
mediaPreviews: Record<string, MediaPreviewDescriptor>,
|
|
350
412
|
): PMNode {
|
|
351
|
-
const children = block.children
|
|
352
|
-
if (child.kind === "paragraph") {
|
|
353
|
-
return buildParagraph(child);
|
|
354
|
-
}
|
|
355
|
-
if (child.kind === "table") {
|
|
356
|
-
return buildTable(child);
|
|
357
|
-
}
|
|
358
|
-
if (child.kind === "sdt_block") {
|
|
359
|
-
return buildSdtBlock(child);
|
|
360
|
-
}
|
|
361
|
-
return buildOpaqueBlock(child);
|
|
362
|
-
});
|
|
413
|
+
const children = buildPMBlocks(block.children, mediaPreviews);
|
|
363
414
|
|
|
364
415
|
if (children.length === 0) {
|
|
365
416
|
children.push(editorSchema.nodes.paragraph.create());
|
|
@@ -392,15 +443,14 @@ function buildOpaqueInlineOrComplexAtom(
|
|
|
392
443
|
const label = segment.label;
|
|
393
444
|
const detail = segment.detail;
|
|
394
445
|
|
|
395
|
-
if (label === "
|
|
446
|
+
if (label === "Embedded chart") {
|
|
396
447
|
return editorSchema.nodes.chart_atom.create({ detail });
|
|
397
448
|
}
|
|
398
|
-
if (label === "SmartArt") {
|
|
449
|
+
if (label === "SmartArt diagram") {
|
|
399
450
|
return editorSchema.nodes.smartart_atom.create({ detail });
|
|
400
451
|
}
|
|
401
|
-
if (label === "
|
|
402
|
-
|
|
403
|
-
const textMatch = /Text: "([^"]+)"/.exec(detail);
|
|
452
|
+
if (label === "Drawing shape" || label === "Text box") {
|
|
453
|
+
const textMatch = /(?:Text content|Content): "([^"]+)"/.exec(detail);
|
|
404
454
|
const geometryMatch = /Geometry: ([^.]+)\./.exec(detail);
|
|
405
455
|
return editorSchema.nodes.shape_atom.create({
|
|
406
456
|
text: textMatch ? textMatch[1] : null,
|
|
@@ -417,8 +467,8 @@ function buildOpaqueInlineOrComplexAtom(
|
|
|
417
467
|
detail,
|
|
418
468
|
});
|
|
419
469
|
}
|
|
420
|
-
if (label === "VML
|
|
421
|
-
const textMatch = /Text: "([^"]+)"/.exec(detail);
|
|
470
|
+
if (label === "Legacy VML drawing") {
|
|
471
|
+
const textMatch = /Text content: "([^"]+)"/.exec(detail);
|
|
422
472
|
const typeMatch = /Type: ([^.]+)\./.exec(detail);
|
|
423
473
|
return editorSchema.nodes.vml_atom.create({
|
|
424
474
|
text: textMatch ? textMatch[1] : null,
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
EditorStoryTarget,
|
|
3
|
+
EditorSurfaceSnapshot,
|
|
4
|
+
} from "../../api/public-types.ts";
|
|
5
|
+
|
|
6
|
+
const surfaceIdentityMap = new WeakMap<EditorSurfaceSnapshot, number>();
|
|
7
|
+
let nextSurfaceIdentity = 0;
|
|
8
|
+
|
|
9
|
+
function getSurfaceIdentity(surface: EditorSurfaceSnapshot): number {
|
|
10
|
+
const cached = surfaceIdentityMap.get(surface);
|
|
11
|
+
if (cached !== undefined) {
|
|
12
|
+
return cached;
|
|
13
|
+
}
|
|
14
|
+
const identity = nextSurfaceIdentity;
|
|
15
|
+
nextSurfaceIdentity += 1;
|
|
16
|
+
surfaceIdentityMap.set(surface, identity);
|
|
17
|
+
return identity;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function createSurfaceDocumentBuildKey(input: {
|
|
21
|
+
surface: EditorSurfaceSnapshot | null | undefined;
|
|
22
|
+
activeStory: EditorStoryTarget;
|
|
23
|
+
mediaPreviewKey: string;
|
|
24
|
+
}): string {
|
|
25
|
+
return JSON.stringify({
|
|
26
|
+
surfaceIdentity:
|
|
27
|
+
input.surface === undefined || input.surface === null
|
|
28
|
+
? "loading"
|
|
29
|
+
: getSurfaceIdentity(input.surface),
|
|
30
|
+
activeStory: input.activeStory,
|
|
31
|
+
mediaPreviewKey: input.mediaPreviewKey,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function createSurfaceDecorationKey(input: {
|
|
36
|
+
markupDisplay: string;
|
|
37
|
+
showTrackedChanges: boolean;
|
|
38
|
+
canEdit: boolean;
|
|
39
|
+
activeCommentId?: string;
|
|
40
|
+
activeRevisionId?: string;
|
|
41
|
+
workflowScopeSignature?: string;
|
|
42
|
+
workflowCandidateSignature?: string;
|
|
43
|
+
workflowBlockedSignature?: string;
|
|
44
|
+
}): string {
|
|
45
|
+
return JSON.stringify({
|
|
46
|
+
markupDisplay: input.markupDisplay,
|
|
47
|
+
showTrackedChanges: input.showTrackedChanges,
|
|
48
|
+
canEdit: input.canEdit,
|
|
49
|
+
activeCommentId: input.activeCommentId ?? null,
|
|
50
|
+
activeRevisionId: input.activeRevisionId ?? null,
|
|
51
|
+
workflowScopeSignature: input.workflowScopeSignature ?? null,
|
|
52
|
+
workflowCandidateSignature: input.workflowCandidateSignature ?? null,
|
|
53
|
+
workflowBlockedSignature: input.workflowBlockedSignature ?? null,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
@@ -7,13 +7,14 @@ export interface TwOpaqueBlockProps {
|
|
|
7
7
|
block: Extract<SurfaceBlockSnapshot, { kind: "opaque_block" }>;
|
|
8
8
|
selection: SelectionSnapshot;
|
|
9
9
|
onSelectionChange?: (selection: SelectionSnapshot) => void;
|
|
10
|
+
workflowTargeted?: boolean;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
const focusRingClass =
|
|
13
14
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-canvas";
|
|
14
15
|
|
|
15
16
|
export function TwOpaqueBlock(props: TwOpaqueBlockProps) {
|
|
16
|
-
const { block, selection } = props;
|
|
17
|
+
const { block, selection, workflowTargeted } = props;
|
|
17
18
|
const selected = selectionTouchesRange(selection, block.from, block.to);
|
|
18
19
|
|
|
19
20
|
return (
|
|
@@ -44,6 +45,11 @@ export function TwOpaqueBlock(props: TwOpaqueBlockProps) {
|
|
|
44
45
|
<span className="inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-semibold text-comment bg-warning-soft">
|
|
45
46
|
preserve-only
|
|
46
47
|
</span>
|
|
48
|
+
{workflowTargeted && (
|
|
49
|
+
<span className="inline-flex items-center px-1.5 py-0.5 rounded-full text-[10px] font-semibold text-amber-700 bg-amber-100">
|
|
50
|
+
workflow-targeted
|
|
51
|
+
</span>
|
|
52
|
+
)}
|
|
47
53
|
</div>
|
|
48
54
|
<p className="text-sm text-secondary">{block.detail}</p>
|
|
49
55
|
</button>
|