@wix/design-system
Version:
@wix/design-system
681 lines (679 loc) • 22.7 kB
JavaScript
"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