virtual-scroller 1.11.3 → 1.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/README.md +6 -4
  2. package/bundle/virtual-scroller-dom.js +1 -1
  3. package/bundle/virtual-scroller-dom.js.map +1 -1
  4. package/bundle/virtual-scroller-react.js +1 -1
  5. package/bundle/virtual-scroller-react.js.map +1 -1
  6. package/bundle/virtual-scroller.js +1 -1
  7. package/bundle/virtual-scroller.js.map +1 -1
  8. package/commonjs/DOM/ItemsContainer.js +10 -3
  9. package/commonjs/DOM/ItemsContainer.js.map +1 -1
  10. package/commonjs/ItemNotRenderedError.js +64 -0
  11. package/commonjs/ItemNotRenderedError.js.map +1 -0
  12. package/commonjs/Layout.test.js +10 -0
  13. package/commonjs/Layout.test.js.map +1 -1
  14. package/commonjs/VirtualScroller.js +2 -1
  15. package/commonjs/VirtualScroller.js.map +1 -1
  16. package/commonjs/VirtualScroller.layout.js +61 -19
  17. package/commonjs/VirtualScroller.layout.js.map +1 -1
  18. package/commonjs/VirtualScroller.onRender.js +97 -45
  19. package/commonjs/VirtualScroller.onRender.js.map +1 -1
  20. package/commonjs/VirtualScroller.state.js +50 -18
  21. package/commonjs/VirtualScroller.state.js.map +1 -1
  22. package/commonjs/react/VirtualScroller.js +26 -42
  23. package/commonjs/react/VirtualScroller.js.map +1 -1
  24. package/commonjs/react/useItemKeys.js +11 -3
  25. package/commonjs/react/useItemKeys.js.map +1 -1
  26. package/commonjs/react/useOnChange.js +19 -0
  27. package/commonjs/react/useOnChange.js.map +1 -0
  28. package/commonjs/react/{useHandleItemsPropertyChange.js → useSetNewItemsOnItemsPropertyChange.js} +15 -14
  29. package/commonjs/react/useSetNewItemsOnItemsPropertyChange.js.map +1 -0
  30. package/commonjs/react/useState.js +162 -69
  31. package/commonjs/react/useState.js.map +1 -1
  32. package/commonjs/react/useStyle.js +3 -5
  33. package/commonjs/react/useStyle.js.map +1 -1
  34. package/commonjs/react/useUpdateItemKeysOnItemsChange.js +61 -0
  35. package/commonjs/react/useUpdateItemKeysOnItemsChange.js.map +1 -0
  36. package/commonjs/test/ItemsContainer.js +22 -1
  37. package/commonjs/test/ItemsContainer.js.map +1 -1
  38. package/commonjs/utility/debug.js +30 -6
  39. package/commonjs/utility/debug.js.map +1 -1
  40. package/index.cjs +2 -0
  41. package/index.d.ts +6 -0
  42. package/index.js +1 -0
  43. package/modules/DOM/ItemsContainer.js +8 -3
  44. package/modules/DOM/ItemsContainer.js.map +1 -1
  45. package/modules/ItemNotRenderedError.js +57 -0
  46. package/modules/ItemNotRenderedError.js.map +1 -0
  47. package/modules/Layout.test.js +10 -0
  48. package/modules/Layout.test.js.map +1 -1
  49. package/modules/VirtualScroller.js +2 -1
  50. package/modules/VirtualScroller.js.map +1 -1
  51. package/modules/VirtualScroller.layout.js +58 -19
  52. package/modules/VirtualScroller.layout.js.map +1 -1
  53. package/modules/VirtualScroller.onRender.js +98 -46
  54. package/modules/VirtualScroller.onRender.js.map +1 -1
  55. package/modules/VirtualScroller.state.js +50 -18
  56. package/modules/VirtualScroller.state.js.map +1 -1
  57. package/modules/react/VirtualScroller.js +26 -42
  58. package/modules/react/VirtualScroller.js.map +1 -1
  59. package/modules/react/useItemKeys.js +8 -3
  60. package/modules/react/useItemKeys.js.map +1 -1
  61. package/modules/react/useOnChange.js +11 -0
  62. package/modules/react/useOnChange.js.map +1 -0
  63. package/modules/react/{useHandleItemsPropertyChange.js → useSetNewItemsOnItemsPropertyChange.js} +11 -13
  64. package/modules/react/useSetNewItemsOnItemsPropertyChange.js.map +1 -0
  65. package/modules/react/useState.js +156 -73
  66. package/modules/react/useState.js.map +1 -1
  67. package/modules/react/useStyle.js +3 -5
  68. package/modules/react/useStyle.js.map +1 -1
  69. package/{commonjs/react/useHandleItemIndexesChange.js → modules/react/useUpdateItemKeysOnItemsChange.js} +18 -21
  70. package/modules/react/useUpdateItemKeysOnItemsChange.js.map +1 -0
  71. package/modules/test/ItemsContainer.js +20 -1
  72. package/modules/test/ItemsContainer.js.map +1 -1
  73. package/modules/utility/debug.js +31 -6
  74. package/modules/utility/debug.js.map +1 -1
  75. package/package.json +1 -1
  76. package/source/DOM/ItemsContainer.js +8 -3
  77. package/source/ItemNotRenderedError.js +16 -0
  78. package/source/Layout.test.js +9 -0
  79. package/source/VirtualScroller.js +2 -0
  80. package/source/VirtualScroller.layout.js +57 -18
  81. package/source/VirtualScroller.onRender.js +95 -42
  82. package/source/VirtualScroller.state.js +57 -20
  83. package/source/react/VirtualScroller.js +23 -35
  84. package/source/react/useItemKeys.js +9 -2
  85. package/source/react/useOnChange.js +11 -0
  86. package/source/react/{useHandleItemsPropertyChange.js → useSetNewItemsOnItemsPropertyChange.js} +11 -11
  87. package/source/react/useState.js +159 -71
  88. package/source/react/useStyle.js +2 -2
  89. package/source/react/{useHandleItemIndexesChange.js → useUpdateItemKeysOnItemsChange.js} +17 -9
  90. package/source/test/ItemsContainer.js +22 -1
  91. package/source/utility/debug.js +18 -4
  92. package/commonjs/react/useHandleItemIndexesChange.js.map +0 -1
  93. package/commonjs/react/useHandleItemsPropertyChange.js.map +0 -1
  94. package/modules/react/useHandleItemIndexesChange.js +0 -45
  95. package/modules/react/useHandleItemIndexesChange.js.map +0 -1
  96. package/modules/react/useHandleItemsPropertyChange.js.map +0 -1
