virtual-scroller 1.8.0 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitlab-ci.yml +1 -1
- package/CHANGELOG.md +57 -0
- package/README.md +337 -160
- package/bundle/virtual-scroller-dom.js +1 -1
- package/bundle/virtual-scroller-dom.js.map +1 -1
- package/bundle/virtual-scroller-react.js +1 -1
- package/bundle/virtual-scroller-react.js.map +1 -1
- package/bundle/virtual-scroller.js +1 -1
- package/bundle/virtual-scroller.js.map +1 -1
- package/commonjs/BeforeResize.js +23 -27
- package/commonjs/BeforeResize.js.map +1 -1
- package/commonjs/DOM/Engine.js +7 -7
- package/commonjs/DOM/Engine.js.map +1 -1
- package/commonjs/DOM/ItemsContainer.js +1 -1
- package/commonjs/DOM/ItemsContainer.js.map +1 -1
- package/commonjs/DOM/ListTopOffsetWatcher.js +15 -9
- package/commonjs/DOM/ListTopOffsetWatcher.js.map +1 -1
- package/commonjs/DOM/ScrollableContainer.js +28 -28
- package/commonjs/DOM/ScrollableContainer.js.map +1 -1
- package/commonjs/DOM/VirtualScroller.js +20 -17
- package/commonjs/DOM/VirtualScroller.js.map +1 -1
- package/commonjs/DOM/tbody.js +16 -10
- package/commonjs/DOM/tbody.js.map +1 -1
- package/commonjs/ItemHeights.js +23 -17
- package/commonjs/ItemHeights.js.map +1 -1
- package/commonjs/Layout.js +15 -13
- package/commonjs/Layout.js.map +1 -1
- package/commonjs/Layout.test.js +8 -3
- package/commonjs/Layout.test.js.map +1 -1
- package/commonjs/{ListHeightChangeWatcher.js → ListHeightMeasurement.js} +26 -28
- package/commonjs/ListHeightMeasurement.js.map +1 -0
- package/commonjs/Resize.js +38 -28
- package/commonjs/Resize.js.map +1 -1
- package/commonjs/Scroll.js +28 -44
- package/commonjs/Scroll.js.map +1 -1
- package/commonjs/VirtualScroller.columns.js +43 -0
- package/commonjs/VirtualScroller.columns.js.map +1 -0
- package/commonjs/VirtualScroller.constructor.js +408 -0
- package/commonjs/VirtualScroller.constructor.js.map +1 -0
- package/commonjs/VirtualScroller.items.js +305 -0
- package/commonjs/VirtualScroller.items.js.map +1 -0
- package/commonjs/VirtualScroller.js +132 -1872
- package/commonjs/VirtualScroller.js.map +1 -1
- package/commonjs/VirtualScroller.layout.js +562 -0
- package/commonjs/VirtualScroller.layout.js.map +1 -0
- package/commonjs/VirtualScroller.onRender.js +357 -0
- package/commonjs/VirtualScroller.onRender.js.map +1 -0
- package/commonjs/VirtualScroller.resize.js +186 -0
- package/commonjs/VirtualScroller.resize.js.map +1 -0
- package/commonjs/VirtualScroller.state.js +301 -0
- package/commonjs/VirtualScroller.state.js.map +1 -0
- package/commonjs/VirtualScroller.verticalSpacing.js +65 -0
- package/commonjs/VirtualScroller.verticalSpacing.js.map +1 -0
- package/commonjs/getItemCoordinates.js.map +1 -1
- package/commonjs/getItemsDiff.js.map +1 -1
- package/commonjs/getVerticalSpacing.js.map +1 -1
- package/commonjs/package.json +5 -0
- package/commonjs/react/VirtualScroller.js +184 -618
- package/commonjs/react/VirtualScroller.js.map +1 -1
- package/commonjs/react/useClassName.js +26 -0
- package/commonjs/react/useClassName.js.map +1 -0
- package/commonjs/react/useHandleItemsChange.js +116 -0
- package/commonjs/react/useHandleItemsChange.js.map +1 -0
- package/commonjs/react/useInstanceMethods.js +37 -0
- package/commonjs/react/useInstanceMethods.js.map +1 -0
- package/commonjs/react/useItemKeys.js +60 -0
- package/commonjs/react/useItemKeys.js.map +1 -0
- package/commonjs/react/useOnItemHeightChange.js +32 -0
- package/commonjs/react/useOnItemHeightChange.js.map +1 -0
- package/commonjs/react/useOnItemStateChange.js +32 -0
- package/commonjs/react/useOnItemStateChange.js.map +1 -0
- package/commonjs/react/useState.js +140 -0
- package/commonjs/react/useState.js.map +1 -0
- package/commonjs/react/useStyle.js +29 -0
- package/commonjs/react/useStyle.js.map +1 -0
- package/commonjs/react/useVirtualScroller.js +62 -0
- package/commonjs/react/useVirtualScroller.js.map +1 -0
- package/commonjs/react/useVirtualScrollerStartStop.js +20 -0
- package/commonjs/react/useVirtualScrollerStartStop.js.map +1 -0
- package/commonjs/test/Engine.js +23 -0
- package/commonjs/test/Engine.js.map +1 -0
- package/commonjs/test/ItemsContainer.js +127 -0
- package/commonjs/test/ItemsContainer.js.map +1 -0
- package/commonjs/test/ScrollableContainer.js +130 -0
- package/commonjs/test/ScrollableContainer.js.map +1 -0
- package/commonjs/test/VirtualScroller.js +281 -0
- package/commonjs/test/VirtualScroller.js.map +1 -0
- package/commonjs/utility/debounce.js +2 -2
- package/commonjs/utility/debounce.js.map +1 -1
- package/commonjs/utility/debug.js.map +1 -1
- package/commonjs/utility/getStateSnapshot.js +2 -2
- package/commonjs/utility/getStateSnapshot.js.map +1 -1
- package/commonjs/utility/px.js.map +1 -1
- package/commonjs/utility/px.test.js +1 -1
- package/commonjs/utility/px.test.js.map +1 -1
- package/commonjs/utility/shallowEqual.js +1 -1
- package/commonjs/utility/shallowEqual.js.map +1 -1
- package/commonjs/utility/throttle.js.map +1 -1
- package/dom/index.cjs +4 -0
- package/dom/index.cjs.js +9 -0
- package/dom/index.d.ts +6 -4
- package/dom/index.js +1 -1
- package/dom/package.json +10 -4
- package/index.cjs +4 -0
- package/index.cjs.js +9 -0
- package/index.d.ts +30 -15
- package/index.js +1 -1
- package/modules/BeforeResize.js +22 -27
- package/modules/BeforeResize.js.map +1 -1
- package/modules/DOM/Engine.js +6 -6
- package/modules/DOM/Engine.js.map +1 -1
- package/modules/DOM/ItemsContainer.js +1 -1
- package/modules/DOM/ItemsContainer.js.map +1 -1
- package/modules/DOM/ListTopOffsetWatcher.js +15 -9
- package/modules/DOM/ListTopOffsetWatcher.js.map +1 -1
- package/modules/DOM/ScrollableContainer.js +28 -28
- package/modules/DOM/ScrollableContainer.js.map +1 -1
- package/modules/DOM/VirtualScroller.js +19 -16
- package/modules/DOM/VirtualScroller.js.map +1 -1
- package/modules/DOM/tbody.js +11 -9
- package/modules/DOM/tbody.js.map +1 -1
- package/modules/ItemHeights.js +22 -16
- package/modules/ItemHeights.js.map +1 -1
- package/modules/Layout.js +14 -12
- package/modules/Layout.js.map +1 -1
- package/modules/Layout.test.js +8 -3
- package/modules/Layout.test.js.map +1 -1
- package/modules/{ListHeightChangeWatcher.js → ListHeightMeasurement.js} +25 -27
- package/modules/ListHeightMeasurement.js.map +1 -0
- package/modules/Resize.js +38 -28
- package/modules/Resize.js.map +1 -1
- package/modules/Scroll.js +28 -44
- package/modules/Scroll.js.map +1 -1
- package/modules/VirtualScroller.columns.js +36 -0
- package/modules/VirtualScroller.columns.js.map +1 -0
- package/modules/VirtualScroller.constructor.js +371 -0
- package/modules/VirtualScroller.constructor.js.map +1 -0
- package/modules/VirtualScroller.items.js +288 -0
- package/modules/VirtualScroller.items.js.map +1 -0
- package/modules/VirtualScroller.js +132 -1860
- package/modules/VirtualScroller.js.map +1 -1
- package/modules/VirtualScroller.layout.js +549 -0
- package/modules/VirtualScroller.layout.js.map +1 -0
- package/modules/VirtualScroller.onRender.js +337 -0
- package/modules/VirtualScroller.onRender.js.map +1 -0
- package/modules/VirtualScroller.resize.js +176 -0
- package/modules/VirtualScroller.resize.js.map +1 -0
- package/modules/VirtualScroller.state.js +283 -0
- package/modules/VirtualScroller.state.js.map +1 -0
- package/modules/VirtualScroller.verticalSpacing.js +54 -0
- package/modules/VirtualScroller.verticalSpacing.js.map +1 -0
- package/modules/getItemCoordinates.js.map +1 -1
- package/modules/getItemsDiff.js.map +1 -1
- package/modules/getVerticalSpacing.js.map +1 -1
- package/modules/react/VirtualScroller.js +176 -625
- package/modules/react/VirtualScroller.js.map +1 -1
- package/modules/react/useClassName.js +18 -0
- package/modules/react/useClassName.js.map +1 -0
- package/modules/react/useHandleItemsChange.js +108 -0
- package/modules/react/useHandleItemsChange.js.map +1 -0
- package/modules/react/useInstanceMethods.js +28 -0
- package/modules/react/useInstanceMethods.js.map +1 -0
- package/modules/react/useItemKeys.js +52 -0
- package/modules/react/useItemKeys.js.map +1 -0
- package/modules/react/useOnItemHeightChange.js +24 -0
- package/modules/react/useOnItemHeightChange.js.map +1 -0
- package/modules/react/useOnItemStateChange.js +24 -0
- package/modules/react/useOnItemStateChange.js.map +1 -0
- package/modules/react/useState.js +132 -0
- package/modules/react/useState.js.map +1 -0
- package/modules/react/useStyle.js +19 -0
- package/modules/react/useStyle.js.map +1 -0
- package/modules/react/useVirtualScroller.js +51 -0
- package/modules/react/useVirtualScroller.js.map +1 -0
- package/modules/react/useVirtualScrollerStartStop.js +12 -0
- package/modules/react/useVirtualScrollerStartStop.js.map +1 -0
- package/modules/test/Engine.js +11 -0
- package/modules/test/Engine.js.map +1 -0
- package/modules/test/ItemsContainer.js +120 -0
- package/modules/test/ItemsContainer.js.map +1 -0
- package/modules/test/ScrollableContainer.js +123 -0
- package/modules/test/ScrollableContainer.js.map +1 -0
- package/modules/test/VirtualScroller.js +270 -0
- package/modules/test/VirtualScroller.js.map +1 -0
- package/modules/utility/debounce.js +2 -2
- package/modules/utility/debounce.js.map +1 -1
- package/modules/utility/debug.js.map +1 -1
- package/modules/utility/getStateSnapshot.js +2 -2
- package/modules/utility/getStateSnapshot.js.map +1 -1
- package/modules/utility/px.js.map +1 -1
- package/modules/utility/px.test.js +1 -1
- package/modules/utility/px.test.js.map +1 -1
- package/modules/utility/shallowEqual.js +1 -1
- package/modules/utility/shallowEqual.js.map +1 -1
- package/modules/utility/throttle.js.map +1 -1
- package/package.json +46 -23
- package/react/index.cjs +4 -0
- package/react/index.cjs.js +9 -0
- package/react/index.d.ts +10 -9
- package/react/index.js +1 -1
- package/react/package.json +10 -4
- package/rollup.config.mjs +62 -0
- package/runnable/create-commonjs-package-json.js +11 -0
- package/source/BeforeResize.js +16 -21
- package/source/DOM/Engine.js +8 -10
- package/source/DOM/ListTopOffsetWatcher.js +13 -8
- package/source/DOM/ScrollableContainer.js +23 -21
- package/source/DOM/VirtualScroller.js +27 -11
- package/source/DOM/tbody.js +30 -21
- package/source/ItemHeights.js +19 -14
- package/source/Layout.js +12 -9
- package/source/Layout.test.js +8 -3
- package/source/{ListHeightChangeWatcher.js → ListHeightMeasurement.js} +21 -20
- package/source/Resize.js +41 -25
- package/source/Scroll.js +27 -35
- package/source/VirtualScroller.columns.js +26 -0
- package/source/VirtualScroller.constructor.js +336 -0
- package/source/VirtualScroller.items.js +302 -0
- package/source/VirtualScroller.js +144 -1872
- package/source/VirtualScroller.layout.js +539 -0
- package/source/VirtualScroller.onRender.js +345 -0
- package/source/VirtualScroller.resize.js +189 -0
- package/source/VirtualScroller.state.js +284 -0
- package/source/VirtualScroller.verticalSpacing.js +51 -0
- package/source/react/VirtualScroller.js +243 -587
- package/source/react/useClassName.js +14 -0
- package/source/react/useHandleItemsChange.js +115 -0
- package/source/react/useInstanceMethods.js +25 -0
- package/source/react/useItemKeys.js +59 -0
- package/source/react/useOnItemHeightChange.js +28 -0
- package/source/react/useOnItemStateChange.js +28 -0
- package/source/react/useState.js +114 -0
- package/source/react/useStyle.js +20 -0
- package/source/react/useVirtualScroller.js +59 -0
- package/source/react/useVirtualScrollerStartStop.js +12 -0
- package/source/test/Engine.js +11 -0
- package/source/test/ItemsContainer.js +87 -0
- package/source/test/ScrollableContainer.js +88 -0
- package/source/test/VirtualScroller.js +232 -0
- package/source/utility/debounce.js +2 -2
- package/source/utility/px.test.js +1 -1
- package/babel.config.js +0 -25
- package/babel.js +0 -5
- package/commonjs/ListHeightChangeWatcher.js.map +0 -1
- package/dom/index.commonjs.js +0 -4
- package/index.commonjs.js +0 -4
- package/modules/ListHeightChangeWatcher.js.map +0 -1
- package/react/index.commonjs.js +0 -4
|
@@ -1,603 +1,259 @@
|
|
|
1
|
-
import React from 'react'
|
|
1
|
+
import React, { useRef, useMemo, useLayoutEffect } from 'react'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
3
|
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
4
|
+
import useState from './useState.js'
|
|
5
|
+
import useVirtualScroller from './useVirtualScroller.js'
|
|
6
|
+
import useVirtualScrollerStartStop from './useVirtualScrollerStartStop.js'
|
|
7
|
+
import useInstanceMethods from './useInstanceMethods.js'
|
|
8
|
+
import useItemKeys from './useItemKeys.js'
|
|
9
|
+
import useOnItemStateChange from './useOnItemStateChange.js'
|
|
10
|
+
import useOnItemHeightChange from './useOnItemHeightChange.js'
|
|
11
|
+
import useHandleItemsChange from './useHandleItemsChange.js'
|
|
12
|
+
import useClassName from './useClassName.js'
|
|
13
|
+
import useStyle from './useStyle.js'
|
|
14
|
+
|
|
15
|
+
function VirtualScroller({
|
|
16
|
+
as: AsComponent,
|
|
17
|
+
items,
|
|
18
|
+
itemComponent: Component,
|
|
19
|
+
itemComponentProps,
|
|
20
|
+
estimatedItemHeight,
|
|
21
|
+
bypass,
|
|
22
|
+
tbody,
|
|
23
|
+
// `preserveScrollPosition` property name is deprecated,
|
|
24
|
+
// use `preserveScrollPositionOnPrependItems` property instead.
|
|
25
|
+
preserveScrollPosition,
|
|
26
|
+
preserveScrollPositionOnPrependItems,
|
|
27
|
+
measureItemsBatchSize,
|
|
28
|
+
// `scrollableContainer` property is deprecated.
|
|
29
|
+
// Use `getScrollableContainer()` property instead.
|
|
30
|
+
scrollableContainer,
|
|
31
|
+
getScrollableContainer,
|
|
32
|
+
getColumnsCount,
|
|
33
|
+
getItemId,
|
|
34
|
+
className,
|
|
35
|
+
onMount,
|
|
36
|
+
// `onItemFirstRender(i)` is deprecated, use `onItemInitialRender(item)` instead.
|
|
37
|
+
onItemFirstRender,
|
|
38
|
+
onItemInitialRender,
|
|
39
|
+
initialScrollPosition,
|
|
40
|
+
onScrollPositionChange,
|
|
41
|
+
onStateChange,
|
|
42
|
+
initialState,
|
|
43
|
+
...rest
|
|
44
|
+
}, ref) {
|
|
45
|
+
// List items "container" DOM Element reference.
|
|
46
|
+
const container = useRef()
|
|
47
|
+
|
|
48
|
+
// Create a `VirtualScroller` instance.
|
|
49
|
+
const virtualScroller = useVirtualScroller({
|
|
50
|
+
items,
|
|
51
|
+
estimatedItemHeight,
|
|
52
|
+
bypass,
|
|
53
|
+
// bypassBatchSize,
|
|
54
|
+
tbody,
|
|
55
|
+
onItemInitialRender,
|
|
40
56
|
// `onItemFirstRender(i)` is deprecated, use `onItemInitialRender(item)` instead.
|
|
41
|
-
onItemFirstRender
|
|
42
|
-
initialScrollPosition
|
|
43
|
-
onScrollPositionChange
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
onItemFirstRender,
|
|
58
|
+
initialScrollPosition,
|
|
59
|
+
onScrollPositionChange,
|
|
60
|
+
measureItemsBatchSize,
|
|
61
|
+
// `scrollableContainer` property is deprecated.
|
|
62
|
+
// Use `getScrollableContainer()` property instead.
|
|
63
|
+
scrollableContainer,
|
|
64
|
+
getScrollableContainer,
|
|
65
|
+
getColumnsCount,
|
|
66
|
+
getItemId,
|
|
67
|
+
AsComponent,
|
|
68
|
+
initialState,
|
|
69
|
+
onStateChange
|
|
70
|
+
}, {
|
|
71
|
+
container
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// Only compute the initial state once.
|
|
75
|
+
const _initialState = useMemo(() => {
|
|
76
|
+
return virtualScroller.getInitialState()
|
|
77
|
+
}, [])
|
|
78
|
+
|
|
79
|
+
// Create state management functions.
|
|
80
|
+
const {
|
|
81
|
+
getState,
|
|
82
|
+
updateState
|
|
83
|
+
} = useState({
|
|
84
|
+
initialState: _initialState,
|
|
85
|
+
onRender: virtualScroller.onRender,
|
|
86
|
+
items
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
// Use custom (external) state storage in the `VirtualScroller`.
|
|
90
|
+
useMemo(() => {
|
|
91
|
+
virtualScroller.useState({
|
|
92
|
+
getState,
|
|
93
|
+
updateState
|
|
56
94
|
})
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// `
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
onItemHeightChange
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
items,
|
|
104
|
-
initialState,
|
|
105
|
-
initialCustomState,
|
|
106
|
-
onStateChange,
|
|
107
|
-
estimatedItemHeight,
|
|
108
|
-
initialScrollPosition,
|
|
109
|
-
onScrollPositionChange,
|
|
110
|
-
measureItemsBatchSize,
|
|
111
|
-
scrollableContainer,
|
|
112
|
-
// `getScrollableContainer` property is deprecated.
|
|
113
|
-
// Use `scrollableContainer` instead.
|
|
114
|
-
getScrollableContainer,
|
|
115
|
-
getColumnsCount,
|
|
116
|
-
getItemId,
|
|
117
|
-
bypass,
|
|
118
|
-
// bypassBatchSize
|
|
119
|
-
} = this.props
|
|
120
|
-
// Create `virtual-scroller` instance.
|
|
121
|
-
this.virtualScroller = new VirtualScrollerCore(
|
|
122
|
-
() => this.container.current,
|
|
123
|
-
items,
|
|
124
|
-
{
|
|
125
|
-
_useTimeoutInRenderLoop: true,
|
|
126
|
-
estimatedItemHeight,
|
|
127
|
-
bypass,
|
|
128
|
-
// bypassBatchSize,
|
|
129
|
-
onItemInitialRender: this.onItemInitialRender,
|
|
130
|
-
// `onItemFirstRender(i)` is deprecated, use `onItemInitialRender(item)` instead.
|
|
131
|
-
onItemFirstRender: this.onItemFirstRender,
|
|
132
|
-
initialScrollPosition,
|
|
133
|
-
onScrollPositionChange,
|
|
134
|
-
shouldUpdateLayoutOnScreenResize: this.shouldUpdateLayoutOnScreenResize,
|
|
135
|
-
measureItemsBatchSize,
|
|
136
|
-
scrollableContainer,
|
|
137
|
-
// `getScrollableContainer` property is deprecated.
|
|
138
|
-
// Use `scrollableContainer` instead.
|
|
139
|
-
getScrollableContainer,
|
|
140
|
-
getColumnsCount,
|
|
141
|
-
getItemId,
|
|
142
|
-
tbody: AsComponent === 'tbody',
|
|
143
|
-
state: initialState,
|
|
144
|
-
customState: initialCustomState,
|
|
145
|
-
onStateChange,
|
|
146
|
-
getState: () => this.state,
|
|
147
|
-
setState: (newState, { willUpdateState, didUpdateState }) => {
|
|
148
|
-
this.willUpdateState = willUpdateState
|
|
149
|
-
this.didUpdateState = didUpdateState
|
|
150
|
-
if (this.state) {
|
|
151
|
-
// Update existing state.
|
|
152
|
-
//
|
|
153
|
-
// In case of hypothetically rewriting this in React hooks,
|
|
154
|
-
// it wouldn't simply be `setState({ ...prevState, ...newState })`.
|
|
155
|
-
// The reason is that `setState()` would be "asynchronous" (not immediate),
|
|
156
|
-
// and `...prevState` would be stale in cases when more than a single
|
|
157
|
-
// `setState()` call is made before the state actually updates,
|
|
158
|
-
// making `prevState` stale, and, as a consequence, losing some
|
|
159
|
-
// of the state updates.
|
|
160
|
-
// For example, the first `setState()` call updates shown item indexes,
|
|
161
|
-
// and the second `setState()` call updates `verticalSpacing`:
|
|
162
|
-
// if it was simply `setState({ ...prevState, ...newState })`,
|
|
163
|
-
// then the second state update could overwrite the first state update,
|
|
164
|
-
// resulting in incorrect items being shown/hidden.
|
|
165
|
-
//
|
|
166
|
-
// I guess, in hooks, it could be something like:
|
|
167
|
-
//
|
|
168
|
-
// const [firstShownItemIndex, setFirstShownItemIndex] = useState()
|
|
169
|
-
// ...
|
|
170
|
-
// const setState = useCallback((newState) => {
|
|
171
|
-
// for (const key in newState) {
|
|
172
|
-
// switch (key) {
|
|
173
|
-
// case 'firstShownItemIndex':
|
|
174
|
-
// setFirstShownItemIndex(newState[key])
|
|
175
|
-
// break
|
|
176
|
-
// ...
|
|
177
|
-
// }
|
|
178
|
-
// }
|
|
179
|
-
// setFirstShownItemIndex
|
|
180
|
-
// }, [])
|
|
181
|
-
// const virtualScroller = new VirtualScrollerCore({
|
|
182
|
-
// setState,
|
|
183
|
-
// ...
|
|
184
|
-
// })
|
|
185
|
-
// // `getState()` function would be updated on every render.
|
|
186
|
-
// virtualScroller.getState = () => ({
|
|
187
|
-
// firstShownItemIndex,
|
|
188
|
-
// ...
|
|
189
|
-
// })
|
|
190
|
-
//
|
|
191
|
-
// But as long as it uses the classic `this.setState()`,
|
|
192
|
-
// it's fine and simple.
|
|
193
|
-
this.setState(newState)
|
|
194
|
-
} else {
|
|
195
|
-
// Set initial state.
|
|
196
|
-
willUpdateState(newState)
|
|
197
|
-
this.state = newState
|
|
198
|
-
didUpdateState()
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
)
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// This is a proxy for `VirtualScroller`'s `.updateLayout` instance method.
|
|
206
|
-
updateLayout = () => this.virtualScroller.updateLayout()
|
|
207
|
-
|
|
208
|
-
// `.layout()` method name is deprecated, use `.updateLayout()` instead.
|
|
209
|
-
layout = () => this.updateLayout()
|
|
210
|
-
|
|
211
|
-
// This proxy is required for cases when
|
|
212
|
-
// `onItemInitialRender` property changes at subsequent renders.
|
|
213
|
-
// For example, if it's passed as an "anonymous" function:
|
|
214
|
-
// `<VirtualScroller onItemInitialRender={() => ...}/>`.
|
|
215
|
-
// In such cases, if this "proxy" workaround hasn't been implemented,
|
|
216
|
-
// the `VirtualScroller` instance would have the reference to the old function.
|
|
217
|
-
onItemInitialRender = (...args) => {
|
|
218
|
-
const { onItemInitialRender } = this.props
|
|
219
|
-
if (onItemInitialRender) {
|
|
220
|
-
onItemInitialRender(...args)
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// This proxy is required for cases when
|
|
225
|
-
// `onItemFirstRender` property changes at subsequent renders.
|
|
226
|
-
// For example, if it's passed as an "anonymous" function:
|
|
227
|
-
// `<VirtualScroller onItemFirstRender={() => ...}/>`.
|
|
228
|
-
// In such cases, if this "proxy" workaround hasn't been implemented,
|
|
229
|
-
// the `VirtualScroller` instance would have the reference to the old function.
|
|
230
|
-
// `onItemFirstRender(i)` is deprecated, use `onItemInitialRender(item)` instead.
|
|
231
|
-
onItemFirstRender = (...args) => {
|
|
232
|
-
const { onItemFirstRender } = this.props
|
|
233
|
-
if (onItemFirstRender) {
|
|
234
|
-
onItemFirstRender(...args)
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
shouldUseRefs() {
|
|
239
|
-
// There's no way to detect if `ref` can be passed to `component`:
|
|
240
|
-
// https://github.com/facebook/react/issues/16309
|
|
241
|
-
// So it only uses `ref`s for `React.Component`s.
|
|
242
|
-
const { itemComponent } = this.props
|
|
243
|
-
return isComponentClass(itemComponent)
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Returns a `key` for an `item`'s element.
|
|
248
|
-
* @param {object} item — The item.
|
|
249
|
-
* @param {number} i — Item's index in `items` list.
|
|
250
|
-
* @return {any}
|
|
251
|
-
*/
|
|
252
|
-
getItemKey(item, i) {
|
|
253
|
-
const { getItemId } = this.props
|
|
254
|
-
if (getItemId) {
|
|
255
|
-
return getItemId(item)
|
|
256
|
-
}
|
|
257
|
-
return `${this.itemKeyPrefix}:${i}`
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* A proxy to `VirtualScroller.getItemCoordinates(i)`.
|
|
262
|
-
* @param {number} i
|
|
263
|
-
* @return {object}
|
|
264
|
-
*/
|
|
265
|
-
/*
|
|
266
|
-
getItemCoordinates(i) {
|
|
267
|
-
return this.virtualScroller.getItemCoordinates(i)
|
|
268
|
-
}
|
|
269
|
-
*/
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* `updateItem(i)` has been renamed to `renderItem(i)`.
|
|
273
|
-
* @param {number} i
|
|
274
|
-
*/
|
|
275
|
-
updateItem(i) {
|
|
276
|
-
return this.renderItem(i)
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Re-renders an item.
|
|
281
|
-
* @param {number} i
|
|
282
|
-
*/
|
|
283
|
-
renderItem(i) {
|
|
284
|
-
i = this.getItemIndex(i)
|
|
285
|
-
if (i === undefined) {
|
|
286
|
-
return reportError(`Item ${JSON.stringify(i)} not found when calling ".renderItem()"`)
|
|
287
|
-
}
|
|
288
|
-
if (this.shouldUseRefs()) {
|
|
289
|
-
// The item may be non-rendered when `.renderItem(i)` is called on it.
|
|
290
|
-
// For example, when there's a "parent comment" having several "replies"
|
|
291
|
-
// each of which has an autogenerated quote of the "parent comment"
|
|
292
|
-
// and then the "parent comment" is updated (for example, a YouTube video
|
|
293
|
-
// link gets parsed into an embedded video player) and all of its "replies"
|
|
294
|
-
// should be updated too to show the parsed video title instead of the URL,
|
|
295
|
-
// so `.renderItem(i)` is simply called on all of the "parent post"'s replies
|
|
296
|
-
// regardless of some of those replies being rendered or not.
|
|
297
|
-
if (this.itemRefs[i] && this.itemRefs[i].current) {
|
|
298
|
-
const { items } = this.props
|
|
299
|
-
// Stores `item` here because the `i` index
|
|
300
|
-
// might have changed when the callback is called,
|
|
301
|
-
// or the item even may have been removed.
|
|
302
|
-
const item = items[i]
|
|
303
|
-
this.itemRefs[i].current.forceUpdate(() => {
|
|
304
|
-
if (this._isMounted) {
|
|
305
|
-
// Recalculates the `i` index here because it
|
|
306
|
-
// might have changed when the callback is called,
|
|
307
|
-
// or the item even may have been removed.
|
|
308
|
-
const i = items.indexOf(item)
|
|
309
|
-
if (i >= 0) {
|
|
310
|
-
this.virtualScroller.onItemHeightChange(i)
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
})
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
getItemIndex(i) {
|
|
319
|
-
if (typeof i === 'number') {
|
|
320
|
-
return i
|
|
321
|
-
}
|
|
322
|
-
if (typeof i === 'object' && i !== null) {
|
|
323
|
-
const { items, getItemId } = this.props
|
|
324
|
-
const item = i
|
|
325
|
-
i = 0
|
|
326
|
-
while (i < items.length) {
|
|
327
|
-
if (getItemId) {
|
|
328
|
-
if (getItemId(item) === getItemId(items[i])) {
|
|
329
|
-
return i
|
|
330
|
-
}
|
|
331
|
-
} else {
|
|
332
|
-
if (item === items[i]) {
|
|
333
|
-
return i
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
i++
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// Functional components can't have a `ref` assigned to them.
|
|
342
|
-
// Item `ref`s are only used for calling `.renderItem(i)` instance method,
|
|
343
|
-
// because `.renderItem(i)` calls `.forceUpdate()` on item `i`.
|
|
344
|
-
// If a developer is not using the `.renderItem(i)` instance method
|
|
345
|
-
// then `ref`s aren't required and will be omitted.
|
|
346
|
-
getItemRef(i) {
|
|
347
|
-
if (!this.itemRefs[i]) {
|
|
348
|
-
this.itemRefs[i] = React.createRef()
|
|
349
|
-
}
|
|
350
|
-
return this.itemRefs[i]
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
getOnItemStateChange(i) {
|
|
354
|
-
if (!this.onItemStateChange[i]) {
|
|
355
|
-
this.onItemStateChange[i] = (itemState) => this.virtualScroller.onItemStateChange(i, itemState)
|
|
356
|
-
}
|
|
357
|
-
return this.onItemStateChange[i]
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
getOnItemHeightChange(i) {
|
|
361
|
-
if (!this.onItemHeightChange[i]) {
|
|
362
|
-
this.onItemHeightChange[i] = () => this.virtualScroller.onItemHeightChange(i)
|
|
363
|
-
}
|
|
364
|
-
return this.onItemHeightChange[i]
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
generateItemKeyPrefix() {
|
|
368
|
-
const prefix = String(Math.random()).slice(2)
|
|
369
|
-
if (this.itemKeyPrefixes.indexOf(prefix) >= 0) {
|
|
370
|
-
return this.generateItemKeyPrefix()
|
|
371
|
-
}
|
|
372
|
-
this.itemKeyPrefixes.push(prefix)
|
|
373
|
-
this.itemKeyPrefix = prefix
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
componentDidMount() {
|
|
377
|
-
const { onMount } = this.props
|
|
95
|
+
}, [])
|
|
96
|
+
|
|
97
|
+
// Start `VirtualScroller` on mount.
|
|
98
|
+
// Stop `VirtualScroller` on unmount.
|
|
99
|
+
useVirtualScrollerStartStop(virtualScroller)
|
|
100
|
+
|
|
101
|
+
// List items are rendered with `key`s so that React doesn't
|
|
102
|
+
// "reuse" `itemComponent`s in cases when `items` are changed.
|
|
103
|
+
const {
|
|
104
|
+
getItemKey,
|
|
105
|
+
updateItemKeysForNewItems
|
|
106
|
+
} = useItemKeys({
|
|
107
|
+
getItemId
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
// Cache per-item `onItemStateChange` functions' "references"
|
|
111
|
+
// so that item components don't get re-rendered needlessly.
|
|
112
|
+
const getOnItemStateChange = useOnItemStateChange({
|
|
113
|
+
items,
|
|
114
|
+
virtualScroller
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
// Cache per-item `onItemHeightChange` functions' "references"
|
|
118
|
+
// so that item components don't get re-rendered needlessly.
|
|
119
|
+
const getOnItemHeightChange = useOnItemHeightChange({
|
|
120
|
+
items,
|
|
121
|
+
virtualScroller
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
// Detect if `items` have changed.
|
|
125
|
+
useHandleItemsChange(items, {
|
|
126
|
+
virtualScroller,
|
|
127
|
+
// `preserveScrollPosition` property name is deprecated,
|
|
128
|
+
// use `preserveScrollPositionOnPrependItems` property instead.
|
|
129
|
+
preserveScrollPosition,
|
|
130
|
+
preserveScrollPositionOnPrependItems,
|
|
131
|
+
updateItemKeysForNewItems
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
// Add instance methods to the React component.
|
|
135
|
+
useInstanceMethods(ref, {
|
|
136
|
+
virtualScroller
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
useLayoutEffect(() => {
|
|
140
|
+
// (deprecated)
|
|
378
141
|
// `onMount()` option is deprecated due to no longer being used.
|
|
379
142
|
// If someone thinks there's a valid use case for it, create an issue.
|
|
380
143
|
if (onMount) {
|
|
381
144
|
onMount()
|
|
382
145
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
146
|
+
}, [])
|
|
147
|
+
|
|
148
|
+
// `willRender()` function is no longer used.
|
|
149
|
+
//
|
|
150
|
+
// // `getSnapshotBeforeUpdate()` is called right before `componentDidUpdate()`.
|
|
151
|
+
// // A hook equivalent/workaround for `getSnapshotBeforeUpdate()`:
|
|
152
|
+
// // https://github.com/facebook/react/issues/15221#issuecomment-583448887
|
|
153
|
+
// //
|
|
154
|
+
// getSnapshotBeforeUpdate(prevProps, prevState) {
|
|
155
|
+
// if (this.state !== prevState) {
|
|
156
|
+
// this.willRender(this.state, prevState)
|
|
157
|
+
// }
|
|
158
|
+
// // Returns `null` to avoid React warning:
|
|
159
|
+
// // "A snapshot value (or null) must be returned. You have returned undefined".
|
|
160
|
+
// return null
|
|
161
|
+
// }
|
|
387
162
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
163
|
+
className = useClassName(className, {
|
|
164
|
+
tbody
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
const style = useStyle({
|
|
168
|
+
tbody,
|
|
169
|
+
virtualScroller
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
const {
|
|
173
|
+
items: renderedItems,
|
|
174
|
+
itemStates,
|
|
175
|
+
firstShownItemIndex,
|
|
176
|
+
lastShownItemIndex
|
|
177
|
+
} = virtualScroller.getState()
|
|
178
|
+
|
|
179
|
+
return (
|
|
180
|
+
<AsComponent
|
|
181
|
+
{...rest}
|
|
182
|
+
ref={container}
|
|
183
|
+
className={className}
|
|
184
|
+
style={style}>
|
|
185
|
+
{renderedItems.map((item, i) => {
|
|
186
|
+
if (i >= firstShownItemIndex && i <= lastShownItemIndex) {
|
|
187
|
+
return (
|
|
188
|
+
<Component
|
|
189
|
+
{...itemComponentProps}
|
|
190
|
+
key={getItemKey(item, i)}
|
|
191
|
+
state={itemStates && itemStates[i]}
|
|
192
|
+
onStateChange={getOnItemStateChange(i)}
|
|
193
|
+
onHeightChange={getOnItemHeightChange(i)}>
|
|
194
|
+
{item}
|
|
195
|
+
</Component>
|
|
196
|
+
)
|
|
197
|
+
}
|
|
198
|
+
return null
|
|
199
|
+
})}
|
|
200
|
+
</AsComponent>
|
|
201
|
+
)
|
|
202
|
+
}
|
|
397
203
|
|
|
398
|
-
|
|
399
|
-
// That would correspond to `useLayoutEffect()` in React Hooks.
|
|
400
|
-
componentDidUpdate(prevProps, prevState) {
|
|
401
|
-
// If `state` did change.
|
|
402
|
-
if (this.state !== prevState) {
|
|
403
|
-
this.didUpdateState(prevState)
|
|
404
|
-
}
|
|
405
|
-
// If `items` property did change then update `virtual-scroller` items.
|
|
406
|
-
// This could have been done in `.render()` but `.setItems()` calls
|
|
407
|
-
// `.setState()` internally which would result in React throwing an error.
|
|
408
|
-
const {
|
|
409
|
-
items,
|
|
410
|
-
preserveScrollPosition,
|
|
411
|
-
preserveScrollPositionOnPrependItems
|
|
412
|
-
} = this.props
|
|
413
|
-
if (items !== prevProps.items) {
|
|
414
|
-
this.virtualScroller.setItems(items, {
|
|
415
|
-
// `preserveScrollPosition` property name is deprecated,
|
|
416
|
-
// use `preserveScrollPositionOnPrependItems` instead.
|
|
417
|
-
preserveScrollPositionOnPrependItems: preserveScrollPositionOnPrependItems || preserveScrollPosition
|
|
418
|
-
})
|
|
419
|
-
}
|
|
420
|
-
}
|
|
204
|
+
VirtualScroller = React.forwardRef(VirtualScroller)
|
|
421
205
|
|
|
422
|
-
|
|
423
|
-
this._isMounted = false
|
|
424
|
-
// Stop listening to scroll events.
|
|
425
|
-
this.virtualScroller.stop()
|
|
426
|
-
}
|
|
206
|
+
export default VirtualScroller
|
|
427
207
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
// get hidden before `componentDidUpdate()` is called.
|
|
476
|
-
//
|
|
477
|
-
// Consider this code example:
|
|
478
|
-
//
|
|
479
|
-
// const { fromIndex, items } = this.state
|
|
480
|
-
// const items = allItems.slice(fromIndex)
|
|
481
|
-
// return (
|
|
482
|
-
// {fromIndex > 0 &&
|
|
483
|
-
// <button onClick={this.onShowPrevious}>
|
|
484
|
-
// Show previous
|
|
485
|
-
// </button>
|
|
486
|
-
// }
|
|
487
|
-
// <VirtualScroller
|
|
488
|
-
// items={items}
|
|
489
|
-
// itemComponent={ItemComponent}/>
|
|
490
|
-
// )
|
|
491
|
-
//
|
|
492
|
-
// Consider a user clicks "Show previous" to show the items from the start.
|
|
493
|
-
// By the time `componentDidUpdate()` is called on `<VirtualScroller/>`,
|
|
494
|
-
// the "Show previous" button has already been hidden
|
|
495
|
-
// (because there're no more "previous" items)
|
|
496
|
-
// which results in the scroll Y position jumping forward
|
|
497
|
-
// by the height of that "Show previous" button.
|
|
498
|
-
// This is because `<VirtualScroller/>` captures scroll Y
|
|
499
|
-
// position when items are prepended via `.setItems()`
|
|
500
|
-
// when the "Show previous" button is still being shown,
|
|
501
|
-
// and then restores scroll Y position in `.didUpdateState()`
|
|
502
|
-
// when the "Show previous" button has already been hidden:
|
|
503
|
-
// that's the reason for the scroll Y "jump".
|
|
504
|
-
//
|
|
505
|
-
// To prevent that, scroll Y position is captured at `render()`
|
|
506
|
-
// time rather than later in `componentDidUpdate()`: this way,
|
|
507
|
-
// scroll Y position is captured while the "Show previous" button
|
|
508
|
-
// is still being shown.
|
|
509
|
-
//
|
|
510
|
-
const newItems = this.props.items
|
|
511
|
-
const previousItems = items // this.virtualScroller.getState().items
|
|
512
|
-
// There's one case when `newItems !== previousItems` is `true`
|
|
513
|
-
// from the start: when `initialState.items` are passed.
|
|
514
|
-
// To handle that single case `this.previousItemsProperty`
|
|
515
|
-
// is tracked and `this.itemsPropertyHasChanged` flag is set.
|
|
516
|
-
if (!this.itemsPropertyWasChanged) {
|
|
517
|
-
this.itemsPropertyWasChanged = this.props.items !== this.previousItemsProperty
|
|
518
|
-
}
|
|
519
|
-
this.previousItemsProperty = this.props.items
|
|
520
|
-
if (this.itemsPropertyWasChanged && newItems !== previousItems) {
|
|
521
|
-
const itemsDiff = this.virtualScroller.getItemsDiff(previousItems, newItems)
|
|
522
|
-
if (itemsDiff && itemsDiff.prependedItemsCount === 0 && itemsDiff.appendedItemsCount > 0) {
|
|
523
|
-
// If it's just items that have been appended
|
|
524
|
-
// then no need to re-generate the prefix
|
|
525
|
-
// and to fix scroll position and to clear caches.
|
|
526
|
-
} else {
|
|
527
|
-
// If the items update was incremental, then it's possible
|
|
528
|
-
// that some items were prepended, and so the scroll Y position
|
|
529
|
-
// should be restored after rendering those new items
|
|
530
|
-
// in order for the currently shown items to stay
|
|
531
|
-
// on the same position on screen.
|
|
532
|
-
// (only if explicitly opted into using this feature)
|
|
533
|
-
//
|
|
534
|
-
// If the items update wasn't incremental
|
|
535
|
-
// then there's no point in restoring scroll position.
|
|
536
|
-
//
|
|
537
|
-
// `preserveScrollPosition` property name is deprecated,
|
|
538
|
-
// use `preserveScrollPositionOnPrependItems` instead.
|
|
539
|
-
//
|
|
540
|
-
if (itemsDiff) {
|
|
541
|
-
const { prependedItemsCount } = itemsDiff
|
|
542
|
-
if (prependedItemsCount > 0) {
|
|
543
|
-
if (preserveScrollPositionOnPrependItems || preserveScrollPosition) {
|
|
544
|
-
if (firstShownItemIndex === 0) {
|
|
545
|
-
this.virtualScroller.listHeightChangeWatcher.snapshot({
|
|
546
|
-
previousItems,
|
|
547
|
-
newItems,
|
|
548
|
-
prependedItemsCount
|
|
549
|
-
})
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
// Reset the unique `key` prefix for item component keys.
|
|
555
|
-
if (!getItemId) {
|
|
556
|
-
this.generateItemKeyPrefix()
|
|
557
|
-
}
|
|
558
|
-
// Reset item refs.
|
|
559
|
-
this.itemRefs = new Array(newItems.length)
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
const tbody = this.virtualScroller.tbody
|
|
563
|
-
return (
|
|
564
|
-
<AsComponent
|
|
565
|
-
{...rest}
|
|
566
|
-
ref={this.container}
|
|
567
|
-
className={tbody ? (className ? className + ' ' + 'VirtualScroller' : 'VirtualScroller') : className}
|
|
568
|
-
style={{
|
|
569
|
-
paddingTop: tbody ? undefined : px(beforeItemsHeight),
|
|
570
|
-
paddingBottom: tbody ? undefined : px(afterItemsHeight)
|
|
571
|
-
}}>
|
|
572
|
-
{items.map((item, i) => {
|
|
573
|
-
if (i >= firstShownItemIndex && i <= lastShownItemIndex) {
|
|
574
|
-
return (
|
|
575
|
-
<Component
|
|
576
|
-
{...itemComponentProps}
|
|
577
|
-
key={this.getItemKey(item, i)}
|
|
578
|
-
ref={this.shouldUseRefs() ? this.getItemRef(i) : undefined}
|
|
579
|
-
state={itemStates && itemStates[i]}
|
|
580
|
-
onStateChange={this.getOnItemStateChange(i)}
|
|
581
|
-
onHeightChange={this.getOnItemHeightChange(i)}>
|
|
582
|
-
{item}
|
|
583
|
-
</Component>
|
|
584
|
-
)
|
|
585
|
-
}
|
|
586
|
-
return null
|
|
587
|
-
})}
|
|
588
|
-
</AsComponent>
|
|
589
|
-
)
|
|
590
|
-
}
|
|
208
|
+
// `PropTypes.elementType` is available in some version of `prop-types`.
|
|
209
|
+
// https://github.com/facebook/prop-types/issues/200
|
|
210
|
+
const elementType = PropTypes.elementType || PropTypes.oneOfType([
|
|
211
|
+
PropTypes.string,
|
|
212
|
+
PropTypes.func,
|
|
213
|
+
PropTypes.object
|
|
214
|
+
])
|
|
215
|
+
|
|
216
|
+
VirtualScroller.propTypes = {
|
|
217
|
+
as: elementType,
|
|
218
|
+
items: PropTypes.arrayOf(PropTypes.any).isRequired,
|
|
219
|
+
itemComponent: elementType.isRequired,
|
|
220
|
+
itemComponentProps: PropTypes.object,
|
|
221
|
+
estimatedItemHeight: PropTypes.number,
|
|
222
|
+
bypass: PropTypes.bool,
|
|
223
|
+
// bypassBatchSize: PropTypes.number,
|
|
224
|
+
tbody: PropTypes.bool,
|
|
225
|
+
preserveScrollPositionOnPrependItems: PropTypes.bool,
|
|
226
|
+
// `preserveScrollPosition` property name is deprecated,
|
|
227
|
+
// use `preserveScrollPositionOnPrependItems` instead.
|
|
228
|
+
preserveScrollPosition: PropTypes.bool,
|
|
229
|
+
measureItemsBatchSize: PropTypes.number,
|
|
230
|
+
// `scrollableContainer` property is deprecated.
|
|
231
|
+
// Use `getScrollableContainer()` property instead.
|
|
232
|
+
scrollableContainer: PropTypes.any,
|
|
233
|
+
getScrollableContainer: PropTypes.func,
|
|
234
|
+
getColumnsCount: PropTypes.func,
|
|
235
|
+
getItemId: PropTypes.func,
|
|
236
|
+
className: PropTypes.string,
|
|
237
|
+
onMount: PropTypes.func,
|
|
238
|
+
onItemInitialRender: PropTypes.func,
|
|
239
|
+
// `onItemFirstRender(i)` is deprecated, use `onItemInitialRender(item)` instead.
|
|
240
|
+
onItemFirstRender: PropTypes.func,
|
|
241
|
+
initialScrollPosition: PropTypes.number,
|
|
242
|
+
onScrollPositionChange: PropTypes.func,
|
|
243
|
+
onStateChange: PropTypes.func,
|
|
244
|
+
initialState: PropTypes.shape({
|
|
245
|
+
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
246
|
+
itemStates: PropTypes.arrayOf(PropTypes.any),
|
|
247
|
+
firstShownItemIndex: PropTypes.number.isRequired,
|
|
248
|
+
lastShownItemIndex: PropTypes.number.isRequired,
|
|
249
|
+
beforeItemsHeight: PropTypes.number.isRequired,
|
|
250
|
+
afterItemsHeight: PropTypes.number.isRequired,
|
|
251
|
+
itemHeights: PropTypes.arrayOf(PropTypes.number).isRequired,
|
|
252
|
+
columnsCount: PropTypes.number,
|
|
253
|
+
verticalSpacing: PropTypes.number
|
|
254
|
+
})
|
|
591
255
|
}
|
|
592
256
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
* https://overreacted.io/how-does-react-tell-a-class-from-a-function/
|
|
596
|
-
* @param {any} Component
|
|
597
|
-
* @return {object} [result] Returns `undefined` if it's not a `React.Component`. Returns an empty object if it's a `React.Component` (`.isReactComponent` is an empty object).
|
|
598
|
-
*/
|
|
599
|
-
function isComponentClass(Component) {
|
|
600
|
-
// return Component.prototype instanceof React.Component
|
|
601
|
-
// `React.memo()` returns `.prototype === undefined` for some reason.
|
|
602
|
-
return Component.prototype && Component.prototype.isReactComponent
|
|
257
|
+
VirtualScroller.defaultProps = {
|
|
258
|
+
as: 'div'
|
|
603
259
|
}
|