@faceless-ui/slider
Version:
A React library for building every kind of slider
144 lines • 5.55 kB
JavaScript
import React, { useEffect, useId, useReducer, useRef, useState, } from 'react';
import smoothscroll from 'smoothscroll-polyfill';
import { SliderContext } from './context.js';
import { reducer } from './reducer.js';
import { useDraggable as useDragScroll } from './useDragScroll.js';
import { useBreakpoints } from './useBreakpoints.js';
import { useMarquee } from './useMarquee.js';
import { useAutoplay } from './useAutoplay.js';
import { useScrollToIndex } from './useScrollToIndex.js';
export const SliderProvider = (props) => {
const { children, currentSlideIndex: slideIndexFromProps = 0, onSlide, pause, id: idFromProps } = props;
// NOTE: some ARIA attributes rely on matching IDs
const uniqueID = useId();
const id = idFromProps || uniqueID;
const settings = useBreakpoints(props);
const { slidesToShow = 3, slideOnSelect, scrollable: scrollableFromProps = true, useFreeScroll, dragScroll, scrollSnap, scrollOffset = 0, autoPlay, autoplaySpeed = 2000, marquee, marqueeSpeed, pauseOnHover = true, alignLastSlide, } = settings;
if (useFreeScroll !== undefined) {
console.warn('`useFreeScroll` prop will be deprecated in the next major release, use `scrollable` instead (`true` by default)');
}
// NOTE: this this only while `useFreeScroll` is still supported, see warning above
const scrollable = scrollableFromProps === undefined ? useFreeScroll : scrollableFromProps;
const [scrollRatio, setScrollRatio] = useState(0);
const [slideWidth, setSlideWidth] = useState();
const [isPaused, setIsPaused] = useState(false);
const [isFullyScrolled, setIsFullyScrolled] = useState(false);
const sliderTrackRef = useRef(null);
const [isDragging, setIsDragging] = useState(false);
const [sliderState, dispatchSliderState] = useReducer(reducer, {
currentSlideIndex: slideIndexFromProps,
selectedSlideIndex: undefined,
slides: [],
});
useDragScroll({
ref: sliderTrackRef,
scrollYAxis: false,
enable: dragScroll || (scrollable && dragScroll !== false),
onDrag: () => { setIsDragging(true); },
onDragEnd: () => { setIsDragging(false); },
});
useMarquee({
sliderTrackRef,
isFullyScrolled,
isPaused,
enable: marquee && !autoPlay,
marqueeSpeed
});
useAutoplay({
sliderTrackRef,
isFullyScrolled,
isPaused,
enable: autoPlay,
autoplaySpeed,
dispatchSliderState
});
useScrollToIndex({
sliderTrackRef,
dispatchSliderState,
onSlide,
scrollOffset,
sliderState
});
const indexFromPropsRef = useRef(slideIndexFromProps);
useEffect(() => {
smoothscroll.polyfill(); // enables scrollTo.behavior: 'smooth' on Safari
}, []);
useEffect(() => {
const newSlideWidth = `${(slidesToShow > 1 ? 1 / slidesToShow : slidesToShow) * 100}%`;
setSlideWidth(newSlideWidth);
}, [
slidesToShow,
]);
// let user control pause, if they need to
useEffect(() => {
if (typeof pause !== 'undefined')
setIsPaused(pause);
}, [pause]);
// NOTE: for performance we set another state for 'isFullyScrolled' to avoid using `scrollRatio` directly as callback dependency
useEffect(() => {
if (scrollRatio === 1)
setIsFullyScrolled(true);
else
setIsFullyScrolled(false);
}, [scrollRatio]);
// NOTE: let props control the slider using 'currentSlideIndex' (aliased as 'slideIndexFromProps')
useEffect(() => {
if (typeof slideIndexFromProps !== 'undefined' && slideIndexFromProps !== indexFromPropsRef.current && slideIndexFromProps !== sliderState.currentSlideIndex) {
dispatchSliderState({
type: 'GO_TO_SLIDE_INDEX',
payload: {
index: slideIndexFromProps,
},
});
}
indexFromPropsRef.current = slideIndexFromProps;
}, [
slideIndexFromProps,
sliderState.currentSlideIndex
]);
const context = Object.assign(Object.assign({ sliderTrackRef,
scrollRatio }, sliderState), { setScrollRatio, goToNextSlide: () => {
dispatchSliderState({
type: 'GO_TO_NEXT_SLIDE',
payload: {
loop: !scrollable,
},
});
}, goToPrevSlide: () => {
dispatchSliderState({
type: 'GO_TO_PREV_SLIDE',
payload: {
loop: !scrollable,
},
});
}, goToSlideIndex: (index) => {
dispatchSliderState({
type: 'GO_TO_SLIDE_INDEX',
payload: {
index,
}
});
}, dispatchSlide: (slide) => {
dispatchSliderState({
type: 'UPDATE_SLIDE',
payload: {
slide,
},
});
}, autoPlay,
slideWidth,
slidesToShow,
slideOnSelect,
scrollable,
dragScroll,
scrollSnap,
scrollOffset,
setIsPaused,
isPaused,
pauseOnHover,
alignLastSlide,
isDragging,
id });
return (React.createElement(SliderContext.Provider, { value: context }, (children && (typeof children === 'function' ? children(Object.assign({}, context)) : children))));
};
//# sourceMappingURL=index.js.map