@embedpdf/web 3.0.0-next.13 → 3.0.0-next.15

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/dist/index.d.cts CHANGED
@@ -7,7 +7,7 @@ interface PickFileOptions {
7
7
  }
8
8
  /** Open the file dialog; resolve the picked file, or null if cancelled. */
9
9
  declare function pickImageFile(options?: PickFileOptions): Promise<File | null>;
10
- /** The same dialog with NO type filter — any file (attachments). */
10
+ /** The same dialog with no type filter — any file (attachments). */
11
11
  declare const pickFile: (options?: PickFileOptions) => Promise<File | null>;
12
12
  /**
13
13
  * Hand bytes to the user as a browser download (a one-shot `<a download>`).
@@ -15,50 +15,112 @@ declare const pickFile: (options?: PickFileOptions) => Promise<File | null>;
15
15
  * capability's `downloadAttachment` or the document `attachments.download`.
16
16
  */
17
17
  declare function saveFile(bytes: Uint8Array | Blob, name: string, mimeType?: string): void;
18
+ /**
19
+ * The browser's default for a plugin's file prompt (the annotation plugin's
20
+ * `FilePickerProvider`): the file dialog, honouring the request's `accept`
21
+ * filter. A picked `File` carries its own name and type, so it goes straight
22
+ * through as the engine's file source; a dismissed dialog answers `null`.
23
+ */
24
+ declare function pickRequestedFile(request: {
25
+ accept?: string | null;
26
+ }): Promise<{
27
+ data: File;
28
+ } | null>;
29
+ /** Where a provider goes: the annotation plugin's port (its capability satisfies it). */
30
+ interface FilePickerPort<Provider> {
31
+ /** Install the provider, `null` to make click-then-pick tools do nothing. Returns its removal. */
32
+ setFilePickerProvider(provider: Provider | null): () => void;
33
+ }
34
+ /**
35
+ * Install `provider` as a document's file picker, until the call it returns
36
+ * removes it. A document has one port, so a second install while the first
37
+ * is there silently replaces it: `onRepeat` hears of it (an adapter warns in
38
+ * development, saying where to install it once).
39
+ */
40
+ declare function installFilePickerProvider<Provider>(annotation: FilePickerPort<Provider>, provider: Provider | null, onRepeat: () => void): () => void;
18
41
  //#endregion
19
- //#region src/clipboard.d.ts
42
+ //#region src/clock.d.ts
20
43
  /**
21
- * Clipboard wiring for text selection — the environmental half of copy.
22
- *
23
- * The selection plugin is deliberately DOM-free: its public capability ends
24
- * at `readText()` (data). Everything that touches `navigator.clipboard` or
25
- * the native `copy` event lives HERE, structurally typed so this module
26
- * stays a pure DOM utility with no EmbedPDF dependencies (the selection
27
- * capability satisfies {@link ClipboardSelectionSource} as-is).
44
+ * The browser's time, for the kernel: `createKernel({ clock: browserClock() })`.
45
+ * Timers, and frames from `requestAnimationFrame`, so plugins can animate and
46
+ * merge their wake-ups into one per painted frame. Structurally `HostClock`
47
+ * from `@embedpdf/core`, declared here so this package stays dependency-free.
48
+ */
49
+ /** Structural twin of `HostClock` (`@embedpdf/core`). */
50
+ interface WebClock {
51
+ now(): number;
52
+ after(ms: number, run: () => void): () => void;
53
+ nextFrame?(run: (timeMs: number) => void): () => void;
54
+ }
55
+ /**
56
+ * The browser's clock. A page without `requestAnimationFrame` (some test
57
+ * environments) gets a clock without frames, and plugins then skip animation.
58
+ */
59
+ declare function browserClock(): WebClock;
60
+ //#endregion
61
+ //#region src/css-text.d.ts
62
+ /**
63
+ * Style records as CSS text. This package hands styles out as records with
64
+ * camelCase names (`strokeWidth`, `fontFamily`) and lengths with their units,
65
+ * the shape a style object takes in React, Vue and Angular. A framework whose
66
+ * `style` is a string (Svelte) turns a record into CSS text with
67
+ * {@link cssText}: `stroke-width: …; font-family: …`. Paint values are
68
+ * `var(--epdf-…, …)`, which only work in `style`, never in an SVG
69
+ * presentation attribute.
28
70
  */
71
+ /** A style record: CSS property names in camelCase, each a value or left out. */
72
+ type StyleRecord<Style> = { readonly [Name in keyof Style]?: string | number | null; };
73
+ /** A style record as CSS text, leaving out what is `undefined` or `null`. */
74
+ declare function cssText<Style extends StyleRecord<Style>>(style: Style): string;
75
+ //#endregion
76
+ //#region src/clipboard.d.ts
29
77
  /** The slice of the selection capability clipboard wiring needs. */
30
78
  interface ClipboardSelectionSource {
31
79
  hasSelection(): boolean;
32
80
  canCopy(): boolean;
33
81
  readText(): Promise<string>;
34
- onChange(cb: () => void): () => void;
35
- onCommit(cb: () => void): () => void;
82
+ onChanged(listener: () => void): () => void;
83
+ onCommitted(listener: () => void): () => void;
36
84
  }
37
85
  interface SelectionClipboardOptions {
38
86
  /**
39
87
  * Prefetch the selected text when the selection settles (default true).
40
- * This is what makes the NATIVE copy path work: a `copy` event handler
88
+ * This is what makes the native copy path work: a `copy` event handler
41
89
  * must call `clipboardData.setData` synchronously — awaiting a page-text
42
90
  * read inside it is too late — and it also keeps the async path instant.
43
91
  * The fetch is one versioned, cached, permission-gated read per page;
44
92
  * pass false to make copying strictly on-demand.
45
93
  */
46
94
  prefetch?: boolean;
47
- /** Event target to listen on. Defaults to `document`. */
48
- target?: Document;
95
+ /**
96
+ * Whose keys and copies these are (default `document`, the whole page). An element takes
97
+ * them only while focus is inside it, for a page with more than one viewer; a copy from the
98
+ * browser's Edit menu included, which reaches the page's body when nothing is selected there.
99
+ */
100
+ target?: Document | HTMLElement;
101
+ /**
102
+ * Called when Ctrl/Cmd+C or a copy (Edit → Copy) meets a selection the user may not copy.
103
+ * The browser's own copy is prevented either way; this is where to say so.
104
+ */
105
+ onRefused?: () => void;
49
106
  }
50
107
  /**
51
108
  * Wire clipboard copy for a selection. Two delivery paths, both fed by the
52
109
  * prefetched text:
53
110
  *
54
111
  * - the native `copy` event (menu Edit→Copy, or ctrl/cmd+C while the page
55
- * has a DOM selection or focused editable — e.g. the viewer shell's
56
- * focus sink): answered SYNCHRONOUSLY from the cache;
112
+ * has a DOM selection): answered synchronously from the cache;
57
113
  * - ctrl/cmd+C with no DOM selection (canvas-rendered viewers usually
58
114
  * have none, and browsers don't dispatch `copy` then): a keydown
59
115
  * fallback writes via the async Clipboard API inside the keystroke's
60
116
  * user-activation window.
61
117
  *
118
+ * A selection the user may not copy is never copied by either path, nor by
119
+ * the browser: the key and the copy are prevented, and `onRefused` says so.
120
+ * Keys and copies in a text field are the field's, and left alone. With an
121
+ * element as `target`, only the keys and copies made while focus is inside it
122
+ * are its own.
123
+ *
62
124
  * Returns the unwire function. Mount once per document view (not per page).
63
125
  */
64
126
  declare function wireSelectionClipboard(selection: ClipboardSelectionSource, options?: SelectionClipboardOptions): () => void;
