UNPKG

react-virtualized

Version:

React components for efficiently rendering large, scrollable lists and tabular data

195 lines (148 loc) 6.84 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); 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 _reactDom = require('react-dom'); var _reactDom2 = _interopRequireDefault(_reactDom); var _reactAddonsShallowCompare = require('react-addons-shallow-compare'); var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare); var _raf = require('raf'); var _raf2 = _interopRequireDefault(_raf); var _onScroll = require('./utils/onScroll'); 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; } var WindowScroller = function (_Component) { _inherits(WindowScroller, _Component); function WindowScroller(props) { _classCallCheck(this, WindowScroller); var _this = _possibleConstructorReturn(this, (WindowScroller.__proto__ || Object.getPrototypeOf(WindowScroller)).call(this, props)); var height = typeof window !== 'undefined' ? window.innerHeight : 0; _this.state = { isScrolling: false, height: height, scrollTop: 0 }; _this._onScrollWindow = _this._onScrollWindow.bind(_this); _this._onResizeWindow = _this._onResizeWindow.bind(_this); _this._enablePointerEventsAfterDelayCallback = _this._enablePointerEventsAfterDelayCallback.bind(_this); return _this; } _createClass(WindowScroller, [{ key: 'componentDidMount', value: function componentDidMount() { var height = this.state.height; // Subtract documentElement top to handle edge-case where a user is navigating back (history) from an already-scrolled bage. // In this case the body's top position will be a negative number and this element's top will be increased (by that amount). this._positionFromTop = _reactDom2.default.findDOMNode(this).getBoundingClientRect().top - document.documentElement.getBoundingClientRect().top; if (height !== window.innerHeight) { this.setState({ height: window.innerHeight }); } (0, _onScroll.registerScrollListener)(this); window.addEventListener('resize', this._onResizeWindow, false); } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { (0, _onScroll.unregisterScrollListener)(this); window.removeEventListener('resize', this._onResizeWindow, false); } /** * Updates the state during the next animation frame. * Use this method to avoid multiple renders in a small span of time. * This helps performance for bursty events (like onScroll). */ }, { key: '_setNextState', value: function _setNextState(state) { var _this2 = this; if (this._setNextStateAnimationFrameId) { _raf2.default.cancel(this._setNextStateAnimationFrameId); } this._setNextStateAnimationFrameId = (0, _raf2.default)(function () { _this2._setNextStateAnimationFrameId = null; _this2.setState(state); }); } }, { key: 'render', value: function render() { var children = this.props.children; var _state = this.state; var isScrolling = _state.isScrolling; var scrollTop = _state.scrollTop; var height = _state.height; return _react2.default.createElement( 'div', null, children({ height: height, isScrolling: isScrolling, scrollTop: scrollTop }) ); } }, { key: 'shouldComponentUpdate', value: function shouldComponentUpdate(nextProps, nextState) { return (0, _reactAddonsShallowCompare2.default)(this, nextProps, nextState); } }, { key: '_enablePointerEventsAfterDelayCallback', value: function _enablePointerEventsAfterDelayCallback() { this.setState({ isScrolling: false }); } }, { key: '_onResizeWindow', value: function _onResizeWindow(event) { var onResize = this.props.onResize; var height = window.innerHeight || 0; this.setState({ height: height }); onResize({ height: height }); } }, { key: '_onScrollWindow', value: function _onScrollWindow(event) { var onScroll = this.props.onScroll; // In IE10+ scrollY is undefined, so we replace that with the latter var scrollY = 'scrollY' in window ? window.scrollY : document.documentElement.scrollTop; var scrollTop = Math.max(0, scrollY - this._positionFromTop); var state = { isScrolling: true, scrollTop: scrollTop }; if (!this.state.isScrolling) { this.setState(state); } else { this._setNextState(state); } onScroll({ scrollTop: scrollTop }); } }]); return WindowScroller; }(_react.Component); WindowScroller.propTypes = { /** * Function respondible for rendering children. * This function should implement the following signature: * ({ height, scrollTop }) => PropTypes.element */ children: _react.PropTypes.func.isRequired, /** Callback to be invoked on-resize: ({ height }) */ onResize: _react.PropTypes.func.isRequired, /** Callback to be invoked on-scroll: ({ scrollTop }) */ onScroll: _react.PropTypes.func.isRequired }; WindowScroller.defaultProps = { onResize: function onResize() {}, onScroll: function onScroll() {} }; exports.default = WindowScroller;