import {ChevronLeftIcon, ChevronRightIcon} from '@heroicons/react/24/solid' import clsx from 'clsx' import {throttle} from 'lodash' import {forwardRef, ReactNode, Ref, useEffect, useRef, useState} from 'react' import {VisibilityObserver} from 'web/components/widgets/visibility-observer' import {Row} from '../layout/row' export function Carousel(props: { children: ReactNode loadMore?: () => void className?: string labelsParentClassName?: string }) { const {children, labelsParentClassName, loadMore, className} = props const ref = useRef(null) const {scrollLeft, scrollRight, atFront, atBack, onScroll} = useCarousel(ref.current) useEffect(onScroll, [children]) return (
{children} {loadMore && ( visible && loadMore()} /> )} {!atFront && (
)} {!atBack && (
)}
) } export const ControlledCarousel = forwardRef(function ( props: { children: ReactNode loadMore?: () => void className?: string labelsParentClassName?: string onScroll: () => void scrollLeft: () => void scrollRight: () => void atFront: boolean atBack: boolean }, current: Ref, ) { const { children, labelsParentClassName, loadMore, className, onScroll, scrollLeft, scrollRight, atFront, atBack, } = props return (
{children} {loadMore && ( visible && loadMore()} /> )} {!atFront && (
)} {!atBack && (
)}
) }) export const useCarousel = (carouselRef: HTMLDivElement | null) => { const th = (f: () => any) => throttle(f, 500, {trailing: false}) const scrollLeft = th(() => { carouselRef?.scrollBy({left: -(carouselRef.clientWidth - 80)}) }) const scrollRight = th(() => { carouselRef?.scrollBy({left: carouselRef.clientWidth - 80}) }) const [atFront, setAtFront] = useState(true) const [atBack, setAtBack] = useState(true) const onScroll = throttle(() => { if (carouselRef) { const {scrollLeft, clientWidth, scrollWidth} = carouselRef setAtFront(scrollLeft < 80) setAtBack(scrollWidth - (clientWidth + scrollLeft) < 80) } }, 500) return { scrollLeft, scrollRight, atFront, atBack, onScroll, } }