@shopify/flash-list 1.8.0 → 2.0.0-alpha.10

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 (317) hide show
  1. package/README.md +179 -27
  2. package/dist/AnimatedFlashList.d.ts +0 -1
  3. package/dist/AnimatedFlashList.d.ts.map +1 -1
  4. package/dist/FlashList.js +2 -3
  5. package/dist/FlashList.js.map +1 -1
  6. package/dist/FlashListProps.d.ts +68 -5
  7. package/dist/FlashListProps.d.ts.map +1 -1
  8. package/dist/GridLayoutProviderWithProps.js +1 -2
  9. package/dist/GridLayoutProviderWithProps.js.map +1 -1
  10. package/dist/MasonryFlashList.d.ts +2 -2
  11. package/dist/MasonryFlashList.d.ts.map +1 -1
  12. package/dist/MasonryFlashList.js.map +1 -1
  13. package/dist/PureComponentWrapper.js +1 -1
  14. package/dist/PureComponentWrapper.js.map +1 -1
  15. package/dist/__tests__/AverageWindow.test.js +35 -0
  16. package/dist/__tests__/AverageWindow.test.js.map +1 -1
  17. package/dist/__tests__/ConsecutiveNumbers.test.d.ts +2 -0
  18. package/dist/__tests__/ConsecutiveNumbers.test.d.ts.map +1 -0
  19. package/dist/__tests__/ConsecutiveNumbers.test.js +224 -0
  20. package/dist/__tests__/ConsecutiveNumbers.test.js.map +1 -0
  21. package/dist/__tests__/FlashList.test.js.map +1 -1
  22. package/dist/__tests__/GridLayoutManager.test.d.ts +2 -0
  23. package/dist/__tests__/GridLayoutManager.test.d.ts.map +1 -0
  24. package/dist/__tests__/GridLayoutManager.test.js +69 -0
  25. package/dist/__tests__/GridLayoutManager.test.js.map +1 -0
  26. package/dist/__tests__/GridLayoutProviderWithProps.test.js.map +1 -1
  27. package/dist/__tests__/LinearLayoutManager.test.d.ts +2 -0
  28. package/dist/__tests__/LinearLayoutManager.test.d.ts.map +1 -0
  29. package/dist/__tests__/LinearLayoutManager.test.js +140 -0
  30. package/dist/__tests__/LinearLayoutManager.test.js.map +1 -0
  31. package/dist/__tests__/MasonryFlashList.test.js.map +1 -1
  32. package/dist/__tests__/MasonryLayoutManager.test.d.ts +2 -0
  33. package/dist/__tests__/MasonryLayoutManager.test.d.ts.map +1 -0
  34. package/dist/__tests__/MasonryLayoutManager.test.js +148 -0
  35. package/dist/__tests__/MasonryLayoutManager.test.js.map +1 -0
  36. package/dist/__tests__/RecycleKeyManager.test.d.ts +2 -0
  37. package/dist/__tests__/RecycleKeyManager.test.d.ts.map +1 -0
  38. package/dist/__tests__/RecycleKeyManager.test.js +210 -0
  39. package/dist/__tests__/RecycleKeyManager.test.js.map +1 -0
  40. package/dist/__tests__/RecyclerView.test.d.ts +2 -0
  41. package/dist/__tests__/RecyclerView.test.d.ts.map +1 -0
  42. package/dist/__tests__/RecyclerView.test.js +59 -0
  43. package/dist/__tests__/RecyclerView.test.js.map +1 -0
  44. package/dist/__tests__/ViewabilityHelper.test.js.map +1 -1
  45. package/dist/__tests__/findVisibleIndex.test.d.ts +2 -0
  46. package/dist/__tests__/findVisibleIndex.test.d.ts.map +1 -0
  47. package/dist/__tests__/findVisibleIndex.test.js +259 -0
  48. package/dist/__tests__/findVisibleIndex.test.js.map +1 -0
  49. package/dist/__tests__/helpers/createLayoutManager.d.ts +34 -0
  50. package/dist/__tests__/helpers/createLayoutManager.d.ts.map +1 -0
  51. package/dist/__tests__/helpers/createLayoutManager.js +111 -0
  52. package/dist/__tests__/helpers/createLayoutManager.js.map +1 -0
  53. package/dist/__tests__/helpers/mountFlashList.d.ts +2 -2
  54. package/dist/__tests__/helpers/mountFlashList.d.ts.map +1 -1
  55. package/dist/__tests__/helpers/mountFlashList.js +2 -2
  56. package/dist/__tests__/helpers/mountFlashList.js.map +1 -1
  57. package/dist/__tests__/helpers/mountMasonryFlashList.d.ts +2 -2
  58. package/dist/__tests__/helpers/mountMasonryFlashList.d.ts.map +1 -1
  59. package/dist/__tests__/helpers/mountMasonryFlashList.js +2 -2
  60. package/dist/__tests__/helpers/mountMasonryFlashList.js.map +1 -1
  61. package/dist/__tests__/useBlankAreaTracker.test.js.map +1 -1
  62. package/dist/__tests__/useUnmountAwareCallbacks.test.d.ts +2 -0
  63. package/dist/__tests__/useUnmountAwareCallbacks.test.d.ts.map +1 -0
  64. package/dist/__tests__/useUnmountAwareCallbacks.test.js +185 -0
  65. package/dist/__tests__/useUnmountAwareCallbacks.test.js.map +1 -0
  66. package/dist/benchmark/AutoScrollHelper.js +2 -2
  67. package/dist/benchmark/AutoScrollHelper.js.map +1 -1
  68. package/dist/benchmark/JSFPSMonitor.js.map +1 -1
  69. package/dist/benchmark/roundToDecimalPlaces.js +1 -2
  70. package/dist/benchmark/roundToDecimalPlaces.js.map +1 -1
  71. package/dist/benchmark/useBenchmark.js +2 -3
  72. package/dist/benchmark/useBenchmark.js.map +1 -1
  73. package/dist/benchmark/useBlankAreaTracker.js +1 -2
  74. package/dist/benchmark/useBlankAreaTracker.js.map +1 -1
  75. package/dist/benchmark/useDataMultiplier.js +1 -2
  76. package/dist/benchmark/useDataMultiplier.js.map +1 -1
  77. package/dist/benchmark/useFlatListBenchmark.d.ts +0 -1
  78. package/dist/benchmark/useFlatListBenchmark.d.ts.map +1 -1
  79. package/dist/benchmark/useFlatListBenchmark.js +1 -2
  80. package/dist/benchmark/useFlatListBenchmark.js.map +1 -1
  81. package/dist/enableNewCore.d.ts +3 -0
  82. package/dist/enableNewCore.d.ts.map +1 -0
  83. package/dist/enableNewCore.js +25 -0
  84. package/dist/enableNewCore.js.map +1 -0
  85. package/dist/errors/CustomError.js.map +1 -1
  86. package/dist/index.d.ts +6 -0
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +34 -8
  89. package/dist/index.js.map +1 -1
  90. package/dist/native/auto-layout/AutoLayoutView.d.ts +1 -1
  91. package/dist/native/auto-layout/AutoLayoutView.d.ts.map +1 -1
  92. package/dist/native/auto-layout/AutoLayoutView.js +1 -1
  93. package/dist/native/auto-layout/AutoLayoutView.js.map +1 -1
  94. package/dist/native/auto-layout/AutoLayoutViewNativeComponent.d.ts.map +1 -1
  95. package/dist/native/auto-layout/AutoLayoutViewNativeComponentProps.d.ts +1 -1
  96. package/dist/native/auto-layout/AutoLayoutViewNativeComponentProps.d.ts.map +1 -1
  97. package/dist/native/config/PlatformHelper.android.d.ts +2 -0
  98. package/dist/native/config/PlatformHelper.android.d.ts.map +1 -1
  99. package/dist/native/config/PlatformHelper.android.js +2 -0
  100. package/dist/native/config/PlatformHelper.android.js.map +1 -1
  101. package/dist/native/config/PlatformHelper.d.ts +2 -0
  102. package/dist/native/config/PlatformHelper.d.ts.map +1 -1
  103. package/dist/native/config/PlatformHelper.ios.d.ts +2 -0
  104. package/dist/native/config/PlatformHelper.ios.d.ts.map +1 -1
  105. package/dist/native/config/PlatformHelper.ios.js +2 -0
  106. package/dist/native/config/PlatformHelper.ios.js.map +1 -1
  107. package/dist/native/config/PlatformHelper.js +2 -0
  108. package/dist/native/config/PlatformHelper.js.map +1 -1
  109. package/dist/native/config/PlatformHelper.web.d.ts +2 -0
  110. package/dist/native/config/PlatformHelper.web.d.ts.map +1 -1
  111. package/dist/native/config/PlatformHelper.web.js +3 -1
  112. package/dist/native/config/PlatformHelper.web.js.map +1 -1
  113. package/dist/recyclerview/RecycleKeyManager.d.ts +82 -0
  114. package/dist/recyclerview/RecycleKeyManager.d.ts.map +1 -0
  115. package/dist/recyclerview/RecycleKeyManager.js +135 -0
  116. package/dist/recyclerview/RecycleKeyManager.js.map +1 -0
  117. package/dist/recyclerview/RecyclerView.d.ts +12 -0
  118. package/dist/recyclerview/RecyclerView.d.ts.map +1 -0
  119. package/dist/recyclerview/RecyclerView.js +300 -0
  120. package/dist/recyclerview/RecyclerView.js.map +1 -0
  121. package/dist/recyclerview/RecyclerViewContextProvider.d.ts +11 -0
  122. package/dist/recyclerview/RecyclerViewContextProvider.d.ts.map +1 -0
  123. package/dist/recyclerview/RecyclerViewContextProvider.js +11 -0
  124. package/dist/recyclerview/RecyclerViewContextProvider.js.map +1 -0
  125. package/dist/recyclerview/RecyclerViewManager.d.ts +62 -0
  126. package/dist/recyclerview/RecyclerViewManager.d.ts.map +1 -0
  127. package/dist/recyclerview/RecyclerViewManager.js +371 -0
  128. package/dist/recyclerview/RecyclerViewManager.js.map +1 -0
  129. package/dist/recyclerview/RecyclerViewProps.d.ts +9 -0
  130. package/dist/recyclerview/RecyclerViewProps.d.ts.map +1 -0
  131. package/dist/recyclerview/RecyclerViewProps.js +3 -0
  132. package/dist/recyclerview/RecyclerViewProps.js.map +1 -0
  133. package/dist/recyclerview/ViewHolder.d.ts +45 -0
  134. package/dist/recyclerview/ViewHolder.d.ts.map +1 -0
  135. package/dist/recyclerview/ViewHolder.js +96 -0
  136. package/dist/recyclerview/ViewHolder.js.map +1 -0
  137. package/dist/recyclerview/ViewHolderCollection.d.ts +57 -0
  138. package/dist/recyclerview/ViewHolderCollection.d.ts.map +1 -0
  139. package/dist/recyclerview/ViewHolderCollection.js +74 -0
  140. package/dist/recyclerview/ViewHolderCollection.js.map +1 -0
  141. package/dist/recyclerview/components/CompatScroller.d.ts +7 -0
  142. package/dist/recyclerview/components/CompatScroller.d.ts.map +1 -0
  143. package/dist/recyclerview/components/CompatScroller.js +8 -0
  144. package/dist/recyclerview/components/CompatScroller.js.map +1 -0
  145. package/dist/recyclerview/components/CompatView.d.ts +7 -0
  146. package/dist/recyclerview/components/CompatView.d.ts.map +1 -0
  147. package/dist/recyclerview/components/CompatView.js +8 -0
  148. package/dist/recyclerview/components/CompatView.js.map +1 -0
  149. package/dist/recyclerview/components/ScrollAnchor.d.ts +29 -0
  150. package/dist/recyclerview/components/ScrollAnchor.d.ts.map +1 -0
  151. package/dist/recyclerview/components/ScrollAnchor.js +34 -0
  152. package/dist/recyclerview/components/ScrollAnchor.js.map +1 -0
  153. package/dist/recyclerview/components/StickyHeaders.d.ts +38 -0
  154. package/dist/recyclerview/components/StickyHeaders.d.ts.map +1 -0
  155. package/dist/recyclerview/components/StickyHeaders.js +111 -0
  156. package/dist/recyclerview/components/StickyHeaders.js.map +1 -0
  157. package/dist/recyclerview/helpers/ConsecutiveNumbers.d.ts +51 -0
  158. package/dist/recyclerview/helpers/ConsecutiveNumbers.d.ts.map +1 -0
  159. package/dist/recyclerview/helpers/ConsecutiveNumbers.js +122 -0
  160. package/dist/recyclerview/helpers/ConsecutiveNumbers.js.map +1 -0
  161. package/dist/recyclerview/helpers/EngagedIndicesTracker.d.ts +105 -0
  162. package/dist/recyclerview/helpers/EngagedIndicesTracker.d.ts.map +1 -0
  163. package/dist/recyclerview/helpers/EngagedIndicesTracker.js +209 -0
  164. package/dist/recyclerview/helpers/EngagedIndicesTracker.js.map +1 -0
  165. package/dist/recyclerview/helpers/RenderTimeTracker.d.ts +10 -0
  166. package/dist/recyclerview/helpers/RenderTimeTracker.d.ts.map +1 -0
  167. package/dist/recyclerview/helpers/RenderTimeTracker.js +39 -0
  168. package/dist/recyclerview/helpers/RenderTimeTracker.js.map +1 -0
  169. package/dist/recyclerview/helpers/VelocityTracker.d.ts +29 -0
  170. package/dist/recyclerview/helpers/VelocityTracker.d.ts.map +1 -0
  171. package/dist/recyclerview/helpers/VelocityTracker.js +70 -0
  172. package/dist/recyclerview/helpers/VelocityTracker.js.map +1 -0
  173. package/dist/recyclerview/hooks/useBoundDetection.d.ts +18 -0
  174. package/dist/recyclerview/hooks/useBoundDetection.d.ts.map +1 -0
  175. package/dist/recyclerview/hooks/useBoundDetection.js +101 -0
  176. package/dist/recyclerview/hooks/useBoundDetection.js.map +1 -0
  177. package/dist/recyclerview/hooks/useLayoutState.d.ts +12 -0
  178. package/dist/recyclerview/hooks/useLayoutState.d.ts.map +1 -0
  179. package/dist/recyclerview/hooks/useLayoutState.js +42 -0
  180. package/dist/recyclerview/hooks/useLayoutState.js.map +1 -0
  181. package/dist/recyclerview/hooks/useMappingHelper.d.ts +9 -0
  182. package/dist/recyclerview/hooks/useMappingHelper.d.ts.map +1 -0
  183. package/dist/recyclerview/hooks/useMappingHelper.js +19 -0
  184. package/dist/recyclerview/hooks/useMappingHelper.js.map +1 -0
  185. package/dist/recyclerview/hooks/useOnLoad.d.ts +25 -0
  186. package/dist/recyclerview/hooks/useOnLoad.d.ts.map +1 -0
  187. package/dist/recyclerview/hooks/useOnLoad.js +74 -0
  188. package/dist/recyclerview/hooks/useOnLoad.js.map +1 -0
  189. package/dist/recyclerview/hooks/useRecyclerViewController.d.ts +72 -0
  190. package/dist/recyclerview/hooks/useRecyclerViewController.d.ts.map +1 -0
  191. package/dist/recyclerview/hooks/useRecyclerViewController.js +424 -0
  192. package/dist/recyclerview/hooks/useRecyclerViewController.js.map +1 -0
  193. package/dist/recyclerview/hooks/useRecyclerViewManager.d.ts +8 -0
  194. package/dist/recyclerview/hooks/useRecyclerViewManager.d.ts.map +1 -0
  195. package/dist/recyclerview/hooks/useRecyclerViewManager.js +30 -0
  196. package/dist/recyclerview/hooks/useRecyclerViewManager.js.map +1 -0
  197. package/dist/recyclerview/hooks/useRecyclingState.d.ts +16 -0
  198. package/dist/recyclerview/hooks/useRecyclingState.d.ts.map +1 -0
  199. package/dist/recyclerview/hooks/useRecyclingState.js +53 -0
  200. package/dist/recyclerview/hooks/useRecyclingState.js.map +1 -0
  201. package/dist/recyclerview/hooks/useSecondaryProps.d.ts +27 -0
  202. package/dist/recyclerview/hooks/useSecondaryProps.d.ts.map +1 -0
  203. package/dist/recyclerview/hooks/useSecondaryProps.js +96 -0
  204. package/dist/recyclerview/hooks/useSecondaryProps.js.map +1 -0
  205. package/dist/recyclerview/hooks/useUnmountAwareCallbacks.d.ts +8 -0
  206. package/dist/recyclerview/hooks/useUnmountAwareCallbacks.d.ts.map +1 -0
  207. package/dist/recyclerview/hooks/useUnmountAwareCallbacks.js +34 -0
  208. package/dist/recyclerview/hooks/useUnmountAwareCallbacks.js.map +1 -0
  209. package/dist/recyclerview/hooks/useUnmountFlag.d.ts +10 -0
  210. package/dist/recyclerview/hooks/useUnmountFlag.d.ts.map +1 -0
  211. package/dist/recyclerview/hooks/useUnmountFlag.js +28 -0
  212. package/dist/recyclerview/hooks/useUnmountFlag.js.map +1 -0
  213. package/dist/recyclerview/layout-managers/GridLayoutManager.d.ts +65 -0
  214. package/dist/recyclerview/layout-managers/GridLayoutManager.d.ts.map +1 -0
  215. package/dist/recyclerview/layout-managers/GridLayoutManager.js +201 -0
  216. package/dist/recyclerview/layout-managers/GridLayoutManager.js.map +1 -0
  217. package/dist/recyclerview/layout-managers/LayoutManager.d.ts +282 -0
  218. package/dist/recyclerview/layout-managers/LayoutManager.d.ts.map +1 -0
  219. package/dist/recyclerview/layout-managers/LayoutManager.js +254 -0
  220. package/dist/recyclerview/layout-managers/LayoutManager.js.map +1 -0
  221. package/dist/recyclerview/layout-managers/LinearLayoutManager.d.ts +51 -0
  222. package/dist/recyclerview/layout-managers/LinearLayoutManager.d.ts.map +1 -0
  223. package/dist/recyclerview/layout-managers/LinearLayoutManager.js +191 -0
  224. package/dist/recyclerview/layout-managers/LinearLayoutManager.js.map +1 -0
  225. package/dist/recyclerview/layout-managers/MasonryLayoutManager.d.ts +73 -0
  226. package/dist/recyclerview/layout-managers/MasonryLayoutManager.d.ts.map +1 -0
  227. package/dist/recyclerview/layout-managers/MasonryLayoutManager.js +272 -0
  228. package/dist/recyclerview/layout-managers/MasonryLayoutManager.js.map +1 -0
  229. package/dist/recyclerview/utils/adjustOffsetForRTL.d.ts +12 -0
  230. package/dist/recyclerview/utils/adjustOffsetForRTL.d.ts.map +1 -0
  231. package/dist/recyclerview/utils/adjustOffsetForRTL.js +17 -0
  232. package/dist/recyclerview/utils/adjustOffsetForRTL.js.map +1 -0
  233. package/dist/recyclerview/utils/componentUtils.d.ts +19 -0
  234. package/dist/recyclerview/utils/componentUtils.d.ts.map +1 -0
  235. package/dist/recyclerview/utils/componentUtils.js +32 -0
  236. package/dist/recyclerview/utils/componentUtils.js.map +1 -0
  237. package/dist/recyclerview/utils/findVisibleIndex.d.ts +24 -0
  238. package/dist/recyclerview/utils/findVisibleIndex.d.ts.map +1 -0
  239. package/dist/recyclerview/utils/findVisibleIndex.js +80 -0
  240. package/dist/recyclerview/utils/findVisibleIndex.js.map +1 -0
  241. package/dist/recyclerview/utils/measureLayout.d.ts +52 -0
  242. package/dist/recyclerview/utils/measureLayout.d.ts.map +1 -0
  243. package/dist/recyclerview/utils/measureLayout.js +107 -0
  244. package/dist/recyclerview/utils/measureLayout.js.map +1 -0
  245. package/dist/recyclerview/utils/measureLayout.web.d.ts +29 -0
  246. package/dist/recyclerview/utils/measureLayout.web.d.ts.map +1 -0
  247. package/dist/recyclerview/utils/measureLayout.web.js +89 -0
  248. package/dist/recyclerview/utils/measureLayout.web.js.map +1 -0
  249. package/dist/specs/AutoLayoutNativeComponent.d.ts +1 -2
  250. package/dist/specs/AutoLayoutNativeComponent.d.ts.map +1 -1
  251. package/dist/specs/CellContainerNativeComponent.d.ts +0 -1
  252. package/dist/specs/CellContainerNativeComponent.d.ts.map +1 -1
  253. package/dist/tsconfig.tsbuildinfo +1 -1
  254. package/dist/utils/AverageWindow.d.ts +13 -0
  255. package/dist/utils/AverageWindow.d.ts.map +1 -1
  256. package/dist/utils/AverageWindow.js +30 -1
  257. package/dist/utils/AverageWindow.js.map +1 -1
  258. package/dist/utils/ContentContainerUtils.d.ts.map +1 -1
  259. package/dist/utils/ContentContainerUtils.js.map +1 -1
  260. package/dist/viewability/ViewabilityHelper.js.map +1 -1
  261. package/dist/viewability/ViewabilityManager.d.ts.map +1 -1
  262. package/dist/viewability/ViewabilityManager.js.map +1 -1
  263. package/package.json +4 -3
  264. package/src/FlashList.tsx +1 -1
  265. package/src/FlashListProps.ts +73 -2
  266. package/src/__tests__/AverageWindow.test.ts +49 -1
  267. package/src/__tests__/ConsecutiveNumbers.test.ts +232 -0
  268. package/src/__tests__/GridLayoutManager.test.ts +113 -0
  269. package/src/__tests__/LinearLayoutManager.test.ts +227 -0
  270. package/src/__tests__/MasonryLayoutManager.test.ts +202 -0
  271. package/src/__tests__/RecycleKeyManager.test.ts +254 -0
  272. package/src/__tests__/RecyclerView.test.tsx +69 -0
  273. package/src/__tests__/findVisibleIndex.test.ts +369 -0
  274. package/src/__tests__/helpers/createLayoutManager.ts +142 -0
  275. package/src/__tests__/useUnmountAwareCallbacks.test.tsx +285 -0
  276. package/src/enableNewCore.ts +24 -0
  277. package/src/index.ts +27 -0
  278. package/src/native/config/PlatformHelper.android.ts +2 -0
  279. package/src/native/config/PlatformHelper.ios.ts +2 -0
  280. package/src/native/config/PlatformHelper.ts +2 -0
  281. package/src/native/config/PlatformHelper.web.ts +3 -1
  282. package/src/recyclerview/RecycleKeyManager.ts +185 -0
  283. package/src/recyclerview/RecyclerView.tsx +535 -0
  284. package/src/recyclerview/RecyclerViewContextProvider.ts +20 -0
  285. package/src/recyclerview/RecyclerViewManager.ts +434 -0
  286. package/src/recyclerview/RecyclerViewProps.ts +11 -0
  287. package/src/recyclerview/ViewHolder.tsx +178 -0
  288. package/src/recyclerview/ViewHolderCollection.tsx +165 -0
  289. package/src/recyclerview/components/CompatScroller.ts +9 -0
  290. package/src/recyclerview/components/CompatView.ts +9 -0
  291. package/src/recyclerview/components/ScrollAnchor.tsx +54 -0
  292. package/src/recyclerview/components/StickyHeaders.tsx +204 -0
  293. package/src/recyclerview/helpers/ConsecutiveNumbers.ts +120 -0
  294. package/src/recyclerview/helpers/EngagedIndicesTracker.ts +302 -0
  295. package/src/recyclerview/helpers/RenderTimeTracker.ts +38 -0
  296. package/src/recyclerview/helpers/VelocityTracker.ts +77 -0
  297. package/src/recyclerview/hooks/useBoundDetection.ts +127 -0
  298. package/src/recyclerview/hooks/useLayoutState.ts +46 -0
  299. package/src/recyclerview/hooks/useMappingHelper.ts +20 -0
  300. package/src/recyclerview/hooks/useOnLoad.ts +81 -0
  301. package/src/recyclerview/hooks/useRecyclerViewController.tsx +546 -0
  302. package/src/recyclerview/hooks/useRecyclerViewManager.ts +34 -0
  303. package/src/recyclerview/hooks/useRecyclingState.ts +63 -0
  304. package/src/recyclerview/hooks/useSecondaryProps.tsx +124 -0
  305. package/src/recyclerview/hooks/useUnmountAwareCallbacks.ts +37 -0
  306. package/src/recyclerview/hooks/useUnmountFlag.ts +26 -0
  307. package/src/recyclerview/layout-managers/GridLayoutManager.ts +212 -0
  308. package/src/recyclerview/layout-managers/LayoutManager.ts +498 -0
  309. package/src/recyclerview/layout-managers/LinearLayoutManager.ts +171 -0
  310. package/src/recyclerview/layout-managers/MasonryLayoutManager.ts +301 -0
  311. package/src/recyclerview/utils/adjustOffsetForRTL.ts +17 -0
  312. package/src/recyclerview/utils/componentUtils.ts +28 -0
  313. package/src/recyclerview/utils/findVisibleIndex.ts +93 -0
  314. package/src/recyclerview/utils/measureLayout.ts +128 -0
  315. package/src/recyclerview/utils/measureLayout.web.ts +104 -0
  316. package/src/utils/AverageWindow.ts +33 -0
  317. package/src/viewability/ViewToken.ts +1 -1
