@shopify/flash-list 2.0.0-alpha.2 → 2.0.0-alpha.21
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.
- package/README.md +67 -96
- package/android/src/main/kotlin/com/shopify/reactnative/flash_list/BlankAreaEvent.kt +2 -2
- package/dist/AnimatedFlashList.d.ts +0 -1
- package/dist/AnimatedFlashList.d.ts.map +1 -1
- package/dist/AnimatedFlashList.js +3 -3
- package/dist/AnimatedFlashList.js.map +1 -1
- package/dist/FlashList.d.ts +9 -0
- package/dist/FlashList.d.ts.map +1 -1
- package/dist/FlashList.js +22 -3
- package/dist/FlashList.js.map +1 -1
- package/dist/FlashListProps.d.ts +33 -13
- package/dist/FlashListProps.d.ts.map +1 -1
- package/dist/FlashListProps.js.map +1 -1
- package/dist/FlashListRef.d.ts +305 -0
- package/dist/FlashListRef.d.ts.map +1 -0
- package/dist/FlashListRef.js +3 -0
- package/dist/FlashListRef.js.map +1 -0
- package/dist/GridLayoutProviderWithProps.js +1 -2
- package/dist/GridLayoutProviderWithProps.js.map +1 -1
- package/dist/MasonryFlashList.d.ts +2 -2
- package/dist/MasonryFlashList.d.ts.map +1 -1
- package/dist/MasonryFlashList.js.map +1 -1
- package/dist/PureComponentWrapper.js +1 -1
- package/dist/PureComponentWrapper.js.map +1 -1
- package/dist/__tests__/AverageWindow.test.js.map +1 -1
- package/dist/__tests__/ConsecutiveNumbers.test.d.ts +2 -0
- package/dist/__tests__/ConsecutiveNumbers.test.d.ts.map +1 -0
- package/dist/__tests__/ConsecutiveNumbers.test.js +224 -0
- package/dist/__tests__/ConsecutiveNumbers.test.js.map +1 -0
- package/dist/__tests__/FlashList.test.js.map +1 -1
- package/dist/__tests__/GridLayoutManager.test.d.ts +2 -0
- package/dist/__tests__/GridLayoutManager.test.d.ts.map +1 -0
- package/dist/__tests__/GridLayoutManager.test.js +69 -0
- package/dist/__tests__/GridLayoutManager.test.js.map +1 -0
- package/dist/__tests__/GridLayoutProviderWithProps.test.js.map +1 -1
- package/dist/__tests__/LayoutCommitObserver.test.d.ts +2 -0
- package/dist/__tests__/LayoutCommitObserver.test.d.ts.map +1 -0
- package/dist/__tests__/LayoutCommitObserver.test.js +35 -0
- package/dist/__tests__/LayoutCommitObserver.test.js.map +1 -0
- package/dist/__tests__/LinearLayoutManager.test.d.ts +2 -0
- package/dist/__tests__/LinearLayoutManager.test.d.ts.map +1 -0
- package/dist/__tests__/LinearLayoutManager.test.js +140 -0
- package/dist/__tests__/LinearLayoutManager.test.js.map +1 -0
- package/dist/__tests__/MasonryFlashList.test.js.map +1 -1
- package/dist/__tests__/MasonryLayoutManager.test.d.ts +2 -0
- package/dist/__tests__/MasonryLayoutManager.test.d.ts.map +1 -0
- package/dist/__tests__/MasonryLayoutManager.test.js +148 -0
- package/dist/__tests__/MasonryLayoutManager.test.js.map +1 -0
- package/dist/__tests__/RecyclerView.test.d.ts +2 -0
- package/dist/__tests__/RecyclerView.test.d.ts.map +1 -0
- package/dist/__tests__/RecyclerView.test.js +103 -0
- package/dist/__tests__/RecyclerView.test.js.map +1 -0
- package/dist/__tests__/RenderStackManager.test.d.ts +2 -0
- package/dist/__tests__/RenderStackManager.test.d.ts.map +1 -0
- package/dist/__tests__/RenderStackManager.test.js +485 -0
- package/dist/__tests__/RenderStackManager.test.js.map +1 -0
- package/dist/__tests__/ViewabilityHelper.test.js.map +1 -1
- package/dist/__tests__/findVisibleIndex.test.d.ts +2 -0
- package/dist/__tests__/findVisibleIndex.test.d.ts.map +1 -0
- package/dist/__tests__/findVisibleIndex.test.js +259 -0
- package/dist/__tests__/findVisibleIndex.test.js.map +1 -0
- package/dist/__tests__/helpers/createLayoutManager.d.ts +34 -0
- package/dist/__tests__/helpers/createLayoutManager.d.ts.map +1 -0
- package/dist/__tests__/helpers/createLayoutManager.js +110 -0
- package/dist/__tests__/helpers/createLayoutManager.js.map +1 -0
- package/dist/__tests__/helpers/mountFlashList.d.ts +2 -2
- package/dist/__tests__/helpers/mountFlashList.d.ts.map +1 -1
- package/dist/__tests__/helpers/mountFlashList.js +2 -2
- package/dist/__tests__/helpers/mountFlashList.js.map +1 -1
- package/dist/__tests__/helpers/mountMasonryFlashList.d.ts +2 -2
- package/dist/__tests__/helpers/mountMasonryFlashList.d.ts.map +1 -1
- package/dist/__tests__/helpers/mountMasonryFlashList.js +2 -2
- package/dist/__tests__/helpers/mountMasonryFlashList.js.map +1 -1
- package/dist/__tests__/useBlankAreaTracker.test.js.map +1 -1
- package/dist/__tests__/useUnmountAwareCallbacks.test.d.ts +2 -0
- package/dist/__tests__/useUnmountAwareCallbacks.test.d.ts.map +1 -0
- package/dist/__tests__/useUnmountAwareCallbacks.test.js +185 -0
- package/dist/__tests__/useUnmountAwareCallbacks.test.js.map +1 -0
- package/dist/benchmark/AutoScrollHelper.js +2 -2
- package/dist/benchmark/AutoScrollHelper.js.map +1 -1
- package/dist/benchmark/JSFPSMonitor.js.map +1 -1
- package/dist/benchmark/roundToDecimalPlaces.js +1 -2
- package/dist/benchmark/roundToDecimalPlaces.js.map +1 -1
- package/dist/benchmark/useBenchmark.js +2 -28
- package/dist/benchmark/useBenchmark.js.map +1 -1
- package/dist/benchmark/useBlankAreaTracker.js +1 -2
- package/dist/benchmark/useBlankAreaTracker.js.map +1 -1
- package/dist/benchmark/useDataMultiplier.js +1 -2
- package/dist/benchmark/useDataMultiplier.js.map +1 -1
- package/dist/benchmark/useFlatListBenchmark.d.ts +0 -1
- package/dist/benchmark/useFlatListBenchmark.d.ts.map +1 -1
- package/dist/benchmark/useFlatListBenchmark.js +9 -9
- package/dist/benchmark/useFlatListBenchmark.js.map +1 -1
- package/dist/enableNewCore.d.ts.map +1 -1
- package/dist/enableNewCore.js +4 -4
- package/dist/enableNewCore.js.map +1 -1
- package/dist/errors/CustomError.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -3
- package/dist/index.js.map +1 -1
- package/dist/native/auto-layout/AutoLayoutView.d.ts +1 -1
- package/dist/native/auto-layout/AutoLayoutView.d.ts.map +1 -1
- package/dist/native/auto-layout/AutoLayoutView.js +1 -1
- package/dist/native/auto-layout/AutoLayoutView.js.map +1 -1
- package/dist/native/auto-layout/AutoLayoutViewNativeComponent.d.ts.map +1 -1
- package/dist/native/auto-layout/AutoLayoutViewNativeComponentProps.d.ts +1 -1
- package/dist/native/auto-layout/AutoLayoutViewNativeComponentProps.d.ts.map +1 -1
- package/dist/native/config/PlatformHelper.android.d.ts +2 -0
- package/dist/native/config/PlatformHelper.android.d.ts.map +1 -1
- package/dist/native/config/PlatformHelper.android.js +2 -0
- package/dist/native/config/PlatformHelper.android.js.map +1 -1
- package/dist/native/config/PlatformHelper.d.ts +2 -0
- package/dist/native/config/PlatformHelper.d.ts.map +1 -1
- package/dist/native/config/PlatformHelper.ios.d.ts +2 -0
- package/dist/native/config/PlatformHelper.ios.d.ts.map +1 -1
- package/dist/native/config/PlatformHelper.ios.js +2 -0
- package/dist/native/config/PlatformHelper.ios.js.map +1 -1
- package/dist/native/config/PlatformHelper.js +2 -0
- package/dist/native/config/PlatformHelper.js.map +1 -1
- package/dist/native/config/PlatformHelper.web.d.ts +2 -0
- package/dist/native/config/PlatformHelper.web.d.ts.map +1 -1
- package/dist/native/config/PlatformHelper.web.js +3 -1
- package/dist/native/config/PlatformHelper.web.js.map +1 -1
- package/dist/recyclerview/LayoutCommitObserver.d.ts +12 -0
- package/dist/recyclerview/LayoutCommitObserver.d.ts.map +1 -0
- package/dist/recyclerview/LayoutCommitObserver.js +62 -0
- package/dist/recyclerview/LayoutCommitObserver.js.map +1 -0
- package/dist/recyclerview/RecyclerView.d.ts +3 -2
- package/dist/recyclerview/RecyclerView.d.ts.map +1 -1
- package/dist/recyclerview/RecyclerView.js +133 -69
- package/dist/recyclerview/RecyclerView.js.map +1 -1
- package/dist/recyclerview/RecyclerViewContextProvider.d.ts +41 -7
- package/dist/recyclerview/RecyclerViewContextProvider.d.ts.map +1 -1
- package/dist/recyclerview/RecyclerViewContextProvider.js +6 -2
- package/dist/recyclerview/RecyclerViewContextProvider.js.map +1 -1
- package/dist/recyclerview/RecyclerViewManager.d.ts +31 -7
- package/dist/recyclerview/RecyclerViewManager.d.ts.map +1 -1
- package/dist/recyclerview/RecyclerViewManager.js +154 -117
- package/dist/recyclerview/RecyclerViewManager.js.map +1 -1
- package/dist/recyclerview/RecyclerViewProps.d.ts +1 -1
- package/dist/recyclerview/RecyclerViewProps.d.ts.map +1 -1
- package/dist/recyclerview/RenderStackManager.d.ts +86 -0
- package/dist/recyclerview/RenderStackManager.d.ts.map +1 -0
- package/dist/recyclerview/RenderStackManager.js +343 -0
- package/dist/recyclerview/RenderStackManager.js.map +1 -0
- package/dist/recyclerview/ViewHolder.d.ts.map +1 -1
- package/dist/recyclerview/ViewHolder.js +8 -6
- package/dist/recyclerview/ViewHolder.js.map +1 -1
- package/dist/recyclerview/ViewHolderCollection.d.ts +10 -4
- package/dist/recyclerview/ViewHolderCollection.d.ts.map +1 -1
- package/dist/recyclerview/ViewHolderCollection.js +26 -10
- package/dist/recyclerview/ViewHolderCollection.js.map +1 -1
- package/dist/recyclerview/components/ScrollAnchor.d.ts +2 -1
- package/dist/recyclerview/components/ScrollAnchor.d.ts.map +1 -1
- package/dist/recyclerview/components/ScrollAnchor.js +12 -9
- package/dist/recyclerview/components/ScrollAnchor.js.map +1 -1
- package/dist/recyclerview/components/StickyHeaders.d.ts +2 -2
- package/dist/recyclerview/components/StickyHeaders.d.ts.map +1 -1
- package/dist/recyclerview/components/StickyHeaders.js +44 -45
- package/dist/recyclerview/components/StickyHeaders.js.map +1 -1
- package/dist/recyclerview/helpers/ConsecutiveNumbers.d.ts +1 -1
- package/dist/recyclerview/helpers/ConsecutiveNumbers.d.ts.map +1 -1
- package/dist/recyclerview/helpers/ConsecutiveNumbers.js +2 -2
- package/dist/recyclerview/helpers/ConsecutiveNumbers.js.map +1 -1
- package/dist/recyclerview/helpers/EngagedIndicesTracker.d.ts +48 -2
- package/dist/recyclerview/helpers/EngagedIndicesTracker.d.ts.map +1 -1
- package/dist/recyclerview/helpers/EngagedIndicesTracker.js +89 -19
- package/dist/recyclerview/helpers/EngagedIndicesTracker.js.map +1 -1
- package/dist/recyclerview/helpers/RenderTimeTracker.d.ts +11 -0
- package/dist/recyclerview/helpers/RenderTimeTracker.d.ts.map +1 -0
- package/dist/recyclerview/helpers/RenderTimeTracker.js +42 -0
- package/dist/recyclerview/helpers/RenderTimeTracker.js.map +1 -0
- package/dist/recyclerview/helpers/VelocityTracker.d.ts +29 -0
- package/dist/recyclerview/helpers/VelocityTracker.d.ts.map +1 -0
- package/dist/recyclerview/helpers/VelocityTracker.js +70 -0
- package/dist/recyclerview/helpers/VelocityTracker.js.map +1 -0
- package/dist/recyclerview/hooks/useBoundDetection.d.ts +1 -3
- package/dist/recyclerview/hooks/useBoundDetection.d.ts.map +1 -1
- package/dist/recyclerview/hooks/useBoundDetection.js +60 -28
- package/dist/recyclerview/hooks/useBoundDetection.js.map +1 -1
- package/dist/recyclerview/hooks/useLayoutState.d.ts +3 -1
- package/dist/recyclerview/hooks/useLayoutState.d.ts.map +1 -1
- package/dist/recyclerview/hooks/useLayoutState.js +6 -5
- package/dist/recyclerview/hooks/useLayoutState.js.map +1 -1
- package/dist/recyclerview/hooks/useMappingHelper.d.ts +9 -0
- package/dist/recyclerview/hooks/useMappingHelper.d.ts.map +1 -0
- package/dist/recyclerview/hooks/useMappingHelper.js +19 -0
- package/dist/recyclerview/hooks/useMappingHelper.js.map +1 -0
- package/dist/recyclerview/hooks/useOnLoad.d.ts +2 -2
- package/dist/recyclerview/hooks/useOnLoad.d.ts.map +1 -1
- package/dist/recyclerview/hooks/useOnLoad.js +9 -10
- package/dist/recyclerview/hooks/useOnLoad.js.map +1 -1
- package/dist/recyclerview/hooks/useRecyclerViewController.d.ts +5 -49
- package/dist/recyclerview/hooks/useRecyclerViewController.d.ts.map +1 -1
- package/dist/recyclerview/hooks/useRecyclerViewController.js +343 -191
- package/dist/recyclerview/hooks/useRecyclerViewController.js.map +1 -1
- package/dist/recyclerview/hooks/useRecyclerViewManager.d.ts +2 -0
- package/dist/recyclerview/hooks/useRecyclerViewManager.d.ts.map +1 -1
- package/dist/recyclerview/hooks/useRecyclerViewManager.js +11 -1
- package/dist/recyclerview/hooks/useRecyclerViewManager.js.map +1 -1
- package/dist/recyclerview/hooks/useRecyclingState.d.ts +4 -2
- package/dist/recyclerview/hooks/useRecyclingState.d.ts.map +1 -1
- package/dist/recyclerview/hooks/useRecyclingState.js +3 -4
- package/dist/recyclerview/hooks/useRecyclingState.js.map +1 -1
- package/dist/recyclerview/hooks/useSecondaryProps.d.ts +1 -1
- package/dist/recyclerview/hooks/useSecondaryProps.d.ts.map +1 -1
- package/dist/recyclerview/hooks/useSecondaryProps.js +15 -12
- package/dist/recyclerview/hooks/useSecondaryProps.js.map +1 -1
- package/dist/recyclerview/hooks/useUnmountAwareCallbacks.d.ts +15 -0
- package/dist/recyclerview/hooks/useUnmountAwareCallbacks.d.ts.map +1 -0
- package/dist/recyclerview/hooks/useUnmountAwareCallbacks.js +63 -0
- package/dist/recyclerview/hooks/useUnmountAwareCallbacks.js.map +1 -0
- package/dist/recyclerview/hooks/useUnmountFlag.d.ts +0 -1
- package/dist/recyclerview/hooks/useUnmountFlag.d.ts.map +1 -1
- package/dist/recyclerview/hooks/useUnmountFlag.js +1 -0
- package/dist/recyclerview/hooks/useUnmountFlag.js.map +1 -1
- package/dist/recyclerview/layout-managers/GridLayoutManager.d.ts +18 -4
- package/dist/recyclerview/layout-managers/GridLayoutManager.d.ts.map +1 -1
- package/dist/recyclerview/layout-managers/GridLayoutManager.js +61 -25
- package/dist/recyclerview/layout-managers/GridLayoutManager.js.map +1 -1
- package/dist/recyclerview/layout-managers/LayoutManager.d.ts +36 -21
- package/dist/recyclerview/layout-managers/LayoutManager.d.ts.map +1 -1
- package/dist/recyclerview/layout-managers/LayoutManager.js +96 -28
- package/dist/recyclerview/layout-managers/LayoutManager.js.map +1 -1
- package/dist/recyclerview/layout-managers/LinearLayoutManager.d.ts +1 -2
- package/dist/recyclerview/layout-managers/LinearLayoutManager.d.ts.map +1 -1
- package/dist/recyclerview/layout-managers/LinearLayoutManager.js +3 -3
- package/dist/recyclerview/layout-managers/LinearLayoutManager.js.map +1 -1
- package/dist/recyclerview/layout-managers/MasonryLayoutManager.d.ts +9 -1
- package/dist/recyclerview/layout-managers/MasonryLayoutManager.d.ts.map +1 -1
- package/dist/recyclerview/layout-managers/MasonryLayoutManager.js +30 -16
- package/dist/recyclerview/layout-managers/MasonryLayoutManager.js.map +1 -1
- package/dist/recyclerview/utils/adjustOffsetForRTL.js +1 -2
- package/dist/recyclerview/utils/adjustOffsetForRTL.js.map +1 -1
- package/dist/recyclerview/utils/componentUtils.d.ts +1 -1
- package/dist/recyclerview/utils/componentUtils.d.ts.map +1 -1
- package/dist/recyclerview/utils/componentUtils.js.map +1 -1
- package/dist/recyclerview/utils/findVisibleIndex.d.ts.map +1 -1
- package/dist/recyclerview/utils/findVisibleIndex.js +3 -5
- package/dist/recyclerview/utils/findVisibleIndex.js.map +1 -1
- package/dist/recyclerview/utils/measureLayout.d.ts +24 -28
- package/dist/recyclerview/utils/measureLayout.d.ts.map +1 -1
- package/dist/recyclerview/utils/measureLayout.js +36 -6
- package/dist/recyclerview/utils/measureLayout.js.map +1 -1
- package/dist/recyclerview/utils/measureLayout.web.d.ts +29 -0
- package/dist/recyclerview/utils/measureLayout.web.d.ts.map +1 -0
- package/dist/recyclerview/utils/measureLayout.web.js +87 -0
- package/dist/recyclerview/utils/measureLayout.web.js.map +1 -0
- package/dist/specs/AutoLayoutNativeComponent.d.ts +1 -2
- package/dist/specs/AutoLayoutNativeComponent.d.ts.map +1 -1
- package/dist/specs/CellContainerNativeComponent.d.ts +0 -1
- package/dist/specs/CellContainerNativeComponent.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/AverageWindow.js.map +1 -1
- package/dist/utils/ContentContainerUtils.d.ts.map +1 -1
- package/dist/utils/ContentContainerUtils.js.map +1 -1
- package/dist/viewability/ViewToken.d.ts +2 -2
- package/dist/viewability/ViewToken.d.ts.map +1 -1
- package/dist/viewability/ViewabilityHelper.js +1 -1
- package/dist/viewability/ViewabilityHelper.js.map +1 -1
- package/dist/viewability/ViewabilityManager.d.ts.map +1 -1
- package/dist/viewability/ViewabilityManager.js +11 -5
- package/dist/viewability/ViewabilityManager.js.map +1 -1
- package/jestSetup.js +30 -11
- package/package.json +4 -3
- package/src/AnimatedFlashList.ts +3 -2
- package/src/FlashList.tsx +25 -1
- package/src/FlashListProps.ts +42 -11
- package/src/FlashListRef.ts +320 -0
- package/src/MasonryFlashList.tsx +2 -2
- package/src/__tests__/ConsecutiveNumbers.test.ts +232 -0
- package/src/__tests__/GridLayoutManager.test.ts +113 -0
- package/src/__tests__/LayoutCommitObserver.test.tsx +60 -0
- package/src/__tests__/LinearLayoutManager.test.ts +227 -0
- package/src/__tests__/MasonryLayoutManager.test.ts +202 -0
- package/src/__tests__/RecyclerView.test.tsx +144 -0
- package/src/__tests__/RenderStackManager.test.ts +574 -0
- package/src/__tests__/findVisibleIndex.test.ts +369 -0
- package/src/__tests__/helpers/createLayoutManager.ts +141 -0
- package/src/__tests__/useUnmountAwareCallbacks.test.tsx +285 -0
- package/src/benchmark/useBenchmark.ts +0 -37
- package/src/benchmark/useFlatListBenchmark.ts +2 -2
- package/src/enableNewCore.ts +3 -1
- package/src/index.ts +14 -3
- package/src/native/config/PlatformHelper.android.ts +2 -0
- package/src/native/config/PlatformHelper.ios.ts +2 -0
- package/src/native/config/PlatformHelper.ts +2 -0
- package/src/native/config/PlatformHelper.web.ts +3 -1
- package/src/recyclerview/LayoutCommitObserver.tsx +74 -0
- package/src/recyclerview/RecyclerView.tsx +178 -89
- package/src/recyclerview/RecyclerViewContextProvider.ts +53 -7
- package/src/recyclerview/RecyclerViewManager.ts +176 -97
- package/src/recyclerview/RecyclerViewProps.ts +2 -1
- package/src/recyclerview/RenderStackManager.ts +317 -0
- package/src/recyclerview/ViewHolder.tsx +13 -6
- package/src/recyclerview/ViewHolderCollection.tsx +45 -16
- package/src/recyclerview/components/ScrollAnchor.tsx +24 -11
- package/src/recyclerview/components/StickyHeaders.tsx +70 -58
- package/src/recyclerview/helpers/ConsecutiveNumbers.ts +2 -2
- package/src/recyclerview/helpers/EngagedIndicesTracker.ts +135 -25
- package/src/recyclerview/helpers/RenderTimeTracker.ts +42 -0
- package/src/recyclerview/helpers/VelocityTracker.ts +77 -0
- package/src/recyclerview/hooks/useBoundDetection.ts +74 -25
- package/src/recyclerview/hooks/useLayoutState.ts +15 -6
- package/src/recyclerview/hooks/useMappingHelper.ts +20 -0
- package/src/recyclerview/hooks/useOnLoad.ts +11 -10
- package/src/recyclerview/hooks/useRecyclerViewController.tsx +380 -241
- package/src/recyclerview/hooks/useRecyclerViewManager.ts +13 -1
- package/src/recyclerview/hooks/useRecyclingState.ts +11 -7
- package/src/recyclerview/hooks/useSecondaryProps.tsx +12 -7
- package/src/recyclerview/hooks/useUnmountAwareCallbacks.ts +73 -0
- package/src/recyclerview/hooks/useUnmountFlag.ts +1 -0
- package/src/recyclerview/layout-managers/GridLayoutManager.ts +68 -27
- package/src/recyclerview/layout-managers/LayoutManager.ts +116 -42
- package/src/recyclerview/layout-managers/LinearLayoutManager.ts +12 -8
- package/src/recyclerview/layout-managers/MasonryLayoutManager.ts +34 -13
- package/src/recyclerview/utils/componentUtils.ts +1 -1
- package/src/recyclerview/utils/findVisibleIndex.ts +1 -2
- package/src/recyclerview/utils/measureLayout.ts +41 -2
- package/src/recyclerview/utils/measureLayout.web.ts +102 -0
- package/src/viewability/ViewToken.ts +2 -2
- package/src/viewability/ViewabilityHelper.ts +1 -1
- package/src/viewability/ViewabilityManager.ts +16 -9
- package/dist/recyclerview/RecycleKeyManager.d.ts +0 -82
- package/dist/recyclerview/RecycleKeyManager.d.ts.map +0 -1
- package/dist/recyclerview/RecycleKeyManager.js +0 -135
- package/dist/recyclerview/RecycleKeyManager.js.map +0 -1
- package/src/recyclerview/RecycleKeyManager.ts +0 -185
|
@@ -7,64 +7,23 @@ import {
|
|
|
7
7
|
useState,
|
|
8
8
|
} from "react";
|
|
9
9
|
import { I18nManager } from "react-native";
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
ScrollToOffsetParams,
|
|
13
|
+
ScrollToIndexParams,
|
|
14
|
+
ScrollToItemParams,
|
|
15
|
+
ScrollToEdgeParams,
|
|
16
|
+
FlashListRef,
|
|
17
|
+
} from "../../FlashListRef";
|
|
11
18
|
import { CompatScroller } from "../components/CompatScroller";
|
|
12
19
|
import { RecyclerViewManager } from "../RecyclerViewManager";
|
|
13
20
|
import { adjustOffsetForRTL } from "../utils/adjustOffsetForRTL";
|
|
14
|
-
import { useUnmountFlag } from "./useUnmountFlag";
|
|
15
21
|
import { RVLayout } from "../layout-managers/LayoutManager";
|
|
16
22
|
import { ScrollAnchorRef } from "../components/ScrollAnchor";
|
|
23
|
+
import { PlatformConfig } from "../../native/config/PlatformHelper";
|
|
17
24
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
* Extends ScrollToEdgeParams to include view positioning options.
|
|
21
|
-
*/
|
|
22
|
-
export interface ScrollToParams extends ScrollToEdgeParams {
|
|
23
|
-
/** Position of the target item relative to the viewport (0 = top, 0.5 = center, 1 = bottom) */
|
|
24
|
-
viewPosition?: number;
|
|
25
|
-
/** Additional offset to apply after viewPosition calculation */
|
|
26
|
-
viewOffset?: number;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Parameters for scrolling to a specific offset in the list.
|
|
31
|
-
* Used when you want to scroll to an exact pixel position.
|
|
32
|
-
*/
|
|
33
|
-
export interface ScrollToOffsetParams extends ScrollToParams {
|
|
34
|
-
/** The pixel offset to scroll to */
|
|
35
|
-
offset: number;
|
|
36
|
-
/**
|
|
37
|
-
* If true, the first item offset will not be added to the offset calculation.
|
|
38
|
-
* First offset represents header size or top padding.
|
|
39
|
-
*/
|
|
40
|
-
skipFirstItemOffset?: boolean;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Parameters for scrolling to a specific index in the list.
|
|
45
|
-
* Used when you want to scroll to a specific item by its position in the data array.
|
|
46
|
-
*/
|
|
47
|
-
export interface ScrollToIndexParams extends ScrollToParams {
|
|
48
|
-
/** The index of the item to scroll to */
|
|
49
|
-
index: number;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Parameters for scrolling to a specific item in the list.
|
|
54
|
-
* Used when you want to scroll to a specific item by its data value.
|
|
55
|
-
*/
|
|
56
|
-
export interface ScrollToItemParams<T> extends ScrollToParams {
|
|
57
|
-
/** The item to scroll to */
|
|
58
|
-
item: T;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Base parameters for scrolling to the edges of the list.
|
|
63
|
-
*/
|
|
64
|
-
export interface ScrollToEdgeParams {
|
|
65
|
-
/** Whether the scroll should be animated */
|
|
66
|
-
animated?: boolean;
|
|
67
|
-
}
|
|
25
|
+
import { useUnmountFlag } from "./useUnmountFlag";
|
|
26
|
+
import { useUnmountAwareTimeout } from "./useUnmountAwareCallbacks";
|
|
68
27
|
|
|
69
28
|
/**
|
|
70
29
|
* Comprehensive hook that manages RecyclerView scrolling behavior and provides
|
|
@@ -84,138 +43,180 @@ export interface ScrollToEdgeParams {
|
|
|
84
43
|
*/
|
|
85
44
|
export function useRecyclerViewController<T>(
|
|
86
45
|
recyclerViewManager: RecyclerViewManager<T>,
|
|
87
|
-
ref: React.Ref<
|
|
46
|
+
ref: React.Ref<FlashListRef<T>>,
|
|
88
47
|
scrollViewRef: RefObject<CompatScroller>,
|
|
89
|
-
scrollAnchorRef: React.RefObject<ScrollAnchorRef
|
|
90
|
-
props: RecyclerViewProps<T>
|
|
48
|
+
scrollAnchorRef: React.RefObject<ScrollAnchorRef>
|
|
91
49
|
) {
|
|
92
|
-
const { horizontal, data } = props;
|
|
93
50
|
const isUnmounted = useUnmountFlag();
|
|
94
51
|
const [_, setRenderId] = useState(0);
|
|
95
|
-
const
|
|
52
|
+
const pauseOffsetCorrection = useRef(false);
|
|
96
53
|
const initialScrollCompletedRef = useRef(false);
|
|
54
|
+
const lastDataLengthRef = useRef(recyclerViewManager.getDataLength());
|
|
55
|
+
const { setTimeout } = useUnmountAwareTimeout();
|
|
97
56
|
|
|
98
57
|
// Track the first visible item for maintaining scroll position
|
|
99
58
|
const firstVisibleItemKey = useRef<string | undefined>(undefined);
|
|
100
59
|
const firstVisibleItemLayout = useRef<RVLayout | undefined>(undefined);
|
|
101
|
-
const pendingScrollResolves = useRef<(() => void)[]>([]);
|
|
102
|
-
|
|
103
|
-
const applyInitialScrollIndex = useCallback(() => {
|
|
104
|
-
const initialScrollIndex =
|
|
105
|
-
recyclerViewManager.getInitialScrollIndex() ?? -1;
|
|
106
|
-
const dataLength = props.data?.length ?? 0;
|
|
107
|
-
if (
|
|
108
|
-
initialScrollIndex >= 0 &&
|
|
109
|
-
initialScrollIndex < dataLength &&
|
|
110
|
-
!initialScrollCompletedRef.current &&
|
|
111
|
-
recyclerViewManager.getIsFirstLayoutComplete()
|
|
112
|
-
) {
|
|
113
|
-
// Use setTimeout to ensure that we keep trying to scroll on first few renders
|
|
114
|
-
setTimeout(() => {
|
|
115
|
-
initialScrollCompletedRef.current = true;
|
|
116
|
-
pauseAdjustRef.current = false;
|
|
117
|
-
}, 100);
|
|
118
60
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const offset = horizontal
|
|
122
|
-
? recyclerViewManager.getLayout(initialScrollIndex).x
|
|
123
|
-
: recyclerViewManager.getLayout(initialScrollIndex).y;
|
|
124
|
-
handlerMethods.scrollToOffset({
|
|
125
|
-
offset,
|
|
126
|
-
animated: false,
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
setTimeout(() => {
|
|
130
|
-
handlerMethods.scrollToOffset({
|
|
131
|
-
offset,
|
|
132
|
-
animated: false,
|
|
133
|
-
});
|
|
134
|
-
}, 0);
|
|
135
|
-
}
|
|
136
|
-
}, [recyclerViewManager, props.data]);
|
|
61
|
+
// Queue to store callbacks that should be executed after scroll offset updates
|
|
62
|
+
const pendingScrollCallbacks = useRef<(() => void)[]>([]);
|
|
137
63
|
|
|
138
64
|
// Handle initial scroll position when the list first loads
|
|
139
65
|
// useOnLoad(recyclerViewManager, () => {
|
|
140
66
|
|
|
141
67
|
// });
|
|
142
68
|
/**
|
|
143
|
-
* Updates the scroll offset and
|
|
144
|
-
*
|
|
69
|
+
* Updates the scroll offset and calls the provided callback
|
|
70
|
+
* after the update has been applied and the component has re-rendered.
|
|
71
|
+
*
|
|
72
|
+
* @param offset - The new scroll offset to apply
|
|
73
|
+
* @param callback - Optional callback to execute after the update is applied
|
|
145
74
|
*/
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
75
|
+
const updateScrollOffsetWithCallback = useCallback(
|
|
76
|
+
(offset: number, callback: () => void): void => {
|
|
77
|
+
// Attempt to update the scroll offset in the RecyclerViewManager
|
|
78
|
+
// This returns undefined if no update is needed
|
|
79
|
+
if (recyclerViewManager.updateScrollOffset(offset) !== undefined) {
|
|
80
|
+
// It will be executed after the next render
|
|
81
|
+
pendingScrollCallbacks.current.push(callback);
|
|
82
|
+
// Trigger a re-render to apply the scroll offset update
|
|
152
83
|
setRenderId((prev) => prev + 1);
|
|
153
|
-
}
|
|
84
|
+
} else {
|
|
85
|
+
// No update needed, execute callback immediately
|
|
86
|
+
callback();
|
|
87
|
+
}
|
|
154
88
|
},
|
|
155
89
|
[recyclerViewManager]
|
|
156
90
|
);
|
|
157
91
|
|
|
92
|
+
const computeFirstVisibleIndexForOffsetCorrection = useCallback(() => {
|
|
93
|
+
if (
|
|
94
|
+
recyclerViewManager.getIsFirstLayoutComplete() &&
|
|
95
|
+
recyclerViewManager.hasStableDataKeys() &&
|
|
96
|
+
recyclerViewManager.getDataLength() > 0 &&
|
|
97
|
+
recyclerViewManager.shouldMaintainVisibleContentPosition()
|
|
98
|
+
) {
|
|
99
|
+
// Update the tracked first visible item
|
|
100
|
+
const firstVisibleIndex = Math.max(
|
|
101
|
+
0,
|
|
102
|
+
recyclerViewManager.computeVisibleIndices().startIndex
|
|
103
|
+
);
|
|
104
|
+
if (firstVisibleIndex !== undefined && firstVisibleIndex >= 0) {
|
|
105
|
+
firstVisibleItemKey.current =
|
|
106
|
+
recyclerViewManager.getDataKey(firstVisibleIndex);
|
|
107
|
+
firstVisibleItemLayout.current = {
|
|
108
|
+
...recyclerViewManager.getLayout(firstVisibleIndex),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}, [recyclerViewManager]);
|
|
113
|
+
|
|
158
114
|
/**
|
|
159
115
|
* Maintains the visible content position when the list updates.
|
|
160
116
|
* This is particularly useful for chat applications where we want to keep
|
|
161
117
|
* the user's current view position when new messages are added.
|
|
162
118
|
*/
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
119
|
+
const applyOffsetCorrection = useCallback(() => {
|
|
120
|
+
const { horizontal, data } = recyclerViewManager.props;
|
|
121
|
+
|
|
122
|
+
// Execute all pending callbacks from previous scroll offset updates
|
|
123
|
+
// This ensures any scroll operations that were waiting for render are completed
|
|
124
|
+
const callbacks = pendingScrollCallbacks.current;
|
|
125
|
+
pendingScrollCallbacks.current = [];
|
|
126
|
+
callbacks.forEach((callback) => callback());
|
|
127
|
+
|
|
128
|
+
const currentDataLength = recyclerViewManager.getDataLength();
|
|
168
129
|
|
|
169
130
|
if (
|
|
170
|
-
!props.horizontal &&
|
|
171
131
|
recyclerViewManager.getIsFirstLayoutComplete() &&
|
|
172
|
-
|
|
173
|
-
|
|
132
|
+
recyclerViewManager.hasStableDataKeys() &&
|
|
133
|
+
currentDataLength > 0 &&
|
|
134
|
+
recyclerViewManager.shouldMaintainVisibleContentPosition()
|
|
174
135
|
) {
|
|
136
|
+
const hasDataChanged = currentDataLength !== lastDataLengthRef.current;
|
|
175
137
|
// If we have a tracked first visible item, maintain its position
|
|
176
138
|
if (firstVisibleItemKey.current) {
|
|
177
|
-
const currentIndexOfFirstVisibleItem =
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
(
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
139
|
+
const currentIndexOfFirstVisibleItem =
|
|
140
|
+
recyclerViewManager
|
|
141
|
+
.getEngagedIndices()
|
|
142
|
+
.findValue(
|
|
143
|
+
(index) =>
|
|
144
|
+
recyclerViewManager.getDataKey(index) ===
|
|
145
|
+
firstVisibleItemKey.current
|
|
146
|
+
) ??
|
|
147
|
+
(hasDataChanged
|
|
148
|
+
? data?.findIndex(
|
|
149
|
+
(item, index) =>
|
|
150
|
+
recyclerViewManager.getDataKey(index) ===
|
|
151
|
+
firstVisibleItemKey.current
|
|
152
|
+
)
|
|
153
|
+
: undefined);
|
|
154
|
+
|
|
155
|
+
if (
|
|
156
|
+
currentIndexOfFirstVisibleItem !== undefined &&
|
|
157
|
+
currentIndexOfFirstVisibleItem >= 0
|
|
158
|
+
) {
|
|
186
159
|
// Calculate the difference in position and apply the offset
|
|
187
|
-
const diff =
|
|
188
|
-
recyclerViewManager.getLayout(currentIndexOfFirstVisibleItem).
|
|
189
|
-
|
|
160
|
+
const diff = horizontal
|
|
161
|
+
? recyclerViewManager.getLayout(currentIndexOfFirstVisibleItem).x -
|
|
162
|
+
firstVisibleItemLayout.current!.x
|
|
163
|
+
: recyclerViewManager.getLayout(currentIndexOfFirstVisibleItem).y -
|
|
164
|
+
firstVisibleItemLayout.current!.y;
|
|
190
165
|
firstVisibleItemLayout.current = {
|
|
191
166
|
...recyclerViewManager.getLayout(currentIndexOfFirstVisibleItem),
|
|
192
167
|
};
|
|
193
|
-
if (
|
|
194
|
-
|
|
195
|
-
|
|
168
|
+
if (
|
|
169
|
+
diff !== 0 &&
|
|
170
|
+
!pauseOffsetCorrection.current &&
|
|
171
|
+
!recyclerViewManager.animationOptimizationsEnabled
|
|
172
|
+
) {
|
|
173
|
+
// console.log("diff", diff, firstVisibleItemKey.current);
|
|
174
|
+
if (PlatformConfig.supportsOffsetCorrection) {
|
|
175
|
+
// console.log("scrollBy", diff);
|
|
176
|
+
scrollAnchorRef.current?.scrollBy(diff);
|
|
177
|
+
} else {
|
|
178
|
+
const scrollToParams = horizontal
|
|
179
|
+
? {
|
|
180
|
+
x: recyclerViewManager.getAbsoluteLastScrollOffset() + diff,
|
|
181
|
+
animated: false,
|
|
182
|
+
}
|
|
183
|
+
: {
|
|
184
|
+
y: recyclerViewManager.getAbsoluteLastScrollOffset() + diff,
|
|
185
|
+
animated: false,
|
|
186
|
+
};
|
|
187
|
+
scrollViewRef.current?.scrollTo(scrollToParams);
|
|
188
|
+
}
|
|
189
|
+
if (hasDataChanged) {
|
|
190
|
+
updateScrollOffsetWithCallback(
|
|
191
|
+
recyclerViewManager.getAbsoluteLastScrollOffset() + diff,
|
|
192
|
+
() => {}
|
|
193
|
+
);
|
|
194
|
+
recyclerViewManager.ignoreScrollEvents = true;
|
|
195
|
+
setTimeout(() => {
|
|
196
|
+
recyclerViewManager.ignoreScrollEvents = false;
|
|
197
|
+
}, 100);
|
|
198
|
+
}
|
|
196
199
|
}
|
|
197
200
|
}
|
|
198
201
|
}
|
|
199
202
|
|
|
200
|
-
|
|
201
|
-
const firstVisibleIndex =
|
|
202
|
-
recyclerViewManager.getVisibleIndices().startIndex;
|
|
203
|
-
if (firstVisibleIndex !== undefined) {
|
|
204
|
-
firstVisibleItemKey.current =
|
|
205
|
-
props.keyExtractor?.(
|
|
206
|
-
props.data![firstVisibleIndex],
|
|
207
|
-
firstVisibleIndex
|
|
208
|
-
) ?? "0";
|
|
209
|
-
firstVisibleItemLayout.current = {
|
|
210
|
-
...recyclerViewManager.getLayout(firstVisibleIndex),
|
|
211
|
-
};
|
|
212
|
-
}
|
|
203
|
+
computeFirstVisibleIndexForOffsetCorrection();
|
|
213
204
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
205
|
+
lastDataLengthRef.current = recyclerViewManager.getDataLength();
|
|
206
|
+
}, [
|
|
207
|
+
recyclerViewManager,
|
|
208
|
+
scrollAnchorRef,
|
|
209
|
+
scrollViewRef,
|
|
210
|
+
setTimeout,
|
|
211
|
+
updateScrollOffsetWithCallback,
|
|
212
|
+
computeFirstVisibleIndexForOffsetCorrection,
|
|
213
|
+
]);
|
|
214
|
+
|
|
215
|
+
const handlerMethods: FlashListRef<T> = useMemo(() => {
|
|
217
216
|
return {
|
|
218
|
-
props
|
|
217
|
+
get props() {
|
|
218
|
+
return recyclerViewManager.props;
|
|
219
|
+
},
|
|
219
220
|
/**
|
|
220
221
|
* Scrolls the list to a specific offset position.
|
|
221
222
|
* Handles RTL layouts and first item offset adjustments.
|
|
@@ -225,14 +226,20 @@ export function useRecyclerViewController<T>(
|
|
|
225
226
|
animated,
|
|
226
227
|
skipFirstItemOffset = true,
|
|
227
228
|
}: ScrollToOffsetParams) => {
|
|
229
|
+
const { horizontal } = recyclerViewManager.props;
|
|
228
230
|
if (scrollViewRef.current) {
|
|
229
231
|
// Adjust offset for RTL layouts in horizontal mode
|
|
230
232
|
if (I18nManager.isRTL && horizontal) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
233
|
+
// eslint-disable-next-line no-param-reassign
|
|
234
|
+
offset =
|
|
235
|
+
adjustOffsetForRTL(
|
|
236
|
+
offset,
|
|
237
|
+
recyclerViewManager.getChildContainerDimensions().width,
|
|
238
|
+
recyclerViewManager.getWindowSize().width
|
|
239
|
+
) +
|
|
240
|
+
(skipFirstItemOffset
|
|
241
|
+
? recyclerViewManager.firstItemOffset
|
|
242
|
+
: -recyclerViewManager.firstItemOffset);
|
|
236
243
|
}
|
|
237
244
|
|
|
238
245
|
// Calculate the final offset including first item offset if needed
|
|
@@ -248,6 +255,9 @@ export function useRecyclerViewController<T>(
|
|
|
248
255
|
});
|
|
249
256
|
}
|
|
250
257
|
},
|
|
258
|
+
clearLayoutCacheOnUpdate: () => {
|
|
259
|
+
recyclerViewManager.markLayoutManagerDirty();
|
|
260
|
+
},
|
|
251
261
|
|
|
252
262
|
// Expose native scroll view methods
|
|
253
263
|
flashScrollIndicators: () => {
|
|
@@ -267,13 +277,19 @@ export function useRecyclerViewController<T>(
|
|
|
267
277
|
* Scrolls to the end of the list.
|
|
268
278
|
*/
|
|
269
279
|
scrollToEnd: async ({ animated }: ScrollToEdgeParams = {}) => {
|
|
280
|
+
const { data } = recyclerViewManager.props;
|
|
270
281
|
if (data && data.length > 0) {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
282
|
+
const lastIndex = data.length - 1;
|
|
283
|
+
if (!recyclerViewManager.getEngagedIndices().includes(lastIndex)) {
|
|
284
|
+
await handlerMethods.scrollToIndex({
|
|
285
|
+
index: lastIndex,
|
|
286
|
+
animated,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
275
289
|
}
|
|
276
|
-
|
|
290
|
+
setTimeout(() => {
|
|
291
|
+
scrollViewRef.current!.scrollToEnd({ animated });
|
|
292
|
+
}, 0);
|
|
277
293
|
},
|
|
278
294
|
|
|
279
295
|
/**
|
|
@@ -289,38 +305,30 @@ export function useRecyclerViewController<T>(
|
|
|
289
305
|
/**
|
|
290
306
|
* Scrolls to a specific index in the list.
|
|
291
307
|
* Supports viewPosition and viewOffset for precise positioning.
|
|
308
|
+
* Returns a Promise that resolves when the scroll is complete.
|
|
292
309
|
*/
|
|
293
|
-
scrollToIndex:
|
|
310
|
+
scrollToIndex: ({
|
|
294
311
|
index,
|
|
295
312
|
animated,
|
|
296
313
|
viewPosition,
|
|
297
314
|
viewOffset,
|
|
298
|
-
}: ScrollToIndexParams) => {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
let finalOffset = 0;
|
|
312
|
-
let attempts = 0;
|
|
313
|
-
const MAX_ATTEMPTS = 5;
|
|
314
|
-
const OFFSET_TOLERANCE = 1; // 1px tolerance
|
|
315
|
-
|
|
316
|
-
do {
|
|
315
|
+
}: ScrollToIndexParams): Promise<void> => {
|
|
316
|
+
return new Promise((resolve) => {
|
|
317
|
+
const { horizontal } = recyclerViewManager.props;
|
|
318
|
+
if (
|
|
319
|
+
scrollViewRef.current &&
|
|
320
|
+
index >= 0 &&
|
|
321
|
+
index < recyclerViewManager.getDataLength()
|
|
322
|
+
) {
|
|
323
|
+
// Pause the scroll offset adjustments
|
|
324
|
+
pauseOffsetCorrection.current = true;
|
|
325
|
+
recyclerViewManager.setOffsetProjectionEnabled(false);
|
|
326
|
+
|
|
327
|
+
const getFinalOffset = () => {
|
|
317
328
|
const layout = recyclerViewManager.getLayout(index);
|
|
318
|
-
if (!layout || isUnmounted.current) break;
|
|
319
|
-
|
|
320
329
|
const offset = horizontal ? layout.x : layout.y;
|
|
321
|
-
finalOffset = offset;
|
|
322
|
-
|
|
323
|
-
// Apply viewPosition and viewOffset adjustments if provided
|
|
330
|
+
let finalOffset = offset;
|
|
331
|
+
// take viewPosition etc into account
|
|
324
332
|
if (viewPosition !== undefined || viewOffset !== undefined) {
|
|
325
333
|
const containerSize = horizontal
|
|
326
334
|
? recyclerViewManager.getWindowSize().width
|
|
@@ -338,77 +346,149 @@ export function useRecyclerViewController<T>(
|
|
|
338
346
|
finalOffset += viewOffset;
|
|
339
347
|
}
|
|
340
348
|
}
|
|
349
|
+
return finalOffset + recyclerViewManager.firstItemOffset;
|
|
350
|
+
};
|
|
351
|
+
const lastAbsoluteScrollOffset =
|
|
352
|
+
recyclerViewManager.getAbsoluteLastScrollOffset();
|
|
353
|
+
const bufferForScroll = horizontal
|
|
354
|
+
? recyclerViewManager.getWindowSize().width
|
|
355
|
+
: recyclerViewManager.getWindowSize().height;
|
|
356
|
+
|
|
357
|
+
const bufferForCompute = bufferForScroll * 2;
|
|
358
|
+
|
|
359
|
+
const getStartScrollOffset = () => {
|
|
360
|
+
let lastScrollOffset = lastAbsoluteScrollOffset;
|
|
361
|
+
const finalOffset = getFinalOffset();
|
|
341
362
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
363
|
+
if (finalOffset > lastScrollOffset) {
|
|
364
|
+
lastScrollOffset = Math.max(
|
|
365
|
+
finalOffset - bufferForCompute,
|
|
366
|
+
lastScrollOffset
|
|
367
|
+
);
|
|
368
|
+
recyclerViewManager.setScrollDirection("forward");
|
|
369
|
+
} else {
|
|
370
|
+
lastScrollOffset = Math.min(
|
|
371
|
+
finalOffset + bufferForCompute,
|
|
372
|
+
lastScrollOffset
|
|
373
|
+
);
|
|
374
|
+
recyclerViewManager.setScrollDirection("backward");
|
|
375
|
+
}
|
|
376
|
+
return lastScrollOffset;
|
|
377
|
+
};
|
|
378
|
+
let initialTargetOffset = getFinalOffset();
|
|
379
|
+
let initialStartScrollOffset = getStartScrollOffset();
|
|
380
|
+
let finalOffset = initialTargetOffset;
|
|
381
|
+
let startScrollOffset = initialStartScrollOffset;
|
|
382
|
+
|
|
383
|
+
const steps = 5;
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Recursively performs the scroll animation steps.
|
|
387
|
+
* This function replaces the async/await loop with callback-based execution.
|
|
388
|
+
*
|
|
389
|
+
* @param currentStep - The current step in the animation (0 to steps-1)
|
|
390
|
+
*/
|
|
391
|
+
const performScrollStep = (currentStep: number) => {
|
|
392
|
+
// Check if component is unmounted or we've completed all steps
|
|
393
|
+
if (isUnmounted.current) {
|
|
394
|
+
resolve();
|
|
395
|
+
return;
|
|
396
|
+
} else if (currentStep >= steps) {
|
|
397
|
+
// All steps completed, perform final scroll
|
|
398
|
+
finishScrollToIndex();
|
|
399
|
+
return;
|
|
345
400
|
}
|
|
346
401
|
|
|
347
|
-
|
|
402
|
+
// Calculate the offset for this step
|
|
403
|
+
// For animated scrolls: interpolate from finalOffset to startScrollOffset
|
|
404
|
+
// For non-animated: interpolate from startScrollOffset to finalOffset
|
|
405
|
+
const nextOffset = animated
|
|
406
|
+
? finalOffset +
|
|
407
|
+
(startScrollOffset - finalOffset) *
|
|
408
|
+
(currentStep / (steps - 1))
|
|
409
|
+
: startScrollOffset +
|
|
410
|
+
(finalOffset - startScrollOffset) *
|
|
411
|
+
(currentStep / (steps - 1));
|
|
412
|
+
|
|
413
|
+
// Update scroll offset with a callback to continue to the next step
|
|
414
|
+
updateScrollOffsetWithCallback(nextOffset, () => {
|
|
415
|
+
// Check if the index is still valid after the update
|
|
416
|
+
if (index >= recyclerViewManager.getDataLength()) {
|
|
417
|
+
// Index out of bounds, scroll to end instead
|
|
418
|
+
handlerMethods.scrollToEnd({ animated });
|
|
419
|
+
resolve(); // Resolve the promise as we're done
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
348
422
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
423
|
+
// Check if the target position has changed significantly
|
|
424
|
+
const newFinalOffset = getFinalOffset();
|
|
425
|
+
if (
|
|
426
|
+
(newFinalOffset < initialTargetOffset &&
|
|
427
|
+
newFinalOffset < initialStartScrollOffset) ||
|
|
428
|
+
(newFinalOffset > initialTargetOffset &&
|
|
429
|
+
newFinalOffset > initialStartScrollOffset)
|
|
430
|
+
) {
|
|
431
|
+
// Target has moved, recalculate and restart from beginning
|
|
432
|
+
finalOffset = newFinalOffset;
|
|
433
|
+
startScrollOffset = getStartScrollOffset();
|
|
434
|
+
initialTargetOffset = newFinalOffset;
|
|
435
|
+
initialStartScrollOffset = startScrollOffset;
|
|
436
|
+
performScrollStep(0); // Restart from step 0
|
|
355
437
|
} else {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
lastScrollOffset
|
|
359
|
-
);
|
|
438
|
+
// Continue to next step
|
|
439
|
+
performScrollStep(currentStep + 1);
|
|
360
440
|
}
|
|
441
|
+
});
|
|
442
|
+
};
|
|
361
443
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
if (animated) {
|
|
370
|
-
const maxOffset =
|
|
371
|
-
(horizontal
|
|
372
|
-
? recyclerViewManager.getChildContainerDimensions().width
|
|
373
|
-
: recyclerViewManager.getChildContainerDimensions().height) -
|
|
374
|
-
(horizontal
|
|
375
|
-
? recyclerViewManager.getWindowSize().width
|
|
376
|
-
: recyclerViewManager.getWindowSize().height);
|
|
444
|
+
/**
|
|
445
|
+
* Completes the scroll to index operation by performing the final scroll
|
|
446
|
+
* and re-enabling offset correction after a delay.
|
|
447
|
+
*/
|
|
448
|
+
const finishScrollToIndex = () => {
|
|
449
|
+
finalOffset = getFinalOffset();
|
|
450
|
+
const maxOffset = recyclerViewManager.getMaxScrollOffset();
|
|
377
451
|
|
|
378
452
|
if (finalOffset > maxOffset) {
|
|
379
453
|
finalOffset = maxOffset;
|
|
380
454
|
}
|
|
381
455
|
|
|
382
|
-
if (
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
lastScrollOffset
|
|
391
|
-
);
|
|
456
|
+
if (animated) {
|
|
457
|
+
// For animated scrolls, first jump to the start position
|
|
458
|
+
// We don't need to add firstItemOffset here as it's already added
|
|
459
|
+
handlerMethods.scrollToOffset({
|
|
460
|
+
offset: startScrollOffset,
|
|
461
|
+
animated: false,
|
|
462
|
+
skipFirstItemOffset: true,
|
|
463
|
+
});
|
|
392
464
|
}
|
|
393
465
|
|
|
394
|
-
//
|
|
466
|
+
// Perform the final scroll to the target position
|
|
395
467
|
handlerMethods.scrollToOffset({
|
|
396
|
-
offset:
|
|
397
|
-
animated
|
|
398
|
-
skipFirstItemOffset:
|
|
468
|
+
offset: finalOffset,
|
|
469
|
+
animated,
|
|
470
|
+
skipFirstItemOffset: true,
|
|
399
471
|
});
|
|
400
|
-
}
|
|
401
472
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
473
|
+
// Re-enable offset correction after a delay
|
|
474
|
+
// Longer delay for animated scrolls to allow animation to complete
|
|
475
|
+
setTimeout(
|
|
476
|
+
() => {
|
|
477
|
+
pauseOffsetCorrection.current = false;
|
|
478
|
+
recyclerViewManager.setOffsetProjectionEnabled(true);
|
|
479
|
+
resolve(); // Resolve the promise after re-enabling corrections
|
|
480
|
+
},
|
|
481
|
+
animated ? 300 : 200
|
|
482
|
+
);
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
// Start the scroll animation process
|
|
486
|
+
performScrollStep(0);
|
|
487
|
+
} else {
|
|
488
|
+
// Invalid parameters, resolve immediately
|
|
489
|
+
resolve();
|
|
407
490
|
}
|
|
408
|
-
|
|
409
|
-
pauseAdjustRef.current = false;
|
|
410
|
-
}, 200);
|
|
411
|
-
}
|
|
491
|
+
});
|
|
412
492
|
},
|
|
413
493
|
|
|
414
494
|
/**
|
|
@@ -421,11 +501,10 @@ export function useRecyclerViewController<T>(
|
|
|
421
501
|
viewPosition,
|
|
422
502
|
viewOffset,
|
|
423
503
|
}: ScrollToItemParams<T>) => {
|
|
504
|
+
const { data } = recyclerViewManager.props;
|
|
424
505
|
if (scrollViewRef.current && data) {
|
|
425
506
|
// Find the index of the item in the data array
|
|
426
|
-
const index =
|
|
427
|
-
(dataItem) => dataItem === item
|
|
428
|
-
);
|
|
507
|
+
const index = data.findIndex((dataItem) => dataItem === item);
|
|
429
508
|
if (index >= 0) {
|
|
430
509
|
handlerMethods.scrollToIndex({
|
|
431
510
|
index,
|
|
@@ -445,7 +524,7 @@ export function useRecyclerViewController<T>(
|
|
|
445
524
|
return recyclerViewManager.getWindowSize();
|
|
446
525
|
},
|
|
447
526
|
getLayout: (index: number) => {
|
|
448
|
-
return recyclerViewManager.
|
|
527
|
+
return recyclerViewManager.tryGetLayout(index);
|
|
449
528
|
},
|
|
450
529
|
getAbsoluteLastScrollOffset: () => {
|
|
451
530
|
return recyclerViewManager.getAbsoluteLastScrollOffset();
|
|
@@ -456,11 +535,11 @@ export function useRecyclerViewController<T>(
|
|
|
456
535
|
recordInteraction: () => {
|
|
457
536
|
recyclerViewManager.recordInteraction();
|
|
458
537
|
},
|
|
459
|
-
|
|
460
|
-
return recyclerViewManager.
|
|
538
|
+
computeVisibleIndices: () => {
|
|
539
|
+
return recyclerViewManager.computeVisibleIndices();
|
|
461
540
|
},
|
|
462
541
|
getFirstVisibleIndex: () => {
|
|
463
|
-
return recyclerViewManager.
|
|
542
|
+
return recyclerViewManager.computeVisibleIndices().startIndex;
|
|
464
543
|
},
|
|
465
544
|
recomputeViewableItems: () => {
|
|
466
545
|
recyclerViewManager.recomputeViewableItems();
|
|
@@ -469,19 +548,79 @@ export function useRecyclerViewController<T>(
|
|
|
469
548
|
* Disables item recycling in preparation for layout animations.
|
|
470
549
|
*/
|
|
471
550
|
prepareForLayoutAnimationRender: () => {
|
|
472
|
-
recyclerViewManager.
|
|
551
|
+
recyclerViewManager.animationOptimizationsEnabled = true;
|
|
473
552
|
},
|
|
474
553
|
};
|
|
475
|
-
}, [
|
|
554
|
+
}, [
|
|
555
|
+
recyclerViewManager,
|
|
556
|
+
scrollViewRef,
|
|
557
|
+
setTimeout,
|
|
558
|
+
isUnmounted,
|
|
559
|
+
updateScrollOffsetWithCallback,
|
|
560
|
+
]);
|
|
561
|
+
|
|
562
|
+
const applyInitialScrollIndex = useCallback(() => {
|
|
563
|
+
const { horizontal, data } = recyclerViewManager.props;
|
|
564
|
+
|
|
565
|
+
const initialScrollIndex =
|
|
566
|
+
recyclerViewManager.getInitialScrollIndex() ?? -1;
|
|
567
|
+
const dataLength = data?.length ?? 0;
|
|
568
|
+
if (
|
|
569
|
+
initialScrollIndex >= 0 &&
|
|
570
|
+
initialScrollIndex < dataLength &&
|
|
571
|
+
!initialScrollCompletedRef.current &&
|
|
572
|
+
recyclerViewManager.getIsFirstLayoutComplete()
|
|
573
|
+
) {
|
|
574
|
+
// Use setTimeout to ensure that we keep trying to scroll on first few renders
|
|
575
|
+
setTimeout(() => {
|
|
576
|
+
initialScrollCompletedRef.current = true;
|
|
577
|
+
pauseOffsetCorrection.current = false;
|
|
578
|
+
}, 100);
|
|
579
|
+
|
|
580
|
+
pauseOffsetCorrection.current = true;
|
|
581
|
+
|
|
582
|
+
const offset = horizontal
|
|
583
|
+
? recyclerViewManager.getLayout(initialScrollIndex).x
|
|
584
|
+
: recyclerViewManager.getLayout(initialScrollIndex).y;
|
|
585
|
+
handlerMethods.scrollToOffset({
|
|
586
|
+
offset,
|
|
587
|
+
animated: false,
|
|
588
|
+
skipFirstItemOffset: false,
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
setTimeout(() => {
|
|
592
|
+
handlerMethods.scrollToOffset({
|
|
593
|
+
offset,
|
|
594
|
+
animated: false,
|
|
595
|
+
skipFirstItemOffset: false,
|
|
596
|
+
});
|
|
597
|
+
}, 0);
|
|
598
|
+
}
|
|
599
|
+
}, [handlerMethods, recyclerViewManager, setTimeout]);
|
|
476
600
|
|
|
477
601
|
// Expose imperative methods through the ref
|
|
478
602
|
useImperativeHandle(
|
|
479
603
|
ref,
|
|
480
604
|
() => {
|
|
481
|
-
|
|
605
|
+
const imperativeApi = { ...scrollViewRef.current, ...handlerMethods };
|
|
606
|
+
// Without this the props getter from handlerMethods is evaluated during spread and
|
|
607
|
+
// future updates to props are not reflected in the ref
|
|
608
|
+
Object.defineProperty(imperativeApi, "props", {
|
|
609
|
+
get() {
|
|
610
|
+
return recyclerViewManager.props;
|
|
611
|
+
},
|
|
612
|
+
enumerable: true,
|
|
613
|
+
configurable: true,
|
|
614
|
+
});
|
|
615
|
+
return imperativeApi;
|
|
482
616
|
},
|
|
483
|
-
[handlerMethods]
|
|
617
|
+
[handlerMethods, scrollViewRef, recyclerViewManager]
|
|
484
618
|
);
|
|
485
619
|
|
|
486
|
-
return {
|
|
620
|
+
return {
|
|
621
|
+
applyOffsetCorrection,
|
|
622
|
+
computeFirstVisibleIndexForOffsetCorrection,
|
|
623
|
+
applyInitialScrollIndex,
|
|
624
|
+
handlerMethods,
|
|
625
|
+
};
|
|
487
626
|
}
|