react-native-reanimated-carousel 4.0.0-alpha.5 → 4.0.0-alpha.6

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 (70) hide show
  1. package/lib/commonjs/{layouts → components}/BaseLayout.js +4 -2
  2. package/lib/commonjs/components/BaseLayout.js.map +1 -0
  3. package/lib/commonjs/components/Carousel.js +4 -3
  4. package/lib/commonjs/components/Carousel.js.map +1 -1
  5. package/lib/commonjs/components/ScrollViewGesture.js +34 -30
  6. package/lib/commonjs/components/ScrollViewGesture.js.map +1 -1
  7. package/lib/commonjs/hooks/useLayoutConfig.js.map +1 -1
  8. package/lib/commonjs/hooks/useOffsetX.js +9 -6
  9. package/lib/commonjs/hooks/useOffsetX.js.map +1 -1
  10. package/lib/commonjs/hooks/useOffsetX.test.js +53 -0
  11. package/lib/commonjs/hooks/useOffsetX.test.js.map +1 -0
  12. package/lib/commonjs/hooks/usePanGestureProxy.js +84 -0
  13. package/lib/commonjs/hooks/usePanGestureProxy.js.map +1 -0
  14. package/lib/commonjs/hooks/usePanGestureProxy.test.js +397 -0
  15. package/lib/commonjs/hooks/usePanGestureProxy.test.js.map +1 -0
  16. package/lib/commonjs/hooks/useUpdateGestureConfig.js.map +1 -1
  17. package/lib/commonjs/hooks/useVisibleRanges.js +17 -6
  18. package/lib/commonjs/hooks/useVisibleRanges.js.map +1 -1
  19. package/lib/commonjs/hooks/useVisibleRanges.test.js +162 -0
  20. package/lib/commonjs/hooks/useVisibleRanges.test.js.map +1 -0
  21. package/lib/module/{layouts → components}/BaseLayout.js +4 -2
  22. package/lib/module/components/BaseLayout.js.map +1 -0
  23. package/lib/module/components/Carousel.js +3 -2
  24. package/lib/module/components/Carousel.js.map +1 -1
  25. package/lib/module/components/ScrollViewGesture.js +36 -31
  26. package/lib/module/components/ScrollViewGesture.js.map +1 -1
  27. package/lib/module/hooks/useLayoutConfig.js.map +1 -1
  28. package/lib/module/hooks/useOffsetX.js +9 -6
  29. package/lib/module/hooks/useOffsetX.js.map +1 -1
  30. package/lib/module/hooks/useOffsetX.test.js +48 -0
  31. package/lib/module/hooks/useOffsetX.test.js.map +1 -0
  32. package/lib/module/hooks/usePanGestureProxy.js +71 -0
  33. package/lib/module/hooks/usePanGestureProxy.js.map +1 -0
  34. package/lib/module/hooks/usePanGestureProxy.test.js +383 -0
  35. package/lib/module/hooks/usePanGestureProxy.test.js.map +1 -0
  36. package/lib/module/hooks/useUpdateGestureConfig.js.map +1 -1
  37. package/lib/module/hooks/useVisibleRanges.js +17 -6
  38. package/lib/module/hooks/useVisibleRanges.js.map +1 -1
  39. package/lib/module/hooks/useVisibleRanges.test.js +157 -0
  40. package/lib/module/hooks/useVisibleRanges.test.js.map +1 -0
  41. package/lib/typescript/hooks/useLayoutConfig.d.ts +1 -1
  42. package/lib/typescript/hooks/useOffsetX.test.d.ts +1 -0
  43. package/lib/typescript/hooks/usePanGestureProxy.d.ts +9 -0
  44. package/lib/typescript/hooks/usePanGestureProxy.test.d.ts +1 -0
  45. package/lib/typescript/hooks/useUpdateGestureConfig.d.ts +3 -2
  46. package/lib/typescript/hooks/useVisibleRanges.d.ts +1 -0
  47. package/lib/typescript/hooks/useVisibleRanges.test.d.ts +1 -0
  48. package/lib/typescript/types.d.ts +5 -0
  49. package/package.json +2 -1
  50. package/src/{layouts → components}/BaseLayout.tsx +10 -8
  51. package/src/components/Carousel.tsx +2 -1
  52. package/src/components/ScrollViewGesture.tsx +48 -43
  53. package/src/hooks/useLayoutConfig.ts +1 -1
  54. package/src/hooks/useOffsetX.test.ts +54 -0
  55. package/src/hooks/useOffsetX.ts +33 -31
  56. package/src/hooks/usePanGestureProxy.test.tsx +377 -0
  57. package/src/hooks/usePanGestureProxy.ts +110 -0
  58. package/src/hooks/useUpdateGestureConfig.ts +4 -2
  59. package/src/hooks/useVisibleRanges.test.tsx +179 -0
  60. package/src/hooks/useVisibleRanges.tsx +23 -7
  61. package/src/types.ts +5 -0
  62. package/lib/commonjs/layouts/BaseLayout.js.map +0 -1
  63. package/lib/commonjs/layouts/ParallaxLayout.js +0 -84
  64. package/lib/commonjs/layouts/ParallaxLayout.js.map +0 -1
  65. package/lib/module/layouts/BaseLayout.js.map +0 -1
  66. package/lib/module/layouts/ParallaxLayout.js +0 -61
  67. package/lib/module/layouts/ParallaxLayout.js.map +0 -1
  68. package/lib/typescript/layouts/ParallaxLayout.d.ts +0 -13
  69. package/src/layouts/ParallaxLayout.tsx +0 -141
  70. /package/lib/typescript/{layouts → components}/BaseLayout.d.ts +0 -0
