react-native-reanimated-carousel 2.3.7 → 2.3.10

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 (54) hide show
  1. package/lib/commonjs/Carousel.js +1 -1
  2. package/lib/commonjs/Carousel.js.map +1 -1
  3. package/lib/commonjs/ScrollViewGesture.js +1 -1
  4. package/lib/commonjs/ScrollViewGesture.js.map +1 -1
  5. package/lib/commonjs/hooks/useAutoPlay.js +1 -1
  6. package/lib/commonjs/hooks/useAutoPlay.js.map +1 -1
  7. package/lib/commonjs/hooks/useCarouselController.js +1 -1
  8. package/lib/commonjs/hooks/useCarouselController.js.map +1 -1
  9. package/lib/commonjs/utils/computedWithAutoFillData.js +1 -1
  10. package/lib/commonjs/utils/computedWithAutoFillData.js.map +1 -1
  11. package/lib/module/Carousel.js +40 -25
  12. package/lib/module/Carousel.js.map +1 -1
  13. package/lib/module/ScrollViewGesture.js +12 -11
  14. package/lib/module/ScrollViewGesture.js.map +1 -1
  15. package/lib/module/hooks/useAutoPlay.js +7 -3
  16. package/lib/module/hooks/useAutoPlay.js.map +1 -1
  17. package/lib/module/hooks/useCarouselController.js +36 -43
  18. package/lib/module/hooks/useCarouselController.js.map +1 -1
  19. package/lib/module/utils/computedWithAutoFillData.js +25 -0
  20. package/lib/module/utils/computedWithAutoFillData.js.map +1 -1
  21. package/lib/typescript/{src/Carousel.d.ts → Carousel.d.ts} +0 -0
  22. package/lib/typescript/{src/LazyView.d.ts → LazyView.d.ts} +0 -0
  23. package/lib/typescript/{src/ScrollViewGesture.d.ts → ScrollViewGesture.d.ts} +0 -0
  24. package/lib/typescript/{src/constants → constants}/index.d.ts +0 -0
  25. package/lib/typescript/{src/hooks → hooks}/useAutoPlay.d.ts +0 -0
  26. package/lib/typescript/{src/hooks → hooks}/useCarouselController.d.ts +4 -10
  27. package/lib/typescript/{src/hooks → hooks}/useCheckMounted.d.ts +0 -0
  28. package/lib/typescript/{src/hooks → hooks}/useCommonVariables.d.ts +0 -0
  29. package/lib/typescript/{src/hooks → hooks}/useInitProps.d.ts +0 -0
  30. package/lib/typescript/{src/hooks → hooks}/useLayoutConfig.d.ts +0 -0
  31. package/lib/typescript/{src/hooks → hooks}/useOffsetX.d.ts +0 -0
  32. package/lib/typescript/{src/hooks → hooks}/useOnProgressChange.d.ts +0 -0
  33. package/lib/typescript/{src/hooks → hooks}/usePropsErrorBoundary.d.ts +0 -0
  34. package/lib/typescript/{src/hooks → hooks}/useVisibleRanges.d.ts +0 -0
  35. package/lib/typescript/{src/index.d.ts → index.d.ts} +0 -0
  36. package/lib/typescript/{src/layouts → layouts}/BaseLayout.d.ts +0 -0
  37. package/lib/typescript/{src/layouts → layouts}/ParallaxLayout.d.ts +0 -0
  38. package/lib/typescript/{src/layouts → layouts}/index.d.ts +0 -0
  39. package/lib/typescript/{src/layouts → layouts}/normal.d.ts +0 -0
  40. package/lib/typescript/{src/layouts → layouts}/parallax.d.ts +0 -0
  41. package/lib/typescript/{src/layouts → layouts}/stack.d.ts +0 -0
  42. package/lib/typescript/{src/store → store}/index.d.ts +0 -0
  43. package/lib/typescript/{src/types.d.ts → types.d.ts} +5 -0
  44. package/lib/typescript/{src/utils → utils}/computedWithAutoFillData.d.ts +4 -0
  45. package/lib/typescript/{src/utils → utils}/dealWithAnimation.d.ts +0 -0
  46. package/lib/typescript/{src/utils → utils}/log.d.ts +0 -0
  47. package/package.json +3 -3
  48. package/src/Carousel.tsx +43 -29
  49. package/src/ScrollViewGesture.tsx +12 -10
  50. package/src/hooks/useAutoPlay.ts +4 -3
  51. package/src/hooks/useCarouselController.tsx +53 -62
  52. package/src/types.ts +4 -0
  53. package/src/utils/computedWithAutoFillData.ts +18 -0
  54. package/lib/typescript/exampleBare/App.d.ts +0 -2
