UNPKG

@wix/design-system

Version:

@wix/design-system

681 lines (679 loc) 22.7 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.default = void 0; var _react = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _CarouselWIPSt = require("./CarouselWIP.st.css.js"); var _wixUiIconsCommon = require("@wix/wix-ui-icons-common"); var _Loader = _interopRequireDefault(require("../Loader")); var _Control = _interopRequireDefault(require("./Control")); var _Slide = _interopRequireDefault(require("./Slide")); var _constants = require("./constants"); var _utils = require("./utils"); var _jsxFileName = "/home/builduser/work/57e038ea7326c1ec/packages/wix-design-system/dist/cjs/CarouselWIP/CarouselWIP.tsx"; function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); } /** The carousel component creates a slideshow for cycling through a series of content. */ class CarouselWIP extends _react.PureComponent { constructor(_props) { var _this; super(_props); _this = this; this.loadingImagesCount = 0; this.childCount = 0; this.autoplayTimer = -1; this.carousel = void 0; this.dragStartX = null; this.initialScrollLeft = 0; this.capturedPointerId = null; this.hasSetPointerCapture = false; // Need to wait for images to load so we know which images are visible // Adding onLoad and onError callbacks to all images under the component this._setImagesOnLoadHandlers = () => { Array.from(this.carousel.children).forEach(child => { var childImages = Array.from(child.getElementsByTagName('img')); childImages.forEach(img => { if (img.complete) { return; } this.setState({ isLoading: true }); this.loadingImagesCount++; img.onload = this._onImageLoad; img.onerror = this._onImageLoad; }); }); }; this._updateChildCount = () => { var _ref, _this$carousel$childr, _this$carousel; var { images } = this.props; this.childCount = (_ref = (_this$carousel$childr = (_this$carousel = this.carousel) == null || (_this$carousel = _this$carousel.children) == null ? void 0 : _this$carousel.length) !== null && _this$carousel$childr !== void 0 ? _this$carousel$childr : images == null ? void 0 : images.length) !== null && _ref !== void 0 ? _ref : 0; }; this._onImageLoad = () => { var { initialSlideIndex } = this.props; this.loadingImagesCount--; if (!this.loadingImagesCount) { this.setState({ isLoading: false }); this._slideTo({ index: initialSlideIndex, immediate: true }).catch(_utils.nop); } }; this._setAutoplayTimer = active => { clearInterval(this.autoplayTimer); if (active) { this.autoplayTimer = window.setInterval(this._next, _constants.AUTOPLAY_SPEED); } }; this._setVisibleSlides = () => { var { props, carousel, childCount } = this; var { infinite } = props; var firstVisibleChild = Math.max(Array.from(carousel.children).findIndex(child => (0, _utils.isWhollyInView)(carousel)(child)), 0); var lastVisibleChild = Math.max(Array.from(carousel.children).findIndex((child, i, children) => (0, _utils.isWhollyInView)(carousel)(child) && (i === children.length - 1 || !(0, _utils.isWhollyInView)(carousel)(children[i + 1]))), 0); this.setState({ visibleSlides: [firstVisibleChild, lastVisibleChild], isLeftArrowDisabled: !infinite && firstVisibleChild === 0, isRightArrowDisabled: !infinite && lastVisibleChild === childCount - 1, isShowStartGradient: firstVisibleChild > 0, isShowEndGradient: lastVisibleChild < childCount - 1 }); }; this._slideTo = function () { var { index = 0, alignTo = _constants.ALIGNMENT.LEFT, immediate } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { index: 0, alignTo: _constants.ALIGNMENT.LEFT, immediate: false }; if (_this.childCount === 0) { return Promise.reject('No children to slide to'); } if (!_this.carousel) { return Promise.reject('The Carousel is not mounted'); } var { afterChange, beforeChange, easing, animationDuration: duration, infinite, startEndOffset = 0 } = _this.props; var { children, scrollLeft, offsetWidth } = _this.carousel; var slideIndex = (0, _utils.normalizeIndex)(index, _this.childCount, infinite); var { visibleSlides } = _this.state; var [firstVisibleSlide] = visibleSlides; var delta; var child = children[slideIndex]; if (alignTo === _constants.ALIGNMENT.RIGHT) { delta = child.offsetWidth - (offsetWidth - child.offsetLeft) - scrollLeft + startEndOffset; } else { delta = child.offsetLeft - scrollLeft - startEndOffset; } if (firstVisibleSlide !== slideIndex && beforeChange) { beforeChange(firstVisibleSlide, index); } _this.setState({ isAnimating: true }); return new Promise((res, _) => { if (immediate) { _this.carousel.scrollLeft = child.offsetLeft; return res(); } else { var prop = 'scrollLeft'; return res((0, _utils.animate)(_this.carousel, { prop, delta, easing, duration })); } }).then(() => { _this.setState({ isAnimating: false }); _this._setVisibleSlides(); if (firstVisibleSlide !== slideIndex && afterChange) { return afterChange(slideIndex); } }).catch(_ => { _this._setVisibleSlides(); _this.setState({ isAnimating: false }); }); }; this._next = () => { var { slidingType, infinite } = this.props; var { visibleSlides } = this.state; var [firstVisibleSlide, lastVisibleSlide] = visibleSlides; var nextSlide, alignTo; if ([_constants.SLIDING_TYPE.REVEAL_CHUNK, _constants.SLIDING_TYPE.REVEAL_ONE].includes(slidingType)) { if (lastVisibleSlide === this.childCount - 1) { nextSlide = infinite ? 0 : lastVisibleSlide; } else { nextSlide = lastVisibleSlide + 1; } alignTo = slidingType === _constants.SLIDING_TYPE.REVEAL_CHUNK ? _constants.ALIGNMENT.LEFT : _constants.ALIGNMENT.RIGHT; } else { if (firstVisibleSlide === this.childCount - 1) { nextSlide = infinite ? 0 : firstVisibleSlide; } else { nextSlide = firstVisibleSlide + 1; } alignTo = _constants.ALIGNMENT.LEFT; } if (nextSlide === this.childCount - 1) { this.setState({ isRightArrowDisabled: true, isShowEndGradient: false }); } if (firstVisibleSlide === 0) { this.setState({ isLeftArrowDisabled: false, isShowStartGradient: true }); } return this._slideTo({ index: nextSlide, alignTo }); }; this._prev = () => { var { slidingType, infinite } = this.props; var { visibleSlides } = this.state; var [firstVisibleSlide, lastVisibleSlide] = visibleSlides; var prevSlide, alignTo; if ([_constants.SLIDING_TYPE.REVEAL_CHUNK, _constants.SLIDING_TYPE.REVEAL_ONE].includes(slidingType)) { if (firstVisibleSlide === 0) { prevSlide = infinite ? this.childCount - 1 : firstVisibleSlide; } else { prevSlide = firstVisibleSlide - 1; } alignTo = slidingType === _constants.SLIDING_TYPE.REVEAL_CHUNK ? _constants.ALIGNMENT.RIGHT : _constants.ALIGNMENT.LEFT; } else { if (firstVisibleSlide === 0) { prevSlide = infinite ? this.childCount - 1 : 0; } else { prevSlide = firstVisibleSlide - 1; } alignTo = _constants.ALIGNMENT.LEFT; } if (prevSlide === 0) { this.setState({ isLeftArrowDisabled: true, isShowStartGradient: false }); } if (lastVisibleSlide === this.childCount - 1) { this.setState({ isRightArrowDisabled: false, isShowEndGradient: true }); } return this._slideTo({ index: prevSlide, alignTo }); }; this._setRef = r => { this.carousel = r; }; this._renderLeftControl = () => { var { isLeftArrowDisabled } = this.state; var { controlsPosition, controlsStartEnd, controlsSize, controlsSkin } = this.props; return controlsPosition !== 'none' && (!isLeftArrowDisabled || controlsStartEnd === _constants.CONTROLS_START_END.DISABLED) && /*#__PURE__*/_react.default.createElement(_Control.default, { dataHook: _constants.DATA_HOOKS.prevButton, onClick: this._prev, icon: /*#__PURE__*/_react.default.createElement(_wixUiIconsCommon.ChevronLeftSmall, { __self: this, __source: { fileName: _jsxFileName, lineNumber: 366, columnNumber: 17 } }), size: controlsSize, skin: controlsSkin, disabled: isLeftArrowDisabled, className: (0, _CarouselWIPSt.st)(_CarouselWIPSt.classes.control, _CarouselWIPSt.classes.prev), __self: this, __source: { fileName: _jsxFileName, lineNumber: 363, columnNumber: 9 } }); }; this._renderRightControl = () => { var { isRightArrowDisabled } = this.state; var { controlsPosition, controlsStartEnd, controlsSize, controlsSkin } = this.props; return controlsPosition !== 'none' && (!isRightArrowDisabled || controlsStartEnd === _constants.CONTROLS_START_END.DISABLED) && /*#__PURE__*/_react.default.createElement(_Control.default, { dataHook: _constants.DATA_HOOKS.nextButton, onClick: this._next, icon: /*#__PURE__*/_react.default.createElement(_wixUiIconsCommon.ChevronRightSmall, { __self: this, __source: { fileName: _jsxFileName, lineNumber: 388, columnNumber: 17 } }), size: controlsSize, skin: controlsSkin, disabled: isRightArrowDisabled, className: (0, _CarouselWIPSt.st)(_CarouselWIPSt.classes.control, _CarouselWIPSt.classes.next), __self: this, __source: { fileName: _jsxFileName, lineNumber: 385, columnNumber: 9 } }); }; this._handlePointerDown = e => { if (!e.isPrimary) return; e.preventDefault(); this.dragStartX = e.clientX; this.initialScrollLeft = this.carousel.scrollLeft; this.capturedPointerId = e.pointerId; this.setState({ isDragging: true }); }; this.requestAnimationFrameId = null; this._handlePointerMove = e => { var { isDragging } = this.state; if (!isDragging || !this.dragStartX || e.pointerId !== this.capturedPointerId) { return; } e.preventDefault(); if (!this.hasSetPointerCapture) { e.currentTarget.setPointerCapture(e.pointerId); this.hasSetPointerCapture = true; } if (this.requestAnimationFrameId) { cancelAnimationFrame(this.requestAnimationFrameId); } var swipeDistance = e.clientX - this.dragStartX; this.requestAnimationFrameId = requestAnimationFrame(() => { this.carousel.scrollLeft = this.initialScrollLeft - swipeDistance; }); }; this._handlePointerUp = e => { var { isDragging } = this.state; if (!isDragging || !this.dragStartX || e.pointerId !== this.capturedPointerId) return; this._handleSwipeEnd(e); this._releasePointerCapture(e.pointerId); this._resetDragState(); }; this._handlePointerCancel = e => { if (e.pointerId !== this.capturedPointerId || !this.dragStartX) { return; } this._handleSwipeEnd(e); this._releasePointerCapture(e.pointerId); this._resetDragState(); }; this._handleSwipeEnd = e => { if (!this.dragStartX) return; var swipeDistance = e.clientX - this.dragStartX; if (Math.abs(swipeDistance) > _constants.SWIPE_THRESHOLD) { if (swipeDistance > 0) { // Swiped right - go to previous slide this._prev(); } else { // Swiped left - go to next slide this._next(); } } else { var { easing, animationDuration: duration } = this.props; // sliding back to the original position (0, _utils.animate)(this.carousel, { prop: 'scrollLeft', delta: swipeDistance, easing, duration }); } }; this._releasePointerCapture = capturedPointerId => { var _this$carousel2; if ((_this$carousel2 = this.carousel) != null && _this$carousel2.hasPointerCapture(capturedPointerId)) { var _this$carousel3; (_this$carousel3 = this.carousel) == null || _this$carousel3.releasePointerCapture(capturedPointerId); } }; this._resetDragState = () => { this.dragStartX = null; this.initialScrollLeft = 0; this.capturedPointerId = null; this.hasSetPointerCapture = false; this.setState({ isDragging: false }); }; this._renderSlides = () => { var { images = [], children, gutter, imagesPosition, imagesFit } = this.props; var slide = _ref2 => { var { i, image, child } = _ref2; return /*#__PURE__*/_react.default.createElement(_Slide.default, { dataHook: _constants.DATA_HOOKS.child, className: _CarouselWIPSt.classes.slide, key: "slide-".concat(i), width: "auto", gutter: i > 0 && gutter != null ? "".concat(gutter, "px") : undefined, image: image, children: child, imagePosition: imagesPosition, imageFit: imagesFit, __self: this, __source: { fileName: _jsxFileName, lineNumber: 529, columnNumber: 7 } }); }; return /*#__PURE__*/_react.default.createElement("div", { className: (0, _CarouselWIPSt.st)(_CarouselWIPSt.classes.carousel, { dragging: this.state.isDragging }), role: "list", ref: this._setRef, "data-hook": _constants.DATA_HOOKS.carousel, onPointerDown: this._handlePointerDown, onPointerMove: this._handlePointerMove, onPointerUp: this._handlePointerUp, onPointerCancel: this._handlePointerCancel, __self: this, __source: { fileName: _jsxFileName, lineNumber: 543, columnNumber: 7 } }, _react.Children.count(children) ? _react.Children.map(children, (child, i) => slide({ i, child })) : images.map((image, i) => slide({ i, image }))); }; this._renderLoader = () => /*#__PURE__*/_react.default.createElement("div", { className: _CarouselWIPSt.classes.loader, __self: this, __source: { fileName: _jsxFileName, lineNumber: 561, columnNumber: 5 } }, /*#__PURE__*/_react.default.createElement(_Loader.default, { dataHook: _constants.DATA_HOOKS.loader, size: "small", __self: this, __source: { fileName: _jsxFileName, lineNumber: 562, columnNumber: 7 } })); this._renderDots = () => { var { children, images } = this.props; var { visibleSlides } = this.state; var [firstVisibleSlide, lastVisibleSlide] = visibleSlides; var slidesCount = _react.Children.count(children) || (images == null ? void 0 : images.length) || 0; return /*#__PURE__*/_react.default.createElement("div", { className: _CarouselWIPSt.classes.dots, __self: this, __source: { fileName: _jsxFileName, lineNumber: 573, columnNumber: 7 } }, Array(slidesCount).fill(0).map((_, index) => /*#__PURE__*/_react.default.createElement("div", { "data-hook": _constants.DATA_HOOKS.pageNavigation(index), key: index, className: (0, _CarouselWIPSt.st)(_CarouselWIPSt.classes.dot, { active: index >= firstVisibleSlide && index <= lastVisibleSlide }), onClick: () => { if (index < firstVisibleSlide || index > lastVisibleSlide) this._slideTo({ index, alignTo: index > firstVisibleSlide ? _constants.ALIGNMENT.RIGHT : _constants.ALIGNMENT.LEFT }); }, __self: this, __source: { fileName: _jsxFileName, lineNumber: 577, columnNumber: 13 } }))); }; this._renderStartGradient = () => /*#__PURE__*/_react.default.createElement("div", { className: _CarouselWIPSt.classes.start, __self: this, __source: { fileName: _jsxFileName, lineNumber: 599, columnNumber: 32 } }); this._renderEndGradient = () => /*#__PURE__*/_react.default.createElement("div", { className: _CarouselWIPSt.classes.end, __self: this, __source: { fileName: _jsxFileName, lineNumber: 601, columnNumber: 30 } }); this.loadingImagesCount = 0; this.state = { visibleSlides: [], isAnimating: false, isLoading: false, isLeftArrowDisabled: true, isRightArrowDisabled: true, isShowStartGradient: false, isShowEndGradient: false, isDragging: false }; } componentDidMount() { var { initialSlideIndex = 0, autoplay } = this.props; this._updateChildCount(); this._setImagesOnLoadHandlers(); if (!this.loadingImagesCount) { this._slideTo({ index: initialSlideIndex, immediate: true }).catch(_utils.nop); this._setVisibleSlides(); } this._setAutoplayTimer(autoplay); } componentDidUpdate(prevProps) { var { autoplay } = this.props; if (prevProps.autoplay !== autoplay) this._setAutoplayTimer(autoplay); var lastCount = this.childCount; this._updateChildCount(); if (this.childCount && lastCount !== this.childCount) { this._setVisibleSlides(); } } render() { var { dataHook, className, controlsPosition, controlsSize, showControlsShadow, sidesGradientColor, hideDots } = this.props; var { isShowStartGradient, isShowEndGradient, isLoading } = this.state; var showSidesGradients = !!sidesGradientColor; return isLoading ? this._renderLoader() : /*#__PURE__*/_react.default.createElement("div", { "data-hook": dataHook, className: (0, _CarouselWIPSt.st)(_CarouselWIPSt.classes.root, { controlsPosition, controlsSize, showControlsShadow, showSidesGradients, hideDots }, className), style: { [_CarouselWIPSt.vars.sidesGradientColor]: sidesGradientColor }, __self: this, __source: { fileName: _jsxFileName, lineNumber: 619, columnNumber: 7 } }, /*#__PURE__*/_react.default.createElement("div", { style: { position: 'relative' }, __self: this, __source: { fileName: _jsxFileName, lineNumber: 634, columnNumber: 9 } }, showSidesGradients && isShowStartGradient && this._renderStartGradient(), this._renderLeftControl(), this._renderSlides(), this._renderRightControl(), showSidesGradients && isShowEndGradient && this._renderEndGradient()), !hideDots && this._renderDots()); } componentWillUnmount() { if (this.capturedPointerId) { this._releasePointerCapture(this.capturedPointerId); } this._setAutoplayTimer(false); } } CarouselWIP.displayName = 'CarouselWIP'; CarouselWIP.propTypes = { dataHook: _propTypes.default.any, className: _propTypes.default.any, children: _propTypes.default.any, images: _propTypes.default.any, controlsSkin: _propTypes.default.any, showControlsShadow: _propTypes.default.any, infinite: _propTypes.default.any, initialSlideIndex: _propTypes.default.any, afterChange: _propTypes.default.any, beforeChange: _propTypes.default.any, controlsPosition: _propTypes.default.any, controlsSize: _propTypes.default.any, controlsStartEnd: _propTypes.default.any, slidingType: _propTypes.default.any, startEndOffset: _propTypes.default.any, gutter: _propTypes.default.any, sidesGradientColor: _propTypes.default.any, imagesPosition: _propTypes.default.any, imagesFit: _propTypes.default.any, autoplay: _propTypes.default.any, hideDots: _propTypes.default.any, variableWidth: _propTypes.default.any, animationDuration: _propTypes.default.any, easing: _propTypes.default.any }; CarouselWIP.defaultProps = { children: [], infinite: true, controlsSkin: 'standard', controlsStartEnd: 'disabled', showControlsShadow: false, images: [], initialSlideIndex: 0, controlsPosition: 'sides', controlsSize: 'medium', slidingType: 'align-to-start', startEndOffset: 0, gutter: undefined, hideDots: false, autoplay: false }; var _default = exports.default = CarouselWIP; //# sourceMappingURL=CarouselWIP.js.map