@beyondwork/docx-react-component 1.0.19 → 1.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/api/public-types.ts +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 +850 -1315
- package/src/ui/editor-command-bag.ts +120 -0
- package/src/ui/editor-runtime-boundary.ts +1422 -0
- package/src/ui/editor-shell-view.tsx +134 -0
- package/src/ui/editor-surface-controller.tsx +51 -0
- package/src/ui/headless/revision-decoration-model.ts +4 -4
- package/src/ui/runtime-snapshot-selectors.ts +197 -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 +35 -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 +51 -0
- package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +7 -1
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +174 -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 +4 -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
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
CompatibilityReport,
|
|
3
3
|
DocumentNavigationSnapshot,
|
|
4
|
+
FieldSnapshot,
|
|
5
|
+
ProtectionSnapshot,
|
|
4
6
|
RuntimeRenderSnapshot,
|
|
5
7
|
} from "../api/public-types.ts";
|
|
6
8
|
import { parseCommentsFromOoxml } from "../io/ooxml/parse-comments.ts";
|
|
@@ -19,6 +21,32 @@ export interface ClosureValidationContext {
|
|
|
19
21
|
navigation?: Pick<DocumentNavigationSnapshot, "pages">;
|
|
20
22
|
compatibility: Pick<CompatibilityReport, "errors" | "featureEntries">;
|
|
21
23
|
surface: RuntimeRenderSnapshot["surface"];
|
|
24
|
+
fieldSnapshot?: FieldSnapshot;
|
|
25
|
+
protectionSnapshot?: ProtectionSnapshot;
|
|
26
|
+
harnessShowcase?: HarnessShowcaseValidationContext;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type HarnessShowcaseArea =
|
|
30
|
+
| "workflow-overlay"
|
|
31
|
+
| "blocked-commands"
|
|
32
|
+
| "preserve-only"
|
|
33
|
+
| "search-candidates"
|
|
34
|
+
| "right-rail"
|
|
35
|
+
| "multi-scope"
|
|
36
|
+
| "public-api"
|
|
37
|
+
| "sidebar-integration"
|
|
38
|
+
| "policy-yaml"
|
|
39
|
+
| "harness-lifecycle"
|
|
40
|
+
| "export-continuity";
|
|
41
|
+
|
|
42
|
+
export interface HarnessShowcaseAreaProof {
|
|
43
|
+
demonstrated: boolean;
|
|
44
|
+
detail?: string;
|
|
45
|
+
proofArtifacts?: string[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface HarnessShowcaseValidationContext {
|
|
49
|
+
areas: Partial<Record<HarnessShowcaseArea, HarnessShowcaseAreaProof>>;
|
|
22
50
|
}
|
|
23
51
|
|
|
24
52
|
export type ClosureValidationCheck =
|
|
@@ -31,6 +59,31 @@ export type ClosureValidationCheck =
|
|
|
31
59
|
| { type: "surfaceBlockKind"; kind: string; count?: number }
|
|
32
60
|
| { type: "opaqueBlockLabelPrefix"; value: string }
|
|
33
61
|
| { type: "opaqueInlineLabelPrefix"; value: string }
|
|
62
|
+
| {
|
|
63
|
+
type: "trackedChangeMatch";
|
|
64
|
+
kind?: "insertion" | "deletion" | "formatting" | "move" | "property-change";
|
|
65
|
+
actionability?: "actionable" | "preserve-only";
|
|
66
|
+
status?: "active" | "accepted" | "rejected" | "detached";
|
|
67
|
+
preserveOnlyReasonIncludes?: string[];
|
|
68
|
+
}
|
|
69
|
+
| {
|
|
70
|
+
type: "fieldEntryMatch";
|
|
71
|
+
fieldFamily?: string;
|
|
72
|
+
supported?: boolean;
|
|
73
|
+
refreshStatus?: string;
|
|
74
|
+
displayTextIncludes?: string[];
|
|
75
|
+
fieldTarget?: string;
|
|
76
|
+
}
|
|
77
|
+
| {
|
|
78
|
+
type: "protectionMatch";
|
|
79
|
+
hasDocumentProtection?: boolean;
|
|
80
|
+
editType?: string;
|
|
81
|
+
enforcementActive?: boolean;
|
|
82
|
+
enforcedRangeCountAtLeast?: number;
|
|
83
|
+
preservedRangeCountAtLeast?: number;
|
|
84
|
+
rangeId?: string;
|
|
85
|
+
rangeEnforced?: boolean;
|
|
86
|
+
}
|
|
34
87
|
| {
|
|
35
88
|
type: "secondaryStoryMatch";
|
|
36
89
|
kind: "header" | "footer" | "footnote" | "endnote";
|
|
@@ -59,6 +112,11 @@ export type ClosureValidationCheck =
|
|
|
59
112
|
entryBodies?: string[];
|
|
60
113
|
entryAuthorIds?: string[];
|
|
61
114
|
authorId?: string;
|
|
115
|
+
}
|
|
116
|
+
| {
|
|
117
|
+
type: "harnessShowcase";
|
|
118
|
+
area: HarnessShowcaseArea;
|
|
119
|
+
claim: string;
|
|
62
120
|
};
|
|
63
121
|
|
|
64
122
|
export interface ClosureValidationResult {
|
|
@@ -87,6 +145,28 @@ export interface DocxCommentProof {
|
|
|
87
145
|
}>;
|
|
88
146
|
}
|
|
89
147
|
|
|
148
|
+
export function evaluateHarnessShowcaseCheck(
|
|
149
|
+
check: Extract<ClosureValidationCheck, { type: "harnessShowcase" }>,
|
|
150
|
+
context: HarnessShowcaseValidationContext,
|
|
151
|
+
): ClosureValidationResult {
|
|
152
|
+
const areaProof = context.areas[check.area];
|
|
153
|
+
if (!areaProof) {
|
|
154
|
+
return {
|
|
155
|
+
type: check.type,
|
|
156
|
+
passed: false,
|
|
157
|
+
reason: `missing harness showcase proof for area ${check.area}: ${check.claim}`,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
type: check.type,
|
|
163
|
+
passed: areaProof.demonstrated,
|
|
164
|
+
reason:
|
|
165
|
+
areaProof.detail ??
|
|
166
|
+
`expected harness showcase proof for area ${check.area}: ${check.claim}`,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
90
170
|
export function evaluateClosureCheck(
|
|
91
171
|
check: ClosureValidationCheck,
|
|
92
172
|
context: ClosureValidationContext,
|
|
@@ -163,6 +243,87 @@ export function evaluateClosureCheck(
|
|
|
163
243
|
passed: hasOpaqueInlineLabelPrefix(context.surface, check.value),
|
|
164
244
|
reason: `expected an opaque inline label starting with ${check.value}`,
|
|
165
245
|
};
|
|
246
|
+
case "trackedChangeMatch": {
|
|
247
|
+
const passed = context.renderSnapshot.trackedChanges.revisions.some((revision) => {
|
|
248
|
+
if (check.kind && revision.kind !== check.kind) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
if (check.actionability && revision.actionability !== check.actionability) {
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
if (check.status && revision.status !== check.status) {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
if (
|
|
258
|
+
check.preserveOnlyReasonIncludes &&
|
|
259
|
+
!check.preserveOnlyReasonIncludes.every((fragment) =>
|
|
260
|
+
(revision.preserveOnlyReason ?? "").includes(fragment),
|
|
261
|
+
)
|
|
262
|
+
) {
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
return true;
|
|
266
|
+
});
|
|
267
|
+
return {
|
|
268
|
+
type: check.type,
|
|
269
|
+
passed,
|
|
270
|
+
reason: `expected a tracked change matching ${describeTrackedChangeMatch(check)}`,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
case "fieldEntryMatch": {
|
|
274
|
+
const passed =
|
|
275
|
+
context.fieldSnapshot?.fields.some((field) => {
|
|
276
|
+
if (check.fieldFamily && field.fieldFamily !== check.fieldFamily) {
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
if (check.supported !== undefined && field.supported !== check.supported) {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
if (check.refreshStatus && field.refreshStatus !== check.refreshStatus) {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
if (check.fieldTarget && field.fieldTarget !== check.fieldTarget) {
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
if (
|
|
289
|
+
check.displayTextIncludes &&
|
|
290
|
+
!check.displayTextIncludes.every((fragment) => field.displayText.includes(fragment))
|
|
291
|
+
) {
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
return true;
|
|
295
|
+
}) ?? false;
|
|
296
|
+
return {
|
|
297
|
+
type: check.type,
|
|
298
|
+
passed,
|
|
299
|
+
reason: `expected a field entry matching ${describeFieldEntryMatch(check)}`,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
case "protectionMatch": {
|
|
303
|
+
const snapshot = context.protectionSnapshot;
|
|
304
|
+
const passed = Boolean(
|
|
305
|
+
snapshot &&
|
|
306
|
+
(check.hasDocumentProtection === undefined ||
|
|
307
|
+
snapshot.hasDocumentProtection === check.hasDocumentProtection) &&
|
|
308
|
+
(check.editType === undefined || snapshot.editType === check.editType) &&
|
|
309
|
+
(check.enforcementActive === undefined ||
|
|
310
|
+
snapshot.enforcementActive === check.enforcementActive) &&
|
|
311
|
+
(check.enforcedRangeCountAtLeast === undefined ||
|
|
312
|
+
snapshot.enforcedRangeCount >= check.enforcedRangeCountAtLeast) &&
|
|
313
|
+
(check.preservedRangeCountAtLeast === undefined ||
|
|
314
|
+
snapshot.preservedRangeCount >= check.preservedRangeCountAtLeast) &&
|
|
315
|
+
(!check.rangeId ||
|
|
316
|
+
snapshot.ranges.some((range) =>
|
|
317
|
+
range.rangeId === check.rangeId &&
|
|
318
|
+
(check.rangeEnforced === undefined || range.enforced === check.rangeEnforced),
|
|
319
|
+
))
|
|
320
|
+
);
|
|
321
|
+
return {
|
|
322
|
+
type: check.type,
|
|
323
|
+
passed,
|
|
324
|
+
reason: `expected protection snapshot matching ${describeProtectionMatch(check)}`,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
166
327
|
case "secondaryStoryMatch": {
|
|
167
328
|
const passed =
|
|
168
329
|
context.surface?.secondaryStories.some((story) => {
|
|
@@ -229,6 +390,8 @@ export function evaluateClosureCheck(
|
|
|
229
390
|
reason: `expected a comment thread matching ${describeCommentThreadMatch(check)}`,
|
|
230
391
|
};
|
|
231
392
|
}
|
|
393
|
+
case "harnessShowcase":
|
|
394
|
+
return evaluateHarnessShowcaseCheck(check, context.harnessShowcase ?? { areas: {} });
|
|
232
395
|
default:
|
|
233
396
|
return {
|
|
234
397
|
type: (check as { type: string }).type,
|
|
@@ -364,6 +527,63 @@ function matchesCommentThread(
|
|
|
364
527
|
return true;
|
|
365
528
|
}
|
|
366
529
|
|
|
530
|
+
function describeTrackedChangeMatch(
|
|
531
|
+
check: Extract<ClosureValidationCheck, { type: "trackedChangeMatch" }>,
|
|
532
|
+
): string {
|
|
533
|
+
return [
|
|
534
|
+
check.kind ? `kind=${check.kind}` : undefined,
|
|
535
|
+
check.actionability ? `actionability=${check.actionability}` : undefined,
|
|
536
|
+
check.status ? `status=${check.status}` : undefined,
|
|
537
|
+
check.preserveOnlyReasonIncludes?.length
|
|
538
|
+
? `preserveOnlyReasonIncludes=${check.preserveOnlyReasonIncludes.join(",")}`
|
|
539
|
+
: undefined,
|
|
540
|
+
]
|
|
541
|
+
.filter(Boolean)
|
|
542
|
+
.join(" ");
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function describeFieldEntryMatch(
|
|
546
|
+
check: Extract<ClosureValidationCheck, { type: "fieldEntryMatch" }>,
|
|
547
|
+
): string {
|
|
548
|
+
return [
|
|
549
|
+
check.fieldFamily ? `fieldFamily=${check.fieldFamily}` : undefined,
|
|
550
|
+
check.supported !== undefined ? `supported=${String(check.supported)}` : undefined,
|
|
551
|
+
check.refreshStatus ? `refreshStatus=${check.refreshStatus}` : undefined,
|
|
552
|
+
check.fieldTarget ? `fieldTarget=${check.fieldTarget}` : undefined,
|
|
553
|
+
check.displayTextIncludes?.length
|
|
554
|
+
? `displayTextIncludes=${check.displayTextIncludes.join(",")}`
|
|
555
|
+
: undefined,
|
|
556
|
+
]
|
|
557
|
+
.filter(Boolean)
|
|
558
|
+
.join(" ");
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
function describeProtectionMatch(
|
|
562
|
+
check: Extract<ClosureValidationCheck, { type: "protectionMatch" }>,
|
|
563
|
+
): string {
|
|
564
|
+
return [
|
|
565
|
+
check.hasDocumentProtection !== undefined
|
|
566
|
+
? `hasDocumentProtection=${String(check.hasDocumentProtection)}`
|
|
567
|
+
: undefined,
|
|
568
|
+
check.editType ? `editType=${check.editType}` : undefined,
|
|
569
|
+
check.enforcementActive !== undefined
|
|
570
|
+
? `enforcementActive=${String(check.enforcementActive)}`
|
|
571
|
+
: undefined,
|
|
572
|
+
check.enforcedRangeCountAtLeast !== undefined
|
|
573
|
+
? `enforcedRangeCountAtLeast=${String(check.enforcedRangeCountAtLeast)}`
|
|
574
|
+
: undefined,
|
|
575
|
+
check.preservedRangeCountAtLeast !== undefined
|
|
576
|
+
? `preservedRangeCountAtLeast=${String(check.preservedRangeCountAtLeast)}`
|
|
577
|
+
: undefined,
|
|
578
|
+
check.rangeId ? `rangeId=${check.rangeId}` : undefined,
|
|
579
|
+
check.rangeEnforced !== undefined
|
|
580
|
+
? `rangeEnforced=${String(check.rangeEnforced)}`
|
|
581
|
+
: undefined,
|
|
582
|
+
]
|
|
583
|
+
.filter(Boolean)
|
|
584
|
+
.join(" ");
|
|
585
|
+
}
|
|
586
|
+
|
|
367
587
|
function getLayoutsForCheck(
|
|
368
588
|
context: ClosureValidationContext,
|
|
369
589
|
check: Extract<ClosureValidationCheck, { type: "pageLayoutMatch" }>,
|