@embedpdf/plugin-stage 3.0.0-next.1 → 3.0.0-next.11

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.ts CHANGED
@@ -1,503 +1,9 @@
1
- import { CapabilityToken, PageLayout, PageObjectNumber, PdfDestination } from "@embedpdf/core";
2
- import { Align, AlignValue, Alignment, Alignment as Alignment$1, AlignmentValue, Anchor, Camera, Direction, Direction as Direction$1, PageBox, PageFrame, PageFrame as PageFrame$1, Point, ScrollMetrics, ScrollMetrics as ScrollMetrics$1, Size, SizingMode, SizingMode as SizingMode$1, SpreadMode, SpreadMode as SpreadMode$1, ZoomMode, ZoomModeValue, ZoomModeValue as ZoomModeValue$1, ZoomSpec, ZoomSpec as ZoomSpec$1 } from "@embedpdf/core-stage";
3
- import { PageRotation, PageTransform, Rect } from "@embedpdf/core-geometry";
4
- //#region src/types.d.ts
5
- type LayoutKind = 'vertical' | 'horizontal' | 'grid';
6
- /** Navigation (goToPage) either tweens the camera or jumps instantly. */
7
- type ScrollBehaviorKind = 'smooth' | 'instant';
8
- /**
9
- * Presentation flow:
10
- * 'continuous' — the whole document is scrollable; the camera roams the full scene.
11
- * 'paged' — one item (page or spread) at a time: the scene is a one-item
12
- * slice at the cursor, and next/prev step between items.
13
- */
14
- type FlowMode = 'continuous' | 'paged';
15
- /**
16
- * Grid column policy:
17
- * 'square' — ≈√n columns (the classic canvas arrangement)
18
- * 'auto' — WRAPPED: as many columns as fit the viewport line at the current
19
- * zoom (the responsive thumbnail-sidebar behavior; re-wraps on resize)
20
- * number — a fixed column count
21
- */
22
- type GridColumns = 'square' | 'auto' | number;
23
- /**
24
- * Space between items — the value's shape carries the unit (like ZoomSpec):
25
- * number — WORLD units: the gap is part of the canvas and scales with zoom,
26
- * so the whole scene zooms as one rigid object (the document feel).
27
- * { px: n } — SCREEN px: UI-stable spacing, the same in every document at every
28
- * zoom (the browser-of-items feel: thumbnails, organizers).
29
- */
30
- type Gap = number | {
31
- px: number;
32
- };
33
- /**
34
- * One axis of the ARRIVAL policy — stage-core's AlignValue ('start' |
35
- * 'center' | 'end' | viewport fraction 0–1) plus one navigation-only word:
36
- * 'keep' — this axis does not move on arrival: page forward, hold your
37
- * pan (the two-column-paper feel; the PDF /XYZ null semantic).
38
- */
39
- type ArrivalAlignValue = AlignValue | 'keep';
40
- interface ArrivalAlignment {
41
- x: ArrivalAlignValue;
42
- y: ArrivalAlignValue;
43
- }
44
- /**
45
- * The Stage's orthogonal, independently-settable primitives. Every field can be set
46
- * on its own (setLayout, setBounded, …) or several at once via `update()`. A
47
- * "preset" is just a `Partial<StageSettings>` the app keeps and applies — no preset
48
- * machinery lives here.
49
- */
50
- interface StageSettings {
51
- /** Continuous scroll, or one item at a time. */
52
- flow: FlowMode;
53
- layout: LayoutKind;
54
- spread: SpreadMode$1;
55
- /** Page sizing: true PDF sizes, or equalize the cross axis so pages sit flush. */
56
- sizing: SizingMode$1;
57
- /** Grid column policy (grid layout only): 'square', 'auto' (wrapped), or a count. */
58
- columns: GridColumns;
59
- /** Clamp the camera to the content? Off = free infinite pan (plans / CAD). */
60
- bounded: boolean;
61
- /**
62
- * Breathing room (screen px) around the content — the one spacing concept.
63
- * Fit-modes inset by it, arrivals leave it as a gutter, and the clamp lets the
64
- * camera reveal exactly this much beyond each content edge.
65
- */
66
- padding: number;
67
- /**
68
- * Space BETWEEN items — and between the halves of a spread. A number is world
69
- * units (scales with zoom — the canvas feel); `{ px }` is screen px (UI-stable
70
- * — the thumbnail feel). See {@link Gap}.
71
- */
72
- gap: Gap;
73
- /**
74
- * Reserved chrome real estate around EACH PAGE, in SCREEN px — one thickness
75
- * per side. The page content is inset by these; the bands hold box-space
76
- * chrome (a label below, a button row above, side rails) painted by the app
77
- * via the adapter's `pageChrome` slot. Per page, not per item: in a spread
78
- * every page keeps its own flanks. Constant screen px (unaffected by zoom).
79
- *
80
- * Naming rule for this settings bag: every setting describes the STAGE itself
81
- * (the container) — `padding`, `gap`, `layout`, … The rare setting owned by the
82
- * page carries the `page` prefix (`pageFrame`; `pageWidth` in zoom).
83
- */
84
- pageFrame: PageFrame$1;
85
- /**
86
- * Reading direction. RTL: horizontal items advance leftward, spreads bind on the
87
- * right, grid rows fill right→left, and alignment 'start' on x means the RIGHT
88
- * edge (logical, CSS-style). Navigation is index-based and never changes.
89
- */
90
- direction: Direction$1;
91
- /**
92
- * The alignment family — EVERY camera move is defined by what it holds
93
- * fixed. Gestures (pan/pinch/wheel) hold the pointer: physics, no setting.
94
- * Explicit arrivals (positioned reveal, destinations, viewpoints) hold
95
- * whatever the call specifies. These four settings govern the rest:
96
- *
97
- * fitAlign — the standing CONSTRAINT: where content rests on an axis
98
- * the camera cannot travel (it fits the TRUE bounds — the
99
- * scene in continuous flow, the item slice in paged). The
100
- * clamp enforces it on every camera write — which is why a
101
- * fitting axis settles identically whatever arrivalAlign
102
- * says. center/center = document feel; y:'start' = sidebar
103
- * thumbnails hugging the top.
104
- * arrivalAlign — the landing POLICY: where navigation (goToPage, next/
105
- * prev, reset) puts the target — THE SAME at every zoom.
106
- * start/start = reading (top-left, direction-aware);
107
- * center/center = presentation/drawings (Drawboard feel);
108
- * y: 0.35 = the find-bar line; 'keep' = don't move an axis.
109
- * zoomAlign — the FOCAL point of a pointer-less zoom (zoomIn/zoomOut,
110
- * zoomTo, fit-mode switches). Pinch/ctrl+wheel always hold
111
- * the pointer instead — that is physics, not policy.
112
- * center/center = the view inflates around its middle;
113
- * y:'start' = the first visible line holds still.
114
- * anchorAlign — the viewport point that SURVIVES a reframe (viewport
115
- * resize, page rotation, spread/gap change): the view
116
- * anchor is captured there and restored there. start/start
117
- * = the browser scroll model (growth reveals below — a
118
- * container that mounts small and expands never shoves the
119
- * document down); center/center = canvas-style symmetric
120
- * resizes (the Figma feel).
121
- *
122
- * Named x values are LOGICAL (CSS-style: 'start' = reading start — the
123
- * right edge in RTL); fractions are physical, like screen coordinates.
124
- */
125
- fitAlign: Alignment$1;
126
- /** See {@link StageSettings.fitAlign} — where navigation lands, per axis. */
127
- arrivalAlign: ArrivalAlignment;
128
- /** See {@link StageSettings.fitAlign} — the pointer-less zoom focal point. */
129
- zoomAlign: AlignmentValue;
130
- /** See {@link StageSettings.fitAlign} — the viewport point reframes hold. */
131
- anchorAlign: AlignmentValue;
132
- /**
133
- * NON-PERSISTENT view rotation: a quarter-turn (clockwise) applied to how
134
- * EVERY page is DISPLAYED in this lens, on top of each page's own /Rotate —
135
- * Adobe's "Rotate View". A display setting like `zoom` or `layout`: per lens
136
- * (the main viewer can rotate while a thumbnail lens stays upright), never
137
- * written to the document, gone when the lens resets. The PERMANENT
138
- * counterpart — writing /Rotate into the PDF — is plugin-page-edit's
139
- * `rotateBy`/`setRotation`.
140
- */
141
- viewRotation: PageRotation;
142
- /** Zoom intent: a fit-mode (automatic/fit-page/fit-width/fit-all) or a fixed level. */
143
- zoom: ZoomSpec$1;
144
- /** Default behaviour for goToPage/next/prev. */
145
- scrollBehavior: ScrollBehaviorKind;
146
- /**
147
- * View pixels per PDF point — the platform's physical unit factor, folded into
148
- * the layout so 100% (zoom 1) is physically accurate. Web = 96/72 (1 pt = 1/72",
149
- * 1 CSS px = 1/96"); a native platform injects its own (iOS pt, Android dp). It
150
- * scales every page's world size (and thus `contentScale`), so the camera math,
151
- * `gap`/`padding`/`pageFrame` (world units), and absolute-px zoom modes
152
- * (`pageWidth`) are all unaffected — only the pages themselves resize.
153
- */
154
- viewUnitsPerPoint: number;
155
- }
156
- /**
157
- * A laid-out page handed to the shell.
158
- * - PageBox + `pon`: LAYOUT truth (world coords + identity) — the shell uses
159
- * `x/y/width/height` only to POSITION the page container.
160
- * - `transform`: PRESENTATION truth — the single bridge between PDF points,
161
- * view px, and device px for this page. Plugins do ALL coordinate work
162
- * through it (`pageToView` / `viewToPage` / `deviceWidth` / `cssMatrix`),
163
- * never by re-deriving `x * scale` / `* dpr`. Page-local, so it's
164
- * camera/pan-invariant.
165
- */
166
- interface VisiblePage extends PageBox {
167
- pon: PageObjectNumber;
168
- /**
169
- * The page's DISPLAY-box (footprint) top-left in screen px, camera-resolved and
170
- * snapped to the device grid. The shell positions the page container at this —
171
- * snapping here (not in the adapter) keeps a CSS-rotated page on the pixel grid
172
- * for every framework, with no hand-rounding.
173
- */
174
- screenX: number;
175
- screenY: number;
176
- transform: PageTransform;
177
- /**
178
- * The page region actually ON SCREEN, in UN-rotated page points (y-down) —
179
- * viewport ∩ footprint inverted through the transform (exact for
180
- * quarter-turns). Zero-sized when the page sits outside the viewport.
181
- * Visibility is the STAGE's data (it already intersects viewport × pages to
182
- * virtualize); adapters and demand consumers (tiling's `PageViewDemand`)
183
- * read it instead of re-deriving camera math per framework.
184
- */
185
- visibleRect: Rect;
186
- }
187
- interface StageState extends StageSettings {
188
- camera: Camera;
189
- vp: Size;
190
- /**
191
- * Device pixels per view pixel (web: `window.devicePixelRatio`). Reported by
192
- * the shell like the viewport; feeds each page's transform so bitmaps render
193
- * crisp (exact device px) and boxes land on the device grid. Defaults to 1.
194
- */
195
- dpr: number;
196
- /**
197
- * The current page — transient like `camera` (NOT a setting), valid in BOTH flows.
198
- * Navigation sets it; in continuous flow scrolling syncs it from the camera; in
199
- * paged flow panning never moves it (the scene is a one-item slice at this page).
200
- * Stored as a page index so it survives spread/layout regrouping.
201
- */
202
- cursor: number;
203
- }
204
- type StageAction = {
205
- type: 'CAMERA';
206
- camera: Camera;
207
- } | {
208
- type: 'VP';
209
- vp: Size;
210
- } | {
211
- type: 'DPR';
212
- dpr: number;
213
- } | {
214
- type: 'CURSOR';
215
- cursor: number;
216
- } | {
217
- type: 'PATCH';
218
- patch: Partial<StageSettings>;
219
- };
220
- /**
221
- * A page-relative view memento: "what I'm looking at and how zoomed". The durable
222
- * currency for per-page view memory (construction worksheets) — capture with
223
- * `viewpoint()`, restore with `goToPage(i, { viewpoint })`. Survives resizes
224
- * because the anchor is page-relative and fit-modes re-resolve.
225
- */
226
- interface Viewpoint {
227
- anchor: Anchor;
228
- zoom: ZoomSpec$1;
229
- }
230
- /** Durable, serializable view state — the unit of session persistence. */
231
- interface StageViewState extends StageSettings {
232
- cursor: number;
233
- anchor: Anchor;
234
- }
235
- /**
236
- * Host timing seam. The pure core (stage-core) never touches time; the camera tween
237
- * lives in this (impure) shell and asks for frames through a Scheduler. The default
238
- * is the browser's requestAnimationFrame; inject a fake in tests, or an instant one
239
- * in Node/SSR.
240
- */
241
- interface Scheduler {
242
- /** Run the callback on the next frame; returns a handle for cancellation. */
243
- raf(callback: (timestampMs: number) => void): number;
244
- /** Cancel a scheduled callback. */
245
- caf(handle: number): void;
246
- }
247
- /**
248
- * Options for the scroller writes — `Element.scrollTo` semantics: absolute
249
- * offsets (screen px) into the current scroll range (see
250
- * {@link StageCapability.scrollMetrics}); an omitted axis does not move.
251
- * `behavior` defaults to 'instant' (the DOM's 'auto'), NOT the stage's
252
- * `scrollBehavior` setting — that setting governs navigation verbs, and a
253
- * scrollbar thumb must track the pointer exactly.
254
- */
255
- interface StageScrollToOptions {
256
- left?: number;
257
- top?: number;
258
- behavior?: ScrollBehaviorKind;
259
- }
260
- /** Options for navigation intents. */
261
- interface GoToOptions {
262
- behavior?: ScrollBehaviorKind;
263
- /** Restore this exact viewpoint instead of fresh placement (per-page memory). */
264
- viewpoint?: Viewpoint;
265
- /** Override the landing for THIS navigation only (explicit beats default). */
266
- arrivalAlign?: Partial<ArrivalAlignment>;
267
- }
268
- /**
269
- * One axis of a reveal arrival — `scrollIntoView` vocabulary plus two
270
- * PDF-protocol necessities:
271
- * absent → minimal movement: scroll only if the target is off-screen
272
- * (CSS 'nearest'; today's reveal semantics)
273
- * 'keep' → this axis does not move AT ALL (PDF /XYZ null coordinate)
274
- * 'start' → target edge at the viewport start (plus padding)
275
- * 'center' → target centered
276
- * 'end' → target edge at the viewport end (minus padding)
277
- * number 0–1 → target CENTER at this viewport fraction (0.35 = "top middle",
278
- * the browser find-bar feel)
279
- */
280
- type RevealAnchorValue = 'keep' | 'start' | 'center' | 'end' | number;
281
- interface RevealAnchor {
282
- x?: RevealAnchorValue;
283
- y?: RevealAnchorValue;
284
- }
285
- /**
286
- * What happens to zoom on a reveal — always relative to the reveal's target
287
- * rect (the whole page when no `rect` is given):
288
- * 'keep' → pure pan, zoom untouched (search hits, /XYZ null zoom)
289
- * { level } → explicit factor (/XYZ zoom)
290
- * 'fit' → the rect fully visible (/FitR; /Fit, /FitB via rect=page/bbox)
291
- * 'fit-width' → the rect's width fills the viewport (/FitH, /FitBH)
292
- * 'fit-height' → the rect's height fills the viewport (/FitV, /FitBV)
293
- */
294
- type RevealZoom = 'keep' | 'fit' | 'fit-width' | 'fit-height' | {
295
- level: number;
296
- };
297
- /**
298
- * Options for `reveal` — the follower-UI arrival verb (search hits, outline
299
- * clicks, PDF destinations, "jump to comment").
300
- *
301
- * With none of `rect`/`zoom`/`anchor` set, reveal keeps its original
302
- * semantics: minimal movement to make the page visible, cursor untouched.
303
- * A POSITIONED reveal (any of the three set) is "you are now looking at
304
- * THIS spot": the camera places the target per the anchor, a zoom
305
- * directive resolves to a concrete level (recorded as the zoom intent),
306
- * and the cursor follows the camera — while still clamping against the
307
- * normal camera bounds, so anchors are best-effort near document edges.
308
- */
309
- interface RevealOptions {
310
- behavior?: ScrollBehaviorKind;
311
- /**
312
- * CONTENT-space target rect on the page (y-down, crop-relative, unscaled
313
- * points — the same space selection/search rects live in). Absent → the
314
- * whole page. A zero-size rect is a point (/XYZ).
315
- */
316
- rect?: Rect;
317
- zoom?: RevealZoom;
318
- anchor?: RevealAnchor;
319
- }
320
- /** The Stage's public contract: selectors (reads) + intents (the only writers). */
321
- interface StageCapability {
322
- camera(): Camera;
323
- viewport(): Size;
324
- /**
325
- * The camera as a NATIVE SCROLLER — the DOM scroll vocabulary in screen px:
326
- * `scrollTop`/`scrollHeight`/`clientHeight` (and the x twins) mean exactly
327
- * what they mean on a DOM element; `scrollableX/Y` false ⇔ nothing to scroll
328
- * on that axis (native: no bar). Derived from the SAME travel range the pan
329
- * clamp uses — paged flow reads the one-item slice — so a scrollbar built on
330
- * it can never disagree with where panning stops. On an UNBOUNDED stage the
331
- * range is the union of the padded content and the current window (the Figma
332
- * bar): pan away and it grows, the thumb shrinking toward the edge but always
333
- * remaining a road back. Reference-stable until a field actually changes.
334
- */
335
- scrollMetrics(): ScrollMetrics$1;
336
- pageCount(): number;
337
- visiblePages(): VisiblePage[];
338
- /** The current page (the cursor) — valid in both flows. */
339
- currentPage(): number;
340
- /** The display indices of the current item's pages (1 page, or a spread's pages). */
341
- currentItemPages(): number[];
342
- /** The full page list with PDF labels — for page thumbnails / worksheet tabs. */
343
- pages(): Array<{
344
- index: number;
345
- pon: PageObjectNumber;
346
- label: string | null;
347
- }>;
348
- /** The laid-out box for a page by its durable pon. */
349
- pageRect(pon: PageObjectNumber): VisiblePage | null;
350
- /**
351
- * Screen point (this Stage's container px) → the page under it + its content
352
- * point, or null over a gap. The viewport-level hit-test the interaction hub
353
- * needs so a single pointer source can drive page-aware features (text
354
- * selection, annotations) AND cross-page drags.
355
- */
356
- pageAt(screen: Point): {
357
- pon: PageObjectNumber;
358
- point: Point;
359
- scale: number;
360
- /** The hit page's TOTAL display rotation (document /Rotate + view rotation). */
361
- rotation: PageRotation;
362
- /** The hit page's zoom relative to its 100% baseline (`transform.zoom`). */
363
- zoom: number;
364
- } | null;
365
- /**
366
- * Screen point → `pon`'s content space, UNCLAMPED — valid even when the point
367
- * is outside the page's bounds (coordinates then fall outside `[0, size]`).
368
- * The frame-stable projection a page-anchored gesture (annotation move/resize)
369
- * tracks with, where `pageAt` would re-resolve to whatever page is under the
370
- * cursor (what a cross-page drag like text selection wants). Null when the
371
- * page isn't currently laid out.
372
- */
373
- pointOnPage(pon: PageObjectNumber, screen: Point): Point | null;
374
- /**
375
- * Page space (intrinsic PDF points) → world space. Applies the page's placed
376
- * origin and contentScale — the transform sizing policies introduce. Compose
377
- * with toScreen for viewport-space overlays anchored to page content.
378
- */
379
- pageToWorld(pon: PageObjectNumber, pt: Point): Point | null;
380
- /**
381
- * Content rect on a page → this Stage viewport's screen-space AABB. Applies page
382
- * rotation/contentScale and the current camera. Use for upright viewport overlays
383
- * that need to frame a selected page region.
384
- */
385
- pageRectToScreen(pon: PageObjectNumber, rect: Rect): Rect | null;
386
- toScreen(world: Point): Point;
387
- toWorld(screen: Point): Point;
388
- flow(): FlowMode;
389
- layout(): LayoutKind;
390
- spread(): SpreadMode$1;
391
- sizing(): SizingMode$1;
392
- columns(): GridColumns;
393
- bounded(): boolean;
394
- padding(): number;
395
- gap(): Gap;
396
- pageFrame(): PageFrame$1;
397
- fitAlign(): Alignment$1;
398
- arrivalAlign(): ArrivalAlignment;
399
- zoomAlign(): AlignmentValue;
400
- anchorAlign(): AlignmentValue;
401
- direction(): Direction$1;
402
- scrollBehavior(): ScrollBehaviorKind;
403
- /** The lens's view rotation — see {@link StageSettings.viewRotation}. */
404
- viewRotation(): PageRotation;
405
- zoomLevel(): number;
406
- /** The active zoom intent: a fit-mode, or 'custom' for a fixed level. */
407
- zoomMode(): ZoomModeValue$1 | 'custom';
408
- /** What I'm looking at + zoom intent — capture for per-page view memory. */
409
- viewpoint(): Viewpoint;
410
- /** A snapshot of all settings (handy for building/saving a customer preset). */
411
- settings(): StageSettings;
412
- viewState(): StageViewState;
413
- setViewport(vp: Size): void;
414
- /** Report the device pixel ratio (web: `devicePixelRatio`). The shell calls
415
- * this once on mount and whenever it changes (e.g. dragging between monitors)
416
- * so page transforms render crisp. */
417
- setDevicePixelRatio(dpr: number): void;
418
- setCamera(c: Camera): void;
419
- panBy(dxScreen: number, dyScreen: number): void;
420
- /** `Element.scrollTo` for the camera: absolute offsets into the scroll range
421
- * (see {@link StageScrollToOptions}) — clamped into it, cursor-synced, zoom
422
- * untouched (scrolling is a pan in scroller clothing). */
423
- scrollTo(opts: StageScrollToOptions): void;
424
- /** `Element.scrollBy`: relative offsets — sugar over `scrollTo`. */
425
- scrollBy(opts: StageScrollToOptions): void;
426
- zoomAround(screenPt: Point, factor: number): void;
427
- zoomIn(): void;
428
- zoomOut(): void;
429
- zoomTo(spec: ZoomSpec$1): void;
430
- fitWidth(): void;
431
- fitPage(): void;
432
- /** Fit the whole scene (every page) in view — the construction overview. */
433
- fitAll(): void;
434
- /** Fit width but never upscale past 100% (Adobe's "Automatic"). */
435
- automatic(): void;
436
- /**
437
- * Re-resolve the active zoom intent and re-place against the CURRENT scene,
438
- * preserving the anchored page-point. Call after the page geometry changes
439
- * underneath the lens — rotate/move/delete — so fit/pixel zoom modes
440
- * (`fitPage`, `pageWidth`, …) recompute against the new footprint. A no-op
441
- * before the first placement; for a fixed `{ level }` zoom it just re-anchors.
442
- * Wired automatically to the document's page-registry revision; exposed for
443
- * any external geometry change a host wants to react to.
444
- */
445
- refit(): void;
446
- /** Go to a page. Fresh arrival places by the unit rule; pass `viewpoint` to restore. */
447
- goToPage(pageIndex: number, opts?: GoToOptions): void;
448
- /**
449
- * The follower-UI arrival verb (thumbnail sidebars, search hits, outline
450
- * clicks, PDF destinations). Bare: make the page visible with minimal
451
- * movement — zero if it already is, cursor untouched (scrollIntoView
452
- * semantics; paged flow delegates to navigation since the page isn't in
453
- * the slice). POSITIONED (rect/zoom/anchor set — see {@link RevealOptions}):
454
- * place the target at the anchor, optionally re-zooming; the cursor
455
- * follows the camera.
456
- */
457
- reveal(pageIndex: number, opts?: RevealOptions): void;
458
- /** Step forward by the navigation unit (the item if it fits the viewport, else the page). */
459
- next(opts?: GoToOptions): void;
460
- /** Step backward by the navigation unit. */
461
- prev(opts?: GoToOptions): void;
462
- /** Set any subset of settings at once — ONE anchor-preserving update. The way to
463
- * apply a customer preset: `update(myPreset)`. */
464
- update(patch: Partial<StageSettings>): void;
465
- setFlow(flow: FlowMode): void;
466
- setLayout(layout: LayoutKind): void;
467
- setSpread(spread: SpreadMode$1): void;
468
- setSizing(sizing: SizingMode$1): void;
469
- setColumns(columns: GridColumns): void;
470
- setBounded(bounded: boolean): void;
471
- setPadding(padding: number): void;
472
- setGap(gap: Gap): void;
473
- setPageFrame(pageFrame: PageFrame$1): void;
474
- setFitAlign(fitAlign: Alignment$1): void;
475
- setArrivalAlign(arrivalAlign: ArrivalAlignment): void;
476
- setZoomAlign(zoomAlign: AlignmentValue): void;
477
- setAnchorAlign(anchorAlign: AlignmentValue): void;
478
- setDirection(direction: Direction$1): void;
479
- /** Set the lens's view rotation to an absolute quarter-turn — see
480
- * {@link StageSettings.viewRotation}. An anchor-preserving reframe, like a
481
- * page rotation: the spot you were looking at stays put (`anchorAlign`). */
482
- setViewRotation(viewRotation: PageRotation): void;
483
- /** Rotate the view a quarter-turn from where it is (the toolbar verb) —
484
- * relative sugar over {@link setViewRotation}, mirroring page-edit's `rotateBy`. */
485
- rotateView(delta: 90 | -90): void;
486
- setScrollBehavior(behavior: ScrollBehaviorKind): void;
487
- applyViewState(view: StageViewState): void;
488
- /** Offer a candidate initial view; the highest-priority non-null wins at placement. */
489
- provideInitialView(priority: number, provider: () => StageViewState | null): void;
490
- /** Resolve the registered providers once (else reset). Called when the viewport is ready. */
491
- placeInitial(): void;
492
- /** Back to the start: page 0, placed by the unit rule at the current zoom intent. */
493
- resetView(): void;
494
- }
495
- interface StageConfig extends Partial<StageSettings> {
496
- /** Override the host timing seam (tests/SSR). Defaults to browser rAF. */
497
- scheduler?: Scheduler;
498
- }
499
- declare const StageToken: import("@embedpdf/core").CapabilityToken<StageCapability>;
500
- //#endregion
1
+ import { C as Viewpoint, S as StageViewState, _ as StageConfig, a as GridColumns, b as StageState, c as RevealAnchor, d as RevealZoom, f as Scheduler, g as StageCapability, h as StageBox, i as GoToOptions, l as RevealAnchorValue, m as StageAction, n as FlowMode, o as LayoutKind, p as ScrollBehaviorKind, r as Gap, s as ResponsiveRule, t as BoxQuery, u as RevealOptions, v as StageScrollToOptions, w as VisiblePage, x as StageToken, y as StageSettings } from "./types-CdIFKQnj.js";
2
+ import { Align, Alignment, Direction, PageFrame, ScrollMetrics, SizingMode, SpreadMode, ZoomMode, ZoomModeValue, ZoomSpec } from "./contract.js";
3
+ import { DestinationReveal, destinationToReveal } from "./destination.js";
4
+ import { CapabilityToken } from "@embedpdf/core";
5
+ import { Size } from "@embedpdf/core-stage";
6
+ import { InteractionCapability, InteractionHandler } from "@embedpdf/plugin-interaction/contract";
501
7
  //#region src/stage.plugin.d.ts
