@embedpdf/plugin-zoom 1.0.11 → 1.0.12

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.
Files changed (49) hide show
  1. package/dist/hammer-Bs-QCG8V.cjs +7 -0
  2. package/dist/hammer-Bs-QCG8V.cjs.map +1 -0
  3. package/dist/hammer-e1aXHboh.js +1810 -0
  4. package/dist/hammer-e1aXHboh.js.map +1 -0
  5. package/dist/index.cjs +2 -481
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.d.ts +1 -147
  8. package/dist/index.js +43 -59
  9. package/dist/index.js.map +1 -1
  10. package/dist/lib/actions.d.ts +20 -0
  11. package/dist/lib/index.d.ts +10 -0
  12. package/dist/lib/manifest.d.ts +4 -0
  13. package/dist/lib/reducer.d.ts +5 -0
  14. package/dist/lib/types.d.ts +84 -0
  15. package/dist/lib/zoom-plugin.d.ts +38 -0
  16. package/dist/preact/adapter.d.ts +5 -0
  17. package/dist/preact/core.d.ts +1 -0
  18. package/dist/preact/index.cjs +2 -262
  19. package/dist/preact/index.cjs.map +1 -1
  20. package/dist/preact/index.d.ts +1 -54
  21. package/dist/preact/index.js +29 -34
  22. package/dist/preact/index.js.map +1 -1
  23. package/dist/preact/interaction-manager.d.ts +1 -0
  24. package/dist/react/adapter.d.ts +2 -0
  25. package/dist/react/core.d.ts +1 -0
  26. package/dist/react/index.cjs +2 -262
  27. package/dist/react/index.cjs.map +1 -1
  28. package/dist/react/index.d.ts +1 -53
  29. package/dist/react/index.js +28 -34
  30. package/dist/react/index.js.map +1 -1
  31. package/dist/react/interaction-manager.d.ts +1 -0
  32. package/dist/shared-preact/components/index.d.ts +2 -0
  33. package/dist/shared-preact/components/marquee-zoom.d.ts +21 -0
  34. package/dist/shared-preact/components/pinch-wrapper.d.ts +7 -0
  35. package/dist/shared-preact/hooks/index.d.ts +2 -0
  36. package/dist/shared-preact/hooks/use-pinch-zoom.d.ts +3 -0
  37. package/dist/shared-preact/hooks/use-zoom.d.ts +15 -0
  38. package/dist/shared-preact/index.d.ts +2 -0
  39. package/dist/shared-react/components/index.d.ts +2 -0
  40. package/dist/shared-react/components/marquee-zoom.d.ts +21 -0
  41. package/dist/shared-react/components/pinch-wrapper.d.ts +7 -0
  42. package/dist/shared-react/hooks/index.d.ts +2 -0
  43. package/dist/shared-react/hooks/use-pinch-zoom.d.ts +3 -0
  44. package/dist/shared-react/hooks/use-zoom.d.ts +15 -0
  45. package/dist/shared-react/index.d.ts +2 -0
  46. package/package.json +18 -17
  47. package/dist/index.d.cts +0 -147
  48. package/dist/preact/index.d.cts +0 -54
  49. package/dist/react/index.d.cts +0 -53
