@quillmark/wasm 0.97.0 → 0.99.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 +303 -0
- package/LICENSE +13 -0
- package/README.md +63 -60
- package/backends/pdfform/wasm.d.ts +300 -143
- package/backends/pdfform/wasm_bg.js +101 -102
- package/backends/pdfform/wasm_bg.wasm +0 -0
- package/backends/typst/wasm.d.ts +300 -143
- package/backends/typst/wasm_bg.js +101 -102
- package/backends/typst/wasm_bg.wasm +0 -0
- package/core/wasm.d.ts +127 -93
- package/core/wasm_bg.js +84 -82
- package/core/wasm_bg.wasm +0 -0
- package/package.json +2 -2
- package/runtime/runtime.d.ts +157 -79
- package/runtime/runtime.js +375 -95
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,22 +127,33 @@ 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
|
-
// `ContentIsland.type
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
//
|
|
129
|
-
//
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
|
|
133
|
-
|
|
139
|
+
// `ContentIsland.type`, `ContentMark.type`, `ContentLine.kind`, and
|
|
140
|
+
// `ContentContainer.container` are open sets: each union has a residual
|
|
141
|
+
// `{ …: string; … }` arm, so a bare discriminant check never narrows the payload
|
|
142
|
+
// (TS keeps the residual arm live, since a `string` can equal the literal).
|
|
143
|
+
// These guards are the checked narrowing path for the pinned arms; an
|
|
144
|
+
// unrecognized discriminant fails every guard and keeps its opaque payload. Only
|
|
145
|
+
// the payload-carrying arms get a guard: the bare marks
|
|
146
|
+
// (`strong`/`emph`/`underline`/`strike`/`code`), the payload-free lines
|
|
147
|
+
// (`para`/`island`/`rule`), and `quote` narrow to nothing.
|
|
148
|
+
|
|
149
|
+
import type {
|
|
150
|
+
ContentIsland,
|
|
151
|
+
TableProps,
|
|
152
|
+
ImageProps,
|
|
153
|
+
ContentMark,
|
|
154
|
+
ContentLine,
|
|
155
|
+
ContentContainer
|
|
156
|
+
} from '../core/wasm.js';
|
|
134
157
|
|
|
135
158
|
/** Narrow a {@link ContentIsland} to the pinned `table` arm (`props: TableProps`). */
|
|
136
159
|
export declare function isTableIsland(
|
|
@@ -152,6 +175,59 @@ export declare function isAnchorMark(
|
|
|
152
175
|
mark: ContentMark
|
|
153
176
|
): mark is ContentMark & { type: 'anchor'; id: string };
|
|
154
177
|
|
|
178
|
+
/** Narrow a {@link ContentLine} to the `heading` arm (carries `level`). */
|
|
179
|
+
export declare function isHeadingLine(
|
|
180
|
+
line: ContentLine
|
|
181
|
+
): line is ContentLine & { kind: 'heading'; level: number };
|
|
182
|
+
|
|
183
|
+
/** Narrow a {@link ContentLine} to the `code` arm (carries `lang`). */
|
|
184
|
+
export declare function isCodeLine(
|
|
185
|
+
line: ContentLine
|
|
186
|
+
): line is ContentLine & { kind: 'code'; lang?: string };
|
|
187
|
+
|
|
188
|
+
/** Narrow a {@link ContentContainer} to the `list_item` arm (carries its shape). */
|
|
189
|
+
export declare function isListItemContainer(
|
|
190
|
+
container: ContentContainer
|
|
191
|
+
): container is ContentContainer & {
|
|
192
|
+
container: 'list_item';
|
|
193
|
+
ordered: boolean;
|
|
194
|
+
start: number;
|
|
195
|
+
ordinal: number;
|
|
196
|
+
};
|
|
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
|
+
|
|
155
231
|
// ── Canonical render-side types ─────────────────────────────────────────────
|
|
156
232
|
// These are the BACKEND-NEUTRAL render contract of the plural-backend API. They
|
|
157
233
|
// are defined HERE (not re-exported from one private backend) because no single
|
|
@@ -180,21 +256,21 @@ export interface RenderOptions {
|
|
|
180
256
|
/**
|
|
181
257
|
* Populate {@link RenderResult.regions} with the schema-field geometry
|
|
182
258
|
* sidecar (the same entries {@link LiveSession.regions} serves), for
|
|
183
|
-
* consumers without a live session
|
|
259
|
+
* consumers without a live session; e.g. overlays over a one-shot SVG
|
|
184
260
|
* export. Defaults to `false`: exports pay no introspection cost.
|
|
185
261
|
*/
|
|
186
262
|
regions?: boolean;
|
|
187
263
|
}
|
|
188
264
|
|
|
189
265
|
/**
|
|
190
|
-
* How precisely a {@link ContentHit.pos} resolved
|
|
266
|
+
* How precisely a {@link ContentHit.pos} resolved: the marker a caret UI reads
|
|
191
267
|
* to decide whether to trust the offset. Never sub-cluster: `'cluster'` is the
|
|
192
268
|
* finest, `'segment'` the floor it degrades to on origin-less ink.
|
|
193
269
|
*
|
|
194
|
-
* - `'cluster'
|
|
270
|
+
* - `'cluster'`: `pos` is the first content char of the cluster under the point
|
|
195
271
|
* (an escaped/CJK/shaping cluster floors to its first char). Place the caret
|
|
196
272
|
* at `pos` directly.
|
|
197
|
-
* - `'segment'
|
|
273
|
+
* - `'segment'`: the point hit origin-less ink (list markers, numbering, a
|
|
198
274
|
* multi-line code fence's interior), so `pos` degraded to the containing
|
|
199
275
|
* segment's start. Treat `pos` as the selected segment, not a caret.
|
|
200
276
|
*/
|
|
@@ -203,7 +279,7 @@ export type HitGranularity = 'cluster' | 'segment';
|
|
|
203
279
|
/** A click resolved to a field and USV offset into its Content. */
|
|
204
280
|
export interface ContentHit {
|
|
205
281
|
/**
|
|
206
|
-
* The field's canonical `DocPath` address (`parseDocPath`-routable)
|
|
282
|
+
* The field's canonical `DocPath` address (`parseDocPath`-routable): the same
|
|
207
283
|
* address {@link LiveSession.fieldAt} returns for that point.
|
|
208
284
|
*/
|
|
209
285
|
field: string;
|
|
@@ -218,28 +294,28 @@ export interface ContentHit {
|
|
|
218
294
|
/**
|
|
219
295
|
* A rendered field region: the canonical `DocPath` field address (`field`) plus
|
|
220
296
|
* its geometry (`rect`) on the page. Emitted by backends that place schema fields
|
|
221
|
-
* (`pdfform` AcroForm widgets; Typst form-fields and span-tracked content
|
|
297
|
+
* (`pdfform` AcroForm widgets; Typst form-fields and span-tracked content:
|
|
222
298
|
* richtext bodies, `richtext[]` elements, card content fields, direct scalar
|
|
223
|
-
* references). Only fields with a schema address produce a region
|
|
299
|
+
* references). Only fields with a schema address produce a region: a
|
|
224
300
|
* backend-only widget produces none, and the backend widget name never
|
|
225
301
|
* appears.
|
|
226
302
|
*
|
|
227
303
|
* Use it to scroll to / highlight the focused field's rect; for the click
|
|
228
304
|
* direction use {@link LiveSession.fieldAt}, which resolves a point on *any*
|
|
229
|
-
* placement, not just the first one surfaced here. Geometry only
|
|
305
|
+
* placement, not just the first one surfaced here. Geometry only:
|
|
230
306
|
* `LiveSession.paint` already bakes every value into the raster (see
|
|
231
307
|
* {@link LiveSession}), so a region is never a compositing input.
|
|
232
308
|
*
|
|
233
309
|
* COORDINATE TRANSFORM. `rect` is in PDF points with a **bottom-left** origin.
|
|
234
310
|
*
|
|
235
311
|
* For an **HTML/CSS overlay** on a `width:100%` canvas, position hotspots as
|
|
236
|
-
* percentages of the page
|
|
312
|
+
* percentages of the page; they track the displayed size across DPI and pane
|
|
237
313
|
* resize for free, and only the Y axis flips:
|
|
238
314
|
*
|
|
239
315
|
* ```js
|
|
240
316
|
* const [x0, y0, x1, y1] = region.rect; // PDF pt, bottom-left origin
|
|
241
317
|
* const left = (x0 / pageWidthPt) * 100; // % of page (from PageSize.widthPt)
|
|
242
|
-
* const top = (1 - y1 / pageHeightPt) * 100; //
|
|
318
|
+
* const top = (1 - y1 / pageHeightPt) * 100; // %: flip Y (from PageSize.heightPt)
|
|
243
319
|
* const width = ((x1 - x0) / pageWidthPt) * 100;
|
|
244
320
|
* const height = ((y1 - y0) / pageHeightPt) * 100;
|
|
245
321
|
* ```
|
|
@@ -265,7 +341,7 @@ export interface FieldRegion {
|
|
|
265
341
|
/** `[x0, y0, x1, y1]` in PDF points (1/72″), bottom-left origin. */
|
|
266
342
|
rect: [number, number, number, number];
|
|
267
343
|
/**
|
|
268
|
-
* The content slice this box covers
|
|
344
|
+
* The content slice this box covers: USV `[start, end)` into the field's
|
|
269
345
|
* `Content` for content ink (one segment), absent for a scalar reference
|
|
270
346
|
* site or widget. Consumers key segment highlights on it;
|
|
271
347
|
* {@link LiveSession.fieldBoxes} unions same-page segments for the
|
|
@@ -281,7 +357,7 @@ export interface RenderResult {
|
|
|
281
357
|
outputFormat: OutputFormat;
|
|
282
358
|
renderTimeMs: number;
|
|
283
359
|
/**
|
|
284
|
-
* Schema-field geometry sidecar
|
|
360
|
+
* Schema-field geometry sidecar: populated only when
|
|
285
361
|
* {@link RenderOptions.regions} requested it; empty otherwise. The same
|
|
286
362
|
* entries {@link LiveSession.regions} serves, for consumers without a live
|
|
287
363
|
* session. Page indices are document-space even under a `pages` subset
|
|
@@ -291,7 +367,7 @@ export interface RenderResult {
|
|
|
291
367
|
}
|
|
292
368
|
|
|
293
369
|
/** Canonical contract every backend build must satisfy. The emittable formats. */
|
|
294
|
-
export type OutputFormat = 'pdf' | 'svg' | '
|
|
370
|
+
export type OutputFormat = 'pdf' | 'svg' | 'png';
|
|
295
371
|
|
|
296
372
|
/**
|
|
297
373
|
* Canonical contract every backend build must satisfy. Page geometry in pt.
|
|
@@ -325,7 +401,7 @@ export interface PaintResult {
|
|
|
325
401
|
*/
|
|
326
402
|
clamped: boolean;
|
|
327
403
|
/**
|
|
328
|
-
* The `densityScale` actually applied
|
|
404
|
+
* The `densityScale` actually applied: equal to the requested value unless
|
|
329
405
|
* `clamped`, then reduced proportionally. `layoutScale × effectiveDensityScale`
|
|
330
406
|
* is the scale the backing store was rasterized at.
|
|
331
407
|
*/
|
|
@@ -348,7 +424,7 @@ export interface ChangeSet {
|
|
|
348
424
|
* imported backend build module; `formats`/`canvas` are the REQUIRED static
|
|
349
425
|
* capability manifest. That manifest is what makes
|
|
350
426
|
* `Engine.supportedFormats`/`Engine.supportsCanvas` always FREE: they answer
|
|
351
|
-
* from it directly
|
|
427
|
+
* from it directly, no backend binary is loaded and no quill is cloned into
|
|
352
428
|
* backend memory. A malformed descriptor throws at `new Engine(...)`.
|
|
353
429
|
*/
|
|
354
430
|
export interface BackendDescriptor {
|
|
@@ -361,7 +437,7 @@ export interface EngineOptions {
|
|
|
361
437
|
/**
|
|
362
438
|
* Extra or overriding backend descriptors, merged over the built-ins. Keys are
|
|
363
439
|
* backend ids (as declared by `Quill.yaml`'s `backend:` and reported by
|
|
364
|
-
* `Quill.backendId`). Each value is a `BackendDescriptor
|
|
440
|
+
* `Quill.backendId`). Each value is a `BackendDescriptor`: `formats`/`canvas`
|
|
365
441
|
* are required, so capability probes are ALWAYS free (no binary load, no quill
|
|
366
442
|
* clone). Malformed entries throw at construction. The default registry maps
|
|
367
443
|
* `"typst"` to the bundled Typst build.
|
|
@@ -401,12 +477,12 @@ export declare class Engine {
|
|
|
401
477
|
supportedFormats(quill: Quill): Promise<OutputFormat[]>;
|
|
402
478
|
|
|
403
479
|
/**
|
|
404
|
-
* Whether `quill`'s BACKEND can paint sessions to a canvas
|
|
480
|
+
* Whether `quill`'s BACKEND can paint sessions to a canvas: a pre-session
|
|
405
481
|
* ESTIMATE, not a fact about any particular compile. Same always-free probe
|
|
406
482
|
* as `supportedFormats`: answered from the descriptor's required `canvas`
|
|
407
483
|
* manifest, no binary load and no quill clone. Both the Typst and pdfform
|
|
408
484
|
* backends report `true` here unconditionally; each paints a complete page
|
|
409
|
-
* raster (see {@link LiveSession.paint})
|
|
485
|
+
* raster (see {@link LiveSession.paint}), but a specific compile can still
|
|
410
486
|
* refuse to paint (e.g. a 0-page document), so this can answer `true` while
|
|
411
487
|
* the resulting {@link LiveSession.supportsCanvas} answers `false`. Gate
|
|
412
488
|
* mounting a canvas UI on this; gate the actual `paint` call on the session's
|
|
@@ -419,7 +495,7 @@ export declare class Engine {
|
|
|
419
495
|
* Iterative render session over a compiled snapshot. `free()` when done.
|
|
420
496
|
*
|
|
421
497
|
* CANVAS PAINT IS COMPLETE. {@link LiveSession.paint} writes a complete page
|
|
422
|
-
* raster
|
|
498
|
+
* raster: every piece of page content is already visible in the painted
|
|
423
499
|
* pixels, with NO compositing required by the caller. Both backends that
|
|
424
500
|
* support canvas satisfy this: Typst rasterizes its laid-out page natively;
|
|
425
501
|
* pdfform pre-flattens bound field values into the page content and rasterizes
|
|
@@ -433,7 +509,7 @@ export declare class LiveSession {
|
|
|
433
509
|
readonly pageCount: number;
|
|
434
510
|
readonly backendId: string;
|
|
435
511
|
/**
|
|
436
|
-
* `true` iff `paint`/`pageSize` will succeed for THIS compile
|
|
512
|
+
* `true` iff `paint`/`pageSize` will succeed for THIS compile: the
|
|
437
513
|
* authoritative answer, derived from the session's canvas seam, so it can
|
|
438
514
|
* never disagree with what `paint` actually does. This can be `false` even
|
|
439
515
|
* when {@link Engine.supportsCanvas} answered `true` for the same `quill`
|
|
@@ -444,7 +520,7 @@ export declare class LiveSession {
|
|
|
444
520
|
readonly supportsCanvas: boolean;
|
|
445
521
|
readonly warnings: Diagnostic[];
|
|
446
522
|
/**
|
|
447
|
-
* Recompile the session against `doc
|
|
523
|
+
* Recompile the session against `doc`: the edit verb of a live preview.
|
|
448
524
|
* Transactional: on throw every read (`render`, `paint`, `pageSize`,
|
|
449
525
|
* `regions`) keeps serving the last-good compile, and the session recovers
|
|
450
526
|
* on the next successful `apply`. On success reads serve the new compile;
|
|
@@ -464,30 +540,30 @@ export declare class LiveSession {
|
|
|
464
540
|
* (so a highlight covers continuation pages); a scalar referenced at
|
|
465
541
|
* several plate sites surfaces each site; tracked content plus a
|
|
466
542
|
* `field:`-bound widget yields both, widget ordered first. Group by
|
|
467
|
-
* `field
|
|
543
|
+
* `field`: every entry routes to that field. Later placements of one
|
|
468
544
|
* content value are not enumerated; {@link fieldAt} still resolves
|
|
469
545
|
* clicks on them.
|
|
470
546
|
*/
|
|
471
547
|
regions(): FieldRegion[];
|
|
472
548
|
/**
|
|
473
549
|
* The whole-field highlight boxes for `field` (a canonical `DocPath` address,
|
|
474
|
-
* as {@link regions} keys)
|
|
550
|
+
* as {@link regions} keys): one union rect per page, over the field's
|
|
475
551
|
* `span`-bearing content segments (the "highlight the focused field"
|
|
476
552
|
* quantity). Owns the union {@link regions} leaves derived
|
|
477
553
|
* (span-filter + per-page union), keeping `regions()` the low-level disjoint
|
|
478
|
-
* truth, so a consumer stops reimplementing it. **Content only
|
|
554
|
+
* truth, so a consumer stops reimplementing it. **Content only**: a field
|
|
479
555
|
* placed solely as a scalar reference or a bound widget carries no `span`
|
|
480
556
|
* and returns `[]`; its box is a single {@link regions} rect. Reflects the
|
|
481
557
|
* current compile, like `regions()`.
|
|
482
558
|
*/
|
|
483
559
|
fieldBoxes(field: string): FieldRegion[];
|
|
484
560
|
/**
|
|
485
|
-
* 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
|
|
486
562
|
* (click → field) direction: hit-test a click against the compiled
|
|
487
563
|
* document and get back the canonical `DocPath` field address
|
|
488
564
|
* (`parseDocPath`-routable) to focus in the editor, or `undefined` off any
|
|
489
565
|
* field's ink. `x`/`y` are PDF points with a **bottom-left** origin, the
|
|
490
|
-
* same space as {@link FieldRegion.rect}
|
|
566
|
+
* same space as {@link FieldRegion.rect}, from a canvas click, invert the
|
|
491
567
|
* overlay transform documented there:
|
|
492
568
|
* `x = clickPx.x / renderScale`,
|
|
493
569
|
* `y = pageHeightPt - clickPx.y / renderScale`. Unlike {@link regions},
|
|
@@ -500,7 +576,7 @@ export declare class LiveSession {
|
|
|
500
576
|
*/
|
|
501
577
|
positionAt(page: number, x: number, y: number): ContentHit | undefined;
|
|
502
578
|
/**
|
|
503
|
-
* Content position → caret rect
|
|
579
|
+
* Content position → caret rect: reverse of {@link positionAt}. `field` is a
|
|
504
580
|
* canonical `DocPath` address (`parseDocPath`-routable), as {@link regions} keys.
|
|
505
581
|
*/
|
|
506
582
|
locate(field: string, pos: number): FieldRegion | undefined;
|
|
@@ -509,18 +585,18 @@ export declare class LiveSession {
|
|
|
509
585
|
/**
|
|
510
586
|
* Paint `page` into a 2D canvas context, sizing the backing store itself
|
|
511
587
|
* (it owns `canvas.width`/`height`; the caller owns `canvas.style.*`). The
|
|
512
|
-
* painted raster is COMPLETE
|
|
588
|
+
* painted raster is COMPLETE: all page content visible, no caller-side
|
|
513
589
|
* compositing (Typst rasterizes natively; pdfform rasterizes its
|
|
514
590
|
* pre-flattened page). Effective rasterization scale is
|
|
515
591
|
* `layoutScale × densityScale`, clamped so neither backing dimension exceeds
|
|
516
|
-
* 16384 px
|
|
592
|
+
* 16384 px: {@link PaintResult.clamped} reports the clamp and
|
|
517
593
|
* {@link PaintResult.effectiveDensityScale} the density actually applied.
|
|
518
594
|
*
|
|
519
595
|
* The write is a whole-backing-store `putImageData`, which bypasses the 2D
|
|
520
596
|
* context transform, `globalAlpha`, and clip: the painter owns the entire
|
|
521
597
|
* canvas, so give each visible page its own `` element. You cannot
|
|
522
598
|
* paint two pages into one canvas, paint into a sub-rect, or apply a context
|
|
523
|
-
* transform through this call
|
|
599
|
+
* transform through this call: the raster is complete precisely so you never
|
|
524
600
|
* need to. Keep the per-page canvases alive while their pages stay near the
|
|
525
601
|
* viewport: each `paint` re-rasterizes from scratch, so reusing (pooling) a
|
|
526
602
|
* canvas across pages on scroll re-runs a full render, whereas an idle canvas
|
|
@@ -534,7 +610,7 @@ export declare class LiveSession {
|
|
|
534
610
|
free(): void;
|
|
535
611
|
}
|
|
536
612
|
|
|
537
|
-
// ── Typed writer
|
|
613
|
+
// ── Typed writer: the schema-bound front door ───────────────────────────────
|
|
538
614
|
|
|
539
615
|
// `quill.writer(doc)` is patched onto the re-exported `Quill` prototype (the
|
|
540
616
|
// class is re-exported verbatim, so the method is declared by merging into the
|
|
@@ -542,20 +618,20 @@ export declare class LiveSession {
|
|
|
542
618
|
declare module '../core/wasm.js' {
|
|
543
619
|
interface Quill {
|
|
544
620
|
/**
|
|
545
|
-
* Bind this quill's schema to `doc` for typed writes
|
|
621
|
+
* Bind this quill's schema to `doc` for typed writes: the documented
|
|
546
622
|
* front door, mirroring core's `quill.writer(&mut doc)`. The schema grants
|
|
547
623
|
* the typing, so the quill is the factory. The returned writer holds both
|
|
548
624
|
* handles by reference and owns neither (nothing to `free()`); it is
|
|
549
|
-
* ephemeral by convention
|
|
625
|
+
* ephemeral by convention: bind, write, discard.
|
|
550
626
|
*/
|
|
551
627
|
writer(doc: Document): DocumentWriter;
|
|
552
628
|
/**
|
|
553
|
-
* 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
|
|
554
630
|
* {@link Quill.writer}, mirroring core's `quill.reader(&doc)`. Each field is
|
|
555
631
|
* read by its declared type (a richtext field to markdown, every other type
|
|
556
632
|
* verbatim) with schema authority, so a name the schema does not declare
|
|
557
633
|
* throws rather than reading back `undefined`. Holds both handles by
|
|
558
|
-
* reference and owns neither (nothing to `free()`); ephemeral by convention
|
|
634
|
+
* reference and owns neither (nothing to `free()`); ephemeral by convention:
|
|
559
635
|
* bind, read, discard.
|
|
560
636
|
*/
|
|
561
637
|
reader(doc: Document): DocumentReader;
|
|
@@ -563,22 +639,22 @@ declare module '../core/wasm.js' {
|
|
|
563
639
|
}
|
|
564
640
|
|
|
565
641
|
/**
|
|
566
|
-
* A `Document` bound to its `Quill` for typed writes
|
|
642
|
+
* A `Document` bound to its `Quill` for typed writes: the schema-bound writer,
|
|
567
643
|
* constructed via {@link Quill.writer}. Speaks names, values, and markdown. Bare
|
|
568
644
|
* `set` / `setAll` / `setBody` / `reviseField` / `addCard` / `card(i).set`
|
|
569
645
|
* instead of threading the `quill` handle through the underscored ABI. Holds both
|
|
570
|
-
* handles by reference and owns neither
|
|
646
|
+
* handles by reference and owns neither: nothing to `free()`.
|
|
571
647
|
*
|
|
572
648
|
* Typed commit is the default whenever a quill is in hand: it resolves each
|
|
573
649
|
* field's schema type and strict-commits it, throwing `UnknownField` for a name
|
|
574
|
-
* the schema does not declare
|
|
650
|
+
* the schema does not declare, on the typed path an undeclared name is a typo,
|
|
575
651
|
* not a fallback. The raw `Document.storeField` / `storeFields` verbs remain the
|
|
576
652
|
* deliberate quill-free primitive (standalone data, storage/migration infra, or
|
|
577
653
|
* holding not-yet-conforming in-progress input).
|
|
578
654
|
*/
|
|
579
655
|
export declare class DocumentWriter {
|
|
580
656
|
constructor(quill: Quill, doc: Document);
|
|
581
|
-
/** The bound document
|
|
657
|
+
/** The bound document: the instance passed in, mutated in place. */
|
|
582
658
|
readonly document: Document;
|
|
583
659
|
/**
|
|
584
660
|
* Typed-commit one main-card field (strict coerce, mismatch throws now).
|
|
@@ -586,19 +662,19 @@ export declare class DocumentWriter {
|
|
|
586
662
|
*/
|
|
587
663
|
set(name: string, value: unknown): void;
|
|
588
664
|
/**
|
|
589
|
-
* Typed-commit several main-card fields atomically
|
|
665
|
+
* Typed-commit several main-card fields atomically: nothing is applied on
|
|
590
666
|
* error (throws a {@link QuillmarkError} carrying one diagnostic per
|
|
591
667
|
* offending field, including an `UnknownField` for each undeclared name).
|
|
592
668
|
*/
|
|
593
669
|
setAll(fields: Record<string, unknown>): void;
|
|
594
670
|
/**
|
|
595
671
|
* Set the main body from markdown (edit semantics: anchors rebase), discarding
|
|
596
|
-
* the delta
|
|
672
|
+
* the delta, the receipt-free body write. Use `doc.revise({}, md)` for the
|
|
597
673
|
* `Delta` receipt.
|
|
598
674
|
*/
|
|
599
675
|
setBody(markdown: string): void;
|
|
600
676
|
/**
|
|
601
|
-
* Revise the richtext main-card field `name` from markdown
|
|
677
|
+
* Revise the richtext main-card field `name` from markdown: typed *and*
|
|
602
678
|
* anchor-preserving. Surviving anchors rebase, then the diffed result is
|
|
603
679
|
* schema-conformed (`richtext(inline)` rejects a multi-block result). Throws
|
|
604
680
|
* `UnknownField` for a name the schema does not declare. Returns the `Delta`.
|
|
@@ -606,7 +682,7 @@ export declare class DocumentWriter {
|
|
|
606
682
|
reviseField(name: string, markdown: string): Delta;
|
|
607
683
|
/**
|
|
608
684
|
* Build a composable card of `kind`, typed-commit `fields` onto it, set its
|
|
609
|
-
* body from optional markdown, and place it
|
|
685
|
+
* body from optional markdown, and place it: the fused `makeCard` + typed
|
|
610
686
|
* commit + insertion. `at` picks the position: omitted appends, a number
|
|
611
687
|
* inserts at that index, so a positioned typed insert is one atomic call
|
|
612
688
|
* rather than `addCard` + `moveCard`. Transactional: a rejected field (throws
|
|
@@ -618,9 +694,10 @@ export declare class DocumentWriter {
|
|
|
618
694
|
removeCard(index: number): Card | undefined;
|
|
619
695
|
/**
|
|
620
696
|
* A {@link CardWriter} for the composable card at `index`. Index validity is
|
|
621
|
-
* checked lazily at commit time, so
|
|
622
|
-
* ephemeral
|
|
623
|
-
* retargets it; for durable addressing stamp `$id` and re-resolve at
|
|
697
|
+
* checked lazily at commit time, so an out-of-range index does not throw here.
|
|
698
|
+
* The cursor is ephemeral: a `removeCard`/`addCard` between binding and writing
|
|
699
|
+
* silently retargets it; for durable addressing stamp `$id` and re-resolve at
|
|
700
|
+
* write.
|
|
624
701
|
*/
|
|
625
702
|
card(index: number): CardWriter;
|
|
626
703
|
}
|
|
@@ -637,7 +714,7 @@ export declare class CardWriter {
|
|
|
637
714
|
readonly index: number;
|
|
638
715
|
/**
|
|
639
716
|
* The bound card's `$kind` (empty string when it carries none), read through
|
|
640
|
-
* the document
|
|
717
|
+
* the document: mirrors core `CardWriter::kind()`. Throws `IndexOutOfRange`
|
|
641
718
|
* if the bound index is out of range.
|
|
642
719
|
*/
|
|
643
720
|
readonly kind: string;
|
|
@@ -646,7 +723,7 @@ export declare class CardWriter {
|
|
|
646
723
|
/** Set this card's body from markdown (edit semantics), discarding the delta. */
|
|
647
724
|
setBody(markdown: string): void;
|
|
648
725
|
/**
|
|
649
|
-
* Revise the richtext field `name` on this card from markdown
|
|
726
|
+
* Revise the richtext field `name` on this card from markdown: typed *and*
|
|
650
727
|
* anchor-preserving; the card twin of {@link DocumentWriter.reviseField}.
|
|
651
728
|
* Throws `UnknownField` for an undeclared name and `IndexOutOfRange` if the
|
|
652
729
|
* bound index is out of range. Returns the `Delta`.
|
|
@@ -655,12 +732,12 @@ export declare class CardWriter {
|
|
|
655
732
|
}
|
|
656
733
|
|
|
657
734
|
/**
|
|
658
|
-
* A `Document` bound to its `Quill` for interpreted reads
|
|
735
|
+
* A `Document` bound to its `Quill` for interpreted reads: the schema-plane read
|
|
659
736
|
* surface, constructed via {@link Quill.reader} and the read twin of
|
|
660
737
|
* {@link DocumentWriter}. One `get` reads each field by its declared type: a
|
|
661
738
|
* richtext field to its markdown projection, a plaintext field to its literal
|
|
662
739
|
* text, every other type its canonical value verbatim. Holds both handles by
|
|
663
|
-
* reference and owns neither
|
|
740
|
+
* reference and owns neither: nothing to `free()`.
|
|
664
741
|
*
|
|
665
742
|
* The schema authority is the point: unlike the quill-free transport `Document.getStored`,
|
|
666
743
|
* a name the schema does not declare throws `UnknownField` (a typo) rather than
|
|
@@ -671,7 +748,7 @@ export declare class CardWriter {
|
|
|
671
748
|
*/
|
|
672
749
|
export declare class DocumentReader {
|
|
673
750
|
constructor(quill: Quill, doc: Document);
|
|
674
|
-
/** The bound document
|
|
751
|
+
/** The bound document: the instance passed in. */
|
|
675
752
|
readonly document: Document;
|
|
676
753
|
/**
|
|
677
754
|
* Read the value at `addr`, interpreted by its declared type: a richtext field
|
|
@@ -682,12 +759,13 @@ export declare class DocumentReader {
|
|
|
682
759
|
* `IndexOutOfRange` for a bad `addr.card`.
|
|
683
760
|
*/
|
|
684
761
|
get(addr: Addr | string): unknown;
|
|
685
|
-
/** The main body's markdown
|
|
762
|
+
/** The main body's markdown: the quill-free body read. Equals `get({})`. */
|
|
686
763
|
getBody(): string;
|
|
687
764
|
/**
|
|
688
765
|
* A {@link CardReader} for the composable card at `index`. Index validity is
|
|
689
|
-
* checked lazily at read time, so
|
|
690
|
-
* a `removeCard`/`addCard` between binding and reading
|
|
766
|
+
* checked lazily at read time, so an out-of-range index does not throw here.
|
|
767
|
+
* The cursor is ephemeral: a `removeCard`/`addCard` between binding and reading
|
|
768
|
+
* silently retargets it.
|
|
691
769
|
*/
|
|
692
770
|
card(index: number): CardReader;
|
|
693
771
|
}
|
|
@@ -713,6 +791,6 @@ export declare class CardReader {
|
|
|
713
791
|
* `IndexOutOfRange` for a bad index.
|
|
714
792
|
*/
|
|
715
793
|
get(name: string): unknown;
|
|
716
|
-
/** This card's body markdown
|
|
794
|
+
/** This card's body markdown: the card twin of {@link DocumentReader.getBody}. */
|
|
717
795
|
getBody(): string;
|
|
718
796
|
}
|