Vendored react-window
Brian Vaughn committed
Jun 5, 2019 at 14:27 UTC
6ff733873c662086f919baced2bb80fcffc1b343
25 files changed
+6869
-15
package.json
-1
@@ -137,7 +137,6 @@
137
"react-is": "^0.0.0-50b50c26f",
138
"react-test-renderer": "^0.0.0-50b50c26f",
139
"react-virtualized-auto-sizer": "^1.0.2",
140
- "react-window": "^1.8.0",
140
"request-promise": "^4.2.4",
141
"rimraf": "^2.6.3",
142
"scheduler": "^0.0.0-50b50c26f",
shells/browser/shared/webpack.backend.js
+1
@@ -26,6 +26,7 @@ module.exports = {
26
resolve: {
27
alias: {
28
src: resolve(__dirname, '../../../src'),
29
+ 'react-window': resolve(__dirname, '../../../vendor/react-window'),
30
},
31
},
32
plugins: [
shells/browser/shared/webpack.config.js
+1
@@ -31,6 +31,7 @@ module.exports = {
31
resolve: {
32
alias: {
33
src: resolve(__dirname, '../../../src'),
34
+ 'react-window': resolve(__dirname, '../../../vendor/react-window'),
35
},
36
},
37
plugins: [
shells/dev/webpack.config.js
+1
@@ -30,6 +30,7 @@ const config = {
30
resolve: {
31
alias: {
32
src: resolve(__dirname, '../../src'),
33
+ 'react-window': resolve(__dirname, '../../vendor/react-window'),
34
},
35
},
36
plugins: [
vendor/react-window/CHANGELOG.md
new
+96
@@ -0,0 +1,96 @@
1
+Changelog
2
+------------
3
+
4
+### 1.8.0
5
+* 🎉 Added new "smart" align option for grid and list scroll-to-item methods ([gaearon](https://github.com/gaearon) - [#209](https://github.com/bvaughn/react-window/pull/209))
6
+
7
+### 1.7.2
8
+* 🐛 Add guards to avoid invalid scroll offsets when `scrollTo()` is called with a negative offset or when `scrollToItem` is called with invalid indices (negative or too large).
9
+
10
+### 1.7.1
11
+* 🐛 Fix SSR regression introduced in 1.7.0 - ([Betree](https://github.com/Betree) - [#185](https://github.com/bvaughn/react-window/pull/185))
12
+
13
+### 1.7.0
14
+* 🎉 Grid `scrollToItem` supports optional `rowIndex` and `columnIndex` params ([jgoz](https://github.com/jgoz) - [#174](https://github.com/bvaughn/react-window/pull/174))
15
+* DEV mode checks for `WeakSet` support before using it to avoid requiring a polyfill for IE11 - ([jgoz](https://github.com/jgoz) - [#167](https://github.com/bvaughn/react-window/pull/167))
16
+
17
+### 1.6.2
18
+* 🐛 Bugfix for RTL when scrolling back towards the beginning (right) of the list.
19
+
20
+### 1.6.1
21
+* 🐛 Bugfix to account for differences between Chrome and non-Chrome browsers with regard to RTL and "scroll" events.
22
+
23
+### 1.6.0
24
+* 🎉 RTL support added for lists and grids. Special thanks to [davidgarsan](https://github.com/davidgarsan) for his support. - [#156](https://github.com/bvaughn/react-window/pull/156)
25
+* 🐛 Grid `scrollToItem` methods take scrollbar size into account when aligning items - [#153](https://github.com/bvaughn/react-window/issues/153)
26
+
27
+### 1.5.2
28
+* 🐛 Edge case bug fix for `VariableSizeList` and `VariableSizeGrid` when the number of items decreases while a scroll is in progress. - ([iamsolankiamit](https://github.com/iamsolankiamit) - [#138](https://github.com/bvaughn/react-window/pull/138))
29
+
30
+### 1.5.1
31
+* 🐛 Updated `getDerivedState` Flow annotations to address a warning in a newer version of Flow.
32
+
33
+### 1.5.0
34
+* 🎉 Added advanced memoization helpers methods `areEqual` and `shouldComponentUpdate` for item renderers. - [#114](https://github.com/bvaughn/react-window/issues/114)
35
+
36
+### 1.4.0
37
+* 🎉 List and Grid components now "overscan" (pre-render) in both directions when scrolling is not active. When scrolling is in progress, cells are only pre-rendered in the direction being scrolled. This change has been made in an effort to reduce visible flicker when scrolling starts without adding additional overhead during scroll (which is the most performance sensitive time).
38
+* 🎉 Grid components now support separate `overscanColumnsCount` and `overscanRowsCount` props. Legacy `overscanCount` prop will continue to work, but with a deprecation warning in DEV mode.
39
+* 🐛 Replaced `setTimeout` with `requestAnimationFrame` based timer, to avoid starvation issue for `isScrolling` reset. - [#106](https://github.com/bvaughn/react-window/issues/106)
40
+* 🎉 Renamed List and Grid `innerTagName` and `outerTagName` props to `innerElementType` and `outerElementType` to formalize support for attaching arbitrary props (e.g. test ids) to List and Grid inner and outer DOM elements. Legacy `innerTagName` and `outerTagName` props will continue to work, but with a deprecation warning in DEV mode.
41
+* 🐛 List re-renders items if `direction` prop changes. - [#104](https://github.com/bvaughn/react-window/issues/104)
42
+
43
+### 1.3.1
44
+* 🎉 Pass `itemData` value to custom `itemKey` callbacks when present - [#90](https://github.com/bvaughn/react-window/issues/90))
45
+
46
+### 1.3.0
47
+* (Skipped)
48
+
49
+### 1.2.4
50
+* 🐛 Added Flow annotations to memoized methods to avoid a Flow warning for newer versions of Flow
51
+
52
+### 1.2.3
53
+* 🐛 Relaxed `children` validation checks. They were too strict and didn't support new React APIs like `memo`.
54
+
55
+### 1.2.2
56
+* 🐛 Improved Flow types for class component item renderers - ([nicholas-l](https://github.com/nicholas-l) - [#77](https://github.com/bvaughn/react-window/pull/77))
57
+
58
+### 1.2.1
59
+* 🎉 Improved Flow types to include optional `itemData` parameter. ([TrySound](https://github.com/TrySound) - [#66](https://github.com/bvaughn/react-window/pull/66))
60
+* 🐛 `VariableSizeList` and `VariableSizeGrid` no longer call size getter functions with invalid index when item count is zero.
61
+
62
+### 1.2.0
63
+* 🎉 Flow types added to NPM package. ([TrySound](https://github.com/TrySound) - [#40](https://github.com/bvaughn/react-window/pull/40))
64
+* 🎉 Relaxed grid `scrollTo` method to make `scrollLeft` and `scrollTop` params _optional_ (so you can only update one axis if desired). - [#63](https://github.com/bvaughn/react-window/pull/63))
65
+* 🐛 Fixed invalid `this` pointer in `VariableSizeGrid` that broke the `resetAfter*` methods - [#58](https://github.com/bvaughn/react-window/pull/58))
66
+* Upgraded to babel 7 and used shared runtime helpers to reduce package size slightly. ([TrySound](https://github.com/TrySound) - [#48](https://github.com/bvaughn/react-window/pull/48))
67
+* Remove `overflow:hidden` from inner container ([souporserious](https://github.com/souporserious) - [#56](https://github.com/bvaughn/react-window/pull/56))
68
+
69
+### 1.1.2
70
+* 🐛 Fixed edge case `scrollToItem` bug that caused lists/grids with very few items to have negative scroll offsets.
71
+
72
+### 1.1.1
73
+* 🐛 `FixedSizeGrid` and `FixedSizeList` automatically clear style cache when item size props change.
74
+
75
+### 1.1.0
76
+* 🎉 Use explicit `constructor` and `super` to generate cleaner component code. ([Andarist](https://github.com/Andarist) - [#26](https://github.com/bvaughn/react-window/pull/26))
77
+* 🎉 Add optional `shouldForceUpdate` param reset-index methods to specify `forceUpdate` behavior. ([nihgwu](https://github.com/nihgwu) - [#32](https://github.com/bvaughn/react-window/pull/32))
78
+
79
+### 1.0.3
80
+* 🐛 Avoid unnecessary scrollbars for lists (e.g. no horizontal scrollbar for a vertical list) unless content requires them.
81
+
82
+### 1.0.2
83
+
84
+* 🎉 Enable Babel `annotate-pure-calls` option so that classes compiled by "transform-es2015-classes" are annotated with `#__PURE__`. This enables [UglifyJS to remove them if they are not referenced](https://github.com/mishoo/UglifyJS2/pull/1448), improving dead code elimination in application code. ([Andarist](https://github.com/Andarist) - [#20](https://github.com/bvaughn/react-window/pull/20))
85
+* 🎉 Update "rollup-plugin-peer-deps-external" and use new `includeDependencies` flag so that the "memoize-one" dependency does not get inlined into the Rollup bundle. ([Andarist](https://github.com/Andarist) - [#19](https://github.com/bvaughn/react-window/pull/19))
86
+* 🎉 Enable [Babel "loose" mode](https://babeljs.io/docs/en/babel-preset-env#loose) to reduce package size (-8%). ([Andarist](https://github.com/Andarist) - [#18](https://github.com/bvaughn/react-window/pull/18))
87
+
88
+### 1.0.1
89
+Updated `README.md` file to remove `@alpha` tag from NPM installation instructions.
90
+
91
+# 1.0.0
92
+Initial release of library. Includes the following components:
93
+* `FixedSizeGrid`
94
+* `FixedSizeList`
95
+* `VariableSizeGrid`
96
+* `VariableSizeList`
vendor/react-window/LICENSE.md
new
+21
@@ -0,0 +1,21 @@
1
+The MIT License (MIT)
2
+
3
+Copyright (c) 2018 Brian Vaughn
4
+
5
+Permission is hereby granted, free of charge, to any person obtaining a copy
6
+of this software and associated documentation files (the "Software"), to deal
7
+in the Software without restriction, including without limitation the rights
8
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+copies of the Software, and to permit persons to whom the Software is
10
+furnished to do so, subject to the following conditions:
11
+
12
+The above copyright notice and this permission notice shall be included in all
13
+copies or substantial portions of the Software.
14
+
15
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+SOFTWARE.
vendor/react-window/README.md
new
+88
@@ -0,0 +1,88 @@
1
+# react-window
2
+
3
+> React components for efficiently rendering large lists and tabular data
4
+
5
+[](https://yarnpkg.com/en/package/react-window) [](https://travis-ci.org/bvaughn/react-window) [](LICENSE.md)
6
+
7
+## Install
8
+
9
+```bash
10
+# Yarn
11
+yarn add react-window
12
+
13
+# NPM
14
+npm install --save react-window
15
+```
16
+
17
+## Usage
18
+
19
+Learn more at [react-window.now.sh](https://react-window.now.sh/):
20
+
21
+## Related libraries
22
+
23
+* [`react-virtualized-auto-sizer`](https://npmjs.com/package/react-virtualized-auto-sizer): HOC that grows to fit all of the available space and passes the width and height values to its child.
24
+* [`react-window-infinite-loader`](https://npmjs.com/package/react-window-infinite-loader): Helps break large data sets down into chunks that can be just-in-time loaded as they are scrolled into view. It can also be used to create infinite loading lists (e.g. Facebook or Twitter).
25
+
26
+## Frequently asked questions
27
+
28
+### How is `react-window` different from `react-virtualized`?
29
+I wrote `react-virtualized` several years ago. At the time, I was new to both React and the concept of windowing. Because of this, I made a few API decisions that I later came to regret. One of these was adding too many non-essential features and components. Once you add something to an open source project, removing it is pretty painful for users.
30
+
31
+`react-window` is a complete rewrite of `react-virtualized`. I didn't try to solve as many problems or support as many use cases. Instead I focused on making the package **smaller**<sup>1</sup> and **faster**. I also put a lot of thought into making the API (and documentation) as beginner-friendly as possible (with the caveat that windowing is still kind of an advanced use case).
32
+
33
+If `react-window` provides the functionality your project needs, I would strongly recommend using it instead of `react-virtualized`. However if you need features that only `react-virtualized` provides, you have two options:
34
+
35
+1. Use `react-virtualized`. (It's still widely used by a lot of successful projects!)
36
+2. Create a component that decorates one of the `react-window` primitives and adds the functionality you need. You may even want to release this component to NPM (as its own, standalone package)! 🙂
37
+
38
+<sup>1 - Adding a `react-virtualized` list to a CRA project increases the (gzipped) build size by ~33.5 KB. Adding a `react-window` list to a CRA project increases the (gzipped) build size by <2 KB.</sup>
39
+
40
+### Can a list or a grid fill 100% the width or height of a page?
41
+
42
+Yes. I recommend using the [`react-virtualized-auto-sizer` package](https://npmjs.com/package/react-virtualized-auto-sizer):
43
+
44
+<img width="336" alt="screen shot 2019-03-07 at 7 29 08 pm" src="https://user-images.githubusercontent.com/29597/54005716-50f41880-410f-11e9-864f-a65bbdf49e07.png">
45
+
46
+Here's a [Code Sandbox demo](https://codesandbox.io/s/3vnx878jk5).
47
+
48
+### Why is my list blank when I scroll?
49
+
50
+If your list looks something like this...
51
+
52
+<img src="https://user-images.githubusercontent.com/29597/54005352-eb535c80-410d-11e9-80b2-d3d02db1f599.gif" width="302" height="152">
53
+
54
+...then you probably forgot to use the `style` parameter! Libraries like react-window work by absolutely positioning the list items (via an inline style), so don't forget to attach it to the DOM element you render!
55
+
56
+<img width="257" alt="screen shot 2019-03-07 at 7 21 48 pm" src="https://user-images.githubusercontent.com/29597/54005433-45ecb880-410e-11e9-8721-420ff1a153da.png">
57
+
58
+### Can I lazy load data for my list?
59
+
60
+Yes. I recommend using the [`react-window-infinite-loader` package](https://npmjs.com/package/react-window-infinite-loader):
61
+
62
+<img width="368" alt="screen shot 2019-03-07 at 7 32 32 pm" src="https://user-images.githubusercontent.com/29597/54006733-653a1480-4113-11e9-907b-08ca5e27b3f9.png">
63
+
64
+Here's a [Code Sandbox demo](https://codesandbox.io/s/5wqo7z2np4).
65
+
66
+### Can I attach custom properties or event handlers?
67
+
68
+Yes, using the `outerElementType` prop.
69
+
70
+<img width="412" alt="Screen Shot 2019-03-12 at 8 58 09 AM" src="https://user-images.githubusercontent.com/29597/54215333-f9ee9a80-44a4-11e9-9142-34c67026d950.png">
71
+
72
+Here's a [Code Sandbox demo](https://codesandbox.io/s/4zqx79nww0).
73
+
74
+### Can I add gutter or padding between items?
75
+
76
+Yes, although it requires a bit of inline styling.
77
+
78
+<img width="416" alt="Screen Shot 2019-03-26 at 6 33 56 PM" src="https://user-images.githubusercontent.com/29597/55043972-c14ad700-4ff5-11e9-9caa-2e9f4d85f96c.png">
79
+
80
+Here's a [Code Sandbox demo](https://codesandbox.io/s/2w8wmlm89p).
81
+
82
+### Does this library support "sticky" items?
83
+
84
+Yes, although it requires a small amount of user code. Here's a [Code Sandbox demo](https://codesandbox.io/s/0mk3qwpl4l).
85
+
86
+## License
87
+
88
+MIT © [bvaughn](https://github.com/bvaughn)
vendor/react-window/dist/index.cjs.js
new
+1894
@@ -0,0 +1,1894 @@
1
+'use strict';
2
+
3
+Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
+
7
+var _extends = _interopDefault(require('@babel/runtime/helpers/extends'));
8
+var _inheritsLoose = _interopDefault(require('@babel/runtime/helpers/inheritsLoose'));
9
+var _assertThisInitialized = _interopDefault(require('@babel/runtime/helpers/assertThisInitialized'));
10
+var memoizeOne = _interopDefault(require('memoize-one'));
11
+var react = require('react');
12
+var _objectWithoutPropertiesLoose = _interopDefault(require('@babel/runtime/helpers/objectWithoutPropertiesLoose'));
13
+
14
+// Animation frame based implementation of setTimeout.
15
+// Inspired by Joe Lambert, https://gist.github.com/joelambert/1002116#file-requesttimeout-js
16
+var hasNativePerformanceNow = typeof performance === 'object' && typeof performance.now === 'function';
17
+var now = hasNativePerformanceNow ? function () {
18
+ return performance.now();
19
+} : function () {
20
+ return Date.now();
21
+};
22
+function cancelTimeout(timeoutID) {
23
+ cancelAnimationFrame(timeoutID.id);
24
+}
25
+function requestTimeout(callback, delay) {
26
+ var start = now();
27
+
28
+ function tick() {
29
+ if (now() - start >= delay) {
30
+ callback.call(null);
31
+ } else {
32
+ timeoutID.id = requestAnimationFrame(tick);
33
+ }
34
+ }
35
+
36
+ var timeoutID = {
37
+ id: requestAnimationFrame(tick)
38
+ };
39
+ return timeoutID;
40
+}
41
+
42
+var size = -1; // This utility copied from "dom-helpers" package.
43
+
44
+function getScrollbarSize(recalculate) {
45
+ if (recalculate === void 0) {
46
+ recalculate = false;
47
+ }
48
+
49
+ if (size === -1 || recalculate) {
50
+ var div = document.createElement('div');
51
+ var style = div.style;
52
+ style.width = '50px';
53
+ style.height = '50px';
54
+ style.overflow = 'scroll';
55
+ document.body.appendChild(div);
56
+ size = div.offsetWidth - div.clientWidth;
57
+ document.body.removeChild(div);
58
+ }
59
+
60
+ return size;
61
+}
62
+
63
+var IS_SCROLLING_DEBOUNCE_INTERVAL = 150;
64
+
65
+var defaultItemKey = function defaultItemKey(_ref) {
66
+ var columnIndex = _ref.columnIndex,
67
+ data = _ref.data,
68
+ rowIndex = _ref.rowIndex;
69
+ return rowIndex + ":" + columnIndex;
70
+}; // In DEV mode, this Set helps us only log a warning once per component instance.
71
+// This avoids spamming the console every time a render happens.
72
+
73
+
74
+var devWarningsOverscanCount = null;
75
+var devWarningsTagName = null;
76
+
77
+if (process.env.NODE_ENV !== 'production') {
78
+ if (typeof window !== 'undefined' && typeof window.WeakSet !== 'undefined') {
79
+ devWarningsOverscanCount =
80
+ /*#__PURE__*/
81
+ new WeakSet();
82
+ devWarningsTagName =
83
+ /*#__PURE__*/
84
+ new WeakSet();
85
+ }
86
+}
87
+
88
+function createGridComponent(_ref2) {
89
+ var _class, _temp;
90
+
91
+ var getColumnOffset = _ref2.getColumnOffset,
92
+ getColumnStartIndexForOffset = _ref2.getColumnStartIndexForOffset,
93
+ getColumnStopIndexForStartIndex = _ref2.getColumnStopIndexForStartIndex,
94
+ getColumnWidth = _ref2.getColumnWidth,
95
+ getEstimatedTotalHeight = _ref2.getEstimatedTotalHeight,
96
+ getEstimatedTotalWidth = _ref2.getEstimatedTotalWidth,
97
+ getOffsetForColumnAndAlignment = _ref2.getOffsetForColumnAndAlignment,
98
+ getOffsetForRowAndAlignment = _ref2.getOffsetForRowAndAlignment,
99
+ getRowHeight = _ref2.getRowHeight,
100
+ getRowOffset = _ref2.getRowOffset,
101
+ getRowStartIndexForOffset = _ref2.getRowStartIndexForOffset,
102
+ getRowStopIndexForStartIndex = _ref2.getRowStopIndexForStartIndex,
103
+ initInstanceProps = _ref2.initInstanceProps,
104
+ shouldResetStyleCacheOnItemSizeChange = _ref2.shouldResetStyleCacheOnItemSizeChange,
105
+ validateProps = _ref2.validateProps;
106
+ return _temp = _class =
107
+ /*#__PURE__*/
108
+ function (_PureComponent) {
109
+ _inheritsLoose(Grid, _PureComponent);
110
+
111
+ // Always use explicit constructor for React components.
112
+ // It produces less code after transpilation. (#26)
113
+ // eslint-disable-next-line no-useless-constructor
114
+ function Grid(props) {
115
+ var _this;
116
+
117
+ _this = _PureComponent.call(this, props) || this;
118
+ _this._instanceProps = initInstanceProps(_this.props, _assertThisInitialized(_assertThisInitialized(_this)));
119
+ _this._resetIsScrollingTimeoutId = null;
120
+ _this._outerRef = void 0;
121
+ _this.state = {
122
+ instance: _assertThisInitialized(_assertThisInitialized(_this)),
123
+ isScrolling: false,
124
+ horizontalScrollDirection: 'forward',
125
+ scrollLeft: typeof _this.props.initialScrollLeft === 'number' ? _this.props.initialScrollLeft : 0,
126
+ scrollTop: typeof _this.props.initialScrollTop === 'number' ? _this.props.initialScrollTop : 0,
127
+ scrollUpdateWasRequested: false,
128
+ verticalScrollDirection: 'forward'
129
+ };
130
+ _this._callOnItemsRendered = void 0;
131
+ _this._callOnItemsRendered = memoizeOne(function (overscanColumnStartIndex, overscanColumnStopIndex, overscanRowStartIndex, overscanRowStopIndex, visibleColumnStartIndex, visibleColumnStopIndex, visibleRowStartIndex, visibleRowStopIndex) {
132
+ return _this.props.onItemsRendered({
133
+ overscanColumnStartIndex: overscanColumnStartIndex,
134
+ overscanColumnStopIndex: overscanColumnStopIndex,
135
+ overscanRowStartIndex: overscanRowStartIndex,
136
+ overscanRowStopIndex: overscanRowStopIndex,
137
+ visibleColumnStartIndex: visibleColumnStartIndex,
138
+ visibleColumnStopIndex: visibleColumnStopIndex,
139
+ visibleRowStartIndex: visibleRowStartIndex,
140
+ visibleRowStopIndex: visibleRowStopIndex
141
+ });
142
+ });
143
+ _this._callOnScroll = void 0;
144
+ _this._callOnScroll = memoizeOne(function (scrollLeft, scrollTop, horizontalScrollDirection, verticalScrollDirection, scrollUpdateWasRequested) {
145
+ return _this.props.onScroll({
146
+ horizontalScrollDirection: horizontalScrollDirection,
147
+ scrollLeft: scrollLeft,
148
+ scrollTop: scrollTop,
149
+ verticalScrollDirection: verticalScrollDirection,
150
+ scrollUpdateWasRequested: scrollUpdateWasRequested
151
+ });
152
+ });
153
+ _this._getItemStyle = void 0;
154
+
155
+ _this._getItemStyle = function (rowIndex, columnIndex) {
156
+ var _this$props = _this.props,
157
+ columnWidth = _this$props.columnWidth,
158
+ direction = _this$props.direction,
159
+ rowHeight = _this$props.rowHeight;
160
+
161
+ var itemStyleCache = _this._getItemStyleCache(shouldResetStyleCacheOnItemSizeChange && columnWidth, shouldResetStyleCacheOnItemSizeChange && direction, shouldResetStyleCacheOnItemSizeChange && rowHeight);
162
+
163
+ var key = rowIndex + ":" + columnIndex;
164
+ var style;
165
+
166
+ if (itemStyleCache.hasOwnProperty(key)) {
167
+ style = itemStyleCache[key];
168
+ } else {
169
+ var _style;
170
+
171
+ itemStyleCache[key] = style = (_style = {
172
+ position: 'absolute'
173
+ }, _style[direction === 'rtl' ? 'right' : 'left'] = getColumnOffset(_this.props, columnIndex, _this._instanceProps), _style.top = getRowOffset(_this.props, rowIndex, _this._instanceProps), _style.height = getRowHeight(_this.props, rowIndex, _this._instanceProps), _style.width = getColumnWidth(_this.props, columnIndex, _this._instanceProps), _style);
174
+ }
175
+
176
+ return style;
177
+ };
178
+
179
+ _this._getItemStyleCache = void 0;
180
+ _this._getItemStyleCache = memoizeOne(function (_, __, ___) {
181
+ return {};
182
+ });
183
+
184
+ _this._onScroll = function (event) {
185
+ var _event$currentTarget = event.currentTarget,
186
+ clientWidth = _event$currentTarget.clientWidth,
187
+ scrollLeft = _event$currentTarget.scrollLeft,
188
+ scrollTop = _event$currentTarget.scrollTop,
189
+ scrollWidth = _event$currentTarget.scrollWidth;
190
+
191
+ _this.setState(function (prevState) {
192
+ if (prevState.scrollLeft === scrollLeft && prevState.scrollTop === scrollTop) {
193
+ // Scroll position may have been updated by cDM/cDU,
194
+ // In which case we don't need to trigger another render,
195
+ // And we don't want to update state.isScrolling.
196
+ return null;
197
+ }
198
+
199
+ var direction = _this.props.direction; // HACK According to the spec, scrollLeft should be negative for RTL aligned elements.
200
+ // Chrome does not seem to adhere; its scrollLeft values are positive (measured relative to the left).
201
+ // See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
202
+
203
+ var calculatedScrollLeft = scrollLeft;
204
+
205
+ if (direction === 'rtl') {
206
+ if (scrollLeft <= 0) {
207
+ calculatedScrollLeft = -scrollLeft;
208
+ } else {
209
+ calculatedScrollLeft = scrollWidth - clientWidth - scrollLeft;
210
+ }
211
+ }
212
+
213
+ return {
214
+ isScrolling: true,
215
+ horizontalScrollDirection: prevState.scrollLeft < scrollLeft ? 'forward' : 'backward',
216
+ scrollLeft: calculatedScrollLeft,
217
+ scrollTop: scrollTop,
218
+ verticalScrollDirection: prevState.scrollTop < scrollTop ? 'forward' : 'backward',
219
+ scrollUpdateWasRequested: false
220
+ };
221
+ }, _this._resetIsScrollingDebounced);
222
+ };
223
+
224
+ _this._outerRefSetter = function (ref) {
225
+ var outerRef = _this.props.outerRef;
226
+ _this._outerRef = ref;
227
+
228
+ if (typeof outerRef === 'function') {
229
+ outerRef(ref);
230
+ } else if (outerRef != null && typeof outerRef === 'object' && outerRef.hasOwnProperty('current')) {
231
+ outerRef.current = ref;
232
+ }
233
+ };
234
+
235
+ _this._resetIsScrollingDebounced = function () {
236
+ if (_this._resetIsScrollingTimeoutId !== null) {
237
+ cancelTimeout(_this._resetIsScrollingTimeoutId);
238
+ }
239
+
240
+ _this._resetIsScrollingTimeoutId = requestTimeout(_this._resetIsScrolling, IS_SCROLLING_DEBOUNCE_INTERVAL);
241
+ };
242
+
243
+ _this._resetIsScrolling = function () {
244
+ _this._resetIsScrollingTimeoutId = null;
245
+
246
+ _this.setState({
247
+ isScrolling: false
248
+ }, function () {
249
+ // Clear style cache after state update has been committed.
250
+ // This way we don't break pure sCU for items that don't use isScrolling param.
251
+ _this._getItemStyleCache(-1);
252
+ });
253
+ };
254
+
255
+ return _this;
256
+ }
257
+
258
+ Grid.getDerivedStateFromProps = function getDerivedStateFromProps(nextProps, prevState) {
259
+ validateSharedProps(nextProps, prevState);
260
+ validateProps(nextProps);
261
+ return null;
262
+ };
263
+
264
+ var _proto = Grid.prototype;
265
+
266
+ _proto.scrollTo = function scrollTo(_ref3) {
267
+ var scrollLeft = _ref3.scrollLeft,
268
+ scrollTop = _ref3.scrollTop;
269
+
270
+ if (scrollLeft !== undefined) {
271
+ scrollLeft = Math.max(0, scrollLeft);
272
+ }
273
+
274
+ if (scrollTop !== undefined) {
275
+ scrollTop = Math.max(0, scrollTop);
276
+ }
277
+
278
+ this.setState(function (prevState) {
279
+ if (scrollLeft === undefined) {
280
+ scrollLeft = prevState.scrollLeft;
281
+ }
282
+
283
+ if (scrollTop === undefined) {
284
+ scrollTop = prevState.scrollTop;
285
+ }
286
+
287
+ if (prevState.scrollLeft === scrollLeft && prevState.scrollTop === scrollTop) {
288
+ return null;
289
+ }
290
+
291
+ return {
292
+ horizontalScrollDirection: prevState.scrollLeft < scrollLeft ? 'forward' : 'backward',
293
+ scrollLeft: scrollLeft,
294
+ scrollTop: scrollTop,
295
+ scrollUpdateWasRequested: true,
296
+ verticalScrollDirection: prevState.scrollTop < scrollTop ? 'forward' : 'backward'
297
+ };
298
+ }, this._resetIsScrollingDebounced);
299
+ };
300
+
301
+ _proto.scrollToItem = function scrollToItem(_ref4) {
302
+ var _ref4$align = _ref4.align,
303
+ align = _ref4$align === void 0 ? 'auto' : _ref4$align,
304
+ columnIndex = _ref4.columnIndex,
305
+ rowIndex = _ref4.rowIndex;
306
+ var _this$props2 = this.props,
307
+ columnCount = _this$props2.columnCount,
308
+ height = _this$props2.height,
309
+ rowCount = _this$props2.rowCount,
310
+ width = _this$props2.width;
311
+ var _this$state = this.state,
312
+ scrollLeft = _this$state.scrollLeft,
313
+ scrollTop = _this$state.scrollTop;
314
+ var scrollbarSize = getScrollbarSize();
315
+
316
+ if (columnIndex !== undefined) {
317
+ columnIndex = Math.max(0, Math.min(columnIndex, columnCount - 1));
318
+ }
319
+
320
+ if (rowIndex !== undefined) {
321
+ rowIndex = Math.max(0, Math.min(rowIndex, rowCount - 1));
322
+ }
323
+
324
+ var estimatedTotalHeight = getEstimatedTotalHeight(this.props, this._instanceProps);
325
+ var estimatedTotalWidth = getEstimatedTotalWidth(this.props, this._instanceProps); // The scrollbar size should be considered when scrolling an item into view,
326
+ // to ensure it's fully visible.
327
+ // But we only need to account for its size when it's actually visible.
328
+
329
+ var horizontalScrollbarSize = estimatedTotalWidth > width ? scrollbarSize : 0;
330
+ var verticalScrollbarSize = estimatedTotalHeight > height ? scrollbarSize : 0;
331
+ this.scrollTo({
332
+ scrollLeft: columnIndex !== undefined ? getOffsetForColumnAndAlignment(this.props, columnIndex, align, scrollLeft, this._instanceProps, verticalScrollbarSize) : scrollLeft,
333
+ scrollTop: rowIndex !== undefined ? getOffsetForRowAndAlignment(this.props, rowIndex, align, scrollTop, this._instanceProps, horizontalScrollbarSize) : scrollTop
334
+ });
335
+ };
336
+
337
+ _proto.componentDidMount = function componentDidMount() {
338
+ var _this$props3 = this.props,
339
+ initialScrollLeft = _this$props3.initialScrollLeft,
340
+ initialScrollTop = _this$props3.initialScrollTop;
341
+
342
+ if (typeof initialScrollLeft === 'number' && this._outerRef != null) {
343
+ this._outerRef.scrollLeft = initialScrollLeft;
344
+ }
345
+
346
+ if (typeof initialScrollTop === 'number' && this._outerRef != null) {
347
+ this._outerRef.scrollTop = initialScrollTop;
348
+ }
349
+
350
+ this._callPropsCallbacks();
351
+ };
352
+
353
+ _proto.componentDidUpdate = function componentDidUpdate() {
354
+ var _this$state2 = this.state,
355
+ scrollLeft = _this$state2.scrollLeft,
356
+ scrollTop = _this$state2.scrollTop,
357
+ scrollUpdateWasRequested = _this$state2.scrollUpdateWasRequested;
358
+
359
+ if (scrollUpdateWasRequested && this._outerRef !== null) {
360
+ this._outerRef.scrollLeft = scrollLeft;
361
+ this._outerRef.scrollTop = scrollTop;
362
+ }
363
+
364
+ this._callPropsCallbacks();
365
+ };
366
+
367
+ _proto.componentWillUnmount = function componentWillUnmount() {
368
+ if (this._resetIsScrollingTimeoutId !== null) {
369
+ cancelTimeout(this._resetIsScrollingTimeoutId);
370
+ }
371
+ };
372
+
373
+ _proto.render = function render() {
374
+ var _this$props4 = this.props,
375
+ children = _this$props4.children,
376
+ className = _this$props4.className,
377
+ columnCount = _this$props4.columnCount,
378
+ direction = _this$props4.direction,
379
+ height = _this$props4.height,
380
+ innerRef = _this$props4.innerRef,
381
+ innerElementType = _this$props4.innerElementType,
382
+ innerTagName = _this$props4.innerTagName,
383
+ itemData = _this$props4.itemData,
384
+ _this$props4$itemKey = _this$props4.itemKey,
385
+ itemKey = _this$props4$itemKey === void 0 ? defaultItemKey : _this$props4$itemKey,
386
+ outerElementType = _this$props4.outerElementType,
387
+ outerTagName = _this$props4.outerTagName,
388
+ rowCount = _this$props4.rowCount,
389
+ style = _this$props4.style,
390
+ useIsScrolling = _this$props4.useIsScrolling,
391
+ width = _this$props4.width;
392
+ var isScrolling = this.state.isScrolling;
393
+
394
+ var _this$_getHorizontalR = this._getHorizontalRangeToRender(),
395
+ columnStartIndex = _this$_getHorizontalR[0],
396
+ columnStopIndex = _this$_getHorizontalR[1];
397
+
398
+ var _this$_getVerticalRan = this._getVerticalRangeToRender(),
399
+ rowStartIndex = _this$_getVerticalRan[0],
400
+ rowStopIndex = _this$_getVerticalRan[1];
401
+
402
+ var items = [];
403
+
404
+ if (columnCount > 0 && rowCount) {
405
+ for (var _rowIndex = rowStartIndex; _rowIndex <= rowStopIndex; _rowIndex++) {
406
+ for (var _columnIndex = columnStartIndex; _columnIndex <= columnStopIndex; _columnIndex++) {
407
+ items.push(react.createElement(children, {
408
+ columnIndex: _columnIndex,
409
+ data: itemData,
410
+ isScrolling: useIsScrolling ? isScrolling : undefined,
411
+ key: itemKey({
412
+ columnIndex: _columnIndex,
413
+ data: itemData,
414
+ rowIndex: _rowIndex
415
+ }),
416
+ rowIndex: _rowIndex,
417
+ style: this._getItemStyle(_rowIndex, _columnIndex)
418
+ }));
419
+ }
420
+ }
421
+ } // Read this value AFTER items have been created,
422
+ // So their actual sizes (if variable) are taken into consideration.
423
+
424
+
425
+ var estimatedTotalHeight = getEstimatedTotalHeight(this.props, this._instanceProps);
426
+ var estimatedTotalWidth = getEstimatedTotalWidth(this.props, this._instanceProps);
427
+ return react.createElement(outerElementType || outerTagName || 'div', {
428
+ className: className,
429
+ onScroll: this._onScroll,
430
+ ref: this._outerRefSetter,
431
+ style: _extends({
432
+ position: 'relative',
433
+ height: height,
434
+ width: width,
435
+ overflow: 'auto',
436
+ WebkitOverflowScrolling: 'touch',
437
+ willChange: 'transform',
438
+ direction: direction
439
+ }, style)
440
+ }, react.createElement(innerElementType || innerTagName || 'div', {
441
+ children: items,
442
+ ref: innerRef,
443
+ style: {
444
+ height: estimatedTotalHeight,
445
+ pointerEvents: isScrolling ? 'none' : '',
446
+ width: estimatedTotalWidth
447
+ }
448
+ }));
449
+ };
450
+
451
+ _proto._callPropsCallbacks = function _callPropsCallbacks() {
452
+ var _this$props5 = this.props,
453
+ columnCount = _this$props5.columnCount,
454
+ onItemsRendered = _this$props5.onItemsRendered,
455
+ onScroll = _this$props5.onScroll,
456
+ rowCount = _this$props5.rowCount;
457
+
458
+ if (typeof onItemsRendered === 'function') {
459
+ if (columnCount > 0 && rowCount > 0) {
460
+ var _this$_getHorizontalR2 = this._getHorizontalRangeToRender(),
461
+ _overscanColumnStartIndex = _this$_getHorizontalR2[0],
462
+ _overscanColumnStopIndex = _this$_getHorizontalR2[1],
463
+ _visibleColumnStartIndex = _this$_getHorizontalR2[2],
464
+ _visibleColumnStopIndex = _this$_getHorizontalR2[3];
465
+
466
+ var _this$_getVerticalRan2 = this._getVerticalRangeToRender(),
467
+ _overscanRowStartIndex = _this$_getVerticalRan2[0],
468
+ _overscanRowStopIndex = _this$_getVerticalRan2[1],
469
+ _visibleRowStartIndex = _this$_getVerticalRan2[2],
470
+ _visibleRowStopIndex = _this$_getVerticalRan2[3];
471
+
472
+ this._callOnItemsRendered(_overscanColumnStartIndex, _overscanColumnStopIndex, _overscanRowStartIndex, _overscanRowStopIndex, _visibleColumnStartIndex, _visibleColumnStopIndex, _visibleRowStartIndex, _visibleRowStopIndex);
473
+ }
474
+ }
475
+
476
+ if (typeof onScroll === 'function') {
477
+ var _this$state3 = this.state,
478
+ _horizontalScrollDirection = _this$state3.horizontalScrollDirection,
479
+ _scrollLeft = _this$state3.scrollLeft,
480
+ _scrollTop = _this$state3.scrollTop,
481
+ _scrollUpdateWasRequested = _this$state3.scrollUpdateWasRequested,
482
+ _verticalScrollDirection = _this$state3.verticalScrollDirection;
483
+
484
+ this._callOnScroll(_scrollLeft, _scrollTop, _horizontalScrollDirection, _verticalScrollDirection, _scrollUpdateWasRequested);
485
+ }
486
+ }; // Lazily create and cache item styles while scrolling,
487
+ // So that pure component sCU will prevent re-renders.
488
+ // We maintain this cache, and pass a style prop rather than index,
489
+ // So that List can clear cached styles and force item re-render if necessary.
490
+
491
+
492
+ _proto._getHorizontalRangeToRender = function _getHorizontalRangeToRender() {
493
+ var _this$props6 = this.props,
494
+ columnCount = _this$props6.columnCount,
495
+ overscanColumnsCount = _this$props6.overscanColumnsCount,
496
+ overscanCount = _this$props6.overscanCount,
497
+ rowCount = _this$props6.rowCount;
498
+ var _this$state4 = this.state,
499
+ horizontalScrollDirection = _this$state4.horizontalScrollDirection,
500
+ isScrolling = _this$state4.isScrolling,
501
+ scrollLeft = _this$state4.scrollLeft;
502
+ var overscanCountResolved = overscanColumnsCount || overscanCount || 1;
503
+
504
+ if (columnCount === 0 || rowCount === 0) {
505
+ return [0, 0, 0, 0];
506
+ }
507
+
508
+ var startIndex = getColumnStartIndexForOffset(this.props, scrollLeft, this._instanceProps);
509
+ var stopIndex = getColumnStopIndexForStartIndex(this.props, startIndex, scrollLeft, this._instanceProps); // Overscan by one item in each direction so that tab/focus works.
510
+ // If there isn't at least one extra item, tab loops back around.
511
+
512
+ var overscanBackward = !isScrolling || horizontalScrollDirection === 'backward' ? Math.max(1, overscanCountResolved) : 1;
513
+ var overscanForward = !isScrolling || horizontalScrollDirection === 'forward' ? Math.max(1, overscanCountResolved) : 1;
514
+ return [Math.max(0, startIndex - overscanBackward), Math.max(0, Math.min(columnCount - 1, stopIndex + overscanForward)), startIndex, stopIndex];
515
+ };
516
+
517
+ _proto._getVerticalRangeToRender = function _getVerticalRangeToRender() {
518
+ var _this$props7 = this.props,
519
+ columnCount = _this$props7.columnCount,
520
+ overscanCount = _this$props7.overscanCount,
521
+ overscanRowsCount = _this$props7.overscanRowsCount,
522
+ rowCount = _this$props7.rowCount;
523
+ var _this$state5 = this.state,
524
+ isScrolling = _this$state5.isScrolling,
525
+ verticalScrollDirection = _this$state5.verticalScrollDirection,
526
+ scrollTop = _this$state5.scrollTop;
527
+ var overscanCountResolved = overscanRowsCount || overscanCount || 1;
528
+
529
+ if (columnCount === 0 || rowCount === 0) {
530
+ return [0, 0, 0, 0];
531
+ }
532
+
533
+ var startIndex = getRowStartIndexForOffset(this.props, scrollTop, this._instanceProps);
534
+ var stopIndex = getRowStopIndexForStartIndex(this.props, startIndex, scrollTop, this._instanceProps); // Overscan by one item in each direction so that tab/focus works.
535
+ // If there isn't at least one extra item, tab loops back around.
536
+
537
+ var overscanBackward = !isScrolling || verticalScrollDirection === 'backward' ? Math.max(1, overscanCountResolved) : 1;
538
+ var overscanForward = !isScrolling || verticalScrollDirection === 'forward' ? Math.max(1, overscanCountResolved) : 1;
539
+ return [Math.max(0, startIndex - overscanBackward), Math.max(0, Math.min(rowCount - 1, stopIndex + overscanForward)), startIndex, stopIndex];
540
+ };
541
+
542
+ return Grid;
543
+ }(react.PureComponent), _class.defaultProps = {
544
+ direction: 'ltr',
545
+ itemData: undefined,
546
+ useIsScrolling: false
547
+ }, _temp;
548
+}
549
+
550
+var validateSharedProps = function validateSharedProps(_ref5, _ref6) {
551
+ var children = _ref5.children,
552
+ direction = _ref5.direction,
553
+ height = _ref5.height,
554
+ innerTagName = _ref5.innerTagName,
555
+ outerTagName = _ref5.outerTagName,
556
+ overscanCount = _ref5.overscanCount,
557
+ width = _ref5.width;
558
+ var instance = _ref6.instance;
559
+
560
+ if (process.env.NODE_ENV !== 'production') {
561
+ if (typeof overscanCount === 'number') {
562
+ if (devWarningsOverscanCount && !devWarningsOverscanCount.has(instance)) {
563
+ devWarningsOverscanCount.add(instance);
564
+ console.warn('The overscanCount prop has been deprecated. ' + 'Please use the overscanColumnsCount and overscanRowsCount props instead.');
565
+ }
566
+ }
567
+
568
+ if (innerTagName != null || outerTagName != null) {
569
+ if (devWarningsTagName && !devWarningsTagName.has(instance)) {
570
+ devWarningsTagName.add(instance);
571
+ console.warn('The innerTagName and outerTagName props have been deprecated. ' + 'Please use the innerElementType and outerElementType props instead.');
572
+ }
573
+ }
574
+
575
+ if (children == null) {
576
+ throw Error('An invalid "children" prop has been specified. ' + 'Value should be a React component. ' + ("\"" + (children === null ? 'null' : typeof children) + "\" was specified."));
577
+ }
578
+
579
+ switch (direction) {
580
+ case 'ltr':
581
+ case 'rtl':
582
+ // Valid values
583
+ break;
584
+
585
+ default:
586
+ throw Error('An invalid "direction" prop has been specified. ' + 'Value should be either "ltr" or "rtl". ' + ("\"" + direction + "\" was specified."));
587
+ }
588
+
589
+ if (typeof width !== 'number') {
590
+ throw Error('An invalid "width" prop has been specified. ' + 'Grids must specify a number for width. ' + ("\"" + (width === null ? 'null' : typeof width) + "\" was specified."));
591
+ }
592
+
593
+ if (typeof height !== 'number') {
594
+ throw Error('An invalid "height" prop has been specified. ' + 'Grids must specify a number for height. ' + ("\"" + (height === null ? 'null' : typeof height) + "\" was specified."));
595
+ }
596
+ }
597
+};
598
+
599
+var DEFAULT_ESTIMATED_ITEM_SIZE = 50;
600
+
601
+var getEstimatedTotalHeight = function getEstimatedTotalHeight(_ref, _ref2) {
602
+ var rowCount = _ref.rowCount;
603
+ var rowMetadataMap = _ref2.rowMetadataMap,
604
+ estimatedRowHeight = _ref2.estimatedRowHeight,
605
+ lastMeasuredRowIndex = _ref2.lastMeasuredRowIndex;
606
+ var totalSizeOfMeasuredRows = 0; // Edge case check for when the number of items decreases while a scroll is in progress.
607
+ // https://github.com/bvaughn/react-window/pull/138
608
+
609
+ if (lastMeasuredRowIndex >= rowCount) {
610
+ lastMeasuredRowIndex = rowCount - 1;
611
+ }
612
+
613
+ if (lastMeasuredRowIndex >= 0) {
614
+ var itemMetadata = rowMetadataMap[lastMeasuredRowIndex];
615
+ totalSizeOfMeasuredRows = itemMetadata.offset + itemMetadata.size;
616
+ }
617
+
618
+ var numUnmeasuredItems = rowCount - lastMeasuredRowIndex - 1;
619
+ var totalSizeOfUnmeasuredItems = numUnmeasuredItems * estimatedRowHeight;
620
+ return totalSizeOfMeasuredRows + totalSizeOfUnmeasuredItems;
621
+};
622
+
623
+var getEstimatedTotalWidth = function getEstimatedTotalWidth(_ref3, _ref4) {
624
+ var columnCount = _ref3.columnCount;
625
+ var columnMetadataMap = _ref4.columnMetadataMap,
626
+ estimatedColumnWidth = _ref4.estimatedColumnWidth,
627
+ lastMeasuredColumnIndex = _ref4.lastMeasuredColumnIndex;
628
+ var totalSizeOfMeasuredRows = 0; // Edge case check for when the number of items decreases while a scroll is in progress.
629
+ // https://github.com/bvaughn/react-window/pull/138
630
+
631
+ if (lastMeasuredColumnIndex >= columnCount) {
632
+ lastMeasuredColumnIndex = columnCount - 1;
633
+ }
634
+
635
+ if (lastMeasuredColumnIndex >= 0) {
636
+ var itemMetadata = columnMetadataMap[lastMeasuredColumnIndex];
637
+ totalSizeOfMeasuredRows = itemMetadata.offset + itemMetadata.size;
638
+ }
639
+
640
+ var numUnmeasuredItems = columnCount - lastMeasuredColumnIndex - 1;
641
+ var totalSizeOfUnmeasuredItems = numUnmeasuredItems * estimatedColumnWidth;
642
+ return totalSizeOfMeasuredRows + totalSizeOfUnmeasuredItems;
643
+};
644
+
645
+var getItemMetadata = function getItemMetadata(itemType, props, index, instanceProps) {
646
+ var itemMetadataMap, itemSize, lastMeasuredIndex;
647
+
648
+ if (itemType === 'column') {
649
+ itemMetadataMap = instanceProps.columnMetadataMap;
650
+ itemSize = props.columnWidth;
651
+ lastMeasuredIndex = instanceProps.lastMeasuredColumnIndex;
652
+ } else {
653
+ itemMetadataMap = instanceProps.rowMetadataMap;
654
+ itemSize = props.rowHeight;
655
+ lastMeasuredIndex = instanceProps.lastMeasuredRowIndex;
656
+ }
657
+
658
+ if (index > lastMeasuredIndex) {
659
+ var offset = 0;
660
+
661
+ if (lastMeasuredIndex >= 0) {
662
+ var itemMetadata = itemMetadataMap[lastMeasuredIndex];
663
+ offset = itemMetadata.offset + itemMetadata.size;
664
+ }
665
+
666
+ for (var i = lastMeasuredIndex + 1; i <= index; i++) {
667
+ var size = itemSize(i);
668
+ itemMetadataMap[i] = {
669
+ offset: offset,
670
+ size: size
671
+ };
672
+ offset += size;
673
+ }
674
+
675
+ if (itemType === 'column') {
676
+ instanceProps.lastMeasuredColumnIndex = index;
677
+ } else {
678
+ instanceProps.lastMeasuredRowIndex = index;
679
+ }
680
+ }
681
+
682
+ return itemMetadataMap[index];
683
+};
684
+
685
+var findNearestItem = function findNearestItem(itemType, props, instanceProps, offset) {
686
+ var itemMetadataMap, lastMeasuredIndex;
687
+
688
+ if (itemType === 'column') {
689
+ itemMetadataMap = instanceProps.columnMetadataMap;
690
+ lastMeasuredIndex = instanceProps.lastMeasuredColumnIndex;
691
+ } else {
692
+ itemMetadataMap = instanceProps.rowMetadataMap;
693
+ lastMeasuredIndex = instanceProps.lastMeasuredRowIndex;
694
+ }
695
+
696
+ var lastMeasuredItemOffset = lastMeasuredIndex > 0 ? itemMetadataMap[lastMeasuredIndex].offset : 0;
697
+
698
+ if (lastMeasuredItemOffset >= offset) {
699
+ // If we've already measured items within this range just use a binary search as it's faster.
700
+ return findNearestItemBinarySearch(itemType, props, instanceProps, lastMeasuredIndex, 0, offset);
701
+ } else {
702
+ // If we haven't yet measured this high, fallback to an exponential search with an inner binary search.
703
+ // The exponential search avoids pre-computing sizes for the full set of items as a binary search would.
704
+ // The overall complexity for this approach is O(log n).
705
+ return findNearestItemExponentialSearch(itemType, props, instanceProps, Math.max(0, lastMeasuredIndex), offset);
706
+ }
707
+};
708
+
709
+var findNearestItemBinarySearch = function findNearestItemBinarySearch(itemType, props, instanceProps, high, low, offset) {
710
+ while (low <= high) {
711
+ var middle = low + Math.floor((high - low) / 2);
712
+ var currentOffset = getItemMetadata(itemType, props, middle, instanceProps).offset;
713
+
714
+ if (currentOffset === offset) {
715
+ return middle;
716
+ } else if (currentOffset < offset) {
717
+ low = middle + 1;
718
+ } else if (currentOffset > offset) {
719
+ high = middle - 1;
720
+ }
721
+ }
722
+
723
+ if (low > 0) {
724
+ return low - 1;
725
+ } else {
726
+ return 0;
727
+ }
728
+};
729
+
730
+var findNearestItemExponentialSearch = function findNearestItemExponentialSearch(itemType, props, instanceProps, index, offset) {
731
+ var itemCount = itemType === 'column' ? props.columnCount : props.rowCount;
732
+ var interval = 1;
733
+
734
+ while (index < itemCount && getItemMetadata(itemType, props, index, instanceProps).offset < offset) {
735
+ index += interval;
736
+ interval *= 2;
737
+ }
738
+
739
+ return findNearestItemBinarySearch(itemType, props, instanceProps, Math.min(index, itemCount - 1), Math.floor(index / 2), offset);
740
+};
741
+
742
+var getOffsetForIndexAndAlignment = function getOffsetForIndexAndAlignment(itemType, props, index, align, scrollOffset, instanceProps, scrollbarSize) {
743
+ var size = itemType === 'column' ? props.width : props.height;
744
+ var itemMetadata = getItemMetadata(itemType, props, index, instanceProps); // Get estimated total size after ItemMetadata is computed,
745
+ // To ensure it reflects actual measurements instead of just estimates.
746
+
747
+ var estimatedTotalSize = itemType === 'column' ? getEstimatedTotalWidth(props, instanceProps) : getEstimatedTotalHeight(props, instanceProps);
748
+ var maxOffset = Math.max(0, Math.min(estimatedTotalSize - size, itemMetadata.offset));
749
+ var minOffset = Math.max(0, itemMetadata.offset - size + scrollbarSize + itemMetadata.size);
750
+
751
+ if (align === 'smart') {
752
+ if (scrollOffset >= minOffset - size && scrollOffset <= maxOffset + size) {
753
+ align = 'auto';
754
+ } else {
755
+ align = 'center';
756
+ }
757
+ }
758
+
759
+ switch (align) {
760
+ case 'start':
761
+ return maxOffset;
762
+
763
+ case 'end':
764
+ return minOffset;
765
+
766
+ case 'center':
767
+ return Math.round(minOffset + (maxOffset - minOffset) / 2);
768
+
769
+ case 'auto':
770
+ default:
771
+ if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
772
+ return scrollOffset;
773
+ } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
774
+ return minOffset;
775
+ } else {
776
+ return maxOffset;
777
+ }
778
+
779
+ }
780
+};
781
+
782
+var VariableSizeGrid =
783
+/*#__PURE__*/
784
+createGridComponent({
785
+ getColumnOffset: function getColumnOffset(props, index, instanceProps) {
786
+ return getItemMetadata('column', props, index, instanceProps).offset;
787
+ },
788
+ getColumnStartIndexForOffset: function getColumnStartIndexForOffset(props, scrollLeft, instanceProps) {
789
+ return findNearestItem('column', props, instanceProps, scrollLeft);
790
+ },
791
+ getColumnStopIndexForStartIndex: function getColumnStopIndexForStartIndex(props, startIndex, scrollLeft, instanceProps) {
792
+ var columnCount = props.columnCount,
793
+ width = props.width;
794
+ var itemMetadata = getItemMetadata('column', props, startIndex, instanceProps);
795
+ var maxOffset = scrollLeft + width;
796
+ var offset = itemMetadata.offset + itemMetadata.size;
797
+ var stopIndex = startIndex;
798
+
799
+ while (stopIndex < columnCount - 1 && offset < maxOffset) {
800
+ stopIndex++;
801
+ offset += getItemMetadata('column', props, stopIndex, instanceProps).size;
802
+ }
803
+
804
+ return stopIndex;
805
+ },
806
+ getColumnWidth: function getColumnWidth(props, index, instanceProps) {
807
+ return instanceProps.columnMetadataMap[index].size;
808
+ },
809
+ getEstimatedTotalHeight: getEstimatedTotalHeight,
810
+ getEstimatedTotalWidth: getEstimatedTotalWidth,
811
+ getOffsetForColumnAndAlignment: function getOffsetForColumnAndAlignment(props, index, align, scrollOffset, instanceProps, scrollbarSize) {
812
+ return getOffsetForIndexAndAlignment('column', props, index, align, scrollOffset, instanceProps, scrollbarSize);
813
+ },
814
+ getOffsetForRowAndAlignment: function getOffsetForRowAndAlignment(props, index, align, scrollOffset, instanceProps, scrollbarSize) {
815
+ return getOffsetForIndexAndAlignment('row', props, index, align, scrollOffset, instanceProps, scrollbarSize);
816
+ },
817
+ getRowOffset: function getRowOffset(props, index, instanceProps) {
818
+ return getItemMetadata('row', props, index, instanceProps).offset;
819
+ },
820
+ getRowHeight: function getRowHeight(props, index, instanceProps) {
821
+ return instanceProps.rowMetadataMap[index].size;
822
+ },
823
+ getRowStartIndexForOffset: function getRowStartIndexForOffset(props, scrollTop, instanceProps) {
824
+ return findNearestItem('row', props, instanceProps, scrollTop);
825
+ },
826
+ getRowStopIndexForStartIndex: function getRowStopIndexForStartIndex(props, startIndex, scrollTop, instanceProps) {
827
+ var rowCount = props.rowCount,
828
+ height = props.height;
829
+ var itemMetadata = getItemMetadata('row', props, startIndex, instanceProps);
830
+ var maxOffset = scrollTop + height;
831
+ var offset = itemMetadata.offset + itemMetadata.size;
832
+ var stopIndex = startIndex;
833
+
834
+ while (stopIndex < rowCount - 1 && offset < maxOffset) {
835
+ stopIndex++;
836
+ offset += getItemMetadata('row', props, stopIndex, instanceProps).size;
837
+ }
838
+
839
+ return stopIndex;
840
+ },
841
+ initInstanceProps: function initInstanceProps(props, instance) {
842
+ var _ref5 = props,
843
+ estimatedColumnWidth = _ref5.estimatedColumnWidth,
844
+ estimatedRowHeight = _ref5.estimatedRowHeight;
845
+ var instanceProps = {
846
+ columnMetadataMap: {},
847
+ estimatedColumnWidth: estimatedColumnWidth || DEFAULT_ESTIMATED_ITEM_SIZE,
848
+ estimatedRowHeight: estimatedRowHeight || DEFAULT_ESTIMATED_ITEM_SIZE,
849
+ lastMeasuredColumnIndex: -1,
850
+ lastMeasuredRowIndex: -1,
851
+ rowMetadataMap: {}
852
+ };
853
+
854
+ instance.resetAfterColumnIndex = function (columnIndex, shouldForceUpdate) {
855
+ if (shouldForceUpdate === void 0) {
856
+ shouldForceUpdate = true;
857
+ }
858
+
859
+ instance.resetAfterIndices({
860
+ columnIndex: columnIndex,
861
+ shouldForceUpdate: shouldForceUpdate
862
+ });
863
+ };
864
+
865
+ instance.resetAfterRowIndex = function (rowIndex, shouldForceUpdate) {
866
+ if (shouldForceUpdate === void 0) {
867
+ shouldForceUpdate = true;
868
+ }
869
+
870
+ instance.resetAfterIndices({
871
+ rowIndex: rowIndex,
872
+ shouldForceUpdate: shouldForceUpdate
873
+ });
874
+ };
875
+
876
+ instance.resetAfterIndices = function (_ref6) {
877
+ var columnIndex = _ref6.columnIndex,
878
+ rowIndex = _ref6.rowIndex,
879
+ _ref6$shouldForceUpda = _ref6.shouldForceUpdate,
880
+ shouldForceUpdate = _ref6$shouldForceUpda === void 0 ? true : _ref6$shouldForceUpda;
881
+
882
+ if (typeof columnIndex === 'number') {
883
+ instanceProps.lastMeasuredColumnIndex = Math.min(instanceProps.lastMeasuredColumnIndex, columnIndex - 1);
884
+ }
885
+
886
+ if (typeof rowIndex === 'number') {
887
+ instanceProps.lastMeasuredRowIndex = Math.min(instanceProps.lastMeasuredRowIndex, rowIndex - 1);
888
+ } // We could potentially optimize further by only evicting styles after this index,
889
+ // But since styles are only cached while scrolling is in progress-
890
+ // It seems an unnecessary optimization.
891
+ // It's unlikely that resetAfterIndex() will be called while a user is scrolling.
892
+
893
+
894
+ instance._getItemStyleCache(-1);
895
+
896
+ if (shouldForceUpdate) {
897
+ instance.forceUpdate();
898
+ }
899
+ };
900
+
901
+ return instanceProps;
902
+ },
903
+ shouldResetStyleCacheOnItemSizeChange: false,
904
+ validateProps: function validateProps(_ref7) {
905
+ var columnWidth = _ref7.columnWidth,
906
+ rowHeight = _ref7.rowHeight;
907
+
908
+ if (process.env.NODE_ENV !== 'production') {
909
+ if (typeof columnWidth !== 'function') {
910
+ throw Error('An invalid "columnWidth" prop has been specified. ' + 'Value should be a function. ' + ("\"" + (columnWidth === null ? 'null' : typeof columnWidth) + "\" was specified."));
911
+ } else if (typeof rowHeight !== 'function') {
912
+ throw Error('An invalid "rowHeight" prop has been specified. ' + 'Value should be a function. ' + ("\"" + (rowHeight === null ? 'null' : typeof rowHeight) + "\" was specified."));
913
+ }
914
+ }
915
+ }
916
+});
917
+
918
+var IS_SCROLLING_DEBOUNCE_INTERVAL$1 = 150;
919
+
920
+var defaultItemKey$1 = function defaultItemKey(index, data) {
921
+ return index;
922
+}; // In DEV mode, this Set helps us only log a warning once per component instance.
923
+// This avoids spamming the console every time a render happens.
924
+
925
+
926
+var devWarningsDirection = null;
927
+var devWarningsTagName$1 = null;
928
+
929
+if (process.env.NODE_ENV !== 'production') {
930
+ if (typeof window !== 'undefined' && typeof window.WeakSet !== 'undefined') {
931
+ devWarningsDirection =
932
+ /*#__PURE__*/
933
+ new WeakSet();
934
+ devWarningsTagName$1 =
935
+ /*#__PURE__*/
936
+ new WeakSet();
937
+ }
938
+}
939
+
940
+function createListComponent(_ref) {
941
+ var _class, _temp;
942
+
943
+ var getItemOffset = _ref.getItemOffset,
944
+ getEstimatedTotalSize = _ref.getEstimatedTotalSize,
945
+ getItemSize = _ref.getItemSize,
946
+ getOffsetForIndexAndAlignment = _ref.getOffsetForIndexAndAlignment,
947
+ getStartIndexForOffset = _ref.getStartIndexForOffset,
948
+ getStopIndexForStartIndex = _ref.getStopIndexForStartIndex,
949
+ initInstanceProps = _ref.initInstanceProps,
950
+ shouldResetStyleCacheOnItemSizeChange = _ref.shouldResetStyleCacheOnItemSizeChange,
951
+ validateProps = _ref.validateProps;
952
+ return _temp = _class =
953
+ /*#__PURE__*/
954
+ function (_PureComponent) {
955
+ _inheritsLoose(List, _PureComponent);
956
+
957
+ // Always use explicit constructor for React components.
958
+ // It produces less code after transpilation. (#26)
959
+ // eslint-disable-next-line no-useless-constructor
960
+ function List(props) {
961
+ var _this;
962
+
963
+ _this = _PureComponent.call(this, props) || this;
964
+ _this._instanceProps = initInstanceProps(_this.props, _assertThisInitialized(_assertThisInitialized(_this)));
965
+ _this._outerRef = void 0;
966
+ _this._resetIsScrollingTimeoutId = null;
967
+ _this.state = {
968
+ instance: _assertThisInitialized(_assertThisInitialized(_this)),
969
+ isScrolling: false,
970
+ scrollDirection: 'forward',
971
+ scrollOffset: typeof _this.props.initialScrollOffset === 'number' ? _this.props.initialScrollOffset : 0,
972
+ scrollUpdateWasRequested: false
973
+ };
974
+ _this._callOnItemsRendered = void 0;
975
+ _this._callOnItemsRendered = memoizeOne(function (overscanStartIndex, overscanStopIndex, visibleStartIndex, visibleStopIndex) {
976
+ return _this.props.onItemsRendered({
977
+ overscanStartIndex: overscanStartIndex,
978
+ overscanStopIndex: overscanStopIndex,
979
+ visibleStartIndex: visibleStartIndex,
980
+ visibleStopIndex: visibleStopIndex
981
+ });
982
+ });
983
+ _this._callOnScroll = void 0;
984
+ _this._callOnScroll = memoizeOne(function (scrollDirection, scrollOffset, scrollUpdateWasRequested) {
985
+ return _this.props.onScroll({
986
+ scrollDirection: scrollDirection,
987
+ scrollOffset: scrollOffset,
988
+ scrollUpdateWasRequested: scrollUpdateWasRequested
989
+ });
990
+ });
991
+ _this._getItemStyle = void 0;
992
+
993
+ _this._getItemStyle = function (index) {
994
+ var _this$props = _this.props,
995
+ direction = _this$props.direction,
996
+ itemSize = _this$props.itemSize,
997
+ layout = _this$props.layout;
998
+
999
+ var itemStyleCache = _this._getItemStyleCache(shouldResetStyleCacheOnItemSizeChange && itemSize, shouldResetStyleCacheOnItemSizeChange && layout, shouldResetStyleCacheOnItemSizeChange && direction);
1000
+
1001
+ var style;
1002
+
1003
+ if (itemStyleCache.hasOwnProperty(index)) {
1004
+ style = itemStyleCache[index];
1005
+ } else {
1006
+ var _style;
1007
+
1008
+ var _offset = getItemOffset(_this.props, index, _this._instanceProps);
1009
+
1010
+ var size = getItemSize(_this.props, index, _this._instanceProps); // TODO Deprecate direction "horizontal"
1011
+
1012
+ var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
1013
+ itemStyleCache[index] = style = (_style = {
1014
+ position: 'absolute'
1015
+ }, _style[direction === 'rtl' ? 'right' : 'left'] = isHorizontal ? _offset : 0, _style.top = !isHorizontal ? _offset : 0, _style.height = !isHorizontal ? size : '100%', _style.width = isHorizontal ? size : '100%', _style);
1016
+ }
1017
+
1018
+ return style;
1019
+ };
1020
+
1021
+ _this._getItemStyleCache = void 0;
1022
+ _this._getItemStyleCache = memoizeOne(function (_, __, ___) {
1023
+ return {};
1024
+ });
1025
+
1026
+ _this._onScrollHorizontal = function (event) {
1027
+ var _event$currentTarget = event.currentTarget,
1028
+ clientWidth = _event$currentTarget.clientWidth,
1029
+ scrollLeft = _event$currentTarget.scrollLeft,
1030
+ scrollWidth = _event$currentTarget.scrollWidth;
1031
+
1032
+ _this.setState(function (prevState) {
1033
+ if (prevState.scrollOffset === scrollLeft) {
1034
+ // Scroll position may have been updated by cDM/cDU,
1035
+ // In which case we don't need to trigger another render,
1036
+ // And we don't want to update state.isScrolling.
1037
+ return null;
1038
+ }
1039
+
1040
+ var direction = _this.props.direction; // HACK According to the spec, scrollLeft should be negative for RTL aligned elements.
1041
+ // Chrome does not seem to adhere; its scrolLeft values are positive (measured relative to the left).
1042
+ // See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
1043
+
1044
+ var scrollOffset = scrollLeft;
1045
+
1046
+ if (direction === 'rtl') {
1047
+ if (scrollLeft <= 0) {
1048
+ scrollOffset = -scrollOffset;
1049
+ } else {
1050
+ scrollOffset = scrollWidth - clientWidth - scrollLeft;
1051
+ }
1052
+ }
1053
+
1054
+ return {
1055
+ isScrolling: true,
1056
+ scrollDirection: prevState.scrollOffset < scrollLeft ? 'forward' : 'backward',
1057
+ scrollOffset: scrollOffset,
1058
+ scrollUpdateWasRequested: false
1059
+ };
1060
+ }, _this._resetIsScrollingDebounced);
1061
+ };
1062
+
1063
+ _this._onScrollVertical = function (event) {
1064
+ var scrollTop = event.currentTarget.scrollTop;
1065
+
1066
+ _this.setState(function (prevState) {
1067
+ if (prevState.scrollOffset === scrollTop) {
1068
+ // Scroll position may have been updated by cDM/cDU,
1069
+ // In which case we don't need to trigger another render,
1070
+ // And we don't want to update state.isScrolling.
1071
+ return null;
1072
+ }
1073
+
1074
+ return {
1075
+ isScrolling: true,
1076
+ scrollDirection: prevState.scrollOffset < scrollTop ? 'forward' : 'backward',
1077
+ scrollOffset: scrollTop,
1078
+ scrollUpdateWasRequested: false
1079
+ };
1080
+ }, _this._resetIsScrollingDebounced);
1081
+ };
1082
+
1083
+ _this._outerRefSetter = function (ref) {
1084
+ var outerRef = _this.props.outerRef;
1085
+ _this._outerRef = ref;
1086
+
1087
+ if (typeof outerRef === 'function') {
1088
+ outerRef(ref);
1089
+ } else if (outerRef != null && typeof outerRef === 'object' && outerRef.hasOwnProperty('current')) {
1090
+ outerRef.current = ref;
1091
+ }
1092
+ };
1093
+
1094
+ _this._resetIsScrollingDebounced = function () {
1095
+ if (_this._resetIsScrollingTimeoutId !== null) {
1096
+ cancelTimeout(_this._resetIsScrollingTimeoutId);
1097
+ }
1098
+
1099
+ _this._resetIsScrollingTimeoutId = requestTimeout(_this._resetIsScrolling, IS_SCROLLING_DEBOUNCE_INTERVAL$1);
1100
+ };
1101
+
1102
+ _this._resetIsScrolling = function () {
1103
+ _this._resetIsScrollingTimeoutId = null;
1104
+
1105
+ _this.setState({
1106
+ isScrolling: false
1107
+ }, function () {
1108
+ // Clear style cache after state update has been committed.
1109
+ // This way we don't break pure sCU for items that don't use isScrolling param.
1110
+ _this._getItemStyleCache(-1, null);
1111
+ });
1112
+ };
1113
+
1114
+ return _this;
1115
+ }
1116
+
1117
+ List.getDerivedStateFromProps = function getDerivedStateFromProps(nextProps, prevState) {
1118
+ validateSharedProps$1(nextProps, prevState);
1119
+ validateProps(nextProps);
1120
+ return null;
1121
+ };
1122
+
1123
+ var _proto = List.prototype;
1124
+
1125
+ _proto.scrollTo = function scrollTo(scrollOffset) {
1126
+ scrollOffset = Math.max(0, scrollOffset);
1127
+ this.setState(function (prevState) {
1128
+ if (prevState.scrollOffset === scrollOffset) {
1129
+ return null;
1130
+ }
1131
+
1132
+ return {
1133
+ scrollDirection: prevState.scrollOffset < scrollOffset ? 'forward' : 'backward',
1134
+ scrollOffset: scrollOffset,
1135
+ scrollUpdateWasRequested: true
1136
+ };
1137
+ }, this._resetIsScrollingDebounced);
1138
+ };
1139
+
1140
+ _proto.scrollToItem = function scrollToItem(index, align) {
1141
+ if (align === void 0) {
1142
+ align = 'auto';
1143
+ }
1144
+
1145
+ var itemCount = this.props.itemCount;
1146
+ var scrollOffset = this.state.scrollOffset;
1147
+ index = Math.max(0, Math.min(index, itemCount - 1));
1148
+ this.scrollTo(getOffsetForIndexAndAlignment(this.props, index, align, scrollOffset, this._instanceProps));
1149
+ };
1150
+
1151
+ _proto.componentDidMount = function componentDidMount() {
1152
+ var _this$props2 = this.props,
1153
+ direction = _this$props2.direction,
1154
+ initialScrollOffset = _this$props2.initialScrollOffset,
1155
+ layout = _this$props2.layout;
1156
+
1157
+ if (typeof initialScrollOffset === 'number' && this._outerRef !== null) {
1158
+ // TODO Deprecate direction "horizontal"
1159
+ if (direction === 'horizontal' || layout === 'horizontal') {
1160
+ this._outerRef.scrollLeft = initialScrollOffset;
1161
+ } else {
1162
+ this._outerRef.scrollTop = initialScrollOffset;
1163
+ }
1164
+ }
1165
+
1166
+ this._callPropsCallbacks();
1167
+ };
1168
+
1169
+ _proto.componentDidUpdate = function componentDidUpdate() {
1170
+ var _this$props3 = this.props,
1171
+ direction = _this$props3.direction,
1172
+ layout = _this$props3.layout;
1173
+ var _this$state = this.state,
1174
+ scrollOffset = _this$state.scrollOffset,
1175
+ scrollUpdateWasRequested = _this$state.scrollUpdateWasRequested;
1176
+
1177
+ if (scrollUpdateWasRequested && this._outerRef !== null) {
1178
+ // TODO Deprecate direction "horizontal"
1179
+ if (direction === 'horizontal' || layout === 'horizontal') {
1180
+ this._outerRef.scrollLeft = scrollOffset;
1181
+ } else {
1182
+ this._outerRef.scrollTop = scrollOffset;
1183
+ }
1184
+ }
1185
+
1186
+ this._callPropsCallbacks();
1187
+ };
1188
+
1189
+ _proto.componentWillUnmount = function componentWillUnmount() {
1190
+ if (this._resetIsScrollingTimeoutId !== null) {
1191
+ cancelTimeout(this._resetIsScrollingTimeoutId);
1192
+ }
1193
+ };
1194
+
1195
+ _proto.render = function render() {
1196
+ var _this$props4 = this.props,
1197
+ children = _this$props4.children,
1198
+ className = _this$props4.className,
1199
+ direction = _this$props4.direction,
1200
+ height = _this$props4.height,
1201
+ innerRef = _this$props4.innerRef,
1202
+ innerElementType = _this$props4.innerElementType,
1203
+ innerTagName = _this$props4.innerTagName,
1204
+ itemCount = _this$props4.itemCount,
1205
+ itemData = _this$props4.itemData,
1206
+ _this$props4$itemKey = _this$props4.itemKey,
1207
+ itemKey = _this$props4$itemKey === void 0 ? defaultItemKey$1 : _this$props4$itemKey,
1208
+ layout = _this$props4.layout,
1209
+ outerElementType = _this$props4.outerElementType,
1210
+ outerTagName = _this$props4.outerTagName,
1211
+ style = _this$props4.style,
1212
+ useIsScrolling = _this$props4.useIsScrolling,
1213
+ width = _this$props4.width;
1214
+ var isScrolling = this.state.isScrolling; // TODO Deprecate direction "horizontal"
1215
+
1216
+ var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
1217
+ var onScroll = isHorizontal ? this._onScrollHorizontal : this._onScrollVertical;
1218
+
1219
+ var _this$_getRangeToRend = this._getRangeToRender(),
1220
+ startIndex = _this$_getRangeToRend[0],
1221
+ stopIndex = _this$_getRangeToRend[1];
1222
+
1223
+ var items = [];
1224
+
1225
+ if (itemCount > 0) {
1226
+ for (var _index = startIndex; _index <= stopIndex; _index++) {
1227
+ items.push(react.createElement(children, {
1228
+ data: itemData,
1229
+ key: itemKey(_index, itemData),
1230
+ index: _index,
1231
+ isScrolling: useIsScrolling ? isScrolling : undefined,
1232
+ style: this._getItemStyle(_index)
1233
+ }));
1234
+ }
1235
+ } // Read this value AFTER items have been created,
1236
+ // So their actual sizes (if variable) are taken into consideration.
1237
+
1238
+
1239
+ var estimatedTotalSize = getEstimatedTotalSize(this.props, this._instanceProps);
1240
+ return react.createElement(outerElementType || outerTagName || 'div', {
1241
+ className: className,
1242
+ onScroll: onScroll,
1243
+ ref: this._outerRefSetter,
1244
+ style: _extends({
1245
+ position: 'relative',
1246
+ height: height,
1247
+ width: width,
1248
+ overflow: 'auto',
1249
+ WebkitOverflowScrolling: 'touch',
1250
+ willChange: 'transform',
1251
+ direction: direction
1252
+ }, style)
1253
+ }, react.createElement(innerElementType || innerTagName || 'div', {
1254
+ children: items,
1255
+ ref: innerRef,
1256
+ style: {
1257
+ height: isHorizontal ? '100%' : estimatedTotalSize,
1258
+ pointerEvents: isScrolling ? 'none' : '',
1259
+ width: isHorizontal ? estimatedTotalSize : '100%'
1260
+ }
1261
+ }));
1262
+ };
1263
+
1264
+ _proto._callPropsCallbacks = function _callPropsCallbacks() {
1265
+ if (typeof this.props.onItemsRendered === 'function') {
1266
+ var itemCount = this.props.itemCount;
1267
+
1268
+ if (itemCount > 0) {
1269
+ var _this$_getRangeToRend2 = this._getRangeToRender(),
1270
+ _overscanStartIndex = _this$_getRangeToRend2[0],
1271
+ _overscanStopIndex = _this$_getRangeToRend2[1],
1272
+ _visibleStartIndex = _this$_getRangeToRend2[2],
1273
+ _visibleStopIndex = _this$_getRangeToRend2[3];
1274
+
1275
+ this._callOnItemsRendered(_overscanStartIndex, _overscanStopIndex, _visibleStartIndex, _visibleStopIndex);
1276
+ }
1277
+ }
1278
+
1279
+ if (typeof this.props.onScroll === 'function') {
1280
+ var _this$state2 = this.state,
1281
+ _scrollDirection = _this$state2.scrollDirection,
1282
+ _scrollOffset = _this$state2.scrollOffset,
1283
+ _scrollUpdateWasRequested = _this$state2.scrollUpdateWasRequested;
1284
+
1285
+ this._callOnScroll(_scrollDirection, _scrollOffset, _scrollUpdateWasRequested);
1286
+ }
1287
+ }; // Lazily create and cache item styles while scrolling,
1288
+ // So that pure component sCU will prevent re-renders.
1289
+ // We maintain this cache, and pass a style prop rather than index,
1290
+ // So that List can clear cached styles and force item re-render if necessary.
1291
+
1292
+
1293
+ _proto._getRangeToRender = function _getRangeToRender() {
1294
+ var _this$props5 = this.props,
1295
+ itemCount = _this$props5.itemCount,
1296
+ overscanCount = _this$props5.overscanCount;
1297
+ var _this$state3 = this.state,
1298
+ isScrolling = _this$state3.isScrolling,
1299
+ scrollDirection = _this$state3.scrollDirection,
1300
+ scrollOffset = _this$state3.scrollOffset;
1301
+
1302
+ if (itemCount === 0) {
1303
+ return [0, 0, 0, 0];
1304
+ }
1305
+
1306
+ var startIndex = getStartIndexForOffset(this.props, scrollOffset, this._instanceProps);
1307
+ var stopIndex = getStopIndexForStartIndex(this.props, startIndex, scrollOffset, this._instanceProps); // Overscan by one item in each direction so that tab/focus works.
1308
+ // If there isn't at least one extra item, tab loops back around.
1309
+
1310
+ var overscanBackward = !isScrolling || scrollDirection === 'backward' ? Math.max(1, overscanCount) : 1;
1311
+ var overscanForward = !isScrolling || scrollDirection === 'forward' ? Math.max(1, overscanCount) : 1;
1312
+ return [Math.max(0, startIndex - overscanBackward), Math.max(0, Math.min(itemCount - 1, stopIndex + overscanForward)), startIndex, stopIndex];
1313
+ };
1314
+
1315
+ return List;
1316
+ }(react.PureComponent), _class.defaultProps = {
1317
+ direction: 'ltr',
1318
+ itemData: undefined,
1319
+ layout: 'vertical',
1320
+ overscanCount: 2,
1321
+ useIsScrolling: false
1322
+ }, _temp;
1323
+} // NOTE: I considered further wrapping individual items with a pure ListItem component.
1324
+// This would avoid ever calling the render function for the same index more than once,
1325
+// But it would also add the overhead of a lot of components/fibers.
1326
+// I assume people already do this (render function returning a class component),
1327
+// So my doing it would just unnecessarily double the wrappers.
1328
+
1329
+var validateSharedProps$1 = function validateSharedProps(_ref2, _ref3) {
1330
+ var children = _ref2.children,
1331
+ direction = _ref2.direction,
1332
+ height = _ref2.height,
1333
+ layout = _ref2.layout,
1334
+ innerTagName = _ref2.innerTagName,
1335
+ outerTagName = _ref2.outerTagName,
1336
+ width = _ref2.width;
1337
+ var instance = _ref3.instance;
1338
+
1339
+ if (process.env.NODE_ENV !== 'production') {
1340
+ if (innerTagName != null || outerTagName != null) {
1341
+ if (devWarningsTagName$1 && !devWarningsTagName$1.has(instance)) {
1342
+ devWarningsTagName$1.add(instance);
1343
+ console.warn('The innerTagName and outerTagName props have been deprecated. ' + 'Please use the innerElementType and outerElementType props instead.');
1344
+ }
1345
+ } // TODO Deprecate direction "horizontal"
1346
+
1347
+
1348
+ var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
1349
+
1350
+ switch (direction) {
1351
+ case 'horizontal':
1352
+ case 'vertical':
1353
+ if (devWarningsDirection && !devWarningsDirection.has(instance)) {
1354
+ devWarningsDirection.add(instance);
1355
+ console.warn('The direction prop should be either "ltr" (default) or "rtl". ' + 'Please use the layout prop to specify "vertical" (default) or "horizontal" orientation.');
1356
+ }
1357
+
1358
+ break;
1359
+
1360
+ case 'ltr':
1361
+ case 'rtl':
1362
+ // Valid values
1363
+ break;
1364
+
1365
+ default:
1366
+ throw Error('An invalid "direction" prop has been specified. ' + 'Value should be either "ltr" or "rtl". ' + ("\"" + direction + "\" was specified."));
1367
+ }
1368
+
1369
+ switch (layout) {
1370
+ case 'horizontal':
1371
+ case 'vertical':
1372
+ // Valid values
1373
+ break;
1374
+
1375
+ default:
1376
+ throw Error('An invalid "layout" prop has been specified. ' + 'Value should be either "horizontal" or "vertical". ' + ("\"" + layout + "\" was specified."));
1377
+ }
1378
+
1379
+ if (children == null) {
1380
+ throw Error('An invalid "children" prop has been specified. ' + 'Value should be a React component. ' + ("\"" + (children === null ? 'null' : typeof children) + "\" was specified."));
1381
+ }
1382
+
1383
+ if (isHorizontal && typeof width !== 'number') {
1384
+ throw Error('An invalid "width" prop has been specified. ' + 'Horizontal lists must specify a number for width. ' + ("\"" + (width === null ? 'null' : typeof width) + "\" was specified."));
1385
+ } else if (!isHorizontal && typeof height !== 'number') {
1386
+ throw Error('An invalid "height" prop has been specified. ' + 'Vertical lists must specify a number for height. ' + ("\"" + (height === null ? 'null' : typeof height) + "\" was specified."));
1387
+ }
1388
+ }
1389
+};
1390
+
1391
+var DEFAULT_ESTIMATED_ITEM_SIZE$1 = 50;
1392
+
1393
+var getItemMetadata$1 = function getItemMetadata(props, index, instanceProps) {
1394
+ var _ref = props,
1395
+ itemSize = _ref.itemSize;
1396
+ var itemMetadataMap = instanceProps.itemMetadataMap,
1397
+ lastMeasuredIndex = instanceProps.lastMeasuredIndex;
1398
+
1399
+ if (index > lastMeasuredIndex) {
1400
+ var offset = 0;
1401
+
1402
+ if (lastMeasuredIndex >= 0) {
1403
+ var itemMetadata = itemMetadataMap[lastMeasuredIndex];
1404
+ offset = itemMetadata.offset + itemMetadata.size;
1405
+ }
1406
+
1407
+ for (var i = lastMeasuredIndex + 1; i <= index; i++) {
1408
+ var size = itemSize(i);
1409
+ itemMetadataMap[i] = {
1410
+ offset: offset,
1411
+ size: size
1412
+ };
1413
+ offset += size;
1414
+ }
1415
+
1416
+ instanceProps.lastMeasuredIndex = index;
1417
+ }
1418
+
1419
+ return itemMetadataMap[index];
1420
+};
1421
+
1422
+var findNearestItem$1 = function findNearestItem(props, instanceProps, offset) {
1423
+ var itemMetadataMap = instanceProps.itemMetadataMap,
1424
+ lastMeasuredIndex = instanceProps.lastMeasuredIndex;
1425
+ var lastMeasuredItemOffset = lastMeasuredIndex > 0 ? itemMetadataMap[lastMeasuredIndex].offset : 0;
1426
+
1427
+ if (lastMeasuredItemOffset >= offset) {
1428
+ // If we've already measured items within this range just use a binary search as it's faster.
1429
+ return findNearestItemBinarySearch$1(props, instanceProps, lastMeasuredIndex, 0, offset);
1430
+ } else {
1431
+ // If we haven't yet measured this high, fallback to an exponential search with an inner binary search.
1432
+ // The exponential search avoids pre-computing sizes for the full set of items as a binary search would.
1433
+ // The overall complexity for this approach is O(log n).
1434
+ return findNearestItemExponentialSearch$1(props, instanceProps, Math.max(0, lastMeasuredIndex), offset);
1435
+ }
1436
+};
1437
+
1438
+var findNearestItemBinarySearch$1 = function findNearestItemBinarySearch(props, instanceProps, high, low, offset) {
1439
+ while (low <= high) {
1440
+ var middle = low + Math.floor((high - low) / 2);
1441
+ var currentOffset = getItemMetadata$1(props, middle, instanceProps).offset;
1442
+
1443
+ if (currentOffset === offset) {
1444
+ return middle;
1445
+ } else if (currentOffset < offset) {
1446
+ low = middle + 1;
1447
+ } else if (currentOffset > offset) {
1448
+ high = middle - 1;
1449
+ }
1450
+ }
1451
+
1452
+ if (low > 0) {
1453
+ return low - 1;
1454
+ } else {
1455
+ return 0;
1456
+ }
1457
+};
1458
+
1459
+var findNearestItemExponentialSearch$1 = function findNearestItemExponentialSearch(props, instanceProps, index, offset) {
1460
+ var itemCount = props.itemCount;
1461
+ var interval = 1;
1462
+
1463
+ while (index < itemCount && getItemMetadata$1(props, index, instanceProps).offset < offset) {
1464
+ index += interval;
1465
+ interval *= 2;
1466
+ }
1467
+
1468
+ return findNearestItemBinarySearch$1(props, instanceProps, Math.min(index, itemCount - 1), Math.floor(index / 2), offset);
1469
+};
1470
+
1471
+var getEstimatedTotalSize = function getEstimatedTotalSize(_ref2, _ref3) {
1472
+ var itemCount = _ref2.itemCount;
1473
+ var itemMetadataMap = _ref3.itemMetadataMap,
1474
+ estimatedItemSize = _ref3.estimatedItemSize,
1475
+ lastMeasuredIndex = _ref3.lastMeasuredIndex;
1476
+ var totalSizeOfMeasuredItems = 0; // Edge case check for when the number of items decreases while a scroll is in progress.
1477
+ // https://github.com/bvaughn/react-window/pull/138
1478
+
1479
+ if (lastMeasuredIndex >= itemCount) {
1480
+ lastMeasuredIndex = itemCount - 1;
1481
+ }
1482
+
1483
+ if (lastMeasuredIndex >= 0) {
1484
+ var itemMetadata = itemMetadataMap[lastMeasuredIndex];
1485
+ totalSizeOfMeasuredItems = itemMetadata.offset + itemMetadata.size;
1486
+ }
1487
+
1488
+ var numUnmeasuredItems = itemCount - lastMeasuredIndex - 1;
1489
+ var totalSizeOfUnmeasuredItems = numUnmeasuredItems * estimatedItemSize;
1490
+ return totalSizeOfMeasuredItems + totalSizeOfUnmeasuredItems;
1491
+};
1492
+
1493
+var VariableSizeList =
1494
+/*#__PURE__*/
1495
+createListComponent({
1496
+ getItemOffset: function getItemOffset(props, index, instanceProps) {
1497
+ return getItemMetadata$1(props, index, instanceProps).offset;
1498
+ },
1499
+ getItemSize: function getItemSize(props, index, instanceProps) {
1500
+ return instanceProps.itemMetadataMap[index].size;
1501
+ },
1502
+ getEstimatedTotalSize: getEstimatedTotalSize,
1503
+ getOffsetForIndexAndAlignment: function getOffsetForIndexAndAlignment(props, index, align, scrollOffset, instanceProps) {
1504
+ var direction = props.direction,
1505
+ height = props.height,
1506
+ layout = props.layout,
1507
+ width = props.width; // TODO Deprecate direction "horizontal"
1508
+
1509
+ var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
1510
+ var size = isHorizontal ? width : height;
1511
+ var itemMetadata = getItemMetadata$1(props, index, instanceProps); // Get estimated total size after ItemMetadata is computed,
1512
+ // To ensure it reflects actual measurements instead of just estimates.
1513
+
1514
+ var estimatedTotalSize = getEstimatedTotalSize(props, instanceProps);
1515
+ var maxOffset = Math.max(0, Math.min(estimatedTotalSize - size, itemMetadata.offset));
1516
+ var minOffset = Math.max(0, itemMetadata.offset - size + itemMetadata.size);
1517
+
1518
+ if (align === 'smart') {
1519
+ if (scrollOffset >= minOffset - size && scrollOffset <= maxOffset + size) {
1520
+ align = 'auto';
1521
+ } else {
1522
+ align = 'center';
1523
+ }
1524
+ }
1525
+
1526
+ switch (align) {
1527
+ case 'start':
1528
+ return maxOffset;
1529
+
1530
+ case 'end':
1531
+ return minOffset;
1532
+
1533
+ case 'center':
1534
+ return Math.round(minOffset + (maxOffset - minOffset) / 2);
1535
+
1536
+ case 'auto':
1537
+ default:
1538
+ if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
1539
+ return scrollOffset;
1540
+ } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
1541
+ return minOffset;
1542
+ } else {
1543
+ return maxOffset;
1544
+ }
1545
+
1546
+ }
1547
+ },
1548
+ getStartIndexForOffset: function getStartIndexForOffset(props, offset, instanceProps) {
1549
+ return findNearestItem$1(props, instanceProps, offset);
1550
+ },
1551
+ getStopIndexForStartIndex: function getStopIndexForStartIndex(props, startIndex, scrollOffset, instanceProps) {
1552
+ var direction = props.direction,
1553
+ height = props.height,
1554
+ itemCount = props.itemCount,
1555
+ layout = props.layout,
1556
+ width = props.width; // TODO Deprecate direction "horizontal"
1557
+
1558
+ var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
1559
+ var size = isHorizontal ? width : height;
1560
+ var itemMetadata = getItemMetadata$1(props, startIndex, instanceProps);
1561
+ var maxOffset = scrollOffset + size;
1562
+ var offset = itemMetadata.offset + itemMetadata.size;
1563
+ var stopIndex = startIndex;
1564
+
1565
+ while (stopIndex < itemCount - 1 && offset < maxOffset) {
1566
+ stopIndex++;
1567
+ offset += getItemMetadata$1(props, stopIndex, instanceProps).size;
1568
+ }
1569
+
1570
+ return stopIndex;
1571
+ },
1572
+ initInstanceProps: function initInstanceProps(props, instance) {
1573
+ var _ref4 = props,
1574
+ estimatedItemSize = _ref4.estimatedItemSize;
1575
+ var instanceProps = {
1576
+ itemMetadataMap: {},
1577
+ estimatedItemSize: estimatedItemSize || DEFAULT_ESTIMATED_ITEM_SIZE$1,
1578
+ lastMeasuredIndex: -1
1579
+ };
1580
+
1581
+ instance.resetAfterIndex = function (index, shouldForceUpdate) {
1582
+ if (shouldForceUpdate === void 0) {
1583
+ shouldForceUpdate = true;
1584
+ }
1585
+
1586
+ instanceProps.lastMeasuredIndex = Math.min(instanceProps.lastMeasuredIndex, index - 1); // We could potentially optimize further by only evicting styles after this index,
1587
+ // But since styles are only cached while scrolling is in progress-
1588
+ // It seems an unnecessary optimization.
1589
+ // It's unlikely that resetAfterIndex() will be called while a user is scrolling.
1590
+
1591
+ instance._getItemStyleCache(-1);
1592
+
1593
+ if (shouldForceUpdate) {
1594
+ instance.forceUpdate();
1595
+ }
1596
+ };
1597
+
1598
+ return instanceProps;
1599
+ },
1600
+ shouldResetStyleCacheOnItemSizeChange: false,
1601
+ validateProps: function validateProps(_ref5) {
1602
+ var itemSize = _ref5.itemSize;
1603
+
1604
+ if (process.env.NODE_ENV !== 'production') {
1605
+ if (typeof itemSize !== 'function') {
1606
+ throw Error('An invalid "itemSize" prop has been specified. ' + 'Value should be a function. ' + ("\"" + (itemSize === null ? 'null' : typeof itemSize) + "\" was specified."));
1607
+ }
1608
+ }
1609
+ }
1610
+});
1611
+
1612
+var FixedSizeGrid =
1613
+/*#__PURE__*/
1614
+createGridComponent({
1615
+ getColumnOffset: function getColumnOffset(_ref, index) {
1616
+ var columnWidth = _ref.columnWidth;
1617
+ return index * columnWidth;
1618
+ },
1619
+ getColumnWidth: function getColumnWidth(_ref2, index) {
1620
+ var columnWidth = _ref2.columnWidth;
1621
+ return columnWidth;
1622
+ },
1623
+ getRowOffset: function getRowOffset(_ref3, index) {
1624
+ var rowHeight = _ref3.rowHeight;
1625
+ return index * rowHeight;
1626
+ },
1627
+ getRowHeight: function getRowHeight(_ref4, index) {
1628
+ var rowHeight = _ref4.rowHeight;
1629
+ return rowHeight;
1630
+ },
1631
+ getEstimatedTotalHeight: function getEstimatedTotalHeight(_ref5) {
1632
+ var rowCount = _ref5.rowCount,
1633
+ rowHeight = _ref5.rowHeight;
1634
+ return rowHeight * rowCount;
1635
+ },
1636
+ getEstimatedTotalWidth: function getEstimatedTotalWidth(_ref6) {
1637
+ var columnCount = _ref6.columnCount,
1638
+ columnWidth = _ref6.columnWidth;
1639
+ return columnWidth * columnCount;
1640
+ },
1641
+ getOffsetForColumnAndAlignment: function getOffsetForColumnAndAlignment(_ref7, columnIndex, align, scrollLeft, instanceProps, scrollbarSize) {
1642
+ var columnCount = _ref7.columnCount,
1643
+ columnWidth = _ref7.columnWidth,
1644
+ width = _ref7.width;
1645
+ var maxOffset = Math.max(0, Math.min(columnCount * columnWidth - width, columnIndex * columnWidth));
1646
+ var minOffset = Math.max(0, columnIndex * columnWidth - width + scrollbarSize + columnWidth);
1647
+
1648
+ if (align === 'smart') {
1649
+ if (scrollLeft >= minOffset - width && scrollLeft <= maxOffset + width) {
1650
+ align = 'auto';
1651
+ } else {
1652
+ align = 'center';
1653
+ }
1654
+ }
1655
+
1656
+ switch (align) {
1657
+ case 'start':
1658
+ return maxOffset;
1659
+
1660
+ case 'end':
1661
+ return minOffset;
1662
+
1663
+ case 'center':
1664
+ return Math.round(minOffset + (maxOffset - minOffset) / 2);
1665
+
1666
+ case 'auto':
1667
+ default:
1668
+ if (scrollLeft >= minOffset && scrollLeft <= maxOffset) {
1669
+ return scrollLeft;
1670
+ } else if (scrollLeft - minOffset < maxOffset - scrollLeft) {
1671
+ return minOffset;
1672
+ } else {
1673
+ return maxOffset;
1674
+ }
1675
+
1676
+ }
1677
+ },
1678
+ getOffsetForRowAndAlignment: function getOffsetForRowAndAlignment(_ref8, rowIndex, align, scrollTop, instanceProps, scrollbarSize) {
1679
+ var rowHeight = _ref8.rowHeight,
1680
+ height = _ref8.height,
1681
+ rowCount = _ref8.rowCount;
1682
+ var maxOffset = Math.max(0, Math.min(rowCount * rowHeight - height, rowIndex * rowHeight));
1683
+ var minOffset = Math.max(0, rowIndex * rowHeight - height + scrollbarSize + rowHeight);
1684
+
1685
+ if (align === 'smart') {
1686
+ if (scrollTop >= minOffset - height && scrollTop <= maxOffset + height) {
1687
+ align = 'auto';
1688
+ } else {
1689
+ align = 'center';
1690
+ }
1691
+ }
1692
+
1693
+ switch (align) {
1694
+ case 'start':
1695
+ return maxOffset;
1696
+
1697
+ case 'end':
1698
+ return minOffset;
1699
+
1700
+ case 'center':
1701
+ return Math.round(minOffset + (maxOffset - minOffset) / 2);
1702
+
1703
+ case 'auto':
1704
+ default:
1705
+ if (scrollTop >= minOffset && scrollTop <= maxOffset) {
1706
+ return scrollTop;
1707
+ } else if (scrollTop - minOffset < maxOffset - scrollTop) {
1708
+ return minOffset;
1709
+ } else {
1710
+ return maxOffset;
1711
+ }
1712
+
1713
+ }
1714
+ },
1715
+ getColumnStartIndexForOffset: function getColumnStartIndexForOffset(_ref9, scrollLeft) {
1716
+ var columnWidth = _ref9.columnWidth,
1717
+ columnCount = _ref9.columnCount;
1718
+ return Math.max(0, Math.min(columnCount - 1, Math.floor(scrollLeft / columnWidth)));
1719
+ },
1720
+ getColumnStopIndexForStartIndex: function getColumnStopIndexForStartIndex(_ref10, startIndex, scrollLeft) {
1721
+ var columnWidth = _ref10.columnWidth,
1722
+ columnCount = _ref10.columnCount,
1723
+ width = _ref10.width;
1724
+ var left = startIndex * columnWidth;
1725
+ return Math.max(0, Math.min(columnCount - 1, startIndex + Math.floor((width + (scrollLeft - left)) / columnWidth)));
1726
+ },
1727
+ getRowStartIndexForOffset: function getRowStartIndexForOffset(_ref11, scrollTop) {
1728
+ var rowHeight = _ref11.rowHeight,
1729
+ rowCount = _ref11.rowCount;
1730
+ return Math.max(0, Math.min(rowCount - 1, Math.floor(scrollTop / rowHeight)));
1731
+ },
1732
+ getRowStopIndexForStartIndex: function getRowStopIndexForStartIndex(_ref12, startIndex, scrollTop) {
1733
+ var rowHeight = _ref12.rowHeight,
1734
+ rowCount = _ref12.rowCount,
1735
+ height = _ref12.height;
1736
+ var left = startIndex * rowHeight;
1737
+ return Math.max(0, Math.min(rowCount - 1, startIndex + Math.floor((height + (scrollTop - left)) / rowHeight)));
1738
+ },
1739
+ initInstanceProps: function initInstanceProps(props) {// Noop
1740
+ },
1741
+ shouldResetStyleCacheOnItemSizeChange: true,
1742
+ validateProps: function validateProps(_ref13) {
1743
+ var columnWidth = _ref13.columnWidth,
1744
+ rowHeight = _ref13.rowHeight;
1745
+
1746
+ if (process.env.NODE_ENV !== 'production') {
1747
+ if (typeof columnWidth !== 'number') {
1748
+ throw Error('An invalid "columnWidth" prop has been specified. ' + 'Value should be a number. ' + ("\"" + (columnWidth === null ? 'null' : typeof columnWidth) + "\" was specified."));
1749
+ }
1750
+
1751
+ if (typeof rowHeight !== 'number') {
1752
+ throw Error('An invalid "rowHeight" prop has been specified. ' + 'Value should be a number. ' + ("\"" + (rowHeight === null ? 'null' : typeof rowHeight) + "\" was specified."));
1753
+ }
1754
+ }
1755
+ }
1756
+});
1757
+
1758
+var FixedSizeList =
1759
+/*#__PURE__*/
1760
+createListComponent({
1761
+ getItemOffset: function getItemOffset(_ref, index) {
1762
+ var itemSize = _ref.itemSize,
1763
+ size = _ref.size;
1764
+ return index * itemSize;
1765
+ },
1766
+ getItemSize: function getItemSize(_ref2, index) {
1767
+ var itemSize = _ref2.itemSize,
1768
+ size = _ref2.size;
1769
+ return itemSize;
1770
+ },
1771
+ getEstimatedTotalSize: function getEstimatedTotalSize(_ref3) {
1772
+ var itemCount = _ref3.itemCount,
1773
+ itemSize = _ref3.itemSize;
1774
+ return itemSize * itemCount;
1775
+ },
1776
+ getOffsetForIndexAndAlignment: function getOffsetForIndexAndAlignment(_ref4, index, align, scrollOffset) {
1777
+ var direction = _ref4.direction,
1778
+ height = _ref4.height,
1779
+ itemCount = _ref4.itemCount,
1780
+ itemSize = _ref4.itemSize,
1781
+ layout = _ref4.layout,
1782
+ width = _ref4.width;
1783
+ // TODO Deprecate direction "horizontal"
1784
+ var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
1785
+ var size = isHorizontal ? width : height;
1786
+ var maxOffset = Math.max(0, Math.min(itemCount * itemSize - size, index * itemSize));
1787
+ var minOffset = Math.max(0, index * itemSize - size + itemSize);
1788
+
1789
+ if (align === 'smart') {
1790
+ if (scrollOffset >= minOffset - size && scrollOffset <= maxOffset + size) {
1791
+ align = 'auto';
1792
+ } else {
1793
+ align = 'center';
1794
+ }
1795
+ }
1796
+
1797
+ switch (align) {
1798
+ case 'start':
1799
+ return maxOffset;
1800
+
1801
+ case 'end':
1802
+ return minOffset;
1803
+
1804
+ case 'center':
1805
+ return Math.round(minOffset + (maxOffset - minOffset) / 2);
1806
+
1807
+ case 'auto':
1808
+ default:
1809
+ if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
1810
+ return scrollOffset;
1811
+ } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
1812
+ return minOffset;
1813
+ } else {
1814
+ return maxOffset;
1815
+ }
1816
+
1817
+ }
1818
+ },
1819
+ getStartIndexForOffset: function getStartIndexForOffset(_ref5, offset) {
1820
+ var itemCount = _ref5.itemCount,
1821
+ itemSize = _ref5.itemSize;
1822
+ return Math.max(0, Math.min(itemCount - 1, Math.floor(offset / itemSize)));
1823
+ },
1824
+ getStopIndexForStartIndex: function getStopIndexForStartIndex(_ref6, startIndex, scrollOffset) {
1825
+ var direction = _ref6.direction,
1826
+ height = _ref6.height,
1827
+ itemCount = _ref6.itemCount,
1828
+ itemSize = _ref6.itemSize,
1829
+ layout = _ref6.layout,
1830
+ width = _ref6.width;
1831
+ // TODO Deprecate direction "horizontal"
1832
+ var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
1833
+ var offset = startIndex * itemSize;
1834
+ var size = isHorizontal ? width : height;
1835
+ return Math.max(0, Math.min(itemCount - 1, startIndex + Math.floor((size + (scrollOffset - offset)) / itemSize)));
1836
+ },
1837
+ initInstanceProps: function initInstanceProps(props) {// Noop
1838
+ },
1839
+ shouldResetStyleCacheOnItemSizeChange: true,
1840
+ validateProps: function validateProps(_ref7) {
1841
+ var itemSize = _ref7.itemSize;
1842
+
1843
+ if (process.env.NODE_ENV !== 'production') {
1844
+ if (typeof itemSize !== 'number') {
1845
+ throw Error('An invalid "itemSize" prop has been specified. ' + 'Value should be a number. ' + ("\"" + (itemSize === null ? 'null' : typeof itemSize) + "\" was specified."));
1846
+ }
1847
+ }
1848
+ }
1849
+});
1850
+
1851
+// Pulled from react-compat
1852
+// https://github.com/developit/preact-compat/blob/7c5de00e7c85e2ffd011bf3af02899b63f699d3a/src/index.js#L349
1853
+function shallowDiffers(prev, next) {
1854
+ for (var attribute in prev) {
1855
+ if (!(attribute in next)) {
1856
+ return true;
1857
+ }
1858
+ }
1859
+
1860
+ for (var _attribute in next) {
1861
+ if (prev[_attribute] !== next[_attribute]) {
1862
+ return true;
1863
+ }
1864
+ }
1865
+
1866
+ return false;
1867
+}
1868
+
1869
+// It knows to compare individual style props and ignore the wrapper object.
1870
+// See https://reactjs.org/docs/react-api.html#reactmemo
1871
+
1872
+function areEqual(prevProps, nextProps) {
1873
+ var prevStyle = prevProps.style,
1874
+ prevRest = _objectWithoutPropertiesLoose(prevProps, ["style"]);
1875
+
1876
+ var nextStyle = nextProps.style,
1877
+ nextRest = _objectWithoutPropertiesLoose(nextProps, ["style"]);
1878
+
1879
+ return !shallowDiffers(prevStyle, nextStyle) && !shallowDiffers(prevRest, nextRest);
1880
+}
1881
+
1882
+// It knows to compare individual style props and ignore the wrapper object.
1883
+// See https://reactjs.org/docs/react-component.html#shouldcomponentupdate
1884
+
1885
+function shouldComponentUpdate(nextProps, nextState) {
1886
+ return !areEqual(this.props, nextProps) || shallowDiffers(this.state, nextState);
1887
+}
1888
+
1889
+exports.VariableSizeGrid = VariableSizeGrid;
1890
+exports.VariableSizeList = VariableSizeList;
1891
+exports.FixedSizeGrid = FixedSizeGrid;
1892
+exports.FixedSizeList = FixedSizeList;
1893
+exports.areEqual = areEqual;
1894
+exports.shouldComponentUpdate = shouldComponentUpdate;
vendor/react-window/dist/index.cjs.js.flow
new
+3
@@ -0,0 +1,3 @@
1
+// @flow
2
+
3
+export * from '../src';
vendor/react-window/dist/index.esm.js
new
+1883
@@ -0,0 +1,1883 @@
1
+import _extends from '@babel/runtime/helpers/esm/extends';
2
+import _inheritsLoose from '@babel/runtime/helpers/esm/inheritsLoose';
3
+import _assertThisInitialized from '@babel/runtime/helpers/esm/assertThisInitialized';
4
+import memoizeOne from 'memoize-one';
5
+import { createElement, PureComponent } from 'react';
6
+import _objectWithoutPropertiesLoose from '@babel/runtime/helpers/esm/objectWithoutPropertiesLoose';
7
+
8
+// Animation frame based implementation of setTimeout.
9
+// Inspired by Joe Lambert, https://gist.github.com/joelambert/1002116#file-requesttimeout-js
10
+var hasNativePerformanceNow = typeof performance === 'object' && typeof performance.now === 'function';
11
+var now = hasNativePerformanceNow ? function () {
12
+ return performance.now();
13
+} : function () {
14
+ return Date.now();
15
+};
16
+function cancelTimeout(timeoutID) {
17
+ cancelAnimationFrame(timeoutID.id);
18
+}
19
+function requestTimeout(callback, delay) {
20
+ var start = now();
21
+
22
+ function tick() {
23
+ if (now() - start >= delay) {
24
+ callback.call(null);
25
+ } else {
26
+ timeoutID.id = requestAnimationFrame(tick);
27
+ }
28
+ }
29
+
30
+ var timeoutID = {
31
+ id: requestAnimationFrame(tick)
32
+ };
33
+ return timeoutID;
34
+}
35
+
36
+var size = -1; // This utility copied from "dom-helpers" package.
37
+
38
+function getScrollbarSize(recalculate) {
39
+ if (recalculate === void 0) {
40
+ recalculate = false;
41
+ }
42
+
43
+ if (size === -1 || recalculate) {
44
+ var div = document.createElement('div');
45
+ var style = div.style;
46
+ style.width = '50px';
47
+ style.height = '50px';
48
+ style.overflow = 'scroll';
49
+ document.body.appendChild(div);
50
+ size = div.offsetWidth - div.clientWidth;
51
+ document.body.removeChild(div);
52
+ }
53
+
54
+ return size;
55
+}
56
+
57
+var IS_SCROLLING_DEBOUNCE_INTERVAL = 150;
58
+
59
+var defaultItemKey = function defaultItemKey(_ref) {
60
+ var columnIndex = _ref.columnIndex,
61
+ data = _ref.data,
62
+ rowIndex = _ref.rowIndex;
63
+ return rowIndex + ":" + columnIndex;
64
+}; // In DEV mode, this Set helps us only log a warning once per component instance.
65
+// This avoids spamming the console every time a render happens.
66
+
67
+
68
+var devWarningsOverscanCount = null;
69
+var devWarningsTagName = null;
70
+
71
+if (process.env.NODE_ENV !== 'production') {
72
+ if (typeof window !== 'undefined' && typeof window.WeakSet !== 'undefined') {
73
+ devWarningsOverscanCount =
74
+ /*#__PURE__*/
75
+ new WeakSet();
76
+ devWarningsTagName =
77
+ /*#__PURE__*/
78
+ new WeakSet();
79
+ }
80
+}
81
+
82
+function createGridComponent(_ref2) {
83
+ var _class, _temp;
84
+
85
+ var getColumnOffset = _ref2.getColumnOffset,
86
+ getColumnStartIndexForOffset = _ref2.getColumnStartIndexForOffset,
87
+ getColumnStopIndexForStartIndex = _ref2.getColumnStopIndexForStartIndex,
88
+ getColumnWidth = _ref2.getColumnWidth,
89
+ getEstimatedTotalHeight = _ref2.getEstimatedTotalHeight,
90
+ getEstimatedTotalWidth = _ref2.getEstimatedTotalWidth,
91
+ getOffsetForColumnAndAlignment = _ref2.getOffsetForColumnAndAlignment,
92
+ getOffsetForRowAndAlignment = _ref2.getOffsetForRowAndAlignment,
93
+ getRowHeight = _ref2.getRowHeight,
94
+ getRowOffset = _ref2.getRowOffset,
95
+ getRowStartIndexForOffset = _ref2.getRowStartIndexForOffset,
96
+ getRowStopIndexForStartIndex = _ref2.getRowStopIndexForStartIndex,
97
+ initInstanceProps = _ref2.initInstanceProps,
98
+ shouldResetStyleCacheOnItemSizeChange = _ref2.shouldResetStyleCacheOnItemSizeChange,
99
+ validateProps = _ref2.validateProps;
100
+ return _temp = _class =
101
+ /*#__PURE__*/
102
+ function (_PureComponent) {
103
+ _inheritsLoose(Grid, _PureComponent);
104
+
105
+ // Always use explicit constructor for React components.
106
+ // It produces less code after transpilation. (#26)
107
+ // eslint-disable-next-line no-useless-constructor
108
+ function Grid(props) {
109
+ var _this;
110
+
111
+ _this = _PureComponent.call(this, props) || this;
112
+ _this._instanceProps = initInstanceProps(_this.props, _assertThisInitialized(_assertThisInitialized(_this)));
113
+ _this._resetIsScrollingTimeoutId = null;
114
+ _this._outerRef = void 0;
115
+ _this.state = {
116
+ instance: _assertThisInitialized(_assertThisInitialized(_this)),
117
+ isScrolling: false,
118
+ horizontalScrollDirection: 'forward',
119
+ scrollLeft: typeof _this.props.initialScrollLeft === 'number' ? _this.props.initialScrollLeft : 0,
120
+ scrollTop: typeof _this.props.initialScrollTop === 'number' ? _this.props.initialScrollTop : 0,
121
+ scrollUpdateWasRequested: false,
122
+ verticalScrollDirection: 'forward'
123
+ };
124
+ _this._callOnItemsRendered = void 0;
125
+ _this._callOnItemsRendered = memoizeOne(function (overscanColumnStartIndex, overscanColumnStopIndex, overscanRowStartIndex, overscanRowStopIndex, visibleColumnStartIndex, visibleColumnStopIndex, visibleRowStartIndex, visibleRowStopIndex) {
126
+ return _this.props.onItemsRendered({
127
+ overscanColumnStartIndex: overscanColumnStartIndex,
128
+ overscanColumnStopIndex: overscanColumnStopIndex,
129
+ overscanRowStartIndex: overscanRowStartIndex,
130
+ overscanRowStopIndex: overscanRowStopIndex,
131
+ visibleColumnStartIndex: visibleColumnStartIndex,
132
+ visibleColumnStopIndex: visibleColumnStopIndex,
133
+ visibleRowStartIndex: visibleRowStartIndex,
134
+ visibleRowStopIndex: visibleRowStopIndex
135
+ });
136
+ });
137
+ _this._callOnScroll = void 0;
138
+ _this._callOnScroll = memoizeOne(function (scrollLeft, scrollTop, horizontalScrollDirection, verticalScrollDirection, scrollUpdateWasRequested) {
139
+ return _this.props.onScroll({
140
+ horizontalScrollDirection: horizontalScrollDirection,
141
+ scrollLeft: scrollLeft,
142
+ scrollTop: scrollTop,
143
+ verticalScrollDirection: verticalScrollDirection,
144
+ scrollUpdateWasRequested: scrollUpdateWasRequested
145
+ });
146
+ });
147
+ _this._getItemStyle = void 0;
148
+
149
+ _this._getItemStyle = function (rowIndex, columnIndex) {
150
+ var _this$props = _this.props,
151
+ columnWidth = _this$props.columnWidth,
152
+ direction = _this$props.direction,
153
+ rowHeight = _this$props.rowHeight;
154
+
155
+ var itemStyleCache = _this._getItemStyleCache(shouldResetStyleCacheOnItemSizeChange && columnWidth, shouldResetStyleCacheOnItemSizeChange && direction, shouldResetStyleCacheOnItemSizeChange && rowHeight);
156
+
157
+ var key = rowIndex + ":" + columnIndex;
158
+ var style;
159
+
160
+ if (itemStyleCache.hasOwnProperty(key)) {
161
+ style = itemStyleCache[key];
162
+ } else {
163
+ var _style;
164
+
165
+ itemStyleCache[key] = style = (_style = {
166
+ position: 'absolute'
167
+ }, _style[direction === 'rtl' ? 'right' : 'left'] = getColumnOffset(_this.props, columnIndex, _this._instanceProps), _style.top = getRowOffset(_this.props, rowIndex, _this._instanceProps), _style.height = getRowHeight(_this.props, rowIndex, _this._instanceProps), _style.width = getColumnWidth(_this.props, columnIndex, _this._instanceProps), _style);
168
+ }
169
+
170
+ return style;
171
+ };
172
+
173
+ _this._getItemStyleCache = void 0;
174
+ _this._getItemStyleCache = memoizeOne(function (_, __, ___) {
175
+ return {};
176
+ });
177
+
178
+ _this._onScroll = function (event) {
179
+ var _event$currentTarget = event.currentTarget,
180
+ clientWidth = _event$currentTarget.clientWidth,
181
+ scrollLeft = _event$currentTarget.scrollLeft,
182
+ scrollTop = _event$currentTarget.scrollTop,
183
+ scrollWidth = _event$currentTarget.scrollWidth;
184
+
185
+ _this.setState(function (prevState) {
186
+ if (prevState.scrollLeft === scrollLeft && prevState.scrollTop === scrollTop) {
187
+ // Scroll position may have been updated by cDM/cDU,
188
+ // In which case we don't need to trigger another render,
189
+ // And we don't want to update state.isScrolling.
190
+ return null;
191
+ }
192
+
193
+ var direction = _this.props.direction; // HACK According to the spec, scrollLeft should be negative for RTL aligned elements.
194
+ // Chrome does not seem to adhere; its scrollLeft values are positive (measured relative to the left).
195
+ // See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
196
+
197
+ var calculatedScrollLeft = scrollLeft;
198
+
199
+ if (direction === 'rtl') {
200
+ if (scrollLeft <= 0) {
201
+ calculatedScrollLeft = -scrollLeft;
202
+ } else {
203
+ calculatedScrollLeft = scrollWidth - clientWidth - scrollLeft;
204
+ }
205
+ }
206
+
207
+ return {
208
+ isScrolling: true,
209
+ horizontalScrollDirection: prevState.scrollLeft < scrollLeft ? 'forward' : 'backward',
210
+ scrollLeft: calculatedScrollLeft,
211
+ scrollTop: scrollTop,
212
+ verticalScrollDirection: prevState.scrollTop < scrollTop ? 'forward' : 'backward',
213
+ scrollUpdateWasRequested: false
214
+ };
215
+ }, _this._resetIsScrollingDebounced);
216
+ };
217
+
218
+ _this._outerRefSetter = function (ref) {
219
+ var outerRef = _this.props.outerRef;
220
+ _this._outerRef = ref;
221
+
222
+ if (typeof outerRef === 'function') {
223
+ outerRef(ref);
224
+ } else if (outerRef != null && typeof outerRef === 'object' && outerRef.hasOwnProperty('current')) {
225
+ outerRef.current = ref;
226
+ }
227
+ };
228
+
229
+ _this._resetIsScrollingDebounced = function () {
230
+ if (_this._resetIsScrollingTimeoutId !== null) {
231
+ cancelTimeout(_this._resetIsScrollingTimeoutId);
232
+ }
233
+
234
+ _this._resetIsScrollingTimeoutId = requestTimeout(_this._resetIsScrolling, IS_SCROLLING_DEBOUNCE_INTERVAL);
235
+ };
236
+
237
+ _this._resetIsScrolling = function () {
238
+ _this._resetIsScrollingTimeoutId = null;
239
+
240
+ _this.setState({
241
+ isScrolling: false
242
+ }, function () {
243
+ // Clear style cache after state update has been committed.
244
+ // This way we don't break pure sCU for items that don't use isScrolling param.
245
+ _this._getItemStyleCache(-1);
246
+ });
247
+ };
248
+
249
+ return _this;
250
+ }
251
+
252
+ Grid.getDerivedStateFromProps = function getDerivedStateFromProps(nextProps, prevState) {
253
+ validateSharedProps(nextProps, prevState);
254
+ validateProps(nextProps);
255
+ return null;
256
+ };
257
+
258
+ var _proto = Grid.prototype;
259
+
260
+ _proto.scrollTo = function scrollTo(_ref3) {
261
+ var scrollLeft = _ref3.scrollLeft,
262
+ scrollTop = _ref3.scrollTop;
263
+
264
+ if (scrollLeft !== undefined) {
265
+ scrollLeft = Math.max(0, scrollLeft);
266
+ }
267
+
268
+ if (scrollTop !== undefined) {
269
+ scrollTop = Math.max(0, scrollTop);
270
+ }
271
+
272
+ this.setState(function (prevState) {
273
+ if (scrollLeft === undefined) {
274
+ scrollLeft = prevState.scrollLeft;
275
+ }
276
+
277
+ if (scrollTop === undefined) {
278
+ scrollTop = prevState.scrollTop;
279
+ }
280
+
281
+ if (prevState.scrollLeft === scrollLeft && prevState.scrollTop === scrollTop) {
282
+ return null;
283
+ }
284
+
285
+ return {
286
+ horizontalScrollDirection: prevState.scrollLeft < scrollLeft ? 'forward' : 'backward',
287
+ scrollLeft: scrollLeft,
288
+ scrollTop: scrollTop,
289
+ scrollUpdateWasRequested: true,
290
+ verticalScrollDirection: prevState.scrollTop < scrollTop ? 'forward' : 'backward'
291
+ };
292
+ }, this._resetIsScrollingDebounced);
293
+ };
294
+
295
+ _proto.scrollToItem = function scrollToItem(_ref4) {
296
+ var _ref4$align = _ref4.align,
297
+ align = _ref4$align === void 0 ? 'auto' : _ref4$align,
298
+ columnIndex = _ref4.columnIndex,
299
+ rowIndex = _ref4.rowIndex;
300
+ var _this$props2 = this.props,
301
+ columnCount = _this$props2.columnCount,
302
+ height = _this$props2.height,
303
+ rowCount = _this$props2.rowCount,
304
+ width = _this$props2.width;
305
+ var _this$state = this.state,
306
+ scrollLeft = _this$state.scrollLeft,
307
+ scrollTop = _this$state.scrollTop;
308
+ var scrollbarSize = getScrollbarSize();
309
+
310
+ if (columnIndex !== undefined) {
311
+ columnIndex = Math.max(0, Math.min(columnIndex, columnCount - 1));
312
+ }
313
+
314
+ if (rowIndex !== undefined) {
315
+ rowIndex = Math.max(0, Math.min(rowIndex, rowCount - 1));
316
+ }
317
+
318
+ var estimatedTotalHeight = getEstimatedTotalHeight(this.props, this._instanceProps);
319
+ var estimatedTotalWidth = getEstimatedTotalWidth(this.props, this._instanceProps); // The scrollbar size should be considered when scrolling an item into view,
320
+ // to ensure it's fully visible.
321
+ // But we only need to account for its size when it's actually visible.
322
+
323
+ var horizontalScrollbarSize = estimatedTotalWidth > width ? scrollbarSize : 0;
324
+ var verticalScrollbarSize = estimatedTotalHeight > height ? scrollbarSize : 0;
325
+ this.scrollTo({
326
+ scrollLeft: columnIndex !== undefined ? getOffsetForColumnAndAlignment(this.props, columnIndex, align, scrollLeft, this._instanceProps, verticalScrollbarSize) : scrollLeft,
327
+ scrollTop: rowIndex !== undefined ? getOffsetForRowAndAlignment(this.props, rowIndex, align, scrollTop, this._instanceProps, horizontalScrollbarSize) : scrollTop
328
+ });
329
+ };
330
+
331
+ _proto.componentDidMount = function componentDidMount() {
332
+ var _this$props3 = this.props,
333
+ initialScrollLeft = _this$props3.initialScrollLeft,
334
+ initialScrollTop = _this$props3.initialScrollTop;
335
+
336
+ if (typeof initialScrollLeft === 'number' && this._outerRef != null) {
337
+ this._outerRef.scrollLeft = initialScrollLeft;
338
+ }
339
+
340
+ if (typeof initialScrollTop === 'number' && this._outerRef != null) {
341
+ this._outerRef.scrollTop = initialScrollTop;
342
+ }
343
+
344
+ this._callPropsCallbacks();
345
+ };
346
+
347
+ _proto.componentDidUpdate = function componentDidUpdate() {
348
+ var _this$state2 = this.state,
349
+ scrollLeft = _this$state2.scrollLeft,
350
+ scrollTop = _this$state2.scrollTop,
351
+ scrollUpdateWasRequested = _this$state2.scrollUpdateWasRequested;
352
+
353
+ if (scrollUpdateWasRequested && this._outerRef !== null) {
354
+ this._outerRef.scrollLeft = scrollLeft;
355
+ this._outerRef.scrollTop = scrollTop;
356
+ }
357
+
358
+ this._callPropsCallbacks();
359
+ };
360
+
361
+ _proto.componentWillUnmount = function componentWillUnmount() {
362
+ if (this._resetIsScrollingTimeoutId !== null) {
363
+ cancelTimeout(this._resetIsScrollingTimeoutId);
364
+ }
365
+ };
366
+
367
+ _proto.render = function render() {
368
+ var _this$props4 = this.props,
369
+ children = _this$props4.children,
370
+ className = _this$props4.className,
371
+ columnCount = _this$props4.columnCount,
372
+ direction = _this$props4.direction,
373
+ height = _this$props4.height,
374
+ innerRef = _this$props4.innerRef,
375
+ innerElementType = _this$props4.innerElementType,
376
+ innerTagName = _this$props4.innerTagName,
377
+ itemData = _this$props4.itemData,
378
+ _this$props4$itemKey = _this$props4.itemKey,
379
+ itemKey = _this$props4$itemKey === void 0 ? defaultItemKey : _this$props4$itemKey,
380
+ outerElementType = _this$props4.outerElementType,
381
+ outerTagName = _this$props4.outerTagName,
382
+ rowCount = _this$props4.rowCount,
383
+ style = _this$props4.style,
384
+ useIsScrolling = _this$props4.useIsScrolling,
385
+ width = _this$props4.width;
386
+ var isScrolling = this.state.isScrolling;
387
+
388
+ var _this$_getHorizontalR = this._getHorizontalRangeToRender(),
389
+ columnStartIndex = _this$_getHorizontalR[0],
390
+ columnStopIndex = _this$_getHorizontalR[1];
391
+
392
+ var _this$_getVerticalRan = this._getVerticalRangeToRender(),
393
+ rowStartIndex = _this$_getVerticalRan[0],
394
+ rowStopIndex = _this$_getVerticalRan[1];
395
+
396
+ var items = [];
397
+
398
+ if (columnCount > 0 && rowCount) {
399
+ for (var _rowIndex = rowStartIndex; _rowIndex <= rowStopIndex; _rowIndex++) {
400
+ for (var _columnIndex = columnStartIndex; _columnIndex <= columnStopIndex; _columnIndex++) {
401
+ items.push(createElement(children, {
402
+ columnIndex: _columnIndex,
403
+ data: itemData,
404
+ isScrolling: useIsScrolling ? isScrolling : undefined,
405
+ key: itemKey({
406
+ columnIndex: _columnIndex,
407
+ data: itemData,
408
+ rowIndex: _rowIndex
409
+ }),
410
+ rowIndex: _rowIndex,
411
+ style: this._getItemStyle(_rowIndex, _columnIndex)
412
+ }));
413
+ }
414
+ }
415
+ } // Read this value AFTER items have been created,
416
+ // So their actual sizes (if variable) are taken into consideration.
417
+
418
+
419
+ var estimatedTotalHeight = getEstimatedTotalHeight(this.props, this._instanceProps);
420
+ var estimatedTotalWidth = getEstimatedTotalWidth(this.props, this._instanceProps);
421
+ return createElement(outerElementType || outerTagName || 'div', {
422
+ className: className,
423
+ onScroll: this._onScroll,
424
+ ref: this._outerRefSetter,
425
+ style: _extends({
426
+ position: 'relative',
427
+ height: height,
428
+ width: width,
429
+ overflow: 'auto',
430
+ WebkitOverflowScrolling: 'touch',
431
+ willChange: 'transform',
432
+ direction: direction
433
+ }, style)
434
+ }, createElement(innerElementType || innerTagName || 'div', {
435
+ children: items,
436
+ ref: innerRef,
437
+ style: {
438
+ height: estimatedTotalHeight,
439
+ pointerEvents: isScrolling ? 'none' : '',
440
+ width: estimatedTotalWidth
441
+ }
442
+ }));
443
+ };
444
+
445
+ _proto._callPropsCallbacks = function _callPropsCallbacks() {
446
+ var _this$props5 = this.props,
447
+ columnCount = _this$props5.columnCount,
448
+ onItemsRendered = _this$props5.onItemsRendered,
449
+ onScroll = _this$props5.onScroll,
450
+ rowCount = _this$props5.rowCount;
451
+
452
+ if (typeof onItemsRendered === 'function') {
453
+ if (columnCount > 0 && rowCount > 0) {
454
+ var _this$_getHorizontalR2 = this._getHorizontalRangeToRender(),
455
+ _overscanColumnStartIndex = _this$_getHorizontalR2[0],
456
+ _overscanColumnStopIndex = _this$_getHorizontalR2[1],
457
+ _visibleColumnStartIndex = _this$_getHorizontalR2[2],
458
+ _visibleColumnStopIndex = _this$_getHorizontalR2[3];
459
+
460
+ var _this$_getVerticalRan2 = this._getVerticalRangeToRender(),
461
+ _overscanRowStartIndex = _this$_getVerticalRan2[0],
462
+ _overscanRowStopIndex = _this$_getVerticalRan2[1],
463
+ _visibleRowStartIndex = _this$_getVerticalRan2[2],
464
+ _visibleRowStopIndex = _this$_getVerticalRan2[3];
465
+
466
+ this._callOnItemsRendered(_overscanColumnStartIndex, _overscanColumnStopIndex, _overscanRowStartIndex, _overscanRowStopIndex, _visibleColumnStartIndex, _visibleColumnStopIndex, _visibleRowStartIndex, _visibleRowStopIndex);
467
+ }
468
+ }
469
+
470
+ if (typeof onScroll === 'function') {
471
+ var _this$state3 = this.state,
472
+ _horizontalScrollDirection = _this$state3.horizontalScrollDirection,
473
+ _scrollLeft = _this$state3.scrollLeft,
474
+ _scrollTop = _this$state3.scrollTop,
475
+ _scrollUpdateWasRequested = _this$state3.scrollUpdateWasRequested,
476
+ _verticalScrollDirection = _this$state3.verticalScrollDirection;
477
+
478
+ this._callOnScroll(_scrollLeft, _scrollTop, _horizontalScrollDirection, _verticalScrollDirection, _scrollUpdateWasRequested);
479
+ }
480
+ }; // Lazily create and cache item styles while scrolling,
481
+ // So that pure component sCU will prevent re-renders.
482
+ // We maintain this cache, and pass a style prop rather than index,
483
+ // So that List can clear cached styles and force item re-render if necessary.
484
+
485
+
486
+ _proto._getHorizontalRangeToRender = function _getHorizontalRangeToRender() {
487
+ var _this$props6 = this.props,
488
+ columnCount = _this$props6.columnCount,
489
+ overscanColumnsCount = _this$props6.overscanColumnsCount,
490
+ overscanCount = _this$props6.overscanCount,
491
+ rowCount = _this$props6.rowCount;
492
+ var _this$state4 = this.state,
493
+ horizontalScrollDirection = _this$state4.horizontalScrollDirection,
494
+ isScrolling = _this$state4.isScrolling,
495
+ scrollLeft = _this$state4.scrollLeft;
496
+ var overscanCountResolved = overscanColumnsCount || overscanCount || 1;
497
+
498
+ if (columnCount === 0 || rowCount === 0) {
499
+ return [0, 0, 0, 0];
500
+ }
501
+
502
+ var startIndex = getColumnStartIndexForOffset(this.props, scrollLeft, this._instanceProps);
503
+ var stopIndex = getColumnStopIndexForStartIndex(this.props, startIndex, scrollLeft, this._instanceProps); // Overscan by one item in each direction so that tab/focus works.
504
+ // If there isn't at least one extra item, tab loops back around.
505
+
506
+ var overscanBackward = !isScrolling || horizontalScrollDirection === 'backward' ? Math.max(1, overscanCountResolved) : 1;
507
+ var overscanForward = !isScrolling || horizontalScrollDirection === 'forward' ? Math.max(1, overscanCountResolved) : 1;
508
+ return [Math.max(0, startIndex - overscanBackward), Math.max(0, Math.min(columnCount - 1, stopIndex + overscanForward)), startIndex, stopIndex];
509
+ };
510
+
511
+ _proto._getVerticalRangeToRender = function _getVerticalRangeToRender() {
512
+ var _this$props7 = this.props,
513
+ columnCount = _this$props7.columnCount,
514
+ overscanCount = _this$props7.overscanCount,
515
+ overscanRowsCount = _this$props7.overscanRowsCount,
516
+ rowCount = _this$props7.rowCount;
517
+ var _this$state5 = this.state,
518
+ isScrolling = _this$state5.isScrolling,
519
+ verticalScrollDirection = _this$state5.verticalScrollDirection,
520
+ scrollTop = _this$state5.scrollTop;
521
+ var overscanCountResolved = overscanRowsCount || overscanCount || 1;
522
+
523
+ if (columnCount === 0 || rowCount === 0) {
524
+ return [0, 0, 0, 0];
525
+ }
526
+
527
+ var startIndex = getRowStartIndexForOffset(this.props, scrollTop, this._instanceProps);
528
+ var stopIndex = getRowStopIndexForStartIndex(this.props, startIndex, scrollTop, this._instanceProps); // Overscan by one item in each direction so that tab/focus works.
529
+ // If there isn't at least one extra item, tab loops back around.
530
+
531
+ var overscanBackward = !isScrolling || verticalScrollDirection === 'backward' ? Math.max(1, overscanCountResolved) : 1;
532
+ var overscanForward = !isScrolling || verticalScrollDirection === 'forward' ? Math.max(1, overscanCountResolved) : 1;
533
+ return [Math.max(0, startIndex - overscanBackward), Math.max(0, Math.min(rowCount - 1, stopIndex + overscanForward)), startIndex, stopIndex];
534
+ };
535
+
536
+ return Grid;
537
+ }(PureComponent), _class.defaultProps = {
538
+ direction: 'ltr',
539
+ itemData: undefined,
540
+ useIsScrolling: false
541
+ }, _temp;
542
+}
543
+
544
+var validateSharedProps = function validateSharedProps(_ref5, _ref6) {
545
+ var children = _ref5.children,
546
+ direction = _ref5.direction,
547
+ height = _ref5.height,
548
+ innerTagName = _ref5.innerTagName,
549
+ outerTagName = _ref5.outerTagName,
550
+ overscanCount = _ref5.overscanCount,
551
+ width = _ref5.width;
552
+ var instance = _ref6.instance;
553
+
554
+ if (process.env.NODE_ENV !== 'production') {
555
+ if (typeof overscanCount === 'number') {
556
+ if (devWarningsOverscanCount && !devWarningsOverscanCount.has(instance)) {
557
+ devWarningsOverscanCount.add(instance);
558
+ console.warn('The overscanCount prop has been deprecated. ' + 'Please use the overscanColumnsCount and overscanRowsCount props instead.');
559
+ }
560
+ }
561
+
562
+ if (innerTagName != null || outerTagName != null) {
563
+ if (devWarningsTagName && !devWarningsTagName.has(instance)) {
564
+ devWarningsTagName.add(instance);
565
+ console.warn('The innerTagName and outerTagName props have been deprecated. ' + 'Please use the innerElementType and outerElementType props instead.');
566
+ }
567
+ }
568
+
569
+ if (children == null) {
570
+ throw Error('An invalid "children" prop has been specified. ' + 'Value should be a React component. ' + ("\"" + (children === null ? 'null' : typeof children) + "\" was specified."));
571
+ }
572
+
573
+ switch (direction) {
574
+ case 'ltr':
575
+ case 'rtl':
576
+ // Valid values
577
+ break;
578
+
579
+ default:
580
+ throw Error('An invalid "direction" prop has been specified. ' + 'Value should be either "ltr" or "rtl". ' + ("\"" + direction + "\" was specified."));
581
+ }
582
+
583
+ if (typeof width !== 'number') {
584
+ throw Error('An invalid "width" prop has been specified. ' + 'Grids must specify a number for width. ' + ("\"" + (width === null ? 'null' : typeof width) + "\" was specified."));
585
+ }
586
+
587
+ if (typeof height !== 'number') {
588
+ throw Error('An invalid "height" prop has been specified. ' + 'Grids must specify a number for height. ' + ("\"" + (height === null ? 'null' : typeof height) + "\" was specified."));
589
+ }
590
+ }
591
+};
592
+
593
+var DEFAULT_ESTIMATED_ITEM_SIZE = 50;
594
+
595
+var getEstimatedTotalHeight = function getEstimatedTotalHeight(_ref, _ref2) {
596
+ var rowCount = _ref.rowCount;
597
+ var rowMetadataMap = _ref2.rowMetadataMap,
598
+ estimatedRowHeight = _ref2.estimatedRowHeight,
599
+ lastMeasuredRowIndex = _ref2.lastMeasuredRowIndex;
600
+ var totalSizeOfMeasuredRows = 0; // Edge case check for when the number of items decreases while a scroll is in progress.
601
+ // https://github.com/bvaughn/react-window/pull/138
602
+
603
+ if (lastMeasuredRowIndex >= rowCount) {
604
+ lastMeasuredRowIndex = rowCount - 1;
605
+ }
606
+
607
+ if (lastMeasuredRowIndex >= 0) {
608
+ var itemMetadata = rowMetadataMap[lastMeasuredRowIndex];
609
+ totalSizeOfMeasuredRows = itemMetadata.offset + itemMetadata.size;
610
+ }
611
+
612
+ var numUnmeasuredItems = rowCount - lastMeasuredRowIndex - 1;
613
+ var totalSizeOfUnmeasuredItems = numUnmeasuredItems * estimatedRowHeight;
614
+ return totalSizeOfMeasuredRows + totalSizeOfUnmeasuredItems;
615
+};
616
+
617
+var getEstimatedTotalWidth = function getEstimatedTotalWidth(_ref3, _ref4) {
618
+ var columnCount = _ref3.columnCount;
619
+ var columnMetadataMap = _ref4.columnMetadataMap,
620
+ estimatedColumnWidth = _ref4.estimatedColumnWidth,
621
+ lastMeasuredColumnIndex = _ref4.lastMeasuredColumnIndex;
622
+ var totalSizeOfMeasuredRows = 0; // Edge case check for when the number of items decreases while a scroll is in progress.
623
+ // https://github.com/bvaughn/react-window/pull/138
624
+
625
+ if (lastMeasuredColumnIndex >= columnCount) {
626
+ lastMeasuredColumnIndex = columnCount - 1;
627
+ }
628
+
629
+ if (lastMeasuredColumnIndex >= 0) {
630
+ var itemMetadata = columnMetadataMap[lastMeasuredColumnIndex];
631
+ totalSizeOfMeasuredRows = itemMetadata.offset + itemMetadata.size;
632
+ }
633
+
634
+ var numUnmeasuredItems = columnCount - lastMeasuredColumnIndex - 1;
635
+ var totalSizeOfUnmeasuredItems = numUnmeasuredItems * estimatedColumnWidth;
636
+ return totalSizeOfMeasuredRows + totalSizeOfUnmeasuredItems;
637
+};
638
+
639
+var getItemMetadata = function getItemMetadata(itemType, props, index, instanceProps) {
640
+ var itemMetadataMap, itemSize, lastMeasuredIndex;
641
+
642
+ if (itemType === 'column') {
643
+ itemMetadataMap = instanceProps.columnMetadataMap;
644
+ itemSize = props.columnWidth;
645
+ lastMeasuredIndex = instanceProps.lastMeasuredColumnIndex;
646
+ } else {
647
+ itemMetadataMap = instanceProps.rowMetadataMap;
648
+ itemSize = props.rowHeight;
649
+ lastMeasuredIndex = instanceProps.lastMeasuredRowIndex;
650
+ }
651
+
652
+ if (index > lastMeasuredIndex) {
653
+ var offset = 0;
654
+
655
+ if (lastMeasuredIndex >= 0) {
656
+ var itemMetadata = itemMetadataMap[lastMeasuredIndex];
657
+ offset = itemMetadata.offset + itemMetadata.size;
658
+ }
659
+
660
+ for (var i = lastMeasuredIndex + 1; i <= index; i++) {
661
+ var size = itemSize(i);
662
+ itemMetadataMap[i] = {
663
+ offset: offset,
664
+ size: size
665
+ };
666
+ offset += size;
667
+ }
668
+
669
+ if (itemType === 'column') {
670
+ instanceProps.lastMeasuredColumnIndex = index;
671
+ } else {
672
+ instanceProps.lastMeasuredRowIndex = index;
673
+ }
674
+ }
675
+
676
+ return itemMetadataMap[index];
677
+};
678
+
679
+var findNearestItem = function findNearestItem(itemType, props, instanceProps, offset) {
680
+ var itemMetadataMap, lastMeasuredIndex;
681
+
682
+ if (itemType === 'column') {
683
+ itemMetadataMap = instanceProps.columnMetadataMap;
684
+ lastMeasuredIndex = instanceProps.lastMeasuredColumnIndex;
685
+ } else {
686
+ itemMetadataMap = instanceProps.rowMetadataMap;
687
+ lastMeasuredIndex = instanceProps.lastMeasuredRowIndex;
688
+ }
689
+
690
+ var lastMeasuredItemOffset = lastMeasuredIndex > 0 ? itemMetadataMap[lastMeasuredIndex].offset : 0;
691
+
692
+ if (lastMeasuredItemOffset >= offset) {
693
+ // If we've already measured items within this range just use a binary search as it's faster.
694
+ return findNearestItemBinarySearch(itemType, props, instanceProps, lastMeasuredIndex, 0, offset);
695
+ } else {
696
+ // If we haven't yet measured this high, fallback to an exponential search with an inner binary search.
697
+ // The exponential search avoids pre-computing sizes for the full set of items as a binary search would.
698
+ // The overall complexity for this approach is O(log n).
699
+ return findNearestItemExponentialSearch(itemType, props, instanceProps, Math.max(0, lastMeasuredIndex), offset);
700
+ }
701
+};
702
+
703
+var findNearestItemBinarySearch = function findNearestItemBinarySearch(itemType, props, instanceProps, high, low, offset) {
704
+ while (low <= high) {
705
+ var middle = low + Math.floor((high - low) / 2);
706
+ var currentOffset = getItemMetadata(itemType, props, middle, instanceProps).offset;
707
+
708
+ if (currentOffset === offset) {
709
+ return middle;
710
+ } else if (currentOffset < offset) {
711
+ low = middle + 1;
712
+ } else if (currentOffset > offset) {
713
+ high = middle - 1;
714
+ }
715
+ }
716
+
717
+ if (low > 0) {
718
+ return low - 1;
719
+ } else {
720
+ return 0;
721
+ }
722
+};
723
+
724
+var findNearestItemExponentialSearch = function findNearestItemExponentialSearch(itemType, props, instanceProps, index, offset) {
725
+ var itemCount = itemType === 'column' ? props.columnCount : props.rowCount;
726
+ var interval = 1;
727
+
728
+ while (index < itemCount && getItemMetadata(itemType, props, index, instanceProps).offset < offset) {
729
+ index += interval;
730
+ interval *= 2;
731
+ }
732
+
733
+ return findNearestItemBinarySearch(itemType, props, instanceProps, Math.min(index, itemCount - 1), Math.floor(index / 2), offset);
734
+};
735
+
736
+var getOffsetForIndexAndAlignment = function getOffsetForIndexAndAlignment(itemType, props, index, align, scrollOffset, instanceProps, scrollbarSize) {
737
+ var size = itemType === 'column' ? props.width : props.height;
738
+ var itemMetadata = getItemMetadata(itemType, props, index, instanceProps); // Get estimated total size after ItemMetadata is computed,
739
+ // To ensure it reflects actual measurements instead of just estimates.
740
+
741
+ var estimatedTotalSize = itemType === 'column' ? getEstimatedTotalWidth(props, instanceProps) : getEstimatedTotalHeight(props, instanceProps);
742
+ var maxOffset = Math.max(0, Math.min(estimatedTotalSize - size, itemMetadata.offset));
743
+ var minOffset = Math.max(0, itemMetadata.offset - size + scrollbarSize + itemMetadata.size);
744
+
745
+ if (align === 'smart') {
746
+ if (scrollOffset >= minOffset - size && scrollOffset <= maxOffset + size) {
747
+ align = 'auto';
748
+ } else {
749
+ align = 'center';
750
+ }
751
+ }
752
+
753
+ switch (align) {
754
+ case 'start':
755
+ return maxOffset;
756
+
757
+ case 'end':
758
+ return minOffset;
759
+
760
+ case 'center':
761
+ return Math.round(minOffset + (maxOffset - minOffset) / 2);
762
+
763
+ case 'auto':
764
+ default:
765
+ if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
766
+ return scrollOffset;
767
+ } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
768
+ return minOffset;
769
+ } else {
770
+ return maxOffset;
771
+ }
772
+
773
+ }
774
+};
775
+
776
+var VariableSizeGrid =
777
+/*#__PURE__*/
778
+createGridComponent({
779
+ getColumnOffset: function getColumnOffset(props, index, instanceProps) {
780
+ return getItemMetadata('column', props, index, instanceProps).offset;
781
+ },
782
+ getColumnStartIndexForOffset: function getColumnStartIndexForOffset(props, scrollLeft, instanceProps) {
783
+ return findNearestItem('column', props, instanceProps, scrollLeft);
784
+ },
785
+ getColumnStopIndexForStartIndex: function getColumnStopIndexForStartIndex(props, startIndex, scrollLeft, instanceProps) {
786
+ var columnCount = props.columnCount,
787
+ width = props.width;
788
+ var itemMetadata = getItemMetadata('column', props, startIndex, instanceProps);
789
+ var maxOffset = scrollLeft + width;
790
+ var offset = itemMetadata.offset + itemMetadata.size;
791
+ var stopIndex = startIndex;
792
+
793
+ while (stopIndex < columnCount - 1 && offset < maxOffset) {
794
+ stopIndex++;
795
+ offset += getItemMetadata('column', props, stopIndex, instanceProps).size;
796
+ }
797
+
798
+ return stopIndex;
799
+ },
800
+ getColumnWidth: function getColumnWidth(props, index, instanceProps) {
801
+ return instanceProps.columnMetadataMap[index].size;
802
+ },
803
+ getEstimatedTotalHeight: getEstimatedTotalHeight,
804
+ getEstimatedTotalWidth: getEstimatedTotalWidth,
805
+ getOffsetForColumnAndAlignment: function getOffsetForColumnAndAlignment(props, index, align, scrollOffset, instanceProps, scrollbarSize) {
806
+ return getOffsetForIndexAndAlignment('column', props, index, align, scrollOffset, instanceProps, scrollbarSize);
807
+ },
808
+ getOffsetForRowAndAlignment: function getOffsetForRowAndAlignment(props, index, align, scrollOffset, instanceProps, scrollbarSize) {
809
+ return getOffsetForIndexAndAlignment('row', props, index, align, scrollOffset, instanceProps, scrollbarSize);
810
+ },
811
+ getRowOffset: function getRowOffset(props, index, instanceProps) {
812
+ return getItemMetadata('row', props, index, instanceProps).offset;
813
+ },
814
+ getRowHeight: function getRowHeight(props, index, instanceProps) {
815
+ return instanceProps.rowMetadataMap[index].size;
816
+ },
817
+ getRowStartIndexForOffset: function getRowStartIndexForOffset(props, scrollTop, instanceProps) {
818
+ return findNearestItem('row', props, instanceProps, scrollTop);
819
+ },
820
+ getRowStopIndexForStartIndex: function getRowStopIndexForStartIndex(props, startIndex, scrollTop, instanceProps) {
821
+ var rowCount = props.rowCount,
822
+ height = props.height;
823
+ var itemMetadata = getItemMetadata('row', props, startIndex, instanceProps);
824
+ var maxOffset = scrollTop + height;
825
+ var offset = itemMetadata.offset + itemMetadata.size;
826
+ var stopIndex = startIndex;
827
+
828
+ while (stopIndex < rowCount - 1 && offset < maxOffset) {
829
+ stopIndex++;
830
+ offset += getItemMetadata('row', props, stopIndex, instanceProps).size;
831
+ }
832
+
833
+ return stopIndex;
834
+ },
835
+ initInstanceProps: function initInstanceProps(props, instance) {
836
+ var _ref5 = props,
837
+ estimatedColumnWidth = _ref5.estimatedColumnWidth,
838
+ estimatedRowHeight = _ref5.estimatedRowHeight;
839
+ var instanceProps = {
840
+ columnMetadataMap: {},
841
+ estimatedColumnWidth: estimatedColumnWidth || DEFAULT_ESTIMATED_ITEM_SIZE,
842
+ estimatedRowHeight: estimatedRowHeight || DEFAULT_ESTIMATED_ITEM_SIZE,
843
+ lastMeasuredColumnIndex: -1,
844
+ lastMeasuredRowIndex: -1,
845
+ rowMetadataMap: {}
846
+ };
847
+
848
+ instance.resetAfterColumnIndex = function (columnIndex, shouldForceUpdate) {
849
+ if (shouldForceUpdate === void 0) {
850
+ shouldForceUpdate = true;
851
+ }
852
+
853
+ instance.resetAfterIndices({
854
+ columnIndex: columnIndex,
855
+ shouldForceUpdate: shouldForceUpdate
856
+ });
857
+ };
858
+
859
+ instance.resetAfterRowIndex = function (rowIndex, shouldForceUpdate) {
860
+ if (shouldForceUpdate === void 0) {
861
+ shouldForceUpdate = true;
862
+ }
863
+
864
+ instance.resetAfterIndices({
865
+ rowIndex: rowIndex,
866
+ shouldForceUpdate: shouldForceUpdate
867
+ });
868
+ };
869
+
870
+ instance.resetAfterIndices = function (_ref6) {
871
+ var columnIndex = _ref6.columnIndex,
872
+ rowIndex = _ref6.rowIndex,
873
+ _ref6$shouldForceUpda = _ref6.shouldForceUpdate,
874
+ shouldForceUpdate = _ref6$shouldForceUpda === void 0 ? true : _ref6$shouldForceUpda;
875
+
876
+ if (typeof columnIndex === 'number') {
877
+ instanceProps.lastMeasuredColumnIndex = Math.min(instanceProps.lastMeasuredColumnIndex, columnIndex - 1);
878
+ }
879
+
880
+ if (typeof rowIndex === 'number') {
881
+ instanceProps.lastMeasuredRowIndex = Math.min(instanceProps.lastMeasuredRowIndex, rowIndex - 1);
882
+ } // We could potentially optimize further by only evicting styles after this index,
883
+ // But since styles are only cached while scrolling is in progress-
884
+ // It seems an unnecessary optimization.
885
+ // It's unlikely that resetAfterIndex() will be called while a user is scrolling.
886
+
887
+
888
+ instance._getItemStyleCache(-1);
889
+
890
+ if (shouldForceUpdate) {
891
+ instance.forceUpdate();
892
+ }
893
+ };
894
+
895
+ return instanceProps;
896
+ },
897
+ shouldResetStyleCacheOnItemSizeChange: false,
898
+ validateProps: function validateProps(_ref7) {
899
+ var columnWidth = _ref7.columnWidth,
900
+ rowHeight = _ref7.rowHeight;
901
+
902
+ if (process.env.NODE_ENV !== 'production') {
903
+ if (typeof columnWidth !== 'function') {
904
+ throw Error('An invalid "columnWidth" prop has been specified. ' + 'Value should be a function. ' + ("\"" + (columnWidth === null ? 'null' : typeof columnWidth) + "\" was specified."));
905
+ } else if (typeof rowHeight !== 'function') {
906
+ throw Error('An invalid "rowHeight" prop has been specified. ' + 'Value should be a function. ' + ("\"" + (rowHeight === null ? 'null' : typeof rowHeight) + "\" was specified."));
907
+ }
908
+ }
909
+ }
910
+});
911
+
912
+var IS_SCROLLING_DEBOUNCE_INTERVAL$1 = 150;
913
+
914
+var defaultItemKey$1 = function defaultItemKey(index, data) {
915
+ return index;
916
+}; // In DEV mode, this Set helps us only log a warning once per component instance.
917
+// This avoids spamming the console every time a render happens.
918
+
919
+
920
+var devWarningsDirection = null;
921
+var devWarningsTagName$1 = null;
922
+
923
+if (process.env.NODE_ENV !== 'production') {
924
+ if (typeof window !== 'undefined' && typeof window.WeakSet !== 'undefined') {
925
+ devWarningsDirection =
926
+ /*#__PURE__*/
927
+ new WeakSet();
928
+ devWarningsTagName$1 =
929
+ /*#__PURE__*/
930
+ new WeakSet();
931
+ }
932
+}
933
+
934
+function createListComponent(_ref) {
935
+ var _class, _temp;
936
+
937
+ var getItemOffset = _ref.getItemOffset,
938
+ getEstimatedTotalSize = _ref.getEstimatedTotalSize,
939
+ getItemSize = _ref.getItemSize,
940
+ getOffsetForIndexAndAlignment = _ref.getOffsetForIndexAndAlignment,
941
+ getStartIndexForOffset = _ref.getStartIndexForOffset,
942
+ getStopIndexForStartIndex = _ref.getStopIndexForStartIndex,
943
+ initInstanceProps = _ref.initInstanceProps,
944
+ shouldResetStyleCacheOnItemSizeChange = _ref.shouldResetStyleCacheOnItemSizeChange,
945
+ validateProps = _ref.validateProps;
946
+ return _temp = _class =
947
+ /*#__PURE__*/
948
+ function (_PureComponent) {
949
+ _inheritsLoose(List, _PureComponent);
950
+
951
+ // Always use explicit constructor for React components.
952
+ // It produces less code after transpilation. (#26)
953
+ // eslint-disable-next-line no-useless-constructor
954
+ function List(props) {
955
+ var _this;
956
+
957
+ _this = _PureComponent.call(this, props) || this;
958
+ _this._instanceProps = initInstanceProps(_this.props, _assertThisInitialized(_assertThisInitialized(_this)));
959
+ _this._outerRef = void 0;
960
+ _this._resetIsScrollingTimeoutId = null;
961
+ _this.state = {
962
+ instance: _assertThisInitialized(_assertThisInitialized(_this)),
963
+ isScrolling: false,
964
+ scrollDirection: 'forward',
965
+ scrollOffset: typeof _this.props.initialScrollOffset === 'number' ? _this.props.initialScrollOffset : 0,
966
+ scrollUpdateWasRequested: false
967
+ };
968
+ _this._callOnItemsRendered = void 0;
969
+ _this._callOnItemsRendered = memoizeOne(function (overscanStartIndex, overscanStopIndex, visibleStartIndex, visibleStopIndex) {
970
+ return _this.props.onItemsRendered({
971
+ overscanStartIndex: overscanStartIndex,
972
+ overscanStopIndex: overscanStopIndex,
973
+ visibleStartIndex: visibleStartIndex,
974
+ visibleStopIndex: visibleStopIndex
975
+ });
976
+ });
977
+ _this._callOnScroll = void 0;
978
+ _this._callOnScroll = memoizeOne(function (scrollDirection, scrollOffset, scrollUpdateWasRequested) {
979
+ return _this.props.onScroll({
980
+ scrollDirection: scrollDirection,
981
+ scrollOffset: scrollOffset,
982
+ scrollUpdateWasRequested: scrollUpdateWasRequested
983
+ });
984
+ });
985
+ _this._getItemStyle = void 0;
986
+
987
+ _this._getItemStyle = function (index) {
988
+ var _this$props = _this.props,
989
+ direction = _this$props.direction,
990
+ itemSize = _this$props.itemSize,
991
+ layout = _this$props.layout;
992
+
993
+ var itemStyleCache = _this._getItemStyleCache(shouldResetStyleCacheOnItemSizeChange && itemSize, shouldResetStyleCacheOnItemSizeChange && layout, shouldResetStyleCacheOnItemSizeChange && direction);
994
+
995
+ var style;
996
+
997
+ if (itemStyleCache.hasOwnProperty(index)) {
998
+ style = itemStyleCache[index];
999
+ } else {
1000
+ var _style;
1001
+
1002
+ var _offset = getItemOffset(_this.props, index, _this._instanceProps);
1003
+
1004
+ var size = getItemSize(_this.props, index, _this._instanceProps); // TODO Deprecate direction "horizontal"
1005
+
1006
+ var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
1007
+ itemStyleCache[index] = style = (_style = {
1008
+ position: 'absolute'
1009
+ }, _style[direction === 'rtl' ? 'right' : 'left'] = isHorizontal ? _offset : 0, _style.top = !isHorizontal ? _offset : 0, _style.height = !isHorizontal ? size : '100%', _style.width = isHorizontal ? size : '100%', _style);
1010
+ }
1011
+
1012
+ return style;
1013
+ };
1014
+
1015
+ _this._getItemStyleCache = void 0;
1016
+ _this._getItemStyleCache = memoizeOne(function (_, __, ___) {
1017
+ return {};
1018
+ });
1019
+
1020
+ _this._onScrollHorizontal = function (event) {
1021
+ var _event$currentTarget = event.currentTarget,
1022
+ clientWidth = _event$currentTarget.clientWidth,
1023
+ scrollLeft = _event$currentTarget.scrollLeft,
1024
+ scrollWidth = _event$currentTarget.scrollWidth;
1025
+
1026
+ _this.setState(function (prevState) {
1027
+ if (prevState.scrollOffset === scrollLeft) {
1028
+ // Scroll position may have been updated by cDM/cDU,
1029
+ // In which case we don't need to trigger another render,
1030
+ // And we don't want to update state.isScrolling.
1031
+ return null;
1032
+ }
1033
+
1034
+ var direction = _this.props.direction; // HACK According to the spec, scrollLeft should be negative for RTL aligned elements.
1035
+ // Chrome does not seem to adhere; its scrolLeft values are positive (measured relative to the left).
1036
+ // See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
1037
+
1038
+ var scrollOffset = scrollLeft;
1039
+
1040
+ if (direction === 'rtl') {
1041
+ if (scrollLeft <= 0) {
1042
+ scrollOffset = -scrollOffset;
1043
+ } else {
1044
+ scrollOffset = scrollWidth - clientWidth - scrollLeft;
1045
+ }
1046
+ }
1047
+
1048
+ return {
1049
+ isScrolling: true,
1050
+ scrollDirection: prevState.scrollOffset < scrollLeft ? 'forward' : 'backward',
1051
+ scrollOffset: scrollOffset,
1052
+ scrollUpdateWasRequested: false
1053
+ };
1054
+ }, _this._resetIsScrollingDebounced);
1055
+ };
1056
+
1057
+ _this._onScrollVertical = function (event) {
1058
+ var scrollTop = event.currentTarget.scrollTop;
1059
+
1060
+ _this.setState(function (prevState) {
1061
+ if (prevState.scrollOffset === scrollTop) {
1062
+ // Scroll position may have been updated by cDM/cDU,
1063
+ // In which case we don't need to trigger another render,
1064
+ // And we don't want to update state.isScrolling.
1065
+ return null;
1066
+ }
1067
+
1068
+ return {
1069
+ isScrolling: true,
1070
+ scrollDirection: prevState.scrollOffset < scrollTop ? 'forward' : 'backward',
1071
+ scrollOffset: scrollTop,
1072
+ scrollUpdateWasRequested: false
1073
+ };
1074
+ }, _this._resetIsScrollingDebounced);
1075
+ };
1076
+
1077
+ _this._outerRefSetter = function (ref) {
1078
+ var outerRef = _this.props.outerRef;
1079
+ _this._outerRef = ref;
1080
+
1081
+ if (typeof outerRef === 'function') {
1082
+ outerRef(ref);
1083
+ } else if (outerRef != null && typeof outerRef === 'object' && outerRef.hasOwnProperty('current')) {
1084
+ outerRef.current = ref;
1085
+ }
1086
+ };
1087
+
1088
+ _this._resetIsScrollingDebounced = function () {
1089
+ if (_this._resetIsScrollingTimeoutId !== null) {
1090
+ cancelTimeout(_this._resetIsScrollingTimeoutId);
1091
+ }
1092
+
1093
+ _this._resetIsScrollingTimeoutId = requestTimeout(_this._resetIsScrolling, IS_SCROLLING_DEBOUNCE_INTERVAL$1);
1094
+ };
1095
+
1096
+ _this._resetIsScrolling = function () {
1097
+ _this._resetIsScrollingTimeoutId = null;
1098
+
1099
+ _this.setState({
1100
+ isScrolling: false
1101
+ }, function () {
1102
+ // Clear style cache after state update has been committed.
1103
+ // This way we don't break pure sCU for items that don't use isScrolling param.
1104
+ _this._getItemStyleCache(-1, null);
1105
+ });
1106
+ };
1107
+
1108
+ return _this;
1109
+ }
1110
+
1111
+ List.getDerivedStateFromProps = function getDerivedStateFromProps(nextProps, prevState) {
1112
+ validateSharedProps$1(nextProps, prevState);
1113
+ validateProps(nextProps);
1114
+ return null;
1115
+ };
1116
+
1117
+ var _proto = List.prototype;
1118
+
1119
+ _proto.scrollTo = function scrollTo(scrollOffset) {
1120
+ scrollOffset = Math.max(0, scrollOffset);
1121
+ this.setState(function (prevState) {
1122
+ if (prevState.scrollOffset === scrollOffset) {
1123
+ return null;
1124
+ }
1125
+
1126
+ return {
1127
+ scrollDirection: prevState.scrollOffset < scrollOffset ? 'forward' : 'backward',
1128
+ scrollOffset: scrollOffset,
1129
+ scrollUpdateWasRequested: true
1130
+ };
1131
+ }, this._resetIsScrollingDebounced);
1132
+ };
1133
+
1134
+ _proto.scrollToItem = function scrollToItem(index, align) {
1135
+ if (align === void 0) {
1136
+ align = 'auto';
1137
+ }
1138
+
1139
+ var itemCount = this.props.itemCount;
1140
+ var scrollOffset = this.state.scrollOffset;
1141
+ index = Math.max(0, Math.min(index, itemCount - 1));
1142
+ this.scrollTo(getOffsetForIndexAndAlignment(this.props, index, align, scrollOffset, this._instanceProps));
1143
+ };
1144
+
1145
+ _proto.componentDidMount = function componentDidMount() {
1146
+ var _this$props2 = this.props,
1147
+ direction = _this$props2.direction,
1148
+ initialScrollOffset = _this$props2.initialScrollOffset,
1149
+ layout = _this$props2.layout;
1150
+
1151
+ if (typeof initialScrollOffset === 'number' && this._outerRef !== null) {
1152
+ // TODO Deprecate direction "horizontal"
1153
+ if (direction === 'horizontal' || layout === 'horizontal') {
1154
+ this._outerRef.scrollLeft = initialScrollOffset;
1155
+ } else {
1156
+ this._outerRef.scrollTop = initialScrollOffset;
1157
+ }
1158
+ }
1159
+
1160
+ this._callPropsCallbacks();
1161
+ };
1162
+
1163
+ _proto.componentDidUpdate = function componentDidUpdate() {
1164
+ var _this$props3 = this.props,
1165
+ direction = _this$props3.direction,
1166
+ layout = _this$props3.layout;
1167
+ var _this$state = this.state,
1168
+ scrollOffset = _this$state.scrollOffset,
1169
+ scrollUpdateWasRequested = _this$state.scrollUpdateWasRequested;
1170
+
1171
+ if (scrollUpdateWasRequested && this._outerRef !== null) {
1172
+ // TODO Deprecate direction "horizontal"
1173
+ if (direction === 'horizontal' || layout === 'horizontal') {
1174
+ this._outerRef.scrollLeft = scrollOffset;
1175
+ } else {
1176
+ this._outerRef.scrollTop = scrollOffset;
1177
+ }
1178
+ }
1179
+
1180
+ this._callPropsCallbacks();
1181
+ };
1182
+
1183
+ _proto.componentWillUnmount = function componentWillUnmount() {
1184
+ if (this._resetIsScrollingTimeoutId !== null) {
1185
+ cancelTimeout(this._resetIsScrollingTimeoutId);
1186
+ }
1187
+ };
1188
+
1189
+ _proto.render = function render() {
1190
+ var _this$props4 = this.props,
1191
+ children = _this$props4.children,
1192
+ className = _this$props4.className,
1193
+ direction = _this$props4.direction,
1194
+ height = _this$props4.height,
1195
+ innerRef = _this$props4.innerRef,
1196
+ innerElementType = _this$props4.innerElementType,
1197
+ innerTagName = _this$props4.innerTagName,
1198
+ itemCount = _this$props4.itemCount,
1199
+ itemData = _this$props4.itemData,
1200
+ _this$props4$itemKey = _this$props4.itemKey,
1201
+ itemKey = _this$props4$itemKey === void 0 ? defaultItemKey$1 : _this$props4$itemKey,
1202
+ layout = _this$props4.layout,
1203
+ outerElementType = _this$props4.outerElementType,
1204
+ outerTagName = _this$props4.outerTagName,
1205
+ style = _this$props4.style,
1206
+ useIsScrolling = _this$props4.useIsScrolling,
1207
+ width = _this$props4.width;
1208
+ var isScrolling = this.state.isScrolling; // TODO Deprecate direction "horizontal"
1209
+
1210
+ var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
1211
+ var onScroll = isHorizontal ? this._onScrollHorizontal : this._onScrollVertical;
1212
+
1213
+ var _this$_getRangeToRend = this._getRangeToRender(),
1214
+ startIndex = _this$_getRangeToRend[0],
1215
+ stopIndex = _this$_getRangeToRend[1];
1216
+
1217
+ var items = [];
1218
+
1219
+ if (itemCount > 0) {
1220
+ for (var _index = startIndex; _index <= stopIndex; _index++) {
1221
+ items.push(createElement(children, {
1222
+ data: itemData,
1223
+ key: itemKey(_index, itemData),
1224
+ index: _index,
1225
+ isScrolling: useIsScrolling ? isScrolling : undefined,
1226
+ style: this._getItemStyle(_index)
1227
+ }));
1228
+ }
1229
+ } // Read this value AFTER items have been created,
1230
+ // So their actual sizes (if variable) are taken into consideration.
1231
+
1232
+
1233
+ var estimatedTotalSize = getEstimatedTotalSize(this.props, this._instanceProps);
1234
+ return createElement(outerElementType || outerTagName || 'div', {
1235
+ className: className,
1236
+ onScroll: onScroll,
1237
+ ref: this._outerRefSetter,
1238
+ style: _extends({
1239
+ position: 'relative',
1240
+ height: height,
1241
+ width: width,
1242
+ overflow: 'auto',
1243
+ WebkitOverflowScrolling: 'touch',
1244
+ willChange: 'transform',
1245
+ direction: direction
1246
+ }, style)
1247
+ }, createElement(innerElementType || innerTagName || 'div', {
1248
+ children: items,
1249
+ ref: innerRef,
1250
+ style: {
1251
+ height: isHorizontal ? '100%' : estimatedTotalSize,
1252
+ pointerEvents: isScrolling ? 'none' : '',
1253
+ width: isHorizontal ? estimatedTotalSize : '100%'
1254
+ }
1255
+ }));
1256
+ };
1257
+
1258
+ _proto._callPropsCallbacks = function _callPropsCallbacks() {
1259
+ if (typeof this.props.onItemsRendered === 'function') {
1260
+ var itemCount = this.props.itemCount;
1261
+
1262
+ if (itemCount > 0) {
1263
+ var _this$_getRangeToRend2 = this._getRangeToRender(),
1264
+ _overscanStartIndex = _this$_getRangeToRend2[0],
1265
+ _overscanStopIndex = _this$_getRangeToRend2[1],
1266
+ _visibleStartIndex = _this$_getRangeToRend2[2],
1267
+ _visibleStopIndex = _this$_getRangeToRend2[3];
1268
+
1269
+ this._callOnItemsRendered(_overscanStartIndex, _overscanStopIndex, _visibleStartIndex, _visibleStopIndex);
1270
+ }
1271
+ }
1272
+
1273
+ if (typeof this.props.onScroll === 'function') {
1274
+ var _this$state2 = this.state,
1275
+ _scrollDirection = _this$state2.scrollDirection,
1276
+ _scrollOffset = _this$state2.scrollOffset,
1277
+ _scrollUpdateWasRequested = _this$state2.scrollUpdateWasRequested;
1278
+
1279
+ this._callOnScroll(_scrollDirection, _scrollOffset, _scrollUpdateWasRequested);
1280
+ }
1281
+ }; // Lazily create and cache item styles while scrolling,
1282
+ // So that pure component sCU will prevent re-renders.
1283
+ // We maintain this cache, and pass a style prop rather than index,
1284
+ // So that List can clear cached styles and force item re-render if necessary.
1285
+
1286
+
1287
+ _proto._getRangeToRender = function _getRangeToRender() {
1288
+ var _this$props5 = this.props,
1289
+ itemCount = _this$props5.itemCount,
1290
+ overscanCount = _this$props5.overscanCount;
1291
+ var _this$state3 = this.state,
1292
+ isScrolling = _this$state3.isScrolling,
1293
+ scrollDirection = _this$state3.scrollDirection,
1294
+ scrollOffset = _this$state3.scrollOffset;
1295
+
1296
+ if (itemCount === 0) {
1297
+ return [0, 0, 0, 0];
1298
+ }
1299
+
1300
+ var startIndex = getStartIndexForOffset(this.props, scrollOffset, this._instanceProps);
1301
+ var stopIndex = getStopIndexForStartIndex(this.props, startIndex, scrollOffset, this._instanceProps); // Overscan by one item in each direction so that tab/focus works.
1302
+ // If there isn't at least one extra item, tab loops back around.
1303
+
1304
+ var overscanBackward = !isScrolling || scrollDirection === 'backward' ? Math.max(1, overscanCount) : 1;
1305
+ var overscanForward = !isScrolling || scrollDirection === 'forward' ? Math.max(1, overscanCount) : 1;
1306
+ return [Math.max(0, startIndex - overscanBackward), Math.max(0, Math.min(itemCount - 1, stopIndex + overscanForward)), startIndex, stopIndex];
1307
+ };
1308
+
1309
+ return List;
1310
+ }(PureComponent), _class.defaultProps = {
1311
+ direction: 'ltr',
1312
+ itemData: undefined,
1313
+ layout: 'vertical',
1314
+ overscanCount: 2,
1315
+ useIsScrolling: false
1316
+ }, _temp;
1317
+} // NOTE: I considered further wrapping individual items with a pure ListItem component.
1318
+// This would avoid ever calling the render function for the same index more than once,
1319
+// But it would also add the overhead of a lot of components/fibers.
1320
+// I assume people already do this (render function returning a class component),
1321
+// So my doing it would just unnecessarily double the wrappers.
1322
+
1323
+var validateSharedProps$1 = function validateSharedProps(_ref2, _ref3) {
1324
+ var children = _ref2.children,
1325
+ direction = _ref2.direction,
1326
+ height = _ref2.height,
1327
+ layout = _ref2.layout,
1328
+ innerTagName = _ref2.innerTagName,
1329
+ outerTagName = _ref2.outerTagName,
1330
+ width = _ref2.width;
1331
+ var instance = _ref3.instance;
1332
+
1333
+ if (process.env.NODE_ENV !== 'production') {
1334
+ if (innerTagName != null || outerTagName != null) {
1335
+ if (devWarningsTagName$1 && !devWarningsTagName$1.has(instance)) {
1336
+ devWarningsTagName$1.add(instance);
1337
+ console.warn('The innerTagName and outerTagName props have been deprecated. ' + 'Please use the innerElementType and outerElementType props instead.');
1338
+ }
1339
+ } // TODO Deprecate direction "horizontal"
1340
+
1341
+
1342
+ var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
1343
+
1344
+ switch (direction) {
1345
+ case 'horizontal':
1346
+ case 'vertical':
1347
+ if (devWarningsDirection && !devWarningsDirection.has(instance)) {
1348
+ devWarningsDirection.add(instance);
1349
+ console.warn('The direction prop should be either "ltr" (default) or "rtl". ' + 'Please use the layout prop to specify "vertical" (default) or "horizontal" orientation.');
1350
+ }
1351
+
1352
+ break;
1353
+
1354
+ case 'ltr':
1355
+ case 'rtl':
1356
+ // Valid values
1357
+ break;
1358
+
1359
+ default:
1360
+ throw Error('An invalid "direction" prop has been specified. ' + 'Value should be either "ltr" or "rtl". ' + ("\"" + direction + "\" was specified."));
1361
+ }
1362
+
1363
+ switch (layout) {
1364
+ case 'horizontal':
1365
+ case 'vertical':
1366
+ // Valid values
1367
+ break;
1368
+
1369
+ default:
1370
+ throw Error('An invalid "layout" prop has been specified. ' + 'Value should be either "horizontal" or "vertical". ' + ("\"" + layout + "\" was specified."));
1371
+ }
1372
+
1373
+ if (children == null) {
1374
+ throw Error('An invalid "children" prop has been specified. ' + 'Value should be a React component. ' + ("\"" + (children === null ? 'null' : typeof children) + "\" was specified."));
1375
+ }
1376
+
1377
+ if (isHorizontal && typeof width !== 'number') {
1378
+ throw Error('An invalid "width" prop has been specified. ' + 'Horizontal lists must specify a number for width. ' + ("\"" + (width === null ? 'null' : typeof width) + "\" was specified."));
1379
+ } else if (!isHorizontal && typeof height !== 'number') {
1380
+ throw Error('An invalid "height" prop has been specified. ' + 'Vertical lists must specify a number for height. ' + ("\"" + (height === null ? 'null' : typeof height) + "\" was specified."));
1381
+ }
1382
+ }
1383
+};
1384
+
1385
+var DEFAULT_ESTIMATED_ITEM_SIZE$1 = 50;
1386
+
1387
+var getItemMetadata$1 = function getItemMetadata(props, index, instanceProps) {
1388
+ var _ref = props,
1389
+ itemSize = _ref.itemSize;
1390
+ var itemMetadataMap = instanceProps.itemMetadataMap,
1391
+ lastMeasuredIndex = instanceProps.lastMeasuredIndex;
1392
+
1393
+ if (index > lastMeasuredIndex) {
1394
+ var offset = 0;
1395
+
1396
+ if (lastMeasuredIndex >= 0) {
1397
+ var itemMetadata = itemMetadataMap[lastMeasuredIndex];
1398
+ offset = itemMetadata.offset + itemMetadata.size;
1399
+ }
1400
+
1401
+ for (var i = lastMeasuredIndex + 1; i <= index; i++) {
1402
+ var size = itemSize(i);
1403
+ itemMetadataMap[i] = {
1404
+ offset: offset,
1405
+ size: size
1406
+ };
1407
+ offset += size;
1408
+ }
1409
+
1410
+ instanceProps.lastMeasuredIndex = index;
1411
+ }
1412
+
1413
+ return itemMetadataMap[index];
1414
+};
1415
+
1416
+var findNearestItem$1 = function findNearestItem(props, instanceProps, offset) {
1417
+ var itemMetadataMap = instanceProps.itemMetadataMap,
1418
+ lastMeasuredIndex = instanceProps.lastMeasuredIndex;
1419
+ var lastMeasuredItemOffset = lastMeasuredIndex > 0 ? itemMetadataMap[lastMeasuredIndex].offset : 0;
1420
+
1421
+ if (lastMeasuredItemOffset >= offset) {
1422
+ // If we've already measured items within this range just use a binary search as it's faster.
1423
+ return findNearestItemBinarySearch$1(props, instanceProps, lastMeasuredIndex, 0, offset);
1424
+ } else {
1425
+ // If we haven't yet measured this high, fallback to an exponential search with an inner binary search.
1426
+ // The exponential search avoids pre-computing sizes for the full set of items as a binary search would.
1427
+ // The overall complexity for this approach is O(log n).
1428
+ return findNearestItemExponentialSearch$1(props, instanceProps, Math.max(0, lastMeasuredIndex), offset);
1429
+ }
1430
+};
1431
+
1432
+var findNearestItemBinarySearch$1 = function findNearestItemBinarySearch(props, instanceProps, high, low, offset) {
1433
+ while (low <= high) {
1434
+ var middle = low + Math.floor((high - low) / 2);
1435
+ var currentOffset = getItemMetadata$1(props, middle, instanceProps).offset;
1436
+
1437
+ if (currentOffset === offset) {
1438
+ return middle;
1439
+ } else if (currentOffset < offset) {
1440
+ low = middle + 1;
1441
+ } else if (currentOffset > offset) {
1442
+ high = middle - 1;
1443
+ }
1444
+ }
1445
+
1446
+ if (low > 0) {
1447
+ return low - 1;
1448
+ } else {
1449
+ return 0;
1450
+ }
1451
+};
1452
+
1453
+var findNearestItemExponentialSearch$1 = function findNearestItemExponentialSearch(props, instanceProps, index, offset) {
1454
+ var itemCount = props.itemCount;
1455
+ var interval = 1;
1456
+
1457
+ while (index < itemCount && getItemMetadata$1(props, index, instanceProps).offset < offset) {
1458
+ index += interval;
1459
+ interval *= 2;
1460
+ }
1461
+
1462
+ return findNearestItemBinarySearch$1(props, instanceProps, Math.min(index, itemCount - 1), Math.floor(index / 2), offset);
1463
+};
1464
+
1465
+var getEstimatedTotalSize = function getEstimatedTotalSize(_ref2, _ref3) {
1466
+ var itemCount = _ref2.itemCount;
1467
+ var itemMetadataMap = _ref3.itemMetadataMap,
1468
+ estimatedItemSize = _ref3.estimatedItemSize,
1469
+ lastMeasuredIndex = _ref3.lastMeasuredIndex;
1470
+ var totalSizeOfMeasuredItems = 0; // Edge case check for when the number of items decreases while a scroll is in progress.
1471
+ // https://github.com/bvaughn/react-window/pull/138
1472
+
1473
+ if (lastMeasuredIndex >= itemCount) {
1474
+ lastMeasuredIndex = itemCount - 1;
1475
+ }
1476
+
1477
+ if (lastMeasuredIndex >= 0) {
1478
+ var itemMetadata = itemMetadataMap[lastMeasuredIndex];
1479
+ totalSizeOfMeasuredItems = itemMetadata.offset + itemMetadata.size;
1480
+ }
1481
+
1482
+ var numUnmeasuredItems = itemCount - lastMeasuredIndex - 1;
1483
+ var totalSizeOfUnmeasuredItems = numUnmeasuredItems * estimatedItemSize;
1484
+ return totalSizeOfMeasuredItems + totalSizeOfUnmeasuredItems;
1485
+};
1486
+
1487
+var VariableSizeList =
1488
+/*#__PURE__*/
1489
+createListComponent({
1490
+ getItemOffset: function getItemOffset(props, index, instanceProps) {
1491
+ return getItemMetadata$1(props, index, instanceProps).offset;
1492
+ },
1493
+ getItemSize: function getItemSize(props, index, instanceProps) {
1494
+ return instanceProps.itemMetadataMap[index].size;
1495
+ },
1496
+ getEstimatedTotalSize: getEstimatedTotalSize,
1497
+ getOffsetForIndexAndAlignment: function getOffsetForIndexAndAlignment(props, index, align, scrollOffset, instanceProps) {
1498
+ var direction = props.direction,
1499
+ height = props.height,
1500
+ layout = props.layout,
1501
+ width = props.width; // TODO Deprecate direction "horizontal"
1502
+
1503
+ var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
1504
+ var size = isHorizontal ? width : height;
1505
+ var itemMetadata = getItemMetadata$1(props, index, instanceProps); // Get estimated total size after ItemMetadata is computed,
1506
+ // To ensure it reflects actual measurements instead of just estimates.
1507
+
1508
+ var estimatedTotalSize = getEstimatedTotalSize(props, instanceProps);
1509
+ var maxOffset = Math.max(0, Math.min(estimatedTotalSize - size, itemMetadata.offset));
1510
+ var minOffset = Math.max(0, itemMetadata.offset - size + itemMetadata.size);
1511
+
1512
+ if (align === 'smart') {
1513
+ if (scrollOffset >= minOffset - size && scrollOffset <= maxOffset + size) {
1514
+ align = 'auto';
1515
+ } else {
1516
+ align = 'center';
1517
+ }
1518
+ }
1519
+
1520
+ switch (align) {
1521
+ case 'start':
1522
+ return maxOffset;
1523
+
1524
+ case 'end':
1525
+ return minOffset;
1526
+
1527
+ case 'center':
1528
+ return Math.round(minOffset + (maxOffset - minOffset) / 2);
1529
+
1530
+ case 'auto':
1531
+ default:
1532
+ if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
1533
+ return scrollOffset;
1534
+ } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
1535
+ return minOffset;
1536
+ } else {
1537
+ return maxOffset;
1538
+ }
1539
+
1540
+ }
1541
+ },
1542
+ getStartIndexForOffset: function getStartIndexForOffset(props, offset, instanceProps) {
1543
+ return findNearestItem$1(props, instanceProps, offset);
1544
+ },
1545
+ getStopIndexForStartIndex: function getStopIndexForStartIndex(props, startIndex, scrollOffset, instanceProps) {
1546
+ var direction = props.direction,
1547
+ height = props.height,
1548
+ itemCount = props.itemCount,
1549
+ layout = props.layout,
1550
+ width = props.width; // TODO Deprecate direction "horizontal"
1551
+
1552
+ var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
1553
+ var size = isHorizontal ? width : height;
1554
+ var itemMetadata = getItemMetadata$1(props, startIndex, instanceProps);
1555
+ var maxOffset = scrollOffset + size;
1556
+ var offset = itemMetadata.offset + itemMetadata.size;
1557
+ var stopIndex = startIndex;
1558
+
1559
+ while (stopIndex < itemCount - 1 && offset < maxOffset) {
1560
+ stopIndex++;
1561
+ offset += getItemMetadata$1(props, stopIndex, instanceProps).size;
1562
+ }
1563
+
1564
+ return stopIndex;
1565
+ },
1566
+ initInstanceProps: function initInstanceProps(props, instance) {
1567
+ var _ref4 = props,
1568
+ estimatedItemSize = _ref4.estimatedItemSize;
1569
+ var instanceProps = {
1570
+ itemMetadataMap: {},
1571
+ estimatedItemSize: estimatedItemSize || DEFAULT_ESTIMATED_ITEM_SIZE$1,
1572
+ lastMeasuredIndex: -1
1573
+ };
1574
+
1575
+ instance.resetAfterIndex = function (index, shouldForceUpdate) {
1576
+ if (shouldForceUpdate === void 0) {
1577
+ shouldForceUpdate = true;
1578
+ }
1579
+
1580
+ instanceProps.lastMeasuredIndex = Math.min(instanceProps.lastMeasuredIndex, index - 1); // We could potentially optimize further by only evicting styles after this index,
1581
+ // But since styles are only cached while scrolling is in progress-
1582
+ // It seems an unnecessary optimization.
1583
+ // It's unlikely that resetAfterIndex() will be called while a user is scrolling.
1584
+
1585
+ instance._getItemStyleCache(-1);
1586
+
1587
+ if (shouldForceUpdate) {
1588
+ instance.forceUpdate();
1589
+ }
1590
+ };
1591
+
1592
+ return instanceProps;
1593
+ },
1594
+ shouldResetStyleCacheOnItemSizeChange: false,
1595
+ validateProps: function validateProps(_ref5) {
1596
+ var itemSize = _ref5.itemSize;
1597
+
1598
+ if (process.env.NODE_ENV !== 'production') {
1599
+ if (typeof itemSize !== 'function') {
1600
+ throw Error('An invalid "itemSize" prop has been specified. ' + 'Value should be a function. ' + ("\"" + (itemSize === null ? 'null' : typeof itemSize) + "\" was specified."));
1601
+ }
1602
+ }
1603
+ }
1604
+});
1605
+
1606
+var FixedSizeGrid =
1607
+/*#__PURE__*/
1608
+createGridComponent({
1609
+ getColumnOffset: function getColumnOffset(_ref, index) {
1610
+ var columnWidth = _ref.columnWidth;
1611
+ return index * columnWidth;
1612
+ },
1613
+ getColumnWidth: function getColumnWidth(_ref2, index) {
1614
+ var columnWidth = _ref2.columnWidth;
1615
+ return columnWidth;
1616
+ },
1617
+ getRowOffset: function getRowOffset(_ref3, index) {
1618
+ var rowHeight = _ref3.rowHeight;
1619
+ return index * rowHeight;
1620
+ },
1621
+ getRowHeight: function getRowHeight(_ref4, index) {
1622
+ var rowHeight = _ref4.rowHeight;
1623
+ return rowHeight;
1624
+ },
1625
+ getEstimatedTotalHeight: function getEstimatedTotalHeight(_ref5) {
1626
+ var rowCount = _ref5.rowCount,
1627
+ rowHeight = _ref5.rowHeight;
1628
+ return rowHeight * rowCount;
1629
+ },
1630
+ getEstimatedTotalWidth: function getEstimatedTotalWidth(_ref6) {
1631
+ var columnCount = _ref6.columnCount,
1632
+ columnWidth = _ref6.columnWidth;
1633
+ return columnWidth * columnCount;
1634
+ },
1635
+ getOffsetForColumnAndAlignment: function getOffsetForColumnAndAlignment(_ref7, columnIndex, align, scrollLeft, instanceProps, scrollbarSize) {
1636
+ var columnCount = _ref7.columnCount,
1637
+ columnWidth = _ref7.columnWidth,
1638
+ width = _ref7.width;
1639
+ var maxOffset = Math.max(0, Math.min(columnCount * columnWidth - width, columnIndex * columnWidth));
1640
+ var minOffset = Math.max(0, columnIndex * columnWidth - width + scrollbarSize + columnWidth);
1641
+
1642
+ if (align === 'smart') {
1643
+ if (scrollLeft >= minOffset - width && scrollLeft <= maxOffset + width) {
1644
+ align = 'auto';
1645
+ } else {
1646
+ align = 'center';
1647
+ }
1648
+ }
1649
+
1650
+ switch (align) {
1651
+ case 'start':
1652
+ return maxOffset;
1653
+
1654
+ case 'end':
1655
+ return minOffset;
1656
+
1657
+ case 'center':
1658
+ return Math.round(minOffset + (maxOffset - minOffset) / 2);
1659
+
1660
+ case 'auto':
1661
+ default:
1662
+ if (scrollLeft >= minOffset && scrollLeft <= maxOffset) {
1663
+ return scrollLeft;
1664
+ } else if (scrollLeft - minOffset < maxOffset - scrollLeft) {
1665
+ return minOffset;
1666
+ } else {
1667
+ return maxOffset;
1668
+ }
1669
+
1670
+ }
1671
+ },
1672
+ getOffsetForRowAndAlignment: function getOffsetForRowAndAlignment(_ref8, rowIndex, align, scrollTop, instanceProps, scrollbarSize) {
1673
+ var rowHeight = _ref8.rowHeight,
1674
+ height = _ref8.height,
1675
+ rowCount = _ref8.rowCount;
1676
+ var maxOffset = Math.max(0, Math.min(rowCount * rowHeight - height, rowIndex * rowHeight));
1677
+ var minOffset = Math.max(0, rowIndex * rowHeight - height + scrollbarSize + rowHeight);
1678
+
1679
+ if (align === 'smart') {
1680
+ if (scrollTop >= minOffset - height && scrollTop <= maxOffset + height) {
1681
+ align = 'auto';
1682
+ } else {
1683
+ align = 'center';
1684
+ }
1685
+ }
1686
+
1687
+ switch (align) {
1688
+ case 'start':
1689
+ return maxOffset;
1690
+
1691
+ case 'end':
1692
+ return minOffset;
1693
+
1694
+ case 'center':
1695
+ return Math.round(minOffset + (maxOffset - minOffset) / 2);
1696
+
1697
+ case 'auto':
1698
+ default:
1699
+ if (scrollTop >= minOffset && scrollTop <= maxOffset) {
1700
+ return scrollTop;
1701
+ } else if (scrollTop - minOffset < maxOffset - scrollTop) {
1702
+ return minOffset;
1703
+ } else {
1704
+ return maxOffset;
1705
+ }
1706
+
1707
+ }
1708
+ },
1709
+ getColumnStartIndexForOffset: function getColumnStartIndexForOffset(_ref9, scrollLeft) {
1710
+ var columnWidth = _ref9.columnWidth,
1711
+ columnCount = _ref9.columnCount;
1712
+ return Math.max(0, Math.min(columnCount - 1, Math.floor(scrollLeft / columnWidth)));
1713
+ },
1714
+ getColumnStopIndexForStartIndex: function getColumnStopIndexForStartIndex(_ref10, startIndex, scrollLeft) {
1715
+ var columnWidth = _ref10.columnWidth,
1716
+ columnCount = _ref10.columnCount,
1717
+ width = _ref10.width;
1718
+ var left = startIndex * columnWidth;
1719
+ return Math.max(0, Math.min(columnCount - 1, startIndex + Math.floor((width + (scrollLeft - left)) / columnWidth)));
1720
+ },
1721
+ getRowStartIndexForOffset: function getRowStartIndexForOffset(_ref11, scrollTop) {
1722
+ var rowHeight = _ref11.rowHeight,
1723
+ rowCount = _ref11.rowCount;
1724
+ return Math.max(0, Math.min(rowCount - 1, Math.floor(scrollTop / rowHeight)));
1725
+ },
1726
+ getRowStopIndexForStartIndex: function getRowStopIndexForStartIndex(_ref12, startIndex, scrollTop) {
1727
+ var rowHeight = _ref12.rowHeight,
1728
+ rowCount = _ref12.rowCount,
1729
+ height = _ref12.height;
1730
+ var left = startIndex * rowHeight;
1731
+ return Math.max(0, Math.min(rowCount - 1, startIndex + Math.floor((height + (scrollTop - left)) / rowHeight)));
1732
+ },
1733
+ initInstanceProps: function initInstanceProps(props) {// Noop
1734
+ },
1735
+ shouldResetStyleCacheOnItemSizeChange: true,
1736
+ validateProps: function validateProps(_ref13) {
1737
+ var columnWidth = _ref13.columnWidth,
1738
+ rowHeight = _ref13.rowHeight;
1739
+
1740
+ if (process.env.NODE_ENV !== 'production') {
1741
+ if (typeof columnWidth !== 'number') {
1742
+ throw Error('An invalid "columnWidth" prop has been specified. ' + 'Value should be a number. ' + ("\"" + (columnWidth === null ? 'null' : typeof columnWidth) + "\" was specified."));
1743
+ }
1744
+
1745
+ if (typeof rowHeight !== 'number') {
1746
+ throw Error('An invalid "rowHeight" prop has been specified. ' + 'Value should be a number. ' + ("\"" + (rowHeight === null ? 'null' : typeof rowHeight) + "\" was specified."));
1747
+ }
1748
+ }
1749
+ }
1750
+});
1751
+
1752
+var FixedSizeList =
1753
+/*#__PURE__*/
1754
+createListComponent({
1755
+ getItemOffset: function getItemOffset(_ref, index) {
1756
+ var itemSize = _ref.itemSize,
1757
+ size = _ref.size;
1758
+ return index * itemSize;
1759
+ },
1760
+ getItemSize: function getItemSize(_ref2, index) {
1761
+ var itemSize = _ref2.itemSize,
1762
+ size = _ref2.size;
1763
+ return itemSize;
1764
+ },
1765
+ getEstimatedTotalSize: function getEstimatedTotalSize(_ref3) {
1766
+ var itemCount = _ref3.itemCount,
1767
+ itemSize = _ref3.itemSize;
1768
+ return itemSize * itemCount;
1769
+ },
1770
+ getOffsetForIndexAndAlignment: function getOffsetForIndexAndAlignment(_ref4, index, align, scrollOffset) {
1771
+ var direction = _ref4.direction,
1772
+ height = _ref4.height,
1773
+ itemCount = _ref4.itemCount,
1774
+ itemSize = _ref4.itemSize,
1775
+ layout = _ref4.layout,
1776
+ width = _ref4.width;
1777
+ // TODO Deprecate direction "horizontal"
1778
+ var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
1779
+ var size = isHorizontal ? width : height;
1780
+ var maxOffset = Math.max(0, Math.min(itemCount * itemSize - size, index * itemSize));
1781
+ var minOffset = Math.max(0, index * itemSize - size + itemSize);
1782
+
1783
+ if (align === 'smart') {
1784
+ if (scrollOffset >= minOffset - size && scrollOffset <= maxOffset + size) {
1785
+ align = 'auto';
1786
+ } else {
1787
+ align = 'center';
1788
+ }
1789
+ }
1790
+
1791
+ switch (align) {
1792
+ case 'start':
1793
+ return maxOffset;
1794
+
1795
+ case 'end':
1796
+ return minOffset;
1797
+
1798
+ case 'center':
1799
+ return Math.round(minOffset + (maxOffset - minOffset) / 2);
1800
+
1801
+ case 'auto':
1802
+ default:
1803
+ if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
1804
+ return scrollOffset;
1805
+ } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
1806
+ return minOffset;
1807
+ } else {
1808
+ return maxOffset;
1809
+ }
1810
+
1811
+ }
1812
+ },
1813
+ getStartIndexForOffset: function getStartIndexForOffset(_ref5, offset) {
1814
+ var itemCount = _ref5.itemCount,
1815
+ itemSize = _ref5.itemSize;
1816
+ return Math.max(0, Math.min(itemCount - 1, Math.floor(offset / itemSize)));
1817
+ },
1818
+ getStopIndexForStartIndex: function getStopIndexForStartIndex(_ref6, startIndex, scrollOffset) {
1819
+ var direction = _ref6.direction,
1820
+ height = _ref6.height,
1821
+ itemCount = _ref6.itemCount,
1822
+ itemSize = _ref6.itemSize,
1823
+ layout = _ref6.layout,
1824
+ width = _ref6.width;
1825
+ // TODO Deprecate direction "horizontal"
1826
+ var isHorizontal = direction === 'horizontal' || layout === 'horizontal';
1827
+ var offset = startIndex * itemSize;
1828
+ var size = isHorizontal ? width : height;
1829
+ return Math.max(0, Math.min(itemCount - 1, startIndex + Math.floor((size + (scrollOffset - offset)) / itemSize)));
1830
+ },
1831
+ initInstanceProps: function initInstanceProps(props) {// Noop
1832
+ },
1833
+ shouldResetStyleCacheOnItemSizeChange: true,
1834
+ validateProps: function validateProps(_ref7) {
1835
+ var itemSize = _ref7.itemSize;
1836
+
1837
+ if (process.env.NODE_ENV !== 'production') {
1838
+ if (typeof itemSize !== 'number') {
1839
+ throw Error('An invalid "itemSize" prop has been specified. ' + 'Value should be a number. ' + ("\"" + (itemSize === null ? 'null' : typeof itemSize) + "\" was specified."));
1840
+ }
1841
+ }
1842
+ }
1843
+});
1844
+
1845
+// Pulled from react-compat
1846
+// https://github.com/developit/preact-compat/blob/7c5de00e7c85e2ffd011bf3af02899b63f699d3a/src/index.js#L349
1847
+function shallowDiffers(prev, next) {
1848
+ for (var attribute in prev) {
1849
+ if (!(attribute in next)) {
1850
+ return true;
1851
+ }
1852
+ }
1853
+
1854
+ for (var _attribute in next) {
1855
+ if (prev[_attribute] !== next[_attribute]) {
1856
+ return true;
1857
+ }
1858
+ }
1859
+
1860
+ return false;
1861
+}
1862
+
1863
+// It knows to compare individual style props and ignore the wrapper object.
1864
+// See https://reactjs.org/docs/react-api.html#reactmemo
1865
+
1866
+function areEqual(prevProps, nextProps) {
1867
+ var prevStyle = prevProps.style,
1868
+ prevRest = _objectWithoutPropertiesLoose(prevProps, ["style"]);
1869
+
1870
+ var nextStyle = nextProps.style,
1871
+ nextRest = _objectWithoutPropertiesLoose(nextProps, ["style"]);
1872
+
1873
+ return !shallowDiffers(prevStyle, nextStyle) && !shallowDiffers(prevRest, nextRest);
1874
+}
1875
+
1876
+// It knows to compare individual style props and ignore the wrapper object.
1877
+// See https://reactjs.org/docs/react-component.html#shouldcomponentupdate
1878
+
1879
+function shouldComponentUpdate(nextProps, nextState) {
1880
+ return !areEqual(this.props, nextProps) || shallowDiffers(this.state, nextState);
1881
+}
1882
+
1883
+export { VariableSizeGrid, VariableSizeList, FixedSizeGrid, FixedSizeList, areEqual, shouldComponentUpdate };
vendor/react-window/dist/index.esm.js.flow
new
+3
@@ -0,0 +1,3 @@
1
+// @flow
2
+
3
+export * from '../src';
vendor/react-window/package.json
new
+108
@@ -0,0 +1,108 @@
1
+{
2
+ "name": "react-window",
3
+ "version": "1.8.0",
4
+ "description":
5
+ "React components for efficiently rendering large, scrollable lists and tabular data",
6
+ "author":
7
+ "Brian Vaughn <brian.david.vaughn@gmail.com> (https://github.com/bvaughn/)",
8
+ "contributors": [
9
+ "Brian Vaughn <brian.david.vaughn@gmail.com> (https://github.com/bvaughn/)"
10
+ ],
11
+ "license": "MIT",
12
+ "homepage": "http://react-window.now.sh/",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/bvaughn/react-window.git"
16
+ },
17
+ "bugs": {
18
+ "url": "https://github.com/bvaughn/react-window/issues"
19
+ },
20
+ "engines": {
21
+ "node": ">8.0.0"
22
+ },
23
+ "keywords": [
24
+ "react",
25
+ "reactjs",
26
+ "virtual",
27
+ "window",
28
+ "windowed",
29
+ "list",
30
+ "scrolling",
31
+ "infinite",
32
+ "virtualized",
33
+ "table",
34
+ "grid",
35
+ "spreadsheet"
36
+ ],
37
+ "main": "dist/index.cjs.js",
38
+ "module": "dist/index.esm.js",
39
+ "files": ["dist", "src/*.js"],
40
+ "scripts": {
41
+ "flow": "flow check --max-warnings=0 src && flow check website",
42
+ "precommit": "lint-staged",
43
+ "prettier": "prettier --write '**/*.{js,json,css}'",
44
+ "linc": "lint-staged",
45
+ "lint": "eslint '**/*.js'",
46
+ "test": "cross-env CI=1 react-scripts test --env=jsdom",
47
+ "test:watch": "react-scripts test --env=jsdom",
48
+ "build:flow":
49
+ "cp flow-template dist/index.cjs.js.flow && cp flow-template dist/index.esm.js.flow",
50
+ "build:source": "rollup -c",
51
+ "build": "del dist && mkdir dist && yarn build:flow && yarn build:source",
52
+ "start": "rollup -c -w",
53
+ "prepare": "yarn run build",
54
+ "website:build": "cd website && yarn build",
55
+ "website:deploy": "cd website && yarn deploy",
56
+ "website:run": "cd website && yarn start"
57
+ },
58
+ "lint-staged": {
59
+ "{website,src}/**/*.{js,json,css}": ["prettier --write", "git add"],
60
+ "**/*.js": "eslint --max-warnings 0"
61
+ },
62
+ "dependencies": {
63
+ "@babel/runtime": "^7.0.0",
64
+ "memoize-one": ">=3.1.1 <6"
65
+ },
66
+ "peerDependencies": {
67
+ "react": "^15.0.0 || ^16.0.0",
68
+ "react-dom": "^15.0.0 || ^16.0.0"
69
+ },
70
+ "devDependencies": {
71
+ "@babel/core": "^7.0.0",
72
+ "@babel/plugin-proposal-class-properties": "^7.0.0",
73
+ "@babel/plugin-transform-runtime": "^7.0.0",
74
+ "@babel/preset-env": "^7.0.0",
75
+ "@babel/preset-flow": "^7.0.0",
76
+ "babel-core": "^7.0.0-bridge.0",
77
+ "babel-eslint": "^9.0.0",
78
+ "babel-plugin-annotate-pure-calls": "^0.3.0",
79
+ "cross-env": "^5.1.4",
80
+ "del-cli": "^1.1.0",
81
+ "eslint": "^4.19.1",
82
+ "eslint-config-prettier": "^2.9.0",
83
+ "eslint-config-react-app": "^2.1.0",
84
+ "eslint-config-standard": "^11.0.0",
85
+ "eslint-config-standard-react": "^6.0.0",
86
+ "eslint-plugin-flowtype": "^2.47.1",
87
+ "eslint-plugin-import": "^2.11.0",
88
+ "eslint-plugin-jsx-a11y": "^5",
89
+ "eslint-plugin-node": "^6.0.1",
90
+ "eslint-plugin-prettier": "^2.6.0",
91
+ "eslint-plugin-promise": "^3.7.0",
92
+ "eslint-plugin-react": "^7.7.0",
93
+ "eslint-plugin-standard": "^3.0.1",
94
+ "flow-bin": "^0.80.0",
95
+ "gh-pages": "^1.1.0",
96
+ "lint-staged": "^7.0.5",
97
+ "prettier": "^1.12.1",
98
+ "react": "^16.8.4",
99
+ "react-dom": "^16.8.4",
100
+ "react-is": "^16.8.4",
101
+ "react-scripts": "^1.1.1",
102
+ "react-test-renderer": "^16.7.0",
103
+ "rollup": "^1.4.1",
104
+ "rollup-plugin-babel": "^4.3.2",
105
+ "rollup-plugin-commonjs": "^9.2.1",
106
+ "rollup-plugin-node-resolve": "^4.0.1"
107
+ }
108
+}
vendor/react-window/src/FixedSizeGrid.js
new
+210
@@ -0,0 +1,210 @@
1
+// @flow
2
+
3
+import createGridComponent from './createGridComponent';
4
+
5
+import type { Props, ScrollToAlign } from './createGridComponent';
6
+
7
+const FixedSizeGrid = createGridComponent({
8
+ getColumnOffset: ({ columnWidth }: Props<any>, index: number): number =>
9
+ index * ((columnWidth: any): number),
10
+
11
+ getColumnWidth: ({ columnWidth }: Props<any>, index: number): number =>
12
+ ((columnWidth: any): number),
13
+
14
+ getRowOffset: ({ rowHeight }: Props<any>, index: number): number =>
15
+ index * ((rowHeight: any): number),
16
+
17
+ getRowHeight: ({ rowHeight }: Props<any>, index: number): number =>
18
+ ((rowHeight: any): number),
19
+
20
+ getEstimatedTotalHeight: ({ rowCount, rowHeight }: Props<any>) =>
21
+ ((rowHeight: any): number) * rowCount,
22
+
23
+ getEstimatedTotalWidth: ({ columnCount, columnWidth }: Props<any>) =>
24
+ ((columnWidth: any): number) * columnCount,
25
+
26
+ getOffsetForColumnAndAlignment: (
27
+ { columnCount, columnWidth, width }: Props<any>,
28
+ columnIndex: number,
29
+ align: ScrollToAlign,
30
+ scrollLeft: number,
31
+ instanceProps: typeof undefined,
32
+ scrollbarSize: number
33
+ ): number => {
34
+ const maxOffset = Math.max(
35
+ 0,
36
+ Math.min(
37
+ columnCount * ((columnWidth: any): number) - width,
38
+ columnIndex * ((columnWidth: any): number)
39
+ )
40
+ );
41
+ const minOffset = Math.max(
42
+ 0,
43
+ columnIndex * ((columnWidth: any): number) -
44
+ width +
45
+ scrollbarSize +
46
+ ((columnWidth: any): number)
47
+ );
48
+
49
+ if (align === 'smart') {
50
+ if (scrollLeft >= minOffset - width && scrollLeft <= maxOffset + width) {
51
+ align = 'auto';
52
+ } else {
53
+ align = 'center';
54
+ }
55
+ }
56
+
57
+ switch (align) {
58
+ case 'start':
59
+ return maxOffset;
60
+ case 'end':
61
+ return minOffset;
62
+ case 'center':
63
+ return Math.round(minOffset + (maxOffset - minOffset) / 2);
64
+ case 'auto':
65
+ default:
66
+ if (scrollLeft >= minOffset && scrollLeft <= maxOffset) {
67
+ return scrollLeft;
68
+ } else if (scrollLeft - minOffset < maxOffset - scrollLeft) {
69
+ return minOffset;
70
+ } else {
71
+ return maxOffset;
72
+ }
73
+ }
74
+ },
75
+
76
+ getOffsetForRowAndAlignment: (
77
+ { rowHeight, height, rowCount }: Props<any>,
78
+ rowIndex: number,
79
+ align: ScrollToAlign,
80
+ scrollTop: number,
81
+ instanceProps: typeof undefined,
82
+ scrollbarSize: number
83
+ ): number => {
84
+ const maxOffset = Math.max(
85
+ 0,
86
+ Math.min(
87
+ rowCount * ((rowHeight: any): number) - height,
88
+ rowIndex * ((rowHeight: any): number)
89
+ )
90
+ );
91
+ const minOffset = Math.max(
92
+ 0,
93
+ rowIndex * ((rowHeight: any): number) -
94
+ height +
95
+ scrollbarSize +
96
+ ((rowHeight: any): number)
97
+ );
98
+
99
+ if (align === 'smart') {
100
+ if (scrollTop >= minOffset - height && scrollTop <= maxOffset + height) {
101
+ align = 'auto';
102
+ } else {
103
+ align = 'center';
104
+ }
105
+ }
106
+
107
+ switch (align) {
108
+ case 'start':
109
+ return maxOffset;
110
+ case 'end':
111
+ return minOffset;
112
+ case 'center':
113
+ return Math.round(minOffset + (maxOffset - minOffset) / 2);
114
+ case 'auto':
115
+ default:
116
+ if (scrollTop >= minOffset && scrollTop <= maxOffset) {
117
+ return scrollTop;
118
+ } else if (scrollTop - minOffset < maxOffset - scrollTop) {
119
+ return minOffset;
120
+ } else {
121
+ return maxOffset;
122
+ }
123
+ }
124
+ },
125
+
126
+ getColumnStartIndexForOffset: (
127
+ { columnWidth, columnCount }: Props<any>,
128
+ scrollLeft: number
129
+ ): number =>
130
+ Math.max(
131
+ 0,
132
+ Math.min(
133
+ columnCount - 1,
134
+ Math.floor(scrollLeft / ((columnWidth: any): number))
135
+ )
136
+ ),
137
+
138
+ getColumnStopIndexForStartIndex: (
139
+ { columnWidth, columnCount, width }: Props<any>,
140
+ startIndex: number,
141
+ scrollLeft: number
142
+ ): number => {
143
+ const left = startIndex * ((columnWidth: any): number);
144
+ return Math.max(
145
+ 0,
146
+ Math.min(
147
+ columnCount - 1,
148
+ startIndex +
149
+ Math.floor(
150
+ (width + (scrollLeft - left)) / ((columnWidth: any): number)
151
+ )
152
+ )
153
+ );
154
+ },
155
+
156
+ getRowStartIndexForOffset: (
157
+ { rowHeight, rowCount }: Props<any>,
158
+ scrollTop: number
159
+ ): number =>
160
+ Math.max(
161
+ 0,
162
+ Math.min(rowCount - 1, Math.floor(scrollTop / ((rowHeight: any): number)))
163
+ ),
164
+
165
+ getRowStopIndexForStartIndex: (
166
+ { rowHeight, rowCount, height }: Props<any>,
167
+ startIndex: number,
168
+ scrollTop: number
169
+ ): number => {
170
+ const left = startIndex * ((rowHeight: any): number);
171
+ return Math.max(
172
+ 0,
173
+ Math.min(
174
+ rowCount - 1,
175
+ startIndex +
176
+ Math.floor((height + (scrollTop - left)) / ((rowHeight: any): number))
177
+ )
178
+ );
179
+ },
180
+
181
+ initInstanceProps(props: Props<any>): any {
182
+ // Noop
183
+ },
184
+
185
+ shouldResetStyleCacheOnItemSizeChange: true,
186
+
187
+ validateProps: ({ columnWidth, rowHeight }: Props<any>): void => {
188
+ if (process.env.NODE_ENV !== 'production') {
189
+ if (typeof columnWidth !== 'number') {
190
+ throw Error(
191
+ 'An invalid "columnWidth" prop has been specified. ' +
192
+ 'Value should be a number. ' +
193
+ `"${
194
+ columnWidth === null ? 'null' : typeof columnWidth
195
+ }" was specified.`
196
+ );
197
+ }
198
+
199
+ if (typeof rowHeight !== 'number') {
200
+ throw Error(
201
+ 'An invalid "rowHeight" prop has been specified. ' +
202
+ 'Value should be a number. ' +
203
+ `"${rowHeight === null ? 'null' : typeof rowHeight}" was specified.`
204
+ );
205
+ }
206
+ }
207
+ },
208
+});
209
+
210
+export default FixedSizeGrid;
vendor/react-window/src/FixedSizeList.js
new
+117
@@ -0,0 +1,117 @@
1
+// @flow
2
+
3
+import createListComponent from './createListComponent';
4
+
5
+import type { Props, ScrollToAlign } from './createListComponent';
6
+
7
+const FixedSizeList = createListComponent({
8
+ getItemOffset: ({ itemSize, size }: Props<any>, index: number): number =>
9
+ index * ((itemSize: any): number),
10
+
11
+ getItemSize: ({ itemSize, size }: Props<any>, index: number): number =>
12
+ ((itemSize: any): number),
13
+
14
+ getEstimatedTotalSize: ({ itemCount, itemSize }: Props<any>) =>
15
+ ((itemSize: any): number) * itemCount,
16
+
17
+ getOffsetForIndexAndAlignment: (
18
+ { direction, height, itemCount, itemSize, layout, width }: Props<any>,
19
+ index: number,
20
+ align: ScrollToAlign,
21
+ scrollOffset: number
22
+ ): number => {
23
+ // TODO Deprecate direction "horizontal"
24
+ const isHorizontal = direction === 'horizontal' || layout === 'horizontal';
25
+ const size = (((isHorizontal ? width : height): any): number);
26
+ const maxOffset = Math.max(
27
+ 0,
28
+ Math.min(
29
+ itemCount * ((itemSize: any): number) - size,
30
+ index * ((itemSize: any): number)
31
+ )
32
+ );
33
+ const minOffset = Math.max(
34
+ 0,
35
+ index * ((itemSize: any): number) - size + ((itemSize: any): number)
36
+ );
37
+
38
+ if (align === 'smart') {
39
+ if (
40
+ scrollOffset >= minOffset - size &&
41
+ scrollOffset <= maxOffset + size
42
+ ) {
43
+ align = 'auto';
44
+ } else {
45
+ align = 'center';
46
+ }
47
+ }
48
+
49
+ switch (align) {
50
+ case 'start':
51
+ return maxOffset;
52
+ case 'end':
53
+ return minOffset;
54
+ case 'center':
55
+ return Math.round(minOffset + (maxOffset - minOffset) / 2);
56
+ case 'auto':
57
+ default:
58
+ if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
59
+ return scrollOffset;
60
+ } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
61
+ return minOffset;
62
+ } else {
63
+ return maxOffset;
64
+ }
65
+ }
66
+ },
67
+
68
+ getStartIndexForOffset: (
69
+ { itemCount, itemSize }: Props<any>,
70
+ offset: number
71
+ ): number =>
72
+ Math.max(
73
+ 0,
74
+ Math.min(itemCount - 1, Math.floor(offset / ((itemSize: any): number)))
75
+ ),
76
+
77
+ getStopIndexForStartIndex: (
78
+ { direction, height, itemCount, itemSize, layout, width }: Props<any>,
79
+ startIndex: number,
80
+ scrollOffset: number
81
+ ): number => {
82
+ // TODO Deprecate direction "horizontal"
83
+ const isHorizontal = direction === 'horizontal' || layout === 'horizontal';
84
+ const offset = startIndex * ((itemSize: any): number);
85
+ const size = (((isHorizontal ? width : height): any): number);
86
+ return Math.max(
87
+ 0,
88
+ Math.min(
89
+ itemCount - 1,
90
+ startIndex +
91
+ Math.floor(
92
+ (size + (scrollOffset - offset)) / ((itemSize: any): number)
93
+ )
94
+ )
95
+ );
96
+ },
97
+
98
+ initInstanceProps(props: Props<any>): any {
99
+ // Noop
100
+ },
101
+
102
+ shouldResetStyleCacheOnItemSizeChange: true,
103
+
104
+ validateProps: ({ itemSize }: Props<any>): void => {
105
+ if (process.env.NODE_ENV !== 'production') {
106
+ if (typeof itemSize !== 'number') {
107
+ throw Error(
108
+ 'An invalid "itemSize" prop has been specified. ' +
109
+ 'Value should be a number. ' +
110
+ `"${itemSize === null ? 'null' : typeof itemSize}" was specified.`
111
+ );
112
+ }
113
+ }
114
+ },
115
+});
116
+
117
+export default FixedSizeList;
vendor/react-window/src/VariableSizeGrid.js
new
+503
@@ -0,0 +1,503 @@
1
+// @flow
2
+
3
+import createGridComponent from './createGridComponent';
4
+
5
+import type { Props, ScrollToAlign } from './createGridComponent';
6
+
7
+const DEFAULT_ESTIMATED_ITEM_SIZE = 50;
8
+
9
+type VariableSizeProps = {|
10
+ estimatedColumnWidth: number,
11
+ estimatedRowHeight: number,
12
+ ...Props<any>,
13
+|};
14
+
15
+type itemSizeGetter = (index: number) => number;
16
+type ItemType = 'column' | 'row';
17
+
18
+type ItemMetadata = {|
19
+ offset: number,
20
+ size: number,
21
+|};
22
+type ItemMetadataMap = { [index: number]: ItemMetadata };
23
+type InstanceProps = {|
24
+ columnMetadataMap: ItemMetadataMap,
25
+ estimatedColumnWidth: number,
26
+ estimatedRowHeight: number,
27
+ lastMeasuredColumnIndex: number,
28
+ lastMeasuredRowIndex: number,
29
+ rowMetadataMap: ItemMetadataMap,
30
+|};
31
+
32
+const getEstimatedTotalHeight = (
33
+ { rowCount }: Props<any>,
34
+ { rowMetadataMap, estimatedRowHeight, lastMeasuredRowIndex }: InstanceProps
35
+) => {
36
+ let totalSizeOfMeasuredRows = 0;
37
+
38
+ // Edge case check for when the number of items decreases while a scroll is in progress.
39
+ // https://github.com/bvaughn/react-window/pull/138
40
+ if (lastMeasuredRowIndex >= rowCount) {
41
+ lastMeasuredRowIndex = rowCount - 1;
42
+ }
43
+
44
+ if (lastMeasuredRowIndex >= 0) {
45
+ const itemMetadata = rowMetadataMap[lastMeasuredRowIndex];
46
+ totalSizeOfMeasuredRows = itemMetadata.offset + itemMetadata.size;
47
+ }
48
+
49
+ const numUnmeasuredItems = rowCount - lastMeasuredRowIndex - 1;
50
+ const totalSizeOfUnmeasuredItems = numUnmeasuredItems * estimatedRowHeight;
51
+
52
+ return totalSizeOfMeasuredRows + totalSizeOfUnmeasuredItems;
53
+};
54
+
55
+const getEstimatedTotalWidth = (
56
+ { columnCount }: Props<any>,
57
+ {
58
+ columnMetadataMap,
59
+ estimatedColumnWidth,
60
+ lastMeasuredColumnIndex,
61
+ }: InstanceProps
62
+) => {
63
+ let totalSizeOfMeasuredRows = 0;
64
+
65
+ // Edge case check for when the number of items decreases while a scroll is in progress.
66
+ // https://github.com/bvaughn/react-window/pull/138
67
+ if (lastMeasuredColumnIndex >= columnCount) {
68
+ lastMeasuredColumnIndex = columnCount - 1;
69
+ }
70
+
71
+ if (lastMeasuredColumnIndex >= 0) {
72
+ const itemMetadata = columnMetadataMap[lastMeasuredColumnIndex];
73
+ totalSizeOfMeasuredRows = itemMetadata.offset + itemMetadata.size;
74
+ }
75
+
76
+ const numUnmeasuredItems = columnCount - lastMeasuredColumnIndex - 1;
77
+ const totalSizeOfUnmeasuredItems = numUnmeasuredItems * estimatedColumnWidth;
78
+
79
+ return totalSizeOfMeasuredRows + totalSizeOfUnmeasuredItems;
80
+};
81
+
82
+const getItemMetadata = (
83
+ itemType: ItemType,
84
+ props: Props<any>,
85
+ index: number,
86
+ instanceProps: InstanceProps
87
+): ItemMetadata => {
88
+ let itemMetadataMap, itemSize, lastMeasuredIndex;
89
+ if (itemType === 'column') {
90
+ itemMetadataMap = instanceProps.columnMetadataMap;
91
+ itemSize = ((props.columnWidth: any): itemSizeGetter);
92
+ lastMeasuredIndex = instanceProps.lastMeasuredColumnIndex;
93
+ } else {
94
+ itemMetadataMap = instanceProps.rowMetadataMap;
95
+ itemSize = ((props.rowHeight: any): itemSizeGetter);
96
+ lastMeasuredIndex = instanceProps.lastMeasuredRowIndex;
97
+ }
98
+
99
+ if (index > lastMeasuredIndex) {
100
+ let offset = 0;
101
+ if (lastMeasuredIndex >= 0) {
102
+ const itemMetadata = itemMetadataMap[lastMeasuredIndex];
103
+ offset = itemMetadata.offset + itemMetadata.size;
104
+ }
105
+
106
+ for (let i = lastMeasuredIndex + 1; i <= index; i++) {
107
+ let size = itemSize(i);
108
+
109
+ itemMetadataMap[i] = {
110
+ offset,
111
+ size,
112
+ };
113
+
114
+ offset += size;
115
+ }
116
+
117
+ if (itemType === 'column') {
118
+ instanceProps.lastMeasuredColumnIndex = index;
119
+ } else {
120
+ instanceProps.lastMeasuredRowIndex = index;
121
+ }
122
+ }
123
+
124
+ return itemMetadataMap[index];
125
+};
126
+
127
+const findNearestItem = (
128
+ itemType: ItemType,
129
+ props: Props<any>,
130
+ instanceProps: InstanceProps,
131
+ offset: number
132
+) => {
133
+ let itemMetadataMap, lastMeasuredIndex;
134
+ if (itemType === 'column') {
135
+ itemMetadataMap = instanceProps.columnMetadataMap;
136
+ lastMeasuredIndex = instanceProps.lastMeasuredColumnIndex;
137
+ } else {
138
+ itemMetadataMap = instanceProps.rowMetadataMap;
139
+ lastMeasuredIndex = instanceProps.lastMeasuredRowIndex;
140
+ }
141
+
142
+ const lastMeasuredItemOffset =
143
+ lastMeasuredIndex > 0 ? itemMetadataMap[lastMeasuredIndex].offset : 0;
144
+
145
+ if (lastMeasuredItemOffset >= offset) {
146
+ // If we've already measured items within this range just use a binary search as it's faster.
147
+ return findNearestItemBinarySearch(
148
+ itemType,
149
+ props,
150
+ instanceProps,
151
+ lastMeasuredIndex,
152
+ 0,
153
+ offset
154
+ );
155
+ } else {
156
+ // If we haven't yet measured this high, fallback to an exponential search with an inner binary search.
157
+ // The exponential search avoids pre-computing sizes for the full set of items as a binary search would.
158
+ // The overall complexity for this approach is O(log n).
159
+ return findNearestItemExponentialSearch(
160
+ itemType,
161
+ props,
162
+ instanceProps,
163
+ Math.max(0, lastMeasuredIndex),
164
+ offset
165
+ );
166
+ }
167
+};
168
+
169
+const findNearestItemBinarySearch = (
170
+ itemType: ItemType,
171
+ props: Props<any>,
172
+ instanceProps: InstanceProps,
173
+ high: number,
174
+ low: number,
175
+ offset: number
176
+): number => {
177
+ while (low <= high) {
178
+ const middle = low + Math.floor((high - low) / 2);
179
+ const currentOffset = getItemMetadata(
180
+ itemType,
181
+ props,
182
+ middle,
183
+ instanceProps
184
+ ).offset;
185
+
186
+ if (currentOffset === offset) {
187
+ return middle;
188
+ } else if (currentOffset < offset) {
189
+ low = middle + 1;
190
+ } else if (currentOffset > offset) {
191
+ high = middle - 1;
192
+ }
193
+ }
194
+
195
+ if (low > 0) {
196
+ return low - 1;
197
+ } else {
198
+ return 0;
199
+ }
200
+};
201
+
202
+const findNearestItemExponentialSearch = (
203
+ itemType: ItemType,
204
+ props: Props<any>,
205
+ instanceProps: InstanceProps,
206
+ index: number,
207
+ offset: number
208
+): number => {
209
+ const itemCount = itemType === 'column' ? props.columnCount : props.rowCount;
210
+ let interval = 1;
211
+
212
+ while (
213
+ index < itemCount &&
214
+ getItemMetadata(itemType, props, index, instanceProps).offset < offset
215
+ ) {
216
+ index += interval;
217
+ interval *= 2;
218
+ }
219
+
220
+ return findNearestItemBinarySearch(
221
+ itemType,
222
+ props,
223
+ instanceProps,
224
+ Math.min(index, itemCount - 1),
225
+ Math.floor(index / 2),
226
+ offset
227
+ );
228
+};
229
+
230
+const getOffsetForIndexAndAlignment = (
231
+ itemType: ItemType,
232
+ props: Props<any>,
233
+ index: number,
234
+ align: ScrollToAlign,
235
+ scrollOffset: number,
236
+ instanceProps: InstanceProps,
237
+ scrollbarSize: number
238
+): number => {
239
+ const size = itemType === 'column' ? props.width : props.height;
240
+ const itemMetadata = getItemMetadata(itemType, props, index, instanceProps);
241
+
242
+ // Get estimated total size after ItemMetadata is computed,
243
+ // To ensure it reflects actual measurements instead of just estimates.
244
+ const estimatedTotalSize =
245
+ itemType === 'column'
246
+ ? getEstimatedTotalWidth(props, instanceProps)
247
+ : getEstimatedTotalHeight(props, instanceProps);
248
+
249
+ const maxOffset = Math.max(
250
+ 0,
251
+ Math.min(estimatedTotalSize - size, itemMetadata.offset)
252
+ );
253
+ const minOffset = Math.max(
254
+ 0,
255
+ itemMetadata.offset - size + scrollbarSize + itemMetadata.size
256
+ );
257
+
258
+ if (align === 'smart') {
259
+ if (scrollOffset >= minOffset - size && scrollOffset <= maxOffset + size) {
260
+ align = 'auto';
261
+ } else {
262
+ align = 'center';
263
+ }
264
+ }
265
+
266
+ switch (align) {
267
+ case 'start':
268
+ return maxOffset;
269
+ case 'end':
270
+ return minOffset;
271
+ case 'center':
272
+ return Math.round(minOffset + (maxOffset - minOffset) / 2);
273
+ case 'auto':
274
+ default:
275
+ if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
276
+ return scrollOffset;
277
+ } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
278
+ return minOffset;
279
+ } else {
280
+ return maxOffset;
281
+ }
282
+ }
283
+};
284
+
285
+const VariableSizeGrid = createGridComponent({
286
+ getColumnOffset: (
287
+ props: Props<any>,
288
+ index: number,
289
+ instanceProps: InstanceProps
290
+ ): number => getItemMetadata('column', props, index, instanceProps).offset,
291
+
292
+ getColumnStartIndexForOffset: (
293
+ props: Props<any>,
294
+ scrollLeft: number,
295
+ instanceProps: InstanceProps
296
+ ): number => findNearestItem('column', props, instanceProps, scrollLeft),
297
+
298
+ getColumnStopIndexForStartIndex: (
299
+ props: Props<any>,
300
+ startIndex: number,
301
+ scrollLeft: number,
302
+ instanceProps: InstanceProps
303
+ ): number => {
304
+ const { columnCount, width } = props;
305
+
306
+ const itemMetadata = getItemMetadata(
307
+ 'column',
308
+ props,
309
+ startIndex,
310
+ instanceProps
311
+ );
312
+ const maxOffset = scrollLeft + width;
313
+
314
+ let offset = itemMetadata.offset + itemMetadata.size;
315
+ let stopIndex = startIndex;
316
+
317
+ while (stopIndex < columnCount - 1 && offset < maxOffset) {
318
+ stopIndex++;
319
+ offset += getItemMetadata('column', props, stopIndex, instanceProps).size;
320
+ }
321
+
322
+ return stopIndex;
323
+ },
324
+
325
+ getColumnWidth: (
326
+ props: Props<any>,
327
+ index: number,
328
+ instanceProps: InstanceProps
329
+ ): number => instanceProps.columnMetadataMap[index].size,
330
+
331
+ getEstimatedTotalHeight,
332
+ getEstimatedTotalWidth,
333
+
334
+ getOffsetForColumnAndAlignment: (
335
+ props: Props<any>,
336
+ index: number,
337
+ align: ScrollToAlign,
338
+ scrollOffset: number,
339
+ instanceProps: InstanceProps,
340
+ scrollbarSize: number
341
+ ): number =>
342
+ getOffsetForIndexAndAlignment(
343
+ 'column',
344
+ props,
345
+ index,
346
+ align,
347
+ scrollOffset,
348
+ instanceProps,
349
+ scrollbarSize
350
+ ),
351
+
352
+ getOffsetForRowAndAlignment: (
353
+ props: Props<any>,
354
+ index: number,
355
+ align: ScrollToAlign,
356
+ scrollOffset: number,
357
+ instanceProps: InstanceProps,
358
+ scrollbarSize: number
359
+ ): number =>
360
+ getOffsetForIndexAndAlignment(
361
+ 'row',
362
+ props,
363
+ index,
364
+ align,
365
+ scrollOffset,
366
+ instanceProps,
367
+ scrollbarSize
368
+ ),
369
+
370
+ getRowOffset: (
371
+ props: Props<any>,
372
+ index: number,
373
+ instanceProps: InstanceProps
374
+ ): number => getItemMetadata('row', props, index, instanceProps).offset,
375
+
376
+ getRowHeight: (
377
+ props: Props<any>,
378
+ index: number,
379
+ instanceProps: InstanceProps
380
+ ): number => instanceProps.rowMetadataMap[index].size,
381
+
382
+ getRowStartIndexForOffset: (
383
+ props: Props<any>,
384
+ scrollTop: number,
385
+ instanceProps: InstanceProps
386
+ ): number => findNearestItem('row', props, instanceProps, scrollTop),
387
+
388
+ getRowStopIndexForStartIndex: (
389
+ props: Props<any>,
390
+ startIndex: number,
391
+ scrollTop: number,
392
+ instanceProps: InstanceProps
393
+ ): number => {
394
+ const { rowCount, height } = props;
395
+
396
+ const itemMetadata = getItemMetadata(
397
+ 'row',
398
+ props,
399
+ startIndex,
400
+ instanceProps
401
+ );
402
+ const maxOffset = scrollTop + height;
403
+
404
+ let offset = itemMetadata.offset + itemMetadata.size;
405
+ let stopIndex = startIndex;
406
+
407
+ while (stopIndex < rowCount - 1 && offset < maxOffset) {
408
+ stopIndex++;
409
+ offset += getItemMetadata('row', props, stopIndex, instanceProps).size;
410
+ }
411
+
412
+ return stopIndex;
413
+ },
414
+
415
+ initInstanceProps(props: Props<any>, instance: any): InstanceProps {
416
+ const {
417
+ estimatedColumnWidth,
418
+ estimatedRowHeight,
419
+ } = ((props: any): VariableSizeProps);
420
+
421
+ const instanceProps = {
422
+ columnMetadataMap: {},
423
+ estimatedColumnWidth: estimatedColumnWidth || DEFAULT_ESTIMATED_ITEM_SIZE,
424
+ estimatedRowHeight: estimatedRowHeight || DEFAULT_ESTIMATED_ITEM_SIZE,
425
+ lastMeasuredColumnIndex: -1,
426
+ lastMeasuredRowIndex: -1,
427
+ rowMetadataMap: {},
428
+ };
429
+
430
+ instance.resetAfterColumnIndex = (
431
+ columnIndex: number,
432
+ shouldForceUpdate?: boolean = true
433
+ ) => {
434
+ instance.resetAfterIndices({ columnIndex, shouldForceUpdate });
435
+ };
436
+
437
+ instance.resetAfterRowIndex = (
438
+ rowIndex: number,
439
+ shouldForceUpdate?: boolean = true
440
+ ) => {
441
+ instance.resetAfterIndices({ rowIndex, shouldForceUpdate });
442
+ };
443
+
444
+ instance.resetAfterIndices = ({
445
+ columnIndex,
446
+ rowIndex,
447
+ shouldForceUpdate = true,
448
+ }: {
449
+ columnIndex?: number,
450
+ rowIndex?: number,
451
+ shouldForceUpdate: boolean,
452
+ }) => {
453
+ if (typeof columnIndex === 'number') {
454
+ instanceProps.lastMeasuredColumnIndex = Math.min(
455
+ instanceProps.lastMeasuredColumnIndex,
456
+ columnIndex - 1
457
+ );
458
+ }
459
+ if (typeof rowIndex === 'number') {
460
+ instanceProps.lastMeasuredRowIndex = Math.min(
461
+ instanceProps.lastMeasuredRowIndex,
462
+ rowIndex - 1
463
+ );
464
+ }
465
+
466
+ // We could potentially optimize further by only evicting styles after this index,
467
+ // But since styles are only cached while scrolling is in progress-
468
+ // It seems an unnecessary optimization.
469
+ // It's unlikely that resetAfterIndex() will be called while a user is scrolling.
470
+ instance._getItemStyleCache(-1);
471
+
472
+ if (shouldForceUpdate) {
473
+ instance.forceUpdate();
474
+ }
475
+ };
476
+
477
+ return instanceProps;
478
+ },
479
+
480
+ shouldResetStyleCacheOnItemSizeChange: false,
481
+
482
+ validateProps: ({ columnWidth, rowHeight }: Props<any>): void => {
483
+ if (process.env.NODE_ENV !== 'production') {
484
+ if (typeof columnWidth !== 'function') {
485
+ throw Error(
486
+ 'An invalid "columnWidth" prop has been specified. ' +
487
+ 'Value should be a function. ' +
488
+ `"${
489
+ columnWidth === null ? 'null' : typeof columnWidth
490
+ }" was specified.`
491
+ );
492
+ } else if (typeof rowHeight !== 'function') {
493
+ throw Error(
494
+ 'An invalid "rowHeight" prop has been specified. ' +
495
+ 'Value should be a function. ' +
496
+ `"${rowHeight === null ? 'null' : typeof rowHeight}" was specified.`
497
+ );
498
+ }
499
+ }
500
+ },
501
+});
502
+
503
+export default VariableSizeGrid;
vendor/react-window/src/VariableSizeList.js
new
+316
@@ -0,0 +1,316 @@
1
+// @flow
2
+
3
+import createListComponent from './createListComponent';
4
+
5
+import type { Props, ScrollToAlign } from './createListComponent';
6
+
7
+const DEFAULT_ESTIMATED_ITEM_SIZE = 50;
8
+
9
+type VariableSizeProps = {|
10
+ estimatedItemSize: number,
11
+ ...Props<any>,
12
+|};
13
+
14
+type itemSizeGetter = (index: number) => number;
15
+
16
+type ItemMetadata = {|
17
+ offset: number,
18
+ size: number,
19
+|};
20
+type InstanceProps = {|
21
+ itemMetadataMap: { [index: number]: ItemMetadata },
22
+ estimatedItemSize: number,
23
+ lastMeasuredIndex: number,
24
+|};
25
+
26
+const getItemMetadata = (
27
+ props: Props<any>,
28
+ index: number,
29
+ instanceProps: InstanceProps
30
+): ItemMetadata => {
31
+ const { itemSize } = ((props: any): VariableSizeProps);
32
+ const { itemMetadataMap, lastMeasuredIndex } = instanceProps;
33
+
34
+ if (index > lastMeasuredIndex) {
35
+ let offset = 0;
36
+ if (lastMeasuredIndex >= 0) {
37
+ const itemMetadata = itemMetadataMap[lastMeasuredIndex];
38
+ offset = itemMetadata.offset + itemMetadata.size;
39
+ }
40
+
41
+ for (let i = lastMeasuredIndex + 1; i <= index; i++) {
42
+ let size = ((itemSize: any): itemSizeGetter)(i);
43
+
44
+ itemMetadataMap[i] = {
45
+ offset,
46
+ size,
47
+ };
48
+
49
+ offset += size;
50
+ }
51
+
52
+ instanceProps.lastMeasuredIndex = index;
53
+ }
54
+
55
+ return itemMetadataMap[index];
56
+};
57
+
58
+const findNearestItem = (
59
+ props: Props<any>,
60
+ instanceProps: InstanceProps,
61
+ offset: number
62
+) => {
63
+ const { itemMetadataMap, lastMeasuredIndex } = instanceProps;
64
+
65
+ const lastMeasuredItemOffset =
66
+ lastMeasuredIndex > 0 ? itemMetadataMap[lastMeasuredIndex].offset : 0;
67
+
68
+ if (lastMeasuredItemOffset >= offset) {
69
+ // If we've already measured items within this range just use a binary search as it's faster.
70
+ return findNearestItemBinarySearch(
71
+ props,
72
+ instanceProps,
73
+ lastMeasuredIndex,
74
+ 0,
75
+ offset
76
+ );
77
+ } else {
78
+ // If we haven't yet measured this high, fallback to an exponential search with an inner binary search.
79
+ // The exponential search avoids pre-computing sizes for the full set of items as a binary search would.
80
+ // The overall complexity for this approach is O(log n).
81
+ return findNearestItemExponentialSearch(
82
+ props,
83
+ instanceProps,
84
+ Math.max(0, lastMeasuredIndex),
85
+ offset
86
+ );
87
+ }
88
+};
89
+
90
+const findNearestItemBinarySearch = (
91
+ props: Props<any>,
92
+ instanceProps: InstanceProps,
93
+ high: number,
94
+ low: number,
95
+ offset: number
96
+): number => {
97
+ while (low <= high) {
98
+ const middle = low + Math.floor((high - low) / 2);
99
+ const currentOffset = getItemMetadata(props, middle, instanceProps).offset;
100
+
101
+ if (currentOffset === offset) {
102
+ return middle;
103
+ } else if (currentOffset < offset) {
104
+ low = middle + 1;
105
+ } else if (currentOffset > offset) {
106
+ high = middle - 1;
107
+ }
108
+ }
109
+
110
+ if (low > 0) {
111
+ return low - 1;
112
+ } else {
113
+ return 0;
114
+ }
115
+};
116
+
117
+const findNearestItemExponentialSearch = (
118
+ props: Props<any>,
119
+ instanceProps: InstanceProps,
120
+ index: number,
121
+ offset: number
122
+): number => {
123
+ const { itemCount } = props;
124
+ let interval = 1;
125
+
126
+ while (
127
+ index < itemCount &&
128
+ getItemMetadata(props, index, instanceProps).offset < offset
129
+ ) {
130
+ index += interval;
131
+ interval *= 2;
132
+ }
133
+
134
+ return findNearestItemBinarySearch(
135
+ props,
136
+ instanceProps,
137
+ Math.min(index, itemCount - 1),
138
+ Math.floor(index / 2),
139
+ offset
140
+ );
141
+};
142
+
143
+const getEstimatedTotalSize = (
144
+ { itemCount }: Props<any>,
145
+ { itemMetadataMap, estimatedItemSize, lastMeasuredIndex }: InstanceProps
146
+) => {
147
+ let totalSizeOfMeasuredItems = 0;
148
+
149
+ // Edge case check for when the number of items decreases while a scroll is in progress.
150
+ // https://github.com/bvaughn/react-window/pull/138
151
+ if (lastMeasuredIndex >= itemCount) {
152
+ lastMeasuredIndex = itemCount - 1;
153
+ }
154
+
155
+ if (lastMeasuredIndex >= 0) {
156
+ const itemMetadata = itemMetadataMap[lastMeasuredIndex];
157
+ totalSizeOfMeasuredItems = itemMetadata.offset + itemMetadata.size;
158
+ }
159
+
160
+ const numUnmeasuredItems = itemCount - lastMeasuredIndex - 1;
161
+ const totalSizeOfUnmeasuredItems = numUnmeasuredItems * estimatedItemSize;
162
+
163
+ return totalSizeOfMeasuredItems + totalSizeOfUnmeasuredItems;
164
+};
165
+
166
+const VariableSizeList = createListComponent({
167
+ getItemOffset: (
168
+ props: Props<any>,
169
+ index: number,
170
+ instanceProps: InstanceProps
171
+ ): number => getItemMetadata(props, index, instanceProps).offset,
172
+
173
+ getItemSize: (
174
+ props: Props<any>,
175
+ index: number,
176
+ instanceProps: InstanceProps
177
+ ): number => instanceProps.itemMetadataMap[index].size,
178
+
179
+ getEstimatedTotalSize,
180
+
181
+ getOffsetForIndexAndAlignment: (
182
+ props: Props<any>,
183
+ index: number,
184
+ align: ScrollToAlign,
185
+ scrollOffset: number,
186
+ instanceProps: InstanceProps
187
+ ): number => {
188
+ const { direction, height, layout, width } = props;
189
+
190
+ // TODO Deprecate direction "horizontal"
191
+ const isHorizontal = direction === 'horizontal' || layout === 'horizontal';
192
+ const size = (((isHorizontal ? width : height): any): number);
193
+ const itemMetadata = getItemMetadata(props, index, instanceProps);
194
+
195
+ // Get estimated total size after ItemMetadata is computed,
196
+ // To ensure it reflects actual measurements instead of just estimates.
197
+ const estimatedTotalSize = getEstimatedTotalSize(props, instanceProps);
198
+
199
+ const maxOffset = Math.max(
200
+ 0,
201
+ Math.min(estimatedTotalSize - size, itemMetadata.offset)
202
+ );
203
+ const minOffset = Math.max(
204
+ 0,
205
+ itemMetadata.offset - size + itemMetadata.size
206
+ );
207
+
208
+ if (align === 'smart') {
209
+ if (
210
+ scrollOffset >= minOffset - size &&
211
+ scrollOffset <= maxOffset + size
212
+ ) {
213
+ align = 'auto';
214
+ } else {
215
+ align = 'center';
216
+ }
217
+ }
218
+
219
+ switch (align) {
220
+ case 'start':
221
+ return maxOffset;
222
+ case 'end':
223
+ return minOffset;
224
+ case 'center':
225
+ return Math.round(minOffset + (maxOffset - minOffset) / 2);
226
+ case 'auto':
227
+ default:
228
+ if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
229
+ return scrollOffset;
230
+ } else if (scrollOffset - minOffset < maxOffset - scrollOffset) {
231
+ return minOffset;
232
+ } else {
233
+ return maxOffset;
234
+ }
235
+ }
236
+ },
237
+
238
+ getStartIndexForOffset: (
239
+ props: Props<any>,
240
+ offset: number,
241
+ instanceProps: InstanceProps
242
+ ): number => findNearestItem(props, instanceProps, offset),
243
+
244
+ getStopIndexForStartIndex: (
245
+ props: Props<any>,
246
+ startIndex: number,
247
+ scrollOffset: number,
248
+ instanceProps: InstanceProps
249
+ ): number => {
250
+ const { direction, height, itemCount, layout, width } = props;
251
+
252
+ // TODO Deprecate direction "horizontal"
253
+ const isHorizontal = direction === 'horizontal' || layout === 'horizontal';
254
+ const size = (((isHorizontal ? width : height): any): number);
255
+ const itemMetadata = getItemMetadata(props, startIndex, instanceProps);
256
+ const maxOffset = scrollOffset + size;
257
+
258
+ let offset = itemMetadata.offset + itemMetadata.size;
259
+ let stopIndex = startIndex;
260
+
261
+ while (stopIndex < itemCount - 1 && offset < maxOffset) {
262
+ stopIndex++;
263
+ offset += getItemMetadata(props, stopIndex, instanceProps).size;
264
+ }
265
+
266
+ return stopIndex;
267
+ },
268
+
269
+ initInstanceProps(props: Props<any>, instance: any): InstanceProps {
270
+ const { estimatedItemSize } = ((props: any): VariableSizeProps);
271
+
272
+ const instanceProps = {
273
+ itemMetadataMap: {},
274
+ estimatedItemSize: estimatedItemSize || DEFAULT_ESTIMATED_ITEM_SIZE,
275
+ lastMeasuredIndex: -1,
276
+ };
277
+
278
+ instance.resetAfterIndex = (
279
+ index: number,
280
+ shouldForceUpdate?: boolean = true
281
+ ) => {
282
+ instanceProps.lastMeasuredIndex = Math.min(
283
+ instanceProps.lastMeasuredIndex,
284
+ index - 1
285
+ );
286
+
287
+ // We could potentially optimize further by only evicting styles after this index,
288
+ // But since styles are only cached while scrolling is in progress-
289
+ // It seems an unnecessary optimization.
290
+ // It's unlikely that resetAfterIndex() will be called while a user is scrolling.
291
+ instance._getItemStyleCache(-1);
292
+
293
+ if (shouldForceUpdate) {
294
+ instance.forceUpdate();
295
+ }
296
+ };
297
+
298
+ return instanceProps;
299
+ },
300
+
301
+ shouldResetStyleCacheOnItemSizeChange: false,
302
+
303
+ validateProps: ({ itemSize }: Props<any>): void => {
304
+ if (process.env.NODE_ENV !== 'production') {
305
+ if (typeof itemSize !== 'function') {
306
+ throw Error(
307
+ 'An invalid "itemSize" prop has been specified. ' +
308
+ 'Value should be a function. ' +
309
+ `"${itemSize === null ? 'null' : typeof itemSize}" was specified.`
310
+ );
311
+ }
312
+ }
313
+ },
314
+});
315
+
316
+export default VariableSizeList;
vendor/react-window/src/areEqual.js
new
+18
@@ -0,0 +1,18 @@
1
+// @flow
2
+
3
+import shallowDiffers from './shallowDiffers';
4
+
5
+// Custom comparison function for React.memo().
6
+// It knows to compare individual style props and ignore the wrapper object.
7
+// See https://reactjs.org/docs/react-api.html#reactmemo
8
+export default function areEqual(
9
+ prevProps: Object,
10
+ nextProps: Object
11
+): boolean {
12
+ const { style: prevStyle, ...prevRest } = prevProps;
13
+ const { style: nextStyle, ...nextRest } = nextProps;
14
+
15
+ return (
16
+ !shallowDiffers(prevStyle, nextStyle) && !shallowDiffers(prevRest, nextRest)
17
+ );
18
+}
vendor/react-window/src/createGridComponent.js
new
+834
@@ -0,0 +1,834 @@
1
+// @flow
2
+
3
+import memoizeOne from 'memoize-one';
4
+import { createElement, PureComponent } from 'react';
5
+import { cancelTimeout, requestTimeout } from './timer';
6
+import { getScrollbarSize } from './domHelpers';
7
+
8
+import type { TimeoutID } from './timer';
9
+
10
+type Direction = 'ltr' | 'rtl';
11
+export type ScrollToAlign = 'auto' | 'smart' | 'center' | 'start' | 'end';
12
+
13
+type itemSize = number | ((index: number) => number);
14
+
15
+type RenderComponentProps<T> = {|
16
+ columnIndex: number,
17
+ data: T,
18
+ isScrolling?: boolean,
19
+ rowIndex: number,
20
+ style: Object,
21
+|};
22
+export type RenderComponent<T> = React$ComponentType<
23
+ $Shape<RenderComponentProps<T>>
24
+>;
25
+
26
+type ScrollDirection = 'forward' | 'backward';
27
+
28
+type OnItemsRenderedCallback = ({
29
+ overscanColumnStartIndex: number,
30
+ overscanColumnStopIndex: number,
31
+ overscanRowStartIndex: number,
32
+ overscanRowStopIndex: number,
33
+ visibleColumnStartIndex: number,
34
+ visibleColumnStopIndex: number,
35
+ visibleRowStartIndex: number,
36
+ visibleRowStopIndex: number,
37
+}) => void;
38
+type OnScrollCallback = ({
39
+ horizontalScrollDirection: ScrollDirection,
40
+ scrollLeft: number,
41
+ scrollTop: number,
42
+ scrollUpdateWasRequested: boolean,
43
+ verticalScrollDirection: ScrollDirection,
44
+}) => void;
45
+
46
+type ScrollEvent = SyntheticEvent<HTMLDivElement>;
47
+type ItemStyleCache = { [key: string]: Object };
48
+
49
+export type Props<T> = {|
50
+ children: RenderComponent<T>,
51
+ className?: string,
52
+ columnCount: number,
53
+ columnWidth: itemSize,
54
+ direction: Direction,
55
+ height: number,
56
+ initialScrollLeft?: number,
57
+ initialScrollTop?: number,
58
+ innerRef?: any,
59
+ innerElementType?: React$ElementType,
60
+ innerTagName?: string, // deprecated
61
+ itemData: T,
62
+ itemKey?: (params: {|
63
+ columnIndex: number,
64
+ data: T,
65
+ rowIndex: number,
66
+ |}) => any,
67
+ onItemsRendered?: OnItemsRenderedCallback,
68
+ onScroll?: OnScrollCallback,
69
+ outerRef?: any,
70
+ outerElementType?: React$ElementType,
71
+ outerTagName?: string, // deprecated
72
+ overscanColumnsCount?: number,
73
+ overscanCount?: number, // deprecated
74
+ overscanRowsCount?: number,
75
+ rowCount: number,
76
+ rowHeight: itemSize,
77
+ style?: Object,
78
+ useIsScrolling: boolean,
79
+ width: number,
80
+|};
81
+
82
+type State = {|
83
+ instance: any,
84
+ isScrolling: boolean,
85
+ horizontalScrollDirection: ScrollDirection,
86
+ scrollLeft: number,
87
+ scrollTop: number,
88
+ scrollUpdateWasRequested: boolean,
89
+ verticalScrollDirection: ScrollDirection,
90
+|};
91
+
92
+type getItemOffset = (
93
+ props: Props<any>,
94
+ index: number,
95
+ instanceProps: any
96
+) => number;
97
+type getItemSize = (
98
+ props: Props<any>,
99
+ index: number,
100
+ instanceProps: any
101
+) => number;
102
+type getEstimatedTotalSize = (props: Props<any>, instanceProps: any) => number;
103
+type GetOffsetForItemAndAlignment = (
104
+ props: Props<any>,
105
+ index: number,
106
+ align: ScrollToAlign,
107
+ scrollOffset: number,
108
+ instanceProps: any,
109
+ scrollbarSize: number
110
+) => number;
111
+type GetStartIndexForOffset = (
112
+ props: Props<any>,
113
+ offset: number,
114
+ instanceProps: any
115
+) => number;
116
+type GetStopIndexForStartIndex = (
117
+ props: Props<any>,
118
+ startIndex: number,
119
+ scrollOffset: number,
120
+ instanceProps: any
121
+) => number;
122
+type InitInstanceProps = (props: Props<any>, instance: any) => any;
123
+type ValidateProps = (props: Props<any>) => void;
124
+
125
+const IS_SCROLLING_DEBOUNCE_INTERVAL = 150;
126
+
127
+const defaultItemKey = ({ columnIndex, data, rowIndex }) =>
128
+ `${rowIndex}:${columnIndex}`;
129
+
130
+// In DEV mode, this Set helps us only log a warning once per component instance.
131
+// This avoids spamming the console every time a render happens.
132
+let devWarningsOverscanCount = null;
133
+let devWarningsTagName = null;
134
+if (process.env.NODE_ENV !== 'production') {
135
+ if (typeof window !== 'undefined' && typeof window.WeakSet !== 'undefined') {
136
+ devWarningsOverscanCount = new WeakSet();
137
+ devWarningsTagName = new WeakSet();
138
+ }
139
+}
140
+
141
+export default function createGridComponent({
142
+ getColumnOffset,
143
+ getColumnStartIndexForOffset,
144
+ getColumnStopIndexForStartIndex,
145
+ getColumnWidth,
146
+ getEstimatedTotalHeight,
147
+ getEstimatedTotalWidth,
148
+ getOffsetForColumnAndAlignment,
149
+ getOffsetForRowAndAlignment,
150
+ getRowHeight,
151
+ getRowOffset,
152
+ getRowStartIndexForOffset,
153
+ getRowStopIndexForStartIndex,
154
+ initInstanceProps,
155
+ shouldResetStyleCacheOnItemSizeChange,
156
+ validateProps,
157
+}: {|
158
+ getColumnOffset: getItemOffset,
159
+ getColumnStartIndexForOffset: GetStartIndexForOffset,
160
+ getColumnStopIndexForStartIndex: GetStopIndexForStartIndex,
161
+ getColumnWidth: getItemSize,
162
+ getEstimatedTotalHeight: getEstimatedTotalSize,
163
+ getEstimatedTotalWidth: getEstimatedTotalSize,
164
+ getOffsetForColumnAndAlignment: GetOffsetForItemAndAlignment,
165
+ getOffsetForRowAndAlignment: GetOffsetForItemAndAlignment,
166
+ getRowOffset: getItemOffset,
167
+ getRowHeight: getItemSize,
168
+ getRowStartIndexForOffset: GetStartIndexForOffset,
169
+ getRowStopIndexForStartIndex: GetStopIndexForStartIndex,
170
+ initInstanceProps: InitInstanceProps,
171
+ shouldResetStyleCacheOnItemSizeChange: boolean,
172
+ validateProps: ValidateProps,
173
+|}) {
174
+ return class Grid<T> extends PureComponent<Props<T>, State> {
175
+ _instanceProps: any = initInstanceProps(this.props, this);
176
+ _resetIsScrollingTimeoutId: TimeoutID | null = null;
177
+ _outerRef: ?HTMLDivElement;
178
+
179
+ static defaultProps = {
180
+ direction: 'ltr',
181
+ itemData: undefined,
182
+ useIsScrolling: false,
183
+ };
184
+
185
+ state: State = {
186
+ instance: this,
187
+ isScrolling: false,
188
+ horizontalScrollDirection: 'forward',
189
+ scrollLeft:
190
+ typeof this.props.initialScrollLeft === 'number'
191
+ ? this.props.initialScrollLeft
192
+ : 0,
193
+ scrollTop:
194
+ typeof this.props.initialScrollTop === 'number'
195
+ ? this.props.initialScrollTop
196
+ : 0,
197
+ scrollUpdateWasRequested: false,
198
+ verticalScrollDirection: 'forward',
199
+ };
200
+
201
+ // Always use explicit constructor for React components.
202
+ // It produces less code after transpilation. (#26)
203
+ // eslint-disable-next-line no-useless-constructor
204
+ constructor(props: Props<T>) {
205
+ super(props);
206
+ }
207
+
208
+ static getDerivedStateFromProps(
209
+ nextProps: Props<T>,
210
+ prevState: State
211
+ ): $Shape<State> | null {
212
+ validateSharedProps(nextProps, prevState);
213
+ validateProps(nextProps);
214
+ return null;
215
+ }
216
+
217
+ scrollTo({
218
+ scrollLeft,
219
+ scrollTop,
220
+ }: {
221
+ scrollLeft: number,
222
+ scrollTop: number,
223
+ }): void {
224
+ if (scrollLeft !== undefined) {
225
+ scrollLeft = Math.max(0, scrollLeft);
226
+ }
227
+ if (scrollTop !== undefined) {
228
+ scrollTop = Math.max(0, scrollTop);
229
+ }
230
+
231
+ this.setState(prevState => {
232
+ if (scrollLeft === undefined) {
233
+ scrollLeft = prevState.scrollLeft;
234
+ }
235
+ if (scrollTop === undefined) {
236
+ scrollTop = prevState.scrollTop;
237
+ }
238
+
239
+ if (
240
+ prevState.scrollLeft === scrollLeft &&
241
+ prevState.scrollTop === scrollTop
242
+ ) {
243
+ return null;
244
+ }
245
+
246
+ return {
247
+ horizontalScrollDirection:
248
+ prevState.scrollLeft < scrollLeft ? 'forward' : 'backward',
249
+ scrollLeft: scrollLeft,
250
+ scrollTop: scrollTop,
251
+ scrollUpdateWasRequested: true,
252
+ verticalScrollDirection:
253
+ prevState.scrollTop < scrollTop ? 'forward' : 'backward',
254
+ };
255
+ }, this._resetIsScrollingDebounced);
256
+ }
257
+
258
+ scrollToItem({
259
+ align = 'auto',
260
+ columnIndex,
261
+ rowIndex,
262
+ }: {
263
+ align: ScrollToAlign,
264
+ columnIndex?: number,
265
+ rowIndex?: number,
266
+ }): void {
267
+ const { columnCount, height, rowCount, width } = this.props;
268
+ const { scrollLeft, scrollTop } = this.state;
269
+ const scrollbarSize = getScrollbarSize();
270
+
271
+ if (columnIndex !== undefined) {
272
+ columnIndex = Math.max(0, Math.min(columnIndex, columnCount - 1));
273
+ }
274
+ if (rowIndex !== undefined) {
275
+ rowIndex = Math.max(0, Math.min(rowIndex, rowCount - 1));
276
+ }
277
+
278
+ const estimatedTotalHeight = getEstimatedTotalHeight(
279
+ this.props,
280
+ this._instanceProps
281
+ );
282
+ const estimatedTotalWidth = getEstimatedTotalWidth(
283
+ this.props,
284
+ this._instanceProps
285
+ );
286
+
287
+ // The scrollbar size should be considered when scrolling an item into view,
288
+ // to ensure it's fully visible.
289
+ // But we only need to account for its size when it's actually visible.
290
+ const horizontalScrollbarSize =
291
+ estimatedTotalWidth > width ? scrollbarSize : 0;
292
+ const verticalScrollbarSize =
293
+ estimatedTotalHeight > height ? scrollbarSize : 0;
294
+
295
+ this.scrollTo({
296
+ scrollLeft:
297
+ columnIndex !== undefined
298
+ ? getOffsetForColumnAndAlignment(
299
+ this.props,
300
+ columnIndex,
301
+ align,
302
+ scrollLeft,
303
+ this._instanceProps,
304
+ verticalScrollbarSize
305
+ )
306
+ : scrollLeft,
307
+ scrollTop:
308
+ rowIndex !== undefined
309
+ ? getOffsetForRowAndAlignment(
310
+ this.props,
311
+ rowIndex,
312
+ align,
313
+ scrollTop,
314
+ this._instanceProps,
315
+ horizontalScrollbarSize
316
+ )
317
+ : scrollTop,
318
+ });
319
+ }
320
+
321
+ componentDidMount() {
322
+ const { initialScrollLeft, initialScrollTop } = this.props;
323
+ if (typeof initialScrollLeft === 'number' && this._outerRef != null) {
324
+ ((this._outerRef: any): HTMLDivElement).scrollLeft = initialScrollLeft;
325
+ }
326
+ if (typeof initialScrollTop === 'number' && this._outerRef != null) {
327
+ ((this._outerRef: any): HTMLDivElement).scrollTop = initialScrollTop;
328
+ }
329
+
330
+ this._callPropsCallbacks();
331
+ }
332
+
333
+ componentDidUpdate() {
334
+ const { scrollLeft, scrollTop, scrollUpdateWasRequested } = this.state;
335
+ if (scrollUpdateWasRequested && this._outerRef !== null) {
336
+ ((this._outerRef: any): HTMLDivElement).scrollLeft = scrollLeft;
337
+ ((this._outerRef: any): HTMLDivElement).scrollTop = scrollTop;
338
+ }
339
+
340
+ this._callPropsCallbacks();
341
+ }
342
+
343
+ componentWillUnmount() {
344
+ if (this._resetIsScrollingTimeoutId !== null) {
345
+ cancelTimeout(this._resetIsScrollingTimeoutId);
346
+ }
347
+ }
348
+
349
+ render() {
350
+ const {
351
+ children,
352
+ className,
353
+ columnCount,
354
+ direction,
355
+ height,
356
+ innerRef,
357
+ innerElementType,
358
+ innerTagName,
359
+ itemData,
360
+ itemKey = defaultItemKey,
361
+ outerElementType,
362
+ outerTagName,
363
+ rowCount,
364
+ style,
365
+ useIsScrolling,
366
+ width,
367
+ } = this.props;
368
+ const { isScrolling } = this.state;
369
+
370
+ const [
371
+ columnStartIndex,
372
+ columnStopIndex,
373
+ ] = this._getHorizontalRangeToRender();
374
+ const [rowStartIndex, rowStopIndex] = this._getVerticalRangeToRender();
375
+
376
+ const items = [];
377
+ if (columnCount > 0 && rowCount) {
378
+ for (
379
+ let rowIndex = rowStartIndex;
380
+ rowIndex <= rowStopIndex;
381
+ rowIndex++
382
+ ) {
383
+ for (
384
+ let columnIndex = columnStartIndex;
385
+ columnIndex <= columnStopIndex;
386
+ columnIndex++
387
+ ) {
388
+ items.push(
389
+ createElement(children, {
390
+ columnIndex,
391
+ data: itemData,
392
+ isScrolling: useIsScrolling ? isScrolling : undefined,
393
+ key: itemKey({ columnIndex, data: itemData, rowIndex }),
394
+ rowIndex,
395
+ style: this._getItemStyle(rowIndex, columnIndex),
396
+ })
397
+ );
398
+ }
399
+ }
400
+ }
401
+
402
+ // Read this value AFTER items have been created,
403
+ // So their actual sizes (if variable) are taken into consideration.
404
+ const estimatedTotalHeight = getEstimatedTotalHeight(
405
+ this.props,
406
+ this._instanceProps
407
+ );
408
+ const estimatedTotalWidth = getEstimatedTotalWidth(
409
+ this.props,
410
+ this._instanceProps
411
+ );
412
+
413
+ return createElement(
414
+ outerElementType || outerTagName || 'div',
415
+ {
416
+ className,
417
+ onScroll: this._onScroll,
418
+ ref: this._outerRefSetter,
419
+ style: {
420
+ position: 'relative',
421
+ height,
422
+ width,
423
+ overflow: 'auto',
424
+ WebkitOverflowScrolling: 'touch',
425
+ willChange: 'transform',
426
+ direction,
427
+ ...style,
428
+ },
429
+ },
430
+ createElement(innerElementType || innerTagName || 'div', {
431
+ children: items,
432
+ ref: innerRef,
433
+ style: {
434
+ height: estimatedTotalHeight,
435
+ pointerEvents: isScrolling ? 'none' : '',
436
+ width: estimatedTotalWidth,
437
+ },
438
+ })
439
+ );
440
+ }
441
+
442
+ _callOnItemsRendered: (
443
+ overscanColumnStartIndex: number,
444
+ overscanColumnStopIndex: number,
445
+ overscanRowStartIndex: number,
446
+ overscanRowStopIndex: number,
447
+ visibleColumnStartIndex: number,
448
+ visibleColumnStopIndex: number,
449
+ visibleRowStartIndex: number,
450
+ visibleRowStopIndex: number
451
+ ) => void;
452
+ _callOnItemsRendered = memoizeOne(
453
+ (
454
+ overscanColumnStartIndex: number,
455
+ overscanColumnStopIndex: number,
456
+ overscanRowStartIndex: number,
457
+ overscanRowStopIndex: number,
458
+ visibleColumnStartIndex: number,
459
+ visibleColumnStopIndex: number,
460
+ visibleRowStartIndex: number,
461
+ visibleRowStopIndex: number
462
+ ) =>
463
+ ((this.props.onItemsRendered: any): OnItemsRenderedCallback)({
464
+ overscanColumnStartIndex,
465
+ overscanColumnStopIndex,
466
+ overscanRowStartIndex,
467
+ overscanRowStopIndex,
468
+ visibleColumnStartIndex,
469
+ visibleColumnStopIndex,
470
+ visibleRowStartIndex,
471
+ visibleRowStopIndex,
472
+ })
473
+ );
474
+
475
+ _callOnScroll: (
476
+ scrollLeft: number,
477
+ scrollTop: number,
478
+ horizontalScrollDirection: ScrollDirection,
479
+ verticalScrollDirection: ScrollDirection,
480
+ scrollUpdateWasRequested: boolean
481
+ ) => void;
482
+ _callOnScroll = memoizeOne(
483
+ (
484
+ scrollLeft: number,
485
+ scrollTop: number,
486
+ horizontalScrollDirection: ScrollDirection,
487
+ verticalScrollDirection: ScrollDirection,
488
+ scrollUpdateWasRequested: boolean
489
+ ) =>
490
+ ((this.props.onScroll: any): OnScrollCallback)({
491
+ horizontalScrollDirection,
492
+ scrollLeft,
493
+ scrollTop,
494
+ verticalScrollDirection,
495
+ scrollUpdateWasRequested,
496
+ })
497
+ );
498
+
499
+ _callPropsCallbacks() {
500
+ const { columnCount, onItemsRendered, onScroll, rowCount } = this.props;
501
+
502
+ if (typeof onItemsRendered === 'function') {
503
+ if (columnCount > 0 && rowCount > 0) {
504
+ const [
505
+ overscanColumnStartIndex,
506
+ overscanColumnStopIndex,
507
+ visibleColumnStartIndex,
508
+ visibleColumnStopIndex,
509
+ ] = this._getHorizontalRangeToRender();
510
+ const [
511
+ overscanRowStartIndex,
512
+ overscanRowStopIndex,
513
+ visibleRowStartIndex,
514
+ visibleRowStopIndex,
515
+ ] = this._getVerticalRangeToRender();
516
+ this._callOnItemsRendered(
517
+ overscanColumnStartIndex,
518
+ overscanColumnStopIndex,
519
+ overscanRowStartIndex,
520
+ overscanRowStopIndex,
521
+ visibleColumnStartIndex,
522
+ visibleColumnStopIndex,
523
+ visibleRowStartIndex,
524
+ visibleRowStopIndex
525
+ );
526
+ }
527
+ }
528
+
529
+ if (typeof onScroll === 'function') {
530
+ const {
531
+ horizontalScrollDirection,
532
+ scrollLeft,
533
+ scrollTop,
534
+ scrollUpdateWasRequested,
535
+ verticalScrollDirection,
536
+ } = this.state;
537
+ this._callOnScroll(
538
+ scrollLeft,
539
+ scrollTop,
540
+ horizontalScrollDirection,
541
+ verticalScrollDirection,
542
+ scrollUpdateWasRequested
543
+ );
544
+ }
545
+ }
546
+
547
+ // Lazily create and cache item styles while scrolling,
548
+ // So that pure component sCU will prevent re-renders.
549
+ // We maintain this cache, and pass a style prop rather than index,
550
+ // So that List can clear cached styles and force item re-render if necessary.
551
+ _getItemStyle: (rowIndex: number, columnIndex: number) => Object;
552
+ _getItemStyle = (rowIndex: number, columnIndex: number): Object => {
553
+ const { columnWidth, direction, rowHeight } = this.props;
554
+
555
+ const itemStyleCache = this._getItemStyleCache(
556
+ shouldResetStyleCacheOnItemSizeChange && columnWidth,
557
+ shouldResetStyleCacheOnItemSizeChange && direction,
558
+ shouldResetStyleCacheOnItemSizeChange && rowHeight
559
+ );
560
+
561
+ const key = `${rowIndex}:${columnIndex}`;
562
+
563
+ let style;
564
+ if (itemStyleCache.hasOwnProperty(key)) {
565
+ style = itemStyleCache[key];
566
+ } else {
567
+ itemStyleCache[key] = style = {
568
+ position: 'absolute',
569
+ [direction === 'rtl' ? 'right' : 'left']: getColumnOffset(
570
+ this.props,
571
+ columnIndex,
572
+ this._instanceProps
573
+ ),
574
+ top: getRowOffset(this.props, rowIndex, this._instanceProps),
575
+ height: getRowHeight(this.props, rowIndex, this._instanceProps),
576
+ width: getColumnWidth(this.props, columnIndex, this._instanceProps),
577
+ };
578
+ }
579
+
580
+ return style;
581
+ };
582
+
583
+ _getItemStyleCache: (_: any, __: any, ___: any) => ItemStyleCache;
584
+ _getItemStyleCache = memoizeOne((_: any, __: any, ___: any) => ({}));
585
+
586
+ _getHorizontalRangeToRender(): [number, number, number, number] {
587
+ const {
588
+ columnCount,
589
+ overscanColumnsCount,
590
+ overscanCount,
591
+ rowCount,
592
+ } = this.props;
593
+ const { horizontalScrollDirection, isScrolling, scrollLeft } = this.state;
594
+
595
+ const overscanCountResolved: number =
596
+ overscanColumnsCount || overscanCount || 1;
597
+
598
+ if (columnCount === 0 || rowCount === 0) {
599
+ return [0, 0, 0, 0];
600
+ }
601
+
602
+ const startIndex = getColumnStartIndexForOffset(
603
+ this.props,
604
+ scrollLeft,
605
+ this._instanceProps
606
+ );
607
+ const stopIndex = getColumnStopIndexForStartIndex(
608
+ this.props,
609
+ startIndex,
610
+ scrollLeft,
611
+ this._instanceProps
612
+ );
613
+
614
+ // Overscan by one item in each direction so that tab/focus works.
615
+ // If there isn't at least one extra item, tab loops back around.
616
+ const overscanBackward =
617
+ !isScrolling || horizontalScrollDirection === 'backward'
618
+ ? Math.max(1, overscanCountResolved)
619
+ : 1;
620
+ const overscanForward =
621
+ !isScrolling || horizontalScrollDirection === 'forward'
622
+ ? Math.max(1, overscanCountResolved)
623
+ : 1;
624
+
625
+ return [
626
+ Math.max(0, startIndex - overscanBackward),
627
+ Math.max(0, Math.min(columnCount - 1, stopIndex + overscanForward)),
628
+ startIndex,
629
+ stopIndex,
630
+ ];
631
+ }
632
+
633
+ _getVerticalRangeToRender(): [number, number, number, number] {
634
+ const {
635
+ columnCount,
636
+ overscanCount,
637
+ overscanRowsCount,
638
+ rowCount,
639
+ } = this.props;
640
+ const { isScrolling, verticalScrollDirection, scrollTop } = this.state;
641
+
642
+ const overscanCountResolved: number =
643
+ overscanRowsCount || overscanCount || 1;
644
+
645
+ if (columnCount === 0 || rowCount === 0) {
646
+ return [0, 0, 0, 0];
647
+ }
648
+
649
+ const startIndex = getRowStartIndexForOffset(
650
+ this.props,
651
+ scrollTop,
652
+ this._instanceProps
653
+ );
654
+ const stopIndex = getRowStopIndexForStartIndex(
655
+ this.props,
656
+ startIndex,
657
+ scrollTop,
658
+ this._instanceProps
659
+ );
660
+
661
+ // Overscan by one item in each direction so that tab/focus works.
662
+ // If there isn't at least one extra item, tab loops back around.
663
+ const overscanBackward =
664
+ !isScrolling || verticalScrollDirection === 'backward'
665
+ ? Math.max(1, overscanCountResolved)
666
+ : 1;
667
+ const overscanForward =
668
+ !isScrolling || verticalScrollDirection === 'forward'
669
+ ? Math.max(1, overscanCountResolved)
670
+ : 1;
671
+
672
+ return [
673
+ Math.max(0, startIndex - overscanBackward),
674
+ Math.max(0, Math.min(rowCount - 1, stopIndex + overscanForward)),
675
+ startIndex,
676
+ stopIndex,
677
+ ];
678
+ }
679
+
680
+ _onScroll = (event: ScrollEvent): void => {
681
+ const {
682
+ clientWidth,
683
+ scrollLeft,
684
+ scrollTop,
685
+ scrollWidth,
686
+ } = event.currentTarget;
687
+ this.setState(prevState => {
688
+ if (
689
+ prevState.scrollLeft === scrollLeft &&
690
+ prevState.scrollTop === scrollTop
691
+ ) {
692
+ // Scroll position may have been updated by cDM/cDU,
693
+ // In which case we don't need to trigger another render,
694
+ // And we don't want to update state.isScrolling.
695
+ return null;
696
+ }
697
+
698
+ const { direction } = this.props;
699
+
700
+ // HACK According to the spec, scrollLeft should be negative for RTL aligned elements.
701
+ // Chrome does not seem to adhere; its scrollLeft values are positive (measured relative to the left).
702
+ // See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
703
+ let calculatedScrollLeft = scrollLeft;
704
+ if (direction === 'rtl') {
705
+ if (scrollLeft <= 0) {
706
+ calculatedScrollLeft = -scrollLeft;
707
+ } else {
708
+ calculatedScrollLeft = scrollWidth - clientWidth - scrollLeft;
709
+ }
710
+ }
711
+
712
+ return {
713
+ isScrolling: true,
714
+ horizontalScrollDirection:
715
+ prevState.scrollLeft < scrollLeft ? 'forward' : 'backward',
716
+ scrollLeft: calculatedScrollLeft,
717
+ scrollTop,
718
+ verticalScrollDirection:
719
+ prevState.scrollTop < scrollTop ? 'forward' : 'backward',
720
+ scrollUpdateWasRequested: false,
721
+ };
722
+ }, this._resetIsScrollingDebounced);
723
+ };
724
+
725
+ _outerRefSetter = (ref: any): void => {
726
+ const { outerRef } = this.props;
727
+
728
+ this._outerRef = ((ref: any): HTMLDivElement);
729
+
730
+ if (typeof outerRef === 'function') {
731
+ outerRef(ref);
732
+ } else if (
733
+ outerRef != null &&
734
+ typeof outerRef === 'object' &&
735
+ outerRef.hasOwnProperty('current')
736
+ ) {
737
+ outerRef.current = ref;
738
+ }
739
+ };
740
+
741
+ _resetIsScrollingDebounced = () => {
742
+ if (this._resetIsScrollingTimeoutId !== null) {
743
+ cancelTimeout(this._resetIsScrollingTimeoutId);
744
+ }
745
+
746
+ this._resetIsScrollingTimeoutId = requestTimeout(
747
+ this._resetIsScrolling,
748
+ IS_SCROLLING_DEBOUNCE_INTERVAL
749
+ );
750
+ };
751
+
752
+ _resetIsScrolling = () => {
753
+ this._resetIsScrollingTimeoutId = null;
754
+
755
+ this.setState({ isScrolling: false }, () => {
756
+ // Clear style cache after state update has been committed.
757
+ // This way we don't break pure sCU for items that don't use isScrolling param.
758
+ this._getItemStyleCache(-1);
759
+ });
760
+ };
761
+ };
762
+}
763
+
764
+const validateSharedProps = (
765
+ {
766
+ children,
767
+ direction,
768
+ height,
769
+ innerTagName,
770
+ outerTagName,
771
+ overscanCount,
772
+ width,
773
+ }: Props<any>,
774
+ { instance }: State
775
+): void => {
776
+ if (process.env.NODE_ENV !== 'production') {
777
+ if (typeof overscanCount === 'number') {
778
+ if (devWarningsOverscanCount && !devWarningsOverscanCount.has(instance)) {
779
+ devWarningsOverscanCount.add(instance);
780
+ console.warn(
781
+ 'The overscanCount prop has been deprecated. ' +
782
+ 'Please use the overscanColumnsCount and overscanRowsCount props instead.'
783
+ );
784
+ }
785
+ }
786
+
787
+ if (innerTagName != null || outerTagName != null) {
788
+ if (devWarningsTagName && !devWarningsTagName.has(instance)) {
789
+ devWarningsTagName.add(instance);
790
+ console.warn(
791
+ 'The innerTagName and outerTagName props have been deprecated. ' +
792
+ 'Please use the innerElementType and outerElementType props instead.'
793
+ );
794
+ }
795
+ }
796
+
797
+ if (children == null) {
798
+ throw Error(
799
+ 'An invalid "children" prop has been specified. ' +
800
+ 'Value should be a React component. ' +
801
+ `"${children === null ? 'null' : typeof children}" was specified.`
802
+ );
803
+ }
804
+
805
+ switch (direction) {
806
+ case 'ltr':
807
+ case 'rtl':
808
+ // Valid values
809
+ break;
810
+ default:
811
+ throw Error(
812
+ 'An invalid "direction" prop has been specified. ' +
813
+ 'Value should be either "ltr" or "rtl". ' +
814
+ `"${direction}" was specified.`
815
+ );
816
+ }
817
+
818
+ if (typeof width !== 'number') {
819
+ throw Error(
820
+ 'An invalid "width" prop has been specified. ' +
821
+ 'Grids must specify a number for width. ' +
822
+ `"${width === null ? 'null' : typeof width}" was specified.`
823
+ );
824
+ }
825
+
826
+ if (typeof height !== 'number') {
827
+ throw Error(
828
+ 'An invalid "height" prop has been specified. ' +
829
+ 'Grids must specify a number for height. ' +
830
+ `"${height === null ? 'null' : typeof height}" was specified.`
831
+ );
832
+ }
833
+ }
834
+};
vendor/react-window/src/createListComponent.js
new
+670
@@ -0,0 +1,670 @@
1
+// @flow
2
+
3
+import memoizeOne from 'memoize-one';
4
+import { createElement, PureComponent } from 'react';
5
+import { cancelTimeout, requestTimeout } from './timer';
6
+
7
+import type { TimeoutID } from './timer';
8
+
9
+export type ScrollToAlign = 'auto' | 'smart' | 'center' | 'start' | 'end';
10
+
11
+type itemSize = number | ((index: number) => number);
12
+// TODO Deprecate directions "horizontal" and "vertical"
13
+type Direction = 'ltr' | 'rtl' | 'horizontal' | 'vertical';
14
+type Layout = 'horizontal' | 'vertical';
15
+
16
+type RenderComponentProps<T> = {|
17
+ data: T,
18
+ index: number,
19
+ isScrolling?: boolean,
20
+ style: Object,
21
+|};
22
+type RenderComponent<T> = React$ComponentType<$Shape<RenderComponentProps<T>>>;
23
+
24
+type ScrollDirection = 'forward' | 'backward';
25
+
26
+type onItemsRenderedCallback = ({
27
+ overscanStartIndex: number,
28
+ overscanStopIndex: number,
29
+ visibleStartIndex: number,
30
+ visibleStopIndex: number,
31
+}) => void;
32
+type onScrollCallback = ({
33
+ scrollDirection: ScrollDirection,
34
+ scrollOffset: number,
35
+ scrollUpdateWasRequested: boolean,
36
+}) => void;
37
+
38
+type ScrollEvent = SyntheticEvent<HTMLDivElement>;
39
+type ItemStyleCache = { [index: number]: Object };
40
+
41
+export type Props<T> = {|
42
+ children: RenderComponent<T>,
43
+ className?: string,
44
+ direction: Direction,
45
+ height: number | string,
46
+ initialScrollOffset?: number,
47
+ innerRef?: any,
48
+ innerElementType?: React$ElementType,
49
+ innerTagName?: string, // deprecated
50
+ itemCount: number,
51
+ itemData: T,
52
+ itemKey?: (index: number, data: T) => any,
53
+ itemSize: itemSize,
54
+ layout: Layout,
55
+ onItemsRendered?: onItemsRenderedCallback,
56
+ onScroll?: onScrollCallback,
57
+ outerRef?: any,
58
+ outerElementType?: React$ElementType,
59
+ outerTagName?: string, // deprecated
60
+ overscanCount: number,
61
+ style?: Object,
62
+ useIsScrolling: boolean,
63
+ width: number | string,
64
+|};
65
+
66
+type State = {|
67
+ instance: any,
68
+ isScrolling: boolean,
69
+ scrollDirection: ScrollDirection,
70
+ scrollOffset: number,
71
+ scrollUpdateWasRequested: boolean,
72
+|};
73
+
74
+type GetItemOffset = (
75
+ props: Props<any>,
76
+ index: number,
77
+ instanceProps: any
78
+) => number;
79
+type GetItemSize = (
80
+ props: Props<any>,
81
+ index: number,
82
+ instanceProps: any
83
+) => number;
84
+type GetEstimatedTotalSize = (props: Props<any>, instanceProps: any) => number;
85
+type GetOffsetForIndexAndAlignment = (
86
+ props: Props<any>,
87
+ index: number,
88
+ align: ScrollToAlign,
89
+ scrollOffset: number,
90
+ instanceProps: any
91
+) => number;
92
+type GetStartIndexForOffset = (
93
+ props: Props<any>,
94
+ offset: number,
95
+ instanceProps: any
96
+) => number;
97
+type GetStopIndexForStartIndex = (
98
+ props: Props<any>,
99
+ startIndex: number,
100
+ scrollOffset: number,
101
+ instanceProps: any
102
+) => number;
103
+type InitInstanceProps = (props: Props<any>, instance: any) => any;
104
+type ValidateProps = (props: Props<any>) => void;
105
+
106
+const IS_SCROLLING_DEBOUNCE_INTERVAL = 150;
107
+
108
+const defaultItemKey = (index: number, data: any) => index;
109
+
110
+// In DEV mode, this Set helps us only log a warning once per component instance.
111
+// This avoids spamming the console every time a render happens.
112
+let devWarningsDirection = null;
113
+let devWarningsTagName = null;
114
+if (process.env.NODE_ENV !== 'production') {
115
+ if (typeof window !== 'undefined' && typeof window.WeakSet !== 'undefined') {
116
+ devWarningsDirection = new WeakSet();
117
+ devWarningsTagName = new WeakSet();
118
+ }
119
+}
120
+
121
+export default function createListComponent({
122
+ getItemOffset,
123
+ getEstimatedTotalSize,
124
+ getItemSize,
125
+ getOffsetForIndexAndAlignment,
126
+ getStartIndexForOffset,
127
+ getStopIndexForStartIndex,
128
+ initInstanceProps,
129
+ shouldResetStyleCacheOnItemSizeChange,
130
+ validateProps,
131
+}: {|
132
+ getItemOffset: GetItemOffset,
133
+ getEstimatedTotalSize: GetEstimatedTotalSize,
134
+ getItemSize: GetItemSize,
135
+ getOffsetForIndexAndAlignment: GetOffsetForIndexAndAlignment,
136
+ getStartIndexForOffset: GetStartIndexForOffset,
137
+ getStopIndexForStartIndex: GetStopIndexForStartIndex,
138
+ initInstanceProps: InitInstanceProps,
139
+ shouldResetStyleCacheOnItemSizeChange: boolean,
140
+ validateProps: ValidateProps,
141
+|}) {
142
+ return class List<T> extends PureComponent<Props<T>, State> {
143
+ _instanceProps: any = initInstanceProps(this.props, this);
144
+ _outerRef: ?HTMLDivElement;
145
+ _resetIsScrollingTimeoutId: TimeoutID | null = null;
146
+
147
+ static defaultProps = {
148
+ direction: 'ltr',
149
+ itemData: undefined,
150
+ layout: 'vertical',
151
+ overscanCount: 2,
152
+ useIsScrolling: false,
153
+ };
154
+
155
+ state: State = {
156
+ instance: this,
157
+ isScrolling: false,
158
+ scrollDirection: 'forward',
159
+ scrollOffset:
160
+ typeof this.props.initialScrollOffset === 'number'
161
+ ? this.props.initialScrollOffset
162
+ : 0,
163
+ scrollUpdateWasRequested: false,
164
+ };
165
+
166
+ // Always use explicit constructor for React components.
167
+ // It produces less code after transpilation. (#26)
168
+ // eslint-disable-next-line no-useless-constructor
169
+ constructor(props: Props<T>) {
170
+ super(props);
171
+ }
172
+
173
+ static getDerivedStateFromProps(
174
+ nextProps: Props<T>,
175
+ prevState: State
176
+ ): $Shape<State> | null {
177
+ validateSharedProps(nextProps, prevState);
178
+ validateProps(nextProps);
179
+ return null;
180
+ }
181
+
182
+ scrollTo(scrollOffset: number): void {
183
+ scrollOffset = Math.max(0, scrollOffset);
184
+
185
+ this.setState(prevState => {
186
+ if (prevState.scrollOffset === scrollOffset) {
187
+ return null;
188
+ }
189
+ return {
190
+ scrollDirection:
191
+ prevState.scrollOffset < scrollOffset ? 'forward' : 'backward',
192
+ scrollOffset: scrollOffset,
193
+ scrollUpdateWasRequested: true,
194
+ };
195
+ }, this._resetIsScrollingDebounced);
196
+ }
197
+
198
+ scrollToItem(index: number, align: ScrollToAlign = 'auto'): void {
199
+ const { itemCount } = this.props;
200
+ const { scrollOffset } = this.state;
201
+
202
+ index = Math.max(0, Math.min(index, itemCount - 1));
203
+
204
+ this.scrollTo(
205
+ getOffsetForIndexAndAlignment(
206
+ this.props,
207
+ index,
208
+ align,
209
+ scrollOffset,
210
+ this._instanceProps
211
+ )
212
+ );
213
+ }
214
+
215
+ componentDidMount() {
216
+ const { direction, initialScrollOffset, layout } = this.props;
217
+
218
+ if (typeof initialScrollOffset === 'number' && this._outerRef !== null) {
219
+ // TODO Deprecate direction "horizontal"
220
+ if (direction === 'horizontal' || layout === 'horizontal') {
221
+ ((this
222
+ ._outerRef: any): HTMLDivElement).scrollLeft = initialScrollOffset;
223
+ } else {
224
+ ((this
225
+ ._outerRef: any): HTMLDivElement).scrollTop = initialScrollOffset;
226
+ }
227
+ }
228
+
229
+ this._callPropsCallbacks();
230
+ }
231
+
232
+ componentDidUpdate() {
233
+ const { direction, layout } = this.props;
234
+ const { scrollOffset, scrollUpdateWasRequested } = this.state;
235
+
236
+ if (scrollUpdateWasRequested && this._outerRef !== null) {
237
+ // TODO Deprecate direction "horizontal"
238
+ if (direction === 'horizontal' || layout === 'horizontal') {
239
+ ((this._outerRef: any): HTMLDivElement).scrollLeft = scrollOffset;
240
+ } else {
241
+ ((this._outerRef: any): HTMLDivElement).scrollTop = scrollOffset;
242
+ }
243
+ }
244
+
245
+ this._callPropsCallbacks();
246
+ }
247
+
248
+ componentWillUnmount() {
249
+ if (this._resetIsScrollingTimeoutId !== null) {
250
+ cancelTimeout(this._resetIsScrollingTimeoutId);
251
+ }
252
+ }
253
+
254
+ render() {
255
+ const {
256
+ children,
257
+ className,
258
+ direction,
259
+ height,
260
+ innerRef,
261
+ innerElementType,
262
+ innerTagName,
263
+ itemCount,
264
+ itemData,
265
+ itemKey = defaultItemKey,
266
+ layout,
267
+ outerElementType,
268
+ outerTagName,
269
+ style,
270
+ useIsScrolling,
271
+ width,
272
+ } = this.props;
273
+ const { isScrolling } = this.state;
274
+
275
+ // TODO Deprecate direction "horizontal"
276
+ const isHorizontal =
277
+ direction === 'horizontal' || layout === 'horizontal';
278
+
279
+ const onScroll = isHorizontal
280
+ ? this._onScrollHorizontal
281
+ : this._onScrollVertical;
282
+
283
+ const [startIndex, stopIndex] = this._getRangeToRender();
284
+
285
+ const items = [];
286
+ if (itemCount > 0) {
287
+ for (let index = startIndex; index <= stopIndex; index++) {
288
+ items.push(
289
+ createElement(children, {
290
+ data: itemData,
291
+ key: itemKey(index, itemData),
292
+ index,
293
+ isScrolling: useIsScrolling ? isScrolling : undefined,
294
+ style: this._getItemStyle(index),
295
+ })
296
+ );
297
+ }
298
+ }
299
+
300
+ // Read this value AFTER items have been created,
301
+ // So their actual sizes (if variable) are taken into consideration.
302
+ const estimatedTotalSize = getEstimatedTotalSize(
303
+ this.props,
304
+ this._instanceProps
305
+ );
306
+
307
+ return createElement(
308
+ outerElementType || outerTagName || 'div',
309
+ {
310
+ className,
311
+ onScroll,
312
+ ref: this._outerRefSetter,
313
+ style: {
314
+ position: 'relative',
315
+ height,
316
+ width,
317
+ overflow: 'auto',
318
+ WebkitOverflowScrolling: 'touch',
319
+ willChange: 'transform',
320
+ direction,
321
+ ...style,
322
+ },
323
+ },
324
+ createElement(innerElementType || innerTagName || 'div', {
325
+ children: items,
326
+ ref: innerRef,
327
+ style: {
328
+ height: isHorizontal ? '100%' : estimatedTotalSize,
329
+ pointerEvents: isScrolling ? 'none' : '',
330
+ width: isHorizontal ? estimatedTotalSize : '100%',
331
+ },
332
+ })
333
+ );
334
+ }
335
+
336
+ _callOnItemsRendered: (
337
+ overscanStartIndex: number,
338
+ overscanStopIndex: number,
339
+ visibleStartIndex: number,
340
+ visibleStopIndex: number
341
+ ) => void;
342
+ _callOnItemsRendered = memoizeOne(
343
+ (
344
+ overscanStartIndex: number,
345
+ overscanStopIndex: number,
346
+ visibleStartIndex: number,
347
+ visibleStopIndex: number
348
+ ) =>
349
+ ((this.props.onItemsRendered: any): onItemsRenderedCallback)({
350
+ overscanStartIndex,
351
+ overscanStopIndex,
352
+ visibleStartIndex,
353
+ visibleStopIndex,
354
+ })
355
+ );
356
+
357
+ _callOnScroll: (
358
+ scrollDirection: ScrollDirection,
359
+ scrollOffset: number,
360
+ scrollUpdateWasRequested: boolean
361
+ ) => void;
362
+ _callOnScroll = memoizeOne(
363
+ (
364
+ scrollDirection: ScrollDirection,
365
+ scrollOffset: number,
366
+ scrollUpdateWasRequested: boolean
367
+ ) =>
368
+ ((this.props.onScroll: any): onScrollCallback)({
369
+ scrollDirection,
370
+ scrollOffset,
371
+ scrollUpdateWasRequested,
372
+ })
373
+ );
374
+
375
+ _callPropsCallbacks() {
376
+ if (typeof this.props.onItemsRendered === 'function') {
377
+ const { itemCount } = this.props;
378
+ if (itemCount > 0) {
379
+ const [
380
+ overscanStartIndex,
381
+ overscanStopIndex,
382
+ visibleStartIndex,
383
+ visibleStopIndex,
384
+ ] = this._getRangeToRender();
385
+ this._callOnItemsRendered(
386
+ overscanStartIndex,
387
+ overscanStopIndex,
388
+ visibleStartIndex,
389
+ visibleStopIndex
390
+ );
391
+ }
392
+ }
393
+
394
+ if (typeof this.props.onScroll === 'function') {
395
+ const {
396
+ scrollDirection,
397
+ scrollOffset,
398
+ scrollUpdateWasRequested,
399
+ } = this.state;
400
+ this._callOnScroll(
401
+ scrollDirection,
402
+ scrollOffset,
403
+ scrollUpdateWasRequested
404
+ );
405
+ }
406
+ }
407
+
408
+ // Lazily create and cache item styles while scrolling,
409
+ // So that pure component sCU will prevent re-renders.
410
+ // We maintain this cache, and pass a style prop rather than index,
411
+ // So that List can clear cached styles and force item re-render if necessary.
412
+ _getItemStyle: (index: number) => Object;
413
+ _getItemStyle = (index: number): Object => {
414
+ const { direction, itemSize, layout } = this.props;
415
+
416
+ const itemStyleCache = this._getItemStyleCache(
417
+ shouldResetStyleCacheOnItemSizeChange && itemSize,
418
+ shouldResetStyleCacheOnItemSizeChange && layout,
419
+ shouldResetStyleCacheOnItemSizeChange && direction
420
+ );
421
+
422
+ let style;
423
+ if (itemStyleCache.hasOwnProperty(index)) {
424
+ style = itemStyleCache[index];
425
+ } else {
426
+ const offset = getItemOffset(this.props, index, this._instanceProps);
427
+ const size = getItemSize(this.props, index, this._instanceProps);
428
+
429
+ // TODO Deprecate direction "horizontal"
430
+ const isHorizontal =
431
+ direction === 'horizontal' || layout === 'horizontal';
432
+
433
+ itemStyleCache[index] = style = {
434
+ position: 'absolute',
435
+ [direction === 'rtl' ? 'right' : 'left']: isHorizontal ? offset : 0,
436
+ top: !isHorizontal ? offset : 0,
437
+ height: !isHorizontal ? size : '100%',
438
+ width: isHorizontal ? size : '100%',
439
+ };
440
+ }
441
+
442
+ return style;
443
+ };
444
+
445
+ _getItemStyleCache: (_: any, __: any, ___: any) => ItemStyleCache;
446
+ _getItemStyleCache = memoizeOne((_: any, __: any, ___: any) => ({}));
447
+
448
+ _getRangeToRender(): [number, number, number, number] {
449
+ const { itemCount, overscanCount } = this.props;
450
+ const { isScrolling, scrollDirection, scrollOffset } = this.state;
451
+
452
+ if (itemCount === 0) {
453
+ return [0, 0, 0, 0];
454
+ }
455
+
456
+ const startIndex = getStartIndexForOffset(
457
+ this.props,
458
+ scrollOffset,
459
+ this._instanceProps
460
+ );
461
+ const stopIndex = getStopIndexForStartIndex(
462
+ this.props,
463
+ startIndex,
464
+ scrollOffset,
465
+ this._instanceProps
466
+ );
467
+
468
+ // Overscan by one item in each direction so that tab/focus works.
469
+ // If there isn't at least one extra item, tab loops back around.
470
+ const overscanBackward =
471
+ !isScrolling || scrollDirection === 'backward'
472
+ ? Math.max(1, overscanCount)
473
+ : 1;
474
+ const overscanForward =
475
+ !isScrolling || scrollDirection === 'forward'
476
+ ? Math.max(1, overscanCount)
477
+ : 1;
478
+
479
+ return [
480
+ Math.max(0, startIndex - overscanBackward),
481
+ Math.max(0, Math.min(itemCount - 1, stopIndex + overscanForward)),
482
+ startIndex,
483
+ stopIndex,
484
+ ];
485
+ }
486
+
487
+ _onScrollHorizontal = (event: ScrollEvent): void => {
488
+ const { clientWidth, scrollLeft, scrollWidth } = event.currentTarget;
489
+ this.setState(prevState => {
490
+ if (prevState.scrollOffset === scrollLeft) {
491
+ // Scroll position may have been updated by cDM/cDU,
492
+ // In which case we don't need to trigger another render,
493
+ // And we don't want to update state.isScrolling.
494
+ return null;
495
+ }
496
+
497
+ const { direction } = this.props;
498
+
499
+ // HACK According to the spec, scrollLeft should be negative for RTL aligned elements.
500
+ // Chrome does not seem to adhere; its scrolLeft values are positive (measured relative to the left).
501
+ // See https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
502
+ let scrollOffset = scrollLeft;
503
+ if (direction === 'rtl') {
504
+ if (scrollLeft <= 0) {
505
+ scrollOffset = -scrollOffset;
506
+ } else {
507
+ scrollOffset = scrollWidth - clientWidth - scrollLeft;
508
+ }
509
+ }
510
+
511
+ return {
512
+ isScrolling: true,
513
+ scrollDirection:
514
+ prevState.scrollOffset < scrollLeft ? 'forward' : 'backward',
515
+ scrollOffset,
516
+ scrollUpdateWasRequested: false,
517
+ };
518
+ }, this._resetIsScrollingDebounced);
519
+ };
520
+
521
+ _onScrollVertical = (event: ScrollEvent): void => {
522
+ const { scrollTop } = event.currentTarget;
523
+ this.setState(prevState => {
524
+ if (prevState.scrollOffset === scrollTop) {
525
+ // Scroll position may have been updated by cDM/cDU,
526
+ // In which case we don't need to trigger another render,
527
+ // And we don't want to update state.isScrolling.
528
+ return null;
529
+ }
530
+
531
+ return {
532
+ isScrolling: true,
533
+ scrollDirection:
534
+ prevState.scrollOffset < scrollTop ? 'forward' : 'backward',
535
+ scrollOffset: scrollTop,
536
+ scrollUpdateWasRequested: false,
537
+ };
538
+ }, this._resetIsScrollingDebounced);
539
+ };
540
+
541
+ _outerRefSetter = (ref: any): void => {
542
+ const { outerRef } = this.props;
543
+
544
+ this._outerRef = ((ref: any): HTMLDivElement);
545
+
546
+ if (typeof outerRef === 'function') {
547
+ outerRef(ref);
548
+ } else if (
549
+ outerRef != null &&
550
+ typeof outerRef === 'object' &&
551
+ outerRef.hasOwnProperty('current')
552
+ ) {
553
+ outerRef.current = ref;
554
+ }
555
+ };
556
+
557
+ _resetIsScrollingDebounced = () => {
558
+ if (this._resetIsScrollingTimeoutId !== null) {
559
+ cancelTimeout(this._resetIsScrollingTimeoutId);
560
+ }
561
+
562
+ this._resetIsScrollingTimeoutId = requestTimeout(
563
+ this._resetIsScrolling,
564
+ IS_SCROLLING_DEBOUNCE_INTERVAL
565
+ );
566
+ };
567
+
568
+ _resetIsScrolling = () => {
569
+ this._resetIsScrollingTimeoutId = null;
570
+
571
+ this.setState({ isScrolling: false }, () => {
572
+ // Clear style cache after state update has been committed.
573
+ // This way we don't break pure sCU for items that don't use isScrolling param.
574
+ this._getItemStyleCache(-1, null);
575
+ });
576
+ };
577
+ };
578
+}
579
+
580
+// NOTE: I considered further wrapping individual items with a pure ListItem component.
581
+// This would avoid ever calling the render function for the same index more than once,
582
+// But it would also add the overhead of a lot of components/fibers.
583
+// I assume people already do this (render function returning a class component),
584
+// So my doing it would just unnecessarily double the wrappers.
585
+
586
+const validateSharedProps = (
587
+ {
588
+ children,
589
+ direction,
590
+ height,
591
+ layout,
592
+ innerTagName,
593
+ outerTagName,
594
+ width,
595
+ }: Props<any>,
596
+ { instance }: State
597
+): void => {
598
+ if (process.env.NODE_ENV !== 'production') {
599
+ if (innerTagName != null || outerTagName != null) {
600
+ if (devWarningsTagName && !devWarningsTagName.has(instance)) {
601
+ devWarningsTagName.add(instance);
602
+ console.warn(
603
+ 'The innerTagName and outerTagName props have been deprecated. ' +
604
+ 'Please use the innerElementType and outerElementType props instead.'
605
+ );
606
+ }
607
+ }
608
+
609
+ // TODO Deprecate direction "horizontal"
610
+ const isHorizontal = direction === 'horizontal' || layout === 'horizontal';
611
+
612
+ switch (direction) {
613
+ case 'horizontal':
614
+ case 'vertical':
615
+ if (devWarningsDirection && !devWarningsDirection.has(instance)) {
616
+ devWarningsDirection.add(instance);
617
+ console.warn(
618
+ 'The direction prop should be either "ltr" (default) or "rtl". ' +
619
+ 'Please use the layout prop to specify "vertical" (default) or "horizontal" orientation.'
620
+ );
621
+ }
622
+ break;
623
+ case 'ltr':
624
+ case 'rtl':
625
+ // Valid values
626
+ break;
627
+ default:
628
+ throw Error(
629
+ 'An invalid "direction" prop has been specified. ' +
630
+ 'Value should be either "ltr" or "rtl". ' +
631
+ `"${direction}" was specified.`
632
+ );
633
+ }
634
+
635
+ switch (layout) {
636
+ case 'horizontal':
637
+ case 'vertical':
638
+ // Valid values
639
+ break;
640
+ default:
641
+ throw Error(
642
+ 'An invalid "layout" prop has been specified. ' +
643
+ 'Value should be either "horizontal" or "vertical". ' +
644
+ `"${layout}" was specified.`
645
+ );
646
+ }
647
+
648
+ if (children == null) {
649
+ throw Error(
650
+ 'An invalid "children" prop has been specified. ' +
651
+ 'Value should be a React component. ' +
652
+ `"${children === null ? 'null' : typeof children}" was specified.`
653
+ );
654
+ }
655
+
656
+ if (isHorizontal && typeof width !== 'number') {
657
+ throw Error(
658
+ 'An invalid "width" prop has been specified. ' +
659
+ 'Horizontal lists must specify a number for width. ' +
660
+ `"${width === null ? 'null' : typeof width}" was specified.`
661
+ );
662
+ } else if (!isHorizontal && typeof height !== 'number') {
663
+ throw Error(
664
+ 'An invalid "height" prop has been specified. ' +
665
+ 'Vertical lists must specify a number for height. ' +
666
+ `"${height === null ? 'null' : typeof height}" was specified.`
667
+ );
668
+ }
669
+ }
670
+};
vendor/react-window/src/domHelpers.js
new
+22
@@ -0,0 +1,22 @@
1
+// @flow
2
+
3
+let size: number = -1;
4
+
5
+// This utility copied from "dom-helpers" package.
6
+export function getScrollbarSize(recalculate?: boolean = false): number {
7
+ if (size === -1 || recalculate) {
8
+ const div = document.createElement('div');
9
+ const style = div.style;
10
+ style.width = '50px';
11
+ style.height = '50px';
12
+ style.overflow = 'scroll';
13
+
14
+ ((document.body: any): HTMLBodyElement).appendChild(div);
15
+
16
+ size = div.offsetWidth - div.clientWidth;
17
+
18
+ ((document.body: any): HTMLBodyElement).removeChild(div);
19
+ }
20
+
21
+ return size;
22
+}
vendor/react-window/src/index.js
new
+9
@@ -0,0 +1,9 @@
1
+// @flow
2
+
3
+export { default as VariableSizeGrid } from './VariableSizeGrid';
4
+export { default as VariableSizeList } from './VariableSizeList';
5
+export { default as FixedSizeGrid } from './FixedSizeGrid';
6
+export { default as FixedSizeList } from './FixedSizeList';
7
+
8
+export { default as areEqual } from './areEqual';
9
+export { default as shouldComponentUpdate } from './shouldComponentUpdate';
vendor/react-window/src/shallowDiffers.js
new
+17
@@ -0,0 +1,17 @@
1
+// @flow
2
+
3
+// Pulled from react-compat
4
+// https://github.com/developit/preact-compat/blob/7c5de00e7c85e2ffd011bf3af02899b63f699d3a/src/index.js#L349
5
+export default function shallowDiffers(prev: Object, next: Object): boolean {
6
+ for (let attribute in prev) {
7
+ if (!(attribute in next)) {
8
+ return true;
9
+ }
10
+ }
11
+ for (let attribute in next) {
12
+ if (prev[attribute] !== next[attribute]) {
13
+ return true;
14
+ }
15
+ }
16
+ return false;
17
+}
vendor/react-window/src/shouldComponentUpdate.js
new
+16
@@ -0,0 +1,16 @@
1
+// @flow
2
+
3
+import areEqual from './areEqual';
4
+import shallowDiffers from './shallowDiffers';
5
+
6
+// Custom shouldComponentUpdate for class components.
7
+// It knows to compare individual style props and ignore the wrapper object.
8
+// See https://reactjs.org/docs/react-component.html#shouldcomponentupdate
9
+export default function shouldComponentUpdate(
10
+ nextProps: Object,
11
+ nextState: Object
12
+): boolean {
13
+ return (
14
+ !areEqual(this.props, nextProps) || shallowDiffers(this.state, nextState)
15
+ );
16
+}
vendor/react-window/src/timer.js
new
+37
@@ -0,0 +1,37 @@
1
+// @flow
2
+
3
+// Animation frame based implementation of setTimeout.
4
+// Inspired by Joe Lambert, https://gist.github.com/joelambert/1002116#file-requesttimeout-js
5
+
6
+const hasNativePerformanceNow =
7
+ typeof performance === 'object' && typeof performance.now === 'function';
8
+
9
+const now = hasNativePerformanceNow
10
+ ? () => performance.now()
11
+ : () => Date.now();
12
+
13
+export type TimeoutID = {|
14
+ id: AnimationFrameID,
15
+|};
16
+
17
+export function cancelTimeout(timeoutID: TimeoutID) {
18
+ cancelAnimationFrame(timeoutID.id);
19
+}
20
+
21
+export function requestTimeout(callback: Function, delay: number): TimeoutID {
22
+ const start = now();
23
+
24
+ function tick() {
25
+ if (now() - start >= delay) {
26
+ callback.call(null);
27
+ } else {
28
+ timeoutID.id = requestAnimationFrame(tick);
29
+ }
30
+ }
31
+
32
+ const timeoutID: TimeoutID = {
33
+ id: requestAnimationFrame(tick),
34
+ };
35
+
36
+ return timeoutID;
37
+}
yarn.lock
+1
-14
@@ -758,7 +758,7 @@
758
"@babel/plugin-transform-react-jsx-self" "^7.0.0"
759
"@babel/plugin-transform-react-jsx-source" "^7.0.0"
760
761
-"@babel/runtime@7.3.1", "@babel/runtime@^7.0.0":
761
+"@babel/runtime@7.3.1":
762
version "7.3.1"
763
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.3.1.tgz#574b03e8e8a9898eaf4a872a92ea20b7846f6f2a"
764
integrity sha512-7jGW8ppV0ant637pIqAcFfQDDH1orEPGJb8aXfUozuCU3QqX7rX4DA8iwrbPrR1hcH0FTTHz47yQnk+bl5xHQA==
@@ -8119,11 +8119,6 @@ mem@^4.0.0:
8119
mimic-fn "^1.0.0"
8120
p-is-promise "^2.0.0"
8121
8122
-"memoize-one@>=3.1.1 <6":
8123
- version "5.0.4"
8124
- resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.0.4.tgz#005928aced5c43d890a4dfab18ca908b0ec92cbc"
8125
- integrity sha512-P0z5IeAH6qHHGkJIXWw0xC2HNEgkx/9uWWBQw64FJj3/ol14VYdfVGWWr0fXfjhhv3TKVIqUq65os6O4GUNksA==
8126
-
8122
memoize-one@^3.1.1:
8123
version "3.1.1"
8124
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-3.1.1.tgz#ef609811e3bc28970eac2884eece64d167830d17"
@@ -9754,14 +9749,6 @@ react-virtualized-auto-sizer@^1.0.2:
9749
resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.2.tgz#a61dd4f756458bbf63bd895a92379f9b70f803bd"
9750
integrity sha512-MYXhTY1BZpdJFjUovvYHVBmkq79szK/k7V3MO+36gJkWGkrXKtyr4vCPtpphaTLRAdDNoYEYFZWE8LjN+PIHNg==
9751
9757
-react-window@^1.8.0:
9758
- version "1.8.0"
9759
- resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.0.tgz#08196d1e0749fe60d0b29bb94ae682d37666e620"
9760
- integrity sha512-impIDEhm3+9/Y8ctiFaUI07a8Y/1jG0U4ONRUmYe7IsU+UQ2B0Ayyfbr+3R3nwAJpVGHx5pfI5SoDBt1o07YFw==
9761
- dependencies:
9762
- "@babel/runtime" "^7.0.0"
9763
- memoize-one ">=3.1.1 <6"
9764
-
9752
react@^0.0.0-50b50c26f:
9753
version "0.0.0-50b50c26f"
9754
resolved "https://registry.yarnpkg.com/react/-/react-0.0.0-50b50c26f.tgz#b782b579ce1f5d8bd696c5e45c744714ebecb111"