@shopify/flash-list 2.0.0-rc.9 → 2.0.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 (304) hide show
  1. package/README.md +27 -97
  2. package/dist/AnimatedFlashList.js +2 -2
  3. package/dist/AnimatedFlashList.js.map +1 -1
  4. package/dist/FlashList.d.ts +1 -167
  5. package/dist/FlashList.d.ts.map +1 -1
  6. package/dist/FlashList.js +3 -595
  7. package/dist/FlashList.js.map +1 -1
  8. package/dist/FlashListProps.d.ts +7 -63
  9. package/dist/FlashListProps.d.ts.map +1 -1
  10. package/dist/FlashListProps.js.map +1 -1
  11. package/dist/__tests__/LayoutCommitObserver.test.d.ts +2 -0
  12. package/dist/__tests__/LayoutCommitObserver.test.d.ts.map +1 -0
  13. package/dist/__tests__/LayoutCommitObserver.test.js +35 -0
  14. package/dist/__tests__/LayoutCommitObserver.test.js.map +1 -0
  15. package/dist/__tests__/ViewabilityHelper.test.js +3 -4
  16. package/dist/__tests__/ViewabilityHelper.test.js.map +1 -1
  17. package/dist/benchmark/JSFPSMonitor.d.ts.map +1 -1
  18. package/dist/benchmark/JSFPSMonitor.js +2 -1
  19. package/dist/benchmark/JSFPSMonitor.js.map +1 -1
  20. package/dist/benchmark/useBenchmark.d.ts +2 -4
  21. package/dist/benchmark/useBenchmark.d.ts.map +1 -1
  22. package/dist/benchmark/useBenchmark.js +12 -49
  23. package/dist/benchmark/useBenchmark.js.map +1 -1
  24. package/dist/benchmark/useFlatListBenchmark.d.ts.map +1 -1
  25. package/dist/benchmark/useFlatListBenchmark.js +2 -1
  26. package/dist/benchmark/useFlatListBenchmark.js.map +1 -1
  27. package/dist/errors/ErrorMessages.d.ts +16 -0
  28. package/dist/errors/ErrorMessages.d.ts.map +1 -0
  29. package/dist/errors/ErrorMessages.js +19 -0
  30. package/dist/errors/ErrorMessages.js.map +1 -0
  31. package/dist/errors/WarningMessages.d.ts +4 -0
  32. package/dist/errors/WarningMessages.d.ts.map +1 -0
  33. package/dist/errors/WarningMessages.js +7 -0
  34. package/dist/errors/WarningMessages.js.map +1 -0
  35. package/dist/index.d.ts +4 -9
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +9 -29
  38. package/dist/index.js.map +1 -1
  39. package/dist/isNewArch.d.ts +2 -0
  40. package/dist/isNewArch.d.ts.map +1 -0
  41. package/dist/isNewArch.js +25 -0
  42. package/dist/isNewArch.js.map +1 -0
  43. package/dist/native/config/PlatformHelper.android.d.ts +1 -22
  44. package/dist/native/config/PlatformHelper.android.d.ts.map +1 -1
  45. package/dist/native/config/PlatformHelper.android.js +1 -16
  46. package/dist/native/config/PlatformHelper.android.js.map +1 -1
  47. package/dist/native/config/PlatformHelper.d.ts +1 -22
  48. package/dist/native/config/PlatformHelper.d.ts.map +1 -1
  49. package/dist/native/config/PlatformHelper.ios.d.ts +1 -22
  50. package/dist/native/config/PlatformHelper.ios.d.ts.map +1 -1
  51. package/dist/native/config/PlatformHelper.ios.js +1 -15
  52. package/dist/native/config/PlatformHelper.ios.js.map +1 -1
  53. package/dist/native/config/PlatformHelper.js +1 -16
  54. package/dist/native/config/PlatformHelper.js.map +1 -1
  55. package/dist/native/config/PlatformHelper.web.d.ts +1 -23
  56. package/dist/native/config/PlatformHelper.web.d.ts.map +1 -1
  57. package/dist/native/config/PlatformHelper.web.js +1 -18
  58. package/dist/native/config/PlatformHelper.web.js.map +1 -1
  59. package/dist/recyclerview/LayoutCommitObserver.d.ts +12 -0
  60. package/dist/recyclerview/LayoutCommitObserver.d.ts.map +1 -0
  61. package/dist/recyclerview/LayoutCommitObserver.js +62 -0
  62. package/dist/recyclerview/LayoutCommitObserver.js.map +1 -0
  63. package/dist/recyclerview/RecyclerView.d.ts.map +1 -1
  64. package/dist/recyclerview/RecyclerView.js +20 -9
  65. package/dist/recyclerview/RecyclerView.js.map +1 -1
  66. package/dist/recyclerview/RecyclerViewManager.d.ts +4 -1
  67. package/dist/recyclerview/RecyclerViewManager.d.ts.map +1 -1
  68. package/dist/recyclerview/RecyclerViewManager.js +43 -34
  69. package/dist/recyclerview/RecyclerViewManager.js.map +1 -1
  70. package/dist/recyclerview/RecyclerViewProps.d.ts +1 -8
  71. package/dist/recyclerview/RecyclerViewProps.d.ts.map +1 -1
  72. package/dist/recyclerview/ViewHolderCollection.d.ts +6 -2
  73. package/dist/recyclerview/ViewHolderCollection.d.ts.map +1 -1
  74. package/dist/recyclerview/ViewHolderCollection.js +3 -1
  75. package/dist/recyclerview/ViewHolderCollection.js.map +1 -1
  76. package/dist/recyclerview/hooks/useBoundDetection.d.ts.map +1 -1
  77. package/dist/recyclerview/hooks/useBoundDetection.js +38 -7
  78. package/dist/recyclerview/hooks/useBoundDetection.js.map +1 -1
  79. package/dist/recyclerview/hooks/useRecyclerViewController.d.ts.map +1 -1
  80. package/dist/recyclerview/hooks/useRecyclerViewController.js +16 -9
  81. package/dist/recyclerview/hooks/useRecyclerViewController.js.map +1 -1
  82. package/dist/recyclerview/layout-managers/LayoutManager.d.ts.map +1 -1
  83. package/dist/recyclerview/layout-managers/LayoutManager.js +2 -1
  84. package/dist/recyclerview/layout-managers/LayoutManager.js.map +1 -1
  85. package/dist/recyclerview/viewability/ViewToken.d.ts.map +1 -0
  86. package/dist/recyclerview/viewability/ViewToken.js.map +1 -0
  87. package/dist/{viewability → recyclerview/viewability}/ViewabilityHelper.d.ts +2 -2
  88. package/dist/recyclerview/viewability/ViewabilityHelper.d.ts.map +1 -0
  89. package/dist/{viewability → recyclerview/viewability}/ViewabilityHelper.js +2 -4
  90. package/dist/{viewability → recyclerview/viewability}/ViewabilityHelper.js.map +1 -1
  91. package/dist/{viewability → recyclerview/viewability}/ViewabilityManager.d.ts +3 -3
  92. package/dist/recyclerview/viewability/ViewabilityManager.d.ts.map +1 -0
  93. package/dist/{viewability → recyclerview/viewability}/ViewabilityManager.js +16 -16
  94. package/dist/recyclerview/viewability/ViewabilityManager.js.map +1 -0
  95. package/dist/tsconfig.tsbuildinfo +1 -1
  96. package/package.json +3 -14
  97. package/src/AnimatedFlashList.ts +2 -2
  98. package/src/FlashList.ts +1 -0
  99. package/src/FlashListProps.ts +8 -79
  100. package/src/__tests__/LayoutCommitObserver.test.tsx +60 -0
  101. package/src/__tests__/ViewabilityHelper.test.ts +13 -14
  102. package/src/benchmark/JSFPSMonitor.ts +3 -3
  103. package/src/benchmark/useBenchmark.ts +12 -77
  104. package/src/benchmark/useFlatListBenchmark.ts +3 -1
  105. package/src/errors/ErrorMessages.ts +26 -0
  106. package/src/errors/WarningMessages.ts +4 -0
  107. package/src/index.ts +11 -43
  108. package/src/isNewArch.ts +25 -0
  109. package/src/native/config/PlatformHelper.android.ts +1 -25
  110. package/src/native/config/PlatformHelper.ios.ts +1 -24
  111. package/src/native/config/PlatformHelper.ts +1 -25
  112. package/src/native/config/PlatformHelper.web.ts +1 -30
  113. package/src/recyclerview/LayoutCommitObserver.tsx +74 -0
  114. package/src/recyclerview/RecyclerView.tsx +25 -12
  115. package/src/recyclerview/RecyclerViewManager.ts +40 -40
  116. package/src/recyclerview/RecyclerViewProps.ts +1 -11
  117. package/src/recyclerview/ViewHolderCollection.tsx +9 -2
  118. package/src/recyclerview/hooks/useBoundDetection.ts +48 -6
  119. package/src/recyclerview/hooks/useRecyclerViewController.tsx +19 -14
  120. package/src/recyclerview/layout-managers/LayoutManager.ts +2 -1
  121. package/src/{viewability → recyclerview/viewability}/ViewabilityHelper.ts +8 -9
  122. package/src/{viewability → recyclerview/viewability}/ViewabilityManager.ts +18 -20
  123. package/RNFlashList.podspec +0 -37
  124. package/android/build.gradle +0 -89
  125. package/android/src/main/AndroidManifest.xml +0 -3
  126. package/android/src/main/kotlin/com/shopify/reactnative/flash_list/AutoLayoutShadow.kt +0 -105
  127. package/android/src/main/kotlin/com/shopify/reactnative/flash_list/AutoLayoutView.kt +0 -158
  128. package/android/src/main/kotlin/com/shopify/reactnative/flash_list/AutoLayoutViewManager.kt +0 -70
  129. package/android/src/main/kotlin/com/shopify/reactnative/flash_list/BlankAreaEvent.kt +0 -29
  130. package/android/src/main/kotlin/com/shopify/reactnative/flash_list/CellContainer.java +0 -16
  131. package/android/src/main/kotlin/com/shopify/reactnative/flash_list/CellContainerImpl.kt +0 -16
  132. package/android/src/main/kotlin/com/shopify/reactnative/flash_list/CellContainerManager.kt +0 -34
  133. package/android/src/main/kotlin/com/shopify/reactnative/flash_list/FlashListPackage.kt +0 -19
  134. package/android/src/paper/java/com/facebook/react/viewmanagers/AutoLayoutViewManagerDelegate.java +0 -47
  135. package/android/src/paper/java/com/facebook/react/viewmanagers/AutoLayoutViewManagerInterface.java +0 -21
  136. package/android/src/paper/java/com/facebook/react/viewmanagers/CellContainerManagerDelegate.java +0 -32
  137. package/android/src/paper/java/com/facebook/react/viewmanagers/CellContainerManagerInterface.java +0 -16
  138. package/android/src/test/java/com/shopify/reactnative/flash_list/AutoLayoutShadowTest.kt +0 -147
  139. package/android/src/test/java/com/shopify/reactnative/flash_list/models/Rect.kt +0 -61
  140. package/android/src/test/java/com/shopify/reactnative/flash_list/models/TestCollection.kt +0 -6
  141. package/android/src/test/java/com/shopify/reactnative/flash_list/models/TestDataModel.kt +0 -8
  142. package/android/src/test/resources/LayoutTestData.json +0 -788
  143. package/dist/GridLayoutProviderWithProps.d.ts +0 -42
  144. package/dist/GridLayoutProviderWithProps.d.ts.map +0 -1
  145. package/dist/GridLayoutProviderWithProps.js +0 -114
  146. package/dist/GridLayoutProviderWithProps.js.map +0 -1
  147. package/dist/MasonryFlashList.d.ts +0 -51
  148. package/dist/MasonryFlashList.d.ts.map +0 -1
  149. package/dist/MasonryFlashList.js +0 -252
  150. package/dist/MasonryFlashList.js.map +0 -1
  151. package/dist/PureComponentWrapper.d.ts +0 -22
  152. package/dist/PureComponentWrapper.d.ts.map +0 -1
  153. package/dist/PureComponentWrapper.js +0 -37
  154. package/dist/PureComponentWrapper.js.map +0 -1
  155. package/dist/__tests__/ContentContainerUtils.test.d.ts +0 -2
  156. package/dist/__tests__/ContentContainerUtils.test.d.ts.map +0 -1
  157. package/dist/__tests__/ContentContainerUtils.test.js +0 -85
  158. package/dist/__tests__/ContentContainerUtils.test.js.map +0 -1
  159. package/dist/__tests__/FlashList.test.d.ts +0 -2
  160. package/dist/__tests__/FlashList.test.d.ts.map +0 -1
  161. package/dist/__tests__/FlashList.test.js +0 -902
  162. package/dist/__tests__/FlashList.test.js.map +0 -1
  163. package/dist/__tests__/GridLayoutProviderWithProps.test.d.ts +0 -2
  164. package/dist/__tests__/GridLayoutProviderWithProps.test.d.ts.map +0 -1
  165. package/dist/__tests__/GridLayoutProviderWithProps.test.js +0 -143
  166. package/dist/__tests__/GridLayoutProviderWithProps.test.js.map +0 -1
  167. package/dist/__tests__/MasonryFlashList.test.d.ts +0 -2
  168. package/dist/__tests__/MasonryFlashList.test.d.ts.map +0 -1
  169. package/dist/__tests__/MasonryFlashList.test.js +0 -254
  170. package/dist/__tests__/MasonryFlashList.test.js.map +0 -1
  171. package/dist/__tests__/PlatformHelper.web.test.d.ts +0 -2
  172. package/dist/__tests__/PlatformHelper.web.test.d.ts.map +0 -1
  173. package/dist/__tests__/PlatformHelper.web.test.js +0 -33
  174. package/dist/__tests__/PlatformHelper.web.test.js.map +0 -1
  175. package/dist/__tests__/helpers/mountFlashList.d.ts +0 -19
  176. package/dist/__tests__/helpers/mountFlashList.d.ts.map +0 -1
  177. package/dist/__tests__/helpers/mountFlashList.js +0 -44
  178. package/dist/__tests__/helpers/mountFlashList.js.map +0 -1
  179. package/dist/__tests__/helpers/mountMasonryFlashList.d.ts +0 -18
  180. package/dist/__tests__/helpers/mountMasonryFlashList.d.ts.map +0 -1
  181. package/dist/__tests__/helpers/mountMasonryFlashList.js +0 -49
  182. package/dist/__tests__/helpers/mountMasonryFlashList.js.map +0 -1
  183. package/dist/__tests__/useBlankAreaTracker.test.d.ts +0 -2
  184. package/dist/__tests__/useBlankAreaTracker.test.d.ts.map +0 -1
  185. package/dist/__tests__/useBlankAreaTracker.test.js +0 -179
  186. package/dist/__tests__/useBlankAreaTracker.test.js.map +0 -1
  187. package/dist/benchmark/useBlankAreaTracker.d.ts +0 -34
  188. package/dist/benchmark/useBlankAreaTracker.d.ts.map +0 -1
  189. package/dist/benchmark/useBlankAreaTracker.js +0 -66
  190. package/dist/benchmark/useBlankAreaTracker.js.map +0 -1
  191. package/dist/enableNewCore.d.ts +0 -3
  192. package/dist/enableNewCore.d.ts.map +0 -1
  193. package/dist/enableNewCore.js +0 -25
  194. package/dist/enableNewCore.js.map +0 -1
  195. package/dist/errors/CustomError.d.ts +0 -8
  196. package/dist/errors/CustomError.d.ts.map +0 -1
  197. package/dist/errors/CustomError.js +0 -14
  198. package/dist/errors/CustomError.js.map +0 -1
  199. package/dist/errors/ExceptionList.d.ts +0 -24
  200. package/dist/errors/ExceptionList.d.ts.map +0 -1
  201. package/dist/errors/ExceptionList.js +0 -26
  202. package/dist/errors/ExceptionList.js.map +0 -1
  203. package/dist/errors/Warnings.d.ts +0 -9
  204. package/dist/errors/Warnings.d.ts.map +0 -1
  205. package/dist/errors/Warnings.js +0 -13
  206. package/dist/errors/Warnings.js.map +0 -1
  207. package/dist/native/auto-layout/AutoLayoutView.d.ts +0 -22
  208. package/dist/native/auto-layout/AutoLayoutView.d.ts.map +0 -1
  209. package/dist/native/auto-layout/AutoLayoutView.js +0 -48
  210. package/dist/native/auto-layout/AutoLayoutView.js.map +0 -1
  211. package/dist/native/auto-layout/AutoLayoutViewNativeComponent.android.d.ts +0 -4
  212. package/dist/native/auto-layout/AutoLayoutViewNativeComponent.android.d.ts.map +0 -1
  213. package/dist/native/auto-layout/AutoLayoutViewNativeComponent.android.js +0 -6
  214. package/dist/native/auto-layout/AutoLayoutViewNativeComponent.android.js.map +0 -1
  215. package/dist/native/auto-layout/AutoLayoutViewNativeComponent.d.ts +0 -5
  216. package/dist/native/auto-layout/AutoLayoutViewNativeComponent.d.ts.map +0 -1
  217. package/dist/native/auto-layout/AutoLayoutViewNativeComponent.ios.d.ts +0 -4
  218. package/dist/native/auto-layout/AutoLayoutViewNativeComponent.ios.d.ts.map +0 -1
  219. package/dist/native/auto-layout/AutoLayoutViewNativeComponent.ios.js +0 -6
  220. package/dist/native/auto-layout/AutoLayoutViewNativeComponent.ios.js.map +0 -1
  221. package/dist/native/auto-layout/AutoLayoutViewNativeComponent.js +0 -6
  222. package/dist/native/auto-layout/AutoLayoutViewNativeComponent.js.map +0 -1
  223. package/dist/native/auto-layout/AutoLayoutViewNativeComponentProps.d.ts +0 -16
  224. package/dist/native/auto-layout/AutoLayoutViewNativeComponentProps.d.ts.map +0 -1
  225. package/dist/native/auto-layout/AutoLayoutViewNativeComponentProps.js +0 -3
  226. package/dist/native/auto-layout/AutoLayoutViewNativeComponentProps.js.map +0 -1
  227. package/dist/native/cell-container/CellContainer.android.d.ts +0 -6
  228. package/dist/native/cell-container/CellContainer.android.d.ts.map +0 -1
  229. package/dist/native/cell-container/CellContainer.android.js +0 -9
  230. package/dist/native/cell-container/CellContainer.android.js.map +0 -1
  231. package/dist/native/cell-container/CellContainer.d.ts +0 -8
  232. package/dist/native/cell-container/CellContainer.d.ts.map +0 -1
  233. package/dist/native/cell-container/CellContainer.ios.d.ts +0 -6
  234. package/dist/native/cell-container/CellContainer.ios.d.ts.map +0 -1
  235. package/dist/native/cell-container/CellContainer.ios.js +0 -9
  236. package/dist/native/cell-container/CellContainer.ios.js.map +0 -1
  237. package/dist/native/cell-container/CellContainer.js +0 -11
  238. package/dist/native/cell-container/CellContainer.js.map +0 -1
  239. package/dist/native/cell-container/CellContainer.web.d.ts +0 -7
  240. package/dist/native/cell-container/CellContainer.web.d.ts.map +0 -1
  241. package/dist/native/cell-container/CellContainer.web.js +0 -13
  242. package/dist/native/cell-container/CellContainer.web.js.map +0 -1
  243. package/dist/specs/AutoLayoutNativeComponent.d.ts +0 -18
  244. package/dist/specs/AutoLayoutNativeComponent.d.ts.map +0 -1
  245. package/dist/specs/AutoLayoutNativeComponent.js +0 -6
  246. package/dist/specs/AutoLayoutNativeComponent.js.map +0 -1
  247. package/dist/specs/CellContainerNativeComponent.d.ts +0 -8
  248. package/dist/specs/CellContainerNativeComponent.d.ts.map +0 -1
  249. package/dist/specs/CellContainerNativeComponent.js +0 -6
  250. package/dist/specs/CellContainerNativeComponent.js.map +0 -1
  251. package/dist/utils/ContentContainerUtils.d.ts +0 -27
  252. package/dist/utils/ContentContainerUtils.d.ts.map +0 -1
  253. package/dist/utils/ContentContainerUtils.js +0 -48
  254. package/dist/utils/ContentContainerUtils.js.map +0 -1
  255. package/dist/viewability/ViewToken.d.ts.map +0 -1
  256. package/dist/viewability/ViewToken.js.map +0 -1
  257. package/dist/viewability/ViewabilityHelper.d.ts.map +0 -1
  258. package/dist/viewability/ViewabilityManager.d.ts.map +0 -1
  259. package/dist/viewability/ViewabilityManager.js.map +0 -1
  260. package/ios/RNFlashList.xcodeproj/project.pbxproj +0 -3
  261. package/ios/RNFlashList.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -4
  262. package/ios/Sources/AutoLayoutView.swift +0 -294
  263. package/ios/Sources/AutoLayoutViewComponentView.h +0 -16
  264. package/ios/Sources/AutoLayoutViewComponentView.mm +0 -90
  265. package/ios/Sources/AutoLayoutViewManager.mm +0 -14
  266. package/ios/Sources/AutoLayoutViewManager.swift +0 -12
  267. package/ios/Sources/CellContainerComponentView.h +0 -18
  268. package/ios/Sources/CellContainerComponentView.mm +0 -62
  269. package/ios/Sources/CellContainerManager.mm +0 -8
  270. package/ios/Sources/CellContainerManager.swift +0 -12
  271. package/ios/Sources/FlatListPro-Bridging-Header.h +0 -11
  272. package/ios/Tests/AutoLayoutViewTests.swift +0 -113
  273. package/src/FlashList.tsx +0 -953
  274. package/src/GridLayoutProviderWithProps.ts +0 -180
  275. package/src/MasonryFlashList.tsx +0 -476
  276. package/src/PureComponentWrapper.tsx +0 -42
  277. package/src/__tests__/ContentContainerUtils.test.ts +0 -130
  278. package/src/__tests__/FlashList.test.tsx +0 -1001
  279. package/src/__tests__/GridLayoutProviderWithProps.test.ts +0 -179
  280. package/src/__tests__/MasonryFlashList.test.ts +0 -292
  281. package/src/__tests__/PlatformHelper.web.test.ts +0 -45
  282. package/src/__tests__/helpers/mountFlashList.tsx +0 -62
  283. package/src/__tests__/helpers/mountMasonryFlashList.tsx +0 -70
  284. package/src/__tests__/useBlankAreaTracker.test.tsx +0 -206
  285. package/src/benchmark/useBlankAreaTracker.ts +0 -117
  286. package/src/enableNewCore.ts +0 -24
  287. package/src/errors/CustomError.ts +0 -10
  288. package/src/errors/ExceptionList.ts +0 -28
  289. package/src/errors/Warnings.ts +0 -15
  290. package/src/native/auto-layout/AutoLayoutView.tsx +0 -73
  291. package/src/native/auto-layout/AutoLayoutViewNativeComponent.android.ts +0 -7
  292. package/src/native/auto-layout/AutoLayoutViewNativeComponent.ios.ts +0 -7
  293. package/src/native/auto-layout/AutoLayoutViewNativeComponent.ts +0 -7
  294. package/src/native/auto-layout/AutoLayoutViewNativeComponentProps.ts +0 -17
  295. package/src/native/cell-container/CellContainer.android.ts +0 -7
  296. package/src/native/cell-container/CellContainer.ios.ts +0 -7
  297. package/src/native/cell-container/CellContainer.tsx +0 -14
  298. package/src/native/cell-container/CellContainer.web.tsx +0 -9
  299. package/src/specs/AutoLayoutNativeComponent.ts +0 -24
  300. package/src/specs/CellContainerNativeComponent.ts +0 -9
  301. package/src/utils/ContentContainerUtils.ts +0 -92
  302. /package/dist/{viewability → recyclerview/viewability}/ViewToken.d.ts +0 -0
  303. /package/dist/{viewability → recyclerview/viewability}/ViewToken.js +0 -0
  304. /package/src/{viewability → recyclerview/viewability}/ViewToken.ts +0 -0
