react-native-reanimated-carousel 5.0.0-beta.6 → 5.0.0-beta.8

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 (68) hide show
  1. package/README.md +32 -2
  2. package/lib/commonjs/components/CarouselLayout.js +1 -1
  3. package/lib/commonjs/components/CarouselLayout.js.map +1 -1
  4. package/lib/commonjs/components/ItemRenderer.js +1 -1
  5. package/lib/commonjs/components/ItemRenderer.js.map +1 -1
  6. package/lib/commonjs/components/ScrollViewGesture.js +1 -1
  7. package/lib/commonjs/components/ScrollViewGesture.js.map +1 -1
  8. package/lib/commonjs/hooks/useOnProgressChange.js +1 -1
  9. package/lib/commonjs/hooks/useOnProgressChange.js.map +1 -1
  10. package/lib/commonjs/hooks/usePropsErrorBoundary.js +1 -1
  11. package/lib/commonjs/hooks/usePropsErrorBoundary.js.map +1 -1
  12. package/lib/commonjs/hooks/useVisibleRanges.js +1 -1
  13. package/lib/commonjs/hooks/useVisibleRanges.js.map +1 -1
  14. package/lib/module/components/CarouselLayout.js +1 -1
  15. package/lib/module/components/CarouselLayout.js.map +1 -1
  16. package/lib/module/components/ItemRenderer.js +1 -1
  17. package/lib/module/components/ItemRenderer.js.map +1 -1
  18. package/lib/module/components/ScrollViewGesture.js +1 -1
  19. package/lib/module/components/ScrollViewGesture.js.map +1 -1
  20. package/lib/module/hooks/useOnProgressChange.js +1 -1
  21. package/lib/module/hooks/useOnProgressChange.js.map +1 -1
  22. package/lib/module/hooks/usePropsErrorBoundary.js +1 -1
  23. package/lib/module/hooks/usePropsErrorBoundary.js.map +1 -1
  24. package/lib/module/hooks/useVisibleRanges.js +1 -1
  25. package/lib/module/hooks/useVisibleRanges.js.map +1 -1
  26. package/lib/typescript/components/CarouselLayout.d.ts.map +1 -1
  27. package/lib/typescript/components/ItemRenderer.d.ts +1 -0
  28. package/lib/typescript/components/ItemRenderer.d.ts.map +1 -1
  29. package/lib/typescript/components/ScrollViewGesture.d.ts.map +1 -1
  30. package/lib/typescript/hooks/usePropsErrorBoundary.d.ts.map +1 -1
  31. package/lib/typescript/hooks/useVisibleRanges.d.ts +6 -0
  32. package/lib/typescript/hooks/useVisibleRanges.d.ts.map +1 -1
  33. package/lib/typescript/types.d.ts +1 -1
  34. package/package.json +4 -2
  35. package/src/components/CarouselLayout.tsx +4 -4
  36. package/src/components/ItemRenderer.tsx +11 -6
  37. package/src/components/ScrollViewGesture.tsx +8 -11
  38. package/src/hooks/useOnProgressChange.ts +1 -1
  39. package/src/hooks/usePropsErrorBoundary.ts +4 -3
  40. package/src/hooks/useVisibleRanges.tsx +80 -54
  41. package/src/types.ts +1 -1
  42. package/src/components/Carousel.test.tsx +0 -1215
  43. package/src/components/LazyView.test.tsx +0 -61
  44. package/src/components/Pagination/Pagination.test.tsx +0 -178
  45. package/src/components/rnr-demo.test.tsx +0 -53
  46. package/src/hooks/useAutoPlay.test.ts +0 -194
  47. package/src/hooks/useCarouselController.test.tsx +0 -1158
  48. package/src/hooks/useCheckMounted.test.ts +0 -47
  49. package/src/hooks/useCommonVariables.test.tsx +0 -384
  50. package/src/hooks/useInitProps.test.tsx +0 -134
  51. package/src/hooks/useLayoutConfig.test.tsx +0 -247
  52. package/src/hooks/useOffsetX.test.ts +0 -54
  53. package/src/hooks/useOnProgressChange.test.tsx +0 -207
  54. package/src/hooks/usePanGestureProxy.test.tsx +0 -368
  55. package/src/hooks/useUpdateGestureConfig.test.ts +0 -89
  56. package/src/hooks/useVisibleRanges.test.tsx +0 -347
  57. package/src/layouts/parallax.test.ts +0 -239
  58. package/src/layouts/stack.test.ts +0 -252
  59. package/src/store/index.test.tsx +0 -314
  60. package/src/utils/compute-gesture-translation.test.ts +0 -70
  61. package/src/utils/compute-offset-if-data-changed.test.ts +0 -133
  62. package/src/utils/compute-offset-if-size-changed.test.ts +0 -78
  63. package/src/utils/computed-with-auto-fill-data.test.ts +0 -298
  64. package/src/utils/deal-with-animation.test.ts +0 -181
  65. package/src/utils/handleroffset-direction.test.ts +0 -124
  66. package/src/utils/index.test.ts +0 -90
  67. package/src/utils/log.test.ts +0 -134
  68. package/src/utils/sanitize-animation-style.test.ts +0 -40
