react-native-gesture-image-viewer 2.0.0-beta.2 → 2.0.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +13 -6
  2. package/lib/module/GestureViewer.js +5 -5
  3. package/lib/module/GestureViewer.js.map +1 -1
  4. package/lib/module/GestureViewerManager.js +5 -5
  5. package/lib/module/GestureViewerManager.js.map +1 -1
  6. package/lib/module/index.js +1 -0
  7. package/lib/module/index.js.map +1 -1
  8. package/lib/module/useGestureViewer.js +40 -63
  9. package/lib/module/useGestureViewer.js.map +1 -1
  10. package/lib/module/useGestureViewerController.js +39 -58
  11. package/lib/module/useGestureViewerController.js.map +1 -1
  12. package/lib/module/useGestureViewerState.js +78 -0
  13. package/lib/module/useGestureViewerState.js.map +1 -0
  14. package/lib/typescript/src/GestureViewer.d.ts +2 -2
  15. package/lib/typescript/src/GestureViewer.d.ts.map +1 -1
  16. package/lib/typescript/src/GestureViewerManager.d.ts +5 -8
  17. package/lib/typescript/src/GestureViewerManager.d.ts.map +1 -1
  18. package/lib/typescript/src/index.d.ts +2 -1
  19. package/lib/typescript/src/index.d.ts.map +1 -1
  20. package/lib/typescript/src/types.d.ts +60 -57
  21. package/lib/typescript/src/types.d.ts.map +1 -1
  22. package/lib/typescript/src/useGestureViewer.d.ts +1 -1
  23. package/lib/typescript/src/useGestureViewer.d.ts.map +1 -1
  24. package/lib/typescript/src/useGestureViewerController.d.ts +10 -21
  25. package/lib/typescript/src/useGestureViewerController.d.ts.map +1 -1
  26. package/lib/typescript/src/useGestureViewerState.d.ts +35 -0
  27. package/lib/typescript/src/useGestureViewerState.d.ts.map +1 -0
  28. package/package.json +1 -1
  29. package/src/GestureViewer.tsx +7 -7
  30. package/src/GestureViewerManager.ts +9 -9
  31. package/src/index.tsx +2 -1
  32. package/src/types.ts +60 -59
  33. package/src/useGestureViewer.ts +41 -69
  34. package/src/useGestureViewerController.ts +43 -62
  35. package/src/useGestureViewerState.ts +85 -0
@@ -0,0 +1,35 @@
1
+ import type { GestureViewerState } from './types';
2
+ /**
3
+ * Hook to access the current state of the gesture viewer.
4
+ *
5
+ * @param id - Viewer instance identifier (default: 'default')
6
+ * @returns Current state of the viewer
7
+ *
8
+ * **Available state:**
9
+ * - `currentIndex: number` - Current active index (read-only)
10
+ * - `totalCount: number` - Total number of items (read-only)
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * const { currentIndex, totalCount } = useGestureViewerState();
15
+ *
16
+ * // Display current position
17
+ * return (
18
+ * <Text>
19
+ * {currentIndex + 1} / {totalCount}
20
+ * </Text>
21
+ * );
22
+ *
23
+ * // React to index changes
24
+ * useEffect(() => {
25
+ * console.log(`Moved to image ${currentIndex + 1}`);
26
+ * trackPageView(currentIndex);
27
+ * }, [currentIndex]);
28
+ *
29
+ * // Check navigation availability
30
+ * const canGoNext = currentIndex < totalCount - 1;
31
+ * const canGoPrevious = currentIndex > 0;
32
+ * ```
33
+ */
34
+ export declare const useGestureViewerState: (id?: string) => GestureViewerState;
35
+ //# sourceMappingURL=useGestureViewerState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGestureViewerState.d.ts","sourceRoot":"","sources":["../../../src/useGestureViewerState.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,qBAAqB,GAAI,WAAc,KAAG,kBAgDtD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-gesture-image-viewer",
3
- "version": "2.0.0-beta.2",
3
+ "version": "2.0.0-beta.4",
4
4
  "description": "🖼️ A highly customizable and easy-to-use React Native image viewer with gesture support and external controls",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -1,5 +1,5 @@
