@shopify/flash-list 2.0.4-alpha.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. package/dist/AnimatedFlashList.js +4 -6
  2. package/dist/AnimatedFlashList.js.map +1 -1
  3. package/dist/FlashList.js +1 -5
  4. package/dist/FlashList.js.map +1 -1
  5. package/dist/FlashListProps.d.ts +41 -1
  6. package/dist/FlashListProps.d.ts.map +1 -1
  7. package/dist/FlashListProps.js +1 -4
  8. package/dist/FlashListProps.js.map +1 -1
  9. package/dist/FlashListRef.js +1 -2
  10. package/dist/benchmark/AutoScrollHelper.js +22 -30
  11. package/dist/benchmark/AutoScrollHelper.js.map +1 -1
  12. package/dist/benchmark/JSFPSMonitor.js +27 -33
  13. package/dist/benchmark/JSFPSMonitor.js.map +1 -1
  14. package/dist/benchmark/roundToDecimalPlaces.js +2 -5
  15. package/dist/benchmark/roundToDecimalPlaces.js.map +1 -1
  16. package/dist/benchmark/useBenchmark.d.ts +9 -1
  17. package/dist/benchmark/useBenchmark.d.ts.map +1 -1
  18. package/dist/benchmark/useBenchmark.js +86 -95
  19. package/dist/benchmark/useBenchmark.js.map +1 -1
  20. package/dist/benchmark/useDataMultiplier.js +6 -10
  21. package/dist/benchmark/useDataMultiplier.js.map +1 -1
  22. package/dist/benchmark/useFlatListBenchmark.d.ts +4 -1
  23. package/dist/benchmark/useFlatListBenchmark.d.ts.map +1 -1
  24. package/dist/benchmark/useFlatListBenchmark.js +73 -81
  25. package/dist/benchmark/useFlatListBenchmark.js.map +1 -1
  26. package/dist/errors/ErrorMessages.js +1 -4
  27. package/dist/errors/ErrorMessages.js.map +1 -1
  28. package/dist/errors/WarningMessages.js +1 -4
  29. package/dist/errors/WarningMessages.js.map +1 -1
  30. package/dist/index.js +17 -35
  31. package/dist/index.js.map +1 -1
  32. package/dist/isNewArch.js +6 -9
  33. package/dist/isNewArch.js.map +1 -1
  34. package/dist/native/config/PlatformHelper.android.js +2 -5
  35. package/dist/native/config/PlatformHelper.android.js.map +1 -1
  36. package/dist/native/config/PlatformHelper.ios.js +2 -5
  37. package/dist/native/config/PlatformHelper.ios.js.map +1 -1
  38. package/dist/native/config/PlatformHelper.js +2 -5
  39. package/dist/native/config/PlatformHelper.js.map +1 -1
  40. package/dist/native/config/PlatformHelper.web.js +2 -5
  41. package/dist/native/config/PlatformHelper.web.js.map +1 -1
  42. package/dist/recyclerview/LayoutCommitObserver.js +20 -24
  43. package/dist/recyclerview/LayoutCommitObserver.js.map +1 -1
  44. package/dist/recyclerview/RecyclerView.d.ts.map +1 -1
  45. package/dist/recyclerview/RecyclerView.js +134 -111
  46. package/dist/recyclerview/RecyclerView.js.map +1 -1
  47. package/dist/recyclerview/RecyclerViewContextProvider.js +7 -12
  48. package/dist/recyclerview/RecyclerViewContextProvider.js.map +1 -1
  49. package/dist/recyclerview/RecyclerViewManager.js +138 -167
  50. package/dist/recyclerview/RecyclerViewManager.js.map +1 -1
  51. package/dist/recyclerview/RecyclerViewProps.js +1 -2
  52. package/dist/recyclerview/RenderStackManager.js +97 -188
  53. package/dist/recyclerview/RenderStackManager.js.map +1 -1
  54. package/dist/recyclerview/ViewHolder.d.ts +2 -0
  55. package/dist/recyclerview/ViewHolder.d.ts.map +1 -1
  56. package/dist/recyclerview/ViewHolder.js +19 -21
  57. package/dist/recyclerview/ViewHolder.js.map +1 -1
  58. package/dist/recyclerview/ViewHolderCollection.d.ts +4 -0
  59. package/dist/recyclerview/ViewHolderCollection.d.ts.map +1 -1
  60. package/dist/recyclerview/ViewHolderCollection.js +26 -30
  61. package/dist/recyclerview/ViewHolderCollection.js.map +1 -1
  62. package/dist/recyclerview/components/CompatScroller.js +6 -7
  63. package/dist/recyclerview/components/CompatScroller.js.map +1 -1
  64. package/dist/recyclerview/components/CompatView.js +6 -7
  65. package/dist/recyclerview/components/CompatView.js.map +1 -1
  66. package/dist/recyclerview/components/ScrollAnchor.js +10 -15
  67. package/dist/recyclerview/components/ScrollAnchor.js.map +1 -1
  68. package/dist/recyclerview/components/StickyHeaders.d.ts +5 -1
  69. package/dist/recyclerview/components/StickyHeaders.d.ts.map +1 -1
  70. package/dist/recyclerview/components/StickyHeaders.js +77 -51
  71. package/dist/recyclerview/components/StickyHeaders.js.map +1 -1
  72. package/dist/recyclerview/helpers/ConsecutiveNumbers.js +39 -66
  73. package/dist/recyclerview/helpers/ConsecutiveNumbers.js.map +1 -1
  74. package/dist/recyclerview/helpers/EngagedIndicesTracker.js +57 -63
  75. package/dist/recyclerview/helpers/EngagedIndicesTracker.js.map +1 -1
  76. package/dist/recyclerview/helpers/RenderTimeTracker.js +19 -24
  77. package/dist/recyclerview/helpers/RenderTimeTracker.js.map +1 -1
  78. package/dist/recyclerview/helpers/VelocityTracker.js +16 -22
  79. package/dist/recyclerview/helpers/VelocityTracker.js.map +1 -1
  80. package/dist/recyclerview/hooks/useBoundDetection.js +37 -40
  81. package/dist/recyclerview/hooks/useBoundDetection.js.map +1 -1
  82. package/dist/recyclerview/hooks/useLayoutState.js +9 -15
  83. package/dist/recyclerview/hooks/useLayoutState.js.map +1 -1
  84. package/dist/recyclerview/hooks/useMappingHelper.js +6 -10
  85. package/dist/recyclerview/hooks/useMappingHelper.js.map +1 -1
  86. package/dist/recyclerview/hooks/useOnLoad.js +16 -22
  87. package/dist/recyclerview/hooks/useOnLoad.js.map +1 -1
  88. package/dist/recyclerview/hooks/useRecyclerViewController.d.ts.map +1 -1
  89. package/dist/recyclerview/hooks/useRecyclerViewController.js +169 -188
  90. package/dist/recyclerview/hooks/useRecyclerViewController.js.map +1 -1
  91. package/dist/recyclerview/hooks/useRecyclerViewManager.js +12 -17
  92. package/dist/recyclerview/hooks/useRecyclerViewManager.js.map +1 -1
  93. package/dist/recyclerview/hooks/useRecyclingState.js +10 -14
  94. package/dist/recyclerview/hooks/useRecyclingState.js.map +1 -1
  95. package/dist/recyclerview/hooks/useSecondaryProps.d.ts +2 -0
  96. package/dist/recyclerview/hooks/useSecondaryProps.d.ts.map +1 -1
  97. package/dist/recyclerview/hooks/useSecondaryProps.js +39 -30
  98. package/dist/recyclerview/hooks/useSecondaryProps.js.map +1 -1
  99. package/dist/recyclerview/hooks/useUnmountAwareCallbacks.js +17 -22
  100. package/dist/recyclerview/hooks/useUnmountAwareCallbacks.js.map +1 -1
  101. package/dist/recyclerview/hooks/useUnmountFlag.js +5 -9
  102. package/dist/recyclerview/hooks/useUnmountFlag.js.map +1 -1
  103. package/dist/recyclerview/layout-managers/GridLayoutManager.js +61 -80
  104. package/dist/recyclerview/layout-managers/GridLayoutManager.js.map +1 -1
  105. package/dist/recyclerview/layout-managers/LayoutManager.js +83 -123
  106. package/dist/recyclerview/layout-managers/LayoutManager.js.map +1 -1
  107. package/dist/recyclerview/layout-managers/LinearLayoutManager.js +51 -91
  108. package/dist/recyclerview/layout-managers/LinearLayoutManager.js.map +1 -1
  109. package/dist/recyclerview/layout-managers/MasonryLayoutManager.js +77 -96
  110. package/dist/recyclerview/layout-managers/MasonryLayoutManager.js.map +1 -1
  111. package/dist/recyclerview/utils/adjustOffsetForRTL.js +1 -4
  112. package/dist/recyclerview/utils/adjustOffsetForRTL.js.map +1 -1
  113. package/dist/recyclerview/utils/componentUtils.js +4 -9
  114. package/dist/recyclerview/utils/componentUtils.js.map +1 -1
  115. package/dist/recyclerview/utils/findVisibleIndex.js +9 -13
  116. package/dist/recyclerview/utils/findVisibleIndex.js.map +1 -1
  117. package/dist/recyclerview/utils/measureLayout.js +12 -20
  118. package/dist/recyclerview/utils/measureLayout.js.map +1 -1
  119. package/dist/recyclerview/utils/measureLayout.web.js +15 -23
  120. package/dist/recyclerview/utils/measureLayout.web.js.map +1 -1
  121. package/dist/recyclerview/viewability/ViewToken.js +1 -2
  122. package/dist/recyclerview/viewability/ViewabilityHelper.js +34 -41
  123. package/dist/recyclerview/viewability/ViewabilityHelper.js.map +1 -1
  124. package/dist/recyclerview/viewability/ViewabilityManager.js +48 -61
  125. package/dist/recyclerview/viewability/ViewabilityManager.js.map +1 -1
  126. package/dist/tsconfig.tsbuildinfo +1 -1
  127. package/dist/utils/AverageWindow.js +28 -39
  128. package/dist/utils/AverageWindow.js.map +1 -1
  129. package/package.json +4 -6
  130. package/src/FlashListProps.ts +51 -1
  131. package/src/benchmark/useBenchmark.ts +47 -4
  132. package/src/benchmark/useFlatListBenchmark.ts +38 -5
  133. package/src/recyclerview/RecyclerView.tsx +42 -8
  134. package/src/recyclerview/ViewHolder.tsx +6 -1
  135. package/src/recyclerview/ViewHolderCollection.tsx +10 -0
  136. package/src/recyclerview/components/StickyHeaders.tsx +54 -13
  137. package/src/recyclerview/hooks/useRecyclerViewController.tsx +7 -4
  138. package/src/recyclerview/hooks/useSecondaryProps.tsx +23 -0
  139. package/dist/__tests__/AverageWindow.test.d.ts +0 -2
  140. package/dist/__tests__/AverageWindow.test.d.ts.map +0 -1
  141. package/dist/__tests__/AverageWindow.test.js +0 -104
  142. package/dist/__tests__/AverageWindow.test.js.map +0 -1
  143. package/dist/__tests__/ConsecutiveNumbers.test.d.ts +0 -2
  144. package/dist/__tests__/ConsecutiveNumbers.test.d.ts.map +0 -1
  145. package/dist/__tests__/ConsecutiveNumbers.test.js +0 -224
  146. package/dist/__tests__/ConsecutiveNumbers.test.js.map +0 -1
  147. package/dist/__tests__/GridLayoutManager.test.d.ts +0 -2
  148. package/dist/__tests__/GridLayoutManager.test.d.ts.map +0 -1
  149. package/dist/__tests__/GridLayoutManager.test.js +0 -69
  150. package/dist/__tests__/GridLayoutManager.test.js.map +0 -1
  151. package/dist/__tests__/LayoutCommitObserver.test.d.ts +0 -2
  152. package/dist/__tests__/LayoutCommitObserver.test.d.ts.map +0 -1
  153. package/dist/__tests__/LayoutCommitObserver.test.js +0 -37
  154. package/dist/__tests__/LayoutCommitObserver.test.js.map +0 -1
  155. package/dist/__tests__/LinearLayoutManager.test.d.ts +0 -2
  156. package/dist/__tests__/LinearLayoutManager.test.d.ts.map +0 -1
  157. package/dist/__tests__/LinearLayoutManager.test.js +0 -140
  158. package/dist/__tests__/LinearLayoutManager.test.js.map +0 -1
  159. package/dist/__tests__/MasonryLayoutManager.test.d.ts +0 -2
  160. package/dist/__tests__/MasonryLayoutManager.test.d.ts.map +0 -1
  161. package/dist/__tests__/MasonryLayoutManager.test.js +0 -148
  162. package/dist/__tests__/MasonryLayoutManager.test.js.map +0 -1
  163. package/dist/__tests__/RecyclerView.test.d.ts +0 -2
  164. package/dist/__tests__/RecyclerView.test.d.ts.map +0 -1
  165. package/dist/__tests__/RecyclerView.test.js +0 -103
  166. package/dist/__tests__/RecyclerView.test.js.map +0 -1
  167. package/dist/__tests__/RecyclerViewManager.test.d.ts +0 -2
  168. package/dist/__tests__/RecyclerViewManager.test.d.ts.map +0 -1
  169. package/dist/__tests__/RecyclerViewManager.test.js +0 -56
  170. package/dist/__tests__/RecyclerViewManager.test.js.map +0 -1
  171. package/dist/__tests__/RenderStackManager.test.d.ts +0 -2
  172. package/dist/__tests__/RenderStackManager.test.d.ts.map +0 -1
  173. package/dist/__tests__/RenderStackManager.test.js +0 -485
  174. package/dist/__tests__/RenderStackManager.test.js.map +0 -1
  175. package/dist/__tests__/ViewabilityHelper.test.d.ts +0 -2
  176. package/dist/__tests__/ViewabilityHelper.test.d.ts.map +0 -1
  177. package/dist/__tests__/ViewabilityHelper.test.js +0 -186
  178. package/dist/__tests__/ViewabilityHelper.test.js.map +0 -1
  179. package/dist/__tests__/findVisibleIndex.test.d.ts +0 -2
  180. package/dist/__tests__/findVisibleIndex.test.d.ts.map +0 -1
  181. package/dist/__tests__/findVisibleIndex.test.js +0 -259
  182. package/dist/__tests__/findVisibleIndex.test.js.map +0 -1
  183. package/dist/__tests__/helpers/createLayoutManager.d.ts +0 -34
  184. package/dist/__tests__/helpers/createLayoutManager.d.ts.map +0 -1
  185. package/dist/__tests__/helpers/createLayoutManager.js +0 -110
  186. package/dist/__tests__/helpers/createLayoutManager.js.map +0 -1
  187. package/dist/__tests__/useUnmountAwareCallbacks.test.d.ts +0 -2
  188. package/dist/__tests__/useUnmountAwareCallbacks.test.d.ts.map +0 -1
  189. package/dist/__tests__/useUnmountAwareCallbacks.test.js +0 -185
  190. package/dist/__tests__/useUnmountAwareCallbacks.test.js.map +0 -1
  191. package/src/__tests__/AverageWindow.test.ts +0 -128
  192. package/src/__tests__/ConsecutiveNumbers.test.ts +0 -232
  193. package/src/__tests__/GridLayoutManager.test.ts +0 -113
  194. package/src/__tests__/LayoutCommitObserver.test.tsx +0 -63
  195. package/src/__tests__/LinearLayoutManager.test.ts +0 -227
  196. package/src/__tests__/MasonryLayoutManager.test.ts +0 -202
  197. package/src/__tests__/RecyclerView.test.tsx +0 -144
  198. package/src/__tests__/RecyclerViewManager.test.ts +0 -74
  199. package/src/__tests__/RenderStackManager.test.ts +0 -574
  200. package/src/__tests__/ViewabilityHelper.test.ts +0 -282
  201. package/src/__tests__/findVisibleIndex.test.ts +0 -369
  202. package/src/__tests__/helpers/createLayoutManager.ts +0 -141
  203. package/src/__tests__/useUnmountAwareCallbacks.test.tsx +0 -285
