@react-native-tvos/virtualized-lists 0.76.2-0 → 0.77.0-0rc1
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.
|
@@ -4,13 +4,12 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
|
-
* @format
|
|
8
7
|
* @flow strict-local
|
|
8
|
+
* @format
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const {InteractionManager} = require('react-native');
|
|
11
|
+
import {InteractionManager} from 'react-native';
|
|
12
|
+
import * as ReactNativeFeatureFlags from 'react-native/src/private/featureflags/ReactNativeFeatureFlags';
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
15
|
* A simple class for batching up invocations of a low-pri callback. A timeout is set to run the
|
|
@@ -38,37 +37,47 @@ class Batchinator {
|
|
|
38
37
|
_callback: () => void;
|
|
39
38
|
_delay: number;
|
|
40
39
|
_taskHandle: ?{cancel: () => void, ...};
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
|
|
41
|
+
constructor(callback: () => void, delay: number) {
|
|
42
|
+
this._delay = delay;
|
|
43
43
|
this._callback = callback;
|
|
44
44
|
}
|
|
45
|
+
|
|
45
46
|
/*
|
|
46
47
|
* Cleanup any pending tasks.
|
|
47
48
|
*
|
|
48
49
|
* By default, if there is a pending task the callback is run immediately. Set the option abort to
|
|
49
50
|
* true to not call the callback if it was pending.
|
|
50
51
|
*/
|
|
51
|
-
dispose(
|
|
52
|
+
dispose(): void {
|
|
52
53
|
if (this._taskHandle) {
|
|
53
54
|
this._taskHandle.cancel();
|
|
54
|
-
if (!options.abort) {
|
|
55
|
-
this._callback();
|
|
56
|
-
}
|
|
57
55
|
this._taskHandle = null;
|
|
58
56
|
}
|
|
59
57
|
}
|
|
60
|
-
|
|
58
|
+
|
|
59
|
+
schedule(): void {
|
|
61
60
|
if (this._taskHandle) {
|
|
62
61
|
return;
|
|
63
62
|
}
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
63
|
+
const invokeCallback = () => {
|
|
64
|
+
// Note that we clear the handle before invoking the callback so that if the callback calls
|
|
65
|
+
// schedule again, it will actually schedule another task.
|
|
66
|
+
this._taskHandle = null;
|
|
67
|
+
this._callback();
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const timeoutHandle = setTimeout(
|
|
71
|
+
// NOTE: When shipping this, delete `Batchinator` instead of only these
|
|
72
|
+
// lines of code. Without `InteractionManager`, it's just a `setTimeout`.
|
|
73
|
+
ReactNativeFeatureFlags.disableInteractionManagerInBatchinator()
|
|
74
|
+
? invokeCallback
|
|
75
|
+
: () => {
|
|
76
|
+
this._taskHandle =
|
|
77
|
+
InteractionManager.runAfterInteractions(invokeCallback);
|
|
78
|
+
},
|
|
79
|
+
this._delay,
|
|
80
|
+
);
|
|
72
81
|
this._taskHandle = {cancel: () => clearTimeout(timeoutHandle)};
|
|
73
82
|
}
|
|
74
83
|
}
|
|
@@ -167,6 +167,30 @@ export default class ListMetricsAggregator {
|
|
|
167
167
|
// check for invalid frames due to row re-ordering
|
|
168
168
|
return frame;
|
|
169
169
|
} else {
|
|
170
|
+
let offset;
|
|
171
|
+
|
|
172
|
+
const highestMeasuredCellIndex = this.getHighestMeasuredCellIndex();
|
|
173
|
+
if (highestMeasuredCellIndex < index) {
|
|
174
|
+
// If any of the cells before this one have been laid out already, we
|
|
175
|
+
// should use that information in the estimations.
|
|
176
|
+
// This is important because if the list has a header, the initial cell
|
|
177
|
+
// will have a larger offset that we should take into account here.
|
|
178
|
+
const highestMeasuredCellFrame = this.getCellMetrics(
|
|
179
|
+
highestMeasuredCellIndex,
|
|
180
|
+
props,
|
|
181
|
+
);
|
|
182
|
+
if (highestMeasuredCellFrame) {
|
|
183
|
+
offset =
|
|
184
|
+
highestMeasuredCellFrame.offset +
|
|
185
|
+
highestMeasuredCellFrame.length +
|
|
186
|
+
this._averageCellLength * (index - highestMeasuredCellIndex - 1);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (offset == null) {
|
|
191
|
+
offset = this._averageCellLength * index;
|
|
192
|
+
}
|
|
193
|
+
|
|
170
194
|
const {data, getItemCount} = props;
|
|
171
195
|
invariant(
|
|
172
196
|
index >= 0 && index < getItemCount(data),
|
|
@@ -174,7 +198,7 @@ export default class ListMetricsAggregator {
|
|
|
174
198
|
);
|
|
175
199
|
return {
|
|
176
200
|
length: this._averageCellLength,
|
|
177
|
-
offset
|
|
201
|
+
offset,
|
|
178
202
|
index,
|
|
179
203
|
isMounted: false,
|
|
180
204
|
};
|
|
@@ -35,7 +35,7 @@ export type ViewabilityConfigCallbackPair = {
|
|
|
35
35
|
...
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
export type ViewabilityConfig = {|
|
|
38
|
+
export type ViewabilityConfig = $ReadOnly<{|
|
|
39
39
|
/**
|
|
40
40
|
* Minimum amount of time (in milliseconds) that an item must be physically viewable before the
|
|
41
41
|
* viewability callback will be fired. A high number means that scrolling through content without
|
|
@@ -62,7 +62,7 @@ export type ViewabilityConfig = {|
|
|
|
62
62
|
* render.
|
|
63
63
|
*/
|
|
64
64
|
waitForInteraction?: boolean,
|
|
65
|
-
|}
|
|
65
|
+
|}>;
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
68
|
* A Utility class for calculating viewable items based on current metrics like scroll position and
|
package/Lists/VirtualizedList.js
CHANGED
|
@@ -357,7 +357,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
|
|
357
357
|
|
|
358
358
|
_registerAsNestedChild = (childList: {
|
|
359
359
|
cellKey: string,
|
|
360
|
-
ref:
|
|
360
|
+
ref: VirtualizedList,
|
|
361
361
|
}): void => {
|
|
362
362
|
this._nestedChildLists.add(childList.ref, childList.cellKey);
|
|
363
363
|
if (this._hasInteracted) {
|
|
@@ -365,9 +365,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
|
|
365
365
|
}
|
|
366
366
|
};
|
|
367
367
|
|
|
368
|
-
_unregisterAsNestedChild = (childList: {
|
|
369
|
-
ref: React.ElementRef<typeof VirtualizedList>,
|
|
370
|
-
}): void => {
|
|
368
|
+
_unregisterAsNestedChild = (childList: {ref: VirtualizedList}): void => {
|
|
371
369
|
this._nestedChildLists.remove(childList.ref);
|
|
372
370
|
};
|
|
373
371
|
|
|
@@ -690,7 +688,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
|
|
690
688
|
if (this._isNestedWithSameOrientation()) {
|
|
691
689
|
this.context.unregisterAsNestedChild({ref: this});
|
|
692
690
|
}
|
|
693
|
-
this._updateCellsToRenderBatcher.dispose(
|
|
691
|
+
this._updateCellsToRenderBatcher.dispose();
|
|
694
692
|
this._viewabilityTuples.forEach(tuple => {
|
|
695
693
|
tuple.viewabilityHelper.dispose();
|
|
696
694
|
});
|
|
@@ -1200,7 +1198,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
|
|
1200
1198
|
}
|
|
1201
1199
|
|
|
1202
1200
|
componentDidUpdate(prevProps: Props) {
|
|
1203
|
-
const {data, extraData} = this.props;
|
|
1201
|
+
const {data, extraData, getItemLayout} = this.props;
|
|
1204
1202
|
if (data !== prevProps.data || extraData !== prevProps.extraData) {
|
|
1205
1203
|
// clear the viewableIndices cache to also trigger
|
|
1206
1204
|
// the onViewableItemsChanged callback with the new data
|
|
@@ -1221,6 +1219,14 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
|
|
1221
1219
|
if (hiPriInProgress) {
|
|
1222
1220
|
this._hiPriInProgress = false;
|
|
1223
1221
|
}
|
|
1222
|
+
|
|
1223
|
+
// We only call `onEndReached` after we render the last cell, but when
|
|
1224
|
+
// getItemLayout is present, we can scroll past the last rendered cell, and
|
|
1225
|
+
// never trigger a new layout or bounds change, so we need to check again
|
|
1226
|
+
// after rendering more cells.
|
|
1227
|
+
if (getItemLayout != null) {
|
|
1228
|
+
this._maybeCallOnEdgeReached();
|
|
1229
|
+
}
|
|
1224
1230
|
}
|
|
1225
1231
|
|
|
1226
1232
|
_cellRefs: {[string]: null | CellRenderer<any>} = {};
|
|
@@ -1536,6 +1542,14 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
|
|
1536
1542
|
onEndReached,
|
|
1537
1543
|
onEndReachedThreshold,
|
|
1538
1544
|
} = this.props;
|
|
1545
|
+
// Wait until we have real metrics
|
|
1546
|
+
if (
|
|
1547
|
+
!this._listMetrics.hasContentLength() ||
|
|
1548
|
+
this._scrollMetrics.visibleLength === 0
|
|
1549
|
+
) {
|
|
1550
|
+
return;
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1539
1553
|
// If we have any pending scroll updates it means that the scroll metrics
|
|
1540
1554
|
// are out of date and we should not call any of the edge reached callbacks.
|
|
1541
1555
|
if (this.state.pendingScrollUpdateCount > 0) {
|
|
@@ -1679,6 +1693,10 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
|
|
1679
1693
|
};
|
|
1680
1694
|
};
|
|
1681
1695
|
|
|
1696
|
+
unstable_onScroll(e: Object) {
|
|
1697
|
+
this._onScroll(e);
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1682
1700
|
_onScroll = (e: Object) => {
|
|
1683
1701
|
this._nestedChildLists.forEach(childList => {
|
|
1684
1702
|
childList._onScroll(e);
|
|
@@ -1784,7 +1802,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
|
|
1784
1802
|
this._hiPriInProgress = true;
|
|
1785
1803
|
// Don't worry about interactions when scrolling quickly; focus on filling content as fast
|
|
1786
1804
|
// as possible.
|
|
1787
|
-
this._updateCellsToRenderBatcher.dispose(
|
|
1805
|
+
this._updateCellsToRenderBatcher.dispose();
|
|
1788
1806
|
this._updateCellsToRender();
|
|
1789
1807
|
return;
|
|
1790
1808
|
} else {
|
|
@@ -1831,6 +1849,10 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
|
|
1831
1849
|
return hiPri;
|
|
1832
1850
|
}
|
|
1833
1851
|
|
|
1852
|
+
unstable_onScrollBeginDrag(e: ScrollEvent) {
|
|
1853
|
+
this._onScrollBeginDrag(e);
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1834
1856
|
_onScrollBeginDrag = (e: ScrollEvent): void => {
|
|
1835
1857
|
this._nestedChildLists.forEach(childList => {
|
|
1836
1858
|
childList._onScrollBeginDrag(e);
|
|
@@ -1842,6 +1864,10 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
|
|
1842
1864
|
this.props.onScrollBeginDrag && this.props.onScrollBeginDrag(e);
|
|
1843
1865
|
};
|
|
1844
1866
|
|
|
1867
|
+
unstable_onScrollEndDrag(e: ScrollEvent) {
|
|
1868
|
+
this._onScrollEndDrag(e);
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1845
1871
|
_onScrollEndDrag = (e: ScrollEvent): void => {
|
|
1846
1872
|
this._nestedChildLists.forEach(childList => {
|
|
1847
1873
|
childList._onScrollEndDrag(e);
|
|
@@ -1854,6 +1880,10 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
|
|
1854
1880
|
this.props.onScrollEndDrag && this.props.onScrollEndDrag(e);
|
|
1855
1881
|
};
|
|
1856
1882
|
|
|
1883
|
+
unstable_onMomentumScrollBegin(e: ScrollEvent) {
|
|
1884
|
+
this._onMomentumScrollBegin(e);
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1857
1887
|
_onMomentumScrollBegin = (e: ScrollEvent): void => {
|
|
1858
1888
|
this._nestedChildLists.forEach(childList => {
|
|
1859
1889
|
childList._onMomentumScrollBegin(e);
|
|
@@ -1861,6 +1891,10 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
|
|
|
1861
1891
|
this.props.onMomentumScrollBegin && this.props.onMomentumScrollBegin(e);
|
|
1862
1892
|
};
|
|
1863
1893
|
|
|
1894
|
+
unstable_onMomentumScrollEnd(e: ScrollEvent) {
|
|
1895
|
+
this._onMomentumScrollEnd(e);
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1864
1898
|
_onMomentumScrollEnd = (e: ScrollEvent): void => {
|
|
1865
1899
|
this._nestedChildLists.forEach(childList => {
|
|
1866
1900
|
childList._onMomentumScrollEnd(e);
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
* @format
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import * as ReactNativeFeatureFlags from 'react-native/src/private/featureflags/ReactNativeFeatureFlags';
|
|
12
11
|
import type {CellRendererProps, RenderItemType} from './VirtualizedListProps';
|
|
13
12
|
import type {ViewStyleProp} from 'react-native/Libraries/StyleSheet/StyleSheet';
|
|
14
13
|
import type {
|
|
@@ -69,17 +68,7 @@ export default class CellRenderer<ItemT> extends React.PureComponent<
|
|
|
69
68
|
props: Props<ItemT>,
|
|
70
69
|
prevState: State<ItemT>,
|
|
71
70
|
): ?State<ItemT> {
|
|
72
|
-
if (
|
|
73
|
-
if (props.item !== prevState.separatorProps.leadingItem) {
|
|
74
|
-
return {
|
|
75
|
-
separatorProps: {
|
|
76
|
-
...prevState.separatorProps,
|
|
77
|
-
leadingItem: props.item,
|
|
78
|
-
},
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
return null;
|
|
82
|
-
} else {
|
|
71
|
+
if (props.item !== prevState.separatorProps.leadingItem) {
|
|
83
72
|
return {
|
|
84
73
|
separatorProps: {
|
|
85
74
|
...prevState.separatorProps,
|
|
@@ -87,6 +76,7 @@ export default class CellRenderer<ItemT> extends React.PureComponent<
|
|
|
87
76
|
},
|
|
88
77
|
};
|
|
89
78
|
}
|
|
79
|
+
return null;
|
|
90
80
|
}
|
|
91
81
|
|
|
92
82
|
// TODO: consider factoring separator stuff out of VirtualizedList into FlatList since it's not
|
|
@@ -146,7 +146,7 @@ class VirtualizedSectionList<
|
|
|
146
146
|
this._listRef.scrollToIndex(toIndexParams);
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
getListRef(): ?
|
|
149
|
+
getListRef(): ?VirtualizedList {
|
|
150
150
|
return this._listRef;
|
|
151
151
|
}
|
|
152
152
|
|
|
@@ -598,14 +598,12 @@ function ItemWithSeparator(props: ItemWithSeparatorProps): React.Node {
|
|
|
598
598
|
);
|
|
599
599
|
}
|
|
600
600
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
}>,
|
|
611
|
-
>);
|
|
601
|
+
module.exports = VirtualizedSectionList as component(
|
|
602
|
+
ref: React.RefSetter<
|
|
603
|
+
interface {
|
|
604
|
+
getListRef(): ?VirtualizedList,
|
|
605
|
+
scrollToLocation(params: ScrollToLocationParamsType): void,
|
|
606
|
+
},
|
|
607
|
+
>,
|
|
608
|
+
...Props<SectionBase<any>>
|
|
609
|
+
);
|