virtual-scroller 1.11.1 → 1.11.3

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 (80) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +9 -9
  3. package/bundle/virtual-scroller-dom.js +1 -1
  4. package/bundle/virtual-scroller-dom.js.map +1 -1
  5. package/bundle/virtual-scroller-react.js +1 -1
  6. package/bundle/virtual-scroller-react.js.map +1 -1
  7. package/bundle/virtual-scroller.js +1 -1
  8. package/bundle/virtual-scroller.js.map +1 -1
  9. package/commonjs/DOM/ItemsContainer.js +22 -9
  10. package/commonjs/DOM/ItemsContainer.js.map +1 -1
  11. package/commonjs/DOM/VirtualScroller.js +13 -1
  12. package/commonjs/DOM/VirtualScroller.js.map +1 -1
  13. package/commonjs/ItemHeights.js +5 -5
  14. package/commonjs/ItemHeights.js.map +1 -1
  15. package/commonjs/VirtualScroller.js +21 -4
  16. package/commonjs/VirtualScroller.js.map +1 -1
  17. package/commonjs/VirtualScroller.layout.js +22 -22
  18. package/commonjs/VirtualScroller.layout.js.map +1 -1
  19. package/commonjs/VirtualScroller.state.js +1 -1
  20. package/commonjs/VirtualScroller.state.js.map +1 -1
  21. package/commonjs/react/VirtualScroller.js +53 -20
  22. package/commonjs/react/VirtualScroller.js.map +1 -1
  23. package/commonjs/react/useHandleItemIndexesChange.js +53 -0
  24. package/commonjs/react/useHandleItemIndexesChange.js.map +1 -0
  25. package/commonjs/react/{useHandleItemsChange.js → useHandleItemsPropertyChange.js} +21 -40
  26. package/commonjs/react/useHandleItemsPropertyChange.js.map +1 -0
  27. package/commonjs/react/{useOnItemHeightChange.js → useOnItemHeightDidChange.js} +9 -9
  28. package/commonjs/react/useOnItemHeightDidChange.js.map +1 -0
  29. package/commonjs/react/useSetItemState.js +2 -2
  30. package/commonjs/react/useSetItemState.js.map +1 -1
  31. package/commonjs/react/useState.js +47 -69
  32. package/commonjs/react/useState.js.map +1 -1
  33. package/commonjs/react/useStyle.js +4 -4
  34. package/commonjs/react/useStyle.js.map +1 -1
  35. package/dom/index.d.ts +1 -1
  36. package/index.d.ts +1 -1
  37. package/modules/DOM/ItemsContainer.js +22 -9
  38. package/modules/DOM/ItemsContainer.js.map +1 -1
  39. package/modules/DOM/VirtualScroller.js +13 -1
  40. package/modules/DOM/VirtualScroller.js.map +1 -1
  41. package/modules/ItemHeights.js +5 -5
  42. package/modules/ItemHeights.js.map +1 -1
  43. package/modules/VirtualScroller.js +15 -4
  44. package/modules/VirtualScroller.js.map +1 -1
  45. package/modules/VirtualScroller.layout.js +22 -22
  46. package/modules/VirtualScroller.layout.js.map +1 -1
  47. package/modules/VirtualScroller.state.js +1 -1
  48. package/modules/VirtualScroller.state.js.map +1 -1
  49. package/modules/react/VirtualScroller.js +52 -21
  50. package/modules/react/VirtualScroller.js.map +1 -1
  51. package/modules/react/useHandleItemIndexesChange.js +45 -0
  52. package/modules/react/useHandleItemIndexesChange.js.map +1 -0
  53. package/modules/react/{useHandleItemsChange.js → useHandleItemsPropertyChange.js} +20 -39
  54. package/modules/react/useHandleItemsPropertyChange.js.map +1 -0
  55. package/modules/react/{useOnItemHeightChange.js → useOnItemHeightDidChange.js} +8 -8
  56. package/modules/react/useOnItemHeightDidChange.js.map +1 -0
  57. package/modules/react/useSetItemState.js +2 -2
  58. package/modules/react/useSetItemState.js.map +1 -1
  59. package/modules/react/useState.js +48 -70
  60. package/modules/react/useState.js.map +1 -1
  61. package/modules/react/useStyle.js +4 -4
  62. package/modules/react/useStyle.js.map +1 -1
  63. package/package.json +1 -1
  64. package/source/DOM/ItemsContainer.js +13 -3
  65. package/source/DOM/VirtualScroller.js +11 -1
  66. package/source/ItemHeights.js +5 -5
  67. package/source/VirtualScroller.js +12 -3
  68. package/source/VirtualScroller.layout.js +22 -22
  69. package/source/VirtualScroller.state.js +1 -1
  70. package/source/react/VirtualScroller.js +50 -17
  71. package/source/react/useHandleItemIndexesChange.js +49 -0
  72. package/source/react/{useHandleItemsChange.js → useHandleItemsPropertyChange.js} +20 -38
  73. package/source/react/{useOnItemHeightChange.js → useOnItemHeightDidChange.js} +7 -7
  74. package/source/react/useSetItemState.js +2 -2
  75. package/source/react/useState.js +57 -72
  76. package/source/react/useStyle.js +2 -2
  77. package/commonjs/react/useHandleItemsChange.js.map +0 -1
  78. package/commonjs/react/useOnItemHeightChange.js.map +0 -1
  79. package/modules/react/useHandleItemsChange.js.map +0 -1
  80. package/modules/react/useOnItemHeightChange.js.map +0 -1
