Skip to content

Commit

Permalink
feat: add index parameter to customAnimation (#735)
Browse files Browse the repository at this point in the history
<!-- Is this PR related to an open issue? -->
<!-- GitHub: Fixes #0, Relates to #1, etc. -->

### Description

<!-- Summary of changes and why if no corresponding issue -->
#709

### Review

- [ ] I self-reviewed this PR

<!-- Call out any changes that you'd like people to review or feedback on -->

### Testing

- [ ] I added/updated tests
- [ ] I manually tested

<!-- Describe any manual testing -->
  • Loading branch information
dohooo authored Nov 29, 2024
1 parent 1e62129 commit 848f458
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 9 deletions.
5 changes: 5 additions & 0 deletions .changeset/modern-carpets-sleep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"react-native-reanimated-carousel": patch
---

This PR updates the customAnimation function signature to include an index parameter, allowing users to apply custom animations based on the item’s index.
59 changes: 55 additions & 4 deletions src/components/Carousel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { FC } from "react";
import React from "react";
import type { PanGesture } from "react-native-gesture-handler";
import { Gesture, State } from "react-native-gesture-handler";
import Animated, { useDerivedValue, useSharedValue } from "react-native-reanimated";
import Animated, { interpolate, useDerivedValue, useSharedValue } from "react-native-reanimated";
import type { ReactTestInstance } from "react-test-renderer";

import { act, render, waitFor } from "@testing-library/react-native";
Expand Down Expand Up @@ -301,7 +301,11 @@ describe("Test the real swipe behavior of Carousel to ensure it's working as exp

fireGestureHandler<PanGesture>(getByGestureTestId(gestureTestId), [
{ state: State.BEGAN, translationX: 0, velocityX: -5 },
{ state: State.ACTIVE, translationX: -slideWidth * 0.15, velocityX: -5 },
{
state: State.ACTIVE,
translationX: -slideWidth * 0.15,
velocityX: -5,
},
{ state: State.END, translationX: -slideWidth * 0.25, velocityX: -5 },
]);

Expand All @@ -314,8 +318,16 @@ describe("Test the real swipe behavior of Carousel to ensure it's working as exp

fireGestureHandler<PanGesture>(getByGestureTestId(gestureTestId), [
{ state: State.BEGAN, translationX: 0, velocityX: -1000 },
{ state: State.ACTIVE, translationX: -slideWidth * 0.15, velocityX: -1000 },
{ state: State.END, translationX: -slideWidth * 0.25, velocityX: -1000 },
{
state: State.ACTIVE,
translationX: -slideWidth * 0.15,
velocityX: -1000,
},
{
state: State.END,
translationX: -slideWidth * 0.25,
velocityX: -1000,
},
]);

await waitFor(() => expect(progress.current).toBe(1));
Expand Down Expand Up @@ -441,6 +453,45 @@ describe("Test the real swipe behavior of Carousel to ensure it's working as exp
}
});

it("`customAnimation` prop: should apply the custom animation", async () => {
const progress = { current: 0 };
const indexes: Record<number, number> = {};
const Wrapper = createCarousel(progress);
const { getByTestId } = render(
<Wrapper
customAnimation={(value: number, index: number) => {
"worklet";

indexes[index] = index;

const zIndex = interpolate(value, [-1, 0, 1], [10, 20, 30]);
const translateX = interpolate(value, [-2, 0, 1], [-slideWidth, 0, slideWidth]);

return {
transform: [{ translateX }],
zIndex,
};
}}
/>
);

await verifyInitialRender(getByTestId);

swipeToLeftOnce();
await waitFor(() => {
expect(progress.current).toBe(1);

expect(indexes).toMatchInlineSnapshot(`
{
"0": 0,
"1": 1,
"2": 2,
"3": 3,
}
`);
});
});

it("`overscrollEnabled` prop: should respect overscrollEnabled=false and prevent scrolling beyond bounds", async () => {
const containerWidth = slideWidth;
const containerHeight = containerWidth / 2;
Expand Down
7 changes: 4 additions & 3 deletions src/components/ItemLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import type { ViewStyle } from "react-native";
import type { SharedValue } from "react-native-reanimated";
import Animated, { useAnimatedStyle, useDerivedValue } from "react-native-reanimated";

import { TCarouselProps } from "src/types";
import type { IOpts } from "../hooks/useOffsetX";
import { useOffsetX } from "../hooks/useOffsetX";
import type { IVisibleRanges } from "../hooks/useVisibleRanges";
import type { ILayoutConfig } from "../layouts/stack";
import { useGlobalState } from "../store";

export type TAnimationStyle = (value: number) => ViewStyle;
export type TAnimationStyle = NonNullable<TCarouselProps["customAnimation"]>;

export const ItemLayout: React.FC<{
index: number;
Expand Down Expand Up @@ -56,8 +57,8 @@ export const ItemLayout: React.FC<{
const x = useOffsetX(offsetXConfig, visibleRanges);
const animationValue = useDerivedValue(() => x.value / size, [x, size]);
const animatedStyle = useAnimatedStyle<ViewStyle>(
() => animationStyle(x.value / size),
[animationStyle]
() => animationStyle(x.value / size, index),
[animationStyle, index]
);

// TODO: For dynamic dimension in the future
Expand Down
2 changes: 1 addition & 1 deletion src/components/ItemRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ interface Props {
handlerOffset: SharedValue<number>;
layoutConfig: TAnimationStyle;
renderItem: CarouselRenderItem<any>;
customAnimation?: (value: number) => ViewStyle;
customAnimation?: (value: number, index: number) => ViewStyle;
}

export const ItemRenderer: FC<Props> = (props) => {
Expand Down
3 changes: 2 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,9 @@ export type TCarouselProps<T = any> = {
/**
* Custom animations.
* Must use `worklet`, Details: https://docs.swmansion.com/react-native-reanimated/docs/2.2.0/worklets/
* @test_coverage ✅ tested in Carousel.test.tsx > should apply the custom animation
*/
customAnimation?: (value: number) => ViewStyle;
customAnimation?: (value: number, index: number) => ViewStyle;
/**
* Render carousel item.
* @test_coverage ✅ tested in Carousel.test.tsx > should render items correctly
Expand Down

0 comments on commit 848f458

Please sign in to comment.