databag/net/web/src/carousel/Carousel.jsx

146 lines
3.6 KiB
React
Raw Normal View History

import React, { useState, useEffect, useRef } from 'react';
import { Skeleton } from 'antd';
import { CarouselWrapper } from './Carousel.styled';
import { RightOutlined, LeftOutlined, CloseOutlined, PictureOutlined, FireOutlined } from '@ant-design/icons';
import ReactResizeDetector from 'react-resize-detector';
export function Carousel({ ready, error, items, itemRenderer, itemRemove }) {
const [slots, setSlots] = useState([]);
const [carouselRef, setCarouselRef] = useState(false);
const [itemIndex, setItemIndex] = useState(0);
const [scrollLeft, setScrollLeft] = useState('hidden');
const [scrollRight, setScrollRight] = useState('hidden');
const FUDGE = 1;
let carousel = useRef();
let itemWidth = useRef(new Map());
useEffect(() => {
setScroll('smooth');
setArrows();
}, [itemIndex, items]);
useEffect(() => {
setScroll('auto');
}, [carouselRef]);
const updateItemIndex = (val) => {
setItemIndex((i) => {
if (i + val < 0) {
return 0;
}
return i + val;
})
}
const onLeft = () => {
if (itemIndex > 0) {
updateItemIndex(-1);
}
}
const onRight = () => {
if(itemIndex + 1 < items.length) {
updateItemIndex(+1);
}
}
const setScroll = (behavior) => {
let pos = FUDGE;
for (let i = 0; i < itemIndex; i++) {
pos += itemWidth.current.get(i) + 32;
}
if (carousel.current) {
carousel.current.scrollTo({ top: 0, left: pos, behavior });
}
}
const setArrows = () => {
if (itemIndex == 0) {
setScrollLeft('hidden');
}
else {
setScrollLeft('unset');
}
if (itemIndex + 1 >= items.length) {
setScrollRight('hidden');
}
else {
setScrollRight('unset');
}
}
const RemoveItem = ({ index }) => {
if (itemRemove) {
return <div class="delitem" onClick={() => itemRemove(index)}><CloseOutlined /></div>
}
return <></>
}
useEffect(() => {
let assets = [];
if (ready) {
for (let i = 0; i < items.length; i++) {
assets.push((
<ReactResizeDetector handleWidth={true} handleHeight={false}>
{({ width, height }) => {
itemWidth.current.set(i, width);
return (
<div class="item noselect">
<div class="asset">{ itemRenderer(items[i], i) }</div>
<RemoveItem index={i} />
</div>
);
}}
</ReactResizeDetector>
));
}
if (items.length > 0) {
assets.push(<div class="space">&nbsp;</div>)
}
if (itemIndex >= items.length) {
if (items.length > 0) {
setItemIndex(items.length - 1);
}
else {
setItemIndex(0);
}
}
}
setSlots(assets);
setScroll();
setArrows();
}, [ready, items]);
const onRefSet = (r) => {
if (r != null) {
carousel.current = r;
setCarouselRef(true);
}
}
2022-08-23 18:14:24 +00:00
return (
<CarouselWrapper>
{ error && (
<div class="status">
<FireOutlined style={{ fontSize: 32, color: '#ff8888' }} />
</div>
2022-08-23 18:14:24 +00:00
)}
{ !ready && !error && (
<div class="status">
<PictureOutlined style={{ fontSize: 32 }} />
</div>
2022-08-23 18:14:24 +00:00
)}
{ ready && !error && (
<div class="carousel" ref={onRefSet}>
{slots}
</div>
2022-08-23 18:14:24 +00:00
)}
<div class="left-arrow" onClick={onRight}><LeftOutlined style={{ visibility: scrollRight }} /></div>
<div class="right-arrow" onClick={onLeft} style={{ visibility: scrollLeft }}><RightOutlined /></div>
</CarouselWrapper>
);
}