react-native-reanimated-carousel 4.0.0-alpha.1 → 4.0.0-alpha.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 (148) hide show
  1. package/README.md +2 -3
  2. package/lib/commonjs/{layouts → components}/BaseLayout.js +5 -21
  3. package/lib/commonjs/components/BaseLayout.js.map +1 -0
  4. package/lib/commonjs/components/Carousel.js +25 -46
  5. package/lib/commonjs/components/Carousel.js.map +1 -1
  6. package/lib/commonjs/components/ItemRenderer.js +80 -0
  7. package/lib/commonjs/components/ItemRenderer.js.map +1 -0
  8. package/lib/commonjs/components/ScrollViewGesture.js +51 -33
  9. package/lib/commonjs/components/ScrollViewGesture.js.map +1 -1
  10. package/lib/commonjs/components/rnr-demo.test.js +45 -0
  11. package/lib/commonjs/components/rnr-demo.test.js.map +1 -0
  12. package/lib/commonjs/hooks/useCarouselController.js +12 -11
  13. package/lib/commonjs/hooks/useCarouselController.js.map +1 -1
  14. package/lib/commonjs/hooks/useCommonVariables.js +38 -12
  15. package/lib/commonjs/hooks/useCommonVariables.js.map +1 -1
  16. package/lib/commonjs/hooks/useCommonVariables.test.js +38 -0
  17. package/lib/commonjs/hooks/useCommonVariables.test.js.map +1 -0
  18. package/lib/commonjs/hooks/useLayoutConfig.js.map +1 -1
  19. package/lib/commonjs/hooks/useOffsetX.js +9 -6
  20. package/lib/commonjs/hooks/useOffsetX.js.map +1 -1
  21. package/lib/commonjs/hooks/useOffsetX.test.js +53 -0
  22. package/lib/commonjs/hooks/useOffsetX.test.js.map +1 -0
  23. package/lib/commonjs/hooks/usePanGestureProxy.js +84 -0
  24. package/lib/commonjs/hooks/usePanGestureProxy.js.map +1 -0
  25. package/lib/commonjs/hooks/usePanGestureProxy.test.js +397 -0
  26. package/lib/commonjs/hooks/usePanGestureProxy.test.js.map +1 -0
  27. package/lib/commonjs/hooks/useUpdateGestureConfig.js.map +1 -1
  28. package/lib/commonjs/hooks/useVisibleRanges.js +48 -19
  29. package/lib/commonjs/hooks/useVisibleRanges.js.map +1 -1
  30. package/lib/commonjs/hooks/useVisibleRanges.test.js +162 -0
  31. package/lib/commonjs/hooks/useVisibleRanges.test.js.map +1 -0
  32. package/lib/commonjs/index.js.map +1 -1
  33. package/lib/commonjs/utils/{computeNewIndexWhenDataChanges.js → compute-offset-if-data-changed.js} +3 -3
  34. package/lib/commonjs/utils/compute-offset-if-data-changed.js.map +1 -0
  35. package/lib/commonjs/utils/compute-offset-if-data-changed.test.js +30 -0
  36. package/lib/commonjs/utils/compute-offset-if-data-changed.test.js.map +1 -0
  37. package/lib/commonjs/utils/compute-offset-if-size-changed.js +18 -0
  38. package/lib/commonjs/utils/compute-offset-if-size-changed.js.map +1 -0
  39. package/lib/commonjs/utils/compute-offset-if-size-changed.test.js +72 -0
  40. package/lib/commonjs/utils/compute-offset-if-size-changed.test.js.map +1 -0
  41. package/lib/commonjs/utils/handleroffset-direction.js +5 -5
  42. package/lib/commonjs/utils/handleroffset-direction.js.map +1 -1
  43. package/lib/commonjs/utils/handleroffset-direction.test.js +46 -0
  44. package/lib/commonjs/utils/handleroffset-direction.test.js.map +1 -0
  45. package/lib/commonjs/utils/index.test.js +6 -6
  46. package/lib/commonjs/utils/index.test.js.map +1 -1
  47. package/lib/module/{layouts → components}/BaseLayout.js +6 -16
  48. package/lib/module/components/BaseLayout.js.map +1 -0
  49. package/lib/module/components/Carousel.js +24 -42
  50. package/lib/module/components/Carousel.js.map +1 -1
  51. package/lib/module/components/ItemRenderer.js +62 -0
  52. package/lib/module/components/ItemRenderer.js.map +1 -0
  53. package/lib/module/components/ScrollViewGesture.js +53 -34
  54. package/lib/module/components/ScrollViewGesture.js.map +1 -1
  55. package/lib/module/components/rnr-demo.test.js +33 -0
  56. package/lib/module/components/rnr-demo.test.js.map +1 -0
  57. package/lib/module/hooks/useCarouselController.js +12 -11
  58. package/lib/module/hooks/useCarouselController.js.map +1 -1
  59. package/lib/module/hooks/useCommonVariables.js +38 -8
  60. package/lib/module/hooks/useCommonVariables.js.map +1 -1
  61. package/lib/module/hooks/useCommonVariables.test.js +34 -0
  62. package/lib/module/hooks/useCommonVariables.test.js.map +1 -0
  63. package/lib/module/hooks/useLayoutConfig.js.map +1 -1
  64. package/lib/module/hooks/useOffsetX.js +9 -6
  65. package/lib/module/hooks/useOffsetX.js.map +1 -1
  66. package/lib/module/hooks/useOffsetX.test.js +48 -0
  67. package/lib/module/hooks/useOffsetX.test.js.map +1 -0
  68. package/lib/module/hooks/usePanGestureProxy.js +71 -0
  69. package/lib/module/hooks/usePanGestureProxy.js.map +1 -0
  70. package/lib/module/hooks/usePanGestureProxy.test.js +383 -0
  71. package/lib/module/hooks/usePanGestureProxy.test.js.map +1 -0
  72. package/lib/module/hooks/useUpdateGestureConfig.js.map +1 -1
  73. package/lib/module/hooks/useVisibleRanges.js +47 -19
  74. package/lib/module/hooks/useVisibleRanges.js.map +1 -1
  75. package/lib/module/hooks/useVisibleRanges.test.js +157 -0
  76. package/lib/module/hooks/useVisibleRanges.test.js.map +1 -0
  77. package/lib/module/index.js.map +1 -1
  78. package/lib/module/utils/{computeNewIndexWhenDataChanges.js → compute-offset-if-data-changed.js} +2 -2
  79. package/lib/module/utils/compute-offset-if-data-changed.js.map +1 -0
  80. package/lib/module/utils/compute-offset-if-data-changed.test.js +27 -0
  81. package/lib/module/utils/compute-offset-if-data-changed.test.js.map +1 -0
  82. package/lib/module/utils/compute-offset-if-size-changed.js +11 -0
  83. package/lib/module/utils/compute-offset-if-size-changed.js.map +1 -0
  84. package/lib/module/utils/compute-offset-if-size-changed.test.js +69 -0
  85. package/lib/module/utils/compute-offset-if-size-changed.test.js.map +1 -0
  86. package/lib/module/utils/handleroffset-direction.js +5 -5
  87. package/lib/module/utils/handleroffset-direction.js.map +1 -1
  88. package/lib/module/utils/handleroffset-direction.test.js +41 -0
  89. package/lib/module/utils/handleroffset-direction.test.js.map +1 -0
  90. package/lib/module/utils/index.test.js +6 -6
  91. package/lib/module/utils/index.test.js.map +1 -1
  92. package/lib/typescript/components/ItemRenderer.d.ts +22 -0
  93. package/lib/typescript/components/ScrollViewGesture.d.ts +1 -1
  94. package/lib/typescript/components/rnr-demo.test.d.ts +1 -0
  95. package/lib/typescript/hooks/useCarouselController.d.ts +3 -2
  96. package/lib/typescript/hooks/useCommonVariables.test.d.ts +1 -0
  97. package/lib/typescript/hooks/useLayoutConfig.d.ts +1 -1
  98. package/lib/typescript/hooks/useOffsetX.test.d.ts +1 -0
  99. package/lib/typescript/hooks/usePanGestureProxy.d.ts +9 -0
  100. package/lib/typescript/hooks/usePanGestureProxy.test.d.ts +1 -0
  101. package/lib/typescript/hooks/useUpdateGestureConfig.d.ts +3 -2
  102. package/lib/typescript/hooks/useVisibleRanges.d.ts +8 -4
  103. package/lib/typescript/hooks/useVisibleRanges.test.d.ts +1 -0
  104. package/lib/typescript/index.d.ts +1 -0
  105. package/lib/typescript/types.d.ts +13 -4
  106. package/lib/typescript/utils/{computeNewIndexWhenDataChanges.d.ts → compute-offset-if-data-changed.d.ts} +1 -1
  107. package/lib/typescript/utils/compute-offset-if-data-changed.test.d.ts +1 -0
  108. package/lib/typescript/utils/compute-offset-if-size-changed.d.ts +5 -0
  109. package/lib/typescript/utils/compute-offset-if-size-changed.test.d.ts +1 -0
  110. package/lib/typescript/utils/handleroffset-direction.d.ts +2 -1
  111. package/lib/typescript/utils/handleroffset-direction.test.d.ts +1 -0
  112. package/package.json +16 -59
  113. package/src/{layouts → components}/BaseLayout.tsx +7 -35
  114. package/src/components/Carousel.tsx +24 -58
  115. package/src/components/ItemRenderer.tsx +105 -0
  116. package/src/components/ScrollViewGesture.tsx +74 -49
  117. package/src/components/rnr-demo.test.tsx +43 -0
  118. package/src/hooks/useCarouselController.tsx +24 -21
  119. package/src/hooks/useCommonVariables.test.tsx +41 -0
  120. package/src/hooks/useCommonVariables.ts +35 -10
  121. package/src/hooks/useLayoutConfig.ts +1 -1
  122. package/src/hooks/useOffsetX.test.ts +54 -0
  123. package/src/hooks/useOffsetX.ts +33 -31
  124. package/src/hooks/usePanGestureProxy.test.tsx +376 -0
  125. package/src/hooks/usePanGestureProxy.ts +110 -0
  126. package/src/hooks/useUpdateGestureConfig.ts +4 -2
  127. package/src/hooks/useVisibleRanges.test.tsx +179 -0
  128. package/src/hooks/useVisibleRanges.tsx +72 -24
  129. package/src/index.tsx +2 -0
  130. package/src/types.ts +13 -4
  131. package/src/utils/compute-offset-if-data-changed.test.ts +30 -0
  132. package/src/utils/{computeNewIndexWhenDataChanges.ts → compute-offset-if-data-changed.ts} +1 -1
  133. package/src/utils/compute-offset-if-size-changed.test.ts +78 -0
  134. package/src/utils/compute-offset-if-size-changed.ts +11 -0
  135. package/src/utils/handleroffset-direction.test.ts +52 -0
  136. package/src/utils/handleroffset-direction.ts +12 -9
  137. package/src/utils/index.test.ts +6 -6
  138. package/lib/commonjs/layouts/BaseLayout.js.map +0 -1
  139. package/lib/commonjs/layouts/ParallaxLayout.js +0 -84
  140. package/lib/commonjs/layouts/ParallaxLayout.js.map +0 -1
  141. package/lib/commonjs/utils/computeNewIndexWhenDataChanges.js.map +0 -1
  142. package/lib/module/layouts/BaseLayout.js.map +0 -1
  143. package/lib/module/layouts/ParallaxLayout.js +0 -61
  144. package/lib/module/layouts/ParallaxLayout.js.map +0 -1
  145. package/lib/module/utils/computeNewIndexWhenDataChanges.js.map +0 -1
  146. package/lib/typescript/layouts/ParallaxLayout.d.ts +0 -13
  147. package/src/layouts/ParallaxLayout.tsx +0 -141
  148. /package/lib/typescript/{layouts → components}/BaseLayout.d.ts +0 -0