@@ -4,16 +4,27 @@ export function useVisibleRanges(options) {
4
4
  total = 0,
5
5
  viewSize,
6
6
  translation,
7
- windowSize: _windowSize = 0
7
+ windowSize: _windowSize = 0,
8
+ loop
8
9
  } = options;
9
10
  const windowSize = total <= _windowSize ? total : _windowSize;
10
11
  const ranges = useDerivedValue(() => {
11
12
  const positiveCount = Math.round(windowSize / 2);
12
13
  const negativeCount = windowSize - positiveCount;
13
- let curIndex = Math.round(-translation.value / viewSize);
14
- curIndex = curIndex < 0 ? curIndex % total + total : curIndex;
15
- const negativeRange = [(curIndex - negativeCount + total) % total, (curIndex - 1 + total) % total];
16
- const positiveRange = [(curIndex + total) % total, (curIndex + positiveCount + total) % total];
14
+ let currentIndex = Math.round(-translation.value / viewSize);
15
+ currentIndex = currentIndex < 0 ? currentIndex % total + total : currentIndex;
16
+
17
+ if (!loop) {
18
+ // Adjusting negative range if the carousel is not loopable.
19
+ // So, It will be only displayed the positive items.
20
+ return {
21
+ negativeRange: [0 + currentIndex - (windowSize - 1), 0 + currentIndex],
22
+ positiveRange: [0 + currentIndex, windowSize - 1 + currentIndex]
23
+ };
24
+ }
25
+
26
+ const negativeRange = [(currentIndex - negativeCount + total) % total, (currentIndex - 1 + total) % total];
27
+ const positiveRange = [(currentIndex + total) % total, (currentIndex + positiveCount + total) % total];
17
28
 
18
29
  if (negativeRange[0] < total && negativeRange[0] > negativeRange[1]) {
19
30
  negativeRange[1] = total - 1;
@@ -29,7 +40,7 @@ export function useVisibleRanges(options) {
29
40
  negativeRange,
30
41
  positiveRange
31
42
  };
32
- }, [total, windowSize, translation]);
43
+ }, [loop, total, windowSize, translation]);
33
44
  return ranges;
34
45
  }
35
46
  //# sourceMappingURL=useVisibleRanges.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["useVisibleRanges.tsx"],"names":["useDerivedValue","useVisibleRanges","options","total","viewSize","translation","windowSize","_windowSize","ranges","positiveCount","Math","round","negativeCount","curIndex","value","negativeRange","positiveRange"],"mappings":"AACA,SAASA,eAAT,QAAgC,yBAAhC;AAOA,OAAO,SAASC,gBAAT,CAA0BC,OAA1B,EAKY;AACjB,QAAM;AACJC,IAAAA,KAAK,GAAG,CADJ;AAEJC,IAAAA,QAFI;AAGJC,IAAAA,WAHI;AAIJC,IAAAA,UAAU,EAAEC,WAAW,GAAG;AAJtB,MAKFL,OALJ;AAOA,QAAMI,UAAU,GAAGH,KAAK,IAAII,WAAT,GAAuBJ,KAAvB,GAA+BI,WAAlD;AAEA,QAAMC,MAAM,GAAGR,eAAe,CAAC,MAAM;AACnC,UAAMS,aAAa,GAAGC,IAAI,CAACC,KAAL,CAAWL,UAAU,GAAG,CAAxB,CAAtB;AACA,UAAMM,aAAa,GAAGN,UAAU,GAAGG,aAAnC;AACA,QAAII,QAAQ,GAAGH,IAAI,CAACC,KAAL,CAAW,CAACN,WAAW,CAACS,KAAb,GAAqBV,QAAhC,CAAf;AACAS,IAAAA,QAAQ,GAAGA,QAAQ,GAAG,CAAX,GAAgBA,QAAQ,GAAGV,KAAZ,GAAqBA,KAApC,GAA4CU,QAAvD;AACA,UAAME,aAAa,GAAG,CACpB,CAACF,QAAQ,GAAGD,aAAX,GAA2BT,KAA5B,IAAqCA,KADjB,EAEpB,CAACU,QAAQ,GAAG,CAAX,GAAeV,KAAhB,IAAyBA,KAFL,CAAtB;AAIA,UAAMa,aAAa,GAAG,CACpB,CAACH,QAAQ,GAAGV,KAAZ,IAAqBA,KADD,EAEpB,CAACU,QAAQ,GAAGJ,aAAX,GAA2BN,KAA5B,IAAqCA,KAFjB,CAAtB;;AAIA,QAAIY,aAAa,CAAC,CAAD,CAAb,GAAmBZ,KAAnB,IAA4BY,aAAa,CAAC,CAAD,CAAb,GAAmBA,aAAa,CAAC,CAAD,CAAhE,EAAqE;AACnEA,MAAAA,aAAa,CAAC,CAAD,CAAb,GAAmBZ,KAAK,GAAG,CAA3B;AACAa,MAAAA,aAAa,CAAC,CAAD,CAAb,GAAmB,CAAnB;AACD;;AACD,QAAIA,aAAa,CAAC,CAAD,CAAb,GAAmBA,aAAa,CAAC,CAAD,CAApC,EAAyC;AACvCD,MAAAA,aAAa,CAAC,CAAD,CAAb,GAAmBZ,KAAK,GAAG,CAA3B;AACAa,MAAAA,aAAa,CAAC,CAAD,CAAb,GAAmB,CAAnB;AACD;;AACD,WAAO;AAAED,MAAAA,aAAF;AAAiBC,MAAAA;AAAjB,KAAP;AACD,GAtB6B,EAsB3B,CAACb,KAAD,EAAQG,UAAR,EAAoBD,WAApB,CAtB2B,CAA9B;AAwBA,SAAOG,MAAP;AACD","sourcesContent":["import type Animated from \"react-native-reanimated\";\nimport { useDerivedValue } from \"react-native-reanimated\";\n\nexport type IVisibleRanges = Animated.SharedValue<{\n negativeRange: number[]\n positiveRange: number[]\n}>;\n\nexport function useVisibleRanges(options: {\n total: number\n viewSize: number\n windowSize?: number\n translation: Animated.SharedValue<number>\n}): IVisibleRanges {\n const {\n total = 0,\n viewSize,\n translation,\n windowSize: _windowSize = 0,\n } = options;\n\n const windowSize = total <= _windowSize ? total : _windowSize;\n\n const ranges = useDerivedValue(() => {\n const positiveCount = Math.round(windowSize / 2);\n const negativeCount = windowSize - positiveCount;\n let curIndex = Math.round(-translation.value / viewSize);\n curIndex = curIndex < 0 ? (curIndex % total) + total : curIndex;\n const negativeRange = [\n (curIndex - negativeCount + total) % total,\n (curIndex - 1 + total) % total,\n ];\n const positiveRange = [\n (curIndex + total) % total,\n (curIndex + positiveCount + total) % total,\n ];\n if (negativeRange[0] < total && negativeRange[0] > negativeRange[1]) {\n negativeRange[1] = total - 1;\n positiveRange[0] = 0;\n }\n if (positiveRange[0] > positiveRange[1]) {\n negativeRange[1] = total - 1;\n positiveRange[0] = 0;\n }\n return { negativeRange, positiveRange };\n }, [total, windowSize, translation]);\n\n return ranges;\n}\n"]}
