react-native-nitro-list 0.1.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.
- package/ios/HybridNitroList.swift +10 -14
- package/lib/commonjs/cell/CellKeyGenerator.js +21 -0
- package/lib/commonjs/cell/CellKeyGenerator.js.map +1 -0
- package/lib/commonjs/cell/CellRecycler.js +48 -40
- package/lib/commonjs/cell/CellRecycler.js.map +1 -1
- package/lib/commonjs/cell/createCell.js +21 -0
- package/lib/commonjs/cell/createCell.js.map +1 -0
- package/lib/commonjs/cell/index.js +20 -0
- package/lib/commonjs/cell/index.js.map +1 -0
- package/lib/commonjs/getVisibleIndices.js.map +1 -1
- package/lib/commonjs/hooks/usePersistentCallback.js +36 -0
- package/lib/commonjs/hooks/usePersistentCallback.js.map +1 -0
- package/lib/commonjs/index.js +1 -1
- package/lib/commonjs/layout/MutableLinearLayout.js +78 -39
- package/lib/commonjs/layout/MutableLinearLayout.js.map +1 -1
- package/lib/commonjs/layout/constants/layoutDefaults.js +19 -0
- package/lib/commonjs/layout/constants/layoutDefaults.js.map +1 -0
- package/lib/commonjs/layout/index.js +0 -18
- package/lib/commonjs/layout/index.js.map +1 -1
- package/lib/commonjs/recycler/CellPool.js +46 -0
- package/lib/commonjs/recycler/CellPool.js.map +1 -0
- package/lib/commonjs/recycler/RecyclerList.js +224 -0
- package/lib/commonjs/recycler/RecyclerList.js.map +1 -0
- package/lib/commonjs/types/Axis.js +2 -0
- package/lib/commonjs/{layout/LayoutProvider.js.map → types/Axis.js.map} +1 -1
- package/lib/commonjs/types/CellKey.js +2 -0
- package/lib/{module/layout/LayoutProvider.js.map → commonjs/types/CellKey.js.map} +1 -1
- package/lib/commonjs/types/CellType.js +2 -0
- package/lib/commonjs/{layout/LayoutRectangle.js.map → types/CellType.js.map} +1 -1
- package/lib/commonjs/types/VisibleRange.js +2 -0
- package/lib/{module/layout/LayoutRectangle.js.map → commonjs/types/VisibleRange.js.map} +1 -1
- package/lib/commonjs/{RecyclerList.types.js → types/VisibleRangeInput.js} +1 -1
- package/lib/commonjs/types/VisibleRangeInput.js.map +1 -0
- package/lib/commonjs/types/index.js +13 -0
- package/lib/commonjs/types/index.js.map +1 -0
- package/lib/commonjs/types/layout/LayoutRect.js +2 -0
- package/lib/commonjs/types/layout/LayoutRect.js.map +1 -0
- package/lib/commonjs/types/layout/LinearLayoutInput.js +6 -0
- package/lib/commonjs/types/layout/LinearLayoutInput.js.map +1 -0
- package/lib/commonjs/types/layout/MainAxisPadding.js +26 -0
- package/lib/commonjs/types/layout/MainAxisPadding.js.map +1 -0
- package/lib/commonjs/types/layout/index.js +2 -0
- package/lib/commonjs/types/layout/index.js.map +1 -0
- package/lib/commonjs/types/recycler/RecyclerCellInstance.js +6 -0
- package/lib/commonjs/types/recycler/RecyclerCellInstance.js.map +1 -0
- package/lib/commonjs/types/recycler/RecyclerItemRenderer.js +6 -0
- package/lib/commonjs/types/recycler/RecyclerItemRenderer.js.map +1 -0
- package/lib/commonjs/types/recycler/RecyclerListProps.js +6 -0
- package/lib/commonjs/types/recycler/RecyclerListProps.js.map +1 -0
- package/lib/commonjs/types/recycler/index.js +2 -0
- package/lib/commonjs/types/recycler/index.js.map +1 -0
- package/lib/commonjs/{layout/LayoutProvider.js → types/scroll/ScrollMetrics.js} +1 -1
- package/lib/commonjs/types/scroll/ScrollMetrics.js.map +1 -0
- package/lib/commonjs/types/scroll/index.js +2 -0
- package/lib/commonjs/types/scroll/index.js.map +1 -0
- package/lib/commonjs/windowing/computeVisibleItemRange.js +71 -0
- package/lib/commonjs/windowing/computeVisibleItemRange.js.map +1 -0
- package/lib/commonjs/windowing/index.js +3 -3
- package/lib/commonjs/windowing/index.js.map +1 -1
- package/lib/module/cell/CellKeyGenerator.js +16 -0
- package/lib/module/cell/CellKeyGenerator.js.map +1 -0
- package/lib/module/cell/CellRecycler.js +48 -39
- package/lib/module/cell/CellRecycler.js.map +1 -1
- package/lib/module/cell/createCell.js +17 -0
- package/lib/module/cell/createCell.js.map +1 -0
- package/lib/module/cell/index.js +7 -0
- package/lib/module/cell/index.js.map +1 -0
- package/lib/module/getVisibleIndices.js.map +1 -1
- package/lib/module/hooks/usePersistentCallback.js +33 -0
- package/lib/module/hooks/usePersistentCallback.js.map +1 -0
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/layout/MutableLinearLayout.js +78 -38
- package/lib/module/layout/MutableLinearLayout.js.map +1 -1
- package/lib/module/layout/constants/layoutDefaults.js +15 -0
- package/lib/module/layout/constants/layoutDefaults.js.map +1 -0
- package/lib/module/layout/index.js +0 -3
- package/lib/module/layout/index.js.map +1 -1
- package/lib/module/recycler/CellPool.js +41 -0
- package/lib/module/recycler/CellPool.js.map +1 -0
- package/lib/module/recycler/RecyclerList.js +221 -0
- package/lib/module/recycler/RecyclerList.js.map +1 -0
- package/lib/module/types/Axis.js +2 -0
- package/lib/module/types/Axis.js.map +1 -0
- package/lib/module/types/CellKey.js +2 -0
- package/lib/module/types/CellKey.js.map +1 -0
- package/lib/module/types/CellType.js +2 -0
- package/lib/module/types/CellType.js.map +1 -0
- package/lib/module/types/VisibleRange.js +2 -0
- package/lib/module/types/VisibleRange.js.map +1 -0
- package/lib/module/types/VisibleRangeInput.js +4 -0
- package/lib/module/types/VisibleRangeInput.js.map +1 -0
- package/lib/module/types/index.js +4 -0
- package/lib/module/types/index.js.map +1 -0
- package/lib/module/types/layout/LayoutRect.js +2 -0
- package/lib/module/types/layout/LayoutRect.js.map +1 -0
- package/lib/module/types/layout/LinearLayoutInput.js +4 -0
- package/lib/module/types/layout/LinearLayoutInput.js.map +1 -0
- package/lib/module/types/layout/MainAxisPadding.js +22 -0
- package/lib/module/types/layout/MainAxisPadding.js.map +1 -0
- package/lib/module/types/layout/index.js +2 -0
- package/lib/module/types/layout/index.js.map +1 -0
- package/lib/module/types/recycler/RecyclerCellInstance.js +4 -0
- package/lib/module/types/recycler/RecyclerCellInstance.js.map +1 -0
- package/lib/module/types/recycler/RecyclerItemRenderer.js +4 -0
- package/lib/module/types/recycler/RecyclerItemRenderer.js.map +1 -0
- package/lib/module/types/recycler/RecyclerListProps.js +4 -0
- package/lib/module/types/recycler/RecyclerListProps.js.map +1 -0
- package/lib/module/types/recycler/index.js +2 -0
- package/lib/module/types/recycler/index.js.map +1 -0
- package/lib/module/types/scroll/ScrollMetrics.js +4 -0
- package/lib/module/types/scroll/ScrollMetrics.js.map +1 -0
- package/lib/module/types/scroll/index.js +2 -0
- package/lib/module/types/scroll/index.js.map +1 -0
- package/lib/module/windowing/computeVisibleItemRange.js +67 -0
- package/lib/module/windowing/computeVisibleItemRange.js.map +1 -0
- package/lib/module/windowing/index.js +1 -1
- package/lib/module/windowing/index.js.map +1 -1
- package/lib/typescript/src/cell/Cell.d.ts +13 -4
- package/lib/typescript/src/cell/Cell.d.ts.map +1 -1
- package/lib/typescript/src/cell/CellKeyGenerator.d.ts +11 -0
- package/lib/typescript/src/cell/CellKeyGenerator.d.ts.map +1 -0
- package/lib/typescript/src/cell/CellRecycler.d.ts +19 -11
- package/lib/typescript/src/cell/CellRecycler.d.ts.map +1 -1
- package/lib/typescript/src/cell/createCell.d.ts +7 -0
- package/lib/typescript/src/cell/createCell.d.ts.map +1 -0
- package/lib/typescript/src/cell/index.d.ts +4 -0
- package/lib/typescript/src/cell/index.d.ts.map +1 -0
- package/lib/typescript/src/getVisibleIndices.d.ts +2 -2
- package/lib/typescript/src/getVisibleIndices.d.ts.map +1 -1
- package/lib/typescript/src/hooks/usePersistentCallback.d.ts +16 -0
- package/lib/typescript/src/hooks/usePersistentCallback.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +1 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/layout/MutableLinearLayout.d.ts +45 -13
- package/lib/typescript/src/layout/MutableLinearLayout.d.ts.map +1 -1
- package/lib/typescript/src/layout/constants/layoutDefaults.d.ts +13 -0
- package/lib/typescript/src/layout/constants/layoutDefaults.d.ts.map +1 -0
- package/lib/typescript/src/layout/index.d.ts +1 -4
- package/lib/typescript/src/layout/index.d.ts.map +1 -1
- package/lib/typescript/src/native/NitroList.types.d.ts +2 -2
- package/lib/typescript/src/native/NitroList.types.d.ts.map +1 -1
- package/lib/typescript/src/recycler/CellPool.d.ts +14 -0
- package/lib/typescript/src/recycler/CellPool.d.ts.map +1 -0
- package/lib/typescript/src/recycler/RecyclerList.d.ts +4 -0
- package/lib/typescript/src/recycler/RecyclerList.d.ts.map +1 -0
- package/lib/typescript/src/specs/nitro-layout-engine.nitro.d.ts +2 -2
- package/lib/typescript/src/specs/nitro-layout-engine.nitro.d.ts.map +1 -1
- package/lib/typescript/src/types/Axis.d.ts +11 -0
- package/lib/typescript/src/types/Axis.d.ts.map +1 -0
- package/lib/typescript/src/types/CellKey.d.ts +10 -0
- package/lib/typescript/src/types/CellKey.d.ts.map +1 -0
- package/lib/typescript/src/types/CellType.d.ts +11 -0
- package/lib/typescript/src/types/CellType.d.ts.map +1 -0
- package/lib/typescript/src/types/VisibleRange.d.ts +10 -0
- package/lib/typescript/src/types/VisibleRange.d.ts.map +1 -0
- package/lib/typescript/src/types/VisibleRangeInput.d.ts +35 -0
- package/lib/typescript/src/types/VisibleRangeInput.d.ts.map +1 -0
- package/lib/typescript/src/types/index.d.ts +8 -0
- package/lib/typescript/src/types/index.d.ts.map +1 -0
- package/lib/typescript/src/types/layout/LayoutRect.d.ts +15 -0
- package/lib/typescript/src/types/layout/LayoutRect.d.ts.map +1 -0
- package/lib/typescript/src/types/layout/LinearLayoutInput.d.ts +10 -0
- package/lib/typescript/src/types/layout/LinearLayoutInput.d.ts.map +1 -0
- package/lib/typescript/src/types/layout/MainAxisPadding.d.ts +20 -0
- package/lib/typescript/src/types/layout/MainAxisPadding.d.ts.map +1 -0
- package/lib/typescript/src/types/layout/index.d.ts +4 -0
- package/lib/typescript/src/types/layout/index.d.ts.map +1 -0
- package/lib/typescript/src/types/recycler/RecyclerCellInstance.d.ts +37 -0
- package/lib/typescript/src/types/recycler/RecyclerCellInstance.d.ts.map +1 -0
- package/lib/typescript/src/types/recycler/RecyclerItemRenderer.d.ts +8 -0
- package/lib/typescript/src/types/recycler/RecyclerItemRenderer.d.ts.map +1 -0
- package/lib/typescript/src/types/recycler/RecyclerListProps.d.ts +66 -0
- package/lib/typescript/src/types/recycler/RecyclerListProps.d.ts.map +1 -0
- package/lib/typescript/src/types/recycler/index.d.ts +4 -0
- package/lib/typescript/src/types/recycler/index.d.ts.map +1 -0
- package/lib/typescript/src/types/scroll/ScrollMetrics.d.ts +15 -0
- package/lib/typescript/src/types/scroll/ScrollMetrics.d.ts.map +1 -0
- package/lib/typescript/src/types/scroll/index.d.ts +2 -0
- package/lib/typescript/src/types/scroll/index.d.ts.map +1 -0
- package/lib/typescript/src/windowing/computeVisibleItemRange.d.ts +15 -0
- package/lib/typescript/src/windowing/computeVisibleItemRange.d.ts.map +1 -0
- package/lib/typescript/src/windowing/index.d.ts +1 -1
- package/lib/typescript/src/windowing/index.d.ts.map +1 -1
- package/nitrogen/generated/android/c++/JHybridNitroLayoutEngineSpec.cpp +7 -7
- package/nitrogen/generated/android/c++/JHybridNitroLayoutEngineSpec.hpp +1 -1
- package/nitrogen/generated/android/c++/{JLayoutRectangle.hpp → JLayoutRect.hpp} +10 -10
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrolist/HybridNitroLayoutEngineSpec.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrolist/{LayoutRectangle.kt → LayoutRect.kt} +5 -5
- package/nitrogen/generated/ios/NitroList-Swift-Cxx-Bridge.hpp +14 -14
- package/nitrogen/generated/ios/NitroList-Swift-Cxx-Umbrella.hpp +3 -3
- package/nitrogen/generated/ios/c++/HybridNitroLayoutEngineSpecSwift.hpp +4 -4
- package/nitrogen/generated/ios/swift/HybridNitroLayoutEngineSpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridNitroLayoutEngineSpec_cxx.swift +5 -5
- package/nitrogen/generated/ios/swift/{LayoutRectangle.swift → LayoutRect.swift} +5 -5
- package/nitrogen/generated/shared/c++/HybridNitroLayoutEngineSpec.hpp +4 -4
- package/nitrogen/generated/shared/c++/{LayoutRectangle.hpp → LayoutRect.hpp} +11 -11
- package/package.json +1 -1
- package/src/cell/Cell.ts +13 -4
- package/src/cell/CellKeyGenerator.ts +17 -0
- package/src/cell/CellRecycler.ts +53 -43
- package/src/cell/createCell.ts +15 -0
- package/src/cell/index.ts +5 -0
- package/src/getVisibleIndices.ts +4 -2
- package/src/hooks/usePersistentCallback.ts +37 -0
- package/src/index.ts +1 -2
- package/src/layout/MutableLinearLayout.ts +91 -58
- package/src/layout/constants/layoutDefaults.ts +12 -0
- package/src/layout/index.ts +1 -4
- package/src/native/NitroList.types.ts +3 -2
- package/src/recycler/CellPool.ts +47 -0
- package/src/recycler/RecyclerList.tsx +304 -0
- package/src/specs/nitro-layout-engine.nitro.ts +2 -2
- package/src/types/Axis.ts +10 -0
- package/src/types/CellKey.ts +9 -0
- package/src/types/CellType.ts +10 -0
- package/src/types/VisibleRange.ts +9 -0
- package/src/types/VisibleRangeInput.ts +39 -0
- package/src/types/index.ts +15 -0
- package/src/types/layout/LayoutRect.ts +14 -0
- package/src/types/layout/LinearLayoutInput.ts +12 -0
- package/src/types/layout/MainAxisPadding.ts +23 -0
- package/src/types/layout/index.ts +3 -0
- package/src/types/recycler/RecyclerCellInstance.ts +40 -0
- package/src/types/recycler/RecyclerItemRenderer.ts +8 -0
- package/src/types/recycler/RecyclerListProps.ts +74 -0
- package/src/types/recycler/index.ts +3 -0
- package/src/types/scroll/ScrollMetrics.ts +18 -0
- package/src/types/scroll/index.ts +1 -0
- package/src/windowing/computeVisibleItemRange.ts +78 -0
- package/src/windowing/index.ts +1 -1
- package/lib/commonjs/RecyclerList.internal.js +0 -25
- package/lib/commonjs/RecyclerList.internal.js.map +0 -1
- package/lib/commonjs/RecyclerList.js +0 -171
- package/lib/commonjs/RecyclerList.js.map +0 -1
- package/lib/commonjs/RecyclerList.types.js.map +0 -1
- package/lib/commonjs/cell/StableKey.js +0 -10
- package/lib/commonjs/cell/StableKey.js.map +0 -1
- package/lib/commonjs/hooks/useCellRenderer.js +0 -62
- package/lib/commonjs/hooks/useCellRenderer.js.map +0 -1
- package/lib/commonjs/hooks/useStableCallback.js +0 -13
- package/lib/commonjs/hooks/useStableCallback.js.map +0 -1
- package/lib/commonjs/layout/EstimatedLayoutProvider.js +0 -30
- package/lib/commonjs/layout/EstimatedLayoutProvider.js.map +0 -1
- package/lib/commonjs/layout/LayoutEngine.js +0 -21
- package/lib/commonjs/layout/LayoutEngine.js.map +0 -1
- package/lib/commonjs/layout/LayoutRectangle.js +0 -2
- package/lib/commonjs/viewability/ViewabilityHelper.js +0 -121
- package/lib/commonjs/viewability/ViewabilityHelper.js.map +0 -1
- package/lib/commonjs/windowing/findVisibleIndexRange.js +0 -48
- package/lib/commonjs/windowing/findVisibleIndexRange.js.map +0 -1
- package/lib/module/RecyclerList.internal.js +0 -22
- package/lib/module/RecyclerList.internal.js.map +0 -1
- package/lib/module/RecyclerList.js +0 -166
- package/lib/module/RecyclerList.js.map +0 -1
- package/lib/module/RecyclerList.types.js +0 -4
- package/lib/module/RecyclerList.types.js.map +0 -1
- package/lib/module/cell/StableKey.js +0 -6
- package/lib/module/cell/StableKey.js.map +0 -1
- package/lib/module/hooks/useCellRenderer.js +0 -58
- package/lib/module/hooks/useCellRenderer.js.map +0 -1
- package/lib/module/hooks/useStableCallback.js +0 -9
- package/lib/module/hooks/useStableCallback.js.map +0 -1
- package/lib/module/layout/EstimatedLayoutProvider.js +0 -25
- package/lib/module/layout/EstimatedLayoutProvider.js.map +0 -1
- package/lib/module/layout/LayoutEngine.js +0 -17
- package/lib/module/layout/LayoutEngine.js.map +0 -1
- package/lib/module/layout/LayoutProvider.js +0 -4
- package/lib/module/layout/LayoutRectangle.js +0 -2
- package/lib/module/viewability/ViewabilityHelper.js +0 -116
- package/lib/module/viewability/ViewabilityHelper.js.map +0 -1
- package/lib/module/windowing/findVisibleIndexRange.js +0 -44
- package/lib/module/windowing/findVisibleIndexRange.js.map +0 -1
- package/lib/typescript/src/RecyclerList.d.ts +0 -26
- package/lib/typescript/src/RecyclerList.d.ts.map +0 -1
- package/lib/typescript/src/RecyclerList.internal.d.ts +0 -9
- package/lib/typescript/src/RecyclerList.internal.d.ts.map +0 -1
- package/lib/typescript/src/RecyclerList.types.d.ts +0 -18
- package/lib/typescript/src/RecyclerList.types.d.ts.map +0 -1
- package/lib/typescript/src/__tests__/windowing/findVisibleIndexRange.test.d.ts +0 -2
- package/lib/typescript/src/__tests__/windowing/findVisibleIndexRange.test.d.ts.map +0 -1
- package/lib/typescript/src/cell/StableKey.d.ts +0 -2
- package/lib/typescript/src/cell/StableKey.d.ts.map +0 -1
- package/lib/typescript/src/hooks/useCellRenderer.d.ts +0 -19
- package/lib/typescript/src/hooks/useCellRenderer.d.ts.map +0 -1
- package/lib/typescript/src/hooks/useStableCallback.d.ts +0 -2
- package/lib/typescript/src/hooks/useStableCallback.d.ts.map +0 -1
- package/lib/typescript/src/layout/EstimatedLayoutProvider.d.ts +0 -15
- package/lib/typescript/src/layout/EstimatedLayoutProvider.d.ts.map +0 -1
- package/lib/typescript/src/layout/LayoutEngine.d.ts +0 -10
- package/lib/typescript/src/layout/LayoutEngine.d.ts.map +0 -1
- package/lib/typescript/src/layout/LayoutProvider.d.ts +0 -16
- package/lib/typescript/src/layout/LayoutProvider.d.ts.map +0 -1
- package/lib/typescript/src/layout/LayoutRectangle.d.ts +0 -11
- package/lib/typescript/src/layout/LayoutRectangle.d.ts.map +0 -1
- package/lib/typescript/src/viewability/ViewabilityHelper.d.ts +0 -50
- package/lib/typescript/src/viewability/ViewabilityHelper.d.ts.map +0 -1
- package/lib/typescript/src/windowing/findVisibleIndexRange.d.ts +0 -11
- package/lib/typescript/src/windowing/findVisibleIndexRange.d.ts.map +0 -1
- package/src/RecyclerList.internal.ts +0 -38
- package/src/RecyclerList.tsx +0 -252
- package/src/RecyclerList.types.ts +0 -24
- package/src/__tests__/windowing/findVisibleIndexRange.test.ts +0 -55
- package/src/cell/StableKey.ts +0 -6
- package/src/hooks/useCellRenderer.ts +0 -86
- package/src/hooks/useStableCallback.ts +0 -13
- package/src/layout/EstimatedLayoutProvider.ts +0 -35
- package/src/layout/LayoutEngine.ts +0 -21
- package/src/layout/LayoutProvider.ts +0 -17
- package/src/layout/LayoutRectangle.ts +0 -10
- package/src/viewability/ViewabilityHelper.ts +0 -130
- package/src/windowing/findVisibleIndexRange.ts +0 -60
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { findVisibleIndexRange } from '../../windowing/findVisibleIndexRange'
|
|
2
|
-
|
|
3
|
-
describe('findVisibleIndexRange', () => {
|
|
4
|
-
/**
|
|
5
|
-
* Layouts:
|
|
6
|
-
* index 0 → y: 0–50
|
|
7
|
-
* index 1 → y: 50–100
|
|
8
|
-
* index 2 → y: 100–150
|
|
9
|
-
* ...
|
|
10
|
-
*/
|
|
11
|
-
const layouts = Array.from({ length: 10 }, (_, i) => ({
|
|
12
|
-
x: 0,
|
|
13
|
-
y: i * 50,
|
|
14
|
-
width: 100,
|
|
15
|
-
height: 50,
|
|
16
|
-
}))
|
|
17
|
-
|
|
18
|
-
it('returns empty array when layouts are empty', () => {
|
|
19
|
-
const result = findVisibleIndexRange([], { offsetY: 0, height: 300 }, 100)
|
|
20
|
-
|
|
21
|
-
expect(result).toEqual([])
|
|
22
|
-
})
|
|
23
|
-
it('returns correct visible indices without buffer', () => {
|
|
24
|
-
const result = findVisibleIndexRange(
|
|
25
|
-
layouts,
|
|
26
|
-
{ offsetY: 100, height: 150 },
|
|
27
|
-
0
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Viewport: 100–250 (inclusive)
|
|
32
|
-
* Items that intersect this window:
|
|
33
|
-
* indices 1–5
|
|
34
|
-
*/
|
|
35
|
-
expect(result).toEqual([1, 2, 3, 4, 5])
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
it('extends window using bufferPx (inclusive boundaries)', () => {
|
|
39
|
-
const result = findVisibleIndexRange(
|
|
40
|
-
layouts,
|
|
41
|
-
{ offsetY: 100, height: 100 },
|
|
42
|
-
100
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Viewport: 100–200
|
|
47
|
-
* Buffer: ±100
|
|
48
|
-
* Effective win: 0–300 (inclusive)
|
|
49
|
-
*
|
|
50
|
-
* index 6 starts at y = 300 → included by design
|
|
51
|
-
* This matches FlashList / RecyclerView behavior
|
|
52
|
-
*/
|
|
53
|
-
expect(result).toEqual([0, 1, 2, 3, 4, 5, 6])
|
|
54
|
-
})
|
|
55
|
-
})
|
package/src/cell/StableKey.ts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { useEffect, useMemo, useRef, useState } from 'react'
|
|
2
|
-
import type { Cell } from '../cell/Cell'
|
|
3
|
-
import { CellRecycler } from '../cell/CellRecycler'
|
|
4
|
-
import { findVisibleIndexRange } from '../windowing/findVisibleIndexRange'
|
|
5
|
-
import type { LayoutRectangle } from '../layout/LayoutRectangle'
|
|
6
|
-
import type { ScrollMetrics } from '../windowing/ScrollMetrics'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* 🔒 Stable empty references (module-level)
|
|
10
|
-
* These MUST NOT be recreated per render.
|
|
11
|
-
*/
|
|
12
|
-
const EMPTY_INDICES: readonly number[] = []
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* React bridge for CellRecycler.
|
|
16
|
-
* FlashList equivalent: useCellRenderer
|
|
17
|
-
*
|
|
18
|
-
* Responsibilities:
|
|
19
|
-
* - Translate scroll state → visible indices
|
|
20
|
-
* - Ask recycler for physical cells
|
|
21
|
-
* - Commit results with referential stability
|
|
22
|
-
*
|
|
23
|
-
* Responsibilities it does NOT have:
|
|
24
|
-
* ❌ Layout mutation
|
|
25
|
-
* ❌ Measurement
|
|
26
|
-
* ❌ Rendering
|
|
27
|
-
*/
|
|
28
|
-
export function useCellRenderer(
|
|
29
|
-
layouts: readonly LayoutRectangle[],
|
|
30
|
-
metrics: ScrollMetrics,
|
|
31
|
-
bufferPx: number,
|
|
32
|
-
getCellType: (index: number) => string
|
|
33
|
-
): readonly Cell[] {
|
|
34
|
-
/**
|
|
35
|
-
* Recycler instance is stable across renders.
|
|
36
|
-
*/
|
|
37
|
-
const recyclerRef = useRef<CellRecycler>(new CellRecycler())
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Compute visible indices.
|
|
41
|
-
* PURE + TOTAL:
|
|
42
|
-
* - Never throws
|
|
43
|
-
* - Always returns the same reference when empty
|
|
44
|
-
*/
|
|
45
|
-
const visibleIndices = useMemo(
|
|
46
|
-
() =>
|
|
47
|
-
layouts.length === 0
|
|
48
|
-
? EMPTY_INDICES
|
|
49
|
-
: findVisibleIndexRange(
|
|
50
|
-
layouts,
|
|
51
|
-
metrics,
|
|
52
|
-
bufferPx
|
|
53
|
-
),
|
|
54
|
-
[layouts, metrics.offsetY, metrics.height, bufferPx]
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Physical cells to render.
|
|
59
|
-
*/
|
|
60
|
-
const [cells, setCells] =
|
|
61
|
-
useState<readonly Cell[]>([])
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Reconcile visible indices → physical cells.
|
|
65
|
-
*
|
|
66
|
-
* FlashList invariant:
|
|
67
|
-
* - Only update state if identity truly changed
|
|
68
|
-
* - Prevents pointless re-renders
|
|
69
|
-
*/
|
|
70
|
-
useEffect(() => {
|
|
71
|
-
const next =
|
|
72
|
-
recyclerRef.current.reconcile(
|
|
73
|
-
visibleIndices,
|
|
74
|
-
getCellType
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
setCells(prev =>
|
|
78
|
-
prev.length === next.length &&
|
|
79
|
-
prev.every((c, i) => c === next[i])
|
|
80
|
-
? prev
|
|
81
|
-
: next
|
|
82
|
-
)
|
|
83
|
-
}, [visibleIndices, getCellType])
|
|
84
|
-
|
|
85
|
-
return cells
|
|
86
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { useRef, useCallback } from 'react'
|
|
2
|
-
|
|
3
|
-
export function useStableCallback<T extends (...args: never[]) => unknown>(
|
|
4
|
-
fn: T
|
|
5
|
-
): T {
|
|
6
|
-
const ref = useRef(fn)
|
|
7
|
-
ref.current = fn
|
|
8
|
-
|
|
9
|
-
return useCallback(
|
|
10
|
-
((...args: never[]) => ref.current(...args)) as T,
|
|
11
|
-
[]
|
|
12
|
-
)
|
|
13
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { LayoutProvider } from './LayoutProvider'
|
|
2
|
-
import type { LayoutRectangle } from './LayoutRectangle'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Layout provider using estimated item heights.
|
|
6
|
-
* Used before real measurements are available.
|
|
7
|
-
*/
|
|
8
|
-
export class EstimatedLayoutProvider implements LayoutProvider {
|
|
9
|
-
private readonly itemCount: number
|
|
10
|
-
private readonly itemHeight: number
|
|
11
|
-
private readonly width: number
|
|
12
|
-
|
|
13
|
-
constructor(
|
|
14
|
-
itemCount: number,
|
|
15
|
-
itemHeight: number,
|
|
16
|
-
width: number
|
|
17
|
-
) {
|
|
18
|
-
this.itemCount = itemCount
|
|
19
|
-
this.itemHeight = itemHeight
|
|
20
|
-
this.width = width
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
getItemCount(): number {
|
|
24
|
-
return this.itemCount
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
getLayout(index: number): LayoutRectangle {
|
|
28
|
-
return {
|
|
29
|
-
x: 0,
|
|
30
|
-
y: index * this.itemHeight,
|
|
31
|
-
width: this.width,
|
|
32
|
-
height: this.itemHeight,
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { LayoutProvider } from './LayoutProvider'
|
|
2
|
-
import type { LayoutRectangle } from './LayoutRectangle'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Resolves layouts eagerly into a contiguous array.
|
|
6
|
-
* Pure, deterministic, and reusable.
|
|
7
|
-
*
|
|
8
|
-
* FlashList equivalent: internal layout resolver.
|
|
9
|
-
*/
|
|
10
|
-
export function computeLayouts(
|
|
11
|
-
provider: LayoutProvider
|
|
12
|
-
): readonly LayoutRectangle[] {
|
|
13
|
-
const count = provider.getItemCount()
|
|
14
|
-
const layouts: LayoutRectangle[] = new Array(count)
|
|
15
|
-
|
|
16
|
-
for (let i = 0; i < count; i++) {
|
|
17
|
-
layouts[i] = provider.getLayout(i)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return layouts
|
|
21
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { LayoutRectangle } from './LayoutRectangle'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Provides layout information for items.
|
|
5
|
-
* FlashList equivalent: LayoutProvider
|
|
6
|
-
*/
|
|
7
|
-
export interface LayoutProvider {
|
|
8
|
-
/**
|
|
9
|
-
* Total number of items
|
|
10
|
-
*/
|
|
11
|
-
getItemCount(): number
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Layout rectangle for a given index
|
|
15
|
-
*/
|
|
16
|
-
getLayout(index: number): LayoutRectangle
|
|
17
|
-
}
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import type { LayoutRectangle } from '../layout/LayoutRectangle'
|
|
2
|
-
import type { ScrollMetrics } from '../windowing/ScrollMetrics'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Public token describing viewability state of an item.
|
|
6
|
-
* Mirrors FlashList's ViewToken concept.
|
|
7
|
-
*/
|
|
8
|
-
export type ViewToken = {
|
|
9
|
-
index: number
|
|
10
|
-
isViewable: boolean
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Configuration for viewability calculations.
|
|
15
|
-
*/
|
|
16
|
-
export type ViewabilityConfig = {
|
|
17
|
-
/**
|
|
18
|
-
* Percentage (0–100) of item height that must be visible
|
|
19
|
-
* for the item to be considered "viewable".
|
|
20
|
-
*/
|
|
21
|
-
itemVisiblePercentThreshold?: number
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* ViewabilityHelper
|
|
26
|
-
*
|
|
27
|
-
* Pure observer:
|
|
28
|
-
* - Does NOT affect layout
|
|
29
|
-
* - Does NOT affect recycling
|
|
30
|
-
* - Computes visibility based on layout + scroll metrics
|
|
31
|
-
*
|
|
32
|
-
* This class is intentionally stateful (lastVisible)
|
|
33
|
-
* to compute "changed" items efficiently.
|
|
34
|
-
*/
|
|
35
|
-
export class ViewabilityHelper {
|
|
36
|
-
/** Previously visible indices */
|
|
37
|
-
private lastVisible = new Set<number>()
|
|
38
|
-
|
|
39
|
-
constructor(
|
|
40
|
-
private readonly config: ViewabilityConfig = {}
|
|
41
|
-
) {}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Computes which items are viewable and which changed
|
|
45
|
-
* since the last invocation.
|
|
46
|
-
*
|
|
47
|
-
* IMPORTANT:
|
|
48
|
-
* - This method should be called AFTER windowing,
|
|
49
|
-
* not on the full dataset.
|
|
50
|
-
*/
|
|
51
|
-
computeViewableItems(
|
|
52
|
-
layouts: readonly LayoutRectangle[],
|
|
53
|
-
metrics: ScrollMetrics
|
|
54
|
-
): {
|
|
55
|
-
viewableItems: ViewToken[]
|
|
56
|
-
changed: ViewToken[]
|
|
57
|
-
} {
|
|
58
|
-
const visibleNow = new Set<number>()
|
|
59
|
-
const viewableItems: ViewToken[] = []
|
|
60
|
-
const changed: ViewToken[] = []
|
|
61
|
-
|
|
62
|
-
const viewportTop = metrics.offsetY
|
|
63
|
-
const viewportBottom = viewportTop + metrics.height
|
|
64
|
-
|
|
65
|
-
// Normalize threshold into [0, 1]
|
|
66
|
-
const threshold =
|
|
67
|
-
(this.config.itemVisiblePercentThreshold ?? 0) / 100
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* NOTE:
|
|
71
|
-
* We intentionally iterate layouts sequentially,
|
|
72
|
-
* but EXIT EARLY when items are completely below viewport.
|
|
73
|
-
*
|
|
74
|
-
* This keeps complexity near O(visibleItems),
|
|
75
|
-
* not O(totalItems).
|
|
76
|
-
*/
|
|
77
|
-
for (let i = 0; i < layouts.length; i++) {
|
|
78
|
-
const layout = layouts[i]!
|
|
79
|
-
|
|
80
|
-
// If item is completely below viewport, stop
|
|
81
|
-
if (layout.y > viewportBottom) {
|
|
82
|
-
break
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const itemTop = layout.y
|
|
86
|
-
const itemBottom = layout.y + layout.height
|
|
87
|
-
|
|
88
|
-
// If item is completely above viewport, skip
|
|
89
|
-
if (itemBottom < viewportTop) {
|
|
90
|
-
continue
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Compute visible intersection
|
|
94
|
-
const visibleTop = Math.max(itemTop, viewportTop)
|
|
95
|
-
const visibleBottom = Math.min(itemBottom, viewportBottom)
|
|
96
|
-
|
|
97
|
-
const visibleHeight = Math.max(0, visibleBottom - visibleTop)
|
|
98
|
-
|
|
99
|
-
// Guard against zero-height items
|
|
100
|
-
const itemHeight =
|
|
101
|
-
layout.height > 0 ? layout.height : 1
|
|
102
|
-
|
|
103
|
-
const visibleRatio = visibleHeight / itemHeight
|
|
104
|
-
|
|
105
|
-
if (visibleRatio >= threshold) {
|
|
106
|
-
visibleNow.add(i)
|
|
107
|
-
viewableItems.push({ index: i, isViewable: true })
|
|
108
|
-
|
|
109
|
-
// Newly visible
|
|
110
|
-
if (!this.lastVisible.has(i)) {
|
|
111
|
-
changed.push({ index: i, isViewable: true })
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Items that were visible before but not anymore
|
|
118
|
-
*/
|
|
119
|
-
for (const index of this.lastVisible) {
|
|
120
|
-
if (!visibleNow.has(index)) {
|
|
121
|
-
changed.push({ index, isViewable: false })
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Update snapshot
|
|
126
|
-
this.lastVisible = visibleNow
|
|
127
|
-
|
|
128
|
-
return { viewableItems, changed }
|
|
129
|
-
}
|
|
130
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import type { LayoutRectangle } from '../layout/LayoutRectangle'
|
|
2
|
-
import type { ScrollMetrics } from './ScrollMetrics'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Computes the contiguous range of item indices
|
|
6
|
-
* intersecting the viewport expanded by bufferPx.
|
|
7
|
-
*
|
|
8
|
-
* PURE function. No allocations besides output.
|
|
9
|
-
* FlashList-style windowing.
|
|
10
|
-
*/
|
|
11
|
-
export function findVisibleIndexRange(
|
|
12
|
-
layouts: readonly LayoutRectangle[],
|
|
13
|
-
metrics: ScrollMetrics,
|
|
14
|
-
bufferPx: number
|
|
15
|
-
): readonly number[] {
|
|
16
|
-
const count = layouts.length
|
|
17
|
-
|
|
18
|
-
// 🔒 CRITICAL GUARDS (FlashList-style)
|
|
19
|
-
if (
|
|
20
|
-
count === 0 ||
|
|
21
|
-
metrics.height <= 0 ||
|
|
22
|
-
bufferPx < 0
|
|
23
|
-
) {
|
|
24
|
-
return []
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const windowStart =
|
|
28
|
-
Math.max(0, metrics.offsetY - bufferPx)
|
|
29
|
-
|
|
30
|
-
const windowEnd =
|
|
31
|
-
metrics.offsetY + metrics.height + bufferPx
|
|
32
|
-
|
|
33
|
-
// Binary search for first intersecting item
|
|
34
|
-
let low = 0
|
|
35
|
-
let high = count - 1
|
|
36
|
-
let firstVisible = count
|
|
37
|
-
|
|
38
|
-
while (low <= high) {
|
|
39
|
-
const mid = (low + high) >> 1
|
|
40
|
-
const rect = layouts[mid]!
|
|
41
|
-
|
|
42
|
-
if (rect.y + rect.height >= windowStart) {
|
|
43
|
-
firstVisible = mid
|
|
44
|
-
high = mid - 1
|
|
45
|
-
} else {
|
|
46
|
-
low = mid + 1
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Linear scan forward
|
|
51
|
-
const visible: number[] = []
|
|
52
|
-
|
|
53
|
-
for (let i = firstVisible; i < count; i++) {
|
|
54
|
-
const rect = layouts[i]!
|
|
55
|
-
if (rect.y > windowEnd) break
|
|
56
|
-
visible.push(i)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return visible
|
|
60
|
-
}
|