@shopify/flash-list 2.0.0-alpha.8 → 2.0.0-rc.1

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 (197) hide show
  1. package/README.md +38 -98
  2. package/dist/AnimatedFlashList.d.ts.map +1 -1
  3. package/dist/AnimatedFlashList.js +3 -3
  4. package/dist/AnimatedFlashList.js.map +1 -1
  5. package/dist/FlashList.d.ts +9 -0
  6. package/dist/FlashList.d.ts.map +1 -1
  7. package/dist/FlashList.js +20 -0
  8. package/dist/FlashList.js.map +1 -1
  9. package/dist/FlashListProps.d.ts +15 -8
  10. package/dist/FlashListProps.d.ts.map +1 -1
  11. package/dist/FlashListProps.js.map +1 -1
  12. package/dist/FlashListRef.d.ts +305 -0
  13. package/dist/FlashListRef.d.ts.map +1 -0
  14. package/dist/FlashListRef.js +3 -0
  15. package/dist/FlashListRef.js.map +1 -0
  16. package/dist/MasonryFlashList.js.map +1 -1
  17. package/dist/__tests__/RecyclerView.test.js +63 -28
  18. package/dist/__tests__/RecyclerView.test.js.map +1 -1
  19. package/dist/__tests__/RenderStackManager.test.d.ts +2 -0
  20. package/dist/__tests__/RenderStackManager.test.d.ts.map +1 -0
  21. package/dist/__tests__/RenderStackManager.test.js +486 -0
  22. package/dist/__tests__/RenderStackManager.test.js.map +1 -0
  23. package/dist/__tests__/helpers/createLayoutManager.d.ts.map +1 -1
  24. package/dist/__tests__/helpers/createLayoutManager.js +3 -4
  25. package/dist/__tests__/helpers/createLayoutManager.js.map +1 -1
  26. package/dist/__tests__/useUnmountAwareCallbacks.test.js +1 -1
  27. package/dist/__tests__/useUnmountAwareCallbacks.test.js.map +1 -1
  28. package/dist/benchmark/useFlatListBenchmark.js +8 -7
  29. package/dist/benchmark/useFlatListBenchmark.js.map +1 -1
  30. package/dist/enableNewCore.d.ts.map +1 -1
  31. package/dist/enableNewCore.js +2 -1
  32. package/dist/enableNewCore.js.map +1 -1
  33. package/dist/index.d.ts +1 -0
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js.map +1 -1
  36. package/dist/native/config/PlatformHelper.android.d.ts +2 -0
  37. package/dist/native/config/PlatformHelper.android.d.ts.map +1 -1
  38. package/dist/native/config/PlatformHelper.android.js +2 -0
  39. package/dist/native/config/PlatformHelper.android.js.map +1 -1
  40. package/dist/native/config/PlatformHelper.d.ts +2 -0
  41. package/dist/native/config/PlatformHelper.d.ts.map +1 -1
  42. package/dist/native/config/PlatformHelper.ios.d.ts +2 -0
  43. package/dist/native/config/PlatformHelper.ios.d.ts.map +1 -1
  44. package/dist/native/config/PlatformHelper.ios.js +2 -0
  45. package/dist/native/config/PlatformHelper.ios.js.map +1 -1
  46. package/dist/native/config/PlatformHelper.js +2 -0
  47. package/dist/native/config/PlatformHelper.js.map +1 -1
  48. package/dist/native/config/PlatformHelper.web.d.ts +2 -0
  49. package/dist/native/config/PlatformHelper.web.d.ts.map +1 -1
  50. package/dist/native/config/PlatformHelper.web.js +3 -1
  51. package/dist/native/config/PlatformHelper.web.js.map +1 -1
  52. package/dist/recyclerview/RecyclerView.d.ts +2 -1
  53. package/dist/recyclerview/RecyclerView.d.ts.map +1 -1
  54. package/dist/recyclerview/RecyclerView.js +64 -37
  55. package/dist/recyclerview/RecyclerView.js.map +1 -1
  56. package/dist/recyclerview/RecyclerViewContextProvider.d.ts +6 -5
  57. package/dist/recyclerview/RecyclerViewContextProvider.d.ts.map +1 -1
  58. package/dist/recyclerview/RecyclerViewContextProvider.js.map +1 -1
  59. package/dist/recyclerview/RecyclerViewManager.d.ts +21 -7
  60. package/dist/recyclerview/RecyclerViewManager.d.ts.map +1 -1
  61. package/dist/recyclerview/RecyclerViewManager.js +105 -113
  62. package/dist/recyclerview/RecyclerViewManager.js.map +1 -1
  63. package/dist/recyclerview/RenderStackManager.d.ts +85 -0
  64. package/dist/recyclerview/RenderStackManager.d.ts.map +1 -0
  65. package/dist/recyclerview/RenderStackManager.js +324 -0
  66. package/dist/recyclerview/RenderStackManager.js.map +1 -0
  67. package/dist/recyclerview/ViewHolder.d.ts.map +1 -1
  68. package/dist/recyclerview/ViewHolder.js +5 -3
  69. package/dist/recyclerview/ViewHolder.js.map +1 -1
  70. package/dist/recyclerview/ViewHolderCollection.d.ts +3 -1
  71. package/dist/recyclerview/ViewHolderCollection.d.ts.map +1 -1
  72. package/dist/recyclerview/ViewHolderCollection.js +23 -8
  73. package/dist/recyclerview/ViewHolderCollection.js.map +1 -1
  74. package/dist/recyclerview/components/ScrollAnchor.d.ts +2 -1
  75. package/dist/recyclerview/components/ScrollAnchor.d.ts.map +1 -1
  76. package/dist/recyclerview/components/ScrollAnchor.js +9 -4
  77. package/dist/recyclerview/components/ScrollAnchor.js.map +1 -1
  78. package/dist/recyclerview/components/StickyHeaders.d.ts +1 -1
  79. package/dist/recyclerview/components/StickyHeaders.d.ts.map +1 -1
  80. package/dist/recyclerview/components/StickyHeaders.js +40 -32
  81. package/dist/recyclerview/components/StickyHeaders.js.map +1 -1
  82. package/dist/recyclerview/helpers/EngagedIndicesTracker.d.ts +45 -1
  83. package/dist/recyclerview/helpers/EngagedIndicesTracker.d.ts.map +1 -1
  84. package/dist/recyclerview/helpers/EngagedIndicesTracker.js +79 -20
  85. package/dist/recyclerview/helpers/EngagedIndicesTracker.js.map +1 -1
  86. package/dist/recyclerview/helpers/RenderTimeTracker.d.ts +10 -0
  87. package/dist/recyclerview/helpers/RenderTimeTracker.d.ts.map +1 -0
  88. package/dist/recyclerview/helpers/RenderTimeTracker.js +39 -0
  89. package/dist/recyclerview/helpers/RenderTimeTracker.js.map +1 -0
  90. package/dist/recyclerview/helpers/VelocityTracker.d.ts +29 -0
  91. package/dist/recyclerview/helpers/VelocityTracker.d.ts.map +1 -0
  92. package/dist/recyclerview/helpers/VelocityTracker.js +70 -0
  93. package/dist/recyclerview/helpers/VelocityTracker.js.map +1 -0
  94. package/dist/recyclerview/hooks/useBoundDetection.d.ts +1 -2
  95. package/dist/recyclerview/hooks/useBoundDetection.d.ts.map +1 -1
  96. package/dist/recyclerview/hooks/useBoundDetection.js +19 -16
  97. package/dist/recyclerview/hooks/useBoundDetection.js.map +1 -1
  98. package/dist/recyclerview/hooks/useMappingHelper.d.ts +1 -1
  99. package/dist/recyclerview/hooks/useMappingHelper.d.ts.map +1 -1
  100. package/dist/recyclerview/hooks/useMappingHelper.js +1 -1
  101. package/dist/recyclerview/hooks/useMappingHelper.js.map +1 -1
  102. package/dist/recyclerview/hooks/useOnLoad.d.ts.map +1 -1
  103. package/dist/recyclerview/hooks/useOnLoad.js +4 -6
  104. package/dist/recyclerview/hooks/useOnLoad.js.map +1 -1
  105. package/dist/recyclerview/hooks/useRecyclerViewController.d.ts +3 -48
  106. package/dist/recyclerview/hooks/useRecyclerViewController.d.ts.map +1 -1
  107. package/dist/recyclerview/hooks/useRecyclerViewController.js +179 -119
  108. package/dist/recyclerview/hooks/useRecyclerViewController.js.map +1 -1
  109. package/dist/recyclerview/hooks/useRecyclerViewManager.d.ts +2 -0
  110. package/dist/recyclerview/hooks/useRecyclerViewManager.d.ts.map +1 -1
  111. package/dist/recyclerview/hooks/useRecyclerViewManager.js +10 -1
  112. package/dist/recyclerview/hooks/useRecyclerViewManager.js.map +1 -1
  113. package/dist/recyclerview/hooks/useSecondaryProps.js +1 -1
  114. package/dist/recyclerview/hooks/useUnmountAwareCallbacks.d.ts +10 -3
  115. package/dist/recyclerview/hooks/useUnmountAwareCallbacks.d.ts.map +1 -1
  116. package/dist/recyclerview/hooks/useUnmountAwareCallbacks.js +33 -4
  117. package/dist/recyclerview/hooks/useUnmountAwareCallbacks.js.map +1 -1
  118. package/dist/recyclerview/layout-managers/GridLayoutManager.d.ts +6 -0
  119. package/dist/recyclerview/layout-managers/GridLayoutManager.d.ts.map +1 -1
  120. package/dist/recyclerview/layout-managers/GridLayoutManager.js +27 -5
  121. package/dist/recyclerview/layout-managers/GridLayoutManager.js.map +1 -1
  122. package/dist/recyclerview/layout-managers/LayoutManager.d.ts +10 -16
  123. package/dist/recyclerview/layout-managers/LayoutManager.d.ts.map +1 -1
  124. package/dist/recyclerview/layout-managers/LayoutManager.js +4 -14
  125. package/dist/recyclerview/layout-managers/LayoutManager.js.map +1 -1
  126. package/dist/recyclerview/layout-managers/MasonryLayoutManager.js +2 -2
  127. package/dist/recyclerview/layout-managers/MasonryLayoutManager.js.map +1 -1
  128. package/dist/recyclerview/utils/measureLayout.d.ts +1 -29
  129. package/dist/recyclerview/utils/measureLayout.d.ts.map +1 -1
  130. package/dist/recyclerview/utils/measureLayout.js +2 -4
  131. package/dist/recyclerview/utils/measureLayout.js.map +1 -1
  132. package/dist/recyclerview/utils/measureLayout.web.d.ts +29 -0
  133. package/dist/recyclerview/utils/measureLayout.web.d.ts.map +1 -0
  134. package/dist/recyclerview/utils/measureLayout.web.js +89 -0
  135. package/dist/recyclerview/utils/measureLayout.web.js.map +1 -0
  136. package/dist/tsconfig.tsbuildinfo +1 -1
  137. package/dist/viewability/ViewToken.d.ts +2 -2
  138. package/dist/viewability/ViewToken.d.ts.map +1 -1
  139. package/dist/viewability/ViewabilityHelper.js +1 -1
  140. package/dist/viewability/ViewabilityHelper.js.map +1 -1
  141. package/dist/viewability/ViewabilityManager.d.ts.map +1 -1
  142. package/dist/viewability/ViewabilityManager.js +1 -2
  143. package/dist/viewability/ViewabilityManager.js.map +1 -1
  144. package/jestSetup.js +30 -11
  145. package/package.json +2 -1
  146. package/src/AnimatedFlashList.ts +3 -2
  147. package/src/FlashList.tsx +24 -0
  148. package/src/FlashListProps.ts +20 -8
  149. package/src/FlashListRef.ts +320 -0
  150. package/src/MasonryFlashList.tsx +2 -2
  151. package/src/__tests__/RecyclerView.test.tsx +84 -30
  152. package/src/__tests__/RenderStackManager.test.ts +575 -0
  153. package/src/__tests__/helpers/createLayoutManager.ts +2 -3
  154. package/src/__tests__/useUnmountAwareCallbacks.test.tsx +12 -12
  155. package/src/benchmark/useFlatListBenchmark.ts +2 -2
  156. package/src/enableNewCore.ts +3 -1
  157. package/src/index.ts +1 -0
  158. package/src/native/config/PlatformHelper.android.ts +2 -0
  159. package/src/native/config/PlatformHelper.ios.ts +2 -0
  160. package/src/native/config/PlatformHelper.ts +2 -0
  161. package/src/native/config/PlatformHelper.web.ts +3 -1
  162. package/src/recyclerview/RecyclerView.tsx +85 -43
  163. package/src/recyclerview/RecyclerViewContextProvider.ts +12 -6
  164. package/src/recyclerview/RecyclerViewManager.ts +123 -98
  165. package/src/recyclerview/RenderStackManager.ts +291 -0
  166. package/src/recyclerview/ViewHolder.tsx +5 -3
  167. package/src/recyclerview/ViewHolderCollection.tsx +33 -12
  168. package/src/recyclerview/components/ScrollAnchor.tsx +21 -8
  169. package/src/recyclerview/components/StickyHeaders.tsx +63 -44
  170. package/src/recyclerview/helpers/EngagedIndicesTracker.ts +120 -23
  171. package/src/recyclerview/helpers/RenderTimeTracker.ts +38 -0
  172. package/src/recyclerview/helpers/VelocityTracker.ts +77 -0
  173. package/src/recyclerview/hooks/useBoundDetection.ts +25 -18
  174. package/src/recyclerview/hooks/useMappingHelper.ts +1 -1
  175. package/src/recyclerview/hooks/useOnLoad.ts +4 -6
  176. package/src/recyclerview/hooks/useRecyclerViewController.tsx +204 -173
  177. package/src/recyclerview/hooks/useRecyclerViewManager.ts +11 -1
  178. package/src/recyclerview/hooks/useSecondaryProps.tsx +1 -1
  179. package/src/recyclerview/hooks/useUnmountAwareCallbacks.ts +39 -3
  180. package/src/recyclerview/layout-managers/GridLayoutManager.ts +30 -7
  181. package/src/recyclerview/layout-managers/LayoutManager.ts +12 -21
  182. package/src/recyclerview/layout-managers/MasonryLayoutManager.ts +1 -1
  183. package/src/recyclerview/utils/measureLayout.ts +3 -3
  184. package/src/recyclerview/utils/measureLayout.web.ts +104 -0
  185. package/src/viewability/ViewToken.ts +2 -2
  186. package/src/viewability/ViewabilityHelper.ts +1 -1
  187. package/src/viewability/ViewabilityManager.ts +6 -3
  188. package/dist/__tests__/RecycleKeyManager.test.d.ts +0 -2
  189. package/dist/__tests__/RecycleKeyManager.test.d.ts.map +0 -1
  190. package/dist/__tests__/RecycleKeyManager.test.js +0 -210
  191. package/dist/__tests__/RecycleKeyManager.test.js.map +0 -1
  192. package/dist/recyclerview/RecycleKeyManager.d.ts +0 -82
  193. package/dist/recyclerview/RecycleKeyManager.d.ts.map +0 -1
  194. package/dist/recyclerview/RecycleKeyManager.js +0 -135
  195. package/dist/recyclerview/RecycleKeyManager.js.map +0 -1
  196. package/src/__tests__/RecycleKeyManager.test.ts +0 -254
  197. package/src/recyclerview/RecycleKeyManager.ts +0 -185
