@quillmark/wasm 0.98.0 → 0.100.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 +208 -1
- package/LICENSE +13 -0
- package/README.md +116 -64
- package/backends/pdfform/wasm.d.ts +336 -146
- package/backends/pdfform/wasm_bg.js +223 -122
- package/backends/pdfform/wasm_bg.wasm +0 -0
- package/backends/pdfform/wasm_bg.wasm.d.ts +3 -1
- package/backends/typst/wasm.d.ts +336 -146
- package/backends/typst/wasm_bg.js +223 -122
- package/backends/typst/wasm_bg.wasm +0 -0
- package/backends/typst/wasm_bg.wasm.d.ts +3 -1
- package/core/wasm.d.ts +163 -96
- package/core/wasm_bg.js +206 -102
- package/core/wasm_bg.wasm +0 -0
- package/core/wasm_bg.wasm.d.ts +3 -1
- package/package.json +2 -2
- package/runtime/runtime.d.ts +151 -76
- package/runtime/runtime.js +381 -100
package/core/wasm_bg.wasm
CHANGED
|
Binary file
|
package/core/wasm_bg.wasm.d.ts
CHANGED
|
@@ -7,12 +7,12 @@ export const document__addCard: (a: number, b: number, c: number, d: number, e:
|
|
|
7
7
|
export const document__commitField: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
8
8
|
export const document__commitFields: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
9
9
|
export const document__readerGet: (a: number, b: number, c: number, d: number) => void;
|
|
10
|
+
export const document__readerGetContent: (a: number, b: number, c: number, d: number) => void;
|
|
10
11
|
export const document__reviseField: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
|
|
11
12
|
export const document_applyChange: (a: number, b: number, c: number, d: number) => void;
|
|
12
13
|
export const document_blueprintInstruction: (a: number, b: number, c: number) => void;
|
|
13
14
|
export const document_card: (a: number, b: number, c: number) => void;
|
|
14
15
|
export const document_cardCount: (a: number) => number;
|
|
15
|
-
export const document_cardIndexById: (a: number, b: number, c: number) => number;
|
|
16
16
|
export const document_cards: (a: number, b: number) => void;
|
|
17
17
|
export const document_clone: (a: number) => number;
|
|
18
18
|
export const document_currentSchemaVersion: (a: number) => void;
|
|
@@ -63,8 +63,10 @@ export const mapPos: (a: number, b: number, c: number, d: number) => void;
|
|
|
63
63
|
export const parseDocPath: (a: number, b: number, c: number) => void;
|
|
64
64
|
export const quill_backendId: (a: number, b: number) => void;
|
|
65
65
|
export const quill_blueprint: (a: number, b: number) => void;
|
|
66
|
+
export const quill_conform: (a: number, b: number, c: number) => void;
|
|
66
67
|
export const quill_fromTree: (a: number, b: number) => void;
|
|
67
68
|
export const quill_metadata: (a: number, b: number) => void;
|
|
69
|
+
export const quill_parse: (a: number, b: number, c: number, d: number) => void;
|
|
68
70
|
export const quill_resolve: (a: number, b: number, c: number) => void;
|
|
69
71
|
export const quill_schema: (a: number, b: number) => void;
|
|
70
72
|
export const quill_seedCard: (a: number, b: number, c: number, d: number, e: number) => void;
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quillmark/wasm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.100.0",
|
|
4
4
|
"description": "WebAssembly bindings for Quillmark, a schema-driven document engine",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"license": "
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
7
|
"engines": {
|
|
8
8
|
"node": ">=22"
|
|
9
9
|
},
|
package/runtime/runtime.d.ts
CHANGED
|
@@ -1,33 +1,38 @@
|
|
|
1
|
-
// @quillmark/wasm/runtime
|
|
1
|
+
// @quillmark/wasm/runtime: canonical consumer API.
|
|
2
2
|
//
|
|
3
3
|
// `Quill`/`Document` are re-exported verbatim from the core build (their full
|
|
4
4
|
// surface, no drift). Render-side types (`RenderResult`, `RenderOptions`,
|
|
5
5
|
// `Artifact`, `OutputFormat`, `PageSize`, `PaintOptions`, `PaintResult`) are
|
|
6
|
-
// defined HERE as the canonical, backend-neutral render contract
|
|
6
|
+
// defined HERE as the canonical, backend-neutral render contract: NOT sourced
|
|
7
7
|
// from any one private backend build. A type-level drift guard
|
|
8
8
|
// (`runtime.types.test-d.ts`, via `npm run typecheck`) asserts they stay
|
|
9
9
|
// mutually assignable with the Typst backend's generated declarations. `Engine`
|
|
10
10
|
// is the render dispatcher that hides the cross-WASM-memory seam.
|
|
11
11
|
|
|
12
12
|
// CANONICAL INVARIANT: the root re-exports the core build's `Quill`/`Document`
|
|
13
|
-
// verbatim
|
|
13
|
+
// verbatim; they are the SAME classes, never wrappers. There is exactly one
|
|
14
14
|
// public entry point, so this is a structural fact. Replacing the re-export
|
|
15
15
|
// with a wrapper is a breaking design change, not a refactor. See runtime.js.
|
|
16
|
+
//
|
|
17
|
+
// ONE COPY PER PROCESS: two copies of this package are two WASM linear memories
|
|
18
|
+
// and two `Quill`/`Document` classes. Every method taking a handle refuses one
|
|
19
|
+
// belonging to another copy, with a `QuillmarkError` naming `npm ls
|
|
20
|
+
// @quillmark/wasm`. Errors are the exception: `isQuillmarkError` is structural.
|
|
16
21
|
export { Quill, Document, init } from '../core/wasm.js';
|
|
17
22
|
// The document-free content codec, re-exported from the core build.
|
|
18
23
|
export { importMarkdown, exportMarkdown, rebase, mapPos } from '../core/wasm.js';
|
|
19
|
-
// The document-model path parser/serializer
|
|
24
|
+
// The document-model path parser/serializer: route on `Diagnostic.path`
|
|
20
25
|
// segments instead of regexing the string.
|
|
21
26
|
export { parseDocPath, formatDocPath } from '../core/wasm.js';
|
|
22
27
|
|
|
23
28
|
import type { CardAddr } from '../core/wasm.js';
|
|
24
29
|
|
|
25
30
|
/**
|
|
26
|
-
* The main card's address
|
|
31
|
+
* The main card's address: the default target of the card-scoped verbs
|
|
27
32
|
* (`storeFields` / `storeExt` / `commitFields` / …). A named, {@link CardAddr}-typed
|
|
28
33
|
* alias for the empty address `{}`, so a main-card write names its target:
|
|
29
34
|
* `doc.storeFields(MAIN_CARD_ADDR, fields)`. It IS `{}` (frozen at runtime), a
|
|
30
|
-
* pure alias
|
|
35
|
+
* pure alias: `{}` and `undefined` stay equally valid. A card selector only,
|
|
31
36
|
* never a field address.
|
|
32
37
|
*/
|
|
33
38
|
export declare const MAIN_CARD_ADDR: CardAddr;
|
|
@@ -49,17 +54,24 @@ export type {
|
|
|
49
54
|
QuillMetadata
|
|
50
55
|
} from '../core/wasm.js';
|
|
51
56
|
|
|
52
|
-
// Content edit vocabulary
|
|
57
|
+
// Content edit vocabulary: the op-grained content model `Document`'s methods
|
|
53
58
|
// speak (`applyChange(addr, bundle)`, `install(addr, rt)`, `revise(…) => Delta`).
|
|
54
59
|
// Declared in the core build; re-exported here so the single public entry point
|
|
55
|
-
// names every type its own re-exported surface already references
|
|
60
|
+
// names every type its own re-exported surface already references: `Card.body`
|
|
56
61
|
// is a `Content`, `PayloadItem.nestedFills` a `PathStep[][]`, `CardInput.body` a
|
|
57
|
-
// `Content | string
|
|
62
|
+
// `Content | string`: rather than forcing consumers to derive them structurally
|
|
58
63
|
// off the `Document` handle. The content write path (a ProseMirror↔content codec)
|
|
59
64
|
// must name all of them; they are its correctness core, not edge types.
|
|
65
|
+
// `ContentLineKind` is the shared half of `ContentLine` and `setKind`, so lifting
|
|
66
|
+
// a line's kind whole (destructure off `containers`/`continues`, spread the rest
|
|
67
|
+
// into the op) is the version-proof spelling of building a `setKind`. Naming it
|
|
68
|
+
// is what makes that spelling type-check without a cast. The alternative, an
|
|
69
|
+
// arm-by-arm switch, means guessing at the open arm's shape and re-editing on
|
|
70
|
+
// every arm added.
|
|
60
71
|
export type {
|
|
61
72
|
Content,
|
|
62
73
|
ContentLine,
|
|
74
|
+
ContentLineKind,
|
|
63
75
|
ContentContainer,
|
|
64
76
|
ContentMark,
|
|
65
77
|
ContentIsland,
|
|
@@ -78,7 +90,7 @@ export type {
|
|
|
78
90
|
DocPathSeg
|
|
79
91
|
} from '../core/wasm.js';
|
|
80
92
|
|
|
81
|
-
// The resolved-value view
|
|
93
|
+
// The resolved-value view: the return shape of `quill.resolve(doc)`. Value
|
|
82
94
|
// + source rung per declared field (the body is a `body` sibling on its card,
|
|
83
95
|
// never a row in `fields`); diagnostics stay `quill.validate`, guidance stays
|
|
84
96
|
// `quill.schema`.
|
|
@@ -96,14 +108,14 @@ export type {
|
|
|
96
108
|
// ── Error contract ──────────────────────────────────────────────────────────
|
|
97
109
|
|
|
98
110
|
/**
|
|
99
|
-
* The error every fallible method in this package throws
|
|
111
|
+
* The error every fallible method in this package throws: parse
|
|
100
112
|
* (`Document.fromMarkdown`), document mutation, validation
|
|
101
113
|
* (`Quill.fromTree`, `quill.validate`), and rendering (`engine.render`,
|
|
102
114
|
* `engine.open`, `session.render`).
|
|
103
115
|
*
|
|
104
116
|
* This is a STRUCTURAL interface, not a class: the WASM layer throws a real
|
|
105
117
|
* `Error` and attaches `diagnostics` to it, so there is no constructor to
|
|
106
|
-
* `instanceof` against
|
|
118
|
+
* `instanceof` against, narrow with {@link isQuillmarkError}. `diagnostics`
|
|
107
119
|
* is always non-empty; `message` is the first diagnostic's message (or an
|
|
108
120
|
* `"N error(s): …"` aggregate for multi-diagnostic failures), so iterate
|
|
109
121
|
* `diagnostics` for per-error detail. The shape is identical to
|
|
@@ -115,20 +127,22 @@ export interface QuillmarkError extends Error {
|
|
|
115
127
|
|
|
116
128
|
/**
|
|
117
129
|
* Narrow an unknown caught value to {@link QuillmarkError}. Structural
|
|
118
|
-
* (`Error` carrying a `diagnostics` array), so it
|
|
119
|
-
*
|
|
120
|
-
*
|
|
130
|
+
* (`Error` carrying a `diagnostics` array), so it narrows errors from any build
|
|
131
|
+
* or WASM instance in the page. Handles are the opposite: a `Quill` or
|
|
132
|
+
* `Document` from a second copy of this package is rejected wherever it is
|
|
133
|
+
* passed, since two copies are two linear memories. An error is data, not a
|
|
134
|
+
* handle, so nothing is gained by refusing one that crossed.
|
|
121
135
|
*/
|
|
122
136
|
export declare function isQuillmarkError(e: unknown): e is QuillmarkError;
|
|
123
137
|
|
|
124
138
|
// ── Open-set discriminant guards ────────────────────────────────────────────
|
|
125
139
|
// `ContentIsland.type`, `ContentMark.type`, `ContentLine.kind`, and
|
|
126
|
-
// `ContentContainer.container` are open sets
|
|
140
|
+
// `ContentContainer.container` are open sets: each union has a residual
|
|
127
141
|
// `{ …: string; … }` arm, so a bare discriminant check never narrows the payload
|
|
128
142
|
// (TS keeps the residual arm live, since a `string` can equal the literal).
|
|
129
143
|
// These guards are the checked narrowing path for the pinned arms; an
|
|
130
144
|
// unrecognized discriminant fails every guard and keeps its opaque payload. Only
|
|
131
|
-
// the payload-carrying arms get a guard
|
|
145
|
+
// the payload-carrying arms get a guard: the bare marks
|
|
132
146
|
// (`strong`/`emph`/`underline`/`strike`/`code`), the payload-free lines
|
|
133
147
|
// (`para`/`island`/`rule`), and `quote` narrow to nothing.
|
|
134
148
|
|
|
@@ -181,6 +195,39 @@ export declare function isListItemContainer(
|
|
|
181
195
|
ordinal: number;
|
|
182
196
|
};
|
|
183
197
|
|
|
198
|
+
// ── Open-set membership guards ──────────────────────────────────────────────
|
|
199
|
+
// The guards above answer "is this arm X", one pinned arm at a time. These four
|
|
200
|
+
// answer "is this a value this build knows?": the question a read-modify-write
|
|
201
|
+
// consumer must ask, since lowering an edit restates every line's kind and
|
|
202
|
+
// containers, and a construct the consumer cannot hold is gone on write-back
|
|
203
|
+
// unless it is carried inertly. Without a predicate a consumer enumerates the
|
|
204
|
+
// built-in names itself and re-couples to a closed set, going wrong at the first
|
|
205
|
+
// release that adds one.
|
|
206
|
+
//
|
|
207
|
+
// They classify unknown TAGS, not unknown payloads on known tags: a future
|
|
208
|
+
// `kind: "footnote"` carrying a sibling `ref` loses `ref` at any consumer that
|
|
209
|
+
// predates it, with or without these.
|
|
210
|
+
|
|
211
|
+
/** True when this build does not know `line.kind`: the open arm, carrying opaque `attrs`. */
|
|
212
|
+
export declare function isUnknownLine(
|
|
213
|
+
line: ContentLine
|
|
214
|
+
): line is ContentLine & { kind: string; attrs: unknown };
|
|
215
|
+
|
|
216
|
+
/** True when this build does not know `container.container`. See {@link isUnknownLine}. */
|
|
217
|
+
export declare function isUnknownContainer(
|
|
218
|
+
container: ContentContainer
|
|
219
|
+
): container is ContentContainer & { container: string; attrs: unknown };
|
|
220
|
+
|
|
221
|
+
/** True when this build does not know `mark.type`. See {@link isUnknownLine}. */
|
|
222
|
+
export declare function isUnknownMark(
|
|
223
|
+
mark: ContentMark
|
|
224
|
+
): mark is ContentMark & { type: string; attrs: unknown };
|
|
225
|
+
|
|
226
|
+
/** True when this build does not know `island.type` (its payload rides `props`, not `attrs`). */
|
|
227
|
+
export declare function isUnknownIsland(
|
|
228
|
+
island: ContentIsland
|
|
229
|
+
): island is ContentIsland & { type: string; props: unknown };
|
|
230
|
+
|
|
184
231
|
// ── Canonical render-side types ─────────────────────────────────────────────
|
|
185
232
|
// These are the BACKEND-NEUTRAL render contract of the plural-backend API. They
|
|
186
233
|
// are defined HERE (not re-exported from one private backend) because no single
|
|
@@ -209,21 +256,21 @@ export interface RenderOptions {
|
|
|
209
256
|
/**
|
|
210
257
|
* Populate {@link RenderResult.regions} with the schema-field geometry
|
|
211
258
|
* sidecar (the same entries {@link LiveSession.regions} serves), for
|
|
212
|
-
* consumers without a live session
|
|
259
|
+
* consumers without a live session; e.g. overlays over a one-shot SVG
|
|
213
260
|
* export. Defaults to `false`: exports pay no introspection cost.
|
|
214
261
|
*/
|
|
215
262
|
regions?: boolean;
|
|
216
263
|
}
|
|
217
264
|
|
|
218
265
|
/**
|
|
219
|
-
* How precisely a {@link ContentHit.pos} resolved
|
|
266
|
+
* How precisely a {@link ContentHit.pos} resolved: the marker a caret UI reads
|
|
220
267
|
* to decide whether to trust the offset. Never sub-cluster: `'cluster'` is the
|
|
221
268
|
* finest, `'segment'` the floor it degrades to on origin-less ink.
|
|
222
269
|
*
|
|
223
|
-
* - `'cluster'
|
|
270
|
+
* - `'cluster'`: `pos` is the first content char of the cluster under the point
|
|
224
271
|
* (an escaped/CJK/shaping cluster floors to its first char). Place the caret
|
|
225
272
|
* at `pos` directly.
|
|
226
|
-
* - `'segment'
|
|
273
|
+
* - `'segment'`: the point hit origin-less ink (list markers, numbering, a
|
|
227
274
|
* multi-line code fence's interior), so `pos` degraded to the containing
|
|
228
275
|
* segment's start. Treat `pos` as the selected segment, not a caret.
|
|
229
276
|
*/
|
|
@@ -232,7 +279,7 @@ export type HitGranularity = 'cluster' | 'segment';
|
|
|
232
279
|
/** A click resolved to a field and USV offset into its Content. */
|
|
233
280
|
export interface ContentHit {
|
|
234
281
|
/**
|
|
235
|
-
* The field's canonical `DocPath` address (`parseDocPath`-routable)
|
|
282
|
+
* The field's canonical `DocPath` address (`parseDocPath`-routable): the same
|
|
236
283
|
* address {@link LiveSession.fieldAt} returns for that point.
|
|
237
284
|
*/
|
|
238
285
|
field: string;
|
|
@@ -247,28 +294,28 @@ export interface ContentHit {
|
|
|
247
294
|
/**
|
|
248
295
|
* A rendered field region: the canonical `DocPath` field address (`field`) plus
|
|
249
296
|
* its geometry (`rect`) on the page. Emitted by backends that place schema fields
|
|
250
|
-
* (`pdfform` AcroForm widgets; Typst form-fields and span-tracked content
|
|
297
|
+
* (`pdfform` AcroForm widgets; Typst form-fields and span-tracked content:
|
|
251
298
|
* richtext bodies, `richtext[]` elements, card content fields, direct scalar
|
|
252
|
-
* references). Only fields with a schema address produce a region
|
|
299
|
+
* references). Only fields with a schema address produce a region: a
|
|
253
300
|
* backend-only widget produces none, and the backend widget name never
|
|
254
301
|
* appears.
|
|
255
302
|
*
|
|
256
303
|
* Use it to scroll to / highlight the focused field's rect; for the click
|
|
257
304
|
* direction use {@link LiveSession.fieldAt}, which resolves a point on *any*
|
|
258
|
-
* placement, not just the first one surfaced here. Geometry only
|
|
305
|
+
* placement, not just the first one surfaced here. Geometry only:
|
|
259
306
|
* `LiveSession.paint` already bakes every value into the raster (see
|
|
260
307
|
* {@link LiveSession}), so a region is never a compositing input.
|
|
261
308
|
*
|
|
262
309
|
* COORDINATE TRANSFORM. `rect` is in PDF points with a **bottom-left** origin.
|
|
263
310
|
*
|
|
264
311
|
* For an **HTML/CSS overlay** on a `width:100%` canvas, position hotspots as
|
|
265
|
-
* percentages of the page
|
|
312
|
+
* percentages of the page; they track the displayed size across DPI and pane
|
|
266
313
|
* resize for free, and only the Y axis flips:
|
|
267
314
|
*
|
|
268
315
|
* ```js
|
|
269
316
|
* const [x0, y0, x1, y1] = region.rect; // PDF pt, bottom-left origin
|
|
270
317
|
* const left = (x0 / pageWidthPt) * 100; // % of page (from PageSize.widthPt)
|
|
271
|
-
* const top = (1 - y1 / pageHeightPt) * 100; //
|
|
318
|
+
* const top = (1 - y1 / pageHeightPt) * 100; // %: flip Y (from PageSize.heightPt)
|
|
272
319
|
* const width = ((x1 - x0) / pageWidthPt) * 100;
|
|
273
320
|
* const height = ((y1 - y0) / pageHeightPt) * 100;
|
|
274
321
|
* ```
|
|
@@ -294,7 +341,7 @@ export interface FieldRegion {
|
|
|
294
341
|
/** `[x0, y0, x1, y1]` in PDF points (1/72″), bottom-left origin. */
|
|
295
342
|
rect: [number, number, number, number];
|
|
296
343
|
/**
|
|
297
|
-
* The content slice this box covers
|
|
344
|
+
* The content slice this box covers: USV `[start, end)` into the field's
|
|
298
345
|
* `Content` for content ink (one segment), absent for a scalar reference
|
|
299
346
|
* site or widget. Consumers key segment highlights on it;
|
|
300
347
|
* {@link LiveSession.fieldBoxes} unions same-page segments for the
|
|
@@ -310,7 +357,7 @@ export interface RenderResult {
|
|
|
310
357
|
outputFormat: OutputFormat;
|
|
311
358
|
renderTimeMs: number;
|
|
312
359
|
/**
|
|
313
|
-
* Schema-field geometry sidecar
|
|
360
|
+
* Schema-field geometry sidecar: populated only when
|
|
314
361
|
* {@link RenderOptions.regions} requested it; empty otherwise. The same
|
|
315
362
|
* entries {@link LiveSession.regions} serves, for consumers without a live
|
|
316
363
|
* session. Page indices are document-space even under a `pages` subset
|
|
@@ -354,7 +401,7 @@ export interface PaintResult {
|
|
|
354
401
|
*/
|
|
355
402
|
clamped: boolean;
|
|
356
403
|
/**
|
|
357
|
-
* The `densityScale` actually applied
|
|
404
|
+
* The `densityScale` actually applied: equal to the requested value unless
|
|
358
405
|
* `clamped`, then reduced proportionally. `layoutScale × effectiveDensityScale`
|
|
359
406
|
* is the scale the backing store was rasterized at.
|
|
360
407
|
*/
|
|
@@ -377,7 +424,7 @@ export interface ChangeSet {
|
|
|
377
424
|
* imported backend build module; `formats`/`canvas` are the REQUIRED static
|
|
378
425
|
* capability manifest. That manifest is what makes
|
|
379
426
|
* `Engine.supportedFormats`/`Engine.supportsCanvas` always FREE: they answer
|
|
380
|
-
* from it directly
|
|
427
|
+
* from it directly, no backend binary is loaded and no quill is cloned into
|
|
381
428
|
* backend memory. A malformed descriptor throws at `new Engine(...)`.
|
|
382
429
|
*/
|
|
383
430
|
export interface BackendDescriptor {
|
|
@@ -390,7 +437,7 @@ export interface EngineOptions {
|
|
|
390
437
|
/**
|
|
391
438
|
* Extra or overriding backend descriptors, merged over the built-ins. Keys are
|
|
392
439
|
* backend ids (as declared by `Quill.yaml`'s `backend:` and reported by
|
|
393
|
-
* `Quill.backendId`). Each value is a `BackendDescriptor
|
|
440
|
+
* `Quill.backendId`). Each value is a `BackendDescriptor`: `formats`/`canvas`
|
|
394
441
|
* are required, so capability probes are ALWAYS free (no binary load, no quill
|
|
395
442
|
* clone). Malformed entries throw at construction. The default registry maps
|
|
396
443
|
* `"typst"` to the bundled Typst build.
|
|
@@ -430,12 +477,12 @@ export declare class Engine {
|
|
|
430
477
|
supportedFormats(quill: Quill): Promise<OutputFormat[]>;
|
|
431
478
|
|
|
432
479
|
/**
|
|
433
|
-
* Whether `quill`'s BACKEND can paint sessions to a canvas
|
|
480
|
+
* Whether `quill`'s BACKEND can paint sessions to a canvas: a pre-session
|
|
434
481
|
* ESTIMATE, not a fact about any particular compile. Same always-free probe
|
|
435
482
|
* as `supportedFormats`: answered from the descriptor's required `canvas`
|
|
436
483
|
* manifest, no binary load and no quill clone. Both the Typst and pdfform
|
|
437
484
|
* backends report `true` here unconditionally; each paints a complete page
|
|
438
|
-
* raster (see {@link LiveSession.paint})
|
|
485
|
+
* raster (see {@link LiveSession.paint}), but a specific compile can still
|
|
439
486
|
* refuse to paint (e.g. a 0-page document), so this can answer `true` while
|
|
440
487
|
* the resulting {@link LiveSession.supportsCanvas} answers `false`. Gate
|
|
441
488
|
* mounting a canvas UI on this; gate the actual `paint` call on the session's
|
|
@@ -448,7 +495,7 @@ export declare class Engine {
|
|
|
448
495
|
* Iterative render session over a compiled snapshot. `free()` when done.
|
|
449
496
|
*
|
|
450
497
|
* CANVAS PAINT IS COMPLETE. {@link LiveSession.paint} writes a complete page
|
|
451
|
-
* raster
|
|
498
|
+
* raster: every piece of page content is already visible in the painted
|
|
452
499
|
* pixels, with NO compositing required by the caller. Both backends that
|
|
453
500
|
* support canvas satisfy this: Typst rasterizes its laid-out page natively;
|
|
454
501
|
* pdfform pre-flattens bound field values into the page content and rasterizes
|
|
@@ -462,7 +509,7 @@ export declare class LiveSession {
|
|
|
462
509
|
readonly pageCount: number;
|
|
463
510
|
readonly backendId: string;
|
|
464
511
|
/**
|
|
465
|
-
* `true` iff `paint`/`pageSize` will succeed for THIS compile
|
|
512
|
+
* `true` iff `paint`/`pageSize` will succeed for THIS compile: the
|
|
466
513
|
* authoritative answer, derived from the session's canvas seam, so it can
|
|
467
514
|
* never disagree with what `paint` actually does. This can be `false` even
|
|
468
515
|
* when {@link Engine.supportsCanvas} answered `true` for the same `quill`
|
|
@@ -473,7 +520,7 @@ export declare class LiveSession {
|
|
|
473
520
|
readonly supportsCanvas: boolean;
|
|
474
521
|
readonly warnings: Diagnostic[];
|
|
475
522
|
/**
|
|
476
|
-
* Recompile the session against `doc
|
|
523
|
+
* Recompile the session against `doc`: the edit verb of a live preview.
|
|
477
524
|
* Transactional: on throw every read (`render`, `paint`, `pageSize`,
|
|
478
525
|
* `regions`) keeps serving the last-good compile, and the session recovers
|
|
479
526
|
* on the next successful `apply`. On success reads serve the new compile;
|
|
@@ -493,30 +540,30 @@ export declare class LiveSession {
|
|
|
493
540
|
* (so a highlight covers continuation pages); a scalar referenced at
|
|
494
541
|
* several plate sites surfaces each site; tracked content plus a
|
|
495
542
|
* `field:`-bound widget yields both, widget ordered first. Group by
|
|
496
|
-
* `field
|
|
543
|
+
* `field`: every entry routes to that field. Later placements of one
|
|
497
544
|
* content value are not enumerated; {@link fieldAt} still resolves
|
|
498
545
|
* clicks on them.
|
|
499
546
|
*/
|
|
500
547
|
regions(): FieldRegion[];
|
|
501
548
|
/**
|
|
502
549
|
* The whole-field highlight boxes for `field` (a canonical `DocPath` address,
|
|
503
|
-
* as {@link regions} keys)
|
|
550
|
+
* as {@link regions} keys): one union rect per page, over the field's
|
|
504
551
|
* `span`-bearing content segments (the "highlight the focused field"
|
|
505
552
|
* quantity). Owns the union {@link regions} leaves derived
|
|
506
553
|
* (span-filter + per-page union), keeping `regions()` the low-level disjoint
|
|
507
|
-
* truth, so a consumer stops reimplementing it. **Content only
|
|
554
|
+
* truth, so a consumer stops reimplementing it. **Content only**: a field
|
|
508
555
|
* placed solely as a scalar reference or a bound widget carries no `span`
|
|
509
556
|
* and returns `[]`; its box is a single {@link regions} rect. Reflects the
|
|
510
557
|
* current compile, like `regions()`.
|
|
511
558
|
*/
|
|
512
559
|
fieldBoxes(field: string): FieldRegion[];
|
|
513
560
|
/**
|
|
514
|
-
* The schema field whose content is under a point on `page
|
|
561
|
+
* The schema field whose content is under a point on `page`, the forward
|
|
515
562
|
* (click → field) direction: hit-test a click against the compiled
|
|
516
563
|
* document and get back the canonical `DocPath` field address
|
|
517
564
|
* (`parseDocPath`-routable) to focus in the editor, or `undefined` off any
|
|
518
565
|
* field's ink. `x`/`y` are PDF points with a **bottom-left** origin, the
|
|
519
|
-
* same space as {@link FieldRegion.rect}
|
|
566
|
+
* same space as {@link FieldRegion.rect}, from a canvas click, invert the
|
|
520
567
|
* overlay transform documented there:
|
|
521
568
|
* `x = clickPx.x / renderScale`,
|
|
522
569
|
* `y = pageHeightPt - clickPx.y / renderScale`. Unlike {@link regions},
|
|
@@ -529,7 +576,7 @@ export declare class LiveSession {
|
|
|
529
576
|
*/
|
|
530
577
|
positionAt(page: number, x: number, y: number): ContentHit | undefined;
|
|
531
578
|
/**
|
|
532
|
-
* Content position → caret rect
|
|
579
|
+
* Content position → caret rect: reverse of {@link positionAt}. `field` is a
|
|
533
580
|
* canonical `DocPath` address (`parseDocPath`-routable), as {@link regions} keys.
|
|
534
581
|
*/
|
|
535
582
|
locate(field: string, pos: number): FieldRegion | undefined;
|
|
@@ -538,18 +585,18 @@ export declare class LiveSession {
|
|
|
538
585
|
/**
|
|
539
586
|
* Paint `page` into a 2D canvas context, sizing the backing store itself
|
|
540
587
|
* (it owns `canvas.width`/`height`; the caller owns `canvas.style.*`). The
|
|
541
|
-
* painted raster is COMPLETE
|
|
588
|
+
* painted raster is COMPLETE: all page content visible, no caller-side
|
|
542
589
|
* compositing (Typst rasterizes natively; pdfform rasterizes its
|
|
543
590
|
* pre-flattened page). Effective rasterization scale is
|
|
544
591
|
* `layoutScale × densityScale`, clamped so neither backing dimension exceeds
|
|
545
|
-
* 16384 px
|
|
592
|
+
* 16384 px: {@link PaintResult.clamped} reports the clamp and
|
|
546
593
|
* {@link PaintResult.effectiveDensityScale} the density actually applied.
|
|
547
594
|
*
|
|
548
595
|
* The write is a whole-backing-store `putImageData`, which bypasses the 2D
|
|
549
596
|
* context transform, `globalAlpha`, and clip: the painter owns the entire
|
|
550
597
|
* canvas, so give each visible page its own `` element. You cannot
|
|
551
598
|
* paint two pages into one canvas, paint into a sub-rect, or apply a context
|
|
552
|
-
* transform through this call
|
|
599
|
+
* transform through this call: the raster is complete precisely so you never
|
|
553
600
|
* need to. Keep the per-page canvases alive while their pages stay near the
|
|
554
601
|
* viewport: each `paint` re-rasterizes from scratch, so reusing (pooling) a
|
|
555
602
|
* canvas across pages on scroll re-runs a full render, whereas an idle canvas
|
|
@@ -563,7 +610,7 @@ export declare class LiveSession {
|
|
|
563
610
|
free(): void;
|
|
564
611
|
}
|
|
565
612
|
|
|
566
|
-
// ── Typed writer
|
|
613
|
+
// ── Typed writer: the schema-bound front door ───────────────────────────────
|
|
567
614
|
|
|
568
615
|
// `quill.writer(doc)` is patched onto the re-exported `Quill` prototype (the
|
|
569
616
|
// class is re-exported verbatim, so the method is declared by merging into the
|
|
@@ -571,20 +618,20 @@ export declare class LiveSession {
|
|
|
571
618
|
declare module '../core/wasm.js' {
|
|
572
619
|
interface Quill {
|
|
573
620
|
/**
|
|
574
|
-
* Bind this quill's schema to `doc` for typed writes
|
|
621
|
+
* Bind this quill's schema to `doc` for typed writes: the documented
|
|
575
622
|
* front door, mirroring core's `quill.writer(&mut doc)`. The schema grants
|
|
576
623
|
* the typing, so the quill is the factory. The returned writer holds both
|
|
577
624
|
* handles by reference and owns neither (nothing to `free()`); it is
|
|
578
|
-
* ephemeral by convention
|
|
625
|
+
* ephemeral by convention: bind, write, discard.
|
|
579
626
|
*/
|
|
580
627
|
writer(doc: Document): DocumentWriter;
|
|
581
628
|
/**
|
|
582
|
-
* Bind this quill's schema to `doc` for interpreted reads
|
|
629
|
+
* Bind this quill's schema to `doc` for interpreted reads: the read twin of
|
|
583
630
|
* {@link Quill.writer}, mirroring core's `quill.reader(&doc)`. Each field is
|
|
584
631
|
* read by its declared type (a richtext field to markdown, every other type
|
|
585
632
|
* verbatim) with schema authority, so a name the schema does not declare
|
|
586
633
|
* throws rather than reading back `undefined`. Holds both handles by
|
|
587
|
-
* reference and owns neither (nothing to `free()`); ephemeral by convention
|
|
634
|
+
* reference and owns neither (nothing to `free()`); ephemeral by convention:
|
|
588
635
|
* bind, read, discard.
|
|
589
636
|
*/
|
|
590
637
|
reader(doc: Document): DocumentReader;
|
|
@@ -592,22 +639,22 @@ declare module '../core/wasm.js' {
|
|
|
592
639
|
}
|
|
593
640
|
|
|
594
641
|
/**
|
|
595
|
-
* A `Document` bound to its `Quill` for typed writes
|
|
642
|
+
* A `Document` bound to its `Quill` for typed writes: the schema-bound writer,
|
|
596
643
|
* constructed via {@link Quill.writer}. Speaks names, values, and markdown. Bare
|
|
597
644
|
* `set` / `setAll` / `setBody` / `reviseField` / `addCard` / `card(i).set`
|
|
598
645
|
* instead of threading the `quill` handle through the underscored ABI. Holds both
|
|
599
|
-
* handles by reference and owns neither
|
|
646
|
+
* handles by reference and owns neither: nothing to `free()`.
|
|
600
647
|
*
|
|
601
648
|
* Typed commit is the default whenever a quill is in hand: it resolves each
|
|
602
649
|
* field's schema type and strict-commits it, throwing `UnknownField` for a name
|
|
603
|
-
* the schema does not declare
|
|
650
|
+
* the schema does not declare, on the typed path an undeclared name is a typo,
|
|
604
651
|
* not a fallback. The raw `Document.storeField` / `storeFields` verbs remain the
|
|
605
652
|
* deliberate quill-free primitive (standalone data, storage/migration infra, or
|
|
606
653
|
* holding not-yet-conforming in-progress input).
|
|
607
654
|
*/
|
|
608
655
|
export declare class DocumentWriter {
|
|
609
656
|
constructor(quill: Quill, doc: Document);
|
|
610
|
-
/** The bound document
|
|
657
|
+
/** The bound document: the instance passed in, mutated in place. */
|
|
611
658
|
readonly document: Document;
|
|
612
659
|
/**
|
|
613
660
|
* Typed-commit one main-card field (strict coerce, mismatch throws now).
|
|
@@ -615,27 +662,31 @@ export declare class DocumentWriter {
|
|
|
615
662
|
*/
|
|
616
663
|
set(name: string, value: unknown): void;
|
|
617
664
|
/**
|
|
618
|
-
* Typed-commit several main-card fields atomically
|
|
665
|
+
* Typed-commit several main-card fields atomically: nothing is applied on
|
|
619
666
|
* error (throws a {@link QuillmarkError} carrying one diagnostic per
|
|
620
667
|
* offending field, including an `UnknownField` for each undeclared name).
|
|
621
668
|
*/
|
|
622
669
|
setAll(fields: Record<string, unknown>): void;
|
|
623
670
|
/**
|
|
624
671
|
* Set the main body from markdown (edit semantics: anchors rebase), discarding
|
|
625
|
-
* the delta
|
|
672
|
+
* the delta, the receipt-free body write. Use `doc.revise({}, md)` for the
|
|
626
673
|
* `Delta` receipt.
|
|
627
674
|
*/
|
|
628
675
|
setBody(markdown: string): void;
|
|
629
676
|
/**
|
|
630
|
-
* Revise the
|
|
677
|
+
* Revise the content main-card field `name` from authored text: typed *and*
|
|
631
678
|
* anchor-preserving. Surviving anchors rebase, then the diffed result is
|
|
632
679
|
* schema-conformed (`richtext(inline)` rejects a multi-block result). Throws
|
|
633
680
|
* `UnknownField` for a name the schema does not declare. Returns the `Delta`.
|
|
681
|
+
*
|
|
682
|
+
* The codec comes from the declared type: `richtext` diffs markdown, while
|
|
683
|
+
* `plaintext` diffs the literal text and never imports markdown, so a
|
|
684
|
+
* byte-identical revise of a value carrying escapes is a byte no-op.
|
|
634
685
|
*/
|
|
635
|
-
reviseField(name: string,
|
|
686
|
+
reviseField(name: string, text: string): Delta;
|
|
636
687
|
/**
|
|
637
688
|
* Build a composable card of `kind`, typed-commit `fields` onto it, set its
|
|
638
|
-
* body from optional markdown, and place it
|
|
689
|
+
* body from optional markdown, and place it: the fused `makeCard` + typed
|
|
639
690
|
* commit + insertion. `at` picks the position: omitted appends, a number
|
|
640
691
|
* inserts at that index, so a positioned typed insert is one atomic call
|
|
641
692
|
* rather than `addCard` + `moveCard`. Transactional: a rejected field (throws
|
|
@@ -647,9 +698,10 @@ export declare class DocumentWriter {
|
|
|
647
698
|
removeCard(index: number): Card | undefined;
|
|
648
699
|
/**
|
|
649
700
|
* A {@link CardWriter} for the composable card at `index`. Index validity is
|
|
650
|
-
* checked lazily at commit time, so
|
|
651
|
-
* ephemeral
|
|
652
|
-
* retargets it;
|
|
701
|
+
* checked lazily at commit time, so an out-of-range index does not throw here.
|
|
702
|
+
* The cursor is ephemeral: a `removeCard`/`addCard` between binding and writing
|
|
703
|
+
* silently retargets it; re-resolve the index at write time when cards may
|
|
704
|
+
* move.
|
|
653
705
|
*/
|
|
654
706
|
card(index: number): CardWriter;
|
|
655
707
|
}
|
|
@@ -666,7 +718,7 @@ export declare class CardWriter {
|
|
|
666
718
|
readonly index: number;
|
|
667
719
|
/**
|
|
668
720
|
* The bound card's `$kind` (empty string when it carries none), read through
|
|
669
|
-
* the document
|
|
721
|
+
* the document: mirrors core `CardWriter::kind()`. Throws `IndexOutOfRange`
|
|
670
722
|
* if the bound index is out of range.
|
|
671
723
|
*/
|
|
672
724
|
readonly kind: string;
|
|
@@ -675,21 +727,21 @@ export declare class CardWriter {
|
|
|
675
727
|
/** Set this card's body from markdown (edit semantics), discarding the delta. */
|
|
676
728
|
setBody(markdown: string): void;
|
|
677
729
|
/**
|
|
678
|
-
* Revise the
|
|
679
|
-
* anchor-preserving; the card twin of {@link DocumentWriter.reviseField}
|
|
680
|
-
* Throws `UnknownField` for an undeclared name and
|
|
681
|
-
* bound index is out of range. Returns the `Delta`.
|
|
730
|
+
* Revise the content field `name` on this card from authored text: typed *and*
|
|
731
|
+
* anchor-preserving; the card twin of {@link DocumentWriter.reviseField},
|
|
732
|
+
* codec included. Throws `UnknownField` for an undeclared name and
|
|
733
|
+
* `IndexOutOfRange` if the bound index is out of range. Returns the `Delta`.
|
|
682
734
|
*/
|
|
683
|
-
reviseField(name: string,
|
|
735
|
+
reviseField(name: string, text: string): Delta;
|
|
684
736
|
}
|
|
685
737
|
|
|
686
738
|
/**
|
|
687
|
-
* A `Document` bound to its `Quill` for interpreted reads
|
|
739
|
+
* A `Document` bound to its `Quill` for interpreted reads: the schema-plane read
|
|
688
740
|
* surface, constructed via {@link Quill.reader} and the read twin of
|
|
689
741
|
* {@link DocumentWriter}. One `get` reads each field by its declared type: a
|
|
690
742
|
* richtext field to its markdown projection, a plaintext field to its literal
|
|
691
743
|
* text, every other type its canonical value verbatim. Holds both handles by
|
|
692
|
-
* reference and owns neither
|
|
744
|
+
* reference and owns neither: nothing to `free()`.
|
|
693
745
|
*
|
|
694
746
|
* The schema authority is the point: unlike the quill-free transport `Document.getStored`,
|
|
695
747
|
* a name the schema does not declare throws `UnknownField` (a typo) rather than
|
|
@@ -697,10 +749,16 @@ export declare class CardWriter {
|
|
|
697
749
|
* decode throws `FieldRichtextDecode`. A field's markdown lives here, not on the
|
|
698
750
|
* body-only `Document.getMarkdown`. The body read stays quill-free (a body's type
|
|
699
751
|
* is a format fact) and never throws.
|
|
752
|
+
*
|
|
753
|
+
* `getContent` is the same read at the other end of the codec, returning the
|
|
754
|
+
* corpus rather than the projection. It binds the quill for the same reason
|
|
755
|
+
* `get` does: a `richtext` string is markdown and a `plaintext` string is
|
|
756
|
+
* literal text, so the same stored bytes decode two ways and only the declared
|
|
757
|
+
* type says which.
|
|
700
758
|
*/
|
|
701
759
|
export declare class DocumentReader {
|
|
702
760
|
constructor(quill: Quill, doc: Document);
|
|
703
|
-
/** The bound document
|
|
761
|
+
/** The bound document: the instance passed in. */
|
|
704
762
|
readonly document: Document;
|
|
705
763
|
/**
|
|
706
764
|
* Read the value at `addr`, interpreted by its declared type: a richtext field
|
|
@@ -711,12 +769,24 @@ export declare class DocumentReader {
|
|
|
711
769
|
* `IndexOutOfRange` for a bad `addr.card`.
|
|
712
770
|
*/
|
|
713
771
|
get(addr: Addr | string): unknown;
|
|
714
|
-
/**
|
|
772
|
+
/**
|
|
773
|
+
* Read the content field at `addr` as its canonical `Content` corpus: the
|
|
774
|
+
* corpus twin of {@link get}, which projects. Decodes through the codec the
|
|
775
|
+
* declared type names (`richtext` as markdown, `plaintext` as literal text),
|
|
776
|
+
* so a committed field and a parsed one read back the same corpus and the
|
|
777
|
+
* storage form stops being the caller's business. An absent `addr.field`
|
|
778
|
+
* reads the body corpus. `undefined` for an absent field; throws
|
|
779
|
+
* `UnknownField`, `FieldNotContent` for a declared type that is not a content
|
|
780
|
+
* leaf, `FieldRichtextDecode` for an undecodable value, and `IndexOutOfRange`.
|
|
781
|
+
*/
|
|
782
|
+
getContent(addr: Addr | string): Content | undefined;
|
|
783
|
+
/** The main body's markdown: the quill-free body read. Equals `get({})`. */
|
|
715
784
|
getBody(): string;
|
|
716
785
|
/**
|
|
717
786
|
* A {@link CardReader} for the composable card at `index`. Index validity is
|
|
718
|
-
* checked lazily at read time, so
|
|
719
|
-
* a `removeCard`/`addCard` between binding and reading
|
|
787
|
+
* checked lazily at read time, so an out-of-range index does not throw here.
|
|
788
|
+
* The cursor is ephemeral: a `removeCard`/`addCard` between binding and reading
|
|
789
|
+
* silently retargets it.
|
|
720
790
|
*/
|
|
721
791
|
card(index: number): CardReader;
|
|
722
792
|
}
|
|
@@ -742,6 +812,11 @@ export declare class CardReader {
|
|
|
742
812
|
* `IndexOutOfRange` for a bad index.
|
|
743
813
|
*/
|
|
744
814
|
get(name: string): unknown;
|
|
745
|
-
/**
|
|
815
|
+
/**
|
|
816
|
+
* Read the content field `name` on this card as its canonical `Content`
|
|
817
|
+
* corpus: the card twin of {@link DocumentReader.getContent}.
|
|
818
|
+
*/
|
|
819
|
+
getContent(name: string): Content | undefined;
|
|
820
|
+
/** This card's body markdown: the card twin of {@link DocumentReader.getBody}. */
|
|
746
821
|
getBody(): string;
|
|
747
822
|
}
|