react-native-nitro-list 0.0.1 → 0.1.2

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 (417) hide show
  1. package/README.md +250 -16
  2. package/android/build.gradle +5 -4
  3. package/android/src/main/java/com/nitrolist/HybridNitroRecyclerView.kt +26 -0
  4. package/android/src/main/java/com/nitrolist/HybridNitroRecyclerViewManager.kt +29 -0
  5. package/android/src/main/java/com/nitrolist/NitroListPackage.kt +13 -24
  6. package/android/src/main/java/com/nitrolist/NitroRecyclerAdapter.kt +32 -0
  7. package/android/src/main/java/com/nitrolist/NitroRecyclerViewHolder.kt +8 -0
  8. package/ios/HybridNitroList.swift +28 -15
  9. package/lib/commonjs/NitroList.js +9 -0
  10. package/lib/commonjs/NitroList.js.map +1 -0
  11. package/lib/commonjs/ReusableView.js +2 -0
  12. package/lib/commonjs/ReusableView.js.map +1 -0
  13. package/lib/commonjs/cell/Cell.js +2 -0
  14. package/lib/{module/specs/nitro-list.nitro.js.map → commonjs/cell/Cell.js.map} +1 -1
  15. package/lib/commonjs/cell/CellKeyGenerator.js +21 -0
  16. package/lib/commonjs/cell/CellKeyGenerator.js.map +1 -0
  17. package/lib/commonjs/cell/CellRecycler.js +70 -0
  18. package/lib/commonjs/cell/CellRecycler.js.map +1 -0
  19. package/lib/commonjs/cell/createCell.js +21 -0
  20. package/lib/commonjs/cell/createCell.js.map +1 -0
  21. package/lib/commonjs/cell/index.js +20 -0
  22. package/lib/commonjs/cell/index.js.map +1 -0
  23. package/lib/commonjs/debug/useDebugOverlay.js +15 -0
  24. package/lib/commonjs/debug/useDebugOverlay.js.map +1 -0
  25. package/lib/commonjs/getVisibleIndices.js +38 -0
  26. package/lib/commonjs/getVisibleIndices.js.map +1 -0
  27. package/lib/commonjs/hooks/usePersistentCallback.js +36 -0
  28. package/lib/commonjs/hooks/usePersistentCallback.js.map +1 -0
  29. package/lib/commonjs/index.js +7 -5
  30. package/lib/commonjs/index.js.map +1 -1
  31. package/lib/commonjs/layout/MutableLinearLayout.js +104 -0
  32. package/lib/commonjs/layout/MutableLinearLayout.js.map +1 -0
  33. package/lib/commonjs/layout/constants/layoutDefaults.js +19 -0
  34. package/lib/commonjs/layout/constants/layoutDefaults.js.map +1 -0
  35. package/lib/commonjs/layout/index.js +2 -0
  36. package/lib/commonjs/{specs/nitro-list.nitro.js.map → layout/index.js.map} +1 -1
  37. package/lib/commonjs/measurement/MeasureLayout.js +20 -0
  38. package/lib/commonjs/measurement/MeasureLayout.js.map +1 -0
  39. package/lib/commonjs/measurement/useItemMeasurement.js +28 -0
  40. package/lib/commonjs/measurement/useItemMeasurement.js.map +1 -0
  41. package/lib/commonjs/native/NitroLayoutEngine.js +9 -0
  42. package/lib/commonjs/native/NitroLayoutEngine.js.map +1 -0
  43. package/lib/commonjs/{specs/nitro-list.nitro.js → native/NitroList.types.js} +1 -1
  44. package/lib/commonjs/native/NitroList.types.js.map +1 -0
  45. package/lib/commonjs/native/NitroRecyclerView.js +9 -0
  46. package/lib/commonjs/native/NitroRecyclerView.js.map +1 -0
  47. package/lib/commonjs/prefetch/PrefetchHelper.js +39 -0
  48. package/lib/commonjs/prefetch/PrefetchHelper.js.map +1 -0
  49. package/lib/commonjs/recycler/CellPool.js +46 -0
  50. package/lib/commonjs/recycler/CellPool.js.map +1 -0
  51. package/lib/commonjs/recycler/RecyclerList.js +224 -0
  52. package/lib/commonjs/recycler/RecyclerList.js.map +1 -0
  53. package/lib/commonjs/specs/nitro-layout-engine.nitro.js +6 -0
  54. package/lib/commonjs/specs/nitro-layout-engine.nitro.js.map +1 -0
  55. package/lib/commonjs/types/Axis.js +2 -0
  56. package/lib/commonjs/types/Axis.js.map +1 -0
  57. package/lib/commonjs/types/CellKey.js +2 -0
  58. package/lib/commonjs/types/CellKey.js.map +1 -0
  59. package/lib/commonjs/types/CellType.js +2 -0
  60. package/lib/commonjs/types/CellType.js.map +1 -0
  61. package/lib/commonjs/types/VisibleRange.js +2 -0
  62. package/lib/commonjs/types/VisibleRange.js.map +1 -0
  63. package/lib/commonjs/types/VisibleRangeInput.js +6 -0
  64. package/lib/commonjs/types/VisibleRangeInput.js.map +1 -0
  65. package/lib/commonjs/types/index.js +13 -0
  66. package/lib/commonjs/types/index.js.map +1 -0
  67. package/lib/commonjs/types/layout/LayoutRect.js +2 -0
  68. package/lib/commonjs/types/layout/LayoutRect.js.map +1 -0
  69. package/lib/commonjs/types/layout/LinearLayoutInput.js +6 -0
  70. package/lib/commonjs/types/layout/LinearLayoutInput.js.map +1 -0
  71. package/lib/commonjs/types/layout/MainAxisPadding.js +26 -0
  72. package/lib/commonjs/types/layout/MainAxisPadding.js.map +1 -0
  73. package/lib/commonjs/types/layout/index.js +2 -0
  74. package/lib/commonjs/types/layout/index.js.map +1 -0
  75. package/lib/commonjs/types/recycler/RecyclerCellInstance.js +6 -0
  76. package/lib/commonjs/types/recycler/RecyclerCellInstance.js.map +1 -0
  77. package/lib/commonjs/types/recycler/RecyclerItemRenderer.js +6 -0
  78. package/lib/commonjs/types/recycler/RecyclerItemRenderer.js.map +1 -0
  79. package/lib/commonjs/types/recycler/RecyclerListProps.js +6 -0
  80. package/lib/commonjs/types/recycler/RecyclerListProps.js.map +1 -0
  81. package/lib/commonjs/types/recycler/index.js +2 -0
  82. package/lib/commonjs/types/recycler/index.js.map +1 -0
  83. package/lib/commonjs/types/scroll/ScrollMetrics.js +6 -0
  84. package/lib/commonjs/types/scroll/ScrollMetrics.js.map +1 -0
  85. package/lib/commonjs/types/scroll/index.js +2 -0
  86. package/lib/commonjs/types/scroll/index.js.map +1 -0
  87. package/lib/commonjs/utils/arrayEqual.js +15 -0
  88. package/lib/commonjs/utils/arrayEqual.js.map +1 -0
  89. package/lib/commonjs/utils/assertNever.js +10 -0
  90. package/lib/commonjs/utils/assertNever.js.map +1 -0
  91. package/lib/commonjs/utils/clamp.js +10 -0
  92. package/lib/commonjs/utils/clamp.js.map +1 -0
  93. package/lib/commonjs/utils/devAssert.js +12 -0
  94. package/lib/commonjs/utils/devAssert.js.map +1 -0
  95. package/lib/commonjs/utils/invariant.js +12 -0
  96. package/lib/commonjs/utils/invariant.js.map +1 -0
  97. package/lib/commonjs/utils/isDefined.js +10 -0
  98. package/lib/commonjs/utils/isDefined.js.map +1 -0
  99. package/lib/commonjs/utils/isNumber.js +10 -0
  100. package/lib/commonjs/utils/isNumber.js.map +1 -0
  101. package/lib/commonjs/utils/noop.js +10 -0
  102. package/lib/commonjs/utils/noop.js.map +1 -0
  103. package/lib/commonjs/utils/shallowEqual.js +22 -0
  104. package/lib/commonjs/utils/shallowEqual.js.map +1 -0
  105. package/lib/commonjs/utils/throttle.js +17 -0
  106. package/lib/commonjs/utils/throttle.js.map +1 -0
  107. package/lib/commonjs/windowing/ScrollMetrics.js +2 -0
  108. package/lib/commonjs/windowing/ScrollMetrics.js.map +1 -0
  109. package/lib/commonjs/windowing/computeVisibleItemRange.js +71 -0
  110. package/lib/commonjs/windowing/computeVisibleItemRange.js.map +1 -0
  111. package/lib/commonjs/windowing/index.js +20 -0
  112. package/lib/commonjs/windowing/index.js.map +1 -0
  113. package/lib/commonjs/windowing/useScrollMetrics.js +39 -0
  114. package/lib/commonjs/windowing/useScrollMetrics.js.map +1 -0
  115. package/lib/module/NitroList.js +5 -0
  116. package/lib/module/NitroList.js.map +1 -0
  117. package/lib/module/ReusableView.js +2 -0
  118. package/lib/module/ReusableView.js.map +1 -0
  119. package/lib/module/cell/Cell.js +2 -0
  120. package/lib/module/cell/Cell.js.map +1 -0
  121. package/lib/module/cell/CellKeyGenerator.js +16 -0
  122. package/lib/module/cell/CellKeyGenerator.js.map +1 -0
  123. package/lib/module/cell/CellRecycler.js +66 -0
  124. package/lib/module/cell/CellRecycler.js.map +1 -0
  125. package/lib/module/cell/createCell.js +17 -0
  126. package/lib/module/cell/createCell.js.map +1 -0
  127. package/lib/module/cell/index.js +7 -0
  128. package/lib/module/cell/index.js.map +1 -0
  129. package/lib/module/debug/useDebugOverlay.js +11 -0
  130. package/lib/module/debug/useDebugOverlay.js.map +1 -0
  131. package/lib/module/getVisibleIndices.js +34 -0
  132. package/lib/module/getVisibleIndices.js.map +1 -0
  133. package/lib/module/hooks/usePersistentCallback.js +33 -0
  134. package/lib/module/hooks/usePersistentCallback.js.map +1 -0
  135. package/lib/module/index.js +1 -3
  136. package/lib/module/index.js.map +1 -1
  137. package/lib/module/layout/MutableLinearLayout.js +100 -0
  138. package/lib/module/layout/MutableLinearLayout.js.map +1 -0
  139. package/lib/module/layout/constants/layoutDefaults.js +15 -0
  140. package/lib/module/layout/constants/layoutDefaults.js.map +1 -0
  141. package/lib/module/layout/index.js +2 -0
  142. package/lib/module/layout/index.js.map +1 -0
  143. package/lib/module/measurement/MeasureLayout.js +16 -0
  144. package/lib/module/measurement/MeasureLayout.js.map +1 -0
  145. package/lib/module/measurement/useItemMeasurement.js +24 -0
  146. package/lib/module/measurement/useItemMeasurement.js.map +1 -0
  147. package/lib/module/native/NitroLayoutEngine.js +5 -0
  148. package/lib/module/native/NitroLayoutEngine.js.map +1 -0
  149. package/lib/module/native/NitroList.types.js +4 -0
  150. package/lib/module/native/NitroList.types.js.map +1 -0
  151. package/lib/module/native/NitroRecyclerView.js +5 -0
  152. package/lib/module/native/NitroRecyclerView.js.map +1 -0
  153. package/lib/module/prefetch/PrefetchHelper.js +34 -0
  154. package/lib/module/prefetch/PrefetchHelper.js.map +1 -0
  155. package/lib/module/recycler/CellPool.js +41 -0
  156. package/lib/module/recycler/CellPool.js.map +1 -0
  157. package/lib/module/recycler/RecyclerList.js +221 -0
  158. package/lib/module/recycler/RecyclerList.js.map +1 -0
  159. package/lib/module/specs/nitro-layout-engine.nitro.js +4 -0
  160. package/lib/module/specs/nitro-layout-engine.nitro.js.map +1 -0
  161. package/lib/module/types/Axis.js +2 -0
  162. package/lib/module/types/Axis.js.map +1 -0
  163. package/lib/module/types/CellKey.js +2 -0
  164. package/lib/module/types/CellKey.js.map +1 -0
  165. package/lib/module/types/CellType.js +2 -0
  166. package/lib/module/types/CellType.js.map +1 -0
  167. package/lib/module/types/VisibleRange.js +2 -0
  168. package/lib/module/types/VisibleRange.js.map +1 -0
  169. package/lib/module/types/VisibleRangeInput.js +4 -0
  170. package/lib/module/types/VisibleRangeInput.js.map +1 -0
  171. package/lib/module/types/index.js +4 -0
  172. package/lib/module/types/index.js.map +1 -0
  173. package/lib/module/types/layout/LayoutRect.js +2 -0
  174. package/lib/module/types/layout/LayoutRect.js.map +1 -0
  175. package/lib/module/types/layout/LinearLayoutInput.js +4 -0
  176. package/lib/module/types/layout/LinearLayoutInput.js.map +1 -0
  177. package/lib/module/types/layout/MainAxisPadding.js +22 -0
  178. package/lib/module/types/layout/MainAxisPadding.js.map +1 -0
  179. package/lib/module/types/layout/index.js +2 -0
  180. package/lib/module/types/layout/index.js.map +1 -0
  181. package/lib/module/types/recycler/RecyclerCellInstance.js +4 -0
  182. package/lib/module/types/recycler/RecyclerCellInstance.js.map +1 -0
  183. package/lib/module/types/recycler/RecyclerItemRenderer.js +4 -0
  184. package/lib/module/types/recycler/RecyclerItemRenderer.js.map +1 -0
  185. package/lib/module/types/recycler/RecyclerListProps.js +4 -0
  186. package/lib/module/types/recycler/RecyclerListProps.js.map +1 -0
  187. package/lib/module/types/recycler/index.js +2 -0
  188. package/lib/module/types/recycler/index.js.map +1 -0
  189. package/lib/module/types/scroll/ScrollMetrics.js +4 -0
  190. package/lib/module/types/scroll/ScrollMetrics.js.map +1 -0
  191. package/lib/module/types/scroll/index.js +2 -0
  192. package/lib/module/types/scroll/index.js.map +1 -0
  193. package/lib/module/utils/arrayEqual.js +11 -0
  194. package/lib/module/utils/arrayEqual.js.map +1 -0
  195. package/lib/module/utils/assertNever.js +6 -0
  196. package/lib/module/utils/assertNever.js.map +1 -0
  197. package/lib/module/utils/clamp.js +6 -0
  198. package/lib/module/utils/clamp.js.map +1 -0
  199. package/lib/module/utils/devAssert.js +8 -0
  200. package/lib/module/utils/devAssert.js.map +1 -0
  201. package/lib/module/utils/invariant.js +8 -0
  202. package/lib/module/utils/invariant.js.map +1 -0
  203. package/lib/module/utils/isDefined.js +6 -0
  204. package/lib/module/utils/isDefined.js.map +1 -0
  205. package/lib/module/utils/isNumber.js +6 -0
  206. package/lib/module/utils/isNumber.js.map +1 -0
  207. package/lib/module/utils/noop.js +6 -0
  208. package/lib/module/utils/noop.js.map +1 -0
  209. package/lib/module/utils/shallowEqual.js +18 -0
  210. package/lib/module/utils/shallowEqual.js.map +1 -0
  211. package/lib/module/utils/throttle.js +13 -0
  212. package/lib/module/utils/throttle.js.map +1 -0
  213. package/lib/module/windowing/ScrollMetrics.js +2 -0
  214. package/lib/module/windowing/ScrollMetrics.js.map +1 -0
  215. package/lib/module/windowing/computeVisibleItemRange.js +67 -0
  216. package/lib/module/windowing/computeVisibleItemRange.js.map +1 -0
  217. package/lib/module/windowing/index.js +5 -0
  218. package/lib/module/windowing/index.js.map +1 -0
  219. package/lib/module/windowing/useScrollMetrics.js +35 -0
  220. package/lib/module/windowing/useScrollMetrics.js.map +1 -0
  221. package/lib/typescript/src/NitroList.d.ts +5 -0
  222. package/lib/typescript/src/NitroList.d.ts.map +1 -0
  223. package/lib/typescript/src/ReusableView.d.ts +9 -0
  224. package/lib/typescript/src/ReusableView.d.ts.map +1 -0
  225. package/lib/typescript/src/cell/Cell.d.ts +22 -0
  226. package/lib/typescript/src/cell/Cell.d.ts.map +1 -0
  227. package/lib/typescript/src/cell/CellKeyGenerator.d.ts +11 -0
  228. package/lib/typescript/src/cell/CellKeyGenerator.d.ts.map +1 -0
  229. package/lib/typescript/src/cell/CellRecycler.d.ts +27 -0
  230. package/lib/typescript/src/cell/CellRecycler.d.ts.map +1 -0
  231. package/lib/typescript/src/cell/createCell.d.ts +7 -0
  232. package/lib/typescript/src/cell/createCell.d.ts.map +1 -0
  233. package/lib/typescript/src/cell/index.d.ts +4 -0
  234. package/lib/typescript/src/cell/index.d.ts.map +1 -0
  235. package/lib/typescript/src/debug/useDebugOverlay.d.ts +2 -0
  236. package/lib/typescript/src/debug/useDebugOverlay.d.ts.map +1 -0
  237. package/lib/typescript/src/getVisibleIndices.d.ts +8 -0
  238. package/lib/typescript/src/getVisibleIndices.d.ts.map +1 -0
  239. package/lib/typescript/src/hooks/usePersistentCallback.d.ts +16 -0
  240. package/lib/typescript/src/hooks/usePersistentCallback.d.ts.map +1 -0
  241. package/lib/typescript/src/index.d.ts +1 -4
  242. package/lib/typescript/src/index.d.ts.map +1 -1
  243. package/lib/typescript/src/layout/MutableLinearLayout.d.ts +54 -0
  244. package/lib/typescript/src/layout/MutableLinearLayout.d.ts.map +1 -0
  245. package/lib/typescript/src/layout/constants/layoutDefaults.d.ts +13 -0
  246. package/lib/typescript/src/layout/constants/layoutDefaults.d.ts.map +1 -0
  247. package/lib/typescript/src/layout/index.d.ts +2 -0
  248. package/lib/typescript/src/layout/index.d.ts.map +1 -0
  249. package/lib/typescript/src/measurement/MeasureLayout.d.ts +10 -0
  250. package/lib/typescript/src/measurement/MeasureLayout.d.ts.map +1 -0
  251. package/lib/typescript/src/measurement/useItemMeasurement.d.ts +11 -0
  252. package/lib/typescript/src/measurement/useItemMeasurement.d.ts.map +1 -0
  253. package/lib/typescript/src/native/NitroLayoutEngine.d.ts +3 -0
  254. package/lib/typescript/src/native/NitroLayoutEngine.d.ts.map +1 -0
  255. package/lib/typescript/src/native/NitroList.types.d.ts +9 -0
  256. package/lib/typescript/src/native/NitroList.types.d.ts.map +1 -0
  257. package/lib/typescript/src/native/NitroRecyclerView.d.ts +5 -0
  258. package/lib/typescript/src/native/NitroRecyclerView.d.ts.map +1 -0
  259. package/lib/typescript/src/prefetch/PrefetchHelper.d.ts +17 -0
  260. package/lib/typescript/src/prefetch/PrefetchHelper.d.ts.map +1 -0
  261. package/lib/typescript/src/recycler/CellPool.d.ts +14 -0
  262. package/lib/typescript/src/recycler/CellPool.d.ts.map +1 -0
  263. package/lib/typescript/src/recycler/RecyclerList.d.ts +4 -0
  264. package/lib/typescript/src/recycler/RecyclerList.d.ts.map +1 -0
  265. package/lib/typescript/src/specs/nitro-layout-engine.nitro.d.ts +14 -0
  266. package/lib/typescript/src/specs/nitro-layout-engine.nitro.d.ts.map +1 -0
  267. package/lib/typescript/src/types/Axis.d.ts +11 -0
  268. package/lib/typescript/src/types/Axis.d.ts.map +1 -0
  269. package/lib/typescript/src/types/CellKey.d.ts +10 -0
  270. package/lib/typescript/src/types/CellKey.d.ts.map +1 -0
  271. package/lib/typescript/src/types/CellType.d.ts +11 -0
  272. package/lib/typescript/src/types/CellType.d.ts.map +1 -0
  273. package/lib/typescript/src/types/VisibleRange.d.ts +10 -0
  274. package/lib/typescript/src/types/VisibleRange.d.ts.map +1 -0
  275. package/lib/typescript/src/types/VisibleRangeInput.d.ts +35 -0
  276. package/lib/typescript/src/types/VisibleRangeInput.d.ts.map +1 -0
  277. package/lib/typescript/src/types/index.d.ts +8 -0
  278. package/lib/typescript/src/types/index.d.ts.map +1 -0
  279. package/lib/typescript/src/types/layout/LayoutRect.d.ts +15 -0
  280. package/lib/typescript/src/types/layout/LayoutRect.d.ts.map +1 -0
  281. package/lib/typescript/src/types/layout/LinearLayoutInput.d.ts +10 -0
  282. package/lib/typescript/src/types/layout/LinearLayoutInput.d.ts.map +1 -0
  283. package/lib/typescript/src/types/layout/MainAxisPadding.d.ts +20 -0
  284. package/lib/typescript/src/types/layout/MainAxisPadding.d.ts.map +1 -0
  285. package/lib/typescript/src/types/layout/index.d.ts +4 -0
  286. package/lib/typescript/src/types/layout/index.d.ts.map +1 -0
  287. package/lib/typescript/src/types/recycler/RecyclerCellInstance.d.ts +37 -0
  288. package/lib/typescript/src/types/recycler/RecyclerCellInstance.d.ts.map +1 -0
  289. package/lib/typescript/src/types/recycler/RecyclerItemRenderer.d.ts +8 -0
  290. package/lib/typescript/src/types/recycler/RecyclerItemRenderer.d.ts.map +1 -0
  291. package/lib/typescript/src/types/recycler/RecyclerListProps.d.ts +66 -0
  292. package/lib/typescript/src/types/recycler/RecyclerListProps.d.ts.map +1 -0
  293. package/lib/typescript/src/types/recycler/index.d.ts +4 -0
  294. package/lib/typescript/src/types/recycler/index.d.ts.map +1 -0
  295. package/lib/typescript/src/types/scroll/ScrollMetrics.d.ts +15 -0
  296. package/lib/typescript/src/types/scroll/ScrollMetrics.d.ts.map +1 -0
  297. package/lib/typescript/src/types/scroll/index.d.ts +2 -0
  298. package/lib/typescript/src/types/scroll/index.d.ts.map +1 -0
  299. package/lib/typescript/src/utils/arrayEqual.d.ts +2 -0
  300. package/lib/typescript/src/utils/arrayEqual.d.ts.map +1 -0
  301. package/lib/typescript/src/utils/assertNever.d.ts +2 -0
  302. package/lib/typescript/src/utils/assertNever.d.ts.map +1 -0
  303. package/lib/typescript/src/utils/clamp.d.ts +2 -0
  304. package/lib/typescript/src/utils/clamp.d.ts.map +1 -0
  305. package/lib/typescript/src/utils/devAssert.d.ts +2 -0
  306. package/lib/typescript/src/utils/devAssert.d.ts.map +1 -0
  307. package/lib/typescript/src/utils/invariant.d.ts +2 -0
  308. package/lib/typescript/src/utils/invariant.d.ts.map +1 -0
  309. package/lib/typescript/src/utils/isDefined.d.ts +2 -0
  310. package/lib/typescript/src/utils/isDefined.d.ts.map +1 -0
  311. package/lib/typescript/src/utils/isNumber.d.ts +2 -0
  312. package/lib/typescript/src/utils/isNumber.d.ts.map +1 -0
  313. package/lib/typescript/src/utils/noop.d.ts +2 -0
  314. package/lib/typescript/src/utils/noop.d.ts.map +1 -0
  315. package/lib/typescript/src/utils/shallowEqual.d.ts +2 -0
  316. package/lib/typescript/src/utils/shallowEqual.d.ts.map +1 -0
  317. package/lib/typescript/src/utils/throttle.d.ts +2 -0
  318. package/lib/typescript/src/utils/throttle.d.ts.map +1 -0
  319. package/lib/typescript/src/windowing/ScrollMetrics.d.ts +11 -0
  320. package/lib/typescript/src/windowing/ScrollMetrics.d.ts.map +1 -0
  321. package/lib/typescript/src/windowing/computeVisibleItemRange.d.ts +15 -0
  322. package/lib/typescript/src/windowing/computeVisibleItemRange.d.ts.map +1 -0
  323. package/lib/typescript/src/windowing/index.d.ts +4 -0
  324. package/lib/typescript/src/windowing/index.d.ts.map +1 -0
  325. package/lib/typescript/src/windowing/useScrollMetrics.d.ts +14 -0
  326. package/lib/typescript/src/windowing/useScrollMetrics.d.ts.map +1 -0
  327. package/nitro.json +20 -13
  328. package/nitrogen/generated/android/NitroList+autolinking.cmake +2 -4
  329. package/nitrogen/generated/android/NitroListOnLoad.cpp +3 -13
  330. package/nitrogen/generated/android/c++/JHybridNitroLayoutEngineSpec.cpp +69 -0
  331. package/nitrogen/generated/android/c++/{JHybridNitroListSpec.hpp → JHybridNitroLayoutEngineSpec.hpp} +12 -13
  332. package/nitrogen/generated/android/c++/JLayoutRect.hpp +69 -0
  333. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrolist/{HybridNitroListSpec.kt → HybridNitroLayoutEngineSpec.kt} +11 -13
  334. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrolist/LayoutRect.kt +47 -0
  335. package/nitrogen/generated/ios/NitroList-Swift-Cxx-Bridge.cpp +9 -9
  336. package/nitrogen/generated/ios/NitroList-Swift-Cxx-Bridge.hpp +50 -13
  337. package/nitrogen/generated/ios/NitroList-Swift-Cxx-Umbrella.hpp +11 -5
  338. package/nitrogen/generated/ios/c++/{HybridNitroListSpecSwift.cpp → HybridNitroLayoutEngineSpecSwift.cpp} +2 -2
  339. package/nitrogen/generated/ios/c++/HybridNitroLayoutEngineSpecSwift.hpp +78 -0
  340. package/nitrogen/generated/ios/swift/HybridNitroLayoutEngineSpec.swift +56 -0
  341. package/nitrogen/generated/ios/swift/{HybridNitroListSpec_cxx.swift → HybridNitroLayoutEngineSpec_cxx.swift} +35 -38
  342. package/nitrogen/generated/ios/swift/LayoutRect.swift +45 -0
  343. package/nitrogen/generated/shared/c++/{HybridNitroListSpec.cpp → HybridNitroLayoutEngineSpec.cpp} +4 -5
  344. package/nitrogen/generated/shared/c++/{HybridNitroListSpec.hpp → HybridNitroLayoutEngineSpec.hpp} +15 -14
  345. package/nitrogen/generated/shared/c++/LayoutRect.hpp +95 -0
  346. package/package.json +12 -4
  347. package/src/NitroList.ts +8 -0
  348. package/src/ReusableView.ts +12 -0
  349. package/src/cell/Cell.ts +23 -0
  350. package/src/cell/CellKeyGenerator.ts +17 -0
  351. package/src/cell/CellRecycler.ts +76 -0
  352. package/src/cell/createCell.ts +15 -0
  353. package/src/cell/index.ts +5 -0
  354. package/src/debug/useDebugOverlay.ts +14 -0
  355. package/src/getVisibleIndices.ts +55 -0
  356. package/src/hooks/usePersistentCallback.ts +37 -0
  357. package/src/index.ts +1 -14
  358. package/src/layout/MutableLinearLayout.ts +112 -0
  359. package/src/layout/constants/layoutDefaults.ts +12 -0
  360. package/src/layout/index.ts +1 -0
  361. package/src/measurement/MeasureLayout.ts +20 -0
  362. package/src/measurement/useItemMeasurement.ts +32 -0
  363. package/src/native/NitroLayoutEngine.ts +7 -0
  364. package/src/native/NitroList.types.ts +13 -0
  365. package/src/native/NitroRecyclerView.ts +8 -0
  366. package/src/prefetch/PrefetchHelper.ts +47 -0
  367. package/src/recycler/CellPool.ts +47 -0
  368. package/src/recycler/RecyclerList.tsx +304 -0
  369. package/src/specs/nitro-layout-engine.nitro.ts +17 -0
  370. package/src/types/Axis.ts +10 -0
  371. package/src/types/CellKey.ts +9 -0
  372. package/src/types/CellType.ts +10 -0
  373. package/src/types/VisibleRange.ts +9 -0
  374. package/src/types/VisibleRangeInput.ts +39 -0
  375. package/src/types/index.ts +15 -0
  376. package/src/types/layout/LayoutRect.ts +14 -0
  377. package/src/types/layout/LinearLayoutInput.ts +12 -0
  378. package/src/types/layout/MainAxisPadding.ts +23 -0
  379. package/src/types/layout/index.ts +3 -0
  380. package/src/types/recycler/RecyclerCellInstance.ts +40 -0
  381. package/src/types/recycler/RecyclerItemRenderer.ts +8 -0
  382. package/src/types/recycler/RecyclerListProps.ts +74 -0
  383. package/src/types/recycler/index.ts +3 -0
  384. package/src/types/scroll/ScrollMetrics.ts +18 -0
  385. package/src/types/scroll/index.ts +1 -0
  386. package/src/utils/arrayEqual.ts +13 -0
  387. package/src/utils/assertNever.ts +3 -0
  388. package/src/utils/clamp.ts +7 -0
  389. package/src/utils/devAssert.ts +8 -0
  390. package/src/utils/invariant.ts +8 -0
  391. package/src/utils/isDefined.ts +5 -0
  392. package/src/utils/isNumber.ts +3 -0
  393. package/src/utils/noop.ts +3 -0
  394. package/src/utils/shallowEqual.ts +34 -0
  395. package/src/utils/throttle.ts +13 -0
  396. package/src/windowing/ScrollMetrics.ts +11 -0
  397. package/src/windowing/computeVisibleItemRange.ts +78 -0
  398. package/src/windowing/index.ts +3 -0
  399. package/src/windowing/useScrollMetrics.ts +56 -0
  400. package/android/src/main/java/com/nitrolist/HybridNitroList.kt +0 -27
  401. package/lib/module/specs/nitro-list.nitro.js +0 -4
  402. package/lib/typescript/src/specs/nitro-list.nitro.d.ts +0 -11
  403. package/lib/typescript/src/specs/nitro-list.nitro.d.ts.map +0 -1
  404. package/nitrogen/generated/android/c++/JHybridNitroListSpec.cpp +0 -56
  405. package/nitrogen/generated/android/c++/views/JHybridNitroListStateUpdater.cpp +0 -56
  406. package/nitrogen/generated/android/c++/views/JHybridNitroListStateUpdater.hpp +0 -49
  407. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrolist/views/HybridNitroListManager.kt +0 -50
  408. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrolist/views/HybridNitroListStateUpdater.kt +0 -23
  409. package/nitrogen/generated/ios/NitroListAutolinking.mm +0 -33
  410. package/nitrogen/generated/ios/NitroListAutolinking.swift +0 -25
  411. package/nitrogen/generated/ios/c++/HybridNitroListSpecSwift.hpp +0 -74
  412. package/nitrogen/generated/ios/c++/views/HybridNitroListComponent.mm +0 -96
  413. package/nitrogen/generated/ios/swift/HybridNitroListSpec.swift +0 -56
  414. package/nitrogen/generated/shared/c++/views/HybridNitroListComponent.cpp +0 -88
  415. package/nitrogen/generated/shared/c++/views/HybridNitroListComponent.hpp +0 -107
  416. package/nitrogen/generated/shared/json/NitroListConfig.json +0 -10
  417. package/src/specs/nitro-list.nitro.ts +0 -13
