@beyondwork/docx-react-component 1.0.1 → 1.0.2
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 +44 -104
- package/package.json +76 -46
- package/src/README.md +85 -0
- package/src/api/README.md +22 -0
- package/src/api/public-types.ts +525 -0
- package/src/compare/diff-engine.ts +530 -0
- package/src/compare/export-redlines.ts +162 -0
- package/src/compare/snapshot.ts +37 -0
- package/src/component-inventory.md +99 -0
- package/src/core/README.md +10 -0
- package/src/core/commands/README.md +3 -0
- package/src/core/commands/formatting-commands.ts +161 -0
- package/src/core/commands/image-commands.ts +144 -0
- package/src/core/commands/index.ts +1013 -0
- package/src/core/commands/list-commands.ts +370 -0
- package/src/core/commands/review-commands.ts +108 -0
- package/src/core/commands/text-commands.ts +119 -0
- package/src/core/schema/README.md +3 -0
- package/src/core/schema/text-schema.ts +512 -0
- package/src/core/selection/README.md +3 -0
- package/src/core/selection/mapping.ts +238 -0
- package/src/core/selection/review-anchors.ts +94 -0
- package/src/core/state/README.md +3 -0
- package/src/core/state/editor-state.ts +580 -0
- package/src/core/state/text-transaction.ts +276 -0
- package/src/formats/xlsx/io/parse-shared-strings.ts +41 -0
- package/src/formats/xlsx/io/parse-sheet.ts +289 -0
- package/src/formats/xlsx/io/parse-styles.ts +57 -0
- package/src/formats/xlsx/io/parse-workbook.ts +75 -0
- package/src/formats/xlsx/io/xlsx-session.ts +306 -0
- package/src/formats/xlsx/model/cell.ts +189 -0
- package/src/formats/xlsx/model/sheet.ts +244 -0
- package/src/formats/xlsx/model/styles.ts +118 -0
- package/src/formats/xlsx/model/workbook.ts +449 -0
- package/src/index.ts +45 -0
- package/src/io/README.md +10 -0
- package/src/io/docx-session.ts +1763 -0
- package/src/io/export/README.md +3 -0
- package/src/io/export/export-session.ts +165 -0
- package/src/io/export/minimal-docx.ts +115 -0
- package/src/io/export/reattach-preserved-parts.ts +54 -0
- package/src/io/export/serialize-comments.ts +876 -0
- package/src/io/export/serialize-footnotes.ts +217 -0
- package/src/io/export/serialize-headers-footers.ts +200 -0
- package/src/io/export/serialize-main-document.ts +982 -0
- package/src/io/export/serialize-numbering.ts +97 -0
- package/src/io/export/serialize-revisions.ts +389 -0
- package/src/io/export/serialize-runtime-revisions.ts +265 -0
- package/src/io/export/serialize-tables.ts +147 -0
- package/src/io/export/split-review-boundaries.ts +194 -0
- package/src/io/normalize/README.md +3 -0
- package/src/io/normalize/normalize-text.ts +437 -0
- package/src/io/ooxml/README.md +3 -0
- package/src/io/ooxml/parse-comments.ts +779 -0
- package/src/io/ooxml/parse-complex-content.ts +287 -0
- package/src/io/ooxml/parse-fields.ts +438 -0
- package/src/io/ooxml/parse-footnotes.ts +403 -0
- package/src/io/ooxml/parse-headers-footers.ts +483 -0
- package/src/io/ooxml/parse-inline-media.ts +431 -0
- package/src/io/ooxml/parse-main-document.ts +1846 -0
- package/src/io/ooxml/parse-numbering.ts +425 -0
- package/src/io/ooxml/parse-revisions.ts +658 -0
- package/src/io/ooxml/parse-shapes.ts +271 -0
- package/src/io/ooxml/parse-tables.ts +568 -0
- package/src/io/ooxml/parse-theme.ts +314 -0
- package/src/io/ooxml/part-manifest.ts +136 -0
- package/src/io/ooxml/revision-boundaries.ts +351 -0
- package/src/io/opc/README.md +3 -0
- package/src/io/opc/corrupt-package.ts +166 -0
- package/src/io/opc/docx-package.ts +74 -0
- package/src/io/opc/package-reader.ts +320 -0
- package/src/io/opc/package-writer.ts +273 -0
- package/src/legal/bookmarks.ts +196 -0
- package/src/legal/cross-references.ts +356 -0
- package/src/legal/defined-terms.ts +203 -0
- package/src/model/README.md +3 -0
- package/src/model/canonical-document.ts +1911 -0
- package/src/model/cds-1.0.0.ts +196 -0
- package/src/model/snapshot.ts +393 -0
- package/src/preservation/README.md +3 -0
- package/src/preservation/markup-compatibility.ts +48 -0
- package/src/preservation/opaque-fragment-store.ts +89 -0
- package/src/preservation/opaque-region.ts +233 -0
- package/src/preservation/package-preservation.ts +120 -0
- package/src/preservation/preserved-part-manifest.ts +56 -0
- package/src/preservation/relationship-retention.ts +57 -0
- package/src/preservation/store.ts +185 -0
- package/src/review/README.md +16 -0
- package/src/review/store/README.md +3 -0
- package/src/review/store/comment-anchors.ts +70 -0
- package/src/review/store/comment-remapping.ts +154 -0
- package/src/review/store/comment-store.ts +331 -0
- package/src/review/store/comment-thread.ts +109 -0
- package/src/review/store/revision-actions.ts +394 -0
- package/src/review/store/revision-store.ts +303 -0
- package/src/review/store/revision-types.ts +168 -0
- package/src/review/store/runtime-comment-store.ts +43 -0
- package/src/runtime/README.md +3 -0
- package/src/runtime/ai-action-policy.ts +764 -0
- package/src/runtime/document-runtime.ts +967 -0
- package/src/runtime/read-only-diagnostics-runtime.ts +232 -0
- package/src/runtime/review-runtime.ts +44 -0
- package/src/runtime/revision-runtime.ts +107 -0
- package/src/runtime/session-capabilities.ts +138 -0
- package/src/runtime/surface-projection.ts +570 -0
- package/src/runtime/table-commands.ts +87 -0
- package/src/runtime/table-schema.ts +140 -0
- package/src/runtime/virtualized-rendering.ts +258 -0
- package/src/ui/README.md +30 -0
- package/src/ui/WordReviewEditor.tsx +1504 -0
- package/src/ui/comments/README.md +3 -0
- package/src/ui/compatibility/README.md +3 -0
- package/src/ui/editor-surface/README.md +3 -0
- package/src/ui/headless/comment-decoration-model.ts +124 -0
- package/src/ui/headless/revision-decoration-model.ts +128 -0
- package/src/ui/headless/selection-helpers.ts +34 -0
- package/src/ui/headless/use-editor-keyboard.ts +98 -0
- package/src/ui/review/README.md +3 -0
- package/src/ui/shared/revision-filters.ts +31 -0
- package/src/ui/status/README.md +3 -0
- package/src/ui/theme/README.md +3 -0
- package/src/ui/toolbar/README.md +3 -0
- package/src/ui-tailwind/chrome/tw-alert-banner.tsx +48 -0
- package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +44 -0
- package/src/ui-tailwind/chrome/tw-unsaved-modal.tsx +58 -0
- package/src/ui-tailwind/chrome/use-before-unload.ts +20 -0
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +139 -0
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +98 -0
- package/src/ui-tailwind/editor-surface/pm-position-map.ts +123 -0
- package/src/ui-tailwind/editor-surface/pm-schema.ts +452 -0
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +327 -0
- package/src/ui-tailwind/editor-surface/search-plugin.ts +157 -0
- package/src/ui-tailwind/editor-surface/tw-caret.tsx +12 -0
- package/src/ui-tailwind/editor-surface/tw-editor-surface.tsx +150 -0
- package/src/ui-tailwind/editor-surface/tw-inline-token.tsx +118 -0
- package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +52 -0
- package/src/ui-tailwind/editor-surface/tw-paragraph-block.tsx +151 -0
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +215 -0
- package/src/ui-tailwind/editor-surface/tw-segment-view.tsx +111 -0
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +122 -0
- package/src/ui-tailwind/index.ts +61 -0
- package/src/ui-tailwind/review/tw-comment-sidebar.tsx +276 -0
- package/src/ui-tailwind/review/tw-health-panel.tsx +120 -0
- package/src/ui-tailwind/review/tw-review-rail.tsx +120 -0
- package/src/ui-tailwind/review/tw-revision-sidebar.tsx +164 -0
- package/src/ui-tailwind/status/tw-status-bar.tsx +58 -0
- package/src/ui-tailwind/theme/editor-theme.css +190 -0
- package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +48 -0
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +231 -0
- package/src/ui-tailwind/tw-review-workspace.tsx +140 -0
- package/src/validation/README.md +3 -0
- package/src/validation/compatibility-engine.ts +317 -0
- package/src/validation/compatibility-report.ts +160 -0
- package/src/validation/diagnostics.ts +203 -0
- package/src/validation/import-diagnostics.ts +128 -0
- package/src/validation/low-priority-word-surfaces.ts +373 -0
- package/dist/chunk-32W6IVQE.js +0 -7725
- package/dist/chunk-32W6IVQE.js.map +0 -1
- package/dist/index.cjs +0 -23722
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -7
- package/dist/index.d.ts +0 -7
- package/dist/index.js +0 -16011
- package/dist/index.js.map +0 -1
- package/dist/public-types-DqCURAz8.d.cts +0 -1152
- package/dist/public-types-DqCURAz8.d.ts +0 -1152
- package/dist/tailwind.cjs +0 -8295
- package/dist/tailwind.cjs.map +0 -1
- package/dist/tailwind.d.cts +0 -323
- package/dist/tailwind.d.ts +0 -323
- package/dist/tailwind.js +0 -553
- package/dist/tailwind.js.map +0 -1
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AbstractNumberingDefinition,
|
|
3
|
+
CanonicalDocument as CanonicalDocumentEnvelope,
|
|
4
|
+
NumberingCatalog,
|
|
5
|
+
NumberingInstance,
|
|
6
|
+
ParagraphNode,
|
|
7
|
+
} from "../../model/canonical-document.ts";
|
|
8
|
+
|
|
9
|
+
export interface ListCommandContext {
|
|
10
|
+
timestamp: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ListCommandResult {
|
|
14
|
+
document: CanonicalDocumentEnvelope;
|
|
15
|
+
affectedParagraphIndexes: number[];
|
|
16
|
+
createdNumberingInstanceId?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type OpaqueBlockLike = { type: "opaque_block"; [key: string]: unknown };
|
|
20
|
+
type BlockLike = ParagraphNode | OpaqueBlockLike;
|
|
21
|
+
|
|
22
|
+
export function toggleNumberedList(
|
|
23
|
+
document: CanonicalDocumentEnvelope,
|
|
24
|
+
paragraphIndexes: readonly number[],
|
|
25
|
+
context: ListCommandContext,
|
|
26
|
+
): ListCommandResult {
|
|
27
|
+
return toggleListKind(document, paragraphIndexes, "numbered", context);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function toggleBulletedList(
|
|
31
|
+
document: CanonicalDocumentEnvelope,
|
|
32
|
+
paragraphIndexes: readonly number[],
|
|
33
|
+
context: ListCommandContext,
|
|
34
|
+
): ListCommandResult {
|
|
35
|
+
return toggleListKind(document, paragraphIndexes, "bulleted", context);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function indentListItems(
|
|
39
|
+
document: CanonicalDocumentEnvelope,
|
|
40
|
+
paragraphIndexes: readonly number[],
|
|
41
|
+
context: ListCommandContext,
|
|
42
|
+
): ListCommandResult {
|
|
43
|
+
return adjustListLevels(document, paragraphIndexes, 1, context);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function outdentListItems(
|
|
47
|
+
document: CanonicalDocumentEnvelope,
|
|
48
|
+
paragraphIndexes: readonly number[],
|
|
49
|
+
context: ListCommandContext,
|
|
50
|
+
): ListCommandResult {
|
|
51
|
+
return adjustListLevels(document, paragraphIndexes, -1, context);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function restartNumbering(
|
|
55
|
+
document: CanonicalDocumentEnvelope,
|
|
56
|
+
paragraphIndex: number,
|
|
57
|
+
context: ListCommandContext,
|
|
58
|
+
startAt = 1,
|
|
59
|
+
): ListCommandResult {
|
|
60
|
+
const working = cloneEnvelope(document, context.timestamp);
|
|
61
|
+
const blocks = captureBlocks(working);
|
|
62
|
+
const target = blocks[paragraphIndex];
|
|
63
|
+
|
|
64
|
+
if (!isParagraphNode(target) || !target.numbering) {
|
|
65
|
+
return {
|
|
66
|
+
document: working,
|
|
67
|
+
affectedParagraphIndexes: [],
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const catalog = ensureNumberingCatalog(working.numbering);
|
|
72
|
+
const existingInstance = catalog.instances[target.numbering.numberingInstanceId];
|
|
73
|
+
if (!existingInstance) {
|
|
74
|
+
return {
|
|
75
|
+
document: working,
|
|
76
|
+
affectedParagraphIndexes: [],
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const numberingInstanceId = createNumberingInstanceId(catalog);
|
|
81
|
+
catalog.instances[numberingInstanceId] = {
|
|
82
|
+
numberingInstanceId,
|
|
83
|
+
abstractNumberingId: existingInstance.abstractNumberingId,
|
|
84
|
+
overrides: mergeOverride(existingInstance.overrides, {
|
|
85
|
+
level: target.numbering.level,
|
|
86
|
+
startAt,
|
|
87
|
+
}),
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const affectedParagraphIndexes: number[] = [];
|
|
91
|
+
for (let index = paragraphIndex; index < blocks.length; index += 1) {
|
|
92
|
+
const block = blocks[index];
|
|
93
|
+
if (!isParagraphNode(block)) {
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
if (block.numbering?.numberingInstanceId !== existingInstance.numberingInstanceId) {
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
block.numbering = {
|
|
101
|
+
numberingInstanceId,
|
|
102
|
+
level: block.numbering.level,
|
|
103
|
+
};
|
|
104
|
+
affectedParagraphIndexes.push(index);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
working.numbering = catalog;
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
document: working,
|
|
111
|
+
affectedParagraphIndexes,
|
|
112
|
+
createdNumberingInstanceId: numberingInstanceId,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function toggleListKind(
|
|
117
|
+
document: CanonicalDocumentEnvelope,
|
|
118
|
+
paragraphIndexes: readonly number[],
|
|
119
|
+
kind: "numbered" | "bulleted",
|
|
120
|
+
context: ListCommandContext,
|
|
121
|
+
): ListCommandResult {
|
|
122
|
+
const working = cloneEnvelope(document, context.timestamp);
|
|
123
|
+
const blocks = captureBlocks(working);
|
|
124
|
+
const normalizedIndexes = normalizeParagraphIndexes(blocks, paragraphIndexes);
|
|
125
|
+
|
|
126
|
+
if (normalizedIndexes.length === 0) {
|
|
127
|
+
return {
|
|
128
|
+
document: working,
|
|
129
|
+
affectedParagraphIndexes: [],
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const catalog = ensureNumberingCatalog(working.numbering);
|
|
134
|
+
const allAlreadyKind = normalizedIndexes.every((index) => {
|
|
135
|
+
const paragraph = blocks[index] as ParagraphNode;
|
|
136
|
+
return paragraph.numbering
|
|
137
|
+
? getListKind(catalog, paragraph.numbering.numberingInstanceId) === kind
|
|
138
|
+
: false;
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
if (allAlreadyKind) {
|
|
142
|
+
for (const index of normalizedIndexes) {
|
|
143
|
+
delete (blocks[index] as ParagraphNode).numbering;
|
|
144
|
+
}
|
|
145
|
+
working.numbering = catalog;
|
|
146
|
+
return {
|
|
147
|
+
document: working,
|
|
148
|
+
affectedParagraphIndexes: normalizedIndexes,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const numberingInstanceId =
|
|
153
|
+
findAdjacentCompatibleInstance(blocks, catalog, normalizedIndexes[0]!, kind) ??
|
|
154
|
+
ensureDefaultInstance(catalog, kind);
|
|
155
|
+
|
|
156
|
+
for (const index of normalizedIndexes) {
|
|
157
|
+
const paragraph = blocks[index] as ParagraphNode;
|
|
158
|
+
paragraph.numbering = {
|
|
159
|
+
numberingInstanceId,
|
|
160
|
+
level: clampLevel(paragraph.numbering?.level ?? 0),
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
working.numbering = catalog;
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
document: working,
|
|
168
|
+
affectedParagraphIndexes: normalizedIndexes,
|
|
169
|
+
createdNumberingInstanceId: numberingInstanceId,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function adjustListLevels(
|
|
174
|
+
document: CanonicalDocumentEnvelope,
|
|
175
|
+
paragraphIndexes: readonly number[],
|
|
176
|
+
delta: -1 | 1,
|
|
177
|
+
context: ListCommandContext,
|
|
178
|
+
): ListCommandResult {
|
|
179
|
+
const working = cloneEnvelope(document, context.timestamp);
|
|
180
|
+
const blocks = captureBlocks(working);
|
|
181
|
+
const affectedParagraphIndexes = normalizeParagraphIndexes(blocks, paragraphIndexes).filter(
|
|
182
|
+
(index) => isParagraphNode(blocks[index]) && Boolean((blocks[index] as ParagraphNode).numbering),
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
for (const index of affectedParagraphIndexes) {
|
|
186
|
+
const paragraph = blocks[index] as ParagraphNode;
|
|
187
|
+
if (!paragraph.numbering) {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
paragraph.numbering = {
|
|
192
|
+
numberingInstanceId: paragraph.numbering.numberingInstanceId,
|
|
193
|
+
level: clampLevel(paragraph.numbering.level + delta),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
document: working,
|
|
199
|
+
affectedParagraphIndexes,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function ensureDefaultInstance(
|
|
204
|
+
catalog: NumberingCatalog,
|
|
205
|
+
kind: "numbered" | "bulleted",
|
|
206
|
+
): string {
|
|
207
|
+
const existing = Object.values(catalog.instances).find(
|
|
208
|
+
(instance) => getListKind(catalog, instance.numberingInstanceId) === kind,
|
|
209
|
+
);
|
|
210
|
+
if (existing) {
|
|
211
|
+
return existing.numberingInstanceId;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const abstractNumberingId = createAbstractNumberingId(catalog);
|
|
215
|
+
catalog.abstractDefinitions[abstractNumberingId] =
|
|
216
|
+
kind === "bulleted" ? createDefaultBulletedDefinition(abstractNumberingId) : createDefaultNumberedDefinition(abstractNumberingId);
|
|
217
|
+
|
|
218
|
+
const numberingInstanceId = createNumberingInstanceId(catalog);
|
|
219
|
+
catalog.instances[numberingInstanceId] = {
|
|
220
|
+
numberingInstanceId,
|
|
221
|
+
abstractNumberingId,
|
|
222
|
+
overrides: [],
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
return numberingInstanceId;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function findAdjacentCompatibleInstance(
|
|
229
|
+
blocks: BlockLike[],
|
|
230
|
+
catalog: NumberingCatalog,
|
|
231
|
+
fromIndex: number,
|
|
232
|
+
kind: "numbered" | "bulleted",
|
|
233
|
+
): string | undefined {
|
|
234
|
+
const previous = blocks[fromIndex - 1];
|
|
235
|
+
if (isParagraphNode(previous) && previous.numbering) {
|
|
236
|
+
const previousKind = getListKind(catalog, previous.numbering.numberingInstanceId);
|
|
237
|
+
if (previousKind === kind) {
|
|
238
|
+
return previous.numbering.numberingInstanceId;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return undefined;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function getListKind(
|
|
246
|
+
catalog: NumberingCatalog,
|
|
247
|
+
numberingInstanceId: string,
|
|
248
|
+
): "numbered" | "bulleted" | undefined {
|
|
249
|
+
const instance = catalog.instances[numberingInstanceId];
|
|
250
|
+
const definition = instance
|
|
251
|
+
? catalog.abstractDefinitions[instance.abstractNumberingId]
|
|
252
|
+
: undefined;
|
|
253
|
+
const levelZero = definition?.levels.find((level) => level.level === 0);
|
|
254
|
+
if (!levelZero) {
|
|
255
|
+
return undefined;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return levelZero.format === "bullet" ? "bulleted" : "numbered";
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function mergeOverride(
|
|
262
|
+
overrides: NumberingInstance["overrides"],
|
|
263
|
+
nextOverride: NumberingInstance["overrides"][number],
|
|
264
|
+
): NumberingInstance["overrides"] {
|
|
265
|
+
const filtered = overrides.filter((override) => override.level !== nextOverride.level);
|
|
266
|
+
filtered.push(nextOverride);
|
|
267
|
+
return filtered.sort((left, right) => left.level - right.level);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function createDefaultNumberedDefinition(abstractNumberingId: string): AbstractNumberingDefinition {
|
|
271
|
+
return {
|
|
272
|
+
abstractNumberingId,
|
|
273
|
+
levels: [
|
|
274
|
+
{ level: 0, format: "decimal", text: "%1." },
|
|
275
|
+
{ level: 1, format: "decimal", text: "%1.%2." },
|
|
276
|
+
{ level: 2, format: "lowerLetter", text: "(%3)" },
|
|
277
|
+
{ level: 3, format: "lowerRoman", text: "(%4)" },
|
|
278
|
+
{ level: 4, format: "decimal", text: "%5." },
|
|
279
|
+
{ level: 5, format: "lowerLetter", text: "(%6)" },
|
|
280
|
+
{ level: 6, format: "lowerRoman", text: "(%7)" },
|
|
281
|
+
{ level: 7, format: "decimal", text: "%8." },
|
|
282
|
+
{ level: 8, format: "lowerLetter", text: "(%9)" },
|
|
283
|
+
],
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function createDefaultBulletedDefinition(abstractNumberingId: string): AbstractNumberingDefinition {
|
|
288
|
+
return {
|
|
289
|
+
abstractNumberingId,
|
|
290
|
+
levels: [
|
|
291
|
+
{ level: 0, format: "bullet", text: "•" },
|
|
292
|
+
{ level: 1, format: "bullet", text: "o" },
|
|
293
|
+
{ level: 2, format: "bullet", text: "■" },
|
|
294
|
+
{ level: 3, format: "bullet", text: "•" },
|
|
295
|
+
{ level: 4, format: "bullet", text: "o" },
|
|
296
|
+
{ level: 5, format: "bullet", text: "■" },
|
|
297
|
+
{ level: 6, format: "bullet", text: "•" },
|
|
298
|
+
{ level: 7, format: "bullet", text: "o" },
|
|
299
|
+
{ level: 8, format: "bullet", text: "■" },
|
|
300
|
+
],
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function createAbstractNumberingId(catalog: NumberingCatalog): string {
|
|
305
|
+
let index = 1;
|
|
306
|
+
while (catalog.abstractDefinitions[`abstract-num:generated-${index}`]) {
|
|
307
|
+
index += 1;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return `abstract-num:generated-${index}`;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function createNumberingInstanceId(catalog: NumberingCatalog): string {
|
|
314
|
+
let index = 1;
|
|
315
|
+
while (catalog.instances[`num:generated-${index}`]) {
|
|
316
|
+
index += 1;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return `num:generated-${index}`;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function ensureNumberingCatalog(value: NumberingCatalog): NumberingCatalog {
|
|
323
|
+
return structuredClone(value);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function cloneEnvelope(
|
|
327
|
+
document: CanonicalDocumentEnvelope,
|
|
328
|
+
timestamp: string,
|
|
329
|
+
): CanonicalDocumentEnvelope {
|
|
330
|
+
return {
|
|
331
|
+
...structuredClone(document),
|
|
332
|
+
updatedAt: timestamp,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function captureBlocks(document: CanonicalDocumentEnvelope): BlockLike[] {
|
|
337
|
+
if (isDocumentRoot(document.content)) {
|
|
338
|
+
return document.content.children as BlockLike[];
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const fallback = {
|
|
342
|
+
type: "doc" as const,
|
|
343
|
+
children: [{ type: "paragraph" as const, children: [] }],
|
|
344
|
+
};
|
|
345
|
+
document.content = fallback;
|
|
346
|
+
return fallback.children as BlockLike[];
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function normalizeParagraphIndexes(
|
|
350
|
+
blocks: BlockLike[],
|
|
351
|
+
paragraphIndexes: readonly number[],
|
|
352
|
+
): number[] {
|
|
353
|
+
return [...new Set(paragraphIndexes)]
|
|
354
|
+
.filter((index) => Number.isInteger(index) && index >= 0 && index < blocks.length)
|
|
355
|
+
.filter((index) => isParagraphNode(blocks[index]))
|
|
356
|
+
.sort((left, right) => left - right);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function clampLevel(level: number): number {
|
|
360
|
+
return Math.max(0, Math.min(8, level));
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function isDocumentRoot(value: unknown): value is { type: "doc"; children: unknown[] } {
|
|
364
|
+
return Boolean(value) && typeof value === "object" && (value as { type?: string }).type === "doc";
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function isParagraphNode(value: unknown): value is ParagraphNode {
|
|
368
|
+
return Boolean(value) && typeof value === "object" && (value as { type?: string }).type === "paragraph";
|
|
369
|
+
}
|
|
370
|
+
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
export interface ReviewCommandOrigin {
|
|
2
|
+
source:
|
|
3
|
+
| "keyboard"
|
|
4
|
+
| "toolbar"
|
|
5
|
+
| "context_menu"
|
|
6
|
+
| "comment_panel"
|
|
7
|
+
| "review_panel"
|
|
8
|
+
| "api"
|
|
9
|
+
| "runtime";
|
|
10
|
+
timestamp: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type ReviewCommand =
|
|
14
|
+
| {
|
|
15
|
+
type: "review.accept-revision";
|
|
16
|
+
revisionId: string;
|
|
17
|
+
origin?: ReviewCommandOrigin;
|
|
18
|
+
}
|
|
19
|
+
| {
|
|
20
|
+
type: "review.reject-revision";
|
|
21
|
+
revisionId: string;
|
|
22
|
+
origin?: ReviewCommandOrigin;
|
|
23
|
+
}
|
|
24
|
+
| {
|
|
25
|
+
type: "review.accept-all-revisions";
|
|
26
|
+
origin?: ReviewCommandOrigin;
|
|
27
|
+
}
|
|
28
|
+
| {
|
|
29
|
+
type: "review.reject-all-revisions";
|
|
30
|
+
origin?: ReviewCommandOrigin;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type SingleRevisionReviewCommand = Extract<
|
|
34
|
+
ReviewCommand,
|
|
35
|
+
{ revisionId: string }
|
|
36
|
+
>;
|
|
37
|
+
|
|
38
|
+
export type BatchRevisionReviewCommand = Exclude<
|
|
39
|
+
ReviewCommand,
|
|
40
|
+
SingleRevisionReviewCommand
|
|
41
|
+
>;
|
|
42
|
+
|
|
43
|
+
export type ReviewCommandIntent = "accept" | "reject";
|
|
44
|
+
|
|
45
|
+
export function isSingleRevisionReviewCommand(
|
|
46
|
+
command: ReviewCommand,
|
|
47
|
+
): command is SingleRevisionReviewCommand {
|
|
48
|
+
return "revisionId" in command;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function isBatchRevisionReviewCommand(
|
|
52
|
+
command: ReviewCommand,
|
|
53
|
+
): command is BatchRevisionReviewCommand {
|
|
54
|
+
return !isSingleRevisionReviewCommand(command);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function getReviewCommandIntent(
|
|
58
|
+
command: ReviewCommand,
|
|
59
|
+
): ReviewCommandIntent {
|
|
60
|
+
switch (command.type) {
|
|
61
|
+
case "review.accept-revision":
|
|
62
|
+
case "review.accept-all-revisions":
|
|
63
|
+
return "accept";
|
|
64
|
+
case "review.reject-revision":
|
|
65
|
+
case "review.reject-all-revisions":
|
|
66
|
+
return "reject";
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function createAcceptRevisionCommand(
|
|
71
|
+
revisionId: string,
|
|
72
|
+
origin?: ReviewCommandOrigin,
|
|
73
|
+
): SingleRevisionReviewCommand {
|
|
74
|
+
return {
|
|
75
|
+
type: "review.accept-revision",
|
|
76
|
+
revisionId,
|
|
77
|
+
...(origin ? { origin } : {}),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function createRejectRevisionCommand(
|
|
82
|
+
revisionId: string,
|
|
83
|
+
origin?: ReviewCommandOrigin,
|
|
84
|
+
): SingleRevisionReviewCommand {
|
|
85
|
+
return {
|
|
86
|
+
type: "review.reject-revision",
|
|
87
|
+
revisionId,
|
|
88
|
+
...(origin ? { origin } : {}),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function createAcceptAllRevisionsCommand(
|
|
93
|
+
origin?: ReviewCommandOrigin,
|
|
94
|
+
): BatchRevisionReviewCommand {
|
|
95
|
+
return {
|
|
96
|
+
type: "review.accept-all-revisions",
|
|
97
|
+
...(origin ? { origin } : {}),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function createRejectAllRevisionsCommand(
|
|
102
|
+
origin?: ReviewCommandOrigin,
|
|
103
|
+
): BatchRevisionReviewCommand {
|
|
104
|
+
return {
|
|
105
|
+
type: "review.reject-all-revisions",
|
|
106
|
+
...(origin ? { origin } : {}),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { CanonicalDocumentEnvelope, SelectionSnapshot } from "../state/editor-state.ts";
|
|
2
|
+
import {
|
|
3
|
+
applyTextTransaction,
|
|
4
|
+
type TextTransactionResult,
|
|
5
|
+
} from "../state/text-transaction.ts";
|
|
6
|
+
|
|
7
|
+
export interface TextCommandContext {
|
|
8
|
+
timestamp: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function insertText(
|
|
12
|
+
document: CanonicalDocumentEnvelope,
|
|
13
|
+
selection: SelectionSnapshot,
|
|
14
|
+
text: string,
|
|
15
|
+
context: TextCommandContext,
|
|
16
|
+
): TextTransactionResult {
|
|
17
|
+
return applyTextTransaction(
|
|
18
|
+
document,
|
|
19
|
+
selection,
|
|
20
|
+
{
|
|
21
|
+
type: "replace",
|
|
22
|
+
insertion: [
|
|
23
|
+
{
|
|
24
|
+
type: "text",
|
|
25
|
+
text,
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
context,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function deleteSelectionOrBackward(
|
|
34
|
+
document: CanonicalDocumentEnvelope,
|
|
35
|
+
selection: SelectionSnapshot,
|
|
36
|
+
context: TextCommandContext,
|
|
37
|
+
): TextTransactionResult {
|
|
38
|
+
return applyTextTransaction(
|
|
39
|
+
document,
|
|
40
|
+
selection,
|
|
41
|
+
selection.isCollapsed
|
|
42
|
+
? {
|
|
43
|
+
type: "delete_backward",
|
|
44
|
+
}
|
|
45
|
+
: {
|
|
46
|
+
type: "replace",
|
|
47
|
+
insertion: [],
|
|
48
|
+
},
|
|
49
|
+
context,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function deleteSelectionOrForward(
|
|
54
|
+
document: CanonicalDocumentEnvelope,
|
|
55
|
+
selection: SelectionSnapshot,
|
|
56
|
+
context: TextCommandContext,
|
|
57
|
+
): TextTransactionResult {
|
|
58
|
+
return applyTextTransaction(
|
|
59
|
+
document,
|
|
60
|
+
selection,
|
|
61
|
+
selection.isCollapsed
|
|
62
|
+
? {
|
|
63
|
+
type: "delete_forward",
|
|
64
|
+
}
|
|
65
|
+
: {
|
|
66
|
+
type: "replace",
|
|
67
|
+
insertion: [],
|
|
68
|
+
},
|
|
69
|
+
context,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function insertTab(
|
|
74
|
+
document: CanonicalDocumentEnvelope,
|
|
75
|
+
selection: SelectionSnapshot,
|
|
76
|
+
context: TextCommandContext,
|
|
77
|
+
): TextTransactionResult {
|
|
78
|
+
return applyTextTransaction(
|
|
79
|
+
document,
|
|
80
|
+
selection,
|
|
81
|
+
{
|
|
82
|
+
type: "replace",
|
|
83
|
+
insertion: [{ type: "tab" }],
|
|
84
|
+
},
|
|
85
|
+
context,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function insertHardBreak(
|
|
90
|
+
document: CanonicalDocumentEnvelope,
|
|
91
|
+
selection: SelectionSnapshot,
|
|
92
|
+
context: TextCommandContext,
|
|
93
|
+
): TextTransactionResult {
|
|
94
|
+
return applyTextTransaction(
|
|
95
|
+
document,
|
|
96
|
+
selection,
|
|
97
|
+
{
|
|
98
|
+
type: "replace",
|
|
99
|
+
insertion: [{ type: "hard_break" }],
|
|
100
|
+
},
|
|
101
|
+
context,
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function splitParagraph(
|
|
106
|
+
document: CanonicalDocumentEnvelope,
|
|
107
|
+
selection: SelectionSnapshot,
|
|
108
|
+
context: TextCommandContext,
|
|
109
|
+
): TextTransactionResult {
|
|
110
|
+
return applyTextTransaction(
|
|
111
|
+
document,
|
|
112
|
+
selection,
|
|
113
|
+
{
|
|
114
|
+
type: "replace",
|
|
115
|
+
insertion: [{ type: "paragraph_break" }],
|
|
116
|
+
},
|
|
117
|
+
context,
|
|
118
|
+
);
|
|
119
|
+
}
|