@gx-design-vue/image 0.1.1 → 0.2.0-alpha.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 (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +71 -7
  3. package/dist/GImage.d.ts +162 -0
  4. package/dist/GImage.js +221 -0
  5. package/dist/ImagePreview/Operations.d.ts +83 -0
  6. package/dist/ImagePreview/Operations.js +71 -0
  7. package/dist/ImagePreview/hooks/getFixScaleEleTransPosition.d.ts +19 -0
  8. package/dist/ImagePreview/hooks/getFixScaleEleTransPosition.js +40 -0
  9. package/dist/ImagePreview/hooks/useImageTransform.d.ts +39 -0
  10. package/dist/ImagePreview/hooks/useImageTransform.js +105 -0
  11. package/dist/ImagePreview/hooks/useMouseEvent.d.ts +14 -0
  12. package/dist/ImagePreview/hooks/useMouseEvent.js +100 -0
  13. package/dist/ImagePreview/hooks/useTouchEvent.d.ts +12 -0
  14. package/dist/ImagePreview/hooks/useTouchEvent.js +123 -0
  15. package/dist/ImagePreview/index.d.ts +162 -0
  16. package/dist/ImagePreview/index.js +303 -0
  17. package/dist/ImagePreview/props.d.ts +88 -0
  18. package/dist/ImagePreview/props.js +53 -0
  19. package/dist/ImagePreview/style.d.ts +30 -0
  20. package/dist/ImagePreview/style.js +286 -0
  21. package/dist/ImagePreview/typings.d.ts +19 -0
  22. package/dist/ImagePreview/typings.js +1 -0
  23. package/dist/ImagePreview/utils/KeyCode.d.ts +438 -0
  24. package/dist/ImagePreview/utils/KeyCode.js +173 -0
  25. package/dist/ImagePreview/utils/addEventListener.d.ts +6 -0
  26. package/dist/ImagePreview/utils/addEventListener.js +22 -0
  27. package/dist/ImagePreview/utils/util.d.ts +7 -0
  28. package/dist/ImagePreview/utils/util.js +8 -0
  29. package/dist/hooks/useFrameSetState.d.ts +5 -0
  30. package/dist/hooks/useFrameSetState.js +33 -0
  31. package/dist/image.esm.js +2374 -0
  32. package/dist/image.js +1 -0
  33. package/dist/index.d.ts +5 -7
  34. package/dist/index.js +6 -0
  35. package/dist/props.d.ts +82 -77
  36. package/dist/props.js +66 -0
  37. package/dist/slots.d.ts +6 -0
  38. package/dist/slots.js +21 -0
  39. package/dist/style.d.ts +9 -0
  40. package/dist/style.js +78 -0
  41. package/dist/typings.d.ts +6 -0
  42. package/dist/typings.js +1 -0
  43. package/dist/utils/aria.d.ts +14 -11
  44. package/dist/utils/aria.js +16 -0
  45. package/dist/utils/util.d.ts +4 -0
  46. package/dist/utils/util.js +8 -0
  47. package/global.d.ts +8 -0
  48. package/package.json +57 -60
  49. package/dist/Image.d.ts +0 -130
  50. package/dist/components/ImageViewer.d.ts +0 -59
  51. package/dist/components/ImageViewerGroup.d.ts +0 -14
  52. package/dist/design/config.less +0 -2
  53. package/dist/image.es.js +0 -801
  54. package/dist/image.umd.js +0 -1
  55. package/dist/style.css +0 -1
  56. package/dist/style.less +0 -177
@@ -0,0 +1,303 @@
1
+ import useImageTransform from "./hooks/useImageTransform.js";
2
+ import addEventListenerWrap from "./utils/addEventListener.js";
3
+ import { BASE_SCALE_RATIO } from "./utils/util.js";
4
+ import useMouseEvent from "./hooks/useMouseEvent.js";
5
+ import useTouchEvent from "./hooks/useTouchEvent.js";
6
+ import props_default from "./props.js";
7
+ import Operations_default from "./Operations.js";
8
+ import { useStyle as useStyle$1 } from "./style.js";
9
+ import KeyCode_default from "./utils/KeyCode.js";
10
+ import { Fragment, Teleport, Transition, computed, createVNode, defineComponent, mergeProps, onMounted, onUnmounted, reactive, ref, toRef, vShow, watch, withDirectives } from "vue";
11
+ import { RotateLeftOutlined, RotateRightOutlined, SwapOutlined, ZoomInOutlined, ZoomOutOutlined } from "@ant-design/icons-vue";
12
+ import { getTransitionProps } from "@gx-design-vue/pro-provider";
13
+ import { getPrefixCls, getSlot, getSlotVNode, getSlotsProps, isArray, isNumber } from "@gx-design-vue/pro-utils";
14
+ import { omit } from "es-toolkit";
15
+ import { useEffect, useMergedState, useState } from "@gx-design-vue/pro-hooks";
16
+
17
+ //#region src/ImagePreview/index.tsx
18
+ const defaultIcons = {
19
+ rotateLeft: createVNode(RotateLeftOutlined, null, null),
20
+ rotateRight: createVNode(RotateRightOutlined, null, null),
21
+ zoomIn: createVNode(ZoomInOutlined, null, null),
22
+ zoomOut: createVNode(ZoomOutOutlined, null, null),
23
+ flipX: createVNode(SwapOutlined, null, null),
24
+ flipY: createVNode(SwapOutlined, { "rotate": 90 }, null)
25
+ };
26
+ const GImagePreview = /* @__PURE__ */ defineComponent({
27
+ name: "GImagePreview",
28
+ props: props_default,
29
+ inheritAttrs: false,
30
+ slots: Object,
31
+ emits: {
32
+ close: () => true,
33
+ transform: (_info) => true,
34
+ "update:open": (_val) => true
35
+ },
36
+ setup: (props, { emit, expose, slots }) => {
37
+ const baseClassName = getPrefixCls({ suffixCls: "image-view" });
38
+ const { wrapSSR, hashId } = useStyle$1(baseClassName);
39
+ const [_, setOpen, innerOpen] = useMergedState(props.open, {
40
+ value: toRef(props, "open"),
41
+ onChange: (val) => {
42
+ props.onOpenChange?.(val);
43
+ emit("update:open", val);
44
+ }
45
+ });
46
+ const [animate, setAnimate] = useState(false);
47
+ const [enableTransition, setEnableTransition] = useState(true);
48
+ const imgRef = ref();
49
+ const { transform, resetTransform, updateTransform, dispatchZoomChange } = useImageTransform(imgRef, toRef(props, "minScale"), toRef(props, "maxScale"), props.onTransform);
50
+ const { isMoving, onMouseDown, onWheel } = useMouseEvent(imgRef, toRef(props, "movable"), innerOpen, toRef(props, "scaleStep"), transform, updateTransform, dispatchZoomChange);
51
+ const { isTouching, onTouchStart, onTouchMove, onTouchEnd } = useTouchEvent(imgRef, toRef(props, "movable"), innerOpen, toRef(props, "minScale"), transform, updateTransform, dispatchZoomChange);
52
+ useEffect(() => {
53
+ if (!enableTransition.value) setEnableTransition(true);
54
+ }, [enableTransition]);
55
+ const wrapper = ref(null);
56
+ const current = ref(props.current);
57
+ const urls = reactive(/* @__PURE__ */ new Map());
58
+ const canPreviewUrls = computed(() => new Map(Array.from(urls).map(([id, { url }]) => [id, url])));
59
+ const currentSrc = computed(() => canPreviewUrls.value.get(current.value));
60
+ const previewGroupCount = computed(() => canPreviewUrls.value.size);
61
+ const urlsKeys = computed(() => Array.from(canPreviewUrls.value.keys()));
62
+ const currentPreviewIndex = computed(() => urlsKeys.value.indexOf(current.value));
63
+ const showLeftOrRightSwitches = computed(() => previewGroupCount.value > 1);
64
+ const showOperationsProgress = computed(() => previewGroupCount.value >= 1);
65
+ watch(innerOpen, (val) => {
66
+ if (val) animate.value = true;
67
+ });
68
+ const setCurrent = (val) => {
69
+ current.value = val;
70
+ };
71
+ watch(() => props.current, (val) => {
72
+ if (isNumber(val)) setCurrent(val);
73
+ });
74
+ function registerImage(id, url) {
75
+ urls.set(id, {
76
+ url,
77
+ loading: true,
78
+ canPreview: false
79
+ });
80
+ }
81
+ const onClose = () => {
82
+ setAnimate(false);
83
+ };
84
+ const onAnimateChange = () => {
85
+ resetTransform("close");
86
+ emit("close");
87
+ };
88
+ const hideMask = (e) => {
89
+ if (isMoving.value) return;
90
+ if (wrapper.value === e?.target) onClose();
91
+ };
92
+ const handleImgLoad = () => {
93
+ const currentImage = urls.get(current.value);
94
+ if (currentImage) {
95
+ currentImage.loading = false;
96
+ currentImage.canPreview = true;
97
+ }
98
+ };
99
+ const handleImgError = (e) => {
100
+ const currentImage = urls.get(current.value);
101
+ if (currentImage) {
102
+ currentImage.loading = false;
103
+ currentImage.canPreview = false;
104
+ }
105
+ e.target.alt = "加载失败";
106
+ };
107
+ const onSwitchLeft = () => {
108
+ if (currentPreviewIndex.value > 0 || props.infinite) {
109
+ const prevIndex = currentPreviewIndex.value - 1 < 0 ? props.urls.length - 1 : currentPreviewIndex.value - 1;
110
+ setCurrent(urlsKeys.value[prevIndex]);
111
+ resetTransform("prev");
112
+ }
113
+ };
114
+ const onSwitchRight = () => {
115
+ if (currentPreviewIndex.value < previewGroupCount.value - 1 || props.infinite) {
116
+ const nextIndex = currentPreviewIndex.value + 1 > props.urls.length - 1 ? 0 : currentPreviewIndex.value + 1;
117
+ setCurrent(urlsKeys.value[nextIndex]);
118
+ resetTransform("next");
119
+ }
120
+ };
121
+ const onZoomIn = () => {
122
+ dispatchZoomChange(BASE_SCALE_RATIO + props.scaleStep, "zoomIn");
123
+ };
124
+ const onZoomOut = () => {
125
+ dispatchZoomChange(BASE_SCALE_RATIO / (BASE_SCALE_RATIO + props.scaleStep), "zoomOut");
126
+ };
127
+ const onRotateRight = () => {
128
+ updateTransform({ rotate: transform.value.rotate + 90 }, "rotateRight");
129
+ };
130
+ const onRotateLeft = () => {
131
+ updateTransform({ rotate: transform.value.rotate - 90 }, "rotateLeft");
132
+ };
133
+ const onFlipX = () => {
134
+ updateTransform({ flipX: !transform.value.flipX }, "flipX");
135
+ };
136
+ const onFlipY = () => {
137
+ updateTransform({ flipY: !transform.value.flipY }, "flipY");
138
+ };
139
+ const toolsFn = () => {
140
+ const slotsProps = getSlotsProps({
141
+ slots,
142
+ props: props.icons,
143
+ keys: [
144
+ "flipY",
145
+ "flipX",
146
+ "rotateLeft",
147
+ "rotateRight",
148
+ "zoomOut",
149
+ "zoomIn"
150
+ ],
151
+ render: true,
152
+ defaultVNodes: [
153
+ defaultIcons.flipY,
154
+ defaultIcons.flipX,
155
+ defaultIcons.rotateLeft,
156
+ defaultIcons.rotateRight,
157
+ defaultIcons.zoomOut,
158
+ defaultIcons.zoomIn
159
+ ]
160
+ });
161
+ return [
162
+ {
163
+ icon: slotsProps.flipY,
164
+ onClick: onFlipY,
165
+ type: "flipY"
166
+ },
167
+ {
168
+ icon: slotsProps.flipX,
169
+ onClick: onFlipX,
170
+ type: "flipX"
171
+ },
172
+ {
173
+ icon: slotsProps.rotateLeft,
174
+ onClick: onRotateLeft,
175
+ type: "rotateLeft"
176
+ },
177
+ {
178
+ icon: slotsProps.rotateRight,
179
+ onClick: onRotateRight,
180
+ type: "rotateRight"
181
+ },
182
+ {
183
+ icon: slotsProps.zoomOut,
184
+ onClick: () => onZoomOut(),
185
+ type: "zoomOut",
186
+ disabled: computed(() => transform.value.scale <= props.minScale)
187
+ },
188
+ {
189
+ icon: slotsProps.zoomIn,
190
+ onClick: () => onZoomIn(),
191
+ type: "zoomIn",
192
+ disabled: computed(() => transform.value.scale === props.maxScale)
193
+ }
194
+ ];
195
+ };
196
+ const onDoubleClick = (event) => {
197
+ if (innerOpen.value) if (transform.value.scale !== 1) updateTransform({
198
+ x: 0,
199
+ y: 0,
200
+ scale: 1
201
+ }, "doubleClick");
202
+ else dispatchZoomChange(BASE_SCALE_RATIO + props.scaleStep, "doubleClick", event.clientX, event.clientY);
203
+ };
204
+ const onKeyDown = (event) => {
205
+ if (event.keyCode === KeyCode_default.ESC) onClose();
206
+ if (!innerOpen.value || !showLeftOrRightSwitches.value) return;
207
+ if (event.keyCode === KeyCode_default.LEFT) onSwitchLeft();
208
+ else if (event.keyCode === KeyCode_default.RIGHT) onSwitchRight();
209
+ };
210
+ let removeListeners = () => {};
211
+ onMounted(() => {
212
+ watch(() => props.urls, (val) => {
213
+ if (isArray(val)) val.forEach((src, currentId) => {
214
+ registerImage(currentId, src);
215
+ });
216
+ }, {
217
+ flush: "post",
218
+ immediate: true
219
+ });
220
+ watch([() => innerOpen.value, () => isMoving.value], () => {
221
+ removeListeners();
222
+ const onKeyDownListener = addEventListenerWrap(window, "keydown", onKeyDown, false);
223
+ removeListeners = () => {
224
+ onKeyDownListener.remove();
225
+ };
226
+ }, {
227
+ flush: "post",
228
+ immediate: true
229
+ });
230
+ });
231
+ onUnmounted(() => {
232
+ removeListeners();
233
+ });
234
+ expose({ setOpen: (val) => {
235
+ setOpen(val);
236
+ current.value = props.current;
237
+ } });
238
+ return () => {
239
+ const transitionProps = getTransitionProps(`${baseClassName}-mask-zoom`);
240
+ const zoomTransitionProps = getTransitionProps(`${baseClassName}-zoom`);
241
+ const icons = {};
242
+ for (const key in props.icons) icons[key] = getSlotVNode({
243
+ slots,
244
+ props: props.icons,
245
+ key
246
+ });
247
+ return wrapSSR(createVNode(Fragment, null, [createVNode(Teleport, { "to": props.getContainer || "body" }, { default: () => [innerOpen.value && createVNode(Fragment, null, [createVNode("div", { "class": `${baseClassName}-root ${hashId.value}` }, [createVNode(Transition, transitionProps, { default: () => [withDirectives(createVNode("div", { "class": `${baseClassName}-mask ${hashId.value}` }, null), [[vShow, innerOpen.value && animate.value]])] }), createVNode("div", {
248
+ "ref": wrapper,
249
+ "tabindex": -1,
250
+ "class": [
251
+ `${baseClassName}-wrap`,
252
+ `${hashId.value}`,
253
+ isMoving.value && `${baseClassName}-moving`
254
+ ],
255
+ "onClick": (e) => props.onHideOnClickModal && hideMask(e)
256
+ }, [createVNode(Transition, mergeProps(zoomTransitionProps, { "onAfterLeave": () => onAnimateChange() }), { default: () => [withDirectives(createVNode("div", {
257
+ "role": "dialog",
258
+ "class": `${baseClassName} ${hashId.value}`
259
+ }, [createVNode("div", { "class": `${baseClassName}-content ${hashId.value}` }, [createVNode("div", { "class": `${baseClassName}-body ${hashId.value}` }, [createVNode("div", { "class": `${baseClassName}-img-wrapper ${hashId.value}` }, [createVNode("img", {
260
+ "ref": imgRef,
261
+ "class": `${baseClassName}-img ${hashId.value}`,
262
+ "src": currentSrc.value,
263
+ "onLoad": () => handleImgLoad(),
264
+ "onError": (e) => handleImgError(e),
265
+ "style": {
266
+ 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)`,
267
+ transitionDuration: !enableTransition.value || isTouching.value ? "0s" : void 0
268
+ },
269
+ "onWheel": onWheel,
270
+ "onMousedown": onMouseDown,
271
+ "onDblclick": onDoubleClick,
272
+ "onTouchstart": onTouchStart,
273
+ "onTouchmove": onTouchMove,
274
+ "onTouchend": onTouchEnd,
275
+ "onTouchcancel": onTouchEnd
276
+ }, null)])])])]), [[vShow, innerOpen.value && animate.value]])] })])])])] }), innerOpen.value && animate.value && createVNode(Operations_default, {
277
+ "open": innerOpen.value && animate.value,
278
+ "hashId": hashId.value,
279
+ "count": props.urls.length,
280
+ "current": current.value,
281
+ "zIndex": props.zIndex + 1,
282
+ "getContainer": props.getContainer,
283
+ "prefixCls": baseClassName,
284
+ "icons": omit(icons, toolsFn().map(({ type }) => type)),
285
+ "tools": toolsFn(),
286
+ "infinite": props.infinite,
287
+ "countRender": getSlot({
288
+ slots,
289
+ props,
290
+ key: "countRender"
291
+ }),
292
+ "showSwitch": showLeftOrRightSwitches.value,
293
+ "showProgress": showOperationsProgress.value,
294
+ "onClose": onClose,
295
+ "onActive": (effect) => effect > 0 ? onSwitchRight() : onSwitchLeft()
296
+ }, null)]));
297
+ };
298
+ }
299
+ });
300
+ var ImagePreview_default = GImagePreview;
301
+
302
+ //#endregion
303
+ export { ImagePreview_default as default };
@@ -0,0 +1,88 @@
1
+ import { TransformAction, TransformType } from "./hooks/useImageTransform.js";
2
+ import { PropType, VNode } from "vue";
3
+ import { CustomRender, WithFalse } from "@gx-design-vue/pro-utils";
4
+
5
+ //#region src/ImagePreview/props.d.ts
6
+ interface PreviewPropsIcons {
7
+ close?: WithFalse<CustomRender>;
8
+ rotateLeft?: WithFalse<CustomRender>;
9
+ rotateRight?: WithFalse<CustomRender>;
10
+ zoomIn?: WithFalse<CustomRender>;
11
+ zoomOut?: WithFalse<CustomRender>;
12
+ left?: WithFalse<CustomRender>;
13
+ right?: WithFalse<CustomRender>;
14
+ flipX?: WithFalse<CustomRender>;
15
+ flipY?: WithFalse<CustomRender>;
16
+ }
17
+ type BaseImagePreviewProps = Partial<{
18
+ urls: string[];
19
+ mask: VNode | boolean;
20
+ maskClass: string;
21
+ disabled: boolean;
22
+ zIndex: number;
23
+ current: number;
24
+ infinite: boolean;
25
+ getContainer: string;
26
+ onHideOnClickModal: boolean;
27
+ countRender: WithFalse<(current: number, total: number) => CustomRender>;
28
+ icons: PreviewPropsIcons;
29
+ }>;
30
+ declare const _default: {
31
+ urls: {
32
+ type: PropType<string[]>;
33
+ default: () => any[];
34
+ };
35
+ open: {
36
+ type: PropType<boolean>;
37
+ default: boolean;
38
+ };
39
+ scaleStep: {
40
+ type: PropType<number>;
41
+ default: number;
42
+ };
43
+ minScale: {
44
+ type: PropType<number>;
45
+ default: number;
46
+ };
47
+ maxScale: {
48
+ type: PropType<number>;
49
+ default: number;
50
+ };
51
+ movable: {
52
+ type: PropType<boolean>;
53
+ default: boolean;
54
+ };
55
+ disabled: PropType<boolean>;
56
+ zIndex: {
57
+ type: PropType<number>;
58
+ default: number;
59
+ };
60
+ current: {
61
+ type: PropType<number>;
62
+ default: number;
63
+ };
64
+ infinite: {
65
+ type: PropType<boolean>;
66
+ default: boolean;
67
+ };
68
+ getContainer: {
69
+ type: PropType<string>;
70
+ };
71
+ onHideOnClickModal: {
72
+ type: PropType<boolean>;
73
+ default: boolean;
74
+ };
75
+ countRender: PropType<WithFalse<(current: number, total: number) => CustomRender>>;
76
+ icons: {
77
+ type: PropType<PreviewPropsIcons>;
78
+ default: () => PreviewPropsIcons;
79
+ };
80
+ onTransform: PropType<(info: {
81
+ transform: TransformType;
82
+ action: TransformAction;
83
+ }) => void>;
84
+ onOpenChange: PropType<(val: boolean) => void>;
85
+ 'onUpdate:open': PropType<(val: boolean) => void>;
86
+ };
87
+ //#endregion
88
+ export { BaseImagePreviewProps, PreviewPropsIcons, _default as default };
@@ -0,0 +1,53 @@
1
+ import { baseProps } from "../props.js";
2
+
3
+ //#region src/ImagePreview/props.ts
4
+ var props_default = {
5
+ urls: {
6
+ type: Array,
7
+ default: () => []
8
+ },
9
+ open: {
10
+ type: Boolean,
11
+ default: false
12
+ },
13
+ scaleStep: {
14
+ type: Number,
15
+ default: .5
16
+ },
17
+ minScale: {
18
+ type: Number,
19
+ default: .32
20
+ },
21
+ maxScale: {
22
+ type: Number,
23
+ default: 32
24
+ },
25
+ movable: {
26
+ type: Boolean,
27
+ default: true
28
+ },
29
+ disabled: Boolean,
30
+ zIndex: baseProps.zIndex,
31
+ current: baseProps.current,
32
+ infinite: baseProps.infinite,
33
+ getContainer: baseProps.getContainer,
34
+ onHideOnClickModal: {
35
+ type: Boolean,
36
+ default: true
37
+ },
38
+ countRender: [
39
+ Function,
40
+ Array,
41
+ Object
42
+ ],
43
+ icons: {
44
+ type: Object,
45
+ default: () => ({})
46
+ },
47
+ onTransform: Function,
48
+ onOpenChange: Function,
49
+ "onUpdate:open": Function
50
+ };
51
+
52
+ //#endregion
53
+ export { props_default as default };
@@ -0,0 +1,30 @@
1
+ import * as vue0 from "vue";
2
+ import { CSSObject, Keyframe, ProAliasToken } from "@gx-design-vue/pro-provider";
3
+ import * as ant_design_vue_es__util_type0 from "ant-design-vue/es/_util/type";
4
+
5
+ //#region src/ImagePreview/style.d.ts
6
+ interface ImageToken extends ProAliasToken {
7
+ previewCls: string;
8
+ zIndexPopup: number;
9
+ previewOperationSize: number;
10
+ modalMaskBg: string;
11
+ componentCls: string;
12
+ iconCls: string;
13
+ previewOperationHoverColor: string;
14
+ previewOperationColor: string;
15
+ imagePreviewSwitchSize: number;
16
+ previewOperationColorDisabled: string;
17
+ }
18
+ declare const viewFadeIn: Keyframe;
19
+ declare const viewFadeOut: Keyframe;
20
+ type PositionType = 'static' | 'relative' | 'fixed' | 'absolute' | 'sticky' | undefined;
21
+ declare function genBoxStyle(position?: PositionType): CSSObject;
22
+ declare function resetComponent(token: ProAliasToken): CSSObject;
23
+ declare function genPreviewOperationsStyle(token: ImageToken): CSSObject;
24
+ declare function genPreviewSwitchStyle(token: ImageToken): CSSObject;
25
+ declare function useStyle(componentCls: string): {
26
+ wrapSSR: (node: ant_design_vue_es__util_type0.VueNode) => ant_design_vue_es__util_type0.VueNode;
27
+ hashId: vue0.ComputedRef<string>;
28
+ };
29
+ //#endregion
30
+ export { ImageToken, PositionType, genBoxStyle, genPreviewOperationsStyle, genPreviewSwitchStyle, resetComponent, useStyle, viewFadeIn, viewFadeOut };