react-native-reanimated-carousel 5.0.0-beta.5 → 5.0.0-beta.7

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 (55) hide show
  1. package/README.md +28 -6
  2. package/lib/commonjs/components/CarouselLayout.js +1 -1
  3. package/lib/commonjs/components/CarouselLayout.js.map +1 -1
  4. package/lib/commonjs/components/ItemLayout.js +1 -1
  5. package/lib/commonjs/components/ItemLayout.js.map +1 -1
  6. package/lib/commonjs/components/ItemRenderer.js +1 -1
  7. package/lib/commonjs/components/ItemRenderer.js.map +1 -1
  8. package/lib/commonjs/components/ScrollViewGesture.js +1 -1
  9. package/lib/commonjs/components/ScrollViewGesture.js.map +1 -1
  10. package/lib/commonjs/hooks/useOnProgressChange.js +1 -1
  11. package/lib/commonjs/hooks/useOnProgressChange.js.map +1 -1
  12. package/lib/commonjs/hooks/usePropsErrorBoundary.js +1 -1
  13. package/lib/commonjs/hooks/usePropsErrorBoundary.js.map +1 -1
  14. package/lib/commonjs/hooks/useVisibleRanges.js +1 -1
  15. package/lib/commonjs/hooks/useVisibleRanges.js.map +1 -1
  16. package/lib/module/components/CarouselLayout.js +1 -1
  17. package/lib/module/components/CarouselLayout.js.map +1 -1
  18. package/lib/module/components/ItemLayout.js +1 -1
  19. package/lib/module/components/ItemLayout.js.map +1 -1
  20. package/lib/module/components/ItemRenderer.js +1 -1
  21. package/lib/module/components/ItemRenderer.js.map +1 -1
  22. package/lib/module/components/ScrollViewGesture.js +1 -1
  23. package/lib/module/components/ScrollViewGesture.js.map +1 -1
  24. package/lib/module/hooks/useOnProgressChange.js +1 -1
  25. package/lib/module/hooks/useOnProgressChange.js.map +1 -1
  26. package/lib/module/hooks/usePropsErrorBoundary.js +1 -1
  27. package/lib/module/hooks/usePropsErrorBoundary.js.map +1 -1
  28. package/lib/module/hooks/useVisibleRanges.js +1 -1
  29. package/lib/module/hooks/useVisibleRanges.js.map +1 -1
  30. package/lib/typescript/components/CarouselLayout.d.ts +11 -0
  31. package/lib/typescript/components/CarouselLayout.d.ts.map +1 -1
  32. package/lib/typescript/components/ItemLayout.d.ts +5 -0
  33. package/lib/typescript/components/ItemLayout.d.ts.map +1 -1
  34. package/lib/typescript/components/ItemRenderer.d.ts +1 -0
  35. package/lib/typescript/components/ItemRenderer.d.ts.map +1 -1
  36. package/lib/typescript/components/ScrollViewGesture.d.ts.map +1 -1
  37. package/lib/typescript/hooks/usePropsErrorBoundary.d.ts.map +1 -1
  38. package/lib/typescript/hooks/useVisibleRanges.d.ts +6 -0
  39. package/lib/typescript/hooks/useVisibleRanges.d.ts.map +1 -1
  40. package/lib/typescript/types.d.ts +1 -1
  41. package/package.json +13 -4
  42. package/src/components/Carousel.test.tsx +152 -0
  43. package/src/components/CarouselLayout.tsx +52 -8
  44. package/src/components/ItemLayout.tsx +31 -7
  45. package/src/components/ItemRenderer.tsx +11 -6
  46. package/src/components/ScrollViewGesture.test.tsx +155 -0
  47. package/src/components/ScrollViewGesture.tsx +8 -11
  48. package/src/components/issue-899-parallax-reverse-loop.test.tsx +131 -0
  49. package/src/hooks/useOnProgressChange.test.tsx +71 -8
  50. package/src/hooks/useOnProgressChange.ts +1 -1
  51. package/src/hooks/usePropsErrorBoundary.test.tsx +57 -0
  52. package/src/hooks/usePropsErrorBoundary.ts +4 -3
  53. package/src/hooks/useVisibleRanges.test.tsx +29 -0
  54. package/src/hooks/useVisibleRanges.tsx +80 -49
  55. package/src/types.ts +1 -1
