@v-c/image 1.0.7 → 1.0.8
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/Image.d.ts +2 -0
- package/dist/{Image.js → image/src/Image.js} +34 -3
- package/dist/{Preview → image/src/Preview}/Footer.js +5 -2
- package/dist/{Preview → image/src/Preview}/PrevNext.js +10 -8
- package/dist/{Preview → image/src/Preview}/index.js +17 -6
- package/dist/{PreviewGroup.js → image/src/PreviewGroup.js} +1 -1
- package/dist/{common.js → image/src/common.js} +2 -1
- package/dist/{hooks → image/src/hooks}/useImageTransform.js +2 -2
- package/dist/{hooks → image/src/hooks}/useMouseEvent.js +1 -1
- package/dist/{hooks → image/src/hooks}/useTouchEvent.js +1 -1
- package/dist/interface.d.ts +1 -1
- package/dist/util/dist/Dom/focus.js +80 -0
- package/dist/util/dist/Dom/isVisible.js +16 -0
- package/package.json +3 -3
- /package/dist/{Preview → image/src/Preview}/CloseBtn.js +0 -0
- /package/dist/{context.js → image/src/context.js} +0 -0
- /package/dist/{getFixScaleEleTransPosition.js → image/src/getFixScaleEleTransPosition.js} +0 -0
- /package/dist/{hooks → image/src/hooks}/usePreviewItems.js +0 -0
- /package/dist/{hooks → image/src/hooks}/useRegisterImage.js +0 -0
- /package/dist/{hooks → image/src/hooks}/useStatus.js +0 -0
- /package/dist/{index.js → image/src/index.js} +0 -0
- /package/dist/{interface.js → image/src/interface.js} +0 -0
- /package/dist/{previewConfig.js → image/src/previewConfig.js} +0 -0
- /package/dist/{util.js → image/src/util.js} +0 -0
package/dist/Image.d.ts
CHANGED
|
@@ -39,8 +39,10 @@ export interface ImageProps extends Partial<Omit<ImageElementProps, 'src'>> {
|
|
|
39
39
|
preview?: boolean | PreviewConfig;
|
|
40
40
|
onClick?: (e: MouseEvent) => void;
|
|
41
41
|
onError?: (e: Event) => void;
|
|
42
|
+
onKeydown?: (e: KeyboardEvent) => void;
|
|
42
43
|
width?: string | number;
|
|
43
44
|
height?: string | number;
|
|
45
|
+
fetchPriority?: HTMLImageElement['fetchPriority'];
|
|
44
46
|
}
|
|
45
47
|
declare const Image: import('vue').DefineSetupFnComponent<ImageProps, {}, {}, ImageProps & {}, import('vue').PublicProps>;
|
|
46
48
|
export default Image;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { useMergedState } from "./util/dist/hooks/useMergedState.js";
|
|
2
|
-
import { pickAttrs } from "./util/dist/pickAttrs.js";
|
|
3
|
-
import { getAttrStyleAndClass, getStylePxValue } from "./util/dist/props-util/index.js";
|
|
4
1
|
import { COMMON_PROPS } from "./common.js";
|
|
5
2
|
import { usePreviewGroupContext } from "./context.js";
|
|
3
|
+
import { useMergedState } from "../../util/dist/hooks/useMergedState.js";
|
|
4
|
+
import { pickAttrs } from "../../util/dist/pickAttrs.js";
|
|
5
|
+
import { getAttrStyleAndClass, getStylePxValue } from "../../util/dist/props-util/index.js";
|
|
6
6
|
import useRegisterImage from "./hooks/useRegisterImage.js";
|
|
7
7
|
import useStatus from "./hooks/useStatus.js";
|
|
8
8
|
import Preview_default from "./Preview/index.js";
|
|
@@ -69,6 +69,24 @@ var Image_default = /* @__PURE__ */ defineComponent((props, { attrs, slots }) =>
|
|
|
69
69
|
const onImgError = (e) => {
|
|
70
70
|
props.onError?.(e);
|
|
71
71
|
};
|
|
72
|
+
const onPreviewKeyDown = (event) => {
|
|
73
|
+
props.onKeydown?.(event);
|
|
74
|
+
if (!canPreview) return;
|
|
75
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
76
|
+
event.preventDefault();
|
|
77
|
+
const rect = event.target.getBoundingClientRect();
|
|
78
|
+
const left = rect.x + rect.width / 2;
|
|
79
|
+
const top = rect.y + rect.height / 2;
|
|
80
|
+
if (groupContext) groupContext.onPreview(imageId, src.value || "", left, top);
|
|
81
|
+
else {
|
|
82
|
+
mousePosition.value = {
|
|
83
|
+
x: left,
|
|
84
|
+
y: top
|
|
85
|
+
};
|
|
86
|
+
triggerPreviewOpen(true);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
72
90
|
return () => {
|
|
73
91
|
const { width, height } = props;
|
|
74
92
|
const { className, style: attrStyle, restAttrs } = getAttrStyleAndClass(attrs);
|
|
@@ -96,6 +114,10 @@ var Image_default = /* @__PURE__ */ defineComponent((props, { attrs, slots }) =>
|
|
|
96
114
|
return createVNode(Fragment, null, [createVNode("div", mergeProps(pickAttrs(restAttrs, false), {
|
|
97
115
|
"class": rootCls,
|
|
98
116
|
"onClick": canPreview.value ? onPreview : onInternalClick,
|
|
117
|
+
"role": canPreview ? "button" : restAttrs.role,
|
|
118
|
+
"tabindex": canPreview && restAttrs.tabIndex == null ? 0 : restAttrs.tabIndex,
|
|
119
|
+
"aria-label": canPreview ? restAttrs["aria-label"] ?? restAttrs.alt : restAttrs["aria-label"],
|
|
120
|
+
"onKeydown": onPreviewKeyDown,
|
|
99
121
|
"style": rootStyle
|
|
100
122
|
}), [
|
|
101
123
|
createVNode("img", mergeProps(imgCommonProps.value, {
|
|
@@ -203,6 +225,11 @@ var Image_default = /* @__PURE__ */ defineComponent((props, { attrs, slots }) =>
|
|
|
203
225
|
required: false,
|
|
204
226
|
default: void 0
|
|
205
227
|
},
|
|
228
|
+
onKeydown: {
|
|
229
|
+
type: Function,
|
|
230
|
+
required: false,
|
|
231
|
+
default: void 0
|
|
232
|
+
},
|
|
206
233
|
width: {
|
|
207
234
|
type: [String, Number],
|
|
208
235
|
required: false,
|
|
@@ -212,6 +239,10 @@ var Image_default = /* @__PURE__ */ defineComponent((props, { attrs, slots }) =>
|
|
|
212
239
|
type: [String, Number],
|
|
213
240
|
required: false,
|
|
214
241
|
default: void 0
|
|
242
|
+
},
|
|
243
|
+
fetchPriority: {
|
|
244
|
+
required: false,
|
|
245
|
+
default: void 0
|
|
215
246
|
}
|
|
216
247
|
}, {
|
|
217
248
|
prefixCls: "vc-image",
|
|
@@ -3,12 +3,15 @@ import { clsx } from "@v-c/util";
|
|
|
3
3
|
var Footer_default = /* @__PURE__ */ defineComponent((props) => {
|
|
4
4
|
const renderOperation = ({ type, disabled, onClick, icon }) => {
|
|
5
5
|
const actionCls = `${props.prefixCls}-actions-action`;
|
|
6
|
-
return createVNode("
|
|
6
|
+
return createVNode("button", {
|
|
7
|
+
"type": "button",
|
|
7
8
|
"key": type,
|
|
8
9
|
"class": clsx(actionCls, `${actionCls}-${type}`, { [`${actionCls}-disabled`]: !!disabled }),
|
|
9
10
|
"onClick": () => {
|
|
10
11
|
if (!disabled) onClick();
|
|
11
|
-
}
|
|
12
|
+
},
|
|
13
|
+
"disabled": !!disabled,
|
|
14
|
+
"aria-label": type
|
|
12
15
|
}, [icon]);
|
|
13
16
|
};
|
|
14
17
|
return () => {
|
|
@@ -6,17 +6,19 @@ var PrevNext_default = /* @__PURE__ */ defineComponent((props) => {
|
|
|
6
6
|
const switchCls = `${prefixCls}-switch`;
|
|
7
7
|
const prevIcon = icons.prev ?? icons.left;
|
|
8
8
|
const nextIcon = icons.next ?? icons.right;
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
return createVNode(Fragment, null, [createVNode("
|
|
12
|
-
"
|
|
9
|
+
const prevDisabled = current === 0;
|
|
10
|
+
const nextDisabled = current === count - 1;
|
|
11
|
+
return createVNode(Fragment, null, [createVNode("button", {
|
|
12
|
+
"type": "button",
|
|
13
|
+
"class": clsx(switchCls, `${switchCls}-prev`, { [`${switchCls}-disabled`]: prevDisabled }),
|
|
13
14
|
"onClick": () => {
|
|
14
|
-
if (!
|
|
15
|
+
if (!prevDisabled) onActive(-1);
|
|
15
16
|
}
|
|
16
|
-
}, [prevIcon]), createVNode("
|
|
17
|
-
"
|
|
17
|
+
}, [prevIcon]), createVNode("button", {
|
|
18
|
+
"type": "button",
|
|
19
|
+
"class": clsx(switchCls, `${switchCls}-next`, { [`${switchCls}-disabled`]: nextDisabled }),
|
|
18
20
|
"onClick": () => {
|
|
19
|
-
if (!
|
|
21
|
+
if (!nextDisabled) onActive(1);
|
|
20
22
|
}
|
|
21
23
|
}, [nextIcon])]);
|
|
22
24
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { usePreviewGroupContext } from "../context.js";
|
|
2
2
|
import useStatus from "../hooks/useStatus.js";
|
|
3
|
-
import { canUseDom } from "
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { canUseDom } from "../../../util/dist/Dom/canUseDom.js";
|
|
4
|
+
import { useLockFocus } from "../../../util/dist/Dom/focus.js";
|
|
5
|
+
import { KeyCodeStr } from "../../../util/dist/KeyCode.js";
|
|
6
|
+
import { getTransitionProps } from "../../../util/dist/utils/transition.js";
|
|
6
7
|
import useImageTransform from "../hooks/useImageTransform.js";
|
|
7
8
|
import { BASE_SCALE_RATIO } from "../previewConfig.js";
|
|
8
9
|
import useMouseEvent from "../hooks/useMouseEvent.js";
|
|
@@ -15,6 +16,7 @@ import { clsx } from "@v-c/util";
|
|
|
15
16
|
import Portal from "@v-c/portal";
|
|
16
17
|
var Preview_default = /* @__PURE__ */ defineComponent((props, { attrs, slots }) => {
|
|
17
18
|
const imgEl = shallowRef();
|
|
19
|
+
const wrapperRef = shallowRef(null);
|
|
18
20
|
const groupContext = usePreviewGroupContext();
|
|
19
21
|
const showLeftOrRightSwitches = computed(() => !!groupContext && (props.count ?? 1) > 1);
|
|
20
22
|
const showOperationsProgress = computed(() => !!groupContext && (props.count ?? 1) >= 1);
|
|
@@ -112,8 +114,9 @@ var Preview_default = /* @__PURE__ */ defineComponent((props, { attrs, slots })
|
|
|
112
114
|
src: computed(() => props.src),
|
|
113
115
|
fallback: computed(() => props.fallback)
|
|
114
116
|
});
|
|
117
|
+
useLockFocus(portalRender, () => wrapperRef.value);
|
|
115
118
|
return () => {
|
|
116
|
-
const { prefixCls, rootClassName, src, alt, imageInfo, open, closeIcon, getContainer, current = 0, count = 1, countRender, motionName = "fade", imageRender, imgCommonProps, actionsRender = slots?.actionsRender, classNames = {}, styles = {}, mousePosition, zIndex, icons = {} } = props;
|
|
119
|
+
const { prefixCls, rootClassName, src, alt, imageInfo, open, closeIcon, getContainer, current = 0, count = 1, countRender, motionName = "fade", imageRender, imgCommonProps, actionsRender = slots?.actionsRender, classNames = {}, styles = {}, mousePosition, zIndex, icons = {}, movable = true } = props;
|
|
117
120
|
const bodyStyle = { ...styles.body ?? {} };
|
|
118
121
|
if (mousePosition) bodyStyle.transformOrigin = `${mousePosition.x}px ${mousePosition.y}px`;
|
|
119
122
|
const image = {
|
|
@@ -149,7 +152,10 @@ var Preview_default = /* @__PURE__ */ defineComponent((props, { attrs, slots })
|
|
|
149
152
|
...attrs.style
|
|
150
153
|
};
|
|
151
154
|
if (zIndex) mergedRootStyle.zIndex = zIndex;
|
|
152
|
-
const mergedRootCls = clsx(prefixCls, rootClassName, classNames.root, {
|
|
155
|
+
const mergedRootCls = clsx(prefixCls, rootClassName, classNames.root, {
|
|
156
|
+
[`${prefixCls}-movable`]: movable,
|
|
157
|
+
[`${prefixCls}-moving`]: isMoving.value
|
|
158
|
+
});
|
|
153
159
|
const transitionProps = getTransitionProps(motionName);
|
|
154
160
|
return createVNode(Portal, {
|
|
155
161
|
"open": open || animatedVisible.value || portalRender.value,
|
|
@@ -161,8 +167,13 @@ var Preview_default = /* @__PURE__ */ defineComponent((props, { attrs, slots })
|
|
|
161
167
|
}), { default: () => {
|
|
162
168
|
if (!(portalRender.value && open)) return null;
|
|
163
169
|
return createVNode("div", {
|
|
170
|
+
"ref": wrapperRef,
|
|
164
171
|
"class": mergedRootCls,
|
|
165
|
-
"style": mergedRootStyle
|
|
172
|
+
"style": mergedRootStyle,
|
|
173
|
+
"role": "dialog",
|
|
174
|
+
"aria-modal": "true",
|
|
175
|
+
"aria-label": alt,
|
|
176
|
+
"tabindex": -1
|
|
166
177
|
}, [
|
|
167
178
|
createVNode("div", {
|
|
168
179
|
"class": clsx(`${prefixCls}-mask`, classNames.mask),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useMergedState } from "./util/dist/hooks/useMergedState.js";
|
|
2
1
|
import { usePreviewGroupProvider } from "./context.js";
|
|
2
|
+
import { useMergedState } from "../../util/dist/hooks/useMergedState.js";
|
|
3
3
|
import Preview_default from "./Preview/index.js";
|
|
4
4
|
import usePreviewItems from "./hooks/usePreviewItems.js";
|
|
5
5
|
import { Fragment, computed, createVNode, defineComponent, mergeDefaults, mergeProps, shallowRef, toRef, watch } from "vue";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getClientSize } from "../util.js";
|
|
2
|
-
import { isEqual_default } from "
|
|
3
|
-
import { raf_default } from "
|
|
2
|
+
import { isEqual_default } from "../../../util/dist/isEqual.js";
|
|
3
|
+
import { raf_default } from "../../../util/dist/raf.js";
|
|
4
4
|
import { ref, shallowRef } from "vue";
|
|
5
5
|
var initialTransform = {
|
|
6
6
|
x: 0,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { canUseDom } from "../util/dist/Dom/canUseDom.js";
|
|
2
1
|
import getFixScaleEleTransPosition from "../getFixScaleEleTransPosition.js";
|
|
2
|
+
import { canUseDom } from "../../../util/dist/Dom/canUseDom.js";
|
|
3
3
|
import { BASE_SCALE_RATIO, WHEEL_MAX_SCALE_RATIO } from "../previewConfig.js";
|
|
4
4
|
import { shallowRef, watch } from "vue";
|
|
5
5
|
import { warning } from "@v-c/util";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { canUseDom } from "../util/dist/Dom/canUseDom.js";
|
|
2
1
|
import getFixScaleEleTransPosition from "../getFixScaleEleTransPosition.js";
|
|
2
|
+
import { canUseDom } from "../../../util/dist/Dom/canUseDom.js";
|
|
3
3
|
import { shallowRef, watchEffect } from "vue";
|
|
4
4
|
function getDistance(a, b) {
|
|
5
5
|
const x = a.x - b.x;
|
package/dist/interface.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Used for PreviewGroup passed image data
|
|
3
3
|
*/
|
|
4
|
-
export type ImageElementProps = Pick<HTMLImageElement, 'src' | 'crossOrigin' | 'decoding' | 'draggable' | 'loading' | 'referrerPolicy' | 'sizes' | 'srcset' | 'useMap' | 'alt'>;
|
|
4
|
+
export type ImageElementProps = Pick<HTMLImageElement, 'src' | 'crossOrigin' | 'decoding' | 'draggable' | 'loading' | 'referrerPolicy' | 'sizes' | 'srcset' | 'useMap' | 'alt' | 'fetchPriority'>;
|
|
5
5
|
export interface PreviewImageElementProps {
|
|
6
6
|
data: ImageElementProps;
|
|
7
7
|
canPreview: boolean;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { isVisible_default } from "./isVisible.js";
|
|
2
|
+
import { watch } from "vue";
|
|
3
|
+
function focusable(node, includePositive = false) {
|
|
4
|
+
if (isVisible_default(node)) {
|
|
5
|
+
const nodeName = node.nodeName.toLowerCase();
|
|
6
|
+
const isFocusableElement = [
|
|
7
|
+
"input",
|
|
8
|
+
"select",
|
|
9
|
+
"textarea",
|
|
10
|
+
"button"
|
|
11
|
+
].includes(nodeName) || node.isContentEditable || nodeName === "a" && !!node.getAttribute("href");
|
|
12
|
+
const tabIndexAttr = node.getAttribute("tabindex");
|
|
13
|
+
const tabIndexNum = Number(tabIndexAttr);
|
|
14
|
+
let tabIndex = null;
|
|
15
|
+
if (tabIndexAttr && !Number.isNaN(tabIndexNum)) tabIndex = tabIndexNum;
|
|
16
|
+
else if (isFocusableElement && tabIndex === null) tabIndex = 0;
|
|
17
|
+
if (isFocusableElement && node.disabled) tabIndex = null;
|
|
18
|
+
return tabIndex !== null && (tabIndex >= 0 || includePositive && tabIndex < 0);
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
function getFocusNodeList(node, includePositive = false) {
|
|
23
|
+
const res = [...node.querySelectorAll("*")].filter((child) => {
|
|
24
|
+
return focusable(child, includePositive);
|
|
25
|
+
});
|
|
26
|
+
if (focusable(node, includePositive)) res.unshift(node);
|
|
27
|
+
return res;
|
|
28
|
+
}
|
|
29
|
+
var lastFocusElement = null;
|
|
30
|
+
var focusElements = [];
|
|
31
|
+
function getLastElement() {
|
|
32
|
+
return focusElements[focusElements.length - 1];
|
|
33
|
+
}
|
|
34
|
+
function hasFocus(element) {
|
|
35
|
+
const { activeElement } = document;
|
|
36
|
+
return element === activeElement || element.contains(activeElement);
|
|
37
|
+
}
|
|
38
|
+
function syncFocus() {
|
|
39
|
+
const lastElement = getLastElement();
|
|
40
|
+
const { activeElement } = document;
|
|
41
|
+
if (lastElement && !hasFocus(lastElement)) {
|
|
42
|
+
const focusableList = getFocusNodeList(lastElement);
|
|
43
|
+
(focusableList.includes(lastFocusElement) ? lastFocusElement : focusableList[0])?.focus();
|
|
44
|
+
} else lastFocusElement = activeElement;
|
|
45
|
+
}
|
|
46
|
+
function onWindowKeyDown(e) {
|
|
47
|
+
if (e.key === "Tab") {
|
|
48
|
+
const { activeElement } = document;
|
|
49
|
+
const focusableList = getFocusNodeList(getLastElement());
|
|
50
|
+
const last = focusableList[focusableList.length - 1];
|
|
51
|
+
if (e.shiftKey && activeElement === focusableList[0]) lastFocusElement = last;
|
|
52
|
+
else if (!e.shiftKey && activeElement === last) lastFocusElement = focusableList[0];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function lockFocus(element) {
|
|
56
|
+
if (element) {
|
|
57
|
+
focusElements = focusElements.filter((ele) => ele !== element);
|
|
58
|
+
focusElements.push(element);
|
|
59
|
+
window.addEventListener("focusin", syncFocus);
|
|
60
|
+
window.addEventListener("keydown", onWindowKeyDown, true);
|
|
61
|
+
syncFocus();
|
|
62
|
+
}
|
|
63
|
+
return () => {
|
|
64
|
+
lastFocusElement = null;
|
|
65
|
+
focusElements = focusElements.filter((ele) => ele !== element);
|
|
66
|
+
if (focusElements.length === 0) {
|
|
67
|
+
window.removeEventListener("focusin", syncFocus);
|
|
68
|
+
window.removeEventListener("keydown", onWindowKeyDown, true);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function useLockFocus(lock, getElement) {
|
|
73
|
+
watch(lock, (_, _o, onCleanup) => {
|
|
74
|
+
if (lock.value) {
|
|
75
|
+
const element = getElement();
|
|
76
|
+
if (element) onCleanup(lockFocus(element));
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
export { useLockFocus };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
var isVisible_default = (element) => {
|
|
2
|
+
if (!element) return false;
|
|
3
|
+
if (element instanceof Element) {
|
|
4
|
+
if (element.offsetParent) return true;
|
|
5
|
+
if (element.getBBox) {
|
|
6
|
+
const { width, height } = element.getBBox();
|
|
7
|
+
if (width || height) return true;
|
|
8
|
+
}
|
|
9
|
+
if (element.getBoundingClientRect) {
|
|
10
|
+
const { width, height } = element.getBoundingClientRect();
|
|
11
|
+
if (width || height) return true;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return false;
|
|
15
|
+
};
|
|
16
|
+
export { isVisible_default };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@v-c/image",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.8",
|
|
5
5
|
"description": "image component",
|
|
6
6
|
"author": "",
|
|
7
7
|
"license": "MIT",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"vue": "^3.0.0"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@v-c/
|
|
36
|
-
"@v-c/
|
|
35
|
+
"@v-c/portal": "^1.0.8",
|
|
36
|
+
"@v-c/util": "^1.0.19"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@ant-design/icons-vue": "^7.0.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|