@@ -1,30 +1,7 @@
1
- import { BaseItemAnimator } from "recyclerlistview";
2
-
3
1
  const PlatformConfig = {
4
2
  defaultDrawDistance: 250,
5
3
  supportsOffsetCorrection: true,
6
4
  trackAverageRenderTimeForOffsetProjection: false,
7
- invertedTransformStyle: { transform: [{ scaleY: -1 }] },
8
- invertedTransformStyleHorizontal: { transform: [{ scaleX: -1 }] },
9
- };
10
- const getCellContainerPlatformStyles = (
11
- inverted: boolean,
12
- parentProps: { x: number; y: number; isHorizontal?: boolean }
13
- ): { transform: string; WebkitTransform: string } | undefined => {
14
- return undefined;
15
- };
16
-
17
- const getItemAnimator = (): BaseItemAnimator | undefined => {
18
- return undefined;
19
5
  };
20
6
 
21
- const getFooterContainer = (): React.ComponentClass | undefined => {
22
- return undefined;
23
- };
24
-
25
- export {
26
- PlatformConfig,
27
- getCellContainerPlatformStyles,
28
- getItemAnimator,
29
- getFooterContainer,
30
- };
7
+ export { PlatformConfig };
@@ -1,31 +1,7 @@
1
- import { BaseItemAnimator } from "recyclerlistview";
2
- import { DefaultJSItemAnimator } from "recyclerlistview/dist/reactnative/platform/reactnative/itemanimators/defaultjsanimator/DefaultJSItemAnimator";
3
-
4
1
  const PlatformConfig = {
5
2
  defaultDrawDistance: 250,
6
3
  supportsOffsetCorrection: false,
7
4
  trackAverageRenderTimeForOffsetProjection: false,
8
- invertedTransformStyle: { transform: [{ scaleY: -1 }] },
9
- invertedTransformStyleHorizontal: { transform: [{ scaleX: -1 }] },
10
- };
11
- const getCellContainerPlatformStyles = (
12
- inverted: boolean,
13
- parentProps: { x: number; y: number; isHorizontal?: boolean }
14
- ): { transform: string; WebkitTransform: string } | undefined => {
15
- return undefined;
16
- };
17
-
18
- const getItemAnimator = (): BaseItemAnimator | undefined => {
19
- return new DefaultJSItemAnimator();
20
5
  };
