@expcat/tigercat-react 0.3.69 → 0.4.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.
Files changed (45) hide show
  1. package/dist/chunk-2EOXY2LP.mjs +353 -0
  2. package/dist/chunk-5CLXOFRZ.mjs +248 -0
  3. package/dist/chunk-6W6CRBBG.mjs +169 -0
  4. package/dist/chunk-EHYSER2Z.js +144 -0
  5. package/dist/chunk-GNMOOYHG.js +250 -0
  6. package/dist/chunk-JWFEJ4XG.js +543 -0
  7. package/dist/chunk-NV3JUZ3N.js +57 -0
  8. package/dist/chunk-PJCY45UP.mjs +536 -0
  9. package/dist/chunk-QFYS5QIZ.mjs +142 -0
  10. package/dist/chunk-QIJG42YQ.mjs +54 -0
  11. package/dist/chunk-U3JOBIDU.js +355 -0
  12. package/dist/chunk-Z7SXK2KO.js +171 -0
  13. package/dist/components/ActivityFeed.js +4 -4
  14. package/dist/components/ActivityFeed.mjs +2 -2
  15. package/dist/components/CropUpload.d.mts +52 -0
  16. package/dist/components/CropUpload.d.ts +52 -0
  17. package/dist/components/CropUpload.js +14 -0
  18. package/dist/components/CropUpload.mjs +5 -0
  19. package/dist/components/Image.d.mts +20 -0
  20. package/dist/components/Image.d.ts +20 -0
  21. package/dist/components/Image.js +13 -0
  22. package/dist/components/Image.mjs +4 -0
  23. package/dist/components/ImageCropper.d.mts +21 -0
  24. package/dist/components/ImageCropper.d.ts +21 -0
  25. package/dist/components/ImageCropper.js +10 -0
  26. package/dist/components/ImageCropper.mjs +1 -0
  27. package/dist/components/ImageGroup.d.mts +30 -0
  28. package/dist/components/ImageGroup.d.ts +30 -0
  29. package/dist/components/ImageGroup.js +16 -0
  30. package/dist/components/ImageGroup.mjs +3 -0
  31. package/dist/components/ImagePreview.d.mts +20 -0
  32. package/dist/components/ImagePreview.d.ts +20 -0
  33. package/dist/components/ImagePreview.js +11 -0
  34. package/dist/components/ImagePreview.mjs +2 -0
  35. package/dist/components/TaskBoard.d.mts +13 -0
  36. package/dist/components/TaskBoard.d.ts +13 -0
  37. package/dist/components/TaskBoard.js +17 -0
  38. package/dist/components/TaskBoard.mjs +2 -0
  39. package/dist/index.d.mts +6 -0
  40. package/dist/index.d.ts +6 -0
  41. package/dist/index.js +108 -74
  42. package/dist/index.mjs +23 -17
  43. package/package.json +2 -2
  44. package/dist/{chunk-MTL2QUM3.mjs → chunk-FTY2W4L2.mjs} +1 -1
  45. package/dist/{chunk-J3HKED4B.js → chunk-IOM7DWWQ.js} +1 -1
