@kitconcept/volto-light-theme
Version:
Volto Light Theme by kitconcept
180 lines (163 loc) • 5.83 kB
JSX
import React, { useCallback, useEffect, useState } from 'react';
import { Message } from 'semantic-ui-react';
import useEmblaCarousel from 'embla-carousel-react';
import Autoplay from 'embla-carousel-autoplay';
import cx from 'classnames';
import { defineMessages, useIntl } from 'react-intl';
import Body from '@kitconcept/volto-slider-block/components/Body';
import withBlockExtensions from '@plone/volto/helpers/Extensions/withBlockExtensions';
import {
DotButton,
NextButton,
PrevButton,
} from '@kitconcept/volto-slider-block/components/DotsAndArrows';
import teaserTemplate from '@kitconcept/volto-slider-block/icons/teaser-template.svg';
const messages = defineMessages({
PleaseChooseContent: {
id: 'Please choose an existing content as source for this element',
defaultMessage:
'Please choose an existing content as source for this element',
},
});
const SliderView = (props) => {
const {
className,
data,
isEditMode = false,
block,
openObjectBrowser,
onChangeBlock,
slideIndex,
setSlideIndex,
} = props;
const intl = useIntl();
const [prevBtnDisabled, setPrevBtnDisabled] = useState(true);
const [nextBtnDisabled, setNextBtnDisabled] = useState(true);
const [selectedIndex, setSelectedIndex] = useState(0);
const [scrollSnaps, setScrollSnaps] = useState([]);
const autoplay =
data.autoplayEnabled !== undefined ? data.autoplayEnabled : false;
const autoplayOptions = {
delay: data.autoplayDelay,
jump: data.autoplayJump,
};
const plugins = isEditMode ? [] : autoplay ? [Autoplay(autoplayOptions)] : [];
const [emblaRef, emblaApi] = useEmblaCarousel({ loop: true }, plugins);
const scrollPrev = useCallback(() => {
if (emblaApi) {
emblaApi.scrollPrev();
setSlideIndex && setSlideIndex(selectedIndex - 1);
}
}, [emblaApi, selectedIndex, setSlideIndex]);
const scrollNext = useCallback(() => {
if (emblaApi) {
emblaApi.scrollNext();
setSlideIndex && setSlideIndex(selectedIndex + 1);
}
}, [emblaApi, selectedIndex, setSlideIndex]);
const scrollTo = useCallback(
(index) => {
if (emblaApi) {
emblaApi.scrollTo(index);
setSlideIndex && setSlideIndex(index);
}
},
[emblaApi, setSlideIndex],
);
const onInit = useCallback((emblaApi) => {
setScrollSnaps(emblaApi.scrollSnapList());
}, []);
const onSelect = useCallback((emblaApi) => {
setSelectedIndex(emblaApi.selectedScrollSnap());
setPrevBtnDisabled(!emblaApi.canScrollPrev());
setNextBtnDisabled(!emblaApi.canScrollNext());
}, []);
useEffect(() => {
if (!emblaApi) return;
onInit(emblaApi);
onSelect(emblaApi);
emblaApi.on('reInit', onInit);
emblaApi.on('reInit', onSelect);
emblaApi.on('select', onSelect);
}, [emblaApi, onInit, onSelect]);
useEffect(() => {
// This syncs the current slide with the objectwidget (or other sources
// able to access the slider context)
// that can modify the SliderContext (and come here via props slideIndex)
if (isEditMode) {
scrollTo(slideIndex);
}
}, [slideIndex, scrollTo, isEditMode]);
const sliderContainerWidth = emblaApi
?.rootNode()
.getBoundingClientRect().width;
return (
<>
{/* START CUSTOMIZATION */}
<div
className={cx('block slider', data.variation || 'default', className)}
style={{ '--slider-container-width': `${sliderContainerWidth}px` }}
>
{/* END CUSTOMIZATION */}
{(data.slides?.length === 0 || !data.slides) && isEditMode && (
<Message>
<div className="teaser-item default">
<img src={teaserTemplate} alt="" />
<p>{intl.formatMessage(messages.PleaseChooseContent)}</p>
</div>
</Message>
)}
{data.slides?.length > 0 && (
<>
<div className="slider-wrapper">
{!data.hideArrows && data.slides?.length > 1 && (
<>
<PrevButton onClick={scrollPrev} disabled={prevBtnDisabled} />
<NextButton onClick={scrollNext} disabled={nextBtnDisabled} />
</>
)}
<div className="slider-viewport" ref={emblaRef}>
<div className="slider-container">
{data.slides &&
data.slides.map((item, index) => {
return (
<div key={item['@id']} className="slider-slide">
<Body
{...props}
key={item['@id']}
data={item}
isEditMode={isEditMode}
dataBlock={data}
index={index}
block={block}
openObjectBrowser={openObjectBrowser}
onChangeBlock={onChangeBlock}
isActive={selectedIndex === index}
/>
</div>
);
})}
</div>
</div>
</div>
{data.slides?.length > 1 && (
<div className="slider-dots">
{scrollSnaps.map((_, index) => (
<DotButton
key={index}
index={index}
onClick={() => scrollTo(index)}
className={'slider-dot'.concat(
index === selectedIndex ? ' slider-dot--selected' : '',
)}
/>
))}
</div>
)}
</>
)}
</div>
</>
);
};
export default withBlockExtensions(SliderView);