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'