21
6
 
22
- const getFooterContainer = (): React.ComponentClass | undefined => {
23
- return undefined;
24
- };
25
-
26
- export {
27
- PlatformConfig,
28
- getCellContainerPlatformStyles,
29
- getItemAnimator,
30
- getFooterContainer,
31
- };
7
+ export { PlatformConfig };
@@ -1,36 +1,7 @@
1
- import React from "react";
2
- import { View } from "react-native";
3
- import { BaseItemAnimator } from "recyclerlistview";
4
- import { DefaultJSItemAnimator } from "recyclerlistview/dist/reactnative/platform/reactnative/itemanimators/defaultjsanimator/DefaultJSItemAnimator";
5
-
6
1
  const PlatformConfig = {
7
2
  defaultDrawDistance: 500,
8
3
  supportsOffsetCorrection: false,
9
4
  trackAverageRenderTimeForOffsetProjection: false,
10
- invertedTransformStyle: { transform: [{ scaleY: -1 }] },
11
- invertedTransformStyleHorizontal: { transform: [{ scaleX: -1 }] },
12
- };
13
- const getCellContainerPlatformStyles = (
14
- inverted: boolean,
15
- parentProps: { x: number; y: number; isHorizontal?: boolean }
16
- ): { transform: string; WebkitTransform: string } | undefined => {
17
- const transformValue = `translate(${parentProps.x}px,${parentProps.y}px)${
18
- inverted ? ` ${parentProps.isHorizontal ? `scaleX` : `scaleY`}(-1)` : ``
19
- }`;
20
- return { transform: transformValue, WebkitTransform: transformValue };
21
- };
22
-
23
- const getItemAnimator = (): BaseItemAnimator | undefined => {
24
- return new DefaultJSItemAnimator();
25
5
  };
