import React, { useState, useEffect, useMemo, MouseEventHandler, useRef, } from 'react'; import { LeftCaratIcon, RightCaratIcon, DownCaratIcon, UpCaratIcon, DotIcon, } from '../Icons'; import { hmsUiClassParserGenerator } from '../../utils/classes'; import { useHMSTheme } from '../../hooks/HMSThemeProvider'; import './index.css'; export interface CarouselProps { children?: React.ReactNode | React.ReactNode[] | string; direction?: 'horizontal' | 'vertical'; showNavigation?: boolean; classes?: CarouselClasses; } interface CarouselClasses { root?: string; rootHorizontal?: string; rootVertical?: string; pageContainer?: string; carouselContainer?: string; carouselInner?: string; videoTileContainer?: string; navContainer?: string; navContainerHorizontal?: string; navContainerVertical?: string; caratActive?: string; caratInactive?: string; dotButton?: string; dotActive?: string; dotInactive?: string; carat?: string; dot?: string; } const defaultClasses: CarouselClasses = { root: `w-full h-full`, rootHorizontal: 'overflow-x-auto pb-6', rootVertical: 'overflow-y-auto flex-col pr-6', pageContainer: 'inline-block align-top w-full h-full', carouselContainer: 'overflow-hidden w-full h-full', carouselInner: 'w-full h-full whitespace-nowrap', videoTileContainer: 'flex justify-center', navContainer: 'absolute w-full flex justify-center items-center', navContainerHorizontal: 'bottom-0 left-0', navContainerVertical: 'top-0 right-0 flex-col', caratActive: 'text-gray-100 dark:text-white cursor-pointer', caratInactive: 'text-transparent-700 dark:text-transparent-300', dotActive: 'text-gray-100 dark:text-white', dotInactive: 'text-transparent-700 dark:text-transparent-300 cursor-pointer', carat: 'w-4 h-4 m-1', dot: 'w-2 h-2 m-1', dotButton: 'inline-block focus:outline-none focus-visible:ring-4 focus-visible:blue-tint', }; const customClasses: CarouselClasses = { root: 'no-scrollbar', }; export const Carousel = React.forwardRef( ( { direction = 'horizontal', showNavigation = true, classes, children, }: CarouselProps, ref: React.ForwardedRef, ) => { const [currentPageIndex, setCurrentPageIndex] = useState(0); const pages = Array.isArray(children) ? children : [children]; const carouselRef = useRef(null); const { tw } = useHMSTheme(); const styler = useMemo( () => hmsUiClassParserGenerator({ tw, classes, customClasses, defaultClasses, tag: 'hmsui-carousel', }), [], ); const showNav = showNavigation && pages.length > 1; const navClassName = `${styler('navContainer')} ${ direction === 'horizontal' ? styler('navContainerHorizontal') : styler('navContainerVertical') }`; useEffect(() => { if (carouselRef) { const el: HTMLElement = carouselRef.current!; const width = el.clientWidth; const scrollAmount = currentPageIndex * width; el.scrollTo({ left: scrollAmount, behavior: 'smooth', }); } }, [currentPageIndex]); return ( <>
{pages.map((page, index) => (
{pages[index]}
))}
{showNav ? (
{ if (currentPageIndex > 0) { setCurrentPageIndex(currentPageIndex - 1); } }} styler={styler} /> {pages.map((page, index) => ( ))} { if (currentPageIndex < pages.length - 1) { setCurrentPageIndex(currentPageIndex + 1); } }} styler={styler} />
) : null} ); }, ); interface ButtonProps { direction: 'horizontal' | 'vertical'; isActive: boolean; onClick: MouseEventHandler; styler: Function; } function NextButton({ direction, isActive, onClick, styler }: ButtonProps) { const className = `${ isActive ? styler('caratActive') : styler('caratInactive') } ${styler('carat')}`; return ( ); } function PrevButton({ direction, isActive, onClick, styler }: ButtonProps) { const className = `${ isActive ? styler('caratActive') : styler('caratInactive') } ${styler('carat')}`; return ( ); }