@@ -1,61 +0,0 @@
1
- import { render } from "@testing-library/react-native";
2
- import React from "react";
3
- import { Text } from "react-native";
4
-
5
- import { LazyView } from "./LazyView";
6
-
7
- describe("LazyView", () => {
8
- it("should render children when shouldUpdate is true", () => {
9
- const { getByText } = render(
10
- <LazyView shouldUpdate={true}>
11
- <Text>Test Child</Text>
12
- </LazyView>
13
- );
14
-
15
- expect(getByText("Test Child")).toBeTruthy();
16
- });
17
-
18
- it("should not render children when shouldUpdate is false", () => {
19
- const { queryByText } = render(
20
- <LazyView shouldUpdate={false}>
21
- <Text>Test Child</Text>
22
- </LazyView>
23
- );
24
-
25
- expect(queryByText("Test Child")).toBeNull();
26
- });
27
-
28
- it("should render empty fragment when shouldUpdate is false", () => {
29
- const { toJSON } = render(
30
- <LazyView shouldUpdate={false}>
31
- <Text>Test Child</Text>
32
- </LazyView>
33
- );
34
-
35
- expect(toJSON()).toBeNull();
36
- });
37
-
38
- it("should handle multiple children when shouldUpdate is true", () => {
39
- const { getByText } = render(
40
- <LazyView shouldUpdate={true}>
41
- <Text>First Child</Text>
42
- <Text>Second Child</Text>
43
- </LazyView>
44
- );
45
-
46
- expect(getByText("First Child")).toBeTruthy();
47
- expect(getByText("Second Child")).toBeTruthy();
48
- });
49
-
50
- it("should not render multiple children when shouldUpdate is false", () => {
51
- const { queryByText } = render(
52
- <LazyView shouldUpdate={false}>
53
- <Text>First Child</Text>
54
- <Text>Second Child</Text>
55
- </LazyView>
56
- );
57
-
58
- expect(queryByText("First Child")).toBeNull();
59
- expect(queryByText("Second Child")).toBeNull();
60
- });
61
- });
@@ -1,178 +0,0 @@
1
- import { act, fireEvent, render } from "@testing-library/react-native";
2
- import { View } from "react-native";
3
- import { useSharedValue } from "react-native-reanimated";
4
-
5
- import { Pagination } from ".";
6
-
7
- jest.mock("react-native-worklets", () => ({
8
- scheduleOnRN: (fn: (...args: unknown[]) => void, ...args: unknown[]) => fn(...args),
9
- }));
10
-
11
- // Use fake timers so the reanimated mapper's mockedRequestAnimationFrame
12
- // (a setTimeout-based RAF) doesn't fire outside of act().
13
- beforeEach(() => {
14
- jest.useFakeTimers();
15
- });
16
-
17
- afterEach(() => {
18
- jest.useRealTimers();
19
- });
20
-
21
- describe("Pagination.Basic", () => {
22
- it("throws when size/dot width/height are non-number", () => {
23
- const Test = () => {
24
- const progress = useSharedValue(0);
25
- return (
26
- <Pagination.Basic
27
- data={[1, 2]}
28
- progress={progress}
29
- // @ts-expect-error intentional invalid type
30
- size={"12px"}
31
- />
32
- );
33
- };
34
-
35
- expect(() => render(<Test />)).toThrow("size/width/height must be a number");
36
- });
37
-
38
- it("renders dots and calls onPress", async () => {
39
- const handlePress = jest.fn();
40
- const Test = () => {
41
- const progress = useSharedValue(0);
42
- return (
43
- <Pagination.Basic
44
- data={[1, 2, 3]}
45
- progress={progress}
46
- onPress={handlePress}
47
- carouselName="Demo"
48
- />
49
- );
50
- };
51
-
52
- const { UNSAFE_root } = render(<Test />);
53
- await act(async () => {
54
- jest.advanceTimersByTime(100);
55
- });
56
-
57
- const buttons = UNSAFE_root.findAll(
58
- (node) =>
59
- node?.props?.accessibilityRole === "button" &&
60
- typeof node?.props?.accessibilityLabel === "string" &&
61
- node.props.accessibilityLabel.startsWith("Slide ")
62
- );
63
-
64
- const uniqueByLabel = Array.from(
65
- new Map(buttons.map((b) => [b.props.accessibilityLabel, b])).values()
66
- );
67
-
68
- expect(uniqueByLabel).toHaveLength(3);
69
-
70
- await act(async () => {
71
- fireEvent.press(uniqueByLabel[1]);
72
- jest.advanceTimersByTime(100);
73
- });
74
- expect(handlePress).toHaveBeenCalledWith(1);
75
- });
76
-
77
- it("does not include undefined in default accessibilityLabel when carouselName is omitted", async () => {
78
- const Test = () => {
79
- const progress = useSharedValue(0);
80
- return <Pagination.Basic data={[1, 2]} progress={progress} />;
81
- };
82
-
83
- const { UNSAFE_root } = render(<Test />);
84
- await act(async () => {
85
- jest.advanceTimersByTime(100);
86
- });
87
-
88
- const buttons = UNSAFE_root.findAll(
89
- (node) =>
90
- node?.props?.accessibilityRole === "button" &&
91
- typeof node?.props?.accessibilityLabel === "string" &&
92
- node.props.accessibilityLabel.startsWith("Slide ")
93
- );
94
-
95
- const uniqueByLabel = Array.from(
96
- new Map(buttons.map((b) => [b.props.accessibilityLabel, b])).values()
97
- );
98
-
99
- expect(uniqueByLabel[0].props.accessibilityLabel).toBe("Slide 1 of 2");
100
- expect(uniqueByLabel[0].props.accessibilityLabel).not.toContain("undefined");
101
- });
102
- });
103
-
104
- describe("Pagination.Custom", () => {
105
- it("throws when any size-related prop is non-number", () => {
106
- const Test = () => {
107
- const progress = useSharedValue(0);
108
- return (
109
- <Pagination.Custom
110
- data={[1]}
111
- progress={progress}
112
- // @ts-expect-error intentional invalid type
113
- activeDotStyle={{ width: "10px" }}
114
- />
115
- );
116
- };
117
-
118
- expect(() => render(<Test />)).toThrow("size/width/height must be a number");
119
- });
120
-
121
- it("uses max item dimensions for container min sizes", async () => {
122
- const Test = () => {
123
- const progress = useSharedValue(0);
124
- return (
125
- <Pagination.Custom
126
- data={[1, 2]}
127
- progress={progress}
128
- size={12}
129
- dotStyle={{ width: 14, height: 8 }}
130
- activeDotStyle={{ width: 16, height: 20 }}
131
- />
132
- );
133
- };
134
-
135
- const { UNSAFE_root } = render(<Test />);
136
- await act(async () => {
137
- jest.advanceTimersByTime(100);
138
- });
139
-
140
- // @ts-expect-error
141
- const container = UNSAFE_root.findByType(View);
142
- const flattened = Array.isArray(container.props.style)
143
- ? Object.assign({}, ...container.props.style.filter(Boolean))
144
- : container.props.style;
145
-
146
- expect(flattened.minWidth).toBe(16);
147
- expect(flattened.minHeight).toBe(20);
148
- });
149
-
150
- it("allows overriding pagination item accessibility props", async () => {
151
- const Test = () => {
152
- const progress = useSharedValue(0);
153
- return (
154
- <Pagination.Custom
155
- data={[1, 2]}
156
- progress={progress}
157
- paginationItemAccessibility={(index: number, length: number) => ({
158
- accessibilityLabel: `Page ${index + 1}/${length}`,
159
- accessibilityHint: `Jump to ${index + 1}`,
160
- accessibilityRole: "link",
161
- })}
162
- />
163
- );
164
- };
165
-
166
- const { UNSAFE_root } = render(<Test />);
167
- await act(async () => {
168
- jest.advanceTimersByTime(100);
169
- });
170
-
171
- const item = UNSAFE_root.find(
172
- (node) =>
173
- node?.props?.accessibilityLabel === "Page 1/2" && node?.props?.accessibilityRole === "link"
174
- );
175
-
176
- expect(item.props.accessibilityHint).toBe("Jump to 1");
177
- });
178
- });
@@ -1,53 +0,0 @@
1
- import { render } from "@testing-library/react-native";
2
- import type { FC } from "react";
3
- import React from "react";
4
- import Animated, { useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated";
5
-
6
- describe("Carousel Animations", () => {
7
- beforeEach(() => {
8
- jest.useFakeTimers();
9
- });
10
-
11
- afterEach(() => {
12
- jest.runOnlyPendingTimers();
13
- jest.useRealTimers();
14
- });
15
-
16
- it("animates opacity with timing", () => {
17
- const TestComponent: FC<{ value: number }> = ({ value }) => {
18
- const sharedValue = useSharedValue(value);
19
-
20
- // Using withTiming to wrap the value change, so it can be tested
21
- const animatedStyle = useAnimatedStyle(() => ({
22
- opacity: withTiming(sharedValue.value, { duration: 500 }),
23
- }));
24
-
25
- // When the prop changes, update the shared value
26
- React.useEffect(() => {
27
- sharedValue.value = value;
28
- }, [value, sharedValue]);
29
-
30
- return <Animated.View testID="animated-view" style={animatedStyle} />;
31
- };
32
-
33
- const initialValue = 0;
34
- const updatedValue = 1;
35
-
36
- const { getByTestId, rerender } = render(<TestComponent value={initialValue} />);
37
- const view = getByTestId("animated-view");
38
-
39
- // Verify the initial state
40
- expect(view).toHaveAnimatedStyle({ opacity: initialValue });
41
-
42
- // Trigger the value change
43
- rerender(<TestComponent value={updatedValue} />);
44
-
45
- // Advance the animation to the middle point
46
- jest.advanceTimersByTime(250);
47
- expect(view).toHaveAnimatedStyle({ opacity: 0.5 }); // Animation middle value
48
-
49
- // Advance the animation to the completion
50
- jest.advanceTimersByTime(250);
51
- expect(view).toHaveAnimatedStyle({ opacity: updatedValue }); // Animation completion
52
- });
53
- });
@@ -1,194 +0,0 @@
1
- import { act, renderHook } from "@testing-library/react-hooks";
2
-
3
- import { useAutoPlay } from "./useAutoPlay";
4
-
5
- describe("useAutoPlay", () => {
6
- // Mock timer
7
- beforeEach(() => {
8
- jest.useFakeTimers();
9
- jest.clearAllMocks();
10
- });
11
-
12
- afterEach(() => {
13
- jest.clearAllTimers();
14
- jest.useRealTimers();
15
- });
16
-
17
- // Mock carousel controller
18
- const mockCarouselController = {
19
- prev: jest.fn(),
20
- next: jest.fn(),
21
- getCurrentIndex: jest.fn(),
22
- getSharedIndex: jest.fn(),
23
- scrollTo: jest.fn(),
24
- };
25
-
26
- it("should start autoplay when autoPlay is true", () => {
27
- renderHook(() =>
28
- useAutoPlay({
29
- autoPlay: true,
30
- autoPlayInterval: 1000,
31
- carouselController: mockCarouselController,
32
- })
33
- );
34
-
35
- act(() => {
36
- jest.runOnlyPendingTimers();
37
- });
38
-
39
- expect(mockCarouselController.next).toHaveBeenCalledTimes(1);
40
- expect(mockCarouselController.next).toHaveBeenCalledWith(
41
- expect.objectContaining({
42
- onFinished: expect.any(Function),
43
- })
44
- );
45
- });
46
-
47
- it("should not start autoplay when autoPlay is false", () => {
48
- renderHook(() =>
49
- useAutoPlay({
50
- autoPlay: false,
51
- autoPlayInterval: 1000,
52
- carouselController: mockCarouselController,
53
- })
54
- );
55
-
56
- act(() => {
57
- jest.runOnlyPendingTimers();
58
- });
59
-
60
- expect(mockCarouselController.next).not.toHaveBeenCalled();
61
- });
62
-
63
- it("should play in reverse when autoPlayReverse is true", () => {
64
- renderHook(() =>
65
- useAutoPlay({
66
- autoPlay: true,
67
- autoPlayReverse: true,
68
- autoPlayInterval: 1000,
69
- carouselController: mockCarouselController,
70
- })
71
- );
72
-
73
- act(() => {
74
- jest.runOnlyPendingTimers();
75
- });
76
-
77
- expect(mockCarouselController.prev).toHaveBeenCalledTimes(1);
78
- expect(mockCarouselController.next).not.toHaveBeenCalled();
79
- });
80
-
81
- it("should clear timer on unmount", () => {
82
- const { unmount } = renderHook(() =>
83
- useAutoPlay({
84
- autoPlay: true,
85
- autoPlayInterval: 1000,
86
- carouselController: mockCarouselController,
87
- })
88
- );
89
-
90
- // Run the timer once to ensure it's set
91
- act(() => {
92
- jest.runOnlyPendingTimers();
93
- });
94
-
95
- // Clear previous call records
96
- mockCarouselController.next.mockClear();
97
-
98
- // Then unmount the component and run the timer again
99
- act(() => {
100
- unmount();
101
- jest.runOnlyPendingTimers();
102
- });
103
-
104
- expect(mockCarouselController.next).not.toHaveBeenCalled();
105
- });
106
-
107
- it("should pause and resume autoplay", () => {
108
- const { result } = renderHook(() =>
109
- useAutoPlay({
110
- autoPlay: true,
111
- autoPlayInterval: 1000,
112
- carouselController: mockCarouselController,
113
- })
114
- );
115
-
116
- // Run the timer once to ensure it's set
117
- act(() => {
118
- jest.runOnlyPendingTimers();
119
- });
120
-
121
- // Clear previous call records
122
- mockCarouselController.next.mockClear();
123
-
124
- // Pause autoplay
125
- act(() => {
126
- result.current.pause();
127
- jest.runOnlyPendingTimers();
128
- });
129
-
130
- expect(mockCarouselController.next).not.toHaveBeenCalled();
131
-
132
- // Resume autoplay
133
- act(() => {
134
- result.current.start();
135
- jest.runOnlyPendingTimers();
136
- });
137
-
138
- expect(mockCarouselController.next).toHaveBeenCalledTimes(1);
139
- });
140
-
141
- it("should respect autoPlayInterval timing", () => {
142
- renderHook(() =>
143
- useAutoPlay({
144
- autoPlay: true,
145
- autoPlayInterval: 2000,
146
- carouselController: mockCarouselController,
147
- })
148
- );
149
-
150
- // Advance less than interval
151
- act(() => {
152
- jest.advanceTimersByTime(1500);
153
- });
154
- expect(mockCarouselController.next).not.toHaveBeenCalled();
155
-
156
- // Advance to complete interval
157
- act(() => {
158
- jest.advanceTimersByTime(500);
159
- });
160
- expect(mockCarouselController.next).toHaveBeenCalledTimes(1);
161
- });
162
-
163
- it("should chain autoplay calls correctly", () => {
164
- renderHook(() =>
165
- useAutoPlay({
166
- autoPlay: true,
167
- autoPlayInterval: 1000,
168
- carouselController: mockCarouselController,
169
- })
170
- );
171
-
172
- // First interval
173
- act(() => {
174
- jest.runOnlyPendingTimers();
175
- });
176
- expect(mockCarouselController.next).toHaveBeenCalledTimes(1);
177
-
178
- // Trigger onFinished callback to start the next timer
179
- const onFinished = mockCarouselController.next.mock.calls[0][0].onFinished;
180
- act(() => {
181
- onFinished();
182
- jest.runOnlyPendingTimers();
183
- });
184
- expect(mockCarouselController.next).toHaveBeenCalledTimes(2);
185
-
186
- // Trigger onFinished callback to start the next timer
187
- const onFinished2 = mockCarouselController.next.mock.calls[1][0].onFinished;
188
- act(() => {
189
- onFinished2();
190
- jest.runOnlyPendingTimers();
191
- });
192
- expect(mockCarouselController.next).toHaveBeenCalledTimes(3);
193
- });
194
- });