|
import { Box, Icon, IconButton } from '@mui/material'; |
|
import { useEffect, useRef, useState } from 'react'; |
|
|
|
const items = [1, 2, 3, 4, 5, 6, 7]; |
|
|
|
const ResponsiveCarousel = () => { |
|
const [visibleItems, setVisibleItems] = useState(4); |
|
const [scrollIndex, setScrollIndex] = useState(0); |
|
const containerRef = useRef(null); |
|
const contentRef = useRef(null); |
|
const [isDragging, setIsDragging] = useState(false); |
|
const [startX, setStartX] = useState(0); |
|
const [scrollLeft, setScrollLeft] = useState(0); |
|
|
|
useEffect(() => { |
|
const handleResize = () => { |
|
const containerWidth = containerRef.current?.offsetWidth; |
|
const newVisibleItems = Math.max(1, Math.floor(containerWidth / 220)); |
|
setVisibleItems(newVisibleItems); |
|
setScrollIndex(0); |
|
}; |
|
|
|
handleResize(); |
|
window.addEventListener('resize', handleResize); |
|
return () => window.removeEventListener('resize', handleResize); |
|
}, []); |
|
|
|
const maxScrollIndex = Math.max(0, items.length - visibleItems); |
|
|
|
const handleScroll = (direction) => { |
|
setScrollIndex((prevIndex) => { |
|
const newIndex = prevIndex + direction; |
|
return Math.max(0, Math.min(newIndex, maxScrollIndex)); |
|
}); |
|
}; |
|
|
|
// Other event handlers... |
|
|
|
useEffect(() => { |
|
const content = contentRef.current; |
|
if (content) { |
|
// Add event listeners... |
|
} |
|
}, [isDragging, startX, scrollLeft, visibleItems, maxScrollIndex]); |
|
|
|
const showNavigation = items.length > visibleItems; |
|
const isContentWidthLessThanContainer = () => { |
|
const contentWidth = contentRef.current?.scrollWidth; |
|
const containerWidth = containerRef.current?.offsetWidth; |
|
return contentWidth <= containerWidth; |
|
}; |
|
|
|
return ( |
|
<Box |
|
ref={containerRef} |
|
sx={{ |
|
display: 'flex', |
|
alignItems: 'center', |
|
position: 'relative', |
|
width: '100%', |
|
overflow: 'hidden', |
|
}} |
|
> |
|
{showNavigation && ( |
|
<IconButton |
|
onClick={() => handleScroll(-1)} |
|
disabled={scrollIndex === 0} |
|
sx={{ position: 'absolute', left: 50, zIndex: 1 }} |
|
> |
|
<Icon>arrow_back_ios</Icon> |
|
</IconButton> |
|
)} |
|
<Box |
|
sx={{ |
|
display: 'flex', |
|
overflow: 'hidden', |
|
px: 4, |
|
cursor: isDragging ? 'grabbing' : 'grab', |
|
}} |
|
> |
|
<Box |
|
ref={contentRef} |
|
sx={{ |
|
display: 'flex', |
|
justifyContent: 'center', |
|
transition: isDragging ? 'none' : 'transform 0.3s ease-in-out', |
|
transform: `translateX(-${scrollIndex * (100 / visibleItems)}%)`, |
|
}} |
|
> |
|
{items.map((item, index) => ( |
|
<Box |
|
key={index} |
|
sx={{ |
|
flex: `0 0 ${100 / visibleItems}%`, |
|
maxWidth: `${100 / visibleItems}%`, |
|
padding: '10px', |
|
boxSizing: 'border-box', |
|
}} |
|
> |
|
<Box |
|
sx={{ |
|
width: '100%', |
|
paddingTop: '100%', |
|
position: 'relative', |
|
}} |
|
> |
|
<Box |
|
sx={{ |
|
position: 'absolute', |
|
top: 0, |
|
left: 0, |
|
right: 0, |
|
bottom: 0, |
|
display: 'flex', |
|
alignItems: 'center', |
|
justifyContent: 'center', |
|
color: 'white', |
|
fontSize: '2rem', |
|
}} |
|
> |
|
{item} |
|
</Box> |
|
</Box> |
|
</Box> |
|
))} |
|
</Box> |
|
</Box> |
|
{showNavigation && ( |
|
<IconButton |
|
onClick={() => handleScroll(1)} |
|
disabled={scrollIndex >= maxScrollIndex || isContentWidthLessThanContainer()} |
|
sx={{ position: 'absolute', right: 0, zIndex: 1 }} |
|
> |
|
<Icon>arrow_forward_ios</Icon> |
|
</IconButton> |
|
)} |
|
</Box> |
|
); |
|
}; |
|
|
|
export default ResponsiveCarousel; |
I replaced
{items.map
with{React.Children.map(children, (child, index) => ( <React.Fragment key={index}>{child}</React.Fragment> ))}
still works. Not sure if the key is good though.ie:
modify ResponsiveCarouselCentered.jsx into
and use it like