@react-native-tvos/virtualized-lists 0.76.6-0 → 0.77.0-0

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
- 'use strict';
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
- constructor(callback: () => void, delayMS: number) {
42
- this._delay = delayMS;
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(options: {abort: boolean, ...} = {abort: false}) {
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
- schedule() {
58
+
59
+ schedule(): void {
61
60
  if (this._taskHandle) {
62
61
  return;
63
62
  }
64
- const timeoutHandle = setTimeout(() => {
65
- this._taskHandle = InteractionManager.runAfterInteractions(() => {
66
- // Note that we clear the handle before invoking the callback so that if the callback calls
67
- // schedule again, it will actually schedule another task.
68
- this._taskHandle = null;
69
- this._callback();
70
- });
71
- }, this._delay);
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: this._averageCellLength * index,
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
@@ -357,7 +357,7 @@ class VirtualizedList extends StateSafePureComponent<Props, State> {
357
357
 
358
358
  _registerAsNestedChild = (childList: {
359
359
  cellKey: string,
360
- ref: React.ElementRef<typeof VirtualizedList>,
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({abort: true});
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({abort: true});
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 (ReactNativeFeatureFlags.enableOptimisedVirtualizedCells()) {
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(): ?React.ElementRef<typeof VirtualizedList> {
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
- /* $FlowFixMe[class-object-subtyping] added when improving typing for this
602
- * parameters */
603
- // $FlowFixMe[method-unbinding]
604
- module.exports = (VirtualizedSectionList: React.AbstractComponent<
605
- React.ElementConfig<typeof VirtualizedSectionList>,
606
- $ReadOnly<{
607
- getListRef: () => ?React.ElementRef<typeof VirtualizedList>,
608
- scrollToLocation: (params: ScrollToLocationParamsType) => void,
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
+ );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-native-tvos/virtualized-lists",
3
- "version": "0.76.6-0",
3
+ "version": "0.77.0-0",
4
4
  "description": "Virtualized lists for React Native.",
5
5
  "license": "MIT",
6
6
  "repository": {