26
6
 
27
- const getFooterContainer = (): React.ComponentClass | undefined => {
28
- return View;
29
- };
30
-
31
- export {
32
- PlatformConfig,
33
- getCellContainerPlatformStyles,
34
- getItemAnimator,
35
- getFooterContainer,
36
- };
7
+ export { PlatformConfig };
@@ -0,0 +1,74 @@
1
+ import React, { useLayoutEffect, useMemo, useRef } from "react";
2
+
3
+ import {
4
+ RecyclerViewContext,
5
+ RecyclerViewContextProvider,
6
+ useRecyclerViewContext,
7
+ } from "./RecyclerViewContextProvider";
8
+ import { useLayoutState } from "./hooks/useLayoutState";
9
+
10
+ export interface LayoutCommitObserverProps {
11
+ children: React.ReactNode;
12
+ onCommitLayoutEffect?: () => void;
13
+ }
14
+
15
+ /**
16
+ * LayoutCommitObserver can be used to observe when FlashList commits a layout.
17
+ * It is useful when your component has one or more FlashLists somewhere down the tree.
18
+ * LayoutCommitObserver will trigger `onCommitLayoutEffect` when all of the FlashLists in the tree have finished their first commit.
19
+ */
20
+ export const LayoutCommitObserver = React.memo(
21
+ (props: LayoutCommitObserverProps) => {
22
+ const { children, onCommitLayoutEffect } = props;
23
+ const parentRecyclerViewContext = useRecyclerViewContext();
24
+ const [_, setRenderId] = useLayoutState(0);
25
+ const pendingChildIds = useRef<Set<string>>(new Set()).current;
26
+
27
+ useLayoutEffect(() => {
28
+ if (pendingChildIds.size > 0) {
29
+ return;
30
+ }
31
+ onCommitLayoutEffect?.();
32
+ });
33
+
34
+ // Create context for child components
35
+ const recyclerViewContext: RecyclerViewContext<unknown> = useMemo(() => {
36
+ return {
37
+ layout: () => {
38
+ setRenderId((prev) => prev + 1);
39
+ },
40
+ getRef: () => {
41
+ return parentRecyclerViewContext?.getRef() ?? null;
42
+ },
43
+ getParentRef: () => {
44
+ return parentRecyclerViewContext?.getParentRef() ?? null;
45
+ },
46
+ getParentScrollViewRef: () => {
47
+ return parentRecyclerViewContext?.getParentScrollViewRef() ?? null;
48
+ },
49
+ getScrollViewRef: () => {
50
+ return parentRecyclerViewContext?.getScrollViewRef() ?? null;
51
+ },
52
+ markChildLayoutAsPending: (id: string) => {
53
+ parentRecyclerViewContext?.markChildLayoutAsPending(id);
54
+ pendingChildIds.add(id);
55
+ },
56
+ unmarkChildLayoutAsPending: (id: string) => {
57
+ parentRecyclerViewContext?.unmarkChildLayoutAsPending(id);
58
+ if (pendingChildIds.has(id)) {
59
+ pendingChildIds.delete(id);
60
+ recyclerViewContext.layout();
61
+ }
62
+ },
63
+ };
64
+ }, [parentRecyclerViewContext, pendingChildIds, setRenderId]);
65
+
66
+ return (
67
+ <RecyclerViewContextProvider value={recyclerViewContext}>
68
+ {children}
69
+ </RecyclerViewContextProvider>
70
+ );
71
+ }
72
+ );
73
+
74
+ LayoutCommitObserver.displayName = "LayoutCommitObserver";
@@ -20,6 +20,7 @@ import {
20
20
  } from "react-native";
