import React, { useState, ReactNode, ReactElement, useEffect, useRef, useCallback, } from 'react'; import css from '../../utils/css'; import { StyledButton, StyledButtonWrapper, StyledButtonList, CarouselContainer, CarouselSingleSlide, CarouselSlideCollection, StyledButtonIconWrapper, } from './StyledCarousel'; import Spinner from '../Spinner'; import Button from '../Button'; import { CommonProps } from '../common'; import { getDotDirection, getDotState, getButtonPlacement } from './utils'; export interface CarouselProps extends CommonProps { /** * Whether to scroll automatically. */ autoPlay?: boolean; /** * List of items to be shown to the story board. Each item must have an unquie id. */ collection: { content: ReactNode; id: number; }[]; /** * Position of dots button. */ dotPlacement?: 'top' | 'right' | 'bottom' | 'left'; /** * Set interval of each slide. */ interval?: number; /** * Set loading state of carousel. */ loading?: boolean; /** * Color of slide background to have corresponding dots color. */ variant?: 'light' | 'dark'; } const Carousel = ({ autoPlay = false, collection, dotPlacement = 'bottom', interval = 2000, loading = false, variant = 'light', className, style, sx = {}, id, 'data-test-id': dataTestId, }: CarouselProps): ReactElement => { const [itemCollection, setItemCollection] = useState([]); const [currentItemIndex, setCurrentItemIndex] = useState(0); const timer = useRef(); const handleItemChange = useCallback( (index: number) => { if (index < itemCollection.length && index >= 0) { setCurrentItemIndex(index); } if (index >= itemCollection.length) { setCurrentItemIndex(0); } if (index < 0) { setCurrentItemIndex(itemCollection.length - 1); } }, [itemCollection] ); const createInterval = useCallback(() => { timer.current = window.setInterval(() => { handleItemChange(currentItemIndex + 1); }, interval); }, [interval, handleItemChange, currentItemIndex]); const destroyInterval = useCallback(() => { clearInterval(timer.current); }, []); useEffect( () => setItemCollection( collection.map(item => { return ( {item.content} ); }) ), [collection] ); useEffect(() => { if (autoPlay === true && loading === false) { createInterval(); return (): void => destroyInterval(); } return undefined; }, [autoPlay, createInterval, destroyInterval, loading]); return ( { if (autoPlay === true) { destroyInterval(); } }} onMouseLeave={(): void => { if (autoPlay === true) { createInterval(); } }} > {loading === true ? ( ) : ( <> {itemCollection} { e.preventDefault(); handleItemChange(currentItemIndex - 1); }} /> { e.preventDefault(); handleItemChange(currentItemIndex + 1); }} /> {collection.map((item, index) => { const active = currentItemIndex === index; return ( { e.preventDefault(); handleItemChange(index); }} active={active} themeVariant={variant} themeDotDirection={getDotDirection({ dotPlacement })} /> ); })} )} ); }; export default Carousel;