UNPKG

10.5 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _isEqual2 = require('lodash/isEqual');
8
9var _isEqual3 = _interopRequireDefault(_isEqual2);
10
11var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
12
13var _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; }; }();
14
15exports.heightPropCheck = heightPropCheck;
16
17var _react = require('react');
18
19var _react2 = _interopRequireDefault(_react);
20
21var _reactabularSticky = require('reactabular-sticky');
22
23var _reactabularTable = require('reactabular-table');
24
25var _types = require('./types');
26
27var _calculateAverageHeight = require('./calculate-average-height');
28
29var _calculateAverageHeight2 = _interopRequireDefault(_calculateAverageHeight);
30
31var _calculateRows = require('./calculate-rows');
32
33var _calculateRows2 = _interopRequireDefault(_calculateRows);
34
35function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
36
37function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
38
39function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
40
41function _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; }
42
43function _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; }
44
45var VirtualizedBody = function (_React$Component) {
46 _inherits(VirtualizedBody, _React$Component);
47
48 function VirtualizedBody(props) {
49 _classCallCheck(this, VirtualizedBody);
50
51 var _this = _possibleConstructorReturn(this, (VirtualizedBody.__proto__ || Object.getPrototypeOf(VirtualizedBody)).call(this, props));
52
53 _this.measuredRows = {}; // row key -> measurement
54 _this.ref = null;
55 _this.scrollTop = 0;
56 _this.initialMeasurement = true;
57 _this.timeoutId = 0;
58
59 _this.state = getInitialState();
60
61 _this.checkMeasurements = _this.checkMeasurements.bind(_this);
62 return _this;
63 }
64
65 _createClass(VirtualizedBody, [{
66 key: 'componentDidMount',
67 value: function componentDidMount() {
68 this.checkMeasurements();
69 }
70 }, {
71 key: 'componentDidUpdate',
72 value: function componentDidUpdate() {
73 this.checkMeasurements();
74 }
75 }, {
76 key: 'componentWillUnmount',
77 value: function componentWillUnmount() {
78 clearTimeout(this.timeoutId);
79 }
80 }, {
81 key: 'getHeight',
82 value: function getHeight(optionalProps) {
83 // If `optionalProps` is defined, we use `optionalProps` instead of `this.props`.
84 var props = optionalProps || this.props;
85 // If `props.height` is not defined, we use `props.style.maxHeight` instead.
86 return props.height || props.style.maxHeight;
87 }
88 }, {
89 key: 'componentWillReceiveProps',
90 value: function componentWillReceiveProps(nextProps) {
91 if (!(0, _isEqual3.default)(this.props.rows, nextProps.rows) || this.getHeight() !== this.getHeight(nextProps)) {
92 if (process.env.NODE_ENV !== 'production' && window.LOG_VIRTUALIZED) {
93 console.log('invalidating measurements'); // eslint-disable-line no-console
94 }
95
96 var rows = (0, _calculateRows2.default)({
97 scrollTop: this.scrollTop,
98 measuredRows: this.measuredRows,
99 height: this.getHeight(nextProps),
100 rowKey: nextProps.rowKey,
101 rows: nextProps.rows
102 });
103
104 if (!rows) {
105 return;
106 }
107
108 this.setState(rows);
109 }
110 }
111 }, {
112 key: 'getChildContext',
113 value: function getChildContext() {
114 var _this2 = this;
115
116 var _state = this.state,
117 startHeight = _state.startHeight,
118 endHeight = _state.endHeight,
119 showExtraRow = _state.showExtraRow;
120
121
122 return {
123 startHeight: startHeight,
124 endHeight: endHeight,
125 showExtraRow: showExtraRow,
126 updateHeight: function updateHeight(rowKey, height) {
127 _this2.measuredRows[rowKey] = height;
128 },
129 // Capture height data only during the initial measurement
130 initialMeasurement: this.initialMeasurement
131 };
132 }
133 }, {
134 key: 'render',
135 value: function render() {
136 var _this3 = this;
137
138 var _props = this.props,
139 _onRow = _props.onRow,
140 rows = _props.rows,
141 _onScroll = _props.onScroll,
142 props = _objectWithoutProperties(_props, ['onRow', 'rows', 'onScroll']);
143
144 var _state2 = this.state,
145 startIndex = _state2.startIndex,
146 amountOfRowsToRender = _state2.amountOfRowsToRender;
147
148 // Attach information about measuring status. This way we can implement
149 // proper shouldComponentUpdate
150
151 var rowsToRender = rows.slice(startIndex, startIndex + amountOfRowsToRender).map(function (rowData, rowIndex) {
152 return _extends({}, rowData, {
153 _measured: !!_this3.measuredRows[(0, _reactabularTable.resolveRowKey)({
154 rowData: rowData,
155 rowIndex: rowIndex,
156 rowKey: _this3.props.rowKey
157 })]
158 });
159 });
160
161 if (process.env.NODE_ENV !== 'production' && window.LOG_VIRTUALIZED) {
162 console.log( // eslint-disable-line no-console
163 'rendering', rowsToRender.length, '/', rows.length, 'rows to render', rowsToRender, 'start index', startIndex, 'amount of rows to render', amountOfRowsToRender);
164 }
165
166 return _react2.default.createElement(_reactabularSticky.Body, _extends({}, props, {
167 onRow: function onRow(row, extra) {
168 var rowProps = _onRow ? _onRow(row, extra) : {};
169
170 return _extends({
171 // Pass index so that row heights can be tracked properly
172 'data-rowkey': extra.rowKey
173 }, rowProps);
174 },
175 rows: rowsToRender,
176 ref: function ref(body) {
177 _this3.ref = body && body.getRef().getRef();
178 },
179 onScroll: function onScroll(e) {
180 _onScroll && _onScroll(e);
181
182 var scrollTop = e.target.scrollTop;
183
184 // Y didn't change, bail to avoid rendering rows
185
186 if (_this3.scrollTop === scrollTop) {
187 return;
188 }
189
190 _this3.scrollTop = scrollTop;
191
192 _this3.setState((0, _calculateRows2.default)({
193 scrollTop: scrollTop,
194 measuredRows: _this3.measuredRows,
195 height: _this3.getHeight(),
196 rowKey: _this3.props.rowKey,
197 rows: _this3.props.rows
198 }));
199 }
200 }));
201 }
202 }, {
203 key: 'getRef',
204 value: function getRef() {
205 var _this4 = this;
206
207 var ref = this.ref;
208
209 ref.scrollTo = function (index) {
210 var startIndex = parseInt(index, 10);
211
212 if (startIndex >= 0) {
213 var startHeight = (0, _calculateAverageHeight2.default)({
214 measuredRows: _this4.measuredRows,
215 rows: _this4.props.rows,
216 rowKey: _this4.props.rowKey
217 }) * startIndex;
218
219 _this4.scrollTop = startHeight;
220 _this4.ref.scrollTop = startHeight;
221 }
222 };
223
224 return ref;
225 }
226 }, {
227 key: 'checkMeasurements',
228 value: function checkMeasurements() {
229 var _this5 = this;
230
231 // If there are no valid measurements, calculate some after waiting a while.
232 // Without this styling solutions like Radium won't work as you might expect
233 // given they can take a while to set container height.
234 if (this.initialMeasurement) {
235 this.timeoutId = setTimeout(function () {
236 var rows = (0, _calculateRows2.default)({
237 scrollTop: _this5.scrollTop,
238 measuredRows: _this5.measuredRows,
239 height: _this5.getHeight(),
240 rowKey: _this5.props.rowKey,
241 rows: _this5.props.rows
242 });
243
244 if (!rows) {
245 // Refresh the rows to trigger measurement.
246 _this5.forceUpdate();
247
248 return;
249 }
250
251 _this5.setState(rows, function () {
252 _this5.initialMeasurement = false;
253 });
254 }, 100);
255 }
256 }
257 }]);
258
259 return VirtualizedBody;
260}(_react2.default.Component);
261
262VirtualizedBody.defaultProps = _reactabularSticky.Body.defaultProps;
263process.env.NODE_ENV !== "production" ? VirtualizedBody.propTypes = _extends({}, _reactabularSticky.Body.propTypes, {
264 height: heightPropCheck
265}) : void 0;
266VirtualizedBody.childContextTypes = _types.bodyChildContextTypes;
267
268/* eslint-disable consistent-return */
269function heightPropCheck(props, propName, componentName) {
270 if (typeof props[propName] !== 'number' && (!props.style || typeof props.style.maxHeight !== 'number')) {
271 return new Error('height or style.maxHeight of type \'number\' is marked as required in ' + componentName);
272 }
273}
274/* eslint-enable consistent-return */
275
276function getInitialState() {
277 return {
278 amountOfRowsToRender: 3, // First few rows for initial measurement
279 startIndex: 0, // Index where to start rendering
280
281 // Heights for extra rows to mimic scrolling
282 startHeight: 0,
283 endHeight: 0,
284
285 // Show extra row (even/odd issue)
286 showExtraRow: false
287 };
288}
289
290exports.default = VirtualizedBody;
\No newline at end of file