react-native-list 1.0.0 → 2.0.0-alpha.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.
- package/README.md +190 -32
- package/ReactNativeList.podspec +39 -0
- package/android/CMakeLists.txt +48 -0
- package/android/build.gradle +151 -0
- package/android/fix-prefab.gradle +51 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/JHybridUiListModule.cpp +192 -0
- package/android/src/main/cpp/JHybridUiListModule.h +50 -0
- package/android/src/main/cpp/cpp-adapter.cpp +12 -0
- package/android/src/main/java/com/hannojg/reactnativelist/ReactNativeListPackage.kt +27 -0
- package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridNativeListDataSource.kt +146 -0
- package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridNativeListLayout.kt +86 -0
- package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridUiListModule.kt +116 -0
- package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridUiListView.kt +410 -0
- package/android/src/main/java/com/margelo/nitro/reactnativelist/HybridViewHolder.kt +9 -0
- package/android/src/main/java/com/margelo/nitro/reactnativelist/NativeListAdapter.kt +217 -0
- package/ios/DataSource/HybridNativeListDataSource.swift +213 -0
- package/ios/HybridObjects/HybridUiListModule.swift +49 -0
- package/ios/HybridObjects/HybridViewHolder.swift +16 -0
- package/ios/Layout/HybridNativeListLayout.swift +128 -0
- package/ios/Utils/ErrorUtils.h +26 -0
- package/ios/Utils/HybridIOSWorkletsModuleProxyHolder.swift +10 -0
- package/ios/Utils/SurfaceHelper.h +20 -0
- package/ios/Utils/SurfaceHelper.mm +144 -0
- package/ios/Utils/SurfacePresenterRegistry.h +17 -0
- package/ios/Utils/SurfacePresenterRegistry.m +31 -0
- package/ios/Utils/TurboModuleInstaller.h +18 -0
- package/ios/Utils/TurboModuleInstaller.mm +267 -0
- package/ios/Views/HostCell.swift +216 -0
- package/ios/Views/HybridUiListView.swift +695 -0
- package/metro/RendererProxyThreadSwitch.js +66 -0
- package/metro-config.d.ts +1 -0
- package/metro-config.js +52 -0
- package/nitro.json +47 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/ReactNativeList+autolinking.cmake +99 -0
- package/nitrogen/generated/android/ReactNativeList+autolinking.gradle +27 -0
- package/nitrogen/generated/android/ReactNativeListOnLoad.cpp +156 -0
- package/nitrogen/generated/android/ReactNativeListOnLoad.hpp +34 -0
- package/nitrogen/generated/android/c++/JFunc_bool_NativeListItem_NativeListItem.hpp +83 -0
- package/nitrogen/generated/android/c++/JFunc_bool_double_NativeListItem_double.hpp +83 -0
- package/nitrogen/generated/android/c++/JFunc_double_std__string.hpp +78 -0
- package/nitrogen/generated/android/c++/JHybridIOSWorkletsModuleProxyHolderSpec.cpp +49 -0
- package/nitrogen/generated/android/c++/JHybridIOSWorkletsModuleProxyHolderSpec.hpp +63 -0
- package/nitrogen/generated/android/c++/JHybridNativeLinearListLayoutSpec.cpp +63 -0
- package/nitrogen/generated/android/c++/JHybridNativeLinearListLayoutSpec.hpp +65 -0
- package/nitrogen/generated/android/c++/JHybridNativeListDataSourceSpec.cpp +101 -0
- package/nitrogen/generated/android/c++/JHybridNativeListDataSourceSpec.hpp +70 -0
- package/nitrogen/generated/android/c++/JHybridNativeListLayoutSpec.cpp +49 -0
- package/nitrogen/generated/android/c++/JHybridNativeListLayoutSpec.hpp +63 -0
- package/nitrogen/generated/android/c++/JHybridUiListModuleSpec.cpp +65 -0
- package/nitrogen/generated/android/c++/JHybridUiListModuleSpec.hpp +64 -0
- package/nitrogen/generated/android/c++/JHybridUiListViewSpec.cpp +92 -0
- package/nitrogen/generated/android/c++/JHybridUiListViewSpec.hpp +67 -0
- package/nitrogen/generated/android/c++/JHybridViewHolderSpec.cpp +49 -0
- package/nitrogen/generated/android/c++/JHybridViewHolderSpec.hpp +63 -0
- package/nitrogen/generated/android/c++/JNativeItemSizeEstimate.hpp +61 -0
- package/nitrogen/generated/android/c++/JNativeLinearListLayoutConfig.hpp +81 -0
- package/nitrogen/generated/android/c++/JNativeLinearListLayoutIOSConfig.hpp +59 -0
- package/nitrogen/generated/android/c++/JNativeListItem.hpp +76 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_HybridIOSWorkletsModuleProxyHolderSpec.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_HybridIOSWorkletsModuleProxyHolderSpec.hpp +72 -0
- package/nitrogen/generated/android/c++/views/JHybridUiListViewStateUpdater.cpp +53 -0
- package/nitrogen/generated/android/c++/views/JHybridUiListViewStateUpdater.hpp +49 -0
- package/nitrogen/generated/android/c++/views/JHybridViewHolderStateUpdater.cpp +53 -0
- package/nitrogen/generated/android/c++/views/JHybridViewHolderStateUpdater.hpp +49 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/Func_bool_NativeListItem_NativeListItem.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/Func_bool_double_NativeListItem_double.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/Func_double_std__string.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridIOSWorkletsModuleProxyHolderSpec.kt +52 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridNativeLinearListLayoutSpec.kt +54 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridNativeListDataSourceSpec.kt +87 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridNativeListLayoutSpec.kt +52 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridUiListModuleSpec.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridUiListViewSpec.kt +76 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/HybridViewHolderSpec.kt +53 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/NativeItemSizeEstimate.kt +56 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/NativeLinearListLayoutConfig.kt +76 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/NativeLinearListLayoutIOSConfig.kt +51 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/NativeListItem.kt +71 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/ReactNativeListOnLoad.kt +35 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/Variant_NullType_HybridIOSWorkletsModuleProxyHolderSpec.kt +62 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/views/HybridUiListViewManager.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/views/HybridUiListViewStateUpdater.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/views/HybridViewHolderManager.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativelist/views/HybridViewHolderStateUpdater.kt +23 -0
- package/nitrogen/generated/ios/ReactNativeList+autolinking.rb +62 -0
- package/nitrogen/generated/ios/ReactNativeList-Swift-Cxx-Bridge.cpp +162 -0
- package/nitrogen/generated/ios/ReactNativeList-Swift-Cxx-Bridge.hpp +368 -0
- package/nitrogen/generated/ios/ReactNativeList-Swift-Cxx-Umbrella.hpp +92 -0
- package/nitrogen/generated/ios/ReactNativeListAutolinking.mm +83 -0
- package/nitrogen/generated/ios/ReactNativeListAutolinking.swift +86 -0
- package/nitrogen/generated/ios/c++/HybridIOSWorkletsModuleProxyHolderSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridIOSWorkletsModuleProxyHolderSpecSwift.hpp +75 -0
- package/nitrogen/generated/ios/c++/HybridNativeLinearListLayoutSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNativeLinearListLayoutSpecSwift.hpp +92 -0
- package/nitrogen/generated/ios/c++/HybridNativeListDataSourceSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNativeListDataSourceSpecSwift.hpp +132 -0
- package/nitrogen/generated/ios/c++/HybridNativeListLayoutSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNativeListLayoutSpecSwift.hpp +75 -0
- package/nitrogen/generated/ios/c++/HybridUiListModuleSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridUiListModuleSpecSwift.hpp +93 -0
- package/nitrogen/generated/ios/c++/HybridUiListViewSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridUiListViewSpecSwift.hpp +121 -0
- package/nitrogen/generated/ios/c++/HybridViewHolderSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridViewHolderSpecSwift.hpp +75 -0
- package/nitrogen/generated/ios/c++/views/HybridUiListViewComponent.mm +118 -0
- package/nitrogen/generated/ios/c++/views/HybridViewHolderComponent.mm +118 -0
- package/nitrogen/generated/ios/swift/Func_bool_NativeListItem_NativeListItem.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_bool_double_NativeListItem_double.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_double_std__string.swift +47 -0
- package/nitrogen/generated/ios/swift/HybridIOSWorkletsModuleProxyHolderSpec.swift +55 -0
- package/nitrogen/generated/ios/swift/HybridIOSWorkletsModuleProxyHolderSpec_cxx.swift +128 -0
- package/nitrogen/generated/ios/swift/HybridNativeLinearListLayoutSpec.swift +55 -0
- package/nitrogen/generated/ios/swift/HybridNativeLinearListLayoutSpec_cxx.swift +140 -0
- package/nitrogen/generated/ios/swift/HybridNativeListDataSourceSpec.swift +62 -0
- package/nitrogen/generated/ios/swift/HybridNativeListDataSourceSpec_cxx.swift +222 -0
- package/nitrogen/generated/ios/swift/HybridNativeListLayoutSpec.swift +55 -0
- package/nitrogen/generated/ios/swift/HybridNativeListLayoutSpec_cxx.swift +128 -0
- package/nitrogen/generated/ios/swift/HybridUiListModuleSpec.swift +56 -0
- package/nitrogen/generated/ios/swift/HybridUiListModuleSpec_cxx.swift +175 -0
- package/nitrogen/generated/ios/swift/HybridUiListViewSpec.swift +59 -0
- package/nitrogen/generated/ios/swift/HybridUiListViewSpec_cxx.swift +227 -0
- package/nitrogen/generated/ios/swift/HybridViewHolderSpec.swift +55 -0
- package/nitrogen/generated/ios/swift/HybridViewHolderSpec_cxx.swift +147 -0
- package/nitrogen/generated/ios/swift/NativeItemSizeEstimate.swift +60 -0
- package/nitrogen/generated/ios/swift/NativeLinearListLayoutConfig.swift +60 -0
- package/nitrogen/generated/ios/swift/NativeLinearListLayoutIOSConfig.swift +35 -0
- package/nitrogen/generated/ios/swift/NativeListItem.swift +75 -0
- package/nitrogen/generated/ios/swift/Variant_NullType__any_HybridIOSWorkletsModuleProxyHolderSpec_.swift +30 -0
- package/nitrogen/generated/shared/c++/HybridIOSWorkletsModuleProxyHolderSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridIOSWorkletsModuleProxyHolderSpec.hpp +62 -0
- package/nitrogen/generated/shared/c++/HybridNativeLinearListLayoutSpec.cpp +22 -0
- package/nitrogen/generated/shared/c++/HybridNativeLinearListLayoutSpec.hpp +67 -0
- package/nitrogen/generated/shared/c++/HybridNativeListDataSourceSpec.cpp +28 -0
- package/nitrogen/generated/shared/c++/HybridNativeListDataSourceSpec.hpp +72 -0
- package/nitrogen/generated/shared/c++/HybridNativeListLayoutSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridNativeListLayoutSpec.hpp +62 -0
- package/nitrogen/generated/shared/c++/HybridUiListModuleSpec.cpp +22 -0
- package/nitrogen/generated/shared/c++/HybridUiListModuleSpec.hpp +68 -0
- package/nitrogen/generated/shared/c++/HybridUiListViewSpec.cpp +25 -0
- package/nitrogen/generated/shared/c++/HybridUiListViewSpec.hpp +79 -0
- package/nitrogen/generated/shared/c++/HybridUiManagerHelperSpec.cpp +23 -0
- package/nitrogen/generated/shared/c++/HybridUiManagerHelperSpec.hpp +65 -0
- package/nitrogen/generated/shared/c++/HybridViewHolderSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridViewHolderSpec.hpp +62 -0
- package/nitrogen/generated/shared/c++/NativeItemSizeEstimate.hpp +87 -0
- package/nitrogen/generated/shared/c++/NativeLinearListLayoutConfig.hpp +105 -0
- package/nitrogen/generated/shared/c++/NativeLinearListLayoutIOSConfig.hpp +85 -0
- package/nitrogen/generated/shared/c++/NativeListItem.hpp +101 -0
- package/nitrogen/generated/shared/c++/views/HybridUiListViewComponent.cpp +72 -0
- package/nitrogen/generated/shared/c++/views/HybridUiListViewComponent.hpp +109 -0
- package/nitrogen/generated/shared/c++/views/HybridViewHolderComponent.cpp +72 -0
- package/nitrogen/generated/shared/c++/views/HybridViewHolderComponent.hpp +109 -0
- package/nitrogen/generated/shared/json/UiListViewConfig.json +9 -0
- package/nitrogen/generated/shared/json/ViewHolderConfig.json +9 -0
- package/package.json +152 -5
- package/react-native.config.js +16 -0
- package/src/ListDataSource.ts +232 -0
- package/src/ListLayout.ts +95 -0
- package/src/UiListModule.ts +5 -0
- package/src/hooks/useChangeEffect.ts +50 -0
- package/src/index.tsx +49 -0
- package/src/privateGlobals.ts +20 -0
- package/src/renderer/fabric/RenderHelper.ts +29 -0
- package/src/renderer/fabric/UiManagerHelper.ts +5 -0
- package/src/renderer/react/ReactFabricMirror.bundle.js +1984 -0
- package/src/renderer/react/ReactFabricMirror.ts +766 -0
- package/src/renderer/react/ReactFabricRenderer.ts +11 -0
- package/src/specs/IOSWorkletsModuleProxyHolder.nitro.ts +6 -0
- package/src/specs/NativeLinearListLayout.nitro.ts +23 -0
- package/src/specs/NativeListDataSource.nitro.ts +28 -0
- package/src/specs/NativeListLayout.nitro.ts +6 -0
- package/src/specs/UIListModule.nitro.ts +13 -0
- package/src/specs/UIManagerHelper.nitro.ts +34 -0
- package/src/specs/UiListView.nitro.ts +31 -0
- package/src/specs/ViewHolder.nitro.ts +11 -0
- package/src/views/List.tsx +525 -0
- package/src/views/UiListHostComponent.ts +8 -0
- package/FillRateHelper.js +0 -179
- package/FlatList.js +0 -494
- package/LICENSE.md +0 -31
- package/ListView/__mocks__/ListViewMock.js +0 -55
- package/MetroListView.js +0 -166
- package/SectionList.js +0 -291
- package/ViewabilityHelper.js +0 -260
- package/VirtualizeUtils.js +0 -163
- package/VirtualizedList.js +0 -861
- package/VirtualizedSectionList.js +0 -397
- package/__flowtests__/FlatList-flowtest.js +0 -90
- package/__flowtests__/SectionList-flowtest.js +0 -89
- package/__tests__/FillRateHelper-test.js +0 -106
- package/__tests__/FlatList-test.js +0 -64
- package/__tests__/SectionList-test.js +0 -67
- package/__tests__/ViewabilityHelper-test.js +0 -359
- package/__tests__/VirtualizeUtils-test.js +0 -74
- package/__tests__/__snapshots__/FlatList-test.js.snap +0 -251
- package/__tests__/__snapshots__/SectionList-test.js.snap +0 -283
- package/index.js +0 -5
|
@@ -1,397 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) 2015-present, Facebook, Inc.
|
|
3
|
-
* All rights reserved.
|
|
4
|
-
*
|
|
5
|
-
* This source code is licensed under the BSD-style license found in the
|
|
6
|
-
* LICENSE file in the root directory of this source tree. An additional grant
|
|
7
|
-
* of patent rights can be found in the PATENTS file in the same directory.
|
|
8
|
-
*
|
|
9
|
-
* @providesModule VirtualizedSectionList
|
|
10
|
-
* @flow
|
|
11
|
-
*/
|
|
12
|
-
'use strict';
|
|
13
|
-
|
|
14
|
-
const React = require('React');
|
|
15
|
-
const View = require('View');
|
|
16
|
-
const VirtualizedList = require('VirtualizedList');
|
|
17
|
-
|
|
18
|
-
const invariant = require('fbjs/lib/invariant');
|
|
19
|
-
const warning = require('fbjs/lib/warning');
|
|
20
|
-
|
|
21
|
-
import type {ViewToken} from './ViewabilityHelper';
|
|
22
|
-
import type {Props as VirtualizedListProps} from 'VirtualizedList';
|
|
23
|
-
|
|
24
|
-
type Item = any;
|
|
25
|
-
type SectionItem = any;
|
|
26
|
-
|
|
27
|
-
type SectionBase = {
|
|
28
|
-
// Must be provided directly on each section.
|
|
29
|
-
data: Array<SectionItem>,
|
|
30
|
-
key: string,
|
|
31
|
-
|
|
32
|
-
// Optional props will override list-wide props just for this section.
|
|
33
|
-
renderItem?: ?({
|
|
34
|
-
item: SectionItem,
|
|
35
|
-
index: number,
|
|
36
|
-
separators: {
|
|
37
|
-
highlight: () => void,
|
|
38
|
-
unhighlight: () => void,
|
|
39
|
-
updateProps: (select: 'leading' | 'trailing', newProps: Object) => void,
|
|
40
|
-
},
|
|
41
|
-
}) => ?React.Element<*>,
|
|
42
|
-
ItemSeparatorComponent?: ?ReactClass<*>,
|
|
43
|
-
keyExtractor?: (item: SectionItem) => string,
|
|
44
|
-
|
|
45
|
-
// TODO: support more optional/override props
|
|
46
|
-
// FooterComponent?: ?ReactClass<*>,
|
|
47
|
-
// HeaderComponent?: ?ReactClass<*>,
|
|
48
|
-
// onViewableItemsChanged?: ({viewableItems: Array<ViewToken>, changed: Array<ViewToken>}) => void,
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
type RequiredProps<SectionT: SectionBase> = {
|
|
52
|
-
sections: Array<SectionT>,
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
type OptionalProps<SectionT: SectionBase> = {
|
|
56
|
-
/**
|
|
57
|
-
* Rendered after the last item in the last section.
|
|
58
|
-
*/
|
|
59
|
-
ListFooterComponent?: ?(ReactClass<*> | React.Element<*>),
|
|
60
|
-
/**
|
|
61
|
-
* Rendered at the very beginning of the list.
|
|
62
|
-
*/
|
|
63
|
-
ListHeaderComponent?: ?(ReactClass<*> | React.Element<*>),
|
|
64
|
-
/**
|
|
65
|
-
* Default renderer for every item in every section.
|
|
66
|
-
*/
|
|
67
|
-
renderItem: (info: {
|
|
68
|
-
item: Item,
|
|
69
|
-
index: number,
|
|
70
|
-
separators: {
|
|
71
|
-
highlight: () => void,
|
|
72
|
-
unhighlight: () => void,
|
|
73
|
-
updateProps: (select: 'leading' | 'trailing', newProps: Object) => void,
|
|
74
|
-
},
|
|
75
|
-
}) => ?React.Element<any>,
|
|
76
|
-
/**
|
|
77
|
-
* Rendered at the top of each section.
|
|
78
|
-
*/
|
|
79
|
-
renderSectionHeader?: ?({section: SectionT}) => ?React.Element<*>,
|
|
80
|
-
/**
|
|
81
|
-
* Rendered at the bottom of every Section, except the very last one, in place of the normal
|
|
82
|
-
* ItemSeparatorComponent.
|
|
83
|
-
*/
|
|
84
|
-
SectionSeparatorComponent?: ?ReactClass<*>,
|
|
85
|
-
/**
|
|
86
|
-
* Rendered at the bottom of every Item except the very last one in the last section.
|
|
87
|
-
*/
|
|
88
|
-
ItemSeparatorComponent?: ?ReactClass<*>,
|
|
89
|
-
/**
|
|
90
|
-
* Warning: Virtualization can drastically improve memory consumption for long lists, but trashes
|
|
91
|
-
* the state of items when they scroll out of the render window, so make sure all relavent data is
|
|
92
|
-
* stored outside of the recursive `renderItem` instance tree.
|
|
93
|
-
*/
|
|
94
|
-
enableVirtualization?: ?boolean,
|
|
95
|
-
keyExtractor: (item: Item, index: number) => string,
|
|
96
|
-
onEndReached?: ?({distanceFromEnd: number}) => void,
|
|
97
|
-
/**
|
|
98
|
-
* If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make
|
|
99
|
-
* sure to also set the `refreshing` prop correctly.
|
|
100
|
-
*/
|
|
101
|
-
onRefresh?: ?Function,
|
|
102
|
-
/**
|
|
103
|
-
* Called when the viewability of rows changes, as defined by the
|
|
104
|
-
* `viewabilityConfig` prop.
|
|
105
|
-
*/
|
|
106
|
-
onViewableItemsChanged?: ?({viewableItems: Array<ViewToken>, changed: Array<ViewToken>}) => void,
|
|
107
|
-
/**
|
|
108
|
-
* Set this true while waiting for new data from a refresh.
|
|
109
|
-
*/
|
|
110
|
-
refreshing?: ?boolean,
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
export type Props<SectionT> =
|
|
114
|
-
RequiredProps<SectionT> &
|
|
115
|
-
OptionalProps<SectionT> &
|
|
116
|
-
VirtualizedListProps;
|
|
117
|
-
|
|
118
|
-
type DefaultProps = (typeof VirtualizedList.defaultProps) & {data: Array<Item>};
|
|
119
|
-
type State = {childProps: VirtualizedListProps};
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Right now this just flattens everything into one list and uses VirtualizedList under the
|
|
123
|
-
* hood. The only operation that might not scale well is concatting the data arrays of all the
|
|
124
|
-
* sections when new props are received, which should be plenty fast for up to ~10,000 items.
|
|
125
|
-
*/
|
|
126
|
-
class VirtualizedSectionList<SectionT: SectionBase>
|
|
127
|
-
extends React.PureComponent<DefaultProps, Props<SectionT>, State>
|
|
128
|
-
{
|
|
129
|
-
props: Props<SectionT>;
|
|
130
|
-
|
|
131
|
-
state: State;
|
|
132
|
-
|
|
133
|
-
static defaultProps: DefaultProps = {
|
|
134
|
-
...VirtualizedList.defaultProps,
|
|
135
|
-
data: [],
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
scrollToLocation(params: {
|
|
139
|
-
animated?: ?boolean, itemIndex: number, sectionIndex: number, viewPosition?: number
|
|
140
|
-
}) {
|
|
141
|
-
let index = params.itemIndex + 1;
|
|
142
|
-
for (let ii = 0; ii < params.sectionIndex; ii++) {
|
|
143
|
-
index += this.props.sections[ii].data.length + 1;
|
|
144
|
-
}
|
|
145
|
-
const toIndexParams = {
|
|
146
|
-
...params,
|
|
147
|
-
index,
|
|
148
|
-
};
|
|
149
|
-
this._listRef.scrollToIndex(toIndexParams);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
getListRef(): VirtualizedList {
|
|
153
|
-
return this._listRef;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
_keyExtractor = (item: Item, index: number) => {
|
|
157
|
-
const info = this._subExtractor(index);
|
|
158
|
-
return (info && info.key) || String(index);
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
_subExtractor(
|
|
162
|
-
index: number,
|
|
163
|
-
): ?{
|
|
164
|
-
section: SectionT,
|
|
165
|
-
key: string, // Key of the section or combined key for section + item
|
|
166
|
-
index: ?number, // Relative index within the section
|
|
167
|
-
} {
|
|
168
|
-
let itemIndex = index;
|
|
169
|
-
const defaultKeyExtractor = this.props.keyExtractor;
|
|
170
|
-
for (let ii = 0; ii < this.props.sections.length; ii++) {
|
|
171
|
-
const section = this.props.sections[ii];
|
|
172
|
-
const key = section.key;
|
|
173
|
-
warning(
|
|
174
|
-
key != null,
|
|
175
|
-
'VirtualizedSectionList: A `section` you supplied is missing the `key` property.'
|
|
176
|
-
);
|
|
177
|
-
itemIndex -= 1; // The section itself is an item
|
|
178
|
-
if (itemIndex >= section.data.length) {
|
|
179
|
-
itemIndex -= section.data.length;
|
|
180
|
-
} else if (itemIndex === -1) {
|
|
181
|
-
return {section, key, index: null};
|
|
182
|
-
} else {
|
|
183
|
-
const keyExtractor = section.keyExtractor || defaultKeyExtractor;
|
|
184
|
-
return {
|
|
185
|
-
section,
|
|
186
|
-
key: key + ':' + keyExtractor(section.data[itemIndex], itemIndex),
|
|
187
|
-
index: itemIndex,
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
_convertViewable = (viewable: ViewToken): ?ViewToken => {
|
|
194
|
-
invariant(viewable.index != null, 'Received a broken ViewToken');
|
|
195
|
-
const info = this._subExtractor(viewable.index);
|
|
196
|
-
if (!info) {
|
|
197
|
-
return null;
|
|
198
|
-
}
|
|
199
|
-
const keyExtractor = info.section.keyExtractor || this.props.keyExtractor;
|
|
200
|
-
return {
|
|
201
|
-
...viewable,
|
|
202
|
-
index: info.index,
|
|
203
|
-
key: keyExtractor(viewable.item, info.index),
|
|
204
|
-
section: info.section,
|
|
205
|
-
};
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
_onViewableItemsChanged = (
|
|
209
|
-
{viewableItems, changed}: {viewableItems: Array<ViewToken>, changed: Array<ViewToken>}
|
|
210
|
-
) => {
|
|
211
|
-
if (this.props.onViewableItemsChanged) {
|
|
212
|
-
this.props.onViewableItemsChanged({
|
|
213
|
-
viewableItems: viewableItems.map(this._convertViewable, this).filter(Boolean),
|
|
214
|
-
changed: changed.map(this._convertViewable, this).filter(Boolean),
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
_renderItem = ({item, index}: {item: Item, index: number}) => {
|
|
220
|
-
const info = this._subExtractor(index);
|
|
221
|
-
if (!info) {
|
|
222
|
-
return null;
|
|
223
|
-
}
|
|
224
|
-
const infoIndex = info.index;
|
|
225
|
-
if (infoIndex == null) {
|
|
226
|
-
const {renderSectionHeader} = this.props;
|
|
227
|
-
return renderSectionHeader ? renderSectionHeader({section: info.section}) : null;
|
|
228
|
-
} else {
|
|
229
|
-
const renderItem = info.section.renderItem || this.props.renderItem;
|
|
230
|
-
const SeparatorComponent = this._getSeparatorComponent(index, info);
|
|
231
|
-
invariant(renderItem, 'no renderItem!');
|
|
232
|
-
return (
|
|
233
|
-
<ItemWithSeparator
|
|
234
|
-
SeparatorComponent={SeparatorComponent}
|
|
235
|
-
LeadingSeparatorComponent={infoIndex === 0
|
|
236
|
-
? this.props.SectionSeparatorComponent
|
|
237
|
-
: undefined
|
|
238
|
-
}
|
|
239
|
-
cellKey={info.key}
|
|
240
|
-
index={infoIndex}
|
|
241
|
-
item={item}
|
|
242
|
-
onUpdateSeparator={this._onUpdateSeparator}
|
|
243
|
-
prevCellKey={(this._subExtractor(index - 1) || {}).key}
|
|
244
|
-
ref={(ref) => {this._cellRefs[info.key] = ref;}}
|
|
245
|
-
renderItem={renderItem}
|
|
246
|
-
section={info.section}
|
|
247
|
-
/>
|
|
248
|
-
);
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
_onUpdateSeparator = (key: string, newProps: Object) => {
|
|
253
|
-
const ref = this._cellRefs[key];
|
|
254
|
-
ref && ref.updateSeparatorProps(newProps);
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
_getSeparatorComponent(index: number, info?: ?Object): ?ReactClass<*> {
|
|
258
|
-
info = info || this._subExtractor(index);
|
|
259
|
-
if (!info) {
|
|
260
|
-
return null;
|
|
261
|
-
}
|
|
262
|
-
const ItemSeparatorComponent = info.section.ItemSeparatorComponent || this.props.ItemSeparatorComponent;
|
|
263
|
-
const {SectionSeparatorComponent} = this.props;
|
|
264
|
-
const isLastItemInList = index === this.state.childProps.getItemCount() - 1;
|
|
265
|
-
const isLastItemInSection = info.index === info.section.data.length - 1;
|
|
266
|
-
if (SectionSeparatorComponent && isLastItemInSection) {
|
|
267
|
-
return SectionSeparatorComponent;
|
|
268
|
-
}
|
|
269
|
-
if (ItemSeparatorComponent && !isLastItemInSection && !isLastItemInList) {
|
|
270
|
-
return ItemSeparatorComponent;
|
|
271
|
-
}
|
|
272
|
-
return null;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
_computeState(props: Props<SectionT>): State {
|
|
276
|
-
const offset = props.ListHeaderComponent ? 1 : 0;
|
|
277
|
-
const stickyHeaderIndices = [];
|
|
278
|
-
const itemCount = props.sections.reduce(
|
|
279
|
-
(v, section) => {
|
|
280
|
-
stickyHeaderIndices.push(v + offset);
|
|
281
|
-
return v + section.data.length + 1;
|
|
282
|
-
},
|
|
283
|
-
0
|
|
284
|
-
);
|
|
285
|
-
return {
|
|
286
|
-
childProps: {
|
|
287
|
-
...props,
|
|
288
|
-
renderItem: this._renderItem,
|
|
289
|
-
ItemSeparatorComponent: undefined, // Rendered with renderItem
|
|
290
|
-
data: props.sections,
|
|
291
|
-
getItemCount: () => itemCount,
|
|
292
|
-
getItem,
|
|
293
|
-
keyExtractor: this._keyExtractor,
|
|
294
|
-
onViewableItemsChanged:
|
|
295
|
-
props.onViewableItemsChanged ? this._onViewableItemsChanged : undefined,
|
|
296
|
-
stickyHeaderIndices: props.stickySectionHeadersEnabled ? stickyHeaderIndices : undefined,
|
|
297
|
-
},
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
constructor(props: Props<SectionT>, context: Object) {
|
|
302
|
-
super(props, context);
|
|
303
|
-
this.state = this._computeState(props);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
componentWillReceiveProps(nextProps: Props<SectionT>) {
|
|
307
|
-
this.setState(this._computeState(nextProps));
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
render() {
|
|
311
|
-
return <VirtualizedList {...this.state.childProps} ref={this._captureRef} />;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
_cellRefs = {};
|
|
315
|
-
_listRef: VirtualizedList;
|
|
316
|
-
_captureRef = (ref) => { this._listRef = ref; };
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
class ItemWithSeparator extends React.Component {
|
|
320
|
-
props: {
|
|
321
|
-
LeadingSeparatorComponent: ?ReactClass<*>,
|
|
322
|
-
SeparatorComponent: ?ReactClass<*>,
|
|
323
|
-
cellKey: string,
|
|
324
|
-
index: number,
|
|
325
|
-
item: Item,
|
|
326
|
-
onUpdateSeparator: (cellKey: string, newProps: Object) => void,
|
|
327
|
-
prevCellKey?: ?string,
|
|
328
|
-
renderItem: Function,
|
|
329
|
-
section: Object,
|
|
330
|
-
};
|
|
331
|
-
|
|
332
|
-
state = {
|
|
333
|
-
separatorProps: {
|
|
334
|
-
highlighted: false,
|
|
335
|
-
leadingItem: this.props.item,
|
|
336
|
-
leadingSection: this.props.section,
|
|
337
|
-
},
|
|
338
|
-
leadingSeparatorProps: {
|
|
339
|
-
highlighted: false,
|
|
340
|
-
},
|
|
341
|
-
};
|
|
342
|
-
|
|
343
|
-
_separators = {
|
|
344
|
-
highlight: () => {
|
|
345
|
-
['leading', 'trailing'].forEach(s => this._separators.updateProps(s, {highlighted: true}));
|
|
346
|
-
},
|
|
347
|
-
unhighlight: () => {
|
|
348
|
-
['leading', 'trailing'].forEach(s => this._separators.updateProps(s, {highlighted: false}));
|
|
349
|
-
},
|
|
350
|
-
updateProps: (select: 'leading' | 'trailing', newProps: Object) => {
|
|
351
|
-
const {LeadingSeparatorComponent, cellKey, prevCellKey} = this.props;
|
|
352
|
-
if (select === 'leading' && LeadingSeparatorComponent) {
|
|
353
|
-
this.setState(state => ({
|
|
354
|
-
leadingSeparatorProps: {...state.leadingSeparatorProps, ...newProps}
|
|
355
|
-
}));
|
|
356
|
-
} else {
|
|
357
|
-
this.props.onUpdateSeparator((select === 'leading' && prevCellKey) || cellKey, newProps);
|
|
358
|
-
}
|
|
359
|
-
},
|
|
360
|
-
};
|
|
361
|
-
|
|
362
|
-
updateSeparatorProps(newProps: Object) {
|
|
363
|
-
this.setState(state => ({separatorProps: {...state.separatorProps, ...newProps}}));
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
render() {
|
|
367
|
-
const {LeadingSeparatorComponent, SeparatorComponent, renderItem, item, index} = this.props;
|
|
368
|
-
const element = renderItem({
|
|
369
|
-
item,
|
|
370
|
-
index,
|
|
371
|
-
separators: this._separators,
|
|
372
|
-
});
|
|
373
|
-
const leadingSeparator = LeadingSeparatorComponent &&
|
|
374
|
-
<LeadingSeparatorComponent {...this.state.leadingSeparatorProps} />;
|
|
375
|
-
const separator = SeparatorComponent && <SeparatorComponent {...this.state.separatorProps} />;
|
|
376
|
-
return separator ? <View>{leadingSeparator}{element}{separator}</View> : element;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
function getItem(sections: ?Array<Item>, index: number): ?Item {
|
|
381
|
-
if (!sections) {
|
|
382
|
-
return null;
|
|
383
|
-
}
|
|
384
|
-
let itemIdx = index - 1;
|
|
385
|
-
for (let ii = 0; ii < sections.length; ii++) {
|
|
386
|
-
if (itemIdx === -1) {
|
|
387
|
-
return sections[ii]; // The section itself is the item
|
|
388
|
-
} else if (itemIdx < sections[ii].data.length) {
|
|
389
|
-
return sections[ii].data[itemIdx];
|
|
390
|
-
} else {
|
|
391
|
-
itemIdx -= (sections[ii].data.length + 1);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
return null;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
module.exports = VirtualizedSectionList;
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) 2015-present, Facebook, Inc.
|
|
3
|
-
* All rights reserved.
|
|
4
|
-
*
|
|
5
|
-
* This source code is licensed under the BSD-style license found in the
|
|
6
|
-
* LICENSE file in the root directory of this source tree. An additional grant
|
|
7
|
-
* of patent rights can be found in the PATENTS file in the same directory.
|
|
8
|
-
*
|
|
9
|
-
* @flow
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
'use strict';
|
|
13
|
-
|
|
14
|
-
const FlatList = require('FlatList');
|
|
15
|
-
const React = require('react');
|
|
16
|
-
|
|
17
|
-
function renderMyListItem(info: {item: {title: string}, index: number}) {
|
|
18
|
-
return <span />;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
module.exports = {
|
|
22
|
-
testEverythingIsFine() {
|
|
23
|
-
const data = [{
|
|
24
|
-
title: 'Title Text',
|
|
25
|
-
key: 1,
|
|
26
|
-
}];
|
|
27
|
-
return <FlatList renderItem={renderMyListItem} data={data} />;
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
testBadDataWithTypicalItem() {
|
|
31
|
-
// $FlowExpectedError - bad title type 6, should be string
|
|
32
|
-
const data = [{
|
|
33
|
-
title: 6,
|
|
34
|
-
key: 1,
|
|
35
|
-
}];
|
|
36
|
-
return <FlatList renderItem={renderMyListItem} data={data} />;
|
|
37
|
-
},
|
|
38
|
-
|
|
39
|
-
testMissingFieldWithTypicalItem() {
|
|
40
|
-
const data = [{
|
|
41
|
-
key: 1,
|
|
42
|
-
}];
|
|
43
|
-
// $FlowExpectedError - missing title
|
|
44
|
-
return <FlatList renderItem={renderMyListItem} data={data} />;
|
|
45
|
-
},
|
|
46
|
-
|
|
47
|
-
testGoodDataWithBadCustomRenderItemFunction() {
|
|
48
|
-
const data = [{
|
|
49
|
-
widget: 6,
|
|
50
|
-
key: 1,
|
|
51
|
-
}];
|
|
52
|
-
return (
|
|
53
|
-
<FlatList
|
|
54
|
-
renderItem={(info) =>
|
|
55
|
-
// $FlowExpectedError - bad widgetCount type 6, should be Object
|
|
56
|
-
<span>{info.item.widget.missingProp}</span>
|
|
57
|
-
}
|
|
58
|
-
data={data}
|
|
59
|
-
/>
|
|
60
|
-
);
|
|
61
|
-
},
|
|
62
|
-
|
|
63
|
-
testBadRenderItemFunction() {
|
|
64
|
-
const data = [{
|
|
65
|
-
title: 'foo',
|
|
66
|
-
key: 1,
|
|
67
|
-
}];
|
|
68
|
-
return [
|
|
69
|
-
// $FlowExpectedError - title should be inside `item`
|
|
70
|
-
<FlatList renderItem={(info: {title: string}) => <span /> } data={data} />,
|
|
71
|
-
// $FlowExpectedError - bad index type string, should be number
|
|
72
|
-
<FlatList renderItem={(info: {item: any, index: string}) => <span /> } data={data} />,
|
|
73
|
-
// $FlowExpectedError - bad title type number, should be string
|
|
74
|
-
<FlatList renderItem={(info: {item: {title: number}}) => <span /> } data={data} />,
|
|
75
|
-
// EverythingIsFine
|
|
76
|
-
<FlatList renderItem={(info: {item: {title: string}}) => <span /> } data={data} />,
|
|
77
|
-
];
|
|
78
|
-
},
|
|
79
|
-
|
|
80
|
-
testOtherBadProps() {
|
|
81
|
-
return [
|
|
82
|
-
// $FlowExpectedError - bad numColumns type "lots"
|
|
83
|
-
<FlatList renderItem={renderMyListItem} data={[]} numColumns="lots" />,
|
|
84
|
-
// $FlowExpectedError - bad windowSize type "big"
|
|
85
|
-
<FlatList renderItem={renderMyListItem} data={[]} windowSize="big" />,
|
|
86
|
-
// $FlowExpectedError - missing `data` prop
|
|
87
|
-
<FlatList renderItem={renderMyListItem} />,
|
|
88
|
-
];
|
|
89
|
-
},
|
|
90
|
-
};
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) 2015-present, Facebook, Inc.
|
|
3
|
-
* All rights reserved.
|
|
4
|
-
*
|
|
5
|
-
* This source code is licensed under the BSD-style license found in the
|
|
6
|
-
* LICENSE file in the root directory of this source tree. An additional grant
|
|
7
|
-
* of patent rights can be found in the PATENTS file in the same directory.
|
|
8
|
-
*
|
|
9
|
-
* @flow
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
'use strict';
|
|
13
|
-
|
|
14
|
-
const React = require('react');
|
|
15
|
-
const SectionList = require('SectionList');
|
|
16
|
-
|
|
17
|
-
function renderMyListItem(info: {item: {title: string}, index: number}) {
|
|
18
|
-
return <span />;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const renderMyHeader = ({section}: {section: {fooNumber: number} & Object}) => <span />;
|
|
22
|
-
|
|
23
|
-
module.exports = {
|
|
24
|
-
testGoodDataWithGoodItem() {
|
|
25
|
-
const sections = [{
|
|
26
|
-
key: 'a', data: [{
|
|
27
|
-
title: 'foo',
|
|
28
|
-
key: 1,
|
|
29
|
-
}],
|
|
30
|
-
}];
|
|
31
|
-
return <SectionList renderItem={renderMyListItem} sections={sections} />;
|
|
32
|
-
},
|
|
33
|
-
|
|
34
|
-
testBadRenderItemFunction() {
|
|
35
|
-
const sections = [{
|
|
36
|
-
key: 'a', data: [{
|
|
37
|
-
title: 'foo',
|
|
38
|
-
key: 1,
|
|
39
|
-
}],
|
|
40
|
-
}];
|
|
41
|
-
return [
|
|
42
|
-
// $FlowExpectedError - title should be inside `item`
|
|
43
|
-
<SectionList renderItem={(info: {title: string}) => <span /> } sections={sections} />,
|
|
44
|
-
// $FlowExpectedError - bad index type string, should be number
|
|
45
|
-
<SectionList renderItem={(info: {index: string}) => <span /> } sections={sections} />,
|
|
46
|
-
// EverythingIsFine
|
|
47
|
-
<SectionList renderItem={(info: {item: {title: string}}) => <span /> } sections={sections} />,
|
|
48
|
-
];
|
|
49
|
-
},
|
|
50
|
-
|
|
51
|
-
testBadInheritedDefaultProp(): React.Element<*> {
|
|
52
|
-
const sections = [];
|
|
53
|
-
// $FlowExpectedError - bad windowSize type "big"
|
|
54
|
-
return <SectionList renderItem={renderMyListItem} sections={sections} windowSize="big" />;
|
|
55
|
-
},
|
|
56
|
-
|
|
57
|
-
testMissingData(): React.Element<*> {
|
|
58
|
-
// $FlowExpectedError - missing `sections` prop
|
|
59
|
-
return <SectionList renderItem={renderMyListItem} />;
|
|
60
|
-
},
|
|
61
|
-
|
|
62
|
-
testBadSectionsShape(): React.Element<*> {
|
|
63
|
-
const sections = [{
|
|
64
|
-
key: 'a', items: [{
|
|
65
|
-
title: 'foo',
|
|
66
|
-
key: 1,
|
|
67
|
-
}],
|
|
68
|
-
}];
|
|
69
|
-
// $FlowExpectedError - section missing `data` field
|
|
70
|
-
return <SectionList renderItem={renderMyListItem} sections={sections} />;
|
|
71
|
-
},
|
|
72
|
-
|
|
73
|
-
testBadSectionsMetadata(): React.Element<*> {
|
|
74
|
-
// $FlowExpectedError - section has bad meta data `fooNumber` field of type string
|
|
75
|
-
const sections = [{
|
|
76
|
-
key: 'a', fooNumber: 'string', data: [{
|
|
77
|
-
title: 'foo',
|
|
78
|
-
key: 1,
|
|
79
|
-
}],
|
|
80
|
-
}];
|
|
81
|
-
return (
|
|
82
|
-
<SectionList
|
|
83
|
-
renderSectionHeader={renderMyHeader}
|
|
84
|
-
renderItem={renderMyListItem}
|
|
85
|
-
sections={sections}
|
|
86
|
-
/>
|
|
87
|
-
);
|
|
88
|
-
},
|
|
89
|
-
};
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) 2015-present, Facebook, Inc.
|
|
3
|
-
* All rights reserved.
|
|
4
|
-
*
|
|
5
|
-
* This source code is licensed under the BSD-style license found in the
|
|
6
|
-
* LICENSE file in the root directory of this source tree. An additional grant
|
|
7
|
-
* of patent rights can be found in the PATENTS file in the same directory.
|
|
8
|
-
*
|
|
9
|
-
*/
|
|
10
|
-
'use strict';
|
|
11
|
-
|
|
12
|
-
jest.unmock('FillRateHelper');
|
|
13
|
-
|
|
14
|
-
const FillRateHelper = require('FillRateHelper');
|
|
15
|
-
|
|
16
|
-
let rowFramesGlobal;
|
|
17
|
-
const dataGlobal = [{key: 'a'}, {key: 'b'}, {key: 'c'}, {key: 'd'}];
|
|
18
|
-
function getFrameMetrics(index: number) {
|
|
19
|
-
const frame = rowFramesGlobal[dataGlobal[index].key];
|
|
20
|
-
return {length: frame.height, offset: frame.y, inLayout: frame.inLayout};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function computeResult({helper, props, state, scroll}) {
|
|
24
|
-
return helper.computeInfoSampled(
|
|
25
|
-
'test',
|
|
26
|
-
{
|
|
27
|
-
data: dataGlobal,
|
|
28
|
-
fillRateTrackingSampleRate: 1,
|
|
29
|
-
getItemCount: (data2) => data2.length,
|
|
30
|
-
initialNumToRender: 10,
|
|
31
|
-
...(props || {}),
|
|
32
|
-
},
|
|
33
|
-
{first: 0, last: 1, ...(state || {})},
|
|
34
|
-
{offset: 0, visibleLength: 100, ...(scroll || {})},
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
describe('computeInfoSampled', function() {
|
|
39
|
-
beforeEach(() => {
|
|
40
|
-
FillRateHelper.setSampleRate(1);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('computes correct blankness of viewport', function() {
|
|
44
|
-
const helper = new FillRateHelper(getFrameMetrics);
|
|
45
|
-
rowFramesGlobal = {
|
|
46
|
-
a: {y: 0, height: 50, inLayout: true},
|
|
47
|
-
b: {y: 50, height: 50, inLayout: true},
|
|
48
|
-
};
|
|
49
|
-
let result = computeResult({helper});
|
|
50
|
-
expect(result).toBeNull();
|
|
51
|
-
result = computeResult({helper, state: {last: 0}});
|
|
52
|
-
expect(result.event.blankness).toBe(0.5);
|
|
53
|
-
result = computeResult({helper, scroll: {offset: 25}});
|
|
54
|
-
expect(result.event.blankness).toBe(0.25);
|
|
55
|
-
result = computeResult({helper, scroll: {visibleLength: 400}});
|
|
56
|
-
expect(result.event.blankness).toBe(0.75);
|
|
57
|
-
result = computeResult({helper, scroll: {offset: 100}});
|
|
58
|
-
expect(result.event.blankness).toBe(1);
|
|
59
|
-
expect(result.aggregate.avg_blankness).toBe(0.5);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('skips frames that are not in layout', function() {
|
|
63
|
-
const helper = new FillRateHelper(getFrameMetrics);
|
|
64
|
-
rowFramesGlobal = {
|
|
65
|
-
a: {y: 0, height: 10, inLayout: false},
|
|
66
|
-
b: {y: 10, height: 30, inLayout: true},
|
|
67
|
-
c: {y: 40, height: 40, inLayout: true},
|
|
68
|
-
d: {y: 80, height: 20, inLayout: false},
|
|
69
|
-
};
|
|
70
|
-
const result = computeResult({helper, state: {last: 3}});
|
|
71
|
-
expect(result.event.blankness).toBe(0.3);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it('sampling rate can disable', function() {
|
|
75
|
-
const helper = new FillRateHelper(getFrameMetrics);
|
|
76
|
-
rowFramesGlobal = {
|
|
77
|
-
a: {y: 0, height: 40, inLayout: true},
|
|
78
|
-
b: {y: 40, height: 40, inLayout: true},
|
|
79
|
-
};
|
|
80
|
-
let result = computeResult({helper});
|
|
81
|
-
expect(result.event.blankness).toBe(0.2);
|
|
82
|
-
|
|
83
|
-
FillRateHelper.setSampleRate(0);
|
|
84
|
-
|
|
85
|
-
result = computeResult({helper});
|
|
86
|
-
expect(result).toBeNull();
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('can handle multiple listeners and unsubscribe', function() {
|
|
90
|
-
const listeners = [jest.fn(), jest.fn(), jest.fn()];
|
|
91
|
-
const subscriptions = listeners.map(
|
|
92
|
-
(listener) => FillRateHelper.addFillRateExceededListener(listener)
|
|
93
|
-
);
|
|
94
|
-
subscriptions[1].remove();
|
|
95
|
-
const helper = new FillRateHelper(getFrameMetrics);
|
|
96
|
-
rowFramesGlobal = {
|
|
97
|
-
a: {y: 0, height: 40, inLayout: true},
|
|
98
|
-
b: {y: 40, height: 40, inLayout: true},
|
|
99
|
-
};
|
|
100
|
-
const result = computeResult({helper});
|
|
101
|
-
expect(result.event.blankness).toBe(0.2);
|
|
102
|
-
expect(listeners[0]).toBeCalledWith(result);
|
|
103
|
-
expect(listeners[1]).not.toBeCalled();
|
|
104
|
-
expect(listeners[2]).toBeCalledWith(result);
|
|
105
|
-
});
|
|
106
|
-
});
|