@@ -69,29 +131,67 @@ declare function wireSelectionClipboard(selection: ClipboardSelectionSource, opt
69
131
  * with what was copied ('' when nothing was — nothing is written then, so an
70
132
  * empty selection never clobbers the user's clipboard).
71
133
  */
72
- declare function copySelection(selection: ClipboardSelectionSource): Promise<string>;
134
+ declare function copySelection(selection: Pick<ClipboardSelectionSource, 'readText'>): Promise<string>;
73
135
  //#endregion
74
- //#region src/anchored-position.d.ts
136
+ //#region src/command-shortcuts.d.ts
137
+ /** Why a matched command won't run whatever the moment, as the commands plugin says it. */
138
+ interface ShortcutRefusal {
139
+ /** Turned off in this viewer, or not allowed by the scope. */
140
+ readonly reason: 'turned-off' | 'not-allowed';
141
+ /** A sentence for the user. */
142
+ readonly message: string;
143
+ }
144
+ /** The part of the commands capability shortcuts need. */
145
+ interface ShortcutCommands {
146
+ /**
147
+ * The command a keystroke's shortcut names, with its refusal when it's refused, or `null`.
148
+ * With `inTextField`, only a command that runs from text fields.
149
+ */
150
+ matchStroke(stroke: KeyboardEvent, options: {
151
+ isMac: boolean;
152
+ inTextField: boolean;
153
+ }): {
154
+ readonly commandId: string;
155
+ readonly refusal: ShortcutRefusal | null;
156
+ } | null;
157
+ canExecute(id: string): boolean;
158
+ execute(id: string): Promise<unknown>;
159
+ }
160
+ interface CommandShortcutOptions {
161
+ /** Whether `Mod` is Cmd (a Mac) or Ctrl. Default: what the browser says. */
162
+ isMac?: boolean;
163
+ /** Where to listen. Default: `window`. */
164
+ target?: Pick<Window, 'addEventListener' | 'removeEventListener'>;
165
+ /** Called when a key's command is turned off or not allowed, with why: say so to the user. */
166
+ onRefused?: (commandId: string, refusal: ShortcutRefusal) => void;
167
+ }
168
+ /** Whether this is an Apple platform, where `Mod` is Cmd and shortcuts show as `⌘K`. */
169
+ declare const isMacPlatform: () => boolean;
170
+ /**
171
+ * Run a command when its shortcut is pressed, and return the function that stops listening.
172
+ * Keys typed into a text field are left alone, except a command's that says it runs from text
173
+ * fields (`shortcutInTextFields`, as Find does). A command that's turned off or not allowed
174
+ * still takes its key, so the browser doesn't do something else with it (Cmd+P printing the
175
+ * page), and `onRefused` says why. A key whose command only can't run right now keeps its
176
+ * browser default.
177
+ */
178
+ declare function bindCommandShortcuts(commands: ShortcutCommands, options?: CommandShortcutOptions): () => void;
179
+ //#endregion
180
+ //#region src/page-ref.d.ts
75
181
  /**
76
- * Anchored-overlay geometry for UI floating over page content (selection
77
- * menus, draft menus, popovers): the projector SNAPSHOT contract, the
78
- * anchor shape, and the placement math. Pure values and pure functions over
79
- * structural rect/point shapes — no EmbedPDF types, no framework, no
80
- * reactive lifecycle — so every framework adapter (React, Vue, Svelte,
81
- * Angular) shares ONE implementation and binds it with its NATIVE
82
- * reactivity (context revision, signals, computed, $derived).
83
- *
84
- * The boundary laws:
85
- * - Placement policy lives HERE, above the projector seam: a projector
86
- * only knows geometry — never what is being positioned nor where it
87
- * prefers to sit.
88
- * - A projector describes the CURRENT projection; it never implements a
89
- * framework-style reactive lifecycle. State-driven changes (the Stage
90
- * camera) must reach consumers through the framework's own render
91
- * cycle so surface and overlay commit TOGETHER; only genuinely
92
- * browser-driven changes (a PageView moving because the document
93
- * scrolled) use an external listener ({@link observeClientGeometry}).
182
+ * A page address — structurally the kernel's `PageRef` from `@embedpdf/core`
183
+ * (`{ kind: 'objectNumber', objectNumber }`), mirrored here like the
184
+ * rect/point shapes so this package stays free of EmbedPDF imports. Every
185
+ * `PageRef` the kernel or a plugin hands out satisfies it; the surfaces pass
186
+ * it through untouched (a stage's `pageAt` result, an anchor's page) — the
187
+ * number is never read here.
94
188
  */
189
+ interface PageRef {
190
+ readonly kind: 'objectNumber';
191
+ readonly objectNumber: number;
192
+ }
193
+ //#endregion
194
+ //#region src/anchored-position.d.ts
95
195
  interface AnchoredRect {
96
196
  x: number;
97
197
  y: number;
@@ -102,36 +202,68 @@ interface AnchoredPoint {
102
202
  x: number;
103
203
  y: number;
104
204
  }
105
- type AnchoredPlacement = 'top' | 'right' | 'bottom' | 'left';
205
+ /** A side of the box. */
206
+ type AnchoredSide = 'top' | 'right' | 'bottom' | 'left';
207
+ /**
208
+ * Where anchored UI sits: a side of the box, centred on it, or lined up with
209
+ * the side's start or end (`'top-end'`: above the box, right edges lined up).
210
+ */
211
+ type AnchoredPlacement = AnchoredSide | `${AnchoredSide}-${'start' | 'end'}`;
212
+ /** How anchored UI is placed: where, how far from the box, and whether it may move to fit. */
213
+ interface AnchoredOptions {
214
+ placement: AnchoredPlacement;
215
+ /** Screen px between the box and the UI; negative overlaps the box. */
216
+ gap: number;
217
+ /** Stays where `placement` puts it: never flips, never moves to stay in view. */
218
+ pinned?: boolean;
219
+ }
106
220
  /** CSS-ready output: absolute/fixed `left`/`top` plus a centering transform. */
107
221
  interface AnchoredPosition {
108
222
  left: number;
109
223
  top: number;
110
224
  transform: string;
225
+ /** Where it sits: the placement asked for, or its opposite side when that had no room. */
226
+ placement: AnchoredPlacement;
227
+ }
228
+ interface AnchoredSize {
229
+ width: number;
230
+ height: number;
111
231
  }
112
232
  /**
113
- * Place an upright element around `box` (screen px). `avoid` is a screen
114
- * point the element must clear (e.g. the rotate knob): the element extends
115
- * ONLY the edge it sits on, and ONLY when the point protrudes past that
116
- * edge — so it clears the obstacle without ever shifting off-centre on the
117
- * other axis. When the point is on another side (e.g. a 90° shape, knob at
118
- * mid-height for a `top` placement) the edge is untouched and the element
119
- * stays centred on `box`.
120
- */
121
- /** What anchored UI attaches to: a content-space rect on a page, plus
122
- * optional content-space points the UI must clear (e.g. a rotate knob).
233
+ * What placement needs to keep anchored UI on screen: the element's size, and
234
+ * the area it must stay inside, in the projector's space (the Stage's own box,
235
+ * or the browser window).
236
+ */
237
+ interface AnchoredFit {
238
+ size: AnchoredSize;
239
+ view: AnchoredRect;
240
+ }
241
+ /** How a page is shown right now: its view scale, its rotation on screen, and its zoom (1 = 100%). */
242
+ interface PageViewEnv {
243
+ scale: number;
244
+ rotation: 0 | 90 | 180 | 270;
245
+ zoom: number;
246
+ }
247
+ /** What anchored UI attaches to: a page-space rect on a page, plus
248
+ * optional page-space points the UI must clear (e.g. a rotate knob).
123
249
  * Structural — plugin anchor reads satisfy it without importing this
124
250
  * package. */
125
251
  interface AnchorTarget {
126
- pon: number;
252
+ page: PageRef;
127
253
  bounds: AnchoredRect;
254
+ /**
255
+ * Where the box is in a given view, for a box whose size or orientation
256
+ * depends on it (a note that keeps its size on screen). The projection
257
+ * calls it, so the anchor itself never has to follow the view.
258
+ */
259
+ boundsIn?: (view: PageViewEnv) => AnchoredRect | null;
128
260
  avoid?: AnchoredPoint[];
129
261
  }
130
262
  /**
131
- * A page surface's PROJECTION SNAPSHOT: how a content-space rect on a page
263
+ * A page surface's projection snapshot: how a page-space rect on a page
132
264
  * becomes screen coordinates, right now. Provided by `<Stage>`
133
265
  * (camera-driven, pure state, no DOM reads) and `<PageView>` (DOM-measured).
134
- * Deliberately NO subscribe here — when projection changes is a framework
266
+ * Deliberately no subscribe here — when projection changes is a framework
135
267
  * binding concern (see the module doc), not part of the snapshot.
136
268
  */
137
269
  interface ViewProjector {
@@ -144,38 +276,163 @@ interface ViewProjector {
144
276
  * position:fixed, so no ancestor overflow can clip. (PageView)
145
277
  */
146
278
  space: 'overlay' | 'client';
147
- /** Content-space rect on a page → coords in `space`. Null: not projectable
279
+ /** Page-space rect on a page → coords in `space`. Null: not projectable
148
280
  * right now (page not shown / not measurable yet). */
149
- toScreen(pon: number, rect: AnchoredRect): AnchoredRect | null;
150
- toScreenPoint(pon: number, at: AnchoredPoint): AnchoredPoint | null;
281
+ toScreen(page: PageRef, rect: AnchoredRect): AnchoredRect | null;
282
+ toScreenPoint(page: PageRef, at: AnchoredPoint): AnchoredPoint | null;
151
283
  /** The page's live view facts (for anchor reads that need them — e.g. the
152
284
  * screen-constant rotate-knob stalk), or null when the page isn't shown. */
153
- viewEnv(pon: number): {
154
- scale: number;
155
- rotation: 0 | 90 | 180 | 270;
156
- zoom: number;
157
- } | null;
285
+ viewEnv(page: PageRef): PageViewEnv | null;
286
+ /** The area anchored UI can be seen in, in `space`: the surface's box, or
287
+ * the window. Null while it isn't measurable yet. */
288
+ view(): AnchoredRect | null;
158
289
  }
159
290
  /**
160
- * THE anchored projection: anchor → screen position, in one pure call —
291
+ * The anchored projection: anchor → screen position, in one pure call —
161
292
  * projection, avoid-point transform, and the shared placement policy.
162
293
  * Frameworks recompute this inside their native reactive primitive
163
294
  * (a React render, a Vue `computed`, an Angular signal, a Svelte
164
295
  * `$derived`); nothing here schedules anything.
296
+ *
297
+ * Null when there is nothing to show: the page isn't shown, or the box is so
298
+ * far out of view that the UI around it can't reach into it.
165
299
  */
166
- declare function projectAnchoredTarget(projector: ViewProjector, anchor: AnchorTarget, placement: AnchoredPlacement, gap: number): AnchoredPosition | null;
300
+ declare function projectAnchoredTarget(projector: ViewProjector, anchor: AnchorTarget, { placement, gap, pinned }: AnchoredOptions, fit?: AnchoredFit | null): AnchoredPosition | null;
167
301
  /**
168
- * The one genuinely BROWSER-driven invalidation: an element in normal
302
+ * The one genuinely browser-driven invalidation: an element in normal
169
303
  * document flow moves when the document scrolls or the window resizes —
170
304
  * no state change announces it. `<PageView>`'s binding registers this;
171
305
  * the Stage never does (its camera is state, delivered through render).
172
306
  */
173
307
  declare function observeClientGeometry(callback: () => void): () => void;
308
+ /**
309
+ * The area anchored UI stays inside: the surface's own box (`'overlay'` space, the element's
310
+ * positioned parent) or the window (`'client'` space). Null while the element has no
311
+ * positioned parent to measure.
312
+ */
313
+ declare function anchoredViewOf(element: HTMLElement, space: ViewProjector['space']): AnchoredRect | null;
314
+ /** Whether two measurements give the same sizes, so a placement made from the first still holds. */
315
+ declare function sameAnchoredFit(left: AnchoredFit | null, right: AnchoredFit): boolean;
316
+ /**
317
+ * Measure anchored UI's `element` and the area it stays inside ({@link anchoredViewOf}) now, and
318
+ * again whenever either resizes: `report` hears every measurement (keep it when
319
+ * {@link sameAnchoredFit} says it changed). A camera move changes neither, so it measures nothing.
320
+ * Returns the function that stops measuring.
321
+ */
322
+ declare function observeAnchoredFit(element: HTMLElement, space: ViewProjector['space'], report: (fit: AnchoredFit) => void): () => void;
323
+ /**
324
+ * Place an upright element around `box` (screen px). `avoid` is a screen
325
+ * point the element must clear (e.g. the rotate knob): the element extends
326
+ * only the edge it sits on, and only when the point protrudes past that
327
+ * edge — so it clears the obstacle without ever shifting along the side.
328
+ * When the point is on another side (e.g. a 90° shape, knob at mid-height
329
+ * for a `top` placement) the edge is untouched.
330
+ */
174
331
  declare function positionAnchoredRect(box: AnchoredRect, placement: AnchoredPlacement, gap: number, avoid?: AnchoredPoint | null): AnchoredPosition;
332
+ /**
333
+ * Place an element of a known size around `box`, inside `fit.view`. It sits
334
+ * where `placement` says when it fits there; otherwise on the opposite side,
335
+ * lined up the same way, when that fits or has more room. Then, while `box`
336
+ * is in view, it moves along both axes to stay inside the view, `gap` from
337
+ * its edges; UI whose box scrolled out of view goes with it. The result is
338
+ * the element's top-left corner, with no transform.
339
+ */
340
+ declare function fitAnchoredRect(box: AnchoredRect, placement: AnchoredPlacement, gap: number, fit: AnchoredFit, avoid?: AnchoredPoint | null): AnchoredPosition;
341
+ //#endregion
342
+ //#region src/annotation-frame.d.ts
343
+ /**
344
+ * An annotation's frame in pixels. The annotation plugin hands out each
345
+ * render item's frame (a box, its turn, and how large the page draws it) and
346
+ * the raster inside it, in page points; these put them in the page layer's
347
+ * pixels, with the CSS turn about the middle. Plain geometry over structural
348
+ * shapes, the same for every framework adapter, so none of them converts,
349
+ * turns or scales anything itself.
350
+ */
351
+ /** A box in page points and its turn, degrees clockwise about its middle. */
352
+ interface TurnedBox {
353
+ box: {
354
+ x: number;
355
+ y: number;
356
+ width: number;
357
+ height: number;
358
+ };
359
+ rotation: number;
360
+ }
361
+ /** A frame: its box and turn, and how large the page draws it relative to its own size. */
362
+ interface FrameBox extends TurnedBox {
363
+ scale: number;
364
+ }
365
+ /** What a page layer converts with: its transform's `toPixels`, its turn, and its zoom (1 = 100%). */
366
+ interface PageLayerTransform {
367
+ toPixels(point: {
368
+ x: number;
369
+ y: number;
370
+ }): {
371
+ x: number;
372
+ y: number;
373
+ };
374
+ rotation: number;
375
+ zoom: number;
376
+ }
377
+ /** A box in pixels and the CSS that turns it about its middle (`undefined` for no turn). */
378
+ interface PixelBox {
379
+ left: number;
380
+ top: number;
381
+ width: number;
382
+ height: number;
383
+ transform: string | undefined;
384
+ }
385
+ /** A frame in the page layer's pixels, and what a look drawn inside it needs. */
386
+ interface FramePixels extends PixelBox {
387
+ /** Its turn on screen: its own and the page's, degrees clockwise. */
388
+ rotationOnScreen: number;
389
+ /**
390
+ * How large the frame is on screen relative to the annotation at its 100%
391
+ * size: the zoom, or for a body that keeps its size on screen, the zoom
392
+ * capped at 1. A look drawn at `design` size is scaled by this.
393
+ */
394
+ scale: number;
395
+ /** The frame's size at the annotation's 100% size, in pixels: the size a look is drawn at. */
396
+ design: {
397
+ width: number;
398
+ height: number;
399
+ };
400
+ }
401
+ /** A box inside its frame as CSS percentages of the frame, so it lands in place at any size. */
402
+ interface FrameFraction {
403
+ left: string;
404
+ top: string;
405
+ width: string;
406
+ height: string;
407
+ transform: string | undefined;
408
+ }
409
+ /** A frame in the page layer's pixels: where it is, its turn, and the size and scale a look is drawn at. */
410
+ declare function frameInPixels(frame: FrameBox, page: PageLayerTransform): FramePixels;
411
+ /**
412
+ * A raster inside its frame, as CSS percentages of the frame. `raster`'s box
413
+ * is relative to the frame's box, as the annotation plugin hands it out.
414
+ */
415
+ declare function rasterInFrame(raster: TurnedBox, frame: TurnedBox): FrameFraction;
416
+ /** The frame a renderer's look draws into: the size to draw at, its turn on screen, and its scale. */
417
+ interface AnnotationLookFrame {
418
+ width: number;
419
+ height: number;
420
+ /** Its turn on screen, the page's and its own, degrees clockwise. */
421
+ rotation: number;
422
+ /** How much the layer scales what the look draws. */
423
+ scale: number;
424
+ }
425
+ /**
426
+ * The frame a look draws into. A `scaled` look (the default) draws at the
427
+ * annotation's 100% size (`design`) inside an element of that size, which
428
+ * the layer scales by `scale` from its top-left corner; an unscaled look
429
+ * draws at the frame's size on screen.
430
+ */
431
+ declare function lookFrameOf(frame: FramePixels, scaled: boolean): AnnotationLookFrame;
175
432
  //#endregion
176
433
  //#region src/cursor.d.ts
177
434
  /**
178
- * SVG → CSS cursor string. The armed-tool indicator is the CURSOR itself (the
435
+ * SVG → CSS cursor string. The armed-tool indicator is the cursor itself (the
179
436
  * only zero-latency pointer-locked pixel the web has — the OS composites it),
180
437
  * so an app hands its toolbar icon here and assigns the result via the
181
438
  * interaction hub's `setToolCursor`.
@@ -207,14 +464,43 @@ interface SvgCursorOptions {
207
464
  }
208
465
  /** Build the CSS cursor value: `url("data:image/svg+xml,…") x y, fallback`. */
209
466
  declare function svgCursor({ svg, hotspot, fallback }: SvgCursorOptions): string;
467
+ /** One cursor slot: an SVG image ({@link SvgCursorOptions}) or a plain CSS cursor ('crosshair', 'url(…) 4 4, copy'). */
468
+ type ToolCursorImage = SvgCursorOptions | string;
469
+ /**
470
+ * A tool's cursors: the tool, and its cursors by keyword. Build `svg` from the same icon your
471
+ * toolbar shows, so the cursor and the button never drift apart.
472
+ */
473
+ interface ToolCursorSpec {
474
+ toolId: string;
475
+ /**
476
+ * keyword → cursor: replace the keywords this tool can show (its own cursor, 'crosshair' or
477
+ * 'copy', and hover claims, 'text' over text) with the tool's look. Keywords left out show as
478
+ * they are: a markup tool's 'default' stays the bare arrow, a 'move' claim drops the icon. An
479
+ * SVG value's `fallback` defaults to the keyword it replaces.
480
+ */
481
+ cursors: Record<string, ToolCursorImage>;
482
+ }
483
+ /**
484
+ * A tool's cursors as CSS cursor values, for the interaction hub's `setToolCursor(toolId,
485
+ * cursors)`: a string stays as it is, an SVG becomes its `url(…)` cursor, falling back to the
486
+ * keyword it replaces unless it names its own fallback.
487
+ */
488
+ declare function toolCursorsOf(cursors: Record<string, ToolCursorImage>): Record<string, string>;
210
489
  //#endregion
211
490
  //#region src/external-uri.d.ts
212
491
  /**
213
- * Validate a link URI for opening in the browser. Returns the URI when its
214
- * scheme is allowed (scheme-relative and bare URIs resolve as https), else
215
- * `null`. Never throws — a malformed URI is just an unopenable one.
492
+ * Validate a link URI for opening in the browser. Returns the absolute URI to open when its
493
+ * scheme is allowed (scheme-relative and bare `www.` URIs become https), else `null`. Never
494
+ * throws — a malformed URI is just an unopenable one.
216
495
  */
217
496
  declare function sanitizeExternalUri(uri: string, allowedSchemes?: Iterable<string>): string | null;
497
+ /**
498
+ * Open a link target in a new tab when its address is allowed (`http`,
499
+ * `https`, `mailto`, `tel`); anything else is refused. True when it opened.
500
+ * Call it inside the user's click (the link plugin's `activate()` does), so
501
+ * the click is still the gesture that opens the tab.
502
+ */
503
+ declare function openExternalUri(uri: string): boolean;
218
504
  //#endregion
219
505
  //#region src/actions-ui.d.ts
220
506
  /** Structural twin of plugin-actions' `ActionOrigin`. */
@@ -226,20 +512,20 @@ interface ActionsUiEffectContext {
226
512
  }
227
513
  /** Structural twin of plugin-actions' `ActionUiAdapter`. */
228
514
  interface ActionsUiAdapterShape {
229
- openUri(uri: string, opts: {
515
+ openUri(uri: string, options: {
230
516
  isMap: boolean;
231
517
  origin: ActionsUiOrigin;
232
518
  }): void;
233
- print(opts?: ActionsUiEffectContext): void;
234
- alert?(message: string, opts: ActionsUiEffectContext & {
519
+ print(options?: ActionsUiEffectContext): void;
520
+ alert?(message: string, options: ActionsUiEffectContext & {
235
521
  icon: number;
236
522
  title?: string;
237
523
  }): void;
238
- gotoPage?(page: number, opts: ActionsUiEffectContext): void;
524
+ gotoPage?(page: number, options: ActionsUiEffectContext): void;
239
525
  }
240
526
  interface DefaultActionsUiAdapterOptions {
241
527
  /**
242
- * Per-handler overrides. Pass a FUNCTION for late binding (a binding's
528
+ * Per-handler overrides. Pass a function for late binding (a binding's
243
529
  * mutable handlers ref) — it is consulted on every effect, so a fresh
244
530
  * closure never needs a reinstall.
245
531
  */
@@ -250,12 +536,18 @@ interface DefaultActionsUiAdapterOptions {
250
536
  declare const createDefaultActionsUiAdapter: (options?: DefaultActionsUiAdapterOptions) => ActionsUiAdapterShape;
251
537
  //#endregion
252
538
  //#region src/painted-image.d.ts
253
- /** A browser image source whose object URL has an explicit lifetime. */
539
+ /**
540
+ * A browser image source whose object URL has an explicit lifetime: an
541
+ * engine `PageImageHandle`, whose `objectUrl()` is cancellable and follows an
542
+ * `AbortSignal` through `abortWith()`.
543
+ */
254
544
  interface ObjectUrlImageSource {
255
- objectUrl(signal?: AbortSignal): Promise<{
256
- url: string;
257
- revoke(): void;
258
- }>;
545
+ objectUrl(): {
546
+ abortWith(signal: AbortSignal): PromiseLike<{
547
+ url: string;
548
+ revoke(): void;
549
+ }>;
550
+ };
259
551
  }
260
552
  interface PaintedImageCallbacks {
261
553
  onPainted(): void;
@@ -280,9 +572,9 @@ declare function bindPaintedImage(image: HTMLImageElement, source: ObjectUrlImag
280
572
  * stays plugin-free, per the layering law).
281
573
  *
282
574
  * Honesty about reach: `navigator.vibrate` works on Android browsers and is
283
- * NOT implemented in iOS Safari — there the default provider is a silent
575
+ * not implemented in iOS Safari — there the default provider is a silent
284
576
  * no-op until Apple ships a haptics API. (The community switch-control hacks
285
- * were evaluated and deliberately NOT shipped: Apple patched programmatic
577
+ * were evaluated and deliberately not shipped: Apple patched programmatic
286
578
  * triggering in iOS 26.5, leaving only tap-on-control tricks that don't fit a
287
579
  * viewer's gesture moments.) The real iPhone haptic today comes through a
288
580
  * native shell: a WKWebView embedder installs a script message handler and
@@ -303,7 +595,7 @@ interface WebPlatformFeedback {
303
595
  declare const vibrationFeedback: WebPlatformFeedback;
304
596
  /**
305
597
  * A provider for native iOS shells: forwards each call to a WKWebView script
306
- * message handler the HOST APP installed under `handlerName` — an explicit
598
+ * message handler the host app installed under `handlerName` — an explicit
307
599
  * contract between the embedder and their own app, never a global this library
308
600
  * sniffs on its own. The message shape is
309
601
  * `{ family: 'selection' } | { family: 'impact', weight } | { family: 'notify', kind }`;
@@ -315,40 +607,40 @@ declare const wkFeedback: (handlerName: string, fallback?: WebPlatformFeedback)
315
607
  //#endregion
316
608
  //#region src/stage-gestures.d.ts
317
609
  /**
318
- * Stage gesture controller — the ONE DOM input binding for a Stage surface,
610
+ * Stage gesture controller — the one DOM input binding for a Stage surface,
319
611
  * shared by every framework adapter (React, Angular, …) so the feel can never
320
612
  * drift between them.
321
613
  *
322
614
  * The premise (see the stage plugin's camera doctrine): desktop inputs arrive
323
615
  * with physics already applied by the OS — momentum lives in the wheel stream,
324
- * a trackpad pinch is one pre-arbitrated gesture stream. Touch arrives RAW:
616
+ * a trackpad pinch is one pre-arbitrated gesture stream. Touch arrives raw:
325
617
  * with `touch-action: none` the platform scroller is out of the loop, so the
326
618
  * ballistics (velocity → fling) and the arbitration (is this contact a scroll,
327
619
  * a pinch, a tap, or a tool gesture?) must be synthesized here.
328
620
  *
329
- * Arbitration is MODALITY-AWARE:
621
+ * Arbitration is modality-aware:
330
622
  * - touch — navigation-first: one finger pans (whatever tool is armed), two
331
623
  * fingers pinch-zoom around their centroid, release velocity flings, a tap
332
624
  * forwards as a click, a double-tap zoom-toggles, a long-press hands the
333
625
  * gesture to the interaction hub (text selection), and a second finger
334
- * landing mid-tool-gesture CANCELS it into a pinch (the Notes/Procreate
626
+ * landing mid-tool-gesture cancels it into a pinch (the Notes/Procreate
335
627
  * convention).
336
628
  * - mouse/pen — tool-first, exactly the pre-existing behavior: with a hub,
337
629
  * every down/move/up forwards (pan is the pan tool's job); without one,
338
630
  * dragging pans. Wheel and Safari-trackpad gesture events are unchanged.
339
631
  *
340
- * Camera writes are rAF-COALESCED: pointer events only update gesture state;
632
+ * Camera writes are rAF-coalesced: pointer events only update gesture state;
341
633
  * one animation-frame tick applies at most one pan and one zoom per frame,
342
634
  * inside the host's begin/endGesture transaction. Events may arrive at 120 Hz;
343
635
  * the camera moves at display rate.
344
636
  *
345
- * Dependency note: this module speaks to the stage through the STRUCTURAL
346
- * {@link StageGestureHost} interface (satisfied by `StageCapability`) and to
637
+ * Dependency note: this module speaks to the stage through the structural
638
+ * {@link StageGestureHost} interface (satisfied by `StageHostCapability`) and to
347
639
  * the interaction hub through {@link StageGestureSink} (a closure the adapter
348
640
  * builds) — @embedpdf/web stays free of plugin imports, per the layering law.
349
641
  */
350
642
  type StagePointerKind = 'mouse' | 'pen' | 'touch';
351
- /** What the controller needs from the camera — `StageCapability` satisfies it. */
643
+ /** What the controller needs from the camera — `StageHostCapability` satisfies it. */
352
644
  interface StageGestureHost {
353
645
  panBy(dxScreen: number, dyScreen: number): void;
354
646
  zoomAround(screenPt: {
@@ -362,7 +654,7 @@ interface StageGestureHost {
362
654
  /** Momentum pan from a release velocity in screen px/s. */
363
655
  fling(velocityX: number, velocityY: number): void;
364
656
  /** True while a tween/fling runs — a touch-down then is a "catch", not a tap. */
365
- cameraInMotion(): boolean;
657
+ isMoving(): boolean;
366
658
  doubleTapZoom(screenPt: {
367
659
  x: number;
368
660
  y: number;
@@ -370,25 +662,25 @@ interface StageGestureHost {
370
662
  }
371
663
  /**
372
664
  * Where non-navigation gestures go — the adapter's bridge to the interaction
373
- * hub. Every callback receives the ORIGINAL PointerEvent so the adapter can
665
+ * hub. Every callback receives the original PointerEvent so the adapter can
374
666
  * resolve pages/points exactly as it always has. Omit the sink entirely for a
375
667
  * hub-less (built-in pan) stage.
376
668
  */
377
669
  interface StageGestureSink {
378
- down(e: PointerEvent, clickCount: number): void;
379
- move(e: PointerEvent): void;
380
- up(e: PointerEvent): void;
670
+ down(event: PointerEvent, clickCount: number): void;
671
+ move(event: PointerEvent): void;
672
+ up(event: PointerEvent): void;
381
673
  /** The gesture was taken over by navigation (second finger → pinch) or
382
674
  * cancelled by the system — abort, don't commit. */
383
- cancel(e: PointerEvent): void;
675
+ cancel(event: PointerEvent): void;
384
676
  /** Pointer travel with no gesture in flight — cursor feedback. */
385
- hover(e: PointerEvent): void;
677
+ hover(event: PointerEvent): void;
386
678
  /** A touch press held still: hand the gesture to the hub (the adapter
387
679
  * typically forwards it as a word-select down). Subsequent move/up arrive
388
680
  * via {@link move}/{@link up}. */
389
- longPress(e: PointerEvent): void;
681
+ longPress(event: PointerEvent): void;
390
682
  /**
391
- * Touch-consent pre-flight, asked at touch-down BEFORE the contact is
683
+ * Touch-consent pre-flight, asked at touch-down before the contact is
392
684
  * classified: does a tool have standing to own this contact? True when the
393
685
  * armed tool takes fingers wholesale (a drawing tool) or something under
394
686
  * the point claims its drags (a selected annotation's body or handles).
@@ -396,7 +688,7 @@ interface StageGestureSink {
396
688
  * where a second finger still cancels it into a pinch. Must be a pure
397
689
  * read. Absent = never; the contact navigates.
398
690
  */
399
- claimsPoint?(e: PointerEvent): boolean;
691
+ claimsPoint?(event: PointerEvent): boolean;
400
692
  }
401
693
  /** The wheel fields the zoom classifier reads (see `./wheel`'s `WheelSample`). */
402
694
  interface StageWheelSample {
@@ -411,7 +703,7 @@ interface StageGestureOptions {
411
703
  * swallowed, never page-zooming the browser. Default true. */
412
704
  zoomGestures?: boolean;
413
705
  /** The wheel → zoom-factor classifier. Defaults to this package's
414
- * `wheelZoomFactor` (browser wheel classification lives HERE, with the rest
706
+ * `wheelZoomFactor` (browser wheel classification lives here, with the rest
415
707
  * of the browser input handling); inject to override or to fake in tests. */
416
708
  wheelZoomFactor?: (sample: StageWheelSample) => number;
417
709
  /** Tool routing for non-navigation gestures; omit for built-in-pan stages. */
@@ -429,7 +721,7 @@ interface StageGestureOptions {
429
721
  * Release velocity from a trail of pointer samples: the mean velocity over the
430
722
  * trailing `windowMs` (first-to-last inside the window). Null when the trail is
431
723
  * too thin or too stale to trust — the standard "held still, then let go"
432
- * case, which must NOT fling. Pure; exported for tests.
724
+ * case, which must not fling. Pure; exported for tests.
433
725
  */
434
726
  declare function computeReleaseVelocity(samples: ReadonlyArray<{
435
727
  t: number;
@@ -440,7 +732,7 @@ declare function computeReleaseVelocity(samples: ReadonlyArray<{
440
732
  vy: number;
441
733
  } | null;
442
734
  /** Attach the gesture controller to a Stage container. Returns the detach fn. */
443
- declare function createStageGestureController(el: HTMLElement, host: StageGestureHost, options: StageGestureOptions): () => void;
735
+ declare function createStageGestureController(element: HTMLElement, host: StageGestureHost, options: StageGestureOptions): () => void;
444
736
  //#endregion
445
737
  //#region src/selection-handles.d.ts
446
738
  /**
@@ -450,12 +742,12 @@ declare function createStageGestureController(el: HTMLElement, host: StageGestur
450
742
  * `handles` module; this file never imports it, per the layering law:
451
743
  * structural interfaces only).
452
744
  *
453
- * The load-bearing subtlety this module owns: the pointer-DOWN shield must be
454
- * a NATIVE listener. The stage's gesture controller listens natively on the
745
+ * The load-bearing subtlety this module owns: the pointer-down shield must be
746
+ * a native listener. The stage's gesture controller listens natively on the
455
747
  * container, so a framework-synthetic stopPropagation (React runs its
456
- * handlers at the root, AFTER the container's native ones) would be too late
748
+ * handlers at the root, after the container's native ones) would be too late
457
749
  * — the stage would already be panning underneath the handle drag. Once the
458
- * down is captured here, movement tracks by CLIENT DELTAS from the handle's
750
+ * down is captured here, movement tracks by client deltas from the handle's
459
751
  * own base point: no DOM geometry reads, and the client↔overlay conversion
460
752
  * cancels out.
461
753
  */
@@ -472,7 +764,7 @@ interface SelectionHandleSession {
472
764
  interface AttachSelectionHandleOptions {
473
765
  /**
474
766
  * Called at pointer-down to arm a drag: return the drag session plus the
475
- * handle's current BASE point in overlay space (the bar's midpoint — the
767
+ * handle's current base point in overlay space (the bar's midpoint — the
476
768
  * point the user grabbed). Return null to decline (endpoint vanished, page
477
769
  * not laid out) — the press then does nothing and nothing is captured.
478
770
  */
@@ -482,30 +774,30 @@ interface AttachSelectionHandleOptions {
482
774
  } | null;
483
775
  }
484
776
  /** Bind one handle element. Returns the detach fn. */
485
- declare function attachSelectionHandle(el: HTMLElement, options: AttachSelectionHandleOptions): () => void;
777
+ declare function attachSelectionHandle(element: HTMLElement, options: AttachSelectionHandleOptions): () => void;
486
778
  //#endregion
487
779
  //#region src/stage-surface.d.ts
488
780
  interface SurfacePoint {
489
781
  x: number;
490
782
  y: number;
491
783
  }
492
- /** What the binding needs from the stage — `StageCapability` satisfies it. */
784
+ /** What the binding needs from the stage — `StageHostCapability` satisfies it. */
493
785
  interface StageSurfaceHost extends StageGestureHost {
494
- setViewport(size: {
786
+ setViewportSize(size: {
495
787
  width: number;
496
788
  height: number;
497
789
  }): void;
498
790
  setDevicePixelRatio(ratio: number): void;
499
791
  /** Viewport point → the page under it (with per-page display context), or null over a gap. */
500
- pageAt(screen: SurfacePoint): {
501
- pon: number;
792
+ getPageAt(screen: SurfacePoint): {
793
+ ref: PageRef;
502
794
  point: SurfacePoint;
503
795
  scale?: number;
504
796
  rotation?: 0 | 90 | 180 | 270;
505
797
  zoom?: number;
506
798
  } | null;
507
- /** Viewport point → a SPECIFIC page's content space, unclamped (frame-stable projection). */
508
- pointOnPage(pon: number, screen: SurfacePoint): SurfacePoint | null;
799
+ /** Viewport point → a specific page's page space, unclamped (frame-stable projection). */
800
+ viewportToPage(page: PageRef, screen: SurfacePoint): SurfacePoint | null;
509
801
  }
510
802
  /**
511
803
  * The page-resolved sample the binding hands the hub — structurally a
@@ -517,13 +809,13 @@ interface StageSurfaceSample {
517
809
  phase: 'down' | 'move' | 'up' | 'cancel';
518
810
  viewport: SurfacePoint;
519
811
  page?: {
520
- pon: number;
812
+ ref: PageRef;
521
813
  point: SurfacePoint;
522
814
  scale?: number;
523
815
  rotation?: 0 | 90 | 180 | 270;
524
816
  zoom?: number;
525
817
  };
526
- project: (pon: number) => SurfacePoint | null;
818
+ project: (page: PageRef) => SurfacePoint | null;
527
819
  modifiers: {
528
820
  shift: boolean;
529
821
  alt: boolean;
@@ -535,11 +827,11 @@ interface StageSurfaceSample {
535
827
  gesture?: 'long-press';
536
828
  source?: string;
537
829
  }
538
- /** What the binding needs from the interaction hub — `InteractionCapability` satisfies it. */
830
+ /** What the binding needs from the interaction hub — `InteractionHostCapability` satisfies it. */
539
831
  interface StageSurfaceHub {
540
- dispatch(sample: StageSurfaceSample): void;
541
- activeTool(): {
542
- touchDirect?: boolean;
832
+ dispatchPointer(sample: StageSurfaceSample): void;
833
+ getActiveTool(): {
834
+ touch?: 'draw' | 'tap';
543
835
  };
544
836
  wouldClaimTouch(sample: StageSurfaceSample): boolean;
545
837
  }
@@ -547,7 +839,7 @@ interface StageSurfaceOptions {
547
839
  /** Route pointer input to the interaction hub (page-resolved samples) instead
548
840
  * of built-in drag-to-pan. Omit/null for a hub-less stage. */
549
841
  hub?: StageSurfaceHub | null;
550
- /** The lens identity stamped on every sample (`StageCapability.lensId()`),
842
+ /** The lens identity stamped on every sample (`StageHostCapability.getLensId()`),
551
843
  * so lens-scoped handlers only see their own stage's input. */
552
844
  source?: string;
553
845
  /** Ambient zoom gestures (see {@link StageGestureOptions}). Default true. */
@@ -556,7 +848,7 @@ interface StageSurfaceOptions {
556
848
  wheelZoomFactor?: (sample: StageWheelSample) => number;
557
849
  }
558
850
  /** Attach the full surface binding. Returns the detach fn. */
559
- declare function createStageSurface(el: HTMLElement, stage: StageSurfaceHost, options?: StageSurfaceOptions): () => void;
851
+ declare function createStageSurface(element: HTMLElement, stage: StageSurfaceHost, options?: StageSurfaceOptions): () => void;
560
852
  //#endregion
561
853
  //#region src/wheel.d.ts
562
854
  /**
@@ -566,14 +858,14 @@ declare function createStageSurface(el: HTMLElement, stage: StageSurfaceHost, op
566
858
  * A ctrl/cmd wheel event is one of three physically different inputs that
567
859
  * happen to share an event type, each with its own unit system:
568
860
  *
569
- * • trackpad PINCH — browsers (Chrome/Edge/Firefox) synthesize ctrl+wheel
861
+ * • trackpad pinch — browsers (Chrome/Edge/Firefox) synthesize ctrl+wheel
570
862
  * px-deltas scaled to the de-facto convention that `exp(-Δ/100)` tracks
571
863
  * the physical finger scale 1:1. Anything weaker feels dead (the content
572
864
  * must track the fingers — the Figma/maps feel).
573
- * • mouse NOTCHES — coarse steps: ±100/±120 px in Chrome, lines/pages mode
865
+ * • mouse notches — coarse steps: ±100/±120 px in Chrome, lines/pages mode
574
866
  * in Firefox. The pinch mapping would triple per click; a notch instead
575
867
  * steps by 1.2, the same ratio as the zoom buttons.
576
- * • cmd + continuous SCROLL — real scroll px, big and streaming (with
868
+ * • cmd + continuous scroll — real scroll px, big and streaming (with
577
869
  * momentum): a gentle scrub coefficient. A cmd+mouse notch (±120 px)
578
870
  * lands within 0.3% of the 1.2 button step, so it needs no special case.
579
871
  *
@@ -588,7 +880,7 @@ interface WheelSample {
588
880
  metaKey: boolean;
589
881
  }
590
882
  /** Zoom factor for a ctrl/cmd wheel event (the caller decides zoom vs pan). */
591
- declare function wheelZoomFactor(e: WheelSample): number;
883
+ declare function wheelZoomFactor(sample: WheelSample): number;
592
884
  //#endregion
593
885
  //#region src/byte-store.d.ts
594
886
  /**
@@ -614,11 +906,11 @@ interface IndexedDbByteStoreOptions {
614
906
  storeName?: string;
615
907
  }
616
908
  /** Open (creating on first use) one IndexedDB object store keyed by id. */
617
- declare function indexedDbByteStore(dbName: string, opts?: IndexedDbByteStoreOptions): ByteStore;
909
+ declare function indexedDbByteStore(dbName: string, options?: IndexedDbByteStoreOptions): ByteStore;
618
910
  //#endregion
619
911
  //#region src/rich-text-editor.d.ts
620
912
  /**
621
- * Rich text editor binding — the ONE contentEditable mechanics module for a
913
+ * Rich text editor binding — the one contentEditable mechanics module for a
622
914
  * FreeText annotation, shared by every framework adapter (React, Angular,
623
915
  * Vue, Svelte…) so editing can never drift between them:
624
916
  *
@@ -631,7 +923,7 @@ declare function indexedDbByteStore(dbName: string, opts?: IndexedDbByteStoreOpt
631
923
  * • hold re-renders during IME composition, paste as plain text, forward
632
924
  * Cmd/Ctrl+B/I/U as commands
633
925
  *
634
- * The browser owns typing; this module only translates. The POLICY — what a
926
+ * The browser owns typing; this module only translates. The policy — what a
635
927
  * command does to the document, when to commit, what a family maps to —
636
928
  * belongs to the host (the annotation plugin), reached through the
637
929
  * structural {@link RichTextEditorHost}: @embedpdf/web imports no plugin,
@@ -642,9 +934,9 @@ declare function indexedDbByteStore(dbName: string, opts?: IndexedDbByteStoreOpt
642
934
  * runs concatenated, a hard break inside a run is a `\r` too. The same
643
935
  * arithmetic the core's run algebra uses.
644
936
  *
645
- * Known limits (by design, recorded in the plan): the browser's native undo
646
- * stack does not span a host-driven restyle; DOM line wrapping approximates
647
- * the engine's layout, the appearance stream is the truth.
937
+ * Known limits, by design: the browser's native undo stack does not span a
938
+ * host-driven restyle; DOM line wrapping approximates the engine's layout,
939
+ * the appearance stream is the truth.
648
940
  */
649
941
  type RichTextEditorDecoration = 'underline' | 'line-through' | 'word';
650
942
  type RichTextEditorScript = 'normal' | 'sub' | 'super';
@@ -689,12 +981,12 @@ interface RichTextEditorHost {
689
981
  /** A keyboard command the host applies to the current selection. */
690
982
  onCommand(command: RichTextEditorCommand): void;
691
983
  /** The CSS family list for a PDF family ("Helvetica" → a web stack, a
692
- * registered family → itself, mounted as a @font-face). */
984
+ * registered family → the family its face is mounted under, see `mountWebFont`). */
693
985
  cssFontFamily(family: string): string;
694
986
  }
695
987
  interface RichTextEditorProps {
696
988
  document: RichTextEditorDocument;
697
- /** Screen px per content unit (the page scale): sizes are content points. */
989
+ /** Screen px per page unit (the page scale): sizes are page points. */
698
990
  scale: number;
699
991
  }
700
992
  interface RichTextEditorBinding {
@@ -768,26 +1060,166 @@ declare function offsetOfPosition(root: EditorNode, position: EditorPosition): n
768
1060
  * else the empty block / the slot after a hard break the offset names. */
769
1061
  declare function positionOfOffset(root: EditorNode, offset: number): EditorPosition | null;
770
1062
  /** Bind one contentEditable element. Returns the Svelte-action-shaped handle. */
771
- declare function attachRichTextEditor(el: HTMLElement, host: RichTextEditorHost, initial: RichTextEditorProps): RichTextEditorBinding;
1063
+ declare function attachRichTextEditor(element: HTMLElement, host: RichTextEditorHost, initial: RichTextEditorProps): RichTextEditorBinding;
772
1064
  //#endregion
773
1065
  //#region src/web-font.d.ts
774
1066
  /**
775
1067
  * Mount a registered font for the DOM: the engine lays text out with the
776
1068
  * font's bytes, the browser needs the same face as a `@font-face` so the
777
1069
  * live editor and the vector renderer show the glyphs the appearance stream
778
- * will bake. The family name is the font's KEY — the CSS family the
779
- * annotation plugin emits for a registered font (`cssFontFamily`) — so
780
- * mounting under the key is what makes the two agree.
1070
+ * will bake. The face's family is {@link webFontFamily} of the key.
781
1071
  *
782
1072
  * Returns the unmount. Idempotent per (document, key): a second mount of a
783
1073
  * key already in the document's font set is a no-op that still returns an
784
- * unmount of its own (the face leaves when the LAST holder unmounts).
1074
+ * unmount of its own (the face leaves when the last holder unmounts).
785
1075
  */
786
1076
  declare function mountWebFont(key: string, data: ArrayBuffer | Uint8Array, options?: {
787
1077
  document?: Document;
788
1078
  weight?: number | string;
789
1079
  style?: 'normal' | 'italic';
790
1080
  }): Promise<() => void>;
1081
+ /**
1082
+ * A font program to mount: its CSS family, its style, and its bytes. The
1083
+ * structural twin of `@embedpdf/core-fonts`' `FontProgram`, whose family is
1084
+ * named by the program's hash, so it never shadows another font.
1085
+ */
1086
+ interface MountableFontProgram {
1087
+ readonly family: string;
1088
+ readonly weight: number;
1089
+ readonly style: 'normal' | 'italic';
1090
+ load(): Promise<Uint8Array>;
1091
+ }
1092
+ /**
1093
+ * Mount a program under its own family, as it is (already in the viewer's
1094
+ * namespace), in its own weight and style, so CSS asking for that style takes
1095
+ * it as it is and never fakes a bold or an italic. Refcounted per document
1096
+ * like {@link mountWebFont}; resolves with the unmount.
1097
+ */
1098
+ declare function mountFontProgram(program: MountableFontProgram, options?: {
1099
+ document?: Document;
1100
+ }): Promise<() => void>;
1101
+ /**
1102
+ * The programs one layer has mounted: each mounted once, however often it's
1103
+ * asked for, and all let go together when the layer goes (a program another
1104
+ * layer holds stays, refcounted per document). A mount after the release
1105
+ * holds again, for a layer that comes back (React's strict mode runs effects
1106
+ * twice).
1107
+ */
1108
+ declare function createFontMounts(options?: {
1109
+ document?: Document;
1110
+ }): {
1111
+ mount(programs: readonly MountableFontProgram[]): void;
1112
+ release(): void;
1113
+ };
1114
+ //#endregion
1115
+ //#region src/object-urls.d.ts
1116
+ /** Bytes and their type, as the stamp and annotation plugins hand out previews. */
1117
+ interface PictureBytes {
1118
+ readonly bytes: Uint8Array;
1119
+ readonly mimeType?: string | null;
1120
+ }
1121
+ /** An object URL, and how to release it. */
1122
+ interface ObjectUrl {
1123
+ readonly url: string;
1124
+ revoke(): void;
1125
+ }
1126
+ /** An object URL for bytes. Revoke it when nothing shows it any more. */
1127
+ declare function objectUrlOf(picture: PictureBytes): ObjectUrl;
1128
+ /**
1129
+ * Load a picture and hand its object URL to `onUrl` once it's there (nothing
1130
+ * for `null`). What it returns cancels: a load still running is dropped, and
1131
+ * the URL is revoked. Keep showing the previous URL until `onUrl` brings the
1132
+ * next one, so a swap never flickers.
1133
+ */
1134
+ declare function loadObjectUrl(load: () => Promise<PictureBytes | null>, onUrl: (url: string) => void): () => void;
1135
+ /**
1136
+ * One picture as its owner hands it out (the annotation plugin's or the form
1137
+ * plugin's `renderAppearances`): an item in one of its states, at its version.
1138
+ */
1139
+ interface AppearancePicture<Ref> {
1140
+ readonly ref: Ref;
1141
+ /** The state it draws (`/AS`), or `null` for an item without states. */
1142
+ readonly state: string | null;
1143
+ /** The box it was rendered into, in page points. */
1144
+ readonly rect: {
1145
+ x: number;
1146
+ y: number;
1147
+ width: number;
1148
+ height: number;
1149
+ };
1150
+ /** The version of its item it shows: an item at another version looks different now. */
1151
+ readonly version: number;
1152
+ readonly image: ObjectUrlImageSource;
1153
+ }
1154
+ /** A picture's URL, the box it was rendered into, and the version of its item it shows. */
1155
+ interface AppearanceUrl {
1156
+ url: string;
1157
+ box: {
1158
+ x: number;
1159
+ y: number;
1160
+ width: number;
1161
+ height: number;
1162
+ };
1163
+ version: number;
1164
+ }
1165
+ /**
1166
+ * The picture an item shows, from {@link loadAppearanceUrls}: the one of the
1167
+ * state it's in (`'Off'` when it names none), or its only picture when it has
1168
+ * no states; `null` until it's loaded.
1169
+ */
1170
+ declare function shownAppearance(urls: Readonly<Record<string, AppearanceUrl>>, itemKey: string, appearanceState: string | null): AppearanceUrl | null;
1171
+ /**
1172
+ * The engine's picture of an annotation as a renderer gets it (its
1173
+ * `appearance`): `{ url }` once {@link loadAppearanceUrls} has loaded the one
1174
+ * of the state it shows, else `null`.
1175
+ */
1176
+ declare function bakedAppearanceOf(urls: Readonly<Record<string, AppearanceUrl>>, itemKey: string, appearanceState: string | null): {
1177
+ url: string;
1178
+ } | null;
1179
+ /**
1180
+ * The URLs a layer shows, kept from one load to the next: a set stays valid
1181
+ * until the set after it is shown, so a picture that shows again before the
1182
+ * next set arrives (an annotation an undo brings back) still has a live URL.
1183
+ * One per layer, passed to every load; `release()` when the layer goes.
1184
+ */
1185
+ interface ShownUrls {
1186
+ /** Revoke the URLs shown now: the layer is going. A later load starts afresh. */
1187
+ release(): void;
1188
+ }
1189
+ /** What a layer shows, for {@link loadAppearanceUrls}. */
1190
+ declare function createShownUrls(): ShownUrls;
1191
+ /**
1192
+ * Load a page's pictures, every state of every item, and hand their URLs to
1193
+ * `onLoaded` once all of them are there; the set `shown` held before is
1194
+ * revoked then. {@link shownAppearance} picks an item's: a check box that
1195
+ * changes shows its other picture at once. What it returns cancels: the load
1196
+ * is aborted and the URLs it made are revoked, unless it already handed them
1197
+ * over. Start it again when the page's appearance epoch or the appearance
1198
+ * scale changes, never mid-gesture.
1199
+ */
1200
+ declare function loadAppearanceUrls<Ref>(shown: ShownUrls, load: (signal: AbortSignal) => Promise<readonly AppearancePicture<Ref>[]>, keyOf: (ref: Ref) => string, onLoaded: (urls: Record<string, AppearanceUrl>) => void): () => void;
1201
+ //#endregion
1202
+ //#region src/picture-or-painting.d.ts
1203
+ type PictureOrPainting<Painting> = {
1204
+ readonly kind: 'picture';
1205
+ readonly picture: AppearanceUrl;
1206
+ } | {
1207
+ readonly kind: 'painting';
1208
+ readonly painting: Painting;
1209
+ } | null;
1210
+ interface LookState<Painting> {
1211
+ /** The owner draws the item live now: a pending change, a widget's look not confirmed yet. */
1212
+ readonly pending: boolean;
1213
+ /** Its picture, for the state it shows; `null` when there is none. */
1214
+ readonly picture: AppearanceUrl | null;
1215
+ /** The item's picture version now. */
1216
+ readonly version: number;
1217
+ /** The page's pictures have loaded at least once. */
1218
+ readonly loaded: boolean;
1219
+ /** Its live drawing; `null` for an item that has none. */
1220
+ readonly paint: () => Painting | null;
1221
+ }
1222
+ declare function pictureOrPainting<Painting>(look: LookState<Painting>): PictureOrPainting<Painting>;
791
1223
  //#endregion
792
1224
  //#region src/web-font-metrics.d.ts
793
1225
  /**
@@ -848,5 +1280,2248 @@ declare function lineModelFor(cssFamily: string, measure?: (cssFamily: string) =
848
1280
  */
849
1281
  declare function firstLineShiftFor(cssFamily: string, fontSize: number, measure?: (cssFamily: string) => WebFontMetrics | null): number;
850
1282
  //#endregion
851
- export { type ActionsUiAdapterShape, type ActionsUiEffectContext, type ActionsUiOrigin, type AnchorTarget, type AnchoredPlacement, type AnchoredPoint, type AnchoredPosition, type AnchoredRect, type AttachSelectionHandleOptions, type ByteStore, type ClipboardSelectionSource, type DefaultActionsUiAdapterOptions, type EditorDocumentFactory, type EditorElement, type EditorNode, type EditorPosition, type EditorRoot, type EditorStyle, type IndexedDbByteStoreOptions, type LineModel, type ObjectUrlImageSource, type PaintedImageCallbacks, type PickFileOptions, type RichTextEditorAlign, type RichTextEditorBinding, type RichTextEditorCommand, type RichTextEditorDecoration, type RichTextEditorDocument, type RichTextEditorHost, type RichTextEditorParagraph, type RichTextEditorProps, type RichTextEditorRange, type RichTextEditorRun, type RichTextEditorScript, type RichTextEditorStyle, type SelectionClipboardOptions, type SelectionHandleSession, type StageGestureHost, type StageGestureOptions, type StageGestureSink, type StagePointerKind, type StageSurfaceHost, type StageSurfaceHub, type StageSurfaceOptions, type StageSurfaceSample, type StageWheelSample, type SvgCursorOptions, type ViewProjector, type WebFontMetrics, type WebPlatformFeedback, type WheelSample, applyFirstLineShift, attachRichTextEditor, attachSelectionHandle, bindPaintedImage, computeReleaseVelocity, copySelection, createDefaultActionsUiAdapter, createStageGestureController, createStageSurface, firstLineShiftFor, indexedDbByteStore, lineModelFor, mountWebFont, observeClientGeometry, offsetOfPosition, pickFile, pickImageFile, positionAnchoredRect, positionOfOffset, projectAnchoredTarget, renderRichText, sanitizeExternalUri, saveFile, serializeRichText, styleDeltaOf, svgCursor, vibrationFeedback, webFontMetrics, wheelZoomFactor, wireSelectionClipboard, wkFeedback };
1283
+ //#region src/theme.d.ts
1284
+ /**
1285
+ * The `--epdf-*` CSS variables that theme EmbedPDF, and the CSS value each
1286
+ * painted part uses. Every paint setting (a color, a line width, a dash, a
1287
+ * shadow, an opacity) can also come from a variable, and any variable wins over
1288
+ * any setting: a part looks for its own variable, then the variables of the
1289
+ * parts its default follows (another part, its plugin's accent, the viewer's
1290
+ * accent), and only then uses its setting's value. Parts you style yourself
1291
+ * have no setting, only a variable and a built-in look.
1292
+ *
1293
+ * {@link EPDF_VARIABLES} is plain data with no imports, so a script can read the
1294
+ * list without a browser. {@link epdfThemeVariables} turns a theme written with
1295
+ * setting names into the variables.
1296
+ */
1297
+ /**
1298
+ * A part other parts' defaults follow: an accent, or a part whose setting is
1299
+ * another part's default, such as the handles the rotation handle looks like.
1300
+ */
1301
+ type EpdfFollowedVariable = 'accent' | 'annotation-accent' | 'annotation-handle-fill' | 'annotation-handle-stroke';
1302
+ /** One themable part, named by its variable without the `--epdf-` prefix. */
1303
+ interface EpdfVariableDefinition {
1304
+ /**
1305
+ * The setting the variable overrides, as `<plugin>.<path>`: `viewer.` for the
1306
+ * viewer's own settings, `[]` for every entry of a list. Absent for a part you
1307
+ * style yourself, which only has CSS.
1308
+ */
1309
+ readonly setting?: string;
1310
+ /**
1311
+ * The part whose setting is this part's default, looked up right after the
1312
+ * part's own variable, and followed in turn: the rotation handle's stroke
1313
+ * follows the handles' stroke, which follows the annotation accent, which
1314
+ * follows the viewer's. So `--epdf-annotation-handle-stroke` reaches the
1315
+ * rotation handle before any accent does.
1316
+ */
1317
+ readonly follows?: EpdfFollowedVariable;
1318
+ /** A translucent default, the accent it follows at this percent: see {@link mixAccent}. */
1319
+ readonly accentPercent?: number;
1320
+ /**
1321
+ * The CSS value of each keyword, for a setting that takes keywords instead of
1322
+ * a CSS value.
1323
+ */
1324
+ readonly keywords?: Readonly<Record<string, string>>;
1325
+ /** What the part paints when neither its setting nor a variable is set. */
1326
+ readonly default: string;
1327
+ }
1328
+ /** Every theming variable, in the order the theming page lists them. */
1329
+ declare const EPDF_VARIABLES: {
1330
+ readonly accent: {
1331
+ readonly setting: "viewer.accent";
1332
+ readonly default: "#3858e9";
1333
+ };
1334
+ readonly 'page-background': {
1335
+ readonly setting: "viewer.page.background";
1336
+ readonly default: "#ffffff";
1337
+ };
1338
+ readonly 'page-shadow': {
1339
+ readonly setting: "viewer.page.shadow";
1340
+ readonly default: "0 6px 18px rgb(0 0 0 / 0.18)";
1341
+ };
1342
+ readonly 'annotation-accent': {
1343
+ readonly setting: "annotation.chrome.accent";
1344
+ readonly follows: "accent";
1345
+ readonly default: "#3858e9";
1346
+ };
1347
+ readonly 'annotation-outline': {
1348
+ readonly setting: "annotation.chrome.outline.color";
1349
+ readonly follows: "annotation-accent";
1350
+ readonly default: "#3858e9";
1351
+ };
1352
+ readonly 'annotation-outline-width': {
1353
+ readonly setting: "annotation.chrome.outline.width";
1354
+ readonly default: "1";
1355
+ };
1356
+ readonly 'annotation-outline-dash': {
1357
+ readonly setting: "annotation.chrome.outline.style";
1358
+ readonly keywords: {
1359
+ readonly solid: "none";
1360
+ readonly dashed: "4 3";
1361
+ };
1362
+ readonly default: "none";
1363
+ };
1364
+ readonly 'annotation-handle-fill': {
1365
+ readonly setting: "annotation.chrome.handles.fill";
1366
+ readonly default: "#ffffff";
1367
+ };
1368
+ readonly 'annotation-handle-stroke': {
1369
+ readonly setting: "annotation.chrome.handles.stroke";
1370
+ readonly follows: "annotation-accent";
1371
+ readonly default: "#3858e9";
1372
+ };
1373
+ readonly 'annotation-rotation-handle-fill': {
1374
+ readonly setting: "annotation.chrome.rotationHandle.fill";
1375
+ readonly follows: "annotation-handle-fill";
1376
+ readonly default: "#ffffff";
1377
+ };
1378
+ readonly 'annotation-rotation-handle-stroke': {
1379
+ readonly setting: "annotation.chrome.rotationHandle.stroke";
1380
+ readonly follows: "annotation-handle-stroke";
1381
+ readonly default: "#3858e9";
1382
+ };
1383
+ readonly 'annotation-guide': {
1384
+ readonly setting: "annotation.chrome.guides.color";
1385
+ readonly default: "#e91e63";
1386
+ };
1387
+ readonly 'annotation-rotation-guide': {
1388
+ readonly setting: "annotation.chrome.guides.rotationColor";
1389
+ readonly follows: "annotation-accent";
1390
+ readonly default: "#3858e9";
1391
+ };
1392
+ readonly 'annotation-guide-width': {
1393
+ readonly setting: "annotation.chrome.guides.width";
1394
+ readonly default: "1.5";
1395
+ };
1396
+ readonly 'annotation-guide-dash': {
1397
+ readonly setting: "annotation.chrome.guides.style";
1398
+ readonly keywords: {
1399
+ readonly solid: "none";
1400
+ readonly dashed: "4 3";
1401
+ };
1402
+ readonly default: "none";
1403
+ };
1404
+ readonly 'annotation-marquee-fill': {
1405
+ readonly setting: "annotation.chrome.marquee.fill";
1406
+ readonly follows: "annotation-accent";
1407
+ readonly accentPercent: 8;
1408
+ readonly default: "color-mix(in srgb, #3858e9 8%, transparent)";
1409
+ };
1410
+ readonly 'annotation-marquee-stroke': {
1411
+ readonly setting: "annotation.chrome.marquee.stroke";
1412
+ readonly follows: "annotation-accent";
1413
+ readonly default: "#3858e9";
1414
+ };
1415
+ readonly 'annotation-text-outline': {
1416
+ readonly setting: "annotation.chrome.textOutline";
1417
+ readonly follows: "annotation-accent";
1418
+ readonly default: "#3858e9";
1419
+ };
1420
+ readonly 'readout-background': {
1421
+ readonly setting: "annotation.chrome.readout.background";
1422
+ readonly default: "rgb(0 0 0 / 0.8)";
1423
+ };
1424
+ readonly 'readout-color': {
1425
+ readonly setting: "annotation.chrome.readout.color";
1426
+ readonly default: "#ffffff";
1427
+ };
1428
+ readonly 'ghost-opacity': {
1429
+ readonly setting: "annotation.tools[].ghost.opacity";
1430
+ readonly default: "0.5";
1431
+ };
1432
+ readonly 'text-selection': {
1433
+ readonly setting: "selection.color";
1434
+ readonly follows: "accent";
1435
+ readonly accentPercent: 35;
1436
+ readonly default: "color-mix(in srgb, #3858e9 35%, transparent)";
1437
+ };
1438
+ readonly 'text-selection-handle': {
1439
+ readonly setting: "selection.handles.color";
1440
+ readonly follows: "accent";
1441
+ readonly default: "#3858e9";
1442
+ };
1443
+ readonly 'text-selection-handle-shadow': {
1444
+ readonly setting: "selection.handles.shadow";
1445
+ readonly default: "0 1px 4px rgb(0 0 0 / 0.35)";
1446
+ };
1447
+ readonly 'search-highlight': {
1448
+ readonly setting: "search.highlight.color";
1449
+ readonly default: "#ffd500";
1450
+ };
1451
+ readonly 'search-highlight-active': {
1452
+ readonly setting: "search.highlight.activeColor";
1453
+ readonly default: "#ff9632";
1454
+ };
1455
+ readonly 'search-blend-mode': {
1456
+ readonly setting: "search.highlight.blendMode";
1457
+ readonly default: "multiply";
1458
+ };
1459
+ readonly 'form-focus': {
1460
+ readonly setting: "form.focus.color";
1461
+ readonly follows: "accent";
1462
+ readonly default: "#3858e9";
1463
+ };
1464
+ readonly 'form-field-border': {
1465
+ readonly setting: "form.fields.border";
1466
+ readonly follows: "accent";
1467
+ readonly accentPercent: 55;
1468
+ readonly default: "color-mix(in srgb, #3858e9 55%, transparent)";
1469
+ };
1470
+ readonly 'form-field-background': {
1471
+ readonly setting: "form.fields.background";
1472
+ readonly default: "rgb(255 255 255 / 0.92)";
1473
+ };
1474
+ readonly 'form-field-color': {
1475
+ readonly setting: "form.fields.color";
1476
+ readonly default: "#1f2a44";
1477
+ };
1478
+ readonly 'scrollbar-thumb': {
1479
+ readonly default: "rgb(0 0 0 / 0.4)";
1480
+ };
1481
+ readonly 'toolbar-surface': {
1482
+ readonly default: "#ffffff";
1483
+ };
1484
+ readonly 'toolbar-border': {
1485
+ readonly default: "rgb(0 0 0 / 0.15)";
1486
+ };
1487
+ readonly 'toolbar-active': {
1488
+ readonly default: "rgb(0 0 0 / 0.12)";
1489
+ };
1490
+ readonly 'font-mono': {
1491
+ readonly default: "ui-monospace, monospace";
1492
+ };
1493
+ };
1494
+ type Definitions = typeof EPDF_VARIABLES;
1495
+ /** A theming variable's name, without its `--epdf-` prefix. */
1496
+ type EpdfVariable = keyof Definitions;
1497
+ /** A variable that overrides a setting: its part paints with {@link paint}. */
1498
+ type EpdfSettingVariable = { [Name in EpdfVariable]: Definitions[Name] extends {
1499
+ readonly setting: string;
1500
+ } ? Name : never; }[EpdfVariable];
1501
+ /** A part you style yourself, which has no setting: it paints with {@link paintDefault}. */
1502
+ type EpdfCssOnlyVariable = Exclude<EpdfVariable, EpdfSettingVariable>;
1503
+ /** A part whose default is the accent at a percent: that default comes from {@link mixAccent}. */
1504
+ type EpdfTranslucentVariable = { [Name in EpdfVariable]: Definitions[Name] extends {
1505
+ readonly accentPercent: number;
1506
+ } ? Name : never; }[EpdfVariable];
1507
+ /**
1508
+ * The CSS value for a painted part: its own variable, then the variables of the
1509
+ * parts its default follows (the part it follows, its plugin's accent,
1510
+ * `--epdf-accent`), then the setting's value. Put it in a style (`style.stroke`),
1511
+ * not an SVG attribute, because attributes don't read `var()`.
1512
+ *
1513
+ * `paint('annotation-outline', '#3858e9')` is
1514
+ * `var(--epdf-annotation-outline, var(--epdf-annotation-accent, var(--epdf-accent, #3858e9)))`,
1515
+ * `paint('annotation-rotation-handle-fill', '#ffffff')` is
1516
+ * `var(--epdf-annotation-rotation-handle-fill, var(--epdf-annotation-handle-fill, #ffffff))`,
1517
+ * and `paint('search-highlight', '#ffd500')` is `var(--epdf-search-highlight, #ffd500)`.
1518
+ */
1519
+ declare function paint(name: EpdfSettingVariable, settingValue: string | number): string;
1520
+ /**
1521
+ * The default of a translucent part, such as "the accent at 35%": the accent it
1522
+ * follows, variables included, mixed with transparent. Use it as the setting's
1523
+ * value while the part's own setting is unset.
1524
+ *
1525
+ * The accent variables sit inside the mix, not in {@link paint}'s lookup: there
1526
+ * a set `--epdf-accent` would paint at full strength, and CSS can't mix a
1527
+ * variable only when it's set. So a part's own setting, when you give one, wins
1528
+ * over the accent variables, though not over the part's own variable.
1529
+ *
1530
+ * `mixAccent('text-selection', '#3858e9')` is
1531
+ * `color-mix(in srgb, var(--epdf-accent, #3858e9) 35%, transparent)`.
1532
+ */
1533
+ declare function mixAccent(name: EpdfTranslucentVariable, accentValue: string): string;
1534
+ /**
1535
+ * The CSS value for a part you style yourself, which has no setting: its
1536
+ * variable, then its built-in look.
1537
+ *
1538
+ * `paintDefault('scrollbar-thumb')` is `var(--epdf-scrollbar-thumb, rgb(0 0 0 / 0.4))`.
1539
+ */
1540
+ declare function paintDefault(name: EpdfCssOnlyVariable): string;
1541
+ /** A setting's path as a theme writes it: the viewer's own at the top, a list's entries as one. */
1542
+ type ThemePath<Setting extends string> = Setting extends `viewer.${infer Rest}` ? Rest : Setting extends `${infer Head}[]${infer Tail}` ? `${Head}${Tail}` : Setting;
1543
+ /** What a part takes: one of its keywords, or a CSS value. */
1544
+ type ThemeValue<Name extends EpdfSettingVariable> = Definitions[Name] extends {
1545
+ readonly keywords: infer Keywords;
1546
+ } ? keyof Keywords & string : string | number;
1547
+ /** One setting as a nested object: `'page.shadow'` is `{ page?: { shadow?: … } }`. */
1548
+ type ThemeBranch<Path extends string, Value> = Path extends `${infer Head}.${infer Rest}` ? { readonly [Key in Head]?: ThemeBranch<Rest, Value>; } : { readonly [Key in Path]?: Value; };
1549
+ type Intersection<Union> = (Union extends unknown ? (value: Union) => void : never) extends ((value: infer Both) => void) ? Both : never;
1550
+ /**
1551
+ * A theme by setting names, every part optional: `{ accent: '#e91e63', search: { highlight:
1552
+ * { color: '#7dd3fc' } } }`. The viewer's own settings sit at the top; each plugin's under its
1553
+ * name, as the theming page lists them.
1554
+ */
1555
+ type EpdfTheme = Intersection<{ [Name in EpdfSettingVariable]: ThemeBranch<ThemePath<Definitions[Name]['setting']>, ThemeValue<Name>>; }[EpdfSettingVariable]>;
1556
+ /** The CSS variables of a theme, by their full name: `{ '--epdf-accent': '#e91e63' }`. */
1557
+ type EpdfThemeVariables = Readonly<Record<`--epdf-${EpdfVariable}`, string>>;
1558
+ /**
1559
+ * The CSS variables that set a theme, for a style on an element around the viewer: CSS variables
1560
+ * win over settings, and reach everything inside the element. A part left out keeps its own
1561
+ * look, so the parts that follow the accent follow a new `accent`.
1562
+ *
1563
+ * `epdfThemeVariables({ accent: '#e91e63', page: { shadow: 'none' } })` is
1564
+ * `{ '--epdf-accent': '#e91e63', '--epdf-page-shadow': 'none' }`.
1565
+ */
1566
+ declare function epdfThemeVariables(theme: EpdfTheme): Partial<EpdfThemeVariables>;
1567
+ //#endregion
1568
+ //#region src/page-pixels.d.ts
1569
+ /**
1570
+ * Page-space shapes in a page layer's pixels. Every layer over a page (the
1571
+ * annotation, form, link, selection and search layers) gets boxes and quads
1572
+ * in page points and places its elements in the page layer's own pixels,
1573
+ * always through the page's `toPixels`: never by multiplying with a scale of
1574
+ * its own. Plain geometry over structural shapes, the same for every
1575
+ * framework adapter.
1576
+ */
1577
+ /** A point in page points or in pixels. */
1578
+ interface PagePoint {
1579
+ x: number;
1580
+ y: number;
1581
+ }
1582
+ /** What a page layer converts with: its transform's `toPixels`. */
1583
+ interface PageToPixels {
1584
+ toPixels(point: PagePoint): PagePoint;
1585
+ }
1586
+ /** A box in a page layer's pixels, the shape a positioned element takes. */
1587
+ interface PixelRect {
1588
+ left: number;
1589
+ top: number;
1590
+ width: number;
1591
+ height: number;
1592
+ }
1593
+ /** A quad's four corners, as the engine names them. */
1594
+ interface PageQuad {
1595
+ upperLeft: PagePoint;
1596
+ upperRight: PagePoint;
1597
+ lowerRight: PagePoint;
1598
+ lowerLeft: PagePoint;
1599
+ }
1600
+ /** A box in page points as a box in the page layer's pixels. */
1601
+ declare function rectInPixels(rect: {
1602
+ x: number;
1603
+ y: number;
1604
+ width: number;
1605
+ height: number;
1606
+ }, page: PageToPixels): PixelRect;
1607
+ /**
1608
+ * A quad's corners in the page layer's pixels, in drawing order (upper left,
1609
+ * upper right, lower right, lower left). The map is affine, so mapping the
1610
+ * corners is exact, for turned text too.
1611
+ */
1612
+ declare function quadInPixels(quad: PageQuad, page: PageToPixels): PagePoint[];
1613
+ /** Points as an SVG `points` attribute: `"x,y x,y …"`. */
1614
+ declare function svgPoints(points: readonly PagePoint[]): string;
1615
+ /** Whether a quad is an upright box: drawn as a positioned box instead of a polygon. */
1616
+ declare function isUprightQuad(quad: PageQuad): boolean;
1617
+ //#endregion
1618
+ //#region src/event-isolation.d.ts
1619
+ /**
1620
+ * Keeping a page's own listeners out of controls drawn over it. The Stage
1621
+ * listens natively on an ancestor of every page: a press that bubbles to it
1622
+ * starts a tool gesture or reads as a click outside (ending an edit), and a
1623
+ * wheel pans or zooms the page. A control that owns its gestures stops them
1624
+ * with a native listener on itself, which runs during real DOM bubbling,
1625
+ * before the Stage's. A framework's own event system may run too late: React
1626
+ * dispatches from its root, above the Stage.
1627
+ */
1628
+ /**
1629
+ * Stop presses that begin inside `element` from reaching the page, and tell `onPress` about each
1630
+ * one. A control that needs the press itself (a link or a form field sending its PDF "mouse down"
1631
+ * action) must take it here: once the press stops at the element, a framework that dispatches
1632
+ * from its root (React) never sees it. Returns the detach.
1633
+ */
1634
+ declare function isolatePointerDown(element: HTMLElement, onPress?: (event: PointerEvent) => void): () => void;
1635
+ /**
1636
+ * Stop wheel events inside `element` from reaching the page, so the browser
1637
+ * scrolls the element itself (a list box) instead of the Stage panning or
1638
+ * zooming. Returns the detach.
1639
+ */
1640
+ declare function isolateWheel(element: HTMLElement): () => void;
1641
+ //#endregion
1642
+ //#region src/outside-press.d.ts
1643
+ /**
1644
+ * Call `onPress` when a pointer press starts anywhere in `element`'s document
1645
+ * outside `element`: how a menu closes when the user presses somewhere else,
1646
+ * in the viewer or on the page around it. Where the press landed is read from
1647
+ * its composed path: at the document, an event from inside a shadow root is
1648
+ * retargeted to the shadow host, so `element.contains(event.target)` would
1649
+ * call every press inside a shadow-rooted menu an outside one. Listens in the
1650
+ * capture phase, so a handler that stops the press can't keep a menu open.
1651
+ * Returns the stop.
1652
+ */
1653
+ declare function observeOutsidePress(element: Element, onPress: (event: PointerEvent) => void): () => void;
1654
+ //#endregion
1655
+ //#region src/anchor-equality.d.ts
1656
+ /**
1657
+ * Equality for the anchors plugins hand out. An anchor read (where a menu, a
1658
+ * badge or a selection handle attaches) returns a new object every time; a
1659
+ * framework adapter compares reads with these, so the UI attached to an
1660
+ * anchor renders again only when the anchor moved. The anchors are mirrored
1661
+ * structurally, so this package stays free of EmbedPDF imports.
1662
+ */
1663
+ interface AnchorPoint {
1664
+ readonly x: number;
1665
+ readonly y: number;
1666
+ }
1667
+ interface AnchorBox {
1668
+ readonly x: number;
1669
+ readonly y: number;
1670
+ readonly width: number;
1671
+ readonly height: number;
1672
+ }
1673
+ interface AnchorPage {
1674
+ readonly objectNumber: number;
1675
+ }
1676
+ /** A box on a page: a text selection's anchor, and the core of every other one. */
1677
+ interface PageBoundsAnchor {
1678
+ readonly page: AnchorPage;
1679
+ readonly bounds: AnchorBox;
1680
+ }
1681
+ /** The same page and box (a text selection's menu anchor). */
1682
+ declare function samePageBounds(left: PageBoundsAnchor | null, right: PageBoundsAnchor | null): boolean;
1683
+ /** The annotation selection's anchor: its page, its box, and its rotation handle when it has one. */
1684
+ interface SelectionAnchorShape extends PageBoundsAnchor {
1685
+ readonly rotationHandle?: AnchorPoint | null;
1686
+ }
1687
+ /** The same annotation selection anchor: page, box and rotation handle. */
1688
+ declare function sameSelectionAnchor(left: SelectionAnchorShape | null, right: SelectionAnchorShape | null): boolean;
1689
+ /** One annotation's anchor: page, box, and the view-dependent box of one that keeps its size on screen. */
1690
+ interface AnnotationAnchorShape extends PageBoundsAnchor {
1691
+ readonly boundsIn?: unknown;
1692
+ }
1693
+ /** The same annotation anchor: page, box, and how it follows the view. */
1694
+ declare function sameAnnotationAnchor(left: AnnotationAnchorShape | null, right: AnnotationAnchorShape | null): boolean;
1695
+ /** A shape being drawn click by click (a polygon): where it is and how far it got. */
1696
+ interface CreationDraftAnchorShape extends PageBoundsAnchor {
1697
+ readonly kind: string;
1698
+ readonly subtype: string;
1699
+ readonly pointCount: number;
1700
+ readonly minPoints: number;
1701
+ readonly canFinish: boolean;
1702
+ }
1703
+ /** The same creation draft: what it draws, its points so far, whether it can finish, and its box. */
1704
+ declare function sameCreationDraftAnchor(left: CreationDraftAnchorShape | null, right: CreationDraftAnchorShape | null): boolean;
1705
+ /** A turn in progress: the pointer's page point and the angle. */
1706
+ interface RotationAnchorShape {
1707
+ readonly page: AnchorPage;
1708
+ readonly at: AnchorPoint;
1709
+ readonly angle: number;
1710
+ }
1711
+ /** The same turn in progress: page, pointer and angle. */
1712
+ declare function sameRotationAnchor(left: RotationAnchorShape | null, right: RotationAnchorShape | null): boolean;
1713
+ interface AnchorQuad {
1714
+ readonly upperLeft: AnchorPoint;
1715
+ readonly upperRight: AnchorPoint;
1716
+ readonly lowerLeft: AnchorPoint;
1717
+ readonly lowerRight: AnchorPoint;
1718
+ }
1719
+ /** One end of a text selection: its page, the boundary glyph's quad, and the side of the glyph. */
1720
+ interface SelectionEndpointShape {
1721
+ readonly page: AnchorPage;
1722
+ readonly glyphQuad: AnchorQuad;
1723
+ readonly advance: unknown;
1724
+ }
1725
+ /** Both ends of a text selection, where its handles sit. */
1726
+ interface SelectionEndpointsShape {
1727
+ readonly start: SelectionEndpointShape;
1728
+ readonly end: SelectionEndpointShape;
1729
+ }
1730
+ /**
1731
+ * The same selection ends. The glyph quads compare corner by corner, so an
1732
+ * end that turns without moving its bounding box still counts as moved.
1733
+ */
1734
+ declare function sameSelectionEndpoints(left: SelectionEndpointsShape | null, right: SelectionEndpointsShape | null): boolean;
1735
+ //#endregion
1736
+ //#region src/annotation-scene.d.ts
1737
+ /** How a scene node paints: the structural twin of core-annotation's `Paint`. */
1738
+ interface ScenePaint {
1739
+ fill?: string;
1740
+ stroke?: string;
1741
+ /** Stroke width, in page points. */
1742
+ width?: number;
1743
+ opacity?: number;
1744
+ /** Stroke dash, in page points. */
1745
+ dash?: number[];
1746
+ blend?: string;
1747
+ lineCap?: 'round';
1748
+ join?: 'round';
1749
+ fillRule?: 'evenodd';
1750
+ }
1751
+ interface SceneBox {
1752
+ x: number;
1753
+ y: number;
1754
+ width: number;
1755
+ height: number;
1756
+ }
1757
+ interface ScenePoint {
1758
+ x: number;
1759
+ y: number;
1760
+ }
1761
+ /** One painted node: the structural twin of core-annotation's `SceneNode`. */
1762
+ type SceneShapeNode = ({
1763
+ kind: 'rect';
1764
+ rect: SceneBox;
1765
+ paint: ScenePaint;
1766
+ } | {
1767
+ kind: 'ellipse';
1768
+ rect: SceneBox;
1769
+ paint: ScenePaint;
1770
+ } | {
1771
+ kind: 'line';
1772
+ a: ScenePoint;
1773
+ b: ScenePoint;
1774
+ paint: ScenePaint;
1775
+ } | {
1776
+ kind: 'poly';
1777
+ points: ScenePoint[];
1778
+ closed: boolean;
1779
+ paint: ScenePaint;
1780
+ } | {
1781
+ kind: 'path';
1782
+ d: string;
1783
+ paint: ScenePaint;
1784
+ } | {
1785
+ kind: 'text';
1786
+ at: ScenePoint;
1787
+ text: string;
1788
+ fontSize: number;
1789
+ fontFamily?: string;
1790
+ rotation?: number;
1791
+ paint: ScenePaint;
1792
+ } | {
1793
+ kind: 'glyphs';
1794
+ at: ScenePoint;
1795
+ text: string;
1796
+ offsets: number[];
1797
+ fontSize: number;
1798
+ fontFamily: string;
1799
+ fontWeight?: number;
1800
+ fontStyle?: 'normal' | 'italic';
1801
+ rotation?: number;
1802
+ /** The face it draws in: whatever draws it mounts it. */
1803
+ program?: MountableFontProgram;
1804
+ paint: ScenePaint;
1805
+ }) & {
1806
+ /** Drawn only inside this upright box. */
1807
+ clip?: SceneBox;
1808
+ };
1809
+ /** The SVG elements a scene draws with; a nested `svg` clips what's inside it to its box. */
1810
+ type SvgShapeTag = 'rect' | 'ellipse' | 'line' | 'path' | 'text' | 'polygon' | 'polyline' | 'svg';
1811
+ /**
1812
+ * One SVG element: its tag, its attributes under their SVG names
1813
+ * (`stroke-width`, `fill-rule`; an attribute left out is not set), the text
1814
+ * inside it, and its blend mode, which is CSS (`mix-blend-mode` in its
1815
+ * `style`), never an attribute.
1816
+ */
1817
+ interface SvgShape {
1818
+ tag: SvgShapeTag;
1819
+ attributes: Readonly<Record<string, string | number>>;
1820
+ text?: string;
1821
+ blend?: string;
1822
+ /** What a clipping `svg` holds, in drawing order. */
1823
+ children?: SvgShape[];
1824
+ /** The face a `text` draws in: the renderer mounts it (`fontProgramsOf`). */
1825
+ program?: MountableFontProgram;
1826
+ }
1827
+ /** The faces shapes draw their text in, each once: a renderer mounts them while it shows the shapes. */
1828
+ declare function fontProgramsOf(shapes: readonly SvgShape[]): MountableFontProgram[];
1829
+ interface SvgShapesOptions {
1830
+ /**
1831
+ * The stroke miter limit, core-annotation's `MITER_LIMIT`: it must be the
1832
+ * one the core's bounds math uses, so a sharp corner spikes or bevels the
1833
+ * same way in both.
1834
+ */
1835
+ miterLimit: number;
1836
+ }
1837
+ /**
1838
+ * Each scene node as one SVG element, in drawing order, in the scene's own
1839
+ * page-point units. A clipped node comes inside an `svg` of its clip box,
1840
+ * which shows only what's inside it (no ids, so every framework draws it the
1841
+ * same).
1842
+ */
1843
+ declare function svgShapesOf(nodes: readonly SceneShapeNode[], options: SvgShapesOptions): SvgShape[];
1844
+ /**
1845
+ * The `viewBox` an item's scene draws in: its box, in page points. `null`
1846
+ * while the box has no area (a drawing at its first press): draw nothing then.
1847
+ *
1848
+ * The `<svg>` fills the item's frame, so the viewBox and the element's size
1849
+ * stay proportional (their ratio is the zoom). Never clamp either one: a
1850
+ * clamped element with a shrinking viewBox scales its content up, and a
1851
+ * cloudy border's scallops flood the page.
1852
+ */
1853
+ declare function sceneViewBox(box: SceneBox): string | null;
1854
+ /** How opaque a tool's ghost paints: `--epdf-ghost-opacity` wins over the tool's own. */
1855
+ declare function ghostOpacity(opacity: number): string;
1856
+ //#endregion
1857
+ //#region src/annotation-chrome.d.ts
1858
+ /** The chrome settings the paint reads: the structural twin of the annotation plugin's `ChromeSettings`. */
1859
+ interface ChromePaintSettings {
1860
+ readonly accent: string | null;
1861
+ readonly outline: {
1862
+ readonly color: string | null;
1863
+ readonly style: string;
1864
+ readonly width: number;
1865
+ };
1866
+ readonly handles: {
1867
+ readonly fill: string;
1868
+ readonly stroke: string | null;
1869
+ };
1870
+ readonly rotationHandle: {
1871
+ readonly fill: string | null;
1872
+ readonly stroke: string | null;
1873
+ };
1874
+ readonly guides: {
1875
+ readonly color: string;
1876
+ readonly rotationColor: string | null;
1877
+ readonly style: string;
1878
+ readonly width: number;
1879
+ };
1880
+ readonly marquee: {
1881
+ readonly fill: string | null;
1882
+ readonly stroke: string | null;
1883
+ };
1884
+ readonly textOutline: string | null;
1885
+ }
1886
+ /** A line's paint as CSS: its color, width and dash. */
1887
+ interface ChromeLinePaint {
1888
+ readonly stroke: string;
1889
+ readonly strokeWidth: string;
1890
+ readonly strokeDasharray: string;
1891
+ }
1892
+ /** A shape's paint as CSS: its fill and its stroke color. */
1893
+ interface ChromeShapePaint {
1894
+ readonly fill: string;
1895
+ readonly stroke: string;
1896
+ }
1897
+ /**
1898
+ * Every chrome color, width and dash as CSS, each its `--epdf-annotation-*`
1899
+ * variable first, then the setting. Put them in `style`: an SVG attribute
1900
+ * doesn't read `var()`.
1901
+ */
1902
+ interface AnnotationChromePaint {
1903
+ /** The selection box. */
1904
+ readonly outline: ChromeLinePaint;
1905
+ /** The resize and point handles. */
1906
+ readonly handle: ChromeShapePaint;
1907
+ /** The rotation handle; its stalk takes the `stroke`. */
1908
+ readonly rotationHandle: ChromeShapePaint;
1909
+ /** A snapped move's alignment guide. */
1910
+ readonly guide: ChromeLinePaint;
1911
+ /** The reference cross and the angle line while turning. */
1912
+ readonly rotationGuide: ChromeLinePaint;
1913
+ /** The box dragged to select. */
1914
+ readonly marquee: ChromeShapePaint;
1915
+ /** The outline color of a text box while someone types in it. */
1916
+ readonly textOutline: string;
1917
+ }
1918
+ /**
1919
+ * The chrome settings as paint. A color left `null` follows the part it
1920
+ * names, and in the end the accent: the chrome's own, else the viewer's.
1921
+ */
1922
+ declare function annotationChromePaint(chrome: ChromePaintSettings, viewerAccent: string): AnnotationChromePaint;
1923
+ /**
1924
+ * One chrome node as the annotation plugin lists it: the structural twin of
1925
+ * core-annotation's `ChromeNode`. `Role` is what a handle reshapes.
1926
+ */
1927
+ type ChromeNodeShape<Role extends string = string> = {
1928
+ kind: 'outline';
1929
+ rect: {
1930
+ x: number;
1931
+ y: number;
1932
+ width: number;
1933
+ height: number;
1934
+ };
1935
+ } | {
1936
+ kind: 'obb';
1937
+ corners: readonly PagePoint[];
1938
+ } | {
1939
+ kind: 'handle';
1940
+ at: PagePoint;
1941
+ rot?: number;
1942
+ role: Role;
1943
+ active: boolean;
1944
+ } | {
1945
+ kind: 'rotate-knob';
1946
+ at: PagePoint;
1947
+ from: PagePoint;
1948
+ } | {
1949
+ kind: 'guide';
1950
+ axis: 'x' | 'y';
1951
+ at: number;
1952
+ lo: number;
1953
+ hi: number;
1954
+ } | {
1955
+ kind: 'rotate-guides';
1956
+ lines: ReadonlyArray<{
1957
+ a: PagePoint;
1958
+ b: PagePoint;
1959
+ role: 'axis' | 'indicator';
1960
+ }>;
1961
+ } | {
1962
+ kind: 'marquee';
1963
+ rect: {
1964
+ x: number;
1965
+ y: number;
1966
+ width: number;
1967
+ height: number;
1968
+ };
1969
+ };
1970
+ /** A line in pixels. */
1971
+ interface ChromeLine {
1972
+ from: PagePoint;
1973
+ to: PagePoint;
1974
+ }
1975
+ /**
1976
+ * A chrome node in the page layer's pixels. What each one draws:
1977
+ * - `outline`, `marquee`: a rectangle, `box` (the marquee is always dashed `4 3`);
1978
+ * - `turned-outline`: a closed polygon through `points`, the outline of a turned selection;
1979
+ * - `handle`: a handle centred on `at`, turned by `rotation` (degrees clockwise) when square;
1980
+ * - `rotation-handle`: a round handle at `at`, its stalk from `from` on the box;
1981
+ * - `guide`: a crisp line, a snapped move's alignment;
1982
+ * - `rotation-guides`: the lines of a turn in progress, each at its `opacity`.
1983
+ */
1984
+ type ChromeInPixels<Role extends string = string> = {
1985
+ kind: 'outline';
1986
+ box: PixelRect;
1987
+ } | {
1988
+ kind: 'marquee';
1989
+ box: PixelRect;
1990
+ } | {
1991
+ kind: 'turned-outline';
1992
+ points: string;
1993
+ } | {
1994
+ kind: 'handle';
1995
+ at: PagePoint;
1996
+ rotation: number;
1997
+ role: Role;
1998
+ active: boolean;
1999
+ } | {
2000
+ kind: 'rotation-handle';
2001
+ at: PagePoint;
2002
+ from: PagePoint;
2003
+ } | ({
2004
+ kind: 'guide';
2005
+ } & ChromeLine) | {
2006
+ kind: 'rotation-guides';
2007
+ lines: Array<ChromeLine & {
2008
+ opacity: number;
2009
+ }>;
2010
+ };
2011
+ /**
2012
+ * Each chrome node in the page layer's pixels, in drawing order. The plugin
2013
+ * already sized the screen-constant parts (handle grab zones, the rotation
2014
+ * handle's offset) for the page's zoom; this only places them.
2015
+ */
2016
+ declare function chromeInPixels<Role extends string>(nodes: readonly ChromeNodeShape<Role>[], page: PageToPixels): ChromeInPixels<Role>[];
2017
+ //#endregion
2018
+ //#region src/text-box-editor.d.ts
2019
+ /** A text box as the annotation plugin lists it (`listTextItems`): the fields the editor reads. */
2020
+ interface TextBoxEditorItem<Ref> {
2021
+ readonly id: string;
2022
+ /** `null` for a box that isn't written yet: nothing to route typing to. */
2023
+ readonly ref: Ref | null;
2024
+ readonly richText: RichTextEditorDocument;
2025
+ /** True while someone types in this box. */
2026
+ readonly editing: boolean;
2027
+ }
2028
+ /** The annotation plugin's text-editing calls (its host capability satisfies it). */
2029
+ interface TextBoxEditorAnnotation<Ref> {
2030
+ draftRichText(ref: Ref, document: RichTextEditorDocument): void;
2031
+ setTextSelection(ref: Ref, range: RichTextEditorRange | null): void;
2032
+ readonly text: {
2033
+ toggleFormat(format: RichTextEditorCommand): unknown;
2034
+ };
2035
+ getCssFontFamily(family: string): string;
2036
+ getEditingId(): string | null;
2037
+ }
2038
+ /** An element made a text box's editor. */
2039
+ interface TextBoxEditor<Ref> {
2040
+ /**
2041
+ * The box as the plugin has it now, at `scale` pixels per point (or `null`
2042
+ * while there is none). Call it whenever either changes: the binding
2043
+ * redraws only when the text differs (so the caret never jumps while
2044
+ * typing), and focus follows `editing`.
2045
+ */
2046
+ update(item: TextBoxEditorItem<Ref> | null, scale: number): void;
2047
+ /** Remove the listeners and the rich-text binding. */
2048
+ detach(): void;
2049
+ }
2050
+ /**
2051
+ * Make `element` the editor of a text box. Typing shows at once and reaches
2052
+ * the engine in one write after a pause (or when the edit ends), not one
2053
+ * write per keystroke.
2054
+ */
2055
+ declare function attachTextBoxEditor<Ref>(element: HTMLElement, annotation: TextBoxEditorAnnotation<Ref>): TextBoxEditor<Ref>;
2056
+ /** Keeps an element the editor of a text box while what it edits with changes. */
2057
+ interface TextBoxEditorFollower<Ref> {
2058
+ /**
2059
+ * The element, the plugin, the box and the scale as they are now. Call it
2060
+ * whenever any of them changes: the editor attaches when there are an
2061
+ * element and a plugin, attaches again when either is another one (a
2062
+ * document that opens anew), and gets the box and the scale every time.
2063
+ */
2064
+ follow(element: HTMLElement | null, annotation: TextBoxEditorAnnotation<Ref> | null, item: TextBoxEditorItem<Ref> | null, scale: number): void;
2065
+ /** Let go of the element, when the component that drew it goes away. */
2066
+ detach(): void;
2067
+ }
2068
+ /**
2069
+ * A text box editor that follows its inputs: what each framework's binding
2070
+ * holds between renders. The update runs right after an attach, in the same
2071
+ * call, so the element never shows an editor without its text.
2072
+ */
2073
+ declare function createTextBoxEditorFollower<Ref>(): TextBoxEditorFollower<Ref>;
2074
+ /**
2075
+ * Pixels per point for an editor element you draw yourself (a renderer's own
2076
+ * text box): the box's width on the page over its width in points, or the
2077
+ * page's view scale while there is no box. Inside a look the layer scales
2078
+ * (`lookScale`, 1 outside one), the element draws at the annotation's 100%
2079
+ * size and the look's scale does the rest.
2080
+ */
2081
+ declare function textBoxEditorScaleOf(item: {
2082
+ box: {
2083
+ x: number;
2084
+ y: number;
2085
+ width: number;
2086
+ height: number;
2087
+ };
2088
+ } | null, page: PageToPixels & {
2089
+ viewScale: number;
2090
+ }, lookScale: number): number;
2091
+ /** A free text body's look, as the plugin hands it (`TextItem.css`). */
2092
+ interface TextBoxCss {
2093
+ fontFamily: string;
2094
+ /** In page points. */
2095
+ fontSize: number;
2096
+ color: string;
2097
+ fontWeight: number;
2098
+ fontStyle: string;
2099
+ textDecoration: string;
2100
+ align: 'left' | 'center' | 'right';
2101
+ /** The plate's inset from the box, in page points. */
2102
+ padding: number;
2103
+ }
2104
+ /** A text box's body style as CSS: put it on the editor element. */
2105
+ interface TextBoxStyle {
2106
+ fontFamily: string;
2107
+ /** In pixels, with its unit. */
2108
+ fontSize: string;
2109
+ color: string;
2110
+ fontWeight: number;
2111
+ fontStyle: string;
2112
+ textDecoration: string;
2113
+ textAlign: 'left' | 'center' | 'right';
2114
+ }
2115
+ /**
2116
+ * A text box's body style at `scale` pixels per point: font, size, color and
2117
+ * alignment. No line height: the editor binding states the engine's line
2118
+ * model per face on the element itself.
2119
+ */
2120
+ declare function textBoxStyleOf(css: TextBoxCss, scale: number): TextBoxStyle;
2121
+ /** Where a free text's editor element goes, and the scale it draws at. */
2122
+ interface TextPlatePixels {
2123
+ left: number;
2124
+ top: number;
2125
+ width: number;
2126
+ height: number;
2127
+ /** Pixels per page point. */
2128
+ scale: number;
2129
+ }
2130
+ /**
2131
+ * The editor element of a free text box in the page layer's pixels: the
2132
+ * engine's text plate (`SetPlateRect` and its `re W n` clip), the box inset
2133
+ * by its padding. Place it there with no CSS padding, so its edge is the
2134
+ * plate's: CSS padding doesn't clip overflow, and scrolled lines would paint
2135
+ * over the border band. The box never grows with its text.
2136
+ */
2137
+ declare function textPlateInPixels(item: {
2138
+ box: {
2139
+ x: number;
2140
+ y: number;
2141
+ width: number;
2142
+ height: number;
2143
+ };
2144
+ css: {
2145
+ padding: number;
2146
+ };
2147
+ }, page: PageToPixels): TextPlatePixels;
2148
+ //#endregion
2149
+ //#region src/annotation-renderers.d.ts
2150
+ /**
2151
+ * The annotation layer's renderers: which drawing each annotation gets, and
2152
+ * the behaviors that `interactive` renderers register. A renderer is a rule
2153
+ * ("draw these annotations with this component"); a framework adapter keeps
2154
+ * the component, and these decide everything around it, the same for every
2155
+ * framework:
2156
+ *
2157
+ * - {@link registerRendererBehaviors}: an `interactive` renderer takes the
2158
+ * pointer through a behavior the annotation plugin knows, registered once
2159
+ * per capability and renderer entry however many pages mount the layer.
2160
+ * - {@link annotationDrawingOf}: per annotation, the layer's own drawing, a
2161
+ * look of yours, or a sibling plugin's control (ownership beats looks).
2162
+ * - {@link editingTextKeyOf} and {@link layerTextBoxesOf}: which text box is
2163
+ * typed in, and which text boxes the layer draws rather than a look.
2164
+ *
2165
+ * The plugin's types are mirrored structurally, so this package stays free of
2166
+ * EmbedPDF imports.
2167
+ */
2168
+ /** A sibling plugin's renderer: it draws what the behavior `behavior` owns (the form plugin's controls). */
2169
+ interface BehaviorRendererEntry {
2170
+ behavior: string;
2171
+ }
2172
+ /** What an `interactive` function is asked: the annotation, and the active tool. */
2173
+ interface RendererInteractiveContext<Annotation> {
2174
+ annotation: Annotation;
2175
+ toolId: string;
2176
+ }
2177
+ /** A look of yours: draws the annotations `for` matches. */
2178
+ interface LookRendererEntry<Annotation> {
2179
+ /** A stable id for the registration (optional; generated). */
2180
+ id?: string;
2181
+ for(annotation: Annotation): boolean;
2182
+ /** Takes the pointer: always, or when the function says so (asked whenever it matters). */
2183
+ interactive?: boolean | ((context: RendererInteractiveContext<Annotation>) => boolean);
2184
+ }
2185
+ type RendererEntry<Annotation> = BehaviorRendererEntry | LookRendererEntry<Annotation>;
2186
+ /** The annotation plugin's behavior registry (its host capability satisfies it). */
2187
+ interface RendererBehaviorRegistry<Annotation> {
2188
+ registerBehavior(behavior: {
2189
+ id: string;
2190
+ matches(annotation: Annotation): boolean;
2191
+ engaged(annotation: Annotation): boolean;
2192
+ }): () => void;
2193
+ getBehaviorFor(annotation: Annotation): {
2194
+ id: string;
2195
+ } | null;
2196
+ }
2197
+ /**
2198
+ * Register a behavior for each `interactive` look in `renderers`, so the
2199
+ * plugin lets that renderer take the pointer. Call it when a layer mounts (and
2200
+ * again when its renderer list changes); call what it returns when it
2201
+ * unmounts. `activeToolId` is read whenever an `interactive` function is asked.
2202
+ */
2203
+ declare function registerRendererBehaviors<Annotation>(annotation: RendererBehaviorRegistry<Annotation>, renderers: readonly RendererEntry<Annotation>[], activeToolId: () => string): () => void;
2204
+ /** The behavior id a renderer entry answers for: a sibling plugin's own, or the one registered for it. */
2205
+ declare function rendererBehaviorId<Annotation>(annotation: object, renderer: RendererEntry<Annotation>): string | null;
2206
+ /** The first of your looks that draws this annotation, or `null`. */
2207
+ declare function lookRendererFor<Annotation, Entry extends RendererEntry<Annotation>>(record: Annotation, renderers: readonly Entry[] | undefined): Extract<Entry, {
2208
+ for: unknown;
2209
+ }> | null;
2210
+ /**
2211
+ * How the layer draws one annotation:
2212
+ * - `native`: its own drawing (the scene or the engine's raster). `inert`
2213
+ * when an engaged behavior's plugin owns the input with no renderer of
2214
+ * yours (a link's anchor takes the click).
2215
+ * - `owned`: a sibling plugin's renderer draws it and takes the input (the
2216
+ * form plugin's fill controls); it places its own controls.
2217
+ * - `look`: your renderer draws it, in the annotation's frame. `interactive`
2218
+ * when an engaged behavior gave it the pointer; otherwise it only draws,
2219
+ * and the frame is `inert` (no pointer, no focus) unless its text box is
2220
+ * being typed in, where the renderer's editor takes the keys.
2221
+ */
2222
+ type AnnotationDrawing<Entry> = {
2223
+ kind: 'native';
2224
+ inert: boolean;
2225
+ } | {
2226
+ kind: 'owned';
2227
+ entry: Extract<Entry, {
2228
+ behavior: string;
2229
+ }>;
2230
+ } | {
2231
+ kind: 'look';
2232
+ entry: Extract<Entry, {
2233
+ for: unknown;
2234
+ }>;
2235
+ interactive: boolean;
2236
+ inert: boolean;
2237
+ };
2238
+ /**
2239
+ * The drawing an annotation gets. Ownership beats looks: an engaged
2240
+ * behavior's renderer is authoritative; `for` rules apply only to what the
2241
+ * layer owns, and draw without the pointer. `typing` is whether this
2242
+ * annotation's text box is being typed in.
2243
+ */
2244
+ declare function annotationDrawingOf<Annotation, Entry extends RendererEntry<Annotation>>(record: Annotation, annotation: RendererBehaviorRegistry<Annotation>, renderers: readonly Entry[] | undefined, typing: boolean): AnnotationDrawing<Entry>;
2245
+ /**
2246
+ * The key of the text box being typed in (the one that is `editing` and has a
2247
+ * ref), or `null`. An annotation with this key is `typing` for
2248
+ * {@link annotationDrawingOf}: while it is, a look's own editor takes the keys.
2249
+ */
2250
+ declare function editingTextKeyOf<Ref>(texts: readonly {
2251
+ readonly editing: boolean;
2252
+ readonly ref: Ref | null;
2253
+ }[], keyOf: (ref: Ref) => string): string | null;
2254
+ /**
2255
+ * The text boxes the layer draws itself: all of them but the ones whose
2256
+ * annotation a look of yours draws, which that look edits with its own editor
2257
+ * (a renderer's rich text editor). `items` are the page's render items, which
2258
+ * carry each annotation; the same array comes back when there is no look.
2259
+ */
2260
+ declare function layerTextBoxesOf<Annotation, Ref, Text extends {
2261
+ readonly ref: Ref | null;
2262
+ }>(texts: readonly Text[], items: readonly {
2263
+ readonly ref: Ref | null;
2264
+ readonly annotation?: Annotation | null;
2265
+ }[], renderers: readonly RendererEntry<Annotation>[] | undefined, keyOf: (ref: Ref) => string): readonly Text[];
2266
+ //#endregion
2267
+ //#region src/comment-threads.d.ts
2268
+ /**
2269
+ * Comment threads with where their page is shown: the join of the annotation
2270
+ * plugin's threads and the document's page list that a comments panel
2271
+ * prints. A thread's identity stays its page's address; the index and the
2272
+ * label are presentation, following page moves and deletes.
2273
+ */
2274
+ /** Where a thread's page is shown now. */
2275
+ interface CommentThreadPage {
2276
+ /** Current 0-based display index of the thread's page; `-1` when the page is no longer in the document. */
2277
+ pageIndex: number;
2278
+ /**
2279
+ * The page's `/PageLabels` label when the PDF declares one ("iv", "A-2"),
2280
+ * else the 1-based position as a string; `'?'` for a page that's gone.
2281
+ * Print it as it is.
2282
+ */
2283
+ pageLabel: string;
2284
+ }
2285
+ /** A page as the document's page list has it: its address, display index and label. */
2286
+ interface CommentPageLayout {
2287
+ readonly ref: {
2288
+ readonly objectNumber: number;
2289
+ };
2290
+ readonly index: number;
2291
+ readonly label?: string | null;
2292
+ }
2293
+ /**
2294
+ * Each thread with its page's display index and label. A thread whose page
2295
+ * was just deleted reads `-1` and `'?'` for the one render before it goes.
2296
+ */
2297
+ declare function enrichCommentThreads<Thread extends {
2298
+ readonly page: {
2299
+ readonly objectNumber: number;
2300
+ };
2301
+ }>(threads: readonly Thread[], pages: readonly CommentPageLayout[]): Array<Thread & CommentThreadPage>;
2302
+ //#endregion
2303
+ //#region src/form-field.d.ts
2304
+ /** The form settings the colors read: the structural twin of the form plugin's `focus` and `fields`. */
2305
+ interface FormColorSettings {
2306
+ readonly focus: {
2307
+ readonly color: string | null;
2308
+ };
2309
+ readonly fields: {
2310
+ readonly border: string | null;
2311
+ readonly background: string;
2312
+ readonly color: string;
2313
+ };
2314
+ }
2315
+ /** The colors the viewer draws fields with, each its `--epdf-form-*` variable first, then the setting. */
2316
+ interface FormColors {
2317
+ /** The focus ring around the field being filled in. */
2318
+ readonly focus: string;
2319
+ /** The edge of a field without a border of its own. */
2320
+ readonly border: string;
2321
+ /** Inside a field without a background of its own, while it's filled in. */
2322
+ readonly background: string;
2323
+ /** The text of a field without a color of its own. */
2324
+ readonly text: string;
2325
+ }
2326
+ /** The form settings as colors: an unset focus color is the accent, an unset edge the accent at 55%. */
2327
+ declare function formColorsOf(settings: FormColorSettings, accent: string): FormColors;
2328
+ /** How a widget looks in the PDF: the structural twin of the form plugin's `FormWidgetLook`. */
2329
+ interface FieldLook {
2330
+ readonly border: string | null;
2331
+ /** In page points. */
2332
+ readonly borderWidth: number;
2333
+ readonly borderStyle: string;
2334
+ readonly background: string | null;
2335
+ readonly color: string | null;
2336
+ /** One of the 14 standard PDF fonts (`'helvetica-bold'`), or `null`. */
2337
+ readonly fontFamily: string | null;
2338
+ /** In page points; `0` or `null` fits the text to the box. */
2339
+ readonly fontSize: number | null;
2340
+ readonly textAlign: 'left' | 'center' | 'right';
2341
+ }
2342
+ /** A standard PDF font as CSS. */
2343
+ type CssFont = {
2344
+ fontFamily: string;
2345
+ fontWeight: number;
2346
+ fontStyle: 'normal' | 'italic';
2347
+ };
2348
+ /** One of the 14 standard PDF fonts as CSS: a family that looks like it, its weight and style. */
2349
+ declare function cssFontOf(pdfFont: string | null): CssFont;
2350
+ /** A field's text as CSS: its font, size, alignment and colors, the settings where it has none. */
2351
+ type FieldTextStyle = CssFont & {
2352
+ /** In pixels, with its unit. */
2353
+ fontSize: string;
2354
+ textAlign: 'left' | 'center' | 'right';
2355
+ color: string;
2356
+ background: string;
2357
+ };
2358
+ /** A text field as the layer's editor shows it while focused, in the field's own font. */
2359
+ type TextFieldStyle = FieldTextStyle & {
2360
+ /** A comb field's spacing (its box split into `maxLength` cells), in pixels with its unit. */
2361
+ letterSpacing?: string;
2362
+ };
2363
+ /**
2364
+ * A text field's editor style. A font size of 0 means "fit the box" in PDF:
2365
+ * the box height for one line, Acrobat's 12 pt for several.
2366
+ */
2367
+ declare function textFieldStyleOf(field: {
2368
+ box: {
2369
+ width: number;
2370
+ };
2371
+ look: FieldLook;
2372
+ multiline: boolean;
2373
+ comb: boolean;
2374
+ maxLength: number | null;
2375
+ }, frame: PixelRect, colors: FormColors): TextFieldStyle;
2376
+ /** A list box as the layer draws it: the field's text look, and its border. */
2377
+ type ListBoxStyle = FieldTextStyle & {
2378
+ /** In pixels, with its unit; never thinner than one pixel. */
2379
+ borderWidth: string;
2380
+ borderStyle: 'solid' | 'dashed';
2381
+ borderColor: string;
2382
+ };
2383
+ /** A list box's style: the field's own look, the settings where it has none (12 pt for a fitted size). */
2384
+ declare function listBoxStyleOf(field: {
2385
+ box: {
2386
+ width: number;
2387
+ };
2388
+ look: FieldLook;
2389
+ }, frame: PixelRect, colors: FormColors): ListBoxStyle;
2390
+ /** The PDF events a widget's `/AA` actions answer, as the actions plugin names them. */
2391
+ type WidgetEventKind = 'cursorEnter' | 'cursorExit' | 'mouseDown' | 'mouseUp' | 'focus' | 'blur';
2392
+ /**
2393
+ * Send a widget's pointer and focus events (`/AA`: enter, exit, down, up,
2394
+ * focus, blur) to `notify`, from native listeners on the widget's box. Put
2395
+ * them on the always-active box, never on the control inside: "may edit this
2396
+ * field" and "may receive PDF action events" are different rights, and a
2397
+ * session that may not fill still sees hover tooltips. Focus is `focusin` and
2398
+ * `focusout`, so the control's focus reaches the box, and a blur arrives
2399
+ * after the control's own blur handler started its commit. Returns the
2400
+ * detach.
2401
+ */
2402
+ declare function bindWidgetEvents(box: HTMLElement, notify: (event: WidgetEventKind) => void): () => void;
2403
+ /** What a toggle press writes with: the form plugin's `setValue`. */
2404
+ interface ToggleForm<Field> {
2405
+ setValue(field: Field, value: {
2406
+ value: string | null;
2407
+ }): Promise<unknown>;
2408
+ }
2409
+ /**
2410
+ * A checkbox or radio button pressed: a checked checkbox clears, a radio
2411
+ * button always selects its own value. The value is written first, then the
2412
+ * widget's action runs (Acrobat's order), so an action script reads the new
2413
+ * state; a read-only toggle writes nothing and still runs its action.
2414
+ */
2415
+ declare function pressToggle<Field>(form: ToggleForm<Field>, toggle: {
2416
+ fieldRef: Field;
2417
+ kind: 'checkbox' | 'radio';
2418
+ checked: boolean;
2419
+ exportValue: string;
2420
+ disabled: boolean;
2421
+ }, activate: () => void): void;
2422
+ /** The form plugin's draft calls for a text field (its host capability satisfies it). */
2423
+ interface TextFieldDrafts<Field> {
2424
+ draftText(field: Field, text: string): void;
2425
+ /** Resolves with how the write ended (`'rejected'`: the form's validation refused it), or `null`. */
2426
+ commitDraftText(field: Field): Promise<{
2427
+ readonly status: string;
2428
+ } | null>;
2429
+ discardDraftText(field: Field): void;
2430
+ }
2431
+ /** What a text field's editor shows: whether it has focus, and the text in it. */
2432
+ interface TextFieldEditorState {
2433
+ readonly focused: boolean;
2434
+ readonly draft: string;
2435
+ }
2436
+ /**
2437
+ * A text field being typed in, framework-free: the editor's `value` is
2438
+ * `draft`, and its events call the methods. Read the state with `getState`
2439
+ * and re-render on `subscribe`; the state object stays the same until it
2440
+ * changes.
2441
+ */
2442
+ interface TextFieldEditor {
2443
+ getState(): TextFieldEditorState;
2444
+ subscribe(listener: () => void): () => void;
2445
+ /** The field's value as the form has it now. The draft follows it, except while focused. */
2446
+ setValue(value: string): void;
2447
+ /** The editor took focus. */
2448
+ focus(): void;
2449
+ /** Someone typed: the draft shows it, and the plugin keeps it so a download writes it. */
2450
+ input(text: string): void;
2451
+ /**
2452
+ * A key went down. True when the editor should blur now: Escape (which
2453
+ * puts the value back) and, in a one-line field, Enter (which commits).
2454
+ */
2455
+ keyDown(key: string, multiline: boolean): boolean;
2456
+ /** The editor lost focus: commit what changed, discard what didn't or was cancelled. */
2457
+ blur(): void;
2458
+ }
2459
+ /**
2460
+ * The editing policy of one text field: typing drafts, blur or Enter
2461
+ * commits, Escape discards. A commit keeps the typed text until the field
2462
+ * shows it (at once, as the form shows a fill before the engine answers), so
2463
+ * a blur never shows the old value for a moment. A value the form's
2464
+ * validation refuses stays typed, as in Acrobat; a write the engine refuses
2465
+ * puts the field's value back.
2466
+ */
2467
+ declare function createTextFieldEditor<Field>(form: TextFieldDrafts<Field>, field: Field, value: string): TextFieldEditor;
2468
+ /**
2469
+ * A list box's selection, shown at once while its write is on its way. The
2470
+ * native control must stay the same element (never remounted), so its own
2471
+ * scroll position stays where the user left it.
2472
+ */
2473
+ interface OptimisticSelection {
2474
+ /** The selection the control shows. */
2475
+ get(): readonly string[];
2476
+ subscribe(listener: () => void): () => void;
2477
+ /** The selection the engine has now: the control shows it once it differs from the last one. */
2478
+ setConfirmed(values: readonly string[]): void;
2479
+ /** Show `values` now and write them; a write that fails puts the engine's selection back. */
2480
+ choose(values: string[], write: (values: string[]) => void | Promise<unknown>): void;
2481
+ }
2482
+ /** A list box's optimistic selection, starting at the engine's. */
2483
+ declare function createOptimisticSelection(confirmed: readonly string[]): OptimisticSelection;
2484
+ /** A native `<select>`, as {@link showSelectedOptions} reads it: its options. */
2485
+ interface SelectOptions {
2486
+ readonly options: ArrayLike<{
2487
+ readonly value: string;
2488
+ selected: boolean;
2489
+ }>;
2490
+ }
2491
+ /**
2492
+ * Show `values` as a native `<select>`'s selection, set on each option. A
2493
+ * `value` binding can't hold several values, and setting the options also
2494
+ * puts a choice back when its write fails before the framework renders
2495
+ * again. Setting the same selection again changes nothing the user sees,
2496
+ * scroll position included.
2497
+ */
2498
+ declare function showSelectedOptions(select: SelectOptions, values: readonly string[]): void;
2499
+ //#endregion
2500
+ //#region src/form-styles.d.ts
2501
+ /** A control that fills the widget's box it sits in: every native control the layer draws. */
2502
+ declare const FORM_CONTROL_FILL: Readonly<{
2503
+ readonly position: "absolute";
2504
+ readonly inset: "0";
2505
+ readonly width: "100%";
2506
+ readonly height: "100%";
2507
+ readonly boxSizing: "border-box";
2508
+ readonly margin: "0";
2509
+ }>;
2510
+ /** {@link FORM_CONTROL_FILL}'s shape. */
2511
+ type FormControlFill = typeof FORM_CONTROL_FILL;
2512
+ /** The box a widget's control sits in, placed over the widget on the page. */
2513
+ type WidgetBoxStyle = {
2514
+ position: 'absolute';
2515
+ left: string;
2516
+ top: string;
2517
+ width: string;
2518
+ height: string;
2519
+ /** Always the widget's event surface: the control inside gates the edits. */
2520
+ pointerEvents: 'auto';
2521
+ /** The edge of a field without a border of its own, so people see where to fill in. */
2522
+ boxShadow?: string;
2523
+ };
2524
+ /**
2525
+ * The style of a widget's box at `frame` (the widget's box in the page
2526
+ * layer's pixels). `edge: false` leaves the edge out, for a control that draws
2527
+ * its own (a list box) or never has one (a button).
2528
+ */
2529
+ declare function widgetBoxStyleOf(widget: {
2530
+ look: Pick<FieldLook, 'border'>;
2531
+ }, frame: PixelRect, colors: FormColors, { edge }?: {
2532
+ edge?: boolean;
2533
+ }): WidgetBoxStyle;
2534
+ /**
2535
+ * Where a text field's editor shows the text typed in it, so it sits where the engine will draw
2536
+ * it (the form plugin's `getTextEditorLayout`), in page points.
2537
+ */
2538
+ interface TextEditorLayout {
2539
+ readonly fontFamily: string;
2540
+ readonly fontWeight: number;
2541
+ readonly fontStyle: 'normal' | 'italic';
2542
+ readonly fontSize: number;
2543
+ readonly lineHeight: number;
2544
+ readonly padding: {
2545
+ readonly top: number;
2546
+ readonly right: number;
2547
+ readonly bottom: number;
2548
+ readonly left: number;
2549
+ };
2550
+ /** A comb's room between characters; it starts at the left padding, whatever the alignment. */
2551
+ readonly letterSpacing: number;
2552
+ readonly comb: boolean;
2553
+ }
2554
+ /** A text field's editor: see-through at rest, the field's own look while focused. */
2555
+ type TextFieldEditorStyle = FormControlFill & TextFieldStyle & {
2556
+ border: 'none';
2557
+ outline: string;
2558
+ outlineOffset: string;
2559
+ padding: string;
2560
+ /** In pixels, with its unit: one line of the engine's layout. */
2561
+ lineHeight?: string;
2562
+ resize: 'none';
2563
+ cursor: 'text';
2564
+ /** 1 while focused, 0 at rest, where the field's picture shows through. */
2565
+ opacity: number;
2566
+ /** `none` for a disabled field: the box below runs the widget's action. */
2567
+ pointerEvents?: 'none';
2568
+ };
2569
+ /**
2570
+ * The style of a text field's editor, the `<input>` or `<textarea>` that is
2571
+ * always there: focused, it shows the field's text in its own font with a
2572
+ * focus ring; at rest it is see-through over the field's picture. A disabled
2573
+ * control would swallow clicks, and the box below runs the widget's action
2574
+ * (the read-only "button" pattern), so a disabled one lets them through.
2575
+ *
2576
+ * With the engine's `layout` of the text being typed, the editor writes it
2577
+ * where the engine will draw it: in the engine's face (mounted), at the size
2578
+ * it draws (a fitted size resolved), in the box inside the border, a line of
2579
+ * the face's height (one line centred, as the engine centres it).
2580
+ */
2581
+ declare function textFieldEditorStyleOf(field: Parameters<typeof textFieldStyleOf>[0] & {
2582
+ disabled: boolean;
2583
+ }, frame: PixelRect, colors: FormColors, focused: boolean, layout?: TextEditorLayout | null): TextFieldEditorStyle;
2584
+ /** A list box: the visible native `<select>` in the field's own look. */
2585
+ type ListBoxControlStyle = FormControlFill & ListBoxStyle & {
2586
+ padding: string;
2587
+ borderRadius: string;
2588
+ outline: 'none';
2589
+ cursor: 'default' | 'pointer';
2590
+ /** `none` for a disabled field: the box below runs the widget's action. */
2591
+ pointerEvents?: 'none';
2592
+ };
2593
+ /**
2594
+ * The style of a list box's `<select>`, filling the widget's box: the field's
2595
+ * own look ({@link listBoxStyleOf}) with its own border, so the box adds no
2596
+ * edge. The focus ring is drawn above it ({@link formFocusRingStyleOf}).
2597
+ */
2598
+ declare function listBoxControlStyleOf(field: Parameters<typeof listBoxStyleOf>[0] & {
2599
+ disabled: boolean;
2600
+ }, frame: PixelRect, colors: FormColors): ListBoxControlStyle;
2601
+ /** The focus ring of a field whose control is see-through, or is the box itself. */
2602
+ type FormFocusRingStyle = {
2603
+ position: 'absolute';
2604
+ inset: string;
2605
+ zIndex: number;
2606
+ boxSizing: 'border-box';
2607
+ outline: string;
2608
+ outlineOffset: string;
2609
+ pointerEvents: 'none';
2610
+ };
2611
+ /**
2612
+ * The style of a field's focus ring in `color` (the form's focus color): an
2613
+ * element of its own above the field's picture and its control. An outline on
2614
+ * the box would sit under an opaque child, so a rectangular checkbox or a
2615
+ * dropdown would look unfocused while it has the focus.
2616
+ */
2617
+ declare function formFocusRingStyleOf(color: string): FormFocusRingStyle;
2618
+ //#endregion
2619
+ //#region src/link-anchor.d.ts
2620
+ /** A link as the link plugin lists it: the fields the anchor reads. */
2621
+ interface LinkAnchorShape {
2622
+ readonly target: {
2623
+ readonly kind: string;
2624
+ readonly uri?: string;
2625
+ };
2626
+ /** The full `/A` tree; a `/Next` after its root chains more actions. */
2627
+ readonly activate?: {
2628
+ readonly root: {
2629
+ readonly next: readonly unknown[];
2630
+ } | null;
2631
+ } | null;
2632
+ /** A link riding an editable annotation (its parent owns its pixels while annotations are edited). */
2633
+ readonly attached: boolean;
2634
+ }
2635
+ /**
2636
+ * The links a page layer shows anchors for. One owner per pixel: while the
2637
+ * active tool edits annotations, a link attached to an annotation stands
2638
+ * down so its parent can be selected and moved; a document's own links
2639
+ * navigate under every tool that enables link navigation.
2640
+ */
2641
+ declare function navigableLinksOf<Link extends LinkAnchorShape>(links: readonly Link[], annotationEditEnabled: boolean): readonly Link[];
2642
+ /**
2643
+ * The anchor's native `href`: only for a website the browser may open and
2644
+ * nothing chained after it. Blocked schemes, targets inside the document and
2645
+ * action chains activate through the plugin instead: a native navigation
2646
+ * would run the first action and silently drop the rest.
2647
+ */
2648
+ declare function linkHrefOf(link: LinkAnchorShape): string | null;
2649
+ /** A link's anchor, ready to draw. */
2650
+ interface LinkAnchor<Link> {
2651
+ readonly link: Link;
2652
+ /** Where the anchor sits, in the page layer's pixels. */
2653
+ readonly box: PixelRect;
2654
+ /** Its native `href` ({@link linkHrefOf}), or null. */
2655
+ readonly href: string | null;
2656
+ /** Its `title` and `aria-label`. */
2657
+ readonly label: string;
2658
+ }
2659
+ /**
2660
+ * The anchor for `link` on a page layer: its box from the link's `bounds`,
2661
+ * its `href`, and the label `labelOf` (the link plugin's `getLabel`) gives it.
2662
+ */
2663
+ declare function linkAnchorOf<Link extends LinkAnchorShape & {
2664
+ readonly bounds: {
2665
+ x: number;
2666
+ y: number;
2667
+ width: number;
2668
+ height: number;
2669
+ };
2670
+ }>(link: Link, page: PageToPixels, labelOf: (link: Link) => string): LinkAnchor<Link>;
2671
+ /**
2672
+ * Whether a click on an anchor with an `href` stays the browser's: a click
2673
+ * with a modifier key opens a background tab or a new window. Every other
2674
+ * click is prevented and follows the link through the plugin.
2675
+ */
2676
+ declare function isModifiedClick(event: {
2677
+ metaKey: boolean;
2678
+ ctrlKey: boolean;
2679
+ shiftKey: boolean;
2680
+ altKey: boolean;
2681
+ }): boolean;
2682
+ //#endregion
2683
+ //#region src/link-events.d.ts
2684
+ /**
2685
+ * What a page link's anchor tells the plugins: the context a click or a key
2686
+ * follows the link with (the link plugin's `activate()`), and the link's own
2687
+ * PDF events (`/AA`): entering and leaving through the layer's hover pump,
2688
+ * the press, the release, focus and blur through the actions plugin's
2689
+ * `dispatch()`. Only a link that is an annotation has events of its own. The
2690
+ * plugins' types are mirrored structurally and their refs stay opaque, so
2691
+ * this package stays free of EmbedPDF imports.
2692
+ */
2693
+ /** The events an anchor sends the actions plugin itself; entering and leaving go through the hover pump. */
2694
+ type LinkAnchorEvent = 'mouseDown' | 'mouseUp' | 'focus' | 'blur';
2695
+ /** A link's fields these read: its `/A` tree, the annotation it is, and which hover trees it has. */
2696
+ interface LinkEventShape<Ref, Action = unknown, HoverEvents = unknown> {
2697
+ readonly activate?: Action;
2698
+ readonly ref?: Ref;
2699
+ readonly hoverEvents?: HoverEvents;
2700
+ }
2701
+ /** The link as the source of an actions-plugin event. */
2702
+ interface LinkActionSource<Ref, Page> {
2703
+ readonly kind: 'link';
2704
+ readonly annotation: Ref;
2705
+ readonly page: Page;
2706
+ }
2707
+ /** The actions plugin, as an anchor uses it. */
2708
+ interface LinkActionDispatcher<Ref, Page> {
2709
+ dispatch(trigger: {
2710
+ readonly scope: 'annotation';
2711
+ readonly event: LinkAnchorEvent;
2712
+ readonly ref: Ref;
2713
+ readonly page: Page;
2714
+ readonly source: LinkActionSource<Ref, Page>;
2715
+ }): unknown;
2716
+ }
2717
+ /** One link layer's hover pump (`createHoverPump` in the actions plugin's contract). */
2718
+ interface LinkHoverPump<Ref, Page, HoverEvents> {
2719
+ hover(target: {
2720
+ readonly ref: Ref;
2721
+ readonly page: Page;
2722
+ readonly source: LinkActionSource<Ref, Page>;
2723
+ readonly events: HoverEvents;
2724
+ } | null): void;
2725
+ }
2726
+ /**
2727
+ * The context a click or a key follows `link` with: its `/A` tree (the
2728
+ * actions plugin runs it instead of the target), the annotation it is, its
2729
+ * page, and the view it was followed in (a page destination moves that one).
2730
+ */
2731
+ declare function linkActivateContextOf<Ref, Action, Page, Stage>(link: LinkEventShape<Ref, Action>, page: Page, stage: Stage | null): {
2732
+ activate?: Action;
2733
+ ref?: Ref;
2734
+ page: Page;
2735
+ stage?: Stage;
2736
+ };
2737
+ /**
2738
+ * Send `link`'s own event for a press, a release or a focus change: only for
2739
+ * a link that is an annotation, and only with the actions plugin.
2740
+ */
2741
+ declare function sendLinkEvent<Ref, Page>(actions: NoInfer<LinkActionDispatcher<Ref, Page>> | null, link: LinkEventShape<Ref>, page: Page, event: LinkAnchorEvent): void;
2742
+ /**
2743
+ * Tell the layer's hover pump the pointer entered `link`: only a link that is
2744
+ * an annotation with hover trees has enter and exit events. Leaving is
2745
+ * `pump.hover(null)`.
2746
+ */
2747
+ declare function hoverLink<Ref, Page, HoverEvents>(pump: NoInfer<LinkHoverPump<Ref, Page, HoverEvents>> | null, link: LinkEventShape<Ref, unknown, HoverEvents>, page: Page): void;
2748
+ //#endregion
2749
+ //#region src/search-highlights.d.ts
2750
+ /** A match as the search plugin lists it: the fields the paint reads. */
2751
+ interface SearchHitShape {
2752
+ /** Where the match starts in the document's text: with the line's index, its key. */
2753
+ readonly start: number;
2754
+ /** One per line the match spans, in page points. */
2755
+ readonly segments: readonly {
2756
+ readonly quad: PageQuad;
2757
+ }[];
2758
+ }
2759
+ /** One line of a match, ready to draw. */
2760
+ interface SearchHighlightPiece<Hit extends SearchHitShape> {
2761
+ readonly key: string;
2762
+ readonly hit: Hit;
2763
+ /** Whether it's a line of the active match. */
2764
+ readonly active: boolean;
2765
+ readonly fill: string;
2766
+ /** The line's box in the page layer's pixels when it's upright; null when it's turned. */
2767
+ readonly box: PixelRect | null;
2768
+ /** The four corners as SVG `points`, for a turned line; null when it's upright. */
2769
+ readonly points: string | null;
2770
+ }
2771
+ /** What {@link searchHighlightsOf} paints with. */
2772
+ interface SearchHighlightOptions<Hit extends SearchHitShape> {
2773
+ /** The search's active match (compared by identity), or null. */
2774
+ readonly active: Hit | null;
2775
+ /** The page layer's transform. */
2776
+ readonly page: PageToPixels;
2777
+ /** The fill of a match, and of the active one (`paint('search-highlight', …)`). */
2778
+ readonly color: string;
2779
+ readonly activeColor: string;
2780
+ }
2781
+ /** Every line of `hits` as a piece to draw, in hit order. */
2782
+ declare function searchHighlightsOf<Hit extends SearchHitShape>(hits: readonly Hit[], options: SearchHighlightOptions<Hit>): SearchHighlightPiece<Hit>[];
2783
+ //#endregion
2784
+ //#region src/press-click.d.ts
2785
+ /**
2786
+ * Telling a click from a drag on something drawn over a page (a search
2787
+ * match). The press still reaches the page, so a drag that starts there
2788
+ * selects text; only a press that stays put counts as a click.
2789
+ */
2790
+ /** A click detector for one layer: feed it the `pointerdown`, ask it at the `click`. */
2791
+ interface ClickDetector {
2792
+ /** A press began (`pointerdown`). */
2793
+ press(event: {
2794
+ clientX: number;
2795
+ clientY: number;
2796
+ pointerType: string;
2797
+ }): void;
2798
+ /** Whether this `click` is a click, not the end of a drag. Forgets the press. */
2799
+ isClick(event: {
2800
+ clientX: number;
2801
+ clientY: number;
2802
+ }): boolean;
2803
+ }
2804
+ declare function createClickDetector(): ClickDetector;
2805
+ //#endregion
2806
+ //#region src/page-projector.d.ts
2807
+ /** The page transform members a projection reads; `PageTransform` satisfies it. */
2808
+ interface ProjectedTransform {
2809
+ readonly viewScale: number;
2810
+ readonly rotation: 0 | 90 | 180 | 270;
2811
+ readonly zoom: number;
2812
+ }
2813
+ /**
2814
+ * The page surface a client projector measures: the page context's members. `transform` may be
2815
+ * the transform or a function that returns the current one (a signal).
2816
+ */
2817
+ interface ClientProjectedPage {
2818
+ readonly ref: PageRef;
2819
+ readonly transform: ProjectedTransform | (() => ProjectedTransform);
2820
+ toClientRect(rect: AnchoredRect): AnchoredRect;
2821
+ toClientPoint(point: {
2822
+ x: number;
2823
+ y: number;
2824
+ }): {
2825
+ x: number;
2826
+ y: number;
2827
+ };
2828
+ }
2829
+ /**
2830
+ * A client-space projector for one page. `mounted` says whether the page
2831
+ * element is in the document yet: until it is, every projection is `null`,
2832
+ * and the anchored UI waits for the first measurable pass. The view is the
2833
+ * window. Pair it with {@link observeClientGeometry}, which reports the
2834
+ * browser-driven moves (document scroll, window resize) no state announces.
2835
+ * Every member reads `page` when it runs, so a page context whose members
2836
+ * change keeps one projector.
2837
+ */
2838
+ declare function clientPageProjector(page: ClientProjectedPage, mounted: () => boolean): ViewProjector;
2839
+ /** What a Stage projection reads from the Stage lens; `StageHostCapability` satisfies it. */
2840
+ interface StageProjection {
2841
+ pageRectToViewport(page: PageRef, rect: AnchoredRect): AnchoredRect | null;
2842
+ getPageFrame(page: PageRef): {
2843
+ readonly transform: ProjectedTransform;
2844
+ } | null;
2845
+ getViewportSize(): {
2846
+ width: number;
2847
+ height: number;
2848
+ };
2849
+ }
2850
+ /**
2851
+ * The Stage's projector: anchored UI positions through the camera, in the Stage's own box
2852
+ * (`'overlay'` space). `stage()` gives the lens when a projection runs, or null without one
2853
+ * (nothing projects then). It reads only the Stage's state, so the binding's revision (the
2854
+ * visible pages) is what tells anchored UI to place itself again, in the same render as the
2855
+ * pages.
2856
+ */
2857
+ declare function stageViewProjector(stage: () => StageProjection | null): ViewProjector;
2858
+ //#endregion
2859
+ //#region src/page-context.d.ts
2860
+ interface ContextPoint {
2861
+ x: number;
2862
+ y: number;
2863
+ }
2864
+ interface ContextRect {
2865
+ x: number;
2866
+ y: number;
2867
+ width: number;
2868
+ height: number;
2869
+ }
2870
+ /** The bands reserved around a page for its chrome, in screen pixels per side. */
2871
+ interface PageFrameShape {
2872
+ top: number;
2873
+ right: number;
2874
+ bottom: number;
2875
+ left: number;
2876
+ }
2877
+ /** What the conversions need from the page transform; `PageTransform` satisfies it. */
2878
+ interface PageContextTransform {
2879
+ viewToPage(point: ContextPoint): ContextPoint;
2880
+ pageToView(point: ContextPoint): ContextPoint;
2881
+ pageToViewRect(rect: ContextRect): ContextRect;
2882
+ }
2883
+ /** Where the page's content box is on screen, in client pixels: `getBoundingClientRect()`. */
2884
+ interface ClientBox {
2885
+ readonly left: number;
2886
+ readonly top: number;
2887
+ }
2888
+ /** Between client (screen) pixels and points on one page. */
2889
+ interface PageClientSpace {
2890
+ /** A client (screen) point to a point on the page: the one platform-bound hit test. */
2891
+ toPagePoint(clientX: number, clientY: number): ContextPoint;
2892
+ /**
2893
+ * A point on the page to client pixels, the exact inverse of `toPagePoint` (rotation applied),
2894
+ * so UI in the view can anchor to a page point without a Stage camera.
2895
+ */
2896
+ toClientPoint(point: ContextPoint): ContextPoint;
2897
+ /** A box on the page to the client-pixel box around it: the box twin of `toClientPoint`. */
2898
+ toClientRect(rect: ContextRect): ContextRect;
2899
+ }
2900
+ /**
2901
+ * The page context. `Transform` is the page transform (`PageTransform`), `Demand` what the view
2902
+ * wants rendered (`PageViewDemand`).
2903
+ */
2904
+ interface PageContext<Transform extends PageContextTransform, Demand> extends PageClientSpace {
2905
+ documentId: string;
2906
+ /**
2907
+ * The page's durable address: use it for keys, rendering and annotations (read
2908
+ * `ref.objectNumber` where a map key is needed). The same object for the surface's lifetime,
2909
+ * so layers may key their work on it.
2910
+ */
2911
+ ref: PageRef;
2912
+ /** The display index (page N), from 0: for ordering and page numbers people read. */
2913
+ pageIndex: number;
2914
+ /**
2915
+ * The bands reserved around the page, in screen pixels per side. The page chrome draws into
2916
+ * the outer box (content and frame): a label in the bottom band is
2917
+ * `bottom: 0; height: frame.bottom`.
2918
+ */
2919
+ frame: PageFrameShape;
2920
+ /**
2921
+ * The one bridge between PDF points, view pixels and device pixels for this page: `toPixels`
2922
+ * to place content, `renderScale` and `deviceWidth` to render, `contentWidth` for sizes
2923
+ * relative to the page. Never multiply by the scale or the device pixel ratio yourself.
2924
+ */
2925
+ transform: Transform;
2926
+ /**
2927
+ * What the page's view wants rendered, as a pull the host fills: a Stage reads the page's
2928
+ * visible part live at call time (a zero box while it is off screen, see
2929
+ * {@link stagePageDemand}); a surface without a camera leaves it out, which means the whole
2930
+ * page.
2931
+ */
2932
+ getViewDemand?: () => Demand;
2933
+ /**
2934
+ * The hosting view's identity: the stage lens id (`stage.getLensId()`) or a per-instance
2935
+ * `PageView` id. Per-view raster planning (tiles) keys its state by it, so two views showing
2936
+ * the same page never fight over one plan.
2937
+ */
2938
+ view: string;
2939
+ }
2940
+ /**
2941
+ * The client-space conversions of a page whose content box `box()` measures on screen when a
2942
+ * conversion runs: client pixels to box-local view pixels, then the transform undoes the turn
2943
+ * and the scale. `toPagePoint` and `toClientPoint` read the same live box, so they never drift.
2944
+ */
2945
+ declare function pageClientSpace(transform: () => PageContextTransform, box: () => ClientBox): PageClientSpace;
2946
+ /**
2947
+ * Build a page context. `getRect` is the page's content box on screen (the turned content
2948
+ * element's bounding box), read when a conversion runs.
2949
+ */
2950
+ declare function makePageContext<Transform extends PageContextTransform, Demand = never>(documentId: string, view: string, ref: PageRef, pageIndex: number, frame: PageFrameShape, transform: Transform, getRect: () => ClientBox, getViewDemand?: () => Demand): PageContext<Transform, Demand>;
2951
+ /**
2952
+ * A page context that reads every member through `current()`: the same object for a surface's
2953
+ * lifetime, current in what it answers. For an adapter whose layers keep the object they were
2954
+ * given once (a Svelte component reads `page.transform` in a template and follows the zoom).
2955
+ */
2956
+ declare function livePageContext<Context extends PageContext<PageContextTransform, unknown>>(current: () => Context): Context;
2957
+ //#endregion
2958
+ //#region src/page-layers.d.ts
2959
+ /**
2960
+ * Which parts of a page the layers on it paint themselves. The annotation
2961
+ * layer paints the annotations, the form layer the form fields; while one is
2962
+ * on the page it says so here, and the page's picture (the render layer)
2963
+ * leaves that part out, so nothing is drawn twice and nobody passes a flag.
2964
+ *
2965
+ * Kept per page surface, by the page ref it hands its layers (`page.ref`):
2966
+ * each surface makes its own, and keeps it while it shows the page, through
2967
+ * zooms. Changes reach subscribers a microtask later, so a layer may say what
2968
+ * it paints from any point in its framework's lifecycle (React's insertion
2969
+ * effects included, which must not start updates); `painted()` is current at
2970
+ * once.
2971
+ */
2972
+ /** A part of a page a layer can paint instead of the page's picture. */
2973
+ type PagePart = 'annotations' | 'formFields';
2974
+ /** Which parts the layers on one page paint. */
2975
+ interface PaintedParts {
2976
+ readonly annotations: boolean;
2977
+ readonly formFields: boolean;
2978
+ }
2979
+ /** One page's layers: which parts they paint. */
2980
+ interface PageLayers {
2981
+ /** Say this layer paints `part`, until the function it returns is called. */
2982
+ paint(part: PagePart): () => void;
2983
+ /** Which parts are painted now: the same object for the same answer. */
2984
+ painted(): PaintedParts;
2985
+ /** Hear when `painted()` changes. Returns the unsubscribe. */
2986
+ subscribe(listener: () => void): () => void;
2987
+ }
2988
+ /** The layers of one page surface, by the page ref it hands its layers. */
2989
+ declare function pageLayersOf(pageRef: object): PageLayers;
2990
+ /** The parts a render layer was told to draw (`true`) or leave out (`false`). */
2991
+ interface PicturePartProps {
2992
+ readonly annotations?: boolean;
2993
+ readonly formFields?: boolean;
2994
+ }
2995
+ /** What the user may read of each part (the render plugin's `getLayerRights()`). */
2996
+ interface PartRights {
2997
+ readonly annotations: boolean;
2998
+ readonly formFields: boolean;
2999
+ }
3000
+ /** The picture's layer options, as the render plugin takes them. */
3001
+ interface PictureLayerOptions {
3002
+ includeAnnotations: boolean;
3003
+ includeFormFields: boolean;
3004
+ }
3005
+ /**
3006
+ * What the page's picture draws, as the render plugin's layer options: a part
3007
+ * the props name is drawn or left out as they say; any other part is drawn
3008
+ * when no layer on the page paints it and the user may read it. Both are
3009
+ * always given, so a picture that leaves the annotations to a layer still
3010
+ * draws the form fields.
3011
+ */
3012
+ declare function pictureLayerOptionsOf(painted: PaintedParts, props: PicturePartProps, may: PartRights): PictureLayerOptions;
3013
+ /**
3014
+ * The parts a picture draws that a layer on the page paints too, because the
3015
+ * props asked for them: drawn twice.
3016
+ */
3017
+ declare function partsDrawnTwice(painted: PaintedParts, props: PicturePartProps): PagePart[];
3018
+ //#endregion
3019
+ //#region src/page-surface.d.ts
3020
+ /** A box in its parent's pixels. */
3021
+ interface SurfaceBox {
3022
+ left: number;
3023
+ top: number;
3024
+ width: number;
3025
+ height: number;
3026
+ }
3027
+ /** The transform members a surface is laid out from; `PageTransform` satisfies it. */
3028
+ interface SurfaceTransform {
3029
+ readonly rotation: 0 | 90 | 180 | 270;
3030
+ readonly viewWidth: number;
3031
+ readonly viewHeight: number;
3032
+ readonly contentWidth: number;
3033
+ readonly contentHeight: number;
3034
+ }
3035
+ /** The three boxes of a page surface. */
3036
+ interface PageSurfaceLayout {
3037
+ /** The footprint and the reserved bands, in the surface's parent; the page chrome fills it. */
3038
+ outer: SurfaceBox;
3039
+ /** The drop shadow at the footprint, in the outer box. */
3040
+ shadow: SurfaceBox;
3041
+ /** The page's content box in the outer box, before it turns; its layers draw in it. */
3042
+ content: SurfaceBox;
3043
+ /** The CSS transform that turns the content box about its centre, or null when it's upright. */
3044
+ turn: string | null;
3045
+ }
3046
+ /**
3047
+ * Lay out a page surface. `footprint` is where the page's footprint sits in the surface's
3048
+ * parent (a Stage page's device-snapped `screenX`/`screenY`); the outer box sits one band further
3049
+ * out, so the content keeps its place. Without it the outer box is at 0, 0 (a `PageView`, placed
3050
+ * by the page around it).
3051
+ */
3052
+ declare function pageSurfaceLayout(transform: SurfaceTransform, frame: PageFrameShape, footprint?: {
3053
+ x: number;
3054
+ y: number;
3055
+ }): PageSurfaceLayout;
3056
+ /** What {@link stagePageDemand} reads from the Stage; `StageCapability` satisfies it. */
3057
+ interface StageDemandSource {
3058
+ listVisiblePages(): readonly {
3059
+ readonly ref: {
3060
+ readonly objectNumber: number;
3061
+ };
3062
+ readonly transform: {
3063
+ readonly deviceWidth: number;
3064
+ };
3065
+ readonly visibleRect: {
3066
+ x: number;
3067
+ y: number;
3068
+ width: number;
3069
+ height: number;
3070
+ };
3071
+ }[];
3072
+ }
3073
+ /** What a page's view wants rendered; the render plugin's `PageViewDemand` takes it. */
3074
+ interface StagePageDemand {
3075
+ desiredDeviceWidth: number;
3076
+ visibleRect: {
3077
+ x: number;
3078
+ y: number;
3079
+ width: number;
3080
+ height: number;
3081
+ };
3082
+ }
3083
+ /**
3084
+ * What a Stage page's view wants rendered, read live from the Stage when the render layer asks:
3085
+ * the page's visible part at its device width, or a zero box (want nothing) while the page is
3086
+ * off screen, at `offScreenDeviceWidth`. Visibility is the Stage's data, so no adapter derives
3087
+ * camera math or keeps a copy of it.
3088
+ */
3089
+ declare function stagePageDemand(stage: StageDemandSource, pageObjectNumber: number, offScreenDeviceWidth: number): StagePageDemand;
3090
+ /** The page a `PageView` shows, as its document's page list has it. */
3091
+ interface PageViewPage {
3092
+ readonly size: {
3093
+ readonly width: number;
3094
+ readonly height: number;
3095
+ };
3096
+ readonly rotation: 0 | 90 | 180 | 270;
3097
+ readonly userUnit: number;
3098
+ }
3099
+ /** The input of `pageTransform()` (`@embedpdf/core-geometry`) for a `PageView`. */
3100
+ interface PageViewTransformInput {
3101
+ pageSize: {
3102
+ width: number;
3103
+ height: number;
3104
+ };
3105
+ rotation: 0 | 90 | 180 | 270;
3106
+ scale: number;
3107
+ baseScale: number;
3108
+ dpr: number;
3109
+ }
3110
+ /**
3111
+ * What a `PageView` builds its page transform from: no camera, so the scale (view pixels per
3112
+ * point) is `width` over the page's width. The base scale is physical 100% on the web, a point
3113
+ * at 96/72 CSS pixels times the page's /UserUnit, so `transform.zoom` still means something: a
3114
+ * thumbnail-sized page reads as zoomed out. Without a page yet, a 1 × 1 placeholder.
3115
+ */
3116
+ declare function pageViewTransformInput(page: PageViewPage | null, width: number, dpr: number): PageViewTransformInput;
3117
+ //#endregion
3118
+ //#region src/page-pointer.d.ts
3119
+ interface PointerPoint {
3120
+ x: number;
3121
+ y: number;
3122
+ }
3123
+ /**
3124
+ * A multi-click counter. `pointerdown.detail` is 0 or 1 in several browsers, so clicks are
3125
+ * counted here from timing and distance: the standard double and triple click. Input is
3126
+ * normalized in the adapter; the hub and its handlers stay pure.
3127
+ */
3128
+ declare function createClickCounter(maxGapMs?: number, maxDistancePx?: number): (now: number, x: number, y: number) => number;
3129
+ /** What the listener reads from the page context when an event arrives. */
3130
+ interface PagePointerPage {
3131
+ readonly ref: PageRef;
3132
+ readonly transform: {
3133
+ readonly viewScale: number;
3134
+ readonly rotation: 0 | 90 | 180 | 270;
3135
+ readonly zoom: number;
3136
+ };
3137
+ toPagePoint(clientX: number, clientY: number): PointerPoint;
3138
+ }
3139
+ /** The sample the listener hands the hub: structurally the interaction plugin's `PointerSample`. */
3140
+ interface PagePointerSample {
3141
+ phase: 'down' | 'move' | 'up';
3142
+ viewport: PointerPoint;
3143
+ page: {
3144
+ ref: PageRef;
3145
+ point: PointerPoint;
3146
+ scale: number;
3147
+ rotation: 0 | 90 | 180 | 270;
3148
+ zoom: number;
3149
+ };
3150
+ project: (page: PageRef) => PointerPoint | null;
3151
+ modifiers: {
3152
+ shift: boolean;
3153
+ alt: boolean;
3154
+ ctrl: boolean;
3155
+ meta: boolean;
3156
+ };
3157
+ clickCount: number;
3158
+ pointerType: 'mouse' | 'pen' | 'touch';
3159
+ }
3160
+ /** What the listener needs from the interaction hub; `InteractionHostCapability` satisfies it. */
3161
+ interface PagePointerHub {
3162
+ dispatchPointer(sample: PagePointerSample): void;
3163
+ }
3164
+ /**
3165
+ * Listen to the pointer on `element` for the page `page()` gives when an event arrives (a zoom
3166
+ * changes it, and a drag carries on through it), and dispatch every event to `hub`. A press
3167
+ * starts on the element; while it lasts the window listens, so a drag goes on outside the page.
3168
+ * Returns the function that stops listening.
3169
+ */
3170
+ declare function attachPagePointer(element: HTMLElement, hub: PagePointerHub, page: () => PagePointerPage): () => void;
3171
+ //#endregion
3172
+ //#region src/scrollbar.d.ts
3173
+ /**
3174
+ * A Stage scrollbar's geometry and its press handling, shared by every framework's `Scrollbar`.
3175
+ *
3176
+ * The Stage gives its scroll position as a scrolling element has it (`scrollTop`,
3177
+ * `scrollHeight`, `clientHeight` and their horizontal twins, in screen pixels). From that and the
3178
+ * measured track this module draws the thumb, and turns presses into Stage calls the way a native
3179
+ * bar does: a thumb drag keeps the point it grabbed under the pointer, and a press on the track
3180
+ * pages toward the pointer, repeating while held and stopping when the thumb reaches it. A drag
3181
+ * is frozen at the press (grab point, travel, range) and applied as relative pans: absolute in
3182
+ * feel on a bounded Stage, and steady on an unbounded one, whose range moves under the pointer.
3183
+ *
3184
+ * The adapters keep their reactive glue: the track's size, auto-hide, hover and the markup.
3185
+ */
3186
+ /** The scroll position a Stage reports (`ScrollMetrics` from the stage plugin satisfies it). */
3187
+ interface ScrollbarMetrics {
3188
+ readonly scrollLeft: number;
3189
+ readonly scrollTop: number;
3190
+ readonly scrollWidth: number;
3191
+ readonly scrollHeight: number;
3192
+ readonly clientWidth: number;
3193
+ readonly clientHeight: number;
3194
+ }
3195
+ /** The bar along one axis, in track pixels. */
3196
+ interface ScrollbarLayout {
3197
+ /** The view's length along the axis. */
3198
+ client: number;
3199
+ /** How far the view is scrolled. */
3200
+ offset: number;
3201
+ /** The farthest it can scroll. */
3202
+ maxOffset: number;
3203
+ thumbLength: number;
3204
+ /** How far the thumb can move along the track. */
3205
+ travel: number;
3206
+ thumbPosition: number;
3207
+ }
3208
+ /**
3209
+ * The thumb from the metrics and the track's length: one formula for drawing, dragging and
3210
+ * paging, so they never disagree. The thumb never gets shorter than `minThumbSize`, and its
3211
+ * position stays proportional over the travel that leaves.
3212
+ */
3213
+ declare function scrollbarLayout(metrics: ScrollbarMetrics, vertical: boolean, trackPx: number, minThumbSize: number): ScrollbarLayout;
3214
+ /** The Stage calls a scrollbar makes; `StageCapability` satisfies it. */
3215
+ interface ScrollbarStage {
3216
+ scrollTo(position: {
3217
+ top?: number;
3218
+ left?: number;
3219
+ }): void;
3220
+ scrollBy(delta: {
3221
+ top?: number;
3222
+ left?: number;
3223
+ }): void;
3224
+ panBy(dx: number, dy: number): void;
3225
+ }
3226
+ /** The bar as it is at a press: what the press handlers read. */
3227
+ interface ScrollbarTrack {
3228
+ readonly stage: ScrollbarStage;
3229
+ readonly vertical: boolean;
3230
+ /** The track element: pointer positions are measured from its start. */
3231
+ readonly element: Element;
3232
+ /** The layout drawn now. */
3233
+ readonly layout: ScrollbarLayout;
3234
+ /** The layout from the Stage's metrics as they are now, for each paging step. */
3235
+ liveLayout(): ScrollbarLayout;
3236
+ }
3237
+ /**
3238
+ * The pointer event a press handler reads: a DOM `PointerEvent`, or a framework's own event
3239
+ * with the same members (React's), so `stopPropagation` and `currentTarget` mean what the
3240
+ * framework's handlers mean.
3241
+ */
3242
+ interface ScrollbarPointerEvent {
3243
+ readonly button: number;
3244
+ readonly pointerId: number;
3245
+ readonly clientX: number;
3246
+ readonly clientY: number;
3247
+ readonly target: EventTarget | null;
3248
+ readonly currentTarget: EventTarget | null;
3249
+ preventDefault(): void;
3250
+ stopPropagation(): void;
3251
+ }
3252
+ /** A scrollbar's presses: wire the thumb's and the track's pointer events to these. */
3253
+ interface ScrollbarPresses {
3254
+ /** A press on the thumb starts a drag. */
3255
+ pressThumb(event: ScrollbarPointerEvent, track: ScrollbarTrack): void;
3256
+ /**
3257
+ * A press on the track itself: `'page'` steps 90% of a view toward the pointer, repeats while
3258
+ * held and stops at the pointer; `'jump'` puts the thumb under the pointer and goes on as a
3259
+ * drag. A press that reached the track from the thumb is the thumb's.
3260
+ */
3261
+ pressTrack(event: ScrollbarPointerEvent, track: ScrollbarTrack, mode: 'page' | 'jump'): void;
3262
+ /** A pointer move on the track (pointer capture sends them there): drags, and paging's target. */
3263
+ move(event: ScrollbarPointerEvent, track: ScrollbarTrack): void;
3264
+ /** The press ended: no drag, no repeat. Also call it when the bar goes away. */
3265
+ release(): void;
3266
+ }
3267
+ /**
3268
+ * One scrollbar's press handling. `onDragging` hears when a drag starts and ends, for the bar's
3269
+ * `data-dragging` and to keep it shown.
3270
+ */
3271
+ declare function createScrollbarPresses(onDragging: (dragging: boolean) => void): ScrollbarPresses;
3272
+ //#endregion
3273
+ //#region src/orientation.d.ts
3274
+ /**
3275
+ * Which way a row of controls runs, and which way its text reads: what a
3276
+ * toolbar measures along, and what its arrow keys move along.
3277
+ */
3278
+ /** A row of controls side by side, or one under another (`aria-orientation`'s values). */
3279
+ type Orientation = 'horizontal' | 'vertical';
3280
+ /** The writing direction an element lays out in: its computed CSS `direction`. */
3281
+ declare function directionOf(element: Element): 'ltr' | 'rtl';
3282
+ //#endregion
3283
+ //#region src/toolbar-measure.d.ts
3284
+ /** The keys the measurement layer reports lengths under, the ones the metrics look up. */
3285
+ declare const toolbarMeasureKey: {
3286
+ /** A unit (`NormalizedUnit.key`) at one variant. */
3287
+ readonly unit: (unitKey: string, variant: string) => string;
3288
+ /** A group in its collapsed form. */
3289
+ readonly group: (groupId: string) => string;
3290
+ /** A shed group's disclosure trigger, measured with the whole group behind it. */
3291
+ readonly groupTrigger: (groupId: string) => string;
3292
+ /** The "More" button. */
3293
+ readonly overflowTrigger: "t:";
3294
+ };
3295
+ /** The lengths a fit needs: the structural twin of core-ui's `FitMetrics`. */
3296
+ interface ToolbarFitMetrics {
3297
+ unit(key: string, variant: string): number | undefined;
3298
+ groupCollapsed(groupId: string): number | undefined;
3299
+ groupTrigger(groupId: string): number | undefined;
3300
+ readonly overflowTrigger: number;
3301
+ readonly gap: number;
3302
+ readonly separator: number;
3303
+ }
3304
+ /**
3305
+ * The measured lengths of one toolbar, kept apart per orientation: a toolbar
3306
+ * turned on its side never fits with the other axis's numbers.
3307
+ */
3308
+ interface ToolbarLengths {
3309
+ /**
3310
+ * A measured element's length along `orientation`, under its
3311
+ * {@link toolbarMeasureKey}. True when it changed by more than half a pixel:
3312
+ * render (and solve) again.
3313
+ */
3314
+ report(orientation: Orientation, key: string, length: number): boolean;
3315
+ /**
3316
+ * The lengths along `orientation` as fit metrics, for items `gap` px apart
3317
+ * and separators `separatorWidth` px thick (a separator's width is its
3318
+ * thickness, across a horizontal bar or down a vertical one). A separator is
3319
+ * one more flex child: its thickness plus one gap. Until the "More" button
3320
+ * is measured it counts as 32 px.
3321
+ */
3322
+ metrics(orientation: Orientation, gap: number, separatorWidth: number): ToolbarFitMetrics;
3323
+ }
3324
+ declare function createToolbarLengths(): ToolbarLengths;
3325
+ /**
3326
+ * Report an element's width (its border box) now and whenever it resizes. Put
3327
+ * it on every element of a horizontal toolbar's measurement layer, and on a
3328
+ * custom slot's `<slot>` socket, which is measured live where it renders.
3329
+ * Returns the detach.
3330
+ */
3331
+ declare function observeWidth(element: Element, onWidth: (width: number) => void): () => void;
3332
+ /** {@link observeWidth} for a vertical toolbar: an element's border-box height. */
3333
+ declare function observeHeight(element: Element, onHeight: (height: number) => void): () => void;
3334
+ /** An element's length along a toolbar: {@link observeWidth} or {@link observeHeight}. */
3335
+ declare function observeLength(element: Element, orientation: Orientation, onLength: (length: number) => void): () => void;
3336
+ /**
3337
+ * Report the width a toolbar has to fill (its content box) now and whenever
3338
+ * it changes by more than half a pixel. Returns the detach.
3339
+ */
3340
+ declare function observeContentWidth(element: HTMLElement, onWidth: (width: number) => void): () => void;
3341
+ /**
3342
+ * The height a vertical toolbar has to fill, like {@link observeContentWidth}.
3343
+ * The toolbar fits the height it's given, so its container needs one.
3344
+ */
3345
+ declare function observeContentHeight(element: HTMLElement, onHeight: (height: number) => void): () => void;
3346
+ /** The room along a toolbar: {@link observeContentWidth} or {@link observeContentHeight}. */
3347
+ declare function observeContentLength(element: HTMLElement, orientation: Orientation, onLength: (length: number) => void): () => void;
3348
+ //#endregion
3349
+ //#region src/focusable.d.ts
3350
+ /**
3351
+ * Which elements take keyboard focus, for the keyboard models (a toolbar's
3352
+ * stops, a menu's items, a dialog's tab order). Decided from the markup only,
3353
+ * never from layout, so it answers the same before the first paint: `hidden`,
3354
+ * `inert` and `disabled` count; a `display: none` from a stylesheet doesn't.
3355
+ */
3356
+ /** Whether an element can take focus now: focusable markup, not disabled, not hidden or inert. */
3357
+ declare function canTakeFocus(element: Element): boolean;
3358
+ /** Whether Tab stops at an element: it takes focus and its `tabIndex` isn't negative. */
3359
+ declare function isTabbable(element: Element): element is HTMLElement;
3360
+ /**
3361
+ * The elements inside `root` that can take focus, in the order they show: through a `<slot>`,
3362
+ * the page's elements the browser shows there (a web component's slotted children).
3363
+ */
3364
+ declare function focusablesIn(root: ParentNode): HTMLElement[];
3365
+ /** The elements inside `root` that Tab stops at, in document order. */
3366
+ declare function tabbablesIn(root: ParentNode): HTMLElement[];
3367
+ /**
3368
+ * The element that has focus, looking into shadow roots: the document's
3369
+ * `activeElement` is only the outermost shadow host. Null when nothing has
3370
+ * focus (the body).
3371
+ */
3372
+ declare function deepActiveElementOf(doc: Document): Element | null;
3373
+ /**
3374
+ * Whether the element with focus is `container` or inside it, as the page shows it: through
3375
+ * shadow roots, and from an element slotted into a shadow root to its slot, so a control
3376
+ * slotted into a viewer counts as inside the viewer, as its keys do.
3377
+ */
3378
+ declare function containsFocus(container: Element): boolean;
3379
+ /**
3380
+ * Whether a control says it can't be used now, through `disabled` or
3381
+ * `aria-disabled="true"`: the keyboard models pass over it.
3382
+ */
3383
+ declare function isUnavailable(element: Element): boolean;
3384
+ /**
3385
+ * Whether a focused control uses `key` itself, so a keyboard model around it
3386
+ * must leave the key alone: a text field moves its caret with Left, Right,
3387
+ * Home and End; a select changes with Up and Down; a slider takes them all.
3388
+ */
3389
+ declare function usesKey(element: Element, key: string): boolean;
3390
+ //#endregion
3391
+ //#region src/roving-focus.d.ts
3392
+ /** Where a key moves focus in a row. */
3393
+ type RovingMove = 'next' | 'previous' | 'first' | 'last';
3394
+ /** The move `key` asks for in a row running `orientation`, or null for a key the row leaves alone. */
3395
+ declare function rovingMoveOf(key: string, orientation: Orientation, direction: 'ltr' | 'rtl'): RovingMove | null;
3396
+ /**
3397
+ * The index `move` lands on among `count` stops, from `current` (-1 for
3398
+ * none), passing over the stops `available` rejects. With `loop`, next and
3399
+ * previous wrap around the ends; without it they stop there. -1 when there is
3400
+ * nowhere to go.
3401
+ */
3402
+ declare function rovingTargetOf(move: RovingMove, current: number, count: number, available: (index: number) => boolean, loop: boolean): number;
3403
+ interface RovingFocusOptions {
3404
+ /** Which arrows move: Left and Right for `'horizontal'`, Up and Down for `'vertical'`. */
3405
+ readonly orientation: Orientation;
3406
+ /** The stops, in order; read again on every key and every {@link RovingFocus.refresh}. */
3407
+ readonly stops: () => readonly HTMLElement[];
3408
+ /** The writing direction. Default: the container's computed `direction`, read on each key. */
3409
+ readonly direction?: () => 'ltr' | 'rtl';
3410
+ /** Whether next and previous wrap around at the ends. Default true. */
3411
+ readonly loop?: boolean;
3412
+ }
3413
+ /** A row's roving focus, from {@link attachRovingFocus}. */
3414
+ interface RovingFocus {
3415
+ /**
3416
+ * Put the one tab stop back after the stops changed: on the stop that had
3417
+ * focus last while it's still there and usable, else on the first usable
3418
+ * one. Call it after every render that can add, remove or disable a stop.
3419
+ */
3420
+ refresh(): void;
3421
+ /** Stop handling keys and focus. The stops keep their `tabIndex`. */
3422
+ detach(): void;
3423
+ }
3424
+ /**
3425
+ * Make the stops of `container` one tab stop with arrow keys between them.
3426
+ * Keys count only while a stop itself has focus, so keys inside a menu or
3427
+ * another control the row holds are theirs; a key with Alt, Control, Meta or
3428
+ * Shift, or one a handler already took (`defaultPrevented`), is left alone.
3429
+ */
3430
+ declare function attachRovingFocus(container: HTMLElement, options: RovingFocusOptions): RovingFocus;
3431
+ //#endregion
3432
+ //#region src/toolbar-focus.d.ts
3433
+ /** The attribute on the element around each item of a toolbar's live row. */
3434
+ declare const TOOLBAR_ITEM_ATTRIBUTE = "data-epdf-toolbar-item";
3435
+ /**
3436
+ * A toolbar's stops: the first element of each item that takes focus, in
3437
+ * order. A menu an item holds open is not part of its stop.
3438
+ */
3439
+ declare function toolbarStopsOf(toolbar: ParentNode): HTMLElement[];
3440
+ /** Arrow keys between a toolbar's items, along its orientation; `refresh()` after each render. */
3441
+ declare function attachToolbarFocus(toolbar: HTMLElement, orientation: Orientation): RovingFocus;
3442
+ //#endregion
3443
+ //#region src/menu-keys.d.ts
3444
+ /**
3445
+ * The item typeahead lands on: the first one from `current` on, wrapping, that
3446
+ * is available and whose label starts with `query` (any case). A one-letter
3447
+ * query starts after `current`, so typing the same letter again moves on, and
3448
+ * a query of one letter repeated ("ppp") cycles like that letter. -1 when no
3449
+ * item matches.
3450
+ */
3451
+ declare function typeaheadMatchOf(labels: readonly string[], current: number, query: string, available: (index: number) => boolean): number;
3452
+ /**
3453
+ * The words typeahead matches an item by: its `aria-label`, else its text,
3454
+ * without the marks a row may start with (a bullet, a check, an icon glyph).
3455
+ */
3456
+ declare function menuItemLabelOf(item: Element): string;
3457
+ interface MenuKeysOptions {
3458
+ /** The button that opened the menu: it says it's expanded, and gets focus back. */
3459
+ readonly trigger: HTMLElement | null;
3460
+ /** Close the menu; removing it is the caller's. */
3461
+ readonly close: () => void;
3462
+ /** The items, in order. Default: the menu's `menuitem`, `menuitemradio` and `menuitemcheckbox` elements. */
3463
+ readonly items?: () => readonly HTMLElement[];
3464
+ /** Which item takes focus when the menu opens. Default `'first'`. */
3465
+ readonly initialFocus?: 'first' | 'last' | 'none';
3466
+ }
3467
+ /**
3468
+ * Drive an open `menu` from the keyboard until the returned detach runs.
3469
+ * Detaching (the menu closed) gives focus back to the trigger when focus was
3470
+ * in the menu or went nowhere, and never when the user moved it elsewhere.
3471
+ */
3472
+ declare function attachMenuKeys(menu: HTMLElement, options: MenuKeysOptions): () => void;
3473
+ //#endregion
3474
+ //#region src/focus-trap.d.ts
3475
+ /**
3476
+ * Move focus into `container` unless it's there already: to `initialFocus`, else its first
3477
+ * control Tab stops at, else the container itself. Focus already inside stays where it is, so a
3478
+ * control that took focus as it appeared (a search field asking for the cursor) keeps it.
3479
+ */
3480
+ declare function moveFocusInto(container: HTMLElement, initialFocus?: HTMLElement | null): void;
3481
+ interface FocusTrapOptions {
3482
+ /**
3483
+ * What takes focus when the trap starts, unless focus is inside already. Default: the first
3484
+ * control Tab stops at.
3485
+ */
3486
+ readonly initialFocus?: HTMLElement | null;
3487
+ /** Whether focus goes back to where it was when the trap is released. Default true. */
3488
+ readonly returnFocus?: boolean;
3489
+ }
3490
+ /** Trap focus in `container` until the returned release runs. */
3491
+ declare function attachFocusTrap(container: HTMLElement, options?: FocusTrapOptions): () => void;
3492
+ //#endregion
3493
+ //#region src/surface-focus.d.ts
3494
+ /**
3495
+ * Putting the cursor in a panel when it asks. The shell raises a surface's `focusRequest` on
3496
+ * every `open(id, { focus: true })` and clears it when the surface closes; the element that
3497
+ * follows it takes focus whenever the request changes to a new value above 0, and when it starts
3498
+ * following while the request is up (the panel opened, or its code loaded, because of it). The
3499
+ * adapters' surface-focus hooks bind a follower to their reactivity; the rule lives here.
3500
+ */
3501
+ /** How an element takes focus when its surface asks. */
3502
+ interface SurfaceFocusOptions {
3503
+ /** Select the text of an input or a text area as it takes focus, so typing replaces it. */
3504
+ readonly select?: boolean;
3505
+ }
3506
+ /** One element following one surface's focus requests. */
3507
+ interface SurfaceFocusFollower {
3508
+ /**
3509
+ * Take the surface's request as it is now. `shell` is the capability it was read from (null
3510
+ * without a document): another document's shell starts over, as a new mount does. Without an
3511
+ * element yet, a request waits for it.
3512
+ */
3513
+ follow(element: HTMLElement | null, shell: object | null, request: number, options?: SurfaceFocusOptions): void;
3514
+ }
3515
+ declare function createSurfaceFocusFollower(): SurfaceFocusFollower;
3516
+ //#endregion
3517
+ //#region src/standard-commands-platform.d.ts
3518
+ /** What the standard commands need from the browser: the structural twin of `StandardCommandsPlatform`. */
3519
+ interface StandardCommandsBrowser {
3520
+ copySelection: typeof copySelection;
3521
+ saveFile(bytes: Uint8Array, fileName: string): void;
3522
+ print(): void;
3523
+ }
3524
+ declare const standardCommandsBrowser: StandardCommandsBrowser;
3525
+ //#endregion
3526
+ export { type ActionsUiAdapterShape, type ActionsUiEffectContext, type ActionsUiOrigin, type AnchorTarget, type AnchoredFit, type AnchoredOptions, type AnchoredPlacement, type AnchoredPoint, type AnchoredPosition, type AnchoredRect, type AnchoredSide, type AnchoredSize, type AnnotationAnchorShape, type AnnotationChromePaint, type AnnotationDrawing, type AnnotationLookFrame, type AppearancePicture, type AppearanceUrl, type AttachSelectionHandleOptions, type BehaviorRendererEntry, type ByteStore, type ChromeInPixels, type ChromeLine, type ChromeLinePaint, type ChromeNodeShape, type ChromePaintSettings, type ChromeShapePaint, type ClickDetector, type ClientBox, type ClientProjectedPage, type ClipboardSelectionSource, type CommandShortcutOptions, type CommentPageLayout, type CommentThreadPage, type CreationDraftAnchorShape, type CssFont, type DefaultActionsUiAdapterOptions, EPDF_VARIABLES, type EditorDocumentFactory, type EditorElement, type EditorNode, type EditorPosition, type EditorRoot, type EditorStyle, type EpdfCssOnlyVariable, type EpdfFollowedVariable, type EpdfSettingVariable, type EpdfTheme, type EpdfThemeVariables, type EpdfTranslucentVariable, type EpdfVariable, type EpdfVariableDefinition, FORM_CONTROL_FILL, type FieldLook, type FieldTextStyle, type FilePickerPort, type FocusTrapOptions, type FormColorSettings, type FormColors, type FormControlFill, type FormFocusRingStyle, type FrameBox, type FrameFraction, type FramePixels, type IndexedDbByteStoreOptions, type LineModel, type LinkActionDispatcher, type LinkActionSource, type LinkAnchor, type LinkAnchorEvent, type LinkAnchorShape, type LinkEventShape, type LinkHoverPump, type ListBoxControlStyle, type ListBoxStyle, type LookRendererEntry, type LookState, type MenuKeysOptions, type MountableFontProgram, type ObjectUrl, type ObjectUrlImageSource, type OptimisticSelection, type Orientation, type PageBoundsAnchor, type PageClientSpace, type PageContext, type PageContextTransform, type PageFrameShape, type PageLayerTransform, type PageLayers, type PagePart, type PagePoint, type PagePointerHub, type PagePointerPage, type PagePointerSample, type PageQuad, type PageRef, type PageSurfaceLayout, type PageToPixels, type PageViewEnv, type PageViewPage, type PageViewTransformInput, type PaintedImageCallbacks, type PaintedParts, type PartRights, type PickFileOptions, type PictureBytes, type PictureLayerOptions, type PictureOrPainting, type PicturePartProps, type PixelBox, type PixelRect, type ProjectedTransform, type RendererBehaviorRegistry, type RendererEntry, type RendererInteractiveContext, type RichTextEditorAlign, type RichTextEditorBinding, type RichTextEditorCommand, type RichTextEditorDecoration, type RichTextEditorDocument, type RichTextEditorHost, type RichTextEditorParagraph, type RichTextEditorProps, type RichTextEditorRange, type RichTextEditorRun, type RichTextEditorScript, type RichTextEditorStyle, type RotationAnchorShape, type RovingFocus, type RovingFocusOptions, type RovingMove, type ScenePaint, type SceneShapeNode, type ScrollbarLayout, type ScrollbarMetrics, type ScrollbarPointerEvent, type ScrollbarPresses, type ScrollbarStage, type ScrollbarTrack, type SearchHighlightOptions, type SearchHighlightPiece, type SearchHitShape, type SelectOptions, type SelectionAnchorShape, type SelectionClipboardOptions, type SelectionEndpointShape, type SelectionEndpointsShape, type SelectionHandleSession, type ShortcutCommands, type ShortcutRefusal, type ShownUrls, type StageDemandSource, type StageGestureHost, type StageGestureOptions, type StageGestureSink, type StagePageDemand, type StagePointerKind, type StageProjection, type StageSurfaceHost, type StageSurfaceHub, type StageSurfaceOptions, type StageSurfaceSample, type StageWheelSample, type StandardCommandsBrowser, type StyleRecord, type SurfaceBox, type SurfaceFocusFollower, type SurfaceFocusOptions, type SurfaceTransform, type SvgCursorOptions, type SvgShape, type SvgShapeTag, type SvgShapesOptions, TOOLBAR_ITEM_ATTRIBUTE, type TextBoxCss, type TextBoxEditor, type TextBoxEditorAnnotation, type TextBoxEditorFollower, type TextBoxEditorItem, type TextBoxStyle, type TextEditorLayout, type TextFieldDrafts, type TextFieldEditor, type TextFieldEditorState, type TextFieldEditorStyle, type TextFieldStyle, type TextPlatePixels, type ToggleForm, type ToolCursorImage, type ToolCursorSpec, type ToolbarFitMetrics, type ToolbarLengths, type TurnedBox, type ViewProjector, type WebClock, type WebFontMetrics, type WebPlatformFeedback, type WheelSample, type WidgetBoxStyle, type WidgetEventKind, anchoredViewOf, annotationChromePaint, annotationDrawingOf, applyFirstLineShift, attachFocusTrap, attachMenuKeys, attachPagePointer, attachRichTextEditor, attachRovingFocus, attachSelectionHandle, attachTextBoxEditor, attachToolbarFocus, bakedAppearanceOf, bindCommandShortcuts, bindPaintedImage, bindWidgetEvents, browserClock, canTakeFocus, chromeInPixels, clientPageProjector, computeReleaseVelocity, containsFocus, copySelection, createClickCounter, createClickDetector, createDefaultActionsUiAdapter, createFontMounts, createOptimisticSelection, createScrollbarPresses, createShownUrls, createStageGestureController, createStageSurface, createSurfaceFocusFollower, createTextBoxEditorFollower, createTextFieldEditor, createToolbarLengths, cssFontOf, cssText, deepActiveElementOf, directionOf, editingTextKeyOf, enrichCommentThreads, epdfThemeVariables, firstLineShiftFor, fitAnchoredRect, focusablesIn, fontProgramsOf, formColorsOf, formFocusRingStyleOf, frameInPixels, ghostOpacity, hoverLink, indexedDbByteStore, installFilePickerProvider, isMacPlatform, isModifiedClick, isTabbable, isUnavailable, isUprightQuad, isolatePointerDown, isolateWheel, layerTextBoxesOf, lineModelFor, linkActivateContextOf, linkAnchorOf, linkHrefOf, listBoxControlStyleOf, listBoxStyleOf, livePageContext, loadAppearanceUrls, loadObjectUrl, lookFrameOf, lookRendererFor, makePageContext, menuItemLabelOf, mixAccent, mountFontProgram, mountWebFont, moveFocusInto, navigableLinksOf, objectUrlOf, observeAnchoredFit, observeClientGeometry, observeContentHeight, observeContentLength, observeContentWidth, observeHeight, observeLength, observeOutsidePress, observeWidth, offsetOfPosition, openExternalUri, pageClientSpace, pageLayersOf, pageSurfaceLayout, pageViewTransformInput, paint, paintDefault, partsDrawnTwice, pickFile, pickImageFile, pickRequestedFile, pictureLayerOptionsOf, pictureOrPainting, positionAnchoredRect, positionOfOffset, pressToggle, projectAnchoredTarget, quadInPixels, rasterInFrame, rectInPixels, registerRendererBehaviors, renderRichText, rendererBehaviorId, rovingMoveOf, rovingTargetOf, sameAnchoredFit, sameAnnotationAnchor, sameCreationDraftAnchor, samePageBounds, sameRotationAnchor, sameSelectionAnchor, sameSelectionEndpoints, sanitizeExternalUri, saveFile, sceneViewBox, scrollbarLayout, searchHighlightsOf, sendLinkEvent, serializeRichText, showSelectedOptions, shownAppearance, stagePageDemand, stageViewProjector, standardCommandsBrowser, styleDeltaOf, svgCursor, svgPoints, svgShapesOf, tabbablesIn, textBoxEditorScaleOf, textBoxStyleOf, textFieldEditorStyleOf, textFieldStyleOf, textPlateInPixels, toolCursorsOf, toolbarMeasureKey, toolbarStopsOf, typeaheadMatchOf, usesKey, vibrationFeedback, webFontMetrics, wheelZoomFactor, widgetBoxStyleOf, wireSelectionClipboard, wkFeedback };
852
3527
  //# sourceMappingURL=index.d.cts.map