@aseity/idocs-preview 0.3.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 +6 -0
- package/README.md +39 -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 +132 -38
- package/dist/core/index.d.ts +6 -19
- package/dist/core/index.js +13 -17
- package/dist/core/protocol.d.ts +87 -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 +30 -0
- package/wasm/idocs_wasm.js +147 -0
- package/wasm/idocs_wasm_bg.wasm +0 -0
- package/wasm/idocs_wasm_bg.wasm.d.ts +13 -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, { exportDocx, 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,17 +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
|
-
outcome = exportDocx(job.bytes, job.name, job.assets, measure);
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
if (job.progressive)
|
|
27
|
-
post({ type: 'pageReset', id });
|
|
28
|
-
const onPage = job.progressive ? (packet) => {
|
|
29
|
-
post({ type: 'page', id, ...packet }, [packet.data.buffer, ...packet.images.map(bytes => bytes.buffer)]);
|
|
30
|
-
} : undefined;
|
|
31
|
-
outcome = openDocument(job.kind, job.bytes, job.name, job.assets, measure, onPage);
|
|
32
|
-
}
|
|
19
|
+
outcome = job.run(measure);
|
|
33
20
|
}
|
|
34
21
|
catch (error) {
|
|
35
22
|
pending.delete(id);
|
|
@@ -49,15 +36,79 @@ export function serve(endpoint, options = {}) {
|
|
|
49
36
|
post({ type: 'exported', id, bytes: outcome.bytes }, [outcome.bytes.buffer]);
|
|
50
37
|
return;
|
|
51
38
|
}
|
|
52
|
-
|
|
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
|
+
});
|
|
53
96
|
};
|
|
54
97
|
endpoint.addEventListener('message', async (event) => {
|
|
55
98
|
const message = event.data;
|
|
56
99
|
if (message.type === 'init') {
|
|
57
|
-
// Start fetching early; a failure is reported to the first open.
|
|
58
100
|
start(message.wasmUrl).catch(() => { });
|
|
59
101
|
return;
|
|
60
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
|
+
}
|
|
61
112
|
try {
|
|
62
113
|
await start();
|
|
63
114
|
}
|
|
@@ -67,26 +118,69 @@ export function serve(endpoint, options = {}) {
|
|
|
67
118
|
post({ type: 'failed', id, error: { code: 'wasm-unavailable', message: String(error), diagnostics: [] } });
|
|
68
119
|
return;
|
|
69
120
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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;
|
|
89
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;
|
|
90
184
|
}
|
|
91
185
|
attempt(message.id);
|
|
92
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,15 +20,6 @@ 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 declare class PreviewError extends Error {
|
|
29
|
-
code: string;
|
|
30
|
-
diagnostics: PreviewDocument['diagnostics'];
|
|
31
|
-
constructor(error: {
|
|
32
|
-
code: string;
|
|
33
|
-
message: string;
|
|
34
|
-
diagnostics: PreviewDocument['diagnostics'];
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
23
|
export type ExportOptions = Pick<OpenOptions, 'name' | 'readResource'>;
|
|
38
24
|
export interface Session {
|
|
39
25
|
exportDocx(bytes: Bytes, options?: ExportOptions): Promise<Uint8Array>;
|
|
@@ -45,5 +31,6 @@ export interface Session {
|
|
|
45
31
|
*/
|
|
46
32
|
dispose(): void;
|
|
47
33
|
}
|
|
34
|
+
export declare function openEditor(options: OpenEditorOptions): Promise<EditorSession>;
|
|
48
35
|
export declare function createSession(options?: SessionOptions): Session;
|
|
49
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;
|
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';
|
|
@@ -105,6 +126,61 @@ export type ToWorker = {
|
|
|
105
126
|
need: ResourceNeed;
|
|
106
127
|
bytes: Uint8Array | null;
|
|
107
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;
|
|
108
184
|
};
|
|
109
185
|
export interface PreviewPage {
|
|
110
186
|
page: DisplayPage;
|
|
@@ -135,6 +211,17 @@ export type FromWorker = {
|
|
|
135
211
|
json: string;
|
|
136
212
|
images: Uint8Array[];
|
|
137
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;
|
|
138
225
|
} | {
|
|
139
226
|
type: 'failed';
|
|
140
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
|
+
};
|