@@ -1,9 +1,3 @@
1
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
2
-
3
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
4
-
5
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6
-
7
1
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
8
2
 
9
3
  function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
@@ -16,21 +10,20 @@ function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Sy
16
10
 
17
11
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
18
12
 
19
- import { useState, useRef, useCallback, useLayoutEffect } from 'react'; // Creates state management functions.
13
+ import log, { isDebug } from '../utility/debug.js';
14
+ import getStateSnapshot from '../utility/getStateSnapshot.js';
15
+ import { useState, useRef, useCallback, useLayoutEffect, useInsertionEffect } from 'react'; // Creates state management functions.
20
16
 
21
17
  export default function _useState(_ref) {
22
18
  var initialState = _ref.initialState,
23
19
  onRender = _ref.onRender,
24
- itemsProperty = _ref.itemsProperty,
25
- USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION = _ref.USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION;
20
+ itemsProperty = _ref.itemsProperty;
26
21
 
27
- // This is a utility state variable that is used to re-render the component.
28
- // It should not be used to access the current `VirtualScroller` state.
29
- // It's more of a "requested" `VirtualScroller` state.
30
- //
31
- // It will also be stale in cases when `USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION`
32
- // feature is used for setting new `items` in state.
33
- //
22
+ // This is a state variable that is used to re-render the component.
23
+ // Right after the component has finished re-rendering,
24
+ // `VirtualScroller` state gets updated from this variable.
25
+ // The reason for that is that `VirtualScroller` state must always
26
+ // correspond exactly to what's currently rendered on the screen.
34
27
  var _useState2 = useState(initialState),
35
28
  _useState3 = _slicedToArray(_useState2, 2),
36
29
  _newState = _useState3[0],
@@ -39,72 +32,162 @@ export default function _useState(_ref) {
39
32
 
40
33
 
41
34
  var state = useRef(initialState);
35
+ var getState = useCallback(function () {
36
+ return state.current;
37
+ }, []);
42
38
  var setState = useCallback(function (newState) {
43
39
  state.current = newState;
44
- }, []); // Accumulates all "pending" state updates until they have been applied.
40
+ }, []); // Updating of the actual `VirtualScroller` state is done in a
41
+ // `useInsertionEffect()` rather than in a `useLayoutEffect()`.
42
+ //
43
+ // The reason is that using `useLayoutEffect()` would result in
44
+ // "breaking" the `<VirtualScroller/>` when an `itemComponent`
45
+ // called `onHeightDidChange()` from its own `useLayoutEffect()`.
46
+ // In those cases, the `itemCompoent`'s effect would run before
47
+ // the `<VirtualScroller/>`'s effect, resulting in
48
+ // `VirtualScroller.onItemHeightDidChange(i)` being run at a moment in time
49
+ // when the DOM has already been updated for the next `VirtualScroller` state
50
+ // but the actual `VirtualScroller` state is still a previous ("stale") one
51
+ // containing "stale" first/last shown item indexes, which would result in an
52
+ // "index out of bounds" error when `onItemHeightDidChange(i)` tries to access
53
+ // and measure the DOM element from item index `i` which doesn't already/yet exist.
54
+ //
55
+ // An example of such situation could be seen from a `VirtualScroller` debug log
56
+ // which was captured for a case when using `useLayoutEffect()` to update the
57
+ // "actual" `VirtualScroller` state after the corresponding DOM changes have been applied:
58
+ // The user has scrolled far enough: perform a re-layout
59
+ // ~ Update Layout (on scroll) ~
60
+ //
61
+ // 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.
62
+ //
63
+ // ~ Calculated Layout ~
64
+ // Columns count 1
65
+ // First shown item index 2
66
+ // Last shown item index 5
67
+ // …
68
+ // Item heights (231) [1056.578125, 783.125, empty × 229]
69
+ // Item states (231) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, …]
70
+ //
71
+ // ~ Set state ~
72
+ // {firstShownItemIndex: 2, lastShownItemIndex: 5, …}
73
+ //
74
+ // ~ Rendered ~
75
+ // State {firstShownItemIndex: 2, lastShownItemIndex: 5, …}
76
+ //
77
+ // ~ Measure item heights ~
78
+ // Item index 2 height 719.8828125
79
+ // Item index 3 height 961.640625
80
+ // Item index 4 height 677.6640625
81
+ // Item index 5 height 1510.1953125
82
+ //
83
+ // ~ Update Layout (on non-measured item heights have been measured) ~
84
+ //
85
+ // ~ Calculated Layout ~
86
+ // Columns count 1
87
+ // First shown item index 4
88
+ // Last shown item index 5
89
+ // …
90
+ // Item heights (231) [1056.578125, 783.125, 719.8828125, 961.640625, 677.6640625, 1510.1953125, empty × 225]
91
+ // Item states (231) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, …]
92
+ //
93
+ // ~ Set state ~
94
+ // {firstShownItemIndex: 4, lastShownItemIndex: 5, beforeItemsHeight: 3521.2265625, afterItemsHeight: 214090.72265624942}
95
+ //
96
+ // ~ On Item Height Did Change was called ~
97
+ // Item index 5
98
+ // ~ Re-measure item height ~
99
+ // 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.
100
+ //
101
+ // React: ~ The requested state is about to be applied in DOM. Set it as the `VirtualScroller` state. ~
102
+ // {firstShownItemIndex: 4, lastShownItemIndex: 5, …}
103
+ //
104
+ // ~ Rendered ~
105
+ // "~ Rendered ~" is what gets output when `onRender()` function gets called.
106
+ // It means that `useLayoutEffect()` was triggered after `onItemHeightDidChange(i)`
107
+ // was called and after the "ERROR" happened.
108
+ //
109
+ // The "ERROR" happened because new item indexes 4…5 were actually rendered instead of
110
+ // item indexes 2…5 by the time the application called `onItemHeightDidChange(i)` function
111
+ // inside `itemComponent`'s `useLayoutEffect()`.
112
+ // Item indexes 4…5 is what was requested in a `setState()` call, which called `_setNewState()`.
113
+ // This means that `_newState` changes have been applied to the DOM
114
+ // but `useLayoutEffect()` wasn't triggered immediately after that.
115
+ // Instead, it was triggered a right after the `itemComponent`'s `useLayoutEffect()`
116
+ // because child effects run before parent effects.
117
+ // So, the `itemComponent`'s `onHeightDidChange()` function call caught the
118
+ // `VirtualScroller` in an inconsistent state.
119
+ //
120
+ // To fix that, `useLayoutEffect()` gets replaced with `useInsertionEffect()`:
121
+ // https://blog.saeloun.com/2022/06/02/react-18-useinsertioneffect
122
+ // https://beta.reactjs.org/reference/react/useInsertionEffect
123
+ //
124
+ // After replacing `useLayoutEffect()` with `useInsertionEffect()`,
125
+ // the log shows that there's no more error:
126
+ //
127
+ // ~ Set state ~
128
+ // {firstShownItemIndex: 0, lastShownItemIndex: 2, …}
129
+ //
130
+ // React: ~ The requested state is about to be applied in DOM. Set it as the `VirtualScroller` state. ~
131
+ // {firstShownItemIndex: 0, lastShownItemIndex: 2, …}
132
+ //
133
+ // ~ On Item Height Did Change was called ~
134
+ // Item index 0
135
+ // ~ Re-measure item height ~
136
+ // Previous height 917
137
+ // New height 1064.453125
138
+ // ~ Item height has changed ~
139
+ //
140
+ // An alternative solution would be demanding the `itemComponent` to
141
+ // accept a `ref` and then measuring the corresponding DOM element height
142
+ // directly using the `ref`-ed DOM element rather than searching for that
143
+ // DOM element in the `ItemsContainer`.
144
+ // So if `useInsertionEffect()` gets removed from React in some hypothetical future,
145
+ // it could be replaced with using `ref`s on `ItemComponent`s to measure the DOM element heights.
146
+ //
45
147
 