@@ -1 +1 @@
1
- {"version":3,"sources":["computedWithAutoFillData.ts"],"names":["DATA_LENGTH","SINGLE_ITEM","DOUBLE_ITEM","isAutoFillData","params","loop","autoFillData","computedOffsetXValueWithAutoFillData","rawDataLength","value","size","computedRealIndexWithAutoFillData","index","dataLength","computedFillDataWithAutoFillData","data"],"mappings":"AAAA,SAASA,WAAT,QAA4B,eAA5B;AAEA,MAAM;AAAEC,EAAAA,WAAF;AAAeC,EAAAA;AAAf,IAA+BF,WAArC;;AAEA,SAASG,cAAT,CAAwBC,MAAxB,EAA0E;AACtE;;AACA,SAAO,CAAC,CAACA,MAAM,CAACC,IAAT,IAAiB,CAAC,CAACD,MAAM,CAACE,YAAjC;AACH;;AAOD,OAAO,SAASC,oCAAT,CACHH,MADG,EAML;AACE;;AAEA,QAAM;AAAEI,IAAAA,aAAF;AAAiBC,IAAAA,KAAjB;AAAwBC,IAAAA,IAAxB;AAA8BL,IAAAA,IAA9B;AAAoCC,IAAAA;AAApC,MAAqDF,MAA3D;;AAEA,MAAID,cAAc,CAAC;AAAEE,IAAAA,IAAF;AAAQC,IAAAA;AAAR,GAAD,CAAlB,EAA4C;AACxC,YAAQE,aAAR;AACI,WAAKP,WAAL;AACI,eAAOQ,KAAK,GAAGC,IAAf;;AACJ,WAAKR,WAAL;AACI,eAAOO,KAAK,IAAIC,IAAI,GAAG,CAAX,CAAZ;AAJR;AAMH;;AAED,SAAOD,KAAP;AACH;AAED,OAAO,SAASE,iCAAT,CACHP,MADG,EAKL;AACE,QAAM;AAAEQ,IAAAA,KAAF;AAASC,IAAAA,UAAT;AAAqBR,IAAAA,IAArB;AAA2BC,IAAAA;AAA3B,MAA4CF,MAAlD;;AAEA,MAAID,cAAc,CAAC;AAAEE,IAAAA,IAAF;AAAQC,IAAAA;AAAR,GAAD,CAAlB,EAA4C;AACxC,YAAQO,UAAR;AACI,WAAKZ,WAAL;AACI,eAAOW,KAAK,GAAG,CAAf;;AACJ,WAAKV,WAAL;AACI,eAAOU,KAAK,GAAG,CAAf;AAJR;AAMH;;AAED,SAAOA,KAAP;AACH;AAED,OAAO,SAASE,gCAAT,CACHV,MADG,EAKA;AACH,QAAM;AAAEW,IAAAA,IAAF;AAAQV,IAAAA,IAAR;AAAcC,IAAAA,YAAd;AAA4BO,IAAAA;AAA5B,MAA2CT,MAAjD;;AAEA,MAAID,cAAc,CAAC;AAAEE,IAAAA,IAAF;AAAQC,IAAAA;AAAR,GAAD,CAAlB,EAA4C;AACxC,YAAQO,UAAR;AACI,WAAKZ,WAAL;AACI,eAAO,CAACc,IAAI,CAAC,CAAD,CAAL,EAAUA,IAAI,CAAC,CAAD,CAAd,EAAmBA,IAAI,CAAC,CAAD,CAAvB,CAAP;;AACJ,WAAKb,WAAL;AACI,eAAO,CAACa,IAAI,CAAC,CAAD,CAAL,EAAUA,IAAI,CAAC,CAAD,CAAd,EAAmBA,IAAI,CAAC,CAAD,CAAvB,EAA4BA,IAAI,CAAC,CAAD,CAAhC,CAAP;AAJR;AAMH;;AAED,SAAOA,IAAP;AACH","sourcesContent":["import { DATA_LENGTH } from 'src/constants';\n\nconst { SINGLE_ITEM, DOUBLE_ITEM } = DATA_LENGTH;\n\nfunction isAutoFillData(params: { autoFillData: boolean; loop: boolean }) {\n 'worklet';\n return !!params.loop && !!params.autoFillData;\n}\n\ntype BaseParams<T extends object = {}> = {\n autoFillData: boolean;\n loop: boolean;\n} & T;\n\nexport function computedOffsetXValueWithAutoFillData(\n params: BaseParams<{\n rawDataLength: number;\n value: number;\n size: number;\n }>\n) {\n 'worklet';\n\n const { rawDataLength, value, size, loop, autoFillData } = params;\n\n if (isAutoFillData({ loop, autoFillData })) {\n switch (rawDataLength) {\n case SINGLE_ITEM:\n return value % size;\n case DOUBLE_ITEM:\n return value % (size * 2);\n }\n }\n\n return value;\n}\n\nexport function computedRealIndexWithAutoFillData(\n params: BaseParams<{\n index: number;\n dataLength: number;\n }>\n) {\n const { index, dataLength, loop, autoFillData } = params;\n\n if (isAutoFillData({ loop, autoFillData })) {\n switch (dataLength) {\n case SINGLE_ITEM:\n return index % 1;\n case DOUBLE_ITEM:\n return index % 2;\n }\n }\n\n return index;\n}\n\nexport function computedFillDataWithAutoFillData<T>(\n params: BaseParams<{\n data: T[];\n dataLength: number;\n }>\n): T[] {\n const { data, loop, autoFillData, dataLength } = params;\n\n if (isAutoFillData({ loop, autoFillData })) {\n switch (dataLength) {\n case SINGLE_ITEM:\n return [data[0], data[0], data[0]];\n case DOUBLE_ITEM:\n return [data[0], data[1], data[0], data[1]];\n }\n }\n\n return data;\n}\n"]}
1
+ {"version":3,"sources":["computedWithAutoFillData.ts"],"names":["DATA_LENGTH","SINGLE_ITEM","DOUBLE_ITEM","isAutoFillData","params","loop","autoFillData","convertToSharedIndex","rawDataLength","index","computedOffsetXValueWithAutoFillData","value","size","computedRealIndexWithAutoFillData","dataLength","computedFillDataWithAutoFillData","data"],"mappings":"AAAA,SAASA,WAAT,QAA4B,eAA5B;AAEA,MAAM;AAAEC,EAAAA,WAAF;AAAeC,EAAAA;AAAf,IAA+BF,WAArC;;AAEA,SAASG,cAAT,CAAwBC,MAAxB,EAA0E;AACtE;;AACA,SAAO,CAAC,CAACA,MAAM,CAACC,IAAT,IAAiB,CAAC,CAACD,MAAM,CAACE,YAAjC;AACH;;AAOD,OAAO,SAASC,oBAAT,CACHH,MADG,EAEL;AACE;;AACA,QAAM;AAAEC,IAAAA,IAAF;AAAQG,IAAAA,aAAR;AAAuBC,IAAAA,KAAvB;AAA8BH,IAAAA;AAA9B,MAA+CF,MAArD;;AAEA,MAAID,cAAc,CAAC;AAAEE,IAAAA,IAAF;AAAQC,IAAAA;AAAR,GAAD,CAAlB,EAA4C;AACxC,YAAQE,aAAR;AACI,WAAKP,WAAL;AACI,eAAO,CAAP;;AACJ,WAAKC,WAAL;AACI,eAAOO,KAAK,GAAG,CAAf;AAJR;AAMH;;AAED,SAAOA,KAAP;AACH;AAED,OAAO,SAASC,oCAAT,CACHN,MADG,EAML;AACE;;AAEA,QAAM;AAAEI,IAAAA,aAAF;AAAiBG,IAAAA,KAAjB;AAAwBC,IAAAA,IAAxB;AAA8BP,IAAAA,IAA9B;AAAoCC,IAAAA;AAApC,MAAqDF,MAA3D;;AAEA,MAAID,cAAc,CAAC;AAAEE,IAAAA,IAAF;AAAQC,IAAAA;AAAR,GAAD,CAAlB,EAA4C;AACxC,YAAQE,aAAR;AACI,WAAKP,WAAL;AACI,eAAOU,KAAK,GAAGC,IAAf;;AACJ,WAAKV,WAAL;AACI,eAAOS,KAAK,IAAIC,IAAI,GAAG,CAAX,CAAZ;AAJR;AAMH;;AAED,SAAOD,KAAP;AACH;AAED,OAAO,SAASE,iCAAT,CACHT,MADG,EAKL;AACE,QAAM;AAAEK,IAAAA,KAAF;AAASK,IAAAA,UAAT;AAAqBT,IAAAA,IAArB;AAA2BC,IAAAA;AAA3B,MAA4CF,MAAlD;;AAEA,MAAID,cAAc,CAAC;AAAEE,IAAAA,IAAF;AAAQC,IAAAA;AAAR,GAAD,CAAlB,EAA4C;AACxC,YAAQQ,UAAR;AACI,WAAKb,WAAL;AACI,eAAOQ,KAAK,GAAG,CAAf;;AACJ,WAAKP,WAAL;AACI,eAAOO,KAAK,GAAG,CAAf;AAJR;AAMH;;AAED,SAAOA,KAAP;AACH;AAED,OAAO,SAASM,gCAAT,CACHX,MADG,EAKA;AACH,QAAM;AAAEY,IAAAA,IAAF;AAAQX,IAAAA,IAAR;AAAcC,IAAAA,YAAd;AAA4BQ,IAAAA;AAA5B,MAA2CV,MAAjD;;AAEA,MAAID,cAAc,CAAC;AAAEE,IAAAA,IAAF;AAAQC,IAAAA;AAAR,GAAD,CAAlB,EAA4C;AACxC,YAAQQ,UAAR;AACI,WAAKb,WAAL;AACI,eAAO,CAACe,IAAI,CAAC,CAAD,CAAL,EAAUA,IAAI,CAAC,CAAD,CAAd,EAAmBA,IAAI,CAAC,CAAD,CAAvB,CAAP;;AACJ,WAAKd,WAAL;AACI,eAAO,CAACc,IAAI,CAAC,CAAD,CAAL,EAAUA,IAAI,CAAC,CAAD,CAAd,EAAmBA,IAAI,CAAC,CAAD,CAAvB,EAA4BA,IAAI,CAAC,CAAD,CAAhC,CAAP;AAJR;AAMH;;AAED,SAAOA,IAAP;AACH","sourcesContent":["import { DATA_LENGTH } from 'src/constants';\n\nconst { SINGLE_ITEM, DOUBLE_ITEM } = DATA_LENGTH;\n\nfunction isAutoFillData(params: { autoFillData: boolean; loop: boolean }) {\n 'worklet';\n return !!params.loop && !!params.autoFillData;\n}\n\ntype BaseParams<T extends object = {}> = {\n autoFillData: boolean;\n loop: boolean;\n} & T;\n\nexport function convertToSharedIndex(\n params: BaseParams<{ index: number; rawDataLength: number }>\n) {\n 'worklet';\n const { loop, rawDataLength, index, autoFillData } = params;\n\n if (isAutoFillData({ loop, autoFillData })) {\n switch (rawDataLength) {\n case SINGLE_ITEM:\n return 0;\n case DOUBLE_ITEM:\n return index % 2;\n }\n }\n\n return index;\n}\n\nexport function computedOffsetXValueWithAutoFillData(\n params: BaseParams<{\n rawDataLength: number;\n value: number;\n size: number;\n }>\n) {\n 'worklet';\n\n const { rawDataLength, value, size, loop, autoFillData } = params;\n\n if (isAutoFillData({ loop, autoFillData })) {\n switch (rawDataLength) {\n case SINGLE_ITEM:\n return value % size;\n case DOUBLE_ITEM:\n return value % (size * 2);\n }\n }\n\n return value;\n}\n\nexport function computedRealIndexWithAutoFillData(\n params: BaseParams<{\n index: number;\n dataLength: number;\n }>\n) {\n const { index, dataLength, loop, autoFillData } = params;\n\n if (isAutoFillData({ loop, autoFillData })) {\n switch (dataLength) {\n case SINGLE_ITEM:\n return index % 1;\n case DOUBLE_ITEM:\n return index % 2;\n }\n }\n\n return index;\n}\n\nexport function computedFillDataWithAutoFillData<T>(\n params: BaseParams<{\n data: T[];\n dataLength: number;\n }>\n): T[] {\n const { data, loop, autoFillData, dataLength } = params;\n\n if (isAutoFillData({ loop, autoFillData })) {\n switch (dataLength) {\n case SINGLE_ITEM:\n return [data[0], data[0], data[0]];\n case DOUBLE_ITEM:\n return [data[0], data[1], data[0], data[1]];\n }\n }\n\n return data;\n}\n"]}
@@ -1,28 +1,22 @@
1
- import React from 'react';
2
1
  import type Animated from 'react-native-reanimated';
