uix-image-magnify 0.1.1 → 0.1.3
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 +409 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +69 -0
- package/dist/index.d.ts +69 -0
- package/dist/index.js +406 -0
- package/dist/index.js.map +1 -0
- package/dist/ssr/index.cjs +459 -0
- package/dist/ssr/index.cjs.map +1 -0
- package/dist/ssr/index.d.cts +12 -0
- package/dist/ssr/index.d.ts +12 -0
- package/dist/ssr/index.js +456 -0
- package/dist/ssr/index.js.map +1 -0
- package/package.json +24 -6
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
|
|
6
|
+
// src/components/ImageMagnify.tsx
|
|
7
|
+
var clamp = (v, min, max) => Math.max(min, Math.min(max, v));
|
|
8
|
+
function useImageMagnify(options = {}) {
|
|
9
|
+
const {
|
|
10
|
+
src,
|
|
11
|
+
zoomSrc,
|
|
12
|
+
zoomScale = 2,
|
|
13
|
+
zoomType = "hover",
|
|
14
|
+
lensSize = 150,
|
|
15
|
+
zoomPreload = true,
|
|
16
|
+
onZoomStart,
|
|
17
|
+
onZoomEnd
|
|
18
|
+
} = options;
|
|
19
|
+
const [isZoomed, setIsZoomed] = react.useState(false);
|
|
20
|
+
const isZoomedRef = react.useRef(false);
|
|
21
|
+
const containerRef = react.useRef(null);
|
|
22
|
+
const imageRef = react.useRef(null);
|
|
23
|
+
const lensRef = react.useRef(null);
|
|
24
|
+
const paneRef = react.useRef(null);
|
|
25
|
+
const cursorRef = react.useRef(null);
|
|
26
|
+
const pointerRef = react.useRef({ x: 0, y: 0 });
|
|
27
|
+
const rafRef = react.useRef(0);
|
|
28
|
+
const lastTouchRef = react.useRef(0);
|
|
29
|
+
const bgImage = zoomSrc || src;
|
|
30
|
+
const isRecentTouch = () => Date.now() - lastTouchRef.current < 700;
|
|
31
|
+
const setZoomed = react.useCallback(
|
|
32
|
+
(z) => {
|
|
33
|
+
if (isZoomedRef.current === z) return;
|
|
34
|
+
isZoomedRef.current = z;
|
|
35
|
+
setIsZoomed(z);
|
|
36
|
+
if (z) onZoomStart?.();
|
|
37
|
+
else onZoomEnd?.();
|
|
38
|
+
},
|
|
39
|
+
[onZoomStart, onZoomEnd]
|
|
40
|
+
);
|
|
41
|
+
const apply = react.useCallback(() => {
|
|
42
|
+
const container = containerRef.current;
|
|
43
|
+
if (!container) return;
|
|
44
|
+
const rect = container.getBoundingClientRect();
|
|
45
|
+
if (!rect.width || !rect.height) return;
|
|
46
|
+
const { x, y } = pointerRef.current;
|
|
47
|
+
const xPct = clamp(x / rect.width, 0, 1);
|
|
48
|
+
const yPct = clamp(y / rect.height, 0, 1);
|
|
49
|
+
const lens = lensRef.current;
|
|
50
|
+
if (lens) {
|
|
51
|
+
const maxX = Math.max(0, rect.width - lensSize);
|
|
52
|
+
const maxY = Math.max(0, rect.height - lensSize);
|
|
53
|
+
const lx = clamp(x - lensSize / 2, 0, maxX);
|
|
54
|
+
const ly = clamp(y - lensSize / 2, 0, maxY);
|
|
55
|
+
const cx = lx + lensSize / 2;
|
|
56
|
+
const cy = ly + lensSize / 2;
|
|
57
|
+
lens.style.transform = `translate3d(${lx}px, ${ly}px, 0)`;
|
|
58
|
+
lens.style.backgroundPosition = `${lensSize / 2 - cx * zoomScale}px ${lensSize / 2 - cy * zoomScale}px`;
|
|
59
|
+
}
|
|
60
|
+
const pane = paneRef.current;
|
|
61
|
+
if (pane) {
|
|
62
|
+
const pw = pane.offsetWidth;
|
|
63
|
+
const ph = pane.offsetHeight;
|
|
64
|
+
const bgW = rect.width * zoomScale;
|
|
65
|
+
const bgH = rect.height * zoomScale;
|
|
66
|
+
let bgX = pw / 2 - xPct * bgW;
|
|
67
|
+
let bgY = ph / 2 - yPct * bgH;
|
|
68
|
+
if (bgW > pw) bgX = clamp(bgX, pw - bgW, 0);
|
|
69
|
+
else bgX = (pw - bgW) / 2;
|
|
70
|
+
if (bgH > ph) bgY = clamp(bgY, ph - bgH, 0);
|
|
71
|
+
else bgY = (ph - bgH) / 2;
|
|
72
|
+
pane.style.backgroundPosition = `${bgX}px ${bgY}px`;
|
|
73
|
+
}
|
|
74
|
+
const cursor = cursorRef.current;
|
|
75
|
+
if (cursor) {
|
|
76
|
+
cursor.style.transform = `translate3d(${x}px, ${y}px, 0)`;
|
|
77
|
+
}
|
|
78
|
+
}, [zoomScale, lensSize]);
|
|
79
|
+
const schedule = react.useCallback(() => {
|
|
80
|
+
if (rafRef.current) return;
|
|
81
|
+
rafRef.current = requestAnimationFrame(() => {
|
|
82
|
+
rafRef.current = 0;
|
|
83
|
+
apply();
|
|
84
|
+
});
|
|
85
|
+
}, [apply]);
|
|
86
|
+
react.useEffect(() => {
|
|
87
|
+
if (isZoomed) schedule();
|
|
88
|
+
}, [isZoomed, schedule]);
|
|
89
|
+
react.useEffect(() => {
|
|
90
|
+
if (!bgImage) return;
|
|
91
|
+
const url = `url("${bgImage}")`;
|
|
92
|
+
if (lensRef.current) lensRef.current.style.backgroundImage = url;
|
|
93
|
+
if (paneRef.current) paneRef.current.style.backgroundImage = url;
|
|
94
|
+
}, [bgImage, isZoomed]);
|
|
95
|
+
react.useEffect(() => {
|
|
96
|
+
const container = containerRef.current;
|
|
97
|
+
if (!container) return;
|
|
98
|
+
const update = () => {
|
|
99
|
+
const rect = container.getBoundingClientRect();
|
|
100
|
+
if (!rect.width || !rect.height) return;
|
|
101
|
+
const size = `${rect.width * zoomScale}px ${rect.height * zoomScale}px`;
|
|
102
|
+
if (lensRef.current) lensRef.current.style.backgroundSize = size;
|
|
103
|
+
if (paneRef.current) paneRef.current.style.backgroundSize = size;
|
|
104
|
+
};
|
|
105
|
+
update();
|
|
106
|
+
const ro = new ResizeObserver(update);
|
|
107
|
+
ro.observe(container);
|
|
108
|
+
return () => ro.disconnect();
|
|
109
|
+
}, [zoomScale, isZoomed]);
|
|
110
|
+
react.useEffect(() => {
|
|
111
|
+
if (!zoomPreload || !bgImage) return;
|
|
112
|
+
const img = new Image();
|
|
113
|
+
img.src = bgImage;
|
|
114
|
+
}, [zoomPreload, bgImage]);
|
|
115
|
+
react.useEffect(
|
|
116
|
+
() => () => {
|
|
117
|
+
if (rafRef.current) cancelAnimationFrame(rafRef.current);
|
|
118
|
+
},
|
|
119
|
+
[]
|
|
120
|
+
);
|
|
121
|
+
const updatePointer = (clientX, clientY) => {
|
|
122
|
+
const container = containerRef.current;
|
|
123
|
+
if (!container) return;
|
|
124
|
+
const rect = container.getBoundingClientRect();
|
|
125
|
+
if (!rect.width || !rect.height) return;
|
|
126
|
+
pointerRef.current = {
|
|
127
|
+
x: clamp(clientX - rect.left, 0, rect.width),
|
|
128
|
+
y: clamp(clientY - rect.top, 0, rect.height)
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
const handlers = {
|
|
132
|
+
onMouseEnter: (e) => {
|
|
133
|
+
if (isRecentTouch()) return;
|
|
134
|
+
updatePointer(e.clientX, e.clientY);
|
|
135
|
+
if (zoomType === "hover") setZoomed(true);
|
|
136
|
+
schedule();
|
|
137
|
+
},
|
|
138
|
+
onMouseMove: (e) => {
|
|
139
|
+
if (isRecentTouch()) return;
|
|
140
|
+
updatePointer(e.clientX, e.clientY);
|
|
141
|
+
if (isZoomedRef.current) schedule();
|
|
142
|
+
},
|
|
143
|
+
onMouseLeave: () => {
|
|
144
|
+
if (isRecentTouch()) return;
|
|
145
|
+
if (zoomType === "hover") setZoomed(false);
|
|
146
|
+
},
|
|
147
|
+
onClick: (e) => {
|
|
148
|
+
if (isRecentTouch()) return;
|
|
149
|
+
if (zoomType !== "click") return;
|
|
150
|
+
updatePointer(e.clientX, e.clientY);
|
|
151
|
+
setZoomed(!isZoomedRef.current);
|
|
152
|
+
schedule();
|
|
153
|
+
},
|
|
154
|
+
onDoubleClick: (e) => {
|
|
155
|
+
if (isRecentTouch()) return;
|
|
156
|
+
if (zoomType !== "double-click") return;
|
|
157
|
+
updatePointer(e.clientX, e.clientY);
|
|
158
|
+
setZoomed(!isZoomedRef.current);
|
|
159
|
+
schedule();
|
|
160
|
+
},
|
|
161
|
+
onTouchStart: (e) => {
|
|
162
|
+
lastTouchRef.current = Date.now();
|
|
163
|
+
const t = e.touches[0];
|
|
164
|
+
if (!t) return;
|
|
165
|
+
updatePointer(t.clientX, t.clientY);
|
|
166
|
+
if (zoomType === "hover") setZoomed(true);
|
|
167
|
+
else setZoomed(!isZoomedRef.current);
|
|
168
|
+
schedule();
|
|
169
|
+
},
|
|
170
|
+
onTouchMove: (e) => {
|
|
171
|
+
lastTouchRef.current = Date.now();
|
|
172
|
+
const t = e.touches[0];
|
|
173
|
+
if (!t) return;
|
|
174
|
+
updatePointer(t.clientX, t.clientY);
|
|
175
|
+
schedule();
|
|
176
|
+
},
|
|
177
|
+
onTouchEnd: () => {
|
|
178
|
+
lastTouchRef.current = Date.now();
|
|
179
|
+
if (zoomType === "hover") setZoomed(false);
|
|
180
|
+
},
|
|
181
|
+
onKeyDown: (e) => {
|
|
182
|
+
const container = containerRef.current;
|
|
183
|
+
if (!container) return;
|
|
184
|
+
const rect = container.getBoundingClientRect();
|
|
185
|
+
const step = 20;
|
|
186
|
+
const { x, y } = pointerRef.current;
|
|
187
|
+
let handled = true;
|
|
188
|
+
switch (e.key) {
|
|
189
|
+
case "ArrowLeft":
|
|
190
|
+
pointerRef.current.x = clamp(x - step, 0, rect.width);
|
|
191
|
+
break;
|
|
192
|
+
case "ArrowRight":
|
|
193
|
+
pointerRef.current.x = clamp(x + step, 0, rect.width);
|
|
194
|
+
break;
|
|
195
|
+
case "ArrowUp":
|
|
196
|
+
pointerRef.current.y = clamp(y - step, 0, rect.height);
|
|
197
|
+
break;
|
|
198
|
+
case "ArrowDown":
|
|
199
|
+
pointerRef.current.y = clamp(y + step, 0, rect.height);
|
|
200
|
+
break;
|
|
201
|
+
case "Enter":
|
|
202
|
+
case " ":
|
|
203
|
+
setZoomed(!isZoomedRef.current);
|
|
204
|
+
break;
|
|
205
|
+
case "Escape":
|
|
206
|
+
setZoomed(false);
|
|
207
|
+
break;
|
|
208
|
+
default:
|
|
209
|
+
handled = false;
|
|
210
|
+
}
|
|
211
|
+
if (handled) {
|
|
212
|
+
e.preventDefault();
|
|
213
|
+
schedule();
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
onFocus: () => {
|
|
217
|
+
if (isRecentTouch()) return;
|
|
218
|
+
if (zoomType === "hover") setZoomed(true);
|
|
219
|
+
},
|
|
220
|
+
onBlur: () => {
|
|
221
|
+
if (zoomType === "hover") setZoomed(false);
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
return {
|
|
225
|
+
isZoomed,
|
|
226
|
+
containerRef,
|
|
227
|
+
imageRef,
|
|
228
|
+
lensRef,
|
|
229
|
+
paneRef,
|
|
230
|
+
cursorRef,
|
|
231
|
+
handlers
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
var ImageMagnify = react.forwardRef(
|
|
235
|
+
(props, ref) => {
|
|
236
|
+
const {
|
|
237
|
+
src,
|
|
238
|
+
alt,
|
|
239
|
+
width,
|
|
240
|
+
mode = "side-by-side",
|
|
241
|
+
className,
|
|
242
|
+
style,
|
|
243
|
+
imageClassName,
|
|
244
|
+
imageStyle,
|
|
245
|
+
lensClassName,
|
|
246
|
+
lensStyle,
|
|
247
|
+
paneClassName,
|
|
248
|
+
paneStyle,
|
|
249
|
+
paneWidth = 400,
|
|
250
|
+
paneHeight = 400,
|
|
251
|
+
lazy,
|
|
252
|
+
panePosition = "right",
|
|
253
|
+
lensSize = 150,
|
|
254
|
+
lensShape = "circle",
|
|
255
|
+
zoomType = "hover",
|
|
256
|
+
...hookOptions
|
|
257
|
+
} = props;
|
|
258
|
+
const {
|
|
259
|
+
isZoomed,
|
|
260
|
+
containerRef,
|
|
261
|
+
imageRef,
|
|
262
|
+
lensRef,
|
|
263
|
+
paneRef,
|
|
264
|
+
cursorRef,
|
|
265
|
+
handlers
|
|
266
|
+
} = useImageMagnify({ src, zoomType, lensSize, ...hookOptions });
|
|
267
|
+
const bgImage = props.zoomSrc || src;
|
|
268
|
+
const paneOffset = {};
|
|
269
|
+
if (panePosition === "right") {
|
|
270
|
+
paneOffset.left = "calc(100% + 12px)";
|
|
271
|
+
paneOffset.top = 0;
|
|
272
|
+
} else if (panePosition === "left") {
|
|
273
|
+
paneOffset.right = "calc(100% + 12px)";
|
|
274
|
+
paneOffset.top = 0;
|
|
275
|
+
} else if (panePosition === "top") {
|
|
276
|
+
paneOffset.left = 0;
|
|
277
|
+
paneOffset.bottom = "calc(100% + 12px)";
|
|
278
|
+
} else {
|
|
279
|
+
paneOffset.left = 0;
|
|
280
|
+
paneOffset.top = "calc(100% + 12px)";
|
|
281
|
+
}
|
|
282
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
283
|
+
"div",
|
|
284
|
+
{
|
|
285
|
+
ref,
|
|
286
|
+
className,
|
|
287
|
+
style: {
|
|
288
|
+
position: "relative",
|
|
289
|
+
display: "inline-block",
|
|
290
|
+
lineHeight: 0,
|
|
291
|
+
width,
|
|
292
|
+
...style
|
|
293
|
+
},
|
|
294
|
+
children: [
|
|
295
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
296
|
+
"div",
|
|
297
|
+
{
|
|
298
|
+
ref: containerRef,
|
|
299
|
+
tabIndex: 0,
|
|
300
|
+
role: "img",
|
|
301
|
+
"aria-label": alt,
|
|
302
|
+
style: {
|
|
303
|
+
position: "relative",
|
|
304
|
+
overflow: "hidden",
|
|
305
|
+
width: "100%",
|
|
306
|
+
cursor: zoomType === "hover" ? "crosshair" : isZoomed ? "zoom-out" : "zoom-in",
|
|
307
|
+
touchAction: "none",
|
|
308
|
+
outline: "none",
|
|
309
|
+
lineHeight: 0
|
|
310
|
+
},
|
|
311
|
+
...handlers,
|
|
312
|
+
children: [
|
|
313
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
314
|
+
"img",
|
|
315
|
+
{
|
|
316
|
+
ref: imageRef,
|
|
317
|
+
src,
|
|
318
|
+
alt,
|
|
319
|
+
loading: lazy ? "lazy" : void 0,
|
|
320
|
+
draggable: false,
|
|
321
|
+
className: imageClassName,
|
|
322
|
+
style: {
|
|
323
|
+
display: "block",
|
|
324
|
+
width: "100%",
|
|
325
|
+
height: "auto",
|
|
326
|
+
userSelect: "none",
|
|
327
|
+
pointerEvents: "none",
|
|
328
|
+
...imageStyle
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
),
|
|
332
|
+
mode === "lens" && isZoomed && /* @__PURE__ */ jsxRuntime.jsx(
|
|
333
|
+
"div",
|
|
334
|
+
{
|
|
335
|
+
ref: lensRef,
|
|
336
|
+
className: lensClassName,
|
|
337
|
+
style: {
|
|
338
|
+
position: "absolute",
|
|
339
|
+
top: 0,
|
|
340
|
+
left: 0,
|
|
341
|
+
width: lensSize,
|
|
342
|
+
height: lensSize,
|
|
343
|
+
borderRadius: lensShape === "circle" ? "50%" : 0,
|
|
344
|
+
backgroundImage: bgImage ? `url("${bgImage}")` : void 0,
|
|
345
|
+
backgroundRepeat: "no-repeat",
|
|
346
|
+
pointerEvents: "none",
|
|
347
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.25)",
|
|
348
|
+
border: "1px solid rgba(255,255,255,0.6)",
|
|
349
|
+
willChange: "transform",
|
|
350
|
+
...lensStyle
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
),
|
|
354
|
+
mode === "side-by-side" && isZoomed && /* @__PURE__ */ jsxRuntime.jsx(
|
|
355
|
+
"div",
|
|
356
|
+
{
|
|
357
|
+
ref: cursorRef,
|
|
358
|
+
style: {
|
|
359
|
+
position: "absolute",
|
|
360
|
+
top: 0,
|
|
361
|
+
left: 0,
|
|
362
|
+
width: 12,
|
|
363
|
+
height: 12,
|
|
364
|
+
marginLeft: -6,
|
|
365
|
+
marginTop: -6,
|
|
366
|
+
borderRadius: "50%",
|
|
367
|
+
background: "rgba(255,255,255,0.7)",
|
|
368
|
+
border: "1px solid rgba(0,0,0,0.5)",
|
|
369
|
+
pointerEvents: "none",
|
|
370
|
+
boxShadow: "0 0 0 1px rgba(255,255,255,0.8)",
|
|
371
|
+
willChange: "transform"
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
)
|
|
375
|
+
]
|
|
376
|
+
}
|
|
377
|
+
),
|
|
378
|
+
mode === "side-by-side" && isZoomed && /* @__PURE__ */ jsxRuntime.jsx(
|
|
379
|
+
"div",
|
|
380
|
+
{
|
|
381
|
+
ref: paneRef,
|
|
382
|
+
className: paneClassName,
|
|
383
|
+
"aria-hidden": "true",
|
|
384
|
+
style: {
|
|
385
|
+
position: "absolute",
|
|
386
|
+
width: paneWidth,
|
|
387
|
+
height: paneHeight,
|
|
388
|
+
backgroundImage: bgImage ? `url("${bgImage}")` : void 0,
|
|
389
|
+
backgroundRepeat: "no-repeat",
|
|
390
|
+
border: "1px solid #e5e5e5",
|
|
391
|
+
borderRadius: 4,
|
|
392
|
+
boxShadow: "0 8px 24px rgba(0,0,0,0.12)",
|
|
393
|
+
pointerEvents: "none",
|
|
394
|
+
...paneOffset,
|
|
395
|
+
...paneStyle
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
)
|
|
399
|
+
]
|
|
400
|
+
}
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
);
|
|
404
|
+
ImageMagnify.displayName = "ImageMagnify";
|
|
405
|
+
|
|
406
|
+
exports.ImageMagnify = ImageMagnify;
|
|
407
|
+
exports.useImageMagnify = useImageMagnify;
|
|
408
|
+
//# sourceMappingURL=index.cjs.map
|
|
409
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useImageMagnify.ts","../src/components/ImageMagnify.tsx"],"names":["useState","useRef","useCallback","useEffect","forwardRef","jsxs","jsx"],"mappings":";;;;;;AA4BA,IAAM,KAAA,GAAQ,CAAC,CAAA,EAAW,GAAA,EAAa,GAAA,KACrC,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,CAAC,CAAC,CAAA;AAEzB,SAAS,eAAA,CAAgB,OAAA,GAAkC,EAAC,EAAG;AACpE,EAAA,MAAM;AAAA,IACJ,GAAA;AAAA,IACA,OAAA;AAAA,IACA,SAAA,GAAY,CAAA;AAAA,IACZ,QAAA,GAAW,OAAA;AAAA,IACX,QAAA,GAAW,GAAA;AAAA,IACX,WAAA,GAAc,IAAA;AAAA,IACd,WAAA;AAAA,IACA;AAAA,GACF,GAAI,OAAA;AAEJ,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIA,eAAS,KAAK,CAAA;AAC9C,EAAA,MAAM,WAAA,GAAcC,aAAO,KAAK,CAAA;AAChC,EAAA,MAAM,YAAA,GAAeA,aAAuB,IAAI,CAAA;AAChD,EAAA,MAAM,QAAA,GAAWA,aAAyB,IAAI,CAAA;AAC9C,EAAA,MAAM,OAAA,GAAUA,aAAuB,IAAI,CAAA;AAC3C,EAAA,MAAM,OAAA,GAAUA,aAAuB,IAAI,CAAA;AAC3C,EAAA,MAAM,SAAA,GAAYA,aAAuB,IAAI,CAAA;AAC7C,EAAA,MAAM,aAAaA,YAAA,CAAO,EAAE,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA;AACxC,EAAA,MAAM,MAAA,GAASA,aAAO,CAAC,CAAA;AACvB,EAAA,MAAM,YAAA,GAAeA,aAAO,CAAC,CAAA;AAE7B,EAAA,MAAM,UAAU,OAAA,IAAW,GAAA;AAE3B,EAAA,MAAM,gBAAgB,MAAM,IAAA,CAAK,GAAA,EAAI,GAAI,aAAa,OAAA,GAAU,GAAA;AAEhE,EAAA,MAAM,SAAA,GAAYC,iBAAA;AAAA,IAChB,CAAC,CAAA,KAAe;AACd,MAAA,IAAI,WAAA,CAAY,YAAY,CAAA,EAAG;AAC/B,MAAA,WAAA,CAAY,OAAA,GAAU,CAAA;AACtB,MAAA,WAAA,CAAY,CAAC,CAAA;AACb,MAAA,IAAI,GAAG,WAAA,IAAc;AAAA,WAChB,SAAA,IAAY;AAAA,IACnB,CAAA;AAAA,IACA,CAAC,aAAa,SAAS;AAAA,GACzB;AAGA,EAAA,MAAM,KAAA,GAAQA,kBAAY,MAAM;AAC9B,IAAA,MAAM,YAAY,YAAA,CAAa,OAAA;AAC/B,IAAA,IAAI,CAAC,SAAA,EAAW;AAChB,IAAA,MAAM,IAAA,GAAO,UAAU,qBAAA,EAAsB;AAC7C,IAAA,IAAI,CAAC,IAAA,CAAK,KAAA,IAAS,CAAC,KAAK,MAAA,EAAQ;AAEjC,IAAA,MAAM,EAAE,CAAA,EAAG,CAAA,EAAE,GAAI,UAAA,CAAW,OAAA;AAC5B,IAAA,MAAM,OAAO,KAAA,CAAM,CAAA,GAAI,IAAA,CAAK,KAAA,EAAO,GAAG,CAAC,CAAA;AACvC,IAAA,MAAM,OAAO,KAAA,CAAM,CAAA,GAAI,IAAA,CAAK,MAAA,EAAQ,GAAG,CAAC,CAAA;AAExC,IAAA,MAAM,OAAO,OAAA,CAAQ,OAAA;AACrB,IAAA,IAAI,IAAA,EAAM;AAGR,MAAA,MAAM,OAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,QAAQ,QAAQ,CAAA;AAC9C,MAAA,MAAM,OAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,SAAS,QAAQ,CAAA;AAC/C,MAAA,MAAM,KAAK,KAAA,CAAM,CAAA,GAAI,QAAA,GAAW,CAAA,EAAG,GAAG,IAAI,CAAA;AAC1C,MAAA,MAAM,KAAK,KAAA,CAAM,CAAA,GAAI,QAAA,GAAW,CAAA,EAAG,GAAG,IAAI,CAAA;AAC1C,MAAA,MAAM,EAAA,GAAK,KAAK,QAAA,GAAW,CAAA;AAC3B,MAAA,MAAM,EAAA,GAAK,KAAK,QAAA,GAAW,CAAA;AAC3B,MAAA,IAAA,CAAK,KAAA,CAAM,SAAA,GAAY,CAAA,YAAA,EAAe,EAAE,OAAO,EAAE,CAAA,MAAA,CAAA;AACjD,MAAA,IAAA,CAAK,KAAA,CAAM,kBAAA,GAAqB,CAAA,EAC9B,QAAA,GAAW,CAAA,GAAI,EAAA,GAAK,SACtB,CAAA,GAAA,EAAM,QAAA,GAAW,CAAA,GAAI,EAAA,GAAK,SAAS,CAAA,EAAA,CAAA;AAAA,IACrC;AAEA,IAAA,MAAM,OAAO,OAAA,CAAQ,OAAA;AACrB,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,MAAM,KAAK,IAAA,CAAK,WAAA;AAChB,MAAA,MAAM,KAAK,IAAA,CAAK,YAAA;AAChB,MAAA,MAAM,GAAA,GAAM,KAAK,KAAA,GAAQ,SAAA;AACzB,MAAA,MAAM,GAAA,GAAM,KAAK,MAAA,GAAS,SAAA;AAC1B,MAAA,IAAI,GAAA,GAAM,EAAA,GAAK,CAAA,GAAI,IAAA,GAAO,GAAA;AAC1B,MAAA,IAAI,GAAA,GAAM,EAAA,GAAK,CAAA,GAAI,IAAA,GAAO,GAAA;AAC1B,MAAA,IAAI,MAAM,EAAA,EAAI,GAAA,GAAM,MAAM,GAAA,EAAK,EAAA,GAAK,KAAK,CAAC,CAAA;AAAA,WACrC,GAAA,GAAA,CAAO,KAAK,GAAA,IAAO,CAAA;AACxB,MAAA,IAAI,MAAM,EAAA,EAAI,GAAA,GAAM,MAAM,GAAA,EAAK,EAAA,GAAK,KAAK,CAAC,CAAA;AAAA,WACrC,GAAA,GAAA,CAAO,KAAK,GAAA,IAAO,CAAA;AACxB,MAAA,IAAA,CAAK,KAAA,CAAM,kBAAA,GAAqB,CAAA,EAAG,GAAG,MAAM,GAAG,CAAA,EAAA,CAAA;AAAA,IACjD;AAEA,IAAA,MAAM,SAAS,SAAA,CAAU,OAAA;AACzB,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,MAAA,CAAO,KAAA,CAAM,SAAA,GAAY,CAAA,YAAA,EAAe,CAAC,OAAO,CAAC,CAAA,MAAA,CAAA;AAAA,IACnD;AAAA,EACF,CAAA,EAAG,CAAC,SAAA,EAAW,QAAQ,CAAC,CAAA;AAGxB,EAAA,MAAM,QAAA,GAAWA,kBAAY,MAAM;AACjC,IAAA,IAAI,OAAO,OAAA,EAAS;AACpB,IAAA,MAAA,CAAO,OAAA,GAAU,sBAAsB,MAAM;AAC3C,MAAA,MAAA,CAAO,OAAA,GAAU,CAAA;AACjB,MAAA,KAAA,EAAM;AAAA,IACR,CAAC,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AAGV,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,UAAU,QAAA,EAAS;AAAA,EACzB,CAAA,EAAG,CAAC,QAAA,EAAU,QAAQ,CAAC,CAAA;AAGvB,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,EAAS;AACd,IAAA,MAAM,GAAA,GAAM,QAAQ,OAAO,CAAA,EAAA,CAAA;AAC3B,IAAA,IAAI,OAAA,CAAQ,OAAA,EAAS,OAAA,CAAQ,OAAA,CAAQ,MAAM,eAAA,GAAkB,GAAA;AAC7D,IAAA,IAAI,OAAA,CAAQ,OAAA,EAAS,OAAA,CAAQ,OAAA,CAAQ,MAAM,eAAA,GAAkB,GAAA;AAAA,EAC/D,CAAA,EAAG,CAAC,OAAA,EAAS,QAAQ,CAAC,CAAA;AAGtB,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,MAAM,YAAY,YAAA,CAAa,OAAA;AAC/B,IAAA,IAAI,CAAC,SAAA,EAAW;AAChB,IAAA,MAAM,SAAS,MAAM;AACnB,MAAA,MAAM,IAAA,GAAO,UAAU,qBAAA,EAAsB;AAC7C,MAAA,IAAI,CAAC,IAAA,CAAK,KAAA,IAAS,CAAC,KAAK,MAAA,EAAQ;AACjC,MAAA,MAAM,IAAA,GAAO,GAAG,IAAA,CAAK,KAAA,GAAQ,SAAS,CAAA,GAAA,EAAM,IAAA,CAAK,SAAS,SAAS,CAAA,EAAA,CAAA;AACnE,MAAA,IAAI,OAAA,CAAQ,OAAA,EAAS,OAAA,CAAQ,OAAA,CAAQ,MAAM,cAAA,GAAiB,IAAA;AAC5D,MAAA,IAAI,OAAA,CAAQ,OAAA,EAAS,OAAA,CAAQ,OAAA,CAAQ,MAAM,cAAA,GAAiB,IAAA;AAAA,IAC9D,CAAA;AACA,IAAA,MAAA,EAAO;AACP,IAAA,MAAM,EAAA,GAAK,IAAI,cAAA,CAAe,MAAM,CAAA;AACpC,IAAA,EAAA,CAAG,QAAQ,SAAS,CAAA;AACpB,IAAA,OAAO,MAAM,GAAG,UAAA,EAAW;AAAA,EAC7B,CAAA,EAAG,CAAC,SAAA,EAAW,QAAQ,CAAC,CAAA;AAGxB,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,WAAA,IAAe,CAAC,OAAA,EAAS;AAC9B,IAAA,MAAM,GAAA,GAAM,IAAI,KAAA,EAAM;AACtB,IAAA,GAAA,CAAI,GAAA,GAAM,OAAA;AAAA,EACZ,CAAA,EAAG,CAAC,WAAA,EAAa,OAAO,CAAC,CAAA;AAGzB,EAAAA,eAAA;AAAA,IACE,MAAM,MAAM;AACV,MAAA,IAAI,MAAA,CAAO,OAAA,EAAS,oBAAA,CAAqB,MAAA,CAAO,OAAO,CAAA;AAAA,IACzD,CAAA;AAAA,IACA;AAAC,GACH;AAEA,EAAA,MAAM,aAAA,GAAgB,CAAC,OAAA,EAAiB,OAAA,KAAoB;AAC1D,IAAA,MAAM,YAAY,YAAA,CAAa,OAAA;AAC/B,IAAA,IAAI,CAAC,SAAA,EAAW;AAChB,IAAA,MAAM,IAAA,GAAO,UAAU,qBAAA,EAAsB;AAC7C,IAAA,IAAI,CAAC,IAAA,CAAK,KAAA,IAAS,CAAC,KAAK,MAAA,EAAQ;AACjC,IAAA,UAAA,CAAW,OAAA,GAAU;AAAA,MACnB,GAAG,KAAA,CAAM,OAAA,GAAU,KAAK,IAAA,EAAM,CAAA,EAAG,KAAK,KAAK,CAAA;AAAA,MAC3C,GAAG,KAAA,CAAM,OAAA,GAAU,KAAK,GAAA,EAAK,CAAA,EAAG,KAAK,MAAM;AAAA,KAC7C;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,QAAA,GAAW;AAAA,IACf,YAAA,EAAc,CAAC,CAAA,KAAwB;AACrC,MAAA,IAAI,eAAc,EAAG;AACrB,MAAA,aAAA,CAAc,CAAA,CAAE,OAAA,EAAS,CAAA,CAAE,OAAO,CAAA;AAClC,MAAA,IAAI,QAAA,KAAa,OAAA,EAAS,SAAA,CAAU,IAAI,CAAA;AACxC,MAAA,QAAA,EAAS;AAAA,IACX,CAAA;AAAA,IACA,WAAA,EAAa,CAAC,CAAA,KAAwB;AACpC,MAAA,IAAI,eAAc,EAAG;AACrB,MAAA,aAAA,CAAc,CAAA,CAAE,OAAA,EAAS,CAAA,CAAE,OAAO,CAAA;AAClC,MAAA,IAAI,WAAA,CAAY,SAAS,QAAA,EAAS;AAAA,IACpC,CAAA;AAAA,IACA,cAAc,MAAM;AAClB,MAAA,IAAI,eAAc,EAAG;AACrB,MAAA,IAAI,QAAA,KAAa,OAAA,EAAS,SAAA,CAAU,KAAK,CAAA;AAAA,IAC3C,CAAA;AAAA,IACA,OAAA,EAAS,CAAC,CAAA,KAAwB;AAChC,MAAA,IAAI,eAAc,EAAG;AACrB,MAAA,IAAI,aAAa,OAAA,EAAS;AAC1B,MAAA,aAAA,CAAc,CAAA,CAAE,OAAA,EAAS,CAAA,CAAE,OAAO,CAAA;AAClC,MAAA,SAAA,CAAU,CAAC,YAAY,OAAO,CAAA;AAC9B,MAAA,QAAA,EAAS;AAAA,IACX,CAAA;AAAA,IACA,aAAA,EAAe,CAAC,CAAA,KAAwB;AACtC,MAAA,IAAI,eAAc,EAAG;AACrB,MAAA,IAAI,aAAa,cAAA,EAAgB;AACjC,MAAA,aAAA,CAAc,CAAA,CAAE,OAAA,EAAS,CAAA,CAAE,OAAO,CAAA;AAClC,MAAA,SAAA,CAAU,CAAC,YAAY,OAAO,CAAA;AAC9B,MAAA,QAAA,EAAS;AAAA,IACX,CAAA;AAAA,IACA,YAAA,EAAc,CAAC,CAAA,KAAwB;AACrC,MAAA,YAAA,CAAa,OAAA,GAAU,KAAK,GAAA,EAAI;AAChC,MAAA,MAAM,CAAA,GAAI,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAA;AACrB,MAAA,IAAI,CAAC,CAAA,EAAG;AACR,MAAA,aAAA,CAAc,CAAA,CAAE,OAAA,EAAS,CAAA,CAAE,OAAO,CAAA;AAClC,MAAA,IAAI,QAAA,KAAa,OAAA,EAAS,SAAA,CAAU,IAAI,CAAA;AAAA,WACnC,SAAA,CAAU,CAAC,WAAA,CAAY,OAAO,CAAA;AACnC,MAAA,QAAA,EAAS;AAAA,IACX,CAAA;AAAA,IACA,WAAA,EAAa,CAAC,CAAA,KAAwB;AACpC,MAAA,YAAA,CAAa,OAAA,GAAU,KAAK,GAAA,EAAI;AAChC,MAAA,MAAM,CAAA,GAAI,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAA;AACrB,MAAA,IAAI,CAAC,CAAA,EAAG;AACR,MAAA,aAAA,CAAc,CAAA,CAAE,OAAA,EAAS,CAAA,CAAE,OAAO,CAAA;AAClC,MAAA,QAAA,EAAS;AAAA,IACX,CAAA;AAAA,IACA,YAAY,MAAM;AAChB,MAAA,YAAA,CAAa,OAAA,GAAU,KAAK,GAAA,EAAI;AAChC,MAAA,IAAI,QAAA,KAAa,OAAA,EAAS,SAAA,CAAU,KAAK,CAAA;AAAA,IAC3C,CAAA;AAAA,IACA,SAAA,EAAW,CAAC,CAAA,KAA2B;AACrC,MAAA,MAAM,YAAY,YAAA,CAAa,OAAA;AAC/B,MAAA,IAAI,CAAC,SAAA,EAAW;AAChB,MAAA,MAAM,IAAA,GAAO,UAAU,qBAAA,EAAsB;AAC7C,MAAA,MAAM,IAAA,GAAO,EAAA;AACb,MAAA,MAAM,EAAE,CAAA,EAAG,CAAA,EAAE,GAAI,UAAA,CAAW,OAAA;AAC5B,MAAA,IAAI,OAAA,GAAU,IAAA;AAEd,MAAA,QAAQ,EAAE,GAAA;AAAK,QACb,KAAK,WAAA;AACH,UAAA,UAAA,CAAW,QAAQ,CAAA,GAAI,KAAA,CAAM,IAAI,IAAA,EAAM,CAAA,EAAG,KAAK,KAAK,CAAA;AACpD,UAAA;AAAA,QACF,KAAK,YAAA;AACH,UAAA,UAAA,CAAW,QAAQ,CAAA,GAAI,KAAA,CAAM,IAAI,IAAA,EAAM,CAAA,EAAG,KAAK,KAAK,CAAA;AACpD,UAAA;AAAA,QACF,KAAK,SAAA;AACH,UAAA,UAAA,CAAW,QAAQ,CAAA,GAAI,KAAA,CAAM,IAAI,IAAA,EAAM,CAAA,EAAG,KAAK,MAAM,CAAA;AACrD,UAAA;AAAA,QACF,KAAK,WAAA;AACH,UAAA,UAAA,CAAW,QAAQ,CAAA,GAAI,KAAA,CAAM,IAAI,IAAA,EAAM,CAAA,EAAG,KAAK,MAAM,CAAA;AACrD,UAAA;AAAA,QACF,KAAK,OAAA;AAAA,QACL,KAAK,GAAA;AACH,UAAA,SAAA,CAAU,CAAC,YAAY,OAAO,CAAA;AAC9B,UAAA;AAAA,QACF,KAAK,QAAA;AACH,UAAA,SAAA,CAAU,KAAK,CAAA;AACf,UAAA;AAAA,QACF;AACE,UAAA,OAAA,GAAU,KAAA;AAAA;AAEd,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,CAAA,CAAE,cAAA,EAAe;AACjB,QAAA,QAAA,EAAS;AAAA,MACX;AAAA,IACF,CAAA;AAAA,IACA,SAAS,MAAM;AACb,MAAA,IAAI,eAAc,EAAG;AACrB,MAAA,IAAI,QAAA,KAAa,OAAA,EAAS,SAAA,CAAU,IAAI,CAAA;AAAA,IAC1C,CAAA;AAAA,IACA,QAAQ,MAAM;AACZ,MAAA,IAAI,QAAA,KAAa,OAAA,EAAS,SAAA,CAAU,KAAK,CAAA;AAAA,IAC3C;AAAA,GACF;AAEA,EAAA,OAAO;AAAA,IACL,QAAA;AAAA,IACA,YAAA;AAAA,IACA,QAAA;AAAA,IACA,OAAA;AAAA,IACA,OAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,GACF;AACF;ACtQO,IAAM,YAAA,GAAeC,gBAAA;AAAA,EAC1B,CAAC,OAAO,GAAA,KAAQ;AACd,IAAA,MAAM;AAAA,MACJ,GAAA;AAAA,MACA,GAAA;AAAA,MACA,KAAA;AAAA,MACA,IAAA,GAAO,cAAA;AAAA,MACP,SAAA;AAAA,MACA,KAAA;AAAA,MACA,cAAA;AAAA,MACA,UAAA;AAAA,MACA,aAAA;AAAA,MACA,SAAA;AAAA,MACA,aAAA;AAAA,MACA,SAAA;AAAA,MACA,SAAA,GAAY,GAAA;AAAA,MACZ,UAAA,GAAa,GAAA;AAAA,MACb,IAAA;AAAA,MACA,YAAA,GAAe,OAAA;AAAA,MACf,QAAA,GAAW,GAAA;AAAA,MACX,SAAA,GAAY,QAAA;AAAA,MACZ,QAAA,GAAW,OAAA;AAAA,MACX,GAAG;AAAA,KACL,GAAI,KAAA;AAEJ,IAAA,MAAM;AAAA,MACJ,QAAA;AAAA,MACA,YAAA;AAAA,MACA,QAAA;AAAA,MACA,OAAA;AAAA,MACA,OAAA;AAAA,MACA,SAAA;AAAA,MACA;AAAA,KACF,GAAI,gBAAgB,EAAE,GAAA,EAAK,UAAU,QAAA,EAAU,GAAG,aAAa,CAAA;AAE/D,IAAA,MAAM,OAAA,GAAU,MAAM,OAAA,IAAW,GAAA;AAEjC,IAAA,MAAM,aAA4B,EAAC;AACnC,IAAA,IAAI,iBAAiB,OAAA,EAAS;AAC5B,MAAA,UAAA,CAAW,IAAA,GAAO,mBAAA;AAClB,MAAA,UAAA,CAAW,GAAA,GAAM,CAAA;AAAA,IACnB,CAAA,MAAA,IAAW,iBAAiB,MAAA,EAAQ;AAClC,MAAA,UAAA,CAAW,KAAA,GAAQ,mBAAA;AACnB,MAAA,UAAA,CAAW,GAAA,GAAM,CAAA;AAAA,IACnB,CAAA,MAAA,IAAW,iBAAiB,KAAA,EAAO;AACjC,MAAA,UAAA,CAAW,IAAA,GAAO,CAAA;AAClB,MAAA,UAAA,CAAW,MAAA,GAAS,mBAAA;AAAA,IACtB,CAAA,MAAO;AACL,MAAA,UAAA,CAAW,IAAA,GAAO,CAAA;AAClB,MAAA,UAAA,CAAW,GAAA,GAAM,mBAAA;AAAA,IACnB;AAEA,IAAA,uBACEC,eAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,SAAA;AAAA,QACA,KAAA,EAAO;AAAA,UACL,QAAA,EAAU,UAAA;AAAA,UACV,OAAA,EAAS,cAAA;AAAA,UACT,UAAA,EAAY,CAAA;AAAA,UACZ,KAAA;AAAA,UACA,GAAG;AAAA,SACL;AAAA,QAEA,QAAA,EAAA;AAAA,0BAAAA,eAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,GAAA,EAAK,YAAA;AAAA,cACL,QAAA,EAAU,CAAA;AAAA,cACV,IAAA,EAAK,KAAA;AAAA,cACL,YAAA,EAAY,GAAA;AAAA,cACZ,KAAA,EAAO;AAAA,gBACL,QAAA,EAAU,UAAA;AAAA,gBACV,QAAA,EAAU,QAAA;AAAA,gBACV,KAAA,EAAO,MAAA;AAAA,gBACP,MAAA,EACE,QAAA,KAAa,OAAA,GACT,WAAA,GACA,WACE,UAAA,GACA,SAAA;AAAA,gBACR,WAAA,EAAa,MAAA;AAAA,gBACb,OAAA,EAAS,MAAA;AAAA,gBACT,UAAA,EAAY;AAAA,eACd;AAAA,cACC,GAAG,QAAA;AAAA,cAEJ,QAAA,EAAA;AAAA,gCAAAC,cAAA;AAAA,kBAAC,KAAA;AAAA,kBAAA;AAAA,oBACC,GAAA,EAAK,QAAA;AAAA,oBACL,GAAA;AAAA,oBACA,GAAA;AAAA,oBACA,OAAA,EAAS,OAAO,MAAA,GAAS,MAAA;AAAA,oBACzB,SAAA,EAAW,KAAA;AAAA,oBACX,SAAA,EAAW,cAAA;AAAA,oBACX,KAAA,EAAO;AAAA,sBACL,OAAA,EAAS,OAAA;AAAA,sBACT,KAAA,EAAO,MAAA;AAAA,sBACP,MAAA,EAAQ,MAAA;AAAA,sBACR,UAAA,EAAY,MAAA;AAAA,sBACZ,aAAA,EAAe,MAAA;AAAA,sBACf,GAAG;AAAA;AACL;AAAA,iBACF;AAAA,gBAEC,IAAA,KAAS,UAAU,QAAA,oBAClBA,cAAA;AAAA,kBAAC,KAAA;AAAA,kBAAA;AAAA,oBACC,GAAA,EAAK,OAAA;AAAA,oBACL,SAAA,EAAW,aAAA;AAAA,oBACX,KAAA,EAAO;AAAA,sBACL,QAAA,EAAU,UAAA;AAAA,sBACV,GAAA,EAAK,CAAA;AAAA,sBACL,IAAA,EAAM,CAAA;AAAA,sBACN,KAAA,EAAO,QAAA;AAAA,sBACP,MAAA,EAAQ,QAAA;AAAA,sBACR,YAAA,EAAc,SAAA,KAAc,QAAA,GAAW,KAAA,GAAQ,CAAA;AAAA,sBAC/C,eAAA,EAAiB,OAAA,GAAU,CAAA,KAAA,EAAQ,OAAO,CAAA,EAAA,CAAA,GAAO,MAAA;AAAA,sBACjD,gBAAA,EAAkB,WAAA;AAAA,sBAClB,aAAA,EAAe,MAAA;AAAA,sBACf,SAAA,EAAW,6BAAA;AAAA,sBACX,MAAA,EAAQ,iCAAA;AAAA,sBACR,UAAA,EAAY,WAAA;AAAA,sBACZ,GAAG;AAAA;AACL;AAAA,iBACF;AAAA,gBAGD,IAAA,KAAS,kBAAkB,QAAA,oBAC1BA,cAAA;AAAA,kBAAC,KAAA;AAAA,kBAAA;AAAA,oBACC,GAAA,EAAK,SAAA;AAAA,oBACL,KAAA,EAAO;AAAA,sBACL,QAAA,EAAU,UAAA;AAAA,sBACV,GAAA,EAAK,CAAA;AAAA,sBACL,IAAA,EAAM,CAAA;AAAA,sBACN,KAAA,EAAO,EAAA;AAAA,sBACP,MAAA,EAAQ,EAAA;AAAA,sBACR,UAAA,EAAY,EAAA;AAAA,sBACZ,SAAA,EAAW,EAAA;AAAA,sBACX,YAAA,EAAc,KAAA;AAAA,sBACd,UAAA,EAAY,uBAAA;AAAA,sBACZ,MAAA,EAAQ,2BAAA;AAAA,sBACR,aAAA,EAAe,MAAA;AAAA,sBACf,SAAA,EAAW,iCAAA;AAAA,sBACX,UAAA,EAAY;AAAA;AACd;AAAA;AACF;AAAA;AAAA,WAEJ;AAAA,UAEC,IAAA,KAAS,kBAAkB,QAAA,oBAC1BA,cAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,GAAA,EAAK,OAAA;AAAA,cACL,SAAA,EAAW,aAAA;AAAA,cACX,aAAA,EAAY,MAAA;AAAA,cACZ,KAAA,EAAO;AAAA,gBACL,QAAA,EAAU,UAAA;AAAA,gBACV,KAAA,EAAO,SAAA;AAAA,gBACP,MAAA,EAAQ,UAAA;AAAA,gBACR,eAAA,EAAiB,OAAA,GAAU,CAAA,KAAA,EAAQ,OAAO,CAAA,EAAA,CAAA,GAAO,MAAA;AAAA,gBACjD,gBAAA,EAAkB,WAAA;AAAA,gBAClB,MAAA,EAAQ,mBAAA;AAAA,gBACR,YAAA,EAAc,CAAA;AAAA,gBACd,SAAA,EAAW,6BAAA;AAAA,gBACX,aAAA,EAAe,MAAA;AAAA,gBACf,GAAG,UAAA;AAAA,gBACH,GAAG;AAAA;AACL;AAAA;AACF;AAAA;AAAA,KAEJ;AAAA,EAEJ;AACF;AAEA,YAAA,CAAa,WAAA,GAAc,cAAA","file":"index.cjs","sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\r\nimport type * as React from \"react\";\r\n\r\nexport type ZoomType = \"hover\" | \"click\" | \"double-click\";\r\nexport type PanePosition = \"left\" | \"right\" | \"top\" | \"bottom\";\r\nexport type LensShape = \"circle\" | \"square\";\r\n\r\nexport interface UseImageMagnifyOptions {\r\n /** Base image URL (required when used standalone). */\r\n src?: string;\r\n /** High-resolution image used for the zoomed view. Defaults to `src`. */\r\n zoomSrc?: string;\r\n /** Magnification factor (2 = 200%). */\r\n zoomScale?: number;\r\n /** Interaction that activates zoom. */\r\n zoomType?: ZoomType;\r\n /** Where the side-by-side pane sits relative to the image. */\r\n panePosition?: PanePosition;\r\n /** Diameter / side length of the lens in px. */\r\n lensSize?: number;\r\n /** Lens shape. */\r\n lensShape?: LensShape;\r\n /** Preload the high-res image to avoid a flash. */\r\n zoomPreload?: boolean;\r\n onZoomStart?: () => void;\r\n onZoomEnd?: () => void;\r\n}\r\n\r\nconst clamp = (v: number, min: number, max: number) =>\r\n Math.max(min, Math.min(max, v));\r\n\r\nexport function useImageMagnify(options: UseImageMagnifyOptions = {}) {\r\n const {\r\n src,\r\n zoomSrc,\r\n zoomScale = 2,\r\n zoomType = \"hover\",\r\n lensSize = 150,\r\n zoomPreload = true,\r\n onZoomStart,\r\n onZoomEnd,\r\n } = options;\r\n\r\n const [isZoomed, setIsZoomed] = useState(false);\r\n const isZoomedRef = useRef(false);\r\n const containerRef = useRef<HTMLDivElement>(null);\r\n const imageRef = useRef<HTMLImageElement>(null);\r\n const lensRef = useRef<HTMLDivElement>(null);\r\n const paneRef = useRef<HTMLDivElement>(null);\r\n const cursorRef = useRef<HTMLDivElement>(null);\r\n const pointerRef = useRef({ x: 0, y: 0 });\r\n const rafRef = useRef(0);\r\n const lastTouchRef = useRef(0);\r\n\r\n const bgImage = zoomSrc || src;\r\n\r\n const isRecentTouch = () => Date.now() - lastTouchRef.current < 700;\r\n\r\n const setZoomed = useCallback(\r\n (z: boolean) => {\r\n if (isZoomedRef.current === z) return;\r\n isZoomedRef.current = z;\r\n setIsZoomed(z);\r\n if (z) onZoomStart?.();\r\n else onZoomEnd?.();\r\n },\r\n [onZoomStart, onZoomEnd],\r\n );\r\n\r\n /** Writes directly to DOM — no React re-renders on mousemove. */\r\n const apply = useCallback(() => {\r\n const container = containerRef.current;\r\n if (!container) return;\r\n const rect = container.getBoundingClientRect();\r\n if (!rect.width || !rect.height) return;\r\n\r\n const { x, y } = pointerRef.current;\r\n const xPct = clamp(x / rect.width, 0, 1);\r\n const yPct = clamp(y / rect.height, 0, 1);\r\n\r\n const lens = lensRef.current;\r\n if (lens) {\r\n // Keep the lens fully inside the container so it never gets clipped\r\n // (and never shows empty background near the edges).\r\n const maxX = Math.max(0, rect.width - lensSize);\r\n const maxY = Math.max(0, rect.height - lensSize);\r\n const lx = clamp(x - lensSize / 2, 0, maxX);\r\n const ly = clamp(y - lensSize / 2, 0, maxY);\r\n const cx = lx + lensSize / 2;\r\n const cy = ly + lensSize / 2;\r\n lens.style.transform = `translate3d(${lx}px, ${ly}px, 0)`;\r\n lens.style.backgroundPosition = `${\r\n lensSize / 2 - cx * zoomScale\r\n }px ${lensSize / 2 - cy * zoomScale}px`;\r\n }\r\n\r\n const pane = paneRef.current;\r\n if (pane) {\r\n const pw = pane.offsetWidth;\r\n const ph = pane.offsetHeight;\r\n const bgW = rect.width * zoomScale;\r\n const bgH = rect.height * zoomScale;\r\n let bgX = pw / 2 - xPct * bgW;\r\n let bgY = ph / 2 - yPct * bgH;\r\n if (bgW > pw) bgX = clamp(bgX, pw - bgW, 0);\r\n else bgX = (pw - bgW) / 2;\r\n if (bgH > ph) bgY = clamp(bgY, ph - bgH, 0);\r\n else bgY = (ph - bgH) / 2;\r\n pane.style.backgroundPosition = `${bgX}px ${bgY}px`;\r\n }\r\n\r\n const cursor = cursorRef.current;\r\n if (cursor) {\r\n cursor.style.transform = `translate3d(${x}px, ${y}px, 0)`;\r\n }\r\n }, [zoomScale, lensSize]);\r\n\r\n /** Coalesce DOM writes into a single rAF. */\r\n const schedule = useCallback(() => {\r\n if (rafRef.current) return;\r\n rafRef.current = requestAnimationFrame(() => {\r\n rafRef.current = 0;\r\n apply();\r\n });\r\n }, [apply]);\r\n\r\n // Position after the lens/pane actually mount.\r\n useEffect(() => {\r\n if (isZoomed) schedule();\r\n }, [isZoomed, schedule]);\r\n\r\n // Background image.\r\n useEffect(() => {\r\n if (!bgImage) return;\r\n const url = `url(\"${bgImage}\")`;\r\n if (lensRef.current) lensRef.current.style.backgroundImage = url;\r\n if (paneRef.current) paneRef.current.style.backgroundImage = url;\r\n }, [bgImage, isZoomed]);\r\n\r\n // Background size tracks the container.\r\n useEffect(() => {\r\n const container = containerRef.current;\r\n if (!container) return;\r\n const update = () => {\r\n const rect = container.getBoundingClientRect();\r\n if (!rect.width || !rect.height) return;\r\n const size = `${rect.width * zoomScale}px ${rect.height * zoomScale}px`;\r\n if (lensRef.current) lensRef.current.style.backgroundSize = size;\r\n if (paneRef.current) paneRef.current.style.backgroundSize = size;\r\n };\r\n update();\r\n const ro = new ResizeObserver(update);\r\n ro.observe(container);\r\n return () => ro.disconnect();\r\n }, [zoomScale, isZoomed]);\r\n\r\n // Preload the high-res image.\r\n useEffect(() => {\r\n if (!zoomPreload || !bgImage) return;\r\n const img = new Image();\r\n img.src = bgImage;\r\n }, [zoomPreload, bgImage]);\r\n\r\n // Cleanup rAF on unmount.\r\n useEffect(\r\n () => () => {\r\n if (rafRef.current) cancelAnimationFrame(rafRef.current);\r\n },\r\n [],\r\n );\r\n\r\n const updatePointer = (clientX: number, clientY: number) => {\r\n const container = containerRef.current;\r\n if (!container) return;\r\n const rect = container.getBoundingClientRect();\r\n if (!rect.width || !rect.height) return;\r\n pointerRef.current = {\r\n x: clamp(clientX - rect.left, 0, rect.width),\r\n y: clamp(clientY - rect.top, 0, rect.height),\r\n };\r\n };\r\n\r\n const handlers = {\r\n onMouseEnter: (e: React.MouseEvent) => {\r\n if (isRecentTouch()) return;\r\n updatePointer(e.clientX, e.clientY);\r\n if (zoomType === \"hover\") setZoomed(true);\r\n schedule();\r\n },\r\n onMouseMove: (e: React.MouseEvent) => {\r\n if (isRecentTouch()) return;\r\n updatePointer(e.clientX, e.clientY);\r\n if (isZoomedRef.current) schedule();\r\n },\r\n onMouseLeave: () => {\r\n if (isRecentTouch()) return;\r\n if (zoomType === \"hover\") setZoomed(false);\r\n },\r\n onClick: (e: React.MouseEvent) => {\r\n if (isRecentTouch()) return;\r\n if (zoomType !== \"click\") return;\r\n updatePointer(e.clientX, e.clientY);\r\n setZoomed(!isZoomedRef.current);\r\n schedule();\r\n },\r\n onDoubleClick: (e: React.MouseEvent) => {\r\n if (isRecentTouch()) return;\r\n if (zoomType !== \"double-click\") return;\r\n updatePointer(e.clientX, e.clientY);\r\n setZoomed(!isZoomedRef.current);\r\n schedule();\r\n },\r\n onTouchStart: (e: React.TouchEvent) => {\r\n lastTouchRef.current = Date.now();\r\n const t = e.touches[0];\r\n if (!t) return;\r\n updatePointer(t.clientX, t.clientY);\r\n if (zoomType === \"hover\") setZoomed(true);\r\n else setZoomed(!isZoomedRef.current);\r\n schedule();\r\n },\r\n onTouchMove: (e: React.TouchEvent) => {\r\n lastTouchRef.current = Date.now();\r\n const t = e.touches[0];\r\n if (!t) return;\r\n updatePointer(t.clientX, t.clientY);\r\n schedule();\r\n },\r\n onTouchEnd: () => {\r\n lastTouchRef.current = Date.now();\r\n if (zoomType === \"hover\") setZoomed(false);\r\n },\r\n onKeyDown: (e: React.KeyboardEvent) => {\r\n const container = containerRef.current;\r\n if (!container) return;\r\n const rect = container.getBoundingClientRect();\r\n const step = 20;\r\n const { x, y } = pointerRef.current;\r\n let handled = true;\r\n\r\n switch (e.key) {\r\n case \"ArrowLeft\":\r\n pointerRef.current.x = clamp(x - step, 0, rect.width);\r\n break;\r\n case \"ArrowRight\":\r\n pointerRef.current.x = clamp(x + step, 0, rect.width);\r\n break;\r\n case \"ArrowUp\":\r\n pointerRef.current.y = clamp(y - step, 0, rect.height);\r\n break;\r\n case \"ArrowDown\":\r\n pointerRef.current.y = clamp(y + step, 0, rect.height);\r\n break;\r\n case \"Enter\":\r\n case \" \":\r\n setZoomed(!isZoomedRef.current);\r\n break;\r\n case \"Escape\":\r\n setZoomed(false);\r\n break;\r\n default:\r\n handled = false;\r\n }\r\n if (handled) {\r\n e.preventDefault();\r\n schedule();\r\n }\r\n },\r\n onFocus: () => {\r\n if (isRecentTouch()) return;\r\n if (zoomType === \"hover\") setZoomed(true);\r\n },\r\n onBlur: () => {\r\n if (zoomType === \"hover\") setZoomed(false);\r\n },\r\n };\r\n\r\n return {\r\n isZoomed,\r\n containerRef,\r\n imageRef,\r\n lensRef,\r\n paneRef,\r\n cursorRef,\r\n handlers,\r\n };\r\n}\r\n","import { forwardRef } from \"react\";\r\nimport type { CSSProperties } from \"react\";\r\nimport { useImageMagnify } from \"../hooks/useImageMagnify\";\r\nimport type { UseImageMagnifyOptions } from \"../hooks/useImageMagnify\";\r\n\r\nexport interface ImageMagnifyProps extends UseImageMagnifyOptions {\r\n src: string;\r\n alt: string;\r\n /** Rendered width of the image (height follows aspect ratio). */\r\n width?: number | string;\r\n mode?: \"lens\" | \"side-by-side\";\r\n className?: string;\r\n style?: CSSProperties;\r\n imageClassName?: string;\r\n imageStyle?: CSSProperties;\r\n lensClassName?: string;\r\n lensStyle?: CSSProperties;\r\n paneClassName?: string;\r\n paneStyle?: CSSProperties;\r\n paneWidth?: number;\r\n paneHeight?: number;\r\n lazy?: boolean;\r\n}\r\n\r\nexport const ImageMagnify = forwardRef<HTMLDivElement, ImageMagnifyProps>(\r\n (props, ref) => {\r\n const {\r\n src,\r\n alt,\r\n width,\r\n mode = \"side-by-side\",\r\n className,\r\n style,\r\n imageClassName,\r\n imageStyle,\r\n lensClassName,\r\n lensStyle,\r\n paneClassName,\r\n paneStyle,\r\n paneWidth = 400,\r\n paneHeight = 400,\r\n lazy,\r\n panePosition = \"right\",\r\n lensSize = 150,\r\n lensShape = \"circle\",\r\n zoomType = \"hover\",\r\n ...hookOptions\r\n } = props;\r\n\r\n const {\r\n isZoomed,\r\n containerRef,\r\n imageRef,\r\n lensRef,\r\n paneRef,\r\n cursorRef,\r\n handlers,\r\n } = useImageMagnify({ src, zoomType, lensSize, ...hookOptions });\r\n\r\n const bgImage = props.zoomSrc || src;\r\n\r\n const paneOffset: CSSProperties = {};\r\n if (panePosition === \"right\") {\r\n paneOffset.left = \"calc(100% + 12px)\";\r\n paneOffset.top = 0;\r\n } else if (panePosition === \"left\") {\r\n paneOffset.right = \"calc(100% + 12px)\";\r\n paneOffset.top = 0;\r\n } else if (panePosition === \"top\") {\r\n paneOffset.left = 0;\r\n paneOffset.bottom = \"calc(100% + 12px)\";\r\n } else {\r\n paneOffset.left = 0;\r\n paneOffset.top = \"calc(100% + 12px)\";\r\n }\r\n\r\n return (\r\n <div\r\n ref={ref}\r\n className={className}\r\n style={{\r\n position: \"relative\",\r\n display: \"inline-block\",\r\n lineHeight: 0,\r\n width,\r\n ...style,\r\n }}\r\n >\r\n <div\r\n ref={containerRef}\r\n tabIndex={0}\r\n role=\"img\"\r\n aria-label={alt}\r\n style={{\r\n position: \"relative\",\r\n overflow: \"hidden\",\r\n width: \"100%\",\r\n cursor:\r\n zoomType === \"hover\"\r\n ? \"crosshair\"\r\n : isZoomed\r\n ? \"zoom-out\"\r\n : \"zoom-in\",\r\n touchAction: \"none\",\r\n outline: \"none\",\r\n lineHeight: 0,\r\n }}\r\n {...handlers}\r\n >\r\n <img\r\n ref={imageRef}\r\n src={src}\r\n alt={alt}\r\n loading={lazy ? \"lazy\" : undefined}\r\n draggable={false}\r\n className={imageClassName}\r\n style={{\r\n display: \"block\",\r\n width: \"100%\",\r\n height: \"auto\",\r\n userSelect: \"none\",\r\n pointerEvents: \"none\",\r\n ...imageStyle,\r\n }}\r\n />\r\n\r\n {mode === \"lens\" && isZoomed && (\r\n <div\r\n ref={lensRef}\r\n className={lensClassName}\r\n style={{\r\n position: \"absolute\",\r\n top: 0,\r\n left: 0,\r\n width: lensSize,\r\n height: lensSize,\r\n borderRadius: lensShape === \"circle\" ? \"50%\" : 0,\r\n backgroundImage: bgImage ? `url(\"${bgImage}\")` : undefined,\r\n backgroundRepeat: \"no-repeat\",\r\n pointerEvents: \"none\",\r\n boxShadow: \"0 4px 12px rgba(0,0,0,0.25)\",\r\n border: \"1px solid rgba(255,255,255,0.6)\",\r\n willChange: \"transform\",\r\n ...lensStyle,\r\n }}\r\n />\r\n )}\r\n\r\n {mode === \"side-by-side\" && isZoomed && (\r\n <div\r\n ref={cursorRef}\r\n style={{\r\n position: \"absolute\",\r\n top: 0,\r\n left: 0,\r\n width: 12,\r\n height: 12,\r\n marginLeft: -6,\r\n marginTop: -6,\r\n borderRadius: \"50%\",\r\n background: \"rgba(255,255,255,0.7)\",\r\n border: \"1px solid rgba(0,0,0,0.5)\",\r\n pointerEvents: \"none\",\r\n boxShadow: \"0 0 0 1px rgba(255,255,255,0.8)\",\r\n willChange: \"transform\",\r\n }}\r\n />\r\n )}\r\n </div>\r\n\r\n {mode === \"side-by-side\" && isZoomed && (\r\n <div\r\n ref={paneRef}\r\n className={paneClassName}\r\n aria-hidden=\"true\"\r\n style={{\r\n position: \"absolute\",\r\n width: paneWidth,\r\n height: paneHeight,\r\n backgroundImage: bgImage ? `url(\"${bgImage}\")` : undefined,\r\n backgroundRepeat: \"no-repeat\",\r\n border: \"1px solid #e5e5e5\",\r\n borderRadius: 4,\r\n boxShadow: \"0 8px 24px rgba(0,0,0,0.12)\",\r\n pointerEvents: \"none\",\r\n ...paneOffset,\r\n ...paneStyle,\r\n }}\r\n />\r\n )}\r\n </div>\r\n );\r\n },\r\n);\r\n\r\nImageMagnify.displayName = \"ImageMagnify\";\r\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { CSSProperties } from 'react';
|
|
3
|
+
|
|
4
|
+
type ZoomType = "hover" | "click" | "double-click";
|
|
5
|
+
type PanePosition = "left" | "right" | "top" | "bottom";
|
|
6
|
+
type LensShape = "circle" | "square";
|
|
7
|
+
interface UseImageMagnifyOptions {
|
|
8
|
+
/** Base image URL (required when used standalone). */
|
|
9
|
+
src?: string;
|
|
10
|
+
/** High-resolution image used for the zoomed view. Defaults to `src`. */
|
|
11
|
+
zoomSrc?: string;
|
|
12
|
+
/** Magnification factor (2 = 200%). */
|
|
13
|
+
zoomScale?: number;
|
|
14
|
+
/** Interaction that activates zoom. */
|
|
15
|
+
zoomType?: ZoomType;
|
|
16
|
+
/** Where the side-by-side pane sits relative to the image. */
|
|
17
|
+
panePosition?: PanePosition;
|
|
18
|
+
/** Diameter / side length of the lens in px. */
|
|
19
|
+
lensSize?: number;
|
|
20
|
+
/** Lens shape. */
|
|
21
|
+
lensShape?: LensShape;
|
|
22
|
+
/** Preload the high-res image to avoid a flash. */
|
|
23
|
+
zoomPreload?: boolean;
|
|
24
|
+
onZoomStart?: () => void;
|
|
25
|
+
onZoomEnd?: () => void;
|
|
26
|
+
}
|
|
27
|
+
declare function useImageMagnify(options?: UseImageMagnifyOptions): {
|
|
28
|
+
isZoomed: boolean;
|
|
29
|
+
containerRef: React.RefObject<HTMLDivElement>;
|
|
30
|
+
imageRef: React.RefObject<HTMLImageElement>;
|
|
31
|
+
lensRef: React.RefObject<HTMLDivElement>;
|
|
32
|
+
paneRef: React.RefObject<HTMLDivElement>;
|
|
33
|
+
cursorRef: React.RefObject<HTMLDivElement>;
|
|
34
|
+
handlers: {
|
|
35
|
+
onMouseEnter: (e: React.MouseEvent) => void;
|
|
36
|
+
onMouseMove: (e: React.MouseEvent) => void;
|
|
37
|
+
onMouseLeave: () => void;
|
|
38
|
+
onClick: (e: React.MouseEvent) => void;
|
|
39
|
+
onDoubleClick: (e: React.MouseEvent) => void;
|
|
40
|
+
onTouchStart: (e: React.TouchEvent) => void;
|
|
41
|
+
onTouchMove: (e: React.TouchEvent) => void;
|
|
42
|
+
onTouchEnd: () => void;
|
|
43
|
+
onKeyDown: (e: React.KeyboardEvent) => void;
|
|
44
|
+
onFocus: () => void;
|
|
45
|
+
onBlur: () => void;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
interface ImageMagnifyProps extends UseImageMagnifyOptions {
|
|
50
|
+
src: string;
|
|
51
|
+
alt: string;
|
|
52
|
+
/** Rendered width of the image (height follows aspect ratio). */
|
|
53
|
+
width?: number | string;
|
|
54
|
+
mode?: "lens" | "side-by-side";
|
|
55
|
+
className?: string;
|
|
56
|
+
style?: CSSProperties;
|
|
57
|
+
imageClassName?: string;
|
|
58
|
+
imageStyle?: CSSProperties;
|
|
59
|
+
lensClassName?: string;
|
|
60
|
+
lensStyle?: CSSProperties;
|
|
61
|
+
paneClassName?: string;
|
|
62
|
+
paneStyle?: CSSProperties;
|
|
63
|
+
paneWidth?: number;
|
|
64
|
+
paneHeight?: number;
|
|
65
|
+
lazy?: boolean;
|
|
66
|
+
}
|
|
67
|
+
declare const ImageMagnify: React.ForwardRefExoticComponent<ImageMagnifyProps & React.RefAttributes<HTMLDivElement>>;
|
|
68
|
+
|
|
69
|
+
export { ImageMagnify, type ImageMagnifyProps, type LensShape, type PanePosition, type UseImageMagnifyOptions, type ZoomType, useImageMagnify };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { CSSProperties } from 'react';
|
|
3
|
+
|
|
4
|
+
type ZoomType = "hover" | "click" | "double-click";
|
|
5
|
+
type PanePosition = "left" | "right" | "top" | "bottom";
|
|
6
|
+
type LensShape = "circle" | "square";
|
|
7
|
+
interface UseImageMagnifyOptions {
|
|
8
|
+
/** Base image URL (required when used standalone). */
|
|
9
|
+
src?: string;
|
|
10
|
+
/** High-resolution image used for the zoomed view. Defaults to `src`. */
|
|
11
|
+
zoomSrc?: string;
|
|
12
|
+
/** Magnification factor (2 = 200%). */
|
|
13
|
+
zoomScale?: number;
|
|
14
|
+
/** Interaction that activates zoom. */
|
|
15
|
+
zoomType?: ZoomType;
|
|
16
|
+
/** Where the side-by-side pane sits relative to the image. */
|
|
17
|
+
panePosition?: PanePosition;
|
|
18
|
+
/** Diameter / side length of the lens in px. */
|
|
19
|
+
lensSize?: number;
|
|
20
|
+
/** Lens shape. */
|
|
21
|
+
lensShape?: LensShape;
|
|
22
|
+
/** Preload the high-res image to avoid a flash. */
|
|
23
|
+
zoomPreload?: boolean;
|
|
24
|
+
onZoomStart?: () => void;
|
|
25
|
+
onZoomEnd?: () => void;
|
|
26
|
+
}
|
|
27
|
+
declare function useImageMagnify(options?: UseImageMagnifyOptions): {
|
|
28
|
+
isZoomed: boolean;
|
|
29
|
+
containerRef: React.RefObject<HTMLDivElement>;
|
|
30
|
+
imageRef: React.RefObject<HTMLImageElement>;
|
|
31
|
+
lensRef: React.RefObject<HTMLDivElement>;
|
|
32
|
+
paneRef: React.RefObject<HTMLDivElement>;
|
|
33
|
+
cursorRef: React.RefObject<HTMLDivElement>;
|
|
34
|
+
handlers: {
|
|
35
|
+
onMouseEnter: (e: React.MouseEvent) => void;
|
|
36
|
+
onMouseMove: (e: React.MouseEvent) => void;
|
|
37
|
+
onMouseLeave: () => void;
|
|
38
|
+
onClick: (e: React.MouseEvent) => void;
|
|
39
|
+
onDoubleClick: (e: React.MouseEvent) => void;
|
|
40
|
+
onTouchStart: (e: React.TouchEvent) => void;
|
|
41
|
+
onTouchMove: (e: React.TouchEvent) => void;
|
|
42
|
+
onTouchEnd: () => void;
|
|
43
|
+
onKeyDown: (e: React.KeyboardEvent) => void;
|
|
44
|
+
onFocus: () => void;
|
|
45
|
+
onBlur: () => void;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
interface ImageMagnifyProps extends UseImageMagnifyOptions {
|
|
50
|
+
src: string;
|
|
51
|
+
alt: string;
|
|
52
|
+
/** Rendered width of the image (height follows aspect ratio). */
|
|
53
|
+
width?: number | string;
|
|
54
|
+
mode?: "lens" | "side-by-side";
|
|
55
|
+
className?: string;
|
|
56
|
+
style?: CSSProperties;
|
|
57
|
+
imageClassName?: string;
|
|
58
|
+
imageStyle?: CSSProperties;
|
|
59
|
+
lensClassName?: string;
|
|
60
|
+
lensStyle?: CSSProperties;
|
|
61
|
+
paneClassName?: string;
|
|
62
|
+
paneStyle?: CSSProperties;
|
|
63
|
+
paneWidth?: number;
|
|
64
|
+
paneHeight?: number;
|
|
65
|
+
lazy?: boolean;
|
|
66
|
+
}
|
|
67
|
+
declare const ImageMagnify: React.ForwardRefExoticComponent<ImageMagnifyProps & React.RefAttributes<HTMLDivElement>>;
|
|
68
|
+
|
|
69
|
+
export { ImageMagnify, type ImageMagnifyProps, type LensShape, type PanePosition, type UseImageMagnifyOptions, type ZoomType, useImageMagnify };
|