diff --git a/example/website/public/quick-swipe.mp4 b/example/website/public/quick-swipe.mp4
new file mode 100644
index 00000000..386fac01
Binary files /dev/null and b/example/website/public/quick-swipe.mp4 differ
diff --git a/src/components/Carousel.tsx b/src/components/Carousel.tsx
index d70d5b96..11a5e377 100644
--- a/src/components/Carousel.tsx
+++ b/src/components/Carousel.tsx
@@ -45,6 +45,7 @@ const Carousel = React.forwardRef>(
autoPlayInterval,
scrollAnimationDuration,
withAnimation,
+ fixedDirection,
renderItem,
onScrollEnd,
onSnapToItem,
@@ -85,9 +86,10 @@ const Carousel = React.forwardRef>(
handlerOffset,
withAnimation,
defaultIndex,
+ fixedDirection,
+ duration: scrollAnimationDuration,
onScrollEnd: () => runOnJS(_onScrollEnd)(),
onScrollBegin: () => !!onScrollBegin && runOnJS(onScrollBegin)(),
- duration: scrollAnimationDuration,
});
const { next, prev, scrollTo, getSharedIndex, getCurrentIndex }
diff --git a/src/hooks/useCarouselController.tsx b/src/hooks/useCarouselController.tsx
index ee230d32..35f7f94e 100644
--- a/src/hooks/useCarouselController.tsx
+++ b/src/hooks/useCarouselController.tsx
@@ -21,9 +21,10 @@ interface IOpts {
loop: boolean
size: number
dataLength: number
- autoFillData: TCarouselProps["autoFillData"]
handlerOffset: Animated.SharedValue
+ autoFillData: TCarouselProps["autoFillData"]
withAnimation?: TCarouselProps["withAnimation"]
+ fixedDirection?: TCarouselProps["fixedDirection"]
duration?: number
defaultIndex?: number
onScrollBegin?: () => void
@@ -48,6 +49,7 @@ export function useCarouselController(options: IOpts): ICarouselController {
defaultIndex = 0,
duration,
autoFillData,
+ fixedDirection,
} = options;
const dataInfo = React.useMemo(
@@ -241,7 +243,7 @@ export function useCarouselController(options: IOpts): ICarouselController {
onScrollBegin?.();
// direction -> 1 | -1
- const direction = handlerOffsetDirection(handlerOffset);
+ const direction = handlerOffsetDirection(handlerOffset, fixedDirection);
// target offset
const offset = i * size * direction;
@@ -252,16 +254,16 @@ export function useCarouselController(options: IOpts): ICarouselController {
if (loop) {
isCloseToNextLoop
- = Math.abs(handlerOffset.value % totalSize) / totalSize
- >= 0.5;
+ = Math.abs(handlerOffset.value % totalSize) / totalSize
+ >= 0.5;
}
const finalOffset
- = (Math.floor(Math.abs(handlerOffset.value / totalSize))
- + (isCloseToNextLoop ? 1 : 0))
- * totalSize
- * direction
- + offset;
+ = (Math.floor(Math.abs(handlerOffset.value / totalSize))
+ + (isCloseToNextLoop ? 1 : 0))
+ * totalSize
+ * direction
+ + offset;
if (animated) {
index.value = i;
@@ -274,13 +276,14 @@ export function useCarouselController(options: IOpts): ICarouselController {
}
},
[
+ size,
+ loop,
index,
- canSliding,
- onScrollBegin,
+ fixedDirection,
handlerOffset,
- size,
dataInfo.length,
- loop,
+ canSliding,
+ onScrollBegin,
scrollWithTiming,
],
);
diff --git a/src/hooks/useVisibleRanges.tsx b/src/hooks/useVisibleRanges.tsx
index 36284ec8..76364669 100644
--- a/src/hooks/useVisibleRanges.tsx
+++ b/src/hooks/useVisibleRanges.tsx
@@ -17,11 +17,11 @@ export function useVisibleRanges(options: {
total = 0,
viewSize,
translation,
- windowSize: _windowSize = 0,
+ windowSize: _windowSize,
loop,
} = options;
- const windowSize = total <= _windowSize ? total : _windowSize;
+ const windowSize = _windowSize ?? total;
const ranges = useDerivedValue(() => {
const positiveCount = Math.round(windowSize / 2);
@@ -35,7 +35,7 @@ export function useVisibleRanges(options: {
// So, It will be only displayed the positive items.
return {
negativeRange: [0 + currentIndex - (windowSize - 1), 0 + currentIndex],
- positiveRange: [0 + currentIndex, windowSize - 1 + currentIndex],
+ positiveRange: [0 + currentIndex, currentIndex + (windowSize - 1)],
};
}
@@ -57,7 +57,7 @@ export function useVisibleRanges(options: {
negativeRange[1] = total - 1;
positiveRange[0] = 0;
}
-
+ // console.log({ negativeRange, positiveRange ,total,windowSize,a:total <= _windowSize})
return { negativeRange, positiveRange };
}, [loop, total, windowSize, translation]);
diff --git a/src/utils/handleroffset-direction.test.ts b/src/utils/handleroffset-direction.test.ts
new file mode 100644
index 00000000..71dd4a29
--- /dev/null
+++ b/src/utils/handleroffset-direction.test.ts
@@ -0,0 +1,52 @@
+import { useSharedValue } from "react-native-reanimated";
+
+import { renderHook } from "@testing-library/react-hooks";
+
+import { handlerOffsetDirection } from "./handleroffset-direction";
+
+describe("handlerOffsetDirection", () => {
+ it("should return -1 when default value equals to zero", () => {
+ const result = renderHook(() => {
+ const handlerOffsetAnimVal = useSharedValue(0);
+ return handlerOffsetDirection(handlerOffsetAnimVal);
+ });
+
+ expect(result.result.current).toBe(-1);
+ });
+
+ it("should return 1 when default value is greater than zero", () => {
+ const result = renderHook(() => {
+ const handlerOffsetAnimVal = useSharedValue(1);
+ return handlerOffsetDirection(handlerOffsetAnimVal);
+ });
+
+ expect(result.result.current).toBe(1);
+ });
+
+ it("should return -1 when default value is less than zero", () => {
+ const result = renderHook(() => {
+ const handlerOffsetAnimVal = useSharedValue(-1);
+ return handlerOffsetDirection(handlerOffsetAnimVal);
+ });
+
+ expect(result.result.current).toBe(-1);
+ });
+
+ it("should return 1 when default value equals to zero and fixedDirection is negative", () => {
+ const result = renderHook(() => {
+ const handlerOffsetAnimVal = useSharedValue(-1);
+ return handlerOffsetDirection(handlerOffsetAnimVal, "positive");
+ });
+
+ expect(result.result.current).toBe(1);
+ });
+
+ it("should return -1 when default value is greater than zero and fixedDirection is negative", () => {
+ const result = renderHook(() => {
+ const handlerOffsetAnimVal = useSharedValue(1);
+ return handlerOffsetDirection(handlerOffsetAnimVal, "negative");
+ });
+
+ expect(result.result.current).toBe(-1);
+ });
+});
diff --git a/src/utils/handleroffset-direction.ts b/src/utils/handleroffset-direction.ts
index ff511605..b2b1731f 100644
--- a/src/utils/handleroffset-direction.ts
+++ b/src/utils/handleroffset-direction.ts
@@ -1,15 +1,18 @@
import type { SharedValue } from "react-native-reanimated";
-export function handlerOffsetDirection(handlerOffset: SharedValue): -1 | 1 {
+import type { TCarouselProps } from "../types";
+
+export function handlerOffsetDirection(handlerOffset: SharedValue, fixedDirection?: TCarouselProps["fixedDirection"]): -1 | 1 {
"worklet";
- const isPositiveZero = Object.is(handlerOffset.value, +0);
- const isNegativeZero = Object.is(handlerOffset.value, -0);
- const direction = isPositiveZero
- ? 1
- : isNegativeZero
- ? -1
- : Math.sign(handlerOffset.value) as -1 | 1;
+ if (fixedDirection === "negative")
+ return -1;
+
+ if (fixedDirection === "positive")
+ return 1;
+
+ if (handlerOffset.value === 0)
+ return -1;
- return direction;
+ return Math.sign(handlerOffset.value) as -1 | 1;
}