UNPKG

lucid-ui

Version:

A UI component library from Xandr.

87 lines 4.45 kB
import _, { omit } from 'lodash'; import React from 'react'; import PropTypes from 'prop-types'; import { lucidClassNames } from '../../util/style-helpers'; import { getFirst } from '../../util/component-types'; import SlidePanel from '../SlidePanel/SlidePanel'; const cx = lucidClassNames.bind('&-InfiniteSlidePanel'); const { func, node, number, oneOfType, string } = PropTypes; const modulo = (n, a) => { return a - n * Math.floor(a / n); }; const InfiniteSlidePanelSlide = (_props) => null; InfiniteSlidePanelSlide.displayName = 'InfiniteSlidePanel.Slide'; InfiniteSlidePanelSlide.propName = 'Slide'; InfiniteSlidePanelSlide.peek = { description: `The slide.` }; const defaultProps = { offset: 0, slidesToShow: 1, onSwipe: _.noop, totalSlides: 8, isAnimated: SlidePanel.defaultProps.isAnimated, isLooped: SlidePanel.defaultProps.isLooped, }; export const InfiniteSlidePanel = (props) => { const { children, className, offset, slidesToShow, onSwipe, totalSlides, ...passThroughs } = props; const slide = getFirst(props, InfiniteSlidePanel.Slide, React.createElement(InfiniteSlidePanelSlide, null, children)); const slideChildRenderFunction = slide.props.children; if (!_.isFunction(slideChildRenderFunction)) { throw new Error('InfiniteSlidePanel children must be a single function `(slideOffset) => { /* returns React.PropTypes.node */ }`'); } const halfSlides = Math.floor(totalSlides / 2); const circularOffset = modulo(totalSlides, offset); const forwardSlideOffsets = _.times(totalSlides - halfSlides, (n) => offset + n); const backwardSlideOffsets = _.times(halfSlides, (n) => offset + n - halfSlides); const transposedSlideOffsets = forwardSlideOffsets.concat(backwardSlideOffsets); const slideOffsetArray = _.takeRight(transposedSlideOffsets, circularOffset).concat(_.take(transposedSlideOffsets, totalSlides - circularOffset)); return (React.createElement(SlidePanel, { ...omit(passThroughs, ['Slide', 'initialState']), className: cx('&', className), offset: offset, slidesToShow: slidesToShow, onSwipe: onSwipe, isLooped: true }, _.map(slideOffsetArray, (slideOffset, elementOffset) => (React.createElement(SlidePanel.Slide, { key: elementOffset, ...slide.props, className: cx({ '&-Slide-in-frame': slideOffset - offset < slidesToShow && slideOffset - offset >= 0, }, slide.props.className) }, slideChildRenderFunction(slideOffset)))))); }; InfiniteSlidePanel.defaultProps = defaultProps; InfiniteSlidePanel.Slide = InfiniteSlidePanelSlide; InfiniteSlidePanel._isPrivate = true; InfiniteSlidePanel.displayName = 'InfiniteSlidePanel'; InfiniteSlidePanel.peek = { description: `A container for rendering an infinite set of horizontal slides. Translation between slides is controlled by passing in a new \`offset\`. Can hook into touch events to update the \`offset\`. This component is made from \`SlidePanel\`, so it accepts the same props.`, categories: ['helpers'], madeFrom: ['SlidePanel'], }; InfiniteSlidePanel.propTypes = { /** Appended to the component-specific class names set on the root element. */ className: string, children: oneOfType([node, func]) /** The only allowed child is a render function which is passed the current slide's offset and returns the slide contents: \`(slideOffset) => { //returns React.PropTypes.node }\` Alternatively, you could pass one \`<InfiniteSlidePanel.Slide {...}>\` element with the render function. The only reason do to the latter is to pass addiontal props to the slide element. */, /** The offset of the left-most rendered slide. */ offset: number, /** Max number of viewable slides to show simultaneously. */ slidesToShow: number, /** Called when a user's swipe would change the offset. Callback passes number of slides by the user (positive for forward swipes, negative for backwards swipes). Signature: \`(slidesSwiped, { event, props }) => {}\` */ onSwipe: func, /** The number of slides rendered at any given time. A good rule-of-thumb is that this should be at least 4 times the \`slidesToShow\` value. */ totalSlides: number, /** Child components of SlidePanel */ Slide: node, }; export default InfiniteSlidePanel; //# sourceMappingURL=InfiniteSlidePanel.js.map