1
+ {"version":3,"sources":["useVisibleRanges.tsx"],"names":["useDerivedValue","useVisibleRanges","options","total","viewSize","translation","windowSize","_windowSize","loop","ranges","positiveCount","Math","round","negativeCount","currentIndex","value","negativeRange","positiveRange"],"mappings":"AACA,SAASA,eAAT,QAAgC,yBAAhC;AAOA,OAAO,SAASC,gBAAT,CAA0BC,OAA1B,EAMY;AACjB,QAAM;AACJC,IAAAA,KAAK,GAAG,CADJ;AAEJC,IAAAA,QAFI;AAGJC,IAAAA,WAHI;AAIJC,IAAAA,UAAU,EAAEC,WAAW,GAAG,CAJtB;AAKJC,IAAAA;AALI,MAMFN,OANJ;AAQA,QAAMI,UAAU,GAAGH,KAAK,IAAII,WAAT,GAAuBJ,KAAvB,GAA+BI,WAAlD;AAEA,QAAME,MAAM,GAAGT,eAAe,CAAC,MAAM;AACnC,UAAMU,aAAa,GAAGC,IAAI,CAACC,KAAL,CAAWN,UAAU,GAAG,CAAxB,CAAtB;AACA,UAAMO,aAAa,GAAGP,UAAU,GAAGI,aAAnC;AAEA,QAAII,YAAY,GAAGH,IAAI,CAACC,KAAL,CAAW,CAACP,WAAW,CAACU,KAAb,GAAqBX,QAAhC,CAAnB;AACAU,IAAAA,YAAY,GAAGA,YAAY,GAAG,CAAf,GAAoBA,YAAY,GAAGX,KAAhB,GAAyBA,KAA5C,GAAoDW,YAAnE;;AAEA,QAAI,CAACN,IAAL,EAAW;AACT;AACA;AACA,aAAO;AACLQ,QAAAA,aAAa,EAAE,CAAC,IAAIF,YAAJ,IAAoBR,UAAU,GAAG,CAAjC,CAAD,EAAsC,IAAIQ,YAA1C,CADV;AAELG,QAAAA,aAAa,EAAE,CAAC,IAAIH,YAAL,EAAmBR,UAAU,GAAG,CAAb,GAAiBQ,YAApC;AAFV,OAAP;AAID;;AAED,UAAME,aAAa,GAAG,CACpB,CAACF,YAAY,GAAGD,aAAf,GAA+BV,KAAhC,IAAyCA,KADrB,EAEpB,CAACW,YAAY,GAAG,CAAf,GAAmBX,KAApB,IAA6BA,KAFT,CAAtB;AAKA,UAAMc,aAAa,GAAG,CACpB,CAACH,YAAY,GAAGX,KAAhB,IAAyBA,KADL,EAEpB,CAACW,YAAY,GAAGJ,aAAf,GAA+BP,KAAhC,IAAyCA,KAFrB,CAAtB;;AAKA,QAAIa,aAAa,CAAC,CAAD,CAAb,GAAmBb,KAAnB,IAA4Ba,aAAa,CAAC,CAAD,CAAb,GAAmBA,aAAa,CAAC,CAAD,CAAhE,EAAqE;AACnEA,MAAAA,aAAa,CAAC,CAAD,CAAb,GAAmBb,KAAK,GAAG,CAA3B;AACAc,MAAAA,aAAa,CAAC,CAAD,CAAb,GAAmB,CAAnB;AACD;;AACD,QAAIA,aAAa,CAAC,CAAD,CAAb,GAAmBA,aAAa,CAAC,CAAD,CAApC,EAAyC;AACvCD,MAAAA,aAAa,CAAC,CAAD,CAAb,GAAmBb,KAAK,GAAG,CAA3B;AACAc,MAAAA,aAAa,CAAC,CAAD,CAAb,GAAmB,CAAnB;AACD;;AAED,WAAO;AAAED,MAAAA,aAAF;AAAiBC,MAAAA;AAAjB,KAAP;AACD,GApC6B,EAoC3B,CAACT,IAAD,EAAOL,KAAP,EAAcG,UAAd,EAA0BD,WAA1B,CApC2B,CAA9B;AAsCA,SAAOI,MAAP;AACD","sourcesContent":["import type Animated from \"react-native-reanimated\";\nimport { useDerivedValue } from \"react-native-reanimated\";\n\nexport type IVisibleRanges = Animated.SharedValue<{\n negativeRange: number[]\n positiveRange: number[]\n}>;\n\nexport function useVisibleRanges(options: {\n total: number\n viewSize: number\n windowSize?: number\n translation: Animated.SharedValue<number>\n loop?: boolean\n}): IVisibleRanges {\n const {\n total = 0,\n viewSize,\n translation,\n windowSize: _windowSize = 0,\n loop,\n } = options;\n\n const windowSize = total <= _windowSize ? total : _windowSize;\n\n const ranges = useDerivedValue(() => {\n const positiveCount = Math.round(windowSize / 2);\n const negativeCount = windowSize - positiveCount;\n\n let currentIndex = Math.round(-translation.value / viewSize);\n currentIndex = currentIndex < 0 ? (currentIndex % total) + total : currentIndex;\n\n if (!loop) {\n // Adjusting negative range if the carousel is not loopable.\n // So, It will be only displayed the positive items.\n return {\n negativeRange: [0 + currentIndex - (windowSize - 1), 0 + currentIndex],\n positiveRange: [0 + currentIndex, windowSize - 1 + currentIndex],\n };\n }\n\n const negativeRange = [\n (currentIndex - negativeCount + total) % total,\n (currentIndex - 1 + total) % total,\n ];\n\n const positiveRange = [\n (currentIndex + total) % total,\n (currentIndex + positiveCount + total) % total,\n ];\n\n if (negativeRange[0] < total && negativeRange[0] > negativeRange[1]) {\n negativeRange[1] = total - 1;\n positiveRange[0] = 0;\n }\n if (positiveRange[0] > positiveRange[1]) {\n negativeRange[1] = total - 1;\n positiveRange[0] = 0;\n }\n\n return { negativeRange, positiveRange };\n }, [loop, total, windowSize, translation]);\n\n return ranges;\n}\n"]}
@@ -0,0 +1,157 @@
1
+ import { useSharedValue } from "react-native-reanimated";
2
+ import { renderHook } from "@testing-library/react-hooks";
3
+ import { useVisibleRanges } from "./useVisibleRanges";
4
+ const viewSize = 393;
5
+ describe("useVisibleRanges", () => {
6
+ it("should only display the front of the list when loop is false", async () => {
7
+ const hook = renderHook(() => {
8
+ const translation = useSharedValue(-0);
9
+ const range = useVisibleRanges({
10
+ total: 10,
11
+ translation,
12
+ viewSize,
13
+ windowSize: 4,
14
+ loop: false
15
+ });
16
+ return range;
17
+ });
18
+ const expected = hook.result.current.value;
19
+ expect(expected).toMatchInlineSnapshot(`
20
+ {
21
+ "negativeRange": [
22
+ -3,
23
+ 0,
24
+ ],
25
+ "positiveRange": [
26
+ 0,
27
+ 3,
28
+ ],
29
+ }
30
+ `);
31
+ });
32
+ it("should display the rear of the list and the front of the list when loop is true", async () => {
33
+ const hook = renderHook(() => {
34
+ const translation = useSharedValue(-0);
35
+ const range = useVisibleRanges({
36
+ total: 10,
37
+ translation,
38
+ viewSize,
39
+ windowSize: 4,
40
+ loop: true
41
+ });
42
+ return range;
43
+ });
44
+ const expected = hook.result.current.value;
45
+ expect(expected).toMatchInlineSnapshot(`
46
+ {
47
+ "negativeRange": [
48
+ 8,
49
+ 9,
50
+ ],
51
+ "positiveRange": [
52
+ 0,
53
+ 2,
54
+ ],
55
+ }
56
+ `);
57
+ });
58
+ it("should shows the increased range of the list when the loop is false and swiped the carousel.", async () => {
59
+ const slide0hook = renderHook(() => {
60
+ const translation = useSharedValue(-0 * viewSize);
61
+ const range = useVisibleRanges({
62
+ total: 10,
63
+ translation,
64
+ viewSize,
65
+ windowSize: 4,
66
+ loop: false
67
+ });
68
+ return range;
69
+ }).result.current.value;
70
+ const slide1hook = renderHook(() => {
71
+ const translation = useSharedValue(-1 * viewSize);
72
+ const range = useVisibleRanges({
73
+ total: 10,
74
+ translation,
75
+ viewSize,
76
+ windowSize: 4,
77
+ loop: false
78
+ });
79
+ return range;
80
+ }).result.current.value;
81
+ const slide2hook = renderHook(() => {
82
+ const translation = useSharedValue(-2 * viewSize);
83
+ const range = useVisibleRanges({
84
+ total: 10,
85
+ translation,
86
+ viewSize,
87
+ windowSize: 4,
88
+ loop: false
89
+ });
90
+ return range;
91
+ }).result.current.value;
92
+ const slide3hook = renderHook(() => {
93
+ const translation = useSharedValue(-3 * viewSize);
94
+ const range = useVisibleRanges({
95
+ total: 10,
96
+ translation,
97
+ viewSize,
98
+ windowSize: 4,
99
+ loop: false
100
+ });
101
+ return range;
102
+ }).result.current.value; // [0,3] Display the 0,1,2,3 items.
103
+
104
+ expect(slide0hook).toMatchInlineSnapshot(`
105
+ {
106
+ "negativeRange": [
107
+ -3,
108
+ 0,
109
+ ],
110
+ "positiveRange": [
111
+ 0,
112
+ 3,
113
+ ],
114
+ }
115
+ `); // [1,4] Display the 1,2,3,4 items.
116
+
117
+ expect(slide1hook).toMatchInlineSnapshot(`
118
+ {
119
+ "negativeRange": [
120
+ -2,
121
+ 1,
122
+ ],
123
+ "positiveRange": [
124
+ 1,
125
+ 4,
126
+ ],
127
+ }
128
+ `); // [2,5] Display the 2,3,4,5 items.
129
+
130
+ expect(slide2hook).toMatchInlineSnapshot(`
131
+ {
132
+ "negativeRange": [
133
+ -1,
134
+ 2,
135
+ ],
136
+ "positiveRange": [
137
+ 2,
138
+ 5,
139
+ ],
140
+ }
141
+ `); // [3.6] Display the 3,4,5,6 items.
142
+
143
+ expect(slide3hook).toMatchInlineSnapshot(`
144
+ {
145
+ "negativeRange": [
146
+ 0,
147
+ 3,
148
+ ],
149
+ "positiveRange": [
150
+ 3,
151
+ 6,
152
+ ],
153
+ }
154
+ `);
155
+ });
156
+ });
157
+ //# sourceMappingURL=useVisibleRanges.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["useVisibleRanges.test.tsx"],"names":["useSharedValue","renderHook","useVisibleRanges","viewSize","describe","it","hook","translation","range","total","windowSize","loop","expected","result","current","value","expect","toMatchInlineSnapshot","slide0hook","slide1hook","slide2hook","slide3hook"],"mappings":"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","sourcesContent":["import { useSharedValue } from \"react-native-reanimated\";\n\nimport { renderHook } from \"@testing-library/react-hooks\";\n\nimport { useVisibleRanges } from \"./useVisibleRanges\";\n\nconst viewSize = 393;\n\ndescribe(\"useVisibleRanges\", () => {\n it(\"should only display the front of the list when loop is false\", async () => {\n const hook = renderHook(() => {\n const translation = useSharedValue(-0);\n const range = useVisibleRanges({\n total: 10,\n translation,\n viewSize,\n windowSize: 4,\n loop: false,\n });\n\n return range;\n });\n\n const expected = hook.result.current.value;\n\n expect(expected).toMatchInlineSnapshot(`\n {\n \"negativeRange\": [\n -3,\n 0,\n ],\n \"positiveRange\": [\n 0,\n 3,\n ],\n }\n `);\n });\n\n it(\"should display the rear of the list and the front of the list when loop is true\", async () => {\n const hook = renderHook(() => {\n const translation = useSharedValue(-0);\n const range = useVisibleRanges({\n total: 10,\n translation,\n viewSize,\n windowSize: 4,\n loop: true,\n });\n\n return range;\n });\n\n const expected = hook.result.current.value;\n\n expect(expected).toMatchInlineSnapshot(`\n {\n \"negativeRange\": [\n 8,\n 9,\n ],\n \"positiveRange\": [\n 0,\n 2,\n ],\n }\n `);\n });\n\n it(\"should shows the increased range of the list when the loop is false and swiped the carousel.\", async () => {\n const slide0hook = renderHook(() => {\n const translation = useSharedValue(-0 * viewSize);\n const range = useVisibleRanges({\n total: 10,\n translation,\n viewSize,\n windowSize: 4,\n loop: false,\n });\n\n return range;\n }).result.current.value;\n\n const slide1hook = renderHook(() => {\n const translation = useSharedValue(-1 * viewSize);\n const range = useVisibleRanges({\n total: 10,\n translation,\n viewSize,\n windowSize: 4,\n loop: false,\n });\n\n return range;\n }).result.current.value;\n\n const slide2hook = renderHook(() => {\n const translation = useSharedValue(-2 * viewSize);\n const range = useVisibleRanges({\n total: 10,\n translation,\n viewSize,\n windowSize: 4,\n loop: false,\n });\n\n return range;\n }).result.current.value;\n\n const slide3hook = renderHook(() => {\n const translation = useSharedValue(-3 * viewSize);\n const range = useVisibleRanges({\n total: 10,\n translation,\n viewSize,\n windowSize: 4,\n loop: false,\n });\n\n return range;\n }).result.current.value;\n\n // [0,3] Display the 0,1,2,3 items.\n expect(slide0hook).toMatchInlineSnapshot(`\n {\n \"negativeRange\": [\n -3,\n 0,\n ],\n \"positiveRange\": [\n 0,\n 3,\n ],\n }\n `);\n\n // [1,4] Display the 1,2,3,4 items.\n expect(slide1hook).toMatchInlineSnapshot(`\n {\n \"negativeRange\": [\n -2,\n 1,\n ],\n \"positiveRange\": [\n 1,\n 4,\n ],\n }\n `);\n\n // [2,5] Display the 2,3,4,5 items.\n expect(slide2hook).toMatchInlineSnapshot(`\n {\n \"negativeRange\": [\n -1,\n 2,\n ],\n \"positiveRange\": [\n 2,\n 5,\n ],\n }\n `);\n\n // [3.6] Display the 3,4,5,6 items.\n expect(slide3hook).toMatchInlineSnapshot(`\n {\n \"negativeRange\": [\n 0,\n 3,\n ],\n \"positiveRange\": [\n 3,\n 6,\n ],\n }\n `);\n });\n});\n"]}
@@ -1,5 +1,5 @@
1
1
  import type { TInitializeCarouselProps } from "./useInitProps";