46
- var nextState = useRef(initialState); // Updates the actual `VirtualScroller` state right after a requested state update
47
- // has been applied. Doesn't do anything at initial render.
148
+ useInsertionEffect(function () {
149
+ // Update the actual `VirtualScroller` state right before the DOM changes
150
+ // are going to be applied for the requested state update.
151
+ //
152
+ // This hook will run right before `useLayoutEffect()`.
153
+ //
154
+ // It doesn't make any difference which one of the two hooks to use to update
155
+ // the actual `VirtualScroller` state in this scenario because the two hooks
156
+ // run synchronously one right after another (insertion effect → DOM update → layout effect)
157
+ // without any free space for any `VirtualScroller` code (like the scroll event handler)
158
+ // to squeeze in and run in-between them, so the `VirtualScroller`'s `state`
159
+ // is always gonna stay consistent with what's currently rendered on screen
160
+ // from the `VirtualScroler`'s point of view, and the short transition period
161
+ // it simply doesn't see because it doesn't "wake up" during that period.
162
+ //
163
+ // Updating the actual `VirtualScroller` state right before `useLayoutEffect()`
164
+ // fixes the bug when an `itemComponent` calls `onHeightDidChange()` in its own
165
+ // `useLayoutEffect()` which would run before this `useLayoutEffect()`
166
+ // because children's effects run before parent's.
167
+ //
168
+ // This hook doesn't do anything at the initial render.
169
+ //
170
+ if (isDebug()) {
171
+ log('React: ~ The requested state is about to be applied in DOM. Set it as the `VirtualScroller` state. ~');
172
+ log(getStateSnapshot(_newState));
173
+ }
48
174
 
49
- useLayoutEffect(function () {
50
175
  setState(_newState);
51
- }, [_newState]); // Calls `onRender()` right after every state update (which is a re-render),
52
- // and also right after the initial render.
53
-
176
+ }, [_newState]);
54
177
  useLayoutEffect(function () {
178
+ // Call `onRender()` right after a requested state update has been applied,
179
+ // and also right after the initial render.
55
180
  onRender();
56
- }, [_newState, // When using `USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION` feature,
57
- // there won't be a `_setNewState()` function call when `items` property changes,
58
- // hence the additional `itemsProperty` dependency.
59
- USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION ? itemsProperty : undefined]);
181
+ }, [_newState]);
60
182
  return {
61
- getState: function getState() {
62
- return state.current;
63
- },
64
- getNextState: function getNextState() {
65
- return nextState.current;
66
- },
183
+ // This is the state the component should render.
184
+ stateToRender: _newState,
185
+ // Returns the current state of the `VirtualScroller`.
186
+ // This function is used in the `VirtualScroller` itself
187
+ // because the `state` is managed outside of it.
188
+ getState: getState,
67
189
  // Requests a state update.
68
- //
69
- // State updates are incremental meaning that this function mimicks
70
- // the classic `React.Component`'s `this.setState()` behavior
71
- // when calling `this.setState()` didn't replace `state` but rather merged
72
- // the updated state properties over the "old" state properties.
73
- //
74
- // The reason for using pending state updates accumulation is that
75
- // `useState()` updates are "asynchronous" (not immediate),
76
- // and simply merging over `...state` would merge over potentially stale
77
- // property values in cases when more than a single `updateState()` call is made
78
- // before the state actually updates, resulting in losing some of those state updates.
79
- //
80
- // Example: the first `updateState()` call updates shown item indexes,
81
- // and the second `updateState()` call updates `verticalSpacing`.
82
- // If it was simply `updateState({ ...state, ...stateUpdate })`
83
- // then the second state update could overwrite the first state update,
84
- // resulting in incorrect items being shown/hidden.
85
- //
86
- updateState: function updateState(stateUpdate) {
87
- nextState.current = _objectSpread(_objectSpread({}, nextState.current), stateUpdate); // If `items` property did change, the component detects it at render time
88
- // and updates `VirtualScroller` items immediately by calling `.setItems()`,
89
- // which, in turn, immediately calls this `updateState()` function
90
- // with a `stateUpdate` argument that contains the new `items`,
91
- // so checking for `stateUpdate.items` could detect situations like that.
92
- //
93
- // When the initial `VirtualScroller` state is being set, it contains the `.items`
94
- // property too, but that initial setting is done using another function called
95
- // `setInitialState()`, so using `if (stateUpdate.items)` condition here for describing
96
- // just the case when `state` has been updated as a result of a `setItems()` call
97
- // seems to be fine.
98
- //
99
-
100
- var _newState = nextState.current;
101
-
102
- if (stateUpdate.items && USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION) {
103
- setState(_newState);
104
- } else {
105
- _setNewState(_newState);
106
- }
107
- }
190
+ setState: _setNewState
108
191
  };