@@ -0,0 +1,179 @@
1
+ import { useSharedValue } from "react-native-reanimated";
2
+
3
+ import { renderHook } from "@testing-library/react-hooks";
4
+
5
+ import { useVisibleRanges } from "./useVisibleRanges";
6
+
7
+ const viewSize = 393;
8
+
9
+ describe("useVisibleRanges", () => {
10
+ it("should only display the front of the list when loop is false", async () => {
11
+ const hook = renderHook(() => {
12
+ const translation = useSharedValue(-0);
13
+ const range = useVisibleRanges({
14
+ total: 10,
15
+ translation,
16
+ viewSize,
17
+ windowSize: 4,
18
+ loop: false,
19
+ });
20
+
21
+ return range;
22
+ });
23
+
24
+ const expected = hook.result.current.value;
25
+
26
+ expect(expected).toMatchInlineSnapshot(`
27
+ {
28
+ "negativeRange": [
29
+ -3,
30
+ 0,
31
+ ],
32
+ "positiveRange": [
33
+ 0,
34
+ 3,
35
+ ],
36
+ }
37
+ `);
38
+ });
39
+
40
+ it("should display the rear of the list and the front of the list when loop is true", async () => {
41
+ const hook = renderHook(() => {
42
+ const translation = useSharedValue(-0);
43
+ const range = useVisibleRanges({
44
+ total: 10,
45
+ translation,
46
+ viewSize,
47
+ windowSize: 4,
48
+ loop: true,
49
+ });
50
+
51
+ return range;
52
+ });
53
+
54
+ const expected = hook.result.current.value;
55
+
56
+ expect(expected).toMatchInlineSnapshot(`
57
+ {
58
+ "negativeRange": [
59
+ 8,
60
+ 9,
61
+ ],
62
+ "positiveRange": [
63
+ 0,
64
+ 2,
65
+ ],
66
+ }
67
+ `);
68
+ });
69
+
70
+ it("should shows the increased range of the list when the loop is false and swiped the carousel.", async () => {
71
+ const slide0hook = renderHook(() => {
72
+ const translation = useSharedValue(-0 * viewSize);
73
+ const range = useVisibleRanges({
74
+ total: 10,
75
+ translation,
76
+ viewSize,
77
+ windowSize: 4,
78
+ loop: false,
79
+ });
80
+
81
+ return range;
82
+ }).result.current.value;
83
+
84
+ const slide1hook = renderHook(() => {
85
+ const translation = useSharedValue(-1 * viewSize);
86
+ const range = useVisibleRanges({
87
+ total: 10,
88
+ translation,
89
+ viewSize,
90
+ windowSize: 4,
91
+ loop: false,
92
+ });
93
+
94
+ return range;
95
+ }).result.current.value;
96
+
97
+ const slide2hook = renderHook(() => {
98
+ const translation = useSharedValue(-2 * viewSize);
99
+ const range = useVisibleRanges({
100
+ total: 10,
101
+ translation,
102
+ viewSize,
103
+ windowSize: 4,
104
+ loop: false,
105
+ });
106
+
107
+ return range;
108
+ }).result.current.value;
109
+
110
+ const slide3hook = renderHook(() => {
111
+ const translation = useSharedValue(-3 * viewSize);
112
+ const range = useVisibleRanges({
113
+ total: 10,
114
+ translation,
115
+ viewSize,
116
+ windowSize: 4,
117
+ loop: false,
118
+ });
119
+
120
+ return range;
121
+ }).result.current.value;
122
+
123
+ // [0,3] Display the 0,1,2,3 items.
124
+ expect(slide0hook).toMatchInlineSnapshot(`
125
+ {
126
+ "negativeRange": [
127
+ -3,
128
+ 0,
129
+ ],
130
+ "positiveRange": [
131
+ 0,
132
+ 3,
133
+ ],
134
+ }
135
+ `);
136
+
137
+ // [1,4] Display the 1,2,3,4 items.
138
+ expect(slide1hook).toMatchInlineSnapshot(`
139
+ {
140
+ "negativeRange": [
141
+ -2,
142
+ 1,
143
+ ],
144
+ "positiveRange": [
145
+ 1,
146
+ 4,
147
+ ],
148
+ }
149
+ `);
150
+
151
+ // [2,5] Display the 2,3,4,5 items.
152
+ expect(slide2hook).toMatchInlineSnapshot(`
153
+ {
154
+ "negativeRange": [
155
+ -1,
156
+ 2,
157
+ ],
158
+ "positiveRange": [
159
+ 2,
160
+ 5,
161
+ ],
162
+ }
163
+ `);
164
+
165
+ // [3.6] Display the 3,4,5,6 items.
166
+ expect(slide3hook).toMatchInlineSnapshot(`
167
+ {
168
+ "negativeRange": [
169
+ 0,
170
+ 3,
171
+ ],
172
+ "positiveRange": [
173
+ 3,
174
+ 6,
175
+ ],
176
+ }
177
+ `);
178
+ });
179
+ });
@@ -1,49 +1,97 @@
1
+ import { useRef } from "react";
1
2
  import type Animated from "react-native-reanimated";
