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.
Files changed (248) hide show
  1. package/.gitlab-ci.yml +1 -1
  2. package/CHANGELOG.md +57 -0
  3. package/README.md +337 -160
  4. package/bundle/virtual-scroller-dom.js +1 -1
  5. package/bundle/virtual-scroller-dom.js.map +1 -1
  6. package/bundle/virtual-scroller-react.js +1 -1
  7. package/bundle/virtual-scroller-react.js.map +1 -1
  8. package/bundle/virtual-scroller.js +1 -1
  9. package/bundle/virtual-scroller.js.map +1 -1
  10. package/commonjs/BeforeResize.js +23 -27
  11. package/commonjs/BeforeResize.js.map +1 -1
  12. package/commonjs/DOM/Engine.js +7 -7
  13. package/commonjs/DOM/Engine.js.map +1 -1
  14. package/commonjs/DOM/ItemsContainer.js +1 -1
  15. package/commonjs/DOM/ItemsContainer.js.map +1 -1
  16. package/commonjs/DOM/ListTopOffsetWatcher.js +15 -9
  17. package/commonjs/DOM/ListTopOffsetWatcher.js.map +1 -1
  18. package/commonjs/DOM/ScrollableContainer.js +28 -28
  19. package/commonjs/DOM/ScrollableContainer.js.map +1 -1
  20. package/commonjs/DOM/VirtualScroller.js +20 -17
  21. package/commonjs/DOM/VirtualScroller.js.map +1 -1
  22. package/commonjs/DOM/tbody.js +16 -10
  23. package/commonjs/DOM/tbody.js.map +1 -1
  24. package/commonjs/ItemHeights.js +23 -17
  25. package/commonjs/ItemHeights.js.map +1 -1
  26. package/commonjs/Layout.js +15 -13
  27. package/commonjs/Layout.js.map +1 -1
  28. package/commonjs/Layout.test.js +8 -3
  29. package/commonjs/Layout.test.js.map +1 -1
  30. package/commonjs/{ListHeightChangeWatcher.js → ListHeightMeasurement.js} +26 -28
  31. package/commonjs/ListHeightMeasurement.js.map +1 -0
  32. package/commonjs/Resize.js +38 -28
  33. package/commonjs/Resize.js.map +1 -1
  34. package/commonjs/Scroll.js +28 -44
  35. package/commonjs/Scroll.js.map +1 -1
  36. package/commonjs/VirtualScroller.columns.js +43 -0
  37. package/commonjs/VirtualScroller.columns.js.map +1 -0
  38. package/commonjs/VirtualScroller.constructor.js +408 -0
  39. package/commonjs/VirtualScroller.constructor.js.map +1 -0
  40. package/commonjs/VirtualScroller.items.js +305 -0
  41. package/commonjs/VirtualScroller.items.js.map +1 -0
  42. package/commonjs/VirtualScroller.js +132 -1872
  43. package/commonjs/VirtualScroller.js.map +1 -1
  44. package/commonjs/VirtualScroller.layout.js +562 -0
  45. package/commonjs/VirtualScroller.layout.js.map +1 -0
  46. package/commonjs/VirtualScroller.onRender.js +357 -0
  47. package/commonjs/VirtualScroller.onRender.js.map +1 -0
  48. package/commonjs/VirtualScroller.resize.js +186 -0
  49. package/commonjs/VirtualScroller.resize.js.map +1 -0
  50. package/commonjs/VirtualScroller.state.js +301 -0
  51. package/commonjs/VirtualScroller.state.js.map +1 -0
  52. package/commonjs/VirtualScroller.verticalSpacing.js +65 -0
  53. package/commonjs/VirtualScroller.verticalSpacing.js.map +1 -0
  54. package/commonjs/getItemCoordinates.js.map +1 -1
  55. package/commonjs/getItemsDiff.js.map +1 -1
  56. package/commonjs/getVerticalSpacing.js.map +1 -1
  57. package/commonjs/package.json +5 -0
  58. package/commonjs/react/VirtualScroller.js +184 -618
  59. package/commonjs/react/VirtualScroller.js.map +1 -1
  60. package/commonjs/react/useClassName.js +26 -0
  61. package/commonjs/react/useClassName.js.map +1 -0
  62. package/commonjs/react/useHandleItemsChange.js +116 -0
  63. package/commonjs/react/useHandleItemsChange.js.map +1 -0
  64. package/commonjs/react/useInstanceMethods.js +37 -0
  65. package/commonjs/react/useInstanceMethods.js.map +1 -0
  66. package/commonjs/react/useItemKeys.js +60 -0
  67. package/commonjs/react/useItemKeys.js.map +1 -0
  68. package/commonjs/react/useOnItemHeightChange.js +32 -0
  69. package/commonjs/react/useOnItemHeightChange.js.map +1 -0
  70. package/commonjs/react/useOnItemStateChange.js +32 -0
  71. package/commonjs/react/useOnItemStateChange.js.map +1 -0
  72. package/commonjs/react/useState.js +140 -0
  73. package/commonjs/react/useState.js.map +1 -0
  74. package/commonjs/react/useStyle.js +29 -0
  75. package/commonjs/react/useStyle.js.map +1 -0
  76. package/commonjs/react/useVirtualScroller.js +62 -0
  77. package/commonjs/react/useVirtualScroller.js.map +1 -0
  78. package/commonjs/react/useVirtualScrollerStartStop.js +20 -0
  79. package/commonjs/react/useVirtualScrollerStartStop.js.map +1 -0
  80. package/commonjs/test/Engine.js +23 -0
  81. package/commonjs/test/Engine.js.map +1 -0
  82. package/commonjs/test/ItemsContainer.js +127 -0
  83. package/commonjs/test/ItemsContainer.js.map +1 -0
  84. package/commonjs/test/ScrollableContainer.js +130 -0
  85. package/commonjs/test/ScrollableContainer.js.map +1 -0
  86. package/commonjs/test/VirtualScroller.js +281 -0
  87. package/commonjs/test/VirtualScroller.js.map +1 -0
  88. package/commonjs/utility/debounce.js +2 -2
  89. package/commonjs/utility/debounce.js.map +1 -1
  90. package/commonjs/utility/debug.js.map +1 -1
  91. package/commonjs/utility/getStateSnapshot.js +2 -2
  92. package/commonjs/utility/getStateSnapshot.js.map +1 -1
  93. package/commonjs/utility/px.js.map +1 -1
  94. package/commonjs/utility/px.test.js +1 -1
  95. package/commonjs/utility/px.test.js.map +1 -1
  96. package/commonjs/utility/shallowEqual.js +1 -1
  97. package/commonjs/utility/shallowEqual.js.map +1 -1
  98. package/commonjs/utility/throttle.js.map +1 -1
  99. package/dom/index.cjs +4 -0
  100. package/dom/index.cjs.js +9 -0
  101. package/dom/index.d.ts +6 -4
  102. package/dom/index.js +1 -1
  103. package/dom/package.json +10 -4
  104. package/index.cjs +4 -0
  105. package/index.cjs.js +9 -0
  106. package/index.d.ts +30 -15
  107. package/index.js +1 -1
  108. package/modules/BeforeResize.js +22 -27
  109. package/modules/BeforeResize.js.map +1 -1
  110. package/modules/DOM/Engine.js +6 -6
  111. package/modules/DOM/Engine.js.map +1 -1
  112. package/modules/DOM/ItemsContainer.js +1 -1
  113. package/modules/DOM/ItemsContainer.js.map +1 -1
  114. package/modules/DOM/ListTopOffsetWatcher.js +15 -9
  115. package/modules/DOM/ListTopOffsetWatcher.js.map +1 -1
  116. package/modules/DOM/ScrollableContainer.js +28 -28
  117. package/modules/DOM/ScrollableContainer.js.map +1 -1
  118. package/modules/DOM/VirtualScroller.js +19 -16
  119. package/modules/DOM/VirtualScroller.js.map +1 -1
  120. package/modules/DOM/tbody.js +11 -9
  121. package/modules/DOM/tbody.js.map +1 -1
  122. package/modules/ItemHeights.js +22 -16
  123. package/modules/ItemHeights.js.map +1 -1
  124. package/modules/Layout.js +14 -12
  125. package/modules/Layout.js.map +1 -1
  126. package/modules/Layout.test.js +8 -3
  127. package/modules/Layout.test.js.map +1 -1
  128. package/modules/{ListHeightChangeWatcher.js → ListHeightMeasurement.js} +25 -27
  129. package/modules/ListHeightMeasurement.js.map +1 -0
  130. package/modules/Resize.js +38 -28
  131. package/modules/Resize.js.map +1 -1
  132. package/modules/Scroll.js +28 -44
  133. package/modules/Scroll.js.map +1 -1
  134. package/modules/VirtualScroller.columns.js +36 -0
  135. package/modules/VirtualScroller.columns.js.map +1 -0
  136. package/modules/VirtualScroller.constructor.js +371 -0
  137. package/modules/VirtualScroller.constructor.js.map +1 -0
  138. package/modules/VirtualScroller.items.js +288 -0
  139. package/modules/VirtualScroller.items.js.map +1 -0
  140. package/modules/VirtualScroller.js +132 -1860
  141. package/modules/VirtualScroller.js.map +1 -1
  142. package/modules/VirtualScroller.layout.js +549 -0
  143. package/modules/VirtualScroller.layout.js.map +1 -0
  144. package/modules/VirtualScroller.onRender.js +337 -0
  145. package/modules/VirtualScroller.onRender.js.map +1 -0
  146. package/modules/VirtualScroller.resize.js +176 -0
  147. package/modules/VirtualScroller.resize.js.map +1 -0
  148. package/modules/VirtualScroller.state.js +283 -0
  149. package/modules/VirtualScroller.state.js.map +1 -0
  150. package/modules/VirtualScroller.verticalSpacing.js +54 -0
  151. package/modules/VirtualScroller.verticalSpacing.js.map +1 -0
  152. package/modules/getItemCoordinates.js.map +1 -1
  153. package/modules/getItemsDiff.js.map +1 -1
  154. package/modules/getVerticalSpacing.js.map +1 -1
  155. package/modules/react/VirtualScroller.js +176 -625
  156. package/modules/react/VirtualScroller.js.map +1 -1
  157. package/modules/react/useClassName.js +18 -0
  158. package/modules/react/useClassName.js.map +1 -0
  159. package/modules/react/useHandleItemsChange.js +108 -0
  160. package/modules/react/useHandleItemsChange.js.map +1 -0
  161. package/modules/react/useInstanceMethods.js +28 -0
  162. package/modules/react/useInstanceMethods.js.map +1 -0
  163. package/modules/react/useItemKeys.js +52 -0
  164. package/modules/react/useItemKeys.js.map +1 -0
  165. package/modules/react/useOnItemHeightChange.js +24 -0
  166. package/modules/react/useOnItemHeightChange.js.map +1 -0
  167. package/modules/react/useOnItemStateChange.js +24 -0
  168. package/modules/react/useOnItemStateChange.js.map +1 -0
  169. package/modules/react/useState.js +132 -0
  170. package/modules/react/useState.js.map +1 -0
  171. package/modules/react/useStyle.js +19 -0
  172. package/modules/react/useStyle.js.map +1 -0
  173. package/modules/react/useVirtualScroller.js +51 -0
  174. package/modules/react/useVirtualScroller.js.map +1 -0
  175. package/modules/react/useVirtualScrollerStartStop.js +12 -0
  176. package/modules/react/useVirtualScrollerStartStop.js.map +1 -0
  177. package/modules/test/Engine.js +11 -0
  178. package/modules/test/Engine.js.map +1 -0
  179. package/modules/test/ItemsContainer.js +120 -0
  180. package/modules/test/ItemsContainer.js.map +1 -0
  181. package/modules/test/ScrollableContainer.js +123 -0
  182. package/modules/test/ScrollableContainer.js.map +1 -0
  183. package/modules/test/VirtualScroller.js +270 -0
  184. package/modules/test/VirtualScroller.js.map +1 -0
  185. package/modules/utility/debounce.js +2 -2
  186. package/modules/utility/debounce.js.map +1 -1
  187. package/modules/utility/debug.js.map +1 -1
  188. package/modules/utility/getStateSnapshot.js +2 -2
  189. package/modules/utility/getStateSnapshot.js.map +1 -1
  190. package/modules/utility/px.js.map +1 -1
  191. package/modules/utility/px.test.js +1 -1
  192. package/modules/utility/px.test.js.map +1 -1
  193. package/modules/utility/shallowEqual.js +1 -1
  194. package/modules/utility/shallowEqual.js.map +1 -1
  195. package/modules/utility/throttle.js.map +1 -1
  196. package/package.json +46 -23
  197. package/react/index.cjs +4 -0
  198. package/react/index.cjs.js +9 -0
  199. package/react/index.d.ts +10 -9
  200. package/react/index.js +1 -1
  201. package/react/package.json +10 -4
  202. package/rollup.config.mjs +62 -0
  203. package/runnable/create-commonjs-package-json.js +11 -0
  204. package/source/BeforeResize.js +16 -21
  205. package/source/DOM/Engine.js +8 -10
  206. package/source/DOM/ListTopOffsetWatcher.js +13 -8
  207. package/source/DOM/ScrollableContainer.js +23 -21
  208. package/source/DOM/VirtualScroller.js +27 -11
  209. package/source/DOM/tbody.js +30 -21
  210. package/source/ItemHeights.js +19 -14
  211. package/source/Layout.js +12 -9
  212. package/source/Layout.test.js +8 -3
  213. package/source/{ListHeightChangeWatcher.js → ListHeightMeasurement.js} +21 -20
  214. package/source/Resize.js +41 -25
  215. package/source/Scroll.js +27 -35
  216. package/source/VirtualScroller.columns.js +26 -0
  217. package/source/VirtualScroller.constructor.js +336 -0
  218. package/source/VirtualScroller.items.js +302 -0
  219. package/source/VirtualScroller.js +144 -1872
  220. package/source/VirtualScroller.layout.js +539 -0
  221. package/source/VirtualScroller.onRender.js +345 -0
  222. package/source/VirtualScroller.resize.js +189 -0
  223. package/source/VirtualScroller.state.js +284 -0
  224. package/source/VirtualScroller.verticalSpacing.js +51 -0
  225. package/source/react/VirtualScroller.js +243 -587
  226. package/source/react/useClassName.js +14 -0
  227. package/source/react/useHandleItemsChange.js +115 -0
  228. package/source/react/useInstanceMethods.js +25 -0
  229. package/source/react/useItemKeys.js +59 -0
  230. package/source/react/useOnItemHeightChange.js +28 -0
  231. package/source/react/useOnItemStateChange.js +28 -0
  232. package/source/react/useState.js +114 -0
  233. package/source/react/useStyle.js +20 -0
  234. package/source/react/useVirtualScroller.js +59 -0
  235. package/source/react/useVirtualScrollerStartStop.js +12 -0
  236. package/source/test/Engine.js +11 -0
  237. package/source/test/ItemsContainer.js +87 -0
  238. package/source/test/ScrollableContainer.js +88 -0
  239. package/source/test/VirtualScroller.js +232 -0
  240. package/source/utility/debounce.js +2 -2
  241. package/source/utility/px.test.js +1 -1
  242. package/babel.config.js +0 -25
  243. package/babel.js +0 -5
  244. package/commonjs/ListHeightChangeWatcher.js.map +0 -1
  245. package/dom/index.commonjs.js +0 -4
  246. package/index.commonjs.js +0 -4
  247. package/modules/ListHeightChangeWatcher.js.map +0 -1
  248. package/react/index.commonjs.js +0 -4
