├── .babelrc
├── .gitignore
├── .travis.yml
├── LICENSE.md
├── README.md
├── README.v1.md
├── demo
├── dist
│ ├── app.js
│ ├── index.html
│ ├── react.js
│ └── virtualList.js
├── src
│ ├── ConfigurableExample.js
│ ├── app.js
│ └── index.html
└── webpack.config.babel.js
├── deploy-to-gh-pages.sh
├── jsconfig.json
├── lib
├── VirtualList.js
└── utils
│ ├── defaultMapVirtualToProps.js
│ ├── getElementTop.js
│ ├── getVisibleItemBounds.js
│ ├── throttleWithRAF.js
│ └── topFromWindow.js
├── package.json
└── src
├── VirtualList.js
├── __tests__
└── VirtualList.js
└── utils
├── __tests__
├── defaultMapVirtualToProps.js
├── getElementTop.js
├── getVisibleItemBounds.js
└── topFromWindow.js
├── defaultMapVirtualToProps.js
├── getElementTop.js
├── getVisibleItemBounds.js
├── throttleWithRAF.js
└── topFromWindow.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "es2015",
4 | "stage-0",
5 | "react"
6 | ]
7 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # node-waf configuration
20 | .lock-wscript
21 |
22 | # Compiled binary addons (http://nodejs.org/api/addons.html)
23 | build/Release
24 |
25 | # Dependency directory
26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
27 | node_modules
28 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js: stable
3 | after_success:
4 | bash ./deploy-to-gh-pages.sh
5 | env:
6 | global:
7 | secure: eel7PQWWJmM2gyxTCiUzv/4GYfDfKqrPTcEZOFYGgF0JkdgAqwowvnbw9B8Oexwhp8z/4hPwZNaeZnOAUlUekTJhpMItRcw6egyPyRxzgw2Uk1JC5JU6WVZdjjqQ4GJ+N6Spt56HGiEnTBtVAo2z1deah6s2Z9ZFnc/wqfz/Y/tE5NWE1ePD3cfqnf35yZ2jQkaOMPUS36inYRm+Fjc3IdCEH0OE/IsKYW00MLWlCyN/OkhElMW9kcjpzfpfdSjsyWNnAZF9BZykD053bh+R8gkKkFdyHzkA/w5wQoXAkRkz7ONkDOYXHNQK4VFwT0sl8+WU2tccmKFM9YGxnwLcBCF4ZUxoUNGaWsZsF9xlDZ0ZaV7/ySYyqpFZtfJvv42R1bx7wbIz8PVWqL2/Tl+HMU47X+L6ukDz3yZPFI/3Dcr0ksMU6/YmQR3yoBlTRyX7eJKjO3hiDHys1lFEsA6gCh9IU43a00msAHXOBJ171OL0SDn5qbeUhSS2LRnwXTBh5HZ9b5o7Zrj9nFtaL450kAXBoE5aulI+hAixce7tPNL7fLs+/WRKnYwxLyrjQ7aiv3NVJbZc3RkdheGVB8Wo15mAZZ6cJKCjChfJTPpIM92ZrFFi45dOa8KhVwll1+vqMv6P0fWXHXvBIItPMrGbMrGz0vzUvpePiEMhX2MjtO8=
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Dizzle
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.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [react-virtual-list](http://developerdizzle.github.io/react-virtual-list/) [](https://travis-ci.org/developerdizzle/react-virtual-list) [](https://bundlephobia.com/result?p=react-virtual-list)
2 |
3 |
4 | Super simple virtualized list [higher-order component](https://facebook.github.io/react/docs/higher-order-components.html) for [React](https://github.com/facebook/react) version `^15.0.0 || ^16.0.0`.
5 |
6 | [Check out the demo here](http://developerdizzle.github.io/react-virtual-list)
7 |
8 | `react-virtual-list` allows you to display a large list of fixed-height items, while only rendering the items visible on the screen. This allows a large list to be rendered with much fewer DOM elements.
9 |
10 | ### Some other benefits:
11 | * One dependency (and it's `prop-types`)
12 | * [Small!](https://bundlephobia.com/result?p=react-virtual-list)
13 | * Performant - demo page almost always stays over 60fps [http://i.imgur.com/CHVCK9x.png](http://i.imgur.com/CHVCK9x.png)
14 | * Keeps your components separate - as a higher-order component
15 | * Gives you control - doesn't force any particular markup, but gives you the necessary styles and data to use.
16 |
17 | ## Legacy
18 |
19 | If you're looking for documentation on version 1, supporting React `~0.13.x`, it's [here](README.v1.md).
20 |
21 | ## Installation
22 |
23 | You can use [npm](https://npmjs.org) to install [react-virtual-list](https://www.npmjs.com/package/react-virtual-list).
24 |
25 | ```console
26 | > npm install react-virtual-list --save
27 | ```
28 |
29 | ## Usage
30 |
31 | The `./lib/VirtualList.js` module exports a single, ES5-compatible, CommonJS-accessible, component factory.
32 |
33 | ```js
34 | import VirtualList from 'react-virtual-list';
35 | ```
36 |
37 | Your inner list component uses the `virtual` property to render the visible items, and set a style to set the overall list height and padding.
38 |
39 | ```js
40 | const MyList = ({
41 | virtual,
42 | itemHeight,
43 | }) => (
44 |
45 | {virtual.items.map(item => (
46 |
47 | Lorem ipsum dolor sit amet
48 |
49 | ))}
50 |
51 | );
52 | ```
53 |
54 | **Note:** You should set [keys](https://facebook.github.io/react/docs/lists-and-keys.html) on your list items.
55 |
56 | Create the virtualized component.
57 |
58 | ```js
59 | const MyVirtualList = VirtualList()(MyList);
60 | ```
61 |
62 | Write the JSX for the virtualized component with the necessary [properties](#properties).
63 |
64 | ```js
65 |
69 | ```
70 |
71 | #### Options
72 |
73 | Options are used before the virtualized component can be created. This means that if you need to change an option after the initial render, you will need to recreate the virtualized component.
74 |
75 | ```js
76 | const options = {
77 | container: this.refs.container, // use this scrollable element as a container
78 | initialState: {
79 | firstItemIndex: 0, // show first ten items
80 | lastItemIndex: 9, // during initial render
81 | },
82 | };
83 |
84 | const MyVirtualList = VirtualList(options)(MyList);
85 | ```
86 |
87 | Name | Type | Default | Description
88 | --- | --- | --- | ---
89 | `container` | DOM Element | window | Scrollable element that contains the list. Use this if you have a list inside an element with `overflow: scroll`.
90 | `initialState` | object | - | An object with `firstItemIndex` and `lastItemIndex` properties, which represent array indexes of `items` (see below). These are used to calculate the visible items before the component is mounted. Useful for server-side rendering.
91 |
92 | #### Properties
93 |
94 | These properties and any others set on your virtual component, such as `className`, will be passed down to the inner component.
95 |
96 | Name | Type | Default | Description
97 | --- | --- | --- | ---
98 | `items` | Array | - | Full array of list items. Only the visible subset of these will be rendered.
99 | `itemHeight` | Number | - | Height in pixels of a single item. **You must have a CSS rule that sets the height of each list item to this value.**
100 | `itemBuffer` | Number | 0 | Number of items that should be rendered before and after the visible viewport. Try using this if you have a complex list that suffers from a bit of lag when scrolling.
101 |
102 | #### Mapping
103 |
104 | `VirtualList` allows a second, optional, parameter, named `mapVirtualToProps`, which functions similarly to [Redux's `mapStateToProps`](https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options). This function can be provided to change the properties passed to `MyList`. Its arguments are:
105 |
106 | Name | Description
107 | --- | ---
108 | `props` | Includes all properties passed to `MyVirtualList`
109 | `state` | Includes `firstItemIndex` and `lastItemIndex`; array indexes of the visible bounds of `items`
110 |
111 | The default `mapVirtualToProps` can be found [here](/src/utils/defaultMapVirtualToProps.js).
112 |
113 | #### Example Usage
114 |
115 | Check out [demo/src/app.js](demo/src/app.js) and [demo/src/ConfigurableExample.js](demo/src/ConfigurableExample.js) for the example used in the [demo](http://developerdizzle.github.io/react-virtual-list).
116 |
117 | ## Tests
118 |
119 | Use `npm test` to run the tests using [Jest](https://github.com/facebook/jest). Not everything is currently tested yet!
120 |
--------------------------------------------------------------------------------
/README.v1.md:
--------------------------------------------------------------------------------
1 | # [react-virtual-list](http://developerdizzle.github.io/react-virtual-list/) [](https://travis-ci.org/developerdizzle/react-virtual-list)
2 | # Legacy (version 1)
3 |
4 | Super simple virtualized list [React](https://github.com/facebook/react) component
5 |
6 | [Check out the demo here](http://developerdizzle.github.io/react-virtual-list)
7 |
8 | This React component allows you to display a large list of fixed-height items in your document, while only rendering the items visible in the viewport. This allows a large list to be rendered with much fewer DOM elements.
9 |
10 | ## Installation
11 |
12 | You can use NPM to install react-virtual-list:
13 |
14 | ```console
15 | $ npm install react-virtual-list --save
16 | ```
17 |
18 | ## Usage
19 |
20 | The `./dist/VirtualList.js` module exports a single React component.
21 |
22 | ```
23 | var VirtualList = require('react-virtual-list');
24 | ```
25 |
26 | #### JSX
27 |
28 | ```
29 |
30 | ```
31 |
32 | #### Properties
33 |
34 | * `items` the full array of list items. Only the visible subset of these will be rendered.
35 | * `renderItem` a function to render a single item, passed as argument `item`. Must return a single React element (`React.createElement(...)`)
36 | * `itemHeight` the height in pixels of a single item. **You must have a CSS rule that sets the height of each list item to this value.**
37 | * `container` the scrollable element that contains the list. Defaults to `window`. Use this if you have a list inside an element with `overflow: scroll`.
38 | * `tagName` the tagName for the root element that surrounds the items rendered by renderItem. Defaults to `div`. Use this if you want to render a list with `ul` and `li`, or any other elements.
39 | * `scrollDelay` the delay in milliseconds after scroll to recalculate. Defaults to `0`. Can be used to throttle recalculation.
40 | * `itemBuffer` the number of items that should be rendered before and after the visible viewport. Defaults to `0`.
41 |
42 | Any other properties set on `VirtualList`, such as `className`, will be reflected on the component's root element.
43 |
44 | #### Functions
45 |
46 | * `visibleItems` the currently visible array of items. Can be used to figure out which items are in the viewport. Eg: `var items = this.refs.list.visibleItems()`
47 |
48 | #### Example Usage
49 |
50 | Check out [https://github.com/developerdizzle/react-virtual-list/blob/gh-pages/App.jsx](https://github.com/developerdizzle/react-virtual-list/blob/gh-pages/App.jsx) for the example used in the demo.
51 |
52 | ## Tests
53 |
54 | Use `npm test` to run the tests using [jasmine-node](https://github.com/mhevery/jasmine-node). Currently only the math calculations are tested. Hoping to add some DOM tests as well.
55 |
56 | ## To Do
57 |
58 | * ES6/2015
59 | * [Known issue with mobile scroll event](https://github.com/developerdizzle/react-virtual-list/issues/1)
--------------------------------------------------------------------------------
/demo/dist/app.js:
--------------------------------------------------------------------------------
1 | webpackJsonp([2],[function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}var a=n(1),r=i(a),o=n(2),l=n(7),s=i(l);n(31);var u=function(e){var t=e.virtual,n=e.itemHeight;return r.default.createElement("ul",{className:"media-list list-group",style:t.style},t.items.map(function(e){return r.default.createElement("li",{key:"item"+e.id,className:"list-group-item",style:{height:n}},r.default.createElement("div",{className:"media-left"},r.default.createElement("img",{className:"media-object",src:"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIHZpZXdCb3g9IjAgMCA2NCA2NCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+PGRlZnMvPjxyZWN0IHdpZHRoPSI2NCIgaGVpZ2h0PSI2NCIgZmlsbD0iI0VFRUVFRSIvPjxnPjx0ZXh0IHg9IjEzLjQ2ODc1IiB5PSIzMiIgc3R5bGU9ImZpbGw6I0FBQUFBQTtmb250LXdlaWdodDpib2xkO2ZvbnQtZmFtaWx5OkFyaWFsLCBIZWx2ZXRpY2EsIE9wZW4gU2Fucywgc2Fucy1zZXJpZiwgbW9ub3NwYWNlO2ZvbnQtc2l6ZToxMHB0O2RvbWluYW50LWJhc2VsaW5lOmNlbnRyYWwiPjY0eDY0PC90ZXh0PjwvZz48L3N2Zz4="})),r.default.createElement("div",{className:"media-body"},r.default.createElement("h4",{className:"media-heading"},e.title),r.default.createElement("p",null,e.text)))}))},c=(0,s.default)(u);(0,o.render)(r.default.createElement(c,null),document.getElementById("app"))},,,,,,,function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function a(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function o(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var l=function(){function e(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:I.default;return function(n){var i,f;return f=i=function(i){function u(t){a(this,u);var n=r(this,(u.__proto__||Object.getPrototypeOf(u)).call(this,t));return n._isMounted=!1,n.options=l({container:"undefined"!=typeof window?window:void 0},e),n.state={firstItemIndex:0,lastItemIndex:-1},e&&e.initialState&&(n.state=l({},n.state,e.initialState)),n.refreshState=n.refreshState.bind(n),"undefined"!=typeof window&&"requestAnimationFrame"in window&&(n.refreshState=(0,g.default)(n.refreshState)),n}return o(u,i),s(u,[{key:"setStateIfNeeded",value:function(e,t,n,i,a){var r=(0,v.default)(e,t,n,i,a);void 0!==r&&(r.firstItemIndex>r.lastItemIndex||r.firstItemIndex===this.state.firstItemIndex&&r.lastItemIndex===this.state.lastItemIndex||this.setState(r))}},{key:"refreshState",value:function(){if(this._isMounted){var e=this.props,t=e.itemHeight,n=e.items,i=e.itemBuffer;this.setStateIfNeeded(this.domNode,this.options.container,n,t,i)}}},{key:"componentWillMount",value:function(){this._isMounted=!0}},{key:"componentDidMount",value:function(){this.domNode=m.default.findDOMNode(this),this.refreshState(),this.options.container.addEventListener("scroll",this.refreshState),this.options.container.addEventListener("resize",this.refreshState)}},{key:"componentWillUnmount",value:function(){this._isMounted=!1,this.options.container.removeEventListener("scroll",this.refreshState),this.options.container.removeEventListener("resize",this.refreshState)}},{key:"componentWillReceiveProps",value:function(e){var t=e.itemHeight,n=e.items,i=e.itemBuffer;this.setStateIfNeeded(this.domNode,this.options.container,n,t,i)}},{key:"render",value:function(){return c.default.createElement(n,l({},this.props,t(this.props,this.state)))}}]),u}(u.PureComponent),i.propTypes={items:h.default.array.isRequired,itemHeight:h.default.number.isRequired,itemBuffer:h.default.number},i.defaultProps={itemBuffer:0},f}};t.default=E},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(e,t){var n=e.items,i=e.itemHeight,a=t.firstItemIndex,r=t.lastItemIndex,o=r>-1?n.slice(a,r+1):[],l=n.length*i,s=a*i;return{virtual:{items:o,style:{height:l,paddingTop:s,boxSizing:"border-box"}}}};t.default=n},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(e){return e.pageYOffset?e.pageYOffset:e.document?e.document.documentElement&&e.document.documentElement.scrollTop?e.document.documentElement.scrollTop:e.document.body&&e.document.body.scrollTop?e.document.body.scrollTop:0:e.scrollY||e.scrollTop||0};t.default=n},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(30),r=i(a),o=n(27),l=i(o),s=function(e,t,n,i,a){if(t&&i&&n&&0!==n.length){var o=t.innerHeight,s=t.clientHeight,u=o||s;if(u){var c=(0,l.default)(t),f=c+u,m=(0,r.default)(e)-(0,r.default)(t),d=i*n.length,h=Math.max(0,c-m),p=Math.max(0,Math.min(d,f-m)),v=Math.max(0,Math.floor(h/i)-a),b=Math.min(n.length,Math.ceil(p/i)+a)-1;return{firstItemIndex:v,lastItemIndex:b}}}};t.default=s},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=arguments;t.default=function(e){var t=!1;return function(){t||(t=!0,window.requestAnimationFrame(function(){e.apply(void 0,n),t=!1}))}}},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function e(t){return"undefined"!=typeof t&&t?(t.offsetTop||0)+e(t.offsetParent):0};t.default=n},function(e,t,n){e.exports=n.p+"index.html"}]);
--------------------------------------------------------------------------------
/demo/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
15 |
16 |
17 |
18 | React Virtual List
19 |
20 |
21 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/demo/dist/react.js:
--------------------------------------------------------------------------------
1 | !function(e){function t(n){if(r[n])return r[n].exports;var o=r[n]={exports:{},id:n,loaded:!1};return e[n].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n=window.webpackJsonp;window.webpackJsonp=function(a,i){for(var l,u,c=0,s=[];cthis.eventPool.length&&this.eventPool.push(e)}function L(e){e.eventPool=[],e.getPooled=M,e.release=U}function z(e,t){switch(e){case"topKeyUp":return-1!==Bn.indexOf(t.keyCode);case"topKeyDown":return 229!==t.keyCode;case"topKeyPress":case"topMouseDown":case"topBlur":return!0;default:return!1}}function A(e){return e=e.detail,"object"===("undefined"==typeof e?"undefined":cn(e))&&"data"in e?e.data:null}function H(e,t){switch(e){case"topCompositionEnd":return A(t);case"topKeyPress":return 32!==t.which?null:(Yn=!0,qn);case"topTextInput":return e=t.data,e===qn&&Yn?null:e;default:return null}}function j(e,t){if(Xn)return"topCompositionEnd"===e||!Wn&&z(e,t)?(e=F(),zn._root=null,zn._startText=null,zn._fallbackText=null,Xn=!1,e):null;switch(e){case"topPaste":return null;case"topKeyPress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1t}return!1}function ce(e,t,n,r,o){this.acceptsBooleans=2===t||3===t||4===t,this.attributeName=r,this.attributeNamespace=o,this.mustUseProperty=n,this.propertyName=e,this.type=t}function se(e){return e[1].toUpperCase()}function fe(e,t,n,r){var o=xr.hasOwnProperty(t)?xr[t]:null,a=null!==o?0===o.type:!r&&(2qr.length&&qr.push(e)}}}function Ke(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit"+e]="webkit"+t,n["Moz"+e]="moz"+t,n["ms"+e]="MS"+t,n["O"+e]="o"+t.toLowerCase(),n}function Qe(e){if(Jr[e])return Jr[e];if(!Xr[e])return e;var t,n=Xr[e];for(t in n)if(n.hasOwnProperty(t)&&t in Zr)return Jr[e]=n[t];return e}function $e(e){return Object.prototype.hasOwnProperty.call(e,oo)||(e[oo]=ro++,no[e[oo]]={}),no[e[oo]]}function qe(e){for(;e&&e.firstChild;)e=e.firstChild;return e}function Ge(e,t){var n=qe(e);e=0;for(var r;n;){if(3===n.nodeType){if(r=e+n.textContent.length,e<=t&&r>=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=qe(n)}}function Ye(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&("input"===t&&"text"===e.type||"textarea"===t||"true"===e.contentEditable)}function Xe(e,t){if(so||null==lo||lo!==hn())return null;var n=lo;return"selectionStart"in n&&Ye(n)?n={start:n.selectionStart,end:n.selectionEnd}:window.getSelection?(n=window.getSelection(),n={anchorNode:n.anchorNode,anchorOffset:n.anchorOffset,focusNode:n.focusNode,focusOffset:n.focusOffset}):n=void 0,co&&mn(co,n)?null:(co=n,e=R.getPooled(io.select,uo,e,t),e.type="select",e.target=lo,N(e),e)}function Je(e,t,n,r){this.tag=e,this.key=n,this.stateNode=this.type=null,this.sibling=this.child=this.return=null,this.index=0,this.ref=null,this.pendingProps=t,this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.effectTag=0,this.lastEffect=this.firstEffect=this.nextEffect=null,this.expirationTime=0,this.alternate=null}function Ze(e,t,n){var r=e.alternate;return null===r?(r=new Je(e.tag,t,e.key,e.mode),r.type=e.type,r.stateNode=e.stateNode,r.alternate=e,e.alternate=r):(r.pendingProps=t,r.effectTag=0,r.nextEffect=null,r.firstEffect=null,r.lastEffect=null),r.expirationTime=n,r.child=e.child,r.memoizedProps=e.memoizedProps,r.memoizedState=e.memoizedState,r.updateQueue=e.updateQueue,r.sibling=e.sibling,r.index=e.index,r.ref=e.ref,r}function et(e,t,n){var o=e.type,a=e.key;e=e.props;var i=void 0;if("function"==typeof o)i=o.prototype&&o.prototype.isReactComponent?2:0;else if("string"==typeof o)i=5;else switch(o){case dr:return tt(e.children,t,n,a);case vr:i=11,t|=3;break;case pr:i=11,t|=2;break;case cr:i=7;break;case sr:i=9;break;default:if("object"===("undefined"==typeof o?"undefined":cn(o))&&null!==o)switch(o.$$typeof){case hr:i=13;break;case mr:i=12;break;case yr:i=14;break;default:if("number"==typeof o.tag)return t=o,t.pendingProps=e,t.expirationTime=n,t;r("130",null==o?o:"undefined"==typeof o?"undefined":cn(o),"")}else r("130",null==o?o:"undefined"==typeof o?"undefined":cn(o),"")}return t=new Je(i,e,a,t),t.type=o,t.expirationTime=n,t}function tt(e,t,n,r){return e=new Je(10,e,r,t),e.expirationTime=n,e}function nt(e,t,n){return e=new Je(6,e,null,t),e.expirationTime=n,e}function rt(e,t,n){return t=new Je(4,null!==e.children?e.children:[],e.key,t),t.expirationTime=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function ot(e){return function(t){try{return e(t)}catch(e){}}}function at(e){if("undefined"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__)return!1;var t=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(t.isDisabled||!t.supportsFiber)return!0;try{var n=t.inject(e);po=ot(function(e){return t.onCommitFiberRoot(n,e)}),ho=ot(function(e){return t.onCommitFiberUnmount(n,e)})}catch(e){}return!0}function it(e){"function"==typeof po&&po(e)}function lt(e){"function"==typeof ho&&ho(e)}function ut(e){return{baseState:e,expirationTime:0,first:null,last:null,callbackList:null,hasForceUpdate:!1,isInitialized:!1,capturedValues:null}}function ct(e,t){null===e.last?e.first=e.last=t:(e.last.next=t,e.last=t),(0===e.expirationTime||e.expirationTime>t.expirationTime)&&(e.expirationTime=t.expirationTime)}function st(e){mo=vo=null;var t=e.alternate,n=e.updateQueue;null===n&&(n=e.updateQueue=ut(null)),null!==t?(e=t.updateQueue,null===e&&(e=t.updateQueue=ut(null))):e=null,mo=n,vo=e!==n?e:null}function ft(e,t){st(e),e=mo;var n=vo;null===n?ct(e,t):null===e.last||null===n.last?(ct(e,t),ct(n,t)):(ct(e,t),n.last=t)}function dt(e,t,n,r){return e=e.partialState,"function"==typeof e?e.call(t,n,r):e}function pt(e,t,n,r,o,a){null!==e&&e.updateQueue===n&&(n=t.updateQueue={baseState:n.baseState,expirationTime:n.expirationTime,first:n.first,last:n.last,isInitialized:n.isInitialized,capturedValues:n.capturedValues,callbackList:null,hasForceUpdate:!1}),n.expirationTime=0,n.isInitialized?e=n.baseState:(e=n.baseState=t.memoizedState,n.isInitialized=!0);for(var i=!0,l=n.first,u=!1;null!==l;){var c=l.expirationTime;if(c>a){var s=n.expirationTime;(0===s||s>c)&&(n.expirationTime=c),u||(u=!0,n.baseState=e)}else u||(n.first=l.next,null===n.first&&(n.last=null)),l.isReplace?(e=dt(l,r,e,o),i=!0):(c=dt(l,r,e,o))&&(e=i?dn({},e,c):dn(e,c),i=!1),l.isForced&&(n.hasForceUpdate=!0),null!==l.callback&&(c=n.callbackList,null===c&&(c=n.callbackList=[]),c.push(l)),null!==l.capturedValue&&(c=n.capturedValues,null===c?n.capturedValues=[l.capturedValue]:c.push(l.capturedValue));l=l.next}return null!==n.callbackList?t.effectTag|=32:null!==n.first||n.hasForceUpdate||null!==n.capturedValues||(t.updateQueue=null),u||(n.baseState=e),e}function ht(e,t){var n=e.callbackList;if(null!==n)for(e.callbackList=null,e=0;em?(v=f,f=null):v=f.sibling;var y=p(r,f,l[m],u);if(null===y){null===f&&(f=v);break}e&&f&&null===y.alternate&&t(r,f),a=i(y,a,m),null===s?c=y:s.sibling=y,s=y,f=v}if(m===l.length)return n(r,f),c;if(null===f){for(;mv?(y=m,m=null):y=m.sibling;var b=p(a,m,g.value,c);if(null===b){m||(m=y);break}e&&m&&null===b.alternate&&t(a,m),l=i(b,l,v),null===f?s=b:f.sibling=b,f=b,m=y}if(g.done)return n(a,m),s;if(null===m){for(;!g.done;v++,g=u.next())g=d(a,g.value,c),null!==g&&(l=i(g,l,v),null===f?s=g:f.sibling=g,f=g);return s}for(m=o(a,m);!g.done;v++,g=u.next())g=h(m,a,v,g.value,c),null!==g&&(e&&null!==g.alternate&&m.delete(null===g.key?v:g.key),l=i(g,l,v),null===f?s=g:f.sibling=g,f=g);return e&&m.forEach(function(e){return t(a,e)}),s}return function(e,o,i,u){"object"===("undefined"==typeof i?"undefined":cn(i))&&null!==i&&i.type===dr&&null===i.key&&(i=i.props.children);var c="object"===("undefined"==typeof i?"undefined":cn(i))&&null!==i;if(c)switch(i.$$typeof){case ur:e:{var s=i.key;for(c=o;null!==c;){if(c.key===s){if(10===c.tag?i.type===dr:c.type===i.type){n(e,c.sibling),o=a(c,i.type===dr?i.props.children:i.props,u),o.ref=vt(e,c,i),o.return=e,e=o;break e}n(e,c);break}t(e,c),c=c.sibling}i.type===dr?(o=tt(i.props.children,e.mode,u,i.key),o.return=e,e=o):(u=et(i,e.mode,u),u.ref=vt(e,o,i),u.return=e,e=u)}return l(e);case fr:e:{for(c=i.key;null!==o;){if(o.key===c){if(4===o.tag&&o.stateNode.containerInfo===i.containerInfo&&o.stateNode.implementation===i.implementation){n(e,o.sibling),o=a(o,i.children||[],u),o.return=e,e=o;break e}n(e,o);break}t(e,o),o=o.sibling}o=rt(i,e.mode,u),o.return=e,e=o}return l(e)}if("string"==typeof i||"number"==typeof i)return i=""+i,null!==o&&6===o.tag?(n(e,o.sibling),o=a(o,i,u)):(n(e,o),o=nt(i,e.mode,u)),o.return=e,e=o,l(e);if(yo(i))return m(e,o,i,u);if(re(i))return v(e,o,i,u);if(c&&yt(e,i),"undefined"==typeof i)switch(e.tag){case 2:case 1:u=e.type,r("152",u.displayName||u.name||"Component")}return n(e,o)}}function bt(e,t,n,o,a,i,l){function u(e,t,n){c(e,t,n,t.expirationTime)}function c(e,t,n,r){t.child=null===e?bo(t,null,n,r):go(t,e.child,n,r)}function s(e,t){var n=t.ref;(null===e&&null!==n||null!==e&&e.ref!==n)&&(t.effectTag|=128)}function f(e,t,n,r,o,a){if(s(e,t),!n&&!o)return r&&E(t,!1),m(e,t);n=t.stateNode,ir.current=t;var i=o?null:n.render();return t.effectTag|=1,o&&(c(e,t,null,a),t.child=null),c(e,t,i,a),t.memoizedState=n.state,t.memoizedProps=n.props,r&&E(t,!0),t.child}function d(e){var t=e.stateNode;t.pendingContext?S(e,t.pendingContext,t.pendingContext!==t.context):t.context&&S(e,t.context,!1),b(e,t.containerInfo)}function p(e,t,n,r){var o=e.child;for(null!==o&&(o.return=e);null!==o;){switch(o.tag){case 12:var a=0|o.stateNode;if(o.type===t&&0!==(a&n)){for(a=o;null!==a;){var i=a.alternate;
15 | if(0===a.expirationTime||a.expirationTime>r)a.expirationTime=r,null!==i&&(0===i.expirationTime||i.expirationTime>r)&&(i.expirationTime=r);else{if(null===i||!(0===i.expirationTime||i.expirationTime>r))break;i.expirationTime=r}a=a.return}a=null}else a=o.child;break;case 13:a=o.type===e.type?null:o.child;break;default:a=o.child}if(null!==a)a.return=o;else for(a=o;null!==a;){if(a===e){a=null;break}if(o=a.sibling,null!==o){a=o;break}a=a.return}o=a}}function h(e,t,n){var r=t.type._context,o=t.pendingProps,a=t.memoizedProps;if(!w()&&a===o)return t.stateNode=0,C(t),m(e,t);var i=o.value;if(t.memoizedProps=o,null===a)i=1073741823;else if(a.value===o.value){if(a.children===o.children)return t.stateNode=0,C(t),m(e,t);i=0}else{var l=a.value;if(l===i&&(0!==l||1/l===1/i)||l!==l&&i!==i){if(a.children===o.children)return t.stateNode=0,C(t),m(e,t);i=0}else if(i="function"==typeof r._calculateChangedBits?r._calculateChangedBits(l,i):1073741823,i|=0,0===i){if(a.children===o.children)return t.stateNode=0,C(t),m(e,t)}else p(t,r,i,n)}return t.stateNode=i,C(t),u(e,t,o.children),t.child}function m(e,t){if(null!==e&&t.child!==e.child?r("153"):void 0,null!==t.child){e=t.child;var n=Ze(e,e.pendingProps,e.expirationTime);for(t.child=n,n.return=t;null!==e.sibling;)e=e.sibling,n=n.sibling=Ze(e,e.pendingProps,e.expirationTime),n.return=t;n.sibling=null}return t.child}var v=e.shouldSetTextContent,y=e.shouldDeprioritizeSubtree,g=t.pushHostContext,b=t.pushHostContainer,C=o.pushProvider,k=n.getMaskedContext,x=n.getUnmaskedContext,w=n.hasContextChanged,T=n.pushContextProvider,S=n.pushTopLevelContextObject,E=n.invalidateContextProvider,_=a.enterHydrationState,P=a.resetHydrationState,N=a.tryToClaimNextHydratableInstance;e=mt(n,i,l,function(e,t){e.memoizedProps=t},function(e,t){e.memoizedState=t});var I=e.adoptClassInstance,O=e.callGetDerivedStateFromProps,F=e.constructClassInstance,D=e.mountClassInstance,R=e.resumeMountClassInstance,M=e.updateClassInstance;return{beginWork:function(e,t,n){if(0===t.expirationTime||t.expirationTime>n){switch(t.tag){case 3:d(t);break;case 2:T(t);break;case 4:b(t,t.stateNode.containerInfo);break;case 13:C(t)}return null}switch(t.tag){case 0:null!==e?r("155"):void 0;var o=t.type,a=t.pendingProps,i=x(t);return i=k(t,i),o=o(a,i),t.effectTag|=1,"object"===("undefined"==typeof o?"undefined":cn(o))&&null!==o&&"function"==typeof o.render&&void 0===o.$$typeof?(i=t.type,t.tag=2,t.memoizedState=null!==o.state&&void 0!==o.state?o.state:null,"function"==typeof i.getDerivedStateFromProps&&(a=O(t,o,a,t.memoizedState),null!==a&&void 0!==a&&(t.memoizedState=dn({},t.memoizedState,a))),a=T(t),I(t,o),D(t,n),e=f(e,t,!0,a,!1,n)):(t.tag=1,u(e,t,o),t.memoizedProps=a,e=t.child),e;case 1:return a=t.type,n=t.pendingProps,w()||t.memoizedProps!==n?(o=x(t),o=k(t,o),a=a(n,o),t.effectTag|=1,u(e,t,a),t.memoizedProps=n,e=t.child):e=m(e,t),e;case 2:a=T(t),null===e?null===t.stateNode?(F(t,t.pendingProps),D(t,n),o=!0):o=R(t,n):o=M(e,t,n),i=!1;var l=t.updateQueue;return null!==l&&null!==l.capturedValues&&(i=o=!0),f(e,t,o,a,i,n);case 3:e:if(d(t),o=t.updateQueue,null!==o){if(i=t.memoizedState,a=pt(e,t,o,null,null,n),t.memoizedState=a,o=t.updateQueue,null!==o&&null!==o.capturedValues)o=null;else{if(i===a){P(),e=m(e,t);break e}o=a.element}i=t.stateNode,(null===e||null===e.child)&&i.hydrate&&_(t)?(t.effectTag|=2,t.child=bo(t,null,o,n)):(P(),u(e,t,o)),t.memoizedState=a,e=t.child}else P(),e=m(e,t);return e;case 5:return g(t),null===e&&N(t),a=t.type,l=t.memoizedProps,o=t.pendingProps,i=null!==e?e.memoizedProps:null,w()||l!==o||((l=1&t.mode&&y(a,o))&&(t.expirationTime=1073741823),l&&1073741823===n)?(l=o.children,v(a,o)?l=null:i&&v(a,i)&&(t.effectTag|=16),s(e,t),1073741823!==n&&1&t.mode&&y(a,o)?(t.expirationTime=1073741823,t.memoizedProps=o,e=null):(u(e,t,l),t.memoizedProps=o,e=t.child)):e=m(e,t),e;case 6:return null===e&&N(t),t.memoizedProps=t.pendingProps,null;case 8:t.tag=7;case 7:return a=t.pendingProps,w()||t.memoizedProps!==a||(a=t.memoizedProps),o=a.children,t.stateNode=null===e?bo(t,t.stateNode,o,n):go(t,e.stateNode,o,n),t.memoizedProps=a,t.stateNode;case 9:return null;case 4:return b(t,t.stateNode.containerInfo),a=t.pendingProps,w()||t.memoizedProps!==a?(null===e?t.child=go(t,null,a,n):u(e,t,a),t.memoizedProps=a,e=t.child):e=m(e,t),e;case 14:return n=t.type.render,n=n(t.pendingProps,t.ref),u(e,t,n),t.memoizedProps=n,t.child;case 10:return n=t.pendingProps,w()||t.memoizedProps!==n?(u(e,t,n),t.memoizedProps=n,e=t.child):e=m(e,t),e;case 11:return n=t.pendingProps.children,w()||null!==n&&t.memoizedProps!==n?(u(e,t,n),t.memoizedProps=n,e=t.child):e=m(e,t),e;case 13:return h(e,t,n);case 12:o=t.type,i=t.pendingProps;var c=t.memoizedProps;return a=o._currentValue,l=o._changedBits,w()||0!==l||c!==i?(t.memoizedProps=i,c=i.unstable_observedBits,void 0!==c&&null!==c||(c=1073741823),t.stateNode=c,0!==(l&c)&&p(t,o,l,n),n=i.children,n=n(a),u(e,t,n),e=t.child):e=m(e,t),e;default:r("156")}}}}function Ct(e,t,n,o,a){function i(e){e.effectTag|=4}var l=e.createInstance,u=e.createTextInstance,c=e.appendInitialChild,s=e.finalizeInitialChildren,f=e.prepareUpdate,d=e.persistence,p=t.getRootHostContainer,h=t.popHostContext,m=t.getHostContext,v=t.popHostContainer,y=n.popContextProvider,g=n.popTopLevelContextObject,b=o.popProvider,C=a.prepareToHydrateHostInstance,k=a.prepareToHydrateHostTextInstance,x=a.popHydrationState,w=void 0,T=void 0,S=void 0;return e.mutation?(w=function(){},T=function(e,t,n){(t.updateQueue=n)&&i(t)},S=function(e,t,n,r){n!==r&&i(t)}):r(d?"235":"236"),{completeWork:function(e,t,n){var o=t.pendingProps;switch(t.tag){case 1:return null;case 2:return y(t),e=t.stateNode,o=t.updateQueue,null!==o&&null!==o.capturedValues&&(t.effectTag&=-65,"function"==typeof e.componentDidCatch?t.effectTag|=256:o.capturedValues=null),null;case 3:return v(t),g(t),o=t.stateNode,o.pendingContext&&(o.context=o.pendingContext,o.pendingContext=null),null!==e&&null!==e.child||(x(t),t.effectTag&=-3),w(t),e=t.updateQueue,null!==e&&null!==e.capturedValues&&(t.effectTag|=256),null;case 5:h(t),n=p();var a=t.type;if(null!==e&&null!=t.stateNode){var d=e.memoizedProps,E=t.stateNode,_=m();E=f(E,a,d,o,n,_),T(e,t,E,a,d,o,n,_),e.ref!==t.ref&&(t.effectTag|=128)}else{if(!o)return null===t.stateNode?r("166"):void 0,null;if(e=m(),x(t))C(t,n,e)&&i(t);else{d=l(a,o,n,e,t);e:for(_=t.child;null!==_;){if(5===_.tag||6===_.tag)c(d,_.stateNode);else if(4!==_.tag&&null!==_.child){_.child.return=_,_=_.child;continue}if(_===t)break;for(;null===_.sibling;){if(null===_.return||_.return===t)break e;_=_.return}_.sibling.return=_.return,_=_.sibling}s(d,a,o,n,e)&&i(t),t.stateNode=d}null!==t.ref&&(t.effectTag|=128)}return null;case 6:if(e&&null!=t.stateNode)S(e,t,e.memoizedProps,o);else{if("string"!=typeof o)return null===t.stateNode?r("166"):void 0,null;e=p(),n=m(),x(t)?k(t)&&i(t):t.stateNode=u(o,e,n,t)}return null;case 7:(o=t.memoizedProps)?void 0:r("165"),t.tag=8,a=[];e:for((d=t.stateNode)&&(d.return=t);null!==d;){if(5===d.tag||6===d.tag||4===d.tag)r("247");else if(9===d.tag)a.push(d.pendingProps.value);else if(null!==d.child){d.child.return=d,d=d.child;continue}for(;null===d.sibling;){if(null===d.return||d.return===t)break e;d=d.return}d.sibling.return=d.return,d=d.sibling}return d=o.handler,o=d(o.props,a),t.child=go(t,null!==e?e.child:null,o,n),t.child;case 8:return t.tag=7,null;case 9:return null;case 14:return null;case 10:return null;case 11:return null;case 4:return v(t),w(t),null;case 13:return b(t),null;case 12:return null;case 0:r("167");default:r("156")}}}}function kt(e,t,n,r,o){var a=e.popHostContainer,i=e.popHostContext,l=t.popContextProvider,u=t.popTopLevelContextObject,c=n.popProvider;return{throwException:function(e,t,n){t.effectTag|=512,t.firstEffect=t.lastEffect=null,t={value:n,source:t,stack:ae(t)};do{switch(e.tag){case 3:return st(e),e.updateQueue.capturedValues=[t],void(e.effectTag|=1024);case 2:if(n=e.stateNode,0===(64&e.effectTag)&&null!==n&&"function"==typeof n.componentDidCatch&&!o(n)){st(e),n=e.updateQueue;var r=n.capturedValues;return null===r?n.capturedValues=[t]:r.push(t),void(e.effectTag|=1024)}}e=e.return}while(null!==e)},unwindWork:function(e){switch(e.tag){case 2:l(e);var t=e.effectTag;return 1024&t?(e.effectTag=t&-1025|64,e):null;case 3:return a(e),u(e),t=e.effectTag,1024&t?(e.effectTag=t&-1025|64,e):null;case 5:return i(e),null;case 4:return a(e),null;case 13:return c(e),null;default:return null}},unwindInterruptedWork:function(e){switch(e.tag){case 2:l(e);break;case 3:a(e),u(e);break;case 5:i(e);break;case 4:a(e);break;case 13:c(e)}}}}function xt(e,t){var n=t.source;null===t.stack&&ae(n),null!==n&&oe(n),t=t.value,null!==e&&2===e.tag&&oe(e);try{t&&t.suppressReactErrorLogging||console.error(t)}catch(e){e&&e.suppressReactErrorLogging||console.error(e)}}function wt(e,t,n,o,a){function i(e){var n=e.ref;if(null!==n)if("function"==typeof n)try{n(null)}catch(n){t(e,n)}else n.current=null}function l(e){switch("function"==typeof lt&<(e),e.tag){case 2:i(e);var n=e.stateNode;if("function"==typeof n.componentWillUnmount)try{n.props=e.memoizedProps,n.state=e.memoizedState,n.componentWillUnmount()}catch(n){t(e,n)}break;case 5:i(e);break;case 7:u(e.stateNode);break;case 4:d&&s(e)}}function u(e){for(var t=e;;)if(l(t),null===t.child||d&&4===t.tag){if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return;t=t.return}t.sibling.return=t.return,t=t.sibling}else t.child.return=t,t=t.child}function c(e){return 5===e.tag||3===e.tag||4===e.tag}function s(e){for(var t=e,n=!1,o=void 0,a=void 0;;){if(!n){n=t.return;e:for(;;){switch(null===n?r("160"):void 0,n.tag){case 5:o=n.stateNode,a=!1;break e;case 3:o=n.stateNode.containerInfo,a=!0;break e;case 4:o=n.stateNode.containerInfo,a=!0;break e}n=n.return}n=!0}if(5===t.tag||6===t.tag)u(t),a?x(o,t.stateNode):k(o,t.stateNode);else if(4===t.tag?o=t.stateNode.containerInfo:l(t),null!==t.child){t.child.return=t,t=t.child;continue}if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return;t=t.return,4===t.tag&&(n=!1)}t.sibling.return=t.return,t=t.sibling}}var f=e.getPublicInstance,d=e.mutation;e=e.persistence,d||r(e?"235":"236");var p=d.commitMount,h=d.commitUpdate,m=d.resetTextContent,v=d.commitTextUpdate,y=d.appendChild,g=d.appendChildToContainer,b=d.insertBefore,C=d.insertInContainerBefore,k=d.removeChild,x=d.removeChildFromContainer;return{commitBeforeMutationLifeCycles:function(e,t){switch(t.tag){case 2:if(2048&t.effectTag&&null!==e){var n=e.memoizedProps,o=e.memoizedState;e=t.stateNode,e.props=t.memoizedProps,e.state=t.memoizedState,t=e.getSnapshotBeforeUpdate(n,o),e.__reactInternalSnapshotBeforeUpdate=t}break;case 3:case 5:case 6:case 4:break;default:r("163")}},commitResetTextContent:function(e){m(e.stateNode)},commitPlacement:function(e){e:{for(var t=e.return;null!==t;){if(c(t)){var n=t;break e}t=t.return}r("160"),n=void 0}var o=t=void 0;switch(n.tag){case 5:t=n.stateNode,o=!1;break;case 3:t=n.stateNode.containerInfo,o=!0;break;case 4:t=n.stateNode.containerInfo,o=!0;break;default:r("161")}16&n.effectTag&&(m(t),n.effectTag&=-17);e:t:for(n=e;;){for(;null===n.sibling;){if(null===n.return||c(n.return)){n=null;break e}n=n.return}for(n.sibling.return=n.return,n=n.sibling;5!==n.tag&&6!==n.tag;){if(2&n.effectTag)continue t;if(null===n.child||4===n.tag)continue t;n.child.return=n,n=n.child}if(!(2&n.effectTag)){n=n.stateNode;break e}}for(var a=e;;){if(5===a.tag||6===a.tag)n?o?C(t,a.stateNode,n):b(t,a.stateNode,n):o?g(t,a.stateNode):y(t,a.stateNode);else if(4!==a.tag&&null!==a.child){a.child.return=a,a=a.child;continue}if(a===e)break;for(;null===a.sibling;){if(null===a.return||a.return===e)return;a=a.return}a.sibling.return=a.return,a=a.sibling}},commitDeletion:function(e){s(e),e.return=null,e.child=null,e.alternate&&(e.alternate.child=null,e.alternate.return=null)},commitWork:function(e,t){switch(t.tag){case 2:break;case 5:var n=t.stateNode;if(null!=n){var o=t.memoizedProps;e=null!==e?e.memoizedProps:o;var a=t.type,i=t.updateQueue;t.updateQueue=null,null!==i&&h(n,i,a,e,o,t)}break;case 6:null===t.stateNode?r("162"):void 0,n=t.memoizedProps,v(t.stateNode,null!==e?e.memoizedProps:n,n);break;case 3:break;default:r("163")}},commitLifeCycles:function(e,t,n){switch(n.tag){case 2:if(e=n.stateNode,4&n.effectTag)if(null===t)e.props=n.memoizedProps,e.state=n.memoizedState,e.componentDidMount();else{var o=t.memoizedProps;t=t.memoizedState,e.props=n.memoizedProps,e.state=n.memoizedState,e.componentDidUpdate(o,t,e.__reactInternalSnapshotBeforeUpdate)}n=n.updateQueue,null!==n&&ht(n,e);break;case 3:if(t=n.updateQueue,null!==t){if(e=null,null!==n.child)switch(n.child.tag){case 5:e=f(n.child.stateNode);break;case 2:e=n.child.stateNode}ht(t,e)}break;case 5:e=n.stateNode,null===t&&4&n.effectTag&&p(e,n.type,n.memoizedProps,n);break;case 6:break;case 4:break;default:r("163")}},commitErrorLogging:function(e,t){switch(e.tag){case 2:var n=e.type;t=e.stateNode;var o=e.updateQueue;null===o||null===o.capturedValues?r("264"):void 0;var i=o.capturedValues;for(o.capturedValues=null,"function"!=typeof n.getDerivedStateFromCatch&&a(t),t.props=e.memoizedProps,t.state=e.memoizedState,n=0;nt||(n.current=e[t],e[t]=null,t--)},push:function(n,r){t++,e[t]=n.current,n.current=r},checkThatStackIsEmpty:function(){},resetStackAfterFatalErrorInDev:function(){}}}function Nt(e){function t(){if(null!==Z)for(var e=Z.return;null!==e;)F(e),e=e.return;ee=null,te=0,Z=null,oe=!1}function n(e){return null!==ie&&ie.has(e)}function o(e){for(;;){var t=e.alternate,n=e.return,r=e.sibling;if(0===(512&e.effectTag)){t=N(t,e,te);var o=e;if(1073741823===te||1073741823!==o.expirationTime){e:switch(o.tag){case 3:case 2:var a=o.updateQueue;a=null===a?0:a.expirationTime;break e;default:a=0}for(var i=o.child;null!==i;)0!==i.expirationTime&&(0===a||a>i.expirationTime)&&(a=i.expirationTime),i=i.sibling;o.expirationTime=a}if(null!==t)return t;if(null!==n&&0===(512&n.effectTag)&&(null===n.firstEffect&&(n.firstEffect=e.firstEffect),null!==e.lastEffect&&(null!==n.lastEffect&&(n.lastEffect.nextEffect=e.firstEffect),n.lastEffect=e.lastEffect),1he)&&(he=e),e}function s(e,n){e:{for(;null!==e;){if((0===e.expirationTime||e.expirationTime>n)&&(e.expirationTime=n),null!==e.alternate&&(0===e.alternate.expirationTime||e.alternate.expirationTime>n)&&(e.alternate.expirationTime=n),null===e.return){if(3!==e.tag){n=void 0;break e}var o=e.stateNode;!J&&0!==te&&nwe&&r("185")}e=e.return}n=void 0}return n}function f(){return G=V()-$,q=(G/10|0)+2}function d(e,t,n,r,o){var a=X;X=1;try{return e(t,n,r,o)}finally{X=a}}function p(e){if(0!==ce){if(e>ce)return;W(se)}var t=V()-$;ce=e,se=B(v,{timeout:10*(e-2)-t})}function h(e,t){if(null===e.nextScheduledRoot)e.remainingExpirationTime=t,null===ue?(le=ue=e,e.nextScheduledRoot=e):(ue=ue.nextScheduledRoot=e,ue.nextScheduledRoot=le);else{var n=e.remainingExpirationTime;(0===n||t=pe)&&(!me||f()>=pe);)C(de,pe,!me),m();else for(;null!==de&&0!==pe&&(0===e||e>=pe);)C(de,pe,!1),m();null!==ge&&(ce=0,se=-1),0!==pe&&p(pe),ge=null,me=!1,b()}function b(){if(Te=0,null!==xe){var e=xe;xe=null;for(var t=0;tSe)&&(me=!0)}function w(e){null===de?r("246"):void 0,de.remainingExpirationTime=0,ve||(ve=!0,ye=e)}var T=Pt(),S=Tt(e,T),E=Et(T);T=_t(T);var _=St(e),P=bt(e,S,E,T,_,s,c).beginWork,N=Ct(e,S,E,T,_).completeWork;S=kt(S,E,T,s,n);var I=S.throwException,O=S.unwindWork,F=S.unwindInterruptedWork;S=wt(e,u,s,c,function(e){null===ie?ie=new Set([e]):ie.add(e)},f);var D=S.commitBeforeMutationLifeCycles,R=S.commitResetTextContent,M=S.commitPlacement,U=S.commitDeletion,L=S.commitWork,z=S.commitLifeCycles,A=S.commitErrorLogging,H=S.commitAttachRef,j=S.commitDetachRef,V=e.now,B=e.scheduleDeferredCallback,W=e.cancelDeferredCallback,K=e.prepareForCommit,Q=e.resetAfterCommit,$=V(),q=2,G=$,Y=0,X=0,J=!1,Z=null,ee=null,te=0,ne=null,re=!1,oe=!1,ie=null,le=null,ue=null,ce=0,se=-1,fe=!1,de=null,pe=0,he=0,me=!1,ve=!1,ye=null,ge=null,be=!1,Ce=!1,ke=!1,xe=null,we=1e3,Te=0,Se=1;return{recalculateCurrentTime:f,computeExpirationForFiber:c,scheduleWork:s,requestWork:h,flushRoot:function(e,t){fe?r("253"):void 0,de=e,pe=t,C(e,t,!1),y(),b()},batchedUpdates:function(e,t){var n=be;be=!0;try{return e(t)}finally{(be=n)||fe||y()}},unbatchedUpdates:function(e,t){if(be&&!Ce){Ce=!0;try{return e(t)}finally{Ce=!1}}return e(t)},flushSync:function(e,t){fe?r("187"):void 0;var n=be;be=!0;try{return d(e,t)}finally{be=n,y()}},flushControlled:function(e){var t=be;be=!0;try{d(e)}finally{(be=t)||fe||g(1,!1,null)}},deferredUpdates:function(e){var t=X;X=25*(((f()+500)/25|0)+1);try{return e()}finally{X=t}},syncUpdates:d,interactiveUpdates:function(e,t,n){if(ke)return e(t,n);be||fe||0===he||(g(he,!1,null),he=0);var r=ke,o=be;be=ke=!0;try{return e(t,n)}finally{ke=r,(be=o)||fe||y()}},flushInteractiveUpdates:function(){fe||0===he||(g(he,!1,null),he=0)},computeUniqueAsyncExpiration:function(){var e=25*(((f()+500)/25|0)+1);return e<=Y&&(e=Y+1),Y=e},legacyContext:E}}function It(e){function t(e,t,n,r,o,a){if(r=t.current,n){n=n._reactInternalFiber;var l=u(n);n=c(n)?s(n,l):l}else n=yn;return null===t.context?t.context=n:t.pendingContext=n,t=a,ft(r,{expirationTime:o,partialState:{element:e},callback:void 0===t?null:t,isReplace:!1,isForced:!1,capturedValue:null,next:null}),i(r,o),o}function n(e){return e=Me(e),null===e?null:e.stateNode}var r=e.getPublicInstance;e=Nt(e);var o=e.recalculateCurrentTime,a=e.computeExpirationForFiber,i=e.scheduleWork,l=e.legacyContext,u=l.findCurrentUnmaskedContext,c=l.isContextProvider,s=l.processChildContext;return{createContainer:function(e,t,n){return t=new Je(3,null,null,t?3:0),e={current:t,containerInfo:e,pendingChildren:null,pendingCommitExpirationTime:0,finishedWork:null,context:null,pendingContext:null,hydrate:n,remainingExpirationTime:0,firstBatch:null,nextScheduledRoot:null},t.stateNode=e},updateContainer:function(e,n,r,i){var l=n.current,u=o();return l=a(l),t(e,n,r,u,l,i)},updateContainerAtExpirationTime:function(e,n,r,a,i){var l=o();return t(e,n,r,l,a,i)},flushRoot:e.flushRoot,requestWork:e.requestWork,computeUniqueAsyncExpiration:e.computeUniqueAsyncExpiration,batchedUpdates:e.batchedUpdates,unbatchedUpdates:e.unbatchedUpdates,deferredUpdates:e.deferredUpdates,syncUpdates:e.syncUpdates,interactiveUpdates:e.interactiveUpdates,flushInteractiveUpdates:e.flushInteractiveUpdates,flushControlled:e.flushControlled,flushSync:e.flushSync,getPublicRootInstance:function(e){if(e=e.current,!e.child)return null;switch(e.child.tag){case 5:return r(e.child.stateNode);default:return e.child.stateNode}},findHostInstance:n,findHostInstanceWithNoPortals:function(e){return e=Ue(e),null===e?null:e.stateNode},injectIntoDevTools:function(e){var t=e.findFiberByHostInstance;return at(dn({},e,{findHostInstanceByFiber:function(e){return n(e)},findFiberByHostInstance:function(e){return t?t(e):null}}))}}}function Ot(e,t,n){var r=3=t.length?void 0:r("93"),t=t[0]),n=""+t),null==n&&(n="")),e._wrapperState={initialValue:""+n}}function zt(e,t){var n=t.value;null!=n&&(n=""+n,n!==e.value&&(e.value=n),null==t.defaultValue&&(e.defaultValue=n)),null!=t.defaultValue&&(e.defaultValue=t.defaultValue)}function At(e){var t=e.textContent;t===e._wrapperState.initialValue&&(e.value=t)}function Ht(e){switch(e){case"svg":return"http://www.w3.org/2000/svg";case"math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function jt(e,t){return null==e||"http://www.w3.org/1999/xhtml"===e?Ht(t):"http://www.w3.org/2000/svg"===e&&"foreignObject"===t?"http://www.w3.org/1999/xhtml":e}function Vt(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&3===n.nodeType)return void(n.nodeValue=t)}e.textContent=t}function Bt(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=0===n.indexOf("--"),o=n,a=t[n];o=null==a||"boolean"==typeof a||""===a?"":r||"number"!=typeof a||0===a||jo.hasOwnProperty(o)&&jo[o]?(""+a).trim():a+"px","float"===n&&(n="cssFloat"),r?e.setProperty(n,o):e[n]=o}}function Wt(e,t,n){t&&(Bo[e]&&(null!=t.children||null!=t.dangerouslySetInnerHTML?r("137",e,n()):void 0),null!=t.dangerouslySetInnerHTML&&(null!=t.children?r("60"):void 0,"object"===cn(t.dangerouslySetInnerHTML)&&"__html"in t.dangerouslySetInnerHTML?void 0:r("61")),null!=t.style&&"object"!==cn(t.style)?r("62",n()):void 0)}function Kt(e,t){if(-1===e.indexOf("-"))return"string"==typeof t.is;switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}function Qt(e,t){e=9===e.nodeType||11===e.nodeType?e:e.ownerDocument;var n=$e(e);t=Tn[t];for(var r=0;r",e=e.removeChild(e.firstChild)):e="string"==typeof t.is?n.createElement(e,{is:t.is}):n.createElement(e):e=n.createElementNS(r,e),e}function qt(e,t){return(9===t.nodeType?t:t.ownerDocument).createTextNode(e)}function Gt(e,t,n,r){var o=Kt(t,n);switch(t){case"iframe":case"object":je("topLoad","load",e);var a=n;break;case"video":case"audio":for(a in to)to.hasOwnProperty(a)&&je(a,to[a],e);a=n;break;case"source":je("topError","error",e),a=n;break;case"img":case"image":case"link":je("topError","error",e),je("topLoad","load",e),a=n;break;case"form":
16 | je("topReset","reset",e),je("topSubmit","submit",e),a=n;break;case"details":je("topToggle","toggle",e),a=n;break;case"input":pe(e,n),a=de(e,n),je("topInvalid","invalid",e),Qt(r,"onChange");break;case"option":a=Dt(e,n);break;case"select":Mt(e,n),a=dn({},n,{value:void 0}),je("topInvalid","invalid",e),Qt(r,"onChange");break;case"textarea":Lt(e,n),a=Ut(e,n),je("topInvalid","invalid",e),Qt(r,"onChange");break;default:a=n}Wt(t,a,Ko);var i,l=a;for(i in l)if(l.hasOwnProperty(i)){var u=l[i];"style"===i?Bt(e,u,Ko):"dangerouslySetInnerHTML"===i?(u=u?u.__html:void 0,null!=u&&Ho(e,u)):"children"===i?"string"==typeof u?("textarea"!==t||""!==u)&&Vt(e,u):"number"==typeof u&&Vt(e,""+u):"suppressContentEditableWarning"!==i&&"suppressHydrationWarning"!==i&&"autoFocus"!==i&&(wn.hasOwnProperty(i)?null!=u&&Qt(r,i):null!=u&&fe(e,i,u,o))}switch(t){case"input":te(e),ve(e,n);break;case"textarea":te(e),At(e,n);break;case"option":null!=n.value&&e.setAttribute("value",n.value);break;case"select":e.multiple=!!n.multiple,t=n.value,null!=t?Rt(e,!!n.multiple,t,!1):null!=n.defaultValue&&Rt(e,!!n.multiple,n.defaultValue,!0);break;default:"function"==typeof a.onClick&&(e.onclick=pn)}}function Yt(e,t,n,r,o){var a=null;switch(t){case"input":n=de(e,n),r=de(e,r),a=[];break;case"option":n=Dt(e,n),r=Dt(e,r),a=[];break;case"select":n=dn({},n,{value:void 0}),r=dn({},r,{value:void 0}),a=[];break;case"textarea":n=Ut(e,n),r=Ut(e,r),a=[];break;default:"function"!=typeof n.onClick&&"function"==typeof r.onClick&&(e.onclick=pn)}Wt(t,r,Ko),t=e=void 0;var i=null;for(e in n)if(!r.hasOwnProperty(e)&&n.hasOwnProperty(e)&&null!=n[e])if("style"===e){var l=n[e];for(t in l)l.hasOwnProperty(t)&&(i||(i={}),i[t]="")}else"dangerouslySetInnerHTML"!==e&&"children"!==e&&"suppressContentEditableWarning"!==e&&"suppressHydrationWarning"!==e&&"autoFocus"!==e&&(wn.hasOwnProperty(e)?a||(a=[]):(a=a||[]).push(e,null));for(e in r){var u=r[e];if(l=null!=n?n[e]:void 0,r.hasOwnProperty(e)&&u!==l&&(null!=u||null!=l))if("style"===e)if(l){for(t in l)!l.hasOwnProperty(t)||u&&u.hasOwnProperty(t)||(i||(i={}),i[t]="");for(t in u)u.hasOwnProperty(t)&&l[t]!==u[t]&&(i||(i={}),i[t]=u[t])}else i||(a||(a=[]),a.push(e,i)),i=u;else"dangerouslySetInnerHTML"===e?(u=u?u.__html:void 0,l=l?l.__html:void 0,null!=u&&l!==u&&(a=a||[]).push(e,""+u)):"children"===e?l===u||"string"!=typeof u&&"number"!=typeof u||(a=a||[]).push(e,""+u):"suppressContentEditableWarning"!==e&&"suppressHydrationWarning"!==e&&(wn.hasOwnProperty(e)?(null!=u&&Qt(o,e),a||l===u||(a=[])):(a=a||[]).push(e,u))}return i&&(a=a||[]).push("style",i),a}function Xt(e,t,n,r,o){"input"===n&&"radio"===o.type&&null!=o.name&&he(e,o),Kt(n,r),r=Kt(n,o);for(var a=0;a=Kn),qn=String.fromCharCode(32),Gn={beforeInput:{phasedRegistrationNames:{bubbled:"onBeforeInput",captured:"onBeforeInputCapture"},dependencies:["topCompositionEnd","topKeyPress","topTextInput","topPaste"]},compositionEnd:{phasedRegistrationNames:{bubbled:"onCompositionEnd",captured:"onCompositionEndCapture"},dependencies:"topBlur topCompositionEnd topKeyDown topKeyPress topKeyUp topMouseDown".split(" ")},compositionStart:{phasedRegistrationNames:{bubbled:"onCompositionStart",captured:"onCompositionStartCapture"},dependencies:"topBlur topCompositionStart topKeyDown topKeyPress topKeyUp topMouseDown".split(" ")},compositionUpdate:{phasedRegistrationNames:{bubbled:"onCompositionUpdate",captured:"onCompositionUpdateCapture"},dependencies:"topBlur topCompositionUpdate topKeyDown topKeyPress topKeyUp topMouseDown".split(" ")}},Yn=!1,Xn=!1,Jn={eventTypes:Gn,extractEvents:function(e,t,n,r){var o=void 0,a=void 0;if(Wn)e:{switch(e){case"topCompositionStart":o=Gn.compositionStart;break e;case"topCompositionEnd":o=Gn.compositionEnd;break e;case"topCompositionUpdate":o=Gn.compositionUpdate;break e}o=void 0}else Xn?z(e,n)&&(o=Gn.compositionEnd):"topKeyDown"===e&&229===n.keyCode&&(o=Gn.compositionStart);return o?($n&&(Xn||o!==Gn.compositionStart?o===Gn.compositionEnd&&Xn&&(a=F()):(zn._root=r,zn._startText=D(),Xn=!0)),o=jn.getPooled(o,t,n,r),a?o.data=a:(a=A(n),null!==a&&(o.data=a)),N(o),a=o):a=null,(e=Qn?H(e,n):j(e,n))?(t=Vn.getPooled(Gn.beforeInput,t,n,r),t.data=e,N(t)):t=null,null===a?t:null===t?a:[a,t]}},Zn=null,er=null,tr=null,nr={injectFiberControlledHostComponent:function(e){Zn=e}},rr=Object.freeze({injection:nr,enqueueStateRestore:B,needsStateRestore:W,restoreStateIfNeeded:K}),or=!1,ar={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0},ir=sn.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,lr="function"==typeof Symbol&&Symbol.for,ur=lr?Symbol.for("react.element"):60103,cr=lr?Symbol.for("react.call"):60104,sr=lr?Symbol.for("react.return"):60105,fr=lr?Symbol.for("react.portal"):60106,dr=lr?Symbol.for("react.fragment"):60107,pr=lr?Symbol.for("react.strict_mode"):60108,hr=lr?Symbol.for("react.provider"):60109,mr=lr?Symbol.for("react.context"):60110,vr=lr?Symbol.for("react.async_mode"):60111,yr=lr?Symbol.for("react.forward_ref"):60112,gr="function"==typeof Symbol&&Symbol.iterator,br=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Cr={},kr={},xr={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){xr[e]=new ce(e,0,!1,e,null)}),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];xr[t]=new ce(t,1,!1,e[1],null)}),["contentEditable","draggable","spellCheck","value"].forEach(function(e){xr[e]=new ce(e,2,!1,e.toLowerCase(),null)}),["autoReverse","externalResourcesRequired","preserveAlpha"].forEach(function(e){xr[e]=new ce(e,2,!1,e,null)}),"allowFullScreen async autoFocus autoPlay controls default defer disabled formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){xr[e]=new ce(e,3,!1,e.toLowerCase(),null)}),["checked","multiple","muted","selected"].forEach(function(e){xr[e]=new ce(e,3,!0,e.toLowerCase(),null)}),["capture","download"].forEach(function(e){xr[e]=new ce(e,4,!1,e.toLowerCase(),null)}),["cols","rows","size","span"].forEach(function(e){xr[e]=new ce(e,6,!1,e.toLowerCase(),null)}),["rowSpan","start"].forEach(function(e){xr[e]=new ce(e,5,!1,e.toLowerCase(),null)});var wr=/[\-\:]([a-z])/g;"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(wr,se);xr[t]=new ce(t,1,!1,e,null)}),"xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(wr,se);xr[t]=new ce(t,1,!1,e,"http://www.w3.org/1999/xlink")}),["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(wr,se);xr[t]=new ce(t,1,!1,e,"http://www.w3.org/XML/1998/namespace")}),xr.tabIndex=new ce("tabIndex",1,!1,"tabindex",null);var Tr={change:{phasedRegistrationNames:{bubbled:"onChange",captured:"onChangeCapture"},dependencies:"topBlur topChange topClick topFocus topInput topKeyDown topKeyUp topSelectionChange".split(" ")}},Sr=null,Er=null,_r=!1;fn.canUseDOM&&(_r=J("input")&&(!document.documentMode||9=document.documentMode,io={select:{phasedRegistrationNames:{bubbled:"onSelect",captured:"onSelectCapture"},dependencies:"topBlur topContextMenu topFocus topKeyDown topKeyUp topMouseDown topMouseUp topSelectionChange".split(" ")}},lo=null,uo=null,co=null,so=!1,fo={eventTypes:io,extractEvents:function(e,t,n,r){var o,a=r.window===r?r.document:9===r.nodeType?r:r.ownerDocument;if(!(o=!a)){e:{a=$e(a),o=Tn.onSelect;for(var i=0;i=Fo-e){if(!(-1!==Io&&Io<=e))return void(Oo||(Oo=!0,requestAnimationFrame(Lo)));Mo.didTimeout=!0}else Mo.didTimeout=!1;Io=-1,e=Po,Po=null,null!==e&&e(Mo)}},!1);var Lo=function(e){Oo=!1;var t=e-Fo+Ro;tt&&(t=8),Ro=t"+t+"",t=Ao.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}}),jo={animationIterationCount:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},Vo=["Webkit","ms","Moz","O"];Object.keys(jo).forEach(function(e){Vo.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),jo[t]=jo[e]})});var Bo=dn({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0}),Wo=zo.html,Ko=pn.thatReturns(""),Qo=Object.freeze({createElement:$t,createTextNode:qt,setInitialProperties:Gt,diffProperties:Yt,updateProperties:Xt,diffHydratedProperties:Jt,diffHydratedText:Zt,warnForUnmatchedText:function(){},warnForDeletedHydratableElement:function(){},warnForDeletedHydratableText:function(){},warnForInsertedHydratedElement:function(){},warnForInsertedHydratedText:function(){},restoreControlledState:function(e,t,n){switch(t){case"input":if(me(e,n),t=n.name,"radio"===n.type&&null!=t){for(n=e;n.parentNode;)n=n.parentNode;for(n=n.querySelectorAll("input[name="+JSON.stringify(""+t)+'][type="radio"]'),t=0;tr&&(o=r,r=e,e=o),o=Ge(n,e);var a=Ge(n,r);if(o&&a&&(1!==t.rangeCount||t.anchorNode!==o.node||t.anchorOffset!==o.offset||t.focusNode!==a.node||t.focusOffset!==a.offset)){var i=document.createRange();i.setStart(o.node,o.offset),t.removeAllRanges(),e>r?(t.addRange(i),t.extend(a.node,a.offset)):(i.setEnd(a.node,a.offset),t.addRange(i))}}for(t=[],e=n;e=e.parentNode;)1===e.nodeType&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(n.focus(),n=0;nL.length&&L.push(e)}function d(e,t,n,o){var a="undefined"==typeof e?"undefined":y(e);"undefined"!==a&&"boolean"!==a||(e=null);var i=!1;if(null===e)i=!0;else switch(a){case"string":case"number":i=!0;break;case"object":switch(e.$$typeof){case x:case w:i=!0}}if(i)return n(o,e,""===t?"."+p(e,0):t),1;if(i=0,t=""===t?".":t+":",Array.isArray(e))for(var l=0;l1&&void 0!==arguments[1]?arguments[1]:I.default;return function(n){var o,u;return u=o=function(o){function u(t){r(this,u);var n=i(this,(u.__proto__||Object.getPrototypeOf(u)).call(this,t));return n._isMounted=!1,n.options=a({container:"undefined"!=typeof window?window:void 0},e),n.state={firstItemIndex:0,lastItemIndex:-1},e&&e.initialState&&(n.state=a({},n.state,e.initialState)),n.refreshState=n.refreshState.bind(n),"undefined"!=typeof window&&"requestAnimationFrame"in window&&(n.refreshState=(0,_.default)(n.refreshState)),n}return s(u,o),f(u,[{key:"setStateIfNeeded",value:function(e,t,n,o,r){var i=(0,v.default)(e,t,n,o,r);void 0!==i&&(i.firstItemIndex>i.lastItemIndex||i.firstItemIndex===this.state.firstItemIndex&&i.lastItemIndex===this.state.lastItemIndex||this.setState(i))}},{key:"refreshState",value:function(){if(this._isMounted){var e=this.props,t=e.itemHeight,n=e.items,o=e.itemBuffer;this.setStateIfNeeded(this.domNode,this.options.container,n,t,o)}}},{key:"componentWillMount",value:function(){this._isMounted=!0}},{key:"componentDidMount",value:function(){this.domNode=p.default.findDOMNode(this),this.refreshState(),this.options.container.addEventListener("scroll",this.refreshState),this.options.container.addEventListener("resize",this.refreshState)}},{key:"componentWillUnmount",value:function(){this._isMounted=!1,this.options.container.removeEventListener("scroll",this.refreshState),this.options.container.removeEventListener("resize",this.refreshState)}},{key:"componentWillReceiveProps",value:function(e){var t=e.itemHeight,n=e.items,o=e.itemBuffer;this.setStateIfNeeded(this.domNode,this.options.container,n,t,o)}},{key:"render",value:function(){return l.default.createElement(n,a({},this.props,t(this.props,this.state)))}}]),u}(c.PureComponent),o.propTypes={items:h.default.array.isRequired,itemHeight:h.default.number.isRequired,itemBuffer:h.default.number},o.defaultProps={itemBuffer:0},u}};t.default=O},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(e,t){var n=e.items,o=e.itemHeight,r=t.firstItemIndex,i=t.lastItemIndex,s=i>-1?n.slice(r,i+1):[],u=n.length*o,a=r*o;return{virtual:{items:s,style:{height:u,paddingTop:a,boxSizing:"border-box"}}}};t.default=n},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(e){return e.pageYOffset?e.pageYOffset:e.document?e.document.documentElement&&e.document.documentElement.scrollTop?e.document.documentElement.scrollTop:e.document.body&&e.document.body.scrollTop?e.document.body.scrollTop:0:e.scrollY||e.scrollTop||0};t.default=n},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var r=n(13),i=o(r),s=n(10),u=o(s),a=function(e,t,n,o,r){if(t&&o&&n&&0!==n.length){var s=t.innerHeight,a=t.clientHeight,f=s||a;if(f){var c=(0,u.default)(t),l=c+f,d=(0,i.default)(e)-(0,i.default)(t),p=o*n.length,m=Math.max(0,c-d),h=Math.max(0,Math.min(p,l-d)),y=Math.max(0,Math.floor(m/o)-r),v=Math.min(n.length,Math.ceil(h/o)+r)-1;return{firstItemIndex:y,lastItemIndex:v}}}};t.default=a},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=arguments;t.default=function(e){var t=!1;return function(){t||(t=!0,window.requestAnimationFrame(function(){e.apply(void 0,n),t=!1}))}}},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function e(t){return"undefined"!=typeof t&&t?(t.offsetTop||0)+e(t.offsetParent):0};t.default=n},,,,function(e,t,n){"use strict";function o(e,t,n,o,i,s,u,a){if(r(t),!e){var f;if(void 0===t)f=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[n,o,i,s,u,a],l=0;f=new Error(t.replace(/%s/g,function(){return c[l++]})),f.name="Invariant Violation"}throw f.framesToPop=1,f}}var r=function(e){};e.exports=o},,,,function(e,t,n){"use strict";var o=n(3),r=n(17),i=n(22);e.exports=function(){function e(e,t,n,o,s,u){u!==i&&r(!1,"Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types")}function t(){return e}e.isRequired=e;var n={array:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t};return n.checkPropTypes=o,n.PropTypes=n,n}},function(e,t){"use strict";var n="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED";e.exports=n}]);
--------------------------------------------------------------------------------
/demo/src/ConfigurableExample.js:
--------------------------------------------------------------------------------
1 | import React, { PureComponent, PropTypes } from 'react';
2 | import VirtualList from '../../src/VirtualList';
3 |
4 | const makeItem = (i) => ({
5 | id: i,
6 | title: `Media heading #${i+1}`,
7 | text: 'Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis.',
8 | });
9 |
10 | const ConfigurableExample = (MyList) => {
11 | let MyVirtualList = VirtualList()(MyList);
12 |
13 | return class MyConfigurableList extends PureComponent {
14 | constructor() {
15 | super();
16 |
17 | const defaultItemCount = 100000;
18 |
19 | const items = [];
20 |
21 | for (let i = 0; i < defaultItemCount; i++) {
22 | items[i] = makeItem(i);
23 | }
24 |
25 | const state = {
26 | itemHeight: 100,
27 | itemCount: defaultItemCount,
28 | items: items,
29 | contained: false,
30 | containerHeight: 250,
31 | itemBuffer: 0,
32 | };
33 |
34 | this.state = state;
35 | };
36 |
37 | update = () => {
38 | const items = [];
39 | const itemCount = parseInt(this.refs.itemCount.value, 10);
40 |
41 | for (var i = 0; i < itemCount; i++) {
42 | items[i] = makeItem(i);
43 | }
44 |
45 | const contained = this.refs.contained.checked;
46 |
47 | const state = {
48 | itemHeight: parseInt(this.refs.itemHeight.value, 10),
49 | itemCount: itemCount,
50 | items: items,
51 | contained: contained,
52 | container: this.refs.container,
53 | containerHeight: parseInt(this.refs.containerHeight.value, 10),
54 | itemBuffer: parseInt(this.refs.itemBuffer.value, 10),
55 | };
56 |
57 | if (state.contained !== this.state.contained) {
58 | const options = {
59 | container: state.contained ? state.container : window,
60 | };
61 |
62 | MyVirtualList = VirtualList(options)(MyList);
63 | }
64 |
65 | this.setState(state);
66 | };
67 |
68 | render() {
69 | return (
70 |
71 |
72 |
73 |
Contained
74 |
75 |
76 |
77 |
Container Height
78 |
79 |
80 |
81 |
82 |
83 |
Item Height
84 |
85 |
86 |
87 |
Item Count
88 |
89 |
90 |
91 |
92 |
93 |
Item Buffer
94 |
95 |
96 |
97 |
98 |
99 |
108 |
109 | );
110 | };
111 | };
112 | };
113 |
114 | export default ConfigurableExample;
--------------------------------------------------------------------------------
/demo/src/app.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from 'react-dom';
3 | import ConfigurableExample from './ConfigurableExample';
4 |
5 | require('file?name=[name].[ext]!./index.html');
6 |
7 | const MyList = ({
8 | virtual,
9 | itemHeight,
10 | }) => (
11 |
12 | {virtual.items.map((item) => (
13 |
14 |
15 |
16 |
17 |
18 |
{item.title}
19 |
{item.text}
20 |
21 |
22 | ))}
23 |
24 | );
25 |
26 | const MyConfigurableExample = ConfigurableExample(MyList);
27 |
28 | render(
29 | ,
30 | document.getElementById('app')
31 | );
32 |
33 |
--------------------------------------------------------------------------------
/demo/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
15 |
16 |
17 |
18 | React Virtual List
19 |
20 |
21 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/demo/webpack.config.babel.js:
--------------------------------------------------------------------------------
1 | import webpack from 'webpack';
2 | import path from 'path';
3 | import packageJson from '../package.json';
4 |
5 | const config = [{
6 | context: __dirname,
7 |
8 | entry: {
9 | app: './src/app.js',
10 | react: ['react', 'react-dom'],
11 | virtualList: ['../lib/VirtualList.js'],
12 | },
13 |
14 | output: {
15 | path: path.join(__dirname, './dist'),
16 | filename: '[name].js',
17 | },
18 |
19 | module: {
20 | loaders: [
21 | {
22 | test: /\.js$/,
23 | loader: 'babel',
24 | query: {
25 | presets: ['es2015', 'stage-0', 'react']
26 | },
27 | },
28 | ],
29 | },
30 |
31 | plugins: [
32 | new webpack.optimize.CommonsChunkPlugin({
33 | names: ['virtualList', 'react'],
34 | minChunks: 2,
35 | }),
36 | new webpack.optimize.OccurenceOrderPlugin(),
37 | new webpack.DefinePlugin({
38 | PACKAGE_NAME: JSON.stringify(packageJson.name),
39 | PACKAGE_VERSION: JSON.stringify(packageJson.version),
40 | 'process.env.NODE_ENV': JSON.stringify('production')
41 | }),
42 | new webpack.optimize.UglifyJsPlugin({
43 | compress: {
44 | warnings: false,
45 | },
46 | }),
47 | ],
48 | }];
49 |
50 | export default config;
--------------------------------------------------------------------------------
/deploy-to-gh-pages.sh:
--------------------------------------------------------------------------------
1 | # See https://medium.com/@nthgergo/publishing-gh-pages-with-travis-ci-53a8270e87db
2 | set -o errexit
3 |
4 | # config
5 | git config --global user.email "developerdizzle+travis@gmail.com"
6 | git config --global user.name "Travis CI"
7 |
8 | # build (CHANGE THIS)
9 | rm -rf demo/dist
10 | mkdir -p demo/dist
11 |
12 | npm run build:demo
13 |
14 | # deploy
15 | cd demo/dist
16 | git init
17 | git add .
18 | git commit -m "[travis] Deploy to Github Pages"
19 | git push --force "https://${GITHUB_TOKEN}@github.com/developerdizzle/react-virtual-list.git" master:gh-pages
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES6",
4 | },
5 | }
6 |
--------------------------------------------------------------------------------
/lib/VirtualList.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
8 |
9 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
10 |
11 | var _react = require('react');
12 |
13 | var _react2 = _interopRequireDefault(_react);
14 |
15 | var _reactDom = require('react-dom');
16 |
17 | var _reactDom2 = _interopRequireDefault(_reactDom);
18 |
19 | var _propTypes = require('prop-types');
20 |
21 | var _propTypes2 = _interopRequireDefault(_propTypes);
22 |
23 | var _getVisibleItemBounds = require('./utils/getVisibleItemBounds');
24 |
25 | var _getVisibleItemBounds2 = _interopRequireDefault(_getVisibleItemBounds);
26 |
27 | var _throttleWithRAF = require('./utils/throttleWithRAF');
28 |
29 | var _throttleWithRAF2 = _interopRequireDefault(_throttleWithRAF);
30 |
31 | var _defaultMapVirtualToProps = require('./utils/defaultMapVirtualToProps');
32 |
33 | var _defaultMapVirtualToProps2 = _interopRequireDefault(_defaultMapVirtualToProps);
34 |
35 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
36 |
37 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
38 |
39 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
40 |
41 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
42 |
43 | var VirtualList = function VirtualList(options) {
44 | var mapVirtualToProps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _defaultMapVirtualToProps2.default;
45 | return function (InnerComponent) {
46 | var _class, _temp;
47 |
48 | return _temp = _class = function (_PureComponent) {
49 | _inherits(vlist, _PureComponent);
50 |
51 | function vlist(props) {
52 | _classCallCheck(this, vlist);
53 |
54 | var _this = _possibleConstructorReturn(this, (vlist.__proto__ || Object.getPrototypeOf(vlist)).call(this, props));
55 |
56 | _this._isMounted = false;
57 |
58 |
59 | _this.options = _extends({
60 | container: typeof window !== 'undefined' ? window : undefined
61 | }, options);
62 |
63 | _this.state = {
64 | firstItemIndex: 0,
65 | lastItemIndex: -1
66 | };
67 |
68 | // initialState allows us to set the first/lastItemIndex (useful for server-rendering)
69 | if (options && options.initialState) {
70 | _this.state = _extends({}, _this.state, options.initialState);
71 | }
72 |
73 | _this.refreshState = _this.refreshState.bind(_this);
74 |
75 | // if requestAnimationFrame is available, use it to throttle refreshState
76 | if (typeof window !== 'undefined' && 'requestAnimationFrame' in window) {
77 | _this.refreshState = (0, _throttleWithRAF2.default)(_this.refreshState);
78 | }
79 | return _this;
80 | }
81 |
82 | _createClass(vlist, [{
83 | key: 'setStateIfNeeded',
84 | value: function setStateIfNeeded(list, container, items, itemHeight, itemBuffer) {
85 | // get first and lastItemIndex
86 | var state = (0, _getVisibleItemBounds2.default)(list, container, items, itemHeight, itemBuffer);
87 |
88 | if (state === undefined) {
89 | return;
90 | }
91 |
92 | if (state.firstItemIndex > state.lastItemIndex) {
93 | return;
94 | }
95 |
96 | if (state.firstItemIndex !== this.state.firstItemIndex || state.lastItemIndex !== this.state.lastItemIndex) {
97 | this.setState(state);
98 | }
99 | }
100 | }, {
101 | key: 'refreshState',
102 | value: function refreshState() {
103 | if (!this._isMounted) {
104 | return;
105 | }
106 |
107 | var _props = this.props,
108 | itemHeight = _props.itemHeight,
109 | items = _props.items,
110 | itemBuffer = _props.itemBuffer;
111 |
112 |
113 | this.setStateIfNeeded(this.domNode, this.options.container, items, itemHeight, itemBuffer);
114 | }
115 | }, {
116 | key: 'componentWillMount',
117 | value: function componentWillMount() {
118 | this._isMounted = true;
119 | }
120 | }, {
121 | key: 'componentDidMount',
122 | value: function componentDidMount() {
123 | // cache the DOM node
124 | this.domNode = _reactDom2.default.findDOMNode(this);
125 |
126 | // we need to refreshState because we didn't have access to the DOM node before
127 | this.refreshState();
128 |
129 | // add events
130 | this.options.container.addEventListener('scroll', this.refreshState);
131 | this.options.container.addEventListener('resize', this.refreshState);
132 | }
133 | }, {
134 | key: 'componentWillUnmount',
135 | value: function componentWillUnmount() {
136 | this._isMounted = false;
137 |
138 | // remove events
139 | this.options.container.removeEventListener('scroll', this.refreshState);
140 | this.options.container.removeEventListener('resize', this.refreshState);
141 | }
142 | }, {
143 | key: 'componentWillReceiveProps',
144 |
145 |
146 | // if props change, just assume we have to recalculate
147 | value: function componentWillReceiveProps(nextProps) {
148 | var itemHeight = nextProps.itemHeight,
149 | items = nextProps.items,
150 | itemBuffer = nextProps.itemBuffer;
151 |
152 |
153 | this.setStateIfNeeded(this.domNode, this.options.container, items, itemHeight, itemBuffer);
154 | }
155 | }, {
156 | key: 'render',
157 | value: function render() {
158 | return _react2.default.createElement(InnerComponent, _extends({}, this.props, mapVirtualToProps(this.props, this.state)));
159 | }
160 | }]);
161 |
162 | return vlist;
163 | }(_react.PureComponent), _class.propTypes = {
164 | items: _propTypes2.default.array.isRequired,
165 | itemHeight: _propTypes2.default.number.isRequired,
166 | itemBuffer: _propTypes2.default.number
167 | }, _class.defaultProps = {
168 | itemBuffer: 0
169 | }, _temp;
170 | };
171 | };
172 |
173 | exports.default = VirtualList;
--------------------------------------------------------------------------------
/lib/utils/defaultMapVirtualToProps.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | var defaultMapToVirtualProps = function defaultMapToVirtualProps(_ref, _ref2) {
7 | var items = _ref.items,
8 | itemHeight = _ref.itemHeight;
9 | var firstItemIndex = _ref2.firstItemIndex,
10 | lastItemIndex = _ref2.lastItemIndex;
11 |
12 | var visibleItems = lastItemIndex > -1 ? items.slice(firstItemIndex, lastItemIndex + 1) : [];
13 |
14 | // style
15 | var height = items.length * itemHeight;
16 | var paddingTop = firstItemIndex * itemHeight;
17 |
18 | return {
19 | virtual: {
20 | items: visibleItems,
21 | style: {
22 | height: height,
23 | paddingTop: paddingTop,
24 | boxSizing: 'border-box'
25 | }
26 | }
27 | };
28 | };
29 |
30 | exports.default = defaultMapToVirtualProps;
--------------------------------------------------------------------------------
/lib/utils/getElementTop.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | var getElementTop = function getElementTop(element) {
7 | if (element.pageYOffset) return element.pageYOffset;
8 |
9 | if (element.document) {
10 | if (element.document.documentElement && element.document.documentElement.scrollTop) return element.document.documentElement.scrollTop;
11 | if (element.document.body && element.document.body.scrollTop) return element.document.body.scrollTop;
12 |
13 | return 0;
14 | }
15 |
16 | return element.scrollY || element.scrollTop || 0;
17 | };
18 |
19 | exports.default = getElementTop;
--------------------------------------------------------------------------------
/lib/utils/getVisibleItemBounds.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 |
7 | var _topFromWindow = require('./topFromWindow');
8 |
9 | var _topFromWindow2 = _interopRequireDefault(_topFromWindow);
10 |
11 | var _getElementTop = require('./getElementTop');
12 |
13 | var _getElementTop2 = _interopRequireDefault(_getElementTop);
14 |
15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16 |
17 | var getVisibleItemBounds = function getVisibleItemBounds(list, container, items, itemHeight, itemBuffer) {
18 | // early return if we can't calculate
19 | if (!container) return undefined;
20 | if (!itemHeight) return undefined;
21 | if (!items) return undefined;
22 | if (items.length === 0) return undefined;
23 |
24 | // what the user can see
25 | var innerHeight = container.innerHeight,
26 | clientHeight = container.clientHeight;
27 |
28 |
29 | var viewHeight = innerHeight || clientHeight; // how many pixels are visible
30 |
31 | if (!viewHeight) return undefined;
32 |
33 | var viewTop = (0, _getElementTop2.default)(container); // top y-coordinate of viewport inside container
34 | var viewBottom = viewTop + viewHeight;
35 |
36 | var listTop = (0, _topFromWindow2.default)(list) - (0, _topFromWindow2.default)(container); // top y-coordinate of container inside window
37 | var listHeight = itemHeight * items.length;
38 |
39 | // visible list inside view
40 | var listViewTop = Math.max(0, viewTop - listTop); // top y-coordinate of list that is visible inside view
41 | var listViewBottom = Math.max(0, Math.min(listHeight, viewBottom - listTop)); // bottom y-coordinate of list that is visible inside view
42 |
43 | // visible item indexes
44 | var firstItemIndex = Math.max(0, Math.floor(listViewTop / itemHeight) - itemBuffer);
45 | var lastItemIndex = Math.min(items.length, Math.ceil(listViewBottom / itemHeight) + itemBuffer) - 1;
46 |
47 | return {
48 | firstItemIndex: firstItemIndex,
49 | lastItemIndex: lastItemIndex
50 | };
51 | };
52 |
53 | exports.default = getVisibleItemBounds;
--------------------------------------------------------------------------------
/lib/utils/throttleWithRAF.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | var _arguments = arguments;
7 |
8 | exports.default = function (fn) {
9 | var running = false;
10 |
11 | return function () {
12 | if (running) return;
13 |
14 | running = true;
15 |
16 | window.requestAnimationFrame(function () {
17 | fn.apply(undefined, _arguments);
18 |
19 | running = false;
20 | });
21 | };
22 | };
--------------------------------------------------------------------------------
/lib/utils/topFromWindow.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | var topFromWindow = function topFromWindow(element) {
7 | if (typeof element === 'undefined' || !element) return 0;
8 |
9 | return (element.offsetTop || 0) + topFromWindow(element.offsetParent);
10 | };
11 |
12 | exports.default = topFromWindow;
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-virtual-list",
3 | "version": "2.3.0",
4 | "description": "Super simple virtualized list React higher-order component",
5 | "main": "lib/VirtualList.js",
6 | "directories": {
7 | "test": "test"
8 | },
9 | "scripts": {
10 | "build": "babel src --out-dir lib --copy-files --ignore tests",
11 | "build:demo": "webpack --config demo/webpack.config.babel.js",
12 | "stats": "webpack .\\demo\\src\\app.js --config .\\demo\\webpack.config.babel.js --profile --json > stats.json",
13 | "test": "jest --verbose"
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "https://github.com/developerdizzle/react-virtual-list.git"
18 | },
19 | "keywords": [
20 | "react",
21 | "virtual",
22 | "list",
23 | "render",
24 | "scroll",
25 | "performance"
26 | ],
27 | "author": "developerdizzle",
28 | "bugs": {
29 | "url": "https://github.com/developerdizzle/react-virtual-list/issues"
30 | },
31 | "homepage": "https://github.com/developerdizzle/react-virtual-list",
32 | "dependencies": {
33 | "prop-types": "^15.5.10"
34 | },
35 | "devDependencies": {
36 | "babel-cli": "^6.18.0",
37 | "babel-core": "^6.18.2",
38 | "babel-jest": "^17.0.2",
39 | "babel-loader": "^6.2.8",
40 | "babel-preset-es2015": "^6.18.0",
41 | "babel-preset-react": "^6.16.0",
42 | "babel-preset-stage-0": "^6.16.0",
43 | "file-loader": "^0.9.0",
44 | "gulp": "^3.8.11",
45 | "gulp-react": "^3.0.1",
46 | "jasmine-node": "^1.14.5",
47 | "jest": "^17.0.3",
48 | "react": "^16.3.1",
49 | "react-dom": "^16.3.1",
50 | "react-test-renderer": "^16.3.1",
51 | "webpack": "^1.13.3"
52 | },
53 | "peerDependencies": {
54 | "react": "^15.0.0 || ^16.0.0",
55 | "react-dom": "^15.0.0 || ^16.0.0"
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/VirtualList.js:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from 'react';
2 | import ReactDOM from 'react-dom';
3 | import PropTypes from 'prop-types';
4 |
5 | import getVisibleItemBounds from './utils/getVisibleItemBounds';
6 | import throttleWithRAF from './utils/throttleWithRAF';
7 | import defaultMapToVirtualProps from './utils/defaultMapVirtualToProps';
8 |
9 | const VirtualList = (options, mapVirtualToProps = defaultMapToVirtualProps) => (InnerComponent) => {
10 | return class vlist extends PureComponent {
11 | static propTypes = {
12 | items: PropTypes.array.isRequired,
13 | itemHeight: PropTypes.number.isRequired,
14 | itemBuffer: PropTypes.number,
15 | };
16 |
17 | static defaultProps = {
18 | itemBuffer: 0,
19 | };
20 |
21 | _isMounted = false;
22 |
23 | constructor(props) {
24 | super(props);
25 |
26 | this.options = {
27 | container: typeof window !== 'undefined' ? window : undefined,
28 | ...options,
29 | };
30 |
31 | this.state = {
32 | firstItemIndex: 0,
33 | lastItemIndex: -1,
34 | };
35 |
36 | // initialState allows us to set the first/lastItemIndex (useful for server-rendering)
37 | if (options && options.initialState) {
38 | this.state = {
39 | ...this.state,
40 | ...options.initialState,
41 | };
42 | }
43 |
44 | this.refreshState = this.refreshState.bind(this);
45 |
46 | // if requestAnimationFrame is available, use it to throttle refreshState
47 | if (typeof window !== 'undefined' && 'requestAnimationFrame' in window) {
48 | this.refreshState = throttleWithRAF(this.refreshState);
49 | }
50 | };
51 |
52 | setStateIfNeeded(list, container, items, itemHeight, itemBuffer) {
53 | // get first and lastItemIndex
54 | const state = getVisibleItemBounds(list, container, items, itemHeight, itemBuffer);
55 |
56 | if (state === undefined) { return; }
57 |
58 | if (state.firstItemIndex > state.lastItemIndex) { return; }
59 |
60 | if (state.firstItemIndex !== this.state.firstItemIndex || state.lastItemIndex !== this.state.lastItemIndex) {
61 | this.setState(state);
62 | }
63 | }
64 |
65 | refreshState() {
66 | if (!this._isMounted) {
67 | return;
68 | }
69 |
70 | const { itemHeight, items, itemBuffer } = this.props;
71 |
72 | this.setStateIfNeeded(this.domNode, this.options.container, items, itemHeight, itemBuffer);
73 | };
74 |
75 | componentWillMount() {
76 | this._isMounted = true;
77 | }
78 |
79 | componentDidMount() {
80 | // cache the DOM node
81 | this.domNode = ReactDOM.findDOMNode(this);
82 |
83 | // we need to refreshState because we didn't have access to the DOM node before
84 | this.refreshState();
85 |
86 | // add events
87 | this.options.container.addEventListener('scroll', this.refreshState);
88 | this.options.container.addEventListener('resize', this.refreshState);
89 | };
90 |
91 | componentWillUnmount() {
92 | this._isMounted = false;
93 |
94 | // remove events
95 | this.options.container.removeEventListener('scroll', this.refreshState);
96 | this.options.container.removeEventListener('resize', this.refreshState);
97 | };
98 |
99 | // if props change, just assume we have to recalculate
100 | componentWillReceiveProps(nextProps) {
101 | const { itemHeight, items, itemBuffer } = nextProps;
102 |
103 | this.setStateIfNeeded(this.domNode, this.options.container, items, itemHeight, itemBuffer);
104 | };
105 |
106 | render() {
107 | return ( );
108 | };
109 | };
110 | };
111 |
112 | export default VirtualList;
113 |
--------------------------------------------------------------------------------
/src/__tests__/VirtualList.js:
--------------------------------------------------------------------------------
1 | import ShallowRenderer from 'react-test-renderer/shallow'
2 | import React from 'react';
3 |
4 | import VirtualList from '../VirtualList';
5 |
6 | const MyList = ({ itemHeight, virtual }) => {
7 | return (
8 |
9 | {virtual.items.map(item => (
10 | {item}
11 | ))}
12 |
13 | );
14 | };
15 |
16 | const items = Array.apply(null, {length: 1000}).map(Number.call, Number);
17 |
18 | describe('higher-order component that only renders visible items', () => {
19 | it('is a function', () => {
20 | expect(typeof VirtualList).toBe('function');
21 | });
22 |
23 | it('renders the inner component', () => {
24 | const MyVirtualList = VirtualList()(MyList);
25 |
26 | const renderer = ShallowRenderer.createRenderer();
27 | renderer.render(
28 | (
29 |
33 | )
34 | );
35 | const result = renderer.getRenderOutput();
36 |
37 | expect(result.type).toBe(MyList);
38 | });
39 |
40 | it('provides the virtual prop', () => {
41 | const MyVirtualList = VirtualList()(MyList);
42 |
43 | const renderer = ShallowRenderer.createRenderer();
44 | renderer.render(
45 | (
46 |
50 | )
51 | );
52 | const result = renderer.getRenderOutput();
53 |
54 | expect(result.props.virtual).not.toBe(undefined);
55 | });
56 |
57 | it('provides the items prop', () => {
58 | const MyVirtualList = VirtualList()(MyList);
59 |
60 | const renderer = ShallowRenderer.createRenderer();
61 | renderer.render(
62 | (
63 |
67 | )
68 | );
69 | const result = renderer.getRenderOutput();
70 |
71 | expect(result.props.virtual.items).not.toBe(undefined);
72 | });
73 |
74 | it('provides the style prop', () => {
75 | const MyVirtualList = VirtualList()(MyList);
76 |
77 | const renderer = ShallowRenderer.createRenderer();
78 | renderer.render(
79 | (
80 |
84 | )
85 | );
86 | const result = renderer.getRenderOutput();
87 |
88 | expect(result.props.virtual.style).not.toBe(undefined);
89 | });
90 |
91 | // it('renders only visible items', () => {
92 | // const container = {
93 | // clientHeight: 500,
94 | // offsetTop: 0,
95 | // };
96 |
97 | // const options = {
98 | // container,
99 | // };
100 |
101 | // const MyVirtualList = VirtualList(options)(MyList);
102 |
103 | // const renderer = ShallowRenderer.createRenderer();
104 | // renderer.render(
105 | // (
106 | //
110 | // )
111 | // );
112 |
113 | // const result = renderer.getRenderOutput();
114 |
115 | // expect(result.props.virtual.items).toHaveLength(5);
116 | // });
117 |
118 | it('uses initialState options', () => {
119 | const container = {
120 | clientHeight: 500,
121 | offsetTop: 0,
122 | };
123 |
124 | const options = {
125 | container,
126 | initialState: {
127 | firstItemIndex: 0,
128 | lastItemIndex: 4,
129 | style: {
130 | height: 500,
131 | paddingTop: 0,
132 | },
133 | },
134 | };
135 |
136 | const MyVirtualList = VirtualList(options)(MyList);
137 |
138 | const renderer = ShallowRenderer.createRenderer();
139 | renderer.render(
140 | (
141 |
145 | )
146 | );
147 |
148 | const result = renderer.getRenderOutput();
149 |
150 | expect(result.props.virtual.items).toHaveLength(5);
151 | });
152 |
153 | it('has default mapVirtualToProps', () => {
154 | const container = {
155 | clientHeight: 500,
156 | offsetTop: 0,
157 | };
158 |
159 | const options = {
160 | container,
161 | initialState: {
162 | firstItemIndex: 0,
163 | lastItemIndex: 4,
164 | },
165 | };
166 |
167 | const MyVirtualList = VirtualList(options)(MyList);
168 |
169 | const renderer = ShallowRenderer.createRenderer();
170 | renderer.render(
171 | (
172 |
176 | )
177 | );
178 |
179 | const result = renderer.getRenderOutput();
180 |
181 | expect(result.props.virtual).toBeDefined();
182 | });
183 |
184 | it('allows custom mapVirtualToProps', () => {
185 | const container = {
186 | clientHeight: 500,
187 | offsetTop: 0,
188 | };
189 |
190 | const options = {
191 | container,
192 | initialState: {
193 | firstItemIndex: 0,
194 | lastItemIndex: 4,
195 | },
196 | };
197 |
198 | const mapVirtualToProps = ({ items }) => ({ customItemsRef: items })
199 |
200 | const MyVirtualList = VirtualList(options, mapVirtualToProps)(MyList);
201 |
202 | const renderer = ShallowRenderer.createRenderer();
203 | renderer.render(
204 | (
205 |
209 | )
210 | );
211 |
212 | const result = renderer.getRenderOutput();
213 |
214 | expect(result.props.virtual).toBeUndefined();
215 | expect(result.props.customItemsRef).toBeDefined();
216 | });
217 | });
218 |
--------------------------------------------------------------------------------
/src/utils/__tests__/defaultMapVirtualToProps.js:
--------------------------------------------------------------------------------
1 | import defaultMapVirtualToProps from '../defaultMapVirtualToProps';
2 |
3 | const defaultProps = {
4 | items: [1, 2, 3, 4, 5],
5 | itemHeight: 100,
6 | };
7 |
8 | const defaultState = {
9 | firstItemIndex: 0,
10 | lastItemIndex: 4,
11 | };
12 |
13 | describe('function to convert state and props into virtual props', () => {
14 | it('is a function', () => {
15 | expect(typeof defaultMapVirtualToProps).toBe('function');
16 | });
17 |
18 | it('returns object with items prop', () => {
19 | const props = defaultMapVirtualToProps(defaultProps, defaultState);
20 |
21 | expect(props.virtual).toBeDefined();
22 | expect(props.virtual.items).toBeDefined();
23 | });
24 |
25 | it('returns object with style prop', () => {
26 | const props = defaultMapVirtualToProps(defaultProps, defaultState);
27 |
28 | expect(props.virtual).toBeDefined();
29 | expect(props.virtual.style).toBeDefined();
30 | expect(props.virtual.style.height).toBeDefined();
31 | expect(props.virtual.style.paddingTop).toBeDefined();
32 | });
33 |
34 | it('calculates items properly', () => {
35 | const props = defaultMapVirtualToProps(defaultProps, defaultState);
36 |
37 | expect(props.virtual.items).toHaveLength(5);
38 | });
39 |
40 | it('calculates style properly', () => {
41 | const props = defaultMapVirtualToProps(defaultProps, defaultState);
42 |
43 | expect(props.virtual.style.height).toBe(500);
44 | expect(props.virtual.style.paddingTop).toBe(0);
45 | });
46 | });
47 |
--------------------------------------------------------------------------------
/src/utils/__tests__/getElementTop.js:
--------------------------------------------------------------------------------
1 | import getElementTop from '../getElementTop';
2 |
3 | describe('function to get top position of element', () => {
4 | it('is a function', () => {
5 | expect(typeof getElementTop).toBe('function');
6 | });
7 |
8 | it('returns pageYOffset for window', () => {
9 | const element = {
10 | pageYOffset: 10,
11 | document: {
12 | documentElement: { },
13 | body: { },
14 | },
15 | };
16 |
17 | const top = getElementTop(element);
18 |
19 | expect(top).toBe(10);
20 | expect(top).toBe(element.pageYOffset);
21 | expect(top).not.toBe(element.document.documentElement.scrollTop);
22 | expect(top).not.toBe(element.document.body.scrollTop);
23 | });
24 |
25 | it('falls back to documentElement.scrollTop for window', () => {
26 | const element = {
27 | document: {
28 | documentElement: {
29 | scrollTop: 10,
30 | },
31 | body: { },
32 | },
33 | };
34 |
35 | const top = getElementTop(element);
36 |
37 | expect(top).toBe(10);
38 | expect(top).not.toBe(element.pageYOffset);
39 | expect(top).toBe(element.document.documentElement.scrollTop);
40 | expect(top).not.toBe(element.document.body.scrollTop);
41 | });
42 |
43 | it('falls back to body.scrollTop for window', () => {
44 | const element = {
45 | document: {
46 | documentElement: { },
47 | body: {
48 | scrollTop: 10,
49 | },
50 | },
51 | };
52 |
53 | const top = getElementTop(element);
54 |
55 | expect(top).toBe(10);
56 | expect(top).not.toBe(element.pageYOffset);
57 | expect(top).not.toBe(element.document.documentElement.scrollTop);
58 | expect(top).toBe(element.document.body.scrollTop);
59 | });
60 |
61 | it('falls back to 0 for window', () => {
62 | const element = {
63 | document: {
64 | documentElement: { },
65 | body: { },
66 | },
67 | };
68 |
69 | const top = getElementTop(element);
70 |
71 | expect(top).toBe(0);
72 | expect(top).not.toBe(element.pageYOffset);
73 | expect(top).not.toBe(element.document.documentElement.scrollTop);
74 | expect(top).not.toBe(element.document.body.scrollTop);
75 | });
76 |
77 |
78 | it('returns scrollY for element', () => {
79 | const element = {
80 | scrollY: 10,
81 | };
82 |
83 | const top = getElementTop(element);
84 |
85 | expect(top).toBe(10);
86 | expect(top).toBe(element.scrollY);
87 | expect(top).not.toBe(element.scrollTop);
88 | });
89 |
90 | it('falls back to scrollTop for element', () => {
91 | const element = {
92 | scrollTop: 10,
93 | };
94 |
95 | const top = getElementTop(element);
96 |
97 | expect(top).toBe(10);
98 | expect(top).not.toBe(element.scrollY);
99 | expect(top).toBe(element.scrollTop);
100 | });
101 |
102 | it('falls back to 0 for element', () => {
103 | const element = { };
104 |
105 | const top = getElementTop(element);
106 |
107 | expect(top).toBe(0);
108 | expect(top).not.toBe(element.scrollY);
109 | expect(top).not.toBe(element.scrollTop);
110 | });
111 | });
112 |
--------------------------------------------------------------------------------
/src/utils/__tests__/getVisibleItemBounds.js:
--------------------------------------------------------------------------------
1 | import getVisibleItemBounds from '../getVisibleItemBounds';
2 |
3 | const items = Array.apply(null, {length: 1000}).map(Number.call, Number);
4 | const itemHeight = 100;
5 | const itemBuffer = 0;
6 |
7 | describe('function to get the visible item bounds within a container', () => {
8 | it('is a function', () => {
9 | expect(typeof getVisibleItemBounds).toBe('function');
10 | });
11 |
12 | it ('returns the correct first/lastItemIndex when the list is at the top of the container', () => {
13 | const container = {
14 | clientHeight: 100,
15 | offsetTop: 0,
16 | };
17 |
18 | const list = {
19 | offsetTop: 0,
20 | };
21 |
22 | const { firstItemIndex, lastItemIndex } = getVisibleItemBounds(list, container, items, itemHeight, itemBuffer);
23 |
24 | expect(firstItemIndex).toBe(0);
25 | expect(lastItemIndex).toBe(0);
26 | });
27 |
28 | it ('returns the correct first/lastItemIndex when the list is at the top of the container', () => {
29 | const container = {
30 | clientHeight: 500,
31 | offsetTop: 0,
32 | };
33 |
34 | const list = {
35 | offsetTop: 0,
36 | };
37 |
38 | const { firstItemIndex, lastItemIndex } = getVisibleItemBounds(list, container, items, itemHeight, itemBuffer);
39 |
40 | expect(firstItemIndex).toBe(0);
41 | expect(lastItemIndex).toBe(4);
42 | });
43 |
44 | it ('returns the correct first/lastItemIndex when the list is in the middle of the container', () => {
45 | const container = {
46 | clientHeight: 500,
47 | offsetTop: 0,
48 | };
49 |
50 | const list = {
51 | offsetTop: 250,
52 | };
53 |
54 | const { firstItemIndex, lastItemIndex } = getVisibleItemBounds(list, container, items, itemHeight, itemBuffer);
55 |
56 | expect(firstItemIndex).toBe(0);
57 | expect(lastItemIndex).toBe(2);
58 | });
59 |
60 | it ('returns 0 and -1 when the list is below the container', () => {
61 | const container = {
62 | clientHeight: 500,
63 | offsetTop: 0,
64 | };
65 |
66 | const list = {
67 | offsetTop: 500,
68 | };
69 |
70 | const { firstItemIndex, lastItemIndex } = getVisibleItemBounds(list, container, items, itemHeight, itemBuffer);
71 |
72 | expect(firstItemIndex).toBe(0);
73 | expect(lastItemIndex).toBe(-1);
74 | });
75 |
76 |
77 | it ('returns the correct first/lastItemIndex when the list is scrolled down', () => {
78 | const container = {
79 | clientHeight: 500,
80 | offsetTop: 500,
81 | };
82 |
83 | const list = {
84 | offsetTop: 0,
85 | };
86 |
87 | const { firstItemIndex, lastItemIndex } = getVisibleItemBounds(list, container, items, itemHeight, itemBuffer);
88 |
89 | expect(firstItemIndex).toBe(5);
90 | expect(lastItemIndex).toBe(9);
91 | });
92 | });
93 |
--------------------------------------------------------------------------------
/src/utils/__tests__/topFromWindow.js:
--------------------------------------------------------------------------------
1 | import topFromWindow from '../topFromWindow';
2 |
3 | describe('function to get distance between the top of an element and the window', () => {
4 | it('is a function', () => {
5 | expect(typeof topFromWindow).toBe('function');
6 | });
7 |
8 | it('returns 0 for window', () => {
9 | const top = topFromWindow(window);
10 |
11 | expect(top).toBe(0);
12 | });
13 |
14 | it('returns 0 for non-object', () => {
15 | const top = topFromWindow(undefined);
16 |
17 | expect(top).toBe(0);
18 | });
19 |
20 | it('returns offsetTop for top-level element', () => {
21 | const element = {
22 | offsetTop: 10,
23 | };
24 |
25 | const top = topFromWindow(element);
26 |
27 | expect(top).toBe(element.offsetTop);
28 | });
29 |
30 | it('returns cumulative offsetTop for nested element', () => {
31 | const element = {
32 | offsetTop: 10,
33 | offsetParent: {
34 | offsetTop: 20,
35 | },
36 | };
37 |
38 | const top = topFromWindow(element);
39 |
40 | const expectedTop = element.offsetTop + element.offsetParent.offsetTop
41 |
42 | expect(top).toBe(expectedTop);
43 | });
44 | });
45 |
--------------------------------------------------------------------------------
/src/utils/defaultMapVirtualToProps.js:
--------------------------------------------------------------------------------
1 | const defaultMapToVirtualProps = ({
2 | items,
3 | itemHeight,
4 | }, {
5 | firstItemIndex,
6 | lastItemIndex,
7 | }) => {
8 | const visibleItems = lastItemIndex > -1 ? items.slice(firstItemIndex, lastItemIndex + 1) : [];
9 |
10 | // style
11 | const height = items.length * itemHeight;
12 | const paddingTop = firstItemIndex * itemHeight;
13 |
14 | return {
15 | virtual: {
16 | items: visibleItems,
17 | style: {
18 | height,
19 | paddingTop,
20 | boxSizing: 'border-box',
21 | },
22 | }
23 | };
24 | }
25 |
26 | export default defaultMapToVirtualProps;
--------------------------------------------------------------------------------
/src/utils/getElementTop.js:
--------------------------------------------------------------------------------
1 | const getElementTop = (element) => {
2 | if (element.pageYOffset) return element.pageYOffset;
3 |
4 | if (element.document) {
5 | if (element.document.documentElement && element.document.documentElement.scrollTop) return element.document.documentElement.scrollTop;
6 | if (element.document.body && element.document.body.scrollTop) return element.document.body.scrollTop;
7 |
8 | return 0;
9 | }
10 |
11 | return element.scrollY || element.scrollTop || 0;
12 | };
13 |
14 | export default getElementTop;
15 |
--------------------------------------------------------------------------------
/src/utils/getVisibleItemBounds.js:
--------------------------------------------------------------------------------
1 | import topFromWindow from './topFromWindow';
2 | import getElementTop from './getElementTop';
3 |
4 | const getVisibleItemBounds = (list, container, items, itemHeight, itemBuffer) => {
5 | // early return if we can't calculate
6 | if (!container) return undefined;
7 | if (!itemHeight) return undefined;
8 | if (!items) return undefined;
9 | if (items.length === 0) return undefined;
10 |
11 | // what the user can see
12 | const { innerHeight, clientHeight } = container;
13 |
14 | const viewHeight = innerHeight || clientHeight; // how many pixels are visible
15 |
16 | if (!viewHeight) return undefined;
17 |
18 | const viewTop = getElementTop(container); // top y-coordinate of viewport inside container
19 | const viewBottom = viewTop + viewHeight;
20 |
21 | const listTop = topFromWindow(list) - topFromWindow(container); // top y-coordinate of container inside window
22 | const listHeight = itemHeight * items.length;
23 |
24 | // visible list inside view
25 | const listViewTop = Math.max(0, viewTop - listTop); // top y-coordinate of list that is visible inside view
26 | const listViewBottom = Math.max(0, Math.min(listHeight, viewBottom - listTop)); // bottom y-coordinate of list that is visible inside view
27 |
28 | // visible item indexes
29 | const firstItemIndex = Math.max(0, Math.floor(listViewTop / itemHeight) - itemBuffer);
30 | const lastItemIndex = Math.min(items.length, Math.ceil(listViewBottom / itemHeight) + itemBuffer) - 1;
31 |
32 | return {
33 | firstItemIndex,
34 | lastItemIndex,
35 | };
36 | };
37 |
38 | export default getVisibleItemBounds;
39 |
--------------------------------------------------------------------------------
/src/utils/throttleWithRAF.js:
--------------------------------------------------------------------------------
1 | export default (fn) => {
2 | let running = false;
3 |
4 | return () => {
5 | if (running) return;
6 |
7 | running = true;
8 |
9 | window.requestAnimationFrame(() => {
10 | fn.apply(this, arguments);
11 |
12 | running = false;
13 | });
14 | };
15 | };
16 |
--------------------------------------------------------------------------------
/src/utils/topFromWindow.js:
--------------------------------------------------------------------------------
1 | const topFromWindow = (element) => {
2 | if (typeof element === 'undefined' || !element) return 0;
3 |
4 | return (element.offsetTop || 0) + topFromWindow(element.offsetParent);
5 | };
6 |
7 | export default topFromWindow;
--------------------------------------------------------------------------------