rc-infinite-carousel
Version:
A lightweight and customizable infinite carousel component for React. Perfect for displaying images, logos, testimonials, or any other content with smooth transitions and flexible configuration options.
76 lines (73 loc) • 3.52 kB
JavaScript
import * as React from 'react';
import { useState, useRef, useLayoutEffect, useCallback, useEffect } from 'react';
const Carousel = ({ data, renderItem, animationDuration = 10, direction = "LEFT", showMask = false, pauseOnHover = false, onSlideClick, ariaLabel, role, }) => {
const [dimensions, setDimensions] = useState({
height: 0,
width: 0,
});
const [visibleSlides, setVisibleSlides] = useState(0);
const [isPaused, setIsPaused] = useState(false);
const tempRef = useRef(null);
const carouselRef = useRef(null);
// Set dimensions of the first slide
useLayoutEffect(() => {
if (tempRef.current) {
const firstSlide = tempRef.current.children[0];
if (firstSlide) {
const { offsetHeight, offsetWidth } = firstSlide;
setDimensions({ height: offsetHeight, width: offsetWidth });
}
}
}, [data]);
// Calculate the number of visible slides based on container width
const calculateVisibleSlides = useCallback(() => {
if (carouselRef.current) {
const containerWidth = carouselRef.current.offsetWidth;
if (dimensions.width === 0)
return;
const visible = Math.floor(containerWidth / dimensions.width);
setVisibleSlides(visible);
}
}, [dimensions.width]);
// Recalculate visible slides when dimensions or data change
useLayoutEffect(() => {
calculateVisibleSlides();
}, [dimensions, data, calculateVisibleSlides]);
// Handle window resize events to recalculate visible slides
useEffect(() => {
const handleResize = () => {
calculateVisibleSlides();
};
const debounceResize = debounce(handleResize, 100);
window.addEventListener("resize", debounceResize);
return () => {
window.removeEventListener("resize", debounceResize);
};
}, [calculateVisibleSlides]);
// Debounce function to limit the rate of function execution
const debounce = (func, wait) => {
let timeout;
return () => {
clearTimeout(timeout);
timeout = setTimeout(func, wait);
};
};
return (React.createElement(React.Fragment, null,
React.createElement("div", { style: {
position: "absolute",
visibility: "hidden",
pointerEvents: "none",
}, ref: tempRef }, renderItem({ item: data[0], index: 0 })),
React.createElement("div", { className: `carousel ${showMask ? "with-mask" : ""}`, ref: carouselRef, "data-reverse": direction === "RIGHT", style: {
"--slide-items": data.length,
"--slide-width": `${dimensions.width}px`,
"--slide-height": `${dimensions.height}px`,
"--visible-slides": visibleSlides,
"--animation-duration": `${animationDuration}s`,
}, onMouseEnter: () => pauseOnHover && setIsPaused(true), onMouseLeave: () => pauseOnHover && setIsPaused(false), "aria-label": ariaLabel, role: role },
React.createElement("div", null, data.map((item, index) => (React.createElement("div", { key: index, className: "slide", style: {
"--slide-index": index + 1,
animationPlayState: isPaused ? "paused" : "running",
}, onClick: () => onSlideClick?.(item, index) }, renderItem({ item, index }))))))));
};
export { Carousel as default };