2
- import type { TAnimationStyle } from "../layouts/BaseLayout";
2
+ import type { TAnimationStyle } from "../components/BaseLayout";
3
3
  declare type TLayoutConfigOpts<T> = TInitializeCarouselProps<T> & {
4
4
  size: number;
5
5
  };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { GestureStateChangeEvent, GestureUpdateEvent, PanGesture, PanGestureHandlerEventPayload } from "react-native-gesture-handler";
2
+ import type { GestureConfig } from "./useUpdateGestureConfig";
3
+ export declare const usePanGestureProxy: (customization: {
4
+ onConfigurePanGesture?: ((gesture: PanGesture) => void) | undefined;
5
+ onGestureBegin: (event: GestureStateChangeEvent<PanGestureHandlerEventPayload>) => void;
6
+ onGestureUpdate: (event: GestureUpdateEvent<PanGestureHandlerEventPayload>) => void;
7
+ onGestureEnd: (event: GestureStateChangeEvent<PanGestureHandlerEventPayload>, success: boolean) => void;
8
+ options?: GestureConfig | undefined;
9
+ }) => import("react-native-gesture-handler/lib/typescript/handlers/gestures/panGesture").PanGesture;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,5 @@
1
1
  import type { PanGesture } from "react-native-gesture-handler";
