'use client'; import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import BaseContainer from '@/components/ui/Container'; import { isCustomColor, resolveColor } from '@/utils/colorPalette'; import { cn, resolveViewPort } from '@/utils/styling'; import { CarouselProps, CarouselVariant } from '.'; export const Carousel: FC = ({ countOfItems, backgroundColor, spacing, border, fluidContent, height, itemsPerPage = '1', children, gapX, variant = CarouselVariant.DEFAULT, }) => { const containerRef = useRef(null); const [currentIndex, setCurrentIndex] = useState(0); const [recheckSlider, setRecheckSlider] = useState(false); const itemsPerPageNumber = Number(itemsPerPage); const totalCountOfItems = useMemo(() => { if (!countOfItems) return 0; return itemsPerPageNumber > 1 ? Math.ceil(countOfItems / itemsPerPageNumber) : countOfItems; }, [countOfItems, itemsPerPageNumber]); useEffect(() => { const handleResize = () => setRecheckSlider(prev => !prev); window.addEventListener('resize', handleResize, { passive: true }); return () => window.removeEventListener('resize', handleResize); }, []); useEffect(() => { if (containerRef.current) { const { clientWidth } = containerRef.current; containerRef.current.scrollLeft = currentIndex * clientWidth; } }, [currentIndex, recheckSlider]); const goToPrevious = useCallback(() => { setCurrentIndex(prev => (prev === 0 ? totalCountOfItems - 1 : prev - 1)); }, [totalCountOfItems]); const goToNext = useCallback(() => { setCurrentIndex(prev => (prev === totalCountOfItems - 1 ? 0 : prev + 1)); }, [totalCountOfItems]); const hasCustomBg = isCustomColor(backgroundColor); const bgFromBackground = resolveColor(backgroundColor, 'background'); const textFromBackground = resolveColor(backgroundColor, 'text'); const renderPagination = () => { if (variant === CarouselVariant.BROCHURE) { return (
{Array.from({ length: totalCountOfItems }).map((_, index) => (
); } if (variant === CarouselVariant.NUMERIC) { return (
{currentIndex + 1} of {totalCountOfItems}
); } return (
); }; const renderSlides = () => children({ className: cn('flex size-full items-center justify-center', { [resolveViewPort(gapX, 'px-{value}')]: gapX, }), style: { minWidth: itemsPerPageNumber > 1 ? `calc(${100 / itemsPerPageNumber}%)` : '100%', }, }); return (
{renderSlides()}
{renderPagination()}
); };