Skip to content

Commit

Permalink
Add VirtualizedList_EXPERIMENTAL (CellRenderMask Usage)
Browse files Browse the repository at this point in the history
Summary:
# This Change

react-native-community/discussions-and-proposals#335  discussed a set of problems with VirtualizedList and focus. These were seen as severe externally for a11y on desktop. The issues center on users of keyboard and accessibility tools, where users expect to be able to move focus in an uninterrupted loop.

The design and implementation evolved to be a bit more general, and without any API-surface behavior changes. It was implemented and rolled out externally as a series of changes. The remaining changes that were not upstreamed into RN are rolled into #32646

This diff brings this change into the repo, as a separate copy of VirtualizedList, to measure its impact to guardrail metrics, without yet making it the default implementation. The intention is for this to be temporary, until there is confidence the implementation is correct.

## List Implementation (more on GitHub)

This change makes it possible to synchronously move native focus to arbitrary items in a VirtualizedList. This is implemented by switching component state to a sparse bitset. This was previously implemented and upstreamed as `CellRenderMask`.

A usage of this is added, to keep the last focused item rendered. This allows the focus loop to remain unbroken, when scrolling away, or tab loops which leave/re-enter the list.

VirtualizedList tracks the last focused cell through the capture phase of `onFocus`. It will keep the cell, and a viewport above and below the last focused cell rendered, to allow movement to it without blanking (without using too much memory).

## Experimentation Implementation

A mechanism is added to gate the change via VirtualizedListInjection, mirroring the approach taken for Switch with D27381306 (683b825).

It allows VirtualizedList to delegate to a global override. It has a slight penalty to needing to import both modules, but means code which imports VirtualizedList directly is affected the changes.

Changelog:
[Internal][Added] - Add VirtualizedList_EXPERIMENTAL (CellRenderMask Usage)

Reviewed By: lunaleaps

Differential Revision: D38020408

fbshipit-source-id: ad0aaa6791f3f4455e3068502a2841f3ffb40b41
  • Loading branch information
NickGerleman authored and roryabraham committed Aug 17, 2022
1 parent 57ae992 commit 3872212
Show file tree
Hide file tree
Showing 8 changed files with 8,008 additions and 5 deletions.
4 changes: 4 additions & 0 deletions Libraries/Lists/CellRenderMask.js
Expand Up @@ -110,6 +110,10 @@ export class CellRenderMask {
);
}

numCells(): number {
return this._numCells;
}

equals(other: CellRenderMask): boolean {
return (
this._numCells === other._numCells &&
Expand Down
2 changes: 0 additions & 2 deletions Libraries/Lists/VirtualizeUtils.js
Expand Up @@ -102,7 +102,6 @@ export function computeWindowedRenderLimits(
prev: {
first: number,
last: number,
...
},
getFrameMetricsApprox: (index: number) => {
length: number,
Expand All @@ -120,7 +119,6 @@ export function computeWindowedRenderLimits(
): {
first: number,
last: number,
...
} {
const itemCount = getItemCount(data);
if (itemCount === 0) {
Expand Down
3 changes: 2 additions & 1 deletion Libraries/Lists/VirtualizedList.js
Expand Up @@ -2217,4 +2217,5 @@ const styles = StyleSheet.create({
},
});

module.exports = VirtualizedList;
module.exports = (require('./VirtualizedListInjection').default
.unstable_VirtualizedList ?? VirtualizedList: typeof VirtualizedList);
16 changes: 16 additions & 0 deletions Libraries/Lists/VirtualizedListInjection.js
@@ -0,0 +1,16 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/

'use strict';
import typeof VirtualizedList from './VirtualizedList';

export default {
unstable_VirtualizedList: (null: ?VirtualizedList),
};

0 comments on commit 3872212

Please sign in to comment.