@gx-design-vue/image 0.2.0-alpha.1 → 0.2.0-alpha.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.
Files changed (69) hide show
  1. package/dist/Image.d.ts +6 -0
  2. package/dist/Image.js +322 -0
  3. package/dist/ImagePreview.d.ts +6 -0
  4. package/dist/ImagePreview.js +593 -0
  5. package/dist/g-image.esm.js +1590 -0
  6. package/dist/g-image.js +1 -0
  7. package/dist/hooks/useImageBoundary.d.ts +15 -0
  8. package/dist/hooks/useImageBoundary.js +24 -0
  9. package/dist/hooks/useImagePreview.d.ts +23 -0
  10. package/dist/hooks/useImagePreview.js +54 -0
  11. package/dist/hooks/useImageTransform.d.ts +23 -0
  12. package/dist/hooks/useImageTransform.js +92 -0
  13. package/dist/hooks/useMouseEvent.d.ts +22 -0
  14. package/dist/hooks/useMouseEvent.js +71 -0
  15. package/dist/hooks/useTouchEvent.d.ts +23 -0
  16. package/dist/{ImagePreview/hooks → hooks}/useTouchEvent.js +31 -32
  17. package/dist/index.d.ts +4 -5
  18. package/dist/index.js +3 -6
  19. package/dist/interface.d.ts +169 -0
  20. package/dist/interface.js +1 -0
  21. package/dist/style/index.d.ts +7 -0
  22. package/dist/{style.js → style/index.js} +19 -26
  23. package/dist/style/preview.d.ts +14 -0
  24. package/dist/style/preview.js +182 -0
  25. package/dist/theme/augment.d.ts +10 -0
  26. package/dist/theme/augment.js +1 -0
  27. package/dist/theme/interface/components.d.ts +10 -0
  28. package/dist/theme/interface/components.js +1 -0
  29. package/package.json +8 -7
  30. package/dist/GImage.d.ts +0 -162
  31. package/dist/GImage.js +0 -221
  32. package/dist/ImagePreview/Operations.d.ts +0 -83
  33. package/dist/ImagePreview/Operations.js +0 -71
  34. package/dist/ImagePreview/hooks/getFixScaleEleTransPosition.d.ts +0 -19
  35. package/dist/ImagePreview/hooks/getFixScaleEleTransPosition.js +0 -40
  36. package/dist/ImagePreview/hooks/useImageTransform.d.ts +0 -39
  37. package/dist/ImagePreview/hooks/useImageTransform.js +0 -105
  38. package/dist/ImagePreview/hooks/useMouseEvent.d.ts +0 -14
  39. package/dist/ImagePreview/hooks/useMouseEvent.js +0 -100
  40. package/dist/ImagePreview/hooks/useTouchEvent.d.ts +0 -12
  41. package/dist/ImagePreview/index.d.ts +0 -162
  42. package/dist/ImagePreview/index.js +0 -303
  43. package/dist/ImagePreview/props.d.ts +0 -88
  44. package/dist/ImagePreview/props.js +0 -53
  45. package/dist/ImagePreview/style.d.ts +0 -30
  46. package/dist/ImagePreview/style.js +0 -286
  47. package/dist/ImagePreview/typings.d.ts +0 -19
  48. package/dist/ImagePreview/typings.js +0 -1
  49. package/dist/ImagePreview/utils/KeyCode.d.ts +0 -438
  50. package/dist/ImagePreview/utils/KeyCode.js +0 -173
  51. package/dist/ImagePreview/utils/addEventListener.d.ts +0 -6
  52. package/dist/ImagePreview/utils/addEventListener.js +0 -22
  53. package/dist/ImagePreview/utils/util.d.ts +0 -7
  54. package/dist/ImagePreview/utils/util.js +0 -8
  55. package/dist/hooks/useFrameSetState.d.ts +0 -5
  56. package/dist/hooks/useFrameSetState.js +0 -33
  57. package/dist/image.esm.js +0 -2374
  58. package/dist/image.js +0 -1
  59. package/dist/props.d.ts +0 -84
  60. package/dist/props.js +0 -66
  61. package/dist/slots.d.ts +0 -6
  62. package/dist/slots.js +0 -21
  63. package/dist/style.d.ts +0 -9
  64. package/dist/typings.d.ts +0 -6
  65. package/dist/typings.js +0 -1
  66. package/dist/utils/aria.d.ts +0 -15
  67. package/dist/utils/aria.js +0 -16
  68. package/dist/utils/util.d.ts +0 -4
  69. package/dist/utils/util.js +0 -8