@@ -0,0 +1,37 @@
1
+ import { useRef, useCallback } from 'react'
2
+
3
+ /**
4
+ * Returns a function whose identity is stable across renders,
5
+ * but always invokes the latest provided implementation.
6
+ *
7
+ * Invariants:
8
+ * - Function reference NEVER changes
9
+ * - Logic is ALWAYS up to date
10
+ *
11
+ * This is critical for long-lived systems such as:
12
+ * - Recyclers
13
+ * - Effects
14
+ * - Native bridges
15
+ * - Event pipelines
16
+ */
17
+ export function usePersistentCallback<
18
+ T extends (...args: never[]) => unknown
19
+ >(fn: T): T {
20
+
21
+ /**
22
+ * Holds the latest implementation.
23
+ * Updating this does NOT trigger re-renders.
24
+ */
25
+ const fnRef = useRef(fn)
26
+ fnRef.current = fn
27
+
28
+ /**
29
+ * Stable wrapper that forwards calls
30
+ * to the latest implementation.
31
+ */
32
+ return useCallback(
33
+ ((...args: never[]) =>
34
+ fnRef.current(...args)) as T,
35
+ []
36
+ )
37
+ }
package/src/index.ts CHANGED
@@ -1,14 +1 @@
1
- import { getHostComponent, type HybridRef } from 'react-native-nitro-modules'
2
- import NitroListConfig from '../nitrogen/generated/shared/json/NitroListConfig.json'
3
- import type {
4
- NitroListProps,
5
- NitroListMethods,
6
- } from './specs/nitro-list.nitro'
7
-
8
-
9
- export const NitroList = getHostComponent<NitroListProps, NitroListMethods>(
10
- 'NitroList',
11
- () => NitroListConfig
12
- )
13
-
14
- export type NitroListRef = HybridRef<NitroListProps, NitroListMethods>
1
+ export { RecyclerList } from './recycler/RecyclerList'
@@ -0,0 +1,112 @@
1
+ import type { Axis } from '../types/Axis'
2
+ import type { LinearLayoutInput } from '../types/layout'
3
+ import type { LayoutRect } from '../types/layout/LayoutRect'
4
+
5
+ import { DEFAULT_ITEM_SPACING } from './constants/layoutDefaults'
6
+
7
+ /**
8
+ * Mutable, deterministic linear layout engine.
9
+ *
10
+ * Responsibilities:
11
+ * - Compute absolute item geometry
12
+ * - Own layout truth (no React, no scroll state)
13
+ * - Guarantee monotonic ordering along the main axis
14
+ *
15
+ * Cross-platform equivalents:
16
+ * - Flutter: RenderSliver / SliverList
17
+ * - Android: LinearLayoutManager
18
+ * - iOS: UICollectionViewFlowLayout (linear)
19
+ */
20
+ export class MutableLinearLayout {
21
+ private readonly isVertical: boolean
22
+
23
+ /** Absolute item layouts in index order */
24
+ private layouts: LayoutRect[] = []
25
+
26
+ /** Total scrollable size along main axis */
27
+ private contentSize = 0
28
+
29
+ constructor(axis: Axis) {
30
+ this.isVertical = axis === 'vertical'
31
+ }
32
+
33
+ /**
34
+ * Computes layout synchronously from input.
35
+ *
36
+ * This method is intentionally parameter-object based
37
+ * to allow future extension without breaking API.
38
+ *
39
+ * Invariants:
40
+ * - Layouts are monotonic along main axis
41
+ * - No gaps except explicit spacing
42
+ * - Deterministic for identical inputs
43
+ */
44
+ compute(input: LinearLayoutInput): void {
45
+ const {
46
+ crossAxisSize,
47
+ itemMainAxisSizes,
48
+ padding,
49
+ itemSpacing = DEFAULT_ITEM_SPACING,
50
+ } = input
51
+
52
+ const itemCount = itemMainAxisSizes.length
53
+ const layouts: LayoutRect[] = new Array(itemCount)
54
+
55
+ let cursor = padding.start
56
+
57
+ for (let i = 0; i < itemCount; i++) {
58
+ const mainAxisSize = itemMainAxisSizes[i]!
59
+
60
+ layouts[i] = this.isVertical
61
+ ? {
62
+ x: 0,
63
+ y: cursor,
64
+ width: crossAxisSize,
65
+ height: mainAxisSize,
66
+ }
67
+ : {
68
+ x: cursor,
69
+ y: 0,
70
+ width: mainAxisSize,
71
+ height: crossAxisSize,
72
+ }
73
+
74
+ cursor += mainAxisSize
75
+
76
+ // Space BETWEEN items, not after the last
77
+ if (i < itemCount - 1) {
78
+ cursor += itemSpacing
79
+ }
80
+ }
81
+
82
+ this.layouts = layouts
83
+ this.contentSize = cursor + padding.end
84
+ }
85
+
86
+ /**
87
+ * Returns computed item layouts.
88
+ *
89
+ * Order is guaranteed monotonic along the main axis,
90
+ * which is required for binary-search-based windowing.
91
+ */
92
+ getLayouts(): readonly LayoutRect[] {
93
+ return this.layouts
94
+ }
95
+
96
+ /**
97
+ * Returns total scrollable size along the main axis,
98
+ * including padding and inter-item spacing.
99
+ */
100
+ getContentSize(): number {
101
+ return this.contentSize
102
+ }
103
+
104
+ /**
105
+ * Clears internal layout state.
106
+ * Call on severe invalidation or teardown.
107
+ */
108
+ reset(): void {
109
+ this.layouts = []
110
+ this.contentSize = 0
111
+ }
112
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Default spacing between items along the main axis.
3
+ *
4
+ * This value is used by layout engines when no explicit
5
+ * itemSpacing is provided.
6
+ *
7
+ * Mirrors:
8
+ * - Android RecyclerView ItemDecoration (typical 8–16dp)
9
+ * - iOS UICollectionViewFlowLayout minimumLineSpacing
10
+ * - Flutter SliverList spacing conventions
11
+ */
12
+ export const DEFAULT_ITEM_SPACING = 12
@@ -0,0 +1 @@
1
+ export type { MutableLinearLayout } from './MutableLinearLayout'
@@ -0,0 +1,20 @@
1
+ import type { LayoutChangeEvent } from 'react-native'
2
+
3
+ export interface MeasuredLayout {
4
+ readonly width: number
5
+ readonly height: number
6
+ }
7
+
8
+ /**
9
+ * Extracts stable layout measurements from RN onLayout event.
10
+ */
11
+ export function measureLayout(
12
+ event: LayoutChangeEvent
13
+ ): MeasuredLayout {
14
+ const { width, height } = event.nativeEvent.layout
15
+
16
+ return {
17
+ width,
18
+ height,
19
+ }
20
+ }
@@ -0,0 +1,32 @@
1
+ import { useCallback, useRef } from 'react'
2
+ import type { LayoutChangeEvent } from 'react-native'
3
+
4
+ /**
5
+ * Hook to measure a rendered item safely.
6
+ *
7
+ * Guarantees:
8
+ * - No duplicate height reports
9
+ * - No render loops
10
+ * - Stable callback identity
11
+ */
12
+ export function useItemMeasurement(
13
+ index: number,
14
+ onMeasured: (index: number, height: number) => void
15
+ ) {
16
+ const lastHeightRef = useRef<number | null>(null)
17
+
18
+ const onLayout = useCallback(
19
+ (e: LayoutChangeEvent) => {
20
+ const height = e.nativeEvent.layout.height
21
+
22
+ // Ignore identical measurements
23
+ if (lastHeightRef.current === height) return
24
+
25
+ lastHeightRef.current = height
26
+ onMeasured(index, height)
27
+ },
28
+ [index, onMeasured]
29
+ )
30
+
31
+ return onLayout
32
+ }
@@ -0,0 +1,7 @@
1
+ import { NitroModules } from 'react-native-nitro-modules'
2
+ import type { NitroLayoutEngine as NitroLayoutEngineSpec } from '../specs/nitro-layout-engine.nitro'
3
+
4
+ export const NitroLayoutEngine =
5
+ NitroModules.createHybridObject<NitroLayoutEngineSpec>(
6
+ 'NitroLayoutEngine'
7
+ )
@@ -0,0 +1,13 @@
1
+ import type { LayoutRect } from "../types/layout";
2
+
3
+
4
+ /**
5
+ * JS runtime interface backed by Nitro (JSI).
6
+ * Must match native HybridNitroList exactly.
7
+ */
8
+ export interface NitroList {
9
+ computeLayout(
10
+ containerWidth: number,
11
+ itemHeights: readonly number[]
12
+ ): readonly LayoutRect[]
13
+ }
@@ -0,0 +1,8 @@
1
+ import { requireNativeComponent } from 'react-native'
2
+
3
+ export type NitroRecyclerViewProps = {
4
+ itemCount: number
5
+ }
6
+
7
+ export const NitroRecyclerView =
8
+ requireNativeComponent<NitroRecyclerViewProps>('NitroRecyclerView')
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Callback invoked when new items should be prefetched.
3
+ */
4
+ export type PrefetchCallback = (indices: number[]) => void
5
+
6
+ /**
7
+ * PrefetchHelper
8
+ *
9
+ * Stateless with respect to layout.
10
+ * Only tracks what has already been prefetched to avoid duplication.
11
+ *
12
+ * Designed to be driven by *visible window*, not scroll events.
13
+ */
14
+ export class PrefetchHelper {
15
+ private lastPrefetched = new Set<number>()
16
+
17
+ runPrefetch(
18
+ visibleIndices: readonly number[],
19
+ itemCount: number,
20
+ aheadCount: number,
21
+ onPrefetch: PrefetchCallback
22
+ ) {
23
+ if (visibleIndices.length === 0) return
24
+
25
+ const lastVisible =
26
+ visibleIndices[visibleIndices.length - 1]!
27
+
28
+ const start = lastVisible + 1
29
+ const end = Math.min(
30
+ itemCount - 1,
31
+ start + aheadCount
32
+ )
33
+
34
+ const toPrefetch: number[] = []
35
+
36
+ for (let i = start; i <= end; i++) {
37
+ if (!this.lastPrefetched.has(i)) {
38
+ this.lastPrefetched.add(i)
39
+ toPrefetch.push(i)
40
+ }
41
+ }
42
+
43
+ if (toPrefetch.length > 0) {
44
+ onPrefetch(toPrefetch)
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,47 @@
1
+ import type { CellType } from '../types/CellType'
2
+ import type { RecyclerCellInstance } from '../types/recycler'
3
+
4
+ export class CellPool {
5
+ private readonly pools = new Map<CellType, RecyclerCellInstance[]>()
6
+ private readonly maxPerType = new Map<CellType, number>()
7
+
8
+ /** ✅ NEW: check if a type is registered */
9
+ hasType(type: CellType): boolean {
10
+ return this.pools.has(type)
11
+ }
12
+
13
+ registerType(type: CellType, maxCount: number): void {
14
+ if (this.maxPerType.has(type)) return
15
+ this.maxPerType.set(type, maxCount)
16
+ this.pools.set(type, [])
17
+ }
18
+
19
+ acquire(type: CellType): RecyclerCellInstance | null {
20
+ const bucket = this.pools.get(type)
21
+ if (!bucket || bucket.length === 0) return null
22
+ return bucket.pop()!
23
+ }
24
+
25
+ release(cell: RecyclerCellInstance): void {
26
+ const { type } = cell
27
+ const bucket = this.pools.get(type)
28
+ const max = this.maxPerType.get(type)
29
+
30
+ if (!bucket || max === undefined) return
31
+
32
+ cell.index = -1
33
+
34
+ if (bucket.length >= max) return
35
+ bucket.push(cell)
36
+ }
37
+
38
+ clear(): void {
39
+ for (const bucket of this.pools.values()) {
40
+ bucket.length = 0
41
+ }
42
+ }
43
+
44
+ getPoolSize(type: CellType): number {
45
+ return this.pools.get(type)?.length ?? 0
46
+ }
47
+ }
@@ -0,0 +1,304 @@
1
+ import React, { useRef, useEffect, useState } from 'react'
2
+ import {
3
+ ScrollView,
4
+ View,
5
+ StyleSheet,
6
+ type NativeSyntheticEvent,
7
+ type NativeScrollEvent,
8
+ } from 'react-native'
9
+
10
+ import type { LayoutRect, VisibleRange } from '../types'
11
+ import type {
12
+ RecyclerCellInstance,
13
+ RecyclerListProps,
14
+ } from '../types/recycler'
15
+ import type { CellType } from '../types/CellType'
16
+
17
+ import { MutableLinearLayout } from '../layout/MutableLinearLayout'
18
+ import { computeVisibleItemRange } from '../windowing'
19
+ import { CellPool } from './CellPool'
20
+
21
+ /* =========================================================
22
+ * Constants
23
+ * =======================================================*/
24
+
25
+ const DEFAULT_VIEWPORT_SIZE = 800
26
+ const DEFAULT_ITEM_SIZE = 60
27
+ const SCROLL_EVENT_THROTTLE = 16
28
+
29
+ /* =========================================================
30
+ * RecyclerList
31
+ * =======================================================*/
32
+
33
+ export function RecyclerList<T>(
34
+ props: RecyclerListProps<T>
35
+ ): React.ReactElement {
36
+ const {
37
+ scrollDirection = 'vertical',
38
+ containerCrossAxisSize,
39
+ data,
40
+ itemMainAxisSizes,
41
+ padding = { start: 0, end: 0 },
42
+ itemSpacing,
43
+ bufferRatio = 1.3,
44
+ getCellType,
45
+ renderItem,
46
+ } = props
47
+
48
+ const isVertical = scrollDirection === 'vertical'
49
+ const itemCount = data.length
50
+
51
+ /* -------------------------------------------------------
52
+ * Controlled render
53
+ * -----------------------------------------------------*/
54
+
55
+ const [, forceRender] = useState(0)
56
+
57
+ /* -------------------------------------------------------
58
+ * Layout engine
59
+ * -----------------------------------------------------*/
60
+
61
+ const layoutEngineRef = useRef<MutableLinearLayout | null>(null)
62
+ const layoutSignatureRef = useRef('')
63
+
64
+ const layoutSignature = [
65
+ scrollDirection,
66
+ containerCrossAxisSize,
67
+ itemCount,
68
+ itemMainAxisSizes,
69
+ padding.start,
70
+ padding.end,
71
+ itemSpacing ?? 'default',
72
+ ].join('|')
73
+
74
+ if (
75
+ !layoutEngineRef.current ||
76
+ layoutSignatureRef.current !== layoutSignature
77
+ ) {
78
+ const engine = new MutableLinearLayout(scrollDirection)
79
+ engine.compute({
80
+ crossAxisSize: containerCrossAxisSize,
81
+ itemMainAxisSizes,
82
+ padding,
83
+ itemSpacing,
84
+ })
85
+ layoutEngineRef.current = engine
86
+ layoutSignatureRef.current = layoutSignature
87
+ }
88
+
89
+ const layouts: readonly LayoutRect[] =
90
+ layoutEngineRef.current.getLayouts()
91
+
92
+ const contentSize =
93
+ layoutEngineRef.current.getContentSize()
94
+
95
+ /* -------------------------------------------------------
96
+ * Scroll metrics
97
+ * -----------------------------------------------------*/
98
+
99
+ const scrollOffsetRef = useRef(0)
100
+ const viewportSizeRef = useRef(DEFAULT_VIEWPORT_SIZE)
101
+
102
+ /* -------------------------------------------------------
103
+ * Cell pool + physical cells
104
+ * -----------------------------------------------------*/
105
+
106
+ const cellPoolRef = useRef(new CellPool())
107
+ const activeCellsRef = useRef<RecyclerCellInstance[]>([])
108
+ const nextCellKeyRef = useRef(0)
109
+
110
+ const createCell = (type: CellType): RecyclerCellInstance => ({
111
+ key: nextCellKeyRef.current++,
112
+ index: -1,
113
+ type,
114
+ })
115
+
116
+ const MAX_CELLS = Math.ceil(
117
+ (viewportSizeRef.current / DEFAULT_ITEM_SIZE) *
118
+ bufferRatio
119
+ ) + 2
120
+
121
+ /* -------------------------------------------------------
122
+ * Visible cell coordinator
123
+ * -----------------------------------------------------*/
124
+
125
+ const updateVisibleCells = (): void => {
126
+ const offset = scrollOffsetRef.current
127
+ const viewportSize = viewportSizeRef.current
128
+ const buffer = viewportSize * bufferRatio
129
+
130
+ const range: VisibleRange | null =
131
+ computeVisibleItemRange({
132
+ layouts,
133
+ offset,
134
+ viewportSize,
135
+ buffer,
136
+ isVertical,
137
+ })
138
+
139
+ if (!range) return
140
+
141
+ const nextCells: RecyclerCellInstance[] = []
142
+ const used = new Set<RecyclerCellInstance>()
143
+
144
+ for (
145
+ let index = range.startIndex;
146
+ index <= range.endIndex;
147
+ index++
148
+ ) {
149
+ const item = data[index]
150
+ if (item === undefined) continue
151
+
152
+ const type = getCellType(item, index)
153
+
154
+ // Register type once, with hard cap
155
+ if (!cellPoolRef.current.hasType(type)) {
156
+ cellPoolRef.current.registerType(type, MAX_CELLS)
157
+ for (let i = 0; i < MAX_CELLS; i++) {
158
+ cellPoolRef.current.release(createCell(type))
159
+ }
160
+ }
161
+
162
+ let cell = cellPoolRef.current.acquire(type)
163
+
164
+ if (!cell) {
165
+ const reuseIndex =
166
+ activeCellsRef.current.findIndex(
167
+ c => c.type === type
168
+ )
169
+
170
+ if (reuseIndex === -1) continue
171
+
172
+ cell =
173
+ activeCellsRef.current.splice(
174
+ reuseIndex,
175
+ 1
176
+ )[0]!
177
+ }
178
+
179
+ cell.index = index
180
+ nextCells.push(cell)
181
+ used.add(cell)
182
+ }
183
+
184
+ for (const cell of activeCellsRef.current) {
185
+ if (!used.has(cell)) {
186
+ cellPoolRef.current.release(cell)
187
+ }
188
+ }
189
+
190
+ let changed =
191
+ nextCells.length !== activeCellsRef.current.length
192
+
193
+ if (!changed) {
194
+ for (let i = 0; i < nextCells.length; i++) {
195
+ if (nextCells[i] !== activeCellsRef.current[i]) {
196
+ changed = true
197
+ break
198
+ }
199
+ }
200
+ }
201
+
202
+ if (changed) {
203
+ activeCellsRef.current = nextCells
204
+ forceRender(v => v + 1)
205
+ }
206
+ }
207
+
208
+ /* -------------------------------------------------------
209
+ * Scroll handlers
210
+ * -----------------------------------------------------*/
211
+
212
+ const frameScheduledRef = useRef(false)
213
+
214
+ const onScroll = (
215
+ e: NativeSyntheticEvent<NativeScrollEvent>
216
+ ): void => {
217
+ scrollOffsetRef.current = isVertical
218
+ ? e.nativeEvent.contentOffset.y
219
+ : e.nativeEvent.contentOffset.x
220
+
221
+ if (frameScheduledRef.current) return
222
+ frameScheduledRef.current = true
223
+
224
+ requestAnimationFrame(() => {
225
+ frameScheduledRef.current = false
226
+ updateVisibleCells()
227
+ })
228
+ }
229
+
230
+ const onLayout = (e: any): void => {
231
+ viewportSizeRef.current = isVertical
232
+ ? e.nativeEvent.layout.height
233
+ : e.nativeEvent.layout.width
234
+
235
+ updateVisibleCells()
236
+ }
237
+
238
+ useEffect(() => {
239
+ updateVisibleCells()
240
+ // eslint-disable-next-line react-hooks/exhaustive-deps
241
+ }, [])
242
+
243
+ /* -------------------------------------------------------
244
+ * Render
245
+ * -----------------------------------------------------*/
246
+
247
+ return (
248
+ <ScrollView
249
+ onScroll={onScroll}
250
+ onLayout={onLayout}
251
+ horizontal={!isVertical}
252
+ scrollEventThrottle={SCROLL_EVENT_THROTTLE}
253
+ removeClippedSubviews
254
+ >
255
+ <View
256
+ style={
257
+ isVertical
258
+ ? { height: contentSize }
259
+ : { width: contentSize }
260
+ }
261
+ >
262
+ {activeCellsRef.current.map(cell => {
263
+ const index = cell.index
264
+ const layout = layouts[index]
265
+ const item = data[index]
266
+
267
+ if (!layout || item === undefined) return null
268
+
269
+ return (
270
+ <View
271
+ key={cell.key}
272
+ style={[
273
+ styles.cell,
274
+ isVertical
275
+ ? {
276
+ top: layout.y,
277
+ height: layout.height,
278
+ width: layout.width,
279
+ }
280
+ : {
281
+ left: layout.x,
282
+ width: layout.width,
283
+ height: layout.height,
284
+ },
285
+ ]}
286
+ >
287
+ {renderItem({ item, index, cell })}
288
+ </View>
289
+ )
290
+ })}
291
+ </View>
292
+ </ScrollView>
293
+ )
294
+ }
295
+
296
+ /* =========================================================
297
+ * Styles
298
+ * =======================================================*/
299
+
300
+ const styles = StyleSheet.create({
301
+ cell: {
302
+ position: 'absolute',
303
+ },
304
+ })
@@ -0,0 +1,17 @@
1
+ import type { HybridObject } from 'react-native-nitro-modules'
2
+
3
+ export interface LayoutRect {
4
+ readonly x: number
5
+ readonly y: number
6
+ readonly width: number
7
+ readonly height: number
8
+ }
9
+
10
+ export interface NitroLayoutEngine
11
+ extends HybridObject<{ ios: 'swift'; android: 'kotlin' }> {
12
+
13
+ computeLayout(
14
+ containerWidth: number,
15
+ itemHeights: readonly number[]
16
+ ): readonly LayoutRect[]
17
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Axis along which scrolling and layout occur.
3
+ *
4
+ * Matches Flutter's Axis:
5
+ * - vertical → Y axis
6
+ * - horizontal → X axis
7
+ *
8
+ * This is NOT gesture direction.
9
+ */
10
+ export type Axis = 'vertical' | 'horizontal'