2
3
  import { useDerivedValue } from "react-native-reanimated";
3
4
 
4
- export type IVisibleRanges = Animated.SharedValue<{
5
- negativeRange: number[]
6
- positiveRange: number[]
7
- }>;
5
+ type Range = [number, number];
6
+
7
+ export interface VisibleRanges {
8
+ negativeRange: Range
9
+ positiveRange: Range
10
+ }
11
+
12
+ export type IVisibleRanges = Animated.SharedValue<VisibleRanges>;
8
13
 
9
14
  export function useVisibleRanges(options: {
10
15
  total: number
11
16
  viewSize: number
12
17
  windowSize?: number
13
18
  translation: Animated.SharedValue<number>
19
+ loop?: boolean
14
20
  }): IVisibleRanges {
15
21
  const {
16
22
  total = 0,
17
23
  viewSize,
18
24
  translation,
19
- windowSize: _windowSize = 0,
25
+ windowSize: _windowSize,
26
+ loop,
20
27
  } = options;
21
28
 
22
- const windowSize = total <= _windowSize ? total : _windowSize;
29
+ const windowSize = _windowSize ?? total;
30
+ const cachedRanges = useRef<VisibleRanges>(null!);
23
31
 
24
32
  const ranges = useDerivedValue(() => {
25
33
  const positiveCount = Math.round(windowSize / 2);
26
34
  const negativeCount = windowSize - positiveCount;
27
- let curIndex = Math.round(-translation.value / viewSize);
28
- curIndex = curIndex < 0 ? (curIndex % total) + total : curIndex;
29
- const negativeRange = [
30
- (curIndex - negativeCount + total) % total,
31
- (curIndex - 1 + total) % total,
32
- ];
33
- const positiveRange = [
34
- (curIndex + total) % total,
35
- (curIndex + positiveCount + total) % total,
36
- ];
37
- if (negativeRange[0] < total && negativeRange[0] > negativeRange[1]) {
38
- negativeRange[1] = total - 1;
39
- positiveRange[0] = 0;
35
+
36
+ let currentIndex = Math.round(-translation.value / viewSize);
37
+ currentIndex = currentIndex < 0 ? (currentIndex % total) + total : currentIndex;
38
+
39
+ let newRanges: VisibleRanges;
40
+
41
+ if (!loop) {
42
+ // Adjusting negative range if the carousel is not loopable.
43
+ // So, It will be only displayed the positive items.
44
+ newRanges = {
45
+ negativeRange: [0 + currentIndex - (windowSize - 1), 0 + currentIndex],
46
+ positiveRange: [0 + currentIndex, currentIndex + (windowSize - 1)],
47
+ };
40
48
  }
41
- if (positiveRange[0] > positiveRange[1]) {
42
- negativeRange[1] = total - 1;
43
- positiveRange[0] = 0;
49
+ else {
50
+ const negativeRange: Range = [
51
+ (currentIndex - negativeCount + total) % total,
52
+ (currentIndex - 1 + total) % total,
53
+ ];
54
+
55
+ const positiveRange: Range = [
56
+ (currentIndex + total) % total,
57
+ (currentIndex + positiveCount + total) % total,
58
+ ];
59
+
60
+ if (negativeRange[0] < total && negativeRange[0] > negativeRange[1]) {
61
+ negativeRange[1] = total - 1;
62
+ positiveRange[0] = 0;
63
+ }
64
+ if (positiveRange[0] > positiveRange[1]) {
65
+ negativeRange[1] = total - 1;
66
+ positiveRange[0] = 0;
67
+ }
68
+
69
+ // console.log({ negativeRange, positiveRange ,total,windowSize,a:total <= _windowSize})
70
+ newRanges = { negativeRange, positiveRange };
44
71
  }
45
- return { negativeRange, positiveRange };
46
- }, [total, windowSize, translation]);
72
+
73
+ if (
74
+ isArraysEqual(
75
+ cachedRanges.current?.negativeRange ?? [],
76
+ newRanges.negativeRange,
77
+ )
78
+ && isArraysEqual(
79
+ cachedRanges.current?.positiveRange ?? [],
80
+ newRanges.positiveRange,
81
+ )
82
+ )
83
+ return cachedRanges.current;
84
+
85
+ cachedRanges.current = newRanges;
86
+ return cachedRanges.current;
87
+ }, [loop, total, windowSize, translation]);
47
88
 
48
89
  return ranges;
49
90
  }
