virtual-scroller 1.13.1 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/README.md +825 -578
- package/bundle/index-dom-bypass.html +198 -0
- package/bundle/index-dom-grid.html +204 -0
- package/bundle/index-dom-scrollableContainer.html +215 -0
- package/bundle/index-dom-tbody-scrollableContainer.html +81 -0
- package/bundle/index-dom-tbody.html +65 -0
- package/bundle/index-dom.html +116 -83
- package/bundle/{index-bypass.html → index-react-bypass.html} +83 -78
- package/bundle/{index-grid.html → index-react-grid.html} +78 -91
- package/bundle/{index-scrollableContainer.html → index-react-scrollableContainer.html} +96 -91
- package/bundle/index-react-strictMode.html +199 -0
- package/bundle/index-react-tbody-scrollableContainer.html +96 -0
- package/bundle/index-react-tbody.html +80 -0
- package/bundle/{messages.js → items.js} +1 -1
- package/bundle/lib/babel.min.js +25 -0
- package/bundle/lib/prop-types.min.js +1 -0
- package/bundle/lib/react-dom.development.js +29924 -0
- package/bundle/lib/react-dom.production.min.js +267 -0
- package/bundle/lib/react.development.js +3343 -0
- package/bundle/lib/react.production.min.js +31 -0
- package/bundle/style.base.css +33 -0
- package/{website/style.css → bundle/style.list.css} +10 -43
- package/bundle/style.list.grid.css +23 -0
- package/bundle/virtual-scroller-dom.js +1 -1
- package/bundle/virtual-scroller-dom.js.map +1 -1
- package/bundle/virtual-scroller-react.js +1 -1
- package/bundle/virtual-scroller-react.js.map +1 -1
- package/bundle/virtual-scroller.js +1 -1
- package/bundle/virtual-scroller.js.map +1 -1
- package/commonjs/BeforeResize.js +1 -2
- package/commonjs/BeforeResize.js.map +1 -1
- package/commonjs/DOM/VirtualScroller.js +67 -44
- package/commonjs/DOM/VirtualScroller.js.map +1 -1
- package/commonjs/DOM/tbody.js +15 -15
- package/commonjs/DOM/tbody.js.map +1 -1
- package/commonjs/ItemHeights.js +10 -13
- package/commonjs/ItemHeights.js.map +1 -1
- package/commonjs/Layout.defaults.js +21 -0
- package/commonjs/Layout.defaults.js.map +1 -0
- package/commonjs/Layout.js +78 -67
- package/commonjs/Layout.js.map +1 -1
- package/commonjs/Layout.test.js +8 -4
- package/commonjs/Layout.test.js.map +1 -1
- package/commonjs/Scroll.js +3 -3
- package/commonjs/Scroll.js.map +1 -1
- package/commonjs/ScrollableContainerResizeHandler.js +4 -5
- package/commonjs/ScrollableContainerResizeHandler.js.map +1 -1
- package/commonjs/VirtualScroller.constructor.js +53 -31
- package/commonjs/VirtualScroller.constructor.js.map +1 -1
- package/commonjs/VirtualScroller.items.js +50 -4
- package/commonjs/VirtualScroller.items.js.map +1 -1
- package/commonjs/VirtualScroller.js +44 -28
- package/commonjs/VirtualScroller.js.map +1 -1
- package/commonjs/VirtualScroller.layout.js +42 -31
- package/commonjs/VirtualScroller.layout.js.map +1 -1
- package/commonjs/VirtualScroller.onContainerResize.js +1 -2
- package/commonjs/VirtualScroller.onContainerResize.js.map +1 -1
- package/commonjs/VirtualScroller.onRender.js +1 -1
- package/commonjs/VirtualScroller.onRender.js.map +1 -1
- package/commonjs/VirtualScroller.state.js +18 -9
- package/commonjs/VirtualScroller.state.js.map +1 -1
- package/commonjs/VirtualScroller.verticalSpacing.js +39 -6
- package/commonjs/VirtualScroller.verticalSpacing.js.map +1 -1
- package/commonjs/react/VirtualScroller.js +98 -37
- package/commonjs/react/VirtualScroller.js.map +1 -1
- package/commonjs/react/useClassName.js +2 -2
- package/commonjs/react/useClassName.js.map +1 -1
- package/commonjs/react/useForwardedRef.js +50 -0
- package/commonjs/react/useForwardedRef.js.map +1 -0
- package/commonjs/react/useInstanceMethods.js +4 -4
- package/commonjs/react/useInstanceMethods.js.map +1 -1
- package/commonjs/react/useItemKeys.js +28 -5
- package/commonjs/react/useItemKeys.js.map +1 -1
- package/commonjs/react/useOnItemHeightDidChange.js +28 -12
- package/commonjs/react/useOnItemHeightDidChange.js.map +1 -1
- package/commonjs/react/useSetItemState.js +31 -12
- package/commonjs/react/useSetItemState.js.map +1 -1
- package/commonjs/react/useState.js +10 -11
- package/commonjs/react/useState.js.map +1 -1
- package/commonjs/react/{useStateNoStaleBug.js → useStateWithRepeatableRead.js} +3 -3
- package/commonjs/react/useStateWithRepeatableRead.js.map +1 -0
- package/commonjs/react/useStyle.js +10 -4
- package/commonjs/react/useStyle.js.map +1 -1
- package/commonjs/react/useValidateTableBodyItemsContainer.js +24 -0
- package/commonjs/react/useValidateTableBodyItemsContainer.js.map +1 -0
- package/commonjs/react/useVirtualScroller.js +12 -14
- package/commonjs/react/useVirtualScroller.js.map +1 -1
- package/commonjs/test/ItemsContainer.js +10 -10
- package/commonjs/test/ItemsContainer.js.map +1 -1
- package/commonjs/test/VirtualScroller.js +25 -10
- package/commonjs/test/VirtualScroller.js.map +1 -1
- package/dom/index.d.ts +11 -9
- package/index.d.ts +19 -9
- package/modules/BeforeResize.js +1 -2
- package/modules/BeforeResize.js.map +1 -1
- package/modules/DOM/VirtualScroller.js +67 -44
- package/modules/DOM/VirtualScroller.js.map +1 -1
- package/modules/DOM/tbody.js +14 -13
- package/modules/DOM/tbody.js.map +1 -1
- package/modules/ItemHeights.js +11 -14
- package/modules/ItemHeights.js.map +1 -1
- package/modules/Layout.defaults.js +11 -0
- package/modules/Layout.defaults.js.map +1 -0
- package/modules/Layout.js +77 -67
- package/modules/Layout.js.map +1 -1
- package/modules/Layout.test.js +8 -4
- package/modules/Layout.test.js.map +1 -1
- package/modules/Scroll.js +3 -3
- package/modules/Scroll.js.map +1 -1
- package/modules/ScrollableContainerResizeHandler.js +4 -5
- package/modules/ScrollableContainerResizeHandler.js.map +1 -1
- package/modules/VirtualScroller.constructor.js +53 -31
- package/modules/VirtualScroller.constructor.js.map +1 -1
- package/modules/VirtualScroller.items.js +51 -5
- package/modules/VirtualScroller.items.js.map +1 -1
- package/modules/VirtualScroller.js +44 -28
- package/modules/VirtualScroller.js.map +1 -1
- package/modules/VirtualScroller.layout.js +42 -31
- package/modules/VirtualScroller.layout.js.map +1 -1
- package/modules/VirtualScroller.onContainerResize.js +1 -2
- package/modules/VirtualScroller.onContainerResize.js.map +1 -1
- package/modules/VirtualScroller.onRender.js +1 -1
- package/modules/VirtualScroller.onRender.js.map +1 -1
- package/modules/VirtualScroller.state.js +18 -9
- package/modules/VirtualScroller.state.js.map +1 -1
- package/modules/VirtualScroller.verticalSpacing.js +38 -6
- package/modules/VirtualScroller.verticalSpacing.js.map +1 -1
- package/modules/react/VirtualScroller.js +97 -38
- package/modules/react/VirtualScroller.js.map +1 -1
- package/modules/react/useClassName.js +3 -3
- package/modules/react/useClassName.js.map +1 -1
- package/modules/react/useForwardedRef.js +42 -0
- package/modules/react/useForwardedRef.js.map +1 -0
- package/modules/react/useInstanceMethods.js +4 -4
- package/modules/react/useInstanceMethods.js.map +1 -1
- package/modules/react/useItemKeys.js +28 -5
- package/modules/react/useItemKeys.js.map +1 -1
- package/modules/react/useOnItemHeightDidChange.js +28 -12
- package/modules/react/useOnItemHeightDidChange.js.map +1 -1
- package/modules/react/useSetItemState.js +31 -12
- package/modules/react/useSetItemState.js.map +1 -1
- package/modules/react/useState.js +10 -11
- package/modules/react/useState.js.map +1 -1
- package/modules/react/{useStateNoStaleBug.js → useStateWithRepeatableRead.js} +2 -2
- package/modules/react/useStateWithRepeatableRead.js.map +1 -0
- package/modules/react/useStyle.js +10 -4
- package/modules/react/useStyle.js.map +1 -1
- package/modules/react/useValidateTableBodyItemsContainer.js +16 -0
- package/modules/react/useValidateTableBodyItemsContainer.js.map +1 -0
- package/modules/react/useVirtualScroller.js +10 -12
- package/modules/react/useVirtualScroller.js.map +1 -1
- package/modules/test/ItemsContainer.js +10 -10
- package/modules/test/ItemsContainer.js.map +1 -1
- package/modules/test/VirtualScroller.js +25 -10
- package/modules/test/VirtualScroller.js.map +1 -1
- package/package.json +1 -1
- package/react/as.d.ts +42 -0
- package/react/index.d.ts +204 -63
- package/source/BeforeResize.js +1 -2
- package/source/DOM/VirtualScroller.js +65 -40
- package/source/DOM/tbody.js +15 -14
- package/source/ItemHeights.js +11 -12
- package/source/Layout.defaults.js +8 -0
- package/source/Layout.js +69 -56
- package/source/Layout.test.js +7 -2
- package/source/Scroll.js +3 -3
- package/source/ScrollableContainerResizeHandler.js +4 -4
- package/source/VirtualScroller.constructor.js +40 -31
- package/source/VirtualScroller.items.js +47 -2
- package/source/VirtualScroller.js +49 -27
- package/source/VirtualScroller.layout.js +43 -30
- package/source/VirtualScroller.onContainerResize.js +1 -2
- package/source/VirtualScroller.onRender.js +1 -1
- package/source/VirtualScroller.state.js +18 -11
- package/source/VirtualScroller.verticalSpacing.js +32 -6
- package/source/react/VirtualScroller.js +111 -36
- package/source/react/useClassName.js +3 -3
- package/source/react/useForwardedRef.js +39 -0
- package/source/react/useInstanceMethods.js +12 -4
- package/source/react/useItemKeys.js +22 -4
- package/source/react/useOnItemHeightDidChange.js +29 -10
- package/source/react/useSetItemState.js +32 -10
- package/source/react/useState.js +7 -8
- package/source/react/{useStateNoStaleBug.js → useStateWithRepeatableRead.js} +1 -1
- package/source/react/useStyle.js +3 -2
- package/source/react/useValidateTableBodyItemsContainer.js +16 -0
- package/source/react/useVirtualScroller.js +4 -6
- package/source/test/ItemsContainer.js +10 -10
- package/source/test/VirtualScroller.js +16 -10
- package/website/index-dom-bypass.html +198 -0
- package/website/index-dom-grid.html +204 -0
- package/website/index-dom-scrollableContainer.html +215 -0
- package/website/index-dom-tbody-scrollableContainer.html +81 -0
- package/website/index-dom-tbody.html +65 -0
- package/website/index-dom.html +117 -84
- package/website/index-react-bypass.html +200 -0
- package/website/{index-grid.html → index-react-grid.html} +79 -92
- package/website/index-react-scrollableContainer.html +213 -0
- package/website/index-react-strictMode.html +199 -0
- package/website/index-react-tbody-scrollableContainer.html +96 -0
- package/website/index-react-tbody.html +80 -0
- package/website/{index-bypass.html → index-react.html} +84 -70
- package/website/index.html +84 -69
- package/website/{messages.js → items.js} +1 -1
- package/website/lib/babel.min.js +25 -0
- package/website/lib/prop-types.min.js +1 -0
- package/website/lib/react-dom.development.js +29924 -0
- package/website/lib/react-dom.production.min.js +267 -0
- package/website/lib/react.development.js +3343 -0
- package/website/lib/react.production.min.js +31 -0
- package/website/style.base.css +33 -0
- package/website/style.list.css +92 -0
- package/website/style.list.grid.css +23 -0
- package/bundle/index-tbody-scrollableContainer.html +0 -70
- package/bundle/index-tbody.html +0 -57
- package/bundle/on-scroll-to-dom.js +0 -2
- package/bundle/on-scroll-to-dom.js.map +0 -1
- package/bundle/on-scroll-to-react.js +0 -2
- package/bundle/on-scroll-to-react.js.map +0 -1
- package/bundle/on-scroll-to.js +0 -2
- package/bundle/on-scroll-to.js.map +0 -1
- package/commonjs/react/useStateNoStaleBug.js.map +0 -1
- package/modules/react/useStateNoStaleBug.js.map +0 -1
- package/website/index-scrollableContainer.html +0 -208
- package/website/index-tbody-scrollableContainer.html +0 -70
- package/website/index-tbody.html +0 -57
- package/website/lib/on-scroll-to-dom.js +0 -2
- package/website/lib/on-scroll-to-dom.js.map +0 -1
- package/website/lib/on-scroll-to-react.js +0 -2
- package/website/lib/on-scroll-to-react.js.map +0 -1
|
@@ -9,12 +9,12 @@ exports["default"] = void 0;
|
|
|
9
9
|
|
|
10
10
|
var _VirtualScrollerConstructor = _interopRequireDefault(require("./VirtualScroller.constructor.js"));
|
|
11
11
|
|
|
12
|
-
var _tbody = require("./DOM/tbody.js");
|
|
13
|
-
|
|
14
12
|
var _Layout = require("./Layout.js");
|
|
15
13
|
|
|
16
14
|
var _debug = _interopRequireWildcard(require("./utility/debug.js"));
|
|
17
15
|
|
|
16
|
+
var _tbody = require("./DOM/tbody.js");
|
|
17
|
+
|
|
18
18
|
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); }
|
|
19
19
|
|
|
20
20
|
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; }
|
|
@@ -35,7 +35,7 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
|
|
|
35
35
|
|
|
36
36
|
var VirtualScroller = /*#__PURE__*/function () {
|
|
37
37
|
/**
|
|
38
|
-
* @param {function} getItemsContainerElement — Returns the container DOM `Element`.
|
|
38
|
+
* @param {function} getItemsContainerElement — Returns the items container DOM `Element`.
|
|
39
39
|
* @param {any[]} items — The list of items.
|
|
40
40
|
* @param {Object} [options] — See README.md.
|
|
41
41
|
* @return {VirtualScroller}
|
|
@@ -100,15 +100,10 @@ var VirtualScroller = /*#__PURE__*/function () {
|
|
|
100
100
|
var isRestart = this._isActive === false;
|
|
101
101
|
|
|
102
102
|
if (!isRestart) {
|
|
103
|
-
this.
|
|
104
|
-
//
|
|
105
|
-
|
|
106
|
-
if (!this._usesCustomStateStorage) {
|
|
107
|
-
this.useDefaultStateStorage();
|
|
108
|
-
} // If `render()` function parameter was passed,
|
|
103
|
+
this.setUpState();
|
|
104
|
+
this.waitingForRender = true; // If `render()` function parameter was passed,
|
|
109
105
|
// perform an initial render.
|
|
110
106
|
|
|
111
|
-
|
|
112
107
|
if (this._render) {
|
|
113
108
|
this._render(this.getState());
|
|
114
109
|
}
|
|
@@ -127,12 +122,24 @@ var VirtualScroller = /*#__PURE__*/function () {
|
|
|
127
122
|
|
|
128
123
|
this._isResizing = undefined; // Reset `_isSettingNewItems` flag just in case it has some "leftover" value.
|
|
129
124
|
|
|
130
|
-
this._isSettingNewItems = undefined; //
|
|
125
|
+
this._isSettingNewItems = undefined; // When `<tbody/>` is used as an items container element,
|
|
126
|
+
// `virtual-scroller` has to work around the HTML bug of
|
|
127
|
+
// `padding` not working on a `<tbody/>` element.
|
|
131
128
|
// https://gitlab.com/catamphetamine/virtual-scroller/-/issues/1
|
|
132
129
|
|
|
133
|
-
if (this.
|
|
134
|
-
if (
|
|
135
|
-
(0, _tbody.
|
|
130
|
+
if (!this.isInBypassMode()) {
|
|
131
|
+
if (this.isItemsContainerElementTableBody()) {
|
|
132
|
+
if ((0, _tbody.supportsTbody)()) {
|
|
133
|
+
if (!(0, _tbody.hasTbodyStyles)(this.getItemsContainerElement())) {
|
|
134
|
+
(0, _debug["default"])('~ <tbody/> container ~');
|
|
135
|
+
(0, _tbody.addTbodyStyles)(this.getItemsContainerElement());
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
(0, _debug["default"])('~ <tbody/> container not supported ~');
|
|
139
|
+
(0, _debug.reportError)(_tbody.BROWSER_NOT_SUPPORTED_ERROR);
|
|
140
|
+
(0, _debug["default"])('~ enter "bypass" mode ~');
|
|
141
|
+
this._bypass = true;
|
|
142
|
+
}
|
|
136
143
|
}
|
|
137
144
|
} // If there was a pending "after render" state update that didn't get applied
|
|
138
145
|
// because the `VirtualScroller` got stopped, then apply that pending "after render"
|
|
@@ -222,10 +229,19 @@ var VirtualScroller = /*#__PURE__*/function () {
|
|
|
222
229
|
value:
|
|
223
230
|
/**
|
|
224
231
|
* Returns the items's top offset relative to the scrollable container's top edge.
|
|
225
|
-
* @param {
|
|
232
|
+
* @param {any} item — Item
|
|
226
233
|
* @return {[number]} Returns the item's scroll Y position. Returns `undefined` if any of the previous items haven't been rendered yet.
|
|
227
234
|
*/
|
|
228
|
-
function getItemScrollPosition(
|
|
235
|
+
function getItemScrollPosition(itemOrIndex) {
|
|
236
|
+
// Item index.
|
|
237
|
+
var i = this._getItemIndexByItemOrIndex(itemOrIndex); // If the item wasn't found, the error was already reported,
|
|
238
|
+
// so just return some "sensible" default value.
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
if (i === undefined) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
229
245
|
var itemTopOffsetInList = this.layout.getItemTopOffset(i);
|
|
230
246
|
|
|
231
247
|
if (itemTopOffsetInList === undefined) {
|
|
@@ -241,32 +257,32 @@ var VirtualScroller = /*#__PURE__*/function () {
|
|
|
241
257
|
|
|
242
258
|
}, {
|
|
243
259
|
key: "onItemHeightChange",
|
|
244
|
-
value: function onItemHeightChange(
|
|
245
|
-
(0, _debug.warn)('`.onItemHeightChange(
|
|
246
|
-
this.onItemHeightDidChange(
|
|
260
|
+
value: function onItemHeightChange(item) {
|
|
261
|
+
(0, _debug.warn)('`.onItemHeightChange(item)` method was renamed to `.onItemHeightDidChange(item)`');
|
|
262
|
+
this.onItemHeightDidChange(item);
|
|
247
263
|
}
|
|
248
264
|
/**
|
|
249
265
|
* Forces a re-measure of an item's height.
|
|
250
|
-
* @param
|
|
266
|
+
* @param {any} item — Item. Legacy argument variant: Item index.
|
|
251
267
|
*/
|
|
252
268
|
|
|
253
269
|
}, {
|
|
254
270
|
key: "onItemHeightDidChange",
|
|
255
|
-
value: function onItemHeightDidChange(
|
|
271
|
+
value: function onItemHeightDidChange(itemOrIndex) {
|
|
256
272
|
// See the comments in the `setItemState()` function below for the rationale
|
|
257
273
|
// on why the `hasToBeStarted()` check was commented out.
|
|
258
274
|
// this.hasToBeStarted()
|
|
259
|
-
this._onItemHeightDidChange(
|
|
275
|
+
this._onItemHeightDidChange(itemOrIndex);
|
|
260
276
|
}
|
|
261
277
|
/**
|
|
262
278
|
* Updates an item's state in `state.itemStates[]`.
|
|
263
|
-
* @param {
|
|
264
|
-
* @param {any}
|
|
279
|
+
* @param {any} item — Item. Legacy argument variant: Item index.
|
|
280
|
+
* @param {any} newItemState — Item's new state
|
|
265
281
|
*/
|
|
266
282
|
|
|
267
283
|
}, {
|
|
268
284
|
key: "setItemState",
|
|
269
|
-
value: function setItemState(
|
|
285
|
+
value: function setItemState(itemOrIndex, newItemState) {
|
|
270
286
|
// There is an issue in React 18.2.0 when `useInsertionEffect()` doesn't run twice
|
|
271
287
|
// on mount unlike `useLayoutEffect()` in "strict" mode. That causes a bug in a React
|
|
272
288
|
// implementation of the `virtual-scroller`.
|
|
@@ -309,14 +325,14 @@ var VirtualScroller = /*#__PURE__*/function () {
|
|
|
309
325
|
// Commenting it out wouldn't result in any potential bugs because the code would work correctly
|
|
310
326
|
// in both cases.
|
|
311
327
|
// this.hasToBeStarted()
|
|
312
|
-
this._setItemState(
|
|
328
|
+
this._setItemState(itemOrIndex, newItemState);
|
|
313
329
|
} // (deprecated)
|
|
314
330
|
// Use `.setItemState()` method name instead.
|
|
315
331
|
|
|
316
332
|
}, {
|
|
317
333
|
key: "onItemStateChange",
|
|
318
|
-
value: function onItemStateChange(
|
|
319
|
-
this.setItemState(
|
|
334
|
+
value: function onItemStateChange(item, newItemState) {
|
|
335
|
+
this.setItemState(item, newItemState);
|
|
320
336
|
}
|
|
321
337
|
/**
|
|
322
338
|
* Updates `items`. For example, can prepend or append new items to the list.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VirtualScroller.js","names":["VirtualScroller","getItemsContainerElement","items","options","_isActive","Error","log","scrollableContainerResizeHandler","stop","scroll","listTopOffsetWatcher","isStarted","cancelLayoutTimer","hasToBeStarted","onUpdateShownItemIndexes","reason","LAYOUT_REASON","MANUAL","_onRender","getState","previousState","VirtualScrollerConstructor","call","isRestart","waitingForRender","_usesCustomStateStorage","useDefaultStateStorage","_render","listHeightMeasurement","reset","_isResizing","undefined","_isSettingNewItems","tbody","hasTbodyStyles","addTbodyStyles","stateUpdate","_afterRenderStateUpdateThatWasStopped","verticalSpacing","verticalSpacingStateUpdate","measureItemHeightsAndSpacing","start","scrollableContainerWidth","scrollableContainer","getWidth","newWidth","prevWidth","onContainerResize","columnsCount","getActualColumnsCount","columnsCountFromState","STARTED","i","itemTopOffsetInList","layout","getItemTopOffset","getListTopOffsetInsideScrollableContainer","warn","onItemHeightDidChange","_onItemHeightDidChange","newItemState","_setItemState","setItemState","newItems","_setItems"],"sources":["../source/VirtualScroller.js"],"sourcesContent":["import VirtualScrollerConstructor from './VirtualScroller.constructor.js'\r\nimport { hasTbodyStyles, addTbodyStyles } from './DOM/tbody.js'\r\nimport { LAYOUT_REASON } from './Layout.js'\r\nimport log, { warn } from './utility/debug.js'\r\n\r\nexport default class VirtualScroller {\r\n\t/**\r\n\t * @param {function} getItemsContainerElement — Returns the container DOM `Element`.\r\n\t * @param {any[]} items — The list of items.\r\n\t * @param {Object} [options] — See README.md.\r\n\t * @return {VirtualScroller}\r\n\t */\r\n\tconstructor(\r\n\t\tgetItemsContainerElement,\r\n\t\titems,\r\n\t\toptions = {}\r\n\t) {\r\n\t\tVirtualScrollerConstructor.call(\r\n\t\t\tthis,\r\n\t\t\tgetItemsContainerElement,\r\n\t\t\titems,\r\n\t\t\toptions\r\n\t\t)\r\n\t}\r\n\r\n\t/**\r\n\t * Should be invoked after a \"container\" DOM Element is mounted (inserted into the DOM tree).\r\n\t */\r\n\tstart() {\r\n\t\tif (this._isActive) {\r\n\t\t\tthrow new Error('[virtual-scroller] `VirtualScroller` has already been started')\r\n\t\t}\r\n\r\n\t\t// If has been stopped previously.\r\n\t\tconst isRestart = this._isActive === false\r\n\r\n\t\tif (!isRestart) {\r\n\t\t\tthis.waitingForRender = true\r\n\r\n\t\t\t// If no custom state storage has been configured, use the default one.\r\n\t\t\t// Also sets the initial state.\r\n\t\t\tif (!this._usesCustomStateStorage) {\r\n\t\t\t\tthis.useDefaultStateStorage()\r\n\t\t\t}\r\n\t\t\t// If `render()` function parameter was passed,\r\n\t\t\t// perform an initial render.\r\n\t\t\tif (this._render) {\r\n\t\t\t\tthis._render(this.getState())\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (isRestart) {\r\n\t\t\tlog('~ Start (restart) ~')\r\n\t\t} else {\r\n\t\t\tlog('~ Start ~')\r\n\t\t}\r\n\r\n\t\t// `this._isActive = true` should be placed somewhere at the start of this function.\r\n\t\tthis._isActive = true\r\n\r\n\t\t// Reset `ListHeightMeasurement` just in case it has some \"leftover\" state.\r\n\t\tthis.listHeightMeasurement.reset()\r\n\r\n\t\t// Reset `_isResizing` flag just in case it has some \"leftover\" value.\r\n\t\tthis._isResizing = undefined\r\n\r\n\t\t// Reset `_isSettingNewItems` flag just in case it has some \"leftover\" value.\r\n\t\tthis._isSettingNewItems = undefined\r\n\r\n\t\t// Work around `<tbody/>` not being able to have `padding`.\r\n\t\t// https://gitlab.com/catamphetamine/virtual-scroller/-/issues/1\r\n\t\tif (this.tbody) {\r\n\t\t\tif (!hasTbodyStyles(this.getItemsContainerElement())) {\r\n\t\t\t\taddTbodyStyles(this.getItemsContainerElement())\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// If there was a pending \"after render\" state update that didn't get applied\r\n\t\t// because the `VirtualScroller` got stopped, then apply that pending \"after render\"\r\n\t\t// state update now. Such state update could include properties like:\r\n\t\t// * A `verticalSpacing` that has been measured in `onRender()`.\r\n\t\t// * A cleaned-up `beforeResize` object that was cleaned-up in `onRender()`.\r\n\t\tlet stateUpdate = this._afterRenderStateUpdateThatWasStopped\r\n\t\tthis._afterRenderStateUpdateThatWasStopped = undefined\r\n\r\n\t\t// Reset `this.verticalSpacing` so that it re-measures it in cases when\r\n\t\t// the `VirtualScroller` was previously stopped and is now being restarted.\r\n\t\t// The rationale is that a previously captured inter-item vertical spacing\r\n\t\t// can't be \"trusted\" in a sense that the user might have resized the window\r\n\t\t// after the previous `state` has been snapshotted.\r\n\t\t// If the user has resized the window, then changing window width might have\r\n\t\t// activated different CSS `@media()` \"queries\" resulting in a potentially different\r\n\t\t// vertical spacing after the restart.\r\n\t\t// If it's not a restart then `this.verticalSpacing` is `undefined` anyway.\r\n\t\tthis.verticalSpacing = undefined\r\n\r\n\t\tconst verticalSpacingStateUpdate = this.measureItemHeightsAndSpacing()\r\n\t\tif (verticalSpacingStateUpdate) {\r\n\t\t\tstateUpdate = {\r\n\t\t\t\t...stateUpdate,\r\n\t\t\t\t...verticalSpacingStateUpdate\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.scrollableContainerResizeHandler.start()\r\n\t\tthis.scroll.start()\r\n\r\n\t\t// If `scrollableContainerWidth` hasn't been measured yet,\r\n\t\t// measure it and write it to state.\r\n\t\tif (this.getState().scrollableContainerWidth === undefined) {\r\n\t\t\tconst scrollableContainerWidth = this.scrollableContainer.getWidth()\r\n\t\t\tstateUpdate = {\r\n\t\t\t\t...stateUpdate,\r\n\t\t\t\tscrollableContainerWidth\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\t// Reset layout:\r\n\t\t\t// * If the scrollable container width has changed while stopped.\r\n\t\t\t// * If the restored state was calculated for another scrollable container width.\r\n\t\t\tconst newWidth = this.scrollableContainer.getWidth()\r\n\t\t\tconst prevWidth = this.getState().scrollableContainerWidth\r\n\t\t\tif (newWidth !== prevWidth) {\r\n\t\t\t\tlog('~ Scrollable container width changed from', prevWidth, 'to', newWidth, '~')\r\n\t\t\t\t// The pending state update (if present) won't be applied in this case.\r\n\t\t\t\t// That's ok because such state update could currently only originate in\r\n\t\t\t\t// `this.onContainerResize()` function. Therefore, alling `this.onContainerResize()` again\r\n\t\t\t\t// would rewrite all those `stateUpdate` properties anyway, so they're not passed.\r\n\t\t\t\treturn this.onContainerResize()\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// If the `VirtualScroller` uses custom (external) state storage, then\r\n\t\t// check if the columns count has changed between calling `.getInitialState()`\r\n\t\t// and `.start()`. If it has, perform a re-layout \"from scratch\".\r\n\t\tif (this._usesCustomStateStorage) {\r\n\t\t\tconst columnsCount = this.getActualColumnsCount()\r\n\t\t\tconst columnsCountFromState = this.getState().columnsCount || 1\r\n\t\t\tif (columnsCount !== columnsCountFromState) {\r\n\t\t\t\treturn this.onContainerResize()\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Re-calculate layout and re-render the list.\r\n\t\t// Do that even if when an initial `state` parameter, containing layout values,\r\n\t\t// has been passed. The reason is that the `state` parameter can't be \"trusted\"\r\n\t\t// in a way that it could have been snapshotted for another window width and\r\n\t\t// the user might have resized their window since then.\r\n\t\tthis.onUpdateShownItemIndexes({ reason: LAYOUT_REASON.STARTED, stateUpdate })\r\n\t}\r\n\r\n\t// Could be passed as a \"callback\" parameter, so bind it to `this`.\r\n\tstop = () => {\r\n\t\tif (!this._isActive) {\r\n\t\t\tthrow new Error('[virtual-scroller] Can\\'t stop a `VirtualScroller` that hasn\\'t been started')\r\n\t\t}\r\n\r\n\t\tthis._isActive = false\r\n\r\n\t\tlog('~ Stop ~')\r\n\r\n\t\tthis.scrollableContainerResizeHandler.stop()\r\n\t\tthis.scroll.stop()\r\n\r\n\t\t// Stop `ListTopOffsetWatcher` if it has been started.\r\n\t\t// There seems to be no need to restart `ListTopOffsetWatcher`.\r\n\t\t// It's mainly a hacky workaround for development mode anyway.\r\n\t\tif (this.listTopOffsetWatcher && this.listTopOffsetWatcher.isStarted()) {\r\n\t\t\tthis.listTopOffsetWatcher.stop()\r\n\t\t}\r\n\r\n\t\t// Cancel any scheduled layout.\r\n\t\tthis.cancelLayoutTimer({})\r\n\t}\r\n\r\n\thasToBeStarted() {\r\n\t\tif (!this._isActive) {\r\n\t\t\tthrow new Error('[virtual-scroller] `VirtualScroller` hasn\\'t been started')\r\n\t\t}\r\n\t}\r\n\r\n\t// Bind it to `this` because this function could hypothetically be passed\r\n\t// as a \"callback\" parameter.\r\n\tupdateLayout = () => {\r\n\t\tthis.hasToBeStarted()\r\n\t\tthis.onUpdateShownItemIndexes({ reason: LAYOUT_REASON.MANUAL })\r\n\t}\r\n\r\n\t// Bind the function to `this` so that it could be passed as a callback\r\n\t// in a random application's code.\r\n\tonRender = () => {\r\n\t\tthis._onRender(this.getState(), this.previousState)\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the items's top offset relative to the scrollable container's top edge.\r\n\t * @param {number} i — Item index\r\n\t * @return {[number]} Returns the item's scroll Y position. Returns `undefined` if any of the previous items haven't been rendered yet.\r\n\t */\r\n\tgetItemScrollPosition(i) {\r\n\t\tconst itemTopOffsetInList = this.layout.getItemTopOffset(i)\r\n\t\tif (itemTopOffsetInList === undefined) {\r\n\t\t\treturn\r\n\t\t}\r\n\t\treturn this.getListTopOffsetInsideScrollableContainer() + itemTopOffsetInList\r\n\t}\r\n\r\n\t/**\r\n\t * @deprecated\r\n\t * `.onItemHeightChange()` has been renamed to `.onItemHeightDidChange()`.\r\n\t */\r\n\tonItemHeightChange(i) {\r\n\t\twarn('`.onItemHeightChange(i)` method was renamed to `.onItemHeightDidChange(i)`')\r\n\t\tthis.onItemHeightDidChange(i)\r\n\t}\r\n\r\n\t/**\r\n\t * Forces a re-measure of an item's height.\r\n\t * @param {number} i — Item index\r\n\t */\r\n\tonItemHeightDidChange(i) {\r\n\t\t// See the comments in the `setItemState()` function below for the rationale\r\n\t\t// on why the `hasToBeStarted()` check was commented out.\r\n\t\t// this.hasToBeStarted()\r\n\t\tthis._onItemHeightDidChange(i)\r\n\t}\r\n\r\n\t/**\r\n\t * Updates an item's state in `state.itemStates[]`.\r\n\t * @param {number} i — Item index\r\n\t * @param {any} i — Item's new state\r\n\t */\r\n\tsetItemState(i, newItemState) {\r\n\t\t// There is an issue in React 18.2.0 when `useInsertionEffect()` doesn't run twice\r\n\t\t// on mount unlike `useLayoutEffect()` in \"strict\" mode. That causes a bug in a React\r\n\t\t// implementation of the `virtual-scroller`.\r\n\t\t// https://gitlab.com/catamphetamine/virtual-scroller/-/issues/33\r\n\t\t// https://github.com/facebook/react/issues/26320\r\n\t\t// A workaround for that bug is ignoring the second-initial run of the effects at mount.\r\n\t\t//\r\n\t\t// But in that case, if an `ItemComponent` calls `setItemState()` in `useLayoutEffect()`,\r\n\t\t// it could result in a bug.\r\n\t\t//\r\n\t\t// Consider a type of `useLayoutEffect()` that skips the initial mount:\r\n\t\t// `useLayoutEffectSkipInitialMount()`.\r\n\t\t// Suppose that effect is written in such a way that it only skips the first call of itself.\r\n\t\t// In that case, if React is run in \"strict\" mode, the effect will no longer work as expected\r\n\t\t// and it won't actually skip the initial mount and will be executed during the second initial run.\r\n\t\t// But the `VirtualScroller` itself has already implemented a workaround that prevents\r\n\t\t// its hooks from running twice on mount. This means that `useVirtualScrollerStartStop()`\r\n\t\t// of the React component would have already stopped the `VirtualScroller` by the time\r\n\t\t// `ItemComponent`'s incorrectly-behaving `useLayoutEffectSkipInitialMount()` effect is run,\r\n\t\t// resulting in an error: \"`VirtualScroller` hasn't been started\".\r\n\t\t//\r\n\t\t// The log when not in \"strict\" mode would be:\r\n\t\t//\r\n\t\t// * `useLayoutEffect()` is run in `ItemComponent` — skips the initial run.\r\n\t\t// * `useLayoutEffect()` is run in `useVirtualScrollerStartStop()`. It starts the `VirtualScroller`.\r\n\t\t// * Some dependency property gets updated inside `ItemComponent`.\r\n\t\t// * `useLayoutEffect()` is run in `ItemComponent` — no longer skips. Calls `setItemState()`.\r\n\t\t// * The `VirtualScroller` is started so it handles `setState()` correctly.\r\n\t\t//\r\n\t\t// The log when in \"strict\" mode would be:\r\n\t\t//\r\n\t\t// * `useLayoutEffect()` is run in `ItemComponent` — skips the initial run.\r\n\t\t// * `useLayoutEffect()` is run in `useVirtualScrollerStartStop()`. It starts the `VirtualScroller`.\r\n\t\t// * `useLayoutEffect()` is unmounted in `useVirtualScrollerStartStop()`. It stops the `VirtualScroller`.\r\n\t\t// * `useLayoutEffect()` is unmounted in `ItemComponent` — does nothing.\r\n\t\t// * `useLayoutEffect()` is run the second time in `ItemComponent` — no longer skips. Calls `setItemState()`.\r\n\t\t// * The `VirtualScroller` is stopped so it throws an error: \"`VirtualScroller` hasn't been started\".\r\n\t\t//\r\n\t\t// For that reason, the requirement of the `VirtualScroller` to be started was commented out.\r\n\t\t// Commenting it out wouldn't result in any potential bugs because the code would work correctly\r\n\t\t// in both cases.\r\n\t\t// this.hasToBeStarted()\r\n\t\tthis._setItemState(i, newItemState)\r\n\t}\r\n\r\n\t// (deprecated)\r\n\t// Use `.setItemState()` method name instead.\r\n\tonItemStateChange(i, newItemState) {\r\n\t\tthis.setItemState(i, newItemState)\r\n\t}\r\n\r\n\t/**\r\n\t * Updates `items`. For example, can prepend or append new items to the list.\r\n\t * @param {any[]} newItems\r\n\t * @param {boolean} [options.preserveScrollPositionOnPrependItems] — Set to `true` to enable \"restore scroll position after prepending items\" feature (could be useful when implementing \"Show previous items\" button).\r\n\t */\r\n\tsetItems(newItems, options = {}) {\r\n\t\tthis.hasToBeStarted()\r\n\t\treturn this._setItems(newItems, options)\r\n\t}\r\n}"],"mappings":";;;;;;;;;AAAA;;AACA;;AACA;;AACA;;;;;;;;;;;;;;;;;;;;IAEqBA,e;EACpB;AACD;AACA;AACA;AACA;AACA;EACC,yBACCC,wBADD,EAECC,KAFD,EAIE;IAAA;;IAAA,IADDC,OACC,uEADS,EACT;;IAAA;;IAAA,8BAuIK,YAAM;MACZ,IAAI,CAAC,KAAI,CAACC,SAAV,EAAqB;QACpB,MAAM,IAAIC,KAAJ,CAAU,8EAAV,CAAN;MACA;;MAED,KAAI,CAACD,SAAL,GAAiB,KAAjB;MAEA,IAAAE,iBAAA,EAAI,UAAJ;;MAEA,KAAI,CAACC,gCAAL,CAAsCC,IAAtC;;MACA,KAAI,CAACC,MAAL,CAAYD,IAAZ,GAVY,CAYZ;MACA;MACA;;;MACA,IAAI,KAAI,CAACE,oBAAL,IAA6B,KAAI,CAACA,oBAAL,CAA0BC,SAA1B,EAAjC,EAAwE;QACvE,KAAI,CAACD,oBAAL,CAA0BF,IAA1B;MACA,CAjBW,CAmBZ;;;MACA,KAAI,CAACI,iBAAL,CAAuB,EAAvB;IACA,CA5JC;;IAAA,sCAsKa,YAAM;MACpB,KAAI,CAACC,cAAL;;MACA,KAAI,CAACC,wBAAL,CAA8B;QAAEC,MAAM,EAAEC,qBAAA,CAAcC;MAAxB,CAA9B;IACA,CAzKC;;IAAA,kCA6KS,YAAM;MAChB,KAAI,CAACC,SAAL,CAAe,KAAI,CAACC,QAAL,EAAf,EAAgC,KAAI,CAACC,aAArC;IACA,CA/KC;;IACDC,sCAAA,CAA2BC,IAA3B,CACC,IADD,EAECrB,wBAFD,EAGCC,KAHD,EAICC,OAJD;EAMA;EAED;AACD;AACA;;;;;WACC,iBAAQ;MACP,IAAI,KAAKC,SAAT,EAAoB;QACnB,MAAM,IAAIC,KAAJ,CAAU,+DAAV,CAAN;MACA,CAHM,CAKP;;;MACA,IAAMkB,SAAS,GAAG,KAAKnB,SAAL,KAAmB,KAArC;;MAEA,IAAI,CAACmB,SAAL,EAAgB;QACf,KAAKC,gBAAL,GAAwB,IAAxB,CADe,CAGf;QACA;;QACA,IAAI,CAAC,KAAKC,uBAAV,EAAmC;UAClC,KAAKC,sBAAL;QACA,CAPc,CAQf;QACA;;;QACA,IAAI,KAAKC,OAAT,EAAkB;UACjB,KAAKA,OAAL,CAAa,KAAKR,QAAL,EAAb;QACA;MACD;;MAED,IAAII,SAAJ,EAAe;QACd,IAAAjB,iBAAA,EAAI,qBAAJ;MACA,CAFD,MAEO;QACN,IAAAA,iBAAA,EAAI,WAAJ;MACA,CA3BM,CA6BP;;;MACA,KAAKF,SAAL,GAAiB,IAAjB,CA9BO,CAgCP;;MACA,KAAKwB,qBAAL,CAA2BC,KAA3B,GAjCO,CAmCP;;MACA,KAAKC,WAAL,GAAmBC,SAAnB,CApCO,CAsCP;;MACA,KAAKC,kBAAL,GAA0BD,SAA1B,CAvCO,CAyCP;MACA;;MACA,IAAI,KAAKE,KAAT,EAAgB;QACf,IAAI,CAAC,IAAAC,qBAAA,EAAe,KAAKjC,wBAAL,EAAf,CAAL,EAAsD;UACrD,IAAAkC,qBAAA,EAAe,KAAKlC,wBAAL,EAAf;QACA;MACD,CA/CM,CAiDP;MACA;MACA;MACA;MACA;;;MACA,IAAImC,WAAW,GAAG,KAAKC,qCAAvB;MACA,KAAKA,qCAAL,GAA6CN,SAA7C,CAvDO,CAyDP;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;;MACA,KAAKO,eAAL,GAAuBP,SAAvB;MAEA,IAAMQ,0BAA0B,GAAG,KAAKC,4BAAL,EAAnC;;MACA,IAAID,0BAAJ,EAAgC;QAC/BH,WAAW,mCACPA,WADO,GAEPG,0BAFO,CAAX;MAIA;;MAED,KAAKhC,gCAAL,CAAsCkC,KAAtC;MACA,KAAKhC,MAAL,CAAYgC,KAAZ,GA7EO,CA+EP;MACA;;MACA,IAAI,KAAKtB,QAAL,GAAgBuB,wBAAhB,KAA6CX,SAAjD,EAA4D;QAC3D,IAAMW,wBAAwB,GAAG,KAAKC,mBAAL,CAAyBC,QAAzB,EAAjC;QACAR,WAAW,mCACPA,WADO;UAEVM,wBAAwB,EAAxBA;QAFU,EAAX;MAIA,CAND,MAMO;QACN;QACA;QACA;QACA,IAAMG,QAAQ,GAAG,KAAKF,mBAAL,CAAyBC,QAAzB,EAAjB;QACA,IAAME,SAAS,GAAG,KAAK3B,QAAL,GAAgBuB,wBAAlC;;QACA,IAAIG,QAAQ,KAAKC,SAAjB,EAA4B;UAC3B,IAAAxC,iBAAA,EAAI,2CAAJ,EAAiDwC,SAAjD,EAA4D,IAA5D,EAAkED,QAAlE,EAA4E,GAA5E,EAD2B,CAE3B;UACA;UACA;UACA;;UACA,OAAO,KAAKE,iBAAL,EAAP;QACA;MACD,CArGM,CAuGP;MACA;MACA;;;MACA,IAAI,KAAKtB,uBAAT,EAAkC;QACjC,IAAMuB,YAAY,GAAG,KAAKC,qBAAL,EAArB;QACA,IAAMC,qBAAqB,GAAG,KAAK/B,QAAL,GAAgB6B,YAAhB,IAAgC,CAA9D;;QACA,IAAIA,YAAY,KAAKE,qBAArB,EAA4C;UAC3C,OAAO,KAAKH,iBAAL,EAAP;QACA;MACD,CAhHM,CAkHP;MACA;MACA;MACA;MACA;;;MACA,KAAKjC,wBAAL,CAA8B;QAAEC,MAAM,EAAEC,qBAAA,CAAcmC,OAAxB;QAAiCf,WAAW,EAAXA;MAAjC,CAA9B;IACA,C,CAED;;;;WAwBA,0BAAiB;MAChB,IAAI,CAAC,KAAKhC,SAAV,EAAqB;QACpB,MAAM,IAAIC,KAAJ,CAAU,2DAAV,CAAN;MACA;IACD,C,CAED;IACA;;;;;IAYA;AACD;AACA;AACA;AACA;IACC,+BAAsB+C,CAAtB,EAAyB;MACxB,IAAMC,mBAAmB,GAAG,KAAKC,MAAL,CAAYC,gBAAZ,CAA6BH,CAA7B,CAA5B;;MACA,IAAIC,mBAAmB,KAAKtB,SAA5B,EAAuC;QACtC;MACA;;MACD,OAAO,KAAKyB,yCAAL,KAAmDH,mBAA1D;IACA;IAED;AACD;AACA;AACA;;;;WACC,4BAAmBD,CAAnB,EAAsB;MACrB,IAAAK,WAAA,EAAK,4EAAL;MACA,KAAKC,qBAAL,CAA2BN,CAA3B;IACA;IAED;AACD;AACA;AACA;;;;WACC,+BAAsBA,CAAtB,EAAyB;MACxB;MACA;MACA;MACA,KAAKO,sBAAL,CAA4BP,CAA5B;IACA;IAED;AACD;AACA;AACA;AACA;;;;WACC,sBAAaA,CAAb,EAAgBQ,YAAhB,EAA8B;MAC7B;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA,KAAKC,aAAL,CAAmBT,CAAnB,EAAsBQ,YAAtB;IACA,C,CAED;IACA;;;;WACA,2BAAkBR,CAAlB,EAAqBQ,YAArB,EAAmC;MAClC,KAAKE,YAAL,CAAkBV,CAAlB,EAAqBQ,YAArB;IACA;IAED;AACD;AACA;AACA;AACA;;;;WACC,kBAASG,QAAT,EAAiC;MAAA,IAAd5D,OAAc,uEAAJ,EAAI;MAChC,KAAKU,cAAL;MACA,OAAO,KAAKmD,SAAL,CAAeD,QAAf,EAAyB5D,OAAzB,CAAP;IACA"}
|
|
1
|
+
{"version":3,"file":"VirtualScroller.js","names":["VirtualScroller","getItemsContainerElement","items","options","_isActive","Error","log","scrollableContainerResizeHandler","stop","scroll","listTopOffsetWatcher","isStarted","cancelLayoutTimer","hasToBeStarted","onUpdateShownItemIndexes","reason","LAYOUT_REASON","MANUAL","_onRender","getState","previousState","VirtualScrollerConstructor","call","isRestart","setUpState","waitingForRender","_render","listHeightMeasurement","reset","_isResizing","undefined","_isSettingNewItems","isInBypassMode","isItemsContainerElementTableBody","supportsTbody","hasTbodyStyles","addTbodyStyles","reportError","BROWSER_NOT_SUPPORTED_ERROR","_bypass","stateUpdate","_afterRenderStateUpdateThatWasStopped","verticalSpacing","verticalSpacingStateUpdate","measureItemHeightsAndSpacing","start","scrollableContainerWidth","scrollableContainer","getWidth","newWidth","prevWidth","onContainerResize","_usesCustomStateStorage","columnsCount","getActualColumnsCount","columnsCountFromState","STARTED","itemOrIndex","i","_getItemIndexByItemOrIndex","itemTopOffsetInList","layout","getItemTopOffset","getListTopOffsetInsideScrollableContainer","item","warn","onItemHeightDidChange","_onItemHeightDidChange","newItemState","_setItemState","setItemState","newItems","_setItems"],"sources":["../source/VirtualScroller.js"],"sourcesContent":["import VirtualScrollerConstructor from './VirtualScroller.constructor.js'\r\nimport { LAYOUT_REASON } from './Layout.js'\r\nimport log, { warn, reportError } from './utility/debug.js'\r\n\r\nimport {\r\n\tsupportsTbody,\r\n\thasTbodyStyles,\r\n\taddTbodyStyles,\r\n\tBROWSER_NOT_SUPPORTED_ERROR\r\n} from './DOM/tbody.js'\r\n\r\nexport default class VirtualScroller {\r\n\t/**\r\n\t * @param {function} getItemsContainerElement — Returns the items container DOM `Element`.\r\n\t * @param {any[]} items — The list of items.\r\n\t * @param {Object} [options] — See README.md.\r\n\t * @return {VirtualScroller}\r\n\t */\r\n\tconstructor(\r\n\t\tgetItemsContainerElement,\r\n\t\titems,\r\n\t\toptions = {}\r\n\t) {\r\n\t\tVirtualScrollerConstructor.call(\r\n\t\t\tthis,\r\n\t\t\tgetItemsContainerElement,\r\n\t\t\titems,\r\n\t\t\toptions\r\n\t\t)\r\n\t}\r\n\r\n\t/**\r\n\t * Should be invoked after a \"container\" DOM Element is mounted (inserted into the DOM tree).\r\n\t */\r\n\tstart() {\r\n\t\tif (this._isActive) {\r\n\t\t\tthrow new Error('[virtual-scroller] `VirtualScroller` has already been started')\r\n\t\t}\r\n\r\n\t\t// If has been stopped previously.\r\n\t\tconst isRestart = this._isActive === false\r\n\r\n\t\tif (!isRestart) {\r\n\t\t\tthis.setUpState()\r\n\t\t\tthis.waitingForRender = true\r\n\t\t\t// If `render()` function parameter was passed,\r\n\t\t\t// perform an initial render.\r\n\t\t\tif (this._render) {\r\n\t\t\t\tthis._render(this.getState())\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (isRestart) {\r\n\t\t\tlog('~ Start (restart) ~')\r\n\t\t} else {\r\n\t\t\tlog('~ Start ~')\r\n\t\t}\r\n\r\n\t\t// `this._isActive = true` should be placed somewhere at the start of this function.\r\n\t\tthis._isActive = true\r\n\r\n\t\t// Reset `ListHeightMeasurement` just in case it has some \"leftover\" state.\r\n\t\tthis.listHeightMeasurement.reset()\r\n\r\n\t\t// Reset `_isResizing` flag just in case it has some \"leftover\" value.\r\n\t\tthis._isResizing = undefined\r\n\r\n\t\t// Reset `_isSettingNewItems` flag just in case it has some \"leftover\" value.\r\n\t\tthis._isSettingNewItems = undefined\r\n\r\n\t\t// When `<tbody/>` is used as an items container element,\r\n\t\t// `virtual-scroller` has to work around the HTML bug of\r\n\t\t// `padding` not working on a `<tbody/>` element.\r\n\t\t// https://gitlab.com/catamphetamine/virtual-scroller/-/issues/1\r\n\t\tif (!this.isInBypassMode()) {\r\n\t\t\tif (this.isItemsContainerElementTableBody()) {\r\n\t\t\t\tif (supportsTbody()) {\r\n\t\t\t\t\tif (!hasTbodyStyles(this.getItemsContainerElement())) {\r\n\t\t\t\t\t\tlog('~ <tbody/> container ~')\r\n\t\t\t\t\t\taddTbodyStyles(this.getItemsContainerElement())\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tlog('~ <tbody/> container not supported ~')\r\n\t\t\t\t\treportError(BROWSER_NOT_SUPPORTED_ERROR)\r\n\t\t\t\t\tlog('~ enter \"bypass\" mode ~')\r\n\t\t\t\t\tthis._bypass = true\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// If there was a pending \"after render\" state update that didn't get applied\r\n\t\t// because the `VirtualScroller` got stopped, then apply that pending \"after render\"\r\n\t\t// state update now. Such state update could include properties like:\r\n\t\t// * A `verticalSpacing` that has been measured in `onRender()`.\r\n\t\t// * A cleaned-up `beforeResize` object that was cleaned-up in `onRender()`.\r\n\t\tlet stateUpdate = this._afterRenderStateUpdateThatWasStopped\r\n\t\tthis._afterRenderStateUpdateThatWasStopped = undefined\r\n\r\n\t\t// Reset `this.verticalSpacing` so that it re-measures it in cases when\r\n\t\t// the `VirtualScroller` was previously stopped and is now being restarted.\r\n\t\t// The rationale is that a previously captured inter-item vertical spacing\r\n\t\t// can't be \"trusted\" in a sense that the user might have resized the window\r\n\t\t// after the previous `state` has been snapshotted.\r\n\t\t// If the user has resized the window, then changing window width might have\r\n\t\t// activated different CSS `@media()` \"queries\" resulting in a potentially different\r\n\t\t// vertical spacing after the restart.\r\n\t\t// If it's not a restart then `this.verticalSpacing` is `undefined` anyway.\r\n\t\tthis.verticalSpacing = undefined\r\n\r\n\t\tconst verticalSpacingStateUpdate = this.measureItemHeightsAndSpacing()\r\n\t\tif (verticalSpacingStateUpdate) {\r\n\t\t\tstateUpdate = {\r\n\t\t\t\t...stateUpdate,\r\n\t\t\t\t...verticalSpacingStateUpdate\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis.scrollableContainerResizeHandler.start()\r\n\t\tthis.scroll.start()\r\n\r\n\t\t// If `scrollableContainerWidth` hasn't been measured yet,\r\n\t\t// measure it and write it to state.\r\n\t\tif (this.getState().scrollableContainerWidth === undefined) {\r\n\t\t\tconst scrollableContainerWidth = this.scrollableContainer.getWidth()\r\n\t\t\tstateUpdate = {\r\n\t\t\t\t...stateUpdate,\r\n\t\t\t\tscrollableContainerWidth\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\t// Reset layout:\r\n\t\t\t// * If the scrollable container width has changed while stopped.\r\n\t\t\t// * If the restored state was calculated for another scrollable container width.\r\n\t\t\tconst newWidth = this.scrollableContainer.getWidth()\r\n\t\t\tconst prevWidth = this.getState().scrollableContainerWidth\r\n\t\t\tif (newWidth !== prevWidth) {\r\n\t\t\t\tlog('~ Scrollable container width changed from', prevWidth, 'to', newWidth, '~')\r\n\t\t\t\t// The pending state update (if present) won't be applied in this case.\r\n\t\t\t\t// That's ok because such state update could currently only originate in\r\n\t\t\t\t// `this.onContainerResize()` function. Therefore, alling `this.onContainerResize()` again\r\n\t\t\t\t// would rewrite all those `stateUpdate` properties anyway, so they're not passed.\r\n\t\t\t\treturn this.onContainerResize()\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// If the `VirtualScroller` uses custom (external) state storage, then\r\n\t\t// check if the columns count has changed between calling `.getInitialState()`\r\n\t\t// and `.start()`. If it has, perform a re-layout \"from scratch\".\r\n\t\tif (this._usesCustomStateStorage) {\r\n\t\t\tconst columnsCount = this.getActualColumnsCount()\r\n\t\t\tconst columnsCountFromState = this.getState().columnsCount || 1\r\n\t\t\tif (columnsCount !== columnsCountFromState) {\r\n\t\t\t\treturn this.onContainerResize()\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Re-calculate layout and re-render the list.\r\n\t\t// Do that even if when an initial `state` parameter, containing layout values,\r\n\t\t// has been passed. The reason is that the `state` parameter can't be \"trusted\"\r\n\t\t// in a way that it could have been snapshotted for another window width and\r\n\t\t// the user might have resized their window since then.\r\n\t\tthis.onUpdateShownItemIndexes({ reason: LAYOUT_REASON.STARTED, stateUpdate })\r\n\t}\r\n\r\n\t// Could be passed as a \"callback\" parameter, so bind it to `this`.\r\n\tstop = () => {\r\n\t\tif (!this._isActive) {\r\n\t\t\tthrow new Error('[virtual-scroller] Can\\'t stop a `VirtualScroller` that hasn\\'t been started')\r\n\t\t}\r\n\r\n\t\tthis._isActive = false\r\n\r\n\t\tlog('~ Stop ~')\r\n\r\n\t\tthis.scrollableContainerResizeHandler.stop()\r\n\t\tthis.scroll.stop()\r\n\r\n\t\t// Stop `ListTopOffsetWatcher` if it has been started.\r\n\t\t// There seems to be no need to restart `ListTopOffsetWatcher`.\r\n\t\t// It's mainly a hacky workaround for development mode anyway.\r\n\t\tif (this.listTopOffsetWatcher && this.listTopOffsetWatcher.isStarted()) {\r\n\t\t\tthis.listTopOffsetWatcher.stop()\r\n\t\t}\r\n\r\n\t\t// Cancel any scheduled layout.\r\n\t\tthis.cancelLayoutTimer({})\r\n\t}\r\n\r\n\thasToBeStarted() {\r\n\t\tif (!this._isActive) {\r\n\t\t\tthrow new Error('[virtual-scroller] `VirtualScroller` hasn\\'t been started')\r\n\t\t}\r\n\t}\r\n\r\n\t// Bind it to `this` because this function could hypothetically be passed\r\n\t// as a \"callback\" parameter.\r\n\tupdateLayout = () => {\r\n\t\tthis.hasToBeStarted()\r\n\t\tthis.onUpdateShownItemIndexes({ reason: LAYOUT_REASON.MANUAL })\r\n\t}\r\n\r\n\t// Bind the function to `this` so that it could be passed as a callback\r\n\t// in a random application's code.\r\n\tonRender = () => {\r\n\t\tthis._onRender(this.getState(), this.previousState)\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the items's top offset relative to the scrollable container's top edge.\r\n\t * @param {any} item — Item\r\n\t * @return {[number]} Returns the item's scroll Y position. Returns `undefined` if any of the previous items haven't been rendered yet.\r\n\t */\r\n\tgetItemScrollPosition(itemOrIndex) {\r\n\t\t// Item index.\r\n\t\tconst i = this._getItemIndexByItemOrIndex(itemOrIndex)\r\n\r\n\t\t// If the item wasn't found, the error was already reported,\r\n\t\t// so just return some \"sensible\" default value.\r\n\t\tif (i === undefined) {\r\n\t\t\treturn\r\n\t\t}\r\n\r\n\t\tconst itemTopOffsetInList = this.layout.getItemTopOffset(i)\r\n\t\tif (itemTopOffsetInList === undefined) {\r\n\t\t\treturn\r\n\t\t}\r\n\t\treturn this.getListTopOffsetInsideScrollableContainer() + itemTopOffsetInList\r\n\t}\r\n\r\n\t/**\r\n\t * @deprecated\r\n\t * `.onItemHeightChange()` has been renamed to `.onItemHeightDidChange()`.\r\n\t */\r\n\tonItemHeightChange(item) {\r\n\t\twarn('`.onItemHeightChange(item)` method was renamed to `.onItemHeightDidChange(item)`')\r\n\t\tthis.onItemHeightDidChange(item)\r\n\t}\r\n\r\n\t/**\r\n\t * Forces a re-measure of an item's height.\r\n\t * @param {any} item — Item. Legacy argument variant: Item index.\r\n\t */\r\n\tonItemHeightDidChange(itemOrIndex) {\r\n\t\t// See the comments in the `setItemState()` function below for the rationale\r\n\t\t// on why the `hasToBeStarted()` check was commented out.\r\n\t\t// this.hasToBeStarted()\r\n\t\tthis._onItemHeightDidChange(itemOrIndex)\r\n\t}\r\n\r\n\t/**\r\n\t * Updates an item's state in `state.itemStates[]`.\r\n\t * @param {any} item — Item. Legacy argument variant: Item index.\r\n\t * @param {any} newItemState — Item's new state\r\n\t */\r\n\tsetItemState(itemOrIndex, newItemState) {\r\n\t\t// There is an issue in React 18.2.0 when `useInsertionEffect()` doesn't run twice\r\n\t\t// on mount unlike `useLayoutEffect()` in \"strict\" mode. That causes a bug in a React\r\n\t\t// implementation of the `virtual-scroller`.\r\n\t\t// https://gitlab.com/catamphetamine/virtual-scroller/-/issues/33\r\n\t\t// https://github.com/facebook/react/issues/26320\r\n\t\t// A workaround for that bug is ignoring the second-initial run of the effects at mount.\r\n\t\t//\r\n\t\t// But in that case, if an `ItemComponent` calls `setItemState()` in `useLayoutEffect()`,\r\n\t\t// it could result in a bug.\r\n\t\t//\r\n\t\t// Consider a type of `useLayoutEffect()` that skips the initial mount:\r\n\t\t// `useLayoutEffectSkipInitialMount()`.\r\n\t\t// Suppose that effect is written in such a way that it only skips the first call of itself.\r\n\t\t// In that case, if React is run in \"strict\" mode, the effect will no longer work as expected\r\n\t\t// and it won't actually skip the initial mount and will be executed during the second initial run.\r\n\t\t// But the `VirtualScroller` itself has already implemented a workaround that prevents\r\n\t\t// its hooks from running twice on mount. This means that `useVirtualScrollerStartStop()`\r\n\t\t// of the React component would have already stopped the `VirtualScroller` by the time\r\n\t\t// `ItemComponent`'s incorrectly-behaving `useLayoutEffectSkipInitialMount()` effect is run,\r\n\t\t// resulting in an error: \"`VirtualScroller` hasn't been started\".\r\n\t\t//\r\n\t\t// The log when not in \"strict\" mode would be:\r\n\t\t//\r\n\t\t// * `useLayoutEffect()` is run in `ItemComponent` — skips the initial run.\r\n\t\t// * `useLayoutEffect()` is run in `useVirtualScrollerStartStop()`. It starts the `VirtualScroller`.\r\n\t\t// * Some dependency property gets updated inside `ItemComponent`.\r\n\t\t// * `useLayoutEffect()` is run in `ItemComponent` — no longer skips. Calls `setItemState()`.\r\n\t\t// * The `VirtualScroller` is started so it handles `setState()` correctly.\r\n\t\t//\r\n\t\t// The log when in \"strict\" mode would be:\r\n\t\t//\r\n\t\t// * `useLayoutEffect()` is run in `ItemComponent` — skips the initial run.\r\n\t\t// * `useLayoutEffect()` is run in `useVirtualScrollerStartStop()`. It starts the `VirtualScroller`.\r\n\t\t// * `useLayoutEffect()` is unmounted in `useVirtualScrollerStartStop()`. It stops the `VirtualScroller`.\r\n\t\t// * `useLayoutEffect()` is unmounted in `ItemComponent` — does nothing.\r\n\t\t// * `useLayoutEffect()` is run the second time in `ItemComponent` — no longer skips. Calls `setItemState()`.\r\n\t\t// * The `VirtualScroller` is stopped so it throws an error: \"`VirtualScroller` hasn't been started\".\r\n\t\t//\r\n\t\t// For that reason, the requirement of the `VirtualScroller` to be started was commented out.\r\n\t\t// Commenting it out wouldn't result in any potential bugs because the code would work correctly\r\n\t\t// in both cases.\r\n\t\t// this.hasToBeStarted()\r\n\t\tthis._setItemState(itemOrIndex, newItemState)\r\n\t}\r\n\r\n\t// (deprecated)\r\n\t// Use `.setItemState()` method name instead.\r\n\tonItemStateChange(item, newItemState) {\r\n\t\tthis.setItemState(item, newItemState)\r\n\t}\r\n\r\n\t/**\r\n\t * Updates `items`. For example, can prepend or append new items to the list.\r\n\t * @param {any[]} newItems\r\n\t * @param {boolean} [options.preserveScrollPositionOnPrependItems] — Set to `true` to enable \"restore scroll position after prepending items\" feature (could be useful when implementing \"Show previous items\" button).\r\n\t */\r\n\tsetItems(newItems, options = {}) {\r\n\t\tthis.hasToBeStarted()\r\n\t\treturn this._setItems(newItems, options)\r\n\t}\r\n}"],"mappings":"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xB,IAAAC,WAAA,EAAK,kFAAL;MACA,KAAKC,qBAAL,CAA2BF,IAA3B;IACA;IAED;AACD;AACA;AACA;;;;WACC,+BAAsBP,WAAtB,EAAmC;MAClC;MACA;MACA;MACA,KAAKU,sBAAL,CAA4BV,WAA5B;IACA;IAED;AACD;AACA;AACA;AACA;;;;WACC,sBAAaA,WAAb,EAA0BW,YAA1B,EAAwC;MACvC;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA,KAAKC,aAAL,CAAmBZ,WAAnB,EAAgCW,YAAhC;IACA,C,CAED;IACA;;;;WACA,2BAAkBJ,IAAlB,EAAwBI,YAAxB,EAAsC;MACrC,KAAKE,YAAL,CAAkBN,IAAlB,EAAwBI,YAAxB;IACA;IAED;AACD;AACA;AACA;AACA;;;;WACC,kBAASG,QAAT,EAAiC;MAAA,IAAdpE,OAAc,uEAAJ,EAAI;MAChC,KAAKU,cAAL;MACA,OAAO,KAAK2D,SAAL,CAAeD,QAAf,EAAyBpE,OAAzB,CAAP;IACA"}
|
|
@@ -126,7 +126,7 @@ function _default() {
|
|
|
126
126
|
// or an "Expand YouTube video" button, which would result
|
|
127
127
|
// in the actual height of the list item being different
|
|
128
128
|
// from what has been initially measured in `this.itemHeights[i]`,
|
|
129
|
-
// if the developer didn't call `.setItemState(
|
|
129
|
+
// if the developer didn't call `.setItemState(item, newState)` and `.onItemHeightDidChange(item)`.
|
|
130
130
|
|
|
131
131
|
|
|
132
132
|
if (!validateWillBeHiddenItemHeightsAreAccurate.call(this, firstShownItemIndex, lastShownItemIndex)) {
|
|
@@ -143,7 +143,7 @@ function _default() {
|
|
|
143
143
|
var afterItemsHeight = this.layout.getAfterItemsHeight(lastShownItemIndex, this.getItemsCount());
|
|
144
144
|
var layoutDuration = Date.now() - startedAt; // Debugging.
|
|
145
145
|
|
|
146
|
-
(0, _debug["default"])('~ Calculated Layout' + (this.
|
|
146
|
+
(0, _debug["default"])('~ Calculated Layout' + (this.isInBypassMode() ? ' (bypass)' : '') + ' ~');
|
|
147
147
|
|
|
148
148
|
if (layoutDuration < SLOW_LAYOUT_DURATION) {// log('Calculated in', layoutDuration, 'ms')
|
|
149
149
|
} else {
|
|
@@ -158,7 +158,7 @@ function _default() {
|
|
|
158
158
|
(0, _debug["default"])('Last shown item index', lastShownItemIndex);
|
|
159
159
|
(0, _debug["default"])('Before items height', beforeItemsHeight);
|
|
160
160
|
(0, _debug["default"])('After items height (actual or estimated)', afterItemsHeight);
|
|
161
|
-
(0, _debug["default"])('Average item height (used for estimated after items height calculation)', this.
|
|
161
|
+
(0, _debug["default"])('Average item height (used for estimated after items height calculation)', this.getAverageItemHeight());
|
|
162
162
|
|
|
163
163
|
if ((0, _debug.isDebug)()) {
|
|
164
164
|
(0, _debug["default"])('Item heights', this.getState().itemHeights.slice());
|
|
@@ -194,9 +194,9 @@ function _default() {
|
|
|
194
194
|
// Instead of using a `this.previouslyCalculatedLayout` instance variable,
|
|
195
195
|
// this code could use `this.getState()` because it reflects what's currently on screen,
|
|
196
196
|
// but there's a single edge case when it could go out of sync —
|
|
197
|
-
// updating item heights externally via `.onItemHeightDidChange(
|
|
197
|
+
// updating item heights externally via `.onItemHeightDidChange(item)`.
|
|
198
198
|
//
|
|
199
|
-
// If, for example, an item height was updated externally via `.onItemHeightDidChange(
|
|
199
|
+
// If, for example, an item height was updated externally via `.onItemHeightDidChange(item)`
|
|
200
200
|
// then `this.getState().itemHeights` would get updated immediately but
|
|
201
201
|
// `this.getState().beforeItemsHeight` or `this.getState().afterItemsHeight`
|
|
202
202
|
// would still correspond to the previous item height, so those would be "stale".
|
|
@@ -248,7 +248,7 @@ function _default() {
|
|
|
248
248
|
var itemsCount = this.getItemsCount();
|
|
249
249
|
var visibleAreaInsideTheList = getCoordinatesOfVisibleAreaInsideTheList.call(this);
|
|
250
250
|
|
|
251
|
-
if (this.
|
|
251
|
+
if (this.isInBypassMode()) {
|
|
252
252
|
return {
|
|
253
253
|
firstShownItemIndex: 0,
|
|
254
254
|
lastShownItemIndex: itemsCount - 1 // shownItemsHeight: this.getState().itemHeights.reduce((sum, itemHeight) => sum + itemHeight, 0)
|
|
@@ -284,7 +284,7 @@ function _default() {
|
|
|
284
284
|
* or an "Expand YouTube video" button, which would result
|
|
285
285
|
* in the actual height of the list item being different
|
|
286
286
|
* from what has been initially measured in `this.itemHeights[i]`,
|
|
287
|
-
* if the developer didn't call `.setItemState(
|
|
287
|
+
* if the developer didn't call `.setItemState(item, newState)` and `.onItemHeightDidChange(item)`.
|
|
288
288
|
*/
|
|
289
289
|
|
|
290
290
|
|
|
@@ -298,26 +298,26 @@ function _default() {
|
|
|
298
298
|
// The item will be hidden. Re-measure its height.
|
|
299
299
|
// The rationale is that there could be a situation when an item's
|
|
300
300
|
// height has changed, and the developer has properly added an
|
|
301
|
-
// `.onItemHeightDidChange(
|
|
301
|
+
// `.onItemHeightDidChange(item)` call to notify `VirtualScroller`
|
|
302
302
|
// about that change, but at the same time that wouldn't work.
|
|
303
303
|
// For example, suppose there's a list of several items on a page,
|
|
304
304
|
// and those items are in "minimized" state (having height 100px).
|
|
305
305
|
// Then, a user clicks an "Expand all items" button, and all items
|
|
306
306
|
// in the list are expanded (expanded item height is gonna be 700px).
|
|
307
|
-
// `VirtualScroller` demands that `.onItemHeightDidChange(
|
|
307
|
+
// `VirtualScroller` demands that `.onItemHeightDidChange(item)` is called
|
|
308
308
|
// in such cases, and the developer has properly added the code to do that.
|
|
309
309
|
// So, if there were 10 "minimized" items visible on a page, then there
|
|
310
|
-
// will be 10 individual `.onItemHeightDidChange(
|
|
311
|
-
// But, as the first `.onItemHeightDidChange(
|
|
310
|
+
// will be 10 individual `.onItemHeightDidChange(item)` calls. No issues so far.
|
|
311
|
+
// But, as the first `.onItemHeightDidChange(item)` call executes, it immediately
|
|
312
312
|
// ("synchronously") triggers a re-layout, and that re-layout finds out
|
|
313
313
|
// that now, because the first item is big, it occupies most of the screen
|
|
314
314
|
// space, and only the first 3 items are visible on screen instead of 10,
|
|
315
315
|
// and so it leaves the first 3 items mounted and unmounts the rest 7.
|
|
316
316
|
// Then, after `VirtualScroller` has rerendered, the code returns to
|
|
317
|
-
// where it was executing, and calls `.onItemHeightDidChange(
|
|
317
|
+
// where it was executing, and calls `.onItemHeightDidChange(item)` for the
|
|
318
318
|
// second item. It also triggers an immediate re-layout that finds out
|
|
319
319
|
// that only the first 2 items are visible on screen, and it unmounts
|
|
320
|
-
// the third one too. After that, it calls `.onItemHeightDidChange(
|
|
320
|
+
// the third one too. After that, it calls `.onItemHeightDidChange(item)`
|
|
321
321
|
// for the third item, but that item is no longer rendered, so its height
|
|
322
322
|
// can't be measured, and the same's for all the rest of the original 10 items.
|
|
323
323
|
// So, even though the developer has written their code properly, the
|
|
@@ -337,7 +337,7 @@ function _default() {
|
|
|
337
337
|
}
|
|
338
338
|
|
|
339
339
|
isValid = false;
|
|
340
|
-
(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 `onItemHeightDidChange(
|
|
340
|
+
(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 `onItemHeightDidChange(item)` 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.');
|
|
341
341
|
}
|
|
342
342
|
}
|
|
343
343
|
|
|
@@ -399,49 +399,57 @@ function _default() {
|
|
|
399
399
|
return listTopOffset;
|
|
400
400
|
};
|
|
401
401
|
|
|
402
|
-
this._onItemHeightDidChange = function (
|
|
403
|
-
|
|
404
|
-
(
|
|
402
|
+
this._onItemHeightDidChange = function (itemOrIndex) {
|
|
403
|
+
// Item index.
|
|
404
|
+
var i = _this._getItemIndexByItemOrIndex(itemOrIndex); // If the item wasn't found, the error was already reported,
|
|
405
|
+
// so just don't do anything else.
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
if (i === undefined) {
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
405
411
|
|
|
406
412
|
var _this$getState2 = _this.getState(),
|
|
407
413
|
itemHeights = _this$getState2.itemHeights,
|
|
408
414
|
firstShownItemIndex = _this$getState2.firstShownItemIndex,
|
|
409
|
-
lastShownItemIndex = _this$getState2.lastShownItemIndex;
|
|
415
|
+
lastShownItemIndex = _this$getState2.lastShownItemIndex;
|
|
410
416
|
|
|
417
|
+
(0, _debug["default"])('~ On Item Height Did Change was called ~');
|
|
418
|
+
(0, _debug["default"])('Item index', i); // Check if the item is still rendered.
|
|
411
419
|
|
|
412
420
|
if (!(i >= firstShownItemIndex && i <= lastShownItemIndex)) {
|
|
413
421
|
// There could be valid cases when an item is no longer rendered
|
|
414
|
-
// by the time `.onItemHeightDidChange(
|
|
422
|
+
// by the time `.onItemHeightDidChange(item)` gets called.
|
|
415
423
|
// For example, suppose there's a list of several items on a page,
|
|
416
424
|
// and those items are in "minimized" state (having height 100px).
|
|
417
425
|
// Then, a user clicks an "Expand all items" button, and all items
|
|
418
426
|
// in the list are expanded (expanded item height is gonna be 700px).
|
|
419
|
-
// `VirtualScroller` demands that `.onItemHeightDidChange(
|
|
427
|
+
// `VirtualScroller` demands that `.onItemHeightDidChange(item)` is called
|
|
420
428
|
// in such cases, and the developer has properly added the code to do that.
|
|
421
429
|
// So, if there were 10 "minimized" items visible on a page, then there
|
|
422
|
-
// will be 10 individual `.onItemHeightDidChange(
|
|
423
|
-
// But, as the first `.onItemHeightDidChange(
|
|
430
|
+
// will be 10 individual `.onItemHeightDidChange(item)` calls. No issues so far.
|
|
431
|
+
// But, as the first `.onItemHeightDidChange(item)` call executes, it immediately
|
|
424
432
|
// ("synchronously") triggers a re-layout, and that re-layout finds out
|
|
425
433
|
// that now, because the first item is big, it occupies most of the screen
|
|
426
434
|
// space, and only the first 3 items are visible on screen instead of 10,
|
|
427
435
|
// and so it leaves the first 3 items mounted and unmounts the rest 7.
|
|
428
436
|
// Then, after `VirtualScroller` has rerendered, the code returns to
|
|
429
|
-
// where it was executing, and calls `.onItemHeightDidChange(
|
|
437
|
+
// where it was executing, and calls `.onItemHeightDidChange(item)` for the
|
|
430
438
|
// second item. It also triggers an immediate re-layout that finds out
|
|
431
439
|
// that only the first 2 items are visible on screen, and it unmounts
|
|
432
|
-
// the third one too. After that, it calls `.onItemHeightDidChange(
|
|
440
|
+
// the third one too. After that, it calls `.onItemHeightDidChange(item)`
|
|
433
441
|
// for the third item, but that item is no longer rendered, so its height
|
|
434
442
|
// can't be measured, and the same's for all the rest of the original 10 items.
|
|
435
443
|
// So, even though the developer has written their code properly, there're
|
|
436
444
|
// still situations when the item could be no longer rendered by the time
|
|
437
|
-
// `.onItemHeightDidChange(
|
|
438
|
-
return (0, _debug.warn)('The item is no longer rendered. This is not necessarily a bug, and could happen, for example, when when a developer calls `onItemHeightDidChange(
|
|
445
|
+
// `.onItemHeightDidChange(item)` gets called.
|
|
446
|
+
return (0, _debug.warn)('The item is no longer rendered. This is not necessarily a bug, and could happen, for example, when when a developer calls `onItemHeightDidChange(item)` while looping through a batch of items.');
|
|
439
447
|
}
|
|
440
448
|
|
|
441
449
|
var previousHeight = itemHeights[i];
|
|
442
450
|
|
|
443
451
|
if (previousHeight === undefined) {
|
|
444
|
-
// There're valid cases when the item still hasn't been measured and `onItemHeightDidChange()`
|
|
452
|
+
// There're valid cases when the item still hasn't been measured and `onItemHeightDidChange(item)`
|
|
445
453
|
// function was called for it. That's because measuring items is only done after the `VirtualScroller`
|
|
446
454
|
// has `start()`ed. But it's not neccessarily `start()`ed by the time it has been rendered (mounted).
|
|
447
455
|
// For example, the React component `<VirtualScroller/>` provides an `readyToStart={false}` property
|
|
@@ -461,7 +469,7 @@ function _default() {
|
|
|
461
469
|
try {
|
|
462
470
|
newHeight = remeasureItemHeight.call(_this, i);
|
|
463
471
|
} catch (error) {
|
|
464
|
-
// Successfully finishing an `onItemHeightDidChange(
|
|
472
|
+
// Successfully finishing an `onItemHeightDidChange(item)` call is not considered
|
|
465
473
|
// critical for `VirtualScroller`'s operation, so such errors could be ignored.
|
|
466
474
|
if (error instanceof _ItemNotRenderedError["default"]) {
|
|
467
475
|
return (0, _debug.reportError)("\"onItemHeightDidChange()\" has been called for item index ".concat(i, " but the item is not currently rendered and can't be measured. The exact error was: ").concat(error.message));
|
|
@@ -483,7 +491,7 @@ function _default() {
|
|
|
483
491
|
updatePreviouslyCalculatedLayoutOnItemHeightChange.call(_this, i, previousHeight, newHeight); // Recalculate layout.
|
|
484
492
|
//
|
|
485
493
|
// If the `VirtualScroller` is already waiting for a state update to be rendered,
|
|
486
|
-
// delay `onItemHeightDidChange(
|
|
494
|
+
// delay `onItemHeightDidChange(item)`'s re-layout until that state update is rendered.
|
|
487
495
|
// The reason is that React `<VirtualScroller/>`'s `onHeightDidChange()` is meant to
|
|
488
496
|
// be called inside `useLayoutEffect()` hook. Due to how React is implemented internally,
|
|
489
497
|
// that might happen in the middle of the currently pending `setState()` operation
|
|
@@ -530,9 +538,12 @@ function _default() {
|
|
|
530
538
|
// scroll past the screen height, because they'd stop to read through
|
|
531
539
|
// the newly visible items first, and when they do stop scrolling, that's
|
|
532
540
|
// when layout gets recalculated).
|
|
533
|
-
|
|
541
|
+
return _this.scrollableContainer.getHeight() * _this.getPrerenderMarginRatio();
|
|
542
|
+
};
|
|
534
543
|
|
|
535
|
-
|
|
544
|
+
this.getPrerenderMarginRatio = function () {
|
|
545
|
+
// See the readme for the description of `prerenderMarginRatio` option.
|
|
546
|
+
return 1; // in scrollable container heights.
|
|
536
547
|
};
|
|
537
548
|
/**
|
|
538
549
|
* Calls `onItemFirstRender()` for items that haven't been
|