@beyondwork/docx-react-component 1.0.41 → 1.0.42
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 +13 -1
- package/src/api/awareness-identity-types.ts +35 -0
- package/src/api/comment-negotiation-types.ts +130 -0
- package/src/api/comment-presentation-types.ts +106 -0
- package/src/api/external-custody-types.ts +74 -0
- package/src/api/participants-types.ts +18 -0
- package/src/api/public-types.ts +347 -4
- package/src/api/scope-metadata-resolver-types.ts +88 -0
- package/src/core/commands/formatting-commands.ts +1 -1
- package/src/core/commands/index.ts +568 -1
- package/src/index.ts +118 -1
- package/src/io/export/escape-xml-attribute.ts +26 -0
- package/src/io/export/external-send.ts +188 -0
- package/src/io/export/serialize-comments.ts +13 -16
- package/src/io/export/serialize-footnotes.ts +17 -24
- package/src/io/export/serialize-headers-footers.ts +17 -24
- package/src/io/export/serialize-main-document.ts +59 -62
- package/src/io/export/serialize-numbering.ts +20 -27
- package/src/io/export/serialize-runtime-revisions.ts +2 -9
- package/src/io/export/serialize-tables.ts +8 -15
- package/src/io/export/table-properties-xml.ts +25 -32
- package/src/io/import/external-reimport.ts +40 -0
- package/src/io/ooxml/bw-xml.ts +244 -0
- package/src/io/ooxml/canonicalize-payload.ts +301 -0
- package/src/io/ooxml/comment-negotiation-payload.ts +288 -0
- package/src/io/ooxml/comment-presentation-payload.ts +311 -0
- package/src/io/ooxml/external-custody-payload.ts +102 -0
- package/src/io/ooxml/participants-payload.ts +97 -0
- package/src/io/ooxml/payload-signature.ts +112 -0
- package/src/io/ooxml/workflow-payload-validator.ts +271 -0
- package/src/io/ooxml/workflow-payload.ts +146 -7
- package/src/runtime/awareness-identity.ts +173 -0
- package/src/runtime/collab/event-types.ts +27 -0
- package/src/runtime/collab-session-bridge.ts +157 -0
- package/src/runtime/collab-session-facet.ts +193 -0
- package/src/runtime/collab-session.ts +273 -0
- package/src/runtime/comment-negotiation-sync.ts +91 -0
- package/src/runtime/comment-negotiation.ts +158 -0
- package/src/runtime/comment-presentation.ts +223 -0
- package/src/runtime/document-runtime.ts +280 -93
- package/src/runtime/external-send-runtime.ts +117 -0
- package/src/runtime/layout/docx-font-loader.ts +11 -30
- package/src/runtime/layout/inert-layout-facet.ts +2 -0
- package/src/runtime/layout/layout-engine-instance.ts +122 -12
- package/src/runtime/layout/page-graph.ts +79 -7
- package/src/runtime/layout/paginated-layout-engine.ts +230 -34
- package/src/runtime/layout/public-facet.ts +185 -13
- package/src/runtime/layout/table-row-split.ts +316 -0
- package/src/runtime/markdown-sanitizer.ts +132 -0
- package/src/runtime/participants.ts +134 -0
- package/src/runtime/resign-payload.ts +120 -0
- package/src/runtime/tamper-gate.ts +157 -0
- package/src/runtime/workflow-markup.ts +9 -0
- package/src/runtime/workflow-rail-segments.ts +244 -5
- package/src/ui/WordReviewEditor.tsx +587 -0
- package/src/ui/editor-runtime-boundary.ts +1 -0
- package/src/ui/editor-shell-view.tsx +11 -0
- package/src/ui-tailwind/chrome/chrome-preset-model.ts +28 -0
- package/src/ui-tailwind/chrome/collab-audience-chip.tsx +73 -0
- package/src/ui-tailwind/chrome/collab-negotiation-action-bar.tsx +244 -0
- package/src/ui-tailwind/chrome/collab-presence-strip.tsx +150 -0
- package/src/ui-tailwind/chrome/collab-role-chip.tsx +62 -0
- package/src/ui-tailwind/chrome/collab-send-to-supplier-button.tsx +68 -0
- package/src/ui-tailwind/chrome/collab-send-to-supplier-modal.tsx +149 -0
- package/src/ui-tailwind/chrome/collab-tamper-banner.tsx +68 -0
- package/src/ui-tailwind/chrome/forward-non-drag-click.ts +104 -0
- package/src/ui-tailwind/chrome/tw-mode-dock.tsx +1 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +7 -1
- package/src/ui-tailwind/chrome/tw-table-grip-layer.tsx +1 -38
- package/src/ui-tailwind/chrome-overlay/index.ts +6 -0
- package/src/ui-tailwind/chrome-overlay/scope-card-role-model.ts +78 -0
- package/src/ui-tailwind/chrome-overlay/scope-keyboard-cycle.ts +49 -0
- package/src/ui-tailwind/chrome-overlay/tw-chrome-overlay.tsx +58 -0
- package/src/ui-tailwind/chrome-overlay/tw-page-stack-overlay-layer.tsx +527 -0
- package/src/ui-tailwind/chrome-overlay/tw-scope-card-layer.tsx +120 -22
- package/src/ui-tailwind/chrome-overlay/tw-scope-card.tsx +310 -32
- package/src/ui-tailwind/chrome-overlay/tw-scope-rail-layer.tsx +93 -14
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +35 -1
- package/src/ui-tailwind/editor-surface/pm-page-break-decorations.ts +86 -3
- package/src/ui-tailwind/editor-surface/pm-schema.ts +15 -13
- package/src/ui-tailwind/editor-surface/remote-cursor-plugin.ts +20 -3
- package/src/ui-tailwind/editor-surface/tw-page-block-view.tsx +15 -14
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +66 -0
- package/src/ui-tailwind/index.ts +32 -0
- package/src/ui-tailwind/review/tw-review-rail-footer.tsx +29 -3
- package/src/ui-tailwind/status/tw-status-bar.tsx +52 -1
- package/src/ui-tailwind/theme/editor-theme.css +25 -0
- package/src/ui-tailwind/tw-review-workspace.tsx +293 -34
|
@@ -38,6 +38,52 @@ import { remapCommentThreads } from "../../review/store/comment-remapping.ts";
|
|
|
38
38
|
import { collectScopeTagTouches } from "../../review/store/scope-tag-diff.ts";
|
|
39
39
|
import { applyRevisionRuntimeCommand } from "../../runtime/revision-runtime.ts";
|
|
40
40
|
import type { RevisionStore } from "../../review/store/revision-store.ts";
|
|
41
|
+
import type {
|
|
42
|
+
HeaderFooterLinkPatch,
|
|
43
|
+
HostAnnotationOverlay,
|
|
44
|
+
InsertTableOptions,
|
|
45
|
+
RuntimeRenderSnapshot,
|
|
46
|
+
SectionBreakType,
|
|
47
|
+
SectionLayoutPatch,
|
|
48
|
+
SectionPageNumberingPatch,
|
|
49
|
+
WorkflowMetadataDefinition,
|
|
50
|
+
WorkflowMetadataEntry,
|
|
51
|
+
WorkflowOverlay,
|
|
52
|
+
} from "../../api/public-types.ts";
|
|
53
|
+
import {
|
|
54
|
+
applyFormattingOperationToDocument,
|
|
55
|
+
type FormattingOperation,
|
|
56
|
+
} from "./formatting-commands.ts";
|
|
57
|
+
import {
|
|
58
|
+
applyParagraphStyleToDocument,
|
|
59
|
+
applyTableStyleToDocument,
|
|
60
|
+
} from "./style-commands.ts";
|
|
61
|
+
import {
|
|
62
|
+
continueNumbering,
|
|
63
|
+
indentListItems,
|
|
64
|
+
outdentListItems,
|
|
65
|
+
restartNumbering,
|
|
66
|
+
toggleBulletedList,
|
|
67
|
+
toggleNumberedList,
|
|
68
|
+
} from "./list-commands.ts";
|
|
69
|
+
import {
|
|
70
|
+
applyTableStructureOperation,
|
|
71
|
+
type TableStructureOperation,
|
|
72
|
+
} from "./table-structure-commands.ts";
|
|
73
|
+
import {
|
|
74
|
+
insertImage,
|
|
75
|
+
repositionFloatingImage,
|
|
76
|
+
resizeImage,
|
|
77
|
+
} from "./image-commands.ts";
|
|
78
|
+
import {
|
|
79
|
+
insertSectionBreakAfterSectionIndex,
|
|
80
|
+
deleteSectionBreakAtSectionIndex,
|
|
81
|
+
updateSectionLayoutAtSectionIndex,
|
|
82
|
+
setSectionPageNumberingAtSectionIndex,
|
|
83
|
+
setHeaderFooterLinkAtSectionIndex,
|
|
84
|
+
} from "./section-layout-commands.ts";
|
|
85
|
+
import { insertPageBreak, insertTable } from "./text-commands.ts";
|
|
86
|
+
import type { TableSelectionDescriptor } from "../../runtime/table-commands.ts";
|
|
41
87
|
|
|
42
88
|
export interface CommandOrigin {
|
|
43
89
|
source:
|
|
@@ -170,6 +216,149 @@ export type EditorCommand =
|
|
|
170
216
|
| {
|
|
171
217
|
type: "history.redo";
|
|
172
218
|
origin?: CommandOrigin;
|
|
219
|
+
}
|
|
220
|
+
| {
|
|
221
|
+
type: "workflow.set-overlay";
|
|
222
|
+
overlay: WorkflowOverlay;
|
|
223
|
+
origin?: CommandOrigin;
|
|
224
|
+
}
|
|
225
|
+
| {
|
|
226
|
+
type: "workflow.clear-overlay";
|
|
227
|
+
origin?: CommandOrigin;
|
|
228
|
+
}
|
|
229
|
+
| {
|
|
230
|
+
type: "workflow.set-metadata-definitions";
|
|
231
|
+
definitions: WorkflowMetadataDefinition[];
|
|
232
|
+
origin?: CommandOrigin;
|
|
233
|
+
}
|
|
234
|
+
| {
|
|
235
|
+
type: "workflow.clear-metadata-definitions";
|
|
236
|
+
origin?: CommandOrigin;
|
|
237
|
+
}
|
|
238
|
+
| {
|
|
239
|
+
type: "workflow.set-metadata-entries";
|
|
240
|
+
entries: WorkflowMetadataEntry[];
|
|
241
|
+
origin?: CommandOrigin;
|
|
242
|
+
}
|
|
243
|
+
| {
|
|
244
|
+
type: "workflow.clear-metadata-entries";
|
|
245
|
+
origin?: CommandOrigin;
|
|
246
|
+
}
|
|
247
|
+
| {
|
|
248
|
+
type: "host-annotation.set-overlay";
|
|
249
|
+
overlay: HostAnnotationOverlay;
|
|
250
|
+
origin?: CommandOrigin;
|
|
251
|
+
}
|
|
252
|
+
| {
|
|
253
|
+
type: "host-annotation.clear-overlay";
|
|
254
|
+
origin?: CommandOrigin;
|
|
255
|
+
}
|
|
256
|
+
| {
|
|
257
|
+
type: "formatting.apply";
|
|
258
|
+
operation: FormattingOperation;
|
|
259
|
+
origin?: CommandOrigin;
|
|
260
|
+
}
|
|
261
|
+
| {
|
|
262
|
+
type: "style.set-paragraph";
|
|
263
|
+
styleId: string | null;
|
|
264
|
+
origin?: CommandOrigin;
|
|
265
|
+
}
|
|
266
|
+
| {
|
|
267
|
+
type: "style.set-table";
|
|
268
|
+
styleId: string | null;
|
|
269
|
+
origin?: CommandOrigin;
|
|
270
|
+
}
|
|
271
|
+
| {
|
|
272
|
+
type: "list.toggle";
|
|
273
|
+
kind: "bulleted" | "numbered";
|
|
274
|
+
paragraphIndexes: readonly number[];
|
|
275
|
+
origin?: CommandOrigin;
|
|
276
|
+
}
|
|
277
|
+
| {
|
|
278
|
+
type: "list.indent";
|
|
279
|
+
paragraphIndexes: readonly number[];
|
|
280
|
+
origin?: CommandOrigin;
|
|
281
|
+
}
|
|
282
|
+
| {
|
|
283
|
+
type: "list.outdent";
|
|
284
|
+
paragraphIndexes: readonly number[];
|
|
285
|
+
origin?: CommandOrigin;
|
|
286
|
+
}
|
|
287
|
+
| {
|
|
288
|
+
type: "list.restart-numbering";
|
|
289
|
+
paragraphIndex: number;
|
|
290
|
+
startAt?: number;
|
|
291
|
+
origin?: CommandOrigin;
|
|
292
|
+
}
|
|
293
|
+
| {
|
|
294
|
+
type: "list.continue-numbering";
|
|
295
|
+
paragraphIndex: number;
|
|
296
|
+
origin?: CommandOrigin;
|
|
297
|
+
}
|
|
298
|
+
| {
|
|
299
|
+
type: "table.apply-structure";
|
|
300
|
+
operation: TableStructureOperation;
|
|
301
|
+
selectionDescriptor: TableSelectionDescriptor | null;
|
|
302
|
+
origin?: CommandOrigin;
|
|
303
|
+
}
|
|
304
|
+
| {
|
|
305
|
+
type: "image.insert";
|
|
306
|
+
data: string;
|
|
307
|
+
mimeType: string;
|
|
308
|
+
width?: number;
|
|
309
|
+
height?: number;
|
|
310
|
+
altText?: string;
|
|
311
|
+
origin?: CommandOrigin;
|
|
312
|
+
}
|
|
313
|
+
| {
|
|
314
|
+
type: "image.set-layout";
|
|
315
|
+
mediaId: string;
|
|
316
|
+
dimensions: { widthEmu: number; heightEmu: number };
|
|
317
|
+
origin?: CommandOrigin;
|
|
318
|
+
}
|
|
319
|
+
| {
|
|
320
|
+
type: "image.set-frame";
|
|
321
|
+
mediaId: string;
|
|
322
|
+
offsets: { horizontalOffsetEmu?: number; verticalOffsetEmu?: number };
|
|
323
|
+
origin?: CommandOrigin;
|
|
324
|
+
}
|
|
325
|
+
| {
|
|
326
|
+
type: "section.insert-break";
|
|
327
|
+
sectionIndex: number;
|
|
328
|
+
breakType: SectionBreakType;
|
|
329
|
+
origin?: CommandOrigin;
|
|
330
|
+
}
|
|
331
|
+
| {
|
|
332
|
+
type: "section.delete-break";
|
|
333
|
+
sectionIndex: number;
|
|
334
|
+
origin?: CommandOrigin;
|
|
335
|
+
}
|
|
336
|
+
| {
|
|
337
|
+
type: "section.update-layout";
|
|
338
|
+
sectionIndex: number;
|
|
339
|
+
patch: SectionLayoutPatch;
|
|
340
|
+
origin?: CommandOrigin;
|
|
341
|
+
}
|
|
342
|
+
| {
|
|
343
|
+
type: "section.set-page-numbering";
|
|
344
|
+
sectionIndex: number;
|
|
345
|
+
patch: SectionPageNumberingPatch | null;
|
|
346
|
+
origin?: CommandOrigin;
|
|
347
|
+
}
|
|
348
|
+
| {
|
|
349
|
+
type: "section.set-header-footer-link";
|
|
350
|
+
sectionIndex: number;
|
|
351
|
+
params: HeaderFooterLinkPatch;
|
|
352
|
+
origin?: CommandOrigin;
|
|
353
|
+
}
|
|
354
|
+
| {
|
|
355
|
+
type: "content.insert-page-break";
|
|
356
|
+
origin?: CommandOrigin;
|
|
357
|
+
}
|
|
358
|
+
| {
|
|
359
|
+
type: "content.insert-table";
|
|
360
|
+
options: InsertTableOptions;
|
|
361
|
+
origin?: CommandOrigin;
|
|
173
362
|
};
|
|
174
363
|
|
|
175
364
|
export interface TransactionEffects {
|
|
@@ -198,11 +387,40 @@ export interface CommandExecutionContext {
|
|
|
198
387
|
timestamp: string;
|
|
199
388
|
documentMode?: "editing" | "suggesting" | "viewing" | "commenting";
|
|
200
389
|
defaultAuthorId?: string;
|
|
390
|
+
/**
|
|
391
|
+
* Runtime-owned render snapshot made available for document-mutating
|
|
392
|
+
* commands that need per-paragraph surface lookups (formatting, styles,
|
|
393
|
+
* section layout). Populated by the runtime at dispatch time; absent for
|
|
394
|
+
* callers that cannot produce it.
|
|
395
|
+
*/
|
|
396
|
+
renderSnapshot?: RuntimeRenderSnapshot;
|
|
201
397
|
}
|
|
202
398
|
|
|
399
|
+
/**
|
|
400
|
+
* Commands that are surfaced on the event log but do NOT mutate `EditorState`.
|
|
401
|
+
* They mutate runtime-scoped overlays (workflow, host annotations) and are
|
|
402
|
+
* applied directly by the runtime rather than through `executeEditorCommand`.
|
|
403
|
+
*/
|
|
404
|
+
export type RuntimeStateCommandType =
|
|
405
|
+
| "history.undo"
|
|
406
|
+
| "history.redo"
|
|
407
|
+
| "workflow.set-overlay"
|
|
408
|
+
| "workflow.clear-overlay"
|
|
409
|
+
| "workflow.set-metadata-definitions"
|
|
410
|
+
| "workflow.clear-metadata-definitions"
|
|
411
|
+
| "workflow.set-metadata-entries"
|
|
412
|
+
| "workflow.clear-metadata-entries"
|
|
413
|
+
| "host-annotation.set-overlay"
|
|
414
|
+
| "host-annotation.clear-overlay";
|
|
415
|
+
|
|
416
|
+
export type StateMutatingCommand = Exclude<
|
|
417
|
+
EditorCommand,
|
|
418
|
+
{ type: RuntimeStateCommandType }
|
|
419
|
+
>;
|
|
420
|
+
|
|
203
421
|
export function executeEditorCommand(
|
|
204
422
|
state: EditorState,
|
|
205
|
-
command:
|
|
423
|
+
command: StateMutatingCommand,
|
|
206
424
|
context: CommandExecutionContext,
|
|
207
425
|
): EditorTransaction {
|
|
208
426
|
switch (command.type) {
|
|
@@ -633,7 +851,356 @@ export function executeEditorCommand(
|
|
|
633
851
|
},
|
|
634
852
|
context.timestamp,
|
|
635
853
|
);
|
|
854
|
+
case "formatting.apply": {
|
|
855
|
+
if (!context.renderSnapshot) {
|
|
856
|
+
return createTransaction(state, { historyBoundary: "skip", markDirty: false });
|
|
857
|
+
}
|
|
858
|
+
const result = applyFormattingOperationToDocument(
|
|
859
|
+
state.document,
|
|
860
|
+
context.renderSnapshot,
|
|
861
|
+
command.operation,
|
|
862
|
+
);
|
|
863
|
+
return buildDocumentReplaceTransaction(state, context, {
|
|
864
|
+
changed: result.changed,
|
|
865
|
+
document: result.document,
|
|
866
|
+
selection: toInternalSelection(result.selection, state.selection),
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
case "style.set-paragraph": {
|
|
870
|
+
if (!context.renderSnapshot) {
|
|
871
|
+
return createTransaction(state, { historyBoundary: "skip", markDirty: false });
|
|
872
|
+
}
|
|
873
|
+
const result = applyParagraphStyleToDocument(
|
|
874
|
+
state.document,
|
|
875
|
+
context.renderSnapshot,
|
|
876
|
+
command.styleId,
|
|
877
|
+
);
|
|
878
|
+
return buildDocumentReplaceTransaction(state, context, {
|
|
879
|
+
changed: result.changed,
|
|
880
|
+
document: result.document,
|
|
881
|
+
selection: toInternalSelection(result.selection, state.selection),
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
case "style.set-table": {
|
|
885
|
+
if (!context.renderSnapshot) {
|
|
886
|
+
return createTransaction(state, { historyBoundary: "skip", markDirty: false });
|
|
887
|
+
}
|
|
888
|
+
const result = applyTableStyleToDocument(
|
|
889
|
+
state.document,
|
|
890
|
+
context.renderSnapshot,
|
|
891
|
+
command.styleId,
|
|
892
|
+
);
|
|
893
|
+
return buildDocumentReplaceTransaction(state, context, {
|
|
894
|
+
changed: result.changed,
|
|
895
|
+
document: result.document,
|
|
896
|
+
selection: toInternalSelection(result.selection, state.selection),
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
case "list.toggle": {
|
|
900
|
+
const result = command.kind === "bulleted"
|
|
901
|
+
? toggleBulletedList(state.document, command.paragraphIndexes, { timestamp: context.timestamp })
|
|
902
|
+
: toggleNumberedList(state.document, command.paragraphIndexes, { timestamp: context.timestamp });
|
|
903
|
+
return buildDocumentReplaceTransaction(state, context, {
|
|
904
|
+
changed: result.affectedParagraphIndexes.length > 0,
|
|
905
|
+
document: result.document,
|
|
906
|
+
selection: state.selection,
|
|
907
|
+
});
|
|
908
|
+
}
|
|
909
|
+
case "list.indent": {
|
|
910
|
+
const result = indentListItems(state.document, command.paragraphIndexes, { timestamp: context.timestamp });
|
|
911
|
+
return buildDocumentReplaceTransaction(state, context, {
|
|
912
|
+
changed: result.affectedParagraphIndexes.length > 0,
|
|
913
|
+
document: result.document,
|
|
914
|
+
selection: state.selection,
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
case "list.outdent": {
|
|
918
|
+
const result = outdentListItems(state.document, command.paragraphIndexes, { timestamp: context.timestamp });
|
|
919
|
+
return buildDocumentReplaceTransaction(state, context, {
|
|
920
|
+
changed: result.affectedParagraphIndexes.length > 0,
|
|
921
|
+
document: result.document,
|
|
922
|
+
selection: state.selection,
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
case "list.restart-numbering": {
|
|
926
|
+
const result = restartNumbering(
|
|
927
|
+
state.document,
|
|
928
|
+
command.paragraphIndex,
|
|
929
|
+
{ timestamp: context.timestamp },
|
|
930
|
+
command.startAt,
|
|
931
|
+
);
|
|
932
|
+
return buildDocumentReplaceTransaction(state, context, {
|
|
933
|
+
changed: result.affectedParagraphIndexes.length > 0,
|
|
934
|
+
document: result.document,
|
|
935
|
+
selection: state.selection,
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
case "list.continue-numbering": {
|
|
939
|
+
const result = continueNumbering(
|
|
940
|
+
state.document,
|
|
941
|
+
command.paragraphIndex,
|
|
942
|
+
{ timestamp: context.timestamp },
|
|
943
|
+
);
|
|
944
|
+
return buildDocumentReplaceTransaction(state, context, {
|
|
945
|
+
changed: result.affectedParagraphIndexes.length > 0,
|
|
946
|
+
document: result.document,
|
|
947
|
+
selection: state.selection,
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
case "table.apply-structure": {
|
|
951
|
+
if (!context.renderSnapshot) {
|
|
952
|
+
return createTransaction(state, { historyBoundary: "skip", markDirty: false });
|
|
953
|
+
}
|
|
954
|
+
const result = applyTableStructureOperation(
|
|
955
|
+
state.document,
|
|
956
|
+
context.renderSnapshot,
|
|
957
|
+
command.selectionDescriptor,
|
|
958
|
+
command.operation,
|
|
959
|
+
);
|
|
960
|
+
return buildDocumentReplaceTransaction(state, context, {
|
|
961
|
+
changed: result.changed,
|
|
962
|
+
document: result.document,
|
|
963
|
+
selection: result.selection,
|
|
964
|
+
mapping: result.mapping,
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
case "image.insert": {
|
|
968
|
+
const dataBytes = decodeBase64ToBytes(command.data);
|
|
969
|
+
const result = insertImage(
|
|
970
|
+
state.document,
|
|
971
|
+
state.selection,
|
|
972
|
+
dataBytes,
|
|
973
|
+
command.mimeType,
|
|
974
|
+
command.width,
|
|
975
|
+
command.height,
|
|
976
|
+
{
|
|
977
|
+
timestamp: context.timestamp,
|
|
978
|
+
...(command.altText ? { altText: command.altText } : {}),
|
|
979
|
+
},
|
|
980
|
+
);
|
|
981
|
+
return buildDocumentReplaceTransaction(state, context, {
|
|
982
|
+
changed: true,
|
|
983
|
+
document: result.document,
|
|
984
|
+
selection: result.selection,
|
|
985
|
+
mapping: result.mapping,
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
case "image.set-layout": {
|
|
989
|
+
try {
|
|
990
|
+
const result = resizeImage(
|
|
991
|
+
state.document,
|
|
992
|
+
command.mediaId,
|
|
993
|
+
command.dimensions,
|
|
994
|
+
context.timestamp,
|
|
995
|
+
);
|
|
996
|
+
return buildDocumentReplaceTransaction(state, context, {
|
|
997
|
+
changed: true,
|
|
998
|
+
document: result.document,
|
|
999
|
+
selection: state.selection,
|
|
1000
|
+
});
|
|
1001
|
+
} catch {
|
|
1002
|
+
return createTransaction(state, { historyBoundary: "skip", markDirty: false });
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
case "image.set-frame": {
|
|
1006
|
+
try {
|
|
1007
|
+
const result = repositionFloatingImage(
|
|
1008
|
+
state.document,
|
|
1009
|
+
command.mediaId,
|
|
1010
|
+
command.offsets,
|
|
1011
|
+
context.timestamp,
|
|
1012
|
+
);
|
|
1013
|
+
return buildDocumentReplaceTransaction(state, context, {
|
|
1014
|
+
changed: true,
|
|
1015
|
+
document: result.document,
|
|
1016
|
+
selection: state.selection,
|
|
1017
|
+
});
|
|
1018
|
+
} catch {
|
|
1019
|
+
return createTransaction(state, { historyBoundary: "skip", markDirty: false });
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
case "section.insert-break": {
|
|
1023
|
+
const result = insertSectionBreakAfterSectionIndex(
|
|
1024
|
+
state.document,
|
|
1025
|
+
command.sectionIndex,
|
|
1026
|
+
command.breakType,
|
|
1027
|
+
{ timestamp: context.timestamp },
|
|
1028
|
+
);
|
|
1029
|
+
return buildDocumentReplaceTransaction(state, context, {
|
|
1030
|
+
changed: result.changed,
|
|
1031
|
+
document: result.document,
|
|
1032
|
+
selection: state.selection,
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
case "section.delete-break": {
|
|
1036
|
+
const result = deleteSectionBreakAtSectionIndex(
|
|
1037
|
+
state.document,
|
|
1038
|
+
command.sectionIndex,
|
|
1039
|
+
{ timestamp: context.timestamp },
|
|
1040
|
+
);
|
|
1041
|
+
return buildDocumentReplaceTransaction(state, context, {
|
|
1042
|
+
changed: result.changed,
|
|
1043
|
+
document: result.document,
|
|
1044
|
+
selection: state.selection,
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
case "section.update-layout": {
|
|
1048
|
+
const result = updateSectionLayoutAtSectionIndex(
|
|
1049
|
+
state.document,
|
|
1050
|
+
command.sectionIndex,
|
|
1051
|
+
command.patch,
|
|
1052
|
+
{ timestamp: context.timestamp },
|
|
1053
|
+
);
|
|
1054
|
+
return buildDocumentReplaceTransaction(state, context, {
|
|
1055
|
+
changed: result.changed,
|
|
1056
|
+
document: result.document,
|
|
1057
|
+
selection: state.selection,
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
case "section.set-page-numbering": {
|
|
1061
|
+
const normalizedPatch = command.patch === null
|
|
1062
|
+
? null
|
|
1063
|
+
: stripNullsFromRecord(command.patch as unknown as Record<string, unknown>);
|
|
1064
|
+
const result = setSectionPageNumberingAtSectionIndex(
|
|
1065
|
+
state.document,
|
|
1066
|
+
command.sectionIndex,
|
|
1067
|
+
normalizedPatch as never,
|
|
1068
|
+
{ timestamp: context.timestamp },
|
|
1069
|
+
);
|
|
1070
|
+
return buildDocumentReplaceTransaction(state, context, {
|
|
1071
|
+
changed: result.changed,
|
|
1072
|
+
document: result.document,
|
|
1073
|
+
selection: state.selection,
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
case "section.set-header-footer-link": {
|
|
1077
|
+
const result = setHeaderFooterLinkAtSectionIndex(
|
|
1078
|
+
state.document,
|
|
1079
|
+
command.sectionIndex,
|
|
1080
|
+
command.params,
|
|
1081
|
+
{ timestamp: context.timestamp },
|
|
1082
|
+
);
|
|
1083
|
+
return buildDocumentReplaceTransaction(state, context, {
|
|
1084
|
+
changed: result.changed,
|
|
1085
|
+
document: result.document,
|
|
1086
|
+
selection: state.selection,
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
1089
|
+
case "content.insert-page-break": {
|
|
1090
|
+
const result = insertPageBreak(
|
|
1091
|
+
state.document,
|
|
1092
|
+
state.selection,
|
|
1093
|
+
{ timestamp: context.timestamp },
|
|
1094
|
+
);
|
|
1095
|
+
return buildDocumentReplaceTransaction(state, context, {
|
|
1096
|
+
changed: result.changed,
|
|
1097
|
+
document: result.document,
|
|
1098
|
+
selection: result.selection,
|
|
1099
|
+
mapping: result.mapping,
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
case "content.insert-table": {
|
|
1103
|
+
const result = insertTable(
|
|
1104
|
+
state.document,
|
|
1105
|
+
state.selection,
|
|
1106
|
+
command.options,
|
|
1107
|
+
{ timestamp: context.timestamp },
|
|
1108
|
+
);
|
|
1109
|
+
return buildDocumentReplaceTransaction(state, context, {
|
|
1110
|
+
changed: result.changed,
|
|
1111
|
+
document: result.document,
|
|
1112
|
+
selection: result.selection,
|
|
1113
|
+
mapping: result.mapping,
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
function buildDocumentReplaceTransaction(
|
|
1120
|
+
state: EditorState,
|
|
1121
|
+
context: CommandExecutionContext,
|
|
1122
|
+
result: {
|
|
1123
|
+
changed: boolean;
|
|
1124
|
+
document: EditorState["document"];
|
|
1125
|
+
selection: SelectionSnapshot;
|
|
1126
|
+
mapping?: TransactionMapping;
|
|
1127
|
+
},
|
|
1128
|
+
): EditorTransaction {
|
|
1129
|
+
if (!result.changed) {
|
|
1130
|
+
return createTransaction(state, { historyBoundary: "skip", markDirty: false });
|
|
1131
|
+
}
|
|
1132
|
+
const mapping = result.mapping ?? createEmptyMapping();
|
|
1133
|
+
const reviewState = remapReviewStateAfterContentChange(
|
|
1134
|
+
state,
|
|
1135
|
+
result.document,
|
|
1136
|
+
mapping,
|
|
1137
|
+
);
|
|
1138
|
+
return createTransaction(
|
|
1139
|
+
{
|
|
1140
|
+
...state,
|
|
1141
|
+
document: reviewState.document,
|
|
1142
|
+
selection: result.selection,
|
|
1143
|
+
warnings: reviewState.warnings,
|
|
1144
|
+
runtime: {
|
|
1145
|
+
...state.runtime,
|
|
1146
|
+
activeCommentId: reviewState.activeCommentId,
|
|
1147
|
+
},
|
|
1148
|
+
compatibility: {
|
|
1149
|
+
...state.compatibility,
|
|
1150
|
+
generatedAt: context.timestamp,
|
|
1151
|
+
warnings: reviewState.warnings,
|
|
1152
|
+
featureEntries: state.compatibility.featureEntries.map((entry) =>
|
|
1153
|
+
entry.affectedAnchor
|
|
1154
|
+
? {
|
|
1155
|
+
...entry,
|
|
1156
|
+
affectedAnchor: mapAnchor(entry.affectedAnchor, mapping),
|
|
1157
|
+
}
|
|
1158
|
+
: entry,
|
|
1159
|
+
),
|
|
1160
|
+
},
|
|
1161
|
+
},
|
|
1162
|
+
{
|
|
1163
|
+
historyBoundary: "push",
|
|
1164
|
+
markDirty: true,
|
|
1165
|
+
mapping,
|
|
1166
|
+
effects: reviewState.effects,
|
|
1167
|
+
},
|
|
1168
|
+
);
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
function decodeBase64ToBytes(value: string): Uint8Array {
|
|
1172
|
+
const binary = atob(value);
|
|
1173
|
+
const bytes = new Uint8Array(binary.length);
|
|
1174
|
+
for (let i = 0; i < binary.length; i++) {
|
|
1175
|
+
bytes[i] = binary.charCodeAt(i);
|
|
1176
|
+
}
|
|
1177
|
+
return bytes;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
function toInternalSelection(
|
|
1181
|
+
publicSelection: RuntimeRenderSnapshot["selection"],
|
|
1182
|
+
fallback: SelectionSnapshot,
|
|
1183
|
+
): SelectionSnapshot {
|
|
1184
|
+
if (
|
|
1185
|
+
publicSelection.anchor === fallback.anchor &&
|
|
1186
|
+
publicSelection.head === fallback.head
|
|
1187
|
+
) {
|
|
1188
|
+
return fallback;
|
|
1189
|
+
}
|
|
1190
|
+
return createSelectionSnapshot(publicSelection.anchor, publicSelection.head);
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
function stripNullsFromRecord<T extends Record<string, unknown>>(
|
|
1194
|
+
value: T,
|
|
1195
|
+
): { [K in keyof T]?: Exclude<T[K], null> } {
|
|
1196
|
+
const out: Record<string, unknown> = {};
|
|
1197
|
+
for (const key of Object.keys(value) as Array<keyof T>) {
|
|
1198
|
+
const v = value[key];
|
|
1199
|
+
if (v !== null && v !== undefined) {
|
|
1200
|
+
out[key as string] = v;
|
|
1201
|
+
}
|
|
636
1202
|
}
|
|
1203
|
+
return out as { [K in keyof T]?: Exclude<T[K], null> };
|
|
637
1204
|
}
|
|
638
1205
|
|
|
639
1206
|
export function remapSelection(
|