@@ -1,574 +0,0 @@
1
- import { RenderStackManager } from "../recyclerview/RenderStackManager";
2
- import { ConsecutiveNumbers } from "../recyclerview/helpers/ConsecutiveNumbers";
3
-
4
- const mock1Data = [
5
- { id: 1, name: "Item 1", itemType: "type1" },
6
- { id: 2, name: "Item 2", itemType: "type2" },
7
- { id: 3, name: "Item 3", itemType: "type1" },
8
- { id: 4, name: "Item 4", itemType: "type2" },
9
- { id: 5, name: "Item 5", itemType: "type1" },
10
- { id: 6, name: "Item 6", itemType: "type2" },
11
- { id: 7, name: "Item 7", itemType: "type1" },
12
- { id: 8, name: "Item 8", itemType: "type2" },
13
- { id: 9, name: "Item 9", itemType: "type1" },
14
- { id: 10, name: "Item 10", itemType: "type2" },
15
- { id: 11, name: "Item 11", itemType: "type1" },
16
- ];
17
- const mock1 = {
18
- data: mock1Data,
19
- getStableId: (index: number) => mock1Data[index].id.toString(),
20
- getItemType: (index: number) => mock1Data[index].itemType,
21
- length: mock1Data.length,
22
- };
23
-
24
- const mock2Data = [
25
- { id: 5, name: "Item 1", itemType: "type1" },
26
- { id: 6, name: "Item 2", itemType: "type2" },
27
- { id: 7, name: "Item 3", itemType: "type1" },
28
- { id: 8, name: "Item 4", itemType: "type2" },
29
- { id: 9, name: "Item 5", itemType: "type1" },
30
- { id: 10, name: "Item 6", itemType: "type2" },
31
- { id: 11, name: "Item 7", itemType: "type1" },
32
- { id: 12, name: "Item 8", itemType: "type2" },
33
- { id: 13, name: "Item 9", itemType: "type1" },
34
- { id: 14, name: "Item 10", itemType: "type2" },
35
- { id: 15, name: "Item 11", itemType: "type1" },
36
- ];
37
- const mock2 = {
38
- data: mock2Data,
39
- getStableId: (index: number) => mock2Data[index].id.toString(),
40
- getItemType: (index: number) => mock2Data[index].itemType,
41
- length: mock2Data.length,
42
- };
43
-
44
- const mock3Data = [
45
- { id: 1, name: "Item 1", itemType: "type1" },
46
- { id: 2, name: "Item 2", itemType: "type1" },
47
- { id: 3, name: "Item 3", itemType: "type1" },
48
- { id: 4, name: "Item 4", itemType: "type1" },
49
- { id: 5, name: "Item 5", itemType: "type1" },
50
- { id: 6, name: "Item 6", itemType: "type1" },
51
- { id: 7, name: "Item 7", itemType: "type1" },
52
- { id: 8, name: "Item 8", itemType: "type1" },
53
- { id: 9, name: "Item 9", itemType: "type1" },
54
- { id: 10, name: "Item 10", itemType: "type1" },
55
- { id: 11, name: "Item 11", itemType: "type1" },
56
- { id: 12, name: "Item 12", itemType: "type1" },
57
- { id: 13, name: "Item 13", itemType: "type1" },
58
- { id: 14, name: "Item 14", itemType: "type1" },
59
- { id: 15, name: "Item 15", itemType: "type1" },
60
- ];
61
- const mock3 = {
62
- data: mock3Data,
63
- getStableId: (index: number) => mock3Data[index].id.toString(),
64
- getItemType: (index: number) => mock3Data[index].itemType,
65
- length: mock3Data.length,
66
- };
67
-
68
- const mock4Data = [
69
- { id: 1, name: "Item 1", itemType: "type1" },
70
- { id: 2, name: "Item 2", itemType: "type1" },
71
- { id: 3, name: "Item 3", itemType: "type1" },
72
- { id: 4, name: "Item 4", itemType: "type1" },
73
- { id: 5, name: "Item 5", itemType: "type1" },
74
- { id: 6, name: "Item 6", itemType: "type1" },
75
- { id: 7, name: "Item 7", itemType: "type1" },
76
- { id: 8, name: "Item 8", itemType: "type2" },
77
- { id: 9, name: "Item 9", itemType: "type2" },
78
- { id: 10, name: "Item 10", itemType: "type2" },
79
- { id: 11, name: "Item 11", itemType: "type2" },
80
- { id: 12, name: "Item 12", itemType: "type2" },
81
- { id: 13, name: "Item 13", itemType: "type2" },
82
- { id: 14, name: "Item 14", itemType: "type2" },
83
- { id: 15, name: "Item 15", itemType: "type2" },
84
- ];
85
- const mock4 = {
86
- data: mock4Data,
87
- getStableId: (index: number) => mock4Data[index].id.toString(),
88
- getItemType: (index: number) => mock4Data[index].itemType,
89
- length: mock4Data.length,
90
- };
91
-
92
- const mock5Data = [
93
- { id: 1, name: "Item 1", itemType: "type2" },
94
- { id: 2, name: "Item 2", itemType: "type2" },
95
- { id: 3, name: "Item 3", itemType: "type2" },
96
- { id: 4, name: "Item 4", itemType: "type2" },
97
- { id: 5, name: "Item 5", itemType: "type2" },
98
- { id: 6, name: "Item 6", itemType: "type2" },
99
- { id: 7, name: "Item 7", itemType: "type2" },
100
- { id: 8, name: "Item 8", itemType: "type1" },
101
- { id: 9, name: "Item 9", itemType: "type1" },
102
- { id: 10, name: "Item 10", itemType: "type1" },
103
- { id: 11, name: "Item 11", itemType: "type1" },
104
- { id: 12, name: "Item 12", itemType: "type1" },
105
- { id: 13, name: "Item 13", itemType: "type1" },
106
- { id: 14, name: "Item 14", itemType: "type1" },
107
- { id: 15, name: "Item 15", itemType: "type1" },
108
- ];
109
- const mock5 = {
110
- data: mock5Data,
111
- getStableId: (index: number) => mock5Data[index].id.toString(),
112
- getItemType: (index: number) => mock5Data[index].itemType,
113
- length: mock5Data.length,
114
- };
115
-
116
- const mock6Data = [
117
- { id: 0, name: "Item 0", itemType: "type1" },
118
- { id: 1, name: "Item 1", itemType: "type1" },
119
- { id: 2, name: "Item 2", itemType: "type1" },
120
- { id: 3, name: "Item 3", itemType: "type1" },
121
- { id: 4, name: "Item 4", itemType: "type1" },
122
- { id: 5, name: "Item 5", itemType: "type1" },
123
- { id: 6, name: "Item 6", itemType: "type1" },
124
- { id: 7, name: "Item 7", itemType: "type1" },
125
- ];
126
- const mock6 = {
127
- data: mock6Data,
128
- getStableId: (index: number) => mock6Data[index].id.toString(),
129
- getItemType: (index: number) => mock6Data[index].itemType,
130
- length: mock6Data.length,
131
- };
132
-
133
- const mock7Data = [
134
- { id: 0, name: "Item 0", itemType: "type1" },
135
- { id: 2, name: "Item 2", itemType: "type1" },
136
- { id: 3, name: "Item 3", itemType: "type1" },
137
- { id: 4, name: "Item 4", itemType: "type1" },
138
- { id: 5, name: "Item 5", itemType: "type1" },
139
- { id: 6, name: "Item 6", itemType: "type1" },
140
- { id: 7, name: "Item 7", itemType: "type1" },
141
- { id: 8, name: "Item 8", itemType: "type1" },
142
- ];
143
- const mock7 = {
144
- data: mock7Data,
145
- getStableId: (index: number) => mock7Data[index].id.toString(),
146
- getItemType: (index: number) => mock7Data[index].itemType,
147
- length: mock7Data.length,
148
- };
149
-
150
- const mock8Data = [
151
- { id: 16, name: "Item 16", itemType: "type1" },
152
- { id: 17, name: "Item 17", itemType: "type1" },
153
- { id: 18, name: "Item 18", itemType: "type1" },
154
- { id: 19, name: "Item 19", itemType: "type1" },
155
- { id: 20, name: "Item 20", itemType: "type1" },
156
- { id: 1, name: "Item 1", itemType: "type1" },
157
- { id: 2, name: "Item 2", itemType: "type1" },
158
- { id: 3, name: "Item 3", itemType: "type1" },
159
- { id: 4, name: "Item 4", itemType: "type1" },
160
- { id: 5, name: "Item 5", itemType: "type1" },
161
- { id: 6, name: "Item 6", itemType: "type1" },
162
- { id: 7, name: "Item 7", itemType: "type1" },
163
- { id: 8, name: "Item 8", itemType: "type1" },
164
- { id: 9, name: "Item 9", itemType: "type1" },
165
- { id: 10, name: "Item 10", itemType: "type1" },
166
- { id: 11, name: "Item 11", itemType: "type1" },
167
- { id: 12, name: "Item 12", itemType: "type1" },
168
- { id: 13, name: "Item 13", itemType: "type1" },
169
- { id: 14, name: "Item 14", itemType: "type1" },
170
- { id: 15, name: "Item 15", itemType: "type1" },
171
- ];
172
- const mock8 = {
173
- data: mock8Data,
174
- getStableId: (index: number) => mock8Data[index].id.toString(),
175
- getItemType: (index: number) => mock8Data[index].itemType,
176
- length: mock8Data.length,
177
- };
178
-
179
- // Helper to create mock data structures
180
- const createMockData = (
181
- items: { id: string | number; itemType: string; name?: string }[]
182
- ) => {
183
- return {
184
- data: items.map((item) => ({
185
- ...item,
186
- name: item.name || `Item ${item.id}`,
187
- })),
188
- getStableId: (index: number) => items[index].id.toString(),
189
- getItemType: (index: number) => items[index].itemType,
190
- length: items.length,
191
- };
192
- };
193
-
194
- // Helper to run sync and get sorted keys from the entire keyMap
195
- const runSyncAndGetEntireKeyMapKeys = (
196
- manager: RenderStackManager,
197
- mock: {
198
- data: any[];
199
- getStableId: (index: number) => string;
200
- getItemType: (index: number) => string;
201
- length: number;
202
- },
203
- engagedIndicesOverride?: ConsecutiveNumbers
204
- ) => {
205
- const dataLength = mock.length;
206
- const engaged =
207
- engagedIndicesOverride ??
208
- new ConsecutiveNumbers(0, dataLength > 0 ? dataLength - 1 : -1);
209
- manager.sync(mock.getStableId, mock.getItemType, engaged, dataLength);
210
- return Array.from(manager.getRenderStack().keys()).sort(
211
- (keyA, keyB) => Number(keyA) - Number(keyB)
212
- );
213
- };
214
-
215
- // Helper to get keys specific to the items in a mock, after a sync
216
- const getKeysForMockItems = (
217
- manager: RenderStackManager,
218
- mockData: {
219
- data: { id: any }[];
220
- getStableId: (index: number) => string;
221
- length: number;
222
- }
223
- ) => {
224
- const stack = manager.getRenderStack();
225
- const keys = [];
226
- // Ensure we only try to get keys for items that exist in mockData
227
- for (let i = 0; i < mockData.length; i++) {
228
- const stableId = mockData.getStableId(i);
229
- for (const [key, info] of stack.entries()) {
230
- if (info.stableId === stableId) {
231
- keys.push(key);
232
- break;
233
- }
234
- }
235
- }
236
- return keys.sort((keyA, keyB) => Number(keyA) - Number(keyB));
237
- };
238
-
239
- const emptyMock = createMockData([]);
240
- const mockDataA5 = createMockData([
241
- { id: "s1", itemType: "typeA" },
242
- { id: "s2", itemType: "typeA" },
243
- { id: "s3", itemType: "typeA" },
244
- { id: "s4", itemType: "typeA" },
245
- { id: "s5", itemType: "typeA" },
246
- ]);
247
- const mockDataB3 = createMockData([
248
- { id: "s6", itemType: "typeA" },
249
- { id: "s7", itemType: "typeA" },
250
- { id: "s8", itemType: "typeA" },
251
- ]);
252
-
253
- describe("RenderStackManager", () => {
254
- it("should reuse keys from removed items when transitioning from mock1 to mock2", () => {
255
- const renderStackManager = new RenderStackManager();
256
- runSyncAndGetEntireKeyMapKeys(renderStackManager, mock1);
257
- const oldRenderStackKeys = Array.from(
258
- renderStackManager.getRenderStack().keys()
259
- ).sort((keyA, keyB) => Number(keyA) - Number(keyB));
260
-
261
- runSyncAndGetEntireKeyMapKeys(renderStackManager, mock2);
262
- const newRenderStackKeys = Array.from(
263
- renderStackManager.getRenderStack().keys()
264
- ).sort((keyA, keyB) => Number(keyA) - Number(keyB));
265
- expect(newRenderStackKeys).toEqual(oldRenderStackKeys);
266
- });
267
-
268
- it("should reuse keys changing item types when transitioning from mock3 to mock4", () => {
269
- const renderStackManager = new RenderStackManager();
270
- runSyncAndGetEntireKeyMapKeys(renderStackManager, mock3);
271
- const oldRenderStackKeys = Array.from(
272
- renderStackManager.getRenderStack().keys()
273
- ).sort((keyA, keyB) => Number(keyA) - Number(keyB));
274
-
275
- runSyncAndGetEntireKeyMapKeys(renderStackManager, mock4);
276
- const newRenderStackKeys = Array.from(
277
- renderStackManager.getRenderStack().keys()
278
- ).sort((keyA, keyB) => Number(keyA) - Number(keyB));
279
- expect(newRenderStackKeys).toEqual(oldRenderStackKeys);
280
- });
281
-
282
- it("should reuse keys changing item types when transitioning from mock4 to mock5", () => {
283
- const renderStackManager = new RenderStackManager();
284
- runSyncAndGetEntireKeyMapKeys(renderStackManager, mock4);
285
- const oldRenderStackKeys = Array.from(
286
- renderStackManager.getRenderStack().keys()
287
- ).sort((keyA, keyB) => Number(keyA) - Number(keyB));
288
-
289
- runSyncAndGetEntireKeyMapKeys(renderStackManager, mock5);
290
- const newRenderStackKeys = Array.from(
291
- renderStackManager.getRenderStack().keys()
292
- ).sort((keyA, keyB) => Number(keyA) - Number(keyB));
293
- expect(newRenderStackKeys).toEqual(oldRenderStackKeys);
294
- });
295
-
296
- it("should have all keys from mock1 when going from mock1 to mock5", () => {
297
- const renderStackManager = new RenderStackManager();
298
- runSyncAndGetEntireKeyMapKeys(renderStackManager, mock1);
299
- const oldRenderStackKeys = Array.from(
300
- renderStackManager.getRenderStack().keys()
301
- ).sort((keyA, keyB) => Number(keyA) - Number(keyB));
302
-
303
- runSyncAndGetEntireKeyMapKeys(renderStackManager, mock5);
304
- const newRenderStackKeys = Array.from(
305
- renderStackManager.getRenderStack().keys()
306
- ).sort((keyA, keyB) => Number(keyA) - Number(keyB));
307
-
308
- oldRenderStackKeys.forEach((key) => {
309
- expect(newRenderStackKeys).toContain(key);
310
- });
311
- });
312
- });
313
-
314
- describe("RenderStackManager with disableRecycling = true", () => {
315
- it("should assign new, non-recycled keys to new items when disableRecycling is true", () => {
316
- const rsm = new RenderStackManager();
317
- rsm.disableRecycling = true;
318
-
319
- // Sync with A5 first
320
- runSyncAndGetEntireKeyMapKeys(rsm, mockDataA5);
321
- const keysA5 = getKeysForMockItems(rsm, mockDataA5);
322
- expect(keysA5).toEqual(["0", "1", "2", "3", "4"]);
323
-
324
- // Sync with B3
325
- runSyncAndGetEntireKeyMapKeys(rsm, mockDataB3);
326
- const keysB3 = getKeysForMockItems(rsm, mockDataB3);
327
- expect(keysB3).toEqual(["5", "6", "7"]); // New keys for B3 items
328
-
329
- // Ensure B3 keys don't overlap with A5 keys that might remain in keyMap
330
- keysA5.forEach((keyA) => {
331
- expect(keysB3).not.toContain(keyA);
332
- });
333
-
334
- // Check the final state of the entire keyMap
335
- // After B3 sync, keys for A5 items at original indices 3,4 (stableIds "s4","s5")
336
- // should be removed because 3 >= B3.length (3) and 4 >= B3.length (3). Keys for 0,1,2 from A5 remain.
337
- const allKeysInMap = runSyncAndGetEntireKeyMapKeys(rsm, mockDataB3); // This re-syncs B3, ensuring state is for B3
338
- expect(
339
- allKeysInMap.sort((keyA, keyB) => Number(keyA) - Number(keyB))
340
- ).toEqual(["5", "6", "7"]);
341
- });
342
-
343
- it("should generate all new keys if starting with disableRecycling = true and items are removed then added", () => {
344
- const rsm = new RenderStackManager();
345
- rsm.disableRecycling = true;
346
-
347
- runSyncAndGetEntireKeyMapKeys(rsm, mockDataA5); // Assigns keys "0" through "4"
348
- runSyncAndGetEntireKeyMapKeys(rsm, emptyMock); // Sync with empty
349
- expect(getKeysForMockItems(rsm, emptyMock)).toEqual([]);
350
-
351
- runSyncAndGetEntireKeyMapKeys(rsm, mockDataB3); // Sync with new data
352
- const keysForNewItems = getKeysForMockItems(rsm, mockDataB3);
353
- expect(keysForNewItems).toEqual(["5", "6", "7"]);
354
- });
355
- });
356
-
357
- describe("RenderStackManager with maxItemsInRecyclePool", () => {
358
- it("should not recycle any keys when maxItemsInRecyclePool is 0", () => {
359
- const rsm = new RenderStackManager(0); // maxItemsInRecyclePool = 0
360
-
361
- runSyncAndGetEntireKeyMapKeys(rsm, mockDataA5);
362
- runSyncAndGetEntireKeyMapKeys(rsm, emptyMock); // Sync with empty, dataLength = 0. All keys are cleaned up.
363
-
364
- runSyncAndGetEntireKeyMapKeys(rsm, mockDataB3);
365
- const keys2 = getKeysForMockItems(rsm, mockDataB3);
366
- expect(keys2).toEqual(["5", "6", "7"]); // Expect new keys as pool was cleared by emptyMock sync
367
- });
368
-
369
- it("should effectively not recycle if intermediate sync has dataLength 0, regardless of maxPoolSize", () => {
370
- const maxPoolSize = 2;
371
- const rsm = new RenderStackManager(maxPoolSize);
372
-
373
- runSyncAndGetEntireKeyMapKeys(rsm, mockDataA5);
374
- runSyncAndGetEntireKeyMapKeys(rsm, emptyMock); // Sync with empty, dataLength = 0. All keys are cleaned up from pool and map.
375
-
376
- const mockDataA3NewIds = createMockData([
377
- { id: "s10", itemType: "typeA" },
378
- { id: "s11", itemType: "typeA" },
379
- { id: "s12", itemType: "typeA" },
380
- ]);
381
- runSyncAndGetEntireKeyMapKeys(rsm, mockDataA3NewIds);
382
- const newKeys = getKeysForMockItems(rsm, mockDataA3NewIds);
383
- // Because emptyMock sync (dataLength=0) clears all keys, these will be new.
384
- expect(newKeys).toEqual(["5", "6", "7"]);
385
- });
386
- it("should not repeat index when going from mock6 to mock7", () => {
387
- const rsm = new RenderStackManager();
388
- rsm.disableRecycling = true;
389
- runSyncAndGetEntireKeyMapKeys(rsm, mock6);
390
- runSyncAndGetEntireKeyMapKeys(rsm, mock7);
391
- const set = new Set<number>();
392
- Array.from(rsm.getRenderStack().entries()).forEach(([key, info]) => {
393
- expect(set.has(info.index)).toBe(false);
394
- set.add(info.index);
395
- });
396
- });
397
- });
398
-
399
- describe("RenderStackManager edge cases", () => {
400
- it("should handle initial sync with empty data and then add items", () => {
401
- const rsm = new RenderStackManager();
402
- runSyncAndGetEntireKeyMapKeys(rsm, emptyMock);
403
- expect(getKeysForMockItems(rsm, emptyMock)).toEqual([]);
404
-
405
- runSyncAndGetEntireKeyMapKeys(rsm, mockDataA5);
406
- expect(getKeysForMockItems(rsm, mockDataA5)).toEqual([
407
- "0",
408
- "1",
409
- "2",
410
- "3",
411
- "4",
412
- ]);
413
- });
414
-
415
- it("should generate new keys if all items removed (synced with empty) and then different items added", () => {
416
- const rsm = new RenderStackManager(); // Default large pool size
417
- runSyncAndGetEntireKeyMapKeys(rsm, mockDataA5);
418
- runSyncAndGetEntireKeyMapKeys(rsm, emptyMock); // Sync with empty, dataLength = 0. All keys are cleaned up.
419
-
420
- const mockDataA3NewIds = createMockData([
421
- { id: "s10", itemType: "typeA" },
422
- { id: "s11", itemType: "typeA" },
423
- { id: "s12", itemType: "typeA" },
424
- ]);
425
- runSyncAndGetEntireKeyMapKeys(rsm, mockDataA3NewIds);
426
- const newKeys = getKeysForMockItems(rsm, mockDataA3NewIds);
427
- // Expect new keys as the emptyMock sync (dataLength=0) cleared the pool and map.
428
- expect(newKeys).toEqual(["5", "6", "7"]);
429
- });
430
-
431
- it("should use new keys if types change completely and no compatible recycled keys exist (after empty sync)", () => {
432
- const rsm = new RenderStackManager();
433
- runSyncAndGetEntireKeyMapKeys(rsm, mockDataA5);
434
- runSyncAndGetEntireKeyMapKeys(rsm, emptyMock); // Clear with empty sync
435
-
436
- runSyncAndGetEntireKeyMapKeys(rsm, mockDataB3);
437
- const keysTypeB = getKeysForMockItems(rsm, mockDataB3);
438
- expect(keysTypeB).toEqual(["5", "6", "7"]); // Should be new keys after empty sync
439
-
440
- const mockSingleTypeA = createMockData([{ id: "s20", itemType: "typeA" }]);
441
- runSyncAndGetEntireKeyMapKeys(rsm, mockSingleTypeA);
442
- const keyForS20 = getKeysForMockItems(rsm, mockSingleTypeA);
443
- // After empty sync and B3 sync, A's pool is gone. Key counter is at 8.
444
- expect(keyForS20).toEqual(["5"]);
445
- });
446
-
447
- it("should maintain keys if data and engaged indices do not change", () => {
448
- const rsm = new RenderStackManager();
449
- runSyncAndGetEntireKeyMapKeys(rsm, mockDataA5);
450
- const keys1 = getKeysForMockItems(rsm, mockDataA5);
451
-
452
- runSyncAndGetEntireKeyMapKeys(rsm, mockDataA5);
453
- const keys2 = getKeysForMockItems(rsm, mockDataA5);
454
- expect(keys2).toEqual(keys1);
455
- });
456
-
457
- it("should not delete keys from pool if they are not visible on index changes when going from mock6 to mock7", () => {
458
- const rsm = new RenderStackManager();
459
- runSyncAndGetEntireKeyMapKeys(rsm, mock6);
460
- runSyncAndGetEntireKeyMapKeys(rsm, mock7, new ConsecutiveNumbers(3, 5));
461
- const keys = getKeysForMockItems(rsm, mock7);
462
- expect(keys).toEqual(["0", "1", "2", "3", "4", "5", "6", "7"]);
463
- });
464
-
465
- it("should not delete keys from pool if they are not visible on index changes when going from mock3 to mock8", () => {
466
- const rsm = new RenderStackManager();
467
- runSyncAndGetEntireKeyMapKeys(rsm, mock3, new ConsecutiveNumbers(0, 10));
468
- runSyncAndGetEntireKeyMapKeys(rsm, mock8, new ConsecutiveNumbers(0, 13));
469
- const keys = getKeysForMockItems(rsm, mock8);
470
- expect(keys).toEqual([
471
- "0",
472
- "1",
473
- "2",
474
- "3",
475
- "4",
476
- "5",
477
- "6",
478
- "7",
479
- "8",
480
- "9",
481
- "10",
482
- "11",
483
- "12",
484
- "13",
485
- ]);
486
- });
487
-
488
- it("should delete keys from pool if they are not visible on index changes when going from mock6 to mock7 (disableRecycling = true)", () => {
489
- const rsm = new RenderStackManager();
490
- rsm.disableRecycling = true;
491
- runSyncAndGetEntireKeyMapKeys(rsm, mock6);
492
- runSyncAndGetEntireKeyMapKeys(rsm, mock7, new ConsecutiveNumbers(3, 5));
493
- const keys = getKeysForMockItems(rsm, mock7);
494
- expect(keys).toEqual(["0", "2", "3", "4", "5", "6", "8"]);
495
- });
496
-
497
- it("should not delete keys from pool if they are not visible on index changes when going from mock6 to mock7 (all engaged)", () => {
498
- const rsm = new RenderStackManager();
499
- runSyncAndGetEntireKeyMapKeys(rsm, mock6);
500
- runSyncAndGetEntireKeyMapKeys(rsm, mock7);
501
- const keys = getKeysForMockItems(rsm, mock7);
502
- expect(keys).toEqual(["0", "1", "2", "3", "4", "5", "6", "7"]);
503
- });
504
-
505
- it("should delete keys from pool if they are not visible on index changes when going from mock6 to mock7 (all engaged,disableRecycling = true)", () => {
506
- const rsm = new RenderStackManager();
507
- rsm.disableRecycling = true;
508
- runSyncAndGetEntireKeyMapKeys(rsm, mock6);
509
- runSyncAndGetEntireKeyMapKeys(rsm, mock7);
510
- const keys = getKeysForMockItems(rsm, mock7);
511
- expect(keys).toEqual(["0", "2", "3", "4", "5", "6", "7", "8"]);
512
- });
513
-
514
- it("should correctly handle partial replacement of items, reusing keys for stable items and recycling for replaced ones", () => {
515
- const rsm = new RenderStackManager();
516
- const initialMock = createMockData([
517
- { id: "s1", itemType: "typeA" },
518
- { id: "s2", itemType: "typeA" },
519
- { id: "s3", itemType: "typeA" },
520
- { id: "s4", itemType: "typeA" },
521
- ]);
522
- runSyncAndGetEntireKeyMapKeys(rsm, initialMock);
523
- const initialKeyMap = new Map<string, string>();
524
- // Populate initialKeyMap correctly using getKeysForMockItems and stable IDs
525
- initialMock.data.forEach((itemData, index) => {
526
- // Get the keys for the initialMock items AFTER the sync.
527
- const currentKeysForInitialMock = getKeysForMockItems(rsm, initialMock);
528
- const key = currentKeysForInitialMock[index]; // Assumes keys are in order of data
529
- if (key !== undefined) {
530
- // Ensure key exists before setting
531
- initialKeyMap.set(itemData.id.toString(), key);
532
- }
533
- });
534
-
535
- const keyForS1 = initialKeyMap.get("s1")!;
536
- const keyForS2 = initialKeyMap.get("s2")!;
537
- const keyForS3 = initialKeyMap.get("s3")!;
538
- const keyForS4 = initialKeyMap.get("s4")!;
539
-
540
- const partiallyReplacedMock = createMockData([
541
- { id: "s1", itemType: "typeA" },
542
- { id: "s5", itemType: "typeA" },
543
- { id: "s6", itemType: "typeA" },
544
- { id: "s4", itemType: "typeA" },
545
- ]);
546
- runSyncAndGetEntireKeyMapKeys(rsm, partiallyReplacedMock);
547
- const finalKeyMap = new Map<string, string>();
548
- partiallyReplacedMock.data.forEach((itemData, index) => {
549
- // Get keys for partiallyReplacedMock items AFTER the sync.
550
- const currentKeysForPartialMock = getKeysForMockItems(
551
- rsm,
552
- partiallyReplacedMock
553
- );
554
- const key = currentKeysForPartialMock[index]; // Assumes keys are in order
555
- if (key !== undefined) {
556
- // Ensure key exists
557
- finalKeyMap.set(itemData.id.toString(), key);
558
- }
559
- });
560
-
561
- expect(finalKeyMap.get("s1")).toBe(keyForS1);
562
- expect(finalKeyMap.get("s4")).toBe(keyForS4);
563
- expect([finalKeyMap.get("s5"), finalKeyMap.get("s6")]).toEqual(
564
- expect.arrayContaining([keyForS2, keyForS3])
565
- );
566
- expect(finalKeyMap.get("s5")).not.toBe(finalKeyMap.get("s6"));
567
-
568
- const finalKeysForCurrentItems = getKeysForMockItems(
569
- rsm,
570
- partiallyReplacedMock
571
- );
572
- expect(finalKeysForCurrentItems).toEqual(["0", "1", "2", "3"]);
573
- });
574
- });