3
2
  import type { TCarouselActionOptions, TCarouselProps } from '../types';
4
3
  interface IOpts {
5
4
  loop: boolean;
6
5
  size: number;
6
+ data: TCarouselProps['data'];
7
+ autoFillData: TCarouselProps['autoFillData'];
7
8
  handlerOffsetX: Animated.SharedValue<number>;
8
9
  withAnimation?: TCarouselProps['withAnimation'];
9
- disable?: boolean;
10
10
  duration?: number;
11
- originalLength: number;
12
- length: number;
13
11
  defaultIndex?: number;
14
12
  onScrollBegin?: () => void;
15
13
  onScrollEnd?: () => void;
16
- onChange: (index: number) => void;
17
14
  }
18
15
  export interface ICarouselController {
19
- length: number;
20
- index: Animated.SharedValue<number>;
21
- sharedIndex: React.MutableRefObject<number>;
22
- sharedPreIndex: React.MutableRefObject<number>;
16
+ sharedIndex: Animated.SharedValue<number>;
17
+ sharedPreIndex: Animated.SharedValue<number>;
23
18
  prev: (opts?: TCarouselActionOptions) => void;
24
19
  next: (opts?: TCarouselActionOptions) => void;
25
- computedIndex: () => void;
26
20
  getCurrentIndex: () => number;
27
21
  to: (index: number, animated?: boolean) => void;
28
22
  scrollTo: (opts?: TCarouselActionOptions) => void;
File without changes
File without changes
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import type { ViewStyle } from 'react-native';
2
3
  import type { PanGestureHandlerProps } from 'react-native-gesture-handler';
3
4
  import type { AnimatedStyleProp, WithSpringConfig, WithTimingConfig } from 'react-native-reanimated';
@@ -128,6 +129,10 @@ export declare type TCarouselProps<T = any> = {
128
129
  * Specifies the scrolling animation effect.
129
130
  */
130
131
  withAnimation?: WithAnimation;
132
+ /**
133
+ * Used to locate this view in end-to-end tests.
134
+ */
135
+ testID?: string;
131
136
  /**
132
137
  * Custom carousel config.
133
138
  */
@@ -2,6 +2,10 @@ declare type BaseParams<T extends object = {}> = {
2
2
  autoFillData: boolean;
3
3
  loop: boolean;
4
4
  } & T;
5
+ export declare function convertToSharedIndex(params: BaseParams<{
6
+ index: number;
7
+ rawDataLength: number;
8
+ }>): number;
5
9
  export declare function computedOffsetXValueWithAutoFillData(params: BaseParams<{
6
10
  rawDataLength: number;
7
11
  value: number;
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-reanimated-carousel",
3
- "version": "2.3.7",
3
+ "version": "2.3.10",
4
4
  "description": "Simple carousel component.fully implemented using Reanimated 2.Infinitely scrolling, very smooth.",
5
5
  "main": "lib/commonjs/index",
6
6
  "types": "lib/typescript/index.d.ts",
@@ -26,8 +26,8 @@
26
26
  "lint": "eslint \"src/**/*.{js,ts,tsx}\"",
27
27
  "dev": "yarn watch 'yarn prepare' ./src",
28
28
  "prepare": "bob build",
29
- "release": "release-it --no-git.requireUpstream",
30
- "preRelease": "release-it --no-git.requireUpstream --preRelease=beta",
29
+ "release": "yarn prepare && release-it --no-git.requireUpstream",
30
+ "preRelease": "yarn prepare && release-it --no-git.requireUpstream --preRelease=beta",
31
31
  "ios": "yarn --cwd example ios",
32
32
  "ios:pretty": "yarn --cwd example ios:pretty",
33
33
  "web": "yarn --cwd example web",
package/src/Carousel.tsx CHANGED
@@ -1,5 +1,9 @@
1
1
  import React from 'react';
2
- import Animated, { runOnJS, useDerivedValue } from 'react-native-reanimated';
2
+ import Animated, {
3
+ runOnJS,
4
+ runOnUI,
5
+ useDerivedValue,
6
+ } from 'react-native-reanimated';
3
7
 
4
8
  import { useCarouselController } from './hooks/useCarouselController';
5
9
  import { useAutoPlay } from './hooks/useAutoPlay';
@@ -22,6 +26,7 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
22
26
  const props = useInitProps(_props);
23
27
 
24
28
  const {
29
+ testID,
25
30
  data,
26
31
  rawData,
27
32
  loop,
@@ -73,28 +78,27 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
73
78
  const carouselController = useCarouselController({
74
79
  loop,
75
80
  size,
81
+ data,
82
+ autoFillData,
76
83
  handlerOffsetX,
77
- length: data.length,
78
- disable: !data.length,
79
84
  withAnimation,
80
- originalLength: data.length,
81
85
  defaultIndex,
82
86
  onScrollEnd: () => runOnJS(_onScrollEnd)(),
83
87
  onScrollBegin: () => !!onScrollBegin && runOnJS(onScrollBegin)(),
84
- onChange: (i) => !!onSnapToItem && runOnJS(onSnapToItem)(i),
85
88
  duration: scrollAnimationDuration,
86
89
  });
87
90
 
88
91
  const {
92
+ sharedIndex,
93
+ sharedPreIndex,
94
+ to,
89
95
  next,
90
96
  prev,
91
- sharedPreIndex,
92
- sharedIndex,
93
- computedIndex,
97
+ scrollTo,
94
98
  getCurrentIndex,
95
99
  } = carouselController;
96
100
 
97
- const { start, pause } = useAutoPlay({
101
+ const { start: startAutoPlay, pause: pauseAutoPlay } = useAutoPlay({
98
102
  autoPlay,
99
103
  autoPlayInterval,
100
104
  autoPlayReverse,
@@ -102,29 +106,44 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
102
106
  });
103
107
 
104
108
  const _onScrollEnd = React.useCallback(() => {
105
- computedIndex();
106
- onScrollEnd?.(sharedPreIndex.current, sharedIndex.current);
107
- }, [sharedPreIndex, sharedIndex, computedIndex, onScrollEnd]);
109
+ 'worklet';
110
+ const _sharedIndex = Math.round(sharedIndex.value);
111
+ const _sharedPreIndex = Math.round(sharedPreIndex.value);
112
+
113
+ if (onSnapToItem) {
114
+ runOnJS(onSnapToItem)(_sharedIndex);
115
+ }
116
+ if (onScrollEnd) {
117
+ runOnJS(onScrollEnd)(_sharedPreIndex, _sharedIndex);
118
+ }
119
+ }, [onSnapToItem, onScrollEnd, sharedIndex, sharedPreIndex]);
108
120
 
109
121
  const scrollViewGestureOnScrollBegin = React.useCallback(() => {
110
- pause();
122
+ pauseAutoPlay();
111
123
  onScrollBegin?.();
112
- }, [onScrollBegin, pause]);
124
+ }, [onScrollBegin, pauseAutoPlay]);
113
125
 
114
126
  const scrollViewGestureOnScrollEnd = React.useCallback(() => {
115
- start();
116
- _onScrollEnd();
117
- }, [_onScrollEnd, start]);
127
+ startAutoPlay();
128
+ /**
129
+ * TODO magic
130
+ */
131
+ runOnUI(_onScrollEnd)();
132
+ }, [_onScrollEnd, startAutoPlay]);
118
133
 
119
- const scrollViewGestureOnTouchBegin = React.useCallback(pause, [pause]);
134
+ const scrollViewGestureOnTouchBegin = React.useCallback(pauseAutoPlay, [
135
+ pauseAutoPlay,
136
+ ]);
120
137
 
121
- const scrollViewGestureOnTouchEnd = React.useCallback(start, [start]);
138
+ const scrollViewGestureOnTouchEnd = React.useCallback(startAutoPlay, [
139
+ startAutoPlay,
140
+ ]);
122
141
 
123
142
  const goToIndex = React.useCallback(
124
143
  (i: number, animated?: boolean) => {
125
- carouselController.to(i, animated);
144
+ to(i, animated);
126
145
  },
127
- [carouselController]
146
+ [to]
128
147
  );
129
148
 
130
149
  React.useImperativeHandle(
@@ -134,15 +153,9 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
134
153
  prev,
135
154
  getCurrentIndex,
136
155
  goToIndex,
137
- scrollTo: carouselController.scrollTo,
156
+ scrollTo,
138
157
  }),
