virtual-scroller 1.7.9 → 1.9.0
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 +71 -1
- package/README.md +434 -151
- package/bundle/index-bypass.html +1 -1
- package/bundle/index-dom.html +1 -1
- package/bundle/index-grid.html +1 -2
- package/bundle/index-scrollableContainer.html +1 -1
- package/bundle/index-tbody-scrollableContainer.html +2 -0
- package/bundle/index-tbody.html +2 -0
- 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 +315 -0
- package/commonjs/BeforeResize.js.map +1 -0
- package/commonjs/DOM/Engine.js +46 -0
- package/commonjs/DOM/Engine.js.map +1 -0
- package/commonjs/DOM/ItemsContainer.js +78 -0
- package/commonjs/DOM/ItemsContainer.js.map +1 -0
- package/commonjs/DOM/{WaitForStylesToLoad.js → ListTopOffsetWatcher.js} +71 -44
- package/commonjs/DOM/ListTopOffsetWatcher.js.map +1 -0
- package/commonjs/DOM/ScrollableContainer.js +69 -101
- package/commonjs/DOM/ScrollableContainer.js.map +1 -1
- package/commonjs/DOM/VirtualScroller.js +37 -29
- package/commonjs/DOM/VirtualScroller.js.map +1 -1
- package/commonjs/DOM/tbody.js +17 -11
- package/commonjs/DOM/tbody.js.map +1 -1
- package/commonjs/ItemHeights.js +33 -34
- package/commonjs/ItemHeights.js.map +1 -1
- package/commonjs/Layout.js +591 -216
- package/commonjs/Layout.js.map +1 -1
- package/commonjs/Layout.test.js +196 -0
- package/commonjs/Layout.test.js.map +1 -0
- package/commonjs/ListHeightMeasurement.js +124 -0
- package/commonjs/ListHeightMeasurement.js.map +1 -0
- package/commonjs/Resize.js +50 -39
- package/commonjs/Resize.js.map +1 -1
- package/commonjs/Scroll.js +139 -95
- 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 +160 -1021
- 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 +8 -8
- package/commonjs/getVerticalSpacing.js.map +1 -1
- package/commonjs/package.json +5 -0
- package/commonjs/react/VirtualScroller.js +182 -628
- 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 +28 -6
- package/commonjs/utility/debounce.js.map +1 -1
- package/commonjs/utility/debug.js +51 -12
- package/commonjs/utility/debug.js.map +1 -1
- package/commonjs/utility/getStateSnapshot.js +50 -0
- package/commonjs/utility/getStateSnapshot.js.map +1 -0
- package/commonjs/utility/px.js +1 -1
- package/commonjs/utility/px.js.map +1 -1
- package/commonjs/utility/px.test.js +14 -0
- package/commonjs/utility/px.test.js.map +1 -0
- 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 +25 -0
- 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 +99 -0
- package/index.js +1 -1
- package/modules/BeforeResize.js +305 -0
- package/modules/BeforeResize.js.map +1 -0
- package/modules/DOM/Engine.js +27 -0
- package/modules/DOM/Engine.js.map +1 -0
- package/modules/DOM/ItemsContainer.js +71 -0
- package/modules/DOM/ItemsContainer.js.map +1 -0
- package/modules/DOM/{WaitForStylesToLoad.js → ListTopOffsetWatcher.js} +72 -44
- package/modules/DOM/ListTopOffsetWatcher.js.map +1 -0
- package/modules/DOM/ScrollableContainer.js +68 -100
- package/modules/DOM/ScrollableContainer.js.map +1 -1
- package/modules/DOM/VirtualScroller.js +32 -28
- 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 +28 -33
- package/modules/ItemHeights.js.map +1 -1
- package/modules/Layout.js +585 -214
- package/modules/Layout.js.map +1 -1
- package/modules/Layout.test.js +190 -0
- package/modules/Layout.test.js.map +1 -0
- package/modules/ListHeightMeasurement.js +117 -0
- package/modules/ListHeightMeasurement.js.map +1 -0
- package/modules/Resize.js +50 -39
- package/modules/Resize.js.map +1 -1
- package/modules/Scroll.js +139 -94
- 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 +159 -1014
- 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 +8 -8
- package/modules/getVerticalSpacing.js.map +1 -1
- package/modules/react/VirtualScroller.js +179 -634
- 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 +28 -6
- package/modules/utility/debounce.js.map +1 -1
- package/modules/utility/debug.js +47 -10
- package/modules/utility/debug.js.map +1 -1
- package/modules/utility/getStateSnapshot.js +43 -0
- package/modules/utility/getStateSnapshot.js.map +1 -0
- package/modules/utility/px.js +1 -1
- package/modules/utility/px.js.map +1 -1
- package/modules/utility/px.test.js +9 -0
- package/modules/utility/px.test.js.map +1 -0
- 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 +54 -29
- package/react/index.cjs +4 -0
- package/react/index.cjs.js +9 -0
- package/react/index.d.ts +28 -0
- 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 +312 -0
- package/source/DOM/Engine.js +30 -0
- package/source/DOM/ItemsContainer.js +48 -0
- package/source/DOM/{WaitForStylesToLoad.js → ListTopOffsetWatcher.js} +61 -30
- package/source/DOM/ScrollableContainer.js +51 -73
- package/source/DOM/VirtualScroller.js +33 -18
- package/source/DOM/tbody.js +30 -21
- package/source/ItemHeights.js +27 -27
- package/source/Layout.js +629 -252
- package/source/Layout.test.js +176 -0
- package/source/ListHeightMeasurement.js +95 -0
- package/source/Resize.js +56 -32
- package/source/Scroll.js +135 -82
- 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 +162 -936
- 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/getVerticalSpacing.js +7 -7
- package/source/react/VirtualScroller.js +243 -603
- 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 +22 -5
- package/source/utility/debug.js +34 -3
- package/source/utility/getStateSnapshot.js +36 -0
- package/source/utility/px.js +1 -1
- package/source/utility/px.test.js +9 -0
- package/website/index-bypass.html +195 -0
- package/website/index-grid.html +0 -1
- package/website/index-scrollableContainer.html +208 -0
- package/website/index-tbody-scrollableContainer.html +68 -0
- package/website/index-tbody.html +55 -0
- package/commonjs/DOM/RenderingEngine.js +0 -33
- package/commonjs/DOM/RenderingEngine.js.map +0 -1
- package/commonjs/DOM/Screen.js +0 -87
- package/commonjs/DOM/Screen.js.map +0 -1
- package/commonjs/DOM/WaitForStylesToLoad.js.map +0 -1
- package/commonjs/RestoreScroll.js +0 -118
- package/commonjs/RestoreScroll.js.map +0 -1
- package/dom/index.commonjs.js +0 -4
- package/index.commonjs.js +0 -4
- package/modules/DOM/RenderingEngine.js +0 -19
- package/modules/DOM/RenderingEngine.js.map +0 -1
- package/modules/DOM/Screen.js +0 -80
- package/modules/DOM/Screen.js.map +0 -1
- package/modules/DOM/WaitForStylesToLoad.js.map +0 -1
- package/modules/RestoreScroll.js +0 -111
- package/modules/RestoreScroll.js.map +0 -1
- package/react/index.commonjs.js +0 -4
- package/source/DOM/RenderingEngine.js +0 -22
- package/source/DOM/Screen.js +0 -51
- package/source/RestoreScroll.js +0 -86
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import log, { isDebug } from './utility/debug.js'
|
|
2
|
+
import getItemsDiff from './getItemsDiff.js'
|
|
3
|
+
|
|
4
|
+
export default function() {
|
|
5
|
+
this.getItemsCount = () => {
|
|
6
|
+
return this.getState().items.length
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Updates `items`. For example, can prepend or append new items to the list.
|
|
11
|
+
* @param {any[]} newItems
|
|
12
|
+
* @param {boolean} [options.preserveScrollPositionOnPrependItems] — Set to `true` to enable "restore scroll position after prepending items" feature (could be useful when implementing "Show previous items" button).
|
|
13
|
+
*/
|
|
14
|
+
this._setItems = (newItems, options = {}) => {
|
|
15
|
+
const {
|
|
16
|
+
items: previousItems
|
|
17
|
+
} = this.getState()
|
|
18
|
+
|
|
19
|
+
// Even if `newItems` are equal to `this.state.items`,
|
|
20
|
+
// still perform a `updateState()` call, because, if `updateState()` calls
|
|
21
|
+
// were "asynchronous", there could be a situation when a developer
|
|
22
|
+
// first calls `setItems(newItems)` and then `setItems(oldItems)`:
|
|
23
|
+
// if this function did `return` `if (newItems === this.state.items)`
|
|
24
|
+
// then `updateState({ items: newItems })` would be scheduled as part of
|
|
25
|
+
// `setItems(newItems)` call, but the subsequent `setItems(oldItems)` call
|
|
26
|
+
// wouldn't do anything resulting in `newItems` being set as a result,
|
|
27
|
+
// and that wouldn't be what the developer intended.
|
|
28
|
+
|
|
29
|
+
let { itemStates } = this.getState()
|
|
30
|
+
let { itemHeights } = this.widthHasChanged
|
|
31
|
+
? this.widthHasChanged.stateUpdate
|
|
32
|
+
: this.getState()
|
|
33
|
+
|
|
34
|
+
log('~ Update items ~')
|
|
35
|
+
|
|
36
|
+
let layoutUpdate
|
|
37
|
+
let itemsUpdateInfo
|
|
38
|
+
|
|
39
|
+
// Compare the new items to the current items.
|
|
40
|
+
const itemsDiff = this.getItemsDiff(previousItems, newItems)
|
|
41
|
+
|
|
42
|
+
// See if it's an "incremental" items update.
|
|
43
|
+
if (itemsDiff) {
|
|
44
|
+
const {
|
|
45
|
+
firstShownItemIndex,
|
|
46
|
+
lastShownItemIndex,
|
|
47
|
+
beforeItemsHeight,
|
|
48
|
+
afterItemsHeight
|
|
49
|
+
} = this.widthHasChanged
|
|
50
|
+
? this.widthHasChanged.stateUpdate
|
|
51
|
+
: this.getState()
|
|
52
|
+
|
|
53
|
+
const shouldRestoreScrollPosition = firstShownItemIndex === 0 &&
|
|
54
|
+
// `preserveScrollPosition` option name is deprecated,
|
|
55
|
+
// use `preserveScrollPositionOnPrependItems` instead.
|
|
56
|
+
(options.preserveScrollPositionOnPrependItems || options.preserveScrollPosition)
|
|
57
|
+
|
|
58
|
+
const {
|
|
59
|
+
prependedItemsCount,
|
|
60
|
+
appendedItemsCount
|
|
61
|
+
} = itemsDiff
|
|
62
|
+
|
|
63
|
+
let shouldResetGridLayout
|
|
64
|
+
|
|
65
|
+
layoutUpdate = this.layout.getLayoutUpdateForItemsDiff({
|
|
66
|
+
firstShownItemIndex,
|
|
67
|
+
lastShownItemIndex,
|
|
68
|
+
beforeItemsHeight,
|
|
69
|
+
afterItemsHeight
|
|
70
|
+
}, {
|
|
71
|
+
prependedItemsCount,
|
|
72
|
+
appendedItemsCount
|
|
73
|
+
}, {
|
|
74
|
+
itemsCount: newItems.length,
|
|
75
|
+
columnsCount: this.getActualColumnsCount(),
|
|
76
|
+
shouldRestoreScrollPosition,
|
|
77
|
+
onResetGridLayout: () => shouldResetGridLayout = true
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
if (prependedItemsCount > 0) {
|
|
81
|
+
log('Prepend', prependedItemsCount, 'items')
|
|
82
|
+
|
|
83
|
+
itemHeights = new Array(prependedItemsCount).concat(itemHeights)
|
|
84
|
+
|
|
85
|
+
if (itemStates) {
|
|
86
|
+
itemStates = new Array(prependedItemsCount).concat(itemStates)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Restore scroll position after prepending items (if requested).
|
|
90
|
+
if (shouldRestoreScrollPosition) {
|
|
91
|
+
log('Will restore scroll position')
|
|
92
|
+
this.listHeightMeasurement.snapshotListHeightBeforeAddingNewItems({
|
|
93
|
+
previousItems,
|
|
94
|
+
newItems,
|
|
95
|
+
prependedItemsCount
|
|
96
|
+
})
|
|
97
|
+
// "Seamless prepend" scenario doesn't result in a re-layout,
|
|
98
|
+
// so if any "non measured item" is currently pending,
|
|
99
|
+
// it doesn't get reset and will be handled after `state` is updated.
|
|
100
|
+
if (this.firstNonMeasuredItemIndex !== undefined) {
|
|
101
|
+
this.firstNonMeasuredItemIndex += prependedItemsCount
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
log('Reset layout')
|
|
105
|
+
if (shouldResetGridLayout) {
|
|
106
|
+
log('Reason: Prepended items count', prependedItemsCount, 'is not divisible by Columns Count', this.getActualColumnsCount())
|
|
107
|
+
// Reset item heights because the whole grid is going to be rebalanced
|
|
108
|
+
// and re-rendered in a different configuration.
|
|
109
|
+
itemHeights = new Array(newItems.length)
|
|
110
|
+
} else {
|
|
111
|
+
// Reset layout because none of the prepended items have been measured.
|
|
112
|
+
log('Reason: Prepended items\' heights are unknown')
|
|
113
|
+
}
|
|
114
|
+
layoutUpdate = this.layout.getInitialLayoutValues({
|
|
115
|
+
itemsCount: newItems.length,
|
|
116
|
+
columnsCount: this.getActualColumnsCount()
|
|
117
|
+
})
|
|
118
|
+
// Unschedule a potentially scheduled layout update
|
|
119
|
+
// after measuring a previously non-measured item
|
|
120
|
+
// because the list will be re-layout anyway
|
|
121
|
+
// due to the new items being set.
|
|
122
|
+
this.firstNonMeasuredItemIndex = undefined
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (appendedItemsCount > 0) {
|
|
127
|
+
log('Append', appendedItemsCount, 'items')
|
|
128
|
+
itemHeights = itemHeights.concat(new Array(appendedItemsCount))
|
|
129
|
+
if (itemStates) {
|
|
130
|
+
itemStates = itemStates.concat(new Array(appendedItemsCount))
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
itemsUpdateInfo = {
|
|
135
|
+
prepend: prependedItemsCount > 0,
|
|
136
|
+
append: appendedItemsCount > 0
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
log('Items have changed, and', (itemsDiff ? 'a re-layout from scratch has been requested.' : 'it\'s not a simple append and/or prepend.'), 'Rerender the entire list from scratch.')
|
|
140
|
+
log('Previous items', previousItems)
|
|
141
|
+
log('New items', newItems)
|
|
142
|
+
|
|
143
|
+
// Reset item heights and item states.
|
|
144
|
+
itemHeights = new Array(newItems.length)
|
|
145
|
+
itemStates = new Array(newItems.length)
|
|
146
|
+
|
|
147
|
+
layoutUpdate = this.layout.getInitialLayoutValues({
|
|
148
|
+
itemsCount: newItems.length,
|
|
149
|
+
columnsCount: this.getActualColumnsCount()
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
// Unschedule a potentially scheduled layout update
|
|
153
|
+
// after measuring a previously non-measured item
|
|
154
|
+
// because the list will be re-layout from scratch
|
|
155
|
+
// due to the new items being set.
|
|
156
|
+
this.firstNonMeasuredItemIndex = undefined
|
|
157
|
+
|
|
158
|
+
// Also reset any potential pending scroll position restoration.
|
|
159
|
+
// For example, imagine a developer first called `.setItems(incrementalItemsUpdate)`
|
|
160
|
+
// and then called `.setItems(differentItems)` and there was no state update
|
|
161
|
+
// in between those two calls. This could happen because state updates aren't
|
|
162
|
+
// required to be "synchronous". On other words, calling `this.updateState()`
|
|
163
|
+
// doesn't necessarily mean that the state is applied immediately.
|
|
164
|
+
// Imagine also that such "delayed" state updates could be batched,
|
|
165
|
+
// like they do in React inside event handlers (though that doesn't apply to this case):
|
|
166
|
+
// https://github.com/facebook/react/issues/10231#issuecomment-316644950
|
|
167
|
+
// If `this.listHeightMeasurement` wasn't reset on `.setItems(differentItems)`
|
|
168
|
+
// and if the second `this.updateState()` call overwrites the first one
|
|
169
|
+
// then it would attempt to restore scroll position in a situation when
|
|
170
|
+
// it should no longer do that. Hence the reset here.
|
|
171
|
+
this.listHeightMeasurement.reset()
|
|
172
|
+
|
|
173
|
+
itemsUpdateInfo = {
|
|
174
|
+
replace: true
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
log('~ Update state ~')
|
|
179
|
+
|
|
180
|
+
// const layoutValuesAfterUpdate = {
|
|
181
|
+
// ...this.getState(),
|
|
182
|
+
// ...layoutUpdate
|
|
183
|
+
// }
|
|
184
|
+
|
|
185
|
+
// `layoutUpdate` is equivalent to `layoutValuesAfterUpdate` because
|
|
186
|
+
// `layoutUpdate` contains all the relevant properties.
|
|
187
|
+
log('First shown item index', layoutUpdate.firstShownItemIndex)
|
|
188
|
+
log('Last shown item index', layoutUpdate.lastShownItemIndex)
|
|
189
|
+
log('Before items height', layoutUpdate.beforeItemsHeight)
|
|
190
|
+
log('After items height (actual or estimated)', layoutUpdate.afterItemsHeight)
|
|
191
|
+
|
|
192
|
+
// Optionally preload items to be rendered.
|
|
193
|
+
//
|
|
194
|
+
// `layoutUpdate` is equivalent to `layoutValuesAfterUpdate` because
|
|
195
|
+
// `layoutUpdate` contains all the relevant properties.
|
|
196
|
+
//
|
|
197
|
+
this.onBeforeShowItems(
|
|
198
|
+
newItems,
|
|
199
|
+
itemHeights,
|
|
200
|
+
layoutUpdate.firstShownItemIndex,
|
|
201
|
+
layoutUpdate.lastShownItemIndex
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
// `this.newItemsWillBeRendered` signals that new `items` are being rendered,
|
|
205
|
+
// and that `VirtualScroller` should temporarily stop all other updates.
|
|
206
|
+
//
|
|
207
|
+
// `this.newItemsWillBeRendered` is cleared in `onRender()`.
|
|
208
|
+
//
|
|
209
|
+
// The values in `this.newItemsWillBeRendered` are used, for example,
|
|
210
|
+
// in `.onResize()` handler in order to not break state consistency when
|
|
211
|
+
// state updates are "asynchronous" (delayed) and there's a window resize event
|
|
212
|
+
// in between calling `updateState()` below and that call actually being applied.
|
|
213
|
+
//
|
|
214
|
+
this.newItemsWillBeRendered = {
|
|
215
|
+
...itemsUpdateInfo,
|
|
216
|
+
count: newItems.length,
|
|
217
|
+
// `layoutUpdate` now contains all layout-related properties, even if those that
|
|
218
|
+
// didn't change. So `firstShownItemIndex` is always in `this.newItemsWillBeRendered`.
|
|
219
|
+
layout: layoutUpdate
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// `layoutUpdate` now contains all layout-related properties, even if those that
|
|
223
|
+
// didn't change. So this part is no longer relevant.
|
|
224
|
+
//
|
|
225
|
+
// // If `firstShownItemIndex` is gonna be modified as a result of setting new items
|
|
226
|
+
// // then keep that "new" `firstShownItemIndex` in order for it to be used by
|
|
227
|
+
// // `onResize()` handler when it calculates "new" `firstShownItemIndex`
|
|
228
|
+
// // based on the new columns count (corresponding to the new window width).
|
|
229
|
+
// if (layoutUpdate.firstShownItemIndex !== undefined) {
|
|
230
|
+
// this.newItemsWillBeRendered = {
|
|
231
|
+
// ...this.newItemsWillBeRendered,
|
|
232
|
+
// firstShownItemIndex: layoutUpdate.firstShownItemIndex
|
|
233
|
+
// }
|
|
234
|
+
// }
|
|
235
|
+
|
|
236
|
+
// Update `VirtualScroller` state.
|
|
237
|
+
//
|
|
238
|
+
// This state update should overwrite all the `state` properties
|
|
239
|
+
// that are also updated in the "on scroll" handler (`getShownItemIndexes()`):
|
|
240
|
+
//
|
|
241
|
+
// * `firstShownItemIndex`
|
|
242
|
+
// * `lastShownItemIndex`
|
|
243
|
+
// * `beforeItemsHeight`
|
|
244
|
+
// * `afterItemsHeight`
|
|
245
|
+
//
|
|
246
|
+
// That's because this `updateState()` update has a higher priority
|
|
247
|
+
// than that of the "on scroll" handler, so it should overwrite
|
|
248
|
+
// any potential state changes dispatched by the "on scroll" handler.
|
|
249
|
+
//
|
|
250
|
+
const newState = {
|
|
251
|
+
...layoutUpdate,
|
|
252
|
+
items: newItems,
|
|
253
|
+
itemStates,
|
|
254
|
+
itemHeights
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Introduced `shouldIncludeBeforeResizeValuesInState()` getter just to prevent
|
|
258
|
+
// cluttering `state` with `beforeResize: undefined` property if `beforeResize`
|
|
259
|
+
// hasn't ever been set in `state` previously.
|
|
260
|
+
if (this.beforeResize.shouldIncludeBeforeResizeValuesInState()) {
|
|
261
|
+
if (this.shouldDiscardBeforeResizeItemHeights()) {
|
|
262
|
+
// Reset "before resize" item heights because now there're new items prepended
|
|
263
|
+
// with unknown heights, or completely new items with unknown heights, so
|
|
264
|
+
// `beforeItemsHeight` value won't be preserved anyway.
|
|
265
|
+
newState.beforeResize = undefined
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
// Overwrite `beforeResize` property in `state` even if it wasn't modified
|
|
269
|
+
// because state updates could be "asynchronous" and in that case there could be
|
|
270
|
+
// some previous `updateState()` call from some previous `setItems()` call that
|
|
271
|
+
// hasn't yet been applied, and that previous call might have scheduled setting
|
|
272
|
+
// `state.beforeResize` property to `undefined` in order to reset it, but this
|
|
273
|
+
// next `updateState()` call might not require resetting `state.beforeResize` property
|
|
274
|
+
// so it should undo resetting it by simply overwriting it with its normal value.
|
|
275
|
+
newState.beforeResize = this.widthHasChanged
|
|
276
|
+
? this.widthHasChanged.stateUpdate.beforeResize
|
|
277
|
+
: this.getState().beforeResize
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// `newState` should also overwrite all `state` properties that're updated in `onResize()`
|
|
282
|
+
// because `setItems()`'s state updates always overwrite `onResize()`'s state updates.
|
|
283
|
+
// (The least-priority ones are `onScroll()` state updates, but those're simply skipped
|
|
284
|
+
// if there's a pending `setItems()` or `onResize()` update).
|
|
285
|
+
//
|
|
286
|
+
// `state` property exceptions:
|
|
287
|
+
//
|
|
288
|
+
// `verticalSpacing` property is not updated here because it's fine setting it to
|
|
289
|
+
// `undefined` in `onResize()` — it will simply be re-measured after the component re-renders.
|
|
290
|
+
//
|
|
291
|
+
// `columnsCount` property is also not updated here because by definition it's only
|
|
292
|
+
// updated in `onResize()`.
|
|
293
|
+
|
|
294
|
+
// Render.
|
|
295
|
+
this._isSettingNewItems = true
|
|
296
|
+
this.updateState(newState)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
this.getItemsDiff = (previousItems, newItems) => {
|
|
300
|
+
return getItemsDiff(previousItems, newItems, this.isItemEqual)
|
|
301
|
+
}
|
|
302
|
+
}
|