@@ -1,11 +1,12 @@
1
1
  import { Animated } from "react-native";
2
2
 
3
- import FlashList from "./FlashList";
4
3
  import { FlashListProps } from "./FlashListProps";
4
+ import { RecyclerView } from "./recyclerview/RecyclerView";
5
5
 
6
+ // Typecast as required
6
7
  const AnimatedFlashList =
7
8
  Animated.createAnimatedComponent<React.ComponentType<FlashListProps<any>>>(
8
- FlashList
9
+ RecyclerView
9
10
  );
10
11
 
11
12
  export default AnimatedFlashList;
package/src/FlashList.tsx CHANGED
@@ -42,6 +42,7 @@ import {
42
42
  hasUnsupportedKeysInContentContainerStyle,
43
43
  updateContentStyle,
44
44
  } from "./utils/ContentContainerUtils";
45
+ import { ScrollToEdgeParams } from "./FlashListRef";
45
46
 
46
47
  interface StickyProps extends StickyContainerProps {
47
48
  children: any;
@@ -924,6 +925,29 @@ class FlashList<T> extends React.PureComponent<
924
925
  public getFirstVisibleIndex() {
925
926
  return this.rlvRef?.findApproxFirstVisibleIndex() ?? -1;
926
927
  }
928
+
929
+ flashScrollIndicators() {
930
+ this.getNativeScrollRef()?.flashScrollIndicators();
931
+ }
932
+
933
+ getNativeScrollRef() {
934
+ return (this.rlvRef as any)?._scrollComponent?._scrollViewRef;
935
+ }
936
+
937
+ getScrollResponder() {
938
+ return this.getNativeScrollRef()?.getScrollResponder();
939
+ }
940
+
941
+ scrollToTop(params?: ScrollToEdgeParams) {
942
+ this.rlvRef?.scrollToTop(params?.animated);
943
+ }
944
+
945
+ computeVisibleIndices() {
946
+ console.warn(
947
+ "computeVisibleIndices is not implemented in old architecture"
948
+ );
949
+ return { startIndex: -1, endIndex: -2 };
950
+ }
927
951
  }