139
- [
140
- getCurrentIndex,
141
- goToIndex,
142
- next,
143
- prev,
144
- carouselController.scrollTo,
145
- ]
158
+ [getCurrentIndex, goToIndex, next, prev, scrollTo]
146
159
  );
147
160
 
148
161
  const visibleRanges = useVisibleRanges({
@@ -201,6 +214,7 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
201
214
  { width: width || '100%', height: height || '100%' },
202
215
  style,
203
216
  ]}
217
+ testID={testID}
204
218
  >
205
219
  <ScrollViewGesture
206
220
  size={size}
@@ -68,24 +68,22 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
68
68
  const _withSpring = React.useCallback(
69
69
  (toValue: number, onFinished?: () => void) => {
70
70
  'worklet';
71
- const callback = (isFinished: boolean) => {
72
- 'worklet';
73
- if (isFinished) {
74
- onFinished && runOnJS(onFinished)();
75
- }
76
- };
77
-
78
71
  const defaultWithAnimation: WithTimingAnimation = {
79
72
  type: 'timing',
80
73
  config: {
81
- duration: scrollAnimationDuration,
74
+ duration: scrollAnimationDuration + 100,
82
75
  easing: Easing.easeOutQuart,
83
76
  },
84
77
  };
85
78
 
86
79
  return dealWithAnimation(withAnimation ?? defaultWithAnimation)(
87
80
  toValue,
88
- callback
81
+ (isFinished: boolean) => {
82
+ 'worklet';
83
+ if (isFinished) {
84
+ onFinished && runOnJS(onFinished)();
85
+ }
86
+ }
89
87
  );
90
88
  },
91
89
  [scrollAnimationDuration, withAnimation]
@@ -273,7 +271,11 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
273
271
 
274
272
  return (
275
273
  <Animated.View
276
- style={[styles.container, directionStyle]}
274
+ style={[
275
+ styles.container,
276
+ directionStyle,
277
+ { width: '100%', height: '100%' },
278
+ ]}
277
279
  onTouchStart={onTouchBegin}
278
280
  onTouchEnd={onTouchEnd}
279
281
  >
@@ -14,6 +14,7 @@ export function useAutoPlay(opts: {
14
14
  carouselController,
15
15
  } = opts;
16
16
 
17
+ const { prev, next } = carouselController;
17
18
  const timer = React.useRef<NodeJS.Timer>();
18
19
  const stopped = React.useRef<boolean>(!autoPlay);
19
20
 
@@ -25,10 +26,10 @@ export function useAutoPlay(opts: {
25
26
  timer.current && clearTimeout(timer.current);
26
27
  timer.current = setTimeout(() => {
27
28
  autoPlayReverse
28
- ? carouselController.prev({ onFinished: play })
29
- : carouselController.next({ onFinished: play });
29
+ ? prev({ onFinished: play })
30
+ : next({ onFinished: play });
30
31
  }, autoPlayInterval);
31
- }, [autoPlayReverse, autoPlayInterval, carouselController]);
32
+ }, [autoPlayReverse, autoPlayInterval, prev, next]);
32
33
 
33
34
  const pause = React.useCallback(() => {
34
35
  if (!autoPlay) {
@@ -1,38 +1,37 @@
1
1
  import React from 'react';
2
2
  import type Animated from 'react-native-reanimated';
3
3
  import { Easing } from '../constants';
4
- import { runOnJS, useSharedValue } from 'react-native-reanimated';
4
+ import {
5
+ runOnJS,
6
+ useAnimatedReaction,
7
+ useSharedValue,
8
+ } from 'react-native-reanimated';
5
9
  import type {
6
10
  TCarouselActionOptions,
7
11
  TCarouselProps,
8
12
  WithTimingAnimation,
9
13
  } from '../types';
10
14
  import { dealWithAnimation } from '@/utils/dealWithAnimation';
15
+ import { convertToSharedIndex } from '@/utils/computedWithAutoFillData';
11
16
 
12
17
  interface IOpts {
13
18
  loop: boolean;
14
19
  size: number;
20
+ data: TCarouselProps['data'];
21
+ autoFillData: TCarouselProps['autoFillData'];
15
22
  handlerOffsetX: Animated.SharedValue<number>;
16
23
  withAnimation?: TCarouselProps['withAnimation'];
17
- disable?: boolean;
18
24
  duration?: number;
19
- originalLength: number;
20
- length: number;
21
25
  defaultIndex?: number;
22
26
  onScrollBegin?: () => void;
23
27
  onScrollEnd?: () => void;
24
- // the length before fill data
25
- onChange: (index: number) => void;
26
28
  }
27
29
 
28
30
  export interface ICarouselController {
29
- length: number;
30
- index: Animated.SharedValue<number>;
31
- sharedIndex: React.MutableRefObject<number>;
32
- sharedPreIndex: React.MutableRefObject<number>;
31
+ sharedIndex: Animated.SharedValue<number>;
32
+ sharedPreIndex: Animated.SharedValue<number>;
33
33
  prev: (opts?: TCarouselActionOptions) => void;
34
34
  next: (opts?: TCarouselActionOptions) => void;
35
- computedIndex: () => void;
36
35
  getCurrentIndex: () => number;
37
36
  to: (index: number, animated?: boolean) => void;
38
37
  scrollTo: (opts?: TCarouselActionOptions) => void;
@@ -41,70 +40,64 @@ export interface ICarouselController {
41
40
  export function useCarouselController(options: IOpts): ICarouselController {
42
41
  const {
43
42
  size,
43
+ data,
44
44
  loop,
45
45
  handlerOffsetX,
46
46
  withAnimation,
47
- disable = false,
48
- originalLength,
49
- length,
50
- onChange,
51
- duration,
52
47
  defaultIndex = 0,
48
+ duration,
49
+ autoFillData,
53
50
  } = options;
54
51
 
52
+ const dataInfo = React.useMemo(
53
+ () => ({
54
+ length: data.length,
55
+ disable: !data.length,
56
+ originalLength: data.length,
57
+ }),
58
+ [data]
59
+ );
60
+
55
61
  const index = useSharedValue<number>(defaultIndex);
56
62
  // The Index displayed to the user
57
- const sharedIndex = React.useRef<number>(defaultIndex);
58
- const sharedPreIndex = React.useRef<number>(defaultIndex);
63
+ const sharedIndex = useSharedValue<number>(defaultIndex);
64
+ const sharedPreIndex = useSharedValue<number>(defaultIndex);
59
65
 
60
66
  const currentFixedPage = React.useCallback(() => {
61
67
  if (loop) {
62
68
  return -Math.round(handlerOffsetX.value / size);
63
69
  }
64
70
 
65
- const fixed = (handlerOffsetX.value / size) % length;
71
+ const fixed = (handlerOffsetX.value / size) % dataInfo.length;
66
72
  return Math.round(
67
73
  handlerOffsetX.value <= 0
68
74
  ? Math.abs(fixed)
69
- : Math.abs(fixed > 0 ? length - fixed : 0)
75
+ : Math.abs(fixed > 0 ? dataInfo.length - fixed : 0)
70
76
  );
71
- }, [handlerOffsetX, length, size, loop]);
77
+ }, [handlerOffsetX, dataInfo, size, loop]);
72
78
 
73
- const convertToSharedIndex = React.useCallback(
74
- (i: number) => {
75
- if (loop) {
76
- switch (originalLength) {
77
- case 1:
78
- return 0;
79
- case 2:
80
- return i % 2;
81
- }
82
- }
83
- return i;
79
+ const computedIndex = React.useCallback(
80
+ (handlerOffsetXValue: number) => {
81
+ 'worklet';
82
+ sharedPreIndex.value = sharedIndex.value;
83
+ const toInt = (handlerOffsetXValue / size) % dataInfo.length;
84
+ const isPositive = handlerOffsetXValue <= 0;
85
+ const i = isPositive
86
+ ? Math.abs(toInt)
87
+ : Math.abs(toInt > 0 ? dataInfo.length - toInt : 0);
88
+ index.value = i;
89
+ sharedIndex.value = convertToSharedIndex({
90
+ loop,
91
+ rawDataLength: dataInfo.originalLength,
92
+ autoFillData: autoFillData!,
93
+ index: i,
94
+ });
84
95
  },
85
- [originalLength, loop]
96
+ [sharedPreIndex, sharedIndex, size, dataInfo, index, loop, autoFillData]
86
97
  );
87
98
 
88
- const computedIndex = React.useCallback(() => {
89
- sharedPreIndex.current = sharedIndex.current;
90
- const toInt = (handlerOffsetX.value / size) % length;
91
- const i =
92
- handlerOffsetX.value <= 0
93
- ? Math.abs(toInt)
94
- : Math.abs(toInt > 0 ? length - toInt : 0);
95
- index.value = i;
96
- const _sharedIndex = convertToSharedIndex(i);
97
- sharedIndex.current = _sharedIndex;
98
- onChange(_sharedIndex);
99
- }, [
100
- length,
99
+ useAnimatedReaction(() => handlerOffsetX.value, computedIndex, [
101
100
  handlerOffsetX,
102
- sharedPreIndex,
103
- index,
104
- size,
105
- sharedIndex,
106
- convertToSharedIndex,
107
- onChange,
108
101
  ]);
109
102
 
110
103
  const getCurrentIndex = React.useCallback(() => {
@@ -112,8 +105,8 @@ export function useCarouselController(options: IOpts): ICarouselController {
112
105
  }, [index]);
113
106
 
114
107
  const canSliding = React.useCallback(() => {
115
- return !disable;
116
- }, [disable]);
108
+ return !dataInfo.disable;
109
+ }, [dataInfo]);
117
110
 
118
111
  const onScrollEnd = React.useCallback(() => {
119
112
  options.onScrollEnd?.();
@@ -151,7 +144,8 @@ export function useCarouselController(options: IOpts): ICarouselController {
151
144
  (opts: TCarouselActionOptions = {}) => {
152
145
  'worklet';
153
146
  const { count = 1, animated = true, onFinished } = opts;
154
- if (!canSliding() || (!loop && index.value >= length - 1)) return;
147
+ if (!canSliding() || (!loop && index.value >= dataInfo.length - 1))
148
+ return;
155
149
 
156
150
  onScrollBegin?.();
157
151
 
@@ -172,7 +166,7 @@ export function useCarouselController(options: IOpts): ICarouselController {
172
166
  canSliding,
173
167
  loop,
174
168
  index,
175
- length,
169
+ dataInfo,
176
170
  onScrollBegin,
177
171
  handlerOffsetX,
178
172
  size,
@@ -259,15 +253,12 @@ export function useCarouselController(options: IOpts): ICarouselController {
259
253
  );
260
254
 
261
255
  return {
256
+ sharedIndex,
257
+ sharedPreIndex,
258
+ to,
262
259
  next,
263
260
  prev,
264
- to,
265
261
  scrollTo,
266
- index,
267
- length,
268
- sharedIndex,
269
- sharedPreIndex,
270
- computedIndex,
271
262
  getCurrentIndex,
272
263
  };
273
264
  }
package/src/types.ts CHANGED
@@ -144,6 +144,10 @@ export type TCarouselProps<T = any> = {
144
144
  * Specifies the scrolling animation effect.
145
145
  */
146
146
  withAnimation?: WithAnimation;
147
+ /**
148
+ * Used to locate this view in end-to-end tests.
149
+ */
150
+ testID?: string;
147
151
  /**
148
152
  * Custom carousel config.
149
153
  */
@@ -12,6 +12,24 @@ type BaseParams<T extends object = {}> = {
12
12
  loop: boolean;
13
13
  } & T;
14
14
 
15
+ export function convertToSharedIndex(
16
+ params: BaseParams<{ index: number; rawDataLength: number }>
17
+ ) {
18
+ 'worklet';
19
+ const { loop, rawDataLength, index, autoFillData } = params;
20
+
21
+ if (isAutoFillData({ loop, autoFillData })) {
22
+ switch (rawDataLength) {
23
+ case SINGLE_ITEM:
24
+ return 0;
25
+ case DOUBLE_ITEM:
26
+ return index % 2;
27
+ }
28
+ }
29
+
30
+ return index;
31
+ }
32
+
15
33
  export function computedOffsetXValueWithAutoFillData(
16
34
  params: BaseParams<{
17
35
  rawDataLength: number;
@@ -1,2 +0,0 @@
1
- declare const App: () => JSX.Element;
2
- export default App;