react-native-gesture-image-viewer 2.3.3 → 3.0.0-beta.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.
- package/README.md +5 -3
- package/lib/module/GestureViewer.js +88 -140
- package/lib/module/GestureViewer.js.map +1 -1
- package/lib/module/GestureViewerManager.js +49 -105
- package/lib/module/GestureViewerManager.js.map +1 -1
- package/lib/module/gestureViewerAnimation.js +18 -0
- package/lib/module/gestureViewerAnimation.js.map +1 -0
- package/lib/module/gestureViewerPaging.js +66 -0
- package/lib/module/gestureViewerPaging.js.map +1 -0
- package/lib/module/gestureViewerRenderWindow.js +29 -0
- package/lib/module/gestureViewerRenderWindow.js.map +1 -0
- package/lib/module/getWebContentProps.js +6 -0
- package/lib/module/getWebContentProps.js.map +1 -0
- package/lib/module/getWebContentProps.web.js +8 -0
- package/lib/module/getWebContentProps.web.js.map +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/platformTapGestures.js +4 -0
- package/lib/module/platformTapGestures.js.map +1 -0
- package/lib/module/platformTapGestures.web.js +4 -0
- package/lib/module/platformTapGestures.web.js.map +1 -0
- package/lib/module/renderWindow.js +160 -0
- package/lib/module/renderWindow.js.map +1 -0
- package/lib/module/useGestureViewer.js +386 -200
- package/lib/module/useGestureViewer.js.map +1 -1
- package/lib/module/useGestureViewerController.js +3 -3
- package/lib/module/useGestureViewerController.js.map +1 -1
- package/lib/module/useGestureViewerManagerBridge.js +85 -0
- package/lib/module/useGestureViewerManagerBridge.js.map +1 -0
- package/lib/module/useGestureViewerPaging.js +147 -65
- package/lib/module/useGestureViewerPaging.js.map +1 -1
- package/lib/module/useWebClickHandler.js +7 -0
- package/lib/module/useWebClickHandler.js.map +1 -0
- package/lib/module/useWebClickHandler.web.js +85 -0
- package/lib/module/useWebClickHandler.web.js.map +1 -0
- package/lib/module/useWebSingleTapTimer.js +12 -0
- package/lib/module/useWebSingleTapTimer.js.map +1 -0
- package/lib/module/useWebSingleTapTimer.web.js +25 -0
- package/lib/module/useWebSingleTapTimer.web.js.map +1 -0
- package/lib/module/utils/index.js +0 -77
- package/lib/module/utils/index.js.map +1 -1
- package/lib/module/utils/tapZoom.js +4 -3
- package/lib/module/utils/tapZoom.js.map +1 -1
- package/lib/typescript/src/GestureViewer.d.ts +1 -1
- package/lib/typescript/src/GestureViewer.d.ts.map +1 -1
- package/lib/typescript/src/GestureViewerManager.d.ts +20 -20
- package/lib/typescript/src/GestureViewerManager.d.ts.map +1 -1
- package/lib/typescript/src/gestureViewerAnimation.d.ts +15 -0
- package/lib/typescript/src/gestureViewerAnimation.d.ts.map +1 -0
- package/lib/typescript/src/gestureViewerPaging.d.ts +13 -0
- package/lib/typescript/src/gestureViewerPaging.d.ts.map +1 -0
- package/lib/typescript/src/gestureViewerRenderWindow.d.ts +15 -0
- package/lib/typescript/src/gestureViewerRenderWindow.d.ts.map +1 -0
- package/lib/typescript/src/getWebContentProps.d.ts +3 -0
- package/lib/typescript/src/getWebContentProps.d.ts.map +1 -0
- package/lib/typescript/src/getWebContentProps.web.d.ts +5 -0
- package/lib/typescript/src/getWebContentProps.web.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/platformTapGestures.d.ts +2 -0
- package/lib/typescript/src/platformTapGestures.d.ts.map +1 -0
- package/lib/typescript/src/platformTapGestures.web.d.ts +2 -0
- package/lib/typescript/src/platformTapGestures.web.d.ts.map +1 -0
- package/lib/typescript/src/renderWindow.d.ts +44 -0
- package/lib/typescript/src/renderWindow.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +45 -52
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/useGestureViewer.d.ts +9 -8
- package/lib/typescript/src/useGestureViewer.d.ts.map +1 -1
- package/lib/typescript/src/useGestureViewerController.d.ts +1 -1
- package/lib/typescript/src/useGestureViewerManagerBridge.d.ts +28 -0
- package/lib/typescript/src/useGestureViewerManagerBridge.d.ts.map +1 -0
- package/lib/typescript/src/useGestureViewerPaging.d.ts +31 -2
- package/lib/typescript/src/useGestureViewerPaging.d.ts.map +1 -1
- package/lib/typescript/src/useWebClickHandler.d.ts +35 -0
- package/lib/typescript/src/useWebClickHandler.d.ts.map +1 -0
- package/lib/typescript/src/useWebClickHandler.web.d.ts +36 -0
- package/lib/typescript/src/useWebClickHandler.web.d.ts.map +1 -0
- package/lib/typescript/src/useWebSingleTapTimer.d.ts +6 -0
- package/lib/typescript/src/useWebSingleTapTimer.d.ts.map +1 -0
- package/lib/typescript/src/useWebSingleTapTimer.web.d.ts +6 -0
- package/lib/typescript/src/useWebSingleTapTimer.web.d.ts.map +1 -0
- package/lib/typescript/src/utils/index.d.ts +0 -20
- package/lib/typescript/src/utils/index.d.ts.map +1 -1
- package/lib/typescript/src/utils/tapZoom.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/GestureViewer.tsx +104 -191
- package/src/GestureViewerManager.ts +77 -122
- package/src/gestureViewerAnimation.ts +18 -0
- package/src/gestureViewerPaging.ts +116 -0
- package/src/gestureViewerRenderWindow.ts +56 -0
- package/src/getWebContentProps.ts +5 -0
- package/src/getWebContentProps.web.ts +5 -0
- package/src/index.tsx +1 -0
- package/src/platformTapGestures.ts +1 -0
- package/src/platformTapGestures.web.ts +1 -0
- package/src/renderWindow.ts +253 -0
- package/src/types.ts +44 -99
- package/src/useGestureViewer.ts +557 -258
- package/src/useGestureViewerController.ts +3 -3
- package/src/useGestureViewerManagerBridge.ts +118 -0
- package/src/useGestureViewerPaging.ts +277 -98
- package/src/useWebClickHandler.ts +44 -0
- package/src/useWebClickHandler.web.ts +146 -0
- package/src/useWebSingleTapTimer.ts +10 -0
- package/src/useWebSingleTapTimer.web.ts +30 -0
- package/src/utils/index.ts +0 -102
- package/src/utils/tapZoom.ts +4 -3
- package/lib/module/WebPagingFixStyle.js +0 -25
- package/lib/module/WebPagingFixStyle.js.map +0 -1
- package/lib/module/scheduleInitialScroll.js +0 -21
- package/lib/module/scheduleInitialScroll.js.map +0 -1
- package/lib/module/useGestureViewerPaging.types.js +0 -4
- package/lib/module/useGestureViewerPaging.types.js.map +0 -1
- package/lib/module/useGestureViewerPaging.web.js +0 -275
- package/lib/module/useGestureViewerPaging.web.js.map +0 -1
- package/lib/module/utils/FlashList.js +0 -9
- package/lib/module/utils/FlashList.js.map +0 -1
- package/lib/module/utils/webScroll.js +0 -70
- package/lib/module/utils/webScroll.js.map +0 -1
- package/lib/typescript/src/WebPagingFixStyle.d.ts +0 -6
- package/lib/typescript/src/WebPagingFixStyle.d.ts.map +0 -1
- package/lib/typescript/src/scheduleInitialScroll.d.ts +0 -3
- package/lib/typescript/src/scheduleInitialScroll.d.ts.map +0 -1
- package/lib/typescript/src/useGestureViewerPaging.types.d.ts +0 -41
- package/lib/typescript/src/useGestureViewerPaging.types.d.ts.map +0 -1
- package/lib/typescript/src/useGestureViewerPaging.web.d.ts +0 -3
- package/lib/typescript/src/useGestureViewerPaging.web.d.ts.map +0 -1
- package/lib/typescript/src/utils/FlashList.d.ts +0 -2
- package/lib/typescript/src/utils/FlashList.d.ts.map +0 -1
- package/lib/typescript/src/utils/webScroll.d.ts +0 -18
- package/lib/typescript/src/utils/webScroll.d.ts.map +0 -1
- package/src/WebPagingFixStyle.tsx +0 -25
- package/src/scheduleInitialScroll.ts +0 -36
- package/src/useGestureViewerPaging.types.ts +0 -41
- package/src/useGestureViewerPaging.web.ts +0 -434
- package/src/utils/FlashList.ts +0 -7
- package/src/utils/webScroll.ts +0 -96
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
|
-
import {
|
|
3
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { useWindowDimensions } from 'react-native';
|
|
5
5
|
import { Gesture } from 'react-native-gesture-handler';
|
|
6
|
-
import { Easing, interpolate, useAnimatedReaction, useAnimatedStyle, useSharedValue, withSpring, withTiming } from 'react-native-reanimated';
|
|
6
|
+
import { Easing, cancelAnimation, interpolate, useAnimatedReaction, useAnimatedStyle, useSharedValue, withSpring, withTiming } from 'react-native-reanimated';
|
|
7
7
|
import { scheduleOnRN } from 'react-native-worklets';
|
|
8
|
+
import { PAGE_SPRING_CONFIG, SWIPE_THRESHOLD_RATIO, SWIPE_VELOCITY_THRESHOLD } from "./gestureViewerAnimation.js";
|
|
9
|
+
import { normalizeHorizontalSwipeThreshold } from "./gestureViewerPaging.js";
|
|
8
10
|
import { registry } from "./GestureViewerRegistry.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
11
|
+
import { resolveGestureViewerRenderWindow } from "./gestureViewerRenderWindow.js";
|
|
12
|
+
import { enableNativeTapGestures } from './platformTapGestures';
|
|
13
|
+
import { getLogicalIndex, getPageStride, getVirtualIndexForLogicalIndex, normalizePageSpacing, clampIndex, resolveNavigation, shouldRunNavigationDuringTransition } from "./renderWindow.js";
|
|
14
|
+
import { useGestureViewerManagerBridge } from "./useGestureViewerManagerBridge.js";
|
|
15
|
+
import { useGestureViewerPaging } from "./useGestureViewerPaging.js";
|
|
16
|
+
import { useWebClickHandler } from './useWebClickHandler';
|
|
17
|
+
import { useWebSingleTapTimer } from './useWebSingleTapTimer';
|
|
18
|
+
import { createBoundsConstraint } from "./utils/index.js";
|
|
12
19
|
import { getDismissDistance, shouldDismissByDirection } from "./utils/dismiss.js";
|
|
13
20
|
import { applyTapZoomAtPoint } from "./utils/tapZoom.js";
|
|
14
21
|
import { calculateFocalPointTranslation, shouldAcceptFocalPoint } from "./utils/zoom.js";
|
|
22
|
+
const isValidTriggerRect = rect => {
|
|
23
|
+
return !!rect && rect.width > 0 && rect.height > 0;
|
|
24
|
+
};
|
|
15
25
|
export const useGestureViewer = ({
|
|
16
26
|
data,
|
|
17
27
|
initialIndex = 0,
|
|
@@ -21,11 +31,12 @@ export const useGestureViewer = ({
|
|
|
21
31
|
dismiss,
|
|
22
32
|
enableDoubleTapZoom = true,
|
|
23
33
|
enablePinchZoom = true,
|
|
24
|
-
|
|
34
|
+
horizontalSwipe,
|
|
25
35
|
enablePanWhenZoomed = true,
|
|
26
36
|
enableLoop = false,
|
|
27
37
|
maxZoomScale = 2,
|
|
28
|
-
|
|
38
|
+
pageSpacing = 0,
|
|
39
|
+
windowSize = 3,
|
|
29
40
|
height: customHeight,
|
|
30
41
|
id = 'default',
|
|
31
42
|
onDismissStart,
|
|
@@ -39,42 +50,59 @@ export const useGestureViewer = ({
|
|
|
39
50
|
} = useWindowDimensions();
|
|
40
51
|
const width = customWidth || screenWidth;
|
|
41
52
|
const height = customHeight || screenHeight;
|
|
53
|
+
const dataLength = data?.length || 0;
|
|
54
|
+
const normalizedPageSpacing = normalizePageSpacing(pageSpacing);
|
|
55
|
+
const pageStride = getPageStride(width, normalizedPageSpacing);
|
|
56
|
+
const initialCurrentIndex = clampIndex(initialIndex, dataLength);
|
|
57
|
+
const horizontalSwipeEnabled = horizontalSwipe?.enabled ?? true;
|
|
58
|
+
const horizontalSwipeDistanceThresholdRatio = normalizeHorizontalSwipeThreshold(horizontalSwipe?.distanceThresholdRatio, SWIPE_THRESHOLD_RATIO);
|
|
59
|
+
const horizontalSwipeVelocityThreshold = normalizeHorizontalSwipeThreshold(horizontalSwipe?.velocityThreshold, SWIPE_VELOCITY_THRESHOLD);
|
|
42
60
|
const dismissGestureRef = useRef(undefined);
|
|
43
61
|
const [isZoomed, setIsZoomed] = useState(false);
|
|
44
62
|
const [isRotated, setIsRotated] = useState(false);
|
|
45
63
|
const [isPinching, setIsPinching] = useState(false);
|
|
46
64
|
const [shouldStartTriggerAnimation, setShouldStartTriggerAnimation] = useState(false);
|
|
47
|
-
const [
|
|
48
|
-
const [
|
|
49
|
-
const [activeTriggerNode, setActiveTriggerNode] = useState(
|
|
50
|
-
const
|
|
65
|
+
const [currentIndex, setCurrentIndex] = useState(initialCurrentIndex);
|
|
66
|
+
const [centerVirtualIndex, setCenterVirtualIndex] = useState(initialCurrentIndex);
|
|
67
|
+
const [activeTriggerNode, setActiveTriggerNode] = useState(() => registry.getActiveTriggerNode(id));
|
|
68
|
+
const [isTriggerOpening, setIsTriggerOpening] = useState(() => !!registry.getActiveTriggerNode(id));
|
|
51
69
|
const triggerRectRef = useRef(null);
|
|
52
|
-
const pendingIndexRef = useRef(
|
|
70
|
+
const pendingIndexRef = useRef(initialCurrentIndex);
|
|
71
|
+
const currentIndexRef = useRef(initialCurrentIndex);
|
|
72
|
+
const centerVirtualIndexRef = useRef(initialCurrentIndex);
|
|
73
|
+
const previousInitialIndexRef = useRef(initialIndex);
|
|
74
|
+
const hasResolvedInitialIndexRef = useRef(dataLength > 0);
|
|
53
75
|
const onAnimationCompleteRef = useRef(triggerAnimation?.onAnimationComplete);
|
|
54
76
|
const onSingleTapRef = useRef(onSingleTap);
|
|
55
77
|
const dataRef = useRef(data);
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
78
|
+
const dataLengthRef = useRef(dataLength);
|
|
79
|
+
const enableLoopRef = useRef(enableLoop);
|
|
80
|
+
const managerRef = useRef(null);
|
|
81
|
+
const isZoomedRef = useRef(isZoomed);
|
|
82
|
+
const isRotatedRef = useRef(isRotated);
|
|
83
|
+
const isPinchingRef = useRef(isPinching);
|
|
60
84
|
const initialTranslateY = useSharedValue(0);
|
|
61
85
|
const initialTranslateX = useSharedValue(0);
|
|
62
86
|
const startScale = useSharedValue(1);
|
|
63
87
|
const translateY = useSharedValue(0);
|
|
64
88
|
const translateX = useSharedValue(0);
|
|
65
89
|
const scale = useSharedValue(1);
|
|
66
|
-
const backdropOpacity = useSharedValue(1);
|
|
67
90
|
const rotation = useSharedValue(0);
|
|
68
91
|
const triggerScale = useSharedValue(1);
|
|
69
92
|
const triggerTranslateX = useSharedValue(0);
|
|
70
93
|
const triggerTranslateY = useSharedValue(0);
|
|
71
|
-
const triggerOpacity = useSharedValue(1);
|
|
94
|
+
const triggerOpacity = useSharedValue(activeTriggerNode ? 0 : 1);
|
|
95
|
+
const hasZoomChangeListeners = useSharedValue(false);
|
|
96
|
+
const hasRotationChangeListeners = useSharedValue(false);
|
|
72
97
|
const lastFocalX = useSharedValue(0);
|
|
73
98
|
const lastFocalY = useSharedValue(0);
|
|
74
99
|
const startFocalX = useSharedValue(0);
|
|
75
100
|
const startFocalY = useSharedValue(0);
|
|
76
101
|
const hasActiveFocal = useSharedValue(false);
|
|
77
|
-
const
|
|
102
|
+
const {
|
|
103
|
+
clearPendingWebSingleTap,
|
|
104
|
+
scheduleWebSingleTap
|
|
105
|
+
} = useWebSingleTapTimer();
|
|
78
106
|
const animationConfig = useMemo(() => ({
|
|
79
107
|
duration: triggerAnimation?.duration ?? 300,
|
|
80
108
|
easing: triggerAnimation?.easing ?? Easing.bezier(0.25, 0.1, 0.25, 1),
|
|
@@ -87,20 +115,22 @@ export const useGestureViewer = ({
|
|
|
87
115
|
resistance: dismiss?.resistance ?? 2,
|
|
88
116
|
threshold: dismiss?.threshold ?? 80
|
|
89
117
|
}), [dismiss?.direction, dismiss?.enabled, dismiss?.threshold, dismiss?.resistance, dismiss?.fadeBackdrop]);
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
118
|
+
const {
|
|
119
|
+
centerVirtualIndex: renderCenterVirtualIndex,
|
|
120
|
+
currentIndex: renderCurrentIndex,
|
|
121
|
+
slots: renderWindowSlots
|
|
122
|
+
} = resolveGestureViewerRenderWindow({
|
|
123
|
+
centerVirtualIndex,
|
|
124
|
+
currentIndex,
|
|
125
|
+
data,
|
|
126
|
+
enableLoop,
|
|
127
|
+
isTriggerOpening,
|
|
128
|
+
windowSize
|
|
129
|
+
});
|
|
96
130
|
const constrainTranslation = useMemo(() => createBoundsConstraint({
|
|
97
131
|
height,
|
|
98
132
|
width
|
|
99
133
|
}), [width, height]);
|
|
100
|
-
const scrollTo = useCallback((index, animated) => {
|
|
101
|
-
const scrollAction = createScrollAction(listRef.current, width + itemSpacing);
|
|
102
|
-
return scrollAction.scrollTo(index, animated);
|
|
103
|
-
}, [width, itemSpacing]);
|
|
104
134
|
const resetTransformState = useCallback(() => {
|
|
105
135
|
translateX.set(withTiming(0));
|
|
106
136
|
translateY.set(withTiming(0));
|
|
@@ -110,111 +140,240 @@ export const useGestureViewer = ({
|
|
|
110
140
|
scale.set(withTiming(1));
|
|
111
141
|
rotation.set(0);
|
|
112
142
|
}, [initialTranslateX, initialTranslateY, rotation, scale, startScale, translateX, translateY]);
|
|
113
|
-
const
|
|
114
|
-
|
|
143
|
+
const resetTransformStateImmediately = useCallback(() => {
|
|
144
|
+
cancelAnimation(translateX);
|
|
145
|
+
cancelAnimation(translateY);
|
|
146
|
+
cancelAnimation(initialTranslateX);
|
|
147
|
+
cancelAnimation(initialTranslateY);
|
|
148
|
+
cancelAnimation(startScale);
|
|
149
|
+
cancelAnimation(scale);
|
|
150
|
+
cancelAnimation(rotation);
|
|
151
|
+
translateX.set(0);
|
|
152
|
+
translateY.set(0);
|
|
153
|
+
initialTranslateX.set(0);
|
|
154
|
+
initialTranslateY.set(0);
|
|
155
|
+
startScale.set(1);
|
|
156
|
+
scale.set(1);
|
|
157
|
+
rotation.set(0);
|
|
158
|
+
}, [initialTranslateX, initialTranslateY, rotation, scale, startScale, translateX, translateY]);
|
|
159
|
+
const commitCurrentIndex = useCallback(nextIndex => {
|
|
160
|
+
pendingIndexRef.current = nextIndex;
|
|
161
|
+
currentIndexRef.current = nextIndex;
|
|
162
|
+
setCurrentIndex(nextIndex);
|
|
163
|
+
managerRef.current?.notifyStateChange();
|
|
164
|
+
}, []);
|
|
165
|
+
const commitVirtualIndexOnly = useCallback(nextVirtualIndex => {
|
|
166
|
+
const nextLogicalIndex = getLogicalIndex(nextVirtualIndex, dataLengthRef.current, enableLoopRef.current);
|
|
167
|
+
if (nextLogicalIndex === null) {
|
|
115
168
|
return;
|
|
116
169
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
170
|
+
centerVirtualIndexRef.current = nextVirtualIndex;
|
|
171
|
+
setCenterVirtualIndex(nextVirtualIndex);
|
|
172
|
+
commitCurrentIndex(nextLogicalIndex);
|
|
173
|
+
}, [commitCurrentIndex]);
|
|
174
|
+
const {
|
|
175
|
+
animateToVirtualPage,
|
|
176
|
+
horizontalPagingGesture,
|
|
177
|
+
isPageTransitioningRef,
|
|
178
|
+
pageTransitionLocked,
|
|
179
|
+
snapToVirtualPage,
|
|
180
|
+
visualPage
|
|
181
|
+
} = useGestureViewerPaging({
|
|
182
|
+
centerVirtualIndex,
|
|
183
|
+
clearPendingWebSingleTap,
|
|
184
|
+
commitVirtualIndexOnly,
|
|
185
|
+
currentIndex,
|
|
186
|
+
dataLength,
|
|
187
|
+
enableLoop,
|
|
188
|
+
horizontalSwipeDistanceThresholdRatio,
|
|
189
|
+
horizontalSwipeEnabled,
|
|
190
|
+
horizontalSwipeVelocityThreshold,
|
|
191
|
+
initialPage: initialCurrentIndex,
|
|
192
|
+
isPinching,
|
|
193
|
+
isRotated,
|
|
194
|
+
isTriggerOpening,
|
|
195
|
+
isZoomed,
|
|
196
|
+
pageStride,
|
|
197
|
+
width
|
|
198
|
+
});
|
|
199
|
+
const navigateToIndex = useCallback((targetIndex, options, preferredDirection) => {
|
|
200
|
+
const resolution = resolveNavigation({
|
|
201
|
+
currentIndex: currentIndexRef.current,
|
|
202
|
+
dataLength: dataLengthRef.current,
|
|
203
|
+
enableLoop: enableLoopRef.current,
|
|
204
|
+
preferredDirection,
|
|
205
|
+
targetIndex
|
|
206
|
+
});
|
|
207
|
+
if (resolution.kind === 'noop') {
|
|
121
208
|
return;
|
|
122
209
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
210
|
+
if (isPageTransitioningRef.current && !shouldRunNavigationDuringTransition(resolution, options)) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const targetVirtualIndex = resolution.kind === 'step' ? centerVirtualIndexRef.current + resolution.direction : getVirtualIndexForLogicalIndex(resolution.targetIndex, centerVirtualIndexRef.current, dataLengthRef.current, enableLoopRef.current);
|
|
214
|
+
if (targetVirtualIndex === null) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (resolution.kind !== 'step' || options?.animated === false) {
|
|
218
|
+
resetTransformStateImmediately();
|
|
219
|
+
snapToVirtualPage(targetVirtualIndex);
|
|
126
220
|
return;
|
|
127
221
|
}
|
|
128
|
-
manager.setCurrentIndex(nextIndex);
|
|
129
|
-
manager.notifyStateChange();
|
|
130
222
|
resetTransformState();
|
|
131
|
-
|
|
223
|
+
animateToVirtualPage(targetVirtualIndex);
|
|
224
|
+
}, [animateToVirtualPage, isPageTransitioningRef, resetTransformStateImmediately, resetTransformState, snapToVirtualPage]);
|
|
225
|
+
const navigateByDirection = useCallback(direction => {
|
|
226
|
+
const currentDataLength = dataLengthRef.current;
|
|
227
|
+
if (currentDataLength <= 0) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const nextIndex = currentIndexRef.current + direction;
|
|
231
|
+
if (nextIndex >= 0 && nextIndex < currentDataLength) {
|
|
232
|
+
navigateToIndex(nextIndex, undefined, direction);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
if (!enableLoopRef.current || currentDataLength <= 1) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
navigateToIndex(direction === 1 ? 0 : currentDataLength - 1, undefined, direction);
|
|
239
|
+
}, [navigateToIndex]);
|
|
240
|
+
const navigateToNext = useCallback(() => {
|
|
241
|
+
navigateByDirection(1);
|
|
242
|
+
}, [navigateByDirection]);
|
|
243
|
+
const navigateToPrevious = useCallback(() => {
|
|
244
|
+
navigateByDirection(-1);
|
|
245
|
+
}, [navigateByDirection]);
|
|
246
|
+
useGestureViewerManagerBridge({
|
|
247
|
+
currentIndexRef,
|
|
248
|
+
dataLengthRef,
|
|
249
|
+
goToIndex: navigateToIndex,
|
|
250
|
+
goToNext: navigateToNext,
|
|
251
|
+
goToPrevious: navigateToPrevious,
|
|
252
|
+
hasRotationChangeListeners,
|
|
253
|
+
hasZoomChangeListeners,
|
|
254
|
+
height,
|
|
255
|
+
id,
|
|
256
|
+
managerRef,
|
|
257
|
+
maxZoomScale,
|
|
258
|
+
rotation,
|
|
259
|
+
scale,
|
|
260
|
+
translateX,
|
|
261
|
+
translateY,
|
|
262
|
+
width
|
|
263
|
+
});
|
|
132
264
|
const emitZoomChange = useCallback((currentScale, prevScale) => {
|
|
133
265
|
managerRef.current?.emitZoomChange(currentScale, prevScale);
|
|
134
266
|
}, []);
|
|
135
267
|
const emitRotationChange = useCallback((currentRotation, prevRotation) => {
|
|
136
268
|
managerRef.current?.emitRotationChange(currentRotation, prevRotation);
|
|
137
269
|
}, []);
|
|
138
|
-
const
|
|
270
|
+
const finishTriggerOpening = useCallback(() => {
|
|
271
|
+
setIsTriggerOpening(false);
|
|
139
272
|
onAnimationCompleteRef.current?.();
|
|
140
273
|
}, []);
|
|
141
274
|
useAnimatedReaction(() => scale.get(), (currentScale, previousScale) => {
|
|
142
|
-
if (currentScale !== previousScale) {
|
|
275
|
+
if (currentScale !== previousScale && hasZoomChangeListeners.get()) {
|
|
143
276
|
scheduleOnRN(emitZoomChange, currentScale, previousScale);
|
|
144
277
|
}
|
|
145
|
-
|
|
278
|
+
const currentIsZoomed = currentScale > 1;
|
|
279
|
+
const previousIsZoomed = (previousScale ?? 1) > 1;
|
|
280
|
+
if (previousScale === null || currentIsZoomed !== previousIsZoomed) {
|
|
281
|
+
scheduleOnRN(setIsZoomed, currentIsZoomed);
|
|
282
|
+
}
|
|
146
283
|
});
|
|
147
284
|
useAnimatedReaction(() => rotation.get(), (currentRotation, previousRotation) => {
|
|
148
|
-
if (currentRotation !== previousRotation) {
|
|
285
|
+
if (currentRotation !== previousRotation && hasRotationChangeListeners.get()) {
|
|
149
286
|
scheduleOnRN(emitRotationChange, currentRotation, previousRotation);
|
|
150
287
|
}
|
|
151
|
-
|
|
288
|
+
const currentIsRotated = currentRotation % 360 !== 0;
|
|
289
|
+
const previousIsRotated = (previousRotation ?? 0) % 360 !== 0;
|
|
290
|
+
if (previousRotation === null || currentIsRotated !== previousIsRotated) {
|
|
291
|
+
scheduleOnRN(setIsRotated, currentIsRotated);
|
|
292
|
+
}
|
|
152
293
|
});
|
|
153
294
|
useEffect(() => {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
setCurrentIndex(state.currentIndex);
|
|
160
|
-
});
|
|
295
|
+
return registry.subscribeToActiveTrigger(id, node => {
|
|
296
|
+
setActiveTriggerNode(node);
|
|
297
|
+
if (node) {
|
|
298
|
+
setIsTriggerOpening(true);
|
|
299
|
+
}
|
|
161
300
|
});
|
|
162
|
-
return () => {
|
|
163
|
-
unsubscribeFromRegistry();
|
|
164
|
-
unsubscribe?.();
|
|
165
|
-
};
|
|
166
301
|
}, [id]);
|
|
167
302
|
useEffect(() => {
|
|
168
|
-
|
|
169
|
-
}, [
|
|
303
|
+
dataRef.current = data;
|
|
304
|
+
}, [data]);
|
|
170
305
|
useEffect(() => {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
manager.setDataLength(dataLength);
|
|
176
|
-
manager.setEnableHorizontalSwipe(enableHorizontalSwipe);
|
|
177
|
-
manager.setCurrentIndex(initialIndex);
|
|
178
|
-
manager.setWidth(width + itemSpacing);
|
|
179
|
-
manager.setHeight(height);
|
|
180
|
-
manager.setZoomSharedValues(scale, translateX, translateY, maxZoomScale);
|
|
181
|
-
manager.setResetTransformCallback(resetTransformState);
|
|
182
|
-
manager.setRotation(rotation);
|
|
183
|
-
manager.setEnableLoop(enableLoop);
|
|
184
|
-
manager.notifyStateChange();
|
|
185
|
-
}, [dataLength, enableHorizontalSwipe, initialIndex, manager, width, itemSpacing, maxZoomScale, enableLoop, scale, height, resetTransformState, translateX, translateY, rotation]);
|
|
306
|
+
isZoomedRef.current = isZoomed;
|
|
307
|
+
}, [isZoomed]);
|
|
186
308
|
useEffect(() => {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
}
|
|
190
|
-
manager.setListRef(listRef.current);
|
|
191
|
-
}, [manager]);
|
|
309
|
+
isRotatedRef.current = isRotated;
|
|
310
|
+
}, [isRotated]);
|
|
192
311
|
useEffect(() => {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
rotation.set(0);
|
|
199
|
-
if (adjustedInitialIndex <= 0 || !listRef.current) {
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
return scheduleInitialScroll(() => {
|
|
203
|
-
scrollTo(adjustedInitialIndex, false);
|
|
204
|
-
});
|
|
205
|
-
}, [adjustedInitialIndex, translateY, backdropOpacity, translateX, scale, startScale, rotation, scrollTo]);
|
|
312
|
+
isPinchingRef.current = isPinching;
|
|
313
|
+
}, [isPinching]);
|
|
314
|
+
useEffect(() => {
|
|
315
|
+
onSingleTapRef.current = onSingleTap;
|
|
316
|
+
}, [onSingleTap]);
|
|
206
317
|
useEffect(() => {
|
|
207
318
|
onAnimationCompleteRef.current = triggerAnimation?.onAnimationComplete;
|
|
208
319
|
}, [triggerAnimation?.onAnimationComplete]);
|
|
320
|
+
useLayoutEffect(() => {
|
|
321
|
+
const initialIndexChanged = previousInitialIndexRef.current !== initialIndex;
|
|
322
|
+
const shouldResolveInitialIndex = initialIndexChanged || !hasResolvedInitialIndexRef.current && dataLength > 0;
|
|
323
|
+
previousInitialIndexRef.current = initialIndex;
|
|
324
|
+
dataLengthRef.current = dataLength;
|
|
325
|
+
enableLoopRef.current = enableLoop;
|
|
326
|
+
hasResolvedInitialIndexRef.current = dataLength > 0;
|
|
327
|
+
const nextIndex = shouldResolveInitialIndex ? clampIndex(initialIndex, dataLength) : clampIndex(currentIndexRef.current, dataLength);
|
|
328
|
+
const nextVirtualIndex = getVirtualIndexForLogicalIndex(nextIndex, centerVirtualIndexRef.current, dataLength, enableLoop) ?? nextIndex;
|
|
329
|
+
const previousIndex = currentIndexRef.current;
|
|
330
|
+
const previousVirtualIndex = centerVirtualIndexRef.current;
|
|
331
|
+
const shouldSyncVirtualPage = isPageTransitioningRef.current || previousVirtualIndex !== nextVirtualIndex;
|
|
332
|
+
const shouldResetTransform = initialIndexChanged || previousIndex !== nextIndex || shouldSyncVirtualPage;
|
|
333
|
+
if (shouldSyncVirtualPage) {
|
|
334
|
+
snapToVirtualPage(nextVirtualIndex);
|
|
335
|
+
if (dataLength === 0) {
|
|
336
|
+
centerVirtualIndexRef.current = nextVirtualIndex;
|
|
337
|
+
setCenterVirtualIndex(nextVirtualIndex);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
const shouldCommitIndexOutsidePaging = !shouldSyncVirtualPage || dataLength === 0;
|
|
341
|
+
if (shouldCommitIndexOutsidePaging && previousIndex !== nextIndex) {
|
|
342
|
+
commitCurrentIndex(nextIndex);
|
|
343
|
+
}
|
|
344
|
+
if (shouldCommitIndexOutsidePaging && previousIndex === nextIndex) {
|
|
345
|
+
managerRef.current?.notifyStateChange();
|
|
346
|
+
}
|
|
347
|
+
if (shouldResetTransform) {
|
|
348
|
+
resetTransformState();
|
|
349
|
+
}
|
|
350
|
+
}, [commitCurrentIndex, dataLength, enableLoop, initialIndex, isPageTransitioningRef, resetTransformState, snapToVirtualPage]);
|
|
209
351
|
useEffect(() => {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}, [
|
|
352
|
+
return () => {
|
|
353
|
+
triggerRectRef.current = null;
|
|
354
|
+
clearPendingWebSingleTap();
|
|
355
|
+
};
|
|
356
|
+
}, [clearPendingWebSingleTap]);
|
|
215
357
|
useEffect(() => {
|
|
216
|
-
|
|
217
|
-
|
|
358
|
+
if (!autoPlay || dataLength <= 1 || isTriggerOpening || isZoomed || isRotated || isPinching || !enableLoop && currentIndex >= dataLength - 1) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
const interval = Math.max(250, Math.floor(autoPlayInterval || 0));
|
|
362
|
+
if (!Number.isFinite(interval)) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const timer = setInterval(() => {
|
|
366
|
+
if (isPageTransitioningRef.current || isZoomedRef.current || isRotatedRef.current || isPinchingRef.current) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
const nextIndex = currentIndexRef.current >= dataLengthRef.current - 1 ? enableLoopRef.current ? 0 : null : currentIndexRef.current + 1;
|
|
370
|
+
if (nextIndex === null) {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
navigateToIndex(nextIndex);
|
|
374
|
+
}, interval);
|
|
375
|
+
return () => clearInterval(timer);
|
|
376
|
+
}, [autoPlay, autoPlayInterval, currentIndex, dataLength, enableLoop, isPinching, isRotated, isTriggerOpening, isZoomed, isPageTransitioningRef, navigateToIndex]);
|
|
218
377
|
useEffect(() => {
|
|
219
378
|
if (shouldStartTriggerAnimation && triggerRectRef.current) {
|
|
220
379
|
const startX = triggerRectRef.current.x + triggerRectRef.current.width / 2 - width / 2;
|
|
@@ -226,7 +385,7 @@ export const useGestureViewer = ({
|
|
|
226
385
|
triggerOpacity.set(0);
|
|
227
386
|
triggerScale.set(withTiming(1, animationConfig, finished => {
|
|
228
387
|
if (finished) {
|
|
229
|
-
scheduleOnRN(
|
|
388
|
+
scheduleOnRN(finishTriggerOpening);
|
|
230
389
|
}
|
|
231
390
|
}));
|
|
232
391
|
triggerTranslateX.set(withTiming(0, animationConfig));
|
|
@@ -238,9 +397,15 @@ export const useGestureViewer = ({
|
|
|
238
397
|
}));
|
|
239
398
|
setShouldStartTriggerAnimation(false);
|
|
240
399
|
}
|
|
241
|
-
}, [shouldStartTriggerAnimation, animationConfig, width, height, triggerOpacity, triggerScale, triggerTranslateX, triggerTranslateY,
|
|
400
|
+
}, [shouldStartTriggerAnimation, animationConfig, width, height, triggerOpacity, triggerScale, triggerTranslateX, triggerTranslateY, finishTriggerOpening]);
|
|
242
401
|
useEffect(() => {
|
|
243
|
-
if (!activeTriggerNode
|
|
402
|
+
if (!activeTriggerNode) {
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
if (typeof activeTriggerNode.measure !== 'function') {
|
|
406
|
+
setIsTriggerOpening(false);
|
|
407
|
+
triggerOpacity.set(1);
|
|
408
|
+
registry.clearActiveTriggerNode(id);
|
|
244
409
|
return;
|
|
245
410
|
}
|
|
246
411
|
activeTriggerNode.measure((_x, _y, measuredWidth, measuredHeight, pageX, pageY) => {
|
|
@@ -251,6 +416,8 @@ export const useGestureViewer = ({
|
|
|
251
416
|
y: pageY
|
|
252
417
|
};
|
|
253
418
|
if (!isValidTriggerRect(nextTriggerRect)) {
|
|
419
|
+
setIsTriggerOpening(false);
|
|
420
|
+
triggerOpacity.set(1);
|
|
254
421
|
registry.clearActiveTriggerNode(id);
|
|
255
422
|
return;
|
|
256
423
|
}
|
|
@@ -259,12 +426,7 @@ export const useGestureViewer = ({
|
|
|
259
426
|
setShouldStartTriggerAnimation(true);
|
|
260
427
|
registry.clearActiveTriggerNode(id);
|
|
261
428
|
});
|
|
262
|
-
}, [activeTriggerNode, id,
|
|
263
|
-
useEffect(() => {
|
|
264
|
-
return () => {
|
|
265
|
-
triggerRectRef.current = null;
|
|
266
|
-
};
|
|
267
|
-
}, []);
|
|
429
|
+
}, [activeTriggerNode, id, triggerOpacity]);
|
|
268
430
|
const animateDismissToRect = useCallback(rect => {
|
|
269
431
|
const endX = rect.x + rect.width / 2 - width / 2;
|
|
270
432
|
const endY = rect.y + rect.height / 2 - height / 2;
|
|
@@ -284,6 +446,9 @@ export const useGestureViewer = ({
|
|
|
284
446
|
}
|
|
285
447
|
}, [onDismiss]);
|
|
286
448
|
const handleDismiss = useCallback(() => {
|
|
449
|
+
if (isPageTransitioningRef.current) {
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
287
452
|
onDismissStart?.();
|
|
288
453
|
const dismissTargetIndex = pendingIndexRef.current;
|
|
289
454
|
const indexedTriggerNode = registry.getIndexedTriggerNode(id, dismissTargetIndex);
|
|
@@ -312,30 +477,98 @@ export const useGestureViewer = ({
|
|
|
312
477
|
return;
|
|
313
478
|
}
|
|
314
479
|
dismissWithoutTrigger();
|
|
315
|
-
}, [animateDismissToRect, dismissWithoutTrigger, id,
|
|
480
|
+
}, [animateDismissToRect, dismissWithoutTrigger, id, isPageTransitioningRef, onDismissStart]);
|
|
316
481
|
const dismissGesture = useMemo(() => {
|
|
317
|
-
const canDismiss = !isZoomed && dismissOptions.enabled;
|
|
482
|
+
const canDismiss = !isTriggerOpening && !isZoomed && dismissOptions.enabled;
|
|
318
483
|
return Gesture.Pan().minDistance(10).averageTouches(true).activeCursor('grabbing').activeOffsetY([-10, 10]).failOffsetX([-10, 10]).withRef(dismissGestureRef).enabled(canDismiss).onUpdate(event => {
|
|
484
|
+
if (pageTransitionLocked.get()) {
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
319
487
|
translateY.set(event.translationY / dismissOptions.resistance);
|
|
320
488
|
}).onEnd(event => {
|
|
489
|
+
if (pageTransitionLocked.get()) {
|
|
490
|
+
translateY.set(withSpring(0, PAGE_SPRING_CONFIG));
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
321
493
|
if (canDismiss && shouldDismissByDirection(event.translationY, dismissOptions.threshold, dismissOptions.direction)) {
|
|
322
494
|
scheduleOnRN(handleDismiss);
|
|
323
495
|
return;
|
|
324
496
|
}
|
|
325
|
-
translateY.set(withSpring(0,
|
|
326
|
-
damping: 50,
|
|
327
|
-
energyThreshold: 6e-9,
|
|
328
|
-
mass: 4,
|
|
329
|
-
overshootClamping: false,
|
|
330
|
-
stiffness: 600
|
|
331
|
-
}));
|
|
497
|
+
translateY.set(withSpring(0, PAGE_SPRING_CONFIG));
|
|
332
498
|
});
|
|
333
|
-
}, [translateY, dismissOptions, handleDismiss, isZoomed]);
|
|
499
|
+
}, [translateY, dismissOptions, handleDismiss, isTriggerOpening, isZoomed, pageTransitionLocked]);
|
|
500
|
+
const getCurrentTapTarget = useCallback(() => {
|
|
501
|
+
const index = pendingIndexRef.current;
|
|
502
|
+
if (index < 0 || index >= dataRef.current.length || !(index in dataRef.current)) {
|
|
503
|
+
return null;
|
|
504
|
+
}
|
|
505
|
+
return {
|
|
506
|
+
index,
|
|
507
|
+
item: dataRef.current[index]
|
|
508
|
+
};
|
|
509
|
+
}, []);
|
|
510
|
+
const isWebInteractionLocked = useCallback(() => isPageTransitioningRef.current || pageTransitionLocked.get(), [isPageTransitioningRef, pageTransitionLocked]);
|
|
511
|
+
const emitSingleTap = useCallback((x, y, tapTarget) => {
|
|
512
|
+
if (isPageTransitioningRef.current) {
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
const target = tapTarget ?? getCurrentTapTarget();
|
|
516
|
+
if (!target) {
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
const {
|
|
520
|
+
index: targetIndex,
|
|
521
|
+
item: targetItem
|
|
522
|
+
} = target;
|
|
523
|
+
if (targetIndex < 0) {
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
managerRef.current?.emitTap({
|
|
527
|
+
kind: 'single',
|
|
528
|
+
x,
|
|
529
|
+
y,
|
|
530
|
+
index: targetIndex
|
|
531
|
+
});
|
|
532
|
+
onSingleTapRef.current?.({
|
|
533
|
+
x,
|
|
534
|
+
y,
|
|
535
|
+
index: targetIndex,
|
|
536
|
+
item: targetItem
|
|
537
|
+
});
|
|
538
|
+
}, [getCurrentTapTarget, isPageTransitioningRef]);
|
|
539
|
+
const singleTapGesture = useMemo(() => Gesture.Tap().enabled(enableNativeTapGestures).numberOfTaps(1).onEnd((event, success) => {
|
|
540
|
+
if (!success || pageTransitionLocked.get()) {
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
scheduleOnRN(emitSingleTap, event.x, event.y);
|
|
544
|
+
}), [emitSingleTap, pageTransitionLocked]);
|
|
545
|
+
const doubleTapGesture = useMemo(() => Gesture.Tap().enabled(enableDoubleTapZoom && enableNativeTapGestures).numberOfTaps(2).onEnd(event => {
|
|
546
|
+
if (pageTransitionLocked.get()) {
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
applyTapZoomAtPoint({
|
|
550
|
+
x: event.x,
|
|
551
|
+
y: event.y,
|
|
552
|
+
width,
|
|
553
|
+
height,
|
|
554
|
+
maxZoomScale,
|
|
555
|
+
scale,
|
|
556
|
+
translateX,
|
|
557
|
+
translateY
|
|
558
|
+
});
|
|
559
|
+
}), [enableDoubleTapZoom, height, maxZoomScale, pageTransitionLocked, scale, translateX, translateY, width]);
|
|
560
|
+
const tapGesture = useMemo(() => Gesture.Exclusive(doubleTapGesture, singleTapGesture), [doubleTapGesture, singleTapGesture]);
|
|
334
561
|
const zoomPinchGesture = useMemo(() => Gesture.Pinch().enabled(enablePinchZoom).onTouchesDown(event => {
|
|
562
|
+
if (pageTransitionLocked.get()) {
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
335
565
|
if (event.numberOfTouches === 2) {
|
|
336
566
|
scheduleOnRN(setIsPinching, true);
|
|
337
567
|
}
|
|
338
568
|
}).onStart(event => {
|
|
569
|
+
if (pageTransitionLocked.get()) {
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
339
572
|
startScale.set(scale.get());
|
|
340
573
|
initialTranslateX.set(translateX.get());
|
|
341
574
|
initialTranslateY.set(translateY.get());
|
|
@@ -345,6 +578,9 @@ export const useGestureViewer = ({
|
|
|
345
578
|
lastFocalY.set(event.focalY);
|
|
346
579
|
hasActiveFocal.set(false);
|
|
347
580
|
}).onUpdate(event => {
|
|
581
|
+
if (pageTransitionLocked.get()) {
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
348
584
|
const initialScale = startScale.get();
|
|
349
585
|
const newScale = initialScale * event.scale;
|
|
350
586
|
scale.set(newScale);
|
|
@@ -398,6 +634,9 @@ export const useGestureViewer = ({
|
|
|
398
634
|
translateX.set(constrainedTranslateX);
|
|
399
635
|
translateY.set(constrainedTranslateY);
|
|
400
636
|
}).onEnd(() => {
|
|
637
|
+
if (pageTransitionLocked.get()) {
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
401
640
|
const currentScale = scale.get();
|
|
402
641
|
if (currentScale > maxZoomScale) {
|
|
403
642
|
scale.set(withTiming(maxZoomScale, {
|
|
@@ -443,11 +682,17 @@ export const useGestureViewer = ({
|
|
|
443
682
|
}).onFinalize(() => {
|
|
444
683
|
hasActiveFocal.set(false);
|
|
445
684
|
scheduleOnRN(setIsPinching, false);
|
|
446
|
-
}), [scale, enablePinchZoom, maxZoomScale, translateX, translateY, startScale, initialTranslateX, initialTranslateY, width, height, constrainTranslation, lastFocalX, lastFocalY, startFocalX, startFocalY, hasActiveFocal]);
|
|
685
|
+
}), [scale, enablePinchZoom, maxZoomScale, translateX, translateY, startScale, initialTranslateX, initialTranslateY, width, height, constrainTranslation, lastFocalX, lastFocalY, startFocalX, startFocalY, hasActiveFocal, pageTransitionLocked]);
|
|
447
686
|
const zoomPanGesture = useMemo(() => Gesture.Pan().enabled(enablePanWhenZoomed && isZoomed).activeCursor('grabbing').averageTouches(true).onBegin(() => {
|
|
687
|
+
if (pageTransitionLocked.get()) {
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
448
690
|
initialTranslateX.set(translateX.get());
|
|
449
691
|
initialTranslateY.set(translateY.get());
|
|
450
692
|
}).onUpdate(event => {
|
|
693
|
+
if (pageTransitionLocked.get()) {
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
451
696
|
const currentScale = scale.get();
|
|
452
697
|
if (currentScale > 1) {
|
|
453
698
|
const newTranslateX = initialTranslateX.get() + event.translationX;
|
|
@@ -463,50 +708,22 @@ export const useGestureViewer = ({
|
|
|
463
708
|
translateX.set(constrainedTranslateX);
|
|
464
709
|
translateY.set(constrainedTranslateY);
|
|
465
710
|
}
|
|
466
|
-
}), [translateX, translateY, enablePanWhenZoomed, isZoomed, scale, initialTranslateX, initialTranslateY, constrainTranslation]);
|
|
467
|
-
const emitSingleTap = useCallback((x, y) => {
|
|
468
|
-
const index = pendingIndexRef.current;
|
|
469
|
-
const currentData = dataRef.current;
|
|
470
|
-
if (index < 0 || index >= currentData.length) {
|
|
471
|
-
return;
|
|
472
|
-
}
|
|
473
|
-
managerRef.current?.emitTap({
|
|
474
|
-
kind: 'single',
|
|
475
|
-
x,
|
|
476
|
-
y,
|
|
477
|
-
index
|
|
478
|
-
});
|
|
479
|
-
const item = currentData[index];
|
|
480
|
-
if (item === undefined) {
|
|
481
|
-
return;
|
|
482
|
-
}
|
|
483
|
-
onSingleTapRef.current?.({
|
|
484
|
-
x,
|
|
485
|
-
y,
|
|
486
|
-
index,
|
|
487
|
-
item
|
|
488
|
-
});
|
|
489
|
-
}, []);
|
|
490
|
-
const singleTapGesture = useMemo(() => Gesture.Tap().enabled(Platform.OS !== 'web').numberOfTaps(1).onEnd((event, success) => {
|
|
491
|
-
if (!success) {
|
|
492
|
-
return;
|
|
493
|
-
}
|
|
494
|
-
scheduleOnRN(emitSingleTap, event.x, event.y);
|
|
495
|
-
}), [emitSingleTap]);
|
|
496
|
-
const doubleTapGesture = useMemo(() => Gesture.Tap().enabled(enableDoubleTapZoom && Platform.OS !== 'web').numberOfTaps(2).onEnd(event => {
|
|
497
|
-
applyTapZoomAtPoint({
|
|
498
|
-
x: event.x,
|
|
499
|
-
y: event.y,
|
|
500
|
-
width,
|
|
501
|
-
height,
|
|
502
|
-
maxZoomScale,
|
|
503
|
-
scale,
|
|
504
|
-
translateX,
|
|
505
|
-
translateY
|
|
506
|
-
});
|
|
507
|
-
}), [enableDoubleTapZoom, height, maxZoomScale, scale, translateX, translateY, width]);
|
|
508
|
-
const tapGesture = useMemo(() => Gesture.Exclusive(doubleTapGesture, singleTapGesture), [doubleTapGesture, singleTapGesture]);
|
|
711
|
+
}), [translateX, translateY, enablePanWhenZoomed, isZoomed, scale, initialTranslateX, initialTranslateY, constrainTranslation, pageTransitionLocked]);
|
|
509
712
|
const zoomGesture = useMemo(() => Gesture.Race(zoomPinchGesture, Gesture.Exclusive(zoomPanGesture, tapGesture)), [zoomPinchGesture, zoomPanGesture, tapGesture]);
|
|
713
|
+
const onWebClick = useWebClickHandler({
|
|
714
|
+
clearPendingWebSingleTap,
|
|
715
|
+
emitSingleTap,
|
|
716
|
+
enableDoubleTapZoom,
|
|
717
|
+
getCurrentTapTarget,
|
|
718
|
+
height,
|
|
719
|
+
maxZoomScale,
|
|
720
|
+
scale,
|
|
721
|
+
scheduleWebSingleTap,
|
|
722
|
+
isInteractionLocked: isWebInteractionLocked,
|
|
723
|
+
translateX,
|
|
724
|
+
translateY,
|
|
725
|
+
width
|
|
726
|
+
});
|
|
510
727
|
const animatedStyle = useAnimatedStyle(() => ({
|
|
511
728
|
opacity: triggerOpacity.get(),
|
|
512
729
|
transform: [{
|
|
@@ -538,53 +755,22 @@ export const useGestureViewer = ({
|
|
|
538
755
|
opacity: baseOpacity * dismissOpacity
|
|
539
756
|
};
|
|
540
757
|
}, [dismissOptions.direction, dismissOptions.fadeBackdrop]);
|
|
541
|
-
const nativeScrollGesture = useMemo(() => {
|
|
542
|
-
return Gesture.Native().requireExternalGestureToFail(dismissGestureRef);
|
|
543
|
-
}, []);
|
|
544
|
-
const {
|
|
545
|
-
onMomentumScrollEnd,
|
|
546
|
-
onScroll,
|
|
547
|
-
onScrollBeginDrag,
|
|
548
|
-
onWebClick
|
|
549
|
-
} = useGestureViewerPaging({
|
|
550
|
-
adjustedInitialIndex,
|
|
551
|
-
autoPlay,
|
|
552
|
-
autoPlayInterval,
|
|
553
|
-
currentIndex,
|
|
554
|
-
dataLength,
|
|
555
|
-
enableDoubleTapZoom,
|
|
556
|
-
enableHorizontalSwipe,
|
|
557
|
-
enableLoop,
|
|
558
|
-
height,
|
|
559
|
-
isRotated,
|
|
560
|
-
isZoomed,
|
|
561
|
-
itemSpacing,
|
|
562
|
-
manager,
|
|
563
|
-
maxZoomScale,
|
|
564
|
-
onSingleTap: emitSingleTap,
|
|
565
|
-
scale,
|
|
566
|
-
scrollTo,
|
|
567
|
-
syncCurrentIndex,
|
|
568
|
-
syncPendingIndex,
|
|
569
|
-
translateX,
|
|
570
|
-
translateY,
|
|
571
|
-
width
|
|
572
|
-
});
|
|
573
758
|
return {
|
|
574
759
|
animatedStyle,
|
|
575
760
|
backdropStyle,
|
|
761
|
+
centerVirtualIndex: renderCenterVirtualIndex,
|
|
762
|
+
currentIndex: renderCurrentIndex,
|
|
576
763
|
dataLength,
|
|
577
764
|
dismissGesture,
|
|
578
765
|
handleDismiss,
|
|
766
|
+
horizontalPagingGesture,
|
|
579
767
|
isPinching,
|
|
580
768
|
isRotated,
|
|
581
769
|
isZoomed,
|
|
582
|
-
listRef,
|
|
583
|
-
nativeScrollGesture,
|
|
584
770
|
onWebClick,
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
771
|
+
pageStride,
|
|
772
|
+
renderWindowSlots,
|
|
773
|
+
visualPage,
|
|
588
774
|
zoomGesture
|
|
589
775
|
};
|
|
590
776
|
};
|