109
192
  }
110
193
  //# sourceMappingURL=useState.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useState.js","names":["useState","useRef","useCallback","useLayoutEffect","_useState","initialState","onRender","itemsProperty","USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION","_newState","_setNewState","state","setState","newState","current","nextState","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,SAASA,QAAT,EAAmBC,MAAnB,EAA2BC,WAA3B,EAAwCC,eAAxC,QAA+D,OAA/D,C,CAEA;;AACA,eAAe,SAASC,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,iBAAkCR,QAAQ,CAACK,YAAD,CAA1C;EAAA;EAAA,IAAOI,SAAP;EAAA,IAAkBC,YAAlB,iBARE,CAUF;EACA;;;EACA,IAAMC,KAAK,GAAGV,MAAM,CAACI,YAAD,CAApB;EAEA,IAAMO,QAAQ,GAAGV,WAAW,CAAC,UAACW,QAAD,EAAc;IAC1CF,KAAK,CAACG,OAAN,GAAgBD,QAAhB;EACA,CAF2B,EAEzB,EAFyB,CAA5B,CAdE,CAkBF;;EACA,IAAME,SAAS,GAAGd,MAAM,CAACI,YAAD,CAAxB,CAnBE,CAqBF;EACA;;EACAF,eAAe,CAAC,YAAM;IACrBS,QAAQ,CAACH,SAAD,CAAR;EACA,CAFc,EAEZ,CACFA,SADE,CAFY,CAAf,CAvBE,CA6BF;EACA;;EACAN,eAAe,CAAC,YAAM;IACrBG,QAAQ;EACR,CAFc,EAEZ,CACFG,SADE,EAEF;EACA;EACA;EACAD,8CAA8C,GAAGD,aAAH,GAAmBS,SAL/D,CAFY,CAAf;EAUA,OAAO;IACNC,QAAQ,EAAE;MAAA,OAAMN,KAAK,CAACG,OAAZ;IAAA,CADJ;IAGNI,YAAY,EAAE;MAAA,OAAMH,SAAS,CAACD,OAAhB;IAAA,CAHR;IAKN;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACAK,WAAW,EAAE,qBAACC,WAAD,EAAiB;MAC7BL,SAAS,CAACD,OAAV,mCACIC,SAAS,CAACD,OADd,GAEIM,WAFJ,EAD6B,CAK7B;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;;MACA,IAAMX,SAAS,GAAGM,SAAS,CAACD,OAA5B;;MACA,IAAIM,WAAW,CAACC,KAAZ,IAAqBb,8CAAzB,EAAyE;QACxEI,QAAQ,CAACH,SAAD,CAAR;MACA,CAFD,MAEO;QACNC,YAAY,CAACD,SAAD,CAAZ;MACA;IACD;EA/CK,CAAP;AAiDA"}
