UNPKG

kitten-components

Version:
281 lines (227 loc) 11.3 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.CarouselInner = undefined; var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _radium = require('radium'); var _radium2 = _interopRequireDefault(_radium); var _resizeObserverPolyfill = require('resize-observer-polyfill'); var _resizeObserverPolyfill2 = _interopRequireDefault(_resizeObserverPolyfill); var _range = require('kitten/helpers/utils/range'); var _featureDetection = require('kitten/helpers/utils/feature-detection'); var _carouselPage = require('kitten/components/carousel/carousel-page'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } if (typeof window !== 'undefined') { require('smoothscroll-polyfill').polyfill(); } var supportScrollSnap = (0, _featureDetection.cssSupports)('scroll-snap-type: mandatory'); var supportScrollSmooth = (0, _featureDetection.cssSupports)('scroll-behavior: smooth'); // inspired by https://github.com/cferdinandi/scrollStop var scrollStop = function scrollStop(callback) { // Make sure a valid callback was provided if (!callback) return; var isScrolling = void 0; var target = void 0; return function (event) { clearTimeout(isScrolling); target = event.target; isScrolling = setTimeout(function () { // Run the callback callback(target); }, // wait more for scrollStop if browser support snap // because of the momentum on ios supportScrollSnap ? 132 : 66); }; }; var getClosest = function getClosest(counts, goal) { return counts.reduce(function (prev, curr) { return Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev; }); }; var getDataForPage = function getDataForPage(data, indexPage, numColumns) { var startIndex = indexPage * numColumns; return data.slice(startIndex, startIndex + numColumns); }; var getRangePageScrollLeft = function getRangePageScrollLeft(targetClientWidth, numPages, siblingPageVisible, itemMarginBetween) { var partSiblingItemExceedWidth = itemMarginBetween; var marginForSibling = siblingPageVisible ? (itemMarginBetween + partSiblingItemExceedWidth) * 2 : 0; var innerWidth = targetClientWidth - marginForSibling; return (0, _range.createRangeFromZeroTo)(numPages).map(function (numPage) { return numPage * (innerWidth + itemMarginBetween); }); }; var CarouselInnerBase = function (_React$Component) { _inherits(CarouselInnerBase, _React$Component); function CarouselInnerBase() { var _ref; var _temp, _this, _ret; _classCallCheck(this, CarouselInnerBase); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = CarouselInnerBase.__proto__ || Object.getPrototypeOf(CarouselInnerBase)).call.apply(_ref, [this].concat(args))), _this), _this.state = { isTouched: false }, _this.onResizeObserve = function (_ref2) { var _ref3 = _slicedToArray(_ref2, 1), entry = _ref3[0]; var widthInner = entry.contentRect.width; _this.props.onResizeInner(widthInner); }, _this.handleInnerScroll = scrollStop(function (target) { if (_this.state.isTouched) return; var _this$props = _this.props, numPages = _this$props.numPages, siblingPageVisible = _this$props.siblingPageVisible, itemMarginBetween = _this$props.itemMarginBetween, indexPageVisible = _this$props.indexPageVisible, goToPage = _this$props.goToPage; var scrollLeft = target.scrollLeft, clientWidth = target.clientWidth; var rangePageScrollLeft = getRangePageScrollLeft(clientWidth, numPages, siblingPageVisible, itemMarginBetween); var closest = getClosest(rangePageScrollLeft, scrollLeft); var indexClosest = rangePageScrollLeft.indexOf(closest); if (indexClosest !== indexPageVisible) { goToPage(indexClosest); } else { // if the user doesn't scroll enough to change page // we need to scroll back to the fake snap page if (closest !== scrollLeft) { target.scrollTo({ top: 0, left: closest, behavior: 'smooth' }); } } }), _this.scrollToPage = function (indexPageToScroll) { var _this$props2 = _this.props, numPages = _this$props2.numPages, siblingPageVisible = _this$props2.siblingPageVisible, itemMarginBetween = _this$props2.itemMarginBetween; var target = _this.carouselInner; var scrollLeft = target.scrollLeft, clientWidth = target.clientWidth; var rangePageScrollLeft = getRangePageScrollLeft(clientWidth, numPages, siblingPageVisible, itemMarginBetween); var closest = rangePageScrollLeft[indexPageToScroll]; if (closest !== scrollLeft) { target.scrollTo({ top: 0, left: closest, behavior: 'smooth' }); } }, _this.handleTouchStart = function () { return _this.setState({ isTouched: true }); }, _this.handleTouchEnd = function () { return _this.setState({ isTouched: false }); }, _this.handlePageClick = function (index) { return function (e) { if (index !== _this.props.indexPageVisible) { e.preventDefault(); _this.scrollToPage(index); document.activeElement.blur(); } }; }, _temp), _possibleConstructorReturn(_this, _ret); } _createClass(CarouselInnerBase, [{ key: 'componentDidMount', value: function componentDidMount() { this.observer = new _resizeObserverPolyfill2.default(this.onResizeObserve); this.observer.observe(this.carouselInner); } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { this.observer.disconnect(); } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { if (nextProps.indexPageVisible !== this.props.indexPageVisible) { this.scrollToPage(nextProps.indexPageVisible); } } }, { key: 'render', value: function render() { var _this2 = this; var _props = this.props, data = _props.data, itemMinWidth = _props.itemMinWidth, renderItem = _props.renderItem, indexPageVisible = _props.indexPageVisible, numColumns = _props.numColumns, numPages = _props.numPages, itemMarginBetween = _props.itemMarginBetween, siblingPageVisible = _props.siblingPageVisible; var rangePage = (0, _range.createRangeFromZeroTo)(numPages); return _react2.default.createElement( 'div', { ref: function ref(div) { _this2.carouselInner = div; }, className: 'k-CarouselInner', style: [styles.carouselInner, { paddingLeft: siblingPageVisible ? itemMarginBetween * 2 : 0, paddingRight: siblingPageVisible ? itemMarginBetween * 2 : 0 }], onScroll: this.handleInnerScroll, onTouchStart: this.handleTouchStart, onTouchEnd: this.handleTouchEnd }, rangePage.map(function (index) { return _react2.default.createElement( 'div', { key: index, style: [styles.carouselPageContainer, index !== indexPageVisible && styles.carouselPageContainerClickable, { marginLeft: index ? itemMarginBetween : 0 }], onClick: _this2.handlePageClick(index) }, _react2.default.createElement(_carouselPage.CarouselPage, { data: getDataForPage(data, index, numColumns), numColumns: numColumns, itemMinWidth: itemMinWidth, itemMarginBetween: itemMarginBetween, renderItem: renderItem }) ); }), siblingPageVisible && _react2.default.createElement('div', { style: { minWidth: itemMarginBetween * 2 } }), _react2.default.createElement(_radium.Style, { scopeSelector: '.k-CarouselInner::-webkit-scrollbar', rules: { display: 'none' } }) ); } }]); return CarouselInnerBase; }(_react2.default.Component); var styles = { carouselInner: { display: 'flex', flexDirect: 'row', overflowX: 'scroll', scrollBehavior: 'smooth', // hide scrollbar on IE and Edge MsOverflowStyle: 'none', // mandatory to combine scroll with this property on iOS WebkitOverflowScrolling: 'touch', // snap only for browser that support snap without prefixes scrollSnapType: supportScrollSnap ? 'mandatory' : 'none', // Fix bug IE11 ResizeObserver, to trigger a first resize minHeight: 1 }, carouselPageContainer: { width: '100%', flexShrink: 0, // snap only for browser that support snap without prefixes scrollSnapAlign: supportScrollSnap ? 'center' : 'none' }, carouselPageContainerClickable: { cursor: 'pointer' } }; var CarouselInner = exports.CarouselInner = (0, _radium2.default)(CarouselInnerBase);