@@ -0,0 +1,593 @@
1
+ import useImageTransform from "./hooks/useImageTransform.js";
2
+ import useMouseEvent from "./hooks/useMouseEvent.js";
3
+ import useTouchEvent from "./hooks/useTouchEvent.js";
4
+ import preview_default from "./style/preview.js";
5
+ import { Fragment, Teleport, Transition, computed, createVNode, defineComponent, mergeDefaults, nextTick, onMounted, onUnmounted, ref, toRef, watch } from "vue";
6
+ import { CloseOutlined, CopyOutlined, DownloadOutlined, LeftOutlined, LoadingOutlined, RightOutlined, RotateLeftOutlined, RotateRightOutlined, SwapOutlined, ZoomInOutlined, ZoomOutOutlined } from "@antdv-next/icons";
7
+ import { classNames, getSlotVNode, getSlotsProps } from "@gx-design-vue/pro-utils";
8
+ import { useWindowSize } from "@vueuse/core";
9
+ import { useBaseConfig } from "antdv-next/config-provider/context";
10
+ import useCSSVarCls from "antdv-next/config-provider/hooks/useCSSVarCls";
11
+ import { useMergedState } from "@gx-design-vue/pro-hooks";
12
+ import { message } from "antdv-next";
13
+ //#region src/ImagePreview.tsx
14
+ const BASE_SCALE_RATIO = 1;
15
+ const defaultIcons = {
16
+ rotateLeft: createVNode(RotateLeftOutlined, null, null),
17
+ rotateRight: createVNode(RotateRightOutlined, null, null),
18
+ zoomIn: createVNode(ZoomInOutlined, null, null),
19
+ zoomOut: createVNode(ZoomOutOutlined, null, null),
20
+ flipX: createVNode(SwapOutlined, null, null),
21
+ flipY: createVNode(SwapOutlined, { "rotate": 90 }, null),
22
+ copy: createVNode(CopyOutlined, null, null),
23
+ download: createVNode(DownloadOutlined, null, null)
24
+ };
25
+ const imagePreviewMessages = {
26
+ copySuccess: "复制成功",
27
+ copyFailed: "复制失败",
28
+ downloadSuccess: "下载成功",
29
+ downloadFailed: "下载失败"
30
+ };
31
+ function getFileNameFromUrl(url) {
32
+ try {
33
+ const matchedFileName = new URL(url, window.location.href).pathname.match(/\/([^/]+)$/)?.[1];
34
+ return matchedFileName ? decodeURIComponent(matchedFileName) : "image";
35
+ } catch {
36
+ const fallbackFileName = url.split("?")[0]?.split("#")[0]?.split("/").pop();
37
+ return fallbackFileName ? decodeURIComponent(fallbackFileName) : "image";
38
+ }
39
+ }
40
+ function getExtensionFromMimeType(mimeType) {
41
+ const mimeTypeMap = {
42
+ "image/gif": "gif",
43
+ "image/jpg": "jpg",
44
+ "image/jpeg": "jpg",
45
+ "image/png": "png",
46
+ "image/svg+xml": "svg",
47
+ "image/webp": "webp"
48
+ };
49
+ const normalizedType = mimeType?.toLowerCase();
50
+ return mimeTypeMap[normalizedType] || normalizedType?.split("/")[1]?.split("+")[0] || "png";
51
+ }
52
+ async function fetchImageBlob(url) {
53
+ const response = await fetch(url, { mode: "cors" });
54
+ if (!response.ok) throw new Error(`Failed to fetch image: ${response.status}`);
55
+ return response.blob();
56
+ }
57
+ /** ClipboardItem 只支持 image/png 和 image/svg+xml。非 PNG/SVG 格式需先转换为 PNG */
58
+ async function blobToPng(blob) {
59
+ return new Promise((resolve, reject) => {
60
+ const img = new Image();
61
+ const url = URL.createObjectURL(blob);
62
+ img.onload = () => {
63
+ URL.revokeObjectURL(url);
64
+ const canvas = document.createElement("canvas");
65
+ canvas.width = img.naturalWidth;
66
+ canvas.height = img.naturalHeight;
67
+ const ctx = canvas.getContext("2d");
68
+ if (!ctx) {
69
+ reject(/* @__PURE__ */ new Error("Canvas context not available"));
70
+ return;
71
+ }
72
+ ctx.drawImage(img, 0, 0);
73
+ canvas.toBlob((pngBlob) => {
74
+ if (pngBlob) resolve(pngBlob);
75
+ else reject(/* @__PURE__ */ new Error("Failed to convert to PNG"));
76
+ }, "image/png", 1);
77
+ };
78
+ img.onerror = () => {
79
+ URL.revokeObjectURL(url);
80
+ reject(/* @__PURE__ */ new Error("Failed to load image for PNG conversion"));
81
+ };
82
+ img.src = url;
83
+ });
84
+ }
85
+ async function getClipboardBlob(blob) {
86
+ const type = (blob.type || "").toLowerCase();
87
+ if (type === "image/png" || type === "image/svg+xml") return { [type]: blob };
88
+ return { "image/png": await blobToPng(blob) };
89
+ }
90
+ function resolveDownloadFileName(url, mimeType) {
91
+ const fileName = getFileNameFromUrl(url);
92
+ if (fileName.includes(".")) return fileName.endsWith(".svg+xml") ? fileName.replace(/\.svg\+xml$/i, ".svg") : fileName;
93
+ return `${fileName}.${getExtensionFromMimeType(mimeType)}`;
94
+ }
95
+ function triggerDownload(blob, fileName) {
96
+ const blobUrl = URL.createObjectURL(blob);
97
+ const link = document.createElement("a");
98
+ link.href = blobUrl;
99
+ link.download = fileName;
100
+ link.style.display = "none";
101
+ document.body.appendChild(link);
102
+ link.click();
103
+ link.remove();
104
+ URL.revokeObjectURL(blobUrl);
105
+ }
106
+ const GImagePreview = /* @__PURE__ */ defineComponent((props, { emit, slots, expose }) => {
107
+ const { width: windowWidth, height: windowHeight } = useWindowSize();
108
+ const { prefixCls } = useBaseConfig("pro-image-preview", props);
109
+ const rootCls = useCSSVarCls(prefixCls);
110
+ const [hashId, cssVarCls] = preview_default(prefixCls, rootCls);
111
+ const [openState, setOpenState] = useMergedState(props.open, {
112
+ value: toRef(props, "open"),
113
+ onChange: (value) => {
114
+ props.onOpenChange?.(value);
115
+ emit("update:open", value);
116
+ }
117
+ });
118
+ const enableTransition = ref(true);
119
+ const imageRef = ref();
120
+ const rootRef = ref();
121
+ const currentIndex = ref(props.current ?? 0);
122
+ const copyLoading = ref(false);
123
+ const downloadLoading = ref(false);
124
+ const { transform, resetTransform, updateTransform, dispatchZoomChange } = useImageTransform({
125
+ imageRef,
126
+ minScale: toRef(props, "minScale"),
127
+ maxScale: toRef(props, "maxScale"),
128
+ windowWidth,
129
+ windowHeight,
130
+ onTransform: props.onTransform
131
+ });
132
+ const { isMoving, onMouseDown, onWheel } = useMouseEvent({
133
+ imageRef,
134
+ movable: toRef(props, "movable"),
135
+ visible: openState,
136
+ scaleStep: toRef(props, "scaleStep"),
137
+ transform,
138
+ updateTransform,
139
+ dispatchZoomChange,
140
+ windowWidth,
141
+ windowHeight
142
+ });
143
+ const { isTouching, onTouchStart, onTouchMove, onTouchEnd } = useTouchEvent({
144
+ imageRef,
145
+ movable: toRef(props, "movable"),
146
+ visible: openState,
147
+ minScale: toRef(props, "minScale"),
148
+ transform,
149
+ updateTransform,
150
+ dispatchZoomChange,
151
+ windowWidth,
152
+ windowHeight
153
+ });
154
+ const currentSrc = computed(() => props.urls[currentIndex.value]);
155
+ const showSwitchButtons = computed(() => props.urls.length > 1);
156
+ const showProgress = computed(() => props.urls.length >= 1);
157
+ const maskConfig = computed(() => {
158
+ if (props.mask === false) return {
159
+ visible: false,
160
+ blur: false
161
+ };
162
+ if (props.mask && typeof props.mask === "object" && !("type" in props.mask)) return {
163
+ visible: true,
164
+ blur: props.mask.blur !== false
165
+ };
166
+ return {
167
+ visible: true,
168
+ blur: true
169
+ };
170
+ });
171
+ const bodyStyle = computed(() => {
172
+ const style = {};
173
+ if (props.mousePosition) style.transformOrigin = `${props.mousePosition.x}px ${props.mousePosition.y}px`;
174
+ return style;
175
+ });
176
+ watch(() => props.current, (value) => {
177
+ if (value !== void 0) currentIndex.value = value;
178
+ });
179
+ watch(() => props.current, (value) => {
180
+ if (value !== void 0) currentIndex.value = value;
181
+ });
182
+ const onClose = () => {
183
+ setOpenState(false);
184
+ props.onClose?.();
185
+ emit("close");
186
+ };
187
+ const onMaskClick = () => {
188
+ if (!isMoving.value) onClose();
189
+ };
190
+ const onSwitchPrevious = () => {
191
+ if (currentIndex.value > 0 || props.infinite) {
192
+ const previousIndex = currentIndex.value - 1 < 0 ? props.urls.length - 1 : currentIndex.value - 1;
193
+ enableTransition.value = false;
194
+ currentIndex.value = previousIndex;
195
+ resetTransform("prev");
196
+ nextTick(() => {
197
+ enableTransition.value = true;
198
+ });
199
+ }
200
+ };
201
+ const onSwitchNext = () => {
202
+ if (currentIndex.value < props.urls.length - 1 || props.infinite) {
203
+ const nextIndex = currentIndex.value + 1 > props.urls.length - 1 ? 0 : currentIndex.value + 1;
204
+ enableTransition.value = false;
205
+ currentIndex.value = nextIndex;
206
+ resetTransform("next");
207
+ nextTick(() => {
208
+ enableTransition.value = true;
209
+ });
210
+ }
211
+ };
212
+ const onZoomIn = () => {
213
+ dispatchZoomChange(BASE_SCALE_RATIO + (props.scaleStep ?? .5), "zoomIn");
214
+ };
215
+ const onZoomOut = () => {
216
+ dispatchZoomChange(BASE_SCALE_RATIO / (BASE_SCALE_RATIO + (props.scaleStep ?? .5)), "zoomOut");
217
+ };
218
+ const onRotateRight = () => {
219
+ updateTransform({ rotate: transform.value.rotate + 90 }, "rotateRight");
220
+ };
221
+ const onRotateLeft = () => {
222
+ updateTransform({ rotate: transform.value.rotate - 90 }, "rotateLeft");
223
+ };
224
+ const onFlipX = () => {
225
+ updateTransform({ flipX: !transform.value.flipX }, "flipX");
226
+ };
227
+ const onFlipY = () => {
228
+ updateTransform({ flipY: !transform.value.flipY }, "flipY");
229
+ };
230
+ const onCopy = async () => {
231
+ if (!currentSrc.value || copyLoading.value) return;
232
+ if (!navigator.clipboard || !window.ClipboardItem) {
233
+ message.error(imagePreviewMessages.copyFailed);
234
+ return;
235
+ }
236
+ copyLoading.value = true;
237
+ try {
238
+ const clipboardBlob = await getClipboardBlob(await fetchImageBlob(currentSrc.value));
239
+ await navigator.clipboard.write([new ClipboardItem(clipboardBlob)]);
240
+ message.success(imagePreviewMessages.copySuccess);
241
+ } catch {
242
+ message.error(imagePreviewMessages.copyFailed);
243
+ } finally {
244
+ copyLoading.value = false;
245
+ }
246
+ };
247
+ const onDownload = async () => {
248
+ if (!currentSrc.value || downloadLoading.value) return;
249
+ downloadLoading.value = true;
250
+ try {
251
+ const blob = await fetchImageBlob(currentSrc.value);
252
+ triggerDownload(blob, resolveDownloadFileName(currentSrc.value, blob.type));
253
+ message.success(imagePreviewMessages.downloadSuccess);
254
+ } catch {
255
+ message.error(imagePreviewMessages.downloadFailed);
256
+ } finally {
257
+ downloadLoading.value = false;
258
+ }
259
+ };
260
+ const onDoubleClick = (event) => {
261
+ if (!openState.value) return;
262
+ if (transform.value.scale !== 1) updateTransform({
263
+ x: 0,
264
+ y: 0,
265
+ scale: 1
266
+ }, "doubleClick");
267
+ else dispatchZoomChange(BASE_SCALE_RATIO + (props.scaleStep ?? .5), "doubleClick", event.clientX, event.clientY);
268
+ };
269
+ const onKeyDown = (event) => {
270
+ if (event.key === "Escape") {
271
+ onClose();
272
+ return;
273
+ }
274
+ if (!openState.value || !showSwitchButtons.value) return;
275
+ if (event.key === "ArrowLeft") onSwitchPrevious();
276
+ else if (event.key === "ArrowRight") onSwitchNext();
277
+ };
278
+ let removeKeyListener;
279
+ onMounted(() => {
280
+ const onKeyDownListener = (event) => onKeyDown(event);
281
+ window.addEventListener("keydown", onKeyDownListener);
282
+ removeKeyListener = () => window.removeEventListener("keydown", onKeyDownListener);
283
+ });
284
+ onUnmounted(() => {
285
+ removeKeyListener?.();
286
+ });
287
+ expose({ setOpen: (value) => {
288
+ setOpenState(value);
289
+ currentIndex.value = props.current ?? 0;
290
+ } });
291
+ const resolveSlotProps = () => {
292
+ return getSlotsProps({
293
+ slots,
294
+ props: { ...props.icons },
295
+ keys: [
296
+ "flipY",
297
+ "flipX",
298
+ "rotateLeft",
299
+ "rotateRight",
300
+ "zoomOut",
301
+ "zoomIn",
302
+ "copy",
303
+ "download"
304
+ ],
305
+ render: true,
306
+ defaultVNodes: [
307
+ defaultIcons.flipY,
308
+ defaultIcons.flipX,
309
+ defaultIcons.rotateLeft,
310
+ defaultIcons.rotateRight,
311
+ defaultIcons.zoomOut,
312
+ defaultIcons.zoomIn,
313
+ defaultIcons.copy,
314
+ defaultIcons.download
315
+ ]
316
+ });
317
+ };
318
+ const getToolbarActions = () => {
319
+ const slotProps = resolveSlotProps();
320
+ return [
321
+ {
322
+ icon: slotProps.flipY,
323
+ onClick: onFlipY,
324
+ type: "flipY"
325
+ },
326
+ {
327
+ icon: slotProps.flipX,
328
+ onClick: onFlipX,
329
+ type: "flipX"
330
+ },
331
+ {
332
+ icon: slotProps.rotateLeft,
333
+ onClick: onRotateLeft,
334
+ type: "rotateLeft"
335
+ },
336
+ {
337
+ icon: slotProps.rotateRight,
338
+ onClick: onRotateRight,
339
+ type: "rotateRight"
340
+ },
341
+ {
342
+ icon: slotProps.zoomOut,
343
+ onClick: onZoomOut,
344
+ type: "zoomOut",
345
+ disabled: computed(() => transform.value.scale <= (props.minScale ?? 1))
346
+ },
347
+ {
348
+ icon: slotProps.zoomIn,
349
+ onClick: onZoomIn,
350
+ type: "zoomIn",
351
+ disabled: computed(() => transform.value.scale === (props.maxScale ?? 50))
352
+ },
353
+ {
354
+ icon: copyLoading.value ? createVNode(LoadingOutlined, { "spin": true }, null) : slotProps.copy,
355
+ onClick: onCopy,
356
+ type: "copy",
357
+ disabled: computed(() => copyLoading.value)
358
+ },
359
+ {
360
+ icon: downloadLoading.value ? createVNode(LoadingOutlined, { "spin": true }, null) : slotProps.download,
361
+ onClick: onDownload,
362
+ type: "download",
363
+ disabled: computed(() => downloadLoading.value)
364
+ }
365
+ ];
366
+ };
367
+ return () => {
368
+ const transformStyle = {
369
+ transform: `translate3d(${transform.value.x}px, ${transform.value.y}px, 0) scale3d(${transform.value.flipX ? "-" : ""}${transform.value.scale}, ${transform.value.flipY ? "-" : ""}${transform.value.scale}, 1) rotate(${transform.value.rotate}deg)`,
370
+ transitionDuration: !enableTransition.value || isTouching.value ? "0s" : void 0
371
+ };
372
+ const closeIcon = getSlotVNode({
373
+ slots,
374
+ props: { close: props.icons?.close },
375
+ key: "close"
376
+ });
377
+ const leftIcon = getSlotVNode({
378
+ slots,
379
+ props: { left: props.icons?.left },
380
+ key: "left"
381
+ });
382
+ const rightIcon = getSlotVNode({
383
+ slots,
384
+ props: { right: props.icons?.right },
385
+ key: "right"
386
+ });
387
+ const actionClassName = `${prefixCls.value}-actions-action`;
388
+ const toolbarActions = getToolbarActions();
389
+ return createVNode(Teleport, { "to": props.getContainer || "body" }, { default: () => [createVNode(Transition, {
390
+ "name": `${prefixCls.value}-fade`,
391
+ "appear": true,
392
+ "onAfterLeave": () => resetTransform("close")
393
+ }, { default: () => [openState.value && createVNode("div", {
394
+ "ref": rootRef,
395
+ "class": classNames(prefixCls.value, hashId.value, cssVarCls.value, rootCls.value, {
396
+ [`${prefixCls.value}-movable`]: props.movable,
397
+ [`${prefixCls.value}-moving`]: isMoving.value
398
+ }),
399
+ "style": { zIndex: props.zIndex },
400
+ "role": "dialog",
401
+ "aria-modal": "true",
402
+ "aria-label": "Image",
403
+ "tabindex": -1
404
+ }, [
405
+ maskConfig.value.visible && createVNode("div", {
406
+ "class": classNames(`${prefixCls.value}-mask`, props.maskClass, { [`${prefixCls.value}-mask-blur`]: maskConfig.value.blur }),
407
+ "onClick": props.onHideOnClickModal ? onMaskClick : void 0
408
+ }, null),
409
+ createVNode("div", {
410
+ "class": `${prefixCls.value}-body`,
411
+ "style": bodyStyle.value
412
+ }, [createVNode("img", {
413
+ "ref": imageRef,
414
+ "class": `${prefixCls.value}-img`,
415
+ "src": currentSrc.value,
416
+ "alt": "Image",
417
+ "loading": "eager",
418
+ "decoding": "sync",
419
+ "style": transformStyle,
420
+ "onWheel": onWheel,
421
+ "onMousedown": onMouseDown,
422
+ "onDblclick": onDoubleClick,
423
+ "onTouchstart": onTouchStart,
424
+ "onTouchmove": onTouchMove,
425
+ "onTouchend": onTouchEnd,
426
+ "onTouchcancel": onTouchEnd
427
+ }, null)]),
428
+ createVNode("button", {
429
+ "type": "button",
430
+ "class": `${prefixCls.value}-close`,
431
+ "onClick": onClose
432
+ }, [closeIcon || createVNode(CloseOutlined, null, null)]),
433
+ showSwitchButtons.value && createVNode(Fragment, null, [createVNode("button", {
434
+ "type": "button",
435
+ "class": classNames(`${prefixCls.value}-switch`, `${prefixCls.value}-switch-prev`, { [`${prefixCls.value}-switch-disabled`]: !props.infinite && currentIndex.value === 0 }),
436
+ "onClick": (event) => {
437
+ event.preventDefault();
438
+ event.stopPropagation();
439
+ onSwitchPrevious();
440
+ }
441
+ }, [leftIcon || createVNode(LeftOutlined, null, null)]), createVNode("button", {
442
+ "type": "button",
443
+ "class": classNames(`${prefixCls.value}-switch`, `${prefixCls.value}-switch-next`, { [`${prefixCls.value}-switch-disabled`]: !props.infinite && currentIndex.value === props.urls.length - 1 }),
444
+ "onClick": (event) => {
445
+ event.preventDefault();
446
+ event.stopPropagation();
447
+ onSwitchNext();
448
+ }
449
+ }, [rightIcon || createVNode(RightOutlined, null, null)])]),
450
+ createVNode("div", { "class": `${prefixCls.value}-footer` }, [showProgress.value && createVNode("div", { "class": `${prefixCls.value}-progress` }, [props.countRender ? props.countRender(currentIndex.value + 1, props.urls.length) : `${currentIndex.value + 1} / ${props.urls.length}`]), createVNode("div", { "class": `${prefixCls.value}-actions` }, [toolbarActions.map(({ icon, onClick, type, disabled }) => createVNode("button", {
451
+ "type": "button",
452
+ "class": classNames(actionClassName, `${actionClassName}-${type}`, { [`${actionClassName}-disabled`]: disabled && disabled.value }),
453
+ "onClick": () => {
454
+ if (!disabled?.value) onClick();
455
+ },
456
+ "disabled": disabled ? disabled.value : false,
457
+ "aria-label": type,
458
+ "key": type
459
+ }, [icon]))])])
460
+ ])] })] });
461
+ };
462
+ }, {
463
+ props: /* @__PURE__ */ mergeDefaults({
464
+ class: {
465
+ type: String,
466
+ required: false
467
+ },
468
+ style: {
469
+ type: Object,
470
+ required: false
471
+ },
472
+ rootClass: {
473
+ type: String,
474
+ required: false
475
+ },
476
+ prefixCls: {
477
+ type: String,
478
+ required: false
479
+ },
480
+ urls: {
481
+ type: Array,
482
+ required: true
483
+ },
484
+ open: {
485
+ type: Boolean,
486
+ required: false,
487
+ default: void 0
488
+ },
489
+ scaleStep: {
490
+ type: Number,
491
+ required: false
492
+ },
493
+ minScale: {
494
+ type: Number,
495
+ required: false
496
+ },
497
+ maxScale: {
498
+ type: Number,
499
+ required: false
500
+ },
501
+ movable: {
502
+ type: Boolean,
503
+ required: false,
504
+ default: void 0
505
+ },
506
+ disabled: {
507
+ type: Boolean,
508
+ required: false,
509
+ default: void 0
510
+ },
511
+ zIndex: {
512
+ type: Number,
513
+ required: false
514
+ },
515
+ current: {
516
+ type: Number,
517
+ required: false
518
+ },
519
+ infinite: {
520
+ type: Boolean,
521
+ required: false,
522
+ default: void 0
523
+ },
524
+ getContainer: {
525
+ type: String,
526
+ required: false
527
+ },
528
+ onHideOnClickModal: {
529
+ type: Boolean,
530
+ required: false,
531
+ default: void 0
532
+ },
533
+ mask: {
534
+ type: [Object, Boolean],
535
+ required: false,
536
+ default: void 0
537
+ },
538
+ maskClass: {
539
+ type: String,
540
+ required: false
541
+ },
542
+ mousePosition: {
543
+ type: [Object, null],
544
+ required: false
545
+ },
546
+ countRender: {
547
+ type: [Function, Boolean],
548
+ required: false,
549
+ default: void 0
550
+ },
551
+ icons: {
552
+ type: Object,
553
+ required: false
554
+ },
555
+ onClose: {
556
+ type: Function,
557
+ required: false
558
+ },
559
+ onTransform: {
560
+ type: Function,
561
+ required: false
562
+ },
563
+ onOpenChange: {
564
+ type: Function,
565
+ required: false
566
+ },
567
+ "onUpdate:open": {
568
+ type: Function,
569
+ required: false
570
+ }
571
+ }, {
572
+ open: false,
573
+ scaleStep: .5,
574
+ minScale: 1,
575
+ maxScale: 50,
576
+ movable: true,
577
+ zIndex: 2e3,
578
+ current: 0,
579
+ infinite: true,
580
+ onHideOnClickModal: true,
581
+ urls: [],
582
+ icons: {}
583
+ }),
584
+ emits: [
585
+ "close",
586
+ "transform",
587
+ "update:open"
588
+ ],
589
+ name: "GImagePreview",
590
+ inheritAttrs: false
591
+ });
592
+ //#endregion
593
+ export { GImagePreview as default };