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.
- package/README.md +2 -3
- package/lib/commonjs/{layouts → components}/BaseLayout.js +5 -21
- package/lib/commonjs/components/BaseLayout.js.map +1 -0
- package/lib/commonjs/components/Carousel.js +25 -46
- package/lib/commonjs/components/Carousel.js.map +1 -1
- package/lib/commonjs/components/ItemRenderer.js +80 -0
- package/lib/commonjs/components/ItemRenderer.js.map +1 -0
- package/lib/commonjs/components/ScrollViewGesture.js +51 -33
- package/lib/commonjs/components/ScrollViewGesture.js.map +1 -1
- package/lib/commonjs/components/rnr-demo.test.js +45 -0
- package/lib/commonjs/components/rnr-demo.test.js.map +1 -0
- package/lib/commonjs/hooks/useCarouselController.js +12 -11
- package/lib/commonjs/hooks/useCarouselController.js.map +1 -1
- package/lib/commonjs/hooks/useCommonVariables.js +38 -12
- package/lib/commonjs/hooks/useCommonVariables.js.map +1 -1
- package/lib/commonjs/hooks/useCommonVariables.test.js +38 -0
- package/lib/commonjs/hooks/useCommonVariables.test.js.map +1 -0
- package/lib/commonjs/hooks/useLayoutConfig.js.map +1 -1
- package/lib/commonjs/hooks/useOffsetX.js +9 -6
- package/lib/commonjs/hooks/useOffsetX.js.map +1 -1
- package/lib/commonjs/hooks/useOffsetX.test.js +53 -0
- package/lib/commonjs/hooks/useOffsetX.test.js.map +1 -0
- package/lib/commonjs/hooks/usePanGestureProxy.js +84 -0
- package/lib/commonjs/hooks/usePanGestureProxy.js.map +1 -0
- package/lib/commonjs/hooks/usePanGestureProxy.test.js +397 -0
- package/lib/commonjs/hooks/usePanGestureProxy.test.js.map +1 -0
- package/lib/commonjs/hooks/useUpdateGestureConfig.js.map +1 -1
- package/lib/commonjs/hooks/useVisibleRanges.js +48 -19
- package/lib/commonjs/hooks/useVisibleRanges.js.map +1 -1
- package/lib/commonjs/hooks/useVisibleRanges.test.js +162 -0
- package/lib/commonjs/hooks/useVisibleRanges.test.js.map +1 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/utils/{computeNewIndexWhenDataChanges.js → compute-offset-if-data-changed.js} +3 -3
- package/lib/commonjs/utils/compute-offset-if-data-changed.js.map +1 -0
- package/lib/commonjs/utils/compute-offset-if-data-changed.test.js +30 -0
- package/lib/commonjs/utils/compute-offset-if-data-changed.test.js.map +1 -0
- package/lib/commonjs/utils/compute-offset-if-size-changed.js +18 -0
- package/lib/commonjs/utils/compute-offset-if-size-changed.js.map +1 -0
- package/lib/commonjs/utils/compute-offset-if-size-changed.test.js +72 -0
- package/lib/commonjs/utils/compute-offset-if-size-changed.test.js.map +1 -0
- package/lib/commonjs/utils/handleroffset-direction.js +5 -5
- package/lib/commonjs/utils/handleroffset-direction.js.map +1 -1
- package/lib/commonjs/utils/handleroffset-direction.test.js +46 -0
- package/lib/commonjs/utils/handleroffset-direction.test.js.map +1 -0
- package/lib/commonjs/utils/index.test.js +6 -6
- package/lib/commonjs/utils/index.test.js.map +1 -1
- package/lib/module/{layouts → components}/BaseLayout.js +6 -16
- package/lib/module/components/BaseLayout.js.map +1 -0
- package/lib/module/components/Carousel.js +24 -42
- package/lib/module/components/Carousel.js.map +1 -1
- package/lib/module/components/ItemRenderer.js +62 -0
- package/lib/module/components/ItemRenderer.js.map +1 -0
- package/lib/module/components/ScrollViewGesture.js +53 -34
- package/lib/module/components/ScrollViewGesture.js.map +1 -1
- package/lib/module/components/rnr-demo.test.js +33 -0
- package/lib/module/components/rnr-demo.test.js.map +1 -0
- package/lib/module/hooks/useCarouselController.js +12 -11
- package/lib/module/hooks/useCarouselController.js.map +1 -1
- package/lib/module/hooks/useCommonVariables.js +38 -8
- package/lib/module/hooks/useCommonVariables.js.map +1 -1
- package/lib/module/hooks/useCommonVariables.test.js +34 -0
- package/lib/module/hooks/useCommonVariables.test.js.map +1 -0
- package/lib/module/hooks/useLayoutConfig.js.map +1 -1
- package/lib/module/hooks/useOffsetX.js +9 -6
- package/lib/module/hooks/useOffsetX.js.map +1 -1
- package/lib/module/hooks/useOffsetX.test.js +48 -0
- package/lib/module/hooks/useOffsetX.test.js.map +1 -0
- package/lib/module/hooks/usePanGestureProxy.js +71 -0
- package/lib/module/hooks/usePanGestureProxy.js.map +1 -0
- package/lib/module/hooks/usePanGestureProxy.test.js +383 -0
- package/lib/module/hooks/usePanGestureProxy.test.js.map +1 -0
- package/lib/module/hooks/useUpdateGestureConfig.js.map +1 -1
- package/lib/module/hooks/useVisibleRanges.js +47 -19
- package/lib/module/hooks/useVisibleRanges.js.map +1 -1
- package/lib/module/hooks/useVisibleRanges.test.js +157 -0
- package/lib/module/hooks/useVisibleRanges.test.js.map +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/utils/{computeNewIndexWhenDataChanges.js → compute-offset-if-data-changed.js} +2 -2
- package/lib/module/utils/compute-offset-if-data-changed.js.map +1 -0
- package/lib/module/utils/compute-offset-if-data-changed.test.js +27 -0
- package/lib/module/utils/compute-offset-if-data-changed.test.js.map +1 -0
- package/lib/module/utils/compute-offset-if-size-changed.js +11 -0
- package/lib/module/utils/compute-offset-if-size-changed.js.map +1 -0
- package/lib/module/utils/compute-offset-if-size-changed.test.js +69 -0
- package/lib/module/utils/compute-offset-if-size-changed.test.js.map +1 -0
- package/lib/module/utils/handleroffset-direction.js +5 -5
- package/lib/module/utils/handleroffset-direction.js.map +1 -1
- package/lib/module/utils/handleroffset-direction.test.js +41 -0
- package/lib/module/utils/handleroffset-direction.test.js.map +1 -0
- package/lib/module/utils/index.test.js +6 -6
- package/lib/module/utils/index.test.js.map +1 -1
- package/lib/typescript/components/ItemRenderer.d.ts +22 -0
- package/lib/typescript/components/ScrollViewGesture.d.ts +1 -1
- package/lib/typescript/components/rnr-demo.test.d.ts +1 -0
- package/lib/typescript/hooks/useCarouselController.d.ts +3 -2
- package/lib/typescript/hooks/useCommonVariables.test.d.ts +1 -0
- package/lib/typescript/hooks/useLayoutConfig.d.ts +1 -1
- package/lib/typescript/hooks/useOffsetX.test.d.ts +1 -0
- package/lib/typescript/hooks/usePanGestureProxy.d.ts +9 -0
- package/lib/typescript/hooks/usePanGestureProxy.test.d.ts +1 -0
- package/lib/typescript/hooks/useUpdateGestureConfig.d.ts +3 -2
- package/lib/typescript/hooks/useVisibleRanges.d.ts +8 -4
- package/lib/typescript/hooks/useVisibleRanges.test.d.ts +1 -0
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/types.d.ts +13 -4
- package/lib/typescript/utils/{computeNewIndexWhenDataChanges.d.ts → compute-offset-if-data-changed.d.ts} +1 -1
- package/lib/typescript/utils/compute-offset-if-data-changed.test.d.ts +1 -0
- package/lib/typescript/utils/compute-offset-if-size-changed.d.ts +5 -0
- package/lib/typescript/utils/compute-offset-if-size-changed.test.d.ts +1 -0
- package/lib/typescript/utils/handleroffset-direction.d.ts +2 -1
- package/lib/typescript/utils/handleroffset-direction.test.d.ts +1 -0
- package/package.json +16 -59
- package/src/{layouts → components}/BaseLayout.tsx +7 -35
- package/src/components/Carousel.tsx +24 -58
- package/src/components/ItemRenderer.tsx +105 -0
- package/src/components/ScrollViewGesture.tsx +74 -49
- package/src/components/rnr-demo.test.tsx +43 -0
- package/src/hooks/useCarouselController.tsx +24 -21
- package/src/hooks/useCommonVariables.test.tsx +41 -0
- package/src/hooks/useCommonVariables.ts +35 -10
- package/src/hooks/useLayoutConfig.ts +1 -1
- package/src/hooks/useOffsetX.test.ts +54 -0
- package/src/hooks/useOffsetX.ts +33 -31
- package/src/hooks/usePanGestureProxy.test.tsx +376 -0
- package/src/hooks/usePanGestureProxy.ts +110 -0
- package/src/hooks/useUpdateGestureConfig.ts +4 -2
- package/src/hooks/useVisibleRanges.test.tsx +179 -0
- package/src/hooks/useVisibleRanges.tsx +72 -24
- package/src/index.tsx +2 -0
- package/src/types.ts +13 -4
- package/src/utils/compute-offset-if-data-changed.test.ts +30 -0
- package/src/utils/{computeNewIndexWhenDataChanges.ts → compute-offset-if-data-changed.ts} +1 -1
- package/src/utils/compute-offset-if-size-changed.test.ts +78 -0
- package/src/utils/compute-offset-if-size-changed.ts +11 -0
- package/src/utils/handleroffset-direction.test.ts +52 -0
- package/src/utils/handleroffset-direction.ts +12 -9
- package/src/utils/index.test.ts +6 -6
- package/lib/commonjs/layouts/BaseLayout.js.map +0 -1
- package/lib/commonjs/layouts/ParallaxLayout.js +0 -84
- package/lib/commonjs/layouts/ParallaxLayout.js.map +0 -1
- package/lib/commonjs/utils/computeNewIndexWhenDataChanges.js.map +0 -1
- package/lib/module/layouts/BaseLayout.js.map +0 -1
- package/lib/module/layouts/ParallaxLayout.js +0 -61
- package/lib/module/layouts/ParallaxLayout.js.map +0 -1
- package/lib/module/utils/computeNewIndexWhenDataChanges.js.map +0 -1
- package/lib/typescript/layouts/ParallaxLayout.d.ts +0 -13
- package/src/layouts/ParallaxLayout.tsx +0 -141
- /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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
|
25
|
+
windowSize: _windowSize,
|
|
26
|
+
loop,
|
|
20
27
|
} = options;
|
|
21
28
|
|
|
22
|
-
const 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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
42
|
-
negativeRange
|
|
43
|
-
|
|
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
|
-
|
|
46
|
-
|
|
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
|
-
*
|
|
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
|
|
187
|
+
* On scroll start
|
|
179
188
|
*/
|
|
180
|
-
|
|
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
|
+
});
|
|
@@ -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,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
|
-
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
|
17
|
+
return Math.sign(handlerOffset.value) as -1 | 1;
|
|
15
18
|
}
|
package/src/utils/index.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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"]}
|