@enigmax/primitives 0.25.0 → 0.26.0
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/chunk-4SZ5N7BA.js +121 -0
- package/dist/chunk-EYZ366LP.js +189 -0
- package/dist/chunk-ISXB5RUH.js +380 -0
- package/dist/chunk-JJVZYW5C.js +946 -0
- package/dist/chunk-QIIV2QSV.js +108 -0
- package/dist/chunk-RUEQ3TGP.js +155 -0
- package/dist/clipboard-menu-BvXJCSFN.d.ts +93 -0
- package/dist/context-BfjYGPnH.d.ts +54 -0
- package/dist/{clipboard-menu-B_ouitfS.d.ts → context-menu-D3FtTn7v.d.ts} +1 -91
- package/dist/index.d.ts +266 -2
- package/dist/index.js +4 -2
- package/dist/menu-MSQSE6U5.js +54 -0
- package/dist/menu-PNQRTRNV.js +33 -0
- package/dist/next/index.d.ts +6 -2
- package/dist/next/index.js +10 -6
- package/dist/react/context-menu.d.ts +8 -54
- package/dist/react/image.d.ts +109 -0
- package/dist/react/image.js +3 -0
- package/dist/react/index.d.ts +6 -2
- package/dist/react/index.js +10 -6
- package/dist/react/input.js +1 -1
- package/dist/react/video.d.ts +120 -0
- package/dist/react/video.js +3 -0
- package/dist/react-router/index.d.ts +6 -2
- package/dist/react-router/index.js +10 -6
- package/dist/viewer-73LSE6RR.js +3 -0
- package/package.json +15 -2
- package/recipes/image/styles.css +182 -0
- package/recipes/video/styles.css +154 -0
- package/registry.json +465 -0
- package/src/core/image-viewer.ts +222 -0
- package/src/core/player.ts +303 -0
- package/src/index.ts +52 -0
- package/src/react/image/icons.tsx +55 -0
- package/src/react/image/index.tsx +185 -0
- package/src/react/image/menu.tsx +76 -0
- package/src/react/image/styles.ts +213 -0
- package/src/react/image/types.ts +113 -0
- package/src/react/image/viewer.tsx +571 -0
- package/src/react/index.ts +3 -0
- package/src/react/video/icons.tsx +135 -0
- package/src/react/video/index.tsx +724 -0
- package/src/react/video/menu.tsx +66 -0
- package/src/react/video/rail.tsx +99 -0
- package/src/react/video/styles.ts +161 -0
- package/src/react/video/types.ts +135 -0
- /package/dist/{chunk-3MGBZOAU.js → chunk-RMNXVWQ4.js} +0 -0
- /package/dist/{chunk-MSOCCQGH.js → chunk-T7I6WJSN.js} +0 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import { IDENTITY, prefersReducedMotion, ZOOM_LIMITS, flightFrom, nextIndex, fittedSize, clampPan, zoomAt, pinchDistance, flightMs, ZOOM_STEP, ZOOM_DOUBLE, wheelFactor } from './chunk-QIIV2QSV.js';
|
|
2
|
+
import { injectImageStyles } from './chunk-EYZ366LP.js';
|
|
3
|
+
import { createPortal } from 'react-dom';
|
|
4
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
|
+
import { lazy, useLayoutEffect, useRef, useState, useMemo, useCallback, useEffect, Suspense } from 'react';
|
|
6
|
+
|
|
7
|
+
function Glyph({ children }) {
|
|
8
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "1.125em", height: "1.125em", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children });
|
|
9
|
+
}
|
|
10
|
+
function Close() {
|
|
11
|
+
return /* @__PURE__ */ jsx(Glyph, { children: /* @__PURE__ */ jsx("path", { d: "M6 6 18 18M18 6 6 18" }) });
|
|
12
|
+
}
|
|
13
|
+
function Plus() {
|
|
14
|
+
return /* @__PURE__ */ jsx(Glyph, { children: /* @__PURE__ */ jsx("path", { d: "M12 5v14M5 12h14" }) });
|
|
15
|
+
}
|
|
16
|
+
function Minus() {
|
|
17
|
+
return /* @__PURE__ */ jsx(Glyph, { children: /* @__PURE__ */ jsx("path", { d: "M5 12h14" }) });
|
|
18
|
+
}
|
|
19
|
+
function ChevronLeft() {
|
|
20
|
+
return /* @__PURE__ */ jsx(Glyph, { children: /* @__PURE__ */ jsx("path", { d: "m15 5-7 7 7 7" }) });
|
|
21
|
+
}
|
|
22
|
+
function ChevronRight() {
|
|
23
|
+
return /* @__PURE__ */ jsx(Glyph, { children: /* @__PURE__ */ jsx("path", { d: "m9 5 7 7-7 7" }) });
|
|
24
|
+
}
|
|
25
|
+
function Trash() {
|
|
26
|
+
return /* @__PURE__ */ jsx(Glyph, { children: /* @__PURE__ */ jsx("path", { d: "M4 7h16M9 7V4h6v3M6 7l1 13h10l1-13" }) });
|
|
27
|
+
}
|
|
28
|
+
function Dots() {
|
|
29
|
+
return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", width: "1.125em", height: "1.125em", fill: "currentColor", "aria-hidden": "true", children: [
|
|
30
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "5", r: "1.75" }),
|
|
31
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "1.75" }),
|
|
32
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "19", r: "1.75" })
|
|
33
|
+
] });
|
|
34
|
+
}
|
|
35
|
+
function Download() {
|
|
36
|
+
return /* @__PURE__ */ jsx(Glyph, { children: /* @__PURE__ */ jsx("path", { d: "M12 3v12M7 11l5 5 5-5M4 20h16" }) });
|
|
37
|
+
}
|
|
38
|
+
var ImageMenu = lazy(() => import('./menu-MSQSE6U5.js').then((module) => ({ default: module.ImageMenu })));
|
|
39
|
+
function ImageViewer({
|
|
40
|
+
items,
|
|
41
|
+
index,
|
|
42
|
+
onIndex,
|
|
43
|
+
onClose,
|
|
44
|
+
zoom,
|
|
45
|
+
navigation,
|
|
46
|
+
thumbnails,
|
|
47
|
+
menu,
|
|
48
|
+
discardable,
|
|
49
|
+
onDiscard,
|
|
50
|
+
loop,
|
|
51
|
+
caption,
|
|
52
|
+
origin,
|
|
53
|
+
animate,
|
|
54
|
+
styles,
|
|
55
|
+
labels
|
|
56
|
+
}) {
|
|
57
|
+
useLayoutEffect(() => {
|
|
58
|
+
if (styles) injectImageStyles();
|
|
59
|
+
}, [styles]);
|
|
60
|
+
const frameRef = useRef(null);
|
|
61
|
+
const stripRef = useRef(null);
|
|
62
|
+
const imageRef = useRef(null);
|
|
63
|
+
const [transform, setTransform] = useState(IDENTITY);
|
|
64
|
+
const [loading, setLoading] = useState(true);
|
|
65
|
+
const [panning, setPanning] = useState(false);
|
|
66
|
+
const [phase, setPhase] = useState(() => animate && origin && !prefersReducedMotion() ? "measuring" : "open");
|
|
67
|
+
const [flight, setFlight] = useState(null);
|
|
68
|
+
const [discarded, setDiscarded] = useState(() => /* @__PURE__ */ new Set());
|
|
69
|
+
const limits = useMemo(() => ({ min: zoom?.min ?? ZOOM_LIMITS.min, max: zoom?.max ?? ZOOM_LIMITS.max }), [zoom]);
|
|
70
|
+
const item = items[index];
|
|
71
|
+
const zoomed = transform.scale > limits.min;
|
|
72
|
+
const remaining = items.length - discarded.size;
|
|
73
|
+
const position = useMemo(() => {
|
|
74
|
+
let seen = 0;
|
|
75
|
+
for (let at = 0; at <= index && at < items.length; at += 1) if (!discarded.has(at)) seen += 1;
|
|
76
|
+
return seen;
|
|
77
|
+
}, [index, items.length, discarded]);
|
|
78
|
+
const layoutBox = useCallback(() => {
|
|
79
|
+
const frame = frameRef.current;
|
|
80
|
+
const element = imageRef.current;
|
|
81
|
+
if (!frame || !element?.offsetWidth) return null;
|
|
82
|
+
const box = frame.getBoundingClientRect();
|
|
83
|
+
return { left: box.left + element.offsetLeft, top: box.top + element.offsetTop, width: element.offsetWidth, height: element.offsetHeight };
|
|
84
|
+
}, []);
|
|
85
|
+
const requestClose = useCallback(() => {
|
|
86
|
+
if (phase === "closing" || phase === "measuring") return onClose();
|
|
87
|
+
const from = origin?.();
|
|
88
|
+
const to = layoutBox();
|
|
89
|
+
const back = animate && !prefersReducedMotion() && from && to ? flightFrom(from, to) : null;
|
|
90
|
+
if (!back) return onClose();
|
|
91
|
+
setPhase("closing");
|
|
92
|
+
setFlight(back);
|
|
93
|
+
}, [phase, origin, layoutBox, animate, onClose]);
|
|
94
|
+
const go = useCallback((step) => {
|
|
95
|
+
const next = nextIndex(index, items.length, step, { loop, skip: discarded });
|
|
96
|
+
if (next === -1 || next === index) return;
|
|
97
|
+
onIndex(next);
|
|
98
|
+
}, [index, items.length, loop, discarded, onIndex]);
|
|
99
|
+
const showAt = useCallback((next) => {
|
|
100
|
+
if (next === index || discarded.has(next)) return;
|
|
101
|
+
onIndex(next);
|
|
102
|
+
}, [index, discarded, onIndex]);
|
|
103
|
+
const discard = useCallback(() => {
|
|
104
|
+
if (!discardable || !item) return;
|
|
105
|
+
const next = nextIndex(index, items.length, 1, { loop: true, skip: /* @__PURE__ */ new Set([...discarded, index]) });
|
|
106
|
+
setDiscarded((current) => new Set(current).add(index));
|
|
107
|
+
onDiscard?.(item, index);
|
|
108
|
+
if (next === -1) requestClose();
|
|
109
|
+
else onIndex(next);
|
|
110
|
+
}, [discardable, item, index, items.length, discarded, onDiscard, onIndex, requestClose]);
|
|
111
|
+
const reset = useCallback(() => setTransform(IDENTITY), []);
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
setTransform(IDENTITY);
|
|
114
|
+
setLoading(true);
|
|
115
|
+
}, [item?.src]);
|
|
116
|
+
const frameBox = useCallback(() => {
|
|
117
|
+
const box = frameRef.current?.getBoundingClientRect();
|
|
118
|
+
return box ? { left: box.left, top: box.top, width: box.width, height: box.height } : null;
|
|
119
|
+
}, []);
|
|
120
|
+
const bounded = useCallback((next) => {
|
|
121
|
+
const box = frameBox();
|
|
122
|
+
const element = imageRef.current;
|
|
123
|
+
if (!box || !element) return next;
|
|
124
|
+
const fitted = fittedSize({ width: element.naturalWidth, height: element.naturalHeight }, box);
|
|
125
|
+
return clampPan(next, box, fitted);
|
|
126
|
+
}, [frameBox]);
|
|
127
|
+
const zoomBy = useCallback((factor, point) => {
|
|
128
|
+
const box = frameBox();
|
|
129
|
+
if (!box) return;
|
|
130
|
+
const at = point ?? { x: box.left + box.width / 2, y: box.top + box.height / 2 };
|
|
131
|
+
setTransform((current) => bounded(zoomAt(current, factor, at, box, limits)));
|
|
132
|
+
}, [frameBox, bounded, limits]);
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
const element = frameRef.current;
|
|
135
|
+
if (!element || !zoom?.wheel) return;
|
|
136
|
+
const onWheel = (event) => {
|
|
137
|
+
event.preventDefault();
|
|
138
|
+
zoomBy(wheelFactor(event.deltaY, event.deltaMode), { x: event.clientX, y: event.clientY });
|
|
139
|
+
};
|
|
140
|
+
element.addEventListener("wheel", onWheel, { passive: false });
|
|
141
|
+
return () => element.removeEventListener("wheel", onWheel);
|
|
142
|
+
}, [zoom?.wheel, zoomBy]);
|
|
143
|
+
const pointers = useRef(/* @__PURE__ */ new Map());
|
|
144
|
+
const pinch = useRef(null);
|
|
145
|
+
const backdropPress = useRef(null);
|
|
146
|
+
const onPointerDown = useCallback((event) => {
|
|
147
|
+
if (event.button !== 0 && event.pointerType === "mouse") return;
|
|
148
|
+
const element = event.currentTarget;
|
|
149
|
+
backdropPress.current = event.target === element && !zoomed ? { x: event.clientX, y: event.clientY } : null;
|
|
150
|
+
pointers.current.set(event.pointerId, { x: event.clientX, y: event.clientY });
|
|
151
|
+
if (pointers.current.size === 2) {
|
|
152
|
+
const [a, b] = [...pointers.current.values()];
|
|
153
|
+
pinch.current = { distance: pinchDistance(a, b), scale: transform.scale };
|
|
154
|
+
setPanning(false);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (!zoomed) return;
|
|
158
|
+
event.preventDefault();
|
|
159
|
+
setPanning(true);
|
|
160
|
+
try {
|
|
161
|
+
element.setPointerCapture(event.pointerId);
|
|
162
|
+
} catch {
|
|
163
|
+
}
|
|
164
|
+
}, [zoomed, transform.scale]);
|
|
165
|
+
const onPointerMove = useCallback((event) => {
|
|
166
|
+
const previous = pointers.current.get(event.pointerId);
|
|
167
|
+
if (!previous) return;
|
|
168
|
+
pointers.current.set(event.pointerId, { x: event.clientX, y: event.clientY });
|
|
169
|
+
if (pointers.current.size === 2 && pinch.current) {
|
|
170
|
+
const [a, b] = [...pointers.current.values()];
|
|
171
|
+
const distance = pinchDistance(a, b);
|
|
172
|
+
if (!pinch.current.distance) return;
|
|
173
|
+
const box = frameBox();
|
|
174
|
+
if (!box) return;
|
|
175
|
+
const factor = distance / pinch.current.distance * (pinch.current.scale / transform.scale);
|
|
176
|
+
setTransform((current) => bounded(zoomAt(current, factor, { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 }, box, limits)));
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (!panning) return;
|
|
180
|
+
setTransform((current) => bounded({ ...current, x: current.x + (event.clientX - previous.x), y: current.y + (event.clientY - previous.y) }));
|
|
181
|
+
}, [panning, bounded, frameBox, limits, transform.scale]);
|
|
182
|
+
const endPointer = useCallback((event) => {
|
|
183
|
+
pointers.current.delete(event.pointerId);
|
|
184
|
+
if (pointers.current.size < 2) pinch.current = null;
|
|
185
|
+
if (pointers.current.size === 0) setPanning(false);
|
|
186
|
+
const started = backdropPress.current;
|
|
187
|
+
backdropPress.current = null;
|
|
188
|
+
if (!started || event.target !== event.currentTarget) return;
|
|
189
|
+
if (Math.abs(event.clientX - started.x) < 4 && Math.abs(event.clientY - started.y) < 4) requestClose();
|
|
190
|
+
}, [requestClose]);
|
|
191
|
+
useLayoutEffect(() => {
|
|
192
|
+
if (phase !== "measuring") return;
|
|
193
|
+
const element = imageRef.current;
|
|
194
|
+
const from = origin?.();
|
|
195
|
+
if (!element || !from) {
|
|
196
|
+
setPhase("open");
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (!element.complete) return;
|
|
200
|
+
const to = layoutBox();
|
|
201
|
+
const start = to ? flightFrom(from, to) : null;
|
|
202
|
+
if (!start) {
|
|
203
|
+
setPhase("open");
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
setFlight(start);
|
|
207
|
+
let second = 0;
|
|
208
|
+
const first = requestAnimationFrame(() => {
|
|
209
|
+
second = requestAnimationFrame(() => {
|
|
210
|
+
setFlight(null);
|
|
211
|
+
setPhase("flying");
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
return () => {
|
|
215
|
+
cancelAnimationFrame(first);
|
|
216
|
+
cancelAnimationFrame(second);
|
|
217
|
+
};
|
|
218
|
+
}, [phase, origin, layoutBox, loading]);
|
|
219
|
+
useEffect(() => {
|
|
220
|
+
if (phase !== "flying" && phase !== "closing") return;
|
|
221
|
+
const element = imageRef.current;
|
|
222
|
+
const done = (event) => {
|
|
223
|
+
if (event && event.propertyName !== "transform") return;
|
|
224
|
+
if (phase === "closing") onClose();
|
|
225
|
+
else setPhase("open");
|
|
226
|
+
};
|
|
227
|
+
element?.addEventListener("transitionend", done);
|
|
228
|
+
const timer = window.setTimeout(() => done(), flightMs(element) + 80);
|
|
229
|
+
return () => {
|
|
230
|
+
element?.removeEventListener("transitionend", done);
|
|
231
|
+
window.clearTimeout(timer);
|
|
232
|
+
};
|
|
233
|
+
}, [phase, onClose]);
|
|
234
|
+
useEffect(() => {
|
|
235
|
+
const onKeyDown = (event) => {
|
|
236
|
+
if (event.defaultPrevented) return;
|
|
237
|
+
const key = event.key;
|
|
238
|
+
if (key === "Escape") return void (event.preventDefault(), requestClose());
|
|
239
|
+
if (navigation && (key === "ArrowRight" || key === "ArrowLeft") && !zoomed) {
|
|
240
|
+
event.preventDefault();
|
|
241
|
+
return go(key === "ArrowRight" ? 1 : -1);
|
|
242
|
+
}
|
|
243
|
+
if (zoom && (key === "+" || key === "=")) return void (event.preventDefault(), zoomBy(ZOOM_STEP));
|
|
244
|
+
if (zoom && key === "-") return void (event.preventDefault(), zoomBy(1 / ZOOM_STEP));
|
|
245
|
+
if (zoom && key === "0") return void (event.preventDefault(), reset());
|
|
246
|
+
if (zoomed && key.startsWith("Arrow")) {
|
|
247
|
+
event.preventDefault();
|
|
248
|
+
const step = event.shiftKey ? 120 : 40;
|
|
249
|
+
const by = key === "ArrowLeft" ? [step, 0] : key === "ArrowRight" ? [-step, 0] : key === "ArrowUp" ? [0, step] : [0, -step];
|
|
250
|
+
return setTransform((current) => bounded({ ...current, x: current.x + by[0], y: current.y + by[1] }));
|
|
251
|
+
}
|
|
252
|
+
if (discardable && (key === "Delete" || key === "Backspace")) return void (event.preventDefault(), discard());
|
|
253
|
+
};
|
|
254
|
+
document.addEventListener("keydown", onKeyDown);
|
|
255
|
+
return () => document.removeEventListener("keydown", onKeyDown);
|
|
256
|
+
}, [requestClose, navigation, zoom, zoomed, go, zoomBy, reset, bounded, discardable, discard]);
|
|
257
|
+
useEffect(() => {
|
|
258
|
+
frameRef.current?.focus();
|
|
259
|
+
const { body } = document;
|
|
260
|
+
const overflow = body.style.overflow;
|
|
261
|
+
body.style.overflow = "hidden";
|
|
262
|
+
return () => {
|
|
263
|
+
body.style.overflow = overflow;
|
|
264
|
+
};
|
|
265
|
+
}, []);
|
|
266
|
+
useEffect(() => {
|
|
267
|
+
if (!thumbnails) return;
|
|
268
|
+
stripRef.current?.querySelector("[aria-current=true]")?.scrollIntoView({ block: "nearest", inline: "center" });
|
|
269
|
+
}, [thumbnails, index]);
|
|
270
|
+
if (!item) return null;
|
|
271
|
+
const drawn = flight ?? transform;
|
|
272
|
+
const style = { transform: `translate(${drawn.x}px, ${drawn.y}px) scale(${drawn.scale})` };
|
|
273
|
+
const counter = (labels.counter ?? "{index} of {total}").replace("{index}", String(position)).replace("{total}", String(remaining));
|
|
274
|
+
return createPortal(
|
|
275
|
+
/* @__PURE__ */ jsxs(
|
|
276
|
+
"div",
|
|
277
|
+
{
|
|
278
|
+
"data-enigma-image-viewer": "",
|
|
279
|
+
"data-state": phase === "measuring" || phase === "flying" ? "opening" : phase,
|
|
280
|
+
role: "dialog",
|
|
281
|
+
"aria-modal": "true",
|
|
282
|
+
"aria-label": labels.viewer ?? "Image viewer",
|
|
283
|
+
onPointerDown: (event) => {
|
|
284
|
+
if (event.target === event.currentTarget) requestClose();
|
|
285
|
+
},
|
|
286
|
+
children: [
|
|
287
|
+
/* @__PURE__ */ jsxs("div", { "data-enigma-image-bar": "", children: [
|
|
288
|
+
navigation && /* @__PURE__ */ jsx("span", { "data-enigma-image-counter": "", children: counter }),
|
|
289
|
+
!navigation && /* @__PURE__ */ jsx("span", { "data-enigma-image-counter": "" }),
|
|
290
|
+
zoom && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
291
|
+
/* @__PURE__ */ jsx("button", { type: "button", "data-enigma-image-button": "", "aria-label": labels.zoomOut ?? "Zoom out", title: labels.zoomOut ?? "Zoom out", disabled: transform.scale <= limits.min, onClick: () => zoomBy(1 / ZOOM_STEP), children: /* @__PURE__ */ jsx(Minus, {}) }),
|
|
292
|
+
/* @__PURE__ */ jsx("button", { type: "button", "data-enigma-image-button": "", "aria-label": labels.zoomIn ?? "Zoom in", title: labels.zoomIn ?? "Zoom in", disabled: transform.scale >= limits.max, onClick: () => zoomBy(ZOOM_STEP), children: /* @__PURE__ */ jsx(Plus, {}) })
|
|
293
|
+
] }),
|
|
294
|
+
discardable && /* @__PURE__ */ jsx("button", { type: "button", "data-enigma-image-button": "", "aria-label": labels.discard ?? "Discard this image", title: labels.discard ?? "Discard this image", onClick: discard, children: /* @__PURE__ */ jsx(Trash, {}) }),
|
|
295
|
+
menu && /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(MenuButton, { label: labels.menu ?? "More", onPress: void 0 }), children: /* @__PURE__ */ jsx(ImageMenu, { item, index, options: menu, labels }) }),
|
|
296
|
+
/* @__PURE__ */ jsx("button", { type: "button", "data-enigma-image-button": "", "aria-label": labels.close ?? "Close", title: labels.close ?? "Close", onClick: requestClose, children: /* @__PURE__ */ jsx(Close, {}) })
|
|
297
|
+
] }),
|
|
298
|
+
/* @__PURE__ */ jsxs(
|
|
299
|
+
"div",
|
|
300
|
+
{
|
|
301
|
+
ref: frameRef,
|
|
302
|
+
"data-enigma-image-frame": "",
|
|
303
|
+
"data-zoom": zoom ? "" : void 0,
|
|
304
|
+
"data-flying": phase === "open" ? void 0 : phase === "measuring" ? "pending" : "moving",
|
|
305
|
+
"data-zoomed": zoomed ? "" : void 0,
|
|
306
|
+
"data-panning": panning ? "" : void 0,
|
|
307
|
+
"data-loading": loading ? "" : void 0,
|
|
308
|
+
tabIndex: -1,
|
|
309
|
+
onPointerDown,
|
|
310
|
+
onPointerMove,
|
|
311
|
+
onPointerUp: endPointer,
|
|
312
|
+
onPointerCancel: endPointer,
|
|
313
|
+
onDoubleClick: (event) => {
|
|
314
|
+
if (!zoom?.doubleClick || phase !== "open") return;
|
|
315
|
+
if (zoomed) return reset();
|
|
316
|
+
zoomBy(ZOOM_DOUBLE / transform.scale, { x: event.clientX, y: event.clientY });
|
|
317
|
+
},
|
|
318
|
+
children: [
|
|
319
|
+
/* @__PURE__ */ jsx(
|
|
320
|
+
"img",
|
|
321
|
+
{
|
|
322
|
+
ref: imageRef,
|
|
323
|
+
src: item.src,
|
|
324
|
+
alt: item.alt ?? "",
|
|
325
|
+
style,
|
|
326
|
+
draggable: false,
|
|
327
|
+
onLoad: () => setLoading(false),
|
|
328
|
+
onError: () => setLoading(false)
|
|
329
|
+
},
|
|
330
|
+
item.src
|
|
331
|
+
),
|
|
332
|
+
loading && /* @__PURE__ */ jsx("span", { "data-enigma-image-spinner": "", role: "progressbar", "aria-label": labels.viewer ?? "Image viewer" }),
|
|
333
|
+
navigation && remaining > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
334
|
+
/* @__PURE__ */ jsx("button", { type: "button", "data-enigma-image-button": "", "data-enigma-image-nav": "previous", "aria-label": labels.previous ?? "Previous image", title: labels.previous ?? "Previous image", onClick: () => go(-1), children: /* @__PURE__ */ jsx(ChevronLeft, {}) }),
|
|
335
|
+
/* @__PURE__ */ jsx("button", { type: "button", "data-enigma-image-button": "", "data-enigma-image-nav": "next", "aria-label": labels.next ?? "Next image", title: labels.next ?? "Next image", onClick: () => go(1), children: /* @__PURE__ */ jsx(ChevronRight, {}) })
|
|
336
|
+
] })
|
|
337
|
+
]
|
|
338
|
+
}
|
|
339
|
+
),
|
|
340
|
+
/* @__PURE__ */ jsxs("div", { "data-enigma-image-foot": "", children: [
|
|
341
|
+
(item.caption ?? caption) && /* @__PURE__ */ jsx("p", { "data-enigma-image-caption": "", children: item.caption ?? caption }),
|
|
342
|
+
thumbnails && remaining > 1 && /* @__PURE__ */ jsx("div", { ref: stripRef, "data-enigma-image-strip": "", role: "tablist", "aria-label": labels.thumbnails ?? "Images", children: items.map((entry, at) => discarded.has(at) ? null : /* @__PURE__ */ jsx(
|
|
343
|
+
"button",
|
|
344
|
+
{
|
|
345
|
+
type: "button",
|
|
346
|
+
role: "tab",
|
|
347
|
+
"data-enigma-image-thumb": "",
|
|
348
|
+
"aria-current": at === index,
|
|
349
|
+
"aria-selected": at === index,
|
|
350
|
+
"aria-label": entry.alt ?? `${at + 1}`,
|
|
351
|
+
onClick: () => showAt(at),
|
|
352
|
+
children: /* @__PURE__ */ jsx("img", { src: entry.thumbnail ?? entry.src, alt: "", loading: "lazy", draggable: false })
|
|
353
|
+
},
|
|
354
|
+
entry.src
|
|
355
|
+
)) })
|
|
356
|
+
] })
|
|
357
|
+
]
|
|
358
|
+
}
|
|
359
|
+
),
|
|
360
|
+
document.body
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
function MenuButton({ label, onPress, expanded }) {
|
|
364
|
+
return /* @__PURE__ */ jsx(
|
|
365
|
+
"button",
|
|
366
|
+
{
|
|
367
|
+
type: "button",
|
|
368
|
+
"data-enigma-image-button": "",
|
|
369
|
+
"data-enigma-image-menu": "",
|
|
370
|
+
"aria-haspopup": "menu",
|
|
371
|
+
"aria-expanded": expanded ?? false,
|
|
372
|
+
"aria-label": label,
|
|
373
|
+
title: label,
|
|
374
|
+
onClick: onPress,
|
|
375
|
+
children: /* @__PURE__ */ jsx(Dots, {})
|
|
376
|
+
}
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
export { Download, ImageViewer, MenuButton };
|