502
8
  /**
503
9
  * Options for registering a stage instance. The Stage is a LENS, not a singleton:
@@ -518,20 +24,6 @@ declare const StageToken: import("@embedpdf/core").CapabilityToken<StageCapabili
518
24
  interface StagePluginOptions extends StageConfig {
519
25
  id?: string;
520
26
  token?: CapabilityToken<StageCapability>;
521
- /**
522
- * Opt this lens into the interaction hub: register a tool-gated `scroll`
523
- * handler (so dragging pans only in `pan` mode). Pair with `<Stage interaction>`
524
- * on the React side, which forwards pointer events to the hub. Default false —
525
- * secondary lenses (thumbnails) stay click-to-navigate.
526
- */
527
- interaction?: boolean;
528
- /**
529
- * When {@link interaction} is on, let drags over page GAPS pan regardless of the
530
- * active tool (and show a grab cursor there) — the gutter always pans, matching
531
- * v2 and the intuition that there's nothing to draw/select outside a page.
532
- * On-page behaviour is untouched. Default true; ignored without `interaction`.
533
- */
534
- panFallback?: boolean;
535
27
  }
536
28
  /**
537
29
  * Wires the parts into a kernel plugin. This file is the "manifest": it says what
@@ -540,51 +32,28 @@ interface StagePluginOptions extends StageConfig {
540
32
  */
