1 | import React, { forwardRef, useImperativeHandle, useRef } from 'react';
|
2 | import { useDrag } from '@use-gesture/react';
|
3 | import { useSpring, animated } from '@react-spring/web';
|
4 | import { Slide } from './slide';
|
5 | import { convertPx } from '../../utils/convert-px';
|
6 | import { bound } from '../../utils/bound';
|
7 | const classPrefix = `adm-image-viewer`;
|
8 | export const Slides = forwardRef((props, ref) => {
|
9 | const slideWidth = window.innerWidth + convertPx(16);
|
10 | const [{
|
11 | x
|
12 | }, api] = useSpring(() => ({
|
13 | x: props.defaultIndex * slideWidth,
|
14 | config: {
|
15 | tension: 250,
|
16 | clamp: true
|
17 | }
|
18 | }));
|
19 | const count = props.images.length;
|
20 | function swipeTo(index, immediate = false) {
|
21 | var _a;
|
22 | const i = bound(index, 0, count - 1);
|
23 | (_a = props.onIndexChange) === null || _a === void 0 ? void 0 : _a.call(props, i);
|
24 | api.start({
|
25 | x: i * slideWidth,
|
26 | immediate
|
27 | });
|
28 | }
|
29 | useImperativeHandle(ref, () => ({
|
30 | swipeTo
|
31 | }));
|
32 | const dragLockRef = useRef(false);
|
33 | const bind = useDrag(state => {
|
34 | if (dragLockRef.current) return;
|
35 | const [offsetX] = state.offset;
|
36 | if (state.last) {
|
37 | const minIndex = Math.floor(offsetX / slideWidth);
|
38 | const maxIndex = minIndex + 1;
|
39 | const velocityOffset = Math.min(state.velocity[0] * 2000, slideWidth) * state.direction[0];
|
40 | swipeTo(bound(Math.round((offsetX + velocityOffset) / slideWidth), minIndex, maxIndex));
|
41 | } else {
|
42 | api.start({
|
43 | x: offsetX,
|
44 | immediate: true
|
45 | });
|
46 | }
|
47 | }, {
|
48 | transform: ([x, y]) => [-x, y],
|
49 | from: () => [x.get(), 0],
|
50 | bounds: () => ({
|
51 | left: 0,
|
52 | right: (count - 1) * slideWidth
|
53 | }),
|
54 | rubberband: true,
|
55 | axis: 'x',
|
56 | pointer: {
|
57 | touch: true
|
58 | }
|
59 | });
|
60 | return React.createElement("div", Object.assign({
|
61 | className: `${classPrefix}-slides`
|
62 | }, bind()), React.createElement(animated.div, {
|
63 | className: `${classPrefix}-indicator`
|
64 | }, x.to(v => {
|
65 | const index = bound(Math.round(v / slideWidth), 0, count - 1);
|
66 | return `${index + 1} / ${count}`;
|
67 | })), React.createElement(animated.div, {
|
68 | className: `${classPrefix}-slides-inner`,
|
69 | style: {
|
70 | x: x.to(x => -x)
|
71 | }
|
72 | }, props.images.map((image, index) => React.createElement(Slide, {
|
73 | key: index,
|
74 | image: image,
|
75 | onTap: props.onTap,
|
76 | maxZoom: props.maxZoom,
|
77 | onZoomChange: zoom => {
|
78 | if (zoom !== 1) {
|
79 | const index = Math.round(x.get() / slideWidth);
|
80 | api.start({
|
81 | x: index * slideWidth
|
82 | });
|
83 | }
|
84 | },
|
85 | dragLockRef: dragLockRef
|
86 | }))));
|
87 | }); |
\ | No newline at end of file |