@@ -1,113 +1,98 @@
1
- import { useState, useRef, useLayoutEffect } from 'react'
1
+ import { useState, useRef, useCallback, useLayoutEffect } from 'react'
2
2
 
3
3
  // Creates state management functions.
4
- export default function _useState({ initialState, onRender, items }) {
5
- // `VirtualScroller` state.
4
+ export default function _useState({
5
+ initialState,
6
+ onRender,
7
+ itemsProperty,
8
+ USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION
9
+ }) {
10
+ // This is a utility state variable that is used to re-render the component.
11
+ // It should not be used to access the current `VirtualScroller` state.
12
+ // It's more of a "requested" `VirtualScroller` state.
6
13
  //
7
- // The `_stateUpdate` variable shouldn't be used directly
8
- // because in some cases its value may not represent
9
- // the actual `state` of the `VirtualScroller`.
14
+ // It will also be stale in cases when `USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION`
15
+ // feature is used for setting new `items` in state.
10
16
  //
11
- // * It will contain an incorrect initial value if `initialState` property is passed
12
- // because it doesn't get initialized to `initialState`.
13
- //
14
- // * If `items` property gets changed, `state` reference variable gets updated immediately
15
- // but the `_stateUpdate` variable here doesn't (until the component re-renders some other time).
16
- //
17
- // Instead, use the `state` reference below.
18
- //
19
- const [_stateUpdate, _setStateUpdate] = useState()
17
+ const [_newState, _setNewState] = useState(initialState)
20
18
 
21
- // This `state` reference is used for accessing the externally stored
22
- // virtual scroller state from inside a `VirtualScroller` instance.
23
- //
24
- // It's also the "source of truth" on the actual `VirtualScroller` state.
25
- //
19
+ // This `state` reference is what `VirtualScroller` uses internally.
20
+ // It's the "source of truth" on the actual `VirtualScroller` state.
26
21
  const state = useRef(initialState)
27
22
 
28
- // Accumulates state updates until they have been applied.
29
- const targetState = useRef(initialState)
23
+ const setState = useCallback((newState) => {
24
+ state.current = newState
25
+ }, [])
30
26
 
31
- // Update the current state reference.
32
- //
33
- // Ignores the cases when `state` reference has already been updated
34
- // "immediately" bypassing a `_setStateUpdate()` call, because
35
- // in that case, `_stateUpdate` holds a stale value.
36
- //
37
- if (state.current !== targetState.current) {
38
- state.current = _stateUpdate
39
- }
27
+ // Accumulates all "pending" state updates until they have been applied.
28
+ const nextState = useRef(initialState)
40
29
 
41
- // Call `onRender()` right after every state update.
42
- //
43
- // When `items` property changes, `useHandleItemsChange()` hook doesn't call
44
- // `_setStateUpdate()` because there's no need for a re-render.
45
- // But chaning `items` still does trigger a `VirtualScroller` state update,
46
- // so added `items` property in the list of this "effect"'s dependencies.
47
- //
30
+ // Updates the actual `VirtualScroller` state right after a requested state update
31
+ // has been applied. Doesn't do anything at initial render.
32
+ useLayoutEffect(() => {
33
+ setState(_newState)
34
+ }, [
35
+ _newState
36
+ ])
37
+
38
+ // Calls `onRender()` right after every state update (which is a re-render),
39
+ // and also right after the initial render.
48
40
  useLayoutEffect(() => {
49
41
  onRender()
50
42
  }, [
51
- _stateUpdate,
52
- items
43
+ _newState,
44
+ // When using `USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION` feature,
45
+ // there won't be a `_setNewState()` function call when `items` property changes,
46
+ // hence the additional `itemsProperty` dependency.
47
+ USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION ? itemsProperty : undefined
53
48
  ])
54
49
 
55
50
  return {
56
51
  getState: () => state.current,
57
52
 
58
- // Updates existing state.
53
+ getNextState: () => nextState.current,
54
+
55
+ // Requests a state update.
59
56
  //
60
- // State updates are incremental meaning that this code should mimick
57
+ // State updates are incremental meaning that this function mimicks
61
58
  // the classic `React.Component`'s `this.setState()` behavior
62
- // when calling `this.setState()` doesn't replace `state` but rather merges
63
- // a set of the updated state properties with the rest of the old ones.
59
+ // when calling `this.setState()` didn't replace `state` but rather merged
60
+ // the updated state properties over the "old" state properties.
64
61
  //
65
- // The reason is that `useState()` updates are "asynchronous" (not immediate),
62
+ // The reason for using pending state updates accumulation is that
63
+ // `useState()` updates are "asynchronous" (not immediate),
66
64
  // and simply merging over `...state` would merge over potentially stale
67
65
  // property values in cases when more than a single `updateState()` call is made
68
- // before the state actually updates, resulting in losing some of the state updates.
66
+ // before the state actually updates, resulting in losing some of those state updates.
69
67
  //
70
- // For example, the first `updateState()` call updates shown item indexes,
68
+ // Example: the first `updateState()` call updates shown item indexes,
71
69
  // and the second `updateState()` call updates `verticalSpacing`.
72
70
  // If it was simply `updateState({ ...state, ...stateUpdate })`
73
71
  // then the second state update could overwrite the first state update,
74
72
  // resulting in incorrect items being shown/hidden.
75
73
  //
76
- // Using `...state.current` instead of `...pendingState.current` here
77
- // would produce "stale" results.
78
- //
79
74
  updateState: (stateUpdate) => {
80
- const newState = {
81
- ...targetState.current,
75
+ nextState.current = {
76
+ ...nextState.current,
82
77
  ...stateUpdate
83
78
  }
84
- targetState.current = newState
85
- // If `items` property did change the component detects it at render time
86
- // and updates `VirtualScroller` items immediately by calling `.setItems()`.
87
- // But, since all of that happens at render time and not in an "effect",
88
- // if the state update was done as usual by calling `_setStateUpdate()`,
89
- // React would throw an error about updating state during render.
90
- // Hence, state update in that particular case should happen "directly",
91
- // without waiting for an "asynchronous" effect to trigger and call
92
- // an "asyncronous" `_setStateUpdate()` function.
93
- //
94
- // Updating state directly in that particular case works because there
95
- // already is a render ongoing, so there's no need to re-render the component
96
- // again after such render-time state update.
79
+ // If `items` property did change, the component detects it at render time
80
+ // and updates `VirtualScroller` items immediately by calling `.setItems()`,
81
+ // which, in turn, immediately calls this `updateState()` function
82
+ // with a `stateUpdate` argument that contains the new `items`,
83
+ // so checking for `stateUpdate.items` could detect situations like that.
97
84
  //
98
- // When the initial `VirtualScroller` state is being set, it contains an `.items`
85
+ // When the initial `VirtualScroller` state is being set, it contains the `.items`
99
86
  // property too, but that initial setting is done using another function called
100
87
  // `setInitialState()`, so using `if (stateUpdate.items)` condition here for describing
101
88
  // just the case when `state` has been updated as a result of a `setItems()` call
102
89
  // seems to be fine.
103
90
  //
104
- if (stateUpdate.items) {
105
- // If a `stateUpdate` contains `items` then it means that there was a `setItems()` call.
106
- // No need to trigger a re-render — the component got re-rendered anyway.
107
- // Just update the `state` "in place".
108
- state.current = newState
91
+ const _newState = nextState.current
92
+ if (stateUpdate.items && USE_ITEMS_UPDATE_NO_SECOND_RENDER_OPTIMIZATION) {
93
+ setState(_newState)
109
94
  } else {
110
- _setStateUpdate(newState)
95
+ _setNewState(_newState)
111
96
  }
112
97
  }
113
98
  }
@@ -2,7 +2,7 @@ import px from '../utility/px.js'
2
2
 
3
3
  export default function useStyle({
4
4
  tbody,
5
- virtualScroller
5
+ getNextState
6
6
  }) {
7
7
  if (tbody) {
8
8
  return
@@ -11,7 +11,7 @@ export default function useStyle({
11
11
  const {
12
12
  beforeItemsHeight,
13
13
  afterItemsHeight
14
- } = virtualScroller.getState()
14
+ } = getNextState()
15
15
 
16
16
  return {
17
17
  paddingTop: px(beforeItemsHeight),
@@ -1 +0,0 @@
1
- {"version":3,"file":"useHandleItemsChange.js","names":["useHandleItemsChange","items","virtualScroller","preserveScrollPosition","preserveScrollPositionOnPrependItems","updateItemKeysForNewItems","getState","renderedItems","firstShownItemIndex","previousItems","useRef","hasItemsPropertyChanged","current","itemsHaveChanged","shouldUpdateItemKeys","itemsDiff","getItemsDiff","prependedItemsCount","appendedItemsCount","setItems"],"sources":["../../source/react/useHandleItemsChange.js"],"sourcesContent":["import { useRef } from 'react'\r\n\r\n// If new `items` are passed:\r\n//\r\n// * Store the scroll Y position for the first one of the current items\r\n// so that it could potentially (in some cases) be restored after the\r\n// new `items` are rendered.\r\n//\r\n// * Call `VirtualScroller.setItems()` function.\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 useHandleItemsChange(items, {\r\n\tvirtualScroller,\r\n\t// `preserveScrollPosition` property name is deprecated,\r\n\t// use `preserveScrollPositionOnPrependItems` property instead.\r\n\tpreserveScrollPosition,\r\n\tpreserveScrollPositionOnPrependItems,\r\n\tupdateItemKeysForNewItems\r\n}) {\r\n\tconst {\r\n\t\titems: renderedItems,\r\n\t\tfirstShownItemIndex\r\n\t} = virtualScroller.getState()\r\n\r\n\t// During render, check if the `items` list has changed.\r\n\t// If it has, capture the Y scroll position and updated item element `key`s.\r\n\r\n\t// A long \"advanced\" sidenote on why capturing scroll Y position\r\n\t// is done during render instead of in an \"effect\":\r\n\t//\r\n\t// Previously, capturing scroll Y position was being done in `useLayoutEffect()`\r\n\t// but it was later found out that it wouldn't work for a \"Show previous\" button\r\n\t// scenario because that button would get hidden by the time `useLayoutEffect()`\r\n\t// gets called when there're no more \"previous\" items to show.\r\n\t//\r\n\t// Consider this code example:\r\n\t//\r\n\t// const { fromIndex, items } = this.state\r\n\t// const items = allItems.slice(fromIndex)\r\n\t// return (\r\n\t// \t{fromIndex > 0 &&\r\n\t// \t\t<button onClick={this.onShowPrevious}>\r\n\t// \t\t\tShow previous\r\n\t// \t\t</button>\r\n\t// \t}\r\n\t// \t<VirtualScroller\r\n\t// \t\titems={items}\r\n\t// \t\titemComponent={ItemComponent}/>\r\n\t// )\r\n\t//\r\n\t// Consider a user clicks \"Show previous\" to show the items from the start.\r\n\t// By the time `componentDidUpdate()` is called on `<VirtualScroller/>`,\r\n\t// the \"Show previous\" button has already been hidden\r\n\t// (because there're no more \"previous\" items)\r\n\t// which results in the scroll Y position jumping forward\r\n\t// by the height of that \"Show previous\" button.\r\n\t// This is because `<VirtualScroller/>` captures scroll Y\r\n\t// position when items are prepended via `.setItems()`\r\n\t// when the \"Show previous\" button is still being shown,\r\n\t// and then restores scroll Y position in `.onRender()`\r\n\t// when the \"Show previous\" button has already been hidden:\r\n\t// that's the reason for the scroll Y \"jump\".\r\n\t//\r\n\t// To prevent that, scroll Y position is captured at `render()`\r\n\t// time rather than later in `componentDidUpdate()`: this way,\r\n\t// scroll Y position is captured while the \"Show previous\" button\r\n\t// is still being shown.\r\n\r\n\tconst previousItems = useRef(items)\r\n\tconst hasItemsPropertyChanged = items !== previousItems.current\r\n\tpreviousItems.current = items\r\n\tif (hasItemsPropertyChanged) {\r\n\t\tlet itemsHaveChanged = true\r\n\t\tlet shouldUpdateItemKeys = true\r\n\t\tconst itemsDiff = virtualScroller.getItemsDiff(renderedItems, items)\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\t// The items haven't changed. No need to re-generate\r\n\t\t\t\t// the `key` prefix or to snapshot the Y scroll position.\r\n\t\t\t\titemsHaveChanged = false\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\t// Just some items got appended. No need to re-generate\r\n\t\t\t\t// the `key` prefix or to snapshot the Y scroll position.\r\n\t\t\t\tshouldUpdateItemKeys = false\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (itemsHaveChanged) {\r\n\t\t\t// Set the new `items`.\r\n\t\t\tvirtualScroller.setItems(items, {\r\n\t\t\t\t// `preserveScrollPosition` property name is deprecated,\r\n\t\t\t\t// use `preserveScrollPositionOnPrependItems` property instead.\r\n\t\t\t\tpreserveScrollPositionOnPrependItems: preserveScrollPositionOnPrependItems || preserveScrollPosition\r\n\t\t\t})\r\n\r\n\t\t\t// Update React element `key`s for the new set of `items`.\r\n\t\t\tif (shouldUpdateItemKeys) {\r\n\t\t\t\tupdateItemKeysForNewItems()\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"],"mappings":";;;;;;;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe,SAASA,oBAAT,CAA8BC,KAA9B,QAOZ;EAAA,IANFC,eAME,QANFA,eAME;EAAA,IAHFC,sBAGE,QAHFA,sBAGE;EAAA,IAFFC,oCAEE,QAFFA,oCAEE;EAAA,IADFC,yBACE,QADFA,yBACE;;EACF,4BAGIH,eAAe,CAACI,QAAhB,EAHJ;EAAA,IACQC,aADR,yBACCN,KADD;EAAA,IAECO,mBAFD,yBAECA,mBAFD,CADE,CAMF;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;;;EAEA,IAAMC,aAAa,GAAG,IAAAC,aAAA,EAAOT,KAAP,CAAtB;EACA,IAAMU,uBAAuB,GAAGV,KAAK,KAAKQ,aAAa,CAACG,OAAxD;EACAH,aAAa,CAACG,OAAd,GAAwBX,KAAxB;;EACA,IAAIU,uBAAJ,EAA6B;IAC5B,IAAIE,gBAAgB,GAAG,IAAvB;IACA,IAAIC,oBAAoB,GAAG,IAA3B;IACA,IAAMC,SAAS,GAAGb,eAAe,CAACc,YAAhB,CAA6BT,aAA7B,EAA4CN,KAA5C,CAAlB,CAH4B,CAI5B;;IACA,IAAIc,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;QACA;QACAL,gBAAgB,GAAG,KAAnB;QACAC,oBAAoB,GAAG,KAAvB;MACA,CALD,MAMK,IAAIG,mBAAmB,KAAK,CAAxB,IAA6BC,kBAAkB,GAAG,CAAtD,EAAyD;QAC7D;QACA;QACAJ,oBAAoB,GAAG,KAAvB;MACA;IACD;;IAED,IAAID,gBAAJ,EAAsB;MACrB;MACAX,eAAe,CAACiB,QAAhB,CAAyBlB,KAAzB,EAAgC;QAC/B;QACA;QACAG,oCAAoC,EAAEA,oCAAoC,IAAID;MAH/C,CAAhC,EAFqB,CAQrB;;MACA,IAAIW,oBAAJ,EAA0B;QACzBT,yBAAyB;MACzB;IACD;EACD;AACD"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"useOnItemHeightChange.js","names":["useOnItemHeightChange","items","virtualScroller","initialCacheValue","useMemo","Array","length","cache","useRef","getOnItemHeightChange","useCallback","i","current","onItemHeightChange"],"sources":["../../source/react/useOnItemHeightChange.js"],"sourcesContent":["import { useMemo, useRef, useCallback } from 'react'\r\n\r\nexport default function useOnItemHeightChange({\r\n\titems,\r\n\tvirtualScroller\r\n}) {\r\n\t// Only compute the initial cache value once.\r\n\tconst initialCacheValue = useMemo(() => {\r\n\t\treturn new Array(items.length)\r\n\t}, [])\r\n\r\n\t// Handler functions cache.\r\n\tconst cache = useRef(initialCacheValue)\r\n\r\n\t// Caches per-item `onItemHeightChange` functions' \"references\"\r\n\t// so that item components don't get re-rendered needlessly.\r\n\tconst getOnItemHeightChange = useCallback((i) => {\r\n\t\tif (!cache.current[i]) {\r\n\t\t\tcache.current[i] = () => virtualScroller.onItemHeightChange(i)\r\n\t\t}\r\n\t\treturn cache.current[i]\r\n\t}, [\r\n\t\tvirtualScroller,\r\n\t\tcache\r\n\t])\r\n\r\n\treturn getOnItemHeightChange\r\n}"],"mappings":";;;;;;;AAAA;;AAEe,SAASA,qBAAT,OAGZ;EAAA,IAFFC,KAEE,QAFFA,KAEE;EAAA,IADFC,eACE,QADFA,eACE;EACF;EACA,IAAMC,iBAAiB,GAAG,IAAAC,cAAA,EAAQ,YAAM;IACvC,OAAO,IAAIC,KAAJ,CAAUJ,KAAK,CAACK,MAAhB,CAAP;EACA,CAFyB,EAEvB,EAFuB,CAA1B,CAFE,CAMF;;EACA,IAAMC,KAAK,GAAG,IAAAC,aAAA,EAAOL,iBAAP,CAAd,CAPE,CASF;EACA;;EACA,IAAMM,qBAAqB,GAAG,IAAAC,kBAAA,EAAY,UAACC,CAAD,EAAO;IAChD,IAAI,CAACJ,KAAK,CAACK,OAAN,CAAcD,CAAd,CAAL,EAAuB;MACtBJ,KAAK,CAACK,OAAN,CAAcD,CAAd,IAAmB;QAAA,OAAMT,eAAe,CAACW,kBAAhB,CAAmCF,CAAnC,CAAN;MAAA,CAAnB;IACA;;IACD,OAAOJ,KAAK,CAACK,OAAN,CAAcD,CAAd,CAAP;EACA,CAL6B,EAK3B,CACFT,eADE,EAEFK,KAFE,CAL2B,CAA9B;EAUA,OAAOE,qBAAP;AACA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"useHandleItemsChange.js","names":["useRef","useHandleItemsChange","items","virtualScroller","preserveScrollPosition","preserveScrollPositionOnPrependItems","updateItemKeysForNewItems","getState","renderedItems","firstShownItemIndex","previousItems","hasItemsPropertyChanged","current","itemsHaveChanged","shouldUpdateItemKeys","itemsDiff","getItemsDiff","prependedItemsCount","appendedItemsCount","setItems"],"sources":["../../source/react/useHandleItemsChange.js"],"sourcesContent":["import { useRef } from 'react'\r\n\r\n// If new `items` are passed:\r\n//\r\n// * Store the scroll Y position for the first one of the current items\r\n// so that it could potentially (in some cases) be restored after the\r\n// new `items` are rendered.\r\n//\r\n// * Call `VirtualScroller.setItems()` function.\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 useHandleItemsChange(items, {\r\n\tvirtualScroller,\r\n\t// `preserveScrollPosition` property name is deprecated,\r\n\t// use `preserveScrollPositionOnPrependItems` property instead.\r\n\tpreserveScrollPosition,\r\n\tpreserveScrollPositionOnPrependItems,\r\n\tupdateItemKeysForNewItems\r\n}) {\r\n\tconst {\r\n\t\titems: renderedItems,\r\n\t\tfirstShownItemIndex\r\n\t} = virtualScroller.getState()\r\n\r\n\t// During render, check if the `items` list has changed.\r\n\t// If it has, capture the Y scroll position and updated item element `key`s.\r\n\r\n\t// A long \"advanced\" sidenote on why capturing scroll Y position\r\n\t// is done during render instead of in an \"effect\":\r\n\t//\r\n\t// Previously, capturing scroll Y position was being done in `useLayoutEffect()`\r\n\t// but it was later found out that it wouldn't work for a \"Show previous\" button\r\n\t// scenario because that button would get hidden by the time `useLayoutEffect()`\r\n\t// gets called when there're no more \"previous\" items to show.\r\n\t//\r\n\t// Consider this code example:\r\n\t//\r\n\t// const { fromIndex, items } = this.state\r\n\t// const items = allItems.slice(fromIndex)\r\n\t// return (\r\n\t// \t{fromIndex > 0 &&\r\n\t// \t\t<button onClick={this.onShowPrevious}>\r\n\t// \t\t\tShow previous\r\n\t// \t\t</button>\r\n\t// \t}\r\n\t// \t<VirtualScroller\r\n\t// \t\titems={items}\r\n\t// \t\titemComponent={ItemComponent}/>\r\n\t// )\r\n\t//\r\n\t// Consider a user clicks \"Show previous\" to show the items from the start.\r\n\t// By the time `componentDidUpdate()` is called on `<VirtualScroller/>`,\r\n\t// the \"Show previous\" button has already been hidden\r\n\t// (because there're no more \"previous\" items)\r\n\t// which results in the scroll Y position jumping forward\r\n\t// by the height of that \"Show previous\" button.\r\n\t// This is because `<VirtualScroller/>` captures scroll Y\r\n\t// position when items are prepended via `.setItems()`\r\n\t// when the \"Show previous\" button is still being shown,\r\n\t// and then restores scroll Y position in `.onRender()`\r\n\t// when the \"Show previous\" button has already been hidden:\r\n\t// that's the reason for the scroll Y \"jump\".\r\n\t//\r\n\t// To prevent that, scroll Y position is captured at `render()`\r\n\t// time rather than later in `componentDidUpdate()`: this way,\r\n\t// scroll Y position is captured while the \"Show previous\" button\r\n\t// is still being shown.\r\n\r\n\tconst previousItems = useRef(items)\r\n\tconst hasItemsPropertyChanged = items !== previousItems.current\r\n\tpreviousItems.current = items\r\n\tif (hasItemsPropertyChanged) {\r\n\t\tlet itemsHaveChanged = true\r\n\t\tlet shouldUpdateItemKeys = true\r\n\t\tconst itemsDiff = virtualScroller.getItemsDiff(renderedItems, items)\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\t// The items haven't changed. No need to re-generate\r\n\t\t\t\t// the `key` prefix or to snapshot the Y scroll position.\r\n\t\t\t\titemsHaveChanged = false\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\t// Just some items got appended. No need to re-generate\r\n\t\t\t\t// the `key` prefix or to snapshot the Y scroll position.\r\n\t\t\t\tshouldUpdateItemKeys = false\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (itemsHaveChanged) {\r\n\t\t\t// Set the new `items`.\r\n\t\t\tvirtualScroller.setItems(items, {\r\n\t\t\t\t// `preserveScrollPosition` property name is deprecated,\r\n\t\t\t\t// use `preserveScrollPositionOnPrependItems` property instead.\r\n\t\t\t\tpreserveScrollPositionOnPrependItems: preserveScrollPositionOnPrependItems || preserveScrollPosition\r\n\t\t\t})\r\n\r\n\t\t\t// Update React element `key`s for the new set of `items`.\r\n\t\t\tif (shouldUpdateItemKeys) {\r\n\t\t\t\tupdateItemKeysForNewItems()\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"],"mappings":"AAAA,SAASA,MAAT,QAAuB,OAAvB,C,CAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AACA,eAAe,SAASC,oBAAT,CAA8BC,KAA9B,QAOZ;EAAA,IANFC,eAME,QANFA,eAME;EAAA,IAHFC,sBAGE,QAHFA,sBAGE;EAAA,IAFFC,oCAEE,QAFFA,oCAEE;EAAA,IADFC,yBACE,QADFA,yBACE;;EACF,4BAGIH,eAAe,CAACI,QAAhB,EAHJ;EAAA,IACQC,aADR,yBACCN,KADD;EAAA,IAECO,mBAFD,yBAECA,mBAFD,CADE,CAMF;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;;;EAEA,IAAMC,aAAa,GAAGV,MAAM,CAACE,KAAD,CAA5B;EACA,IAAMS,uBAAuB,GAAGT,KAAK,KAAKQ,aAAa,CAACE,OAAxD;EACAF,aAAa,CAACE,OAAd,GAAwBV,KAAxB;;EACA,IAAIS,uBAAJ,EAA6B;IAC5B,IAAIE,gBAAgB,GAAG,IAAvB;IACA,IAAIC,oBAAoB,GAAG,IAA3B;IACA,IAAMC,SAAS,GAAGZ,eAAe,CAACa,YAAhB,CAA6BR,aAA7B,EAA4CN,KAA5C,CAAlB,CAH4B,CAI5B;;IACA,IAAIa,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;QACA;QACAL,gBAAgB,GAAG,KAAnB;QACAC,oBAAoB,GAAG,KAAvB;MACA,CALD,MAMK,IAAIG,mBAAmB,KAAK,CAAxB,IAA6BC,kBAAkB,GAAG,CAAtD,EAAyD;QAC7D;QACA;QACAJ,oBAAoB,GAAG,KAAvB;MACA;IACD;;IAED,IAAID,gBAAJ,EAAsB;MACrB;MACAV,eAAe,CAACgB,QAAhB,CAAyBjB,KAAzB,EAAgC;QAC/B;QACA;QACAG,oCAAoC,EAAEA,oCAAoC,IAAID;MAH/C,CAAhC,EAFqB,CAQrB;;MACA,IAAIU,oBAAJ,EAA0B;QACzBR,yBAAyB;MACzB;IACD;EACD;AACD"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"useOnItemHeightChange.js","names":["useMemo","useRef","useCallback","useOnItemHeightChange","items","virtualScroller","initialCacheValue","Array","length","cache","getOnItemHeightChange","i","current","onItemHeightChange"],"sources":["../../source/react/useOnItemHeightChange.js"],"sourcesContent":["import { useMemo, useRef, useCallback } from 'react'\r\n\r\nexport default function useOnItemHeightChange({\r\n\titems,\r\n\tvirtualScroller\r\n}) {\r\n\t// Only compute the initial cache value once.\r\n\tconst initialCacheValue = useMemo(() => {\r\n\t\treturn new Array(items.length)\r\n\t}, [])\r\n\r\n\t// Handler functions cache.\r\n\tconst cache = useRef(initialCacheValue)\r\n\r\n\t// Caches per-item `onItemHeightChange` functions' \"references\"\r\n\t// so that item components don't get re-rendered needlessly.\r\n\tconst getOnItemHeightChange = useCallback((i) => {\r\n\t\tif (!cache.current[i]) {\r\n\t\t\tcache.current[i] = () => virtualScroller.onItemHeightChange(i)\r\n\t\t}\r\n\t\treturn cache.current[i]\r\n\t}, [\r\n\t\tvirtualScroller,\r\n\t\tcache\r\n\t])\r\n\r\n\treturn getOnItemHeightChange\r\n}"],"mappings":"AAAA,SAASA,OAAT,EAAkBC,MAAlB,EAA0BC,WAA1B,QAA6C,OAA7C;AAEA,eAAe,SAASC,qBAAT,OAGZ;EAAA,IAFFC,KAEE,QAFFA,KAEE;EAAA,IADFC,eACE,QADFA,eACE;EACF;EACA,IAAMC,iBAAiB,GAAGN,OAAO,CAAC,YAAM;IACvC,OAAO,IAAIO,KAAJ,CAAUH,KAAK,CAACI,MAAhB,CAAP;EACA,CAFgC,EAE9B,EAF8B,CAAjC,CAFE,CAMF;;EACA,IAAMC,KAAK,GAAGR,MAAM,CAACK,iBAAD,CAApB,CAPE,CASF;EACA;;EACA,IAAMI,qBAAqB,GAAGR,WAAW,CAAC,UAACS,CAAD,EAAO;IAChD,IAAI,CAACF,KAAK,CAACG,OAAN,CAAcD,CAAd,CAAL,EAAuB;MACtBF,KAAK,CAACG,OAAN,CAAcD,CAAd,IAAmB;QAAA,OAAMN,eAAe,CAACQ,kBAAhB,CAAmCF,CAAnC,CAAN;MAAA,CAAnB;IACA;;IACD,OAAOF,KAAK,CAACG,OAAN,CAAcD,CAAd,CAAP;EACA,CALwC,EAKtC,CACFN,eADE,EAEFI,KAFE,CALsC,CAAzC;EAUA,OAAOC,qBAAP;AACA"}