import React, { forwardRef, HTMLAttributes, useContext, useEffect, useState, useRef } from 'react' import PropTypes from 'prop-types' import classNames from 'classnames' import { useForkedRef } from '../../hooks' import { CCarouselContext } from './CCarouselContext' export interface CCarouselItemProps extends HTMLAttributes { /** * @ignore */ active?: boolean /** * A string of all className you want applied to the base component. */ className?: string /** * @ignore */ direction?: string /** * The amount of time to delay between automatically cycling an item. */ interval?: boolean | number } export const CCarouselItem = forwardRef( ({ children, className, active, direction, interval = false, ...rest }, ref) => { const { setAnimating, setCustomInterval } = useContext(CCarouselContext) const carouselItemRef = useRef(null) const forkedRef = useForkedRef(ref, carouselItemRef) const prevActive = useRef(undefined) const [directionClassName, setDirectionClassName] = useState() const [orderClassName, setOrderClassName] = useState() const [activeClassName, setActiveClassName] = useState(active && 'active') const [count, setCount] = useState(0) useEffect(() => { if (active) { setCustomInterval(interval) if (count !== 0) setOrderClassName(`carousel-item-${direction}`) } if (prevActive.current && !active) { setActiveClassName('active') } if (active || prevActive.current) { setTimeout(() => { if (count !== 0) { // @ts-expect-error reflow is necessary to proper transition // eslint-disable-next-line @typescript-eslint/no-unused-vars const reflow = carouselItemRef.current?.offsetHeight setDirectionClassName(`carousel-item-${direction === 'next' ? 'start' : 'end'}`) } }, 0) } prevActive.current = active if (count === 0) setCount(count + 1) }, [active]) useEffect(() => { carouselItemRef.current?.addEventListener('transitionstart', () => { active && setAnimating(true) }) carouselItemRef.current?.addEventListener('transitionend', () => { active && setAnimating(false) setDirectionClassName('') setOrderClassName('') if (active) { setActiveClassName('active') } if (!active) { setActiveClassName('') } }) return () => { carouselItemRef.current?.removeEventListener('transitionstart', () => { active && setAnimating(true) }) carouselItemRef.current?.removeEventListener('transitionend', () => { active && setAnimating(false) setDirectionClassName('') setOrderClassName('') if (active) { setActiveClassName('active') } if (!active) { setActiveClassName('') } }) } }) return (
{children}
) } ) CCarouselItem.propTypes = { active: PropTypes.bool, children: PropTypes.node, className: PropTypes.string, direction: PropTypes.string, interval: PropTypes.oneOfType([PropTypes.bool, PropTypes.number]), } CCarouselItem.displayName = 'CCarouselItem'