928
952
 
929
953
  export default FlashList;
@@ -23,6 +23,12 @@ export interface ListRenderItemInfo<TItem> {
23
23
  extraData?: any;
24
24
  }
25
25
 
26
+ export interface OverrideProps {
27
+ initialDrawBatchSize?: number;
28
+ // rest can be string to any
29
+ [key: string]: any;
30
+ }
31
+
26
32
  export type RenderTarget = "Cell" | "StickyHeader" | "Measurement";
27
33
 
28
34
  export const RenderTargetOptions: Record<string, RenderTarget> = {
@@ -248,7 +254,10 @@ export interface FlashListProps<TItem>
248
254
  * they might be deferred until JS thread is less busy.
249
255
  */
250
256
  onViewableItemsChanged?:
251
- | ((info: { viewableItems: ViewToken[]; changed: ViewToken[] }) => void)
257
+ | ((info: {
258
+ viewableItems: ViewToken<TItem>[];
259
+ changed: ViewToken<TItem>[];
260
+ }) => void)
252
261
  | null
253
262
  | undefined;
254
263
 
@@ -293,7 +302,7 @@ export interface FlashListProps<TItem>
293
302
  /**
294
303
  * For debugging and exception use cases, internal props will be overriden with these values if used
295
304
  */
296
- overrideProps?: object;
305
+ overrideProps?: OverrideProps;
297
306
 
298
307
  /**
299
308
  * Set this when offset is needed for the loading indicator to show correctly.
@@ -334,6 +343,15 @@ export interface FlashListProps<TItem>
334
343
  */
335
344
  disableAutoLayout?: boolean;
336
345
 
346
+ /**
347
+ * New arch only
348
+ * Maximum number of items in the recycle pool. These are the items that are cached in the recycle pool when they are scrolled off the screen.
349
+ * Unless you have a huge number of item types, you shouldn't need to set this.
350
+ * Setting this to 0, will disable the recycle pool and items will unmount once they are scrolled off the screen.
351
+ * There's no limit by default.
352
+ */
353
+ maxItemsInRecyclePool?: number;
354
+
337
355
  /**
338
356
  * New arch only
339
357
  * Enable masonry layout.
@@ -360,12 +378,6 @@ export interface FlashListProps<TItem>
360
378
  */
361
379
  onStartReachedThreshold?: FlashListProps<TItem>["onEndReachedThreshold"];
362
380
 
363
- /**
364
- * New arch only
365
- * If true, the RecyclerView will not recycle items.
366
- */
367
- disableRecycling?: boolean;
368
-
369
381
  /**
370
382
  * New arch only
371
383
  * Style for the RecyclerView's parent container.
@@ -0,0 +1,320 @@
1
+ import type { RVLayout } from "./recyclerview/layout-managers/LayoutManager";
2
+ import { RecyclerViewProps } from "./recyclerview/RecyclerViewProps";
3
+ import { CompatScroller } from "./recyclerview/components/CompatScroller";
4
+
5
+ /**
6
+ * Base parameters for scrolling to the edges of the list.
7
+ */
8
+ export interface ScrollToEdgeParams {
9
+ /** Whether the scroll should be animated */
10
+ animated?: boolean;
11
+ }
12
+
13
+ /**
14
+ * Parameters for scrolling to a specific position in the list.
15
+ * Extends ScrollToEdgeParams to include view positioning options.
16
+ */
17
+ export interface ScrollToParams extends ScrollToEdgeParams {
18
+ /** Position of the target item relative to the viewport (0 = top, 0.5 = center, 1 = bottom) */
19
+ viewPosition?: number;
20
+ /** Additional offset to apply after viewPosition calculation */
21
+ viewOffset?: number;
22
+ }
23
+
24
+ /**
25
+ * Parameters for scrolling to a specific offset in the list.
26
+ * Used when you want to scroll to an exact pixel position.
27
+ */
28
+ export interface ScrollToOffsetParams extends ScrollToParams {
29
+ /** The pixel offset to scroll to */
30
+ offset: number;
31
+ /**
32
+ * If true, the first item offset will not be added to the offset calculation.
33
+ * First offset represents header size or top padding.
34
+ */
35
+ skipFirstItemOffset?: boolean;
36
+ }
37
+
38
+ /**
39
+ * Parameters for scrolling to a specific index in the list.
40
+ * Used when you want to scroll to a specific item by its position in the data array.
41
+ */
42
+ export interface ScrollToIndexParams extends ScrollToParams {
43
+ /** The index of the item to scroll to */
44
+ index: number;
45
+ }
46
+
47
+ /**
48
+ * Parameters for scrolling to a specific item in the list.
49
+ * Used when you want to scroll to a specific item by its data value.
50
+ */
51
+ export interface ScrollToItemParams<T> extends ScrollToParams {
52
+ /** The item to scroll to */
53
+ item: T;
54
+ }
55
+
56
+ /**
57
+ * Interface for FlashList's ref object that provides imperative methods
58
+ * for controlling list behavior.
59
+ *
60
+ * Usage example:
61
+ * ```tsx
62
+ * const listRef = useRef<FlashListRef<ItemType>>(null);
63
+ *
64
+ * // Later in your component
65
+ * <FlashList
66
+ * ref={listRef}
67
+ * data={data}
68
+ * renderItem={renderItem}
69
+ * />
70
+ *
71
+ * // Somewhere else in your component
72
+ * listRef.current?.scrollToIndex({ index: 5, animated: true });
73
+ * ```
74
+ */
75
+ export interface FlashListRef<T> {
76
+ /**
77
+ * Get access to current props
78
+ */
79
+ props: RecyclerViewProps<T>;
80
+ /**
81
+ * Scrolls the list to a specific offset position.
82
+ *
83
+ * Use this method when you want precise control over the scroll position in pixels
84
+ * rather than by item index.
85
+ *
86
+ * @param params - Parameters for scrolling to offset
87
+ * @param params.offset - The pixel offset to scroll to
88
+ * @param params.animated - Whether the scroll should be animated (default: false)
89
+ * @param params.skipFirstItemOffset - If true, the first item offset (headers/padding)
90
+ * will not be included in calculation (default: true)
91
+ *
92
+ * @example
93
+ * // Scroll to 200px from the top/left
94
+ * listRef.current?.scrollToOffset({ offset: 200, animated: true });
95
+ */
96
+ scrollToOffset: (params: ScrollToOffsetParams) => void;
97
+
98
+ /**
99
+ * Makes the scroll indicators flash momentarily.
100
+ *
101
+ * Useful to indicate to users that there is more content to scroll.
102
+ *
103
+ * @example
104
+ * listRef.current?.flashScrollIndicators();
105
+ */
106
+ flashScrollIndicators: () => void;
107
+
108
+ /**
109
+ * Returns the underlying native scroll view reference.
110
+ *
111
+ * Use this when you need direct access to the native scroll component.
112
+ * This is generally not recommended for regular use.
113
+ *
114
+ * @returns The native scroll view reference
115
+ */
116
+ getNativeScrollRef: () => CompatScroller | null;
117
+
118
+ /**
119
+ * Returns a reference to the scroll responder.
120
+ *
121
+ * Useful for more advanced scroll handling and integrations.
122
+ *
123
+ * @returns The scroll responder
124
+ */
125
+ getScrollResponder: CompatScroller["getScrollResponder"];
126
+
127
+ /**
128
+ * Returns the underlying scrollable node.
129
+ *
130
+ * Primarily used for platform-specific integrations.
131
+ *
132
+ * @returns The scrollable node
133
+ */
134
+ getScrollableNode: () => any;
135
+
136
+ /**
137
+ * Scrolls to the end of the list.
138
+ *
139
+ * @param params - Optional parameters for scrolling
140
+ * @param params.animated - Whether the scroll should be animated (default: false)
141
+ *
142
+ * @example
143
+ * // Animate scroll to the end of the list
144
+ * listRef.current?.scrollToEnd({ animated: true });
145
+ */
146
+ scrollToEnd: (params?: ScrollToEdgeParams) => void;
147
+
148
+ /**
149
+ * Scrolls to the top (or start) of the list.
150
+ *
151
+ * @param params - Optional parameters for scrolling
152
+ * @param params.animated - Whether the scroll should be animated (default: false)
153
+ *
154
+ * @example
155
+ * // Smoothly scroll to the top
156
+ * listRef.current?.scrollToTop({ animated: true });
157
+ */
158
+ scrollToTop: (params?: ScrollToEdgeParams) => void;
159
+
160
+ /**
161
+ * Scrolls to a specific index in the list.
162
+ *
163
+ * This is the most common method to scroll to a particular item.
164
+ *
165
+ * @param params - Parameters for scrolling to index
166
+ * @param params.index - The index of the item to scroll to
167
+ * @param params.animated - Whether the scroll should be animated (default: false)
168
+ * @param params.viewPosition - Position of the item within the visible area:
169
+ * 0 = top/left, 0.5 = center, 1 = bottom/right (default: 0)
170
+ * @param params.viewOffset - Additional offset to apply after viewPosition calculation
171
+ *
172
+ * @returns A Promise that resolves when the scroll operation is complete
173
+ *
174
+ * @example
175
+ * // Scroll to the 5th item (index 4) and center it
176
+ * listRef.current?.scrollToIndex({
177
+ * index: 4,
178
+ * animated: true,
179
+ * viewPosition: 0.5
180
+ * });
181
+ */
182
+ scrollToIndex: (params: ScrollToIndexParams) => Promise<void>;
183
+
184
+ /**
185
+ * Scrolls to a specific item in the list.
186
+ *
187
+ * Similar to scrollToIndex, but works with the item reference instead of its index.
188
+ * Useful when you have a reference to an item but don't know its index.
189
+ *
190
+ * @param params - Parameters for scrolling to item
191
+ * @param params.item - The item object to scroll to
192
+ * @param params.animated - Whether the scroll should be animated (default: false)
193
+ * @param params.viewPosition - Position of the item within the visible area:
194
+ * 0 = top/left, 0.5 = center, 1 = bottom/right (default: 0)
195
+ * @param params.viewOffset - Additional offset to apply after viewPosition calculation
196
+ *
197
+ * @example
198
+ * // Scroll to a specific item
199
+ * const targetItem = data[10];
200
+ * listRef.current?.scrollToItem({
201
+ * item: targetItem,
202
+ * animated: true
203
+ * });
204
+ */
205
+ scrollToItem: (params: ScrollToItemParams<T>) => void;
206
+
207
+ /**
208
+ * Returns the offset of the first item (accounts for header/padding).
209
+ *
210
+ * Useful when implementing custom scroll behavior or calculating positions.
211
+ *
212
+ * @returns The pixel offset of the first item
213
+ */
214
+ getFirstItemOffset: () => number;
215
+
216
+ /**
217
+ * Returns the current viewport dimensions.
218
+ *
219
+ * @returns An object with width and height properties representing viewport size
220
+ */
221
+ getWindowSize: () => { width: number; height: number };
222
+
223
+ /**
224
+ * Returns the layout information for a specific item.
225
+ *
226
+ * Use this to get position and size information for an item at a given index.
227
+ *
228
+ * @param index - The index of the item to get layout information for
229
+ * @returns Layout information including x, y, width, and height
230
+ *
231
+ * @example
232
+ * const itemLayout = listRef.current?.getLayout(5);
233
+ * console.log(`Item 5 position: (${itemLayout.x}, ${itemLayout.y})`);
234
+ */
235
+ getLayout: (index: number) => RVLayout | undefined;
236
+
237
+ /**
238
+ * Returns the absolute last scroll offset.
239
+ *
240
+ * Useful for implementing custom scroll tracking functionality.
241
+ *
242
+ * @returns The last scroll offset in pixels
243
+ */
244
+ getAbsoluteLastScrollOffset: () => number;
245
+
246
+ /**
247
+ * Returns the dimensions of the child container.
248
+ *
249
+ * @returns An object with width and height properties
250
+ */
251
+ getChildContainerDimensions: () => { width: number; height: number };
252
+
253
+ /**
254
+ * Marks the list as having been interacted with.
255
+ *
256
+ * Call this method when you want to manually trigger the onViewableItemsChanged
257
+ * callback without an actual scroll event.
258
+ */
259
+ recordInteraction: () => void;
260
+
261
+ /**
262
+ * Returns the currently visible item indices.
263
+ *
264
+ * Use this to determine which items are currently visible to the user.
265
+ *
266
+ * @returns An object with startIndex and endIndex properties
267
+ *
268
+ * @example
269
+ * const { startIndex, endIndex } = listRef.current?.getVisibleIndices();
270
+ * console.log(`Visible items: ${startIndex} to ${endIndex}`);
271
+ */
272
+ computeVisibleIndices: () => { startIndex: number; endIndex: number };
273
+
274
+ /**
275
+ * Returns the index of the first visible item.
276
+ *
277
+ * Convenience method when you only need the first visible item.
278
+ *
279
+ * @returns The index of the first visible item
280
+ *
281
+ * @example
282
+ * const firstVisibleIndex = listRef.current?.getFirstVisibleIndex();
283
+ */
284
+ getFirstVisibleIndex: () => number;
285
+
286
+ /**
287
+ * Forces recalculation of viewable items (vieability callbacks).
288
+ *
289
+ * Call this after any operation that might affect item visibility but
290
+ * doesn't trigger a scroll event.
291
+ *
292
+ * @example
293
+ * // After manually changing item sizes
294
+ * listRef.current?.recomputeViewableItems();
295
+ */
296
+ recomputeViewableItems: () => void;
297
+
298
+ /**
299
+ * Disables item recycling in preparation for layout animations.
300
+ *
301
+ * Call this before performing layout animations to prevent visual glitches.
302
+ * Remember to reset disableRecycling after animations complete.
303
+ *
304
+ * @example
305
+ * // Before starting layout animations
306
+ * listRef.current?.prepareForLayoutAnimationRender();
307
+ */
308
+ prepareForLayoutAnimationRender: () => void;
309
+
310
+ /**
311
+ * Clears the layout cache on update.
312
+ * Call this when you want to clear the layout cache on update.
313
+ * Can be useful for carousals when orientation changes.
314
+ * This should be called before the render and not in an effect.
315
+ *
316
+ * @example
317
+ * listRef.current?.clearLayoutCacheOnUpdate();
318
+ */
319
+ clearLayoutCacheOnUpdate: () => void;
320
+ }
@@ -258,7 +258,7 @@ const MasonryFlashListComponent = React.forwardRef(
258
258
  ? (info) => {
259
259
  updateViewTokens(info.viewableItems);
260
260
  updateViewTokens(info.changed);
261
- onViewableItemsChanged?.(info);
261
+ onViewableItemsChanged?.(info as any);
262
262
  }
263
263
  : undefined
264
264
  }
@@ -437,7 +437,7 @@ const getFlashListScrollView = (
437
437
  FlashListScrollView.displayName = "FlashListScrollView";
438
438
  return FlashListScrollView;
439
439
  };
440
- const updateViewTokens = (tokens: ViewToken[]) => {
440
+ const updateViewTokens = (tokens: ViewToken<any>[]) => {
441
441
  const length = tokens.length;
442
442
  for (let i = 0; i < length; i++) {
443
443
  const token = tokens[i];
@@ -15,14 +15,14 @@ jest.mock("../recyclerview/utils/measureLayout", () => {
15
15
  measureParentSize: jest.fn().mockImplementation(() => ({
16
16
  x: 0,
17
17
  y: 0,
18
- width: 400,
19
- height: 900,
18
+ width: 399,
19
+ height: 899,
20
20
  })),
21
- measureChildContainerLayout: jest.fn().mockImplementation(() => ({
21
+ measureFirstChildLayout: jest.fn().mockImplementation(() => ({
22
22
  x: 0,
23
23
  y: 0,
24
- width: 400,
25
- height: 900,
24
+ width: 399,
25
+ height: 899,
26
26
  })),
27
27
  measureItemLayout: jest.fn().mockImplementation(() => ({
28
28
  x: 0,
@@ -33,37 +33,91 @@ jest.mock("../recyclerview/utils/measureLayout", () => {
33
33
  };
34
34
  });
35
35
 
36
+ const renderRecyclerView = (args: {
37
+ numColumns?: number;
38
+ masonry?: boolean;
39
+ horizontal?: boolean;
40
+ }) => {
41
+ const { numColumns = 1, masonry = false, horizontal = false } = args;
42
+ return render(
43
+ <RecyclerView
44
+ data={[
45
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
46
+ ]}
47
+ masonry={masonry}
48
+ overrideProps={{ initialDrawBatchSize: 1 }}
49
+ drawDistance={0}
50
+ numColumns={numColumns}
51
+ horizontal={horizontal}
52
+ renderItem={({ item }) => <Text>{item}</Text>}
53
+ />
54
+ );
55
+ };
56
+
36
57
  describe("RecyclerView", () => {
37
58
  beforeEach(() => {
38
59
  jest.clearAllMocks();
39
60
  jest.useFakeTimers();
40
61
  });
62
+ describe("Linear Layout", () => {
63
+ it("renders items ", () => {
64
+ const result = renderRecyclerView({});
65
+
66
+ expect(result).toContainReactComponent(Text, { children: 0 });
67
+ expect(result).not.toContainReactComponent(Text, { children: 11 });
68
+ });
69
+ });
70
+
71
+ describe("Masonry Layout", () => {
72
+ it("renders items with masonry", () => {
73
+ const result = renderRecyclerView({ masonry: true });
74
+
75
+ expect(result).toContainReactComponent(Text, { children: 0 });
76
+ });
77
+ it("should not render item 18, 19 with numColumns 2", () => {
78
+ const result = renderRecyclerView({ numColumns: 2, masonry: true });
79
+
80
+ expect(result).toContainReactComponent(Text, {
81
+ children: 17,
82
+ });
83
+ expect(result).not.toContainReactComponent(Text, {
84
+ children: 18,
85
+ });
86
+
87
+ expect(result).not.toContainReactComponent(Text, {
88
+ children: 19,
89
+ });
90
+ });
91
+ });
92
+
93
+ describe("Grid Layout", () => {
94
+ it("renders items with numColumns 2", () => {
95
+ const result = renderRecyclerView({ numColumns: 2 });
96
+
97
+ expect(result).toContainReactComponent(Text, { children: 0 });
98
+ });
99
+ it("should not render item 18, 19 with numColumns 2", () => {
100
+ const result = renderRecyclerView({ numColumns: 2 });
101
+
102
+ expect(result).toContainReactComponent(Text, {
103
+ children: 17,
104
+ });
105
+ expect(result).not.toContainReactComponent(Text, {
106
+ children: 18,
107
+ });
108
+
109
+ expect(result).not.toContainReactComponent(Text, {
110
+ children: 19,
111
+ });
112
+ });
113
+ });
41
114
 
42
- it("renders items ", () => {
43
- const result = render(
44
- <RecyclerView
45
- data={[
46
- "One",
47
- "Two",
48
- "Three",
49
- "Four",
50
- "Five",
51
- "Six",
52
- "Seven",
53
- "Eight",
54
- "Nine",
55
- "Ten",
56
- "Eleven",
57
- "Twelve",
58
- "Thirteen",
59
- "Fourteen",
60
- "Fifteen",
61
- ]}
62
- renderItem={({ item }) => <Text>{item}</Text>}
63
- />
64
- );
115
+ describe("Horizontal Layout", () => {
116
+ it("renders items with horizontal", () => {
117
+ const result = renderRecyclerView({ horizontal: true });
65
118
 
66
- expect(result).toContainReactComponent(Text, { children: "One" });
67
- expect(result).not.toContainReactComponent(Text, { children: "Eleven" });
119
+ expect(result).toContainReactComponent(Text, { children: 0 });
120
+ expect(result).not.toContainReactComponent(Text, { children: 4 });
121
+ });
68
122
  });
69
123
  });