541
33
  declare const stagePlugin: (options?: StagePluginOptions) => import("@embedpdf/core").PluginDef<StageState, StageAction, StageCapability>;
542
34
  //#endregion
543
- //#region src/destination.d.ts
544
- interface DestinationReveal {
545
- /** Display index for `reveal()` — from the layout row. */
546
- pageIndex: number;
547
- options: RevealOptions;
35
+ //#region src/scroll-handler.d.ts
36
+ interface ScrollHandlerOptions {
37
+ /**
38
+ * Let a drag over a page GAP pan regardless of the active tool — and show a grab
39
+ * cursor there — so the gutter always pans (v2 parity, and the natural feel:
40
+ * outside a page there's nothing to draw/select on). On-page behaviour is
41
+ * untouched; the tool's own gesture still owns page space. Default true.
42
+ */
43
+ panFallback?: boolean;
548
44
  }
549
45
  /**
550
- * Translate one explicit destination against its target page's layout.
551
- * `bbox` is the page's content BOUNDING box in CONTENT space, for the
552
- * `/FitB*` kinds — pass it when known; the crop box is the spec-tolerated
553
- * fallback until the engine exposes it.
554
- */
555
- declare function destinationToReveal(dest: PdfDestination, layout: PageLayout, bbox?: Rect): DestinationReveal;
556
- //#endregion
557
- //#region src/wheel.d.ts
558
- /**
559
- * Wheel-input classification for ambient zoom — pure, so every framework
560
- * adapter shares one feel and the mapping is unit-testable.
561
- *
562
- * A ctrl/cmd wheel event is one of three physically different inputs that
563
- * happen to share an event type, each with its own unit system:
564
- *
565
- * • trackpad PINCH — browsers (Chrome/Edge/Firefox) synthesize ctrl+wheel
566
- * px-deltas scaled to the de-facto convention that `exp(-Δ/100)` tracks
567
- * the physical finger scale 1:1. Anything weaker feels dead (the content
568
- * must track the fingers — the Figma/maps feel).
569
- * • mouse NOTCHES — coarse steps: ±100/±120 px in Chrome, lines/pages mode
570
- * in Firefox. The pinch mapping would triple per click; a notch instead
571
- * steps by 1.2, the same ratio as the zoom buttons.
572
- * • cmd + continuous SCROLL — real scroll px, big and streaming (with
573
- * momentum): a gentle scrub coefficient. A cmd+mouse notch (±120 px)
574
- * lands within 0.3% of the 1.2 button step, so it needs no special case.
46
+ * Pan-the-camera as an interaction handler. Live under the built-in `pan` tool
47
+ * (the `scroll` tag) and — with `panFallback` — under every tool, where it then
48
+ * captures ONLY page-gap drags (on-page downs belong to the active tool, which
49
+ * claims them first at higher priority). It uses the sample's viewport delta, so
50
+ * it pans over the whole viewport (pages and gaps).
575
51
  *
576
- * (Safari never synthesizes ctrl+wheel for pinch — it fires proprietary
577
- * gesture events with an absolute scale; that wiring lives in the adapters.)
52
+ * Cursor feel: a closed hand (`grabbing`) while dragging; an open hand (`grab`)
53
+ * hovering a gap under a non-pan tool. The pan tool's own resting `grab` comes
54
+ * from its `Tool.cursor`, so hovering it needs no claim here.
578
55
  */
579
- interface WheelSample {
580
- deltaY: number;
581
- /** WheelEvent.deltaMode: 0 = pixels, 1 = lines, 2 = pages. */
582
- deltaMode: number;
583
- ctrlKey: boolean;
584
- metaKey: boolean;
585
- }
586
- /** Zoom factor for a ctrl/cmd wheel event (the caller decides zoom vs pan). */
587
- declare function wheelZoomFactor(e: WheelSample): number;
56
+ declare function createScrollHandler(stage: StageCapability, interaction: InteractionCapability, options?: ScrollHandlerOptions): InteractionHandler;
588
57
  //#endregion
589
58
  //#region src/settings.d.ts
590
59
  /**
@@ -595,9 +64,41 @@ declare function wheelZoomFactor(e: WheelSample): number;
595
64
  * `update()`, so that taxonomy stays a customer concern.
596
65
  */
597
66
  declare const DEFAULT_SETTINGS: StageSettings;
67
+ /**
68
+ * Out-of-the-box responsive rules — the platform feel with zero configuration:
69
+ * a compact container gets the thin gutter phones use (space, not device — an
70
+ * embedded 500px pane on a desktop is compact too). Override the whole list
71
+ * with `stagePlugin({ responsive: [...] })`; `responsive: []` opts out. The
72
+ * 'compact' name is queryable app-side via `stage.matches('compact')`.
73
+ */
74
+ declare const DEFAULT_RESPONSIVE: readonly ResponsiveRule[];
598
75
  /** Field-by-field settings equality, derived from the registry — a new setting is
599
76
  * covered automatically. (The React `useStageSettings` selector equality.) */
600
77
  declare const settingsEqual: (a: StageSettings, b: StageSettings) => boolean;
601
78
  //#endregion
602
- export { type Align, type Alignment, DEFAULT_SETTINGS, type DestinationReveal, type Direction, type FlowMode, type Gap, type GoToOptions, type GridColumns, type LayoutKind, type PageFrame, type RevealAnchor, type RevealAnchorValue, type RevealOptions, type RevealZoom, type Scheduler, type ScrollBehaviorKind, type ScrollMetrics, type SizingMode, type SpreadMode, type StageAction, type StageCapability, type StageConfig, type StagePluginOptions, type StageScrollToOptions, type StageSettings, type StageState, StageToken, type StageViewState, type Viewpoint, type VisiblePage, type WheelSample, ZoomMode, type ZoomModeValue, type ZoomSpec, destinationToReveal, settingsEqual, stagePlugin, wheelZoomFactor };
79
+ //#region src/responsive.d.ts
80
+ /**
81
+ * Container queries for the settings bag — the pure half. The capability owns
82
+ * the driver (when to re-resolve, how to react); the LAWS live here: what a
83
+ * box is, when a query matches, and what the effective settings are. No state,
84
+ * no dispatch — property-testable in isolation (the `wheel.ts` convention).
85
+ *
86
+ * The query vocabulary is deliberately just the box: a headless, DOM-free
87
+ * stage knows exactly one environmental fact — the viewport it was told.
88
+ * Anything else (pointer coarseness, platform, app state) is either per-event
89
+ * (`PointerSample.pointerType`) or the app's own business via `update()`.
90
+ */
91
+ /** The reported viewport as a queryable box. A square box is 'portrait' (CSS). */
92
+ declare const boxOf: (vp: Size) => StageBox;
93
+ /** All bounds inclusive, all fields optional, conditions AND-ed (CSS ranges). */
94
+ declare const matchesQuery: (q: BoxQuery, box: StageBox) => boolean;
95
+ interface ResolvedResponsive {
96
+ /** base ⊕ every matching rule's patch, in source order (later wins per key). */
97
+ effective: StageSettings;
98
+ /** Names of the matching rules, in source order. */
99
+ active: string[];
100
+ }
101
+ declare const resolveResponsive: (base: StageSettings, rules: readonly ResponsiveRule[], box: StageBox) => ResolvedResponsive;
102
+ //#endregion
103
+ export { type Align, type Alignment, type BoxQuery, DEFAULT_RESPONSIVE, DEFAULT_SETTINGS, type DestinationReveal, type Direction, type FlowMode, type Gap, type GoToOptions, type GridColumns, type LayoutKind, type PageFrame, type ResponsiveRule, type RevealAnchor, type RevealAnchorValue, type RevealOptions, type RevealZoom, type Scheduler, type ScrollBehaviorKind, type ScrollHandlerOptions, type ScrollMetrics, type SizingMode, type SpreadMode, type StageAction, type StageBox, type StageCapability, type StageConfig, type StagePluginOptions, type StageScrollToOptions, type StageSettings, type StageState, StageToken, type StageViewState, type Viewpoint, type VisiblePage, ZoomMode, type ZoomModeValue, type ZoomSpec, boxOf, createScrollHandler, destinationToReveal, matchesQuery, resolveResponsive, settingsEqual, stagePlugin };
603
104
  //# sourceMappingURL=index.d.ts.map