@@ -1,55 +1,29 @@
1
1
  "use strict";
2
2
 
3
- function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
4
-
5
3
  Object.defineProperty(exports, "__esModule", {
6
4
  value: true
7
5
  });
8
6
  exports["default"] = void 0;
9
7
 
10
- var _requestAnimationFrameTimeout = require("request-animation-frame-timeout");
11
-
12
- var _tbody = require("./DOM/tbody");
13
-
14
- var _Engine = _interopRequireDefault(require("./DOM/Engine"));
15
-
16
- var _Layout = _interopRequireWildcard(require("./Layout"));
17
-
18
- var _Resize = _interopRequireDefault(require("./Resize"));
19
-
20
- var _BeforeResize = _interopRequireDefault(require("./BeforeResize"));
21
-
22
- var _Scroll = _interopRequireDefault(require("./Scroll"));
23
-
24
- var _ListHeightChangeWatcher = _interopRequireDefault(require("./ListHeightChangeWatcher"));
25
-
26
- var _ItemHeights = _interopRequireDefault(require("./ItemHeights"));
27
-
28
- var _getItemsDiff2 = _interopRequireDefault(require("./getItemsDiff"));
29
-
30
- var _getVerticalSpacing = _interopRequireDefault(require("./getVerticalSpacing"));
31
-
32
- var _debug = _interopRequireWildcard(require("./utility/debug"));
8
+ var _VirtualScrollerConstructor = _interopRequireDefault(require("./VirtualScroller.constructor.js"));
33
9
 
34
- var _shallowEqual = _interopRequireDefault(require("./utility/shallowEqual"));
10
+ var _tbody = require("./DOM/tbody.js");
35
11
 
36
- var _getStateSnapshot = _interopRequireDefault(require("./utility/getStateSnapshot"));
12
+ var _Layout = require("./Layout.js");
37
13
 
38
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
39
-
40
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
14
+ var _debug = _interopRequireDefault(require("./utility/debug.js"));
41
15
 
42
16
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
43
17
 
44
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
18
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
45
19
 
46
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
20
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
47
21
 
48
22
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
49
23
 
50
24
  function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
51
25
 
52
- function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
26
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
53
27
 
54
28
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
55
29
 