1
1
  import { useCallback, useEffect, useMemo, useRef } from 'react';
2
- import { type FlatList, Platform, type ScrollViewProps, StyleSheet, useWindowDimensions, View } from 'react-native';
2
+ import { Platform, type ScrollView, type ScrollViewProps, StyleSheet, useWindowDimensions, View } from 'react-native';
3
3
  import { Gesture, GestureDetector, GestureHandlerRootView } from 'react-native-gesture-handler';
4
4
  import Animated from 'react-native-reanimated';
5
5
  import { registry } from './GestureViewerRegistry';
@@ -8,7 +8,7 @@ import { useGestureViewer } from './useGestureViewer';
8
8
  import { createLoopData, isFlashListLike, isFlatListLike, isScrollViewLike } from './utils';
9
9
  import WebPagingFixStyle from './WebPagingFixStyle';
10
10
 
11
- export function GestureViewer<T = any, LC = typeof FlatList>({
11
+ export function GestureViewer<T = any, LC = typeof ScrollView>({
12
12
  id = 'default',
13
13
  data,
14
14
  renderItem: renderItemProp,
@@ -20,7 +20,7 @@ export function GestureViewer<T = any, LC = typeof FlatList>({
20
20
  containerStyle,
21
21
  initialIndex = 0,
22
22
  itemSpacing = 0,
23
- useSnap = false,
23
+ enableSnapMode = false,
24
24
  enableLoop = false,
25
25
  ...props
26
26
  }: GestureViewerProps<T, LC>) {
@@ -31,7 +31,7 @@ export function GestureViewer<T = any, LC = typeof FlatList>({
31
31
 
32
32
  const { width: screenWidth } = useWindowDimensions();
33
33
 
34
- const width = useSnap ? customWidth || screenWidth : screenWidth;
34
+ const width = enableSnapMode ? customWidth || screenWidth : screenWidth;
35
35
 
36
36
  const loopData = useMemo(() => createLoopData(dataRef, enableLoop), [enableLoop]);
37
37
 
@@ -53,7 +53,7 @@ export function GestureViewer<T = any, LC = typeof FlatList>({
53
53
  width,
54
54
  initialIndex,
55
55
  itemSpacing,
56
- useSnap,
56
+ enableSnapMode,
57
57
  enableLoop,
58
58
  ...props,
59
59
  });
@@ -118,7 +118,7 @@ export function GestureViewer<T = any, LC = typeof FlatList>({
118
118
  showsHorizontalScrollIndicator: false,
119
119
  onMomentumScrollEnd: onMomentumScrollEnd,
120
120
  onScrollBeginDrag,
121
- ...(useSnap
121
+ ...(enableSnapMode
122
122
  ? {
123
123
  snapToInterval: width + itemSpacing,
124
124
  snapToAlignment: 'center',
@@ -130,7 +130,7 @@ export function GestureViewer<T = any, LC = typeof FlatList>({
130
130
  scrollEventThrottle: 16,
131
131
  removeClippedSubviews: true,
132
132
  }) satisfies ScrollViewProps,
133
- [width, itemSpacing, isZoomed, isRotated, onMomentumScrollEnd, onScrollBeginDrag, useSnap],
133
+ [width, itemSpacing, isZoomed, isRotated, onMomentumScrollEnd, onScrollBeginDrag, enableSnapMode],
134
134
  );
135
135
 
136
136
  const listComponent = (
@@ -1,9 +1,9 @@
1
1
  import { type SharedValue, withTiming } from 'react-native-reanimated';
2
2
  import type {
3
- GestureViewerControllerState,
4
3
  GestureViewerEventCallback,
5
4
  GestureViewerEventData,
6
5
  GestureViewerEventType,
6
+ GestureViewerState,
7
7
  } from './types';
8
8
  import { createBoundsConstraint, createScrollAction } from './utils';
9
9
 
@@ -13,7 +13,7 @@ class GestureViewerManager {
13
13
  private width = 0;
14
14
  private height = 0;
15
15
  private maxZoomScale = 2;
16
- private enableSwipeGesture = true;
16
+ private enableHorizontalSwipe = true;
17
17
  private enableLoop = false;
18
18
  private listRef: any | null = null;
19
19
 
@@ -24,7 +24,7 @@ class GestureViewerManager {
24
24
 
25
25
  private loopCallback: (() => void) | null = null;
26
26
 
27
- private listeners = new Set<(state: GestureViewerControllerState) => void>();
27
+ private listeners = new Set<(state: GestureViewerState) => void>();
28
28
  private eventListeners = new Map<GestureViewerEventType, Set<(data: any) => void>>();
29
29
 
30
30
  private notifyListeners() {
@@ -33,7 +33,7 @@ class GestureViewerManager {
33
33
  this.listeners.forEach((listener) => listener(state));
34
34
  }
35
35
 
36
- subscribe(listener: (state: GestureViewerControllerState) => void) {
36
+ subscribe(listener: (state: GestureViewerState) => void) {
37
37
  this.listeners.add(listener);
38
38
 
39
39
  return () => {
@@ -77,7 +77,7 @@ class GestureViewerManager {
77
77
  this.emitEvent('rotationChange', { rotation, previousRotation });
78
78
  };
79
79
 
80
- getState() {
80
+ getState(): GestureViewerState {
81
81
  return {
82
82
  currentIndex: this.currentIndex,
83
83
  totalCount: this.dataLength,
@@ -104,8 +104,8 @@ class GestureViewerManager {
104
104
  this.dataLength = length;
105
105
  }
106
106
 
107
- setEnableSwipeGesture(enabled: boolean) {
108
- this.enableSwipeGesture = enabled;
107
+ setEnableHorizontalSwipe(enabled: boolean) {
108
+ this.enableHorizontalSwipe = enabled;
109
109
  }
110
110
 
111
111
  setCurrentIndex(index: number) {
@@ -224,7 +224,7 @@ class GestureViewerManager {
224
224
  };
225
225
 
226
226
  goToIndex = (index: number) => {
227
- if (!this.enableSwipeGesture || !this.listRef) {
227
+ if (!this.enableHorizontalSwipe || !this.listRef) {
228
228
  return;
229
229
  }
230
230
 
@@ -299,7 +299,7 @@ class GestureViewerManager {
299
299
  this.loopCallback = null;
300
300
  this.listeners.clear();
301
301
  this.listRef = null;
302
- this.enableSwipeGesture = true;
302
+ this.enableHorizontalSwipe = true;
303
303
  this.currentIndex = 0;
304
304
  this.dataLength = 0;
305
305
  this.maxZoomScale = 2;
package/src/index.tsx CHANGED
@@ -1,11 +1,12 @@
1
1
  export { GestureViewer } from './GestureViewer';
2
2
  export type {
3
3
  GestureViewerController,
4
- GestureViewerControllerState,
5
4
  GestureViewerEventCallback,
6
5
  GestureViewerEventData,
7
6
  GestureViewerEventType,
8
7
  GestureViewerProps,
8
+ GestureViewerState,
9
9
  } from './types';
10
10
  export { useGestureViewerController } from './useGestureViewerController';
11
11
  export { useGestureViewerEvent } from './useGestureViewerEvent';
12
+ export { useGestureViewerState } from './useGestureViewerState';
package/src/types.ts CHANGED
@@ -13,7 +13,7 @@ type ConditionalListProps<LC> = LC extends FlatListComponent
13
13
  ? React.ComponentProps<LC>
14
14
  : GetComponentProps<LC>;
15
15
 
16
- export interface GestureViewerProps<T = any, LC = typeof RNFlatList> {
16
+ export interface GestureViewerProps<T = any, LC = typeof RNScrollView> {
17
17
  /**
18
18
  * When you want to efficiently manage multiple `GestureViewer` instances, you can use the `id` prop to use multiple `GestureViewer` components.
19
19
  * @remark `GestureViewer` automatically removes instances from memory when components are unmounted, so no manual memory management is required.
@@ -29,10 +29,6 @@ export interface GestureViewerProps<T = any, LC = typeof RNFlatList> {
29
29
  * @defaultValue 0
30
30
  */
31
31
  initialIndex?: number;
32
- /**
33
- * A callback function that is called when the index of the item changes.
34
- */
35
- onIndexChange?: (index: number) => void;
36
32
  /**
37
33
  * A callback function that is called when the `GestureViewer` is dismissed.
38
34
  */
@@ -55,44 +51,6 @@ export interface GestureViewerProps<T = any, LC = typeof RNFlatList> {
55
51
  * @defaultValue screen width
56
52
  */
57
53
  width?: number;
58
- /**
59
- * Enables snap scrolling mode.
60
- *
61
- * @remark
62
- * **`false` (default)**: Paging mode (`pagingEnabled: true`)
63
- * - Scrolls by full screen size increments
64
- *
65
- * **`true`**: Snap mode (`snapToInterval` auto-calculated)
66
- * - `snapToInterval` is automatically calculated based on `width` and `itemSpacing` values
67
- * - Use this option when you need item spacing
68
- * @defaultValue false
69
- *
70
- */
71
- useSnap?: boolean;
72
- /**
73
- * `dismissThreshold` controls when `onDismiss` is called by applying a threshold value during vertical gestures.
74
- * @defaultValue 80
75
- */
76
- dismissThreshold?: number;
77
- // swipeThreshold?: number;
78
- // velocityThreshold?: number;
79
- /**
80
- * Calls `onDismiss` function when swiping down.
81
- * @remark Useful for closing modals with downward swipe gestures.
82
- * @defaultValue true
83
- */
84
- enableDismissGesture?: boolean;
85
- /**
86
- * Controls left/right swipe gestures.
87
- * @remark When `false`, horizontal gestures are disabled.
88
- * @defaultValue true
89
- */
90
- enableSwipeGesture?: boolean;
91
- /**
92
- * `resistance` controls the range of vertical movement by applying resistance during vertical gestures.
93
- * @defaultValue 2
94
- */
95
- resistance?: number;
96
54
  /**
97
55
  * The props to pass to the list component.
98
56
  * @remark The `listProps` provides **type inference based on the selected list component**, ensuring accurate autocompletion and type safety in your IDE.
@@ -107,45 +65,86 @@ export interface GestureViewerProps<T = any, LC = typeof RNFlatList> {
107
65
  */
108
66
  containerStyle?: StyleProp<ViewStyle>;
109
67
  /**
110
- * By default, the background `opacity` gradually decreases from 1 to 0 during downward swipe gestures.
111
- * @remark When `false`, this animation is disabled.
68
+ * Dismiss gesture options. Calls `onDismiss` function when swiping down.
69
+ * @remark Useful for closing modals with downward swipe gestures.
70
+ */
71
+ dismiss?: {
72
+ /**
73
+ * When `false`, dismiss gesture is disabled.
74
+ * @defaultValue true
75
+ */
76
+ enabled?: boolean;
77
+ /**
78
+ * `threshold` controls when `onDismiss` is called by applying a threshold value during vertical gestures.
79
+ * @defaultValue 80
80
+ */
81
+ threshold?: number;
82
+ /**
83
+ * `resistance` controls the range of vertical movement by applying resistance during dismiss gestures.
84
+ * @defaultValue 2
85
+ */
86
+ resistance?: number;
87
+ /**
88
+ * By default, the background `opacity` gradually decreases from 1 to 0 during downward swipe gestures.
89
+ * @remark When `false`, this animation is disabled.
90
+ * @defaultValue true
91
+ */
92
+ fadeBackdrop?: boolean;
93
+ };
94
+ /**
95
+ * Controls left/right swipe gestures.
96
+ * @remark When `false`, horizontal gestures are disabled.
112
97
  * @defaultValue true
113
98
  */
114
- animateBackdrop?: boolean;
99
+ enableHorizontalSwipe?: boolean;
115
100
  /**
116
101
  * Only works when zoom is active, allows moving item position when zoomed.
117
102
  * @remark When `false`, gesture movement is disabled during zoom.
118
103
  * @defaultValue true
119
104
  */
120
- enableZoomPanGesture?: boolean;
105
+ enablePanWhenZoomed?: boolean;
121
106
  /**
122
107
  * Controls two-finger pinch gestures.
123
108
  * @remark When `false`, two-finger zoom gestures are disabled.
124
109
  * @defaultValue true
125
110
  */
126
- enableZoomGesture?: boolean;
111
+ enablePinchZoom?: boolean;
127
112
  /**
128
113
  * Controls double-tap zoom gestures.
129
114
  * @remark When `false`, double-tap zoom gestures are disabled.
130
115
  * @defaultValue true
131
116
  */
132
- enableDoubleTapGesture?: boolean;
117
+ enableDoubleTapZoom?: boolean;
133
118
  /**
134
119
  * Enables infinite loop navigation.
135
120
  * @defaultValue false
136
121
  */
137
122
  enableLoop?: boolean;
138
123
  /**
139
- * The maximum zoom scale.
140
- * @defaultValue 2
124
+ * Enables snap scrolling mode.
125
+ *
126
+ * @remark
127
+ * **`false` (default)**: Paging mode (`pagingEnabled: true`)
128
+ * - Scrolls by full screen size increments
129
+ *
130
+ * **`true`**: Snap mode (`snapToInterval` auto-calculated)
131
+ * - `snapToInterval` is automatically calculated based on `width` and `itemSpacing` values
132
+ * - Use this option when you need item spacing
133
+ * @defaultValue false
134
+ *
141
135
  */
142
- maxZoomScale?: number;
136
+ enableSnapMode?: boolean;
143
137
  /**
144
138
  * The spacing between items in pixels.
145
- * @remark Only applied when `useSnap` is `true`.
139
+ * @remark Only applied when `enableSnapMode` is `true`.
146
140
  * @defaultValue 0
147
141
  */
148
142
  itemSpacing?: number;
143
+ /**
144
+ * The maximum zoom scale.
145
+ * @defaultValue 2
146
+ */
147
+ maxZoomScale?: number;
149
148
  }
150
149
 
151
150
  /**
@@ -167,8 +166,10 @@ export type GestureViewerController = {
167
166
  *
168
167
  * @example
169
168
  * ```typescript
169
+ * const { totalCount } = useGestureViewerState();
170
+ *
170
171
  * controller.goToIndex(0); // Go to first item
171
- * controller.goToIndex(controller.totalCount - 1); // Go to last item
172
+ * controller.goToIndex(totalCount - 1); // Go to last item
172
173
  * ```
173
174
  */
174
175
  goToIndex: (index: number) => void;
@@ -252,13 +253,13 @@ export type GestureViewerController = {
252
253
  * ```
253
254
  */
254
255
  rotate: (angle?: RotationAngle, clockwise?: boolean) => void;
255
- } & GestureViewerControllerState;
256
+ };
256
257
 
257
258
  /**
258
259
  * State information for the gesture viewer controller.
259
260
  * Contains read-only properties that reflect the current state.
260
261
  */
261
- export type GestureViewerControllerState = {
262
+ export type GestureViewerState = {
262
263
  /**
263
264
  * The current index of the active item in the viewer.
264
265
  *
@@ -267,7 +268,7 @@ export type GestureViewerControllerState = {
267
268
  *
268
269
  * @example
269
270
  * ```typescript
270
- * console.log(`Currently viewing item ${controller.currentIndex + 1} of ${controller.totalCount}`);
271
+ * console.log(`Currently viewing item ${currentIndex + 1} of ${totalCount}`);
271
272
  * ```
272
273
  */
273
274
  readonly currentIndex: number;
@@ -280,8 +281,8 @@ export type GestureViewerControllerState = {
280
281
  *
281
282
  * @example
282
283
  * ```typescript
283
- * const hasNext = controller.currentIndex < controller.totalCount - 1;
284
- * const hasPrevious = controller.currentIndex > 0;
284
+ * const hasNext = currentIndex < totalCount - 1;
285
+ * const hasPrevious = currentIndex > 0;
285
286
  * ```
286
287
  */
287
288
  readonly totalCount: number;
@@ -29,36 +29,27 @@ type UseGestureViewerProps<T = any> = Omit<
29
29
  export const useGestureViewer = <T = any>({
30
30
  data,
31
31
  initialIndex = 0,
32
- onIndexChange,
33
32
  onDismiss,
34
33
  width: customWidth,
35
- dismissThreshold = 80,
36
- resistance = 2,
37
- // swipeThreshold = 0.5,
38
- // velocityThreshold = 200,
39
- animateBackdrop = true,
40
- enableDismissGesture = true,
41
- enableSwipeGesture = true,
42
- enableZoomGesture = true,
43
- enableDoubleTapGesture = true,
44
- enableZoomPanGesture = true,
34
+ dismiss,
35
+ enableDoubleTapZoom = true,
36
+ enablePinchZoom = true,
37
+ enableHorizontalSwipe = true,
38
+ enablePanWhenZoomed = true,
45
39
  enableLoop = false,
46
40
  maxZoomScale = 2,
47
41
  itemSpacing = 0,
48
- useSnap = false,
42
+ enableSnapMode = false,
49
43
  id = 'default',
50
44
  }: UseGestureViewerProps<T>) => {
51
45
  const { width: screenWidth, height: screenHeight } = useWindowDimensions();
52
- const width = useSnap ? customWidth || screenWidth : screenWidth;
46
+ const width = enableSnapMode ? customWidth || screenWidth : screenWidth;
53
47
 
54
48
  const [isZoomed, setIsZoomed] = useState(false);
55
49
  const [isRotated, setIsRotated] = useState(false);
56
50
  const [manager, setManager] = useState<GestureViewerManager | null>(null);
57
51
 
58
52
  const listRef = useRef<any>(null);
59
- const unsubscribeRef = useRef<(() => void) | null>(null);
60
- const onIndexChangeRef = useRef<((index: number) => void) | null>(null);
61
- const lastEmittedIndexRef = useRef<number>(null);
62
53
 
63
54
  const initialTranslateY = useSharedValue(0);
64
55
  const initialTranslateX = useSharedValue(0);
@@ -72,6 +63,15 @@ export const useGestureViewer = <T = any>({
72
63
 
73
64
  const dataLength = data?.length || 0;
74
65
 
66
+ const dismissOptions = useMemo(() => {
67
+ return {
68
+ enabled: dismiss?.enabled ?? true,
69
+ threshold: dismiss?.threshold ?? 80,
70
+ resistance: dismiss?.resistance ?? 2,
71
+ fadeBackdrop: dismiss?.fadeBackdrop ?? true,
72
+ };
73
+ }, [dismiss?.enabled, dismiss?.threshold, dismiss?.resistance, dismiss?.fadeBackdrop]);
74
+
75
75
  const adjustedInitialIndex = useMemo(() => {
76
76
  if (enableLoop && data.length > 1) {
77
77
  return initialIndex + 1;
@@ -96,14 +96,18 @@ export const useGestureViewer = <T = any>({
96
96
 
97
97
  const emitZoomChange = useCallback(
98
98
  (currentScale: number, prevScale: number | null) => {
99
- manager?.emitZoomChange(currentScale, prevScale);
99
+ if (manager) {
100
+ manager.emitZoomChange(currentScale, prevScale);
101
+ }
100
102
  },
101
103
  [manager],
102
104
  );
103
105
 
104
106
  const emitRotationChange = useCallback(
105
107
  (currentRotation: number, prevRotation: number | null) => {
106
- manager?.emitRotationChange(currentRotation, prevRotation);
108
+ if (manager) {
109
+ manager.emitRotationChange(currentRotation, prevRotation);
110
+ }
107
111
  },
108
112
  [manager],
109
113
  );
@@ -111,7 +115,7 @@ export const useGestureViewer = <T = any>({
111
115
  useAnimatedReaction(
112
116
  () => scale.value,
113
117
  (currentScale, previousScale) => {
114
- if (manager && currentScale !== previousScale) {
118
+ if (currentScale !== previousScale) {
115
119
  runOnJS(emitZoomChange)(currentScale, previousScale);
116
120
  }
117
121
 
@@ -122,7 +126,7 @@ export const useGestureViewer = <T = any>({
122
126
  useAnimatedReaction(
123
127
  () => rotation.value,
124
128
  (currentRotation, previousRotation) => {
125
- if (manager && currentRotation !== previousRotation) {
129
+ if (currentRotation !== previousRotation) {
126
130
  runOnJS(emitRotationChange)(currentRotation, previousRotation);
127
131
  }
128
132
 
@@ -131,41 +135,9 @@ export const useGestureViewer = <T = any>({
131
135
  );
132
136
 
133
137
  useEffect(() => {
134
- onIndexChangeRef.current = onIndexChange ?? null;
135
- });
136
-
137
- useEffect(() => {
138
- return () => {
139
- onIndexChangeRef.current = null;
140
- };
141
- }, []);
138
+ const unsubscribe = registry.subscribeToManager(id, setManager);
142
139
 
143
- useEffect(() => {
144
- const handleManagerChange = (manager: GestureViewerManager | null) => {
145
- unsubscribeRef.current?.();
146
- unsubscribeRef.current = null;
147
-
148
- setManager(manager);
149
-
150
- lastEmittedIndexRef.current = null;
151
-
152
- if (manager) {
153
- unsubscribeRef.current = manager.subscribe((state) => {
154
- if (lastEmittedIndexRef.current !== state.currentIndex) {
155
- lastEmittedIndexRef.current = state.currentIndex;
156
- onIndexChangeRef.current?.(state.currentIndex);
157
- }
158
- });
159
- return;
160
- }
161
- };
162
-
163
- const unsubscribeFromRegistry = registry.subscribeToManager(id, handleManagerChange);
164
-
165
- return () => {
166
- unsubscribeFromRegistry();
167
- unsubscribeRef.current?.();
168
- };
140
+ return unsubscribe;
169
141
  }, [id]);
170
142
 
171
143
  useEffect(() => {
@@ -174,7 +146,7 @@ export const useGestureViewer = <T = any>({
174
146
  }
175
147
 
176
148
  manager.setDataLength(dataLength);
177
- manager.setEnableSwipeGesture(enableSwipeGesture);
149
+ manager.setEnableHorizontalSwipe(enableHorizontalSwipe);
178
150
  manager.setCurrentIndex(initialIndex);
179
151
  manager.setWidth(width + itemSpacing);
180
152
  manager.setHeight(screenHeight);
@@ -184,7 +156,7 @@ export const useGestureViewer = <T = any>({
184
156
  manager.notifyStateChange();
185
157
  }, [
186
158
  dataLength,
187
- enableSwipeGesture,
159
+ enableHorizontalSwipe,
188
160
  initialIndex,
189
161
  manager,
190
162
  width,
@@ -229,7 +201,7 @@ export const useGestureViewer = <T = any>({
229
201
 
230
202
  const onMomentumScrollEnd = useCallback(
231
203
  (event: NativeSyntheticEvent<NativeScrollEvent>) => {
232
- if (!enableSwipeGesture) {
204
+ if (!enableHorizontalSwipe) {
233
205
  return;
234
206
  }
235
207
 
@@ -271,7 +243,7 @@ export const useGestureViewer = <T = any>({
271
243
  dataLength,
272
244
  width,
273
245
  itemSpacing,
274
- enableSwipeGesture,
246
+ enableHorizontalSwipe,
275
247
  enableLoop,
276
248
  translateX,
277
249
  translateY,
@@ -292,10 +264,10 @@ export const useGestureViewer = <T = any>({
292
264
  .failOffsetX([-10, 10])
293
265
  .enabled(!isZoomed)
294
266
  .onUpdate((event) => {
295
- translateY.value = event.translationY / resistance;
267
+ translateY.value = event.translationY / dismissOptions.resistance;
296
268
  })
297
269
  .onEnd((event) => {
298
- if (event.translationY > dismissThreshold && enableDismissGesture && onDismiss) {
270
+ if (event.translationY > dismissOptions.threshold && dismissOptions.enabled && onDismiss) {
299
271
  runOnJS(onDismiss)();
300
272
  return;
301
273
  }
@@ -308,11 +280,11 @@ export const useGestureViewer = <T = any>({
308
280
  energyThreshold: 6e-9,
309
281
  });
310
282
  });
311
- }, [translateY, dismissThreshold, enableDismissGesture, onDismiss, resistance, isZoomed]);
283
+ }, [translateY, dismissOptions.threshold, dismissOptions.enabled, onDismiss, dismissOptions.resistance, isZoomed]);
312
284
 
313
285
  const zoomPinchGesture = useMemo(() => {
314
286
  return Gesture.Pinch()
315
- .enabled(enableZoomGesture)
287
+ .enabled(enablePinchZoom)
316
288
  .onBegin(() => {
317
289
  startScale.value = scale.value;
318
290
  initialTranslateX.value = translateX.value;
@@ -388,7 +360,7 @@ export const useGestureViewer = <T = any>({
388
360
  });
389
361
  }, [
390
362
  scale,
391
- enableZoomGesture,
363
+ enablePinchZoom,
392
364
  maxZoomScale,
393
365
  translateX,
394
366
  translateY,
@@ -402,7 +374,7 @@ export const useGestureViewer = <T = any>({
402
374
 
403
375
  const zoomPanGesture = useMemo(() => {
404
376
  return Gesture.Pan()
405
- .enabled(enableZoomPanGesture && isZoomed)
377
+ .enabled(enablePanWhenZoomed && isZoomed)
406
378
  .activeCursor('grabbing')
407
379
  .averageTouches(true)
408
380
  .onBegin(() => {
@@ -427,7 +399,7 @@ export const useGestureViewer = <T = any>({
427
399
  }, [
428
400
  translateX,
429
401
  translateY,
430
- enableZoomPanGesture,
402
+ enablePanWhenZoomed,
431
403
  isZoomed,
432
404
  scale,
433
405
  initialTranslateX,
@@ -437,7 +409,7 @@ export const useGestureViewer = <T = any>({
437
409
 
438
410
  const doubleTapGesture = useMemo(() => {
439
411
  return Gesture.Tap()
440
- .enabled(enableDoubleTapGesture)
412
+ .enabled(enableDoubleTapZoom)
441
413
  .numberOfTaps(2)
442
414
  .onEnd((event) => {
443
415
  const nextScale = scale.value > 1 ? 1 : maxZoomScale;
@@ -471,7 +443,7 @@ export const useGestureViewer = <T = any>({
471
443
  easing: Easing.bezier(0.25, 0.1, 0.25, 1.0),
472
444
  });
473
445
  });
474
- }, [scale, enableDoubleTapGesture, maxZoomScale, translateX, translateY, width, screenHeight]);
446
+ }, [scale, enableDoubleTapZoom, maxZoomScale, translateX, translateY, width, screenHeight]);
475
447
 
476
448
  const zoomGesture = useMemo(() => {
477
449
  return Gesture.Race(zoomPinchGesture, Gesture.Exclusive(zoomPanGesture, doubleTapGesture));
@@ -489,14 +461,14 @@ export const useGestureViewer = <T = any>({
489
461
  });
490
462
 
491
463
  const backdropStyle = useAnimatedStyle(() => {
492
- if (!animateBackdrop || scale.value !== 1) {
464
+ if (!dismissOptions.fadeBackdrop || scale.value !== 1) {
493
465
  return { opacity: 1 };
494
466
  }
495
467
 
496
468
  const opacity = interpolate(translateY.value, [0, 200], [1, 0], 'clamp');
497
469
 
498
470
  return { opacity };
499
- }, [animateBackdrop]);
471
+ }, [dismissOptions.fadeBackdrop]);
500
472
 
501
473
  const onScrollBeginDrag = useCallback(() => {
502
474
  manager?.handleScrollBeginDrag();