91
+
92
+ function isArraysEqual(a: number[], b: number[]): boolean {
93
+ "worklet";
94
+ if (a.length !== b.length) return false;
95
+
96
+ return a.every((value, index) => value === b[index]);
97
+ }
package/src/index.tsx CHANGED
@@ -1,10 +1,12 @@
1
1
  import Carousel from "./components/Carousel";
2
+
2
3
  export type {
3
4
  TCarouselProps,
4
5
  ICarouselInstance,
5
6
  IComputedDirectionTypes,
6
7
  CarouselRenderItem,
7
8
  } from "./types";
9
+ export type { TAnimationStyle } from "./components/BaseLayout";
8
10
  export type { ILayoutConfig } from "./layouts/stack";
9
11
 
10
12
  export default Carousel;
package/src/types.ts CHANGED
@@ -153,10 +153,19 @@ export type TCarouselProps<T = any> = {
153
153
  testID?: string
154
154
  /**
155
155
  * Maximum offset value for once scroll.
156
- * props.vertical = true => maxScrollDistancePerSwipeY
157
- * props.vertical = false => maxScrollDistancePerSwipeX
156
+ * Carousel cannot scroll over than this value.
158
157
  * */
159
158
  maxScrollDistancePerSwipe?: number
159
+ /**
160
+ * Minimum offset value for once scroll.
161
+ * If the translation value is less than this value, the carousel will not scroll.
162
+ * */
163
+ minScrollDistancePerSwipe?: number
164
+ /**
165
+ * @experimental This API will be changed in the future.
166
+ * If positive, the carousel will scroll to the positive direction and vice versa.
167
+ * */
168
+ fixedDirection?: "positive" | "negative"
160
169
  /**
161
170
  * Custom carousel config.
162
171
  */
@@ -175,9 +184,9 @@ export type TCarouselProps<T = any> = {
175
184
  */
176
185
  onSnapToItem?: (index: number) => void
177
186
  /**
178
- * On scroll begin
187
+ * On scroll start
179
188
  */
180
- onScrollBegin?: () => void
189
+ onScrollStart?: () => void
181
190
  /**
182
191
  * On scroll end
183
192
  */
@@ -0,0 +1,30 @@
1
+ import { computeOffsetIfDataChanged } from "./compute-offset-if-data-changed";
2
+
3
+ describe("computeOffsetIfDataChanged", () => {
4
+ const size = 634;
5
+ it("should return the correct values, if index is 0", () => {
6
+ const index = 0;
7
+ const result = computeOffsetIfDataChanged({
8
+ direction: -1,
9
+ previousLength: 4,
10
+ currentLength: 6,
11
+ size,
12
+ handlerOffset: index * size,
13
+ });
14
+
15
+ expect(result).toMatchInlineSnapshot("0");
16
+ });
17
+
18
+ it("should return the correct values, if index is 1", () => {
19
+ const index = 1;
20
+ const result = computeOffsetIfDataChanged({
21
+ direction: -1,
22
+ previousLength: 4,
23
+ currentLength: 6,
24
+ size,
25
+ handlerOffset: index * size,
26
+ });
27
+
28
+ expect(result).toMatchInlineSnapshot("634");
29
+ });
30
+ });
@@ -6,7 +6,7 @@ export function omitZero(a: number, b: number) {
6
6
  return b;
7
7
  }
8
8
 
9
- export function computeNewIndexWhenDataChanges(params: {
9
+ export function computeOffsetIfDataChanged(params: {
10
10
  direction: number
11
11
  handlerOffset: number
12
12
  size: number
@@ -0,0 +1,78 @@
1
+ import { computeOffsetIfSizeChanged } from "./compute-offset-if-size-changed";
2
+
3
+ describe("computeOffsetIfSizeChanged", () => {
4
+ it("[CASE 1] should return the correct values when size does not change", () => {
5
+ const prevIndex = 1;
6
+ const prevSize = 500;
7
+ const size = 500;
8
+ const handlerOffset = prevIndex * size;
9
+ const result = computeOffsetIfSizeChanged({
10
+ prevSize,
11
+ size,
12
+ handlerOffset,
13
+ });
14
+
15
+ const finallyIndex = result / size;
16
+ expect(finallyIndex).toEqual(prevIndex);
17
+ });
18
+
19
+ it("[CASE 2] should return the correct values when size changes from 500 to 400", () => {
20
+ const prevIndex = 1;
21
+ const prevSize = 500;
22
+ const size = 400;
23
+ const handlerOffset = prevIndex * prevSize;
24
+ const result = computeOffsetIfSizeChanged({
25
+ prevSize,
26
+ size,
27
+ handlerOffset,
28
+ });
29
+
30
+ const finallyIndex = result / size;
31
+ expect(finallyIndex).toEqual(prevIndex);
32
+ });
33
+
34
+ it("[CASE 3] should return the correct values when size changes from 500 to 499", () => {
35
+ const prevIndex = 1;
36
+ const prevSize = 500;
37
+ const size = 499;
38
+ const handlerOffset = prevIndex * prevSize;
39
+ const result = computeOffsetIfSizeChanged({
40
+ prevSize,
41
+ size,
42
+ handlerOffset,
43
+ });
44
+
45
+ const finallyIndex = result / size;
46
+ expect(finallyIndex).toEqual(prevIndex);
47
+ });
48
+
49
+ it("[CASE 4] should return the correct values when size changes from 500 to 501", () => {
50
+ const prevIndex = 1;
51
+ const prevSize = 500;
52
+ const size = 501;
53
+ const handlerOffset = prevIndex * prevSize;
54
+ const result = computeOffsetIfSizeChanged({
55
+ prevSize,
56
+ size,
57
+ handlerOffset,
58
+ });
59
+
60
+ const finallyIndex = result / size;
61
+ expect(finallyIndex).toEqual(prevIndex);
62
+ });
63
+
64
+ it("[CASE 5] should return the correct values when size changes from 224 to 524", () => {
65
+ const prevIndex = 1;
66
+ const prevSize = 224;
67
+ const size = 524;
68
+ const handlerOffset = prevIndex * prevSize;
69
+ const result = computeOffsetIfSizeChanged({
70
+ prevSize,
71
+ size,
72
+ handlerOffset,
73
+ });
74
+
75
+ const finallyIndex = result / size;
76
+ expect(finallyIndex).toEqual(prevIndex);
77
+ });
78
+ });
@@ -0,0 +1,11 @@
1
+ export function computeOffsetIfSizeChanged(params: {
2
+ handlerOffset: number
3
+ prevSize: number
4
+ size: number
5
+ }) {
6
+ "worklet";
7
+ const { handlerOffset, prevSize, size } = params;
8
+
9
+ return handlerOffset / prevSize * size;
10
+ }
11
+
@@ -0,0 +1,52 @@
1
+ import { useSharedValue } from "react-native-reanimated";
2
+
3
+ import { renderHook } from "@testing-library/react-hooks";
4
+
5
+ import { handlerOffsetDirection } from "./handleroffset-direction";
6
+
7
+ describe("handlerOffsetDirection", () => {
8
+ it("should return -1 when default value equals to zero", () => {
9
+ const result = renderHook(() => {
10
+ const handlerOffsetAnimVal = useSharedValue(0);
11
+ return handlerOffsetDirection(handlerOffsetAnimVal);
12
+ });
13
+
14
+ expect(result.result.current).toBe(-1);
15
+ });
16
+
17
+ it("should return 1 when default value is greater than zero", () => {
18
+ const result = renderHook(() => {
19
+ const handlerOffsetAnimVal = useSharedValue(1);
20
+ return handlerOffsetDirection(handlerOffsetAnimVal);
21
+ });
22
+
23
+ expect(result.result.current).toBe(1);
24
+ });
25
+
26
+ it("should return -1 when default value is less than zero", () => {
27
+ const result = renderHook(() => {
28
+ const handlerOffsetAnimVal = useSharedValue(-1);
29
+ return handlerOffsetDirection(handlerOffsetAnimVal);
30
+ });
31
+
32
+ expect(result.result.current).toBe(-1);
33
+ });
34
+
35
+ it("should return 1 when default value equals to zero and fixedDirection is negative", () => {
36
+ const result = renderHook(() => {
37
+ const handlerOffsetAnimVal = useSharedValue(-1);
38
+ return handlerOffsetDirection(handlerOffsetAnimVal, "positive");
39
+ });
40
+
41
+ expect(result.result.current).toBe(1);
42
+ });
43
+
44
+ it("should return -1 when default value is greater than zero and fixedDirection is negative", () => {
45
+ const result = renderHook(() => {
46
+ const handlerOffsetAnimVal = useSharedValue(1);
47
+ return handlerOffsetDirection(handlerOffsetAnimVal, "negative");
48
+ });
49
+
50
+ expect(result.result.current).toBe(-1);
51
+ });
52
+ });
@@ -1,15 +1,18 @@
1
1
  import type { SharedValue } from "react-native-reanimated";
2
2
 
3
- export function handlerOffsetDirection(handlerOffset: SharedValue<number>): -1 | 1 {
3
+ import type { TCarouselProps } from "../types";
4
+
5
+ export function handlerOffsetDirection(handlerOffset: SharedValue<number>, fixedDirection?: TCarouselProps["fixedDirection"]): -1 | 1 {
4
6
  "worklet";
5
7
 
6
- const isPositiveZero = Object.is(handlerOffset.value, +0);
7
- const isNegativeZero = Object.is(handlerOffset.value, -0);
8
- const direction = isPositiveZero
9
- ? 1
10
- : isNegativeZero
11
- ? -1
12
- : Math.sign(handlerOffset.value) as -1 | 1;
8
+ if (fixedDirection === "negative")
9
+ return -1;
10
+
11
+ if (fixedDirection === "positive")
12
+ return 1;
13
+
14
+ if (handlerOffset.value === 0)
15
+ return -1;
13
16
 
14
- return direction;
17
+ return Math.sign(handlerOffset.value) as -1 | 1;
15
18
  }
@@ -1,4 +1,4 @@
1
- import { computeNewIndexWhenDataChanges } from "./computeNewIndexWhenDataChanges";
1
+ import { computeOffsetIfDataChanged } from "./compute-offset-if-data-changed";
2
2
 
3
3
  describe("should work as expected", () => {
4
4
  const size = 375;
@@ -24,7 +24,7 @@ describe("should work as expected", () => {
24
24
 
25
25
  it("The direction is negative, And changing length of data set from 4 to 3, the new index will to be 2.", async () => {
26
26
  const currentIndex = 1;
27
- const handlerOffset = computeNewIndexWhenDataChanges(params({
27
+ const handlerOffset = computeOffsetIfDataChanged(params({
28
28
  currentIndex,
29
29
  direction: "negative",
30
30
  previousLength: 4,
@@ -35,7 +35,7 @@ describe("should work as expected", () => {
35
35
  });
36
36
 
37
37
  it("The direction is negative, Changing length of data set from 4 to 3, the index remains original.", async () => {
38
- const handlerOffset = computeNewIndexWhenDataChanges(params({
38
+ const handlerOffset = computeOffsetIfDataChanged(params({
39
39
  currentIndex: 2,
40
40
  direction: "negative",
41
41
  previousLength: 4,
@@ -46,7 +46,7 @@ describe("should work as expected", () => {
46
46
  });
47
47
 
48
48
  it("The direction is positive, Changing length of data set from 4 to 5, the index remains original.", async () => {
49
- const handlerOffset = computeNewIndexWhenDataChanges(params({
49
+ const handlerOffset = computeOffsetIfDataChanged(params({
50
50
  currentIndex: 3,
51
51
  direction: "positive",
52
52
  previousLength: 4,
@@ -57,7 +57,7 @@ describe("should work as expected", () => {
57
57
  });
58
58
 
59
59
  it("The direction is negative, Changing length of data set from 4 to 5, the index remains original.", async () => {
60
- const handlerOffset = computeNewIndexWhenDataChanges(params({
60
+ const handlerOffset = computeOffsetIfDataChanged(params({
61
61
  currentIndex: 3,
62
62
  direction: "negative",
63
63
  previousLength: 4,
@@ -68,7 +68,7 @@ describe("should work as expected", () => {
68
68
  });
69
69
 
70
70
  it("Changing length of data set from 0 to 3, the index remains original.", async () => {
71
- const handlerOffset = computeNewIndexWhenDataChanges(params({
71
+ const handlerOffset = computeOffsetIfDataChanged(params({
72
72
  currentIndex: 0,
73
73
  direction: "positive",
74
74
  previousLength: 0,
@@ -1 +0,0 @@
1
- {"version":3,"sources":["BaseLayout.tsx"],"names":["BaseLayout","props","mounted","handlerOffset","index","children","visibleRanges","animationStyle","context","React","useContext","CTX","loop","dataLength","width","height","vertical","customConfig","mode","modeConfig","size","shouldUpdate","setShouldUpdate","useState","offsetXConfig","snapDirection","showLength","type","viewCount","x","animationValue","value","animatedStyle","updateView","useCallback","negativeRange","positiveRange","current","position"],"mappings":"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","sourcesContent":["import React from \"react\";\nimport type { ViewStyle } from \"react-native\";\nimport type { AnimatedStyleProp } from \"react-native-reanimated\";\nimport Animated, {\n runOnJS,\n useAnimatedReaction,\n useAnimatedStyle,\n useDerivedValue,\n} from \"react-native-reanimated\";\n\nimport type { ILayoutConfig } from \"./stack\";\n\nimport { LazyView } from \"../components/LazyView\";\nimport { useCheckMounted } from \"../hooks/useCheckMounted\";\nimport type { IOpts } from \"../hooks/useOffsetX\";\nimport { useOffsetX } from \"../hooks/useOffsetX\";\nimport type { IVisibleRanges } from \"../hooks/useVisibleRanges\";\nimport { CTX } from \"../store\";\n\nexport type TAnimationStyle = (value: number) => AnimatedStyleProp<ViewStyle>;\n\nexport const BaseLayout: React.FC<{\n index: number\n handlerOffset: Animated.SharedValue<number>\n visibleRanges: IVisibleRanges\n animationStyle: TAnimationStyle\n children: (ctx: {\n animationValue: Animated.SharedValue<number>\n }) => React.ReactElement\n}> = (props) => {\n const mounted = useCheckMounted();\n const { handlerOffset, index, children, visibleRanges, animationStyle }\n = props;\n\n const context = React.useContext(CTX);\n const {\n props: {\n loop,\n dataLength,\n width,\n height,\n vertical,\n customConfig,\n mode,\n modeConfig,\n },\n } = context;\n const size = vertical ? height : width;\n const [shouldUpdate, setShouldUpdate] = React.useState(false);\n let offsetXConfig: IOpts = {\n handlerOffset,\n index,\n size,\n dataLength,\n loop,\n ...(typeof customConfig === \"function\" ? customConfig() : {}),\n };\n\n if (mode === \"horizontal-stack\") {\n const { snapDirection, showLength } = modeConfig as ILayoutConfig;\n\n offsetXConfig = {\n handlerOffset,\n index,\n size,\n dataLength,\n loop,\n type: snapDirection === \"right\" ? \"negative\" : \"positive\",\n viewCount: showLength,\n };\n }\n\n const x = useOffsetX(offsetXConfig, visibleRanges);\n const animationValue = useDerivedValue(() => x.value / size, [x, size]);\n const animatedStyle = useAnimatedStyle(\n () => animationStyle(x.value / size),\n [animationStyle],\n );\n\n const updateView = React.useCallback(\n (negativeRange: number[], positiveRange: number[]) => {\n mounted.current\n && setShouldUpdate(\n (index >= negativeRange[0] && index <= negativeRange[1])\n || (index >= positiveRange[0] && index <= positiveRange[1]),\n );\n },\n [index, mounted],\n );\n\n useAnimatedReaction(\n () => visibleRanges.value,\n () => {\n runOnJS(updateView)(\n visibleRanges.value.negativeRange,\n visibleRanges.value.positiveRange,\n );\n },\n [visibleRanges.value],\n );\n\n return (\n <Animated.View\n style={[\n {\n width: width || \"100%\",\n height: height || \"100%\",\n position: \"absolute\",\n },\n animatedStyle,\n ]}\n /**\n * We use this testID to know when the carousel item is ready to be tested in test.\n * e.g.\n * The testID of first item will be changed to __CAROUSEL_ITEM_0_READY__ from __CAROUSEL_ITEM_0_NOT_READY__ when the item is ready.\n * */\n testID={`__CAROUSEL_ITEM_${index}_${shouldUpdate ? \"READY\" : \"NOT_READY\"}__`}\n >\n <LazyView shouldUpdate={shouldUpdate}>\n {children({ animationValue })}\n </LazyView>\n </Animated.View>\n );\n};\n"]}