@@ -67,989 +41,155 @@ var VirtualScroller = /*#__PURE__*/function () {
67
41
 
68
42
  _classCallCheck(this, VirtualScroller);
69
43
 
70
- _defineProperty(this, "getActualColumnsCountForState", function () {
71
- return _this._getColumnsCount ? _this._getColumnsCount(_this.scrollableContainer) : undefined;
72
- });
73
-
74
- _defineProperty(this, "getVerticalSpacing", function () {
75
- return _this.verticalSpacing || 0;
76
- });
77
-
78
- _defineProperty(this, "getListTopOffsetInsideScrollableContainer", function () {
79
- var listTopOffset = _this.scrollableContainer.getItemsContainerTopOffset();
80
-
81
- if (_this.listTopOffsetWatcher) {
82
- _this.listTopOffsetWatcher.onListTopOffset(listTopOffset);
44
+ _defineProperty(this, "stop", function () {
45
+ if (!_this._isActive) {
46
+ throw new Error('[virtual-scroller] Can\'t stop a `VirtualScroller` that hasn\'t been started');
83
47
  }
84
48
 
85
- return listTopOffset;
86
- });
87
-
88
- _defineProperty(this, "stop", function () {
89
- _this.isRendered = false;
49
+ _this._isActive = false;
50
+ (0, _debug["default"])('~ Stop ~');
90
51
 
91
52
  _this.resize.stop();
92
53
 
93
- _this.scroll.stop();
54
+ _this.scroll.stop(); // Stop `ListTopOffsetWatcher` if it has been started.
55
+ // There seems to be no need to restart `ListTopOffsetWatcher`.
56
+ // It's mainly a hacky workaround for development mode anyway.
57
+
94
58
 
95
- if (_this.listTopOffsetWatcher) {
59
+ if (_this.listTopOffsetWatcher && _this.listTopOffsetWatcher.isStarted()) {
96
60
  _this.listTopOffsetWatcher.stop();
97
- }
61
+ } // Cancel any scheduled layout.
62
+
98
63
 
99
64
  _this.cancelLayoutTimer({});
100
65
  });
101
66
 
102
- _defineProperty(this, "willUpdateState", function (newState, prevState) {
103
- // Ignore setting initial state.
104
- if (!prevState) {
105
- return;
106
- } // This function isn't currently used.
107
- // Was previously used to capture scroll position in order to
108
- // restore it later after the new state is rendered.
67
+ _defineProperty(this, "updateLayout", function () {
68
+ _this.hasToBeStarted();
109
69
 
70
+ _this.onUpdateShownItemIndexes({
71
+ reason: _Layout.LAYOUT_REASON.MANUAL
72
+ });
110
73
  });
111
74
 
112
- _defineProperty(this, "didUpdateState", function (prevState) {
113
- var newState = _this.getState();
114
-
115
- if (_this.onStateChange) {
116
- if (!(0, _shallowEqual["default"])(newState, prevState)) {
117
- _this.onStateChange(newState, prevState);
118
- }
119
- } // Ignore setting initial state.
120
-
121
-
122
- if (!prevState) {
123
- return;
124
- }
125
-
126
- if (!_this.isRendered) {
127
- return;
128
- }
129
-
130
- (0, _debug["default"])('~ Rendered ~');
131
-
132
- if ((0, _debug.isDebug)()) {
133
- (0, _debug["default"])('State', (0, _getStateSnapshot["default"])(newState));
134
- }
135
-
136
- var layoutUpdateReason;
137
-
138
- if (_this.firstNonMeasuredItemIndex !== undefined) {
139
- layoutUpdateReason = _Layout.LAYOUT_REASON.ACTUAL_ITEM_HEIGHTS_HAVE_BEEN_MEASURED;
140
- }
141
-
142
- if (_this.resetLayoutAfterResize) {
143
- layoutUpdateReason = _Layout.LAYOUT_REASON.VIEWPORT_WIDTH_CHANGED;
144
- } // If `this.resetLayoutAfterResize` flag was reset after calling
145
- // `this.measureItemHeightsAndSpacingAndUpdateTablePadding()`
146
- // then there would be a bug because
147
- // `this.measureItemHeightsAndSpacingAndUpdateTablePadding()`
148
- // calls `this.setState({ verticalSpacing })` which calls
149
- // `this.didUpdateState()` immediately, so `this.resetLayoutAfterResize`
150
- // flag wouldn't be reset by that time and would trigger things
151
- // like `this.itemHeights.reset()` a second time.
152
- //
153
- // So, instead read the value of `this.resetLayoutAfterResize` flag
154
- // and reset it right away to prevent any such potential bugs.
155
- //
156
-
157
-
158
- var resetLayoutAfterResize = _this.resetLayoutAfterResize; // Reset `this.firstNonMeasuredItemIndex`.
75
+ _defineProperty(this, "onRender", function () {
76
+ _this._onRender(_this.getState(), _this.previousState);
77
+ });
159
78
 
160
- _this.firstNonMeasuredItemIndex = undefined; // Reset `this.resetLayoutAfterResize` flag.
79
+ _VirtualScrollerConstructor["default"].call(this, getItemsContainerElement, items, options);
80
+ }
81
+ /**
82
+ * Should be invoked after a "container" DOM Element is mounted (inserted into the DOM tree).
83
+ */
161
84
 
162
- _this.resetLayoutAfterResize = undefined; // Reset `this.newItemsWillBeRendered` flag.
163
85
 
164
- _this.newItemsWillBeRendered = undefined; // Reset `this.itemHeightsThatChangedWhileNewItemsWereBeingRendered`.
86
+ _createClass(VirtualScroller, [{
87
+ key: "start",
88
+ value: function start() {
89
+ if (this._isActive) {
90
+ throw new Error('[virtual-scroller] `VirtualScroller` has already been started');
91
+ } // If has been stopped previously.
165
92
 
166
- _this.itemHeightsThatChangedWhileNewItemsWereBeingRendered = undefined; // Reset `this.itemStatesThatChangedWhileNewItemsWereBeingRendered`.
167
93
 
168
- _this.itemStatesThatChangedWhileNewItemsWereBeingRendered = undefined;
94
+ var isRestart = this._isActive === false;
169
95
 
170
- if (resetLayoutAfterResize) {
171
- // Reset measured item heights on viewport width change.
172
- _this.itemHeights.reset(); // Reset `verticalSpacing` (will be re-measured).
96
+ if (!isRestart) {
97
+ // If no custom one has been configured, uses the default one.
98
+ // Also sets the initial state.
99
+ if (!this._usesCustomStateStorage) {
100
+ this.useDefaultStateStorage();
101
+ } // If `render()` function parameter was passed,
102
+ // perform an initial render.
173
103
 
174
104
 
175
- _this.verticalSpacing = undefined;
105
+ if (this._render) {
106
+ this._render(this.getState());
107
+ }
176
108
  }
177
109
 
178
- var previousItems = prevState.items;
179
- var newItems = newState.items; // Even if `this.newItemsWillBeRendered` flag is `true`,
180
- // `newItems` could still be equal to `previousItems`.
181
- // For example, when `setState()` calls don't update `state` immediately
182
- // and a developer first calls `setItems(newItems)` and then calls `setItems(oldItems)`:
183
- // in that case, `this.newItemsWillBeRendered` flag will be `true` but the actual `items`
184
- // in state wouldn't have changed due to the first `setState()` call being overwritten
185
- // by the second `setState()` call (that's called "batching state updates" in React).
186
-
187
- if (newItems !== previousItems) {
188
- var itemsDiff = _this.getItemsDiff(previousItems, newItems);
110
+ (0, _debug["default"])('~ Start ~'); // `this._isActive = true` should be placed somewhere at the start of this function.
189
111
 
190
- if (itemsDiff) {
191
- // The call to `.onPrepend()` must precede the call to `.measureItemHeights()`
192
- // which is called in `.onRendered()`.
193
- // `this.itemHeights.onPrepend()` updates `firstMeasuredItemIndex`
194
- // and `lastMeasuredItemIndex` of `this.itemHeights`.
195
- var prependedItemsCount = itemsDiff.prependedItemsCount;
112
+ this._isActive = true; // Reset `ListHeightMeasurement` just in case it has some "leftover" state.
196
113
 
197
- _this.itemHeights.onPrepend(prependedItemsCount);
198
- } else {
199
- _this.itemHeights.reset(); // `newState.itemHeights` is an array of `undefined`s.
114
+ this.listHeightMeasurement.reset(); // Reset `_isResizing` flag just in case it has some "leftover" value.
200
115
 
116
+ this._isResizing = undefined; // Reset `_isSettingNewItems` flag just in case it has some "leftover" value.
201
117
 
202
- _this.itemHeights.initialize(newState.itemHeights);
203
- }
118
+ this._isSettingNewItems = undefined; // Work around `<tbody/>` not being able to have `padding`.
119
+ // https://gitlab.com/catamphetamine/virtual-scroller/-/issues/1
204
120
 
205
- if (!resetLayoutAfterResize) {
206
- // The call to `this.onNewItemsRendered()` must precede the call to
207
- // `.measureItemHeights()` which is called in `.onRendered()` because
208
- // `this.onNewItemsRendered()` updates `firstMeasuredItemIndex` and
209
- // `lastMeasuredItemIndex` of `this.itemHeights` in case of a prepend.
210
- //
211
- // If after prepending items the scroll position
212
- // should be "restored" so that there's no "jump" of content
213
- // then it means that all previous items have just been rendered
214
- // in a single pass, and there's no need to update layout again.
215
- //
216
- if (_this.onNewItemsRendered(itemsDiff, newState) !== 'SEAMLESS_PREPEND') {
217
- layoutUpdateReason = _Layout.LAYOUT_REASON.ITEMS_CHANGED;
218
- }
121
+ if (this.tbody) {
122
+ if (!(0, _tbody.hasTbodyStyles)(this.getItemsContainerElement())) {
123
+ (0, _tbody.addTbodyStyles)(this.getItemsContainerElement());
219
124
  }
220
- }
221
-
222
- var stateUpdate; // Re-measure item heights.
223
- // Also, measure vertical spacing (if not measured) and fix `<table/>` padding.
125
+ } // If there was a pending state update that didn't get applied
126
+ // because of stopping the `VirtualScroller`, apply that state update now.
224
127
  //
225
- // This block should go after `if (newItems !== previousItems) {}`
226
- // because `this.itemHeights` can get `.reset()` there, which would
227
- // discard all the measurements done here, and having currently shown
228
- // item height measurements is required.
128
+ // The pending state update won't get applied if the scrollable container width
129
+ // has changed but that's ok because that state update currently could only contain:
130
+ // * `scrollableContainerWidth`
131
+ // * `verticalSpacing`
132
+ // * `beforeResize`
133
+ // All of those get rewritten in `onResize()` anyway.
229
134
  //
230
135
 
231
- if (newState.firstShownItemIndex !== prevState.firstShownItemIndex || newState.lastShownItemIndex !== prevState.lastShownItemIndex || newState.items !== prevState.items || resetLayoutAfterResize) {
232
- var verticalSpacingStateUpdate = _this.measureItemHeightsAndSpacingAndUpdateTablePadding();
233
-
234
- if (verticalSpacingStateUpdate) {
235
- stateUpdate = _objectSpread(_objectSpread({}, stateUpdate), verticalSpacingStateUpdate);
236
- }
237
- } // Clean up "before resize" item heights and adjust the scroll position accordingly.
238
- // Calling `this.beforeResize.cleanUpBeforeResizeItemHeights()` might trigger
239
- // a `this.setState()` call but that wouldn't matter because `beforeResize`
240
- // properties have already been modified directly in `state` (a hacky technique)
241
136
 
137
+ var stateUpdate = this._stoppedStateUpdate;
138
+ this._stoppedStateUpdate = undefined; // Reset `this.verticalSpacing` so that it re-measures it in cases when
139
+ // the `VirtualScroller` was previously stopped and is now being restarted.
140
+ // The rationale is that a previously captured inter-item vertical spacing
141
+ // can't be "trusted" in a sense that the user might have resized the window
142
+ // after the previous `state` has been snapshotted.
143
+ // If the user has resized the window, then changing window width might have
144
+ // activated different CSS `@media()` "queries" resulting in a potentially different
145
+ // vertical spacing after the restart.
146
+ // If it's not a restart then `this.verticalSpacing` is `undefined` anyway.
242
147
 
243
- var cleanedUpBeforeResize = _this.beforeResize.cleanUpBeforeResizeItemHeights(prevState);
148
+ this.verticalSpacing = undefined;
149
+ var verticalSpacingStateUpdate = this.measureItemHeightsAndSpacing();
244
150
 
245
- if (cleanedUpBeforeResize !== undefined) {
246
- var scrollBy = cleanedUpBeforeResize.scrollBy,
247
- beforeResize = cleanedUpBeforeResize.beforeResize;
248
- (0, _debug["default"])('Correct scroll position by', scrollBy);
249
-
250
- _this.scroll.scrollByY(scrollBy);
251
-
252
- stateUpdate = _objectSpread(_objectSpread({}, stateUpdate), {}, {
253
- beforeResize: beforeResize
254
- });
151
+ if (verticalSpacingStateUpdate) {
152
+ stateUpdate = _objectSpread(_objectSpread({}, stateUpdate), verticalSpacingStateUpdate);
255
153
  }
256
154
 
257
- if (layoutUpdateReason) {
258
- _this.updateStateRightAfterRender({
259
- stateUpdate: stateUpdate,
260
- reason: layoutUpdateReason
261
- });
262
- } else if (stateUpdate) {
263
- _this.setState(stateUpdate);
264
- }
265
- });
155
+ this.resize.start();
156
+ this.scroll.start(); // If `scrollableContainerWidth` hasn't been measured yet,
157
+ // measure it and write it to state.
266
158
 
267
- _defineProperty(this, "updateShownItemIndexes", function (_ref) {
268
- var stateUpdate = _ref.stateUpdate;
269
- var startedAt = Date.now(); // Get shown item indexes.
270
-
271
- var _this$getShownItemInd = _this.getShownItemIndexes(),
272
- firstShownItemIndex = _this$getShownItemInd.firstShownItemIndex,
273
- lastShownItemIndex = _this$getShownItemInd.lastShownItemIndex,
274
- shownItemsHeight = _this$getShownItemInd.shownItemsHeight,
275
- firstNonMeasuredItemIndex = _this$getShownItemInd.firstNonMeasuredItemIndex; // If scroll position is scheduled to be restored after render,
276
- // then the "anchor" item must be rendered, and all of the prepended
277
- // items before it, all in a single pass. This way, all of the
278
- // prepended items' heights could be measured right after the render
279
- // has finished, and the scroll position can then be immediately restored.
280
-
281
-
282
- if (_this.listHeightChangeWatcher.hasSnapshot()) {
283
- if (lastShownItemIndex < _this.listHeightChangeWatcher.getAnchorItemIndex()) {
284
- lastShownItemIndex = _this.listHeightChangeWatcher.getAnchorItemIndex();
285
- } // `firstShownItemIndex` is always `0` when prepending items.
286
- // And `lastShownItemIndex` always covers all prepended items in this case.
287
- // None of the prepended items have been rendered before,
288
- // so their heights are unknown. The code at the start of this function
289
- // did therefore set `firstNonMeasuredItemIndex` to non-`undefined`
290
- // in order to render just the first prepended item in order to
291
- // measure it, and only then make a decision on how many other
292
- // prepended items to render. But since we've instructed the code
293
- // to show all of the prepended items at once, there's no need to
294
- // "redo layout after render". Additionally, if layout was re-done
295
- // after render, then there would be a short interval of visual
296
- // "jitter" due to the scroll position not being restored because it'd
297
- // wait for the second layout to finish instead of being restored
298
- // right after the first one.
299
-
300
-
301
- firstNonMeasuredItemIndex = undefined;
302
- } // Validate the heights of items to be hidden on next render.
303
- // For example, a user could click a "Show more" button,
304
- // or an "Expand YouTube video" button, which would result
305
- // in the actual height of the list item being different
306
- // from what has been initially measured in `this.itemHeights[i]`,
307
- // if the developer didn't call `.onItemStateChange()` and `.onItemHeightChange(i)`.
308
-
309
-
310
- if (!_this.validateWillBeHiddenItemHeightsAreAccurate(firstShownItemIndex, lastShownItemIndex)) {
311
- (0, _debug["default"])('~ Because some of the will-be-hidden item heights (listed above) have changed since they\'ve last been measured, redo layout. ~'); // Redo layout, now with the correct item heights.
312
-
313
- return _this.updateShownItemIndexes({
314
- stateUpdate: stateUpdate
159
+ if (this.getState().scrollableContainerWidth === undefined) {
160
+ var scrollableContainerWidth = this.scrollableContainer.getWidth();
161
+ stateUpdate = _objectSpread(_objectSpread({}, stateUpdate), {}, {
162
+ scrollableContainerWidth: scrollableContainerWidth
315
163
  });
316
- } // Measure "before" items height.
317
-
318
-
319
- var beforeItemsHeight = _this.layout.getBeforeItemsHeight(firstShownItemIndex); // Measure "after" items height.
320
-
321
-
322
- var afterItemsHeight = _this.layout.getAfterItemsHeight(lastShownItemIndex, _this.getItemsCount());
323
-
324
- var layoutDuration = Date.now() - startedAt; // Debugging.
325
-
326
- (0, _debug["default"])('~ Layout values ' + (_this.bypass ? '(bypass) ' : '') + '~');
327
-
328
- if (layoutDuration < SLOW_LAYOUT_DURATION) {// log('Calculated in', layoutDuration, 'ms')
329
164
  } else {
330
- (0, _debug.warn)('Layout calculated in', layoutDuration, 'ms');
331
- }
332
-
333
- if (_this._getColumnsCount) {
334
- (0, _debug["default"])('Columns count', _this.getColumnsCount());
335
- }
336
-
337
- (0, _debug["default"])('First shown item index', firstShownItemIndex);
338
- (0, _debug["default"])('Last shown item index', lastShownItemIndex);
339
- (0, _debug["default"])('Before items height', beforeItemsHeight);
340
- (0, _debug["default"])('After items height (actual or estimated)', afterItemsHeight);
341
- (0, _debug["default"])('Average item height (used for estimated after items height calculation)', _this.itemHeights.getAverage());
342
-
343
- if ((0, _debug.isDebug)()) {
344
- (0, _debug["default"])('Item heights', _this.getState().itemHeights.slice());
345
- (0, _debug["default"])('Item states', _this.getState().itemStates.slice());
346
- } // Optionally preload items to be rendered.
347
-
348
-
349
- _this.onBeforeShowItems(_this.getState().items, _this.getState().itemHeights, firstShownItemIndex, lastShownItemIndex); // Set `this.firstNonMeasuredItemIndex`.
350
-
351
-
352
- _this.firstNonMeasuredItemIndex = firstNonMeasuredItemIndex; // Set "previously calculated layout".
353
- //
354
- // The "previously calculated layout" feature is not currently used.
355
- //
356
- // The current layout snapshot could be stored as a "previously calculated layout" variable
357
- // so that it could theoretically be used when calculating new layout incrementally
358
- // rather than from scratch, which would be an optimization.
359
- //
360
- // Currently, this feature is not used, and `shownItemsHeight` property
361
- // is not returned at all, so don't set any "previously calculated layout".
362
- //
363
-
364
- if (shownItemsHeight === undefined) {
365
- _this.previouslyCalculatedLayout = undefined;
366
- } else {
367
- // If "previously calculated layout" feature would be implmeneted,
368
- // then this code would set "previously calculate layout" instance variable.
369
- //
370
- // What for would this instance variable be used?
371
- //
372
- // Instead of using a `this.previouslyCalculatedLayout` instance variable,
373
- // this code could use `this.getState()` because it reflects what's currently on screen,
374
- // but there's a single edge case when it could go out of sync —
375
- // updating item heights externally via `.onItemHeightChange(i)`.
376
- //
377
- // If, for example, an item height was updated externally via `.onItemHeightChange(i)`
378
- // then `this.getState().itemHeights` would get updated immediately but
379
- // `this.getState().beforeItemsHeight` or `this.getState().afterItemsHeight`
380
- // would still correspond to the previous item height, so those would be "stale".
381
- // On the other hand, same values in `this.previouslyCalculatedLayout` instance variable
382
- // can also be updated immediately, so they won't go out of sync with the updated item height.
383
- // That seems the only edge case when using a separate `this.previouslyCalculatedLayout`
384
- // instance variable instead of using `this.getState()` would theoretically be justified.
385
- //
386
- _this.previouslyCalculatedLayout = {
387
- firstShownItemIndex: firstShownItemIndex,
388
- lastShownItemIndex: lastShownItemIndex,
389
- beforeItemsHeight: beforeItemsHeight,
390
- shownItemsHeight: shownItemsHeight
391
- };
392
- } // Update `VirtualScroller` state.
393
- // `VirtualScroller` automatically re-renders on state updates.
394
- //
395
- // All `state` properties updated here should be overwritten in
396
- // the implementation of `setItems()` and `onResize()` methods
397
- // so that the `state` is not left in an inconsistent state
398
- // whenever there're concurrent `setState()` updates that could
399
- // possibly conflict with one another — instead, those state updates
400
- // should overwrite each other in terms of priority.
401
- // These "on scroll" updates have the lowest priority compared to
402
- // the state updates originating from `setItems()` and `onResize()` methods.
403
- //
404
-
405
-
406
- _this.setState(_objectSpread({
407
- firstShownItemIndex: firstShownItemIndex,
408
- lastShownItemIndex: lastShownItemIndex,
409
- beforeItemsHeight: beforeItemsHeight,
410
- afterItemsHeight: afterItemsHeight
411
- }, stateUpdate));
412
- });
413
-
414
- _defineProperty(this, "onUpdateShownItemIndexes", function (_ref2) {
415
- var reason = _ref2.reason,
416
- stateUpdate = _ref2.stateUpdate;
417
-
418
- // In case of "don't do anything".
419
- var skip = function skip() {
420
- if (stateUpdate) {
421
- _this.setState(stateUpdate);
165
+ // Reset layout:
166
+ // * If the scrollable container width has changed while stopped.
167
+ // * If the restored state was calculated for another scrollable container width.
168
+ var newWidth = this.scrollableContainer.getWidth();
169
+ var prevWidth = this.getState().scrollableContainerWidth;
170
+
171
+ if (newWidth !== prevWidth) {
172
+ (0, _debug["default"])('~ Scrollable container width changed from', prevWidth, 'to', newWidth, '~'); // `stateUpdate` doesn't get passed to `this.onResize()`, and, therefore,
173
+ // won't be applied. But that's ok because currently it could only contain:
174
+ // * `scrollableContainerWidth`
175
+ // * `verticalSpacing`
176
+ // * `beforeResize`
177
+ // All of those get rewritten in `onResize()` anyway.
178
+
179
+ return this.onResize();
422
180
  }
423
- }; // If new `items` have been set and are waiting to be applied,
424
- // or if the viewport width has changed requiring a re-layout,
425
- // then temporarily stop all other updates like "on scroll" updates.
426
- // This prevents `state` being inconsistent, because, for example,
427
- // both `setItems()` and this function could update `VirtualScroller` state
428
- // and having them operate in parallel could result in incorrectly calculated
429
- // `beforeItemsHeight` / `afterItemsHeight` / `firstShownItemIndex` /
430
- // `lastShownItemIndex`, because, when operating in parallel, this function
431
- // would have different `items` than the `setItems()` function, so their
432
- // results could diverge.
433
-
434
-
435
- if (_this.newItemsWillBeRendered || _this.resetLayoutAfterResize || _this.isResizing) {
436
- return skip();
437
- } // If there're no items then there's no need to re-layout anything.
438
-
439
-
440
- if (_this.getItemsCount() === 0) {
441
- return skip();
442
- } // Cancel a "re-layout when user stops scrolling" timer.
443
-
444
-
445
- _this.scroll.cancelScheduledLayout(); // Cancel a re-layout that is scheduled to run at the next "frame",
446
- // because a re-layout will be performed right now.
447
-
448
-
449
- stateUpdate = _this.cancelLayoutTimer({
450
- stateUpdate: stateUpdate
451
- }); // Perform a re-layout.
452
-
453
- (0, _debug["default"])("~ Update Layout (on ".concat(reason, ") ~"));
454
-
455
- _this.updateShownItemIndexes({
456
- stateUpdate: stateUpdate
457
- });
458
- });
459
-
460
- _defineProperty(this, "updateLayout", function () {
461
- return _this.onUpdateShownItemIndexes({
462
- reason: _Layout.LAYOUT_REASON.MANUAL
463
- });
464
- });
465
-
466
- _defineProperty(this, "layout", function () {
467
- return _this.updateLayout();
468
- });
469
-
470
- var onStateChange = options.onStateChange,
471
- customState = options.customState,
472
- initialScrollPosition = options.initialScrollPosition,
473
- onScrollPositionChange = options.onScrollPositionChange,
474
- measureItemsBatchSize = options.measureItemsBatchSize,
475
- getScrollableContainer = options.getScrollableContainer,
476
- getColumnsCount = options.getColumnsCount,
477
- getItemId = options.getItemId,
478
- tbody = options.tbody,
479
- _useTimeoutInRenderLoop = options._useTimeoutInRenderLoop,
480
- _waitForScrollingToStop = options._waitForScrollingToStop;
481
- var getState = options.getState,
482
- setState = options.setState;
483
- var bypass = options.bypass,
484
- estimatedItemHeight = options.estimatedItemHeight,
485
- onItemInitialRender = options.onItemInitialRender,
486
- onItemFirstRender = options.onItemFirstRender,
487
- scrollableContainer = options.scrollableContainer,
488
- state = options.state,
489
- engine = options.engine;
490
- (0, _debug["default"])('~ Initialize ~'); // If `state` is passed then use `items` from `state`
491
- // instead of the `items` argument.
492
-
493
- if (state) {
494
- items = state.items;
495
- } // `getScrollableContainer` option is deprecated.
496
- // Use `scrollableContainer` instead.
497
-
498
-
499
- if (!scrollableContainer && getScrollableContainer) {
500
- scrollableContainer = getScrollableContainer();
501
- } // Could support non-DOM rendering engines.
502
- // For example, React Native, `<canvas/>`, etc.
503
-
504
-
505
- if (!engine) {
506
- engine = _Engine["default"];
507
- } // Sometimes, when `new VirtualScroller()` instance is created,
508
- // `getItemsContainerElement()` might not be ready to return the "container" DOM Element yet
509
- // (for example, because it's not rendered yet). That's the reason why it's a getter function.
510
- // For example, in React `<VirtualScroller/>` component, a `VirtualScroller`
511
- // instance is created in the React component's `constructor()`, and at that time
512
- // the container Element is not yet available. The container Element is available
513
- // in `componentDidMount()`, but `componentDidMount()` is not executed on server,
514
- // which would mean that React `<VirtualScroller/>` wouldn't render at all
515
- // on server side, while with the `getItemsContainerElement()` approach, on server side,
516
- // it still "renders" a list with a predefined amount of items in it by default.
517
- // (`initiallyRenderedItemsCount`, or `1`).
518
-
519
-
520
- this.getItemsContainerElement = getItemsContainerElement;
521
- this.itemsContainer = engine.createItemsContainer(getItemsContainerElement); // Remove any accidental text nodes from container (like whitespace).
522
- // Also guards against cases when someone accidentally tries
523
- // using `VirtualScroller` on a non-empty element.
524
-
525
- if (getItemsContainerElement()) {
526
- this.itemsContainer.clear();
527
- }
528
-
529
- this.scrollableContainer = engine.createScrollableContainer(scrollableContainer, getItemsContainerElement); // if (prerenderMargin === undefined) {
530
- // // Renders items which are outside of the screen by this "prerender margin".
531
- // // Is the screen height by default: seems to be the optimal value
532
- // // for "Page Up" / "Page Down" navigation and optimized mouse wheel scrolling.
533
- // prerenderMargin = this.scrollableContainer ? this.scrollableContainer.getHeight() : 0
534
- // }
535
- // Work around `<tbody/>` not being able to have `padding`.
536
- // https://gitlab.com/catamphetamine/virtual-scroller/-/issues/1
537
-
538
- if (tbody) {
539
- if (engine !== _Engine["default"]) {
540
- throw new Error('[virtual-scroller] `tbody` option is only supported for DOM rendering engine');
541
- }
542
-
543
- (0, _debug["default"])('~ <tbody/> detected ~');
544
- this.tbody = true;
545
-
546
- if (!(0, _tbody.supportsTbody)()) {
547
- (0, _debug["default"])('~ <tbody/> not supported ~');
548
- (0, _debug.reportError)(_tbody.BROWSER_NOT_SUPPORTED_ERROR);
549
- bypass = true;
550
- }
551
- }
552
-
553
- if (bypass) {
554
- (0, _debug["default"])('~ "bypass" mode ~');
555
- } // In `bypass` mode, `VirtualScroller` doesn't wait
556
- // for the user to scroll down to render all items:
557
- // instead, it renders all items right away, as if
558
- // the list is rendered without using `VirtualScroller`.
559
- // It was added just to measure how much is the
560
- // performance difference between using a `VirtualScroller`
561
- // and not using a `VirtualScroller`.
562
- // It turned out that unmounting large React component trees
563
- // is a very long process, so `VirtualScroller` does seem to
564
- // make sense when used in a React application.
565
-
566
-
567
- this.bypass = bypass; // this.bypassBatchSize = bypassBatchSize || 10
568
- // Using `setTimeout()` in render loop is a workaround
569
- // for avoiding a React error message:
570
- // "Maximum update depth exceeded.
571
- // This can happen when a component repeatedly calls
572
- // `.setState()` inside `componentWillUpdate()` or `componentDidUpdate()`.
573
- // React limits the number of nested updates to prevent infinite loops."
574
-
575
- this._useTimeoutInRenderLoop = _useTimeoutInRenderLoop;
576
-
577
- if (getItemId) {
578
- this.isItemEqual = function (a, b) {
579
- return getItemId(a) === getItemId(b);
580
- };
581
- } else {
582
- this.isItemEqual = function (a, b) {
583
- return a === b;
584
- };
585
- }
586
-
587
- this.initialItems = items; // this.prerenderMargin = prerenderMargin
588
-
589
- this.onStateChange = onStateChange;
590
- this._getColumnsCount = getColumnsCount;
591
-
592
- if (onItemInitialRender) {
593
- this.onItemInitialRender = onItemInitialRender;
594
- } // `onItemFirstRender(i)` is deprecated, use `onItemInitialRender(item)` instead.
595
- else if (onItemFirstRender) {
596
- this.onItemInitialRender = function (item) {
597
- (0, _debug.warn)('`onItemFirstRender(i)` is deprecated, use `onItemInitialRender(item)` instead.');
598
-
599
- var _this$getState = _this.getState(),
600
- items = _this$getState.items;
601
-
602
- var i = items.indexOf(item); // The `item` could also be non-found due to the inconsistency bug:
603
- // The reason is that `i` can be non-consistent with the `items`
604
- // passed to `<VirtualScroller/>` in React due to `setState()` not being
605
- // instanteneous: when new `items` are passed to `<VirtualScroller/>`,
606
- // `VirtualScroller.setState({ items })` is called, and if `onItemFirstRender(i)`
607
- // is called after the aforementioned `setState()` is called but before it finishes,
608
- // `i` would point to an index in "previous" `items` while the application
609
- // would assume that `i` points to an index in the "new" `items`,
610
- // resulting in an incorrect item being assumed by the application
611
- // or even in an "array index out of bounds" error.
612
-
613
- if (i >= 0) {
614
- onItemFirstRender(i);
615
- }
616
- };
617
- }
618
-
619
- (0, _debug["default"])('Items count', items.length);
620
-
621
- if (estimatedItemHeight) {
622
- (0, _debug["default"])('Estimated item height', estimatedItemHeight);
623
- } // There're three main places where state is updated:
624
- //
625
- // * On scroll.
626
- // * On window resize.
627
- // * On set new items.
628
- //
629
- // State updates may be "asynchronous" (like in React), in which case the
630
- // corresponding operation is "pending" until the state update is applied.
631
- //
632
- // If there's a "pending" window resize or a "pending" update of the set of items,
633
- // then "on scroll" updates aren't dispatched.
634
- //
635
- // If there's a "pending" on scroll update and the window is resize or a new set
636
- // of items is set, then that "pending" on scroll update gets overwritten.
637
- //
638
- // If there's a "pending" update of the set of items, then window resize handler
639
- // sees that "pending" update and dispatches its own state update so that the
640
- // "pending" state update originating from `setItems()` is not lost.
641
- //
642
- // If there's a "pending" window resize, and a new set of items is set,
643
- // then the state update of the window resize handler gets overwritten.
644
- // Create default `getState()`/`setState()` functions.
645
-
646
-
647
- if (!getState) {
648
- getState = function getState() {
649
- return _this.state;
650
- };
651
-
652
- setState = function setState(stateUpdate, _ref3) {
653
- var willUpdateState = _ref3.willUpdateState,
654
- didUpdateState = _ref3.didUpdateState;
655
- var prevState = getState(); // Because this variant of `.setState()` is "synchronous" (immediate),
656
- // it can be written like `...prevState`, and no state updates would be lost.
657
- // But if it was "asynchronous" (not immediate), then `...prevState`
658
- // wouldn't work in all cases, because it could be stale in cases
659
- // when more than a single `setState()` call is made before
660
- // the state actually updates, making `prevState` stale.
661
-
662
- var newState = _objectSpread(_objectSpread({}, prevState), stateUpdate);
663
-
664
- willUpdateState(newState, prevState);
665
- _this.state = newState; // // Is only used in tests.
666
- // if (this._onStateUpdate) {
667
- // this._onStateUpdate(stateUpdate)
668
- // }
669
-
670
- didUpdateState(prevState);
671
- };
672
- }
673
-
674
- this.getState = getState;
675
-
676
- this.setState = function (stateUpdate) {
677
- if ((0, _debug.isDebug)()) {
678
- (0, _debug["default"])('Set state', (0, _getStateSnapshot["default"])(stateUpdate));
679
- }
680
-
681
- setState(stateUpdate, {
682
- willUpdateState: _this.willUpdateState,
683
- didUpdateState: _this.didUpdateState
684
- });
685
- };
686
-
687
- if (state) {
688
- if ((0, _debug.isDebug)()) {
689
- (0, _debug["default"])('Initial state (passed)', (0, _getStateSnapshot["default"])(state));
690
- }
691
- } // Check if the current `columnsCount` matches the one from state.
692
- // For example, a developer might snapshot `VirtualScroller` state
693
- // when the user navigates from the page containing the list
694
- // in order to later restore the list's state when the user goes "Back".
695
- // But, the user might have also resized the window while being on that
696
- // "other" page, and when they come "Back", their snapshotted state
697
- // no longer qualifies. Well, it does qualify, but only partially.
698
- // For example, `itemStates` are still valid, but first and last shown
699
- // item indexes aren't.
700
-
701
-
702
- if (state) {
703
- var shouldResetLayout;
704
- var columnsCountForState = this.getActualColumnsCountForState();
705
-
706
- if (columnsCountForState !== state.columnsCount) {
707
- (0, _debug.warn)('~ Columns Count changed from', state.columnsCount || 1, 'to', columnsCountForState || 1, '~');
708
- shouldResetLayout = true;
709
- }
710
-
711
- var columnsCount = this.getActualColumnsCount();
712
- var firstShownItemIndex = Math.floor(state.firstShownItemIndex / columnsCount) * columnsCount;
713
-
714
- if (firstShownItemIndex !== state.firstShownItemIndex) {
715
- (0, _debug.warn)('~ First Shown Item Index', state.firstShownItemIndex, 'is not divisible by Columns Count', columnsCount, '~');
716
- shouldResetLayout = true;
717
- }
718
-
719
- if (shouldResetLayout) {
720
- (0, _debug.warn)('Reset Layout');
721
- state = _objectSpread(_objectSpread({}, state), this.getInitialLayoutState(state.items));
722
- }
723
- } // Reset `verticalSpacing` so that it re-measures it after the list
724
- // has been rendered initially. The rationale is that the `state`
725
- // can't be "trusted" in a sense that the user might have resized
726
- // their window after the `state` has been snapshotted, and changing
727
- // window width might have activated different CSS `@media()` "queries"
728
- // resulting in a potentially different vertical spacing.
729
-
730
-
731
- if (state) {
732
- state = _objectSpread(_objectSpread({}, state), {}, {
733
- verticalSpacing: undefined
734
- });
735
- } // Create `ItemHeights` instance.
736
-
737
-
738
- this.itemHeights = new _ItemHeights["default"](this.itemsContainer, function (i) {
739
- return _this.getState().itemHeights[i];
740
- }, function (i, height) {
741
- return _this.getState().itemHeights[i] = height;
742
- }); // Initialize `ItemHeights` from the initially passed `state`.
743
-
744
- if (state) {
745
- this.itemHeights.initialize(state.itemHeights);
746
- }
747
-
748
- this.layout = new _Layout["default"]({
749
- bypass: bypass,
750
- estimatedItemHeight: estimatedItemHeight,
751
- measureItemsBatchSize: measureItemsBatchSize === undefined ? 50 : measureItemsBatchSize,
752
- getPrerenderMargin: function getPrerenderMargin() {
753
- return _this.getPrerenderMargin();
754
- },
755
- getVerticalSpacing: function getVerticalSpacing() {
756
- return _this.getVerticalSpacing();
757
- },
758
- getVerticalSpacingBeforeResize: function getVerticalSpacingBeforeResize() {
759
- return _this.getVerticalSpacingBeforeResize();
760
- },
761
- getColumnsCount: function getColumnsCount() {
762
- return _this.getColumnsCount();
763
- },
764
- getColumnsCountBeforeResize: function getColumnsCountBeforeResize() {
765
- return _this.getState().beforeResize && _this.getState().beforeResize.columnsCount;
766
- },
767
- getItemHeight: function getItemHeight(i) {
768
- return _this.getState().itemHeights[i];
769
- },
770
- getItemHeightBeforeResize: function getItemHeightBeforeResize(i) {
771
- return _this.getState().beforeResize && _this.getState().beforeResize.itemHeights[i];
772
- },
773
- getBeforeResizeItemsCount: function getBeforeResizeItemsCount() {
774
- return _this.getState().beforeResize ? _this.getState().beforeResize.itemHeights.length : 0;
775
- },
776
- getAverageItemHeight: function getAverageItemHeight() {
777
- return _this.itemHeights.getAverage();
778
- },
779
- getMaxVisibleAreaHeight: function getMaxVisibleAreaHeight() {
780
- return _this.scrollableContainer && _this.scrollableContainer.getHeight();
781
- },
782
- //
783
- // The "previously calculated layout" feature is not currently used.
784
- //
785
- // The current layout snapshot could be stored as a "previously calculated layout" variable
786
- // so that it could theoretically be used when calculating new layout incrementally
787
- // rather than from scratch, which would be an optimization.
788
- //
789
- getPreviouslyCalculatedLayout: function getPreviouslyCalculatedLayout() {
790
- return _this.previouslyCalculatedLayout;
791
- }
792
- });
793
- this.resize = new _Resize["default"]({
794
- bypass: bypass,
795
- scrollableContainer: this.scrollableContainer,
796
- onStart: function onStart() {
797
- (0, _debug["default"])('~ Scrollable container resize started ~');
798
- _this.isResizing = true;
799
- },
800
- onStop: function onStop() {
801
- (0, _debug["default"])('~ Scrollable container resize finished ~');
802
- _this.isResizing = undefined;
803
- },
804
- onNoChange: function onNoChange() {
805
- // There might have been some missed `this.onUpdateShownItemIndexes()` calls
806
- // due to setting `this.isResizing` flag to `true` during the resize.
807
- // So, update shown item indexes just in case.
808
- _this.onUpdateShownItemIndexes({
809
- reason: _Layout.LAYOUT_REASON.VIEWPORT_SIZE_UNCHANGED
810
- });
811
- },
812
- onHeightChange: function onHeightChange() {
813
- return _this.onUpdateShownItemIndexes({
814
- reason: _Layout.LAYOUT_REASON.VIEWPORT_HEIGHT_CHANGED
815
- });
816
- },
817
- onWidthChange: function onWidthChange(prevWidth, newWidth) {
818
- (0, _debug["default"])('~ Scrollable container width changed from', prevWidth, 'to', newWidth, '~');
819
-
820
- _this.onResize();
821
- }
822
- });
823
- this.scroll = new _Scroll["default"]({
824
- bypass: this.bypass,
825
- scrollableContainer: this.scrollableContainer,
826
- itemsContainer: this.itemsContainer,
827
- waitForScrollingToStop: _waitForScrollingToStop,
828
- onScroll: function onScroll() {
829
- var _ref4 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
830
- delayed = _ref4.delayed;
831
-
832
- _this.onUpdateShownItemIndexes({
833
- reason: delayed ? _Layout.LAYOUT_REASON.STOPPED_SCROLLING : _Layout.LAYOUT_REASON.SCROLL
834
- });
835
- },
836
- initialScrollPosition: initialScrollPosition,
837
- onScrollPositionChange: onScrollPositionChange,
838
- isImmediateLayoutScheduled: function isImmediateLayoutScheduled() {
839
- return _this.layoutTimer;
840
- },
841
- hasNonRenderedItemsAtTheTop: function hasNonRenderedItemsAtTheTop() {
842
- return _this.getState().firstShownItemIndex > 0;
843
- },
844
- hasNonRenderedItemsAtTheBottom: function hasNonRenderedItemsAtTheBottom() {
845
- return _this.getState().lastShownItemIndex < _this.getItemsCount() - 1;
846
- },
847
- getLatestLayoutVisibleArea: function getLatestLayoutVisibleArea() {
848
- return _this.latestLayoutVisibleArea;
849
- },
850
- getListTopOffset: this.getListTopOffsetInsideScrollableContainer,
851
- getPrerenderMargin: function getPrerenderMargin() {
852
- return _this.getPrerenderMargin();
853
- }
854
- });
855
- this.listHeightChangeWatcher = new _ListHeightChangeWatcher["default"]({
856
- itemsContainer: this.itemsContainer,
857
- getListTopOffset: this.getListTopOffsetInsideScrollableContainer
858
- });
859
-
860
- if (engine.watchListTopOffset) {
861
- this.listTopOffsetWatcher = engine.watchListTopOffset({
862
- getListTopOffset: this.getListTopOffsetInsideScrollableContainer,
863
- onListTopOffsetChange: function onListTopOffsetChange(_ref5) {
864
- var reason = _ref5.reason;
865
- return _this.onUpdateShownItemIndexes({
866
- reason: _Layout.LAYOUT_REASON.TOP_OFFSET_CHANGED
867
- });
868
- }
869
- });
870
- }
871
-
872
- this.beforeResize = new _BeforeResize["default"]({
873
- getState: this.getState,
874
- getVerticalSpacing: this.getVerticalSpacing,
875
- getColumnsCount: this.getColumnsCount
876
- }); // Possibly clean up "before resize" property in state.
877
- // "Before resize" state property is cleaned up when all "before resize" item heights
878
- // have been re-measured in an asynchronous `this.setState({ beforeResize: undefined })` call.
879
- // If `VirtualScroller` state was snapshotted externally before that `this.setState()` call
880
- // has been applied, then "before resize" property might have not been cleaned up properly.
881
-
882
- this.beforeResize.onInitialState(state); // `this.verticalSpacing` acts as a "true" source for vertical spacing value.
883
- // Vertical spacing is also stored in `state` but `state` updates could be
884
- // "asynchronous" (not applied immediately) and `this.onUpdateShownItemIndexes()`
885
- // requires vertical spacing to be correct at any time, without any delays.
886
- // So, vertical spacing is also duplicated in `state`, but the "true" source
887
- // is still `this.verticalSpacing`.
888
- //
889
- // `this.verticalSpacing` must be initialized before calling `this.getInitialState()`.
890
- //
891
-
892
- this.verticalSpacing = state ? state.verticalSpacing : undefined; // Set initial `state`.
893
-
894
- this.setState(state || this.getInitialState(customState));
895
- }
896
- /**
897
- * Returns the initial state of the `VirtualScroller`.
898
- * @param {object} [customState] — Any additional "custom" state may be stored in `VirtualScroller`'s state. For example, React implementation stores item "refs" as "custom" state.
899
- * @return {object}
900
- */
181
+ } // If the `VirtualScroller` uses custom (external) state storage, then
182
+ // check if the columns count has changed between calling `.getInitialState()`
183
+ // and `.start()`. If it has, perform a re-layout "from scratch".
901
184
 
902
185
 
903
- _createClass(VirtualScroller, [{
904
- key: "getInitialState",
905
- value: function getInitialState(customState) {
906
- var items = this.initialItems;
907
-
908
- var state = _objectSpread(_objectSpread(_objectSpread({}, customState), this.getInitialLayoutState(items)), {}, {
909
- items: items,
910
- itemStates: new Array(items.length)
911
- });
912
-
913
- if ((0, _debug.isDebug)()) {
914
- (0, _debug["default"])('Initial state (autogenerated)', (0, _getStateSnapshot["default"])(state));
915
- }
916
-
917
- (0, _debug["default"])('First shown item index', state.firstShownItemIndex);
918
- (0, _debug["default"])('Last shown item index', state.lastShownItemIndex);
919
- return state;
920
- }
921
- }, {
922
- key: "getInitialLayoutState",
923
- value: function getInitialLayoutState(items) {
924
- var itemsCount = items.length;
925
-
926
- var _this$layout$getIniti = this.layout.getInitialLayoutValues({
927
- itemsCount: itemsCount,
928
- columnsCount: this.getColumnsCount()
929
- }),
930
- firstShownItemIndex = _this$layout$getIniti.firstShownItemIndex,
931
- lastShownItemIndex = _this$layout$getIniti.lastShownItemIndex,
932
- beforeItemsHeight = _this$layout$getIniti.beforeItemsHeight,
933
- afterItemsHeight = _this$layout$getIniti.afterItemsHeight;
934
-
935
- var itemHeights = new Array(itemsCount); // Optionally preload items to be rendered.
936
-
937
- this.onBeforeShowItems(items, itemHeights, firstShownItemIndex, lastShownItemIndex);
938
- return {
939
- itemHeights: itemHeights,
940
- columnsCount: this.getActualColumnsCountForState(),
941
- verticalSpacing: this.verticalSpacing,
942
- firstShownItemIndex: firstShownItemIndex,
943
- lastShownItemIndex: lastShownItemIndex,
944
- beforeItemsHeight: beforeItemsHeight,
945
- afterItemsHeight: afterItemsHeight
946
- };
947
- } // Bind to `this` in order to prevent bugs when this function is passed by reference
948
- // and then called with its `this` being unintentionally `window` resulting in
949
- // the `if` condition being "falsy".
950
-
951
- }, {
952
- key: "getActualColumnsCount",
953
- value: function getActualColumnsCount() {
954
- return this.getActualColumnsCountForState() || 1;
955
- } // Bind to `this` in order to prevent bugs when this function is passed by reference
956
- // and then called with its `this` being unintentionally `window` resulting in
957
- // the `if` condition being "falsy".
958
-
959
- }, {
960
- key: "getVerticalSpacingBeforeResize",
961
- value: function getVerticalSpacingBeforeResize() {
962
- // `beforeResize.verticalSpacing` can be `undefined`.
963
- // For example, if `this.setState({ verticalSpacing })` call hasn't been applied
964
- // before the resize happened (in case of an "asynchronous" state update).
965
- return this.getState().beforeResize && this.getState().beforeResize.verticalSpacing || 0;
966
- }
967
- }, {
968
- key: "getColumnsCount",
969
- value: function getColumnsCount() {
970
- return this.getState() && this.getState().columnsCount || 1;
971
- }
972
- }, {
973
- key: "getItemsCount",
974
- value: function getItemsCount() {
975
- return this.getState().items.length;
976
- }
977
- }, {
978
- key: "getPrerenderMargin",
979
- value: function getPrerenderMargin() {
980
- // The list component renders not only the items that're currently visible
981
- // but also the items that lie within some extra vertical margin (called
982
- // "prerender margin") on top and bottom for future scrolling: this way,
983
- // there'll be significantly less layout recalculations as the user scrolls,
984
- // because now it doesn't have to recalculate layout on each scroll event.
985
- // By default, the "prerender margin" is equal to the screen height:
986
- // this seems to be the optimal value for "Page Up" / "Page Down" navigation
987
- // and optimized mouse wheel scrolling (a user is unlikely to continuously
988
- // scroll past the screen height, because they'd stop to read through
989
- // the newly visible items first, and when they do stop scrolling, that's
990
- // when layout gets recalculated).
991
- var renderAheadMarginRatio = 1; // in scrollable container heights.
992
-
993
- return this.scrollableContainer.getHeight() * renderAheadMarginRatio;
994
- }
995
- /**
996
- * Calls `onItemFirstRender()` for items that haven't been
997
- * "seen" previously.
998
- * @param {any[]} items
999
- * @param {number[]} itemHeights
1000
- * @param {number} firstShownItemIndex
1001
- * @param {number} lastShownItemIndex
1002
- */
1003
-
1004
- }, {
1005
- key: "onBeforeShowItems",
1006
- value: function onBeforeShowItems(items, itemHeights, firstShownItemIndex, lastShownItemIndex) {
1007
- if (this.onItemInitialRender) {
1008
- var i = firstShownItemIndex;
186
+ if (this._usesCustomStateStorage) {
187
+ var columnsCount = this.getActualColumnsCount();
188
+ var columnsCountFromState = this.getState().columnsCount || 1;
1009
189
 
1010
- while (i <= lastShownItemIndex) {
1011
- if (itemHeights[i] === undefined) {
1012
- this.onItemInitialRender(items[i]);
1013
- }
1014
-
1015
- i++;
190
+ if (columnsCount !== columnsCountFromState) {
191
+ return this.onResize();
1016
192
  }
1017
- }
1018
- }
1019
- }, {
1020
- key: "onMount",
1021
- value: function onMount() {
1022
- (0, _debug.warn)('`.onMount()` instance method name is deprecated, use `.listen()` instance method name instead.');
1023
- this.listen();
1024
- }
1025
- }, {
1026
- key: "render",
1027
- value: function render() {
1028
- (0, _debug.warn)('`.render()` instance method name is deprecated, use `.listen()` instance method name instead.');
1029
- this.listen();
1030
- }
1031
- /**
1032
- * Should be invoked after a "container" DOM Element is mounted (inserted into the DOM tree).
1033
- */
1034
-
1035
- }, {
1036
- key: "listen",
1037
- value: function listen() {
1038
- if (this.isRendered === false) {
1039
- throw new Error('[virtual-scroller] Can\'t restart a `VirtualScroller` after it has been stopped');
1040
- }
1041
-
1042
- (0, _debug["default"])('~ Rendered (initial) ~'); // `this.isRendered = true` should be the first statement in this function,
1043
- // otherwise `DOMVirtualScroller` would enter an infinite re-render loop.
1044
-
1045
- this.isRendered = true;
1046
- var stateUpdate = this.measureItemHeightsAndSpacingAndUpdateTablePadding();
1047
- this.resize.listen();
1048
- this.scroll.listen(); // Work around `<tbody/>` not being able to have `padding`.
1049
- // https://gitlab.com/catamphetamine/virtual-scroller/-/issues/1
1050
-
1051
- if (this.tbody) {
1052
- (0, _tbody.addTbodyStyles)(this.getItemsContainerElement());
1053
193
  } // Re-calculate layout and re-render the list.
1054
194
  // Do that even if when an initial `state` parameter, containing layout values,
1055
195
  // has been passed. The reason is that the `state` parameter can't be "trusted"
@@ -1058,48 +198,19 @@ var VirtualScroller = /*#__PURE__*/function () {
1058
198
 
1059
199
 
1060
200
  this.onUpdateShownItemIndexes({
1061
- reason: _Layout.LAYOUT_REASON.MOUNTED,
201
+ reason: _Layout.LAYOUT_REASON.STARTED,
1062
202
  stateUpdate: stateUpdate
1063
203
  });
1064
- }
1065
- }, {
1066
- key: "measureItemHeightsAndSpacingAndUpdateTablePadding",
1067
- value: function measureItemHeightsAndSpacingAndUpdateTablePadding() {
1068
- // Measure "newly shown" item heights.
1069
- // Also re-validate already measured items' heights.
1070
- this.itemHeights.measureItemHeights(this.getState().firstShownItemIndex, this.getState().lastShownItemIndex); // Update item vertical spacing.
1071
-
1072
- var verticalSpacing = this.measureVerticalSpacing(); // Update `<tbody/>` `padding`.
1073
- // (`<tbody/>` is different in a way that it can't have `margin`, only `padding`).
1074
- // https://gitlab.com/catamphetamine/virtual-scroller/-/issues/1
1075
-
1076
- if (this.tbody) {
1077
- (0, _tbody.setTbodyPadding)(this.getItemsContainerElement(), this.getState().beforeItemsHeight, this.getState().afterItemsHeight);
1078
- } // Return a state update.
204
+ } // Could be passed as a "callback" parameter, so bind it to `this`.
1079
205
 
1080
-
1081
- if (verticalSpacing !== undefined) {
1082
- return {
1083
- verticalSpacing: verticalSpacing
1084
- };
1085
- }
1086
- }
1087
206
  }, {
1088
- key: "getVisibleArea",
1089
- value: function getVisibleArea() {
1090
- var visibleArea = this.scroll.getVisibleAreaBounds();
1091
- this.latestLayoutVisibleArea = visibleArea; // Subtract the top offset of the list inside the scrollable container.
1092
-
1093
- var listTopOffsetInsideScrollableContainer = this.getListTopOffsetInsideScrollableContainer();
1094
- return {
1095
- top: visibleArea.top - listTopOffsetInsideScrollableContainer,
1096
- bottom: visibleArea.bottom - listTopOffsetInsideScrollableContainer
1097
- };
1098
- }
1099
- /**
1100
- * Returns the list's top offset relative to the scrollable container's top edge.
1101
- * @return {number}
1102
- */
207
+ key: "hasToBeStarted",
208
+ value: function hasToBeStarted() {
209
+ if (!this._isActive) {
210
+ throw new Error('[virtual-scroller] `VirtualScroller` hasn\'t been started');
211
+ }
212
+ } // Bind it to `this` because this function could hypothetically be passed
213
+ // as a "callback" parameter.
1103
214
 
1104
215
  }, {
1105
216
  key: "getItemScrollPosition",
@@ -1118,479 +229,30 @@ var VirtualScroller = /*#__PURE__*/function () {
1118
229
 
1119
230
  return this.getListTopOffsetInsideScrollableContainer() + itemTopOffsetInList;
1120
231
  }
1121
- }, {
1122
- key: "onUnmount",
1123
- value: function onUnmount() {
1124
- (0, _debug.warn)('`.onUnmount()` instance method name is deprecated, use `.stop()` instance method name instead.');
1125
- this.stop();
1126
- }
1127
- }, {
1128
- key: "destroy",
1129
- value: function destroy() {
1130
- (0, _debug.warn)('`.destroy()` instance method name is deprecated, use `.stop()` instance method name instead.');
1131
- this.stop();
1132
- }
1133
- }, {
1134
- key: "cancelLayoutTimer",
1135
- value: function cancelLayoutTimer(_ref6) {
1136
- var stateUpdate = _ref6.stateUpdate;
1137
-
1138
- if (this.layoutTimer) {
1139
- (0, _requestAnimationFrameTimeout.clearTimeout)(this.layoutTimer);
1140
- this.layoutTimer = undefined; // Merge state updates.
1141
-
1142
- if (stateUpdate || this.layoutTimerStateUpdate) {
1143
- stateUpdate = _objectSpread(_objectSpread({}, this.layoutTimerStateUpdate), stateUpdate);
1144
- this.layoutTimerStateUpdate = undefined;
1145
- return stateUpdate;
1146
- }
1147
- } else {
1148
- return stateUpdate;
1149
- }
1150
- }
1151
- }, {
1152
- key: "scheduleLayoutTimer",
1153
- value: function scheduleLayoutTimer(_ref7) {
1154
- var _this2 = this;
1155
-
1156
- var reason = _ref7.reason,
1157
- stateUpdate = _ref7.stateUpdate;
1158
- this.layoutTimerStateUpdate = stateUpdate;
1159
- this.layoutTimer = (0, _requestAnimationFrameTimeout.setTimeout)(function () {
1160
- _this2.layoutTimerStateUpdate = undefined;
1161
- _this2.layoutTimer = undefined;
1162
-
1163
- _this2.onUpdateShownItemIndexes({
1164
- reason: reason,
1165
- stateUpdate: stateUpdate
1166
- });
1167
- }, 0);
1168
- }
1169
232
  /**
1170
- * Should be called right before `state` is updated.
1171
- * @param {object} prevState
1172
- * @param {object} newState
233
+ * Forces a re-measure of an item's height.
234
+ * @param {number} i — Item index
1173
235
  */
1174
236
 
1175
- }, {
1176
- key: "onNewItemsRendered",
1177
- value: // After a new set of items has been rendered:
1178
- //
1179
- // * Restores scroll position when using `preserveScrollPositionOnPrependItems`
1180
- // and items have been prepended.
1181
- //
1182
- // * Applies any "pending" `itemHeights` updates — those ones that happened
1183
- // while an asynchronous `setState()` call in `setItems()` was pending.
1184
- //
1185
- // * Either creates or resets the snapshot of the current layout.
1186
- //
1187
- // The current layout snapshot could be stored as a "previously calculated layout" variable
1188
- // so that it could theoretically be used when calculating new layout incrementally
1189
- // rather than from scratch, which would be an optimization.
1190
- //
1191
- // The "previously calculated layout" feature is not currently used.
1192
- //
1193
- function onNewItemsRendered(itemsDiff, newLayout) {
1194
- // If it's an "incremental" update.
1195
- if (itemsDiff) {
1196
- var prependedItemsCount = itemsDiff.prependedItemsCount,
1197
- appendedItemsCount = itemsDiff.appendedItemsCount;
1198
-
1199
- var _this$getState2 = this.getState(),
1200
- itemHeights = _this$getState2.itemHeights,
1201
- itemStates = _this$getState2.itemStates; // See if any items' heights changed while new items were being rendered.
1202
-
1203
-
1204
- if (this.itemHeightsThatChangedWhileNewItemsWereBeingRendered) {
1205
- for (var _i = 0, _Object$keys = Object.keys(this.itemHeightsThatChangedWhileNewItemsWereBeingRendered); _i < _Object$keys.length; _i++) {
1206
- var i = _Object$keys[_i];
1207
- itemHeights[prependedItemsCount + parseInt(i)] = this.itemHeightsThatChangedWhileNewItemsWereBeingRendered[i];
1208
- }
1209
- } // See if any items' states changed while new items were being rendered.
1210
-
1211
-
1212
- if (this.itemStatesThatChangedWhileNewItemsWereBeingRendered) {
1213
- for (var _i2 = 0, _Object$keys2 = Object.keys(this.itemStatesThatChangedWhileNewItemsWereBeingRendered); _i2 < _Object$keys2.length; _i2++) {
1214
- var _i3 = _Object$keys2[_i2];
1215
- itemStates[prependedItemsCount + parseInt(_i3)] = this.itemStatesThatChangedWhileNewItemsWereBeingRendered[_i3];
1216
- }
1217
- }
1218
-
1219
- if (prependedItemsCount === 0) {
1220
- // Adjust `this.previouslyCalculatedLayout`.
1221
- if (this.previouslyCalculatedLayout) {
1222
- if (this.previouslyCalculatedLayout.firstShownItemIndex === newLayout.firstShownItemIndex && this.previouslyCalculatedLayout.lastShownItemIndex === newLayout.lastShownItemIndex) {// `this.previouslyCalculatedLayout` stays the same.
1223
- // `firstShownItemIndex` / `lastShownItemIndex` didn't get changed in `setItems()`,
1224
- // so `beforeItemsHeight` and `shownItemsHeight` also stayed the same.
1225
- } else {
1226
- (0, _debug.warn)('Unexpected (non-matching) "firstShownItemIndex" or "lastShownItemIndex" encountered in "didUpdateState()" after appending items');
1227
- (0, _debug.warn)('Previously calculated layout', this.previouslyCalculatedLayout);
1228
- (0, _debug.warn)('New layout', newLayout);
1229
- this.previouslyCalculatedLayout = undefined;
1230
- }
1231
- }
1232
-
1233
- return 'SEAMLESS_APPEND';
1234
- } else {
1235
- if (this.listHeightChangeWatcher.hasSnapshot()) {
1236
- if (newLayout.firstShownItemIndex === 0) {
1237
- // Restore (adjust) scroll position.
1238
- (0, _debug["default"])('~ Restore Scroll Position ~');
1239
- var listBottomOffsetChange = this.listHeightChangeWatcher.getListBottomOffsetChange({
1240
- beforeItemsHeight: newLayout.beforeItemsHeight
1241
- });
1242
- this.listHeightChangeWatcher.reset();
1243
-
1244
- if (listBottomOffsetChange) {
1245
- (0, _debug["default"])('Scroll down by', listBottomOffsetChange);
1246
- this.scroll.scrollByY(listBottomOffsetChange);
1247
- } else {
1248
- (0, _debug["default"])('Scroll position hasn\'t changed');
1249
- } // Create new `this.previouslyCalculatedLayout`.
1250
-
1251
-
1252
- if (this.previouslyCalculatedLayout) {
1253
- if (this.previouslyCalculatedLayout.firstShownItemIndex === 0 && this.previouslyCalculatedLayout.lastShownItemIndex === newLayout.lastShownItemIndex - prependedItemsCount) {
1254
- this.previouslyCalculatedLayout = {
1255
- beforeItemsHeight: 0,
1256
- shownItemsHeight: this.previouslyCalculatedLayout.shownItemsHeight + listBottomOffsetChange,
1257
- firstShownItemIndex: 0,
1258
- lastShownItemIndex: newLayout.lastShownItemIndex
1259
- };
1260
- } else {
1261
- (0, _debug.warn)('Unexpected (non-matching) "firstShownItemIndex" or "lastShownItemIndex" encountered in "didUpdateState()" after prepending items');
1262
- (0, _debug.warn)('Previously calculated layout', this.previouslyCalculatedLayout);
1263
- (0, _debug.warn)('New layout', newLayout);
1264
- this.previouslyCalculatedLayout = undefined;
1265
- }
1266
- }
1267
-
1268
- return 'SEAMLESS_PREPEND';
1269
- } else {
1270
- (0, _debug.warn)("Unexpected \"firstShownItemIndex\" ".concat(newLayout.firstShownItemIndex, " encountered in \"didUpdateState()\" after prepending items. Expected 0."));
1271
- }
1272
- }
1273
- }
1274
- } // Reset `this.previouslyCalculatedLayout` in any case other than
1275
- // SEAMLESS_PREPEND or SEAMLESS_APPEND.
1276
-
1277
-
1278
- this.previouslyCalculatedLayout = undefined;
1279
- }
1280
- }, {
1281
- key: "updateStateRightAfterRender",
1282
- value: function updateStateRightAfterRender(_ref8) {
1283
- var reason = _ref8.reason,
1284
- stateUpdate = _ref8.stateUpdate;
1285
-
1286
- // In React, `setTimeout()` is used to prevent a React error:
1287
- // "Maximum update depth exceeded.
1288
- // This can happen when a component repeatedly calls
1289
- // `.setState()` inside `componentWillUpdate()` or `componentDidUpdate()`.
1290
- // React limits the number of nested updates to prevent infinite loops."
1291
- if (this._useTimeoutInRenderLoop) {
1292
- // Cancel a previously scheduled re-layout.
1293
- stateUpdate = this.cancelLayoutTimer({
1294
- stateUpdate: stateUpdate
1295
- }); // Schedule a new re-layout.
1296
-
1297
- this.scheduleLayoutTimer({
1298
- reason: reason,
1299
- stateUpdate: stateUpdate
1300
- });
1301
- } else {
1302
- this.onUpdateShownItemIndexes({
1303
- reason: reason,
1304
- stateUpdate: stateUpdate
1305
- });
1306
- }
1307
- }
1308
- }, {
1309
- key: "measureVerticalSpacing",
1310
- value: function measureVerticalSpacing() {
1311
- if (this.verticalSpacing === undefined) {
1312
- var _this$getState3 = this.getState(),
1313
- firstShownItemIndex = _this$getState3.firstShownItemIndex,
1314
- lastShownItemIndex = _this$getState3.lastShownItemIndex;
1315
-
1316
- (0, _debug["default"])('~ Measure item vertical spacing ~');
1317
- var verticalSpacing = (0, _getVerticalSpacing["default"])({
1318
- itemsContainer: this.itemsContainer,
1319
- renderedItemsCount: lastShownItemIndex - firstShownItemIndex + 1
1320
- });
1321
-
1322
- if (verticalSpacing === undefined) {
1323
- (0, _debug["default"])('Not enough items rendered to measure vertical spacing');
1324
- } else {
1325
- (0, _debug["default"])('Item vertical spacing', verticalSpacing);
1326
- this.verticalSpacing = verticalSpacing;
1327
-
1328
- if (verticalSpacing !== 0) {
1329
- return verticalSpacing;
1330
- }
1331
- }
1332
- }
1333
- }
1334
- }, {
1335
- key: "remeasureItemHeight",
1336
- value: function remeasureItemHeight(i) {
1337
- var _this$getState4 = this.getState(),
1338
- firstShownItemIndex = _this$getState4.firstShownItemIndex;
1339
-
1340
- return this.itemHeights.remeasureItemHeight(i, firstShownItemIndex);
1341
- }
1342
- }, {
1343
- key: "onItemStateChange",
1344
- value: function onItemStateChange(i, newItemState) {
1345
- if ((0, _debug.isDebug)()) {
1346
- (0, _debug["default"])('~ Item state changed ~');
1347
- (0, _debug["default"])('Item', i); // Uses `JSON.stringify()` here instead of just outputting the JSON objects as is
1348
- // because outputting JSON objects as is would show different results later when
1349
- // the developer inspects those in the web browser console if those state objects
1350
- // get modified in between they've been output to the console and the developer
1351
- // decided to inspect them.
1352
-
1353
- (0, _debug["default"])('Previous state' + '\n' + JSON.stringify(this.getState().itemStates[i], null, 2));
1354
- (0, _debug["default"])('New state' + '\n' + JSON.stringify(newItemState, null, 2));
1355
- }
1356
-
1357
- this.getState().itemStates[i] = newItemState; // Schedule the item state update for after the new items have been rendered.
1358
-
1359
- if (this.newItemsWillBeRendered) {
1360
- if (!this.itemStatesThatChangedWhileNewItemsWereBeingRendered) {
1361
- this.itemStatesThatChangedWhileNewItemsWereBeingRendered = {};
1362
- }
1363
-
1364
- this.itemStatesThatChangedWhileNewItemsWereBeingRendered[String(i)] = newItemState;
1365
- }
1366
- }
1367
237
  }, {
1368
238
  key: "onItemHeightChange",
1369
239
  value: function onItemHeightChange(i) {
1370
- (0, _debug["default"])('~ Re-measure item height ~');
1371
- (0, _debug["default"])('Item', i);
1372
-
1373
- var _this$getState5 = this.getState(),
1374
- itemHeights = _this$getState5.itemHeights,
1375
- firstShownItemIndex = _this$getState5.firstShownItemIndex,
1376
- lastShownItemIndex = _this$getState5.lastShownItemIndex; // Check if the item is still rendered.
1377
-
1378
-
1379
- if (!(i >= firstShownItemIndex && i <= lastShownItemIndex)) {
1380
- // There could be valid cases when an item is no longer rendered
1381
- // by the time `.onItemHeightChange(i)` gets called.
1382
- // For example, suppose there's a list of several items on a page,
1383
- // and those items are in "minimized" state (having height 100px).
1384
- // Then, a user clicks an "Expand all items" button, and all items
1385
- // in the list are expanded (expanded item height is gonna be 700px).
1386
- // `VirtualScroller` demands that `.onItemHeightChange(i)` is called
1387
- // in such cases, and the developer has properly added the code to do that.
1388
- // So, if there were 10 "minimized" items visible on a page, then there
1389
- // will be 10 individual `.onItemHeightChange(i)` calls. No issues so far.
1390
- // But, as the first `.onItemHeightChange(i)` call executes, it immediately
1391
- // ("synchronously") triggers a re-layout, and that re-layout finds out
1392
- // that now, because the first item is big, it occupies most of the screen
1393
- // space, and only the first 3 items are visible on screen instead of 10,
1394
- // and so it leaves the first 3 items mounted and unmounts the rest 7.
1395
- // Then, after `VirtualScroller` has rerendered, the code returns to
1396
- // where it was executing, and calls `.onItemHeightChange(i)` for the
1397
- // second item. It also triggers an immediate re-layout that finds out
1398
- // that only the first 2 items are visible on screen, and it unmounts
1399
- // the third one too. After that, it calls `.onItemHeightChange(i)`
1400
- // for the third item, but that item is no longer rendered, so its height
1401
- // can't be measured, and the same's for all the rest of the original 10 items.
1402
- // So, even though the developer has written their code properly, there're
1403
- // still situations when the item could be no longer rendered by the time
1404
- // `.onItemHeightChange(i)` gets called.
1405
- return (0, _debug.warn)('The item is no longer rendered. This is not necessarily a bug, and could happen, for example, when there\'re several `onItemHeightChange(i)` calls issued at the same time.');
1406
- }
1407
-
1408
- var previousHeight = itemHeights[i];
1409
-
1410
- if (previousHeight === undefined) {
1411
- return (0, _debug.reportError)("\"onItemHeightChange()\" has been called for item ".concat(i, ", but that item hasn't been rendered before."));
1412
- }
1413
-
1414
- var newHeight = this.remeasureItemHeight(i);
1415
- (0, _debug["default"])('Previous height', previousHeight);
1416
- (0, _debug["default"])('New height', newHeight);
240
+ this.hasToBeStarted();
1417
241
 
1418
- if (previousHeight !== newHeight) {
1419
- (0, _debug["default"])('~ Item height has changed ~'); // Update or reset previously calculated layout.
1420
-
1421
- this.updatePreviouslyCalculatedLayoutOnItemHeightChange(i, previousHeight, newHeight); // Recalculate layout.
1422
-
1423
- this.onUpdateShownItemIndexes({
1424
- reason: _Layout.LAYOUT_REASON.ITEM_HEIGHT_CHANGED
1425
- }); // Schedule the item height update for after the new items have been rendered.
1426
-
1427
- if (this.newItemsWillBeRendered) {
1428
- if (!this.itemHeightsThatChangedWhileNewItemsWereBeingRendered) {
1429
- this.itemHeightsThatChangedWhileNewItemsWereBeingRendered = {};
1430
- }
1431
-
1432
- this.itemHeightsThatChangedWhileNewItemsWereBeingRendered[String(i)] = newHeight;
1433
- }
1434
- }
1435
- } // Updates the snapshot of the current layout when an item's height changes.
1436
- //
1437
- // The "previously calculated layout" feature is not currently used.
1438
- //
1439
- // The current layout snapshot could be stored as a "previously calculated layout" variable
1440
- // so that it could theoretically be used when calculating new layout incrementally
1441
- // rather than from scratch, which would be an optimization.
1442
- //
1443
-
1444
- }, {
1445
- key: "updatePreviouslyCalculatedLayoutOnItemHeightChange",
1446
- value: function updatePreviouslyCalculatedLayoutOnItemHeightChange(i, previousHeight, newHeight) {
1447
- if (this.previouslyCalculatedLayout) {
1448
- var heightDifference = newHeight - previousHeight;
1449
-
1450
- if (i < this.previouslyCalculatedLayout.firstShownItemIndex) {
1451
- // Patch `this.previouslyCalculatedLayout`'s `.beforeItemsHeight`.
1452
- this.previouslyCalculatedLayout.beforeItemsHeight += heightDifference;
1453
- } else if (i > this.previouslyCalculatedLayout.lastShownItemIndex) {
1454
- // Could patch `.afterItemsHeight` of `this.previouslyCalculatedLayout` here,
1455
- // if `.afterItemsHeight` property existed in `this.previouslyCalculatedLayout`.
1456
- if (this.previouslyCalculatedLayout.afterItemsHeight !== undefined) {
1457
- this.previouslyCalculatedLayout.afterItemsHeight += heightDifference;
1458
- }
1459
- } else {
1460
- // Patch `this.previouslyCalculatedLayout`'s shown items height.
1461
- this.previouslyCalculatedLayout.shownItemsHeight += newHeight - previousHeight;
1462
- }
1463
- }
242
+ this._onItemHeightChange(i);
1464
243
  }
1465
244
  /**
1466
- * Validates the heights of items to be hidden on next render.
1467
- * For example, a user could click a "Show more" button,
1468
- * or an "Expand YouTube video" button, which would result
1469
- * in the actual height of the list item being different
1470
- * from what has been initially measured in `this.itemHeights[i]`,
1471
- * if the developer didn't call `.onItemStateChange()` and `.onItemHeightChange(i)`.
245
+ * Updates an item's state in `state.itemStates[]`.
246
+ * @param {number} i Item index
247
+ * @param {any} i Item's new state
1472
248
  */
1473
249
 
1474
250
  }, {
1475
- key: "validateWillBeHiddenItemHeightsAreAccurate",
1476
- value: function validateWillBeHiddenItemHeightsAreAccurate(firstShownItemIndex, lastShownItemIndex) {
1477
- var isValid = true;
1478
- var i = this.getState().firstShownItemIndex;
1479
-
1480
- while (i <= this.getState().lastShownItemIndex) {
1481
- if (i >= firstShownItemIndex && i <= lastShownItemIndex) {// The item's still visible.
1482
- } else {
1483
- // The item will be hidden. Re-measure its height.
1484
- // The rationale is that there could be a situation when an item's
1485
- // height has changed, and the developer has properly added an
1486
- // `.onItemHeightChange(i)` call to notify `VirtualScroller`
1487
- // about that change, but at the same time that wouldn't work.
1488
- // For example, suppose there's a list of several items on a page,
1489
- // and those items are in "minimized" state (having height 100px).
1490
- // Then, a user clicks an "Expand all items" button, and all items
1491
- // in the list are expanded (expanded item height is gonna be 700px).
1492
- // `VirtualScroller` demands that `.onItemHeightChange(i)` is called
1493
- // in such cases, and the developer has properly added the code to do that.
1494
- // So, if there were 10 "minimized" items visible on a page, then there
1495
- // will be 10 individual `.onItemHeightChange(i)` calls. No issues so far.
1496
- // But, as the first `.onItemHeightChange(i)` call executes, it immediately
1497
- // ("synchronously") triggers a re-layout, and that re-layout finds out
1498
- // that now, because the first item is big, it occupies most of the screen
1499
- // space, and only the first 3 items are visible on screen instead of 10,
1500
- // and so it leaves the first 3 items mounted and unmounts the rest 7.
1501
- // Then, after `VirtualScroller` has rerendered, the code returns to
1502
- // where it was executing, and calls `.onItemHeightChange(i)` for the
1503
- // second item. It also triggers an immediate re-layout that finds out
1504
- // that only the first 2 items are visible on screen, and it unmounts
1505
- // the third one too. After that, it calls `.onItemHeightChange(i)`
1506
- // for the third item, but that item is no longer rendered, so its height
1507
- // can't be measured, and the same's for all the rest of the original 10 items.
1508
- // So, even though the developer has written their code properly, the
1509
- // `VirtualScroller` still ends up having incorrect `itemHeights[]`:
1510
- // `[700px, 700px, 100px, 100px, 100px, 100px, 100px, 100px, 100px, 100px]`
1511
- // while it should have been `700px` for all of them.
1512
- // To work around such issues, every item's height is re-measured before it
1513
- // gets hidden.
1514
- var previouslyMeasuredItemHeight = this.getState().itemHeights[i];
1515
- var actualItemHeight = this.remeasureItemHeight(i);
1516
-
1517
- if (actualItemHeight !== previouslyMeasuredItemHeight) {
1518
- if (isValid) {
1519
- (0, _debug["default"])('~ Validate will-be-hidden item heights. ~'); // Update or reset previously calculated layout.
1520
-
1521
- this.updatePreviouslyCalculatedLayoutOnItemHeightChange(i, previouslyMeasuredItemHeight, actualItemHeight);
1522
- }
1523
-
1524
- isValid = false;
1525
- (0, _debug.warn)('Item index', i, 'is no longer visible and will be unmounted. Its height has changed from', previouslyMeasuredItemHeight, 'to', actualItemHeight, 'since it was last measured. This is not necessarily a bug, and could happen, for example, on screen width change, or when there\'re several `onItemHeightChange(i)` calls issued at the same time, and the first one triggers a re-layout before the rest of them have had a chance to be executed.');
1526
- }
1527
- }
1528
-
1529
- i++;
1530
- }
1531
-
1532
- return isValid;
1533
- }
1534
- }, {
1535
- key: "getShownItemIndexes",
1536
- value: function getShownItemIndexes() {
1537
- var itemsCount = this.getItemsCount();
1538
-
1539
- var _this$getVisibleArea = this.getVisibleArea(),
1540
- visibleAreaTop = _this$getVisibleArea.top,
1541
- visibleAreaBottom = _this$getVisibleArea.bottom;
1542
-
1543
- if (this.bypass) {
1544
- return {
1545
- firstShownItemIndex: 0,
1546
- lastShownItemIndex: itemsCount - 1 // shownItemsHeight: this.getState().itemHeights.reduce((sum, itemHeight) => sum + itemHeight, 0)
1547
-
1548
- };
1549
- } // Find the indexes of the items that are currently visible
1550
- // (or close to being visible) in the scrollable container.
1551
- // For scrollable containers other than the main screen, it could also
1552
- // check the visibility of such scrollable container itself, because it
1553
- // might be not visible.
1554
- // If such kind of an optimization would hypothetically be implemented,
1555
- // then it would also require listening for "scroll" events on the screen.
1556
- // Overall, I suppose that such "actual visibility" feature would be
1557
- // a very minor optimization and not something I'd deal with.
1558
-
1559
-
1560
- var isVisible = visibleAreaTop < this.itemsContainer.getHeight() && visibleAreaBottom > 0;
1561
-
1562
- if (!isVisible) {
1563
- (0, _debug["default"])('The entire list is off-screen. No items are visible.');
1564
- return this.layout.getNonVisibleListShownItemIndexes();
1565
- } // Get shown item indexes.
1566
-
1567
-
1568
- return this.layout.getShownItemIndexes({
1569
- itemsCount: this.getItemsCount(),
1570
- visibleAreaTop: visibleAreaTop,
1571
- visibleAreaBottom: visibleAreaBottom
1572
- });
1573
- }
1574
- /**
1575
- * Updates the "from" and "to" shown item indexes.
1576
- * If the list is visible and some of the items being shown are new
1577
- * and are required to be measured first, then
1578
- * `firstNonMeasuredItemIndex` is defined.
1579
- * If the list is visible and all items being shown have been encountered
1580
- * (and measured) before, then `firstNonMeasuredItemIndex` is `undefined`.
1581
- *
1582
- * The `stateUpdate` parameter is just an optional "additional" state update.
1583
- */
251
+ key: "onItemStateChange",
252
+ value: function onItemStateChange(i, newItemState) {
253
+ this.hasToBeStarted();
1584
254
 
1585
- }, {
1586
- key: "updateItems",
1587
- value:
1588
- /**
1589
- * @deprecated
1590
- * `.updateItems()` has been renamed to `.setItems()`.
1591
- */
1592
- function updateItems(newItems, options) {
1593
- return this.setItems(newItems, options);
255
+ this._onItemStateChange(i, newItemState);
1594
256
  }
1595
257
  /**
1596
258
  * Updates `items`. For example, can prepend or append new items to the list.
@@ -1602,409 +264,8 @@ var VirtualScroller = /*#__PURE__*/function () {
1602
264
  key: "setItems",
1603
265
  value: function setItems(newItems) {
1604
266
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1605
-
1606
- // * @param {object} [newCustomState] — If `customState` was passed to `getInitialState()`, this `newCustomState` updates it.
1607
- var _this$getState6 = this.getState(),
1608
- previousItems = _this$getState6.items; // Even if `newItems` are equal to `this.state.items`,
1609
- // still perform a `setState()` call, because, if `setState()` calls
1610
- // were "asynchronous", there could be a situation when a developer
1611
- // first calls `setItems(newItems)` and then `setItems(oldItems)`:
1612
- // if this function did `return` `if (newItems === this.state.items)`
1613
- // then `setState({ items: newItems })` would be scheduled as part of
1614
- // `setItems(newItems)` call, but the subsequent `setItems(oldItems)` call
1615
- // wouldn't do anything resulting in `newItems` being set as a result,
1616
- // and that wouldn't be what the developer intended.
1617
-
1618
-
1619
- var _this$getState7 = this.getState(),
1620
- itemStates = _this$getState7.itemStates;
1621
-
1622
- var _ref9 = this.resetLayoutAfterResize ? this.resetLayoutAfterResize.stateUpdate : this.getState(),
1623
- itemHeights = _ref9.itemHeights;
1624
-
1625
- (0, _debug["default"])('~ Update items ~');
1626
- var layoutUpdate;
1627
- var itemsUpdateInfo; // Compare the new items to the current items.
1628
-
1629
- var itemsDiff = this.getItemsDiff(previousItems, newItems); // See if it's an "incremental" items update.
1630
-
1631
- if (itemsDiff) {
1632
- var _ref10 = this.resetLayoutAfterResize ? this.resetLayoutAfterResize.stateUpdate : this.getState(),
1633
- firstShownItemIndex = _ref10.firstShownItemIndex,
1634
- lastShownItemIndex = _ref10.lastShownItemIndex,
1635
- beforeItemsHeight = _ref10.beforeItemsHeight,
1636
- afterItemsHeight = _ref10.afterItemsHeight;
1637
-
1638
- var shouldRestoreScrollPosition = firstShownItemIndex === 0 && ( // `preserveScrollPosition` option name is deprecated,
1639
- // use `preserveScrollPositionOnPrependItems` instead.
1640
- options.preserveScrollPositionOnPrependItems || options.preserveScrollPosition);
1641
- var prependedItemsCount = itemsDiff.prependedItemsCount,
1642
- appendedItemsCount = itemsDiff.appendedItemsCount;
1643
- layoutUpdate = this.layout.getLayoutUpdateForItemsDiff({
1644
- firstShownItemIndex: firstShownItemIndex,
1645
- lastShownItemIndex: lastShownItemIndex,
1646
- beforeItemsHeight: beforeItemsHeight,
1647
- afterItemsHeight: afterItemsHeight
1648
- }, {
1649
- prependedItemsCount: prependedItemsCount,
1650
- appendedItemsCount: appendedItemsCount
1651
- }, {
1652
- itemsCount: newItems.length,
1653
- columnsCount: this.getActualColumnsCount(),
1654
- shouldRestoreScrollPosition: shouldRestoreScrollPosition
1655
- });
1656
-
1657
- if (prependedItemsCount > 0) {
1658
- (0, _debug["default"])('Prepend', prependedItemsCount, 'items');
1659
- itemHeights = new Array(prependedItemsCount).concat(itemHeights);
1660
-
1661
- if (itemStates) {
1662
- itemStates = new Array(prependedItemsCount).concat(itemStates);
1663
- } // Restore scroll position after prepending items (if requested).
1664
-
1665
-
1666
- if (shouldRestoreScrollPosition) {
1667
- (0, _debug["default"])('Will restore scroll position');
1668
- this.listHeightChangeWatcher.snapshot({
1669
- previousItems: previousItems,
1670
- newItems: newItems,
1671
- prependedItemsCount: prependedItemsCount
1672
- }); // "Seamless prepend" scenario doesn't result in a re-layout,
1673
- // so if any "non measured item" is currently pending,
1674
- // it doesn't get reset and will be handled after `state` is updated.
1675
-
1676
- if (this.firstNonMeasuredItemIndex !== undefined) {
1677
- this.firstNonMeasuredItemIndex += prependedItemsCount;
1678
- }
1679
- } else {
1680
- (0, _debug["default"])('Reset layout'); // Reset layout because none of the prepended items have been measured.
1681
-
1682
- layoutUpdate = this.layout.getInitialLayoutValues({
1683
- itemsCount: newItems.length,
1684
- columnsCount: this.getActualColumnsCount()
1685
- }); // Unschedule a potentially scheduled layout update
1686
- // after measuring a previously non-measured item
1687
- // because the list will be re-layout anyway
1688
- // due to the new items being set.
1689
-
1690
- this.firstNonMeasuredItemIndex = undefined;
1691
- }
1692
- }
1693
-
1694
- if (appendedItemsCount > 0) {
1695
- (0, _debug["default"])('Append', appendedItemsCount, 'items');
1696
- itemHeights = itemHeights.concat(new Array(appendedItemsCount));
1697
-
1698
- if (itemStates) {
1699
- itemStates = itemStates.concat(new Array(appendedItemsCount));
1700
- }
1701
- }
1702
-
1703
- itemsUpdateInfo = {
1704
- prepend: prependedItemsCount > 0,
1705
- append: appendedItemsCount > 0
1706
- };
1707
- } else {
1708
- (0, _debug["default"])('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.');
1709
- (0, _debug["default"])('Previous items', previousItems);
1710
- (0, _debug["default"])('New items', newItems); // Reset item heights and item states.
1711
-
1712
- itemHeights = new Array(newItems.length);
1713
- itemStates = new Array(newItems.length);
1714
- layoutUpdate = this.layout.getInitialLayoutValues({
1715
- itemsCount: newItems.length,
1716
- columnsCount: this.getActualColumnsCount()
1717
- }); // Unschedule a potentially scheduled layout update
1718
- // after measuring a previously non-measured item
1719
- // because the list will be re-layout from scratch
1720
- // due to the new items being set.
1721
-
1722
- this.firstNonMeasuredItemIndex = undefined; // Also reset any potential pending scroll position restoration.
1723
- // For example, imagine a developer first called `.setItems(incrementalItemsUpdate)`
1724
- // and then called `.setItems(differentItems)` and there was no state update
1725
- // in between those two calls. This could happen because state updates aren't
1726
- // required to be "synchronous". On other words, calling `this.setState()`
1727
- // doesn't necessarily mean that the state is applied immediately.
1728
- // Imagine also that such "delayed" state updates could be batched,
1729
- // like they do in React inside event handlers (though that doesn't apply to this case):
1730
- // https://github.com/facebook/react/issues/10231#issuecomment-316644950
1731
- // If `this.listHeightChangeWatcher` wasn't reset on `.setItems(differentItems)`
1732
- // and if the second `this.setState()` call overwrites the first one
1733
- // then it would attempt to restore scroll position in a situation when
1734
- // it should no longer do that. Hence the reset here.
1735
-
1736
- this.listHeightChangeWatcher.reset();
1737
- itemsUpdateInfo = {
1738
- replace: true
1739
- };
1740
- }
1741
-
1742
- (0, _debug["default"])('~ Update state ~'); // const layoutValuesAfterUpdate = {
1743
- // ...this.getState(),
1744
- // ...layoutUpdate
1745
- // }
1746
- // `layoutUpdate` is equivalent to `layoutValuesAfterUpdate` because
1747
- // `layoutUpdate` contains all the relevant properties.
1748
-
1749
- (0, _debug["default"])('First shown item index', layoutUpdate.firstShownItemIndex);
1750
- (0, _debug["default"])('Last shown item index', layoutUpdate.lastShownItemIndex);
1751
- (0, _debug["default"])('Before items height', layoutUpdate.beforeItemsHeight);
1752
- (0, _debug["default"])('After items height (actual or estimated)', layoutUpdate.afterItemsHeight); // Optionally preload items to be rendered.
1753
- //
1754
- // `layoutUpdate` is equivalent to `layoutValuesAfterUpdate` because
1755
- // `layoutUpdate` contains all the relevant properties.
1756
- //
1757
-
1758
- this.onBeforeShowItems(newItems, itemHeights, layoutUpdate.firstShownItemIndex, layoutUpdate.lastShownItemIndex); // `this.newItemsWillBeRendered` signals that new `items` are being rendered,
1759
- // and that `VirtualScroller` should temporarily stop all other updates.
1760
- //
1761
- // `this.newItemsWillBeRendered` is cleared in `didUpdateState()`.
1762
- //
1763
- // The values in `this.newItemsWillBeRendered` are used, for example,
1764
- // in `.onResize()` handler in order to not break state consistency when
1765
- // state updates are "asynchronous" (delayed) and there's a window resize event
1766
- // in between calling `setState()` below and that call actually being applied.
1767
- //
1768
-
1769
- this.newItemsWillBeRendered = _objectSpread(_objectSpread({}, itemsUpdateInfo), {}, {
1770
- count: newItems.length,
1771
- // `layoutUpdate` now contains all layout-related properties, even if those that
1772
- // didn't change. So `firstShownItemIndex` is always in `this.newItemsWillBeRendered`.
1773
- layout: layoutUpdate
1774
- }); // `layoutUpdate` now contains all layout-related properties, even if those that
1775
- // didn't change. So this part is no longer relevant.
1776
- //
1777
- // // If `firstShownItemIndex` is gonna be modified as a result of setting new items
1778
- // // then keep that "new" `firstShownItemIndex` in order for it to be used by
1779
- // // `onResize()` handler when it calculates "new" `firstShownItemIndex`
1780
- // // based on the new columns count (corresponding to the new window width).
1781
- // if (layoutUpdate.firstShownItemIndex !== undefined) {
1782
- // this.newItemsWillBeRendered = {
1783
- // ...this.newItemsWillBeRendered,
1784
- // firstShownItemIndex: layoutUpdate.firstShownItemIndex
1785
- // }
1786
- // }
1787
- // Update `VirtualScroller` state.
1788
- //
1789
- // This state update should overwrite all the `state` properties
1790
- // that are also updated in the "on scroll" handler (`getShownItemIndexes()`):
1791
- //
1792
- // * `firstShownItemIndex`
1793
- // * `lastShownItemIndex`
1794
- // * `beforeItemsHeight`
1795
- // * `afterItemsHeight`
1796
- //
1797
- // That's because this `setState()` update has a higher priority
1798
- // than that of the "on scroll" handler, so it should overwrite
1799
- // any potential state changes dispatched by the "on scroll" handler.
1800
- //
1801
-
1802
- var newState = _objectSpread(_objectSpread({}, layoutUpdate), {}, {
1803
- items: newItems,
1804
- itemStates: itemStates,
1805
- itemHeights: itemHeights
1806
- }); // Introduced `shouldIncludeBeforeResizeValuesInState()` getter just to prevent
1807
- // cluttering `state` with `beforeResize: undefined` property if `beforeResize`
1808
- // hasn't ever been set in `state` previously.
1809
-
1810
-
1811
- if (this.beforeResize.shouldIncludeBeforeResizeValuesInState()) {
1812
- if (this.shouldDiscardBeforeResizeItemHeights()) {
1813
- // Reset "before resize" item heights because now there're new items prepended
1814
- // with unknown heights, or completely new items with unknown heights, so
1815
- // `beforeItemsHeight` value won't be preserved anyway.
1816
- newState.beforeResize = undefined;
1817
- } else {
1818
- // Overwrite `beforeResize` property in `state` even if it wasn't modified
1819
- // because state updates could be "asynchronous" and in that case there could be
1820
- // some previous `setState()` call from some previous `setItems()` call that
1821
- // hasn't yet been applied, and that previous call might have scheduled setting
1822
- // `state.beforeResize` property to `undefined` in order to reset it, but this
1823
- // next `setState()` call might not require resetting `state.beforeResize` property
1824
- // so it should undo resetting it by simply overwriting it with its normal value.
1825
- newState.beforeResize = this.resetLayoutAfterResize ? this.resetLayoutAfterResize.stateUpdate.beforeResize : this.getState().beforeResize;
1826
- }
1827
- } // `newState` should also overwrite all `state` properties that're updated in `onResize()`
1828
- // because `setItems()`'s state updates always overwrite `onResize()`'s state updates.
1829
- // (The least-priority ones are `onScroll()` state updates, but those're simply skipped
1830
- // if there's a pending `setItems()` or `onResize()` update).
1831
- //
1832
- // `state` property exceptions:
1833
- //
1834
- // `verticalSpacing` property is not updated here because it's fine setting it to
1835
- // `undefined` in `onResize()` — it will simply be re-measured after the component re-renders.
1836
- //
1837
- // `columnsCount` property is also not updated here because by definition it's only
1838
- // updated in `onResize()`.
1839
- // Render.
1840
-
1841
-
1842
- this.setState(newState);
1843
- }
1844
- }, {
1845
- key: "getItemsDiff",
1846
- value: function getItemsDiff(previousItems, newItems) {
1847
- return (0, _getItemsDiff2["default"])(previousItems, newItems, this.isItemEqual);
1848
- } // Returns whether "before resize" item heights should be discarded
1849
- // as a result of calling `setItems()` with a new set of items
1850
- // when an asynchronous `setState()` call inside that function
1851
- // hasn't been applied yet.
1852
- //
1853
- // If `setItems()` update was an "incremental" one and no items
1854
- // have been prepended, then `firstShownItemIndex` is preserved,
1855
- // and all items' heights before it should be kept in order to
1856
- // preserve the top offset of the first shown item so that there's
1857
- // no "content jumping".
1858
- //
1859
- // If `setItems()` update was an "incremental" one but there're
1860
- // some prepended items, then it means that now there're new items
1861
- // with unknown heights at the top, so the top offset of the first
1862
- // shown item won't be preserved because there're no "before resize"
1863
- // heights of those items.
1864
- //
1865
- // If `setItems()` update was not an "incremental" one, then don't
1866
- // attempt to restore previous item heights after a potential window
1867
- // width change because all item heights have been reset.
1868
- //
1869
-
1870
- }, {
1871
- key: "shouldDiscardBeforeResizeItemHeights",
1872
- value: function shouldDiscardBeforeResizeItemHeights() {
1873
- if (this.newItemsWillBeRendered) {
1874
- var _this$newItemsWillBeR = this.newItemsWillBeRendered,
1875
- prepend = _this$newItemsWillBeR.prepend,
1876
- replace = _this$newItemsWillBeR.replace;
1877
- return prepend || replace;
1878
- }
1879
- }
1880
- }, {
1881
- key: "onResize",
1882
- value: function onResize() {
1883
- // Reset "previously calculated layout".
1884
- //
1885
- // The "previously calculated layout" feature is not currently used.
1886
- //
1887
- // The current layout snapshot could be stored as a "previously calculated layout" variable
1888
- // so that it could theoretically be used when calculating new layout incrementally
1889
- // rather than from scratch, which would be an optimization.
1890
- //
1891
- this.previouslyCalculatedLayout = undefined; // Cancel any potential scheduled scroll position restoration.
1892
-
1893
- this.listHeightChangeWatcher.reset(); // Get the most recent items count.
1894
- // If there're a "pending" `setItems()` call then use the items count from that call
1895
- // instead of using the count of currently shown `items` from `state`.
1896
- // A `setItems()` call is "pending" when `setState()` operation is "asynchronous", that is
1897
- // when `setState()` calls aren't applied immediately, like in React.
1898
-
1899
- var itemsCount = this.newItemsWillBeRendered ? this.newItemsWillBeRendered.count : this.getState().itemHeights.length; // If layout values have been calculated as a result of a "pending" `setItems()` call,
1900
- // then don't discard those new layout values and use them instead of the ones from `state`.
1901
- //
1902
- // A `setItems()` call is "pending" when `setState()` operation is "asynchronous", that is
1903
- // when `setState()` calls aren't applied immediately, like in React.
1904
- //
1905
-
1906
- var layout = this.newItemsWillBeRendered ? this.newItemsWillBeRendered.layout : this.getState(); // Update `VirtualScroller` state.
1907
-
1908
- var newState = {
1909
- // This state update should also overwrite all the `state` properties
1910
- // that are also updated in the "on scroll" handler (`getShownItemIndexes()`):
1911
- //
1912
- // * `firstShownItemIndex`
1913
- // * `lastShownItemIndex`
1914
- // * `beforeItemsHeight`
1915
- // * `afterItemsHeight`
1916
- //
1917
- // That's because this `setState()` update has a higher priority
1918
- // than that of the "on scroll" handler, so it should overwrite
1919
- // any potential state changes dispatched by the "on scroll" handler.
1920
- //
1921
- // All these properties might have changed, but they're not
1922
- // recalculated here becase they'll be recalculated after
1923
- // this new state is applied (rendered).
1924
- //
1925
- firstShownItemIndex: layout.firstShownItemIndex,
1926
- lastShownItemIndex: layout.lastShownItemIndex,
1927
- beforeItemsHeight: layout.beforeItemsHeight,
1928
- afterItemsHeight: layout.afterItemsHeight,
1929
- // Reset item heights, because if scrollable container's width (or height)
1930
- // has changed, then the list width (or height) most likely also has changed,
1931
- // and also some CSS `@media()` rules might have been added or removed.
1932
- // So re-render the list entirely.
1933
- itemHeights: new Array(itemsCount),
1934
- columnsCount: this.getActualColumnsCountForState(),
1935
- // Re-measure vertical spacing after render because new CSS styles
1936
- // might be applied for the new window width.
1937
- verticalSpacing: undefined
1938
- };
1939
- var firstShownItemIndex = layout.firstShownItemIndex,
1940
- lastShownItemIndex = layout.lastShownItemIndex; // Get the `columnsCount` for the new window width.
1941
-
1942
- var newColumnsCount = this.getActualColumnsCount(); // Re-calculate `firstShownItemIndex` and `lastShownItemIndex`
1943
- // based on the new `columnsCount` so that the whole row is visible.
1944
-
1945
- var newFirstShownItemIndex = Math.floor(firstShownItemIndex / newColumnsCount) * newColumnsCount;
1946
- var newLastShownItemIndex = Math.ceil((lastShownItemIndex + 1) / newColumnsCount) * newColumnsCount - 1; // Potentially update `firstShownItemIndex` if it needs to be adjusted in order to
1947
- // correspond to the new `columnsCount`.
1948
-
1949
- if (newFirstShownItemIndex !== firstShownItemIndex) {
1950
- (0, _debug["default"])('Columns Count changed from', this.getState().columnsCount || 1, 'to', newColumnsCount);
1951
- (0, _debug["default"])('First Shown Item Index needs to change from', firstShownItemIndex, 'to', newFirstShownItemIndex);
1952
- } // Always rewrite `firstShownItemIndex` and `lastShownItemIndex`
1953
- // as part of the `state` update, even if it hasn't been modified.
1954
- //
1955
- // The reason is that there could be two subsequent `onResize()` calls:
1956
- // the first one could be user resizing the window to half of its width,
1957
- // resulting in an "asynchronous" `setState()` call, and then, before that
1958
- // `setState()` call is applied, a second resize event happens when the user
1959
- // has resized the window back to its original width, meaning that the
1960
- // `columnsCount` is back to its original value.
1961
- // In that case, the final `newFirstShownItemIndex` will be equal to the
1962
- // original `firstShownItemIndex` that was in `state` before the user
1963
- // has started resizing the window, so, in the end, `state.firstShownItemIndex`
1964
- // property wouldn't have changed, but it still has to be part of the final
1965
- // state update in order to overwrite the previous update of `firstShownItemIndex`
1966
- // property that has been scheduled to be applied in state after the first resize
1967
- // happened.
1968
- //
1969
-
1970
-
1971
- newState.firstShownItemIndex = newFirstShownItemIndex;
1972
- newState.lastShownItemIndex = newLastShownItemIndex;
1973
- var verticalSpacing = this.getVerticalSpacing();
1974
- var columnsCount = this.getColumnsCount(); // `beforeResize` is always overwritten in `state` here.
1975
- // (once it has started being tracked in `state`)
1976
-
1977
- if (this.shouldDiscardBeforeResizeItemHeights() || newFirstShownItemIndex === 0) {
1978
- if (this.beforeResize.shouldIncludeBeforeResizeValuesInState()) {
1979
- newState.beforeResize = undefined;
1980
- }
1981
- } // Snapshot "before resize" values in order to preserve the currently
1982
- // shown items' vertical position on screen so that there's no "content jumping".
1983
- else {
1984
- // Keep "before resize" values in order to preserve the currently
1985
- // shown items' vertical position on screen so that there's no
1986
- // "content jumping". These "before resize" values will be discarded
1987
- // when (if) the user scrolls back to the top of the list.
1988
- newState.beforeResize = {
1989
- verticalSpacing: verticalSpacing,
1990
- columnsCount: columnsCount,
1991
- itemHeights: this.beforeResize.snapshotBeforeResizeItemHeights({
1992
- firstShownItemIndex: firstShownItemIndex,
1993
- newFirstShownItemIndex: newFirstShownItemIndex,
1994
- newColumnsCount: newColumnsCount
1995
- })
1996
- };
1997
- } // `this.resetLayoutAfterResize` tells `VirtualScroller` that it should
1998
- // temporarily stop other updates (like "on scroll" updates) and wait
1999
- // for the new `state` to be applied, after which the `didUpdateState()`
2000
- // function will clear this flag and perform a re-layout.
2001
-
2002
-
2003
- this.resetLayoutAfterResize = {
2004
- stateUpdate: newState
2005
- }; // Rerender.
2006
-
2007
- this.setState(newState);
267
+ this.hasToBeStarted();
268
+ return this._setItems(newItems, options);
2008
269
  }
2009
270
  }]);
2010
271
 
@@ -2012,5 +273,4 @@ var VirtualScroller = /*#__PURE__*/function () {
2012
273
  }();
2013
274
 
2014
275
  exports["default"] = VirtualScroller;
2015
- var SLOW_LAYOUT_DURATION = 15; // in milliseconds.
2016
276
  //# sourceMappingURL=VirtualScroller.js.map