@@ -11,6 +11,83 @@ export interface VisibleRanges {
11
11
 
12
12
  export type IVisibleRanges = SharedValue<VisibleRanges>;
13
13
 
14
+ function normalizeWindowSize(total: number, windowSize?: number) {
15
+ "worklet";
16
+
17
+ return typeof windowSize === "number" && Number.isFinite(windowSize) && windowSize > 0
18
+ ? windowSize
19
+ : total;
20
+ }
21
+
22
+ function normalizeLoopIndex(currentIndex: number, total: number) {
23
+ "worklet";
24
+
25
+ return currentIndex < 0 ? (currentIndex % total) + total : currentIndex;
26
+ }
27
+
28
+ export function computeVisibleRanges(params: {
29
+ total: number;
30
+ windowSize?: number;
31
+ currentIndex: number;
32
+ loop?: boolean;
33
+ }): VisibleRanges {
34
+ "worklet";
35
+
36
+ const { total = 0, loop } = params;
37
+ const windowSize = normalizeWindowSize(total, params.windowSize);
38
+
39
+ if (total <= 0) {
40
+ return {
41
+ negativeRange: [0, 0],
42
+ positiveRange: [0, -1],
43
+ };
44
+ }
45
+
46
+ if (loop && windowSize >= total) {
47
+ return {
48
+ negativeRange: [0, 0],
49
+ positiveRange: [0, total - 1],
50
+ };
51
+ }
52
+
53
+ const positiveCount = Math.round(windowSize / 2);
54
+ const negativeCount = windowSize - positiveCount;
55
+
56
+ let currentIndex = params.currentIndex;
57
+ if (!Number.isFinite(currentIndex)) currentIndex = 0;
58
+
59
+ if (!loop) {
60
+ currentIndex = Math.max(0, Math.min(total - 1, currentIndex));
61
+ return {
62
+ negativeRange: [Math.max(0, currentIndex - (windowSize - 1)), currentIndex],
63
+ positiveRange: [currentIndex, Math.min(total - 1, currentIndex + (windowSize - 1))],
64
+ };
65
+ }
66
+
67
+ currentIndex = normalizeLoopIndex(currentIndex, total);
68
+
69
+ const negativeRange: Range = [
70
+ (currentIndex - negativeCount + total) % total,
71
+ (currentIndex - 1 + total) % total,
72
+ ];
73
+
74
+ const positiveRange: Range = [
75
+ (currentIndex + total) % total,
76
+ (currentIndex + positiveCount + total) % total,
77
+ ];
78
+
79
+ if (negativeRange[0] < total && negativeRange[0] > negativeRange[1]) {
80
+ negativeRange[1] = total - 1;
81
+ positiveRange[0] = 0;
82
+ }
83
+ if (positiveRange[0] > positiveRange[1]) {
84
+ negativeRange[1] = total - 1;
85
+ positiveRange[0] = 0;
86
+ }
87
+
88
+ return { negativeRange, positiveRange };
89
+ }
90
+
14
91
  export function useVisibleRanges(options: {
15
92
  total: number;
16
93
  viewSize: number;
@@ -20,18 +97,12 @@ export function useVisibleRanges(options: {
20
97
  }): IVisibleRanges {
21
98
  const { total = 0, viewSize, translation, windowSize: _windowSize, loop } = options;
22
99
 
23
- const windowSize =
24
- typeof _windowSize === "number" && Number.isFinite(_windowSize) && _windowSize > 0
25
- ? _windowSize
26
- : total;
100
+ const windowSize = normalizeWindowSize(total, _windowSize);
27
101
  const cachedRanges = useRef<VisibleRanges | null>(null);
28
102
 
29
103
  const ranges = useDerivedValue(() => {
30
104
  if (total <= 0) {
31
- return {
32
- negativeRange: [0, 0] as Range,
33
- positiveRange: [0, -1] as Range,
34
- };
105
+ return computeVisibleRanges({ total, currentIndex: 0, windowSize, loop });
35
106
  }
36
107
 
37
108
  // Prevent division by zero when viewSize is not yet measured
@@ -42,50 +113,10 @@ export function useVisibleRanges(options: {
42
113
  };
43
114
  }
44
115
 
45
- const positiveCount = Math.round(windowSize / 2);
46
- const negativeCount = windowSize - positiveCount;
47
-
48
116
  let currentIndex = Math.round(-translation.value / viewSize);
49
117
  if (!Number.isFinite(currentIndex)) currentIndex = 0;
50
118
 
51
- let newRanges: VisibleRanges;
52
-
53
- if (!loop) {
54
- // Clamp currentIndex to valid range [0, total-1] for non-loop mode
55
- // When overdragging right, translation.value becomes positive, making currentIndex negative
56
- currentIndex = Math.max(0, Math.min(total - 1, currentIndex));
57
-
58
- // Adjusting negative range if the carousel is not loopable.
59
- // So, It will be only displayed the positive items.
60
- newRanges = {
61
- negativeRange: [Math.max(0, currentIndex - (windowSize - 1)), currentIndex],
62
- positiveRange: [currentIndex, Math.min(total - 1, currentIndex + (windowSize - 1))],
63
- };
64
- } else {
65
- currentIndex = currentIndex < 0 ? (currentIndex % total) + total : currentIndex;
66
-
67
- const negativeRange: Range = [
68
- (currentIndex - negativeCount + total) % total,
69
- (currentIndex - 1 + total) % total,
70
- ];
71
-
72
- const positiveRange: Range = [
73
- (currentIndex + total) % total,
74
- (currentIndex + positiveCount + total) % total,
75
- ];
76
-
77
- if (negativeRange[0] < total && negativeRange[0] > negativeRange[1]) {
78
- negativeRange[1] = total - 1;
79
- positiveRange[0] = 0;
80
- }
81
- if (positiveRange[0] > positiveRange[1]) {
82
- negativeRange[1] = total - 1;
83
- positiveRange[0] = 0;
84
- }
85
-
86
- // console.log({ negativeRange, positiveRange ,total,windowSize,a:total <= _windowSize})
87
- newRanges = { negativeRange, positiveRange };
88
- }
119
+ const newRanges = computeVisibleRanges({ total, windowSize, currentIndex, loop });
89
120
 
90
121
  if (
91
122
  cachedRanges.current &&
package/src/types.ts CHANGED
@@ -242,7 +242,7 @@ export type TCarouselProps<T = any> = {
242
242
  customConfig?: CustomConfig | (() => CustomConfig);
243
243
  /**
244
244
  * Custom animations.
245
- * Must use `worklet`, Details: https://docs.swmansion.com/react-native-reanimated/docs/2.2.0/worklets/
245
+ * Must be worklet-compatible. See https://docs.swmansion.com/react-native-reanimated/docs/guides/worklets/
246
246
  * @test_coverage ✅ tested in Carousel.test.tsx > should apply the custom animation
247
247
  */
248
248
  customAnimation?: (value: number, index: number) => ViewStyle;