UNPKG

@faceless-ui/slider

Version:

A React library for building every kind of slider

109 lines 4.47 kB
var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; import React, { useCallback, useEffect, useRef } from 'react'; import { useSlider } from '../useSlider/index.js'; import { getGhostSlideWidth } from './getGhostSlideWidth.js'; export const SliderTrack = (props) => { const { htmlElement: Tag = 'div', children, style } = props, rest = __rest(props, ["htmlElement", "children", "style"]); const sliderContext = useSlider(); const { sliderTrackRef, setScrollRatio, slideWidth, scrollable, scrollSnap, setIsPaused, pauseOnHover, alignLastSlide, isDragging, autoPlay, id: idFromContext, } = sliderContext; const hasAddedScrollListener = useRef(false); const animationFrameID = useRef(undefined); const getScrollRatio = useCallback(() => { const track = sliderTrackRef.current; if (track) { const newScrollRatio = track.scrollLeft / (track.scrollWidth - track.clientWidth); setScrollRatio(newScrollRatio); } }, [ sliderTrackRef, setScrollRatio, ]); const onScroll = useCallback(() => { const track = sliderTrackRef.current; if (track) { // prevent compounding events if (animationFrameID.current) cancelAnimationFrame(animationFrameID.current); const requestID = requestAnimationFrame(getScrollRatio); animationFrameID.current = requestID; } }, [ sliderTrackRef, getScrollRatio, ]); // NOTE: handle updates to the track's current scroll, which could originate from either the user or the program useEffect(() => { const track = sliderTrackRef.current; if (track && hasAddedScrollListener.current === false) { track.addEventListener('scroll', onScroll, false); hasAddedScrollListener.current = true; } return () => { hasAddedScrollListener.current = false; if (track) { track.removeEventListener('scroll', onScroll); } }; }, [ sliderTrackRef, onScroll, ]); // NOTE: if the user does not want scroll enabled, we need to remove the event listener without canceling programmatic scroll useEffect(() => { const track = sliderTrackRef.current; if (track) { if (!scrollable) { track.addEventListener('wheel', (e) => { e.preventDefault(); }); } } return () => { if (track) { track.removeEventListener('scroll', onScroll); } }; }, [ scrollable, onScroll, sliderTrackRef ]); const ghostSlideWidth = getGhostSlideWidth(sliderContext); let scrollSnapType; if (scrollSnap && slideWidth) { scrollSnapType = !isDragging ? 'x mandatory' : 'none'; } return (React.createElement(Tag, Object.assign({ // NOTE: the 'aria-controls' attribute of the toggler should match this ID id: `slider-track_${idFromContext}`, 'aria-live': autoPlay ? "polite" : "off" }, rest, { style: Object.assign({ position: 'relative', display: 'flex', overflowX: 'scroll', WebkitOverflowScrolling: 'touch', // NOTE: only apply after slide width has populated and while NOT dragging scrollSnapType }, style), ref: sliderTrackRef, onMouseEnter: () => { if (pauseOnHover) setIsPaused(true); // TODO: fire external methods from props, too }, onMouseLeave: () => { if (pauseOnHover) setIsPaused(false); // TODO: fire external methods from props, too } }), children && children, alignLastSlide !== undefined && (React.createElement("div", { style: { flexShrink: 0, width: ghostSlideWidth, pointerEvents: 'none' } }, "\u00A0")))); }; export default SliderTrack; //# sourceMappingURL=index.js.map