import useEmblaCarousel, { type UseEmblaCarouselType } from "embla-carousel-react";
import * as React from "react";
type CarouselApi = UseEmblaCarouselType[1];
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
type CarouselOptions = UseCarouselParameters[0];
type CarouselPlugin = UseCarouselParameters[1];
interface UseCarouselProps {
count: number;
initialIndex?: number;
orientation?: "horizontal" | "vertical";
opts?: CarouselOptions;
plugins?: CarouselPlugin;
setApi?: (api: CarouselApi) => void;
}
export function useCarousel({
count,
initialIndex = 0,
orientation = "horizontal",
opts,
plugins,
setApi,
}: UseCarouselProps) {
const [carouselRef, api] = useEmblaCarousel(
{
inViewThreshold: 1,
...opts,
startIndex: initialIndex,
axis: orientation === "horizontal" ? "x" : "y",
},
plugins
);
const [activeIndex, setActiveIndex] = React.useState(initialIndex);
const [canScrollPrev, setCanScrollPrev] = React.useState(false);
const [canScrollNext, setCanScrollNext] = React.useState(count > 1);
const onSelect = React.useCallback((emblaApi: CarouselApi) => {
if (!emblaApi) return;
setActiveIndex(emblaApi.selectedScrollSnap());
setCanScrollPrev(emblaApi.canScrollPrev());
setCanScrollNext(emblaApi.canScrollNext());
}, []);
React.useEffect(() => {
if (!api) return;
onSelect(api);
api.on("select", onSelect);
api.on("reInit", onSelect);
return () => {
api.off("select", onSelect);
api.off("reInit", onSelect);
};
}, [api, onSelect]);
React.useEffect(() => {
if (!api || !setApi) return;
setApi(api);
}, [api, setApi]);
const scrollPrev = React.useCallback(() => {
api?.scrollPrev();
}, [api]);
const scrollNext = React.useCallback(() => {
api?.scrollNext();
}, [api]);
const scrollTo = React.useCallback(
(index: number) => {
if (!api) return;
const clamped = Math.max(0, Math.min(index, count - 1));
api.scrollTo(clamped);
},
[api, count]
);
const handleKeyDown = React.useCallback(
(event: React.KeyboardEvent<HTMLDivElement>) => {
if (event.key === "ArrowLeft") {
event.preventDefault();
scrollPrev();
} else if (event.key === "ArrowRight") {
event.preventDefault();
scrollNext();
}
},
[scrollPrev, scrollNext]
);
return {
carouselRef,
api,
opts,
orientation: orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
activeIndex,
canScrollPrev,
canScrollNext,
scrollPrev,
scrollNext,
scrollTo,
handleKeyDown,
} as const;
}