@embedpdf/plugin-stage 3.0.0-next.6 → 3.0.0-next.7
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.cjs +528 -81
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +172 -44
- package/dist/index.d.ts +172 -44
- package/dist/index.js +524 -81
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -22,10 +22,153 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
22
22
|
}) : target, mod));
|
|
23
23
|
//#endregion
|
|
24
24
|
let _embedpdf_core = require("@embedpdf/core");
|
|
25
|
-
let _embedpdf_plugin_interaction = require("@embedpdf/plugin-interaction");
|
|
26
25
|
let _embedpdf_core_stage = require("@embedpdf/core-stage");
|
|
27
26
|
_embedpdf_core_stage = __toESM(_embedpdf_core_stage, 1);
|
|
28
27
|
let _embedpdf_core_geometry = require("@embedpdf/core-geometry");
|
|
28
|
+
//#region src/motion.ts
|
|
29
|
+
/**
|
|
30
|
+
* The camera's MOTION vocabulary — every formula, pure.
|
|
31
|
+
*
|
|
32
|
+
* The capability owns the impure drivers (scheduler frames, dispatch, gesture
|
|
33
|
+
* state); the LAWS those drivers integrate live here, parameterized by dt/t
|
|
34
|
+
* with no state, no scheduler, no dispatch — unit-testable in isolation, and
|
|
35
|
+
* with zero plugin dependencies, liftable into stage-core if the native port
|
|
36
|
+
* ever wants them.
|
|
37
|
+
*
|
|
38
|
+
* Two families:
|
|
39
|
+
* • ballistic — one per-axis law for every free motion: `glideStep` (the
|
|
40
|
+
* touch fling, decaying on UIScrollView's curve) and `springStep` (a
|
|
41
|
+
* critically-damped return to the clamp). A glide that reaches a content
|
|
42
|
+
* edge converts to a spring with its velocity carried in, so the bounce
|
|
43
|
+
* grows out of physics rather than a scripted overshoot.
|
|
44
|
+
* • resistance — the iOS rubber-band curve `rubberOut` and its exact
|
|
45
|
+
* inverse `rubberIn`: dragging `d` px past an edge displays an
|
|
46
|
+
* asymptotically-bounded stretch, and re-entering a gesture over a
|
|
47
|
+
* stretched camera (the mid-bounce catch) reconstructs the
|
|
48
|
+
* finger-integrated position the curve came from.
|
|
49
|
+
* Plus the tween interpolators: `easeOutCubic` for coordinate tweens and
|
|
50
|
+
* `zoomLerp` — GEOMETRIC zoom interpolation (zoom is multiplicative; equal
|
|
51
|
+
* ratios per unit time, not equal deltas — the linear lerp's visible "dip").
|
|
52
|
+
*/
|
|
53
|
+
/** Resistance coefficient of the rubber-band curve (the iOS feel). */
|
|
54
|
+
const RUBBER = .55;
|
|
55
|
+
/** Glide decay per ms — UIScrollView's normal deceleration rate. */
|
|
56
|
+
const FLING_DECAY = .998;
|
|
57
|
+
/** rad/ms — critically damped, ~400ms to settle. */
|
|
58
|
+
const SPRING_OMEGA = .015;
|
|
59
|
+
/**
|
|
60
|
+
* Overshoot distance → displayed stretch: asymptotic to the viewport
|
|
61
|
+
* dimension `dim`, so the content never leaves the screen however far the
|
|
62
|
+
* finger travels. `rubberOut(0) === 0` — inside the bounds the curve is
|
|
63
|
+
* invisible.
|
|
64
|
+
*/
|
|
65
|
+
const rubberOut = (d, dim) => (1 - 1 / (d * RUBBER / dim + 1)) * dim;
|
|
66
|
+
/** Exact inverse of `rubberOut` (defined for `out < dim`). */
|
|
67
|
+
const rubberIn = (out, dim) => out * dim / (RUBBER * (dim - out));
|
|
68
|
+
/**
|
|
69
|
+
* One frame of free glide: exponential velocity decay, position advanced by
|
|
70
|
+
* the midpoint integral of the decay over `dt` (exact for the exponential —
|
|
71
|
+
* frame-rate independent).
|
|
72
|
+
*/
|
|
73
|
+
const glideStep = (p, v, dt) => {
|
|
74
|
+
const k = Math.pow(FLING_DECAY, dt);
|
|
75
|
+
const np = p + v * (dt * (1 + k) / 2);
|
|
76
|
+
const nv = v * k;
|
|
77
|
+
return Math.abs(nv) < .02 ? {
|
|
78
|
+
p: np,
|
|
79
|
+
v: 0,
|
|
80
|
+
done: true
|
|
81
|
+
} : {
|
|
82
|
+
p: np,
|
|
83
|
+
v: nv,
|
|
84
|
+
done: false
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* One frame of critically-damped spring toward `edge` — semi-implicit Euler
|
|
89
|
+
* on x'' = −ω²(x−e) − 2ωx'. Lands exactly ON the edge (position snapped,
|
|
90
|
+
* velocity zeroed) once inside half a pixel at negligible speed.
|
|
91
|
+
*/
|
|
92
|
+
const springStep = (p, v, edge, dt) => {
|
|
93
|
+
const nv = v + (-.015 * SPRING_OMEGA * (p - edge) - 2 * SPRING_OMEGA * v) * dt;
|
|
94
|
+
const np = p + nv * dt;
|
|
95
|
+
if (Math.abs(np - edge) < .5 && Math.abs(nv) < .01) return {
|
|
96
|
+
p: edge,
|
|
97
|
+
v: 0,
|
|
98
|
+
done: true
|
|
99
|
+
};
|
|
100
|
+
return {
|
|
101
|
+
p: np,
|
|
102
|
+
v: nv,
|
|
103
|
+
done: false
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
const easeOutCubic = (t) => 1 - Math.pow(1 - t, 3);
|
|
107
|
+
/**
|
|
108
|
+
* Geometric zoom interpolation: `z0·(z1/z0)^k`. Zoom is multiplicative, so a
|
|
109
|
+
* constant-RATE zoom moves equal ratios per unit time; interpolating the
|
|
110
|
+
* level linearly instead makes the start rush and the end crawl (and, under
|
|
111
|
+
* a focal anchor, swings the anchored point along a curved path).
|
|
112
|
+
*/
|
|
113
|
+
const zoomLerp = (z0, z1, k) => z0 * Math.pow(z1 / z0, k);
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region src/responsive.ts
|
|
116
|
+
/**
|
|
117
|
+
* Container queries for the settings bag — the pure half. The capability owns
|
|
118
|
+
* the driver (when to re-resolve, how to react); the LAWS live here: what a
|
|
119
|
+
* box is, when a query matches, and what the effective settings are. No state,
|
|
120
|
+
* no dispatch — property-testable in isolation (the `wheel.ts` convention).
|
|
121
|
+
*
|
|
122
|
+
* The query vocabulary is deliberately just the box: a headless, DOM-free
|
|
123
|
+
* stage knows exactly one environmental fact — the viewport it was told.
|
|
124
|
+
* Anything else (pointer coarseness, platform, app state) is either per-event
|
|
125
|
+
* (`PointerSample.pointerType`) or the app's own business via `update()`.
|
|
126
|
+
*/
|
|
127
|
+
/** The reported viewport as a queryable box. A square box is 'portrait' (CSS). */
|
|
128
|
+
const boxOf = (vp) => ({
|
|
129
|
+
width: vp.width,
|
|
130
|
+
height: vp.height,
|
|
131
|
+
orientation: vp.height >= vp.width ? "portrait" : "landscape"
|
|
132
|
+
});
|
|
133
|
+
/** All bounds inclusive, all fields optional, conditions AND-ed (CSS ranges). */
|
|
134
|
+
const matchesQuery = (q, box) => (q.minWidth === void 0 || box.width >= q.minWidth) && (q.maxWidth === void 0 || box.width <= q.maxWidth) && (q.minHeight === void 0 || box.height >= q.minHeight) && (q.maxHeight === void 0 || box.height <= q.maxHeight) && (q.orientation === void 0 || box.orientation === q.orientation);
|
|
135
|
+
const ruleMatches = (rule, box) => typeof rule.when === "function" ? !!rule.when(box) : matchesQuery(rule.when, box);
|
|
136
|
+
/** Merge a patch over settings, skipping undefined values (Partial semantics). */
|
|
137
|
+
const mergeSettings = (into, patch) => {
|
|
138
|
+
const out = { ...into };
|
|
139
|
+
let key;
|
|
140
|
+
for (key in patch) {
|
|
141
|
+
const value = patch[key];
|
|
142
|
+
if (value !== void 0) Object.assign(out, { [key]: value });
|
|
143
|
+
}
|
|
144
|
+
return out;
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Setting-value equality: primitives by identity, the flat objects the
|
|
148
|
+
* settings vocabulary uses (`{ px }`, `{ x, y }`, page frames, zoom specs) by
|
|
149
|
+
* one level of own-key comparison. Settings values are never nested deeper.
|
|
150
|
+
*/
|
|
151
|
+
const eqSetting = (a, b) => {
|
|
152
|
+
if (a === b) return true;
|
|
153
|
+
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
|
|
154
|
+
const ka = Object.keys(a);
|
|
155
|
+
const kb = Object.keys(b);
|
|
156
|
+
return ka.length === kb.length && ka.every((k) => a[k] === b[k]);
|
|
157
|
+
};
|
|
158
|
+
const resolveResponsive = (base, rules, box) => {
|
|
159
|
+
let effective = base;
|
|
160
|
+
const active = [];
|
|
161
|
+
for (const rule of rules) {
|
|
162
|
+
if (!ruleMatches(rule, box)) continue;
|
|
163
|
+
if (rule.name !== void 0) active.push(rule.name);
|
|
164
|
+
if (rule.settings) effective = mergeSettings(effective, rule.settings);
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
effective,
|
|
168
|
+
active
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
//#endregion
|
|
29
172
|
//#region src/settings.ts
|
|
30
173
|
/**
|
|
31
174
|
* Out-of-the-box defaults — a sensible document-reading feel. They are JUST
|
|
@@ -71,6 +214,18 @@ const DEFAULT_SETTINGS = {
|
|
|
71
214
|
scrollBehavior: "smooth",
|
|
72
215
|
viewUnitsPerPoint: 96 / 72
|
|
73
216
|
};
|
|
217
|
+
/**
|
|
218
|
+
* Out-of-the-box responsive rules — the platform feel with zero configuration:
|
|
219
|
+
* a compact container gets the thin gutter phones use (space, not device — an
|
|
220
|
+
* embedded 500px pane on a desktop is compact too). Override the whole list
|
|
221
|
+
* with `stagePlugin({ responsive: [...] })`; `responsive: []` opts out. The
|
|
222
|
+
* 'compact' name is queryable app-side via `stage.matches('compact')`.
|
|
223
|
+
*/
|
|
224
|
+
const DEFAULT_RESPONSIVE = [{
|
|
225
|
+
name: "compact",
|
|
226
|
+
when: { maxWidth: 600 },
|
|
227
|
+
settings: { padding: 4 }
|
|
228
|
+
}];
|
|
74
229
|
const SETTINGS_EFFECT = {
|
|
75
230
|
flow: "reflow",
|
|
76
231
|
layout: "scene",
|
|
@@ -109,8 +264,9 @@ const settingsEqual = (a, b) => SETTING_KEYS.every((k) => valueEq(a[k], b[k]));
|
|
|
109
264
|
* Layering, stated honestly:
|
|
110
265
|
* • stage-core — PURE spatial math (no DOM, no time). Ports to Rust later.
|
|
111
266
|
* • this capability — the IMPURE platform shell. It dispatches, caches, and owns
|
|
112
|
-
* the camera tween. It is NOT pure;
|
|
113
|
-
*
|
|
267
|
+
* the camera tween. It is NOT pure; its one host dependency (frame timing)
|
|
268
|
+
* enters through the Scheduler seam — injectable, defaulting to the host's
|
|
269
|
+
* own frame clock when one exists (see the seam below).
|
|
114
270
|
*
|
|
115
271
|
* The model: EVERY camera move is defined by what it holds fixed.
|
|
116
272
|
* • gestures (pan/pinch/wheel) — the content under the pointer. Physics, no setting.
|
|
@@ -397,6 +553,10 @@ function createStageCapability(ctx, config = {}) {
|
|
|
397
553
|
direction: ctx.getState().direction
|
|
398
554
|
});
|
|
399
555
|
let hasPlaced = false;
|
|
556
|
+
let gestureDepth = 0;
|
|
557
|
+
let gestureZoomed = false;
|
|
558
|
+
let gestureElastic = false;
|
|
559
|
+
let gestureRaw = null;
|
|
400
560
|
const REST_MS = 150;
|
|
401
561
|
let restRaf = 0;
|
|
402
562
|
const armRest = () => {
|
|
@@ -423,12 +583,69 @@ function createStageCapability(ctx, config = {}) {
|
|
|
423
583
|
};
|
|
424
584
|
const setCam = (next, bounds = stayBounds()) => {
|
|
425
585
|
const clamped = _embedpdf_core_stage.clampCamera(next, bounds, vp(), constraint());
|
|
426
|
-
if (clamped.zoom !== cam().zoom)
|
|
586
|
+
if (clamped.zoom !== cam().zoom) if (gestureDepth > 0) {
|
|
587
|
+
gestureZoomed = true;
|
|
588
|
+
if (ctx.getState().cameraResting) ctx.dispatch({
|
|
589
|
+
type: "CAMERA_REST",
|
|
590
|
+
resting: false
|
|
591
|
+
});
|
|
592
|
+
if (restRaf) {
|
|
593
|
+
scheduler.caf(restRaf);
|
|
594
|
+
restRaf = 0;
|
|
595
|
+
}
|
|
596
|
+
} else armRest();
|
|
427
597
|
ctx.dispatch({
|
|
428
598
|
type: "CAMERA",
|
|
429
599
|
camera: clamped
|
|
430
600
|
});
|
|
431
601
|
};
|
|
602
|
+
const axisTravels = (origin, content, view, zoom) => !_embedpdf_core_stage.travelRange(origin, content, view, zoom, constraint().padding).fits;
|
|
603
|
+
/** Unclamped finger-integrated camera → the DISPLAYED camera: clamp, then
|
|
604
|
+
* re-apply the overshoot through the resistance curve, per travelling axis.
|
|
605
|
+
* Inside the bounds this is exactly the clamp (rubber of zero is zero);
|
|
606
|
+
* on a fitting axis it is exactly the clamp ALWAYS. */
|
|
607
|
+
const rubberize = (raw) => {
|
|
608
|
+
const clamped = _embedpdf_core_stage.clampCamera(raw, stayBounds(), vp(), constraint());
|
|
609
|
+
const v = vp();
|
|
610
|
+
const b = stayBounds();
|
|
611
|
+
const axis = (rawA, clampedA, dim, travels) => {
|
|
612
|
+
if (!travels) return clampedA;
|
|
613
|
+
const dWorld = rawA - clampedA;
|
|
614
|
+
if (dWorld === 0) return clampedA;
|
|
615
|
+
const out = rubberOut(Math.abs(dWorld) * raw.zoom, Math.max(1, dim));
|
|
616
|
+
return clampedA + Math.sign(dWorld) * out / raw.zoom;
|
|
617
|
+
};
|
|
618
|
+
return {
|
|
619
|
+
zoom: raw.zoom,
|
|
620
|
+
x: axis(raw.x, clamped.x, v.width, axisTravels(b.x, b.width, v.width, raw.zoom)),
|
|
621
|
+
y: axis(raw.y, clamped.y, v.height, axisTravels(b.y, b.height, v.height, raw.zoom))
|
|
622
|
+
};
|
|
623
|
+
};
|
|
624
|
+
/** Displayed camera → the raw position `rubberize` would have produced it
|
|
625
|
+
* from. Overshoot is capped just under the asymptote so the inverse stays
|
|
626
|
+
* finite whatever state a catch finds the camera in. */
|
|
627
|
+
const unrubberize = (displayed) => {
|
|
628
|
+
const clamped = _embedpdf_core_stage.clampCamera(displayed, stayBounds(), vp(), constraint());
|
|
629
|
+
const v = vp();
|
|
630
|
+
const b = stayBounds();
|
|
631
|
+
const axis = (dispA, clampedA, dim, travels) => {
|
|
632
|
+
if (!travels) return clampedA;
|
|
633
|
+
const dWorld = dispA - clampedA;
|
|
634
|
+
if (dWorld === 0) return clampedA;
|
|
635
|
+
const d = Math.max(1, dim);
|
|
636
|
+
const out = Math.min(Math.abs(dWorld) * displayed.zoom, d - 1);
|
|
637
|
+
return clampedA + Math.sign(dWorld) * rubberIn(out, d) / displayed.zoom;
|
|
638
|
+
};
|
|
639
|
+
return {
|
|
640
|
+
zoom: displayed.zoom,
|
|
641
|
+
x: axis(displayed.x, clamped.x, v.width, axisTravels(b.x, b.width, v.width, displayed.zoom)),
|
|
642
|
+
y: axis(displayed.y, clamped.y, v.height, axisTravels(b.y, b.height, v.height, displayed.zoom))
|
|
643
|
+
};
|
|
644
|
+
};
|
|
645
|
+
const setCamRaw = (c) => ctx.dispatch({
|
|
646
|
+
type: "CAMERA",
|
|
647
|
+
camera: c
|
|
648
|
+
});
|
|
432
649
|
/**
|
|
433
650
|
* Cursor reconciliation, one direction per interaction:
|
|
434
651
|
* navigation → cursor is INTENT, set explicitly; the camera honors it as far
|
|
@@ -462,7 +679,6 @@ function createStageCapability(ctx, config = {}) {
|
|
|
462
679
|
}
|
|
463
680
|
cancelAnim();
|
|
464
681
|
const from = cam();
|
|
465
|
-
const ease = (t) => 1 - Math.pow(1 - t, 3);
|
|
466
682
|
let started = false;
|
|
467
683
|
let t0 = 0;
|
|
468
684
|
const tick = (now) => {
|
|
@@ -470,7 +686,7 @@ function createStageCapability(ctx, config = {}) {
|
|
|
470
686
|
started = true;
|
|
471
687
|
t0 = now;
|
|
472
688
|
}
|
|
473
|
-
const k =
|
|
689
|
+
const k = easeOutCubic(Math.min(1, (now - t0) / ms));
|
|
474
690
|
setCam({
|
|
475
691
|
x: lerp(from.x, target.x, k),
|
|
476
692
|
y: lerp(from.y, target.y, k),
|
|
@@ -484,6 +700,116 @@ function createStageCapability(ctx, config = {}) {
|
|
|
484
700
|
};
|
|
485
701
|
raf = scheduler.raf(tick);
|
|
486
702
|
};
|
|
703
|
+
/**
|
|
704
|
+
* Zoom-anchored tween — animates THE INVARIANT, not the coordinates. A
|
|
705
|
+
* camera move is defined by what it holds fixed; for an anchored zoom that
|
|
706
|
+
* is "the focal page-point stays at `pt` while scale changes". Lerping
|
|
707
|
+
* x/y/zoom independently (the plain tween) breaks that mid-flight: holding
|
|
708
|
+
* a screen point requires `x(t) = focal.x − pt.x / zoom(t)` — hyperbolic in
|
|
709
|
+
* the zoom — so linear coordinates swing the tapped point along a curved
|
|
710
|
+
* path (the visible "dip"). Here the zoom interpolates GEOMETRICALLY
|
|
711
|
+
* (constant rate — zoom is multiplicative) and each frame's camera derives
|
|
712
|
+
* from the anchor at that zoom, then clamps: the focal point is stationary
|
|
713
|
+
* by construction, and a zoom-out rails into its fit progressively as the
|
|
714
|
+
* shrinking travel range lets the clamp take over.
|
|
715
|
+
*/
|
|
716
|
+
const animateZoomAnchored = (focal, pt, targetZoom, ms = 240, then) => {
|
|
717
|
+
if (!canAnimate) {
|
|
718
|
+
const sc = buildScene();
|
|
719
|
+
if (sc.itemCount) setCam(_embedpdf_core_stage.cameraForAnchorAtScreen(focal, sc, pt, targetZoom));
|
|
720
|
+
then?.();
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
cancelAnim();
|
|
724
|
+
const z0 = cam().zoom;
|
|
725
|
+
let started = false;
|
|
726
|
+
let t0 = 0;
|
|
727
|
+
const tick = (now) => {
|
|
728
|
+
if (!started) {
|
|
729
|
+
started = true;
|
|
730
|
+
t0 = now;
|
|
731
|
+
}
|
|
732
|
+
const k = easeOutCubic(Math.min(1, (now - t0) / ms));
|
|
733
|
+
const z = zoomLerp(z0, targetZoom, k);
|
|
734
|
+
const sc = buildScene();
|
|
735
|
+
if (sc.itemCount) setCam(_embedpdf_core_stage.cameraForAnchorAtScreen(focal, sc, pt, z));
|
|
736
|
+
if (k < 1) raf = scheduler.raf(tick);
|
|
737
|
+
else {
|
|
738
|
+
raf = 0;
|
|
739
|
+
then?.();
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
raf = scheduler.raf(tick);
|
|
743
|
+
};
|
|
744
|
+
const startCameraPhysics = (vxFinger, vyFinger) => {
|
|
745
|
+
if (!canAnimate) {
|
|
746
|
+
setCam(cam());
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
cancelAnim();
|
|
750
|
+
const zoom = cam().zoom;
|
|
751
|
+
const c0 = cam();
|
|
752
|
+
const cl0 = _embedpdf_core_stage.clampCamera(c0, stayBounds(), vp(), constraint());
|
|
753
|
+
const b0 = stayBounds();
|
|
754
|
+
const v0 = vp();
|
|
755
|
+
const mk = (camA, clampedA, fingerV) => ({
|
|
756
|
+
p: camA * zoom,
|
|
757
|
+
v: -fingerV / 1e3,
|
|
758
|
+
springing: camA !== clampedA,
|
|
759
|
+
done: false
|
|
760
|
+
});
|
|
761
|
+
const ax = mk(c0.x, cl0.x, axisTravels(b0.x, b0.width, v0.width, zoom) ? vxFinger : 0);
|
|
762
|
+
const ay = mk(c0.y, cl0.y, axisTravels(b0.y, b0.height, v0.height, zoom) ? vyFinger : 0);
|
|
763
|
+
if (!ax.springing && !ay.springing && Math.hypot(ax.v, ay.v) < .02) return;
|
|
764
|
+
let started = false;
|
|
765
|
+
let last = 0;
|
|
766
|
+
const tick = (now) => {
|
|
767
|
+
raf = 0;
|
|
768
|
+
const dt = started ? Math.min(64, Math.max(1, now - last)) : 16;
|
|
769
|
+
started = true;
|
|
770
|
+
last = now;
|
|
771
|
+
const cl = _embedpdf_core_stage.clampCamera({
|
|
772
|
+
x: ax.p / zoom,
|
|
773
|
+
y: ay.p / zoom,
|
|
774
|
+
zoom
|
|
775
|
+
}, stayBounds(), vp(), constraint());
|
|
776
|
+
const step = (a, edgeWorld) => {
|
|
777
|
+
if (a.done) return;
|
|
778
|
+
const r = a.springing ? springStep(a.p, a.v, edgeWorld * zoom, dt) : glideStep(a.p, a.v, dt);
|
|
779
|
+
a.p = r.p;
|
|
780
|
+
a.v = r.v;
|
|
781
|
+
a.done = r.done;
|
|
782
|
+
};
|
|
783
|
+
step(ax, cl.x);
|
|
784
|
+
step(ay, cl.y);
|
|
785
|
+
const ncl = _embedpdf_core_stage.clampCamera({
|
|
786
|
+
x: ax.p / zoom,
|
|
787
|
+
y: ay.p / zoom,
|
|
788
|
+
zoom
|
|
789
|
+
}, stayBounds(), vp(), constraint());
|
|
790
|
+
const convert = (a, clampedA) => {
|
|
791
|
+
if (!a.springing && Math.abs(clampedA * zoom - a.p) > 1e-6) {
|
|
792
|
+
a.p = clampedA * zoom;
|
|
793
|
+
a.springing = true;
|
|
794
|
+
a.done = false;
|
|
795
|
+
}
|
|
796
|
+
};
|
|
797
|
+
convert(ax, ncl.x);
|
|
798
|
+
convert(ay, ncl.y);
|
|
799
|
+
setCamRaw({
|
|
800
|
+
x: ax.p / zoom,
|
|
801
|
+
y: ay.p / zoom,
|
|
802
|
+
zoom
|
|
803
|
+
});
|
|
804
|
+
syncCursorFromCamera();
|
|
805
|
+
if (ax.done && ay.done) {
|
|
806
|
+
setCam(cam());
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
raf = scheduler.raf(tick);
|
|
810
|
+
};
|
|
811
|
+
raf = scheduler.raf(tick);
|
|
812
|
+
};
|
|
487
813
|
const anchorAt = (at) => {
|
|
488
814
|
const sc = buildScene();
|
|
489
815
|
return sc.itemCount ? _embedpdf_core_stage.anchorFromCamera(cam(), sc, vp(), at) : {
|
|
@@ -683,6 +1009,72 @@ function createStageCapability(ctx, config = {}) {
|
|
|
683
1009
|
return out;
|
|
684
1010
|
};
|
|
685
1011
|
const snapshotSettings = () => pickSettings(ctx.getState());
|
|
1012
|
+
/**
|
|
1013
|
+
* Settings change, reacted per the registry — the strongest effect among the
|
|
1014
|
+
* touched settings wins: 'reflow' ⊃ 'scene'/'refit' ⊃ 'reclamp' ⊃ 'none'.
|
|
1015
|
+
* The ONE reactive applier: the public `update()` and the responsive driver
|
|
1016
|
+
* both land here, so a breakpoint crossing gets exactly the invariant a
|
|
1017
|
+
* hand-written update would.
|
|
1018
|
+
*/
|
|
1019
|
+
const applySettings = (patch) => {
|
|
1020
|
+
cancelAnim();
|
|
1021
|
+
const touched = (effect) => SETTING_KEYS.some((k) => patch[k] !== void 0 && SETTINGS_EFFECT[k] === effect);
|
|
1022
|
+
const align = touched("refit") && !touched("scene") && !touched("reflow") ? ctx.getState().zoomAlign : ctx.getState().anchorAlign;
|
|
1023
|
+
const anchor = anchorAt(alignPoint(align, vp()));
|
|
1024
|
+
ctx.dispatch({
|
|
1025
|
+
type: "PATCH",
|
|
1026
|
+
patch
|
|
1027
|
+
});
|
|
1028
|
+
if (touched("scene")) sceneCache = null;
|
|
1029
|
+
if (touched("reflow")) goToTarget(ctx.getState().cursor, { behavior: "instant" });
|
|
1030
|
+
else if (touched("scene") || touched("refit")) reapply(anchor, align);
|
|
1031
|
+
else if (touched("reclamp")) setCam(cam());
|
|
1032
|
+
};
|
|
1033
|
+
let base = snapshotSettings();
|
|
1034
|
+
let rules = config.responsive ?? DEFAULT_RESPONSIVE;
|
|
1035
|
+
let lastEffective = base;
|
|
1036
|
+
const publishActive = (active) => {
|
|
1037
|
+
const prev = ctx.getState().activeRules;
|
|
1038
|
+
if (prev.length !== active.length || active.some((n, i) => n !== prev[i])) ctx.dispatch({
|
|
1039
|
+
type: "RESPONSIVE",
|
|
1040
|
+
active
|
|
1041
|
+
});
|
|
1042
|
+
};
|
|
1043
|
+
/**
|
|
1044
|
+
* Re-resolve and apply what CHANGED since the last resolution. `react: true`
|
|
1045
|
+
* routes the patch through `applySettings` (full anchor-preserving update);
|
|
1046
|
+
* `react: false` (inside `setViewport`, whose caller runs its own reframe)
|
|
1047
|
+
* just lands the patch + cache invalidation and reports the strongest
|
|
1048
|
+
* effect so the caller can escalate a rule-driven flow flip.
|
|
1049
|
+
*/
|
|
1050
|
+
const syncResponsive = (react) => {
|
|
1051
|
+
const { effective, active } = resolveResponsive(base, rules, boxOf(vp()));
|
|
1052
|
+
const patch = {};
|
|
1053
|
+
for (const k of SETTING_KEYS) if (!eqSetting(effective[k], lastEffective[k])) Object.assign(patch, { [k]: effective[k] });
|
|
1054
|
+
lastEffective = effective;
|
|
1055
|
+
publishActive(active);
|
|
1056
|
+
const keys = Object.keys(patch);
|
|
1057
|
+
if (keys.length === 0) return "none";
|
|
1058
|
+
if (react) {
|
|
1059
|
+
applySettings(patch);
|
|
1060
|
+
return "none";
|
|
1061
|
+
}
|
|
1062
|
+
ctx.dispatch({
|
|
1063
|
+
type: "PATCH",
|
|
1064
|
+
patch
|
|
1065
|
+
});
|
|
1066
|
+
const rank = {
|
|
1067
|
+
none: 0,
|
|
1068
|
+
reclamp: 1,
|
|
1069
|
+
refit: 2,
|
|
1070
|
+
scene: 3,
|
|
1071
|
+
reflow: 4
|
|
1072
|
+
};
|
|
1073
|
+
let strongest = "none";
|
|
1074
|
+
for (const k of keys) if (rank[SETTINGS_EFFECT[k]] > rank[strongest]) strongest = SETTINGS_EFFECT[k];
|
|
1075
|
+
if (strongest === "scene" || strongest === "reflow") sceneCache = null;
|
|
1076
|
+
return strongest;
|
|
1077
|
+
};
|
|
686
1078
|
const initialViewProviders = [];
|
|
687
1079
|
const api = {
|
|
688
1080
|
camera: cam,
|
|
@@ -806,6 +1198,7 @@ function createStageCapability(ctx, config = {}) {
|
|
|
806
1198
|
type: "VP",
|
|
807
1199
|
vp: v
|
|
808
1200
|
});
|
|
1201
|
+
syncResponsive(false);
|
|
809
1202
|
if (v.width > 0 && v.height > 0 && (ctx.document()?.pageCount ?? 0) > 0) api.placeInitial();
|
|
810
1203
|
return;
|
|
811
1204
|
}
|
|
@@ -815,7 +1208,8 @@ function createStageCapability(ctx, config = {}) {
|
|
|
815
1208
|
type: "VP",
|
|
816
1209
|
vp: v
|
|
817
1210
|
});
|
|
818
|
-
|
|
1211
|
+
if (syncResponsive(false) === "reflow") goToTarget(ctx.getState().cursor, { behavior: "instant" });
|
|
1212
|
+
else reapply(anchor);
|
|
819
1213
|
},
|
|
820
1214
|
setDevicePixelRatio: (ratio) => {
|
|
821
1215
|
if (ratio > 0 && ratio !== dpr()) ctx.dispatch({
|
|
@@ -830,7 +1224,10 @@ function createStageCapability(ctx, config = {}) {
|
|
|
830
1224
|
},
|
|
831
1225
|
panBy: (dx, dy) => {
|
|
832
1226
|
cancelAnim();
|
|
833
|
-
|
|
1227
|
+
if (gestureDepth > 0 && gestureElastic) {
|
|
1228
|
+
gestureRaw = _embedpdf_core_stage.panByScreen(gestureRaw ?? unrubberize(cam()), dx, dy);
|
|
1229
|
+
setCamRaw(rubberize(gestureRaw));
|
|
1230
|
+
} else setCam(_embedpdf_core_stage.panByScreen(cam(), dx, dy));
|
|
834
1231
|
syncCursorFromCamera();
|
|
835
1232
|
},
|
|
836
1233
|
scrollTo: (opts) => {
|
|
@@ -856,14 +1253,72 @@ function createStageCapability(ctx, config = {}) {
|
|
|
856
1253
|
const before = buildScene();
|
|
857
1254
|
const focal = before.itemCount ? _embedpdf_core_stage.anchorAtPoint(before, _embedpdf_core_stage.toWorld(cam(), pt)) : null;
|
|
858
1255
|
setCam(_embedpdf_core_stage.zoomAround(cam(), pt, factor));
|
|
859
|
-
ctx.dispatch({
|
|
1256
|
+
if (gestureDepth === 0) ctx.dispatch({
|
|
860
1257
|
type: "PATCH",
|
|
861
1258
|
patch: { zoom: { level: cam().zoom } }
|
|
862
1259
|
});
|
|
863
1260
|
const after = buildScene();
|
|
864
1261
|
if (after !== before && focal && after.itemCount) setCam(_embedpdf_core_stage.cameraForAnchorAtScreen(focal, after, pt, cam().zoom));
|
|
1262
|
+
if (gestureDepth > 0 && gestureElastic) gestureRaw = unrubberize(cam());
|
|
865
1263
|
syncCursorFromCamera();
|
|
866
1264
|
},
|
|
1265
|
+
beginGesture: (options) => {
|
|
1266
|
+
gestureDepth++;
|
|
1267
|
+
if (gestureDepth === 1) {
|
|
1268
|
+
cancelAnim();
|
|
1269
|
+
gestureZoomed = false;
|
|
1270
|
+
gestureElastic = options?.elastic === true;
|
|
1271
|
+
gestureRaw = null;
|
|
1272
|
+
}
|
|
1273
|
+
},
|
|
1274
|
+
endGesture: () => {
|
|
1275
|
+
if (gestureDepth === 0) return;
|
|
1276
|
+
gestureDepth--;
|
|
1277
|
+
if (gestureDepth > 0) return;
|
|
1278
|
+
gestureRaw = null;
|
|
1279
|
+
const wasElastic = gestureElastic;
|
|
1280
|
+
gestureElastic = false;
|
|
1281
|
+
if (gestureZoomed) {
|
|
1282
|
+
gestureZoomed = false;
|
|
1283
|
+
ctx.dispatch({
|
|
1284
|
+
type: "PATCH",
|
|
1285
|
+
patch: { zoom: { level: cam().zoom } }
|
|
1286
|
+
});
|
|
1287
|
+
armRest();
|
|
1288
|
+
}
|
|
1289
|
+
syncCursorFromCamera();
|
|
1290
|
+
if (wasElastic) {
|
|
1291
|
+
const c = cam();
|
|
1292
|
+
const cl = _embedpdf_core_stage.clampCamera(c, stayBounds(), vp(), constraint());
|
|
1293
|
+
if (cl.x !== c.x || cl.y !== c.y) startCameraPhysics(0, 0);
|
|
1294
|
+
}
|
|
1295
|
+
},
|
|
1296
|
+
fling: (vx, vy) => startCameraPhysics(vx, vy),
|
|
1297
|
+
cameraInMotion: () => raf !== 0,
|
|
1298
|
+
doubleTapZoom: (pt) => {
|
|
1299
|
+
cancelAnim();
|
|
1300
|
+
const sc0 = buildScene();
|
|
1301
|
+
if (!sc0.itemCount) return;
|
|
1302
|
+
const item = paged() ? sc0.items[0] : sc0.items[itemIndexOfPage(ctx.getState().cursor)];
|
|
1303
|
+
const fit = fitBox(item);
|
|
1304
|
+
const auto = _embedpdf_core_stage.resolveZoom({ mode: _embedpdf_core_stage.ZoomMode.Automatic }, fit, vp(), pad());
|
|
1305
|
+
const stops = [
|
|
1306
|
+
auto,
|
|
1307
|
+
_embedpdf_core_stage.resolveZoom({ mode: _embedpdf_core_stage.ZoomMode.FitWidth }, fit, vp(), pad()),
|
|
1308
|
+
Math.min(auto * 2.5, _embedpdf_core_stage.ZOOM_MAX)
|
|
1309
|
+
].sort((a, b) => a - b).filter((z, i, all) => i === 0 || z > all[i - 1] * 1.1);
|
|
1310
|
+
const near = (z, stop) => z > stop / 1.1 && z < stop * 1.1;
|
|
1311
|
+
const onRung = stops.findIndex((s) => near(cam().zoom, s));
|
|
1312
|
+
const target = onRung >= 0 ? stops[(onRung + 1) % stops.length] : stops[0];
|
|
1313
|
+
ctx.dispatch({
|
|
1314
|
+
type: "PATCH",
|
|
1315
|
+
patch: { zoom: { level: target } }
|
|
1316
|
+
});
|
|
1317
|
+
const sc = buildScene();
|
|
1318
|
+
if (!sc.itemCount) return;
|
|
1319
|
+
const focal = _embedpdf_core_stage.anchorAtPoint(sc, _embedpdf_core_stage.toWorld(cam(), pt));
|
|
1320
|
+
animateZoomAnchored(focal, pt, target, 240, syncCursorFromCamera);
|
|
1321
|
+
},
|
|
867
1322
|
zoomIn: () => api.zoomAround(alignPoint(ctx.getState().zoomAlign, vp()), 1.2),
|
|
868
1323
|
zoomOut: () => api.zoomAround(alignPoint(ctx.getState().zoomAlign, vp()), 1 / 1.2),
|
|
869
1324
|
zoomTo: (spec) => api.update({ zoom: spec }),
|
|
@@ -947,20 +1402,17 @@ function createStageCapability(ctx, config = {}) {
|
|
|
947
1402
|
},
|
|
948
1403
|
next: (opts) => step(1, opts),
|
|
949
1404
|
prev: (opts) => step(-1, opts),
|
|
1405
|
+
lensId: () => ctx.id,
|
|
950
1406
|
update: (patch) => {
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
patch
|
|
958
|
-
});
|
|
959
|
-
if (touched("scene")) sceneCache = null;
|
|
960
|
-
if (touched("reflow")) goToTarget(ctx.getState().cursor, { behavior: "instant" });
|
|
961
|
-
else if (touched("scene") || touched("refit")) reapply(anchor, align);
|
|
962
|
-
else if (touched("reclamp")) setCam(cam());
|
|
1407
|
+
base = mergeSettings(base, patch);
|
|
1408
|
+
syncResponsive(true);
|
|
1409
|
+
},
|
|
1410
|
+
setResponsive: (next) => {
|
|
1411
|
+
rules = next;
|
|
1412
|
+
syncResponsive(true);
|
|
963
1413
|
},
|
|
1414
|
+
matches: (name) => ctx.getState().activeRules.includes(name),
|
|
1415
|
+
activeRules: () => ctx.getState().activeRules,
|
|
964
1416
|
setFlow: (flow) => api.update({ flow }),
|
|
965
1417
|
setLayout: (layout) => api.update({ layout }),
|
|
966
1418
|
setSpread: (spread) => api.update({ spread }),
|
|
@@ -980,9 +1432,13 @@ function createStageCapability(ctx, config = {}) {
|
|
|
980
1432
|
setScrollBehavior: (behavior) => api.update({ scrollBehavior: behavior }),
|
|
981
1433
|
applyViewState: (view) => {
|
|
982
1434
|
cancelAnim();
|
|
1435
|
+
base = mergeSettings(base, pickSettings(view));
|
|
1436
|
+
const { effective, active } = resolveResponsive(base, rules, boxOf(vp()));
|
|
1437
|
+
lastEffective = effective;
|
|
1438
|
+
publishActive(active);
|
|
983
1439
|
ctx.dispatch({
|
|
984
1440
|
type: "PATCH",
|
|
985
|
-
patch:
|
|
1441
|
+
patch: effective
|
|
986
1442
|
});
|
|
987
1443
|
ctx.dispatch({
|
|
988
1444
|
type: "CURSOR",
|
|
@@ -1014,46 +1470,6 @@ function createStageCapability(ctx, config = {}) {
|
|
|
1014
1470
|
return api;
|
|
1015
1471
|
}
|
|
1016
1472
|
//#endregion
|
|
1017
|
-
//#region src/scroll-handler.ts
|
|
1018
|
-
/**
|
|
1019
|
-
* Pan-the-camera as an interaction handler. Live under the built-in `pan` tool
|
|
1020
|
-
* (the `scroll` tag) and — with `panFallback` — under every tool, where it then
|
|
1021
|
-
* captures ONLY page-gap drags (on-page downs belong to the active tool, which
|
|
1022
|
-
* claims them first at higher priority). It uses the sample's viewport delta, so
|
|
1023
|
-
* it pans over the whole viewport (pages and gaps).
|
|
1024
|
-
*
|
|
1025
|
-
* Cursor feel: a closed hand (`grabbing`) while dragging; an open hand (`grab`)
|
|
1026
|
-
* hovering a gap under a non-pan tool. The pan tool's own resting `grab` comes
|
|
1027
|
-
* from its `Tool.cursor`, so hovering it needs no claim here.
|
|
1028
|
-
*/
|
|
1029
|
-
function createScrollHandler(stage, interaction, options = {}) {
|
|
1030
|
-
const panFallback = options.panFallback ?? true;
|
|
1031
|
-
let last = {
|
|
1032
|
-
x: 0,
|
|
1033
|
-
y: 0
|
|
1034
|
-
};
|
|
1035
|
-
const isPanTool = () => interaction.activeTool().enables.has("scroll");
|
|
1036
|
-
return {
|
|
1037
|
-
id: "stage-scroll",
|
|
1038
|
-
priority: 10,
|
|
1039
|
-
enabledFor: (tool) => tool.enables.has("scroll") || panFallback,
|
|
1040
|
-
onDown: (s) => {
|
|
1041
|
-
if (!isPanTool() && s.page) return false;
|
|
1042
|
-
last = s.viewport;
|
|
1043
|
-
interaction.setCursor("stage-grab", "grabbing", 40);
|
|
1044
|
-
return true;
|
|
1045
|
-
},
|
|
1046
|
-
onMove: (s) => {
|
|
1047
|
-
stage.panBy(s.viewport.x - last.x, s.viewport.y - last.y);
|
|
1048
|
-
last = s.viewport;
|
|
1049
|
-
},
|
|
1050
|
-
onUp: () => interaction.setCursor("stage-grab", null),
|
|
1051
|
-
onHover: (s) => {
|
|
1052
|
-
if (panFallback && !isPanTool()) interaction.setCursor("stage-pan-fallback", s.page ? null : "grab", 5);
|
|
1053
|
-
}
|
|
1054
|
-
};
|
|
1055
|
-
}
|
|
1056
|
-
//#endregion
|
|
1057
1473
|
//#region src/effects.ts
|
|
1058
1474
|
/**
|
|
1059
1475
|
* The one effect a stage lens needs: when the document's page registry changes
|
|
@@ -1076,7 +1492,7 @@ function registerStageEffects(ctx, token) {
|
|
|
1076
1492
|
//#endregion
|
|
1077
1493
|
//#region src/reducer.ts
|
|
1078
1494
|
const initialStageState = (config) => {
|
|
1079
|
-
const { scheduler: _scheduler, ...overrides } = config;
|
|
1495
|
+
const { scheduler: _scheduler, responsive: _responsive, ...overrides } = config;
|
|
1080
1496
|
return {
|
|
1081
1497
|
camera: {
|
|
1082
1498
|
x: 0,
|
|
@@ -1090,6 +1506,7 @@ const initialStageState = (config) => {
|
|
|
1090
1506
|
},
|
|
1091
1507
|
dpr: 1,
|
|
1092
1508
|
cursor: 0,
|
|
1509
|
+
activeRules: [],
|
|
1093
1510
|
...DEFAULT_SETTINGS,
|
|
1094
1511
|
...overrides
|
|
1095
1512
|
};
|
|
@@ -1132,6 +1549,10 @@ const stageReducer = (state, a) => {
|
|
|
1132
1549
|
cursor: a.cursor
|
|
1133
1550
|
};
|
|
1134
1551
|
case "PATCH": return applyPatch(state, a.patch);
|
|
1552
|
+
case "RESPONSIVE": return {
|
|
1553
|
+
...state,
|
|
1554
|
+
activeRules: a.active
|
|
1555
|
+
};
|
|
1135
1556
|
default: return state;
|
|
1136
1557
|
}
|
|
1137
1558
|
};
|
|
@@ -1146,19 +1567,14 @@ const StageToken = (0, _embedpdf_core.createCapabilityToken)("stage");
|
|
|
1146
1567
|
* sibling files.
|
|
1147
1568
|
*/
|
|
1148
1569
|
const stagePlugin = (options = {}) => {
|
|
1149
|
-
const { id = "stage", token = StageToken,
|
|
1570
|
+
const { id = "stage", token = StageToken, ...config } = options;
|
|
1150
1571
|
return (0, _embedpdf_core.definePlugin)({
|
|
1151
1572
|
id,
|
|
1152
1573
|
token,
|
|
1153
1574
|
scope: "document",
|
|
1154
|
-
optional: interaction ? [_embedpdf_plugin_interaction.InteractionToken] : void 0,
|
|
1155
1575
|
initialState: () => initialStageState(config),
|
|
1156
1576
|
reduce: stageReducer,
|
|
1157
1577
|
capability: (ctx) => createStageCapability(ctx, config),
|
|
1158
|
-
init: interaction ? (ctx) => {
|
|
1159
|
-
const ix = ctx.tryGet(_embedpdf_plugin_interaction.InteractionToken);
|
|
1160
|
-
if (ix) ix.registerHandler(createScrollHandler(ctx.get(token), ix, { panFallback }));
|
|
1161
|
-
} : void 0,
|
|
1162
1578
|
effects: (ctx) => registerStageEffects(ctx, token)
|
|
1163
1579
|
});
|
|
1164
1580
|
};
|
|
@@ -1305,19 +1721,47 @@ function destinationToReveal(dest, layout, bbox) {
|
|
|
1305
1721
|
};
|
|
1306
1722
|
}
|
|
1307
1723
|
//#endregion
|
|
1308
|
-
//#region src/
|
|
1309
|
-
/**
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1724
|
+
//#region src/scroll-handler.ts
|
|
1725
|
+
/**
|
|
1726
|
+
* Pan-the-camera as an interaction handler. Live under the built-in `pan` tool
|
|
1727
|
+
* (the `scroll` tag) and — with `panFallback` — under every tool, where it then
|
|
1728
|
+
* captures ONLY page-gap drags (on-page downs belong to the active tool, which
|
|
1729
|
+
* claims them first at higher priority). It uses the sample's viewport delta, so
|
|
1730
|
+
* it pans over the whole viewport (pages and gaps).
|
|
1731
|
+
*
|
|
1732
|
+
* Cursor feel: a closed hand (`grabbing`) while dragging; an open hand (`grab`)
|
|
1733
|
+
* hovering a gap under a non-pan tool. The pan tool's own resting `grab` comes
|
|
1734
|
+
* from its `Tool.cursor`, so hovering it needs no claim here.
|
|
1735
|
+
*/
|
|
1736
|
+
function createScrollHandler(stage, interaction, options = {}) {
|
|
1737
|
+
const panFallback = options.panFallback ?? true;
|
|
1738
|
+
let last = {
|
|
1739
|
+
x: 0,
|
|
1740
|
+
y: 0
|
|
1741
|
+
};
|
|
1742
|
+
const isPanTool = () => interaction.activeTool().enables.has("scroll");
|
|
1743
|
+
return {
|
|
1744
|
+
id: "stage-scroll",
|
|
1745
|
+
priority: 10,
|
|
1746
|
+
enabledFor: (tool) => tool.enables.has("scroll") || panFallback,
|
|
1747
|
+
onDown: (s) => {
|
|
1748
|
+
if (!isPanTool() && s.page) return false;
|
|
1749
|
+
last = s.viewport;
|
|
1750
|
+
interaction.setCursor("stage-grab", "grabbing", 40);
|
|
1751
|
+
return true;
|
|
1752
|
+
},
|
|
1753
|
+
onMove: (s) => {
|
|
1754
|
+
stage.panBy(s.viewport.x - last.x, s.viewport.y - last.y);
|
|
1755
|
+
last = s.viewport;
|
|
1756
|
+
},
|
|
1757
|
+
onUp: () => interaction.setCursor("stage-grab", null),
|
|
1758
|
+
onHover: (s) => {
|
|
1759
|
+
if (panFallback && !isPanTool()) interaction.setCursor("stage-pan-fallback", s.page ? null : "grab", 5);
|
|
1760
|
+
}
|
|
1761
|
+
};
|
|
1319
1762
|
}
|
|
1320
1763
|
//#endregion
|
|
1764
|
+
exports.DEFAULT_RESPONSIVE = DEFAULT_RESPONSIVE;
|
|
1321
1765
|
exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
|
|
1322
1766
|
exports.StageToken = StageToken;
|
|
1323
1767
|
Object.defineProperty(exports, "ZoomMode", {
|
|
@@ -1326,9 +1770,12 @@ Object.defineProperty(exports, "ZoomMode", {
|
|
|
1326
1770
|
return _embedpdf_core_stage.ZoomMode;
|
|
1327
1771
|
}
|
|
1328
1772
|
});
|
|
1773
|
+
exports.boxOf = boxOf;
|
|
1774
|
+
exports.createScrollHandler = createScrollHandler;
|
|
1329
1775
|
exports.destinationToReveal = destinationToReveal;
|
|
1776
|
+
exports.matchesQuery = matchesQuery;
|
|
1777
|
+
exports.resolveResponsive = resolveResponsive;
|
|
1330
1778
|
exports.settingsEqual = settingsEqual;
|
|
1331
1779
|
exports.stagePlugin = stagePlugin;
|
|
1332
|
-
exports.wheelZoomFactor = wheelZoomFactor;
|
|
1333
1780
|
|
|
1334
1781
|
//# sourceMappingURL=index.cjs.map
|