@@ -0,0 +1,84 @@
1
+ import { BasePluginConfig, EventHook } from '@embedpdf/core';
2
+ import { Rect } from '@embedpdf/models';
3
+ import { ViewportMetrics } from '@embedpdf/plugin-viewport';
4
+ export declare enum ZoomMode {
5
+ Automatic = "automatic",
6
+ FitPage = "fit-page",
7
+ FitWidth = "fit-width"
8
+ }
9
+ export type ZoomLevel = ZoomMode | number;
10
+ export interface Point {
11
+ vx: number;
12
+ vy: number;
13
+ }
14
+ export interface ZoomChangeEvent {
15
+ /** old and new *actual* scale factors */
16
+ oldZoom: number;
17
+ newZoom: number;
18
+ /** level used to obtain the newZoom (number | mode) */
19
+ level: ZoomLevel;
20
+ /** viewport point kept under the finger / mouse‑wheel focus */
21
+ center: Point;
22
+ /** where the viewport should scroll to after the scale change */
23
+ desiredScrollLeft: number;
24
+ desiredScrollTop: number;
25
+ /** metrics at the moment the zoom was requested */
26
+ viewport: ViewportMetrics;
27
+ }
28
+ export interface ZoomCapability {
29
+ /** subscribe – returns the unsubscribe function */
30
+ onZoomChange: EventHook<ZoomChangeEvent>;
31
+ /** subscribe – returns the unsubscribe function */
32
+ onStateChange: EventHook<ZoomState>;
33
+ /** absolute requests -------------------------------------------------- */
34
+ requestZoom(level: ZoomLevel, center?: Point): void;
35
+ /** relative requests -------------------------------------------------- */
36
+ requestZoomBy(delta: number, center?: Point): void;
37
+ /** absolute requests -------------------------------------------------- */
38
+ zoomIn(): void;
39
+ zoomOut(): void;
40
+ zoomToArea(pageIndex: number, rect: Rect): void;
41
+ /** zoom in on an area -------------------------------------------------- */
42
+ enableMarqueeZoom(): void;
43
+ disableMarqueeZoom(): void;
44
+ toggleMarqueeZoom(): void;
45
+ isMarqueeZoomActive(): boolean;
46
+ getState(): ZoomState;
47
+ getPresets(): ZoomPreset[];
48
+ }
49
+ export interface ZoomRangeStep {
50
+ min: number;
51
+ max: number;
52
+ step: number;
53
+ }
54
+ export interface ZoomPreset {
55
+ name: string;
56
+ value: ZoomLevel;
57
+ icon?: string;
58
+ }
59
+ export interface ZoomPluginConfig extends BasePluginConfig {
60
+ defaultZoomLevel: ZoomLevel;
61
+ minZoom?: number;
62
+ maxZoom?: number;
63
+ zoomStep?: number;
64
+ zoomRanges?: ZoomRangeStep[];
65
+ presets?: ZoomPreset[];
66
+ }
67
+ export interface ZoomState {
68
+ zoomLevel: ZoomLevel;
69
+ currentZoomLevel: number;
70
+ }
71
+ export declare enum VerticalZoomFocus {
72
+ Center = 0,
73
+ Top = 1
74
+ }
75
+ export interface ZoomRequest {
76
+ level: ZoomLevel;
77
+ delta?: number;
78
+ center?: Point;
79
+ focus?: VerticalZoomFocus;
80
+ /** Scroll so that the focal point ends up …
81
+ * ▸ `"keep"` (default) at the same viewport coords
82
+ * ▸ `"center"` centred in the viewport */
83
+ align?: 'keep' | 'center';
84
+ }
@@ -0,0 +1,38 @@
1
+ import { BasePlugin, PluginRegistry } from '@embedpdf/core';
2
+ import { ZoomAction } from './actions';
3
+ import { ZoomPluginConfig, ZoomState, ZoomCapability } from './types';
4
+ export declare class ZoomPlugin extends BasePlugin<ZoomPluginConfig, ZoomCapability, ZoomState, ZoomAction> {
5
+ static readonly id: "zoom";
6
+ private readonly zoom$;
7
+ private readonly state$;
8
+ private readonly viewport;
9
+ private readonly viewportPlugin;
10
+ private readonly scroll;
11
+ private readonly interactionManager;
12
+ private readonly presets;
13
+ private readonly zoomRanges;
14
+ private readonly minZoom;
15
+ private readonly maxZoom;
16
+ private readonly zoomStep;
17
+ constructor(id: string, registry: PluginRegistry, cfg: ZoomPluginConfig);
18
+ protected buildCapability(): ZoomCapability;
19
+ initialize(): Promise<void>;
20
+ destroy(): Promise<void>;
21
+ /**
22
+ * Sort ranges once, make sure they are sane
23
+ */
24
+ private normalizeRanges;
25
+ /** pick the step that applies to a given numeric zoom */
26
+ private stepFor;
27
+ /** clamp + round helper reused later */
28
+ private toZoom;
29
+ private handleRequest;
30
+ /** numeric zoom for Automatic / FitPage / FitWidth */
31
+ private computeZoomForMode;
32
+ /** where to scroll so that *focus* stays stable after scaling */
33
+ private computeScrollForZoomChange;
34
+ private handleZoomToArea;
35
+ /** recalculates Automatic / Fit* when viewport or pages change */
36
+ private recalcAuto;
37
+ onStoreUpdated(_prevState: ZoomState, newState: ZoomState): void;
38
+ }
@@ -0,0 +1,5 @@
1
+ export { Fragment } from 'preact';
2
+ export { useEffect, useRef, useState, useCallback, useMemo } from 'preact/hooks';
3
+ export type { ComponentChildren as ReactNode } from 'preact';
4
+ export type CSSProperties = import('preact').JSX.CSSProperties;
5
+ export type HTMLAttributes<T = any> = import('preact').JSX.HTMLAttributes<T extends EventTarget ? T : never>;
@@ -0,0 +1 @@
1
+ export * from '@embedpdf/core/preact';
@@ -1,262 +1,2 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/preact/index.ts
31
- var preact_exports = {};
32
- __export(preact_exports, {
33
- MarqueeZoom: () => MarqueeZoom,
34
- PinchWrapper: () => PinchWrapper,
35
- usePinch: () => usePinch,
36
- useZoom: () => useZoom,
37
- useZoomCapability: () => useZoomCapability,
38
- useZoomPlugin: () => useZoomPlugin
39
- });
40
- module.exports = __toCommonJS(preact_exports);
41
-
42
- // src/preact/hooks/use-zoom.ts
43
- var import_preact = require("@embedpdf/core/preact");
44
- var import_plugin_zoom = require("@embedpdf/plugin-zoom");
45
- var import_hooks = require("preact/hooks");
46
- var useZoomCapability = () => (0, import_preact.useCapability)(import_plugin_zoom.ZoomPlugin.id);
47
- var useZoomPlugin = () => (0, import_preact.usePlugin)(import_plugin_zoom.ZoomPlugin.id);
48
- var useZoom = () => {
49
- const { provides } = useZoomCapability();
50
- const [state, setState] = (0, import_hooks.useState)(import_plugin_zoom.initialState);
51
- (0, import_hooks.useEffect)(() => {
52
- return provides?.onStateChange((action) => {
53
- setState(action);
54
- });
55
- }, [provides]);
56
- return {
57
- state,
58
- provides
59
- };
60
- };
61
-
62
- // src/preact/hooks/use-pinch-zoom.ts
63
- var import_hooks2 = require("preact/hooks");
64
- var import_preact2 = require("@embedpdf/core/preact");
65
- function usePinch() {
66
- const { provides: viewportProvides } = (0, import_preact2.useCapability)("viewport");
67
- const { provides: zoomProvides } = useZoomCapability();
68
- const elementRef = (0, import_hooks2.useRef)(null);
69
- (0, import_hooks2.useEffect)(() => {
70
- const element = elementRef.current;
71
- if (!element || !viewportProvides || !zoomProvides) {
72
- return;
73
- }
74
- if (typeof window === "undefined") {
75
- return;
76
- }
77
- let hammer;
78
- let initialZoom = 0;
79
- let lastCenter = { x: 0, y: 0 };
80
- const getState = () => zoomProvides.getState();
81
- const updateTransform = (scale) => {
82
- element.style.transform = `scale(${scale})`;
83
- };
84
- const resetTransform = () => {
85
- element.style.transform = "none";
86
- element.style.transformOrigin = "0 0";
87
- };
88
- const pinchStart = (e) => {
89
- initialZoom = getState().currentZoomLevel;
90
- const contRect = viewportProvides.getBoundingRect();
91
- lastCenter = {
92
- x: e.center.x - contRect.origin.x,
93
- y: e.center.y - contRect.origin.y
94
- };
95
- const innerRect = element.getBoundingClientRect();
96
- element.style.transformOrigin = `${e.center.x - innerRect.left}px ${e.center.y - innerRect.top}px`;
97
- if (e.srcEvent?.cancelable) {
98
- e.srcEvent.preventDefault();
99
- e.srcEvent.stopPropagation();
100
- }
101
- };
102
- const pinchMove = (e) => {
103
- updateTransform(e.scale);
104
- if (e.srcEvent?.cancelable) {
105
- e.srcEvent.preventDefault();
106
- e.srcEvent.stopPropagation();
107
- }
108
- };
109
- const pinchEnd = (e) => {
110
- const delta = (e.scale - 1) * initialZoom;
111
- zoomProvides.requestZoomBy(delta, { vx: lastCenter.x, vy: lastCenter.y });
112
- resetTransform();
113
- initialZoom = 0;
114
- };
115
- const setupHammer = async () => {
116
- try {
117
- const Hammer = (await import("hammerjs")).default;
118
- const inputClass = (() => {
119
- const MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
120
- const SUPPORT_TOUCH = "ontouchstart" in window || navigator.maxTouchPoints > 0;
121
- const SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);
122
- if (SUPPORT_ONLY_TOUCH) return Hammer.TouchInput;
123
- if (!SUPPORT_TOUCH) return Hammer.MouseInput;
124
- return Hammer.TouchMouseInput;
125
- })();
126
- hammer = new Hammer(element, {
127
- touchAction: "pan-x pan-y",
128
- // allow scroll in every direction
129
- inputClass
130
- });
131
- hammer.get("pinch").set({ enable: true, pointers: 2, threshold: 0.1 });
132
- hammer.on("pinchstart", pinchStart);
133
- hammer.on("pinchmove", pinchMove);
134
- hammer.on("pinchend", pinchEnd);
135
- } catch (error) {
136
- console.warn("Failed to load HammerJS:", error);
137
- }
138
- };
139
- setupHammer();
140
- return () => {
141
- hammer?.destroy();
142
- resetTransform();
143
- };
144
- }, [viewportProvides, zoomProvides]);
145
- return { elementRef };
146
- }
147
-
148
- // src/preact/components/pinch-wrapper.tsx
149
- var import_jsx_runtime = require("preact/jsx-runtime");
150
- function PinchWrapper({ children, style, ...props }) {
151
- const { elementRef } = usePinch();
152
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
153
- "div",
154
- {
155
- ref: elementRef,
156
- ...props,
157
- style: {
158
- ...style,
159
- display: "block",
160
- width: "fit-content",
161
- overflow: "visible",
162
- boxSizing: "border-box",
163
- margin: "0px auto"
164
- },
165
- children
166
- }
167
- );
168
- }
169
-
170
- // src/preact/components/marquee-zoom.tsx
171
- var import_hooks4 = require("preact/hooks");
172
- var import_preact3 = require("@embedpdf/plugin-interaction-manager/preact");
173
- var import_jsx_runtime2 = require("preact/jsx-runtime");
174
- var MarqueeZoom = ({
175
- pageIndex,
176
- scale,
177
- pageWidth,
178
- pageHeight,
179
- className,
180
- stroke = "rgba(33,150,243,0.8)",
181
- fill = "rgba(33,150,243,0.15)"
182
- }) => {
183
- const { provides: zoom } = useZoomCapability();
184
- const { register } = (0, import_preact3.usePointerHandlers)({ modeId: "marqueeZoom", pageIndex });
185
- const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
186
- const startRef = (0, import_hooks4.useRef)(null);
187
- const [rect, setRect] = (0, import_hooks4.useState)(null);
188
- const pageWidthPDF = pageWidth / scale;
189
- const pageHeightPDF = pageHeight / scale;
190
- const handlers = (0, import_hooks4.useMemo)(
191
- () => ({
192
- onPointerDown: (pos, evt) => {
193
- startRef.current = pos;
194
- setRect({ origin: { x: pos.x, y: pos.y }, size: { width: 0, height: 0 } });
195
- evt.target?.setPointerCapture?.(evt.pointerId);
196
- },
197
- onPointerMove: (pos) => {
198
- if (!startRef.current) return;
199
- const curX = clamp(pos.x, 0, pageWidthPDF);
200
- const curY = clamp(pos.y, 0, pageHeightPDF);
201
- const { x: sx, y: sy } = startRef.current;
202
- const left = Math.min(sx, curX);
203
- const top = Math.min(sy, curY);
204
- const width = Math.abs(curX - sx);
205
- const height = Math.abs(curY - sy);
206
- setRect({ origin: { x: left, y: top }, size: { width, height } });
207
- },
208
- onPointerUp: (_, evt) => {
209
- if (rect && zoom) {
210
- const dragPx = Math.max(rect.size.width, rect.size.height) * scale;
211
- if (dragPx > 5) {
212
- zoom.zoomToArea(pageIndex, rect);
213
- } else {
214
- zoom.zoomIn();
215
- }
216
- }
217
- startRef.current = null;
218
- setRect(null);
219
- evt.target?.releasePointerCapture?.(evt.pointerId);
220
- },
221
- onPointerCancel: (_, evt) => {
222
- startRef.current = null;
223
- setRect(null);
224
- evt.target?.releasePointerCapture?.(evt.pointerId);
225
- }
226
- }),
227
- [pageWidthPDF, pageWidthPDF, zoom, scale, rect, pageIndex]
228
- );
229
- (0, import_hooks4.useEffect)(() => {
230
- if (!register) return;
231
- return register(handlers);
232
- }, [register, handlers]);
233
- if (!rect) return null;
234
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
235
- "div",
236
- {
237
- style: {
238
- position: "absolute",
239
- pointerEvents: "none",
240
- // ignore hits – underlying page still gets events
241
- left: rect.origin.x * scale,
242
- top: rect.origin.y * scale,
243
- width: rect.size.width * scale,
244
- height: rect.size.height * scale,
245
- border: `1px solid ${stroke}`,
246
- background: fill,
247
- boxSizing: "border-box"
248
- },
249
- className
250
- }
251
- );
252
- };
253
- // Annotate the CommonJS export names for ESM import in node:
254
- 0 && (module.exports = {
255
- MarqueeZoom,
256
- PinchWrapper,
257
- usePinch,
258
- useZoom,
259
- useZoomCapability,
260
- useZoomPlugin
261
- });
262
- //# sourceMappingURL=index.cjs.map
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core/preact"),t=require("@embedpdf/plugin-zoom");require("preact");const n=require("preact/hooks"),r=require("preact/jsx-runtime"),o=require("@embedpdf/plugin-interaction-manager/preact"),i=()=>e.useCapability(t.ZoomPlugin.id);function a(){const{provides:t}=e.useCapability("viewport"),{provides:r}=i(),o=n.useRef(null);return n.useEffect((()=>{const e=o.current;if(!e||!t||!r)return;if("undefined"==typeof window)return;let n,i=0,a={x:0,y:0};const s=()=>{e.style.transform="none",e.style.transformOrigin="0 0"},l=n=>{var o;i=r.getState().currentZoomLevel;const s=t.getBoundingRect();a={x:n.center.x-s.origin.x,y:n.center.y-s.origin.y};const l=e.getBoundingClientRect();e.style.transformOrigin=`${n.center.x-l.left}px ${n.center.y-l.top}px`,(null==(o=n.srcEvent)?void 0:o.cancelable)&&(n.srcEvent.preventDefault(),n.srcEvent.stopPropagation())},u=t=>{var n,r;r=t.scale,e.style.transform=`scale(${r})`,(null==(n=t.srcEvent)?void 0:n.cancelable)&&(t.srcEvent.preventDefault(),t.srcEvent.stopPropagation())},c=e=>{const t=(e.scale-1)*i;r.requestZoomBy(t,{vx:a.x,vy:a.y}),s(),i=0};return(async()=>{try{const t=(await Promise.resolve().then((()=>require("../hammer-Bs-QCG8V.cjs"))).then((e=>e.hammer))).default,r=(()=>{const e="ontouchstart"in window||navigator.maxTouchPoints>0;return e&&/mobile|tablet|ip(ad|hone|od)|android/i.test(navigator.userAgent)?t.TouchInput:e?t.TouchMouseInput:t.MouseInput})();n=new t(e,{touchAction:"pan-x pan-y",inputClass:r}),n.get("pinch").set({enable:!0,pointers:2,threshold:.1}),n.on("pinchstart",l),n.on("pinchmove",u),n.on("pinchend",c)}catch(t){console.warn("Failed to load HammerJS:",t)}})(),()=>{null==n||n.destroy(),s()}}),[t,r]),{elementRef:o}}exports.MarqueeZoom=({pageIndex:e,scale:t,pageWidth:a,pageHeight:s,className:l,stroke:u="rgba(33,150,243,0.8)",fill:c="rgba(33,150,243,0.15)"})=>{const{provides:p}=i(),{register:d}=o.usePointerHandlers({modeId:"marqueeZoom",pageIndex:e}),g=(e,t,n)=>Math.max(t,Math.min(n,e)),h=n.useRef(null),[m,v]=n.useState(null),x=a/t,f=s/t,y=n.useMemo((()=>({onPointerDown:(e,t)=>{var n,r;h.current=e,v({origin:{x:e.x,y:e.y},size:{width:0,height:0}}),null==(r=null==(n=t.target)?void 0:n.setPointerCapture)||r.call(n,t.pointerId)},onPointerMove:e=>{if(!h.current)return;const t=g(e.x,0,x),n=g(e.y,0,f),{x:r,y:o}=h.current,i=Math.min(r,t),a=Math.min(o,n),s=Math.abs(t-r),l=Math.abs(n-o);v({origin:{x:i,y:a},size:{width:s,height:l}})},onPointerUp:(n,r)=>{var o,i;if(m&&p){Math.max(m.size.width,m.size.height)*t>5?p.zoomToArea(e,m):p.zoomIn()}h.current=null,v(null),null==(i=null==(o=r.target)?void 0:o.releasePointerCapture)||i.call(o,r.pointerId)},onPointerCancel:(e,t)=>{var n,r;h.current=null,v(null),null==(r=null==(n=t.target)?void 0:n.releasePointerCapture)||r.call(n,t.pointerId)}})),[x,x,p,t,m,e]);return n.useEffect((()=>{if(d)return d(y)}),[d,y]),m?r.jsx("div",{style:{position:"absolute",pointerEvents:"none",left:m.origin.x*t,top:m.origin.y*t,width:m.size.width*t,height:m.size.height*t,border:`1px solid ${u}`,background:c,boxSizing:"border-box"},className:l}):null},exports.PinchWrapper=function({children:e,style:t,...n}){const{elementRef:o}=a();return r.jsx("div",{ref:o,...n,style:{...t,display:"block",width:"fit-content",overflow:"visible",boxSizing:"border-box",margin:"0px auto"},children:e})},exports.usePinch=a,exports.useZoom=()=>{const{provides:e}=i(),[r,o]=n.useState(t.initialState);return n.useEffect((()=>null==e?void 0:e.onStateChange((e=>{o(e)}))),[e]),{state:r,provides:e}},exports.useZoomCapability=i,exports.useZoomPlugin=()=>e.usePlugin(t.ZoomPlugin.id);
2
+ //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/preact/index.ts","../../src/preact/hooks/use-zoom.ts","../../src/preact/hooks/use-pinch-zoom.ts","../../src/preact/components/pinch-wrapper.tsx","../../src/preact/components/marquee-zoom.tsx"],"sourcesContent":["export * from './hooks';\nexport * from './components';\n","import { useCapability, usePlugin } from '@embedpdf/core/preact';\nimport { initialState, ZoomPlugin, ZoomState } from '@embedpdf/plugin-zoom';\nimport { useEffect, useState } from 'preact/hooks';\n\nexport const useZoomCapability = () => useCapability<ZoomPlugin>(ZoomPlugin.id);\nexport const useZoomPlugin = () => usePlugin<ZoomPlugin>(ZoomPlugin.id);\n\nexport const useZoom = () => {\n const { provides } = useZoomCapability();\n const [state, setState] = useState<ZoomState>(initialState);\n\n useEffect(() => {\n return provides?.onStateChange((action) => {\n setState(action);\n });\n }, [provides]);\n\n return {\n state,\n provides,\n };\n};\n","import { useEffect, useRef } from 'preact/hooks';\nimport { useCapability } from '@embedpdf/core/preact';\nimport { ViewportPlugin } from '@embedpdf/plugin-viewport';\nimport { ZoomState } from '@embedpdf/plugin-zoom';\n\nimport { useZoomCapability } from './use-zoom';\n\nexport function usePinch() {\n const { provides: viewportProvides } = useCapability<ViewportPlugin>('viewport');\n const { provides: zoomProvides } = useZoomCapability();\n const elementRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const element = elementRef.current;\n if (!element || !viewportProvides || !zoomProvides) {\n return;\n }\n\n // Check if we're on the client side\n if (typeof window === 'undefined') {\n return;\n }\n\n let hammer: any | undefined;\n let initialZoom = 0; // numeric scale at pinchstart\n let lastCenter = { x: 0, y: 0 };\n\n const getState = (): ZoomState => zoomProvides.getState();\n\n const updateTransform = (scale: number) => {\n // 1 → no scale; we only scale *relatively* to the start\n element.style.transform = `scale(${scale})`;\n };\n\n const resetTransform = () => {\n element.style.transform = 'none';\n element.style.transformOrigin = '0 0';\n };\n\n const pinchStart = (e: HammerInput) => {\n initialZoom = getState().currentZoomLevel;\n\n const contRect = viewportProvides.getBoundingRect();\n\n lastCenter = {\n x: e.center.x - contRect.origin.x,\n y: e.center.y - contRect.origin.y,\n };\n\n // put the transform-origin under the fingers so the preview feels right\n const innerRect = element.getBoundingClientRect();\n element.style.transformOrigin = `${e.center.x - innerRect.left}px ${e.center.y - innerRect.top}px`;\n\n // stop the browser’s own pinch-zoom\n if (e.srcEvent?.cancelable) {\n e.srcEvent.preventDefault();\n e.srcEvent.stopPropagation();\n }\n };\n\n const pinchMove = (e: HammerInput) => {\n updateTransform(e.scale); // *only* CSS, no real zoom yet\n if (e.srcEvent?.cancelable) {\n e.srcEvent.preventDefault();\n e.srcEvent.stopPropagation();\n }\n };\n\n const pinchEnd = (e: HammerInput) => {\n // translate the relative hammer scale into a delta for requestZoomBy\n const delta = (e.scale - 1) * initialZoom;\n zoomProvides.requestZoomBy(delta, { vx: lastCenter.x, vy: lastCenter.y });\n\n resetTransform();\n initialZoom = 0;\n };\n\n // Dynamically import and setup Hammer\n const setupHammer = async () => {\n try {\n const Hammer = (await import('hammerjs')).default;\n\n /* ------------------------------------------------------------------ */\n /* Hammer setup */\n /* ------------------------------------------------------------------ */\n const inputClass = (() => {\n const MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;\n const SUPPORT_TOUCH = 'ontouchstart' in window || navigator.maxTouchPoints > 0;\n const SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);\n if (SUPPORT_ONLY_TOUCH) return Hammer.TouchInput;\n if (!SUPPORT_TOUCH) return Hammer.MouseInput;\n return Hammer.TouchMouseInput;\n })();\n\n hammer = new Hammer(element, {\n touchAction: 'pan-x pan-y', // allow scroll in every direction\n inputClass,\n });\n\n hammer.get('pinch').set({ enable: true, pointers: 2, threshold: 0.1 });\n\n hammer.on('pinchstart', pinchStart);\n hammer.on('pinchmove', pinchMove);\n hammer.on('pinchend', pinchEnd);\n } catch (error) {\n console.warn('Failed to load HammerJS:', error);\n }\n };\n\n setupHammer();\n\n return () => {\n hammer?.destroy();\n resetTransform();\n };\n }, [viewportProvides, zoomProvides]);\n\n return { elementRef };\n}\n","/** @jsxImportSource preact */\nimport { ComponentChildren, JSX } from 'preact';\n\nimport { usePinch } from '../hooks';\n\ntype PinchWrapperProps = Omit<JSX.HTMLAttributes<HTMLDivElement>, 'style'> & {\n children: ComponentChildren;\n style?: JSX.CSSProperties;\n};\n\nexport function PinchWrapper({ children, style, ...props }: PinchWrapperProps) {\n const { elementRef } = usePinch();\n\n return (\n <div\n ref={elementRef}\n {...props}\n style={{\n ...style,\n display: 'block',\n width: 'fit-content',\n overflow: 'visible',\n boxSizing: 'border-box',\n margin: '0px auto',\n }}\n >\n {children}\n </div>\n );\n}\n","/** @jsxImportSource preact */\nimport { useEffect, useMemo, useRef, useState } from 'preact/hooks';\nimport type { PointerEventHandlers } from '@embedpdf/plugin-interaction-manager';\nimport { usePointerHandlers } from '@embedpdf/plugin-interaction-manager/preact';\nimport { Rect } from '@embedpdf/models';\n\nimport { useZoomCapability } from '../hooks/use-zoom';\n\ninterface MarqueeZoomProps {\n /** Index of the page this layer lives on */\n pageIndex: number;\n /** Scale of the page */\n scale: number;\n /** Width of the page */\n pageWidth: number;\n /** Height of the page */\n pageHeight: number;\n /** Optional CSS class applied to the marquee rectangle */\n className?: string;\n /** Stroke / fill colours (defaults below) */\n stroke?: string;\n fill?: string;\n}\n\n/**\n * Draws a marquee rectangle while the user drags.\n * Hook it into the interaction-manager with modeId = 'marqueeZoom'.\n */\nexport const MarqueeZoom = ({\n pageIndex,\n scale,\n pageWidth,\n pageHeight,\n className,\n stroke = 'rgba(33,150,243,0.8)',\n fill = 'rgba(33,150,243,0.15)',\n}: MarqueeZoomProps) => {\n /* ------------------------------------------------------------------ */\n /* zoom capability */\n /* ------------------------------------------------------------------ */\n const { provides: zoom } = useZoomCapability();\n\n /* ------------------------------------------------------------------ */\n /* integration with interaction-manager */\n /* ------------------------------------------------------------------ */\n const { register } = usePointerHandlers({ modeId: 'marqueeZoom', pageIndex });\n\n /* ------------------------------------------------------------------ */\n /* helpers */\n /* ------------------------------------------------------------------ */\n const clamp = (v: number, min: number, max: number) => Math.max(min, Math.min(max, v));\n\n /* ------------------------------------------------------------------ */\n /* local state – start / current drag position */\n /* ------------------------------------------------------------------ */\n const startRef = useRef<{ x: number; y: number } | null>(null);\n const [rect, setRect] = useState<Rect | null>(null);\n\n /* page size in **PDF-space** (unscaled) ----------------------------- */\n const pageWidthPDF = pageWidth / scale;\n const pageHeightPDF = pageHeight / scale;\n\n /* ------------------------------------------------------------------ */\n /* pointer handlers */\n /* ------------------------------------------------------------------ */\n const handlers = useMemo<PointerEventHandlers<PointerEvent>>(\n () => ({\n onPointerDown: (pos, evt) => {\n startRef.current = pos;\n setRect({ origin: { x: pos.x, y: pos.y }, size: { width: 0, height: 0 } });\n (evt.target as HTMLElement)?.setPointerCapture?.(evt.pointerId);\n },\n onPointerMove: (pos) => {\n if (!startRef.current) return;\n /* clamp current position to the page bounds */\n const curX = clamp(pos.x, 0, pageWidthPDF);\n const curY = clamp(pos.y, 0, pageHeightPDF);\n\n const { x: sx, y: sy } = startRef.current;\n const left = Math.min(sx, curX);\n const top = Math.min(sy, curY);\n const width = Math.abs(curX - sx);\n const height = Math.abs(curY - sy);\n\n setRect({ origin: { x: left, y: top }, size: { width, height } });\n },\n onPointerUp: (_, evt) => {\n if (rect && zoom) {\n const dragPx = Math.max(rect.size.width, rect.size.height) * scale;\n if (dragPx > 5) {\n // real drag → zoom to it\n zoom.zoomToArea(pageIndex, rect);\n } else {\n // tiny drag → simple zoom-in\n zoom.zoomIn();\n }\n }\n\n startRef.current = null;\n setRect(null);\n (evt.target as HTMLElement)?.releasePointerCapture?.(evt.pointerId);\n },\n onPointerCancel: (_, evt) => {\n startRef.current = null;\n setRect(null);\n (evt.target as HTMLElement)?.releasePointerCapture?.(evt.pointerId);\n },\n }),\n [pageWidthPDF, pageWidthPDF, zoom, scale, rect, pageIndex],\n );\n\n /* register with the interaction-manager */\n useEffect(() => {\n if (!register) return;\n return register(handlers);\n }, [register, handlers]);\n\n /* ------------------------------------------------------------------ */\n /* render */\n /* ------------------------------------------------------------------ */\n if (!rect) return null; // nothing to draw\n\n return (\n <div\n /* Each page wrapper is position:relative, so absolute is fine */\n style={{\n position: 'absolute',\n pointerEvents: 'none', // ignore hits – underlying page still gets events\n left: rect.origin.x * scale,\n top: rect.origin.y * scale,\n width: rect.size.width * scale,\n height: rect.size.height * scale,\n border: `1px solid ${stroke}`,\n background: fill,\n boxSizing: 'border-box',\n }}\n className={className}\n />\n );\n};\n"],"mappings":"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","names":["import_hooks","import_preact","import_hooks","import_preact","import_jsx_runtime"]}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-zoom.ts","../../src/shared/hooks/use-pinch-zoom.ts","../../src/shared/components/marquee-zoom.tsx","../../src/shared/components/pinch-wrapper.tsx"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { initialState, ZoomPlugin, ZoomState } from '@embedpdf/plugin-zoom';\nimport { useEffect, useState } from '@framework';\n\nexport const useZoomCapability = () => useCapability<ZoomPlugin>(ZoomPlugin.id);\nexport const useZoomPlugin = () => usePlugin<ZoomPlugin>(ZoomPlugin.id);\n\nexport const useZoom = () => {\n const { provides } = useZoomCapability();\n const [state, setState] = useState<ZoomState>(initialState);\n\n useEffect(() => {\n return provides?.onStateChange((action) => {\n setState(action);\n });\n }, [provides]);\n\n return {\n state,\n provides,\n };\n};\n","import { useEffect, useRef } from '@framework';\nimport { useCapability } from '@embedpdf/core/@framework';\nimport { ViewportPlugin } from '@embedpdf/plugin-viewport';\nimport { ZoomState } from '@embedpdf/plugin-zoom';\n\nimport { useZoomCapability } from './use-zoom';\n\nexport function usePinch() {\n const { provides: viewportProvides } = useCapability<ViewportPlugin>('viewport');\n const { provides: zoomProvides } = useZoomCapability();\n const elementRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const element = elementRef.current;\n if (!element || !viewportProvides || !zoomProvides) {\n return;\n }\n\n // Check if we're on the client side\n if (typeof window === 'undefined') {\n return;\n }\n\n let hammer: any | undefined;\n let initialZoom = 0; // numeric scale at pinchstart\n let lastCenter = { x: 0, y: 0 };\n\n const getState = (): ZoomState => zoomProvides.getState();\n\n const updateTransform = (scale: number) => {\n // 1 → no scale; we only scale *relatively* to the start\n element.style.transform = `scale(${scale})`;\n };\n\n const resetTransform = () => {\n element.style.transform = 'none';\n element.style.transformOrigin = '0 0';\n };\n\n const pinchStart = (e: HammerInput) => {\n initialZoom = getState().currentZoomLevel;\n\n const contRect = viewportProvides.getBoundingRect();\n\n lastCenter = {\n x: e.center.x - contRect.origin.x,\n y: e.center.y - contRect.origin.y,\n };\n\n // put the transform-origin under the fingers so the preview feels right\n const innerRect = element.getBoundingClientRect();\n element.style.transformOrigin = `${e.center.x - innerRect.left}px ${e.center.y - innerRect.top}px`;\n\n // stop the browser’s own pinch-zoom\n if (e.srcEvent?.cancelable) {\n e.srcEvent.preventDefault();\n e.srcEvent.stopPropagation();\n }\n };\n\n const pinchMove = (e: HammerInput) => {\n updateTransform(e.scale); // *only* CSS, no real zoom yet\n if (e.srcEvent?.cancelable) {\n e.srcEvent.preventDefault();\n e.srcEvent.stopPropagation();\n }\n };\n\n const pinchEnd = (e: HammerInput) => {\n // translate the relative hammer scale into a delta for requestZoomBy\n const delta = (e.scale - 1) * initialZoom;\n zoomProvides.requestZoomBy(delta, { vx: lastCenter.x, vy: lastCenter.y });\n\n resetTransform();\n initialZoom = 0;\n };\n\n // Dynamically import and setup Hammer\n const setupHammer = async () => {\n try {\n const Hammer = (await import('hammerjs')).default;\n\n /* ------------------------------------------------------------------ */\n /* Hammer setup */\n /* ------------------------------------------------------------------ */\n const inputClass = (() => {\n const MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;\n const SUPPORT_TOUCH = 'ontouchstart' in window || navigator.maxTouchPoints > 0;\n const SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);\n if (SUPPORT_ONLY_TOUCH) return Hammer.TouchInput;\n if (!SUPPORT_TOUCH) return Hammer.MouseInput;\n return Hammer.TouchMouseInput;\n })();\n\n hammer = new Hammer(element, {\n touchAction: 'pan-x pan-y', // allow scroll in every direction\n inputClass,\n });\n\n hammer.get('pinch').set({ enable: true, pointers: 2, threshold: 0.1 });\n\n hammer.on('pinchstart', pinchStart);\n hammer.on('pinchmove', pinchMove);\n hammer.on('pinchend', pinchEnd);\n } catch (error) {\n console.warn('Failed to load HammerJS:', error);\n }\n };\n\n setupHammer();\n\n return () => {\n hammer?.destroy();\n resetTransform();\n };\n }, [viewportProvides, zoomProvides]);\n\n return { elementRef };\n}\n","import { useEffect, useMemo, useRef, useState } from '@framework';\nimport type { PointerEventHandlers } from '@embedpdf/plugin-interaction-manager';\nimport { usePointerHandlers } from '@embedpdf/plugin-interaction-manager/@framework';\nimport { Rect } from '@embedpdf/models';\n\nimport { useZoomCapability } from '../hooks/use-zoom';\n\ninterface MarqueeZoomProps {\n /** Index of the page this layer lives on */\n pageIndex: number;\n /** Scale of the page */\n scale: number;\n /** Width of the page */\n pageWidth: number;\n /** Height of the page */\n pageHeight: number;\n /** Optional CSS class applied to the marquee rectangle */\n className?: string;\n /** Stroke / fill colours (defaults below) */\n stroke?: string;\n fill?: string;\n}\n\n/**\n * Draws a marquee rectangle while the user drags.\n * Hook it into the interaction-manager with modeId = 'marqueeZoom'.\n */\nexport const MarqueeZoom = ({\n pageIndex,\n scale,\n pageWidth,\n pageHeight,\n className,\n stroke = 'rgba(33,150,243,0.8)',\n fill = 'rgba(33,150,243,0.15)',\n}: MarqueeZoomProps) => {\n /* ------------------------------------------------------------------ */\n /* zoom capability */\n /* ------------------------------------------------------------------ */\n const { provides: zoom } = useZoomCapability();\n\n /* ------------------------------------------------------------------ */\n /* integration with interaction-manager */\n /* ------------------------------------------------------------------ */\n const { register } = usePointerHandlers({ modeId: 'marqueeZoom', pageIndex });\n\n /* ------------------------------------------------------------------ */\n /* helpers */\n /* ------------------------------------------------------------------ */\n const clamp = (v: number, min: number, max: number) => Math.max(min, Math.min(max, v));\n\n /* ------------------------------------------------------------------ */\n /* local state – start / current drag position */\n /* ------------------------------------------------------------------ */\n const startRef = useRef<{ x: number; y: number } | null>(null);\n const [rect, setRect] = useState<Rect | null>(null);\n\n /* page size in **PDF-space** (unscaled) ----------------------------- */\n const pageWidthPDF = pageWidth / scale;\n const pageHeightPDF = pageHeight / scale;\n\n /* ------------------------------------------------------------------ */\n /* pointer handlers */\n /* ------------------------------------------------------------------ */\n const handlers = useMemo<PointerEventHandlers<PointerEvent>>(\n () => ({\n onPointerDown: (pos, evt) => {\n startRef.current = pos;\n setRect({ origin: { x: pos.x, y: pos.y }, size: { width: 0, height: 0 } });\n (evt.target as HTMLElement)?.setPointerCapture?.(evt.pointerId);\n },\n onPointerMove: (pos) => {\n if (!startRef.current) return;\n /* clamp current position to the page bounds */\n const curX = clamp(pos.x, 0, pageWidthPDF);\n const curY = clamp(pos.y, 0, pageHeightPDF);\n\n const { x: sx, y: sy } = startRef.current;\n const left = Math.min(sx, curX);\n const top = Math.min(sy, curY);\n const width = Math.abs(curX - sx);\n const height = Math.abs(curY - sy);\n\n setRect({ origin: { x: left, y: top }, size: { width, height } });\n },\n onPointerUp: (_, evt) => {\n if (rect && zoom) {\n const dragPx = Math.max(rect.size.width, rect.size.height) * scale;\n if (dragPx > 5) {\n // real drag → zoom to it\n zoom.zoomToArea(pageIndex, rect);\n } else {\n // tiny drag → simple zoom-in\n zoom.zoomIn();\n }\n }\n\n startRef.current = null;\n setRect(null);\n (evt.target as HTMLElement)?.releasePointerCapture?.(evt.pointerId);\n },\n onPointerCancel: (_, evt) => {\n startRef.current = null;\n setRect(null);\n (evt.target as HTMLElement)?.releasePointerCapture?.(evt.pointerId);\n },\n }),\n [pageWidthPDF, pageWidthPDF, zoom, scale, rect, pageIndex],\n );\n\n /* register with the interaction-manager */\n useEffect(() => {\n if (!register) return;\n return register(handlers);\n }, [register, handlers]);\n\n /* ------------------------------------------------------------------ */\n /* render */\n /* ------------------------------------------------------------------ */\n if (!rect) return null; // nothing to draw\n\n return (\n <div\n /* Each page wrapper is position:relative, so absolute is fine */\n style={{\n position: 'absolute',\n pointerEvents: 'none', // ignore hits – underlying page still gets events\n left: rect.origin.x * scale,\n top: rect.origin.y * scale,\n width: rect.size.width * scale,\n height: rect.size.height * scale,\n border: `1px solid ${stroke}`,\n background: fill,\n boxSizing: 'border-box',\n }}\n className={className}\n />\n );\n};\n","import { ReactNode, HTMLAttributes, CSSProperties } from '@framework';\n\nimport { usePinch } from '../hooks';\n\ntype PinchWrapperProps = Omit<HTMLAttributes<HTMLDivElement>, 'style'> & {\n children: ReactNode;\n style?: CSSProperties;\n};\n\nexport function PinchWrapper({ children, style, ...props }: PinchWrapperProps) {\n const { elementRef } = usePinch();\n\n return (\n <div\n ref={elementRef}\n {...props}\n style={{\n ...style,\n display: 'block',\n width: 'fit-content',\n overflow: 'visible',\n boxSizing: 'border-box',\n margin: '0px auto',\n }}\n >\n {children}\n </div>\n );\n}\n"],"names":["useZoomCapability","useCapability","ZoomPlugin","id","usePinch","provides","viewportProvides","zoomProvides","elementRef","useRef","useEffect","element","current","window","hammer","initialZoom","lastCenter","x","y","resetTransform","style","transform","transformOrigin","pinchStart","e","getState","currentZoomLevel","contRect","getBoundingRect","center","origin","innerRect","getBoundingClientRect","left","top","_a","srcEvent","cancelable","preventDefault","stopPropagation","pinchMove","scale","pinchEnd","delta","requestZoomBy","vx","vy","async","Hammer","Promise","resolve","then","require","n","default","inputClass","SUPPORT_TOUCH","navigator","maxTouchPoints","test","userAgent","TouchInput","TouchMouseInput","MouseInput","touchAction","get","set","enable","pointers","threshold","on","error","console","warn","setupHammer","destroy","pageIndex","pageWidth","pageHeight","className","stroke","fill","zoom","register","usePointerHandlers","modeId","clamp","v","min","max","Math","startRef","rect","setRect","useState","pageWidthPDF","pageHeightPDF","handlers","useMemo","onPointerDown","pos","evt","size","width","height","_b","target","setPointerCapture","call","pointerId","onPointerMove","curX","curY","sx","sy","abs","onPointerUp","_","zoomToArea","zoomIn","releasePointerCapture","onPointerCancel","jsxRuntime","jsx","position","pointerEvents","border","background","boxSizing","children","props","ref","display","overflow","margin","state","setState","initialState","onStateChange","action","usePlugin"],"mappings":"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"}
@@ -1,54 +1 @@
1
- import * as _embedpdf_plugin_zoom from '@embedpdf/plugin-zoom';
2
- import { ZoomPlugin, ZoomState } from '@embedpdf/plugin-zoom';
3
- import * as preact from 'preact';
4
- import { JSX, ComponentChildren } from 'preact';
5
-
6
- declare const useZoomCapability: () => {
7
- provides: Readonly<_embedpdf_plugin_zoom.ZoomCapability> | null;
8
- isLoading: boolean;
9
- ready: Promise<void>;
10
- };
11
- declare const useZoomPlugin: () => {
12
- plugin: ZoomPlugin | null;
13
- isLoading: boolean;
14
- ready: Promise<void>;
15
- };
16
- declare const useZoom: () => {
17
- state: ZoomState;
18
- provides: Readonly<_embedpdf_plugin_zoom.ZoomCapability> | null;
19
- };
20
-
21
- declare function usePinch(): {
22
- elementRef: preact.RefObject<HTMLDivElement>;
23
- };
24
-
25
- /** @jsxImportSource preact */
26
-
27
- type PinchWrapperProps = Omit<JSX.HTMLAttributes<HTMLDivElement>, 'style'> & {
28
- children: ComponentChildren;
29
- style?: JSX.CSSProperties;
30
- };
31
- declare function PinchWrapper({ children, style, ...props }: PinchWrapperProps): JSX.Element;
32
-
33
- interface MarqueeZoomProps {
34
- /** Index of the page this layer lives on */
35
- pageIndex: number;
36
- /** Scale of the page */
37
- scale: number;
38
- /** Width of the page */
39
- pageWidth: number;
40
- /** Height of the page */
41
- pageHeight: number;
42
- /** Optional CSS class applied to the marquee rectangle */
43
- className?: string;
44
- /** Stroke / fill colours (defaults below) */
45
- stroke?: string;
46
- fill?: string;
47
- }
48
- /**
49
- * Draws a marquee rectangle while the user drags.
50
- * Hook it into the interaction-manager with modeId = 'marqueeZoom'.
51
- */
52
- declare const MarqueeZoom: ({ pageIndex, scale, pageWidth, pageHeight, className, stroke, fill, }: MarqueeZoomProps) => preact.JSX.Element | null;
53
-
54
- export { MarqueeZoom, PinchWrapper, usePinch, useZoom, useZoomCapability, useZoomPlugin };
1
+ export * from '../shared-preact';