1
+ {"version":3,"file":"useState.js","names":["log","isDebug","getStateSnapshot","useState","useRef","useCallback","useLayoutEffect","useInsertionEffect","_useState","initialState","onRender","itemsProperty","_newState","_setNewState","state","getState","current","setState","newState","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,OAAOA,GAAP,IAAcC,OAAd,QAA6B,qBAA7B;AACA,OAAOC,gBAAP,MAA6B,gCAA7B;AAEA,SAASC,QAAT,EAAmBC,MAAnB,EAA2BC,WAA3B,EAAwCC,eAAxC,EAAyDC,kBAAzD,QAAmF,OAAnF,C,CAEA;;AACA,eAAe,SAASC,SAAT,OAIZ;EAAA,IAHFC,YAGE,QAHFA,YAGE;EAAA,IAFFC,QAEE,QAFFA,QAEE;EAAA,IADFC,aACE,QADFA,aACE;;EACF;EACA;EACA;EACA;EACA;EACA,iBAAkCR,QAAQ,CAACM,YAAD,CAA1C;EAAA;EAAA,IAAOG,SAAP;EAAA,IAAkBC,YAAlB,iBANE,CAQF;EACA;;;EACA,IAAMC,KAAK,GAAGV,MAAM,CAACK,YAAD,CAApB;EAEA,IAAMM,QAAQ,GAAGV,WAAW,CAAC,YAAM;IAClC,OAAOS,KAAK,CAACE,OAAb;EACA,CAF2B,EAEzB,EAFyB,CAA5B;EAIA,IAAMC,QAAQ,GAAGZ,WAAW,CAAC,UAACa,QAAD,EAAc;IAC1CJ,KAAK,CAACE,OAAN,GAAgBE,QAAhB;EACA,CAF2B,EAEzB,EAFyB,CAA5B,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;;EACAX,kBAAkB,CAAC,YAAM;IACxB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA,IAAIN,OAAO,EAAX,EAAe;MACdD,GAAG,CAAC,sGAAD,CAAH;MACAA,GAAG,CAACE,gBAAgB,CAACU,SAAD,CAAjB,CAAH;IACA;;IACDK,QAAQ,CAACL,SAAD,CAAR;EACA,CA3BiB,EA2Bf,CAACA,SAAD,CA3Be,CAAlB;EA6BAN,eAAe,CAAC,YAAM;IACrB;IACA;IACAI,QAAQ;EACR,CAJc,EAIZ,CAACE,SAAD,CAJY,CAAf;EAMA,OAAO;IACN;IACAO,aAAa,EAAEP,SAFT;IAIN;IACA;IACA;IACAG,QAAQ,EAARA,QAPM;IASN;IACAE,QAAQ,EAAEJ;EAVJ,CAAP;AAYA"}
@@ -1,16 +1,14 @@
1
1
  import px from '../utility/px.js';
2
2
  export default function useStyle(_ref) {
3
3
  var tbody = _ref.tbody,
4
- getNextState = _ref.getNextState;
4
+ state = _ref.state;
5
5
 
6
6
  if (tbody) {
7
7
  return;
8
8
  }
9
9
 
10
- var _getNextState = getNextState(),
11
- beforeItemsHeight = _getNextState.beforeItemsHeight,
12
- afterItemsHeight = _getNextState.afterItemsHeight;
13
-
10
+ var beforeItemsHeight = state.beforeItemsHeight,
11
+ afterItemsHeight = state.afterItemsHeight;
14
12
  return {
15
13
  paddingTop: px(beforeItemsHeight),
16
14
  paddingBottom: px(afterItemsHeight)
@@ -1 +1 @@
1
- {"version":3,"file":"useStyle.js","names":["px","useStyle","tbody","getNextState","beforeItemsHeight","afterItemsHeight","paddingTop","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\tgetNextState\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} = getNextState()\r\n\r\n\treturn {\r\n\t\tpaddingTop: px(beforeItemsHeight),\r\n\t\tpaddingBottom: px(afterItemsHeight)\r\n\t}\r\n}"],"mappings":"AAAA,OAAOA,EAAP,MAAe,kBAAf;AAEA,eAAe,SAASC,QAAT,OAGZ;EAAA,IAFFC,KAEE,QAFFA,KAEE;EAAA,IADFC,YACE,QADFA,YACE;;EACF,IAAID,KAAJ,EAAW;IACV;EACA;;EAED,oBAGIC,YAAY,EAHhB;EAAA,IACCC,iBADD,iBACCA,iBADD;EAAA,IAECC,gBAFD,iBAECA,gBAFD;;EAKA,OAAO;IACNC,UAAU,EAAEN,EAAE,CAACI,iBAAD,CADR;IAENG,aAAa,EAAEP,EAAE,CAACK,gBAAD;EAFX,CAAP;AAIA"}
1
+ {"version":3,"file":"useStyle.js","names":["px","useStyle","tbody","state","beforeItemsHeight","afterItemsHeight","paddingTop","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,OAAOA,EAAP,MAAe,kBAAf;AAEA,eAAe,SAASC,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,EAAEN,EAAE,CAACI,iBAAD,CADR;IAENG,aAAa,EAAEP,EAAE,CAACK,gBAAD;EAFX,CAAP;AAIA"}
@@ -1,13 +1,5 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports["default"] = useHandleItemIndexesChange;
7
-
8
- var _react = require("react");
9
-
10
- // If the order of the `items` changes, or new `items` get prepended resulting in a "shift":
1
+ import log from '../utility/debug.js';
2
+ import useOnChange from './useOnChange.js'; // If the order of the `items` changes, or new `items` get prepended resulting in a "shift":
11
3
  //
12
4
  // * Re-generate the React `key` prefix for item elements
13
5
  // so that all item components are re-rendered for the new `items` list.
@@ -16,16 +8,18 @@ var _react = require("react");
16
8
  // might result in bugs, which React would do with its "re-using" policy
17
9
  // if the unique `key` workaround hasn't been used.
18
10
  //
19
- function useHandleItemIndexesChange(_ref) {
11
+
12
+ export default function useUpdateItemKeysOnItemsChange(itemsBeingRendered, _ref) {
20
13
  var virtualScroller = _ref.virtualScroller,
21
- itemsBeingRendered = _ref.itemsBeingRendered,
14
+ usesAutogeneratedItemKeys = _ref.usesAutogeneratedItemKeys,
22
15
  updateItemKeysForNewItems = _ref.updateItemKeysForNewItems;
23
- var previousItemsBeingRenderedRef = (0, _react.useRef)(itemsBeingRendered);
24
- var previousItemsBeingRendered = previousItemsBeingRenderedRef.current;
25
- var haveItemsChanged = itemsBeingRendered !== previousItemsBeingRendered;
26
- previousItemsBeingRenderedRef.current = itemsBeingRendered;
16
+ // Update item keys if the items being rendered have changed.
17
+ useOnChange(itemsBeingRendered, function (itemsBeingRendered, previousItemsBeingRendered) {
18
+ if (!usesAutogeneratedItemKeys) {
19
+ return;
20
+ }
27
21
 
28
- if (haveItemsChanged) {
22
+ log('React: ~ Different `items` are about to be rendered', itemsBeingRendered);
29
23
  var shouldUpdateItemKeys = true;
30
24
  var itemsDiff = virtualScroller.getItemsDiff(previousItemsBeingRendered, itemsBeingRendered); // `itemsDiff` will be `undefined` in case of a non-incremental items list change.
31
25
 
@@ -34,20 +28,23 @@ function useHandleItemIndexesChange(_ref) {
34
28
  appendedItemsCount = itemsDiff.appendedItemsCount;
35
29
 
36
30
  if (prependedItemsCount === 0 && appendedItemsCount === 0) {
37
- // The items order hasn't changed.
31
+ log('React: ~ The `items` elements to be rendered are identical to the previously rendered ones'); // The items order hasn't changed.
38
32
  // No need to re-generate the `key` prefix.
33
+
39
34
  shouldUpdateItemKeys = false;
40
35
  } else if (prependedItemsCount === 0 && appendedItemsCount > 0) {
41
- // The item order hasn't changed.
36
+ log('React: ~ The `items` elements order hasn\'t changed:', appendedItemsCount, 'items have been appended'); // The item order hasn't changed.
42
37
  // No need to re-generate the `key` prefix.
38
+
43
39
  shouldUpdateItemKeys = false;
44
40
  }
45
41
  } // Update React element `key`s for the new set of `items`.
46
42
 
47
43
 
48
44
  if (shouldUpdateItemKeys) {
45
+ log('React: ~ Update item `key`s');
49
46
  updateItemKeysForNewItems();
50
47
  }
51
- }
48
+ });
52
49
  }
53
- //# sourceMappingURL=useHandleItemIndexesChange.js.map
50
+ //# sourceMappingURL=useUpdateItemKeysOnItemsChange.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useUpdateItemKeysOnItemsChange.js","names":["log","useOnChange","useUpdateItemKeysOnItemsChange","itemsBeingRendered","virtualScroller","usesAutogeneratedItemKeys","updateItemKeysForNewItems","previousItemsBeingRendered","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,OAAOA,GAAP,MAAgB,qBAAhB;AAEA,OAAOC,WAAP,MAAwB,kBAAxB,C,CAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,eAAe,SAASC,8BAAT,CAAwCC,kBAAxC,QAIZ;EAAA,IAHFC,eAGE,QAHFA,eAGE;EAAA,IAFFC,yBAEE,QAFFA,yBAEE;EAAA,IADFC,yBACE,QADFA,yBACE;EACF;EACAL,WAAW,CAACE,kBAAD,EAAqB,UAACA,kBAAD,EAAqBI,0BAArB,EAAoD;IACnF,IAAI,CAACF,yBAAL,EAAgC;MAC/B;IACA;;IAEDL,GAAG,CAAC,qDAAD,EAAwDG,kBAAxD,CAAH;IAEA,IAAIK,oBAAoB,GAAG,IAA3B;IAEA,IAAMC,SAAS,GAAGL,eAAe,CAACM,YAAhB,CAA6BH,0BAA7B,EAAyDJ,kBAAzD,CAAlB,CATmF,CAWnF;;IACA,IAAIM,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;QAC1DZ,GAAG,CAAC,4FAAD,CAAH,CAD0D,CAE1D;QACA;;QACAQ,oBAAoB,GAAG,KAAvB;MACA,CALD,MAMK,IAAIG,mBAAmB,KAAK,CAAxB,IAA6BC,kBAAkB,GAAG,CAAtD,EAAyD;QAC7DZ,GAAG,CAAC,sDAAD,EAAyDY,kBAAzD,EAA6E,0BAA7E,CAAH,CAD6D,CAE7D;QACA;;QACAJ,oBAAoB,GAAG,KAAvB;MACA;IACD,CA7BkF,CA+BnF;;;IACA,IAAIA,oBAAJ,EAA0B;MACzBR,GAAG,CAAC,6BAAD,CAAH;MACAM,yBAAyB;IACzB;EACD,CApCU,CAAX;AAqCA"}
@@ -4,6 +4,8 @@ function _defineProperties(target, props) { for (var i = 0; i < props.length; i+
4
4
 
5
5
  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
6
6
 
7
+ import ItemNotRenderedError from '../ItemNotRenderedError.js';
8
+
7
9
  var ItemsContainer = /*#__PURE__*/function () {
8
10
  /**
9
11
  * Constructs a new "container" from an element.
@@ -30,6 +32,14 @@ var ItemsContainer = /*#__PURE__*/function () {
30
32
  var rowWidth;
31
33
  var rowHeight;
32
34
  var startNewRow = true;
35
+
36
+ if (renderedElementIndex > children.length - 1) {
37
+ throw new ItemNotRenderedError({
38
+ renderedElementIndex: renderedElementIndex,
39
+ renderedElementsCount: children.length
40
+ });
41
+ }
42
+
33
43
  var i = 0;
34
44
 
35
45
  while (i <= renderedElementIndex) {
@@ -66,7 +76,16 @@ var ItemsContainer = /*#__PURE__*/function () {
66
76
  }, {
67
77
  key: "getNthRenderedItemHeight",
68
78
  value: function getNthRenderedItemHeight(renderedElementIndex) {
69
- return this.getElement().children[renderedElementIndex].height;
79
+ var children = this.getElement().children;
80
+
81
+ if (renderedElementIndex > children.length - 1) {
82
+ throw new ItemNotRenderedError({
83
+ renderedElementIndex: renderedElementIndex,
84
+ renderedElementsCount: children.length
85
+ });
86
+ }
87
+
88
+ return children[renderedElementIndex].height;
70
89
  }
71
90
  /**
72
91
  * 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","length","verticalSpacing","paddingBottom"],"sources":["../../source/test/ItemsContainer.js"],"sourcesContent":["export 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\t\tlet rowWidth\r\n\t\tlet rowHeight\r\n\t\tlet startNewRow = true\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\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\treturn this.getElement().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":";;;;;;IAAqBA,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;MACA,IAAIC,QAAJ;MACA,IAAIC,SAAJ;MACA,IAAIC,WAAW,GAAG,IAAlB;MACA,IAAIC,CAAC,GAAG,CAAR;;MACA,OAAOA,CAAC,IAAIT,oBAAZ,EAAkC;QACjC,IAAIQ,WAAW,IAAIF,QAAQ,GAAGL,QAAQ,CAACQ,CAAD,CAAR,CAAYN,KAAvB,GAA+BD,QAAlD,EAA4D;UAC3D,IAAIO,CAAC,GAAG,CAAR,EAAW;YACVL,SAAS,IAAIG,SAAb;YACAH,SAAS,IAAIH,QAAQ,CAACQ,CAAD,CAAR,CAAYC,SAAzB;UACA;;UACDJ,QAAQ,GAAGL,QAAQ,CAACQ,CAAD,CAAR,CAAYN,KAAvB;UACAI,SAAS,GAAGN,QAAQ,CAACQ,CAAD,CAAR,CAAYE,MAAxB;;UACA,IAAIL,QAAQ,GAAGJ,QAAf,EAAyB;YACxBM,WAAW,GAAG,IAAd;UACA,CAFD,MAEO;YACNA,WAAW,GAAG,KAAd;UACA;QACD,CAZD,MAYO;UACNF,QAAQ,IAAIL,QAAQ,CAACQ,CAAD,CAAR,CAAYN,KAAxB;UACAI,SAAS,GAAGK,IAAI,CAACC,GAAL,CAASN,SAAT,EAAoBN,QAAQ,CAACQ,CAAD,CAAR,CAAYE,MAAhC,CAAZ;QACA;;QACDF,CAAC;MACD;;MACD,OAAOL,SAAP;IACA;IAED;AACD;AACA;AACA;AACA;;;;WACC,kCAAyBJ,oBAAzB,EAA+C;MAC9C,OAAO,KAAKD,UAAL,GAAkBE,QAAlB,CAA2BD,oBAA3B,EAAiDW,MAAxD;IACA;IAED;AACD;AACA;AACA;;;;WACC,qBAAY;MACX,IAAMV,QAAQ,GAAG,KAAKF,UAAL,GAAkBE,QAAnC;MACA,IAAMC,QAAQ,GAAG,KAAKH,UAAL,GAAkBI,KAAnC;MACA,IAAIW,aAAa,GAAG,KAAKf,UAAL,GAAkBM,UAAtC;MACA,IAAII,CAAC,GAAG,CAAR;;MACA,OAAOA,CAAC,GAAGR,QAAQ,CAACc,MAApB,EAA4B;QAC3B,IAAIT,QAAQ,GAAG,CAAf;QACA,IAAIC,SAAS,GAAG,CAAhB;;QACA,OAAOD,QAAQ,IAAIJ,QAAZ,IAAwBO,CAAC,GAAGR,QAAQ,CAACc,MAA5C,EAAoD;UACnD,IAAIT,QAAQ,KAAK,CAAb,IAAkBG,CAAC,GAAG,CAA1B,EAA6B;YAC5B,IAAMO,eAAe,GAAGf,QAAQ,CAACQ,CAAD,CAAR,CAAYC,SAApC;YACAI,aAAa,IAAIE,eAAjB;UACA;;UACDV,QAAQ,IAAIL,QAAQ,CAACQ,CAAD,CAAR,CAAYN,KAAxB;UACAI,SAAS,GAAGK,IAAI,CAACC,GAAL,CAASN,SAAT,EAAoBN,QAAQ,CAACQ,CAAD,CAAR,CAAYE,MAAhC,CAAZ;UACAF,CAAC;QACD;;QACDK,aAAa,IAAIP,SAAjB;MACA;;MACDO,aAAa,IAAI,KAAKf,UAAL,GAAkBkB,aAAnC;MACA,OAAOH,aAAP;IACA;IAED;AACD;AACA;;;;WACC,iBAAQ;MACP,KAAKf,UAAL,GAAkBE,QAAlB,GAA6B,EAA7B;IACA;;;;;;SArFmBH,c"}
1
+ {"version":3,"file":"ItemsContainer.js","names":["ItemNotRenderedError","ItemsContainer","getElement","renderedElementIndex","children","maxWidth","width","topOffset","paddingTop","rowWidth","rowHeight","startNewRow","length","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,OAAOA,oBAAP,MAAiC,4BAAjC;;IAEqBC,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,IAAIZ,oBAAJ,CAAyB;UAC9BG,oBAAoB,EAApBA,oBAD8B;UAE9BU,qBAAqB,EAAET,QAAQ,CAACQ;QAFF,CAAzB,CAAN;MAIA;;MAED,IAAIE,CAAC,GAAG,CAAR;;MACA,OAAOA,CAAC,IAAIX,oBAAZ,EAAkC;QACjC,IAAIQ,WAAW,IAAIF,QAAQ,GAAGL,QAAQ,CAACU,CAAD,CAAR,CAAYR,KAAvB,GAA+BD,QAAlD,EAA4D;UAC3D,IAAIS,CAAC,GAAG,CAAR,EAAW;YACVP,SAAS,IAAIG,SAAb;YACAH,SAAS,IAAIH,QAAQ,CAACU,CAAD,CAAR,CAAYC,SAAzB;UACA;;UACDN,QAAQ,GAAGL,QAAQ,CAACU,CAAD,CAAR,CAAYR,KAAvB;UACAI,SAAS,GAAGN,QAAQ,CAACU,CAAD,CAAR,CAAYE,MAAxB;;UACA,IAAIP,QAAQ,GAAGJ,QAAf,EAAyB;YACxBM,WAAW,GAAG,IAAd;UACA,CAFD,MAEO;YACNA,WAAW,GAAG,KAAd;UACA;QACD,CAZD,MAYO;UACNF,QAAQ,IAAIL,QAAQ,CAACU,CAAD,CAAR,CAAYR,KAAxB;UACAI,SAAS,GAAGO,IAAI,CAACC,GAAL,CAASR,SAAT,EAAoBN,QAAQ,CAACU,CAAD,CAAR,CAAYE,MAAhC,CAAZ;QACA;;QACDF,CAAC;MACD;;MAED,OAAOP,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,IAAIZ,oBAAJ,CAAyB;UAC9BG,oBAAoB,EAApBA,oBAD8B;UAE9BU,qBAAqB,EAAET,QAAQ,CAACQ;QAFF,CAAzB,CAAN;MAIA;;MAED,OAAOR,QAAQ,CAACD,oBAAD,CAAR,CAA+Ba,MAAtC;IACA;IAED;AACD;AACA;AACA;;;;WACC,qBAAY;MACX,IAAMZ,QAAQ,GAAG,KAAKF,UAAL,GAAkBE,QAAnC;MACA,IAAMC,QAAQ,GAAG,KAAKH,UAAL,GAAkBI,KAAnC;MACA,IAAIa,aAAa,GAAG,KAAKjB,UAAL,GAAkBM,UAAtC;MACA,IAAIM,CAAC,GAAG,CAAR;;MACA,OAAOA,CAAC,GAAGV,QAAQ,CAACQ,MAApB,EAA4B;QAC3B,IAAIH,QAAQ,GAAG,CAAf;QACA,IAAIC,SAAS,GAAG,CAAhB;;QACA,OAAOD,QAAQ,IAAIJ,QAAZ,IAAwBS,CAAC,GAAGV,QAAQ,CAACQ,MAA5C,EAAoD;UACnD,IAAIH,QAAQ,KAAK,CAAb,IAAkBK,CAAC,GAAG,CAA1B,EAA6B;YAC5B,IAAMM,eAAe,GAAGhB,QAAQ,CAACU,CAAD,CAAR,CAAYC,SAApC;YACAI,aAAa,IAAIC,eAAjB;UACA;;UACDX,QAAQ,IAAIL,QAAQ,CAACU,CAAD,CAAR,CAAYR,KAAxB;UACAI,SAAS,GAAGO,IAAI,CAACC,GAAL,CAASR,SAAT,EAAoBN,QAAQ,CAACU,CAAD,CAAR,CAAYE,MAAhC,CAAZ;UACAF,CAAC;QACD;;QACDK,aAAa,IAAIT,SAAjB;MACA;;MACDS,aAAa,IAAI,KAAKjB,UAAL,GAAkBmB,aAAnC;MACA,OAAOF,aAAP;IACA;IAED;AACD;AACA;;;;WACC,iBAAQ;MACP,KAAKjB,UAAL,GAAkBE,QAAlB,GAA6B,EAA7B;IACA;;;;;;SAxGmBH,c"}
@@ -36,16 +36,31 @@ export function warn() {
36
36
  (_console2 = console).warn.apply(_console2, _toConsumableArray(['[virtual-scroller]'].concat(args)));
37
37
  }
38
38
  }
39
- export function reportError() {
39
+
40
+ function error() {
41
+ var _console3;
42
+
40
43
  for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
41
44
  args[_key3] = arguments[_key3];
42
45
  }
43
46
 
47
+ (_console3 = console).error.apply(_console3, _toConsumableArray(['[virtual-scroller]'].concat(args)));
48
+ }
49
+
50
+ export function reportError() {
51
+ for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
52
+ args[_key4] = arguments[_key4];
53
+ }
54
+
55
+ var createError = function createError() {
56
+ return new Error(['[virtual-scroller]'].concat(args).join(' '));
57
+ };
58
+
44
59
  if (typeof window !== 'undefined') {
45
60
  // In a web browser.
46
61
  // Output a debug message immediately so that it's known
47
62
  // at which point did the error occur between other debug logs.
48
- log.apply(this, ['ERROR'].concat(args));
63
+ error.apply(this, ['ERROR'].concat(args));
49
64
  setTimeout(function () {
50
65
  // Throw an error in a timeout so that it doesn't interrupt the application's flow.
51
66
  // At the same time, by throwing a client-side error, such error could be spotted
@@ -53,13 +68,23 @@ export function reportError() {
53
68
  // in the console.
54
69
  // The `.join(' ')` part doesn't support stringifying JSON objects,
55
70
  // but those don't seem to be used in any of the error messages.
56
- throw new Error(['[virtual-scroller]'].concat(args).join(' '));
71
+ throw createError();
57
72
  }, 0);
58
73
  } else {
59
- var _console3;
74
+ // In Node.js.
75
+ // If tests are being run, throw in case of any errors.
76
+ var catchError = getGlobalVariable('VirtualScrollerCatchError');
77
+
78
+ if (catchError) {
79
+ return catchError(createError());
80
+ }
81
+
82
+ if (getGlobalVariable('VirtualScrollerThrowErrors')) {
83
+ throw createError();
84
+ } // Print the error in the console.
85
+
60
86
 
61
- // On a server.
62
- (_console3 = console).error.apply(_console3, _toConsumableArray(['[virtual-scroller]'].concat(args)));
87
+ error.apply(this, ['ERROR'].concat(args));
63
88
  }
64
89
  }
65
90
  export function isDebug() {
@@ -1 +1 @@
1
- {"version":3,"file":"debug.js","names":["log","isDebug","args","console","concat","warn","isWarn","warningsAreErrors","reportError","apply","window","setTimeout","Error","join","error","debug","getDebug","undefined","getGlobalVariable","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\nexport function reportError(...args) {\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\tlog.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 new Error(['[virtual-scroller]'].concat(args).join(' '))\r\n\t\t}, 0)\r\n\t} else {\r\n\t\t// On a server.\r\n\t\tconsole.error(...['[virtual-scroller]'].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":";;;;;;;;;;;;AAAA,eAAe,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;AAED,OAAO,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,OAAO,SAASM,WAAT,GAA8B;EAAA,mCAANN,IAAM;IAANA,IAAM;EAAA;;EACpC,IAAI,OAAOQ,MAAP,KAAkB,WAAtB,EAAmC;IAClC;IACA;IACA;IACAV,GAAG,CAACS,KAAJ,CAAU,IAAV,EAAgB,CAAC,OAAD,EAAUL,MAAV,CAAiBF,IAAjB,CAAhB;IACAS,UAAU,CAAC,YAAM;MAChB;MACA;MACA;MACA;MACA;MACA;MACA,MAAM,IAAIC,KAAJ,CAAU,CAAC,oBAAD,EAAuBR,MAAvB,CAA8BF,IAA9B,EAAoCW,IAApC,CAAyC,GAAzC,CAAV,CAAN;IACA,CARS,EAQP,CARO,CAAV;EASA,CAdD,MAcO;IAAA;;IACN;IACA,aAAAV,OAAO,EAACW,KAAR,qCAAiB,CAAC,oBAAD,EAAuBV,MAAvB,CAA8BF,IAA9B,CAAjB;EACA;AACD;AAED,OAAO,SAASD,OAAT,GAAmB;EACzB,IAAMc,KAAK,GAAGC,QAAQ,EAAtB;;EACA,IAAID,KAAK,KAAKE,SAAd,EAAyB;IACxB,OAAOF,KAAK,KAAK,IAAV,IAAkBA,KAAK,KAAK,OAAnC;EACA;AACD;AAED,OAAO,SAAST,MAAT,GAAkB;EACxB;EACA;EACA;EACA;EACA;EACA;EACA,OAAO,IAAP;AACA;;AAED,SAASU,QAAT,GAAoB;EACnB,OAAOE,iBAAiB,CAAC,sBAAD,CAAxB;AACA;;AAED,SAASX,iBAAT,GAA6B;EAC5B,OAAOW,iBAAiB,CAAC,kCAAD,CAAxB;AACA;;AAED,SAASA,iBAAT,CAA2BC,IAA3B,EAAiC;EAChC,IAAI,OAAOT,MAAP,KAAkB,WAAtB,EAAmC;IAClC,OAAOA,MAAM,CAACS,IAAD,CAAb;EACA,CAFD,MAEO,IAAI,OAAOC,MAAP,KAAkB,WAAtB,EAAmC;IACzC,OAAOA,MAAM,CAACD,IAAD,CAAb;EACA;AACD"}
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":";;;;;;;;;;;;AAAA,eAAe,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;AAED,OAAO,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;;AAED,OAAO,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;AAED,OAAO,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;AAED,OAAO,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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "virtual-scroller",
3
- "version": "1.11.3",
3
+ "version": "1.12.1",
4
4
  "description": "A component for efficiently rendering large lists of variable height items",
5
5
  "main": "index.cjs",
6
6
  "module": "index.js",
@@ -1,3 +1,5 @@
1
+ import ItemNotRenderedError from '../ItemNotRenderedError.js'
2
+
1
3
  export default class ItemsContainer {
2
4
  /**
3
5
  * Constructs a new "container" from an element.
@@ -10,9 +12,12 @@ export default class ItemsContainer {
10
12
  _getNthRenderedItemElement(renderedElementIndex) {
11
13
  const childNodes = this.getElement().childNodes
12
14
  if (renderedElementIndex > childNodes.length - 1) {
13
- console.log('~ Items Container Contents ~')
14
- console.log(this.getElement().innerHTML)
15
- throw new Error(`Element with index ${renderedElementIndex} was not found in the list of Rendered Item Elements in the Items Container of Virtual Scroller. There're only ${childNodes.length} Elements there.`)
15
+ // console.log('~ Items Container Contents ~')
16
+ // console.log(this.getElement().innerHTML)
17
+ throw new ItemNotRenderedError({
18
+ renderedElementIndex,
19
+ renderedElementsCount: childNodes.length
20
+ })
16
21
  }
17
22
  return childNodes[renderedElementIndex]
18
23
  }