UNPKG

grommet

Version:

focus on the essential experience

334 lines (256 loc) 11.5 kB
"use strict"; exports.__esModule = true; exports.InfiniteScroll = void 0; var _react = _interopRequireWildcard(require("react")); var _reactDom = require("react-dom"); var _utils = require("../../utils"); var _Box = require("../Box"); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } // Wraps an item to ensure we can get a ref to it /* eslint-disable react/no-multi-comp, react/no-find-dom-node */ var Ref = /*#__PURE__*/ function (_Component) { _inheritsLoose(Ref, _Component); function Ref() { return _Component.apply(this, arguments) || this; } var _proto = Ref.prototype; _proto.render = function render() { var children = this.props.children; return children; }; return Ref; }(_react.Component); var InfiniteScroll = /*#__PURE__*/ function (_PureComponent) { _inheritsLoose(InfiniteScroll, _PureComponent); function InfiniteScroll() { var _this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _PureComponent.call.apply(_PureComponent, [this].concat(args)) || this; _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "state", {}); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "initialScroll", false); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "belowMarkerRef", (0, _react.createRef)()); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "firstPageItemRef", (0, _react.createRef)()); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "lastPageItemRef", (0, _react.createRef)()); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "showRef", (0, _react.createRef)()); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "addScrollListener", function () { var pageHeight = _this.state.pageHeight; if (pageHeight && _this.belowMarkerRef.current && !_this.scrollParents) { _this.scrollParents = (0, _utils.findScrollParents)(_this.belowMarkerRef.current); _this.scrollParents.forEach(function (scrollParent) { return scrollParent.addEventListener('scroll', _this.onScroll); }); } }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "removeScrollListener", function () { if (_this.scrollParents) { _this.scrollParents.forEach(function (scrollParent) { return scrollParent.removeEventListener('scroll', _this.place); }); _this.scrollParents = undefined; } }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "scrollShow", function () { var show = _this.props.show; if (show && !_this.initialScroll && _this.showRef.current) { _this.initialScroll = true; // on initial render, scroll to any 'show' (0, _reactDom.findDOMNode)(_this.showRef.current).scrollIntoView(); } }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "setPageHeight", function () { var step = _this.props.step; var pageHeight = _this.state.pageHeight; if (_this.firstPageItemRef.current && _this.lastPageItemRef.current && !pageHeight) { /* eslint-disable react/no-find-dom-node */ var beginRect = (0, _reactDom.findDOMNode)(_this.firstPageItemRef.current).getBoundingClientRect(); var endRect = (0, _reactDom.findDOMNode)(_this.lastPageItemRef.current).getBoundingClientRect(); /* eslint-enable react/no-find-dom-node */ var nextPageHeight = endRect.y + endRect.height - beginRect.y; // Check if the items are arranged in a single column or not. var multiColumn = nextPageHeight / step < endRect.height; var pageArea = endRect.height * endRect.width * step; // In case the pageHeight is smaller than the visible area, // we call onScroll to set the page boundaries appropriately. _this.setState({ multiColumn: multiColumn, pageArea: pageArea, pageHeight: nextPageHeight }, _this.onScroll); } }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "onScroll", function () { var _this$props = _this.props, onMore = _this$props.onMore, replace = _this$props.replace; var _this$state = _this.state, beginPage = _this$state.beginPage, endPage = _this$state.endPage, lastPage = _this$state.lastPage, multiColumn = _this$state.multiColumn, pageArea = _this$state.pageArea, pageHeight = _this$state.pageHeight; if (_this.scrollParents && _this.scrollParents[0] && pageHeight) { var scrollParent = _this.scrollParents[0]; // Determine the window into the first scroll parent var top; var height; var width; if (scrollParent === document) { top = document.documentElement.scrollTop || document.body.scrollTop; height = window.innerHeight; width = window.innerWidth; } else { top = scrollParent.scrollTop; var rect = scrollParent.getBoundingClientRect(); height = rect.height; width = rect.width; } // Figure out which pages we should make visible based on the scroll // window. var offset = height / 4; var nextBeginPage = replace ? Math.min(lastPage, Math.max(0, multiColumn ? Math.floor(Math.max(0, top - offset) * width / pageArea) : Math.floor(Math.max(0, top - offset) / pageHeight))) : 0; var nextEndPage = Math.min(lastPage, Math.max(!replace && endPage || 0, multiColumn ? Math.ceil((top + height + offset) * width / pageArea) : Math.floor((top + height + offset) / pageHeight))); if (nextBeginPage !== beginPage || nextEndPage !== endPage) { _this.setState({ beginPage: nextBeginPage, endPage: nextEndPage }, function () { if (onMore && nextEndPage === lastPage) { onMore(); } }); } } }); return _this; } InfiniteScroll.getDerivedStateFromProps = function getDerivedStateFromProps(nextProps, prevState) { var items = nextProps.items, show = nextProps.show, step = nextProps.step; var lastPage = Math.ceil(items.length / step) - 1; if (prevState.beginPage === undefined || show && show >= step * (prevState.lastPage + 1) || lastPage !== prevState.lastPage) { var endPage = prevState.endPage || 0; if (show && show >= step * (endPage + 1)) { endPage = Math.floor((show + step) / step) - 1; } return { beginPage: 0, endPage: endPage, lastPage: lastPage, pageHeight: undefined }; } return null; }; var _proto2 = InfiniteScroll.prototype; _proto2.componentDidMount = function componentDidMount() { var _this2 = this; // ride out any animation, 100ms was chosen empirically clearTimeout(this.animationDelayTimer); this.animationDelayTimer = setTimeout(function () { _this2.setPageHeight(); _this2.addScrollListener(); _this2.scrollShow(); _this2.onScroll(); }, 100); }; _proto2.componentDidUpdate = function componentDidUpdate() { this.setPageHeight(); this.removeScrollListener(); this.addScrollListener(); this.scrollShow(); }; _proto2.componentWillUnmount = function componentWillUnmount() { this.removeScrollListener(); clearTimeout(this.animationDelayTimer); clearTimeout(this.scrollTimer); }; _proto2.render = function render() { var _this3 = this; var _this$props2 = this.props, children = _this$props2.children, items = _this$props2.items, onMore = _this$props2.onMore, renderMarker = _this$props2.renderMarker, replace = _this$props2.replace, show = _this$props2.show, step = _this$props2.step; var _this$state2 = this.state, beginPage = _this$state2.beginPage, endPage = _this$state2.endPage, lastPage = _this$state2.lastPage, pageHeight = _this$state2.pageHeight; var firstIndex = beginPage * step; var lastIndex = (endPage + 1) * step - 1; var result = []; if (replace && pageHeight && firstIndex) { var marker = _react.default.createElement(_Box.Box, { key: "above", flex: false, height: beginPage * pageHeight + "px" }); if (renderMarker) { // need to give it a key marker = _react.default.cloneElement(renderMarker(marker), { key: 'above' }); } result.push(marker); } items.slice(firstIndex, lastIndex + 1).forEach(function (item, index) { var itemsIndex = firstIndex + index; var child = children(item, itemsIndex); if (!pageHeight && itemsIndex === 0) { child = _react.default.createElement(Ref, { key: "first", ref: _this3.firstPageItemRef }, child); } else if (!pageHeight && itemsIndex === step - 1) { child = _react.default.createElement(Ref, { key: "last", ref: _this3.lastPageItemRef }, child); } if (show && show === itemsIndex) { child = _react.default.createElement(Ref, { key: "show", ref: _this3.showRef }, child); } result.push(child); }); if (endPage < lastPage || replace || onMore) { var _marker = _react.default.createElement(_Box.Box, { key: "below", ref: this.belowMarkerRef, flex: false, height: (replace ? (lastPage - endPage) * pageHeight : 0) + "px" }); if (renderMarker) { // need to give it a key _marker = _react.default.cloneElement(renderMarker(_marker), { key: 'below' }); } result.push(_marker); } return result; }; return InfiniteScroll; }(_react.PureComponent); _defineProperty(InfiniteScroll, "defaultProps", { items: [], step: 50 }); var InfiniteScrollDoc; if (process.env.NODE_ENV !== 'production') { InfiniteScrollDoc = require('./doc').doc(InfiniteScroll); // eslint-disable-line global-require } var InfiniteScrollWrapper = InfiniteScrollDoc || InfiniteScroll; /* eslint-enable react/no-find-dom-node, react/no-multi-comp */ exports.InfiniteScroll = InfiniteScrollWrapper;