import React, { createContext, useContext, useState, useCallback, useRef, useEffect, } from 'react'; import { cn } from '@/lib/utils'; import { Button } from './button'; interface CarouselContextType { currentIndex: number; totalItems: number; scrollPrev: () => void; scrollNext: () => void; canScrollPrev: boolean; canScrollNext: boolean; orientation: 'horizontal' | 'vertical'; } const CarouselContext = createContext( undefined ); function useCarousel() { const context = useContext(CarouselContext); if (!context) { throw new Error('Carousel components must be used within a Carousel'); } return context; } interface CarouselProps { children: React.ReactNode; orientation?: 'horizontal' | 'vertical'; className?: string; autoPlay?: boolean; autoPlayInterval?: number; } function Carousel({ children, orientation = 'horizontal', className, autoPlay = false, autoPlayInterval = 3000, }: CarouselProps) { const [currentIndex, setCurrentIndex] = useState(0); const itemCount = React.Children.count(children); const autoPlayTimerRef = useRef(null); const canScrollPrev = currentIndex > 0; const canScrollNext = currentIndex < itemCount - 1; const scrollPrev = useCallback(() => { setCurrentIndex((prev) => Math.max(0, prev - 1)); }, []); const scrollNext = useCallback(() => { setCurrentIndex((prev) => Math.min(itemCount - 1, prev + 1)); }, [itemCount]); useEffect(() => { if (!autoPlay) return; autoPlayTimerRef.current = setInterval(() => { setCurrentIndex((prev) => { if (prev >= itemCount - 1) { return 0; } return prev + 1; }); }, autoPlayInterval); return () => { if (autoPlayTimerRef.current) { clearInterval(autoPlayTimerRef.current); } }; }, [autoPlay, autoPlayInterval, itemCount]); return (
{children}
); } interface CarouselContentProps { className?: string; children: React.ReactNode; } function CarouselContent({ className, children }: CarouselContentProps) { const { currentIndex, orientation } = useCarousel(); return (
{children}
); } interface CarouselItemProps { className?: string; children: React.ReactNode; } function CarouselItem({ className, children }: CarouselItemProps) { const { orientation } = useCarousel(); return (
{children}
); } interface CarouselPreviousProps { className?: string; } function CarouselPrevious({ className }: CarouselPreviousProps) { const { scrollPrev, canScrollPrev, orientation } = useCarousel(); return ( ); } interface CarouselNextProps { className?: string; } function CarouselNext({ className }: CarouselNextProps) { const { scrollNext, canScrollNext, orientation } = useCarousel(); return ( ); } export { Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext, useCarousel, };