react-native-gesture-image-viewer 1.5.1 → 1.6.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"GestureViewer.d.ts","sourceRoot":"","sources":["../../../src/GestureViewer.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,QAAQ,EAAyE,MAAM,cAAc,CAAC;AAIpH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAKlD,wBAAgB,aAAa,CAAC,CAAC,GAAG,GAAG,EAAE,EAAE,GAAG,OAAO,QAAQ,EAAE,EAC3D,EAAc,EACd,IAAI,EACJ,UAAU,EAAE,cAAc,EAC1B,eAAe,EACf,aAAa,EACb,KAAK,EAAE,WAAW,EAClB,SAAS,EACT,aAAa,EAAE,kBAAkB,EACjC,cAAc,EACd,YAAgB,EAChB,WAAe,EACf,OAAe,EACf,GAAG,KAAK,EACT,EAAE,kBAAkB,CAAC,CAAC,EAAE,EAAE,CAAC,2CAuI3B"}
1
+ {"version":3,"file":"GestureViewer.d.ts","sourceRoot":"","sources":["../../../src/GestureViewer.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,QAAQ,EAAyE,MAAM,cAAc,CAAC;AAIpH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAKlD,wBAAgB,aAAa,CAAC,CAAC,GAAG,GAAG,EAAE,EAAE,GAAG,OAAO,QAAQ,EAAE,EAC3D,EAAc,EACd,IAAI,EACJ,UAAU,EAAE,cAAc,EAC1B,eAAe,EACf,aAAa,EACb,KAAK,EAAE,WAAW,EAClB,SAAS,EACT,aAAa,EAAE,kBAAkB,EACjC,cAAc,EACd,YAAgB,EAChB,WAAe,EACf,OAAe,EACf,UAAkB,EAClB,GAAG,KAAK,EACT,EAAE,kBAAkB,CAAC,CAAC,EAAE,EAAE,CAAC,2CAsJ3B"}
@@ -5,14 +5,16 @@ declare class GestureViewerManager {
5
5
  private dataLength;
6
6
  private width;
7
7
  private height;
8
+ private maxZoomScale;
9
+ private enableSwipeGesture;
10
+ private enableLoop;
11
+ private listRef;
8
12
  private scale;
13
+ private rotation;
9
14
  private translateX;
10
15
  private translateY;
11
- private maxZoomScale;
12
- private listRef;
13
- private enableSwipeGesture;
16
+ private loopCallback;
14
17
  private listeners;
15
- private rotation;
16
18
  private eventListeners;
17
19
  private notifyListeners;
18
20
  subscribe(listener: (state: GestureViewerControllerState) => void): () => void;
@@ -24,6 +26,7 @@ declare class GestureViewerManager {
24
26
  currentIndex: number;
25
27
  totalCount: number;
26
28
  };
29
+ setEnableLoop(enabled: boolean): void;
27
30
  setWidth(width: number): void;
28
31
  setHeight(height: number): void;
29
32
  setListRef(ref: any): void;
@@ -38,9 +41,12 @@ declare class GestureViewerManager {
38
41
  zoomOut: (multiplier?: number) => void;
39
42
  resetZoom: (scale?: number) => void;
40
43
  goToIndex: (index: number) => void;
44
+ handleMomentumScrollEnd: (scrollIndex: number) => boolean;
45
+ handleScrollBeginDrag: () => void;
41
46
  goToPrevious: () => void;
42
47
  goToNext: () => void;
43
48
  cleanUp(): void;
49
+ private updateCurrentIndex;
44
50
  }
45
51
  export default GestureViewerManager;
46
52
  //# sourceMappingURL=GestureViewerManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"GestureViewerManager.d.ts","sourceRoot":"","sources":["../../../src/GestureViewerManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAc,MAAM,yBAAyB,CAAC;AACvE,OAAO,KAAK,EACV,4BAA4B,EAC5B,0BAA0B,EAE1B,sBAAsB,EACvB,MAAM,SAAS,CAAC;AAGjB,cAAM,oBAAoB;IACxB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,kBAAkB,CAAQ;IAClC,OAAO,CAAC,SAAS,CAA4D;IAC7E,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,cAAc,CAA+D;IAErF,OAAO,CAAC,eAAe;IAMvB,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,4BAA4B,KAAK,IAAI;IAQjE,gBAAgB,CAAC,CAAC,SAAS,sBAAsB,EAAE,SAAS,EAAE,CAAC,EAAE,QAAQ,EAAE,0BAA0B,CAAC,CAAC,CAAC;IAoBxG,OAAO,CAAC,SAAS;IAQjB,cAAc,GAAI,OAAO,MAAM,EAAE,eAAe,MAAM,GAAG,IAAI,UAE3D;IAEF,kBAAkB,GAAI,UAAU,MAAM,EAAE,kBAAkB,MAAM,GAAG,IAAI,UAErE;IAEF,QAAQ;;;;IAOR,QAAQ,CAAC,KAAK,EAAE,MAAM;IAItB,SAAS,CAAC,MAAM,EAAE,MAAM;IAIxB,UAAU,CAAC,GAAG,EAAE,GAAG;IAInB,aAAa,CAAC,MAAM,EAAE,MAAM;IAI5B,qBAAqB,CAAC,OAAO,EAAE,OAAO;IAItC,eAAe,CAAC,KAAK,EAAE,MAAM;IAM7B,mBAAmB,CACjB,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,EAC1B,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,EAC/B,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,EAC/B,YAAY,EAAE,MAAM;IAQtB,iBAAiB;IAIjB,WAAW,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC;IAIzC,MAAM,GAAI,QAAO,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAQ,EAAE,mBAAgB,UA2B9D;IAEF,MAAM,GAAI,mBAAiB,UAoBzB;IAEF,OAAO,GAAI,mBAAiB,UA0B1B;IAEF,SAAS,GAAI,cAAS,UAQpB;IAEF,SAAS,GAAI,OAAO,MAAM,UAcxB;IAEF,YAAY,aAIV;IAEF,QAAQ,aAIN;IAEF,OAAO;CAcR;AAED,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"GestureViewerManager.d.ts","sourceRoot":"","sources":["../../../src/GestureViewerManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAc,MAAM,yBAAyB,CAAC;AACvE,OAAO,KAAK,EACV,4BAA4B,EAC5B,0BAA0B,EAE1B,sBAAsB,EACvB,MAAM,SAAS,CAAC;AAGjB,cAAM,oBAAoB;IACxB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,kBAAkB,CAAQ;IAClC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAoB;IAEnC,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,UAAU,CAAoC;IAEtD,OAAO,CAAC,YAAY,CAA6B;IAEjD,OAAO,CAAC,SAAS,CAA4D;IAC7E,OAAO,CAAC,cAAc,CAA+D;IAErF,OAAO,CAAC,eAAe;IAMvB,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,4BAA4B,KAAK,IAAI;IAQjE,gBAAgB,CAAC,CAAC,SAAS,sBAAsB,EAAE,SAAS,EAAE,CAAC,EAAE,QAAQ,EAAE,0BAA0B,CAAC,CAAC,CAAC;IAoBxG,OAAO,CAAC,SAAS;IAQjB,cAAc,GAAI,OAAO,MAAM,EAAE,eAAe,MAAM,GAAG,IAAI,UAE3D;IAEF,kBAAkB,GAAI,UAAU,MAAM,EAAE,kBAAkB,MAAM,GAAG,IAAI,UAErE;IAEF,QAAQ;;;;IAOR,aAAa,CAAC,OAAO,EAAE,OAAO;IAI9B,QAAQ,CAAC,KAAK,EAAE,MAAM;IAItB,SAAS,CAAC,MAAM,EAAE,MAAM;IAIxB,UAAU,CAAC,GAAG,EAAE,GAAG;IAInB,aAAa,CAAC,MAAM,EAAE,MAAM;IAI5B,qBAAqB,CAAC,OAAO,EAAE,OAAO;IAItC,eAAe,CAAC,KAAK,EAAE,MAAM;IAM7B,mBAAmB,CACjB,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,EAC1B,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,EAC/B,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,EAC/B,YAAY,EAAE,MAAM;IAQtB,iBAAiB;IAIjB,WAAW,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC;IAIzC,MAAM,GAAI,QAAO,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAQ,EAAE,mBAAgB,UA2B9D;IAEF,MAAM,GAAI,mBAAiB,UAoBzB;IAEF,OAAO,GAAI,mBAAiB,UA0B1B;IAEF,SAAS,GAAI,cAAS,UAQpB;IAEF,SAAS,GAAI,OAAO,MAAM,UA4CxB;IAEF,uBAAuB,GAAI,aAAa,MAAM,aAY5C;IAEF,qBAAqB,aAEnB;IAEF,YAAY,aAEV;IAEF,QAAQ,aAEN;IAEF,OAAO;IAeP,OAAO,CAAC,kBAAkB,CAGxB;CACH;AAED,eAAe,oBAAoB,CAAC"}
@@ -120,6 +120,11 @@ export interface GestureViewerProps<T = any, LC = typeof RNFlatList> {
120
120
  * @defaultValue true
121
121
  */
122
122
  enableDoubleTapGesture?: boolean;
123
+ /**
124
+ * Enables infinite loop navigation.
125
+ * @defaultValue false
126
+ */
127
+ enableLoop?: boolean;
123
128
  /**
124
129
  * The maximum zoom scale.
125
130
  * @defaultValue 2
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { type NativeScrollEvent, type NativeSyntheticEvent } from 'react-native';
2
2
  import type { GestureViewerProps } from './types';
3
3
  type UseGestureViewerProps<T = any> = Omit<GestureViewerProps<T>, 'renderItem' | 'renderContainer' | 'ListComponent' | 'listProps' | 'containerStyle' | 'backdropStyle'>;
4
- export declare const useGestureViewer: <T = any>({ data, initialIndex, onIndexChange, onDismiss, width: customWidth, dismissThreshold, resistance, animateBackdrop, enableDismissGesture, enableSwipeGesture, enableZoomGesture, enableDoubleTapGesture, enableZoomPanGesture, maxZoomScale, itemSpacing, useSnap, id, }: UseGestureViewerProps<T>) => {
4
+ export declare const useGestureViewer: <T = any>({ data, initialIndex, onIndexChange, onDismiss, width: customWidth, dismissThreshold, resistance, animateBackdrop, enableDismissGesture, enableSwipeGesture, enableZoomGesture, enableDoubleTapGesture, enableZoomPanGesture, enableLoop, maxZoomScale, itemSpacing, useSnap, id, }: UseGestureViewerProps<T>) => {
5
5
  currentIndex: number;
6
6
  dataLength: number;
7
7
  translateY: import("react-native-reanimated").SharedValue<number>;
@@ -11,6 +11,7 @@ export declare const useGestureViewer: <T = any>({ data, initialIndex, onIndexCh
11
11
  dismissGesture: import("react-native-gesture-handler/lib/typescript/handlers/gestures/panGesture").PanGesture;
12
12
  zoomGesture: import("react-native-gesture-handler/lib/typescript/handlers/gestures/gestureComposition").ComposedGesture;
13
13
  onMomentumScrollEnd: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
14
+ onScrollBeginDrag: () => void;
14
15
  animatedStyle: {
15
16
  transform: ({
16
17
  translateY: number;
@@ -1 +1 @@
1
- {"version":3,"file":"useGestureViewer.d.ts","sourceRoot":"","sources":["../../../src/useGestureViewer.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EAE1B,MAAM,cAAc,CAAC;AActB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAGlD,KAAK,qBAAqB,CAAC,CAAC,GAAG,GAAG,IAAI,IAAI,CACxC,kBAAkB,CAAC,CAAC,CAAC,EACrB,YAAY,GAAG,iBAAiB,GAAG,eAAe,GAAG,WAAW,GAAG,gBAAgB,GAAG,eAAe,CACtG,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,CAAC,GAAG,GAAG,EAAE,yQAoBvC,qBAAqB,CAAC,CAAC,CAAC;;;;;;;;;iCAoKf,oBAAoB,CAAC,iBAAiB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4QlD,CAAC"}
1
+ {"version":3,"file":"useGestureViewer.d.ts","sourceRoot":"","sources":["../../../src/useGestureViewer.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EAE1B,MAAM,cAAc,CAAC;AActB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAGlD,KAAK,qBAAqB,CAAC,CAAC,GAAG,GAAG,IAAI,IAAI,CACxC,kBAAkB,CAAC,CAAC,CAAC,EACrB,YAAY,GAAG,iBAAiB,GAAG,eAAe,GAAG,WAAW,GAAG,gBAAgB,GAAG,eAAe,CACtG,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,CAAC,GAAG,GAAG,EAAE,qRAqBvC,qBAAqB,CAAC,CAAC,CAAC;;;;;;;;;iCA6Kf,oBAAoB,CAAC,iBAAiB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+RlD,CAAC"}
@@ -13,4 +13,13 @@ export declare const createBoundsConstraint: ({ width, height }: {
13
13
  translateX: number;
14
14
  translateY: number;
15
15
  };
16
+ export declare const createLoopData: <T>(dataRef: React.RefObject<T[]>, enableLoop: boolean) => T[];
17
+ export declare const getLoopAdjustedIndex: (scrollIndex: number, originalDataLength: number, enableLoop: boolean) => {
18
+ realIndex: number;
19
+ needsJump: boolean;
20
+ jumpToIndex?: number;
21
+ };
22
+ export declare const createScrollAction: (listRef: any, width: number) => {
23
+ scrollTo: (index: number, animated: boolean) => void;
24
+ };
16
25
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEtE,eAAO,MAAM,gBAAgB,GAAI,WAAW,GAAG,KAAG,SAAS,IAAI,mBAE9D,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,WAAW,GAAG,KAAG,SAAS,IAAI,iBAM5D,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,WAAW,GAAG,KAAG,SAAS,IAAI,GAY7D,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAChC,mBAAmB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,MACpD,mCAAmC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE;;;CAiB5F,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEtE,eAAO,MAAM,gBAAgB,GAAI,WAAW,GAAG,KAAG,SAAS,IAAI,mBAE9D,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,WAAW,GAAG,KAAG,SAAS,IAAI,iBAM5D,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,WAAW,GAAG,KAAG,SAAS,IAAI,GAY7D,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAChC,mBAAmB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,MACpD,mCAAmC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE;;;CAiB5F,CAAC;AAEJ,eAAO,MAAM,cAAc,GAAI,CAAC,EAAE,SAAS,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,YAAY,OAAO,KAAG,CAAC,EAevF,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,aAAa,MAAM,EACnB,oBAAoB,MAAM,EAC1B,YAAY,OAAO,KAClB;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAoB/D,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,SAAS,GAAG,EAAE,OAAO,MAAM;sBAC1C,MAAM,YAAY,OAAO;CAO3C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-gesture-image-viewer",
3
- "version": "1.5.1",
3
+ "version": "1.6.1",
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,11 +1,11 @@
1
- import { useCallback, useEffect, useMemo } from 'react';
1
+ import { useCallback, useEffect, useMemo, useRef } from 'react';
2
2
  import { type FlatList, Platform, 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';
6
6
  import type { GestureViewerProps } from './types';
7
7
  import { useGestureViewer } from './useGestureViewer';
8
- import { isFlashListLike, isFlatListLike, isScrollViewLike } from './utils';
8
+ import { createLoopData, isFlashListLike, isFlatListLike, isScrollViewLike } from './utils';
9
9
  import WebPagingFixStyle from './WebPagingFixStyle';
10
10
 
11
11
  export function GestureViewer<T = any, LC = typeof FlatList>({
@@ -21,14 +21,20 @@ export function GestureViewer<T = any, LC = typeof FlatList>({
21
21
  initialIndex = 0,
22
22
  itemSpacing = 0,
23
23
  useSnap = false,
24
+ enableLoop = false,
24
25
  ...props
25
26
  }: GestureViewerProps<T, LC>) {
26
27
  const Component = ListComponent as React.ComponentType<any>;
27
28
 
29
+ const dataRef = useRef(data);
30
+ dataRef.current = data;
31
+
28
32
  const { width: screenWidth } = useWindowDimensions();
29
33
 
30
34
  const width = useSnap ? customWidth || screenWidth : screenWidth;
31
35
 
36
+ const loopData = useMemo(() => createLoopData(dataRef, enableLoop), [enableLoop]);
37
+
32
38
  const {
33
39
  listRef,
34
40
  isZoomed,
@@ -36,6 +42,7 @@ export function GestureViewer<T = any, LC = typeof FlatList>({
36
42
  dismissGesture,
37
43
  zoomGesture,
38
44
  onMomentumScrollEnd,
45
+ onScrollBeginDrag,
39
46
  animatedStyle,
40
47
  backdropStyle,
41
48
  } = useGestureViewer({
@@ -45,14 +52,26 @@ export function GestureViewer<T = any, LC = typeof FlatList>({
45
52
  initialIndex,
46
53
  itemSpacing,
47
54
  useSnap,
55
+ enableLoop,
48
56
  ...props,
49
57
  });
50
58
 
59
+ const keyExtractor = useCallback(
60
+ (item: T, index: number) => {
61
+ if (enableLoop) {
62
+ return typeof item === 'string' ? `${item}-${index}` : `item-${index}`;
63
+ }
64
+
65
+ return typeof item === 'string' ? item : `image-${index}`;
66
+ },
67
+ [enableLoop],
68
+ );
69
+
51
70
  const renderItem = useCallback(
52
71
  ({ item, index }: { item: T; index: number }) => {
53
72
  return (
54
73
  <View
55
- key={typeof item === 'string' ? item : index}
74
+ key={keyExtractor(item, index)}
56
75
  style={[
57
76
  {
58
77
  width,
@@ -67,7 +86,7 @@ export function GestureViewer<T = any, LC = typeof FlatList>({
67
86
  </View>
68
87
  );
69
88
  },
70
- [width, itemSpacing, renderItemProp],
89
+ [width, itemSpacing, renderItemProp, keyExtractor],
71
90
  );
72
91
 
73
92
  const getItemLayout = useCallback(
@@ -79,11 +98,6 @@ export function GestureViewer<T = any, LC = typeof FlatList>({
79
98
  [width, itemSpacing],
80
99
  );
81
100
 
82
- const keyExtractor = useCallback(
83
- (item: T, index: number) => (typeof item === 'string' ? item : `image-${index}`),
84
- [],
85
- );
86
-
87
101
  const gesture = useMemo(() => {
88
102
  return Gesture.Race(dismissGesture, zoomGesture);
89
103
  }, [zoomGesture, dismissGesture]);
@@ -94,25 +108,27 @@ export function GestureViewer<T = any, LC = typeof FlatList>({
94
108
  return () => registry.deleteManager(id);
95
109
  }, [id]);
96
110
 
97
- const commonProps: ScrollViewProps = useMemo(
98
- () => ({
99
- horizontal: true,
100
- scrollEnabled: !isZoomed && !isRotated,
101
- showsHorizontalScrollIndicator: false,
102
- onMomentumScrollEnd: onMomentumScrollEnd,
103
- ...(useSnap
104
- ? {
105
- snapToInterval: width + itemSpacing,
106
- snapToAlignment: 'center',
107
- decelerationRate: 'fast',
108
- }
109
- : {
110
- pagingEnabled: true,
111
- }),
112
- scrollEventThrottle: 16,
113
- removeClippedSubviews: true,
114
- }),
115
- [width, itemSpacing, isZoomed, isRotated, onMomentumScrollEnd, useSnap],
111
+ const commonProps = useMemo(
112
+ () =>
113
+ ({
114
+ horizontal: true,
115
+ scrollEnabled: !isZoomed && !isRotated,
116
+ showsHorizontalScrollIndicator: false,
117
+ onMomentumScrollEnd: onMomentumScrollEnd,
118
+ onScrollBeginDrag,
119
+ ...(useSnap
120
+ ? {
121
+ snapToInterval: width + itemSpacing,
122
+ snapToAlignment: 'center',
123
+ decelerationRate: 'fast',
124
+ }
125
+ : {
126
+ pagingEnabled: true,
127
+ }),
128
+ scrollEventThrottle: 16,
129
+ removeClippedSubviews: true,
130
+ }) satisfies ScrollViewProps,
131
+ [width, itemSpacing, isZoomed, isRotated, onMomentumScrollEnd, onScrollBeginDrag, useSnap],
116
132
  );
117
133
 
118
134
  const listComponent = (
@@ -127,16 +143,16 @@ export function GestureViewer<T = any, LC = typeof FlatList>({
127
143
  >
128
144
  {isScrollViewLike(Component) ? (
129
145
  <Component ref={listRef} {...commonProps} {...listProps}>
130
- {data.map((item, index) => renderItem({ item, index }))}
146
+ {loopData.map((item, index) => renderItem({ item, index }))}
131
147
  </Component>
132
148
  ) : (
133
149
  isFlatListLike(Component) && (
134
150
  <Component
135
151
  ref={listRef}
136
152
  {...commonProps}
137
- data={data}
153
+ data={loopData}
138
154
  renderItem={renderItem}
139
- initialScrollIndex={initialIndex}
155
+ initialScrollIndex={enableLoop && data.length > 1 ? initialIndex + 1 : initialIndex}
140
156
  keyExtractor={keyExtractor}
141
157
  windowSize={3}
142
158
  maxToRenderPerBatch={3}
@@ -5,21 +5,26 @@ import type {
5
5
  GestureViewerEventData,
6
6
  GestureViewerEventType,
7
7
  } from './types';
8
- import { createBoundsConstraint } from './utils';
8
+ import { createBoundsConstraint, createScrollAction } from './utils';
9
9
 
10
10
  class GestureViewerManager {
11
11
  private currentIndex = 0;
12
12
  private dataLength = 0;
13
13
  private width = 0;
14
14
  private height = 0;
15
+ private maxZoomScale = 2;
16
+ private enableSwipeGesture = true;
17
+ private enableLoop = false;
18
+ private listRef: any | null = null;
19
+
15
20
  private scale: SharedValue<number> | null = null;
21
+ private rotation: SharedValue<number> | null = null;
16
22
  private translateX: SharedValue<number> | null = null;
17
23
  private translateY: SharedValue<number> | null = null;
18
- private maxZoomScale = 2;
19
- private listRef: any | null = null;
20
- private enableSwipeGesture = true;
24
+
25
+ private loopCallback: (() => void) | null = null;
26
+
21
27
  private listeners = new Set<(state: GestureViewerControllerState) => void>();
22
- private rotation: SharedValue<number> | null = null;
23
28
  private eventListeners = new Map<GestureViewerEventType, Set<(data: any) => void>>();
24
29
 
25
30
  private notifyListeners() {
@@ -79,6 +84,10 @@ class GestureViewerManager {
79
84
  };
80
85
  }
81
86
 
87
+ setEnableLoop(enabled: boolean) {
88
+ this.enableLoop = enabled;
89
+ }
90
+
82
91
  setWidth(width: number) {
83
92
  this.width = width;
84
93
  }
@@ -215,40 +224,84 @@ class GestureViewerManager {
215
224
  };
216
225
 
217
226
  goToIndex = (index: number) => {
218
- if (index < 0 || index >= this.dataLength || !this.enableSwipeGesture || !this.listRef) {
227
+ if (!this.enableSwipeGesture || !this.listRef) {
228
+ return;
229
+ }
230
+
231
+ this.loopCallback = null;
232
+
233
+ const { scrollTo } = createScrollAction(this.listRef, this.width);
234
+
235
+ if (this.enableLoop && this.dataLength > 1) {
236
+ if (index < 0) {
237
+ this.loopCallback = () => {
238
+ scrollTo(this.dataLength, false);
239
+ this.updateCurrentIndex(this.dataLength - 1);
240
+ this.loopCallback = null;
241
+ };
242
+
243
+ scrollTo(0, true);
244
+ return;
245
+ }
246
+
247
+ if (index >= this.dataLength) {
248
+ this.loopCallback = () => {
249
+ scrollTo(1, false);
250
+ this.updateCurrentIndex(0);
251
+ this.loopCallback = null;
252
+ };
253
+
254
+ scrollTo(this.dataLength + 1, true);
255
+ return;
256
+ }
257
+
258
+ scrollTo(index + 1, true);
259
+ this.updateCurrentIndex(index);
260
+
219
261
  return;
220
262
  }
221
263
 
222
- this.currentIndex = index;
264
+ if (index < 0 || index >= this.dataLength) {
265
+ return;
266
+ }
223
267
 
224
- if (this.listRef.scrollToIndex) {
225
- this.listRef.scrollToIndex({ index, animated: true });
226
- } else if (this.listRef.scrollTo) {
227
- this.listRef.scrollTo({ x: index * this.width, animated: true });
268
+ scrollTo(index, true);
269
+ this.updateCurrentIndex(index);
270
+ };
271
+
272
+ handleMomentumScrollEnd = (scrollIndex: number) => {
273
+ if (!this.loopCallback) {
274
+ return false;
228
275
  }
229
276
 
230
- this.notifyListeners();
277
+ if (scrollIndex === 0 || scrollIndex === this.dataLength + 1) {
278
+ this.loopCallback();
279
+ return true;
280
+ }
281
+
282
+ this.loopCallback = null;
283
+ return true;
284
+ };
285
+
286
+ handleScrollBeginDrag = () => {
287
+ this.loopCallback = null;
231
288
  };
232
289
 
233
290
  goToPrevious = () => {
234
- if (this.currentIndex > 0) {
235
- this.goToIndex(this.currentIndex - 1);
236
- }
291
+ this.goToIndex(this.currentIndex - 1);
237
292
  };
238
293
 
239
294
  goToNext = () => {
240
- if (this.currentIndex < this.dataLength - 1) {
241
- this.goToIndex(this.currentIndex + 1);
242
- }
295
+ this.goToIndex(this.currentIndex + 1);
243
296
  };
244
297
 
245
298
  cleanUp() {
299
+ this.loopCallback = null;
246
300
  this.listeners.clear();
247
301
  this.listRef = null;
248
302
  this.enableSwipeGesture = true;
249
303
  this.currentIndex = 0;
250
304
  this.dataLength = 0;
251
-
252
305
  this.maxZoomScale = 2;
253
306
  this.scale = null;
254
307
  this.translateX = null;
@@ -256,6 +309,11 @@ class GestureViewerManager {
256
309
  this.rotation = null;
257
310
  this.eventListeners.clear();
258
311
  }
312
+
313
+ private updateCurrentIndex = (targetIndex: number) => {
314
+ this.currentIndex = targetIndex;
315
+ this.notifyListeners();
316
+ };
259
317
  }
260
318
 
261
319
  export default GestureViewerManager;
package/src/types.ts CHANGED
@@ -130,6 +130,11 @@ export interface GestureViewerProps<T = any, LC = typeof RNFlatList> {
130
130
  * @defaultValue true
131
131
  */
132
132
  enableDoubleTapGesture?: boolean;
133
+ /**
134
+ * Enables infinite loop navigation.
135
+ * @defaultValue false
136
+ */
137
+ enableLoop?: boolean;
133
138
  /**
134
139
  * The maximum zoom scale.
135
140
  * @defaultValue 2
@@ -19,7 +19,7 @@ import {
19
19
  import type GestureViewerManager from './GestureViewerManager';
20
20
  import { registry } from './GestureViewerRegistry';
21
21
  import type { GestureViewerProps } from './types';
22
- import { createBoundsConstraint } from './utils';
22
+ import { createBoundsConstraint, createScrollAction, getLoopAdjustedIndex } from './utils';
23
23
 
24
24
  type UseGestureViewerProps<T = any> = Omit<
25
25
  GestureViewerProps<T>,
@@ -42,6 +42,7 @@ export const useGestureViewer = <T = any>({
42
42
  enableZoomGesture = true,
43
43
  enableDoubleTapGesture = true,
44
44
  enableZoomPanGesture = true,
45
+ enableLoop = false,
45
46
  maxZoomScale = 2,
46
47
  itemSpacing = 0,
47
48
  useSnap = false,
@@ -71,11 +72,28 @@ export const useGestureViewer = <T = any>({
71
72
 
72
73
  const dataLength = data?.length || 0;
73
74
 
75
+ const adjustedInitialIndex = useMemo(() => {
76
+ if (enableLoop && data.length > 1) {
77
+ return initialIndex + 1;
78
+ }
79
+
80
+ return initialIndex;
81
+ }, [enableLoop, data.length, initialIndex]);
82
+
74
83
  const constrainTranslation = useMemo(
75
84
  () => createBoundsConstraint({ width, height: screenHeight }),
76
85
  [width, screenHeight],
77
86
  );
78
87
 
88
+ const scrollTo = useCallback(
89
+ (index: number, animated: boolean) => {
90
+ const scrollAction = createScrollAction(listRef.current, width + itemSpacing);
91
+
92
+ return scrollAction.scrollTo(index, animated);
93
+ },
94
+ [width, itemSpacing],
95
+ );
96
+
79
97
  const emitZoomChange = useCallback(
80
98
  (currentScale: number, prevScale: number | null) => {
81
99
  manager?.emitZoomChange(currentScale, prevScale);
@@ -150,6 +168,7 @@ export const useGestureViewer = <T = any>({
150
168
  manager.setHeight(screenHeight);
151
169
  manager.setZoomSharedValues(scale, translateX, translateY, maxZoomScale);
152
170
  manager.setRotation(rotation);
171
+ manager.setEnableLoop(enableLoop);
153
172
  manager.notifyStateChange();
154
173
  }, [
155
174
  dataLength,
@@ -159,6 +178,7 @@ export const useGestureViewer = <T = any>({
159
178
  width,
160
179
  itemSpacing,
161
180
  maxZoomScale,
181
+ enableLoop,
162
182
  scale,
163
183
  screenHeight,
164
184
  translateX,
@@ -186,28 +206,18 @@ export const useGestureViewer = <T = any>({
186
206
  startScale.value = 1;
187
207
  rotation.value = 0;
188
208
 
189
- if (initialIndex <= 0 || !listRef.current) {
209
+ if (adjustedInitialIndex <= 0 || !listRef.current) {
190
210
  return;
191
211
  }
192
212
 
193
213
  const runAfterInteractions = InteractionManager.runAfterInteractions(() => {
194
- if (listRef.current.scrollToIndex) {
195
- listRef.current.scrollToIndex({
196
- index: initialIndex,
197
- animated: false,
198
- });
199
- } else if (listRef.current.scrollTo) {
200
- listRef.current.scrollTo({
201
- x: initialIndex * (width + itemSpacing),
202
- animated: false,
203
- });
204
- }
214
+ scrollTo(adjustedInitialIndex, false);
205
215
  });
206
216
 
207
217
  return () => {
208
218
  runAfterInteractions?.cancel();
209
219
  };
210
- }, [initialIndex, translateY, backdropOpacity, translateX, scale, startScale, width, itemSpacing, rotation]);
220
+ }, [adjustedInitialIndex, translateY, backdropOpacity, translateX, scale, startScale, rotation, scrollTo]);
211
221
 
212
222
  const onMomentumScrollEnd = useCallback(
213
223
  (event: NativeSyntheticEvent<NativeScrollEvent>) => {
@@ -216,12 +226,24 @@ export const useGestureViewer = <T = any>({
216
226
  }
217
227
 
218
228
  const contentOffset = event.nativeEvent.contentOffset;
219
- const newIndex = Math.round(contentOffset.x / (width + itemSpacing));
229
+ const scrollIndex = Math.round(contentOffset.x / (width + itemSpacing));
220
230
 
221
- if (newIndex !== currentIndex && newIndex >= 0 && newIndex < dataLength) {
231
+ const isLoopHandled = manager?.handleMomentumScrollEnd(scrollIndex);
232
+
233
+ if (isLoopHandled) {
234
+ return;
235
+ }
236
+
237
+ const { realIndex, needsJump, jumpToIndex } = getLoopAdjustedIndex(scrollIndex, dataLength, enableLoop);
238
+
239
+ if (needsJump && jumpToIndex !== undefined) {
240
+ scrollTo(jumpToIndex, false);
241
+ }
242
+
243
+ if (realIndex !== currentIndex && realIndex >= 0 && realIndex < dataLength) {
222
244
  if (manager) {
223
- manager.setCurrentIndex(newIndex);
224
- setCurrentIndex(newIndex);
245
+ manager.setCurrentIndex(realIndex);
246
+ setCurrentIndex(realIndex);
225
247
  manager.notifyStateChange();
226
248
  }
227
249
 
@@ -235,12 +257,14 @@ export const useGestureViewer = <T = any>({
235
257
  }
236
258
  },
237
259
  [
260
+ scrollTo,
238
261
  manager,
239
262
  currentIndex,
240
263
  dataLength,
241
264
  width,
242
265
  itemSpacing,
243
266
  enableSwipeGesture,
267
+ enableLoop,
244
268
  translateX,
245
269
  translateY,
246
270
  scale,
@@ -463,6 +487,10 @@ export const useGestureViewer = <T = any>({
463
487
  return { opacity };
464
488
  }, [animateBackdrop]);
465
489
 
490
+ const onScrollBeginDrag = useCallback(() => {
491
+ manager?.handleScrollBeginDrag();
492
+ }, [manager]);
493
+
466
494
  return {
467
495
  currentIndex,
468
496
  dataLength,
@@ -474,6 +502,7 @@ export const useGestureViewer = <T = any>({
474
502
  zoomGesture,
475
503
 
476
504
  onMomentumScrollEnd,
505
+ onScrollBeginDrag,
477
506
 
478
507
  animatedStyle,
479
508
  backdropStyle,