@@ -0,0 +1,434 @@
1
+ import ViewabilityManager from "../viewability/ViewabilityManager";
2
+
3
+ import { ConsecutiveNumbers } from "./helpers/ConsecutiveNumbers";
4
+ import { RVGridLayoutManagerImpl } from "./layout-managers/GridLayoutManager";
5
+ import {
6
+ RVDimension,
7
+ RVLayoutInfo,
8
+ RVLayoutManager,
9
+ } from "./layout-managers/LayoutManager";
10
+ import { RVLinearLayoutManagerImpl } from "./layout-managers/LinearLayoutManager";
11
+ import { RVMasonryLayoutManagerImpl } from "./layout-managers/MasonryLayoutManager";
12
+ import { RecycleKeyManagerImpl, RecycleKeyManager } from "./RecycleKeyManager";
13
+ import { RecyclerViewProps } from "./RecyclerViewProps";
14
+ import {
15
+ RVEngagedIndicesTracker,
16
+ RVEngagedIndicesTrackerImpl,
17
+ Velocity,
18
+ } from "./helpers/EngagedIndicesTracker";
19
+
20
+ // Abstracts layout manager, key manager and viewability manager and generates render stack (progressively on load)
21
+ export class RecyclerViewManager<T> {
22
+ private initialDrawBatchSize = 1;
23
+ private engagedIndicesTracker: RVEngagedIndicesTracker;
24
+ private recycleKeyManager: RecycleKeyManager;
25
+ private layoutManager?: RVLayoutManager;
26
+ // Map of index to key
27
+ private renderStack: Map<number, string> = new Map();
28
+ private isFirstLayoutComplete = false;
29
+ private hasRenderedProgressively = false;
30
+ private props: RecyclerViewProps<T>;
31
+ private itemViewabilityManager: ViewabilityManager<T>;
32
+ private allocatedKeyTracker: Set<string> = new Set();
33
+ private _isDisposed = false;
34
+
35
+ public disableRecycling = false;
36
+ public firstItemOffset = 0;
37
+ public ignoreScrollEvents = false;
38
+
39
+ public get isOffsetProjectionEnabled() {
40
+ return this.engagedIndicesTracker.enableOffsetProjection;
41
+ }
42
+
43
+ public get isDisposed() {
44
+ return this._isDisposed;
45
+ }
46
+
47
+ constructor(props: RecyclerViewProps<T>) {
48
+ this.props = props;
49
+ this.engagedIndicesTracker = new RVEngagedIndicesTrackerImpl();
50
+ this.recycleKeyManager = new RecycleKeyManagerImpl();
51
+ this.itemViewabilityManager = new ViewabilityManager<T>(this as any);
52
+ }
53
+
54
+ // updates render stack based on the engaged indices which are sorted. Recycles unused keys.
55
+ // TODO: Write comprehensive tests for this function
56
+ private updateRenderStack = (engagedIndices: ConsecutiveNumbers): void => {
57
+ // console.log("updateRenderStack", engagedIndices);
58
+
59
+ this.allocatedKeyTracker.clear();
60
+ const newRenderStack = new Map<number, string>();
61
+ for (const [index, key] of this.renderStack) {
62
+ if (!engagedIndices.includes(index)) {
63
+ this.recycleKeyManager.recycleKey(key);
64
+ }
65
+ }
66
+ if (this.disableRecycling) {
67
+ this.recycleKeyManager.clearPool();
68
+ }
69
+ for (const index of engagedIndices) {
70
+ const currentKey = this.renderStack.get(index);
71
+
72
+ if (
73
+ currentKey &&
74
+ !this.disableRecycling &&
75
+ !this.allocatedKeyTracker.has(currentKey)
76
+ ) {
77
+ this.recycleKeyManager.recycleKey(currentKey);
78
+ }
79
+
80
+ const newKey = this.recycleKeyManager.getKey(
81
+ this.getItemType(index),
82
+ this.getStableId(index),
83
+ currentKey
84
+ );
85
+ this.allocatedKeyTracker.add(newKey);
86
+ newRenderStack.set(index, newKey);
87
+ }
88
+ // DANGER
89
+ for (const [index, key] of this.renderStack) {
90
+ if (
91
+ this.recycleKeyManager.hasKeyInPool(key) &&
92
+ !newRenderStack.has(index) &&
93
+ index < (this.props.data?.length ?? 0)
94
+ ) {
95
+ this.allocatedKeyTracker.add(key);
96
+ newRenderStack.set(index, key);
97
+ }
98
+ }
99
+
100
+ this.renderStack = newRenderStack;
101
+ };
102
+
103
+ setOffsetProjectionEnabled(value: boolean) {
104
+ this.engagedIndicesTracker.enableOffsetProjection = value;
105
+ }
106
+
107
+ updateProps(props: RecyclerViewProps<T>) {
108
+ this.props = props;
109
+ this.engagedIndicesTracker.drawDistance =
110
+ props.drawDistance ?? this.engagedIndicesTracker.drawDistance;
111
+ if (this.props.drawDistance === 0) {
112
+ this.initialDrawBatchSize = 1;
113
+ } else {
114
+ this.initialDrawBatchSize = (props.numColumns ?? 1) * 2;
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Updates the scroll offset and returns the engaged indices if any
120
+ * @param offset
121
+ * @param velocity
122
+ */
123
+ updateScrollOffset(
124
+ offset: number,
125
+ velocity?: Velocity
126
+ ): ConsecutiveNumbers | undefined {
127
+ if (this.layoutManager && !this.isDisposed) {
128
+ const engagedIndices = this.engagedIndicesTracker.updateScrollOffset(
129
+ offset - this.firstItemOffset,
130
+ velocity,
131
+ this.layoutManager
132
+ );
133
+
134
+ if (engagedIndices) {
135
+ this.updateRenderStack(engagedIndices);
136
+ return engagedIndices;
137
+ }
138
+ }
139
+ return undefined;
140
+ }
141
+
142
+ updateAverageRenderTime(time: number) {
143
+ this.engagedIndicesTracker.averageRenderTime = time;
144
+ }
145
+
146
+ getIsFirstLayoutComplete() {
147
+ return this.isFirstLayoutComplete;
148
+ }
149
+
150
+ getLayout(index: number) {
151
+ if (!this.layoutManager) {
152
+ throw new Error(
153
+ "LayoutManager is not initialized, layout info is unavailable"
154
+ );
155
+ }
156
+ return this.layoutManager.getLayout(index);
157
+ }
158
+
159
+ // Doesn't include header / foot etc
160
+ getChildContainerDimensions() {
161
+ if (!this.layoutManager) {
162
+ throw new Error(
163
+ "LayoutManager is not initialized, child container layout is unavailable"
164
+ );
165
+ }
166
+ return this.layoutManager.getLayoutSize();
167
+ }
168
+
169
+ getRenderStack() {
170
+ return this.renderStack;
171
+ }
172
+
173
+ getWindowSize() {
174
+ if (!this.layoutManager) {
175
+ throw new Error(
176
+ "LayoutManager is not initialized, window size is unavailable"
177
+ );
178
+ }
179
+ return this.layoutManager.getWindowsSize();
180
+ }
181
+
182
+ // Includes first item offset correction
183
+ getLastScrollOffset() {
184
+ return this.engagedIndicesTracker.scrollOffset;
185
+ }
186
+
187
+ getMaxScrollOffset() {
188
+ return Math.max(
189
+ 0,
190
+ (this.props.horizontal
191
+ ? this.getChildContainerDimensions().width
192
+ : this.getChildContainerDimensions().height) -
193
+ (this.props.horizontal
194
+ ? this.getWindowSize().width
195
+ : this.getWindowSize().height) +
196
+ this.firstItemOffset
197
+ );
198
+ }
199
+
200
+ // Doesn't include first item offset correction
201
+ getAbsoluteLastScrollOffset() {
202
+ return this.engagedIndicesTracker.scrollOffset + this.firstItemOffset;
203
+ }
204
+
205
+ setScrollDirection(scrollDirection: "forward" | "backward") {
206
+ this.engagedIndicesTracker.setScrollDirection(scrollDirection);
207
+ }
208
+
209
+ resetVelocityCompute() {
210
+ this.engagedIndicesTracker.resetVelocityHistory();
211
+ }
212
+
213
+ updateLayoutParams(windowSize: RVDimension, firstItemOffset: number) {
214
+ this.firstItemOffset = firstItemOffset;
215
+ const LayoutManagerClass = this.getLayoutManagerClass();
216
+ if (
217
+ this.layoutManager &&
218
+ Boolean(this.layoutManager?.isHorizontal()) !==
219
+ Boolean(this.props.horizontal)
220
+ ) {
221
+ throw new Error(
222
+ "Horizontal prop cannot be toggled, you can use a key on FlashList to recreate it."
223
+ );
224
+ }
225
+ if (!(this.layoutManager instanceof LayoutManagerClass)) {
226
+ // console.log("-----> new LayoutManagerClass");
227
+
228
+ this.layoutManager = new LayoutManagerClass(
229
+ {
230
+ windowSize,
231
+ maxColumns: this.props.numColumns ?? 1,
232
+ horizontal: Boolean(this.props.horizontal),
233
+ optimizeItemArrangement: this.props.optimizeItemArrangement ?? true,
234
+ overrideItemLayout: (index, layout) => {
235
+ this.props?.overrideItemLayout?.(
236
+ layout,
237
+ this.props.data![index],
238
+ index,
239
+ this.props.numColumns ?? 1,
240
+ this.props.extraData
241
+ );
242
+ },
243
+ },
244
+ this.layoutManager
245
+ );
246
+ } else {
247
+ this.layoutManager.updateLayoutParams({
248
+ windowSize,
249
+ maxColumns: this.props.numColumns ?? 1,
250
+ horizontal: Boolean(this.props.horizontal),
251
+ optimizeItemArrangement: this.props.optimizeItemArrangement ?? true,
252
+ });
253
+ }
254
+ }
255
+
256
+ hasLayout() {
257
+ return this.layoutManager !== undefined;
258
+ }
259
+
260
+ getVisibleIndices() {
261
+ if (!this.layoutManager) {
262
+ throw new Error(
263
+ "LayoutManager is not initialized, visible indices are not unavailable"
264
+ );
265
+ }
266
+ return this.engagedIndicesTracker.computeVisibleIndices(this.layoutManager);
267
+ }
268
+
269
+ getEngagedIndices() {
270
+ return this.engagedIndicesTracker.getEngagedIndices();
271
+ }
272
+
273
+ modifyChildrenLayout(
274
+ layoutInfo: RVLayoutInfo[],
275
+ dataLength: number
276
+ ): boolean {
277
+ this.layoutManager?.modifyLayout(layoutInfo, dataLength);
278
+ if (dataLength === 0) {
279
+ return false;
280
+ }
281
+ if (this.layoutManager?.requiresRepaint) {
282
+ // console.log("requiresRepaint triggered");
283
+ this.layoutManager.requiresRepaint = false;
284
+ return true;
285
+ }
286
+ if (this.hasRenderedProgressively) {
287
+ return this.recomputeEngagedIndices() !== undefined;
288
+ } else {
289
+ this.renderProgressively();
290
+ }
291
+ return !this.hasRenderedProgressively;
292
+ }
293
+
294
+ computeItemViewability() {
295
+ // Using higher buffer for masonry to avoid missing items
296
+ this.itemViewabilityManager.shouldListenToVisibleIndices &&
297
+ this.itemViewabilityManager.updateViewableItems(
298
+ this.props.masonry
299
+ ? this.engagedIndicesTracker.getEngagedIndices().toArray()
300
+ : this.getVisibleIndices().toArray()
301
+ );
302
+ }
303
+
304
+ recordInteraction() {
305
+ this.itemViewabilityManager.recordInteraction();
306
+ }
307
+
308
+ recomputeViewableItems() {
309
+ this.itemViewabilityManager.recomputeViewableItems();
310
+ }
311
+
312
+ processDataUpdate() {
313
+ if (this.hasLayout()) {
314
+ this.modifyChildrenLayout([], this.props.data?.length ?? 0);
315
+ if (!this.recomputeEngagedIndices()) {
316
+ // recomputeEngagedIndices will update the render stack if there are any changes in the engaged indices.
317
+ // It's important to update render stack so that elements are assgined right keys incase items were deleted.
318
+ this.updateRenderStack(this.engagedIndicesTracker.getEngagedIndices());
319
+ }
320
+ }
321
+ }
322
+
323
+ recomputeEngagedIndices(): ConsecutiveNumbers | undefined {
324
+ return this.updateScrollOffset(this.getAbsoluteLastScrollOffset());
325
+ }
326
+
327
+ dispose() {
328
+ this._isDisposed = true;
329
+ this.itemViewabilityManager.dispose();
330
+ }
331
+
332
+ getInitialScrollIndex() {
333
+ return (
334
+ this.props.initialScrollIndex ??
335
+ (this.props.maintainVisibleContentPosition?.startRenderingFromBottom
336
+ ? this.getDataLength() - 1
337
+ : undefined)
338
+ );
339
+ }
340
+
341
+ getDataLength() {
342
+ return this.props.data?.length ?? 0;
343
+ }
344
+
345
+ private getLayoutManagerClass() {
346
+ // throw errors for incompatible props
347
+ if (this.props.masonry && this.props.horizontal) {
348
+ throw new Error("Masonry and horizontal props are incompatible");
349
+ }
350
+ if ((this.props.numColumns ?? 1) > 1 && this.props.horizontal) {
351
+ throw new Error("numColumns and horizontal props are incompatible");
352
+ }
353
+ return this.props.masonry
354
+ ? RVMasonryLayoutManagerImpl
355
+ : (this.props.numColumns ?? 1) > 1 && !this.props.horizontal
356
+ ? RVGridLayoutManagerImpl
357
+ : RVLinearLayoutManagerImpl;
358
+ }
359
+
360
+ private applyInitialScrollAdjustment() {
361
+ if (!this.layoutManager || this.getDataLength() === 0) {
362
+ return;
363
+ }
364
+
365
+ const initialScrollIndex = this.getInitialScrollIndex();
366
+ const initialItemLayout = this.layoutManager?.getLayout(
367
+ initialScrollIndex ?? 0
368
+ );
369
+ const initialItemOffset = this.props.horizontal
370
+ ? initialItemLayout?.x
371
+ : initialItemLayout?.y;
372
+
373
+ if (initialScrollIndex !== undefined) {
374
+ // console.log(
375
+ // "initialItemOffset",
376
+ // initialScrollIndex,
377
+ // initialItemOffset,
378
+ // this.firstItemOffset
379
+ // );
380
+ this.layoutManager.recomputeLayouts(0, initialScrollIndex);
381
+ this.engagedIndicesTracker.scrollOffset =
382
+ initialItemOffset ?? 0 + this.firstItemOffset;
383
+ } else {
384
+ // console.log("initialItemOffset", initialItemOffset, this.firstItemOffset);
385
+ this.engagedIndicesTracker.scrollOffset =
386
+ (initialItemOffset ?? 0) - this.firstItemOffset;
387
+ }
388
+ }
389
+
390
+ private renderProgressively() {
391
+ const layoutManager = this.layoutManager;
392
+ if (layoutManager) {
393
+ this.applyInitialScrollAdjustment();
394
+ const visibleIndices = this.getVisibleIndices();
395
+ // console.log("---------> visibleIndices", visibleIndices);
396
+ this.hasRenderedProgressively = visibleIndices.every(
397
+ (index) =>
398
+ layoutManager.getLayout(index).isHeightMeasured &&
399
+ layoutManager.getLayout(index).isWidthMeasured
400
+ );
401
+
402
+ if (this.hasRenderedProgressively) {
403
+ this.isFirstLayoutComplete = true;
404
+ }
405
+
406
+ // If everything is measured then render stack will be in sync. The buffer items will get rendered in the next update
407
+ // triggered by the useOnLoad hook.
408
+ !this.hasRenderedProgressively &&
409
+ this.updateRenderStack(
410
+ // pick first n indices from visible ones and n is size of renderStack
411
+ visibleIndices.slice(
412
+ 0,
413
+ Math.min(
414
+ visibleIndices.length,
415
+ this.renderStack.size + this.initialDrawBatchSize
416
+ )
417
+ )
418
+ );
419
+ }
420
+ }
421
+
422
+ private getItemType(index: number): string {
423
+ return (
424
+ this.props.getItemType?.(this.props.data![index], index) ?? "default"
425
+ ).toString();
426
+ }
427
+
428
+ private getStableId(index: number): string {
429
+ return (
430
+ this.props.keyExtractor?.(this.props.data![index], index) ??
431
+ index.toString()
432
+ );
433
+ }
434
+ }
@@ -0,0 +1,11 @@
1
+ import { ScrollViewProps } from "react-native";
2
+
3
+ import { FlashListProps } from "../FlashListProps";
4
+
5
+ export interface RecyclerViewProps<TItem>
6
+ extends Omit<FlashListProps<TItem>, "contentContainerStyle"> {
7
+ /**
8
+ * Style for the RecyclerView's parent container.
9
+ */
10
+ contentContainerStyle?: ScrollViewProps["contentContainerStyle"];
11
+ }
@@ -0,0 +1,178 @@
1
+ /**
2
+ * ViewHolder is a core component in FlashList that manages individual item rendering and layout.
3
+ * It handles the rendering of list items, separators, and manages layout updates for each item.
4
+ * The component is memoized to prevent unnecessary re-renders and includes layout comparison logic.
5
+ */
6
+
7
+ import { LayoutChangeEvent } from "react-native";
8
+ import React, {
9
+ RefObject,
10
+ useCallback,
11
+ useLayoutEffect,
12
+ useMemo,
13
+ useRef,
14
+ } from "react";
15
+
16
+ import { FlashListProps, RenderTarget } from "../FlashListProps";
17
+
18
+ import { RVDimension, RVLayout } from "./layout-managers/LayoutManager";
19
+ import { CompatView } from "./components/CompatView";
20
+
21
+ /**
22
+ * Props interface for the ViewHolder component
23
+ * @template TItem - The type of item being rendered in the list
24
+ */
25
+ export interface ViewHolderProps<TItem> {
26
+ /** Index of the item in the data array */
27
+ index: number;
28
+ /** Layout information for positioning and sizing the item */
29
+ layout: RVLayout;
30
+ /** Map to store refs for each ViewHolder instance, keyed by index */
31
+ refHolder: Map<number, RefObject<CompatView | null>>;
32
+ /** Additional data passed to renderItem that can trigger re-renders */
33
+ extraData: any;
34
+ /** Specifies the rendering target (e.g., "Cell", "StickyHeader") */
35
+ target: RenderTarget;
36
+ /** The actual item data to be rendered */
37
+ item: TItem;
38
+ /** The next item in the list, used for rendering separators */
39
+ trailingItem: TItem | undefined;
40
+ /** Function to render the item content */
41
+ renderItem: FlashListProps<TItem>["renderItem"];
42
+ /** Optional custom component to wrap each item */
43
+ CellRendererComponent?: FlashListProps<TItem>["CellRendererComponent"];
44
+ /** Optional component to render between items */
45
+ ItemSeparatorComponent?: FlashListProps<TItem>["ItemSeparatorComponent"];
46
+ /** Whether the list is horizontal or vertical */
47
+ horizontal?: FlashListProps<TItem>["horizontal"];
48
+ /** Callback when the item's size changes */
49
+ onSizeChanged?: (index: number, size: RVDimension) => void;
50
+ }
51
+
52
+ /**
53
+ * Internal ViewHolder component that handles the actual rendering of list items
54
+ * @template TItem - The type of item being rendered in the list
55
+ */
56
+ const ViewHolderInternal = <TItem,>(props: ViewHolderProps<TItem>) => {
57
+ // create ref for View
58
+ const viewRef = useRef<CompatView>(null);
59
+ const {
60
+ index,
61
+ refHolder,
62
+ layout,
63
+ onSizeChanged,
64
+ renderItem,
65
+ extraData,
66
+ item,
67
+ target,
68
+ CellRendererComponent,
69
+ ItemSeparatorComponent,
70
+ trailingItem,
71
+ horizontal,
72
+ } = props;
73
+
74
+ useLayoutEffect(() => {
75
+ refHolder.set(index, viewRef);
76
+ return () => {
77
+ if (refHolder.get(index) === viewRef) {
78
+ refHolder.delete(index);
79
+ }
80
+ };
81
+ }, [index, refHolder]);
82
+
83
+ const onLayout = useCallback(
84
+ (event: LayoutChangeEvent) => {
85
+ onSizeChanged?.(index, event.nativeEvent.layout);
86
+ },
87
+ [index, onSizeChanged]
88
+ );
89
+
90
+ const separator = useMemo(() => {
91
+ return ItemSeparatorComponent ? (
92
+ <ItemSeparatorComponent leadingItem={item} trailingItem={trailingItem} />
93
+ ) : null;
94
+ }, [ItemSeparatorComponent, item, trailingItem]);
95
+
96
+ // console.log("ViewHolder re-render", index);
97
+
98
+ const children = useMemo(() => {
99
+ return renderItem?.({ item, index, extraData, target }) ?? null;
100
+ }, [item, index, extraData, target, renderItem]);
101
+
102
+ const style = {
103
+ flexDirection: horizontal ? "row" : "column",
104
+ position: target === "StickyHeader" ? "relative" : "absolute",
105
+ width: layout.enforcedWidth ? layout.width : undefined,
106
+ height: layout.enforcedHeight ? layout.height : undefined,
107
+ minHeight: layout.minHeight,
108
+ minWidth: layout.minWidth,
109
+ maxHeight: layout.maxHeight,
110
+ maxWidth: layout.maxWidth,
111
+ left: layout.x,
112
+ top: layout.y,
113
+ zIndex: 0,
114
+ } as const;
115
+
116
+ // TODO: Fix this type issue
117
+ const CompatContainer = (CellRendererComponent ??
118
+ CompatView) as unknown as any;
119
+
120
+ return (
121
+ <CompatContainer
122
+ ref={viewRef}
123
+ onLayout={onLayout}
124
+ style={style}
125
+ index={index}
126
+ >
127
+ {children}
128
+ {separator}
129
+ </CompatContainer>
130
+ );
131
+ };
132
+
133
+ /**
134
+ * Memoized ViewHolder component that prevents unnecessary re-renders by comparing props
135
+ * @template TItem - The type of item being rendered in the list
136
+ */
137
+ export const ViewHolder = React.memo(
138
+ ViewHolderInternal,
139
+ (prevProps, nextProps) => {
140
+ // compare all props and spread layout
141
+ return (
142
+ prevProps.index === nextProps.index &&
143
+ areLayoutsEqual(prevProps.layout, nextProps.layout) &&
144
+ prevProps.refHolder === nextProps.refHolder &&
145
+ prevProps.onSizeChanged === nextProps.onSizeChanged &&
146
+ prevProps.extraData === nextProps.extraData &&
147
+ prevProps.target === nextProps.target &&
148
+ prevProps.item === nextProps.item &&
149
+ prevProps.renderItem === nextProps.renderItem &&
150
+ prevProps.CellRendererComponent === nextProps.CellRendererComponent &&
151
+ prevProps.ItemSeparatorComponent === nextProps.ItemSeparatorComponent &&
152
+ prevProps.trailingItem === nextProps.trailingItem &&
153
+ prevProps.horizontal === nextProps.horizontal
154
+ );
155
+ }
156
+ );
157
+
158
+ /**
159
+ * Compares two RVLayout objects to determine if they are equal
160
+ * Used in the memo comparison function to prevent unnecessary re-renders
161
+ * @param prevLayout - Previous layout object
162
+ * @param nextLayout - Next layout object
163
+ * @returns boolean indicating if layouts are equal
164
+ */
165
+ function areLayoutsEqual(prevLayout: RVLayout, nextLayout: RVLayout): boolean {
166
+ return (
167
+ prevLayout.x === nextLayout.x &&
168
+ prevLayout.y === nextLayout.y &&
169
+ prevLayout.width === nextLayout.width &&
170
+ prevLayout.height === nextLayout.height &&
171
+ prevLayout.enforcedWidth === nextLayout.enforcedWidth &&
172
+ prevLayout.enforcedHeight === nextLayout.enforcedHeight &&
173
+ prevLayout.minWidth === nextLayout.minWidth &&
174
+ prevLayout.minHeight === nextLayout.minHeight &&
175
+ prevLayout.maxWidth === nextLayout.maxWidth &&
176
+ prevLayout.maxHeight === nextLayout.maxHeight
177
+ );
178
+ }