2
- export declare const useUpdateGestureConfig: (gesture: PanGesture, config: {
2
+ export interface GestureConfig {
3
3
  enabled?: boolean;
4
- }) => void;
4
+ }
5
+ export declare const useUpdateGestureConfig: (gesture: PanGesture, config: GestureConfig) => void;
@@ -8,4 +8,5 @@ export declare function useVisibleRanges(options: {
8
8
  viewSize: number;
9
9
  windowSize?: number;
10
10
  translation: Animated.SharedValue<number>;
11
+ loop?: boolean;
11
12
  }): IVisibleRanges;
@@ -0,0 +1 @@
1
+ export {};
@@ -141,6 +141,11 @@ export declare type TCarouselProps<T = any> = {
141
141
  * props.vertical = false => maxScrollDistancePerSwipeX
142
142
  * */
143
143
  maxScrollDistancePerSwipe?: number;
144
+ /**
145
+ * @experimental This API will be changed in the future.
146
+ * If positive, the carousel will scroll to the positive direction and vice versa.
147
+ * */
148
+ fixedDirection?: "positive" | "negative";
144
149
  /**
145
150
  * Custom carousel config.
146
151
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-reanimated-carousel",
3
- "version": "4.0.0-alpha.5",
3
+ "version": "4.0.0-alpha.6",
4
4
  "description": "Simple carousel component.fully implemented using Reanimated 2.Infinitely scrolling, very smooth.",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -63,6 +63,7 @@
63
63
  "del-cli": "^5.0.0",
64
64
  "eslint": "^8.26.0",
65
65
  "eslint-config-prettier": "^7.0.0",
66
+ "eslint-plugin-jest": "^27.6.0",
66
67
  "eslint-plugin-prettier": "^3.1.3",
67
68
  "gifify": "^2.4.3",
68
69
  "husky": "^4.2.5",
@@ -8,13 +8,13 @@ import Animated, {
8
8
  useDerivedValue,
9
9
  } from "react-native-reanimated";
10
10
 
11
- import type { ILayoutConfig } from "./stack";
11
+ import { LazyView } from "./LazyView";
12
12
 
13
- import { LazyView } from "../components/LazyView";
14
13
  import { useCheckMounted } from "../hooks/useCheckMounted";
15
14
  import type { IOpts } from "../hooks/useOffsetX";
16
15
  import { useOffsetX } from "../hooks/useOffsetX";
17
16
  import type { IVisibleRanges } from "../hooks/useVisibleRanges";
17
+ import type { ILayoutConfig } from "../layouts/stack";
18
18
  import { CTX } from "../store";
19
19
 
20
20
  export type TAnimationStyle = (value: number) => AnimatedStyleProp<ViewStyle>;
@@ -30,7 +30,7 @@ export const BaseLayout: React.FC<{
30
30
  }> = (props) => {
31
31
  const mounted = useCheckMounted();
32
32
  const { handlerOffset, index, children, visibleRanges, animationStyle }
33
- = props;
33
+ = props;
34
34
 
35
35
  const context = React.useContext(CTX);
36
36
  const {
@@ -73,17 +73,19 @@ export const BaseLayout: React.FC<{
73
73
  const x = useOffsetX(offsetXConfig, visibleRanges);
74
74
  const animationValue = useDerivedValue(() => x.value / size, [x, size]);
75
75
  const animatedStyle = useAnimatedStyle(
76
- () => animationStyle(x.value / size),
76
+ () => {
77
+ return animationStyle(x.value / size);
78
+ },
77
79
  [animationStyle],
78
80
  );
79
81
 
80
82
  const updateView = React.useCallback(
81
83
  (negativeRange: number[], positiveRange: number[]) => {
82
84
  mounted.current
83
- && setShouldUpdate(
84
- (index >= negativeRange[0] && index <= negativeRange[1])
85
- || (index >= positiveRange[0] && index <= positiveRange[1]),
86
- );
85
+ && setShouldUpdate(
86
+ (index >= negativeRange[0] && index <= negativeRange[1])
87
+ || (index >= positiveRange[0] && index <= positiveRange[1]),
88
+ );
87
89
  },
88
90
  [index, mounted],
89
91
  );
@@ -3,6 +3,7 @@ import { StyleSheet } from "react-native";
3
3
  import { GestureHandlerRootView } from "react-native-gesture-handler";
4
4
  import { runOnJS, useDerivedValue } from "react-native-reanimated";
5
5
 
6
+ import { BaseLayout } from "./BaseLayout";
6
7
  import { ScrollViewGesture } from "./ScrollViewGesture";
7
8
 
8
9
  import { useAutoPlay } from "../hooks/useAutoPlay";
@@ -13,7 +14,6 @@ import { useLayoutConfig } from "../hooks/useLayoutConfig";
13
14
  import { useOnProgressChange } from "../hooks/useOnProgressChange";
14
15
  import { usePropsErrorBoundary } from "../hooks/usePropsErrorBoundary";
15
16
  import { useVisibleRanges } from "../hooks/useVisibleRanges";
16
- import { BaseLayout } from "../layouts/BaseLayout";
17
17
  import { CTX } from "../store";
18
18
  import type { ICarouselInstance, TCarouselProps } from "../types";
19
19
  import { computedRealIndexWithAutoFillData } from "../utils/computed-with-auto-fill-data";
@@ -158,6 +158,7 @@ const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
158
158
  viewSize: size,
159
159
  translation: handlerOffset,
160
160
  windowSize,
161
+ loop,
161
162
  });
162
163
 
163
164
  const layoutConfig = useLayoutConfig({ ...props, size });
@@ -1,11 +1,8 @@
1
1
  import type { PropsWithChildren } from "react";
2
- import React, { useCallback, useMemo } from "react";
2
+ import React, { useCallback } from "react";
3
3
  import type { StyleProp, ViewStyle } from "react-native";
4
4
  import type { GestureStateChangeEvent, PanGestureHandlerEventPayload } from "react-native-gesture-handler";
5
- import {
6
- Gesture,
7
- GestureDetector,
8
- } from "react-native-gesture-handler";
5
+ import { GestureDetector } from "react-native-gesture-handler";
9
6
  import Animated, {
10
7
  cancelAnimation,
11
8
  measure,
@@ -18,7 +15,7 @@ import Animated, {
18
15
  } from "react-native-reanimated";
19
16
 
20
17
  import { Easing } from "../constants";
21
- import { useUpdateGestureConfig } from "../hooks/useUpdateGestureConfig";
18
+ import { usePanGestureProxy } from "../hooks/usePanGestureProxy";
22
19
  import { CTX } from "../store";
23
20
  import type { WithTimingAnimation } from "../types";
24
21
  import { dealWithAnimation } from "../utils/deal-with-animation";
@@ -42,13 +39,14 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
42
39
  vertical,
43
40
  pagingEnabled,
44
41
  snapEnabled,
45
- loop: infinite,
42
+ loop,
46
43
  scrollAnimationDuration,
47
44
  withAnimation,
48
45
  enabled,
49
46
  dataLength,
50
47
  overscrollEnabled,
51
48
  maxScrollDistancePerSwipe,
49
+ fixedDirection,
52
50
  },
53
51
  } = React.useContext(CTX);
54
52
 
@@ -78,7 +76,7 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
78
76
  const getLimit = React.useCallback(() => {
79
77
  "worklet";
80
78
 
81
- if (!infinite && !overscrollEnabled) {
79
+ if (!loop && !overscrollEnabled) {
82
80
  const { width: containerWidth = 0 } = measure(containerRef);
83
81
 
84
82
  // If the item's total width is less than the container's width, then there is no need to scroll.
@@ -90,7 +88,7 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
90
88
  }
91
89
 
92
90
  return dataLength * size;
93
- }, [infinite, size, dataLength, overscrollEnabled]);
91
+ }, [loop, size, dataLength, overscrollEnabled]);
94
92
 
95
93
  const withSpring = React.useCallback(
96
94
  (toValue: number, onFinished?: () => void) => {
@@ -141,7 +139,7 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
141
139
  const computed = offset < 0 ? Math.ceil : Math.floor;
142
140
  const page = computed(-translation.value / size);
143
141
 
144
- if (infinite) {
142
+ if (loop) {
145
143
  const finalPage = page + offset;
146
144
  finalTranslation = withSpring(withProcessTranslation(-finalPage * size), onFinished);
147
145
  }
@@ -161,7 +159,7 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
161
159
  translation.value = finalTranslation;
162
160
 
163
161
  function withProcessTranslation(translation: number) {
164
- if (!infinite && !overscrollEnabled) {
162
+ if (!loop && !overscrollEnabled) {
165
163
  const limit = getLimit();
166
164
  const sign = Math.sign(translation);
167
165
  return sign * Math.max(0, Math.min(limit, Math.abs(translation)));
@@ -174,7 +172,7 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
174
172
  withSpring,
175
173
  size,
176
174
  maxPage,
177
- infinite,
175
+ loop,
178
176
  snapEnabled,
179
177
  translation,
180
178
  pagingEnabled,
@@ -215,7 +213,7 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
215
213
  activeDecay();
216
214
  return;
217
215
  }
218
- if (!infinite) {
216
+ if (!loop) {
219
217
  translation.value = withSpring(0);
220
218
  return;
221
219
  }
@@ -226,7 +224,7 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
226
224
  activeDecay();
227
225
  return;
228
226
  }
229
- if (!infinite)
227
+ if (!loop)
230
228
  translation.value = withSpring(-((maxPage - 1) * size));
231
229
  }
232
230
  }, [
@@ -235,7 +233,7 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
235
233
  maxPage,
236
234
  size,
237
235
  scrollEndTranslation.value,
238
- infinite,
236
+ loop,
239
237
  activeDecay,
240
238
  withSpring,
241
239
  ]);
@@ -252,7 +250,7 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
252
250
  function withProcessTranslation(translation: number) {
253
251
  "worklet";
254
252
 
255
- if (!infinite && !overscrollEnabled) {
253
+ if (!loop && !overscrollEnabled) {
256
254
  const limit = getLimit();
257
255
  const sign = Math.sign(translation);
258
256
  return sign * Math.max(0, Math.min(limit, Math.abs(translation)));
@@ -261,7 +259,7 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
261
259
  return translation;
262
260
  }
263
261
 
264
- const onGestureBegin = useCallback(() => {
262
+ const onGestureBegin = useCallback((_: PanGestureHandlerEventPayload) => {
265
263
  "worklet";
266
264
 
267
265
  touching.value = true;
@@ -269,7 +267,7 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
269
267
  onScrollBegin && runOnJS(onScrollBegin)();
270
268
 
271
269
  max.value = (maxPage - 1) * size;
272
- if (!infinite && !overscrollEnabled)
270
+ if (!loop && !overscrollEnabled)
273
271
  max.value = getLimit();
274
272
 
275
273
  panOffset.value = translation.value;
@@ -277,7 +275,7 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
277
275
  max,
278
276
  size,
279
277
  maxPage,
280
- infinite,
278
+ loop,
281
279
  touching,
282
280
  panOffset,
283
281
  validStart,
@@ -296,10 +294,18 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
296
294
  }
297
295
  touching.value = true;
298
296
  const { translationX, translationY } = e;
299
- const panTranslation = isHorizontal.value
297
+
298
+ let panTranslation = isHorizontal.value
300
299
  ? translationX
301
300
  : translationY;
302
- if (!infinite) {
301
+
302
+ if (fixedDirection === "negative")
303
+ panTranslation = -Math.abs(panTranslation);
304
+
305
+ else if (fixedDirection === "positive")
306
+ panTranslation = +Math.abs(panTranslation);
307
+
308
+ if (!loop) {
303
309
  if ((translation.value > 0 || translation.value < -max.value)) {
304
310
  const boundary = translation.value > 0 ? 0 : -max.value;
305
311
  const fixed = boundary - panOffset.value;
@@ -315,24 +321,34 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
315
321
  isHorizontal,
316
322
  max,
317
323
  panOffset,
318
- infinite,
324
+ loop,
319
325
  overscrollEnabled,
326
+ fixedDirection,
320
327
  translation,
321
328
  validStart,
322
329
  touching,
323
330
  ]);
324
331
 
325
- const onGestureFinish = useCallback((e: GestureStateChangeEvent<PanGestureHandlerEventPayload>) => {
332
+ const onGestureEnd = useCallback((e: GestureStateChangeEvent<PanGestureHandlerEventPayload>, _success: boolean) => {
326
333
  "worklet";
327
334
 
328
335
  const { velocityX, velocityY, translationX, translationY } = e;
329
336
  scrollEndVelocity.value = isHorizontal.value
330
337
  ? velocityX
331
338
  : velocityY;
332
- scrollEndTranslation.value = isHorizontal.value
339
+
340
+ let panTranslation = isHorizontal.value
333
341
  ? translationX
334
342
  : translationY;
335
343
 
344
+ if (fixedDirection === "negative")
345
+ panTranslation = -Math.abs(panTranslation);
346
+
347
+ else if (fixedDirection === "positive")
348
+ panTranslation = +Math.abs(panTranslation);
349
+
350
+ scrollEndTranslation.value = panTranslation;
351
+
336
352
  const totalTranslation = scrollEndVelocity.value + scrollEndTranslation.value;
337
353
 
338
354
  if (maxScrollDistancePerSwipeIsSet && Math.abs(totalTranslation) > maxScrollDistancePerSwipe) {
@@ -343,17 +359,18 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
343
359
  endWithSpring(onScrollEnd);
344
360
  }
345
361
 
346
- if (!infinite)
362
+ if (!loop)
347
363
  touching.value = false;
348
364
  }, [
349
365
  size,
350
- infinite,
366
+ loop,
351
367
  touching,
352
368
  panOffset,
353
369
  translation,
354
370
  isHorizontal,
355
371
  scrollEndVelocity,
356
372
  scrollEndTranslation,
373
+ fixedDirection,
357
374
  maxScrollDistancePerSwipeIsSet,
358
375
  maxScrollDistancePerSwipe,
359
376
  endWithSpring,
@@ -361,25 +378,13 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
361
378
  onScrollEnd,
362
379
  ]);
363
380
 
364
- const gesture = useMemo(() => {
365
- const gesture = Gesture.Pan()
366
- .onBegin(onGestureBegin)
367
- .onUpdate(onGestureUpdate)
368
- .onEnd(onGestureFinish);
369
-
370
- if (onConfigurePanGesture)
371
- onConfigurePanGesture(gesture);
372
-
373
- return gesture;
374
- },
375
- [
381
+ const gesture = usePanGestureProxy({
382
+ onConfigurePanGesture,
376
383
  onGestureBegin,
377
384
  onGestureUpdate,
378
- onGestureFinish,
379
- onConfigurePanGesture,
380
- ]);
381
-
382
- useUpdateGestureConfig(gesture, { enabled });
385
+ onGestureEnd,
386
+ options: { enabled },
387
+ });
383
388
 
384
389
  return (
385
390
  <GestureDetector gesture={gesture}>
@@ -2,8 +2,8 @@ import React from "react";
2
2
 
3
3
  import type { TInitializeCarouselProps } from "./useInitProps";
4
4
 
5
+ import type { TAnimationStyle } from "../components/BaseLayout";
5
6
  import { Layouts } from "../layouts";
6
- import type { TAnimationStyle } from "../layouts/BaseLayout";
7
7
 
8
8
  type TLayoutConfigOpts<T> = TInitializeCarouselProps<T> & { size: number };
9
9