@aseity/idocs-preview 0.2.0 → 0.4.0
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/CHANGELOG.md +12 -0
- package/README.md +70 -3
- package/dist/core/display.d.ts +67 -0
- package/dist/core/editor.d.ts +172 -0
- package/dist/core/editor.js +527 -0
- package/dist/core/engine.js +136 -29
- package/dist/core/index.d.ts +8 -19
- package/dist/core/index.js +35 -22
- package/dist/core/protocol.d.ts +96 -0
- package/dist/core/protocol.js +13 -1
- package/dist/view/edit-selection.d.ts +80 -0
- package/dist/view/edit-selection.js +841 -0
- package/dist/view/editor.d.ts +77 -0
- package/dist/view/editor.js +1477 -0
- package/dist/view/find.d.ts +2 -1
- package/dist/view/find.js +7 -0
- package/dist/view/ime.d.ts +63 -0
- package/dist/view/ime.js +352 -0
- package/dist/view/index.d.ts +4 -0
- package/dist/view/index.js +3 -0
- package/dist/view/selection-layer.d.ts +1 -0
- package/dist/view/selection-layer.js +4 -4
- package/dist/view/workspace-styles.d.ts +1 -0
- package/dist/view/workspace-styles.js +879 -0
- package/dist/view/workspace.d.ts +70 -0
- package/dist/view/workspace.js +1028 -0
- package/package.json +2 -2
- package/wasm/idocs_wasm.d.ts +33 -0
- package/wasm/idocs_wasm.js +163 -0
- package/wasm/idocs_wasm_bg.wasm +0 -0
- package/wasm/idocs_wasm_bg.wasm.d.ts +14 -0
package/dist/core/engine.js
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
// protocol.ts. `serve` takes any message endpoint, so Node tests run the same
|
|
3
|
-
// code behind a MessageChannel. Layout is synchronous inside one wasm call;
|
|
4
|
-
// resources the host has not answered yet come back as `needs`, and the open
|
|
5
|
-
// is retried once they arrive.
|
|
6
|
-
import init, { openDocument } from '../../wasm/idocs_wasm.js';
|
|
1
|
+
import init, { exportDocx, openDocument, WasmEditorSession } from '../../wasm/idocs_wasm.js';
|
|
7
2
|
import { canvasMeasure } from './fonts.js';
|
|
3
|
+
const textDecoder = new TextDecoder();
|
|
8
4
|
export function serve(endpoint, options = {}) {
|
|
9
5
|
let ready;
|
|
10
6
|
const start = (wasm = options.wasm) => (ready ??= init(wasm === undefined ? undefined : { module_or_path: wasm }));
|
|
11
7
|
const measure = options.measure === undefined ? canvasMeasure() : (options.measure ?? undefined);
|
|
12
8
|
const pending = new Map();
|
|
9
|
+
const editors = new Map();
|
|
13
10
|
const post = (message, transfer = []) => endpoint.postMessage(message, transfer);
|
|
14
11
|
const attempt = (id) => {
|
|
15
12
|
const job = pending.get(id);
|
|
@@ -19,12 +16,7 @@ export function serve(endpoint, options = {}) {
|
|
|
19
16
|
try {
|
|
20
17
|
if (!measure)
|
|
21
18
|
throw new Error('Browser font measurement requires OffscreenCanvas 2D');
|
|
22
|
-
|
|
23
|
-
post({ type: 'pageReset', id });
|
|
24
|
-
const onPage = job.progressive ? (packet) => {
|
|
25
|
-
post({ type: 'page', id, ...packet }, [packet.data.buffer, ...packet.images.map(bytes => bytes.buffer)]);
|
|
26
|
-
} : undefined;
|
|
27
|
-
outcome = openDocument(job.kind, job.bytes, job.name, job.assets, measure, onPage);
|
|
19
|
+
outcome = job.run(measure);
|
|
28
20
|
}
|
|
29
21
|
catch (error) {
|
|
30
22
|
pending.delete(id);
|
|
@@ -40,15 +32,83 @@ export function serve(endpoint, options = {}) {
|
|
|
40
32
|
post({ type: 'failed', id, error: JSON.parse(outcome.json) });
|
|
41
33
|
return;
|
|
42
34
|
}
|
|
43
|
-
|
|
35
|
+
if (outcome.status === 'exported') {
|
|
36
|
+
post({ type: 'exported', id, bytes: outcome.bytes }, [outcome.bytes.buffer]);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (job.kind === 'editorJson') {
|
|
40
|
+
post({ type: 'editorJson', id, json: outcome.json });
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const transfers = [
|
|
44
|
+
outcome.data.buffer,
|
|
45
|
+
...outcome.images.map((bytes) => bytes.buffer),
|
|
46
|
+
];
|
|
47
|
+
if (job.kind === 'editorRendered') {
|
|
48
|
+
post({
|
|
49
|
+
type: 'editorRendered',
|
|
50
|
+
id,
|
|
51
|
+
json: outcome.json,
|
|
52
|
+
images: outcome.images,
|
|
53
|
+
data: outcome.data,
|
|
54
|
+
metaJson: outcome.metaJson ?? '{}',
|
|
55
|
+
}, transfers);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
post({ type: 'opened', id, json: outcome.json, images: outcome.images, data: outcome.data }, transfers);
|
|
59
|
+
};
|
|
60
|
+
const enqueueOpen = (message) => {
|
|
61
|
+
const assets = new Map();
|
|
62
|
+
const progressive = message.progressive ?? false;
|
|
63
|
+
pending.set(message.id, {
|
|
64
|
+
kind: 'open',
|
|
65
|
+
assets,
|
|
66
|
+
run: (activeMeasure) => {
|
|
67
|
+
if (progressive)
|
|
68
|
+
post({ type: 'pageReset', id: message.id });
|
|
69
|
+
const onPage = progressive
|
|
70
|
+
? (packet) => {
|
|
71
|
+
post({ type: 'page', id: message.id, ...packet }, [packet.data.buffer, ...packet.images.map((b) => b.buffer)]);
|
|
72
|
+
}
|
|
73
|
+
: undefined;
|
|
74
|
+
return openDocument(message.kind, message.bytes, message.name, assets, activeMeasure, onPage);
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
const enqueueEditorCall = (id, editorId, kind, exec) => {
|
|
79
|
+
const existing = editors.get(editorId);
|
|
80
|
+
if (!existing) {
|
|
81
|
+
pending.set(id, {
|
|
82
|
+
kind,
|
|
83
|
+
assets: new Map(),
|
|
84
|
+
run: () => ({
|
|
85
|
+
status: 'failed',
|
|
86
|
+
json: JSON.stringify({ code: 'session-closed', message: 'The editor session is closed', diagnostics: [] }),
|
|
87
|
+
}),
|
|
88
|
+
});
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
pending.set(id, {
|
|
92
|
+
kind,
|
|
93
|
+
assets: existing.assets,
|
|
94
|
+
run: (activeMeasure) => exec(existing, activeMeasure),
|
|
95
|
+
});
|
|
44
96
|
};
|
|
45
97
|
endpoint.addEventListener('message', async (event) => {
|
|
46
98
|
const message = event.data;
|
|
47
99
|
if (message.type === 'init') {
|
|
48
|
-
// Start fetching early; a failure is reported to the first open.
|
|
49
100
|
start(message.wasmUrl).catch(() => { });
|
|
50
101
|
return;
|
|
51
102
|
}
|
|
103
|
+
if (message.type === 'editorDispose') {
|
|
104
|
+
const existing = editors.get(message.editorId);
|
|
105
|
+
if (existing) {
|
|
106
|
+
existing.session.dispose();
|
|
107
|
+
existing.session.free?.();
|
|
108
|
+
editors.delete(message.editorId);
|
|
109
|
+
}
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
52
112
|
try {
|
|
53
113
|
await start();
|
|
54
114
|
}
|
|
@@ -58,22 +118,69 @@ export function serve(endpoint, options = {}) {
|
|
|
58
118
|
post({ type: 'failed', id, error: { code: 'wasm-unavailable', message: String(error), diagnostics: [] } });
|
|
59
119
|
return;
|
|
60
120
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
job.
|
|
121
|
+
switch (message.type) {
|
|
122
|
+
case 'exportDocx': {
|
|
123
|
+
const assets = new Map();
|
|
124
|
+
pending.set(message.id, {
|
|
125
|
+
kind: 'exportDocx',
|
|
126
|
+
assets,
|
|
127
|
+
run: (activeMeasure) => exportDocx(message.bytes, message.name, assets, activeMeasure),
|
|
128
|
+
});
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
case 'open':
|
|
132
|
+
enqueueOpen(message);
|
|
133
|
+
break;
|
|
134
|
+
case 'resources': {
|
|
135
|
+
const job = pending.get(message.id);
|
|
136
|
+
if (!job)
|
|
137
|
+
return;
|
|
138
|
+
for (const { need, bytes } of message.answers) {
|
|
139
|
+
job.assets.set(need.name, bytes);
|
|
140
|
+
}
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
case 'editorOpen': {
|
|
144
|
+
const session = new WasmEditorSession();
|
|
145
|
+
const assets = new Map();
|
|
146
|
+
editors.set(message.editorId, { session, assets });
|
|
147
|
+
const source = textDecoder.decode(message.bytes);
|
|
148
|
+
pending.set(message.id, {
|
|
149
|
+
kind: 'editorJson',
|
|
150
|
+
assets,
|
|
151
|
+
run: (activeMeasure) => session.open(source, message.name, assets, activeMeasure),
|
|
152
|
+
});
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
case 'editorRange':
|
|
156
|
+
enqueueEditorCall(message.id, message.editorId, 'editorJson', ({ session }) => session.range(message.revision, message.startJson, message.endJson));
|
|
157
|
+
break;
|
|
158
|
+
case 'editorApply':
|
|
159
|
+
enqueueEditorCall(message.id, message.editorId, 'editorJson', ({ session, assets }, m) => session.apply(message.base, message.editJson, assets, m));
|
|
160
|
+
break;
|
|
161
|
+
case 'editorUndo':
|
|
162
|
+
enqueueEditorCall(message.id, message.editorId, 'editorJson', ({ session, assets }, m) => session.undo(message.base, assets, m));
|
|
163
|
+
break;
|
|
164
|
+
case 'editorRedo':
|
|
165
|
+
enqueueEditorCall(message.id, message.editorId, 'editorJson', ({ session, assets }, m) => session.redo(message.base, assets, m));
|
|
166
|
+
break;
|
|
167
|
+
case 'editorRefresh': {
|
|
168
|
+
const source = textDecoder.decode(message.bytes);
|
|
169
|
+
enqueueEditorCall(message.id, message.editorId, 'editorJson', ({ session, assets }, m) => session.refresh(message.base, source, assets, m));
|
|
170
|
+
break;
|
|
76
171
|
}
|
|
172
|
+
case 'editorMarkSaved':
|
|
173
|
+
enqueueEditorCall(message.id, message.editorId, 'editorJson', ({ session }) => session.markSaved(message.revision));
|
|
174
|
+
break;
|
|
175
|
+
case 'editorSnapshot':
|
|
176
|
+
enqueueEditorCall(message.id, message.editorId, 'editorJson', ({ session }) => session.snapshot());
|
|
177
|
+
break;
|
|
178
|
+
case 'editorRender':
|
|
179
|
+
enqueueEditorCall(message.id, message.editorId, 'editorRendered', ({ session, assets }, m) => session.render(assets, m));
|
|
180
|
+
break;
|
|
181
|
+
case 'editorExportDocx':
|
|
182
|
+
enqueueEditorCall(message.id, message.editorId, 'editorExport', ({ session, assets }, m) => session.exportDocx(assets, m));
|
|
183
|
+
break;
|
|
77
184
|
}
|
|
78
185
|
attempt(message.id);
|
|
79
186
|
});
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type OpenEditorOptions, type EditorSession, lineCaretX, locateLineSource } from './editor.js';
|
|
2
|
+
import { type DocumentKind, type PreviewDocument, type PreviewPage, type Read, type SessionOptions } from './protocol.js';
|
|
2
3
|
export type * from './display.js';
|
|
3
4
|
export type * from './protocol.js';
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
/** `.wasm` address; defaults to the file next to the wasm glue. */
|
|
8
|
-
wasmUrl?: string | URL;
|
|
9
|
-
/** An already created worker (a MessagePort works too); `workerUrl` is then ignored. */
|
|
10
|
-
worker?: Endpoint;
|
|
11
|
-
}
|
|
5
|
+
export { PreviewError, type Read, type SessionOptions, } from './protocol.js';
|
|
6
|
+
export type { Commit, Edit, EditRange, EditorFrame, EditorSession, EditorState, ImageAlign, InsertBlock, LayoutState, LineHit, Mark, OpenEditorOptions, RenderStats, Selection, SourceSnapshot, TableAction, } from './editor.js';
|
|
7
|
+
export { lineCaretX, locateLineSource };
|
|
12
8
|
type Bytes = Uint8Array | ArrayBuffer;
|
|
13
|
-
export type Read = (name: string) => Bytes | null | undefined | Promise<Bytes | null | undefined>;
|
|
14
9
|
export interface OpenOptions {
|
|
15
10
|
/** Receive provisional pages while the worker builds the remaining display list. */
|
|
16
11
|
onPage?: (page: PreviewPage) => void;
|
|
@@ -25,16 +20,9 @@ export interface OpenOptions {
|
|
|
25
20
|
/** Reads a path relative to the source document (images). Throw or return null when absent. */
|
|
26
21
|
readResource?: Read;
|
|
27
22
|
}
|
|
28
|
-
export
|
|
29
|
-
code: string;
|
|
30
|
-
diagnostics: PreviewDocument['diagnostics'];
|
|
31
|
-
constructor(error: {
|
|
32
|
-
code: string;
|
|
33
|
-
message: string;
|
|
34
|
-
diagnostics: PreviewDocument['diagnostics'];
|
|
35
|
-
});
|
|
36
|
-
}
|
|
23
|
+
export type ExportOptions = Pick<OpenOptions, 'name' | 'readResource'>;
|
|
37
24
|
export interface Session {
|
|
25
|
+
exportDocx(bytes: Bytes, options?: ExportOptions): Promise<Uint8Array>;
|
|
38
26
|
open(bytes: Bytes, options?: OpenOptions): Promise<PreviewDocument>;
|
|
39
27
|
/**
|
|
40
28
|
* Terminates the worker; pending opens reject. A worker that fails on its
|
|
@@ -43,5 +31,6 @@ export interface Session {
|
|
|
43
31
|
*/
|
|
44
32
|
dispose(): void;
|
|
45
33
|
}
|
|
34
|
+
export declare function openEditor(options: OpenEditorOptions): Promise<EditorSession>;
|
|
46
35
|
export declare function createSession(options?: SessionOptions): Session;
|
|
47
36
|
export type { Measure } from './fonts.js';
|
package/dist/core/index.js
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
|
+
import { openEditorWith, lineCaretX, locateLineSource, } from './editor.js';
|
|
2
|
+
import { copyBytes, PreviewError, } from './protocol.js';
|
|
1
3
|
import { decodeCompact } from './wire.js';
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
diagnostics;
|
|
5
|
-
constructor(error) {
|
|
6
|
-
super(error.message);
|
|
7
|
-
this.name = 'PreviewError';
|
|
8
|
-
this.code = error.code;
|
|
9
|
-
this.diagnostics = error.diagnostics;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
4
|
+
export { PreviewError, } from './protocol.js';
|
|
5
|
+
export { lineCaretX, locateLineSource };
|
|
12
6
|
function isZip(bytes) {
|
|
13
7
|
return bytes[0] === 0x50 && bytes[1] === 0x4b;
|
|
14
8
|
}
|
|
@@ -18,18 +12,20 @@ function isWordFile(bytes, name) {
|
|
|
18
12
|
OLE_MAGIC.every((byte, i) => bytes[i] === byte) ||
|
|
19
13
|
/\.(docx|docm|dotx|dotm|doc)$/i.test(name ?? ''));
|
|
20
14
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return new Uint8Array(bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes));
|
|
24
|
-
}
|
|
25
|
-
export function createSession(options = {}) {
|
|
26
|
-
const worker = options.worker ??
|
|
15
|
+
function createWorker(options = {}) {
|
|
16
|
+
return (options.worker ??
|
|
27
17
|
(options.workerUrl
|
|
28
18
|
? new Worker(options.workerUrl, { type: 'module' })
|
|
29
19
|
: // Literally `new Worker(new URL(...), ...)`: the form bundlers
|
|
30
20
|
// (Turbopack, webpack, Vite) recognize to bundle the worker with its
|
|
31
21
|
// imports. Behind `??` they copy the file as a bare asset instead.
|
|
32
|
-
new Worker(new URL('./worker.js', import.meta.url), { type: 'module' }));
|
|
22
|
+
new Worker(new URL('./worker.js', import.meta.url), { type: 'module' })));
|
|
23
|
+
}
|
|
24
|
+
export function openEditor(options) {
|
|
25
|
+
return openEditorWith(createWorker(options.runtime), options);
|
|
26
|
+
}
|
|
27
|
+
export function createSession(options = {}) {
|
|
28
|
+
const worker = createWorker(options);
|
|
33
29
|
const post = (message, transfer = []) => worker.postMessage(message, transfer);
|
|
34
30
|
const jobs = new Map();
|
|
35
31
|
let next = 1;
|
|
@@ -52,14 +48,14 @@ export function createSession(options = {}) {
|
|
|
52
48
|
const job = jobs.get(message.id);
|
|
53
49
|
if (!job)
|
|
54
50
|
return;
|
|
55
|
-
if (message.type === 'pageReset') {
|
|
51
|
+
if (message.type === 'pageReset' && job.kind === 'open') {
|
|
56
52
|
job.pages = [];
|
|
57
53
|
job.images = [];
|
|
58
54
|
job.previewImages = [];
|
|
59
55
|
job.outlines = [];
|
|
60
56
|
return;
|
|
61
57
|
}
|
|
62
|
-
if (message.type === 'page') {
|
|
58
|
+
if (message.type === 'page' && job.kind === 'open') {
|
|
63
59
|
try {
|
|
64
60
|
job.images.push(...message.images);
|
|
65
61
|
const partial = decodeCompact(message.json, message.data, message.images);
|
|
@@ -86,7 +82,10 @@ export function createSession(options = {}) {
|
|
|
86
82
|
return;
|
|
87
83
|
}
|
|
88
84
|
jobs.delete(message.id);
|
|
89
|
-
if (message.type === '
|
|
85
|
+
if (message.type === 'exported' && job.kind === 'export') {
|
|
86
|
+
job.resolve(message.bytes);
|
|
87
|
+
}
|
|
88
|
+
else if (message.type === 'opened' && job.kind === 'open') {
|
|
90
89
|
try {
|
|
91
90
|
const doc = decodeCompact(message.json, message.data, job.options.onPage ? job.images : message.images);
|
|
92
91
|
if (job.options.onPage) {
|
|
@@ -100,8 +99,10 @@ export function createSession(options = {}) {
|
|
|
100
99
|
job.reject(new PreviewError({ code: 'internal-error', message: String(error), diagnostics: [] }));
|
|
101
100
|
}
|
|
102
101
|
}
|
|
103
|
-
else
|
|
102
|
+
else if (message.type === 'failed')
|
|
104
103
|
job.reject(new PreviewError(message.error));
|
|
104
|
+
else
|
|
105
|
+
job.reject(new PreviewError({ code: 'internal-error', message: 'Unexpected worker response', diagnostics: [] }));
|
|
105
106
|
});
|
|
106
107
|
// A worker script that fails to load or run, or a message that cannot be
|
|
107
108
|
// deserialized, leaves no reply to wait for: give up on the worker.
|
|
@@ -124,6 +125,18 @@ export function createSession(options = {}) {
|
|
|
124
125
|
worker.start?.();
|
|
125
126
|
post({ type: 'init', wasmUrl: options.wasmUrl?.toString() });
|
|
126
127
|
return {
|
|
128
|
+
exportDocx(input, exportOptions = {}) {
|
|
129
|
+
if (disposed)
|
|
130
|
+
return Promise.reject(new Error('The preview session is disposed'));
|
|
131
|
+
if (broken)
|
|
132
|
+
return Promise.reject(broken);
|
|
133
|
+
const bytes = copyBytes(input);
|
|
134
|
+
const id = next++;
|
|
135
|
+
return new Promise((resolve, reject) => {
|
|
136
|
+
jobs.set(id, { kind: 'export', options: exportOptions, resolve, reject });
|
|
137
|
+
post({ type: 'exportDocx', id, name: exportOptions.name ?? 'document.idoc', bytes }, [bytes.buffer]);
|
|
138
|
+
});
|
|
139
|
+
},
|
|
127
140
|
open(input, openOptions = {}) {
|
|
128
141
|
if (disposed)
|
|
129
142
|
return Promise.reject(new Error('The preview session is disposed'));
|
|
@@ -132,7 +145,7 @@ export function createSession(options = {}) {
|
|
|
132
145
|
const bytes = copyBytes(input);
|
|
133
146
|
const id = next++;
|
|
134
147
|
return new Promise((resolve, reject) => {
|
|
135
|
-
jobs.set(id, { options: openOptions, resolve, reject, pages: [], images: [], previewImages: [], outlines: [] });
|
|
148
|
+
jobs.set(id, { kind: 'open', options: openOptions, resolve, reject, pages: [], images: [], previewImages: [], outlines: [] });
|
|
136
149
|
post({
|
|
137
150
|
type: 'open',
|
|
138
151
|
progressive: openOptions.onPage !== undefined,
|
package/dist/core/protocol.d.ts
CHANGED
|
@@ -76,6 +76,27 @@ export interface PreviewDocument {
|
|
|
76
76
|
/** For `.idoc`: what export to DOCX would lose. For DOCX: what DOCX conversion lost. */
|
|
77
77
|
conversionLosses: ConversionLoss[];
|
|
78
78
|
}
|
|
79
|
+
export type PreviewDiagnostic = Diagnostic;
|
|
80
|
+
export interface SessionOptions {
|
|
81
|
+
/** Worker script address; defaults to the bundled worker beside this module. */
|
|
82
|
+
workerUrl?: string | URL;
|
|
83
|
+
/** `.wasm` address; defaults to the file next to the wasm glue. */
|
|
84
|
+
wasmUrl?: string | URL;
|
|
85
|
+
/** An already created worker (a MessagePort works too); `workerUrl` is then ignored. */
|
|
86
|
+
worker?: Endpoint;
|
|
87
|
+
}
|
|
88
|
+
export type Bytes = Uint8Array | ArrayBuffer;
|
|
89
|
+
export type Read = (name: string) => Bytes | null | undefined | Promise<Bytes | null | undefined>;
|
|
90
|
+
export declare class PreviewError extends Error {
|
|
91
|
+
code: string;
|
|
92
|
+
diagnostics: Diagnostic[];
|
|
93
|
+
constructor(error: {
|
|
94
|
+
code: string;
|
|
95
|
+
message: string;
|
|
96
|
+
diagnostics: Diagnostic[];
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
export declare function copyBytes(bytes: Bytes): Uint8Array;
|
|
79
100
|
/** A lookup core made that the host has not answered yet. */
|
|
80
101
|
export type ResourceNeed = {
|
|
81
102
|
kind: 'asset';
|
|
@@ -84,6 +105,11 @@ export type ResourceNeed = {
|
|
|
84
105
|
export type ToWorker = {
|
|
85
106
|
type: 'init';
|
|
86
107
|
wasmUrl?: string;
|
|
108
|
+
} | {
|
|
109
|
+
type: 'exportDocx';
|
|
110
|
+
id: number;
|
|
111
|
+
name: string;
|
|
112
|
+
bytes: Uint8Array;
|
|
87
113
|
} | {
|
|
88
114
|
type: 'open';
|
|
89
115
|
id: number;
|
|
@@ -100,6 +126,61 @@ export type ToWorker = {
|
|
|
100
126
|
need: ResourceNeed;
|
|
101
127
|
bytes: Uint8Array | null;
|
|
102
128
|
}[];
|
|
129
|
+
} | {
|
|
130
|
+
type: 'editorOpen';
|
|
131
|
+
id: number;
|
|
132
|
+
editorId: number;
|
|
133
|
+
name: string;
|
|
134
|
+
bytes: Uint8Array;
|
|
135
|
+
} | {
|
|
136
|
+
type: 'editorRange';
|
|
137
|
+
id: number;
|
|
138
|
+
editorId: number;
|
|
139
|
+
revision: string;
|
|
140
|
+
startJson: string;
|
|
141
|
+
endJson: string;
|
|
142
|
+
} | {
|
|
143
|
+
type: 'editorApply';
|
|
144
|
+
id: number;
|
|
145
|
+
editorId: number;
|
|
146
|
+
base: string;
|
|
147
|
+
editJson: string;
|
|
148
|
+
} | {
|
|
149
|
+
type: 'editorUndo';
|
|
150
|
+
id: number;
|
|
151
|
+
editorId: number;
|
|
152
|
+
base: string;
|
|
153
|
+
} | {
|
|
154
|
+
type: 'editorRedo';
|
|
155
|
+
id: number;
|
|
156
|
+
editorId: number;
|
|
157
|
+
base: string;
|
|
158
|
+
} | {
|
|
159
|
+
type: 'editorRefresh';
|
|
160
|
+
id: number;
|
|
161
|
+
editorId: number;
|
|
162
|
+
base: string;
|
|
163
|
+
bytes: Uint8Array;
|
|
164
|
+
} | {
|
|
165
|
+
type: 'editorMarkSaved';
|
|
166
|
+
id: number;
|
|
167
|
+
editorId: number;
|
|
168
|
+
revision: string;
|
|
169
|
+
} | {
|
|
170
|
+
type: 'editorSnapshot';
|
|
171
|
+
id: number;
|
|
172
|
+
editorId: number;
|
|
173
|
+
} | {
|
|
174
|
+
type: 'editorRender';
|
|
175
|
+
id: number;
|
|
176
|
+
editorId: number;
|
|
177
|
+
} | {
|
|
178
|
+
type: 'editorExportDocx';
|
|
179
|
+
id: number;
|
|
180
|
+
editorId: number;
|
|
181
|
+
} | {
|
|
182
|
+
type: 'editorDispose';
|
|
183
|
+
editorId: number;
|
|
103
184
|
};
|
|
104
185
|
export interface PreviewPage {
|
|
105
186
|
page: DisplayPage;
|
|
@@ -120,12 +201,27 @@ export type FromWorker = {
|
|
|
120
201
|
type: 'needs';
|
|
121
202
|
id: number;
|
|
122
203
|
needs: ResourceNeed[];
|
|
204
|
+
} | {
|
|
205
|
+
type: 'exported';
|
|
206
|
+
id: number;
|
|
207
|
+
bytes: Uint8Array;
|
|
123
208
|
} | {
|
|
124
209
|
type: 'opened';
|
|
125
210
|
id: number;
|
|
126
211
|
json: string;
|
|
127
212
|
images: Uint8Array[];
|
|
128
213
|
data: Uint8Array;
|
|
214
|
+
} | {
|
|
215
|
+
type: 'editorJson';
|
|
216
|
+
id: number;
|
|
217
|
+
json: string;
|
|
218
|
+
} | {
|
|
219
|
+
type: 'editorRendered';
|
|
220
|
+
id: number;
|
|
221
|
+
json: string;
|
|
222
|
+
images: Uint8Array[];
|
|
223
|
+
data: Uint8Array;
|
|
224
|
+
metaJson: string;
|
|
129
225
|
} | {
|
|
130
226
|
type: 'failed';
|
|
131
227
|
id: number;
|
package/dist/core/protocol.js
CHANGED
|
@@ -1 +1,13 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export class PreviewError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
diagnostics;
|
|
4
|
+
constructor(error) {
|
|
5
|
+
super(error.message);
|
|
6
|
+
this.name = 'PreviewError';
|
|
7
|
+
this.code = error.code;
|
|
8
|
+
this.diagnostics = error.diagnostics;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function copyBytes(bytes) {
|
|
12
|
+
return new Uint8Array(bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes));
|
|
13
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { type Anchor, type DisplayPage, type EditRange, type FlowId, type GeneratedRole, type ReadOnlyReason } from '../core/index.js';
|
|
2
|
+
import { type HighlightBox, type PagePoint } from './selection.js';
|
|
3
|
+
export interface CaretBox {
|
|
4
|
+
readonly page: number;
|
|
5
|
+
readonly x: number;
|
|
6
|
+
readonly top: number;
|
|
7
|
+
readonly bottom: number;
|
|
8
|
+
readonly baseline: number;
|
|
9
|
+
readonly height: number;
|
|
10
|
+
readonly turn?: [number, number];
|
|
11
|
+
}
|
|
12
|
+
export interface ReadOnlyTarget {
|
|
13
|
+
readonly page: number;
|
|
14
|
+
readonly path: string;
|
|
15
|
+
readonly reason: ReadOnlyReason;
|
|
16
|
+
readonly role?: GeneratedRole;
|
|
17
|
+
readonly box: HighlightBox;
|
|
18
|
+
readonly before?: Anchor;
|
|
19
|
+
readonly after?: Anchor;
|
|
20
|
+
}
|
|
21
|
+
export type EditPointHit = {
|
|
22
|
+
kind: 'editable';
|
|
23
|
+
anchor: Anchor;
|
|
24
|
+
caret: CaretBox;
|
|
25
|
+
page: number;
|
|
26
|
+
path: string;
|
|
27
|
+
} | {
|
|
28
|
+
kind: 'readOnly';
|
|
29
|
+
target: ReadOnlyTarget;
|
|
30
|
+
} | {
|
|
31
|
+
kind: 'empty';
|
|
32
|
+
};
|
|
33
|
+
export declare class EditDocumentIndex {
|
|
34
|
+
#private;
|
|
35
|
+
constructor(pages: readonly DisplayPage[]);
|
|
36
|
+
flowPath(flow: FlowId): string | undefined;
|
|
37
|
+
firstFlow(): FlowId | undefined;
|
|
38
|
+
flowBounds(flow: FlowId): {
|
|
39
|
+
start: Anchor;
|
|
40
|
+
end: Anchor;
|
|
41
|
+
} | undefined;
|
|
42
|
+
locatePoint(point: PagePoint): EditPointHit;
|
|
43
|
+
locatePointInFlow(flow: FlowId, point: PagePoint): Anchor | undefined;
|
|
44
|
+
wordRangeInFlow(flow: FlowId, point: PagePoint): {
|
|
45
|
+
start: Anchor;
|
|
46
|
+
end: Anchor;
|
|
47
|
+
} | undefined;
|
|
48
|
+
selectionPageBounds(range: EditRange): {
|
|
49
|
+
page: number;
|
|
50
|
+
bounds: {
|
|
51
|
+
left: number;
|
|
52
|
+
right: number;
|
|
53
|
+
top: number;
|
|
54
|
+
bottom: number;
|
|
55
|
+
};
|
|
56
|
+
} | undefined;
|
|
57
|
+
caretForAnchor(anchor: Anchor): CaretBox | undefined;
|
|
58
|
+
highlightsForRange(range: EditRange, page: number): HighlightBox[];
|
|
59
|
+
selectedText(range: EditRange): string;
|
|
60
|
+
neighborStop(anchor: Anchor, direction: 'backward' | 'forward'): Anchor | undefined;
|
|
61
|
+
moveHorizontal(anchor: Anchor, direction: 'backward' | 'forward', granularity?: 'character' | 'word'): Anchor;
|
|
62
|
+
moveVertical(anchor: Anchor, direction: 'up' | 'down', preferredX?: number): {
|
|
63
|
+
anchor: Anchor;
|
|
64
|
+
preferredX: number;
|
|
65
|
+
};
|
|
66
|
+
moveLineBoundary(anchor: Anchor, edge: 'start' | 'end'): Anchor;
|
|
67
|
+
wordRangeAt(point: PagePoint): {
|
|
68
|
+
start: Anchor;
|
|
69
|
+
end: Anchor;
|
|
70
|
+
} | undefined;
|
|
71
|
+
flowRangeAt(point: PagePoint): {
|
|
72
|
+
start: Anchor;
|
|
73
|
+
end: Anchor;
|
|
74
|
+
} | undefined;
|
|
75
|
+
}
|
|
76
|
+
export declare function orderedAnchors(a: Anchor, b: Anchor): {
|
|
77
|
+
start: Anchor;
|
|
78
|
+
end: Anchor;
|
|
79
|
+
reversed: boolean;
|
|
80
|
+
};
|