@canlooks/can-ui 0.0.121 → 0.0.123
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/cjs/components/gallery/gallery.d.ts +3 -1
- package/dist/cjs/components/gallery/gallery.js +110 -47
- package/dist/cjs/components/gallery/gallery.style.js +7 -11
- package/dist/cjs/components/gallery/imageItem.d.ts +5 -2
- package/dist/cjs/components/gallery/imageItem.js +6 -4
- package/dist/cjs/components/pinchable/pinchable.d.ts +7 -1
- package/dist/cjs/components/pinchable/pinchable.js +20 -8
- package/dist/cjs/components/pinchable/pinchable.style.js +8 -2
- package/dist/cjs/utils/bezier.d.ts +4 -3
- package/dist/cjs/utils/bezier.js +1 -1
- package/dist/cjs/utils/dnd.d.ts +9 -0
- package/dist/cjs/utils/dnd.js +16 -0
- package/dist/cjs/utils/style.js +8 -6
- package/dist/esm/components/gallery/gallery.d.ts +3 -1
- package/dist/esm/components/gallery/gallery.js +111 -48
- package/dist/esm/components/gallery/gallery.style.js +7 -11
- package/dist/esm/components/gallery/imageItem.d.ts +5 -2
- package/dist/esm/components/gallery/imageItem.js +7 -5
- package/dist/esm/components/pinchable/pinchable.d.ts +7 -1
- package/dist/esm/components/pinchable/pinchable.js +21 -9
- package/dist/esm/components/pinchable/pinchable.style.js +8 -2
- package/dist/esm/utils/bezier.d.ts +4 -3
- package/dist/esm/utils/bezier.js +1 -1
- package/dist/esm/utils/dnd.d.ts +9 -0
- package/dist/esm/utils/dnd.js +15 -0
- package/dist/esm/utils/style.js +8 -6
- package/package.json +1 -1
|
@@ -15,6 +15,8 @@ export interface ImagePreviewProps extends ModalProps {
|
|
|
15
15
|
showClose?: boolean;
|
|
16
16
|
/** 自定义渲染控制按钮 */
|
|
17
17
|
renderControl?: ReactNode;
|
|
18
|
+
/** 拖拽至最边缘时,是否允许弹性溢出,默认为`true` */
|
|
19
|
+
allowEdgeBounce?: boolean;
|
|
18
20
|
/** 元素弹性移动距离,默认为24 */
|
|
19
21
|
bounceElementTranslate?: number;
|
|
20
22
|
/** 手指弹性拖拽距离,默认为240 */
|
|
@@ -22,4 +24,4 @@ export interface ImagePreviewProps extends ModalProps {
|
|
|
22
24
|
/** 滑动生效的速度,默认为450 (px/s) */
|
|
23
25
|
effectiveSpeed?: number;
|
|
24
26
|
}
|
|
25
|
-
export declare const Gallery: import("react").MemoExoticComponent<({ src, defaultIndex, index, onIndexChange, defaultOpen, open, onOpenChange, showRotation, showZoom, showClose, renderControl, bounceElementTranslate, bounceDragDistance, effectiveSpeed, ...props }: ImagePreviewProps) => import("@emotion/react/jsx-runtime").JSX.Element>;
|
|
27
|
+
export declare const Gallery: import("react").MemoExoticComponent<({ src, defaultIndex, index, onIndexChange, defaultOpen, open, onOpenChange, showRotation, showZoom, showClose, renderControl, allowEdgeBounce, bounceElementTranslate, bounceDragDistance, effectiveSpeed, ...props }: ImagePreviewProps) => import("@emotion/react/jsx-runtime").JSX.Element>;
|
|
@@ -24,94 +24,152 @@ const commonControlProps = {
|
|
|
24
24
|
size: 'large',
|
|
25
25
|
color: 'text'
|
|
26
26
|
};
|
|
27
|
-
const
|
|
28
|
-
exports.Gallery = (0, react_1.memo)(({ src, defaultIndex = 0, index, onIndexChange, defaultOpen = false, open, onOpenChange, showRotation = true, showZoom = true, showClose = true, renderControl, bounceElementTranslate = 24, bounceDragDistance = 240, effectiveSpeed = 450, ...props }) => {
|
|
27
|
+
const DOUBLE_CLICK_DELAY = 300;
|
|
28
|
+
exports.Gallery = (0, react_1.memo)(({ src, defaultIndex = 0, index, onIndexChange, defaultOpen = false, open, onOpenChange, showRotation = true, showZoom = true, showClose = true, renderControl, allowEdgeBounce = true, bounceElementTranslate = 24, bounceDragDistance = 240, effectiveSpeed = 450, ...props }) => {
|
|
29
29
|
const srcArr = (0, utils_1.useSync)((0, utils_1.toArray)(src || []));
|
|
30
30
|
const [innerOpen, setInnerOpen] = (0, utils_1.useControlled)(defaultOpen, open, onOpenChange);
|
|
31
31
|
const close = () => {
|
|
32
32
|
setInnerOpen(false);
|
|
33
33
|
};
|
|
34
34
|
const [innerIndex, setInnerIndex] = (0, utils_1.useControlled)(defaultIndex, index, onIndexChange);
|
|
35
|
+
const maskRef = (0, react_1.useRef)(null);
|
|
35
36
|
const wrapperRef = (0, react_1.useRef)(null);
|
|
36
37
|
const imageItemRefs = (0, react_1.useRef)([]);
|
|
37
38
|
imageItemRefs.current = [];
|
|
39
|
+
const imgRefs = (0, react_1.useRef)([]);
|
|
40
|
+
imgRefs.current = [];
|
|
38
41
|
/**
|
|
39
42
|
* --------------------------------------------------------------
|
|
40
43
|
* 左右滚动翻页
|
|
41
44
|
*/
|
|
45
|
+
const dragDirection = (0, react_1.useRef)(void 0);
|
|
42
46
|
const draggableHandles = (0, utils_1.useDraggable)({
|
|
43
47
|
onDragStart() {
|
|
44
|
-
|
|
48
|
+
maskRef.current.style.transition = 'none';
|
|
45
49
|
return {
|
|
46
50
|
isFit: imageItemRefs.current[innerIndex.current].isFit(),
|
|
47
51
|
startLeft: -innerIndex.current * wrapperRef.current.offsetWidth
|
|
48
52
|
};
|
|
49
53
|
},
|
|
50
|
-
onDrag({ diff: [dx], data: { isFit: { left, right }, startLeft } }) {
|
|
51
|
-
if ((!left && dx > 0)
|
|
54
|
+
onDrag({ diff: [dx, dy], data: { isFit: { left, right, top, bottom }, startLeft } }) {
|
|
55
|
+
if ((!left && dx > 0)
|
|
56
|
+
|| (!right && dx < 0)
|
|
57
|
+
|| (!top && dy > 0)
|
|
58
|
+
|| (!bottom && dy < 0)) {
|
|
59
|
+
// 图片超出边缘时,无需触发Gallery的滑动翻页,此时拖拽效果由Pinchable处理
|
|
52
60
|
return;
|
|
53
61
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
62
|
+
if (!dragDirection.current) {
|
|
63
|
+
if (dx <= -5 || 5 <= dx) {
|
|
64
|
+
dragDirection.current = 'horizontal';
|
|
65
|
+
resetVerticalDrag();
|
|
66
|
+
}
|
|
67
|
+
if (dy <= -5 || 5 <= dy) {
|
|
68
|
+
dragDirection.current = 'vertical';
|
|
69
|
+
}
|
|
59
70
|
}
|
|
60
|
-
|
|
61
|
-
|
|
71
|
+
if (dragDirection.current !== 'vertical') {
|
|
72
|
+
// 处理横向拖动
|
|
73
|
+
const min = -wrapperRef.current.offsetWidth * (srcArr.current.length - 1);
|
|
74
|
+
const max = 0;
|
|
75
|
+
const newLeft = (0, utils_1.edgeBounce)(startLeft + dx, { min, max, allowEdgeBounce, bounceElementTranslate, bounceDragDistance });
|
|
76
|
+
wrapperRef.current.style.left = newLeft + 'px';
|
|
62
77
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return;
|
|
78
|
+
if (dragDirection.current !== 'horizontal') {
|
|
79
|
+
// 处理纵向拖动
|
|
80
|
+
const rate = 1 - Math.abs(dy) / 2 / wrapperRef.current.offsetHeight;
|
|
81
|
+
imageItemRefs.current[innerIndex.current].style.transform = `translateY(${dy}px) scale(${rate})`;
|
|
82
|
+
maskRef.current.style.opacity = rate.toString();
|
|
69
83
|
}
|
|
70
|
-
|
|
84
|
+
},
|
|
85
|
+
onDragEnd({ diff: [dx, dy], speed: [speedX, speedY], data: { isFit: { left, right, top, bottom } } }) {
|
|
86
|
+
if (!dx && !dy) {
|
|
71
87
|
return;
|
|
72
88
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
? reset()
|
|
80
|
-
: goPrevLoop();
|
|
81
|
-
};
|
|
82
|
-
const goNext = () => {
|
|
83
|
-
innerIndex.current === srcArr.current.length - 1
|
|
84
|
-
? reset()
|
|
85
|
-
: goNextLoop();
|
|
86
|
-
};
|
|
87
|
-
if (effectiveSpeed && speedX * 1000 >= effectiveSpeed) {
|
|
88
|
-
dx > 0 ? goPrev() : goNext();
|
|
89
|
+
resetVerticalDrag(true);
|
|
90
|
+
if ((!left && dx > 0)
|
|
91
|
+
|| (!right && dx < 0)
|
|
92
|
+
|| (!top && dy > 0)
|
|
93
|
+
|| (!bottom && dy < 0)) {
|
|
94
|
+
// 图片超出边缘时,无需触发Gallery的滑动翻页,此时拖拽效果由Pinchable处理
|
|
89
95
|
return;
|
|
90
96
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
goNext();
|
|
97
|
+
if (dragDirection.current === 'vertical') {
|
|
98
|
+
if ((effectiveSpeed && speedY * 1000 >= effectiveSpeed)
|
|
99
|
+
|| Math.abs(dy) > wrapperRef.current.offsetHeight / 2) {
|
|
100
|
+
close();
|
|
101
|
+
}
|
|
97
102
|
}
|
|
98
103
|
else {
|
|
99
|
-
|
|
104
|
+
const goPrev = () => {
|
|
105
|
+
innerIndex.current === 0
|
|
106
|
+
? resetHorizontalDrag()
|
|
107
|
+
: goPrevLoop();
|
|
108
|
+
};
|
|
109
|
+
const goNext = () => {
|
|
110
|
+
innerIndex.current === srcArr.current.length - 1
|
|
111
|
+
? resetHorizontalDrag()
|
|
112
|
+
: goNextLoop();
|
|
113
|
+
};
|
|
114
|
+
// 满足速度要求
|
|
115
|
+
if (effectiveSpeed && speedX * 1000 >= effectiveSpeed) {
|
|
116
|
+
dx > 0 ? goPrev() : goNext();
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// 拖拽距离达到一半
|
|
120
|
+
const halfWidth = wrapperRef.current.offsetWidth / 2;
|
|
121
|
+
if (dx >= halfWidth) {
|
|
122
|
+
goPrev();
|
|
123
|
+
}
|
|
124
|
+
else if (dx <= -halfWidth) {
|
|
125
|
+
goNext();
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
resetHorizontalDrag();
|
|
129
|
+
}
|
|
100
130
|
}
|
|
131
|
+
dragDirection.current = void 0;
|
|
101
132
|
},
|
|
102
133
|
onClick: () => {
|
|
103
|
-
doubleClicked.current = false;
|
|
104
134
|
setTimeout(() => {
|
|
105
135
|
!doubleClicked.current && close();
|
|
106
|
-
},
|
|
136
|
+
}, DOUBLE_CLICK_DELAY);
|
|
107
137
|
}
|
|
108
138
|
});
|
|
139
|
+
const resetHorizontalDrag = () => {
|
|
140
|
+
allowSlideTransition('bounce');
|
|
141
|
+
wrapperRef.current.style.left = -innerIndex.current * wrapperRef.current.offsetWidth + 'px';
|
|
142
|
+
};
|
|
143
|
+
const resetVerticalDrag = (transition = false) => {
|
|
144
|
+
const imageItem = imageItemRefs.current[innerIndex.current];
|
|
145
|
+
const mask = maskRef.current;
|
|
146
|
+
if (transition) {
|
|
147
|
+
imageItem.dataset.transition = 'true';
|
|
148
|
+
// mask的css定义了transition,只需去掉style.transition即可实现过渡
|
|
149
|
+
mask.style.transition = '';
|
|
150
|
+
}
|
|
151
|
+
imageItem.style.transform = '';
|
|
152
|
+
mask.style.opacity = '';
|
|
153
|
+
};
|
|
109
154
|
const doubleClicked = (0, react_1.useRef)(false);
|
|
110
155
|
const doubleClickHandler = () => {
|
|
111
156
|
doubleClicked.current = true;
|
|
157
|
+
setTimeout(() => doubleClicked.current = false, DOUBLE_CLICK_DELAY);
|
|
158
|
+
};
|
|
159
|
+
const allowSlideTransition = (transitionType = 'true') => {
|
|
160
|
+
if (wrapperRef.current) {
|
|
161
|
+
wrapperRef.current.dataset.transition = transitionType;
|
|
162
|
+
}
|
|
112
163
|
};
|
|
113
|
-
const
|
|
114
|
-
|
|
164
|
+
const clearTransition = () => {
|
|
165
|
+
if (wrapperRef.current) {
|
|
166
|
+
wrapperRef.current.dataset.transition = '';
|
|
167
|
+
}
|
|
168
|
+
const imageItem = imageItemRefs.current[innerIndex.current];
|
|
169
|
+
if (imageItem) {
|
|
170
|
+
imageItem.dataset.transition = '';
|
|
171
|
+
}
|
|
172
|
+
maskRef.current.style.transition = '';
|
|
115
173
|
};
|
|
116
174
|
const goPrevLoop = () => {
|
|
117
175
|
allowSlideTransition();
|
|
@@ -153,13 +211,18 @@ exports.Gallery = (0, react_1.memo)(({ src, defaultIndex = 0, index, onIndexChan
|
|
|
153
211
|
};
|
|
154
212
|
return ((0, jsx_runtime_1.jsx)(modal_1.Modal, { ...props, css: gallery_style_1.style, className: (0, utils_1.clsx)(gallery_style_1.classes.root, props.className), open: innerOpen.current, onClosed: resetAll, maskProps: {
|
|
155
213
|
...props.maskProps,
|
|
214
|
+
ref: (0, utils_1.cloneRef)(maskRef, props.maskProps?.ref),
|
|
156
215
|
children: ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: gallery_style_1.classes.control, children: [renderControl, showRotation &&
|
|
157
216
|
(0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(tooltip_1.Tooltip, { title: "\u65CB\u8F6C-90\u00B0", children: (0, jsx_runtime_1.jsx)(button_1.Button, { ...commonControlProps, onClick: rotateLeft, children: (0, jsx_runtime_1.jsx)(icon_1.Icon, { icon: faArrowRotateLeft_1.faArrowRotateLeft }) }) }), (0, jsx_runtime_1.jsx)(tooltip_1.Tooltip, { title: "\u65CB\u8F6C90\u00B0", children: (0, jsx_runtime_1.jsx)(button_1.Button, { ...commonControlProps, onClick: rotateRight, children: (0, jsx_runtime_1.jsx)(icon_1.Icon, { icon: faArrowRotateRight_1.faArrowRotateRight }) }) })] }), showZoom &&
|
|
158
217
|
(0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(tooltip_1.Tooltip, { title: "\u7F29\u5C0F", children: (0, jsx_runtime_1.jsx)(button_1.Button, { ...commonControlProps, onClick: zoomOut, children: (0, jsx_runtime_1.jsx)(icon_1.Icon, { icon: faMagnifyingGlassMinus_1.faMagnifyingGlassMinus }) }) }), (0, jsx_runtime_1.jsx)(tooltip_1.Tooltip, { title: "\u653E\u5927", children: (0, jsx_runtime_1.jsx)(button_1.Button, { ...commonControlProps, onClick: zoomIn, children: (0, jsx_runtime_1.jsx)(icon_1.Icon, { icon: faMagnifyingGlassPlus_1.faMagnifyingGlassPlus }) }) }), (0, jsx_runtime_1.jsx)(tooltip_1.Tooltip, { title: "\u9002\u5E94\u5C4F\u5E55", children: (0, jsx_runtime_1.jsx)(button_1.Button, { ...commonControlProps, onClick: reset, children: (0, jsx_runtime_1.jsx)(icon_1.Icon, { icon: faExpand_1.faExpand }) }) })] }), showClose &&
|
|
159
218
|
(0, jsx_runtime_1.jsx)(button_1.Button, { ...commonControlProps, onClick: close, children: (0, jsx_runtime_1.jsx)(icon_1.Icon, { icon: faXmark_1.faXmark }) })] }), srcArr.current.length > 1 &&
|
|
160
219
|
(0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: gallery_style_1.classes.swap, children: [(0, jsx_runtime_1.jsx)(button_1.Button, { ...commonControlProps, onClick: goPrevLoop, children: (0, jsx_runtime_1.jsx)(icon_1.Icon, { icon: faAngleLeft_1.faAngleLeft }) }), (0, jsx_runtime_1.jsx)(button_1.Button, { ...commonControlProps, onClick: goNextLoop, children: (0, jsx_runtime_1.jsx)(icon_1.Icon, { icon: faAngleRight_1.faAngleRight }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: gallery_style_1.classes.counter, children: [innerIndex.current + 1, " / ", srcArr.current.length] })] })] }))
|
|
161
220
|
}, children: srcArr.current.length > 0 &&
|
|
162
|
-
(0, jsx_runtime_1.jsx)("div", { className: gallery_style_1.classes.galleryContainer, ...draggableHandles, onDoubleClick: doubleClickHandler, children: (0, jsx_runtime_1.jsx)("div", { ref: wrapperRef, className: gallery_style_1.classes.galleryWrapper, style: { left: -innerIndex.current * 100 + '%' }, onTransitionEnd:
|
|
221
|
+
(0, jsx_runtime_1.jsx)("div", { className: gallery_style_1.classes.galleryContainer, ...draggableHandles, onDoubleClick: doubleClickHandler, children: (0, jsx_runtime_1.jsx)("div", { ref: wrapperRef, className: gallery_style_1.classes.galleryWrapper, style: { left: -innerIndex.current * 100 + '%' }, onTransitionEnd: clearTransition, children: srcArr.current.map((src, i) => (0, jsx_runtime_1.jsx)(imageItem_1.ImageItem, { ref: r => {
|
|
163
222
|
r && imageItemRefs.current.push(r);
|
|
223
|
+
}, imgProps: {
|
|
224
|
+
ref: r => {
|
|
225
|
+
r && imgRefs.current.push(r);
|
|
226
|
+
}
|
|
164
227
|
}, style: { left: i * 100 + '%' }, src: src }, i)) }) }) }));
|
|
165
228
|
});
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.style = exports.classes = void 0;
|
|
4
4
|
const react_1 = require("@emotion/react");
|
|
5
5
|
const utils_1 = require("../../utils");
|
|
6
|
-
exports.classes = (0, utils_1.defineInnerClasses)('
|
|
6
|
+
exports.classes = (0, utils_1.defineInnerClasses)('gallery', [
|
|
7
7
|
'button',
|
|
8
8
|
'control',
|
|
9
9
|
'swap',
|
|
@@ -82,14 +82,14 @@ exports.style = (0, utils_1.defineCss)(({ spacing, easing, breakpoints }) => (0,
|
|
|
82
82
|
&, .${exports.classes.imageItem} {
|
|
83
83
|
position: absolute;
|
|
84
84
|
top: 0;
|
|
85
|
-
}
|
|
86
85
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
&[data-transition=true] {
|
|
87
|
+
transition: all .3s ${easing.easeOut};
|
|
88
|
+
}
|
|
90
89
|
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
&[data-transition=bounce] {
|
|
91
|
+
transition: all .25s ${easing.bounce};
|
|
92
|
+
}
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
.${exports.classes.imageItem} {
|
|
@@ -108,10 +108,6 @@ exports.style = (0, utils_1.defineCss)(({ spacing, easing, breakpoints }) => (0,
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
.${exports.classes.galleryContainer} .${exports.classes.galleryWrapper} {
|
|
111
|
-
&[data-transition=true] {
|
|
112
|
-
transition: left .4s ${easing.ease};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
111
|
.${exports.classes.imageItem} {
|
|
116
112
|
padding: 0;
|
|
117
113
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { Ref } from 'react';
|
|
1
|
+
import { JSX, Ref } from 'react';
|
|
2
2
|
import { PinchableProps, PinchableRef } from '../pinchable';
|
|
3
3
|
export interface ImageItemRef extends PinchableRef {
|
|
4
4
|
isFit(): {
|
|
5
|
+
top: boolean;
|
|
6
|
+
bottom: boolean;
|
|
5
7
|
left: boolean;
|
|
6
8
|
right: boolean;
|
|
7
9
|
};
|
|
@@ -9,6 +11,7 @@ export interface ImageItemRef extends PinchableRef {
|
|
|
9
11
|
interface ImageItemProps extends PinchableProps {
|
|
10
12
|
ref?: Ref<ImageItemRef>;
|
|
11
13
|
src?: string;
|
|
14
|
+
imgProps?: JSX.IntrinsicElements['img'];
|
|
12
15
|
}
|
|
13
|
-
export declare function ImageItem({ ref, src, ...props }: ImageItemProps): import("@emotion/react/jsx-runtime").JSX.Element;
|
|
16
|
+
export declare function ImageItem({ ref, src, imgProps, ...props }: ImageItemProps): import("@emotion/react/jsx-runtime").JSX.Element;
|
|
14
17
|
export {};
|
|
@@ -6,13 +6,15 @@ const gallery_style_1 = require("./gallery.style");
|
|
|
6
6
|
const react_1 = require("react");
|
|
7
7
|
const utils_1 = require("../../utils");
|
|
8
8
|
const pinchable_1 = require("../pinchable");
|
|
9
|
-
function ImageItem({ ref, src, ...props }) {
|
|
9
|
+
function ImageItem({ ref, src, imgProps, ...props }) {
|
|
10
10
|
(0, react_1.useImperativeHandle)(ref, () => {
|
|
11
11
|
if (pinchableRef.current) {
|
|
12
12
|
pinchableRef.current.isFit = () => {
|
|
13
|
-
const { x: pinchableX, width: pinchableWidth } = pinchableRef.current.getBoundingClientRect();
|
|
14
|
-
const { x: imgX, width: imgWidth } = imgRef.current.getBoundingClientRect();
|
|
13
|
+
const { x: pinchableX, y: pinchableY, width: pinchableWidth, height: pinchableHeight } = pinchableRef.current.getBoundingClientRect();
|
|
14
|
+
const { x: imgX, y: imgY, width: imgWidth, height: imgHeight } = imgRef.current.getBoundingClientRect();
|
|
15
15
|
return {
|
|
16
|
+
top: imgY >= pinchableY,
|
|
17
|
+
bottom: imgY + imgHeight <= pinchableY + pinchableHeight,
|
|
16
18
|
left: imgX >= pinchableX,
|
|
17
19
|
right: imgX + imgWidth <= pinchableX + pinchableWidth
|
|
18
20
|
};
|
|
@@ -47,5 +49,5 @@ function ImageItem({ ref, src, ...props }) {
|
|
|
47
49
|
resizeObserver.disconnect();
|
|
48
50
|
};
|
|
49
51
|
}, []);
|
|
50
|
-
return ((0, jsx_runtime_1.jsx)(pinchable_1.Pinchable, { ...props, ref: pinchableRef, className: (0, utils_1.clsx)(gallery_style_1.classes.imageItem, props.className), children: (0, jsx_runtime_1.jsx)("img", {
|
|
52
|
+
return ((0, jsx_runtime_1.jsx)(pinchable_1.Pinchable, { ...props, ref: pinchableRef, className: (0, utils_1.clsx)(gallery_style_1.classes.imageItem, props.className), allowEdgeBounce: false, children: (0, jsx_runtime_1.jsx)("img", { draggable: false, alt: "", src: src, ...imgProps, ref: (0, utils_1.cloneRef)(imgRef, imgProps?.ref), className: (0, utils_1.clsx)(gallery_style_1.classes.image, imgProps?.className) }) }));
|
|
51
53
|
}
|
|
@@ -22,11 +22,17 @@ type PinchableOwnProps = {
|
|
|
22
22
|
translate?: [number, number];
|
|
23
23
|
onTranslateChange?(translate: [number, number]): void;
|
|
24
24
|
/** 平移限制,`translate`非受控模式下有效 */
|
|
25
|
-
translateLimit?: (targetX: number, targetY: number, scale: number) => [number, number];
|
|
25
|
+
translateLimit?: (targetX: number, targetY: number, scale: number, rotateDeg: number) => [number, number];
|
|
26
26
|
defaultRotate?: number;
|
|
27
27
|
rotate?: number;
|
|
28
28
|
onRotateChange?(rotate: number): void;
|
|
29
29
|
children?: ReactElement;
|
|
30
|
+
/** 拖拽至最边缘时,是否允许弹性溢出,默认为`true` */
|
|
31
|
+
allowEdgeBounce?: boolean;
|
|
32
|
+
/** 元素弹性移动距离,默认为24 */
|
|
33
|
+
bounceElementTranslate?: number;
|
|
34
|
+
/** 手指弹性拖拽距离,默认为240 */
|
|
35
|
+
bounceDragDistance?: number;
|
|
30
36
|
};
|
|
31
37
|
export type PinchableProps<C extends ElementType = 'div'> = OverridableProps<PinchableOwnProps, C>;
|
|
32
38
|
export declare const Pinchable: <C extends ElementType = "div">(props: PinchableProps<C>) => ReactElement;
|
|
@@ -5,7 +5,7 @@ const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
|
|
|
5
5
|
const react_1 = require("react");
|
|
6
6
|
const utils_1 = require("../../utils");
|
|
7
7
|
const pinchable_style_1 = require("./pinchable.style");
|
|
8
|
-
exports.Pinchable = (({ component: Component = 'div', ref, gestureOptions, defaultScale = 1, scale, onScaleChange, scaleLimit = [1, 6], defaultTranslate = [0, 0], translate, onTranslateChange, translateLimit, defaultRotate = 0, rotate, onRotateChange, children, ...props }) => {
|
|
8
|
+
exports.Pinchable = (({ component: Component = 'div', ref, gestureOptions, defaultScale = 1, scale, onScaleChange, scaleLimit = [1, 6], defaultTranslate = [0, 0], translate, onTranslateChange, translateLimit, defaultRotate = 0, rotate, onRotateChange, children, allowEdgeBounce = true, bounceElementTranslate = 24, bounceDragDistance = 240, ...props }) => {
|
|
9
9
|
(0, react_1.useImperativeHandle)(ref, () => {
|
|
10
10
|
if (wrapperRef.current) {
|
|
11
11
|
wrapperRef.current.zoomIn = () => {
|
|
@@ -41,6 +41,12 @@ exports.Pinchable = (({ component: Component = 'div', ref, gestureOptions, defau
|
|
|
41
41
|
onDrag(info, e) {
|
|
42
42
|
gestureOptions?.onDrag?.(info, e);
|
|
43
43
|
const { diff: [dx, dy], data: [startX, startY] } = info;
|
|
44
|
+
setInnerTranslate(translateLimitFn(startX + dx, startY + dy, void 0, void 0, true));
|
|
45
|
+
},
|
|
46
|
+
onDragEnd(info) {
|
|
47
|
+
gestureOptions?.onDragEnd?.(info);
|
|
48
|
+
const { diff: [dx, dy], data: [startX, startY] } = info;
|
|
49
|
+
allowTransition('bounce');
|
|
44
50
|
setInnerTranslate(translateLimitFn(startX + dx, startY + dy));
|
|
45
51
|
},
|
|
46
52
|
onPinchStart(info) {
|
|
@@ -78,9 +84,9 @@ exports.Pinchable = (({ component: Component = 'div', ref, gestureOptions, defau
|
|
|
78
84
|
if (!children) {
|
|
79
85
|
return;
|
|
80
86
|
}
|
|
81
|
-
const translateLimitFn = (x, y, scale = innerScale.current, deg = innerRotate.current) => {
|
|
87
|
+
const translateLimitFn = (x, y, scale = innerScale.current, deg = innerRotate.current, bounce = false) => {
|
|
82
88
|
if (translateLimit) {
|
|
83
|
-
return translateLimit(x, y, scale);
|
|
89
|
+
return translateLimit(x, y, scale, deg);
|
|
84
90
|
}
|
|
85
91
|
const { clientWidth: wrapperWidth, clientHeight: wrapperHeight } = wrapperRef.current;
|
|
86
92
|
const { offsetWidth, offsetHeight } = contentRef.current;
|
|
@@ -89,14 +95,20 @@ exports.Pinchable = (({ component: Component = 'div', ref, gestureOptions, defau
|
|
|
89
95
|
const contentHeight = (isRotated ? offsetWidth : offsetHeight) * scale;
|
|
90
96
|
const limitX = contentWidth > wrapperWidth ? (contentWidth - wrapperWidth) / 2 : 0;
|
|
91
97
|
const limitY = contentHeight > wrapperHeight ? (contentHeight - wrapperHeight) / 2 : 0;
|
|
98
|
+
if (!bounce) {
|
|
99
|
+
return [
|
|
100
|
+
(0, utils_1.range)(x, -limitX, limitX),
|
|
101
|
+
(0, utils_1.range)(y, -limitY, limitY)
|
|
102
|
+
];
|
|
103
|
+
}
|
|
92
104
|
return [
|
|
93
|
-
(0, utils_1.
|
|
94
|
-
(0, utils_1.
|
|
105
|
+
(0, utils_1.edgeBounce)(x, { min: -limitX, max: limitX, allowEdgeBounce, bounceElementTranslate, bounceDragDistance }),
|
|
106
|
+
(0, utils_1.edgeBounce)(y, { min: -limitY, max: limitY, allowEdgeBounce, bounceElementTranslate, bounceDragDistance })
|
|
95
107
|
];
|
|
96
108
|
};
|
|
97
109
|
const childrenProps = children.props;
|
|
98
|
-
const allowTransition = () => {
|
|
99
|
-
contentRef.current && (contentRef.current.dataset.transition =
|
|
110
|
+
const allowTransition = (transitionType = 'true') => {
|
|
111
|
+
contentRef.current && (contentRef.current.dataset.transition = transitionType);
|
|
100
112
|
};
|
|
101
113
|
const zoomFn = (targetScale, originX, originY) => {
|
|
102
114
|
allowTransition();
|
|
@@ -150,7 +162,7 @@ exports.Pinchable = (({ component: Component = 'div', ref, gestureOptions, defau
|
|
|
150
162
|
: zoomFn(innerScale.current * 1.2, e.clientX, e.clientY);
|
|
151
163
|
};
|
|
152
164
|
const onTransitionEnd = (e) => {
|
|
153
|
-
e.currentTarget.dataset.transition = '
|
|
165
|
+
e.currentTarget.dataset.transition = '';
|
|
154
166
|
setInnerRotate(innerRotate.current % 360);
|
|
155
167
|
};
|
|
156
168
|
return ((0, jsx_runtime_1.jsx)(Component, { ...props, ref: wrapperRef, css: pinchable_style_1.style, className: (0, utils_1.clsx)(pinchable_style_1.classes.root, props.className), ...pinchableHandles, children: (0, react_1.cloneElement)(children, {
|
|
@@ -16,8 +16,14 @@ exports.style = (0, utils_1.defineCss)(({ easing }) => (0, react_1.css) `
|
|
|
16
16
|
touch-action: none;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
.${exports.classes.content}
|
|
20
|
-
transition
|
|
19
|
+
.${exports.classes.content} {
|
|
20
|
+
&[data-transition=true] {
|
|
21
|
+
transition: all .25s ${easing.easeOut};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&[data-transition=bounce] {
|
|
25
|
+
transition: all .25s ${easing.bounce};
|
|
26
|
+
}
|
|
21
27
|
}
|
|
22
28
|
}
|
|
23
29
|
`);
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
export type BezierFunc = (x: number) => number;
|
|
1
2
|
/**
|
|
2
3
|
* 创建一个Bezier曲线函数,默认从(0,0)到(1,1)
|
|
3
4
|
* @param p1x
|
|
4
5
|
* @param p1y
|
|
5
6
|
* @param p2x
|
|
6
7
|
* @param p2y
|
|
7
|
-
* @returns {
|
|
8
|
+
* @returns {BezierFunc} 返回一个函数,接收x返回y
|
|
8
9
|
*/
|
|
9
|
-
export declare function cubicBezier(p1x: number, p1y: number, p2x: number, p2y: number):
|
|
10
|
+
export declare function cubicBezier(p1x: number, p1y: number, p2x: number, p2y: number): BezierFunc;
|
|
10
11
|
export declare namespace cubicBezier {
|
|
11
|
-
var preset: (preset: Preset) =>
|
|
12
|
+
var preset: (preset: Preset) => BezierFunc;
|
|
12
13
|
}
|
|
13
14
|
export type Preset = 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out';
|
package/dist/cjs/utils/bezier.js
CHANGED
package/dist/cjs/utils/dnd.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DragEndEvent } from '@dnd-kit/core';
|
|
2
2
|
import { Id, Obj } from '../types';
|
|
3
3
|
import { NodeType, SortInfo } from '../components/tree';
|
|
4
|
+
import { BezierFunc } from './bezier';
|
|
4
5
|
/**
|
|
5
6
|
* 默认提供给@dnd-kit的sensors属性
|
|
6
7
|
*/
|
|
@@ -19,3 +20,11 @@ export declare function onDndDragEnd<S extends Obj>(e: DragEndEvent, prevState:
|
|
|
19
20
|
* @param primaryKey 索引用的主键,默认为`id`
|
|
20
21
|
*/
|
|
21
22
|
export declare function onTreeNodeSort<N extends NodeType<V>, V extends Id = Id>(info: SortInfo<V>, treeNodes: N[], primaryKey?: string): N[];
|
|
23
|
+
export declare function edgeBounce(value: number, { allowEdgeBounce, min, max, bounceElementTranslate, bounceDragDistance, bezierFn }: {
|
|
24
|
+
allowEdgeBounce: boolean;
|
|
25
|
+
min: number;
|
|
26
|
+
max: number;
|
|
27
|
+
bounceElementTranslate: number;
|
|
28
|
+
bounceDragDistance: number;
|
|
29
|
+
bezierFn?: BezierFunc;
|
|
30
|
+
}): number;
|
package/dist/cjs/utils/dnd.js
CHANGED
|
@@ -3,8 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.useDndSensors = useDndSensors;
|
|
4
4
|
exports.onDndDragEnd = onDndDragEnd;
|
|
5
5
|
exports.onTreeNodeSort = onTreeNodeSort;
|
|
6
|
+
exports.edgeBounce = edgeBounce;
|
|
6
7
|
const core_1 = require("@dnd-kit/core");
|
|
7
8
|
const sortable_1 = require("@dnd-kit/sortable");
|
|
9
|
+
const utils_1 = require("./utils");
|
|
10
|
+
const bezier_1 = require("./bezier");
|
|
8
11
|
/**
|
|
9
12
|
* 默认提供给@dnd-kit的sensors属性
|
|
10
13
|
*/
|
|
@@ -73,3 +76,16 @@ function onTreeNodeSort(info, treeNodes, primaryKey = 'id') {
|
|
|
73
76
|
}
|
|
74
77
|
return treeNodes;
|
|
75
78
|
}
|
|
79
|
+
function edgeBounce(value, { allowEdgeBounce, min, max, bounceElementTranslate, bounceDragDistance, bezierFn = (0, bezier_1.cubicBezier)(0, 0, 0, 1) }) {
|
|
80
|
+
if (allowEdgeBounce && bounceElementTranslate && bounceDragDistance > 0) {
|
|
81
|
+
value = (0, utils_1.range)(value, min - bounceDragDistance, max + bounceDragDistance);
|
|
82
|
+
if (value < min) {
|
|
83
|
+
value = min - bezierFn((min - value) / bounceDragDistance) * bounceElementTranslate;
|
|
84
|
+
}
|
|
85
|
+
else if (value > max) {
|
|
86
|
+
value = max + bezierFn((value - max) / bounceDragDistance) * bounceElementTranslate;
|
|
87
|
+
}
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
return (0, utils_1.range)(value, min, max);
|
|
91
|
+
}
|
package/dist/cjs/utils/style.js
CHANGED
|
@@ -200,12 +200,14 @@ function useResponsiveValue(prop, disabled = false) {
|
|
|
200
200
|
const syncBreakpoints = (0, hooks_1.useSync)(breakpoints);
|
|
201
201
|
const fn = () => {
|
|
202
202
|
let maxBreakpoint = 'xs';
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
203
|
+
if (typeof window !== 'undefined') {
|
|
204
|
+
for (const k in syncBreakpoints.current) {
|
|
205
|
+
if (window.innerWidth < syncBreakpoints.current[k]) {
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
if (k in responsiveObj) {
|
|
209
|
+
maxBreakpoint = k;
|
|
210
|
+
}
|
|
209
211
|
}
|
|
210
212
|
}
|
|
211
213
|
return responsiveObj[maxBreakpoint];
|
|
@@ -15,6 +15,8 @@ export interface ImagePreviewProps extends ModalProps {
|
|
|
15
15
|
showClose?: boolean;
|
|
16
16
|
/** 自定义渲染控制按钮 */
|
|
17
17
|
renderControl?: ReactNode;
|
|
18
|
+
/** 拖拽至最边缘时,是否允许弹性溢出,默认为`true` */
|
|
19
|
+
allowEdgeBounce?: boolean;
|
|
18
20
|
/** 元素弹性移动距离,默认为24 */
|
|
19
21
|
bounceElementTranslate?: number;
|
|
20
22
|
/** 手指弹性拖拽距离,默认为240 */
|
|
@@ -22,4 +24,4 @@ export interface ImagePreviewProps extends ModalProps {
|
|
|
22
24
|
/** 滑动生效的速度,默认为450 (px/s) */
|
|
23
25
|
effectiveSpeed?: number;
|
|
24
26
|
}
|
|
25
|
-
export declare const Gallery: import("react").MemoExoticComponent<({ src, defaultIndex, index, onIndexChange, defaultOpen, open, onOpenChange, showRotation, showZoom, showClose, renderControl, bounceElementTranslate, bounceDragDistance, effectiveSpeed, ...props }: ImagePreviewProps) => import("@emotion/react/jsx-runtime").JSX.Element>;
|
|
27
|
+
export declare const Gallery: import("react").MemoExoticComponent<({ src, defaultIndex, index, onIndexChange, defaultOpen, open, onOpenChange, showRotation, showZoom, showClose, renderControl, allowEdgeBounce, bounceElementTranslate, bounceDragDistance, effectiveSpeed, ...props }: ImagePreviewProps) => import("@emotion/react/jsx-runtime").JSX.Element>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
|
|
2
2
|
import { memo, useRef } from 'react';
|
|
3
3
|
import { Modal } from '../modal';
|
|
4
|
-
import {
|
|
4
|
+
import { cloneRef, clsx, edgeBounce, toArray, useControlled, useDraggable, useSync } from '../../utils';
|
|
5
5
|
import { classes, style } from './gallery.style';
|
|
6
6
|
import { Button } from '../button';
|
|
7
7
|
import { Tooltip } from '../tooltip';
|
|
@@ -21,94 +21,152 @@ const commonControlProps = {
|
|
|
21
21
|
size: 'large',
|
|
22
22
|
color: 'text'
|
|
23
23
|
};
|
|
24
|
-
const
|
|
25
|
-
export const Gallery = memo(({ src, defaultIndex = 0, index, onIndexChange, defaultOpen = false, open, onOpenChange, showRotation = true, showZoom = true, showClose = true, renderControl, bounceElementTranslate = 24, bounceDragDistance = 240, effectiveSpeed = 450, ...props }) => {
|
|
24
|
+
const DOUBLE_CLICK_DELAY = 300;
|
|
25
|
+
export const Gallery = memo(({ src, defaultIndex = 0, index, onIndexChange, defaultOpen = false, open, onOpenChange, showRotation = true, showZoom = true, showClose = true, renderControl, allowEdgeBounce = true, bounceElementTranslate = 24, bounceDragDistance = 240, effectiveSpeed = 450, ...props }) => {
|
|
26
26
|
const srcArr = useSync(toArray(src || []));
|
|
27
27
|
const [innerOpen, setInnerOpen] = useControlled(defaultOpen, open, onOpenChange);
|
|
28
28
|
const close = () => {
|
|
29
29
|
setInnerOpen(false);
|
|
30
30
|
};
|
|
31
31
|
const [innerIndex, setInnerIndex] = useControlled(defaultIndex, index, onIndexChange);
|
|
32
|
+
const maskRef = useRef(null);
|
|
32
33
|
const wrapperRef = useRef(null);
|
|
33
34
|
const imageItemRefs = useRef([]);
|
|
34
35
|
imageItemRefs.current = [];
|
|
36
|
+
const imgRefs = useRef([]);
|
|
37
|
+
imgRefs.current = [];
|
|
35
38
|
/**
|
|
36
39
|
* --------------------------------------------------------------
|
|
37
40
|
* 左右滚动翻页
|
|
38
41
|
*/
|
|
42
|
+
const dragDirection = useRef(void 0);
|
|
39
43
|
const draggableHandles = useDraggable({
|
|
40
44
|
onDragStart() {
|
|
41
|
-
|
|
45
|
+
maskRef.current.style.transition = 'none';
|
|
42
46
|
return {
|
|
43
47
|
isFit: imageItemRefs.current[innerIndex.current].isFit(),
|
|
44
48
|
startLeft: -innerIndex.current * wrapperRef.current.offsetWidth
|
|
45
49
|
};
|
|
46
50
|
},
|
|
47
|
-
onDrag({ diff: [dx], data: { isFit: { left, right }, startLeft } }) {
|
|
48
|
-
if ((!left && dx > 0)
|
|
51
|
+
onDrag({ diff: [dx, dy], data: { isFit: { left, right, top, bottom }, startLeft } }) {
|
|
52
|
+
if ((!left && dx > 0)
|
|
53
|
+
|| (!right && dx < 0)
|
|
54
|
+
|| (!top && dy > 0)
|
|
55
|
+
|| (!bottom && dy < 0)) {
|
|
56
|
+
// 图片超出边缘时,无需触发Gallery的滑动翻页,此时拖拽效果由Pinchable处理
|
|
49
57
|
return;
|
|
50
58
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
if (!dragDirection.current) {
|
|
60
|
+
if (dx <= -5 || 5 <= dx) {
|
|
61
|
+
dragDirection.current = 'horizontal';
|
|
62
|
+
resetVerticalDrag();
|
|
63
|
+
}
|
|
64
|
+
if (dy <= -5 || 5 <= dy) {
|
|
65
|
+
dragDirection.current = 'vertical';
|
|
66
|
+
}
|
|
56
67
|
}
|
|
57
|
-
|
|
58
|
-
|
|
68
|
+
if (dragDirection.current !== 'vertical') {
|
|
69
|
+
// 处理横向拖动
|
|
70
|
+
const min = -wrapperRef.current.offsetWidth * (srcArr.current.length - 1);
|
|
71
|
+
const max = 0;
|
|
72
|
+
const newLeft = edgeBounce(startLeft + dx, { min, max, allowEdgeBounce, bounceElementTranslate, bounceDragDistance });
|
|
73
|
+
wrapperRef.current.style.left = newLeft + 'px';
|
|
59
74
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return;
|
|
75
|
+
if (dragDirection.current !== 'horizontal') {
|
|
76
|
+
// 处理纵向拖动
|
|
77
|
+
const rate = 1 - Math.abs(dy) / 2 / wrapperRef.current.offsetHeight;
|
|
78
|
+
imageItemRefs.current[innerIndex.current].style.transform = `translateY(${dy}px) scale(${rate})`;
|
|
79
|
+
maskRef.current.style.opacity = rate.toString();
|
|
66
80
|
}
|
|
67
|
-
|
|
81
|
+
},
|
|
82
|
+
onDragEnd({ diff: [dx, dy], speed: [speedX, speedY], data: { isFit: { left, right, top, bottom } } }) {
|
|
83
|
+
if (!dx && !dy) {
|
|
68
84
|
return;
|
|
69
85
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
? reset()
|
|
77
|
-
: goPrevLoop();
|
|
78
|
-
};
|
|
79
|
-
const goNext = () => {
|
|
80
|
-
innerIndex.current === srcArr.current.length - 1
|
|
81
|
-
? reset()
|
|
82
|
-
: goNextLoop();
|
|
83
|
-
};
|
|
84
|
-
if (effectiveSpeed && speedX * 1000 >= effectiveSpeed) {
|
|
85
|
-
dx > 0 ? goPrev() : goNext();
|
|
86
|
+
resetVerticalDrag(true);
|
|
87
|
+
if ((!left && dx > 0)
|
|
88
|
+
|| (!right && dx < 0)
|
|
89
|
+
|| (!top && dy > 0)
|
|
90
|
+
|| (!bottom && dy < 0)) {
|
|
91
|
+
// 图片超出边缘时,无需触发Gallery的滑动翻页,此时拖拽效果由Pinchable处理
|
|
86
92
|
return;
|
|
87
93
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
goNext();
|
|
94
|
+
if (dragDirection.current === 'vertical') {
|
|
95
|
+
if ((effectiveSpeed && speedY * 1000 >= effectiveSpeed)
|
|
96
|
+
|| Math.abs(dy) > wrapperRef.current.offsetHeight / 2) {
|
|
97
|
+
close();
|
|
98
|
+
}
|
|
94
99
|
}
|
|
95
100
|
else {
|
|
96
|
-
|
|
101
|
+
const goPrev = () => {
|
|
102
|
+
innerIndex.current === 0
|
|
103
|
+
? resetHorizontalDrag()
|
|
104
|
+
: goPrevLoop();
|
|
105
|
+
};
|
|
106
|
+
const goNext = () => {
|
|
107
|
+
innerIndex.current === srcArr.current.length - 1
|
|
108
|
+
? resetHorizontalDrag()
|
|
109
|
+
: goNextLoop();
|
|
110
|
+
};
|
|
111
|
+
// 满足速度要求
|
|
112
|
+
if (effectiveSpeed && speedX * 1000 >= effectiveSpeed) {
|
|
113
|
+
dx > 0 ? goPrev() : goNext();
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// 拖拽距离达到一半
|
|
117
|
+
const halfWidth = wrapperRef.current.offsetWidth / 2;
|
|
118
|
+
if (dx >= halfWidth) {
|
|
119
|
+
goPrev();
|
|
120
|
+
}
|
|
121
|
+
else if (dx <= -halfWidth) {
|
|
122
|
+
goNext();
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
resetHorizontalDrag();
|
|
126
|
+
}
|
|
97
127
|
}
|
|
128
|
+
dragDirection.current = void 0;
|
|
98
129
|
},
|
|
99
130
|
onClick: () => {
|
|
100
|
-
doubleClicked.current = false;
|
|
101
131
|
setTimeout(() => {
|
|
102
132
|
!doubleClicked.current && close();
|
|
103
|
-
},
|
|
133
|
+
}, DOUBLE_CLICK_DELAY);
|
|
104
134
|
}
|
|
105
135
|
});
|
|
136
|
+
const resetHorizontalDrag = () => {
|
|
137
|
+
allowSlideTransition('bounce');
|
|
138
|
+
wrapperRef.current.style.left = -innerIndex.current * wrapperRef.current.offsetWidth + 'px';
|
|
139
|
+
};
|
|
140
|
+
const resetVerticalDrag = (transition = false) => {
|
|
141
|
+
const imageItem = imageItemRefs.current[innerIndex.current];
|
|
142
|
+
const mask = maskRef.current;
|
|
143
|
+
if (transition) {
|
|
144
|
+
imageItem.dataset.transition = 'true';
|
|
145
|
+
// mask的css定义了transition,只需去掉style.transition即可实现过渡
|
|
146
|
+
mask.style.transition = '';
|
|
147
|
+
}
|
|
148
|
+
imageItem.style.transform = '';
|
|
149
|
+
mask.style.opacity = '';
|
|
150
|
+
};
|
|
106
151
|
const doubleClicked = useRef(false);
|
|
107
152
|
const doubleClickHandler = () => {
|
|
108
153
|
doubleClicked.current = true;
|
|
154
|
+
setTimeout(() => doubleClicked.current = false, DOUBLE_CLICK_DELAY);
|
|
155
|
+
};
|
|
156
|
+
const allowSlideTransition = (transitionType = 'true') => {
|
|
157
|
+
if (wrapperRef.current) {
|
|
158
|
+
wrapperRef.current.dataset.transition = transitionType;
|
|
159
|
+
}
|
|
109
160
|
};
|
|
110
|
-
const
|
|
111
|
-
|
|
161
|
+
const clearTransition = () => {
|
|
162
|
+
if (wrapperRef.current) {
|
|
163
|
+
wrapperRef.current.dataset.transition = '';
|
|
164
|
+
}
|
|
165
|
+
const imageItem = imageItemRefs.current[innerIndex.current];
|
|
166
|
+
if (imageItem) {
|
|
167
|
+
imageItem.dataset.transition = '';
|
|
168
|
+
}
|
|
169
|
+
maskRef.current.style.transition = '';
|
|
112
170
|
};
|
|
113
171
|
const goPrevLoop = () => {
|
|
114
172
|
allowSlideTransition();
|
|
@@ -150,13 +208,18 @@ export const Gallery = memo(({ src, defaultIndex = 0, index, onIndexChange, defa
|
|
|
150
208
|
};
|
|
151
209
|
return (_jsx(Modal, { ...props, css: style, className: clsx(classes.root, props.className), open: innerOpen.current, onClosed: resetAll, maskProps: {
|
|
152
210
|
...props.maskProps,
|
|
211
|
+
ref: cloneRef(maskRef, props.maskProps?.ref),
|
|
153
212
|
children: (_jsxs(_Fragment, { children: [_jsxs("div", { className: classes.control, children: [renderControl, showRotation &&
|
|
154
213
|
_jsxs(_Fragment, { children: [_jsx(Tooltip, { title: "\u65CB\u8F6C-90\u00B0", children: _jsx(Button, { ...commonControlProps, onClick: rotateLeft, children: _jsx(Icon, { icon: faArrowRotateLeft }) }) }), _jsx(Tooltip, { title: "\u65CB\u8F6C90\u00B0", children: _jsx(Button, { ...commonControlProps, onClick: rotateRight, children: _jsx(Icon, { icon: faArrowRotateRight }) }) })] }), showZoom &&
|
|
155
214
|
_jsxs(_Fragment, { children: [_jsx(Tooltip, { title: "\u7F29\u5C0F", children: _jsx(Button, { ...commonControlProps, onClick: zoomOut, children: _jsx(Icon, { icon: faMagnifyingGlassMinus }) }) }), _jsx(Tooltip, { title: "\u653E\u5927", children: _jsx(Button, { ...commonControlProps, onClick: zoomIn, children: _jsx(Icon, { icon: faMagnifyingGlassPlus }) }) }), _jsx(Tooltip, { title: "\u9002\u5E94\u5C4F\u5E55", children: _jsx(Button, { ...commonControlProps, onClick: reset, children: _jsx(Icon, { icon: faExpand }) }) })] }), showClose &&
|
|
156
215
|
_jsx(Button, { ...commonControlProps, onClick: close, children: _jsx(Icon, { icon: faXmark }) })] }), srcArr.current.length > 1 &&
|
|
157
216
|
_jsxs(_Fragment, { children: [_jsxs("div", { className: classes.swap, children: [_jsx(Button, { ...commonControlProps, onClick: goPrevLoop, children: _jsx(Icon, { icon: faAngleLeft }) }), _jsx(Button, { ...commonControlProps, onClick: goNextLoop, children: _jsx(Icon, { icon: faAngleRight }) })] }), _jsxs("div", { className: classes.counter, children: [innerIndex.current + 1, " / ", srcArr.current.length] })] })] }))
|
|
158
217
|
}, children: srcArr.current.length > 0 &&
|
|
159
|
-
_jsx("div", { className: classes.galleryContainer, ...draggableHandles, onDoubleClick: doubleClickHandler, children: _jsx("div", { ref: wrapperRef, className: classes.galleryWrapper, style: { left: -innerIndex.current * 100 + '%' }, onTransitionEnd:
|
|
218
|
+
_jsx("div", { className: classes.galleryContainer, ...draggableHandles, onDoubleClick: doubleClickHandler, children: _jsx("div", { ref: wrapperRef, className: classes.galleryWrapper, style: { left: -innerIndex.current * 100 + '%' }, onTransitionEnd: clearTransition, children: srcArr.current.map((src, i) => _jsx(ImageItem, { ref: r => {
|
|
160
219
|
r && imageItemRefs.current.push(r);
|
|
220
|
+
}, imgProps: {
|
|
221
|
+
ref: r => {
|
|
222
|
+
r && imgRefs.current.push(r);
|
|
223
|
+
}
|
|
161
224
|
}, style: { left: i * 100 + '%' }, src: src }, i)) }) }) }));
|
|
162
225
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { css } from '@emotion/react';
|
|
2
2
|
import { defineInnerClasses, defineCss } from '../../utils';
|
|
3
|
-
export const classes = defineInnerClasses('
|
|
3
|
+
export const classes = defineInnerClasses('gallery', [
|
|
4
4
|
'button',
|
|
5
5
|
'control',
|
|
6
6
|
'swap',
|
|
@@ -79,14 +79,14 @@ export const style = defineCss(({ spacing, easing, breakpoints }) => css `
|
|
|
79
79
|
&, .${classes.imageItem} {
|
|
80
80
|
position: absolute;
|
|
81
81
|
top: 0;
|
|
82
|
-
}
|
|
83
82
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
&[data-transition=true] {
|
|
84
|
+
transition: all .3s ${easing.easeOut};
|
|
85
|
+
}
|
|
87
86
|
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
&[data-transition=bounce] {
|
|
88
|
+
transition: all .25s ${easing.bounce};
|
|
89
|
+
}
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
.${classes.imageItem} {
|
|
@@ -105,10 +105,6 @@ export const style = defineCss(({ spacing, easing, breakpoints }) => css `
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
.${classes.galleryContainer} .${classes.galleryWrapper} {
|
|
108
|
-
&[data-transition=true] {
|
|
109
|
-
transition: left .4s ${easing.ease};
|
|
110
|
-
}
|
|
111
|
-
|
|
112
108
|
.${classes.imageItem} {
|
|
113
109
|
padding: 0;
|
|
114
110
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { Ref } from 'react';
|
|
1
|
+
import { JSX, Ref } from 'react';
|
|
2
2
|
import { PinchableProps, PinchableRef } from '../pinchable';
|
|
3
3
|
export interface ImageItemRef extends PinchableRef {
|
|
4
4
|
isFit(): {
|
|
5
|
+
top: boolean;
|
|
6
|
+
bottom: boolean;
|
|
5
7
|
left: boolean;
|
|
6
8
|
right: boolean;
|
|
7
9
|
};
|
|
@@ -9,6 +11,7 @@ export interface ImageItemRef extends PinchableRef {
|
|
|
9
11
|
interface ImageItemProps extends PinchableProps {
|
|
10
12
|
ref?: Ref<ImageItemRef>;
|
|
11
13
|
src?: string;
|
|
14
|
+
imgProps?: JSX.IntrinsicElements['img'];
|
|
12
15
|
}
|
|
13
|
-
export declare function ImageItem({ ref, src, ...props }: ImageItemProps): import("@emotion/react/jsx-runtime").JSX.Element;
|
|
16
|
+
export declare function ImageItem({ ref, src, imgProps, ...props }: ImageItemProps): import("@emotion/react/jsx-runtime").JSX.Element;
|
|
14
17
|
export {};
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx } from "@emotion/react/jsx-runtime";
|
|
2
2
|
import { classes } from './gallery.style';
|
|
3
3
|
import { useEffect, useImperativeHandle, useRef } from 'react';
|
|
4
|
-
import { clsx } from '../../utils';
|
|
4
|
+
import { cloneRef, clsx } from '../../utils';
|
|
5
5
|
import { Pinchable } from '../pinchable';
|
|
6
|
-
export function ImageItem({ ref, src, ...props }) {
|
|
6
|
+
export function ImageItem({ ref, src, imgProps, ...props }) {
|
|
7
7
|
useImperativeHandle(ref, () => {
|
|
8
8
|
if (pinchableRef.current) {
|
|
9
9
|
pinchableRef.current.isFit = () => {
|
|
10
|
-
const { x: pinchableX, width: pinchableWidth } = pinchableRef.current.getBoundingClientRect();
|
|
11
|
-
const { x: imgX, width: imgWidth } = imgRef.current.getBoundingClientRect();
|
|
10
|
+
const { x: pinchableX, y: pinchableY, width: pinchableWidth, height: pinchableHeight } = pinchableRef.current.getBoundingClientRect();
|
|
11
|
+
const { x: imgX, y: imgY, width: imgWidth, height: imgHeight } = imgRef.current.getBoundingClientRect();
|
|
12
12
|
return {
|
|
13
|
+
top: imgY >= pinchableY,
|
|
14
|
+
bottom: imgY + imgHeight <= pinchableY + pinchableHeight,
|
|
13
15
|
left: imgX >= pinchableX,
|
|
14
16
|
right: imgX + imgWidth <= pinchableX + pinchableWidth
|
|
15
17
|
};
|
|
@@ -44,5 +46,5 @@ export function ImageItem({ ref, src, ...props }) {
|
|
|
44
46
|
resizeObserver.disconnect();
|
|
45
47
|
};
|
|
46
48
|
}, []);
|
|
47
|
-
return (_jsx(Pinchable, { ...props, ref: pinchableRef, className: clsx(classes.imageItem, props.className), children: _jsx("img", {
|
|
49
|
+
return (_jsx(Pinchable, { ...props, ref: pinchableRef, className: clsx(classes.imageItem, props.className), allowEdgeBounce: false, children: _jsx("img", { draggable: false, alt: "", src: src, ...imgProps, ref: cloneRef(imgRef, imgProps?.ref), className: clsx(classes.image, imgProps?.className) }) }));
|
|
48
50
|
}
|
|
@@ -22,11 +22,17 @@ type PinchableOwnProps = {
|
|
|
22
22
|
translate?: [number, number];
|
|
23
23
|
onTranslateChange?(translate: [number, number]): void;
|
|
24
24
|
/** 平移限制,`translate`非受控模式下有效 */
|
|
25
|
-
translateLimit?: (targetX: number, targetY: number, scale: number) => [number, number];
|
|
25
|
+
translateLimit?: (targetX: number, targetY: number, scale: number, rotateDeg: number) => [number, number];
|
|
26
26
|
defaultRotate?: number;
|
|
27
27
|
rotate?: number;
|
|
28
28
|
onRotateChange?(rotate: number): void;
|
|
29
29
|
children?: ReactElement;
|
|
30
|
+
/** 拖拽至最边缘时,是否允许弹性溢出,默认为`true` */
|
|
31
|
+
allowEdgeBounce?: boolean;
|
|
32
|
+
/** 元素弹性移动距离,默认为24 */
|
|
33
|
+
bounceElementTranslate?: number;
|
|
34
|
+
/** 手指弹性拖拽距离,默认为240 */
|
|
35
|
+
bounceDragDistance?: number;
|
|
30
36
|
};
|
|
31
37
|
export type PinchableProps<C extends ElementType = 'div'> = OverridableProps<PinchableOwnProps, C>;
|
|
32
38
|
export declare const Pinchable: <C extends ElementType = "div">(props: PinchableProps<C>) => ReactElement;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx } from "@emotion/react/jsx-runtime";
|
|
2
2
|
import { cloneElement, useImperativeHandle, useRef } from 'react';
|
|
3
|
-
import { cloneRef, clsx, range, useControlled, useGesture } from '../../utils';
|
|
3
|
+
import { cloneRef, clsx, edgeBounce, range, useControlled, useGesture } from '../../utils';
|
|
4
4
|
import { classes, style } from './pinchable.style';
|
|
5
|
-
export const Pinchable = (({ component: Component = 'div', ref, gestureOptions, defaultScale = 1, scale, onScaleChange, scaleLimit = [1, 6], defaultTranslate = [0, 0], translate, onTranslateChange, translateLimit, defaultRotate = 0, rotate, onRotateChange, children, ...props }) => {
|
|
5
|
+
export const Pinchable = (({ component: Component = 'div', ref, gestureOptions, defaultScale = 1, scale, onScaleChange, scaleLimit = [1, 6], defaultTranslate = [0, 0], translate, onTranslateChange, translateLimit, defaultRotate = 0, rotate, onRotateChange, children, allowEdgeBounce = true, bounceElementTranslate = 24, bounceDragDistance = 240, ...props }) => {
|
|
6
6
|
useImperativeHandle(ref, () => {
|
|
7
7
|
if (wrapperRef.current) {
|
|
8
8
|
wrapperRef.current.zoomIn = () => {
|
|
@@ -38,6 +38,12 @@ export const Pinchable = (({ component: Component = 'div', ref, gestureOptions,
|
|
|
38
38
|
onDrag(info, e) {
|
|
39
39
|
gestureOptions?.onDrag?.(info, e);
|
|
40
40
|
const { diff: [dx, dy], data: [startX, startY] } = info;
|
|
41
|
+
setInnerTranslate(translateLimitFn(startX + dx, startY + dy, void 0, void 0, true));
|
|
42
|
+
},
|
|
43
|
+
onDragEnd(info) {
|
|
44
|
+
gestureOptions?.onDragEnd?.(info);
|
|
45
|
+
const { diff: [dx, dy], data: [startX, startY] } = info;
|
|
46
|
+
allowTransition('bounce');
|
|
41
47
|
setInnerTranslate(translateLimitFn(startX + dx, startY + dy));
|
|
42
48
|
},
|
|
43
49
|
onPinchStart(info) {
|
|
@@ -75,9 +81,9 @@ export const Pinchable = (({ component: Component = 'div', ref, gestureOptions,
|
|
|
75
81
|
if (!children) {
|
|
76
82
|
return;
|
|
77
83
|
}
|
|
78
|
-
const translateLimitFn = (x, y, scale = innerScale.current, deg = innerRotate.current) => {
|
|
84
|
+
const translateLimitFn = (x, y, scale = innerScale.current, deg = innerRotate.current, bounce = false) => {
|
|
79
85
|
if (translateLimit) {
|
|
80
|
-
return translateLimit(x, y, scale);
|
|
86
|
+
return translateLimit(x, y, scale, deg);
|
|
81
87
|
}
|
|
82
88
|
const { clientWidth: wrapperWidth, clientHeight: wrapperHeight } = wrapperRef.current;
|
|
83
89
|
const { offsetWidth, offsetHeight } = contentRef.current;
|
|
@@ -86,14 +92,20 @@ export const Pinchable = (({ component: Component = 'div', ref, gestureOptions,
|
|
|
86
92
|
const contentHeight = (isRotated ? offsetWidth : offsetHeight) * scale;
|
|
87
93
|
const limitX = contentWidth > wrapperWidth ? (contentWidth - wrapperWidth) / 2 : 0;
|
|
88
94
|
const limitY = contentHeight > wrapperHeight ? (contentHeight - wrapperHeight) / 2 : 0;
|
|
95
|
+
if (!bounce) {
|
|
96
|
+
return [
|
|
97
|
+
range(x, -limitX, limitX),
|
|
98
|
+
range(y, -limitY, limitY)
|
|
99
|
+
];
|
|
100
|
+
}
|
|
89
101
|
return [
|
|
90
|
-
|
|
91
|
-
|
|
102
|
+
edgeBounce(x, { min: -limitX, max: limitX, allowEdgeBounce, bounceElementTranslate, bounceDragDistance }),
|
|
103
|
+
edgeBounce(y, { min: -limitY, max: limitY, allowEdgeBounce, bounceElementTranslate, bounceDragDistance })
|
|
92
104
|
];
|
|
93
105
|
};
|
|
94
106
|
const childrenProps = children.props;
|
|
95
|
-
const allowTransition = () => {
|
|
96
|
-
contentRef.current && (contentRef.current.dataset.transition =
|
|
107
|
+
const allowTransition = (transitionType = 'true') => {
|
|
108
|
+
contentRef.current && (contentRef.current.dataset.transition = transitionType);
|
|
97
109
|
};
|
|
98
110
|
const zoomFn = (targetScale, originX, originY) => {
|
|
99
111
|
allowTransition();
|
|
@@ -147,7 +159,7 @@ export const Pinchable = (({ component: Component = 'div', ref, gestureOptions,
|
|
|
147
159
|
: zoomFn(innerScale.current * 1.2, e.clientX, e.clientY);
|
|
148
160
|
};
|
|
149
161
|
const onTransitionEnd = (e) => {
|
|
150
|
-
e.currentTarget.dataset.transition = '
|
|
162
|
+
e.currentTarget.dataset.transition = '';
|
|
151
163
|
setInnerRotate(innerRotate.current % 360);
|
|
152
164
|
};
|
|
153
165
|
return (_jsx(Component, { ...props, ref: wrapperRef, css: style, className: clsx(classes.root, props.className), ...pinchableHandles, children: cloneElement(children, {
|
|
@@ -13,8 +13,14 @@ export const style = defineCss(({ easing }) => css `
|
|
|
13
13
|
touch-action: none;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
.${classes.content}
|
|
17
|
-
transition
|
|
16
|
+
.${classes.content} {
|
|
17
|
+
&[data-transition=true] {
|
|
18
|
+
transition: all .25s ${easing.easeOut};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
&[data-transition=bounce] {
|
|
22
|
+
transition: all .25s ${easing.bounce};
|
|
23
|
+
}
|
|
18
24
|
}
|
|
19
25
|
}
|
|
20
26
|
`);
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
export type BezierFunc = (x: number) => number;
|
|
1
2
|
/**
|
|
2
3
|
* 创建一个Bezier曲线函数,默认从(0,0)到(1,1)
|
|
3
4
|
* @param p1x
|
|
4
5
|
* @param p1y
|
|
5
6
|
* @param p2x
|
|
6
7
|
* @param p2y
|
|
7
|
-
* @returns {
|
|
8
|
+
* @returns {BezierFunc} 返回一个函数,接收x返回y
|
|
8
9
|
*/
|
|
9
|
-
export declare function cubicBezier(p1x: number, p1y: number, p2x: number, p2y: number):
|
|
10
|
+
export declare function cubicBezier(p1x: number, p1y: number, p2x: number, p2y: number): BezierFunc;
|
|
10
11
|
export declare namespace cubicBezier {
|
|
11
|
-
var preset: (preset: Preset) =>
|
|
12
|
+
var preset: (preset: Preset) => BezierFunc;
|
|
12
13
|
}
|
|
13
14
|
export type Preset = 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out';
|
package/dist/esm/utils/bezier.js
CHANGED
package/dist/esm/utils/dnd.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DragEndEvent } from '@dnd-kit/core';
|
|
2
2
|
import { Id, Obj } from '../types';
|
|
3
3
|
import { NodeType, SortInfo } from '../components/tree';
|
|
4
|
+
import { BezierFunc } from './bezier';
|
|
4
5
|
/**
|
|
5
6
|
* 默认提供给@dnd-kit的sensors属性
|
|
6
7
|
*/
|
|
@@ -19,3 +20,11 @@ export declare function onDndDragEnd<S extends Obj>(e: DragEndEvent, prevState:
|
|
|
19
20
|
* @param primaryKey 索引用的主键,默认为`id`
|
|
20
21
|
*/
|
|
21
22
|
export declare function onTreeNodeSort<N extends NodeType<V>, V extends Id = Id>(info: SortInfo<V>, treeNodes: N[], primaryKey?: string): N[];
|
|
23
|
+
export declare function edgeBounce(value: number, { allowEdgeBounce, min, max, bounceElementTranslate, bounceDragDistance, bezierFn }: {
|
|
24
|
+
allowEdgeBounce: boolean;
|
|
25
|
+
min: number;
|
|
26
|
+
max: number;
|
|
27
|
+
bounceElementTranslate: number;
|
|
28
|
+
bounceDragDistance: number;
|
|
29
|
+
bezierFn?: BezierFunc;
|
|
30
|
+
}): number;
|
package/dist/esm/utils/dnd.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { PointerSensor, useSensor, useSensors } from '@dnd-kit/core';
|
|
2
2
|
import { arrayMove } from '@dnd-kit/sortable';
|
|
3
|
+
import { range } from './utils';
|
|
4
|
+
import { cubicBezier } from './bezier';
|
|
3
5
|
/**
|
|
4
6
|
* 默认提供给@dnd-kit的sensors属性
|
|
5
7
|
*/
|
|
@@ -68,3 +70,16 @@ export function onTreeNodeSort(info, treeNodes, primaryKey = 'id') {
|
|
|
68
70
|
}
|
|
69
71
|
return treeNodes;
|
|
70
72
|
}
|
|
73
|
+
export function edgeBounce(value, { allowEdgeBounce, min, max, bounceElementTranslate, bounceDragDistance, bezierFn = cubicBezier(0, 0, 0, 1) }) {
|
|
74
|
+
if (allowEdgeBounce && bounceElementTranslate && bounceDragDistance > 0) {
|
|
75
|
+
value = range(value, min - bounceDragDistance, max + bounceDragDistance);
|
|
76
|
+
if (value < min) {
|
|
77
|
+
value = min - bezierFn((min - value) / bounceDragDistance) * bounceElementTranslate;
|
|
78
|
+
}
|
|
79
|
+
else if (value > max) {
|
|
80
|
+
value = max + bezierFn((value - max) / bounceDragDistance) * bounceElementTranslate;
|
|
81
|
+
}
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
return range(value, min, max);
|
|
85
|
+
}
|
package/dist/esm/utils/style.js
CHANGED
|
@@ -184,12 +184,14 @@ export function useResponsiveValue(prop, disabled = false) {
|
|
|
184
184
|
const syncBreakpoints = useSync(breakpoints);
|
|
185
185
|
const fn = () => {
|
|
186
186
|
let maxBreakpoint = 'xs';
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
187
|
+
if (typeof window !== 'undefined') {
|
|
188
|
+
for (const k in syncBreakpoints.current) {
|
|
189
|
+
if (window.innerWidth < syncBreakpoints.current[k]) {
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
if (k in responsiveObj) {
|
|
193
|
+
maxBreakpoint = k;
|
|
194
|
+
}
|
|
193
195
|
}
|
|
194
196
|
}
|
|
195
197
|
return responsiveObj[maxBreakpoint];
|