diff --git a/src/components/Carousel.tsx b/src/components/Carousel.tsx index 4d279970..febdd03c 100644 --- a/src/components/Carousel.tsx +++ b/src/components/Carousel.tsx @@ -19,6 +19,7 @@ import { computedRealIndexWithAutoFillData } from "../utils/computed-with-auto-f const Carousel = React.forwardRef>( (_props, ref) => { + const [containerWidth, setContainerWidth] = React.useState(0); const props = useInitProps(_props); const { @@ -87,6 +88,8 @@ const Carousel = React.forwardRef>( duration: scrollAnimationDuration, onScrollEnd: () => runOnJS(_onScrollEnd)(), onScrollStart: () => !!onScrollStart && runOnJS(onScrollStart)(), + containerWidth, + overscrollEnabled: props.overscrollEnabled, }); const { next, prev, scrollTo, getSharedIndex, getCurrentIndex } @@ -155,7 +158,12 @@ const Carousel = React.forwardRef>( const layoutConfig = useLayoutConfig({ ...props, size }); return ( - + { + const { width } = event.nativeEvent.layout; + setContainerWidth(width); + }} + > void onScrollEnd?: () => void + containerWidth: number + overscrollEnabled?: boolean } export interface ICarouselController { @@ -50,6 +52,8 @@ export function useCarouselController(options: IOpts): ICarouselController { duration, autoFillData, fixedDirection, + containerWidth, + overscrollEnabled, } = options; const dataInfo = React.useMemo( @@ -177,15 +181,16 @@ export function useCarouselController(options: IOpts): ICarouselController { const nextPage = currentFixedPage() + count; index.value = nextPage; + let value = -nextPage * size; + if (!loop && !overscrollEnabled) { + value = Math.max(value, -(dataLength * size - containerWidth)); + } if (animated) { - handlerOffset.value = scrollWithTiming( - -nextPage * size, - onFinished, - ) as any; + handlerOffset.value = scrollWithTiming(value, onFinished) as any; } else { - handlerOffset.value = -nextPage * size; + handlerOffset.value = value; onFinished?.(); } }, @@ -205,21 +210,31 @@ export function useCarouselController(options: IOpts): ICarouselController { const prev = React.useCallback( (opts: TCarouselActionOptions = {}) => { const { count = 1, animated = true, onFinished } = opts; - if (!canSliding() || (!loop && index.value <= 0)) return; + /* Checking handlerOffset.value === 0 because if going to the next item doesn't + clear the first element (can happen if overscrollEnabled = false), then we wouldn't + be allowed to go to the previous item + */ + if (!canSliding() || (!loop && index.value <= 0 && handlerOffset.value === 0)) return; onScrollStart?.(); const prevPage = currentFixedPage() - count; index.value = prevPage; + let value = -prevPage * size; + // Avoid overscrolling the first item + if(!loop && value > 0){ + value = 0 + } + if (animated) { handlerOffset.value = scrollWithTiming( - -prevPage * size, + value, onFinished, ); } else { - handlerOffset.value = -prevPage * size; + handlerOffset.value = value; onFinished?.(); } },