21
21
 
22
22
  import { FlashListRef } from "../FlashListRef";
23
+ import { ErrorMessages } from "../errors/ErrorMessages";
23
24
 
24
25
  import { RVDimension } from "./layout-managers/LayoutManager";
25
26
  import {
@@ -384,6 +385,9 @@ const RecyclerViewComponent = <T,>(
384
385
  stickyHeaderIndices &&
385
386
  stickyHeaderIndices.length > 0
386
387
  ) {
388
+ if (horizontal) {
389
+ throw new Error(ErrorMessages.stickyHeadersNotSupportedForHorizontal);
390
+ }
387
391
  return (
388
392
  <StickyHeaders
389
393
  stickyHeaderIndices={stickyHeaderIndices}
@@ -402,6 +406,7 @@ const RecyclerViewComponent = <T,>(
402
406
  stickyHeaderIndices,
403
407
  renderItem,
404
408
  scrollY,
409
+ horizontal,
405
410
  recyclerViewManager,
406
411
  extraData,
407
412
  ]);
@@ -434,16 +439,6 @@ const RecyclerViewComponent = <T,>(
434
439
  recyclerViewManager.getDataLength() > 0 &&
435
440
  (maintainVisibleContentPosition?.startRenderingFromBottom ?? false);
436
441
 
437
- // Calculate minimum height adjustment for bottom rendering
438
- const adjustmentMinHeight = recyclerViewManager.hasLayout()
439
- ? Math.max(
440
- 0,
441
- recyclerViewManager.getWindowSize().height -
442
- recyclerViewManager.getChildContainerDimensions().height -
443
- recyclerViewManager.firstItemOffset
444
- )
445
- : 0;
446
-
447
442
  // Create view for measuring bounded size
448
443
  const viewToMeasureBoundedSize = useMemo(() => {
449
444
  return (
@@ -451,12 +446,11 @@ const RecyclerViewComponent = <T,>(
451
446
  style={{
452
447
  height: horizontal ? undefined : 0,
453
448
  width: horizontal ? 0 : undefined,
454
- minHeight: shouldRenderFromBottom ? adjustmentMinHeight : undefined,
455
449
  }}
456
450
  ref={firstChildViewRef}
457
451
  />
458
452
  );
459
- }, [horizontal, shouldRenderFromBottom, adjustmentMinHeight]);
453
+ }, [horizontal]);
460
454
 
461
455
  const scrollAnchor = useMemo(() => {
462
456
  if (shouldMaintainVisibleContentPosition) {
@@ -527,6 +521,25 @@ const RecyclerViewComponent = <T,>(
527
521
  horizontal={horizontal}
528
522
  renderStack={recyclerViewManager.getRenderStack()}
529
523
  getLayout={(index) => recyclerViewManager.getLayout(index)}
524
+ getAdjustmentMargin={() => {
525
+ if (!shouldRenderFromBottom || !recyclerViewManager.hasLayout()) {
526
+ return 0;
527
+ }
528
+
529
+ const windowSize = horizontal
530
+ ? recyclerViewManager.getWindowSize().width
531
+ : recyclerViewManager.getWindowSize().height;
532
+ const childContainerSize = horizontal
533
+ ? recyclerViewManager.getChildContainerDimensions().width
534
+ : recyclerViewManager.getChildContainerDimensions().height;
535
+
536
+ return Math.max(
537
+ 0,
538
+ windowSize -
539
+ childContainerSize -
540
+ recyclerViewManager.firstItemOffset
541
+ );
542
+ }}
530
543
  refHolder={refHolder}
531
544
  onSizeChanged={validateItemSize}
532
545
  renderItem={renderItem}
@@ -1,5 +1,6 @@
1
- import ViewabilityManager from "../viewability/ViewabilityManager";
1
+ import { ErrorMessages } from "../errors/ErrorMessages";
2
2
 
3
+ import ViewabilityManager from "./viewability/ViewabilityManager";
3
4
  import { ConsecutiveNumbers } from "./helpers/ConsecutiveNumbers";
4
5
  import { RVGridLayoutManagerImpl } from "./layout-managers/GridLayoutManager";
5
6
  import {
@@ -20,13 +21,14 @@ import {
20
21
  import { RenderStackManager } from "./RenderStackManager";
21
22
  // Abstracts layout manager, render stack manager and viewability manager and generates render stack (progressively on load)
22
23
  export class RecyclerViewManager<T> {
23
- private initialDrawBatchSize = 1;
24
+ private initialDrawBatchSize = 2;
24
25
  private engagedIndicesTracker: RVEngagedIndicesTracker;
25
26
  private renderStackManager: RenderStackManager;
26
27
  private layoutManager?: RVLayoutManager;
27
28
  // Map of index to key
28
29
  private isFirstLayoutComplete = false;
29
30
  private hasRenderedProgressively = false;
31
+ private progressiveRenderCount = 0;
30
32
  private propsRef: RecyclerViewProps<T>;
31
33
  private itemViewabilityManager: ViewabilityManager<T>;
32
34
  private _isDisposed = false;
@@ -53,8 +55,12 @@ export class RecyclerViewManager<T> {
53
55
  return this._isDisposed;
54
56
  }
55
57
 
58
+ public get numColumns() {
59
+ return this.propsRef.numColumns ?? 1;
60
+ }
61
+
56
62
  constructor(props: RecyclerViewProps<T>) {
57
- this.getStableId = this.getStableId.bind(this);
63
+ this.getDataKey = this.getDataKey.bind(this);
58
64
  this.getItemType = this.getItemType.bind(this);
59
65
  this.overrideItemLayout = this.overrideItemLayout.bind(this);
60
66
  this.propsRef = props;
@@ -68,7 +74,7 @@ export class RecyclerViewManager<T> {
68
74
  // updates render stack based on the engaged indices which are sorted. Recycles unused keys.
69
75
  private updateRenderStack = (engagedIndices: ConsecutiveNumbers): void => {
70
76
  this.renderStackManager.sync(
71
- this.getStableId,
77
+ this.getDataKey,
72
78
  this.getItemType,
73
79
  engagedIndices,
74
80
  this.getDataLength()
@@ -87,11 +93,6 @@ export class RecyclerViewManager<T> {
87
93
  this.propsRef = props;
88
94
  this.engagedIndicesTracker.drawDistance =
89
95
  props.drawDistance ?? this.engagedIndicesTracker.drawDistance;
90
- if (this.propsRef.drawDistance === 0) {
91
- this.initialDrawBatchSize = 1;
92
- } else {
93
- this.initialDrawBatchSize = (props.numColumns ?? 1) * 2;
94
- }
95
96
  this.initialDrawBatchSize =
96
97
  this.propsRef.overrideProps?.initialDrawBatchSize ??
97
98
  this.initialDrawBatchSize;
@@ -131,9 +132,7 @@ export class RecyclerViewManager<T> {
131
132
 
132
133
  getLayout(index: number) {
133
134
  if (!this.layoutManager) {
134
- throw new Error(
135
- "LayoutManager is not initialized, layout info is unavailable"
136
- );
135
+ throw new Error(ErrorMessages.layoutManagerNotInitializedLayoutInfo);
137
136
  }
138
137
  return this.layoutManager.getLayout(index);
139
138
  }
@@ -152,9 +151,7 @@ export class RecyclerViewManager<T> {
152
151
  // Doesn't include header / foot etc
153
152
  getChildContainerDimensions() {
154
153
  if (!this.layoutManager) {
155
- throw new Error(
156
- "LayoutManager is not initialized, child container layout is unavailable"
157
- );
154
+ throw new Error(ErrorMessages.layoutManagerNotInitializedChildContainer);
158
155
  }
159
156
  return this.layoutManager.getLayoutSize();
160
157
  }
@@ -165,9 +162,7 @@ export class RecyclerViewManager<T> {
165
162
 
166
163
  getWindowSize() {
167
164
  if (!this.layoutManager) {
168
- throw new Error(
169
- "LayoutManager is not initialized, window size is unavailable"
170
- );
165
+ throw new Error(ErrorMessages.layoutManagerNotInitializedWindowSize);
171
166
  }
172
167
  return this.layoutManager.getWindowsSize();
173
168
  }
@@ -211,9 +206,7 @@ export class RecyclerViewManager<T> {
211
206
  Boolean(this.layoutManager?.isHorizontal()) !==
212
207
  Boolean(this.propsRef.horizontal)
213
208
  ) {
214
- throw new Error(
215
- "Horizontal prop cannot be toggled, you can use a key on FlashList to recreate it."
216
- );
209
+ throw new Error(ErrorMessages.horizontalPropCannotBeToggled);
217
210
  }
218
211
  if (this._isLayoutManagerDirty) {
219
212
  this.layoutManager = undefined;
@@ -221,7 +214,7 @@ export class RecyclerViewManager<T> {
221
214
  }
222
215
  const layoutManagerParams: LayoutParams = {
223
216
  windowSize,
224
- maxColumns: this.propsRef.numColumns ?? 1,
217
+ maxColumns: this.numColumns,
225
218
  horizontal: Boolean(this.propsRef.horizontal),
226
219
  optimizeItemArrangement: this.propsRef.optimizeItemArrangement ?? true,
227
220
  overrideItemLayout: this.overrideItemLayout,
@@ -245,9 +238,7 @@ export class RecyclerViewManager<T> {
245
238
 
246
239
  computeVisibleIndices() {
247
240
  if (!this.layoutManager) {
248
- throw new Error(
249
- "LayoutManager is not initialized, visible indices are not unavailable"
250
- );
241
+ throw new Error(ErrorMessages.layoutManagerNotInitializedVisibleIndices);
251
242
  }
252
243
  return this.engagedIndicesTracker.computeVisibleIndices(this.layoutManager);
253
244
  }
@@ -298,7 +289,7 @@ export class RecyclerViewManager<T> {
298
289
  processDataUpdate() {
299
290
  if (this.hasLayout()) {
300
291
  this.modifyChildrenLayout([], this.propsRef.data?.length ?? 0);
301
- if (!this.recomputeEngagedIndices()) {
292
+ if (this.hasRenderedProgressively && !this.recomputeEngagedIndices()) {
302
293
  // recomputeEngagedIndices will update the render stack if there are any changes in the engaged indices.
303
294
  // It's important to update render stack so that elements are assgined right keys incase items were deleted.
304
295
  this.updateRenderStack(this.engagedIndicesTracker.getEngagedIndices());
@@ -346,17 +337,28 @@ export class RecyclerViewManager<T> {
346
337
  return this.propsRef.data?.length ?? 0;
347
338
  }
348
339
 
340
+ hasStableDataKeys() {
341
+ return Boolean(this.propsRef.keyExtractor);
342
+ }
343
+
344
+ getDataKey(index: number): string {
345
+ return (
346
+ this.propsRef.keyExtractor?.(this.propsRef.data![index], index) ??
347
+ index.toString()
348
+ );
349
+ }
350
+
349
351
  private getLayoutManagerClass() {
350
352
  // throw errors for incompatible props
351
353
  if (this.propsRef.masonry && this.propsRef.horizontal) {
352
- throw new Error("Masonry and horizontal props are incompatible");
354
+ throw new Error(ErrorMessages.masonryAndHorizontalIncompatible);
353
355
  }
354
- if ((this.propsRef.numColumns ?? 1) > 1 && this.propsRef.horizontal) {
355
- throw new Error("numColumns and horizontal props are incompatible");
356
+ if (this.numColumns > 1 && this.propsRef.horizontal) {
357
+ throw new Error(ErrorMessages.numColumnsAndHorizontalIncompatible);
356
358
  }
357
359
  return this.propsRef.masonry
358
360
  ? RVMasonryLayoutManagerImpl
359
- : (this.propsRef.numColumns ?? 1) > 1 && !this.propsRef.horizontal
361
+ : this.numColumns > 1 && !this.propsRef.horizontal
360
362
  ? RVGridLayoutManagerImpl
361
363
  : RVLinearLayoutManagerImpl;
362
364
  }
@@ -392,6 +394,7 @@ export class RecyclerViewManager<T> {
392
394
  }
393
395
 
394
396
  private renderProgressively() {
397
+ this.progressiveRenderCount++;
395
398
  const layoutManager = this.layoutManager;
396
399
  if (layoutManager) {
397
400
  this.applyInitialScrollAdjustment();
@@ -407,16 +410,20 @@ export class RecyclerViewManager<T> {
407
410
  this.isFirstLayoutComplete = true;
408
411
  }
409
412
 
413
+ const batchSize =
414
+ this.numColumns *
415
+ this.initialDrawBatchSize ** Math.ceil(this.progressiveRenderCount / 5);
416
+
410
417
  // If everything is measured then render stack will be in sync. The buffer items will get rendered in the next update
411
418
  // triggered by the useOnLoad hook.
412
419
  !this.hasRenderedProgressively &&
413
420
  this.updateRenderStack(
414
- // pick first n indices from visible ones and n is size of renderStack
421
+ // pick first n indices from visible ones based on batch size
415
422
  visibleIndices.slice(
416
423
  0,
417
424
  Math.min(
418
425
  visibleIndices.length,
419
- this.getRenderStack().size + this.initialDrawBatchSize
426
+ this.getRenderStack().size + batchSize
420
427
  )
421
428
  )
422
429
  );
@@ -430,19 +437,12 @@ export class RecyclerViewManager<T> {
430
437
  ).toString();
431
438
  }
432
439
 
433
- private getStableId(index: number): string {
434
- return (
435
- this.propsRef.keyExtractor?.(this.propsRef.data![index], index) ??
436
- index.toString()
437
- );
438
- }
439
-
440
440
  private overrideItemLayout(index: number, layout: SpanSizeInfo) {
441
441
  this.propsRef?.overrideItemLayout?.(
442
442
  layout,
443
443
  this.propsRef.data![index],
444
444
  index,
445
- this.propsRef.numColumns ?? 1,
445
+ this.numColumns,
446
446
  this.propsRef.extraData
447
447
  );
448
448
  }
@@ -1,11 +1 @@
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
- }
1
+ export { FlashListProps as RecyclerViewProps } from "../FlashListProps";
@@ -37,15 +37,19 @@ export interface ViewHolderCollectionProps<TItem> {
37
37
  /** Function to get the container's layout dimensions */
38
38
  getChildContainerLayout: () => RVDimension | undefined;
39
39
  /** Callback after layout effects are committed */
40
- onCommitLayoutEffect?: () => void;
40
+ onCommitLayoutEffect: () => void;
41
41
  /** Callback after effects are committed */
42
- onCommitEffect?: () => void;
42
+ onCommitEffect: () => void;
43
43
  /** Optional custom component to wrap each item */
44
44
  CellRendererComponent?: FlashListProps<TItem>["CellRendererComponent"];
45
45
  /** Optional component to render between items */
46
46
  ItemSeparatorComponent?: FlashListProps<TItem>["ItemSeparatorComponent"];
47
47
  /** Whether the list is horizontal or vertical */
48
48
  horizontal: FlashListProps<TItem>["horizontal"];
49
+ /** Function to get the adjustment margin for the container.
50
+ * For startRenderingFromBottom, we need to adjust the height of the container
51
+ */
52
+ getAdjustmentMargin: () => number;
49
53
  }
50
54
 
51
55
  /**
@@ -79,6 +83,7 @@ export const ViewHolderCollection = <TItem,>(
79
83
  ItemSeparatorComponent,
80
84
  onCommitEffect,
81
85
  horizontal,
86
+ getAdjustmentMargin,
82
87
  } = props;
83
88
 
84
89
  const [renderId, setRenderId] = React.useState(0);
@@ -136,6 +141,8 @@ export const ViewHolderCollection = <TItem,>(
136
141
  const containerStyle = {
137
142
  width: horizontal ? containerLayout?.width : undefined,
138
143
  height: containerLayout?.height,
144
+ marginTop: horizontal ? undefined : getAdjustmentMargin(),
145
+ marginLeft: horizontal ? getAdjustmentMargin() : undefined,
139
146
  // TODO: Temp workaround, useLayoutEffect doesn't block paint in some cases
140
147
  // We need to investigate why this is happening
141
148
  opacity: renderId > 0 ? 1 : 0,
@@ -26,14 +26,35 @@ export function useBoundDetection<T>(
26
26
  const pendingStartReached = useRef(false);
27
27
  // Track whether we should auto-scroll to bottom when new content is added
28
28
  const pendingAutoscrollToBottom = useRef(false);
29
+
30
+ const lastCheckBoundsTime = useRef(Date.now());
31
+
29
32
  const { data } = recyclerViewManager.props;
30
33
  const { requestAnimationFrame } = useUnmountAwareAnimationFrame();
31
34
 
35
+ const windowHeight = recyclerViewManager.hasLayout()
36
+ ? recyclerViewManager.getWindowSize().height
37
+ : 0;
38
+
39
+ const contentHeight = recyclerViewManager.hasLayout()
40
+ ? recyclerViewManager.getChildContainerDimensions().height
41
+ : 0;
42
+
43
+ const windowWidth = recyclerViewManager.hasLayout()
44
+ ? recyclerViewManager.getWindowSize().width
45
+ : 0;
46
+
47
+ const contentWidth = recyclerViewManager.hasLayout()
48
+ ? recyclerViewManager.getChildContainerDimensions().width
49
+ : 0;
50
+
32
51
  /**
33
52
  * Checks if the scroll position is near the start or end of the list
34
53
  * and triggers appropriate callbacks if configured.
35
54
  */
36
55
  const checkBounds = useCallback(() => {
56
+ lastCheckBoundsTime.current = Date.now();
57
+
37
58
  const {
38
59
  onEndReached,
39
60
  onStartReached,
@@ -111,6 +132,20 @@ export function useBoundDetection<T>(
111
132
  }
112
133
  }, [recyclerViewManager]);
113
134
 
135
+ const runAutoScrollToBottomCheck = useCallback(() => {
136
+ if (pendingAutoscrollToBottom.current) {
137
+ pendingAutoscrollToBottom.current = false;
138
+ requestAnimationFrame(() => {
139
+ const shouldAnimate =
140
+ recyclerViewManager.props.maintainVisibleContentPosition
141
+ ?.animateAutoScrollToBottom ?? true;
142
+ scrollViewRef.current?.scrollToEnd({
143
+ animated: shouldAnimate,
144
+ });
145
+ });
146
+ }
147
+ }, [requestAnimationFrame, scrollViewRef, recyclerViewManager]);
148
+
114
149
  // Reset end reached state when data changes
115
150
  useMemo(() => {
116
151
  pendingEndReached.current = false;
@@ -120,13 +155,20 @@ export function useBoundDetection<T>(
120
155
 
121
156
  // Auto-scroll to bottom when new content is added and we're near the bottom
122
157
  useEffect(() => {
123
- if (pendingAutoscrollToBottom.current) {
124
- requestAnimationFrame(() => {
125
- scrollViewRef.current?.scrollToEnd();
126
- pendingAutoscrollToBottom.current = false;
127
- });
158
+ runAutoScrollToBottomCheck();
159
+ }, [data, runAutoScrollToBottomCheck, windowHeight, windowWidth]);
160
+
161
+ // Since content changes frequently, we try and avoid doing the auto scroll during active scrolls
162
+ useEffect(() => {
163
+ if (Date.now() - lastCheckBoundsTime.current >= 100) {
164
+ runAutoScrollToBottomCheck();
128
165
  }
129
- }, [data, requestAnimationFrame, scrollViewRef]);
166
+ }, [
167
+ contentHeight,
168
+ contentWidth,
169
+ recyclerViewManager.firstItemOffset,
170
+ runAutoScrollToBottomCheck,
171
+ ]);
130
172
 
131
173
  return {
132
174
  checkBounds,