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.
Files changed (283) hide show
  1. package/.gitlab-ci.yml +1 -1
  2. package/CHANGELOG.md +71 -1
  3. package/README.md +434 -151
  4. package/bundle/index-bypass.html +1 -1
  5. package/bundle/index-dom.html +1 -1
  6. package/bundle/index-grid.html +1 -2
  7. package/bundle/index-scrollableContainer.html +1 -1
  8. package/bundle/index-tbody-scrollableContainer.html +2 -0
  9. package/bundle/index-tbody.html +2 -0
  10. package/bundle/virtual-scroller-dom.js +1 -1
  11. package/bundle/virtual-scroller-dom.js.map +1 -1
  12. package/bundle/virtual-scroller-react.js +1 -1
  13. package/bundle/virtual-scroller-react.js.map +1 -1
  14. package/bundle/virtual-scroller.js +1 -1
  15. package/bundle/virtual-scroller.js.map +1 -1
  16. package/commonjs/BeforeResize.js +315 -0
  17. package/commonjs/BeforeResize.js.map +1 -0
  18. package/commonjs/DOM/Engine.js +46 -0
  19. package/commonjs/DOM/Engine.js.map +1 -0
  20. package/commonjs/DOM/ItemsContainer.js +78 -0
  21. package/commonjs/DOM/ItemsContainer.js.map +1 -0
  22. package/commonjs/DOM/{WaitForStylesToLoad.js → ListTopOffsetWatcher.js} +71 -44
  23. package/commonjs/DOM/ListTopOffsetWatcher.js.map +1 -0
  24. package/commonjs/DOM/ScrollableContainer.js +69 -101
  25. package/commonjs/DOM/ScrollableContainer.js.map +1 -1
  26. package/commonjs/DOM/VirtualScroller.js +37 -29
  27. package/commonjs/DOM/VirtualScroller.js.map +1 -1
  28. package/commonjs/DOM/tbody.js +17 -11
  29. package/commonjs/DOM/tbody.js.map +1 -1
  30. package/commonjs/ItemHeights.js +33 -34
  31. package/commonjs/ItemHeights.js.map +1 -1
  32. package/commonjs/Layout.js +591 -216
  33. package/commonjs/Layout.js.map +1 -1
  34. package/commonjs/Layout.test.js +196 -0
  35. package/commonjs/Layout.test.js.map +1 -0
  36. package/commonjs/ListHeightMeasurement.js +124 -0
  37. package/commonjs/ListHeightMeasurement.js.map +1 -0
  38. package/commonjs/Resize.js +50 -39
  39. package/commonjs/Resize.js.map +1 -1
  40. package/commonjs/Scroll.js +139 -95
  41. package/commonjs/Scroll.js.map +1 -1
  42. package/commonjs/VirtualScroller.columns.js +43 -0
  43. package/commonjs/VirtualScroller.columns.js.map +1 -0
  44. package/commonjs/VirtualScroller.constructor.js +408 -0
  45. package/commonjs/VirtualScroller.constructor.js.map +1 -0
  46. package/commonjs/VirtualScroller.items.js +305 -0
  47. package/commonjs/VirtualScroller.items.js.map +1 -0
  48. package/commonjs/VirtualScroller.js +160 -1021
  49. package/commonjs/VirtualScroller.js.map +1 -1
  50. package/commonjs/VirtualScroller.layout.js +562 -0
  51. package/commonjs/VirtualScroller.layout.js.map +1 -0
  52. package/commonjs/VirtualScroller.onRender.js +357 -0
  53. package/commonjs/VirtualScroller.onRender.js.map +1 -0
  54. package/commonjs/VirtualScroller.resize.js +186 -0
  55. package/commonjs/VirtualScroller.resize.js.map +1 -0
  56. package/commonjs/VirtualScroller.state.js +301 -0
  57. package/commonjs/VirtualScroller.state.js.map +1 -0
  58. package/commonjs/VirtualScroller.verticalSpacing.js +65 -0
  59. package/commonjs/VirtualScroller.verticalSpacing.js.map +1 -0
  60. package/commonjs/getItemCoordinates.js.map +1 -1
  61. package/commonjs/getItemsDiff.js.map +1 -1
  62. package/commonjs/getVerticalSpacing.js +8 -8
  63. package/commonjs/getVerticalSpacing.js.map +1 -1
  64. package/commonjs/package.json +5 -0
  65. package/commonjs/react/VirtualScroller.js +182 -628
  66. package/commonjs/react/VirtualScroller.js.map +1 -1
  67. package/commonjs/react/useClassName.js +26 -0
  68. package/commonjs/react/useClassName.js.map +1 -0
  69. package/commonjs/react/useHandleItemsChange.js +116 -0
  70. package/commonjs/react/useHandleItemsChange.js.map +1 -0
  71. package/commonjs/react/useInstanceMethods.js +37 -0
  72. package/commonjs/react/useInstanceMethods.js.map +1 -0
  73. package/commonjs/react/useItemKeys.js +60 -0
  74. package/commonjs/react/useItemKeys.js.map +1 -0
  75. package/commonjs/react/useOnItemHeightChange.js +32 -0
  76. package/commonjs/react/useOnItemHeightChange.js.map +1 -0
  77. package/commonjs/react/useOnItemStateChange.js +32 -0
  78. package/commonjs/react/useOnItemStateChange.js.map +1 -0
  79. package/commonjs/react/useState.js +140 -0
  80. package/commonjs/react/useState.js.map +1 -0
  81. package/commonjs/react/useStyle.js +29 -0
  82. package/commonjs/react/useStyle.js.map +1 -0
  83. package/commonjs/react/useVirtualScroller.js +62 -0
  84. package/commonjs/react/useVirtualScroller.js.map +1 -0
  85. package/commonjs/react/useVirtualScrollerStartStop.js +20 -0
  86. package/commonjs/react/useVirtualScrollerStartStop.js.map +1 -0
  87. package/commonjs/test/Engine.js +23 -0
  88. package/commonjs/test/Engine.js.map +1 -0
  89. package/commonjs/test/ItemsContainer.js +127 -0
  90. package/commonjs/test/ItemsContainer.js.map +1 -0
  91. package/commonjs/test/ScrollableContainer.js +130 -0
  92. package/commonjs/test/ScrollableContainer.js.map +1 -0
  93. package/commonjs/test/VirtualScroller.js +281 -0
  94. package/commonjs/test/VirtualScroller.js.map +1 -0
  95. package/commonjs/utility/debounce.js +28 -6
  96. package/commonjs/utility/debounce.js.map +1 -1
  97. package/commonjs/utility/debug.js +51 -12
  98. package/commonjs/utility/debug.js.map +1 -1
  99. package/commonjs/utility/getStateSnapshot.js +50 -0
  100. package/commonjs/utility/getStateSnapshot.js.map +1 -0
  101. package/commonjs/utility/px.js +1 -1
  102. package/commonjs/utility/px.js.map +1 -1
  103. package/commonjs/utility/px.test.js +14 -0
  104. package/commonjs/utility/px.test.js.map +1 -0
  105. package/commonjs/utility/shallowEqual.js +1 -1
  106. package/commonjs/utility/shallowEqual.js.map +1 -1
  107. package/commonjs/utility/throttle.js.map +1 -1
  108. package/dom/index.cjs +4 -0
  109. package/dom/index.cjs.js +9 -0
  110. package/dom/index.d.ts +25 -0
  111. package/dom/index.js +1 -1
  112. package/dom/package.json +10 -4
  113. package/index.cjs +4 -0
  114. package/index.cjs.js +9 -0
  115. package/index.d.ts +99 -0
  116. package/index.js +1 -1
  117. package/modules/BeforeResize.js +305 -0
  118. package/modules/BeforeResize.js.map +1 -0
  119. package/modules/DOM/Engine.js +27 -0
  120. package/modules/DOM/Engine.js.map +1 -0
  121. package/modules/DOM/ItemsContainer.js +71 -0
  122. package/modules/DOM/ItemsContainer.js.map +1 -0
  123. package/modules/DOM/{WaitForStylesToLoad.js → ListTopOffsetWatcher.js} +72 -44
  124. package/modules/DOM/ListTopOffsetWatcher.js.map +1 -0
  125. package/modules/DOM/ScrollableContainer.js +68 -100
  126. package/modules/DOM/ScrollableContainer.js.map +1 -1
  127. package/modules/DOM/VirtualScroller.js +32 -28
  128. package/modules/DOM/VirtualScroller.js.map +1 -1
  129. package/modules/DOM/tbody.js +11 -9
  130. package/modules/DOM/tbody.js.map +1 -1
  131. package/modules/ItemHeights.js +28 -33
  132. package/modules/ItemHeights.js.map +1 -1
  133. package/modules/Layout.js +585 -214
  134. package/modules/Layout.js.map +1 -1
  135. package/modules/Layout.test.js +190 -0
  136. package/modules/Layout.test.js.map +1 -0
  137. package/modules/ListHeightMeasurement.js +117 -0
  138. package/modules/ListHeightMeasurement.js.map +1 -0
  139. package/modules/Resize.js +50 -39
  140. package/modules/Resize.js.map +1 -1
  141. package/modules/Scroll.js +139 -94
  142. package/modules/Scroll.js.map +1 -1
  143. package/modules/VirtualScroller.columns.js +36 -0
  144. package/modules/VirtualScroller.columns.js.map +1 -0
  145. package/modules/VirtualScroller.constructor.js +371 -0
  146. package/modules/VirtualScroller.constructor.js.map +1 -0
  147. package/modules/VirtualScroller.items.js +288 -0
  148. package/modules/VirtualScroller.items.js.map +1 -0
  149. package/modules/VirtualScroller.js +159 -1014
  150. package/modules/VirtualScroller.js.map +1 -1
  151. package/modules/VirtualScroller.layout.js +549 -0
  152. package/modules/VirtualScroller.layout.js.map +1 -0
  153. package/modules/VirtualScroller.onRender.js +337 -0
  154. package/modules/VirtualScroller.onRender.js.map +1 -0
  155. package/modules/VirtualScroller.resize.js +176 -0
  156. package/modules/VirtualScroller.resize.js.map +1 -0
  157. package/modules/VirtualScroller.state.js +283 -0
  158. package/modules/VirtualScroller.state.js.map +1 -0
  159. package/modules/VirtualScroller.verticalSpacing.js +54 -0
  160. package/modules/VirtualScroller.verticalSpacing.js.map +1 -0
  161. package/modules/getItemCoordinates.js.map +1 -1
  162. package/modules/getItemsDiff.js.map +1 -1
  163. package/modules/getVerticalSpacing.js +8 -8
  164. package/modules/getVerticalSpacing.js.map +1 -1
  165. package/modules/react/VirtualScroller.js +179 -634
  166. package/modules/react/VirtualScroller.js.map +1 -1
  167. package/modules/react/useClassName.js +18 -0
  168. package/modules/react/useClassName.js.map +1 -0
  169. package/modules/react/useHandleItemsChange.js +108 -0
  170. package/modules/react/useHandleItemsChange.js.map +1 -0
  171. package/modules/react/useInstanceMethods.js +28 -0
  172. package/modules/react/useInstanceMethods.js.map +1 -0
  173. package/modules/react/useItemKeys.js +52 -0
  174. package/modules/react/useItemKeys.js.map +1 -0
  175. package/modules/react/useOnItemHeightChange.js +24 -0
  176. package/modules/react/useOnItemHeightChange.js.map +1 -0
  177. package/modules/react/useOnItemStateChange.js +24 -0
  178. package/modules/react/useOnItemStateChange.js.map +1 -0
  179. package/modules/react/useState.js +132 -0
  180. package/modules/react/useState.js.map +1 -0
  181. package/modules/react/useStyle.js +19 -0
  182. package/modules/react/useStyle.js.map +1 -0
  183. package/modules/react/useVirtualScroller.js +51 -0
  184. package/modules/react/useVirtualScroller.js.map +1 -0
  185. package/modules/react/useVirtualScrollerStartStop.js +12 -0
  186. package/modules/react/useVirtualScrollerStartStop.js.map +1 -0
  187. package/modules/test/Engine.js +11 -0
  188. package/modules/test/Engine.js.map +1 -0
  189. package/modules/test/ItemsContainer.js +120 -0
  190. package/modules/test/ItemsContainer.js.map +1 -0
  191. package/modules/test/ScrollableContainer.js +123 -0
  192. package/modules/test/ScrollableContainer.js.map +1 -0
  193. package/modules/test/VirtualScroller.js +270 -0
  194. package/modules/test/VirtualScroller.js.map +1 -0
  195. package/modules/utility/debounce.js +28 -6
  196. package/modules/utility/debounce.js.map +1 -1
  197. package/modules/utility/debug.js +47 -10
  198. package/modules/utility/debug.js.map +1 -1
  199. package/modules/utility/getStateSnapshot.js +43 -0
  200. package/modules/utility/getStateSnapshot.js.map +1 -0
  201. package/modules/utility/px.js +1 -1
  202. package/modules/utility/px.js.map +1 -1
  203. package/modules/utility/px.test.js +9 -0
  204. package/modules/utility/px.test.js.map +1 -0
  205. package/modules/utility/shallowEqual.js +1 -1
  206. package/modules/utility/shallowEqual.js.map +1 -1
  207. package/modules/utility/throttle.js.map +1 -1
  208. package/package.json +54 -29
  209. package/react/index.cjs +4 -0
  210. package/react/index.cjs.js +9 -0
  211. package/react/index.d.ts +28 -0
  212. package/react/index.js +1 -1
  213. package/react/package.json +10 -4
  214. package/rollup.config.mjs +62 -0
  215. package/runnable/create-commonjs-package-json.js +11 -0
  216. package/source/BeforeResize.js +312 -0
  217. package/source/DOM/Engine.js +30 -0
  218. package/source/DOM/ItemsContainer.js +48 -0
  219. package/source/DOM/{WaitForStylesToLoad.js → ListTopOffsetWatcher.js} +61 -30
  220. package/source/DOM/ScrollableContainer.js +51 -73
  221. package/source/DOM/VirtualScroller.js +33 -18
  222. package/source/DOM/tbody.js +30 -21
  223. package/source/ItemHeights.js +27 -27
  224. package/source/Layout.js +629 -252
  225. package/source/Layout.test.js +176 -0
  226. package/source/ListHeightMeasurement.js +95 -0
  227. package/source/Resize.js +56 -32
  228. package/source/Scroll.js +135 -82
  229. package/source/VirtualScroller.columns.js +26 -0
  230. package/source/VirtualScroller.constructor.js +336 -0
  231. package/source/VirtualScroller.items.js +302 -0
  232. package/source/VirtualScroller.js +162 -936
  233. package/source/VirtualScroller.layout.js +539 -0
  234. package/source/VirtualScroller.onRender.js +345 -0
  235. package/source/VirtualScroller.resize.js +189 -0
  236. package/source/VirtualScroller.state.js +284 -0
  237. package/source/VirtualScroller.verticalSpacing.js +51 -0
  238. package/source/getVerticalSpacing.js +7 -7
  239. package/source/react/VirtualScroller.js +243 -603
  240. package/source/react/useClassName.js +14 -0
  241. package/source/react/useHandleItemsChange.js +115 -0
  242. package/source/react/useInstanceMethods.js +25 -0
  243. package/source/react/useItemKeys.js +59 -0
  244. package/source/react/useOnItemHeightChange.js +28 -0
  245. package/source/react/useOnItemStateChange.js +28 -0
  246. package/source/react/useState.js +114 -0
  247. package/source/react/useStyle.js +20 -0
  248. package/source/react/useVirtualScroller.js +59 -0
  249. package/source/react/useVirtualScrollerStartStop.js +12 -0
  250. package/source/test/Engine.js +11 -0
  251. package/source/test/ItemsContainer.js +87 -0
  252. package/source/test/ScrollableContainer.js +88 -0
  253. package/source/test/VirtualScroller.js +232 -0
  254. package/source/utility/debounce.js +22 -5
  255. package/source/utility/debug.js +34 -3
  256. package/source/utility/getStateSnapshot.js +36 -0
  257. package/source/utility/px.js +1 -1
  258. package/source/utility/px.test.js +9 -0
  259. package/website/index-bypass.html +195 -0
  260. package/website/index-grid.html +0 -1
  261. package/website/index-scrollableContainer.html +208 -0
  262. package/website/index-tbody-scrollableContainer.html +68 -0
  263. package/website/index-tbody.html +55 -0
  264. package/commonjs/DOM/RenderingEngine.js +0 -33
  265. package/commonjs/DOM/RenderingEngine.js.map +0 -1
  266. package/commonjs/DOM/Screen.js +0 -87
  267. package/commonjs/DOM/Screen.js.map +0 -1
  268. package/commonjs/DOM/WaitForStylesToLoad.js.map +0 -1
  269. package/commonjs/RestoreScroll.js +0 -118
  270. package/commonjs/RestoreScroll.js.map +0 -1
  271. package/dom/index.commonjs.js +0 -4
  272. package/index.commonjs.js +0 -4
  273. package/modules/DOM/RenderingEngine.js +0 -19
  274. package/modules/DOM/RenderingEngine.js.map +0 -1
  275. package/modules/DOM/Screen.js +0 -80
  276. package/modules/DOM/Screen.js.map +0 -1
  277. package/modules/DOM/WaitForStylesToLoad.js.map +0 -1
  278. package/modules/RestoreScroll.js +0 -111
  279. package/modules/RestoreScroll.js.map +0 -1
  280. package/react/index.commonjs.js +0 -4
  281. package/source/DOM/RenderingEngine.js +0 -22
  282. package/source/DOM/Screen.js +0 -51
  283. 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
+ }