virtual-scroller 1.11.2 → 1.12.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 +5 -0
- package/README.md +13 -11
- 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/DOM/ItemsContainer.js +10 -3
- package/commonjs/DOM/ItemsContainer.js.map +1 -1
- package/commonjs/DOM/VirtualScroller.js +13 -1
- package/commonjs/DOM/VirtualScroller.js.map +1 -1
- package/commonjs/ItemHeights.js +5 -5
- package/commonjs/ItemHeights.js.map +1 -1
- package/commonjs/ItemNotRenderedError.js +64 -0
- package/commonjs/ItemNotRenderedError.js.map +1 -0
- package/commonjs/Layout.test.js +10 -0
- package/commonjs/Layout.test.js.map +1 -1
- package/commonjs/VirtualScroller.js +23 -5
- package/commonjs/VirtualScroller.js.map +1 -1
- package/commonjs/VirtualScroller.layout.js +81 -39
- package/commonjs/VirtualScroller.layout.js.map +1 -1
- package/commonjs/VirtualScroller.onRender.js +97 -45
- package/commonjs/VirtualScroller.onRender.js.map +1 -1
- package/commonjs/VirtualScroller.state.js +50 -18
- package/commonjs/VirtualScroller.state.js.map +1 -1
- package/commonjs/react/VirtualScroller.js +31 -46
- package/commonjs/react/VirtualScroller.js.map +1 -1
- package/commonjs/react/useItemKeys.js +11 -3
- package/commonjs/react/useItemKeys.js.map +1 -1
- package/commonjs/react/useOnChange.js +19 -0
- package/commonjs/react/useOnChange.js.map +1 -0
- package/commonjs/react/{useOnItemHeightChange.js → useOnItemHeightDidChange.js} +7 -7
- package/commonjs/react/useOnItemHeightDidChange.js.map +1 -0
- package/commonjs/react/{useHandleItemsPropertyChange.js → useSetNewItemsOnItemsPropertyChange.js} +15 -14
- package/commonjs/react/useSetNewItemsOnItemsPropertyChange.js.map +1 -0
- package/commonjs/react/useState.js +162 -69
- package/commonjs/react/useState.js.map +1 -1
- package/commonjs/react/useStyle.js +3 -5
- package/commonjs/react/useStyle.js.map +1 -1
- package/commonjs/react/useUpdateItemKeysOnItemsChange.js +61 -0
- package/commonjs/react/useUpdateItemKeysOnItemsChange.js.map +1 -0
- package/commonjs/test/ItemsContainer.js +22 -1
- package/commonjs/test/ItemsContainer.js.map +1 -1
- package/commonjs/utility/debug.js +30 -6
- package/commonjs/utility/debug.js.map +1 -1
- package/dom/index.d.ts +1 -1
- package/index.cjs +2 -0
- package/index.d.ts +7 -1
- package/index.js +1 -0
- package/modules/DOM/ItemsContainer.js +8 -3
- package/modules/DOM/ItemsContainer.js.map +1 -1
- package/modules/DOM/VirtualScroller.js +13 -1
- package/modules/DOM/VirtualScroller.js.map +1 -1
- package/modules/ItemHeights.js +5 -5
- package/modules/ItemHeights.js.map +1 -1
- package/modules/ItemNotRenderedError.js +57 -0
- package/modules/ItemNotRenderedError.js.map +1 -0
- package/modules/Layout.test.js +10 -0
- package/modules/Layout.test.js.map +1 -1
- package/modules/VirtualScroller.js +17 -5
- package/modules/VirtualScroller.js.map +1 -1
- package/modules/VirtualScroller.layout.js +78 -39
- package/modules/VirtualScroller.layout.js.map +1 -1
- package/modules/VirtualScroller.onRender.js +98 -46
- package/modules/VirtualScroller.onRender.js.map +1 -1
- package/modules/VirtualScroller.state.js +50 -18
- package/modules/VirtualScroller.state.js.map +1 -1
- package/modules/react/VirtualScroller.js +31 -46
- package/modules/react/VirtualScroller.js.map +1 -1
- package/modules/react/useItemKeys.js +8 -3
- package/modules/react/useItemKeys.js.map +1 -1
- package/modules/react/useOnChange.js +11 -0
- package/modules/react/useOnChange.js.map +1 -0
- package/modules/react/{useOnItemHeightChange.js → useOnItemHeightDidChange.js} +6 -6
- package/modules/react/useOnItemHeightDidChange.js.map +1 -0
- package/modules/react/{useHandleItemsPropertyChange.js → useSetNewItemsOnItemsPropertyChange.js} +11 -13
- package/modules/react/useSetNewItemsOnItemsPropertyChange.js.map +1 -0
- package/modules/react/useState.js +156 -73
- package/modules/react/useState.js.map +1 -1
- package/modules/react/useStyle.js +3 -5
- package/modules/react/useStyle.js.map +1 -1
- package/{commonjs/react/useHandleItemIndexesChange.js → modules/react/useUpdateItemKeysOnItemsChange.js} +18 -21
- package/modules/react/useUpdateItemKeysOnItemsChange.js.map +1 -0
- package/modules/test/ItemsContainer.js +20 -1
- package/modules/test/ItemsContainer.js.map +1 -1
- package/modules/utility/debug.js +31 -6
- package/modules/utility/debug.js.map +1 -1
- package/package.json +1 -1
- package/source/DOM/ItemsContainer.js +8 -3
- package/source/DOM/VirtualScroller.js +11 -1
- package/source/ItemHeights.js +5 -5
- package/source/ItemNotRenderedError.js +16 -0
- package/source/Layout.test.js +9 -0
- package/source/VirtualScroller.js +14 -3
- package/source/VirtualScroller.layout.js +77 -38
- package/source/VirtualScroller.onRender.js +95 -42
- package/source/VirtualScroller.state.js +57 -20
- package/source/react/VirtualScroller.js +28 -39
- package/source/react/useItemKeys.js +9 -2
- package/source/react/useOnChange.js +11 -0
- package/source/react/{useOnItemHeightChange.js → useOnItemHeightDidChange.js} +5 -5
- package/source/react/{useHandleItemsPropertyChange.js → useSetNewItemsOnItemsPropertyChange.js} +11 -11
- package/source/react/useState.js +159 -71
- package/source/react/useStyle.js +2 -2
- package/source/react/{useHandleItemIndexesChange.js → useUpdateItemKeysOnItemsChange.js} +17 -9
- package/source/test/ItemsContainer.js +22 -1
- package/source/utility/debug.js +18 -4
- package/commonjs/react/useHandleItemIndexesChange.js.map +0 -1
- package/commonjs/react/useHandleItemsPropertyChange.js.map +0 -1
- package/commonjs/react/useOnItemHeightChange.js.map +0 -1
- package/modules/react/useHandleItemIndexesChange.js +0 -45
- package/modules/react/useHandleItemIndexesChange.js.map +0 -1
- package/modules/react/useHandleItemsPropertyChange.js.map +0 -1
- package/modules/react/useOnItemHeightChange.js.map +0 -1
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
|
|
4
|
+
|
|
3
5
|
Object.defineProperty(exports, "__esModule", {
|
|
4
6
|
value: true
|
|
5
7
|
});
|
|
6
8
|
exports["default"] = _useState;
|
|
7
9
|
|
|
10
|
+
var _debug = _interopRequireWildcard(require("../utility/debug.js"));
|
|
11
|
+
|
|
12
|
+
var _getStateSnapshot = _interopRequireDefault(require("../utility/getStateSnapshot.js"));
|
|
13
|
+
|
|
8
14
|
var _react = require("react");
|
|
9
15
|
|
|
10
|
-
function
|
|
16
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
|
|
11
17
|
|
|
12
|
-
function
|
|
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); }
|
|
13
19
|
|
|
14
|
-
function
|
|
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; }
|
|
15
21
|
|
|
16
22
|
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
17
23
|
|
|
@@ -29,16 +35,13 @@ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
|
29
35
|
function _useState(_ref) {
|
|
30
36
|
var initialState = _ref.initialState,
|
|
31
37
|
onRender = _ref.onRender,
|
|
32
|
-
itemsProperty = _ref.itemsProperty
|
|
33
|
-
USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION = _ref.USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION;
|
|
38
|
+
itemsProperty = _ref.itemsProperty;
|
|
34
39
|
|
|
35
|
-
// This is a
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
// feature is used for setting new `items` in state.
|
|
41
|
-
//
|
|
40
|
+
// This is a state variable that is used to re-render the component.
|
|
41
|
+
// Right after the component has finished re-rendering,
|
|
42
|
+
// `VirtualScroller` state gets updated from this variable.
|
|
43
|
+
// The reason for that is that `VirtualScroller` state must always
|
|
44
|
+
// correspond exactly to what's currently rendered on the screen.
|
|
42
45
|
var _useState2 = (0, _react.useState)(initialState),
|
|
43
46
|
_useState3 = _slicedToArray(_useState2, 2),
|
|
44
47
|
_newState = _useState3[0],
|
|
@@ -47,72 +50,162 @@ function _useState(_ref) {
|
|
|
47
50
|
|
|
48
51
|
|
|
49
52
|
var state = (0, _react.useRef)(initialState);
|
|
53
|
+
var getState = (0, _react.useCallback)(function () {
|
|
54
|
+
return state.current;
|
|
55
|
+
}, []);
|
|
50
56
|
var setState = (0, _react.useCallback)(function (newState) {
|
|
51
57
|
state.current = newState;
|
|
52
|
-
}, []); //
|
|
58
|
+
}, []); // Updating of the actual `VirtualScroller` state is done in a
|
|
59
|
+
// `useInsertionEffect()` rather than in a `useLayoutEffect()`.
|
|
60
|
+
//
|
|
61
|
+
// The reason is that using `useLayoutEffect()` would result in
|
|
62
|
+
// "breaking" the `<VirtualScroller/>` when an `itemComponent`
|
|
63
|
+
// called `onHeightDidChange()` from its own `useLayoutEffect()`.
|
|
64
|
+
// In those cases, the `itemCompoent`'s effect would run before
|
|
65
|
+
// the `<VirtualScroller/>`'s effect, resulting in
|
|
66
|
+
// `VirtualScroller.onItemHeightDidChange(i)` being run at a moment in time
|
|
67
|
+
// when the DOM has already been updated for the next `VirtualScroller` state
|
|
68
|
+
// but the actual `VirtualScroller` state is still a previous ("stale") one
|
|
69
|
+
// containing "stale" first/last shown item indexes, which would result in an
|
|
70
|
+
// "index out of bounds" error when `onItemHeightDidChange(i)` tries to access
|
|
71
|
+
// and measure the DOM element from item index `i` which doesn't already/yet exist.
|
|
72
|
+
//
|
|
73
|
+
// An example of such situation could be seen from a `VirtualScroller` debug log
|
|
74
|
+
// which was captured for a case when using `useLayoutEffect()` to update the
|
|
75
|
+
// "actual" `VirtualScroller` state after the corresponding DOM changes have been applied:
|
|
76
|
+
// The user has scrolled far enough: perform a re-layout
|
|
77
|
+
// ~ Update Layout (on scroll) ~
|
|
78
|
+
//
|
|
79
|
+
// Item index 2 height is required for calculations but hasn't been measured yet. Mark the item as "shown", rerender the list, measure the item's height and redo the layout.
|
|
80
|
+
//
|
|
81
|
+
// ~ Calculated Layout ~
|
|
82
|
+
// Columns count 1
|
|
83
|
+
// First shown item index 2
|
|
84
|
+
// Last shown item index 5
|
|
85
|
+
// …
|
|
86
|
+
// Item heights (231) [1056.578125, 783.125, empty × 229]
|
|
87
|
+
// Item states (231) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, …]
|
|
88
|
+
//
|
|
89
|
+
// ~ Set state ~
|
|
90
|
+
// {firstShownItemIndex: 2, lastShownItemIndex: 5, …}
|
|
91
|
+
//
|
|
92
|
+
// ~ Rendered ~
|
|
93
|
+
// State {firstShownItemIndex: 2, lastShownItemIndex: 5, …}
|
|
94
|
+
//
|
|
95
|
+
// ~ Measure item heights ~
|
|
96
|
+
// Item index 2 height 719.8828125
|
|
97
|
+
// Item index 3 height 961.640625
|
|
98
|
+
// Item index 4 height 677.6640625
|
|
99
|
+
// Item index 5 height 1510.1953125
|
|
100
|
+
//
|
|
101
|
+
// ~ Update Layout (on non-measured item heights have been measured) ~
|
|
102
|
+
//
|
|
103
|
+
// ~ Calculated Layout ~
|
|
104
|
+
// Columns count 1
|
|
105
|
+
// First shown item index 4
|
|
106
|
+
// Last shown item index 5
|
|
107
|
+
// …
|
|
108
|
+
// Item heights (231) [1056.578125, 783.125, 719.8828125, 961.640625, 677.6640625, 1510.1953125, empty × 225]
|
|
109
|
+
// Item states (231) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, …]
|
|
110
|
+
//
|
|
111
|
+
// ~ Set state ~
|
|
112
|
+
// {firstShownItemIndex: 4, lastShownItemIndex: 5, beforeItemsHeight: 3521.2265625, afterItemsHeight: 214090.72265624942}
|
|
113
|
+
//
|
|
114
|
+
// ~ On Item Height Did Change was called ~
|
|
115
|
+
// Item index 5
|
|
116
|
+
// ~ Re-measure item height ~
|
|
117
|
+
// ERROR "onItemHeightDidChange()" has been called for item index 5 but the item is not currently rendered and can't be measured. The exact error was: Element with index 3 was not found in the list of Rendered Item Elements in the Items Container of Virtual Scroller. There're only 2 Elements there.
|
|
118
|
+
//
|
|
119
|
+
// React: ~ The requested state is about to be applied in DOM. Set it as the `VirtualScroller` state. ~
|
|
120
|
+
// {firstShownItemIndex: 4, lastShownItemIndex: 5, …}
|
|
121
|
+
//
|
|
122
|
+
// ~ Rendered ~
|
|
123
|
+
// "~ Rendered ~" is what gets output when `onRender()` function gets called.
|
|
124
|
+
// It means that `useLayoutEffect()` was triggered after `onItemHeightDidChange(i)`
|
|
125
|
+
// was called and after the "ERROR" happened.
|
|
126
|
+
//
|
|
127
|
+
// The "ERROR" happened because new item indexes 4…5 were actually rendered instead of
|
|
128
|
+
// item indexes 2…5 by the time the application called `onItemHeightDidChange(i)` function
|
|
129
|
+
// inside `itemComponent`'s `useLayoutEffect()`.
|
|
130
|
+
// Item indexes 4…5 is what was requested in a `setState()` call, which called `_setNewState()`.
|
|
131
|
+
// This means that `_newState` changes have been applied to the DOM
|
|
132
|
+
// but `useLayoutEffect()` wasn't triggered immediately after that.
|
|
133
|
+
// Instead, it was triggered a right after the `itemComponent`'s `useLayoutEffect()`
|
|
134
|
+
// because child effects run before parent effects.
|
|
135
|
+
// So, the `itemComponent`'s `onHeightDidChange()` function call caught the
|
|
136
|
+
// `VirtualScroller` in an inconsistent state.
|
|
137
|
+
//
|
|
138
|
+
// To fix that, `useLayoutEffect()` gets replaced with `useInsertionEffect()`:
|
|
139
|
+
// https://blog.saeloun.com/2022/06/02/react-18-useinsertioneffect
|
|
140
|
+
// https://beta.reactjs.org/reference/react/useInsertionEffect
|
|
141
|
+
//
|
|
142
|
+
// After replacing `useLayoutEffect()` with `useInsertionEffect()`,
|
|
143
|
+
// the log shows that there's no more error:
|
|
144
|
+
//
|
|
145
|
+
// ~ Set state ~
|
|
146
|
+
// {firstShownItemIndex: 0, lastShownItemIndex: 2, …}
|
|
147
|
+
//
|
|
148
|
+
// React: ~ The requested state is about to be applied in DOM. Set it as the `VirtualScroller` state. ~
|
|
149
|
+
// {firstShownItemIndex: 0, lastShownItemIndex: 2, …}
|
|
150
|
+
//
|
|
151
|
+
// ~ On Item Height Did Change was called ~
|
|
152
|
+
// Item index 0
|
|
153
|
+
// ~ Re-measure item height ~
|
|
154
|
+
// Previous height 917
|
|
155
|
+
// New height 1064.453125
|
|
156
|
+
// ~ Item height has changed ~
|
|
157
|
+
//
|
|
158
|
+
// An alternative solution would be demanding the `itemComponent` to
|
|
159
|
+
// accept a `ref` and then measuring the corresponding DOM element height
|
|
160
|
+
// directly using the `ref`-ed DOM element rather than searching for that
|
|
161
|
+
// DOM element in the `ItemsContainer`.
|
|
162
|
+
// So if `useInsertionEffect()` gets removed from React in some hypothetical future,
|
|
163
|
+
// it could be replaced with using `ref`s on `ItemComponent`s to measure the DOM element heights.
|
|
164
|
+
//
|
|
53
165
|
|
|
54
|
-
|
|
55
|
-
|
|
166
|
+
(0, _react.useInsertionEffect)(function () {
|
|
167
|
+
// Update the actual `VirtualScroller` state right before the DOM changes
|
|
168
|
+
// are going to be applied for the requested state update.
|
|
169
|
+
//
|
|
170
|
+
// This hook will run right before `useLayoutEffect()`.
|
|
171
|
+
//
|
|
172
|
+
// It doesn't make any difference which one of the two hooks to use to update
|
|
173
|
+
// the actual `VirtualScroller` state in this scenario because the two hooks
|
|
174
|
+
// run synchronously one right after another (insertion effect → DOM update → layout effect)
|
|
175
|
+
// without any free space for any `VirtualScroller` code (like the scroll event handler)
|
|
176
|
+
// to squeeze in and run in-between them, so the `VirtualScroller`'s `state`
|
|
177
|
+
// is always gonna stay consistent with what's currently rendered on screen
|
|
178
|
+
// from the `VirtualScroler`'s point of view, and the short transition period
|
|
179
|
+
// it simply doesn't see because it doesn't "wake up" during that period.
|
|
180
|
+
//
|
|
181
|
+
// Updating the actual `VirtualScroller` state right before `useLayoutEffect()`
|
|
182
|
+
// fixes the bug when an `itemComponent` calls `onHeightDidChange()` in its own
|
|
183
|
+
// `useLayoutEffect()` which would run before this `useLayoutEffect()`
|
|
184
|
+
// because children's effects run before parent's.
|
|
185
|
+
//
|
|
186
|
+
// This hook doesn't do anything at the initial render.
|
|
187
|
+
//
|
|
188
|
+
if ((0, _debug.isDebug)()) {
|
|
189
|
+
(0, _debug["default"])('React: ~ The requested state is about to be applied in DOM. Set it as the `VirtualScroller` state. ~');
|
|
190
|
+
(0, _debug["default"])((0, _getStateSnapshot["default"])(_newState));
|
|
191
|
+
}
|
|
56
192
|
|
|
57
|
-
(0, _react.useLayoutEffect)(function () {
|
|
58
193
|
setState(_newState);
|
|
59
|
-
}, [_newState]);
|
|
60
|
-
// and also right after the initial render.
|
|
61
|
-
|
|
194
|
+
}, [_newState]);
|
|
62
195
|
(0, _react.useLayoutEffect)(function () {
|
|
196
|
+
// Call `onRender()` right after a requested state update has been applied,
|
|
197
|
+
// and also right after the initial render.
|
|
63
198
|
onRender();
|
|
64
|
-
}, [_newState
|
|
65
|
-
// there won't be a `_setNewState()` function call when `items` property changes,
|
|
66
|
-
// hence the additional `itemsProperty` dependency.
|
|
67
|
-
USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION ? itemsProperty : undefined]);
|
|
199
|
+
}, [_newState]);
|
|
68
200
|
return {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
201
|
+
// This is the state the component should render.
|
|
202
|
+
stateToRender: _newState,
|
|
203
|
+
// Returns the current state of the `VirtualScroller`.
|
|
204
|
+
// This function is used in the `VirtualScroller` itself
|
|
205
|
+
// because the `state` is managed outside of it.
|
|
206
|
+
getState: getState,
|
|
75
207
|
// Requests a state update.
|
|
76
|
-
|
|
77
|
-
// State updates are incremental meaning that this function mimicks
|
|
78
|
-
// the classic `React.Component`'s `this.setState()` behavior
|
|
79
|
-
// when calling `this.setState()` didn't replace `state` but rather merged
|
|
80
|
-
// the updated state properties over the "old" state properties.
|
|
81
|
-
//
|
|
82
|
-
// The reason for using pending state updates accumulation is that
|
|
83
|
-
// `useState()` updates are "asynchronous" (not immediate),
|
|
84
|
-
// and simply merging over `...state` would merge over potentially stale
|
|
85
|
-
// property values in cases when more than a single `updateState()` call is made
|
|
86
|
-
// before the state actually updates, resulting in losing some of those state updates.
|
|
87
|
-
//
|
|
88
|
-
// Example: the first `updateState()` call updates shown item indexes,
|
|
89
|
-
// and the second `updateState()` call updates `verticalSpacing`.
|
|
90
|
-
// If it was simply `updateState({ ...state, ...stateUpdate })`
|
|
91
|
-
// then the second state update could overwrite the first state update,
|
|
92
|
-
// resulting in incorrect items being shown/hidden.
|
|
93
|
-
//
|
|
94
|
-
updateState: function updateState(stateUpdate) {
|
|
95
|
-
nextState.current = _objectSpread(_objectSpread({}, nextState.current), stateUpdate); // If `items` property did change, the component detects it at render time
|
|
96
|
-
// and updates `VirtualScroller` items immediately by calling `.setItems()`,
|
|
97
|
-
// which, in turn, immediately calls this `updateState()` function
|
|
98
|
-
// with a `stateUpdate` argument that contains the new `items`,
|
|
99
|
-
// so checking for `stateUpdate.items` could detect situations like that.
|
|
100
|
-
//
|
|
101
|
-
// When the initial `VirtualScroller` state is being set, it contains the `.items`
|
|
102
|
-
// property too, but that initial setting is done using another function called
|
|
103
|
-
// `setInitialState()`, so using `if (stateUpdate.items)` condition here for describing
|
|
104
|
-
// just the case when `state` has been updated as a result of a `setItems()` call
|
|
105
|
-
// seems to be fine.
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
var _newState = nextState.current;
|
|
109
|
-
|
|
110
|
-
if (stateUpdate.items && USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION) {
|
|
111
|
-
setState(_newState);
|
|
112
|
-
} else {
|
|
113
|
-
_setNewState(_newState);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
208
|
+
setState: _setNewState
|
|
116
209
|
};
|
|
117
210
|
}
|
|
118
211
|
//# sourceMappingURL=useState.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useState.js","names":["_useState","initialState","onRender","itemsProperty","USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION","useState","_newState","_setNewState","state","useRef","setState","useCallback","newState","current","nextState","useLayoutEffect","undefined","getState","getNextState","updateState","stateUpdate","items"],"sources":["../../source/react/useState.js"],"sourcesContent":["import { useState, useRef, useCallback, useLayoutEffect } from 'react'\r\n\r\n// Creates state management functions.\r\nexport default function _useState({\r\n\tinitialState,\r\n\tonRender,\r\n\titemsProperty,\r\n\tUSE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION\r\n}) {\r\n\t// This is a utility state variable that is used to re-render the component.\r\n\t// It should not be used to access the current `VirtualScroller` state.\r\n\t// It's more of a \"requested\" `VirtualScroller` state.\r\n\t//\r\n\t// It will also be stale in cases when `USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION`\r\n\t// feature is used for setting new `items` in state.\r\n\t//\r\n\tconst [_newState, _setNewState] = useState(initialState)\r\n\r\n\t// This `state` reference is what `VirtualScroller` uses internally.\r\n\t// It's the \"source of truth\" on the actual `VirtualScroller` state.\r\n\tconst state = useRef(initialState)\r\n\r\n\tconst setState = useCallback((newState) => {\r\n\t\tstate.current = newState\r\n\t}, [])\r\n\r\n\t// Accumulates all \"pending\" state updates until they have been applied.\r\n\tconst nextState = useRef(initialState)\r\n\r\n\t// Updates the actual `VirtualScroller` state right after a requested state update\r\n\t// has been applied. Doesn't do anything at initial render.\r\n\tuseLayoutEffect(() => {\r\n\t\tsetState(_newState)\r\n\t}, [\r\n\t\t_newState\r\n\t])\r\n\r\n\t// Calls `onRender()` right after every state update (which is a re-render),\r\n\t// and also right after the initial render.\r\n\tuseLayoutEffect(() => {\r\n\t\tonRender()\r\n\t}, [\r\n\t\t_newState,\r\n\t\t// When using `USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION` feature,\r\n\t\t// there won't be a `_setNewState()` function call when `items` property changes,\r\n\t\t// hence the additional `itemsProperty` dependency.\r\n\t\tUSE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION ? itemsProperty : undefined\r\n\t])\r\n\r\n\treturn {\r\n\t\tgetState: () => state.current,\r\n\r\n\t\tgetNextState: () => nextState.current,\r\n\r\n\t\t// Requests a state update.\r\n\t\t//\r\n\t\t// State updates are incremental meaning that this function mimicks\r\n\t\t// the classic `React.Component`'s `this.setState()` behavior\r\n\t\t// when calling `this.setState()` didn't replace `state` but rather merged\r\n\t\t// the updated state properties over the \"old\" state properties.\r\n\t\t//\r\n\t\t// The reason for using pending state updates accumulation is that\r\n\t\t// `useState()` updates are \"asynchronous\" (not immediate),\r\n\t\t// and simply merging over `...state` would merge over potentially stale\r\n\t\t// property values in cases when more than a single `updateState()` call is made\r\n\t\t// before the state actually updates, resulting in losing some of those state updates.\r\n\t\t//\r\n\t\t// Example: the first `updateState()` call updates shown item indexes,\r\n\t\t// and the second `updateState()` call updates `verticalSpacing`.\r\n\t\t// If it was simply `updateState({ ...state, ...stateUpdate })`\r\n\t\t// then the second state update could overwrite the first state update,\r\n\t\t// resulting in incorrect items being shown/hidden.\r\n\t\t//\r\n\t\tupdateState: (stateUpdate) => {\r\n\t\t\tnextState.current = {\r\n\t\t\t\t...nextState.current,\r\n\t\t\t\t...stateUpdate\r\n\t\t\t}\r\n\t\t\t// If `items` property did change, the component detects it at render time\r\n\t\t\t// and updates `VirtualScroller` items immediately by calling `.setItems()`,\r\n\t\t\t// which, in turn, immediately calls this `updateState()` function\r\n\t\t\t// with a `stateUpdate` argument that contains the new `items`,\r\n\t\t\t// so checking for `stateUpdate.items` could detect situations like that.\r\n\t\t\t//\r\n\t\t\t// When the initial `VirtualScroller` state is being set, it contains the `.items`\r\n\t\t\t// property too, but that initial setting is done using another function called\r\n\t\t\t// `setInitialState()`, so using `if (stateUpdate.items)` condition here for describing\r\n\t\t\t// just the case when `state` has been updated as a result of a `setItems()` call\r\n\t\t\t// seems to be fine.\r\n\t\t\t//\r\n\t\t\tconst _newState = nextState.current\r\n\t\t\tif (stateUpdate.items && USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION) {\r\n\t\t\t\tsetState(_newState)\r\n\t\t\t} else {\r\n\t\t\t\t_setNewState(_newState)\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"],"mappings":";;;;;;;AAAA;;;;;;;;;;;;;;;;;;;;AAEA;AACe,SAASA,SAAT,OAKZ;EAAA,IAJFC,YAIE,QAJFA,YAIE;EAAA,IAHFC,QAGE,QAHFA,QAGE;EAAA,IAFFC,aAEE,QAFFA,aAEE;EAAA,IADFC,8CACE,QADFA,8CACE;;EACF;EACA;EACA;EACA;EACA;EACA;EACA;EACA,iBAAkC,IAAAC,eAAA,EAASJ,YAAT,CAAlC;EAAA;EAAA,IAAOK,SAAP;EAAA,IAAkBC,YAAlB,iBARE,CAUF;EACA;;;EACA,IAAMC,KAAK,GAAG,IAAAC,aAAA,EAAOR,YAAP,CAAd;EAEA,IAAMS,QAAQ,GAAG,IAAAC,kBAAA,EAAY,UAACC,QAAD,EAAc;IAC1CJ,KAAK,CAACK,OAAN,GAAgBD,QAAhB;EACA,CAFgB,EAEd,EAFc,CAAjB,CAdE,CAkBF;;EACA,IAAME,SAAS,GAAG,IAAAL,aAAA,EAAOR,YAAP,CAAlB,CAnBE,CAqBF;EACA;;EACA,IAAAc,sBAAA,EAAgB,YAAM;IACrBL,QAAQ,CAACJ,SAAD,CAAR;EACA,CAFD,EAEG,CACFA,SADE,CAFH,EAvBE,CA6BF;EACA;;EACA,IAAAS,sBAAA,EAAgB,YAAM;IACrBb,QAAQ;EACR,CAFD,EAEG,CACFI,SADE,EAEF;EACA;EACA;EACAF,8CAA8C,GAAGD,aAAH,GAAmBa,SAL/D,CAFH;EAUA,OAAO;IACNC,QAAQ,EAAE;MAAA,OAAMT,KAAK,CAACK,OAAZ;IAAA,CADJ;IAGNK,YAAY,EAAE;MAAA,OAAMJ,SAAS,CAACD,OAAhB;IAAA,CAHR;IAKN;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACAM,WAAW,EAAE,qBAACC,WAAD,EAAiB;MAC7BN,SAAS,CAACD,OAAV,mCACIC,SAAS,CAACD,OADd,GAEIO,WAFJ,EAD6B,CAK7B;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;;MACA,IAAMd,SAAS,GAAGQ,SAAS,CAACD,OAA5B;;MACA,IAAIO,WAAW,CAACC,KAAZ,IAAqBjB,8CAAzB,EAAyE;QACxEM,QAAQ,CAACJ,SAAD,CAAR;MACA,CAFD,MAEO;QACNC,YAAY,CAACD,SAAD,CAAZ;MACA;IACD;EA/CK,CAAP;AAiDA"}
|
|
1
|
+
{"version":3,"file":"useState.js","names":["_useState","initialState","onRender","itemsProperty","useState","_newState","_setNewState","state","useRef","getState","useCallback","current","setState","newState","useInsertionEffect","isDebug","log","getStateSnapshot","useLayoutEffect","stateToRender"],"sources":["../../source/react/useState.js"],"sourcesContent":["import log, { isDebug } from '../utility/debug.js'\r\nimport getStateSnapshot from '../utility/getStateSnapshot.js'\r\n\r\nimport { useState, useRef, useCallback, useLayoutEffect, useInsertionEffect } from 'react'\r\n\r\n// Creates state management functions.\r\nexport default function _useState({\r\n\tinitialState,\r\n\tonRender,\r\n\titemsProperty\r\n}) {\r\n\t// This is a state variable that is used to re-render the component.\r\n\t// Right after the component has finished re-rendering,\r\n\t// `VirtualScroller` state gets updated from this variable.\r\n\t// The reason for that is that `VirtualScroller` state must always\r\n\t// correspond exactly to what's currently rendered on the screen.\r\n\tconst [_newState, _setNewState] = useState(initialState)\r\n\r\n\t// This `state` reference is what `VirtualScroller` uses internally.\r\n\t// It's the \"source of truth\" on the actual `VirtualScroller` state.\r\n\tconst state = useRef(initialState)\r\n\r\n\tconst getState = useCallback(() => {\r\n\t\treturn state.current\r\n\t}, [])\r\n\r\n\tconst setState = useCallback((newState) => {\r\n\t\tstate.current = newState\r\n\t}, [])\r\n\r\n\t// Updating of the actual `VirtualScroller` state is done in a\r\n\t// `useInsertionEffect()` rather than in a `useLayoutEffect()`.\r\n\t//\r\n\t// The reason is that using `useLayoutEffect()` would result in\r\n\t// \"breaking\" the `<VirtualScroller/>` when an `itemComponent`\r\n\t// called `onHeightDidChange()` from its own `useLayoutEffect()`.\r\n\t// In those cases, the `itemCompoent`'s effect would run before\r\n\t// the `<VirtualScroller/>`'s effect, resulting in\r\n\t// `VirtualScroller.onItemHeightDidChange(i)` being run at a moment in time\r\n\t// when the DOM has already been updated for the next `VirtualScroller` state\r\n\t// but the actual `VirtualScroller` state is still a previous (\"stale\") one\r\n\t// containing \"stale\" first/last shown item indexes, which would result in an\r\n\t// \"index out of bounds\" error when `onItemHeightDidChange(i)` tries to access\r\n\t// and measure the DOM element from item index `i` which doesn't already/yet exist.\r\n\t//\r\n\t// An example of such situation could be seen from a `VirtualScroller` debug log\r\n\t// which was captured for a case when using `useLayoutEffect()` to update the\r\n\t// \"actual\" `VirtualScroller` state after the corresponding DOM changes have been applied:\r\n\r\n\t// The user has scrolled far enough: perform a re-layout\r\n\t// ~ Update Layout (on scroll) ~\r\n\t//\r\n\t// Item index 2 height is required for calculations but hasn't been measured yet. Mark the item as \"shown\", rerender the list, measure the item's height and redo the layout.\r\n\t//\r\n\t// ~ Calculated Layout ~\r\n\t// Columns count 1\r\n\t// First shown item index 2\r\n\t// Last shown item index 5\r\n\t// …\r\n\t// Item heights (231) [1056.578125, 783.125, empty × 229]\r\n\t// Item states (231) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, …]\r\n\t//\r\n\t// ~ Set state ~\r\n\t// {firstShownItemIndex: 2, lastShownItemIndex: 5, …}\r\n\t//\r\n\t// ~ Rendered ~\r\n\t// State {firstShownItemIndex: 2, lastShownItemIndex: 5, …}\r\n\t//\r\n\t// ~ Measure item heights ~\r\n\t// Item index 2 height 719.8828125\r\n\t// Item index 3 height 961.640625\r\n\t// Item index 4 height 677.6640625\r\n\t// Item index 5 height 1510.1953125\r\n\t//\r\n\t// ~ Update Layout (on non-measured item heights have been measured) ~\r\n\t//\r\n\t// ~ Calculated Layout ~\r\n\t// Columns count 1\r\n\t// First shown item index 4\r\n\t// Last shown item index 5\r\n\t// …\r\n\t// Item heights (231) [1056.578125, 783.125, 719.8828125, 961.640625, 677.6640625, 1510.1953125, empty × 225]\r\n\t// Item states (231) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, …]\r\n\t//\r\n\t// ~ Set state ~\r\n\t// {firstShownItemIndex: 4, lastShownItemIndex: 5, beforeItemsHeight: 3521.2265625, afterItemsHeight: 214090.72265624942}\r\n\t//\r\n\t// ~ On Item Height Did Change was called ~\r\n\t// Item index 5\r\n\t// ~ Re-measure item height ~\r\n\t// ERROR \"onItemHeightDidChange()\" has been called for item index 5 but the item is not currently rendered and can't be measured. The exact error was: Element with index 3 was not found in the list of Rendered Item Elements in the Items Container of Virtual Scroller. There're only 2 Elements there.\r\n\t//\r\n\t// React: ~ The requested state is about to be applied in DOM. Set it as the `VirtualScroller` state. ~\r\n\t// {firstShownItemIndex: 4, lastShownItemIndex: 5, …}\r\n\t//\r\n\t// ~ Rendered ~\r\n\r\n\t// \"~ Rendered ~\" is what gets output when `onRender()` function gets called.\r\n\t// It means that `useLayoutEffect()` was triggered after `onItemHeightDidChange(i)`\r\n\t// was called and after the \"ERROR\" happened.\r\n\t//\r\n\t// The \"ERROR\" happened because new item indexes 4…5 were actually rendered instead of\r\n\t// item indexes 2…5 by the time the application called `onItemHeightDidChange(i)` function\r\n\t// inside `itemComponent`'s `useLayoutEffect()`.\r\n\t// Item indexes 4…5 is what was requested in a `setState()` call, which called `_setNewState()`.\r\n\t// This means that `_newState` changes have been applied to the DOM\r\n\t// but `useLayoutEffect()` wasn't triggered immediately after that.\r\n\t// Instead, it was triggered a right after the `itemComponent`'s `useLayoutEffect()`\r\n\t// because child effects run before parent effects.\r\n\t// So, the `itemComponent`'s `onHeightDidChange()` function call caught the\r\n\t// `VirtualScroller` in an inconsistent state.\r\n\t//\r\n\t// To fix that, `useLayoutEffect()` gets replaced with `useInsertionEffect()`:\r\n\t// https://blog.saeloun.com/2022/06/02/react-18-useinsertioneffect\r\n\t// https://beta.reactjs.org/reference/react/useInsertionEffect\r\n\t//\r\n\t// After replacing `useLayoutEffect()` with `useInsertionEffect()`,\r\n\t// the log shows that there's no more error:\r\n\t//\r\n\t// ~ Set state ~\r\n\t// {firstShownItemIndex: 0, lastShownItemIndex: 2, …}\r\n\t//\r\n\t// React: ~ The requested state is about to be applied in DOM. Set it as the `VirtualScroller` state. ~\r\n\t// {firstShownItemIndex: 0, lastShownItemIndex: 2, …}\r\n\t//\r\n\t// ~ On Item Height Did Change was called ~\r\n\t// Item index 0\r\n\t// ~ Re-measure item height ~\r\n\t// Previous height 917\r\n\t// New height 1064.453125\r\n\t// ~ Item height has changed ~\r\n\t//\r\n\t// An alternative solution would be demanding the `itemComponent` to\r\n\t// accept a `ref` and then measuring the corresponding DOM element height\r\n\t// directly using the `ref`-ed DOM element rather than searching for that\r\n\t// DOM element in the `ItemsContainer`.\r\n\t// So if `useInsertionEffect()` gets removed from React in some hypothetical future,\r\n\t// it could be replaced with using `ref`s on `ItemComponent`s to measure the DOM element heights.\r\n\t//\r\n\tuseInsertionEffect(() => {\r\n\t\t// Update the actual `VirtualScroller` state right before the DOM changes\r\n\t\t// are going to be applied for the requested state update.\r\n\t\t//\r\n\t\t// This hook will run right before `useLayoutEffect()`.\r\n\t\t//\r\n\t\t// It doesn't make any difference which one of the two hooks to use to update\r\n\t\t// the actual `VirtualScroller` state in this scenario because the two hooks\r\n\t\t// run synchronously one right after another (insertion effect → DOM update → layout effect)\r\n\t\t// without any free space for any `VirtualScroller` code (like the scroll event handler)\r\n\t\t// to squeeze in and run in-between them, so the `VirtualScroller`'s `state`\r\n\t\t// is always gonna stay consistent with what's currently rendered on screen\r\n\t\t// from the `VirtualScroler`'s point of view, and the short transition period\r\n\t\t// it simply doesn't see because it doesn't \"wake up\" during that period.\r\n\t\t//\r\n\t\t// Updating the actual `VirtualScroller` state right before `useLayoutEffect()`\r\n\t\t// fixes the bug when an `itemComponent` calls `onHeightDidChange()` in its own\r\n\t\t// `useLayoutEffect()` which would run before this `useLayoutEffect()`\r\n\t\t// because children's effects run before parent's.\r\n\t\t//\r\n\t\t// This hook doesn't do anything at the initial render.\r\n\t\t//\r\n\t\tif (isDebug()) {\r\n\t\t\tlog('React: ~ The requested state is about to be applied in DOM. Set it as the `VirtualScroller` state. ~')\r\n\t\t\tlog(getStateSnapshot(_newState))\r\n\t\t}\r\n\t\tsetState(_newState)\r\n\t}, [_newState])\r\n\r\n\tuseLayoutEffect(() => {\r\n\t\t// Call `onRender()` right after a requested state update has been applied,\r\n\t\t// and also right after the initial render.\r\n\t\tonRender()\r\n\t}, [_newState])\r\n\r\n\treturn {\r\n\t\t// This is the state the component should render.\r\n\t\tstateToRender: _newState,\r\n\r\n\t\t// Returns the current state of the `VirtualScroller`.\r\n\t\t// This function is used in the `VirtualScroller` itself\r\n\t\t// because the `state` is managed outside of it.\r\n\t\tgetState,\r\n\r\n\t\t// Requests a state update.\r\n\t\tsetState: _setNewState\r\n\t}\r\n}"],"mappings":";;;;;;;;;AAAA;;AACA;;AAEA;;;;;;;;;;;;;;;;;;;;AAEA;AACe,SAASA,SAAT,OAIZ;EAAA,IAHFC,YAGE,QAHFA,YAGE;EAAA,IAFFC,QAEE,QAFFA,QAEE;EAAA,IADFC,aACE,QADFA,aACE;;EACF;EACA;EACA;EACA;EACA;EACA,iBAAkC,IAAAC,eAAA,EAASH,YAAT,CAAlC;EAAA;EAAA,IAAOI,SAAP;EAAA,IAAkBC,YAAlB,iBANE,CAQF;EACA;;;EACA,IAAMC,KAAK,GAAG,IAAAC,aAAA,EAAOP,YAAP,CAAd;EAEA,IAAMQ,QAAQ,GAAG,IAAAC,kBAAA,EAAY,YAAM;IAClC,OAAOH,KAAK,CAACI,OAAb;EACA,CAFgB,EAEd,EAFc,CAAjB;EAIA,IAAMC,QAAQ,GAAG,IAAAF,kBAAA,EAAY,UAACG,QAAD,EAAc;IAC1CN,KAAK,CAACI,OAAN,GAAgBE,QAAhB;EACA,CAFgB,EAEd,EAFc,CAAjB,CAhBE,CAoBF;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EACA,IAAAC,yBAAA,EAAmB,YAAM;IACxB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA,IAAI,IAAAC,cAAA,GAAJ,EAAe;MACd,IAAAC,iBAAA,EAAI,sGAAJ;MACA,IAAAA,iBAAA,EAAI,IAAAC,4BAAA,EAAiBZ,SAAjB,CAAJ;IACA;;IACDO,QAAQ,CAACP,SAAD,CAAR;EACA,CA3BD,EA2BG,CAACA,SAAD,CA3BH;EA6BA,IAAAa,sBAAA,EAAgB,YAAM;IACrB;IACA;IACAhB,QAAQ;EACR,CAJD,EAIG,CAACG,SAAD,CAJH;EAMA,OAAO;IACN;IACAc,aAAa,EAAEd,SAFT;IAIN;IACA;IACA;IACAI,QAAQ,EAARA,QAPM;IASN;IACAG,QAAQ,EAAEN;EAVJ,CAAP;AAYA"}
|
|
@@ -11,16 +11,14 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "d
|
|
|
11
11
|
|
|
12
12
|
function useStyle(_ref) {
|
|
13
13
|
var tbody = _ref.tbody,
|
|
14
|
-
|
|
14
|
+
state = _ref.state;
|
|
15
15
|
|
|
16
16
|
if (tbody) {
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
var
|
|
21
|
-
|
|
22
|
-
afterItemsHeight = _getNextState.afterItemsHeight;
|
|
23
|
-
|
|
20
|
+
var beforeItemsHeight = state.beforeItemsHeight,
|
|
21
|
+
afterItemsHeight = state.afterItemsHeight;
|
|
24
22
|
return {
|
|
25
23
|
paddingTop: (0, _px["default"])(beforeItemsHeight),
|
|
26
24
|
paddingBottom: (0, _px["default"])(afterItemsHeight)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useStyle.js","names":["useStyle","tbody","
|
|
1
|
+
{"version":3,"file":"useStyle.js","names":["useStyle","tbody","state","beforeItemsHeight","afterItemsHeight","paddingTop","px","paddingBottom"],"sources":["../../source/react/useStyle.js"],"sourcesContent":["import px from '../utility/px.js'\r\n\r\nexport default function useStyle({\r\n\ttbody,\r\n\tstate\r\n}) {\r\n\tif (tbody) {\r\n\t\treturn\r\n\t}\r\n\r\n\tconst {\r\n\t\tbeforeItemsHeight,\r\n\t\tafterItemsHeight\r\n\t} = state\r\n\r\n\treturn {\r\n\t\tpaddingTop: px(beforeItemsHeight),\r\n\t\tpaddingBottom: px(afterItemsHeight)\r\n\t}\r\n}"],"mappings":";;;;;;;AAAA;;;;AAEe,SAASA,QAAT,OAGZ;EAAA,IAFFC,KAEE,QAFFA,KAEE;EAAA,IADFC,KACE,QADFA,KACE;;EACF,IAAID,KAAJ,EAAW;IACV;EACA;;EAED,IACCE,iBADD,GAGID,KAHJ,CACCC,iBADD;EAAA,IAECC,gBAFD,GAGIF,KAHJ,CAECE,gBAFD;EAKA,OAAO;IACNC,UAAU,EAAE,IAAAC,cAAA,EAAGH,iBAAH,CADN;IAENI,aAAa,EAAE,IAAAD,cAAA,EAAGF,gBAAH;EAFT,CAAP;AAIA"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports["default"] = useUpdateItemKeysOnItemsChange;
|
|
7
|
+
|
|
8
|
+
var _debug = _interopRequireDefault(require("../utility/debug.js"));
|
|
9
|
+
|
|
10
|
+
var _useOnChange = _interopRequireDefault(require("./useOnChange.js"));
|
|
11
|
+
|
|
12
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
|
|
13
|
+
|
|
14
|
+
// If the order of the `items` changes, or new `items` get prepended resulting in a "shift":
|
|
15
|
+
//
|
|
16
|
+
// * Re-generate the React `key` prefix for item elements
|
|
17
|
+
// so that all item components are re-rendered for the new `items` list.
|
|
18
|
+
// That's because item components may have their own internal state,
|
|
19
|
+
// and simply passing another `item` property for an item component
|
|
20
|
+
// might result in bugs, which React would do with its "re-using" policy
|
|
21
|
+
// if the unique `key` workaround hasn't been used.
|
|
22
|
+
//
|
|
23
|
+
function useUpdateItemKeysOnItemsChange(itemsBeingRendered, _ref) {
|
|
24
|
+
var virtualScroller = _ref.virtualScroller,
|
|
25
|
+
usesAutogeneratedItemKeys = _ref.usesAutogeneratedItemKeys,
|
|
26
|
+
updateItemKeysForNewItems = _ref.updateItemKeysForNewItems;
|
|
27
|
+
// Update item keys if the items being rendered have changed.
|
|
28
|
+
(0, _useOnChange["default"])(itemsBeingRendered, function (itemsBeingRendered, previousItemsBeingRendered) {
|
|
29
|
+
if (!usesAutogeneratedItemKeys) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
(0, _debug["default"])('React: ~ Different `items` are about to be rendered', itemsBeingRendered);
|
|
34
|
+
var shouldUpdateItemKeys = true;
|
|
35
|
+
var itemsDiff = virtualScroller.getItemsDiff(previousItemsBeingRendered, itemsBeingRendered); // `itemsDiff` will be `undefined` in case of a non-incremental items list change.
|
|
36
|
+
|
|
37
|
+
if (itemsDiff) {
|
|
38
|
+
var prependedItemsCount = itemsDiff.prependedItemsCount,
|
|
39
|
+
appendedItemsCount = itemsDiff.appendedItemsCount;
|
|
40
|
+
|
|
41
|
+
if (prependedItemsCount === 0 && appendedItemsCount === 0) {
|
|
42
|
+
(0, _debug["default"])('React: ~ The `items` elements to be rendered are identical to the previously rendered ones'); // The items order hasn't changed.
|
|
43
|
+
// No need to re-generate the `key` prefix.
|
|
44
|
+
|
|
45
|
+
shouldUpdateItemKeys = false;
|
|
46
|
+
} else if (prependedItemsCount === 0 && appendedItemsCount > 0) {
|
|
47
|
+
(0, _debug["default"])('React: ~ The `items` elements order hasn\'t changed:', appendedItemsCount, 'items have been appended'); // The item order hasn't changed.
|
|
48
|
+
// No need to re-generate the `key` prefix.
|
|
49
|
+
|
|
50
|
+
shouldUpdateItemKeys = false;
|
|
51
|
+
}
|
|
52
|
+
} // Update React element `key`s for the new set of `items`.
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
if (shouldUpdateItemKeys) {
|
|
56
|
+
(0, _debug["default"])('React: ~ Update item `key`s');
|
|
57
|
+
updateItemKeysForNewItems();
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=useUpdateItemKeysOnItemsChange.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useUpdateItemKeysOnItemsChange.js","names":["useUpdateItemKeysOnItemsChange","itemsBeingRendered","virtualScroller","usesAutogeneratedItemKeys","updateItemKeysForNewItems","useOnChange","previousItemsBeingRendered","log","shouldUpdateItemKeys","itemsDiff","getItemsDiff","prependedItemsCount","appendedItemsCount"],"sources":["../../source/react/useUpdateItemKeysOnItemsChange.js"],"sourcesContent":["import log from '../utility/debug.js'\r\n\r\nimport useOnChange from './useOnChange.js'\r\n\r\n// If the order of the `items` changes, or new `items` get prepended resulting in a \"shift\":\r\n//\r\n// * Re-generate the React `key` prefix for item elements\r\n// so that all item components are re-rendered for the new `items` list.\r\n// That's because item components may have their own internal state,\r\n// and simply passing another `item` property for an item component\r\n// might result in bugs, which React would do with its \"re-using\" policy\r\n// if the unique `key` workaround hasn't been used.\r\n//\r\nexport default function useUpdateItemKeysOnItemsChange(itemsBeingRendered, {\r\n\tvirtualScroller,\r\n\tusesAutogeneratedItemKeys,\r\n\tupdateItemKeysForNewItems\r\n}) {\r\n\t// Update item keys if the items being rendered have changed.\r\n\tuseOnChange(itemsBeingRendered, (itemsBeingRendered, previousItemsBeingRendered) => {\r\n\t\tif (!usesAutogeneratedItemKeys) {\r\n\t\t\treturn\r\n\t\t}\r\n\r\n\t\tlog('React: ~ Different `items` are about to be rendered', itemsBeingRendered)\r\n\r\n\t\tlet shouldUpdateItemKeys = true\r\n\r\n\t\tconst itemsDiff = virtualScroller.getItemsDiff(previousItemsBeingRendered, itemsBeingRendered)\r\n\r\n\t\t// `itemsDiff` will be `undefined` in case of a non-incremental items list change.\r\n\t\tif (itemsDiff) {\r\n\t\t\tconst {\r\n\t\t\t\tprependedItemsCount,\r\n\t\t\t\tappendedItemsCount\r\n\t\t\t} = itemsDiff\r\n\t\t\tif (prependedItemsCount === 0 && appendedItemsCount === 0) {\r\n\t\t\t\tlog('React: ~ The `items` elements to be rendered are identical to the previously rendered ones')\r\n\t\t\t\t// The items order hasn't changed.\r\n\t\t\t\t// No need to re-generate the `key` prefix.\r\n\t\t\t\tshouldUpdateItemKeys = false\r\n\t\t\t}\r\n\t\t\telse if (prependedItemsCount === 0 && appendedItemsCount > 0) {\r\n\t\t\t\tlog('React: ~ The `items` elements order hasn\\'t changed:', appendedItemsCount, 'items have been appended')\r\n\t\t\t\t// The item order hasn't changed.\r\n\t\t\t\t// No need to re-generate the `key` prefix.\r\n\t\t\t\tshouldUpdateItemKeys = false\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Update React element `key`s for the new set of `items`.\r\n\t\tif (shouldUpdateItemKeys) {\r\n\t\t\tlog('React: ~ Update item `key`s')\r\n\t\t\tupdateItemKeysForNewItems()\r\n\t\t}\r\n\t})\r\n}"],"mappings":";;;;;;;AAAA;;AAEA;;;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe,SAASA,8BAAT,CAAwCC,kBAAxC,QAIZ;EAAA,IAHFC,eAGE,QAHFA,eAGE;EAAA,IAFFC,yBAEE,QAFFA,yBAEE;EAAA,IADFC,yBACE,QADFA,yBACE;EACF;EACA,IAAAC,uBAAA,EAAYJ,kBAAZ,EAAgC,UAACA,kBAAD,EAAqBK,0BAArB,EAAoD;IACnF,IAAI,CAACH,yBAAL,EAAgC;MAC/B;IACA;;IAED,IAAAI,iBAAA,EAAI,qDAAJ,EAA2DN,kBAA3D;IAEA,IAAIO,oBAAoB,GAAG,IAA3B;IAEA,IAAMC,SAAS,GAAGP,eAAe,CAACQ,YAAhB,CAA6BJ,0BAA7B,EAAyDL,kBAAzD,CAAlB,CATmF,CAWnF;;IACA,IAAIQ,SAAJ,EAAe;MACd,IACCE,mBADD,GAGIF,SAHJ,CACCE,mBADD;MAAA,IAECC,kBAFD,GAGIH,SAHJ,CAECG,kBAFD;;MAIA,IAAID,mBAAmB,KAAK,CAAxB,IAA6BC,kBAAkB,KAAK,CAAxD,EAA2D;QAC1D,IAAAL,iBAAA,EAAI,4FAAJ,EAD0D,CAE1D;QACA;;QACAC,oBAAoB,GAAG,KAAvB;MACA,CALD,MAMK,IAAIG,mBAAmB,KAAK,CAAxB,IAA6BC,kBAAkB,GAAG,CAAtD,EAAyD;QAC7D,IAAAL,iBAAA,EAAI,sDAAJ,EAA4DK,kBAA5D,EAAgF,0BAAhF,EAD6D,CAE7D;QACA;;QACAJ,oBAAoB,GAAG,KAAvB;MACA;IACD,CA7BkF,CA+BnF;;;IACA,IAAIA,oBAAJ,EAA0B;MACzB,IAAAD,iBAAA,EAAI,6BAAJ;MACAH,yBAAyB;IACzB;EACD,CApCD;AAqCA"}
|
|
@@ -5,6 +5,10 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports["default"] = void 0;
|
|
7
7
|
|
|
8
|
+
var _ItemNotRenderedError = _interopRequireDefault(require("../ItemNotRenderedError.js"));
|
|
9
|
+
|
|
10
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
|
|
11
|
+
|
|
8
12
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
9
13
|
|
|
10
14
|
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); } }
|
|
@@ -37,6 +41,14 @@ var ItemsContainer = /*#__PURE__*/function () {
|
|
|
37
41
|
var rowWidth;
|
|
38
42
|
var rowHeight;
|
|
39
43
|
var startNewRow = true;
|
|
44
|
+
|
|
45
|
+
if (renderedElementIndex > children.length - 1) {
|
|
46
|
+
throw new _ItemNotRenderedError["default"]({
|
|
47
|
+
renderedElementIndex: renderedElementIndex,
|
|
48
|
+
renderedElementsCount: children.length
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
40
52
|
var i = 0;
|
|
41
53
|
|
|
42
54
|
while (i <= renderedElementIndex) {
|
|
@@ -73,7 +85,16 @@ var ItemsContainer = /*#__PURE__*/function () {
|
|
|
73
85
|
}, {
|
|
74
86
|
key: "getNthRenderedItemHeight",
|
|
75
87
|
value: function getNthRenderedItemHeight(renderedElementIndex) {
|
|
76
|
-
|
|
88
|
+
var children = this.getElement().children;
|
|
89
|
+
|
|
90
|
+
if (renderedElementIndex > children.length - 1) {
|
|
91
|
+
throw new _ItemNotRenderedError["default"]({
|
|
92
|
+
renderedElementIndex: renderedElementIndex,
|
|
93
|
+
renderedElementsCount: children.length
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return children[renderedElementIndex].height;
|
|
77
98
|
}
|
|
78
99
|
/**
|
|
79
100
|
* Returns items container height.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ItemsContainer.js","names":["ItemsContainer","getElement","renderedElementIndex","children","maxWidth","width","topOffset","paddingTop","rowWidth","rowHeight","startNewRow","i","marginTop","height","Math","max","contentHeight","
|
|
1
|
+
{"version":3,"file":"ItemsContainer.js","names":["ItemsContainer","getElement","renderedElementIndex","children","maxWidth","width","topOffset","paddingTop","rowWidth","rowHeight","startNewRow","length","ItemNotRenderedError","renderedElementsCount","i","marginTop","height","Math","max","contentHeight","verticalSpacing","paddingBottom"],"sources":["../../source/test/ItemsContainer.js"],"sourcesContent":["import ItemNotRenderedError from '../ItemNotRenderedError.js'\r\n\r\nexport default class ItemsContainer {\r\n\t/**\r\n\t * Constructs a new \"container\" from an element.\r\n\t * @param {function} getElement\r\n\t */\r\n\tconstructor(getElement) {\r\n\t\tthis.getElement = getElement\r\n\t}\r\n\r\n\t/**\r\n\t * Returns an item element's \"top offset\", relative to the items `container`'s top edge.\r\n\t * @param {number} renderedElementIndex — An index of an item relative to the \"first shown item index\". For example, if the list is showing items from index 8 to index 12 then `renderedElementIndex = 0` would mean the item at index `8`.\r\n\t * @return {number}\r\n\t */\r\n\tgetNthRenderedItemTopOffset(renderedElementIndex) {\r\n\t\tconst children = this.getElement().children\r\n\t\tconst maxWidth = this.getElement().width\r\n\t\tlet topOffset = this.getElement().paddingTop\r\n\r\n\t\tlet rowWidth\r\n\t\tlet rowHeight\r\n\t\tlet startNewRow = true\r\n\r\n\t\tif (renderedElementIndex > children.length - 1) {\r\n\t\t\tthrow new ItemNotRenderedError({\r\n\t\t\t\trenderedElementIndex,\r\n\t\t\t\trenderedElementsCount: children.length\r\n\t\t\t})\r\n\t\t}\r\n\r\n\t\tlet i = 0\r\n\t\twhile (i <= renderedElementIndex) {\r\n\t\t\tif (startNewRow || rowWidth + children[i].width > maxWidth) {\r\n\t\t\t\tif (i > 0) {\r\n\t\t\t\t\ttopOffset += rowHeight\r\n\t\t\t\t\ttopOffset += children[i].marginTop\r\n\t\t\t\t}\r\n\t\t\t\trowWidth = children[i].width\r\n\t\t\t\trowHeight = children[i].height\r\n\t\t\t\tif (rowWidth > maxWidth) {\r\n\t\t\t\t\tstartNewRow = true\r\n\t\t\t\t} else {\r\n\t\t\t\t\tstartNewRow = false\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\trowWidth += children[i].width\r\n\t\t\t\trowHeight = Math.max(rowHeight, children[i].height)\r\n\t\t\t}\r\n\t\t\ti++\r\n\t\t}\r\n\r\n\t\treturn topOffset\r\n\t}\r\n\r\n\t/**\r\n\t * Returns an item element's height.\r\n\t * @param {number} renderedElementIndex — An index of an item relative to the \"first shown item index\". For example, if the list is showing items from index 8 to index 12 then `renderedElementIndex = 0` would mean the item at index `8`.\r\n\t * @return {number}\r\n\t */\r\n\tgetNthRenderedItemHeight(renderedElementIndex) {\r\n\t\tconst children = this.getElement().children\r\n\r\n\t\tif (renderedElementIndex > children.length - 1) {\r\n\t\t\tthrow new ItemNotRenderedError({\r\n\t\t\t\trenderedElementIndex,\r\n\t\t\t\trenderedElementsCount: children.length\r\n\t\t\t})\r\n\t\t}\r\n\r\n\t\treturn children[renderedElementIndex].height\r\n\t}\r\n\r\n\t/**\r\n\t * Returns items container height.\r\n\t * @return {number}\r\n\t */\r\n\tgetHeight() {\r\n\t\tconst children = this.getElement().children\r\n\t\tconst maxWidth = this.getElement().width\r\n\t\tlet contentHeight = this.getElement().paddingTop\r\n\t\tlet i = 0\r\n\t\twhile (i < children.length) {\r\n\t\t\tlet rowWidth = 0\r\n\t\t\tlet rowHeight = 0\r\n\t\t\twhile (rowWidth <= maxWidth && i < children.length) {\r\n\t\t\t\tif (rowWidth === 0 && i > 0) {\r\n\t\t\t\t\tconst verticalSpacing = children[i].marginTop\r\n\t\t\t\t\tcontentHeight += verticalSpacing\r\n\t\t\t\t}\r\n\t\t\t\trowWidth += children[i].width\r\n\t\t\t\trowHeight = Math.max(rowHeight, children[i].height)\r\n\t\t\t\ti++\r\n\t\t\t}\r\n\t\t\tcontentHeight += rowHeight\r\n\t\t}\r\n\t\tcontentHeight += this.getElement().paddingBottom\r\n\t\treturn contentHeight\r\n\t}\r\n\r\n\t/**\r\n\t * Removes all item elements of an items container.\r\n\t */\r\n\tclear() {\r\n\t\tthis.getElement().children = []\r\n\t}\r\n}"],"mappings":";;;;;;;AAAA;;;;;;;;;;IAEqBA,c;EACpB;AACD;AACA;AACA;EACC,wBAAYC,UAAZ,EAAwB;IAAA;;IACvB,KAAKA,UAAL,GAAkBA,UAAlB;EACA;EAED;AACD;AACA;AACA;AACA;;;;;WACC,qCAA4BC,oBAA5B,EAAkD;MACjD,IAAMC,QAAQ,GAAG,KAAKF,UAAL,GAAkBE,QAAnC;MACA,IAAMC,QAAQ,GAAG,KAAKH,UAAL,GAAkBI,KAAnC;MACA,IAAIC,SAAS,GAAG,KAAKL,UAAL,GAAkBM,UAAlC;MAEA,IAAIC,QAAJ;MACA,IAAIC,SAAJ;MACA,IAAIC,WAAW,GAAG,IAAlB;;MAEA,IAAIR,oBAAoB,GAAGC,QAAQ,CAACQ,MAAT,GAAkB,CAA7C,EAAgD;QAC/C,MAAM,IAAIC,gCAAJ,CAAyB;UAC9BV,oBAAoB,EAApBA,oBAD8B;UAE9BW,qBAAqB,EAAEV,QAAQ,CAACQ;QAFF,CAAzB,CAAN;MAIA;;MAED,IAAIG,CAAC,GAAG,CAAR;;MACA,OAAOA,CAAC,IAAIZ,oBAAZ,EAAkC;QACjC,IAAIQ,WAAW,IAAIF,QAAQ,GAAGL,QAAQ,CAACW,CAAD,CAAR,CAAYT,KAAvB,GAA+BD,QAAlD,EAA4D;UAC3D,IAAIU,CAAC,GAAG,CAAR,EAAW;YACVR,SAAS,IAAIG,SAAb;YACAH,SAAS,IAAIH,QAAQ,CAACW,CAAD,CAAR,CAAYC,SAAzB;UACA;;UACDP,QAAQ,GAAGL,QAAQ,CAACW,CAAD,CAAR,CAAYT,KAAvB;UACAI,SAAS,GAAGN,QAAQ,CAACW,CAAD,CAAR,CAAYE,MAAxB;;UACA,IAAIR,QAAQ,GAAGJ,QAAf,EAAyB;YACxBM,WAAW,GAAG,IAAd;UACA,CAFD,MAEO;YACNA,WAAW,GAAG,KAAd;UACA;QACD,CAZD,MAYO;UACNF,QAAQ,IAAIL,QAAQ,CAACW,CAAD,CAAR,CAAYT,KAAxB;UACAI,SAAS,GAAGQ,IAAI,CAACC,GAAL,CAAST,SAAT,EAAoBN,QAAQ,CAACW,CAAD,CAAR,CAAYE,MAAhC,CAAZ;QACA;;QACDF,CAAC;MACD;;MAED,OAAOR,SAAP;IACA;IAED;AACD;AACA;AACA;AACA;;;;WACC,kCAAyBJ,oBAAzB,EAA+C;MAC9C,IAAMC,QAAQ,GAAG,KAAKF,UAAL,GAAkBE,QAAnC;;MAEA,IAAID,oBAAoB,GAAGC,QAAQ,CAACQ,MAAT,GAAkB,CAA7C,EAAgD;QAC/C,MAAM,IAAIC,gCAAJ,CAAyB;UAC9BV,oBAAoB,EAApBA,oBAD8B;UAE9BW,qBAAqB,EAAEV,QAAQ,CAACQ;QAFF,CAAzB,CAAN;MAIA;;MAED,OAAOR,QAAQ,CAACD,oBAAD,CAAR,CAA+Bc,MAAtC;IACA;IAED;AACD;AACA;AACA;;;;WACC,qBAAY;MACX,IAAMb,QAAQ,GAAG,KAAKF,UAAL,GAAkBE,QAAnC;MACA,IAAMC,QAAQ,GAAG,KAAKH,UAAL,GAAkBI,KAAnC;MACA,IAAIc,aAAa,GAAG,KAAKlB,UAAL,GAAkBM,UAAtC;MACA,IAAIO,CAAC,GAAG,CAAR;;MACA,OAAOA,CAAC,GAAGX,QAAQ,CAACQ,MAApB,EAA4B;QAC3B,IAAIH,QAAQ,GAAG,CAAf;QACA,IAAIC,SAAS,GAAG,CAAhB;;QACA,OAAOD,QAAQ,IAAIJ,QAAZ,IAAwBU,CAAC,GAAGX,QAAQ,CAACQ,MAA5C,EAAoD;UACnD,IAAIH,QAAQ,KAAK,CAAb,IAAkBM,CAAC,GAAG,CAA1B,EAA6B;YAC5B,IAAMM,eAAe,GAAGjB,QAAQ,CAACW,CAAD,CAAR,CAAYC,SAApC;YACAI,aAAa,IAAIC,eAAjB;UACA;;UACDZ,QAAQ,IAAIL,QAAQ,CAACW,CAAD,CAAR,CAAYT,KAAxB;UACAI,SAAS,GAAGQ,IAAI,CAACC,GAAL,CAAST,SAAT,EAAoBN,QAAQ,CAACW,CAAD,CAAR,CAAYE,MAAhC,CAAZ;UACAF,CAAC;QACD;;QACDK,aAAa,IAAIV,SAAjB;MACA;;MACDU,aAAa,IAAI,KAAKlB,UAAL,GAAkBoB,aAAnC;MACA,OAAOF,aAAP;IACA;IAED;AACD;AACA;;;;WACC,iBAAQ;MACP,KAAKlB,UAAL,GAAkBE,QAAlB,GAA6B,EAA7B;IACA"}
|
|
@@ -49,16 +49,30 @@ function warn() {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
function
|
|
52
|
+
function error() {
|
|
53
|
+
var _console3;
|
|
54
|
+
|
|
53
55
|
for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
|
|
54
56
|
args[_key3] = arguments[_key3];
|
|
55
57
|
}
|
|
56
58
|
|
|
59
|
+
(_console3 = console).error.apply(_console3, _toConsumableArray(['[virtual-scroller]'].concat(args)));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function reportError() {
|
|
63
|
+
for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
|
|
64
|
+
args[_key4] = arguments[_key4];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
var createError = function createError() {
|
|
68
|
+
return new Error(['[virtual-scroller]'].concat(args).join(' '));
|
|
69
|
+
};
|
|
70
|
+
|
|
57
71
|
if (typeof window !== 'undefined') {
|
|
58
72
|
// In a web browser.
|
|
59
73
|
// Output a debug message immediately so that it's known
|
|
60
74
|
// at which point did the error occur between other debug logs.
|
|
61
|
-
|
|
75
|
+
error.apply(this, ['ERROR'].concat(args));
|
|
62
76
|
setTimeout(function () {
|
|
63
77
|
// Throw an error in a timeout so that it doesn't interrupt the application's flow.
|
|
64
78
|
// At the same time, by throwing a client-side error, such error could be spotted
|
|
@@ -66,13 +80,23 @@ function reportError() {
|
|
|
66
80
|
// in the console.
|
|
67
81
|
// The `.join(' ')` part doesn't support stringifying JSON objects,
|
|
68
82
|
// but those don't seem to be used in any of the error messages.
|
|
69
|
-
throw
|
|
83
|
+
throw createError();
|
|
70
84
|
}, 0);
|
|
71
85
|
} else {
|
|
72
|
-
|
|
86
|
+
// In Node.js.
|
|
87
|
+
// If tests are being run, throw in case of any errors.
|
|
88
|
+
var catchError = getGlobalVariable('VirtualScrollerCatchError');
|
|
89
|
+
|
|
90
|
+
if (catchError) {
|
|
91
|
+
return catchError(createError());
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (getGlobalVariable('VirtualScrollerThrowErrors')) {
|
|
95
|
+
throw createError();
|
|
96
|
+
} // Print the error in the console.
|
|
97
|
+
|
|
73
98
|
|
|
74
|
-
|
|
75
|
-
(_console3 = console).error.apply(_console3, _toConsumableArray(['[virtual-scroller]'].concat(args)));
|
|
99
|
+
error.apply(this, ['ERROR'].concat(args));
|
|
76
100
|
}
|
|
77
101
|
}
|
|
78
102
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debug.js","names":["log","isDebug","args","console","concat","warn","isWarn","warningsAreErrors","reportError","apply","
|
|
1
|
+
{"version":3,"file":"debug.js","names":["log","isDebug","args","console","concat","warn","isWarn","warningsAreErrors","reportError","apply","error","createError","Error","join","window","setTimeout","catchError","getGlobalVariable","debug","getDebug","undefined","name","global"],"sources":["../../source/utility/debug.js"],"sourcesContent":["export default function log(...args) {\r\n\tif (isDebug()) {\r\n\t\tconsole.log(...['[virtual-scroller]'].concat(args))\r\n\t}\r\n}\r\n\r\nexport function warn(...args) {\r\n\tif (isWarn()) {\r\n\t\tif (warningsAreErrors()) {\r\n\t\t\treturn reportError.apply(this, args)\r\n\t\t}\r\n\t\tconsole.warn(...['[virtual-scroller]'].concat(args))\r\n\t}\r\n}\r\n\r\nfunction error(...args) {\r\n\tconsole.error(...['[virtual-scroller]'].concat(args))\r\n}\r\n\r\nexport function reportError(...args) {\r\n\tconst createError = () => new Error(['[virtual-scroller]'].concat(args).join(' '))\r\n\tif (typeof window !== 'undefined') {\r\n\t\t// In a web browser.\r\n\t\t// Output a debug message immediately so that it's known\r\n\t\t// at which point did the error occur between other debug logs.\r\n\t\terror.apply(this, ['ERROR'].concat(args))\r\n\t\tsetTimeout(() => {\r\n\t\t\t// Throw an error in a timeout so that it doesn't interrupt the application's flow.\r\n\t\t\t// At the same time, by throwing a client-side error, such error could be spotted\r\n\t\t\t// in some error monitoring software like `sentry.io`, while also being visible\r\n\t\t\t// in the console.\r\n\t\t\t// The `.join(' ')` part doesn't support stringifying JSON objects,\r\n\t\t\t// but those don't seem to be used in any of the error messages.\r\n\t\t\tthrow createError()\r\n\t\t}, 0)\r\n\t} else {\r\n\t\t// In Node.js.\r\n\t\t// If tests are being run, throw in case of any errors.\r\n\t\tconst catchError = getGlobalVariable('VirtualScrollerCatchError')\r\n\t\tif (catchError) {\r\n\t\t\treturn catchError(createError())\r\n\t\t}\r\n\t\tif (getGlobalVariable('VirtualScrollerThrowErrors')) {\r\n\t\t\tthrow createError()\r\n\t\t}\r\n\t\t// Print the error in the console.\r\n\t\terror.apply(this, ['ERROR'].concat(args))\r\n\t}\r\n}\r\n\r\nexport function isDebug() {\r\n\tconst debug = getDebug()\r\n\tif (debug !== undefined) {\r\n\t\treturn debug === true || debug === 'debug'\r\n\t}\r\n}\r\n\r\nexport function isWarn() {\r\n\t// const debug = getDebug()\r\n\t// return debug === undefined\r\n\t// \t|| debug === true\r\n\t// \t|| debug === 'debug'\r\n\t// \t|| debug === 'warn'\r\n\t//\r\n\treturn true\r\n}\r\n\r\nfunction getDebug() {\r\n\treturn getGlobalVariable('VirtualScrollerDebug')\r\n}\r\n\r\nfunction warningsAreErrors() {\r\n\treturn getGlobalVariable('VirtualScrollerWarningsAreErrors')\r\n}\r\n\r\nfunction getGlobalVariable(name) {\r\n\tif (typeof window !== 'undefined') {\r\n\t\treturn window[name]\r\n\t} else if (typeof global !== 'undefined') {\r\n\t\treturn global[name]\r\n\t}\r\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAe,SAASA,GAAT,GAAsB;EACpC,IAAIC,OAAO,EAAX,EAAe;IAAA;;IAAA,kCADeC,IACf;MADeA,IACf;IAAA;;IACd,YAAAC,OAAO,EAACH,GAAR,oCAAe,CAAC,oBAAD,EAAuBI,MAAvB,CAA8BF,IAA9B,CAAf;EACA;AACD;;AAEM,SAASG,IAAT,GAAuB;EAC7B,IAAIC,MAAM,EAAV,EAAc;IAAA;;IAAA,mCADSJ,IACT;MADSA,IACT;IAAA;;IACb,IAAIK,iBAAiB,EAArB,EAAyB;MACxB,OAAOC,WAAW,CAACC,KAAZ,CAAkB,IAAlB,EAAwBP,IAAxB,CAAP;IACA;;IACD,aAAAC,OAAO,EAACE,IAAR,qCAAgB,CAAC,oBAAD,EAAuBD,MAAvB,CAA8BF,IAA9B,CAAhB;EACA;AACD;;AAED,SAASQ,KAAT,GAAwB;EAAA;;EAAA,mCAANR,IAAM;IAANA,IAAM;EAAA;;EACvB,aAAAC,OAAO,EAACO,KAAR,qCAAiB,CAAC,oBAAD,EAAuBN,MAAvB,CAA8BF,IAA9B,CAAjB;AACA;;AAEM,SAASM,WAAT,GAA8B;EAAA,mCAANN,IAAM;IAANA,IAAM;EAAA;;EACpC,IAAMS,WAAW,GAAG,SAAdA,WAAc;IAAA,OAAM,IAAIC,KAAJ,CAAU,CAAC,oBAAD,EAAuBR,MAAvB,CAA8BF,IAA9B,EAAoCW,IAApC,CAAyC,GAAzC,CAAV,CAAN;EAAA,CAApB;;EACA,IAAI,OAAOC,MAAP,KAAkB,WAAtB,EAAmC;IAClC;IACA;IACA;IACAJ,KAAK,CAACD,KAAN,CAAY,IAAZ,EAAkB,CAAC,OAAD,EAAUL,MAAV,CAAiBF,IAAjB,CAAlB;IACAa,UAAU,CAAC,YAAM;MAChB;MACA;MACA;MACA;MACA;MACA;MACA,MAAMJ,WAAW,EAAjB;IACA,CARS,EAQP,CARO,CAAV;EASA,CAdD,MAcO;IACN;IACA;IACA,IAAMK,UAAU,GAAGC,iBAAiB,CAAC,2BAAD,CAApC;;IACA,IAAID,UAAJ,EAAgB;MACf,OAAOA,UAAU,CAACL,WAAW,EAAZ,CAAjB;IACA;;IACD,IAAIM,iBAAiB,CAAC,4BAAD,CAArB,EAAqD;MACpD,MAAMN,WAAW,EAAjB;IACA,CATK,CAUN;;;IACAD,KAAK,CAACD,KAAN,CAAY,IAAZ,EAAkB,CAAC,OAAD,EAAUL,MAAV,CAAiBF,IAAjB,CAAlB;EACA;AACD;;AAEM,SAASD,OAAT,GAAmB;EACzB,IAAMiB,KAAK,GAAGC,QAAQ,EAAtB;;EACA,IAAID,KAAK,KAAKE,SAAd,EAAyB;IACxB,OAAOF,KAAK,KAAK,IAAV,IAAkBA,KAAK,KAAK,OAAnC;EACA;AACD;;AAEM,SAASZ,MAAT,GAAkB;EACxB;EACA;EACA;EACA;EACA;EACA;EACA,OAAO,IAAP;AACA;;AAED,SAASa,QAAT,GAAoB;EACnB,OAAOF,iBAAiB,CAAC,sBAAD,CAAxB;AACA;;AAED,SAASV,iBAAT,GAA6B;EAC5B,OAAOU,iBAAiB,CAAC,kCAAD,CAAxB;AACA;;AAED,SAASA,iBAAT,CAA2BI,IAA3B,EAAiC;EAChC,IAAI,OAAOP,MAAP,KAAkB,WAAtB,EAAmC;IAClC,OAAOA,MAAM,CAACO,IAAD,CAAb;EACA,CAFD,MAEO,IAAI,OAAOC,MAAP,KAAkB,WAAtB,EAAmC;IACzC,OAAOA,MAAM,CAACD,IAAD,CAAb;EACA;AACD"}
|
package/dom/index.d.ts
CHANGED
|
@@ -21,6 +21,6 @@ export default class VirtualScroller<Item, ItemState = NoItemState> {
|
|
|
21
21
|
// start(): void;
|
|
22
22
|
stop(): void;
|
|
23
23
|
setItems(newItems: Item[], options?: SetItemsOptions): void;
|
|
24
|
-
|
|
24
|
+
onItemHeightDidChange(i: number): void;
|
|
25
25
|
setItemState(i: number, newState: ItemState): void;
|
|
26
26
|
}
|
package/index.cjs
CHANGED