@@ -0,0 +1,353 @@
1
+ import { forwardRef, useRef, useState, useEffect, useImperativeHandle, useCallback, useMemo } from 'react';
2
+ import { getInitialCropRect, cropCanvas, classNames, imageCropperContainerClasses, CROP_HANDLES, imageCropperImgClasses, imageCropperMaskClasses, imageCropperSelectionClasses, imageCropperDragAreaClasses, imageCropperGuideClasses, getCropperHandleClasses, moveCropRect, resizeCropRect } from '@expcat/tigercat-core';
3
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
+
5
+ // src/components/ImageCropper.tsx
6
+ var ImageCropper = forwardRef(
7
+ ({
8
+ src,
9
+ aspectRatio,
10
+ minWidth = 20,
11
+ minHeight = 20,
12
+ outputType = "image/png",
13
+ quality = 0.92,
14
+ guides = true,
15
+ className,
16
+ style,
17
+ onCropChange,
18
+ onReady
19
+ }, ref) => {
20
+ const containerRef = useRef(null);
21
+ const imageRef = useRef(null);
22
+ const [imageLoaded, setImageLoaded] = useState(false);
23
+ const [displayWidth, setDisplayWidth] = useState(0);
24
+ const [displayHeight, setDisplayHeight] = useState(0);
25
+ const [cropRect, setCropRect] = useState({ x: 0, y: 0, width: 0, height: 0 });
26
+ const dragModeRef = useRef("none");
27
+ const activeHandleRef = useRef(null);
28
+ const dragStartPosRef = useRef({ x: 0, y: 0 });
29
+ const dragStartRectRef = useRef({ x: 0, y: 0, width: 0, height: 0 });
30
+ const displayDimsRef = useRef({ w: 0, h: 0 });
31
+ useEffect(() => {
32
+ displayDimsRef.current = { w: displayWidth, h: displayHeight };
33
+ }, [displayWidth, displayHeight]);
34
+ useEffect(() => {
35
+ setImageLoaded(false);
36
+ const img = new window.Image();
37
+ img.crossOrigin = "anonymous";
38
+ img.onload = () => {
39
+ imageRef.current = img;
40
+ const container = containerRef.current;
41
+ const containerW = container ? container.clientWidth : img.naturalWidth;
42
+ const containerH = container ? container.clientHeight || 400 : img.naturalHeight;
43
+ const ratio = Math.min(containerW / img.naturalWidth, containerH / img.naturalHeight, 1);
44
+ const dw = img.naturalWidth * ratio;
45
+ const dh = img.naturalHeight * ratio;
46
+ setDisplayWidth(dw);
47
+ setDisplayHeight(dh);
48
+ displayDimsRef.current = { w: dw, h: dh };
49
+ const initial = getInitialCropRect(dw, dh, aspectRatio);
50
+ setCropRect(initial);
51
+ setImageLoaded(true);
52
+ onReady?.();
53
+ };
54
+ img.src = src;
55
+ }, [src, aspectRatio, onReady]);
56
+ useImperativeHandle(
57
+ ref,
58
+ () => ({
59
+ getCropResult: () => {
60
+ return new Promise((resolve, reject) => {
61
+ if (!imageRef.current) {
62
+ reject(new Error("Image not loaded"));
63
+ return;
64
+ }
65
+ const { canvas, dataUrl } = cropCanvas(
66
+ imageRef.current,
67
+ cropRect,
68
+ displayWidth,
69
+ displayHeight,
70
+ outputType,
71
+ quality
72
+ );
73
+ canvas.toBlob(
74
+ (blob) => {
75
+ if (blob) {
76
+ resolve({ canvas, blob, dataUrl, cropRect: { ...cropRect } });
77
+ } else {
78
+ reject(new Error("Failed to create blob"));
79
+ }
80
+ },
81
+ outputType,
82
+ quality
83
+ );
84
+ });
85
+ }
86
+ }),
87
+ [cropRect, displayWidth, displayHeight, outputType, quality]
88
+ );
89
+ const handleMouseDown = useCallback(
90
+ (e, mode, handle) => {
91
+ e.preventDefault();
92
+ e.stopPropagation();
93
+ dragModeRef.current = mode;
94
+ activeHandleRef.current = handle || null;
95
+ dragStartPosRef.current = { x: e.clientX, y: e.clientY };
96
+ dragStartRectRef.current = { ...cropRect };
97
+ const onMouseMove = (ev) => {
98
+ const dx = ev.clientX - dragStartPosRef.current.x;
99
+ const dy = ev.clientY - dragStartPosRef.current.y;
100
+ const dims = displayDimsRef.current;
101
+ let newRect;
102
+ if (dragModeRef.current === "move") {
103
+ newRect = moveCropRect(dragStartRectRef.current, dx, dy, dims.w, dims.h);
104
+ } else {
105
+ newRect = resizeCropRect(
106
+ dragStartRectRef.current,
107
+ activeHandleRef.current,
108
+ dx,
109
+ dy,
110
+ dims.w,
111
+ dims.h,
112
+ aspectRatio,
113
+ minWidth,
114
+ minHeight
115
+ );
116
+ }
117
+ setCropRect(newRect);
118
+ onCropChange?.(newRect);
119
+ };
120
+ const onMouseUp = () => {
121
+ dragModeRef.current = "none";
122
+ activeHandleRef.current = null;
123
+ document.removeEventListener("mousemove", onMouseMove);
124
+ document.removeEventListener("mouseup", onMouseUp);
125
+ };
126
+ document.addEventListener("mousemove", onMouseMove);
127
+ document.addEventListener("mouseup", onMouseUp);
128
+ },
129
+ [cropRect, aspectRatio, minWidth, minHeight, onCropChange]
130
+ );
131
+ const handleTouchStart = useCallback(
132
+ (e, mode, handle) => {
133
+ if (e.touches.length !== 1) return;
134
+ e.preventDefault();
135
+ e.stopPropagation();
136
+ const touch = e.touches[0];
137
+ dragModeRef.current = mode;
138
+ activeHandleRef.current = handle || null;
139
+ dragStartPosRef.current = { x: touch.clientX, y: touch.clientY };
140
+ dragStartRectRef.current = { ...cropRect };
141
+ const onTouchMove = (ev) => {
142
+ if (ev.touches.length !== 1) return;
143
+ const t = ev.touches[0];
144
+ const dx = t.clientX - dragStartPosRef.current.x;
145
+ const dy = t.clientY - dragStartPosRef.current.y;
146
+ const dims = displayDimsRef.current;
147
+ let newRect;
148
+ if (dragModeRef.current === "move") {
149
+ newRect = moveCropRect(dragStartRectRef.current, dx, dy, dims.w, dims.h);
150
+ } else {
151
+ newRect = resizeCropRect(
152
+ dragStartRectRef.current,
153
+ activeHandleRef.current,
154
+ dx,
155
+ dy,
156
+ dims.w,
157
+ dims.h,
158
+ aspectRatio,
159
+ minWidth,
160
+ minHeight
161
+ );
162
+ }
163
+ setCropRect(newRect);
164
+ onCropChange?.(newRect);
165
+ };
166
+ const onTouchEnd = () => {
167
+ dragModeRef.current = "none";
168
+ activeHandleRef.current = null;
169
+ document.removeEventListener("touchmove", onTouchMove);
170
+ document.removeEventListener("touchend", onTouchEnd);
171
+ };
172
+ document.addEventListener("touchmove", onTouchMove, { passive: false });
173
+ document.addEventListener("touchend", onTouchEnd);
174
+ },
175
+ [cropRect, aspectRatio, minWidth, minHeight, onCropChange]
176
+ );
177
+ const containerClasses = useMemo(
178
+ () => classNames(imageCropperContainerClasses, className),
179
+ [className]
180
+ );
181
+ const cr = cropRect;
182
+ if (!imageLoaded) {
183
+ return /* @__PURE__ */ jsx(
184
+ "div",
185
+ {
186
+ ref: containerRef,
187
+ className: classNames(containerClasses, "flex items-center justify-center"),
188
+ style: { ...style, minHeight: "200px" },
189
+ role: "img",
190
+ "aria-label": "Loading image for cropping",
191
+ children: /* @__PURE__ */ jsx("div", { className: "w-8 h-8 border-2 border-white/30 border-t-white rounded-full animate-spin" })
192
+ }
193
+ );
194
+ }
195
+ return /* @__PURE__ */ jsxs(
196
+ "div",
197
+ {
198
+ ref: containerRef,
199
+ className: containerClasses,
200
+ style: {
201
+ ...style,
202
+ width: `${displayWidth}px`,
203
+ height: `${displayHeight}px`
204
+ },
205
+ role: "application",
206
+ "aria-label": "Image cropper",
207
+ "aria-roledescription": "image cropper",
208
+ children: [
209
+ /* @__PURE__ */ jsx(
210
+ "img",
211
+ {
212
+ src,
213
+ className: imageCropperImgClasses,
214
+ style: { width: `${displayWidth}px`, height: `${displayHeight}px` },
215
+ draggable: false,
216
+ alt: "Image to crop"
217
+ }
218
+ ),
219
+ /* @__PURE__ */ jsxs(
220
+ "svg",
221
+ {
222
+ className: imageCropperMaskClasses,
223
+ width: displayWidth,
224
+ height: displayHeight,
225
+ xmlns: "http://www.w3.org/2000/svg",
226
+ children: [
227
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("mask", { id: "crop-mask", children: [
228
+ /* @__PURE__ */ jsx("rect", { width: displayWidth, height: displayHeight, fill: "white" }),
229
+ /* @__PURE__ */ jsx("rect", { x: cr.x, y: cr.y, width: cr.width, height: cr.height, fill: "black" })
230
+ ] }) }),
231
+ /* @__PURE__ */ jsx(
232
+ "rect",
233
+ {
234
+ width: displayWidth,
235
+ height: displayHeight,
236
+ fill: "var(--tiger-image-cropper-mask, rgba(0,0,0,0.55))",
237
+ mask: "url(#crop-mask)"
238
+ }
239
+ )
240
+ ]
241
+ }
242
+ ),
243
+ /* @__PURE__ */ jsx(
244
+ "div",
245
+ {
246
+ className: imageCropperSelectionClasses,
247
+ style: {
248
+ left: `${cr.x}px`,
249
+ top: `${cr.y}px`,
250
+ width: `${cr.width}px`,
251
+ height: `${cr.height}px`
252
+ }
253
+ }
254
+ ),
255
+ /* @__PURE__ */ jsx(
256
+ "div",
257
+ {
258
+ className: imageCropperDragAreaClasses,
259
+ style: {
260
+ left: `${cr.x}px`,
261
+ top: `${cr.y}px`,
262
+ width: `${cr.width}px`,
263
+ height: `${cr.height}px`
264
+ },
265
+ onMouseDown: (e) => handleMouseDown(e, "move"),
266
+ onTouchStart: (e) => handleTouchStart(e, "move")
267
+ }
268
+ ),
269
+ guides && /* @__PURE__ */ jsxs(Fragment, { children: [
270
+ /* @__PURE__ */ jsx(
271
+ "div",
272
+ {
273
+ className: imageCropperGuideClasses,
274
+ style: {
275
+ left: `${cr.x}px`,
276
+ top: `${cr.y + cr.height / 3}px`,
277
+ width: `${cr.width}px`,
278
+ height: 0,
279
+ borderTopWidth: "1px",
280
+ borderTopStyle: "dashed"
281
+ }
282
+ }
283
+ ),
284
+ /* @__PURE__ */ jsx(
285
+ "div",
286
+ {
287
+ className: imageCropperGuideClasses,
288
+ style: {
289
+ left: `${cr.x}px`,
290
+ top: `${cr.y + cr.height * 2 / 3}px`,
291
+ width: `${cr.width}px`,
292
+ height: 0,
293
+ borderTopWidth: "1px",
294
+ borderTopStyle: "dashed"
295
+ }
296
+ }
297
+ ),
298
+ /* @__PURE__ */ jsx(
299
+ "div",
300
+ {
301
+ className: imageCropperGuideClasses,
302
+ style: {
303
+ left: `${cr.x + cr.width / 3}px`,
304
+ top: `${cr.y}px`,
305
+ width: 0,
306
+ height: `${cr.height}px`,
307
+ borderLeftWidth: "1px",
308
+ borderLeftStyle: "dashed"
309
+ }
310
+ }
311
+ ),
312
+ /* @__PURE__ */ jsx(
313
+ "div",
314
+ {
315
+ className: imageCropperGuideClasses,
316
+ style: {
317
+ left: `${cr.x + cr.width * 2 / 3}px`,
318
+ top: `${cr.y}px`,
319
+ width: 0,
320
+ height: `${cr.height}px`,
321
+ borderLeftWidth: "1px",
322
+ borderLeftStyle: "dashed"
323
+ }
324
+ }
325
+ )
326
+ ] }),
327
+ CROP_HANDLES.map((handle) => {
328
+ const pos = {};
329
+ if (handle.includes("n")) pos.top = `${cr.y}px`;
330
+ if (handle.includes("s")) pos.top = `${cr.y + cr.height}px`;
331
+ if (handle === "e" || handle === "w") pos.top = `${cr.y + cr.height / 2}px`;
332
+ if (handle.includes("w")) pos.left = `${cr.x}px`;
333
+ if (handle.includes("e")) pos.left = `${cr.x + cr.width}px`;
334
+ if (handle === "n" || handle === "s") pos.left = `${cr.x + cr.width / 2}px`;
335
+ return /* @__PURE__ */ jsx(
336
+ "div",
337
+ {
338
+ className: getCropperHandleClasses(handle),
339
+ style: pos,
340
+ onMouseDown: (e) => handleMouseDown(e, "resize", handle),
341
+ onTouchStart: (e) => handleTouchStart(e, "resize", handle)
342
+ },
343
+ handle
344
+ );
345
+ })
346
+ ]
347
+ }
348
+ );
349
+ }
350
+ );
351
+ ImageCropper.displayName = "ImageCropper";
352
+
353
+ export { ImageCropper };
@@ -0,0 +1,248 @@
1
+ import { useEscapeKey } from './chunk-WLIFEALE.mjs';
2
+ import { useState, useRef, useCallback, useEffect, useMemo } from 'react';
3
+ import { createPortal } from 'react-dom';
4
+ import { getPreviewNavState, clampScale, calculateTransform, imagePreviewWrapperClasses, imagePreviewMaskClasses, imagePreviewImgClasses, imagePreviewCloseBtnClasses, previewCloseIconPath, classNames, prevIconPath, imagePreviewNavBtnClasses, nextIconPath, imagePreviewToolbarClasses, imagePreviewToolbarBtnClasses, zoomOutIconPath, resetIconPath, zoomInIconPath, imagePreviewCounterClasses } from '@expcat/tigercat-core';
5
+ import { jsxs, jsx } from 'react/jsx-runtime';
6
+
7
+ var SvgIcon = ({ d, cls = "w-5 h-5" }) => /* @__PURE__ */ jsx(
8
+ "svg",
9
+ {
10
+ className: cls,
11
+ xmlns: "http://www.w3.org/2000/svg",
12
+ fill: "none",
13
+ viewBox: "0 0 24 24",
14
+ stroke: "currentColor",
15
+ children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d })
16
+ }
17
+ );
18
+ var ImagePreview = ({
19
+ visible,
20
+ images,
21
+ currentIndex = 0,
22
+ zIndex = 1050,
23
+ maskClosable = true,
24
+ scaleStep = 0.5,
25
+ minScale = 0.25,
26
+ maxScale = 5,
27
+ onVisibleChange,
28
+ onCurrentIndexChange,
29
+ onScaleChange
30
+ }) => {
31
+ const [scale, setScale] = useState(1);
32
+ const [offsetX, setOffsetX] = useState(0);
33
+ const [offsetY, setOffsetY] = useState(0);
34
+ const [index, setIndex] = useState(currentIndex);
35
+ const draggingRef = useRef(false);
36
+ const dragStartRef = useRef({ x: 0, y: 0, ox: 0, oy: 0 });
37
+ const resetTransform = useCallback(() => {
38
+ setScale(1);
39
+ setOffsetX(0);
40
+ setOffsetY(0);
41
+ }, []);
42
+ useEffect(() => {
43
+ setIndex(currentIndex);
44
+ resetTransform();
45
+ }, [currentIndex, resetTransform]);
46
+ useEffect(() => {
47
+ if (visible) {
48
+ resetTransform();
49
+ setIndex(currentIndex);
50
+ document.body.style.overflow = "hidden";
51
+ } else {
52
+ document.body.style.overflow = "";
53
+ }
54
+ return () => {
55
+ document.body.style.overflow = "";
56
+ };
57
+ }, [visible, currentIndex, resetTransform]);
58
+ const handleClose = useCallback(() => {
59
+ onVisibleChange?.(false);
60
+ }, [onVisibleChange]);
61
+ useEscapeKey({ enabled: !!visible, onEscape: handleClose });
62
+ const navState = useMemo(() => getPreviewNavState(index, images.length), [index, images.length]);
63
+ const handleZoomIn = useCallback(() => {
64
+ setScale((s) => {
65
+ const next = clampScale(s + scaleStep, minScale, maxScale);
66
+ onScaleChange?.(next);
67
+ return next;
68
+ });
69
+ }, [scaleStep, minScale, maxScale, onScaleChange]);
70
+ const handleZoomOut = useCallback(() => {
71
+ setScale((s) => {
72
+ const next = clampScale(s - scaleStep, minScale, maxScale);
73
+ onScaleChange?.(next);
74
+ return next;
75
+ });
76
+ }, [scaleStep, minScale, maxScale, onScaleChange]);
77
+ const handleReset = useCallback(() => {
78
+ resetTransform();
79
+ onScaleChange?.(1);
80
+ }, [resetTransform, onScaleChange]);
81
+ const handlePrev = useCallback(() => {
82
+ if (index > 0) {
83
+ const next = index - 1;
84
+ setIndex(next);
85
+ resetTransform();
86
+ onCurrentIndexChange?.(next);
87
+ }
88
+ }, [index, resetTransform, onCurrentIndexChange]);
89
+ const handleNext = useCallback(() => {
90
+ if (index < images.length - 1) {
91
+ const next = index + 1;
92
+ setIndex(next);
93
+ resetTransform();
94
+ onCurrentIndexChange?.(next);
95
+ }
96
+ }, [index, images.length, resetTransform, onCurrentIndexChange]);
97
+ useEffect(() => {
98
+ if (!visible) return;
99
+ const handler = (e) => {
100
+ if (e.key === "ArrowLeft") handlePrev();
101
+ if (e.key === "ArrowRight") handleNext();
102
+ };
103
+ document.addEventListener("keydown", handler);
104
+ return () => document.removeEventListener("keydown", handler);
105
+ }, [visible, handlePrev, handleNext]);
106
+ const handleWheel = useCallback(
107
+ (e) => {
108
+ e.preventDefault();
109
+ const delta = e.deltaY > 0 ? -scaleStep : scaleStep;
110
+ setScale((s) => {
111
+ const next = clampScale(s + delta, minScale, maxScale);
112
+ onScaleChange?.(next);
113
+ return next;
114
+ });
115
+ },
116
+ [scaleStep, minScale, maxScale, onScaleChange]
117
+ );
118
+ const handleMouseDown = useCallback(
119
+ (e) => {
120
+ if (e.button !== 0) return;
121
+ e.preventDefault();
122
+ draggingRef.current = true;
123
+ dragStartRef.current = { x: e.clientX, y: e.clientY, ox: offsetX, oy: offsetY };
124
+ },
125
+ [offsetX, offsetY]
126
+ );
127
+ const handleMouseMove = useCallback((e) => {
128
+ if (!draggingRef.current) return;
129
+ setOffsetX(dragStartRef.current.ox + (e.clientX - dragStartRef.current.x));
130
+ setOffsetY(dragStartRef.current.oy + (e.clientY - dragStartRef.current.y));
131
+ }, []);
132
+ const handleMouseUp = useCallback(() => {
133
+ draggingRef.current = false;
134
+ }, []);
135
+ const handleMaskClick = useCallback(
136
+ (e) => {
137
+ if (maskClosable && e.target === e.currentTarget) {
138
+ handleClose();
139
+ }
140
+ },
141
+ [maskClosable, handleClose]
142
+ );
143
+ const transform = useMemo(
144
+ () => calculateTransform(scale, offsetX, offsetY),
145
+ [scale, offsetX, offsetY]
146
+ );
147
+ if (!visible || !images.length) return null;
148
+ const currentSrc = images[index] || images[0];
149
+ return createPortal(
150
+ /* @__PURE__ */ jsxs(
151
+ "div",
152
+ {
153
+ className: imagePreviewWrapperClasses,
154
+ style: { zIndex },
155
+ role: "dialog",
156
+ "aria-modal": "true",
157
+ "aria-label": "Image preview",
158
+ onClick: handleMaskClick,
159
+ onWheel: handleWheel,
160
+ children: [
161
+ /* @__PURE__ */ jsx("div", { className: imagePreviewMaskClasses, "aria-hidden": "true" }),
162
+ /* @__PURE__ */ jsx(
163
+ "img",
164
+ {
165
+ src: currentSrc,
166
+ className: imagePreviewImgClasses,
167
+ style: { transform },
168
+ alt: `Preview image ${index + 1}`,
169
+ draggable: false,
170
+ onMouseDown: handleMouseDown,
171
+ onMouseMove: handleMouseMove,
172
+ onMouseUp: handleMouseUp,
173
+ onMouseLeave: handleMouseUp
174
+ }
175
+ ),
176
+ /* @__PURE__ */ jsx(
177
+ "button",
178
+ {
179
+ className: imagePreviewCloseBtnClasses,
180
+ onClick: handleClose,
181
+ "aria-label": "Close preview",
182
+ type: "button",
183
+ children: /* @__PURE__ */ jsx(SvgIcon, { d: previewCloseIconPath })
184
+ }
185
+ ),
186
+ images.length > 1 && /* @__PURE__ */ jsx(
187
+ "button",
188
+ {
189
+ className: classNames(imagePreviewNavBtnClasses, "left-4"),
190
+ onClick: handlePrev,
191
+ disabled: !navState.hasPrev,
192
+ "aria-label": "Previous image",
193
+ type: "button",
194
+ children: /* @__PURE__ */ jsx(SvgIcon, { d: prevIconPath })
195
+ }
196
+ ),
197
+ images.length > 1 && /* @__PURE__ */ jsx(
198
+ "button",
199
+ {
200
+ className: classNames(imagePreviewNavBtnClasses, "right-4"),
201
+ onClick: handleNext,
202
+ disabled: !navState.hasNext,
203
+ "aria-label": "Next image",
204
+ type: "button",
205
+ children: /* @__PURE__ */ jsx(SvgIcon, { d: nextIconPath })
206
+ }
207
+ ),
208
+ /* @__PURE__ */ jsxs("div", { className: imagePreviewToolbarClasses, children: [
209
+ /* @__PURE__ */ jsx(
210
+ "button",
211
+ {
212
+ className: imagePreviewToolbarBtnClasses,
213
+ onClick: handleZoomOut,
214
+ "aria-label": "Zoom out",
215
+ type: "button",
216
+ children: /* @__PURE__ */ jsx(SvgIcon, { d: zoomOutIconPath })
217
+ }
218
+ ),
219
+ /* @__PURE__ */ jsx(
220
+ "button",
221
+ {
222
+ className: imagePreviewToolbarBtnClasses,
223
+ onClick: handleReset,
224
+ "aria-label": "Reset",
225
+ type: "button",
226
+ children: /* @__PURE__ */ jsx(SvgIcon, { d: resetIconPath })
227
+ }
228
+ ),
229
+ /* @__PURE__ */ jsx(
230
+ "button",
231
+ {
232
+ className: imagePreviewToolbarBtnClasses,
233
+ onClick: handleZoomIn,
234
+ "aria-label": "Zoom in",
235
+ type: "button",
236
+ children: /* @__PURE__ */ jsx(SvgIcon, { d: zoomInIconPath })
237
+ }
238
+ ),
239
+ navState.counter && /* @__PURE__ */ jsx("span", { className: imagePreviewCounterClasses, children: navState.counter })
240
+ ] })
241
+ ]
242
+ }
243
+ ),
244
+ document.body
245
+ );
246
+ };
247
+
248
+ export { ImagePreview };