From c74354925994cb2142fb5229f08335dbcafa8715 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Tue, 19 Jul 2022 15:13:32 -0700 Subject: [PATCH 1/3] Keyboard navigation in Flatlist (#1258) * add pull yml * match handleOpenURLNotification event payload with iOS (#755) (#2) Co-authored-by: Ryan Linton * [pull] master from microsoft:master (#11) * Deprecated api (#853) * Remove deprecated/unused context param * Update a few Mac deprecated APIs * Packing RN dependencies, hermes and ignoring javadoc failure, (#852) * Ignore javadoc failure * Bringing few more changes from 0.63-stable * Fixing a patch in engine selection * Fixing a patch in nuget spec * Fixing the output directory of nuget pack * Packaging dependencies in the nuget * Fix onMouseEnter/onMouseLeave callbacks not firing on Pressable (#855) * add pull yml * match handleOpenURLNotification event payload with iOS (#755) (#2) Co-authored-by: Ryan Linton * fix mouse evetns on pressable * delete extra yml from this branch * Add macOS tags * reorder props to have onMouseEnter/onMouseLeave always be before onPress Co-authored-by: pull[bot] <39814207+pull[bot]@users.noreply.github.com> Co-authored-by: Ryan Linton * Grammar fixes. (#856) Updates simple grammar issues. Co-authored-by: Nick Trescases <42704557+ntre@users.noreply.github.com> Co-authored-by: Anandraj Co-authored-by: Saad Najmi Co-authored-by: pull[bot] <39814207+pull[bot]@users.noreply.github.com> Co-authored-by: Ryan Linton Co-authored-by: Muhammad Hamza Zaman * wip * wip * more wip * Home/End/OptionUp/OptionDown work * ensureItemAtIndexIsVisible works * Home/End work * Initial cleanup for PR * More cleanup * More cleanup * Make it a real prop * No need for client code * Don't move keyboard focus with selection * Update tags * Fix flow errors * Update colors, make ScrollView focusable * prettier * undo change * Fix flow errors * Clean up code + handle page up/down with new prop Co-authored-by: pull[bot] <39814207+pull[bot]@users.noreply.github.com> Co-authored-by: Ryan Linton Co-authored-by: Nick Trescases <42704557+ntre@users.noreply.github.com> Co-authored-by: Anandraj Co-authored-by: Muhammad Hamza Zaman --- Libraries/Components/ScrollView/ScrollView.js | 40 +----- Libraries/Lists/VirtualizedList.js | 119 ++++++++++++------ React/Views/ScrollView/RCTScrollView.m | 57 +++++---- React/Views/UIView+React.m | 28 +++-- .../js/components/ListExampleShared.js | 32 ++++- .../js/examples/FlatList/FlatListExample.js | 19 ++- 6 files changed, 182 insertions(+), 113 deletions(-) diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index 541245effac1c2..95214edcef6045 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -1201,42 +1201,10 @@ class ScrollView extends React.Component { nativeEvent.contentOffset.y + nativeEvent.layoutMeasurement.height, }); - } else if (key === 'LEFT_ARROW') { - this._handleScrollByKeyDown(event, { - x: - nativeEvent.contentOffset.x + - -(this.props.horizontalLineScroll !== undefined - ? this.props.horizontalLineScroll - : kMinScrollOffset), - y: nativeEvent.contentOffset.y, - }); - } else if (key === 'RIGHT_ARROW') { - this._handleScrollByKeyDown(event, { - x: - nativeEvent.contentOffset.x + - (this.props.horizontalLineScroll !== undefined - ? this.props.horizontalLineScroll - : kMinScrollOffset), - y: nativeEvent.contentOffset.y, - }); - } else if (key === 'DOWN_ARROW') { - this._handleScrollByKeyDown(event, { - x: nativeEvent.contentOffset.x, - y: - nativeEvent.contentOffset.y + - (this.props.verticalLineScroll !== undefined - ? this.props.verticalLineScroll - : kMinScrollOffset), - }); - } else if (key === 'UP_ARROW') { - this._handleScrollByKeyDown(event, { - x: nativeEvent.contentOffset.x, - y: - nativeEvent.contentOffset.y + - -(this.props.verticalLineScroll !== undefined - ? this.props.verticalLineScroll - : kMinScrollOffset), - }); + } else if (key === 'HOME') { + this.scrollTo({x: 0, y: 0}); + } else if (key === 'END') { + this.scrollToEnd({animated: true}); } } } diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index 1422f27a444fd5..e04fc2179c0155 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -588,7 +588,7 @@ class VirtualizedList extends React.PureComponent { const newOffset = Math.min(contentLength, visTop + (frameEnd - visEnd)); this.scrollToOffset({offset: newOffset}); } else if (frame.offset < visTop) { - const newOffset = Math.max(0, visTop - frame.length); + const newOffset = Math.min(frame.offset, visTop - frame.length); this.scrollToOffset({offset: newOffset}); } } @@ -882,7 +882,13 @@ class VirtualizedList extends React.PureComponent { index={ii} inversionStyle={inversionStyle} item={item} - isSelected={this.state.selectedRowIndex === ii ? true : false} // TODO(macOS GH#774) + // [TODO(macOS GH#774) + isSelected={ + this.props.enableSelectionOnKeyPress && + this.state.selectedRowIndex === ii + ? true + : false + } // TODO(macOS GH#774)] key={key} prevCellKey={prevCellKey} onUpdateSeparators={this._onUpdateSeparators} @@ -1323,10 +1329,12 @@ class VirtualizedList extends React.PureComponent { // $FlowFixMe[prop-missing] Invalid prop usage { // $FlowFixMe Invalid prop usage ); } @@ -1507,6 +1515,13 @@ class VirtualizedList extends React.PureComponent { return rowAbove; }; + _selectRowAtIndex = rowIndex => { + this.setState(state => { + return {selectedRowIndex: rowIndex}; + }); + return rowIndex; + }; + _selectRowBelowIndex = rowIndex => { if (this.props.getItemCount) { const {data} = this.props; @@ -1521,14 +1536,14 @@ class VirtualizedList extends React.PureComponent { } }; - _handleKeyDown = (e: ScrollEvent) => { + _handleKeyDown = (event: ScrollEvent) => { if (this.props.onScrollKeyDown) { - this.props.onScrollKeyDown(e); + this.props.onScrollKeyDown(event); } else { if (Platform.OS === 'macos') { // $FlowFixMe Cannot get e.nativeEvent because property nativeEvent is missing in Event - const event = e.nativeEvent; - const key = event.key; + const nativeEvent = event.nativeEvent; + const key = nativeEvent.key; let prevIndex = -1; let newIndex = -1; @@ -1536,46 +1551,66 @@ class VirtualizedList extends React.PureComponent { prevIndex = this.state.selectedRowIndex; } - const {data, getItem} = this.props; - if (key === 'DOWN_ARROW') { - newIndex = this._selectRowBelowIndex(prevIndex); - this.ensureItemAtIndexIsVisible(newIndex); - - if (prevIndex !== newIndex) { - const item = getItem(data, newIndex); - if (this.props.onSelectionChanged) { - this.props.onSelectionChanged({ - previousSelection: prevIndex, - newSelection: newIndex, - item: item, - }); - } - } - } else if (key === 'UP_ARROW') { + // const {data, getItem} = this.props; + if (key === 'UP_ARROW') { newIndex = this._selectRowAboveIndex(prevIndex); - this.ensureItemAtIndexIsVisible(newIndex); - - if (prevIndex !== newIndex) { - const item = getItem(data, newIndex); - if (this.props.onSelectionChanged) { - this.props.onSelectionChanged({ - previousSelection: prevIndex, - newSelection: newIndex, - item: item, - }); - } - } + this._handleSelectionChange(prevIndex, newIndex); + } else if (key === 'DOWN_ARROW') { + newIndex = this._selectRowBelowIndex(prevIndex); + this._handleSelectionChange(prevIndex, newIndex); } else if (key === 'ENTER') { if (this.props.onSelectionEntered) { - const item = getItem(data, prevIndex); + const item = this.props.getItem(this.props.data, prevIndex); if (this.props.onSelectionEntered) { this.props.onSelectionEntered(item); } } + } else if (key === 'OPTION_UP') { + newIndex = this._selectRowAtIndex(0); + this._handleSelectionChange(prevIndex, newIndex); + } else if (key === 'OPTION_DOWN') { + newIndex = this._selectRowAtIndex(this.state.last); + this._handleSelectionChange(prevIndex, newIndex); + } else if (key === 'PAGE_UP') { + const maxY = + event.nativeEvent.contentSize.height - + event.nativeEvent.layoutMeasurement.height; + const newOffset = Math.min( + maxY, + nativeEvent.contentOffset.y + -nativeEvent.layoutMeasurement.height, + ); + this.scrollToOffset({animated: true, offset: newOffset}); + } else if (key === 'PAGE_DOWN') { + const maxY = + event.nativeEvent.contentSize.height - + event.nativeEvent.layoutMeasurement.height; + const newOffset = Math.min( + maxY, + nativeEvent.contentOffset.y + nativeEvent.layoutMeasurement.height, + ); + this.scrollToOffset({animated: true, offset: newOffset}); + } else if (key === 'HOME') { + this.scrollToOffset({animated: true, offset: 0}); + } else if (key === 'END') { + this.scrollToEnd({animated: true}); } } } }; + + _handleSelectionChange = (prevIndex, newIndex) => { + this.ensureItemAtIndexIsVisible(newIndex); + if (prevIndex !== newIndex) { + const item = this.props.getItem(this.props.data, newIndex); + if (this.props.onSelectionChanged) { + this.props.onSelectionChanged({ + previousSelection: prevIndex, + newSelection: newIndex, + item: item, + }); + } + } + }; // ]TODO(macOS GH#774) _renderDebugOverlay() { @@ -2182,6 +2217,7 @@ class CellRenderer extends React.Component< return React.createElement(ListItemComponent, { item, index, + isSelected, separators: this._separators, }); } @@ -2258,6 +2294,7 @@ class CellRenderer extends React.Component< {itemSeparator} ); + // TODO(macOS GH#774)] return ( diff --git a/React/Views/ScrollView/RCTScrollView.m b/React/Views/ScrollView/RCTScrollView.m index 5ae6d4bd4e7dfc..807025f884e331 100644 --- a/React/Views/ScrollView/RCTScrollView.m +++ b/React/Views/ScrollView/RCTScrollView.m @@ -1180,16 +1180,22 @@ - (void)uiManagerWillPerformMounting:(RCTUIManager *)manager #if TARGET_OS_OSX // [TODO(macOS GH#774) -- (NSString*)keyCommandFromKeyCode:(NSInteger)keyCode +- (NSString*)keyCommandFromKeyCode:(NSInteger)keyCode modifierFlags:(NSEventModifierFlags)modifierFlags { switch (keyCode) { case 36: return @"ENTER"; + case 115: + return @"HOME"; + case 116: return @"PAGE_UP"; + case 119: + return @"END"; + case 121: return @"PAGE_DOWN"; @@ -1200,10 +1206,18 @@ - (NSString*)keyCommandFromKeyCode:(NSInteger)keyCode return @"RIGHT_ARROW"; case 125: - return @"DOWN_ARROW"; + if (modifierFlags & NSEventModifierFlagOption) { + return @"OPTION_DOWN"; + } else { + return @"DOWN_ARROW"; + } case 126: - return @"UP_ARROW"; + if (modifierFlags & NSEventModifierFlagOption) { + return @"OPTION_UP"; + } else { + return @"UP_ARROW"; + } } return @""; } @@ -1211,24 +1225,25 @@ - (NSString*)keyCommandFromKeyCode:(NSInteger)keyCode - (void)keyDown:(UIEvent*)theEvent { // Don't emit a scroll event if tab was pressed while the scrollview is first responder - if (self == [[self window] firstResponder] && - theEvent.keyCode != 48) { - NSString *keyCommand = [self keyCommandFromKeyCode:theEvent.keyCode]; - RCT_SEND_SCROLL_EVENT(onScrollKeyDown, (@{ @"key": keyCommand})); - } else { - [super keyDown:theEvent]; - - // AX: if a tab key was pressed and the first responder is currently clipped by the scroll view, - // automatically scroll to make the view visible to make it navigable via keyboard. - if ([theEvent keyCode] == 48) { //tab key - id firstResponder = [[self window] firstResponder]; - if ([firstResponder isKindOfClass:[NSView class]] && - [firstResponder isDescendantOf:[_scrollView documentView]]) { - NSView *view = (NSView*)firstResponder; - NSRect visibleRect = ([view superview] == [_scrollView documentView]) ? NSInsetRect(view.frame, -1, -1) : - [view convertRect:view.frame toView:_scrollView.documentView]; - [[_scrollView documentView] scrollRectToVisible:visibleRect]; - } + if (!(self == [[self window] firstResponder] && theEvent.keyCode == 48)) { + NSString *keyCommand = [self keyCommandFromKeyCode:theEvent.keyCode modifierFlags:theEvent.modifierFlags]; + if (![keyCommand isEqual: @""]) { + RCT_SEND_SCROLL_EVENT(onScrollKeyDown, (@{ @"key": keyCommand})); + } else { + [super keyDown:theEvent]; + } + } + + // AX: if a tab key was pressed and the first responder is currently clipped by the scroll view, + // automatically scroll to make the view visible to make it navigable via keyboard. + if ([theEvent keyCode] == 48) { //tab key + id firstResponder = [[self window] firstResponder]; + if ([firstResponder isKindOfClass:[NSView class]] && + [firstResponder isDescendantOf:[_scrollView documentView]]) { + NSView *view = (NSView*)firstResponder; + NSRect visibleRect = ([view superview] == [_scrollView documentView]) ? NSInsetRect(view.frame, -1, -1) : + [view convertRect:view.frame toView:_scrollView.documentView]; + [[_scrollView documentView] scrollRectToVisible:visibleRect]; } } } diff --git a/React/Views/UIView+React.m b/React/Views/UIView+React.m index 14a58f1cf79f7b..604790b3de9ba4 100644 --- a/React/Views/UIView+React.m +++ b/React/Views/UIView+React.m @@ -285,29 +285,37 @@ - (void)setReactIsFocusNeeded:(BOOL)isFocusNeeded - (void)reactFocus { - if (![self becomeFirstResponder]) { - self.reactIsFocusNeeded = YES; - } +#if TARGET_OS_OSX // [TODO(macOS GH#774) + if (![[self window] makeFirstResponder:self]) { +#else + if (![self becomeFirstResponder]) { +#endif //// TODO(macOS GH#774)] + self.reactIsFocusNeeded = YES; + } } - (void)reactFocusIfNeeded { - if (self.reactIsFocusNeeded) { - if ([self becomeFirstResponder]) { - self.reactIsFocusNeeded = NO; - } - } + if (self.reactIsFocusNeeded) { +#if TARGET_OS_OSX // [TODO(macOS GH#774) + if ([[self window] makeFirstResponder:self]) { +#else + if ([self becomeFirstResponder]) { +#endif // TODO(macOS GH#774)] + self.reactIsFocusNeeded = NO; + } + } } - (void)reactBlur { -#if TARGET_OS_OSX // TODO(macOS GH#774) +#if TARGET_OS_OSX // [TODO(macOS GH#774) if (self == [[self window] firstResponder]) { [[self window] makeFirstResponder:[[self window] nextResponder]]; } #else [self resignFirstResponder]; -#endif +#endif // TODO(macOS GH#774)] } #pragma mark - Layout diff --git a/packages/rn-tester/js/components/ListExampleShared.js b/packages/rn-tester/js/components/ListExampleShared.js index 2312ee69c22f93..36a81d25041bb9 100644 --- a/packages/rn-tester/js/components/ListExampleShared.js +++ b/packages/rn-tester/js/components/ListExampleShared.js @@ -22,6 +22,7 @@ const { Text, TextInput, View, + PlatformColor, // TODO(macOS GH#774) } = require('react-native'); export type Item = { @@ -57,13 +58,22 @@ class ItemComponent extends React.PureComponent<{ onPress: (key: string) => void, onShowUnderlay?: () => void, onHideUnderlay?: () => void, + textSelectable?: ?boolean, + isSelected?: ?Boolean, // TODO(macOS GH#774) ... }> { _onPress = () => { this.props.onPress(this.props.item.key); }; render(): React.Node { - const {fixedHeight, horizontal, item} = this.props; + // [TODO(macOS GH#774) + const { + fixedHeight, + horizontal, + item, + textSelectable, + isSelected, + } = this.props; // TODO(macOS GH#774)] const itemHash = Math.abs(hashCode(item.title)); const imgSource = THUMB_URLS[itemHash % THUMB_URLS.length]; return ( @@ -77,11 +87,15 @@ class ItemComponent extends React.PureComponent<{ styles.row, horizontal && {width: HORIZ_WIDTH}, fixedHeight && {height: ITEM_HEIGHT}, - ]}> + isSelected && styles.selectedItem, // TODO(macOS GH#774) + ]} + > {!item.noImage && } + style={[styles.text, isSelected && styles.selectedItemText]} // TODO(macOS GH#774) + selectable={textSelectable} + numberOfLines={horizontal || fixedHeight ? 3 : undefined} + > {item.title} - {item.text} @@ -350,6 +364,16 @@ const styles = StyleSheet.create({ text: { flex: 1, }, + // [TODO(macOS GH#774) + selectedItem: { + backgroundColor: PlatformColor('selectedContentBackgroundColor'), + }, + selectedItemText: { + // This was the closest UI Element color that looked right... + // https://developer.apple.com/documentation/appkit/nscolor/ui_element_colors + color: PlatformColor('selectedMenuItemTextColor'), + }, + // [TODO(macOS GH#774)] }); module.exports = { diff --git a/packages/rn-tester/js/examples/FlatList/FlatListExample.js b/packages/rn-tester/js/examples/FlatList/FlatListExample.js index 4606d68090c628..ffd38c288343d4 100644 --- a/packages/rn-tester/js/examples/FlatList/FlatListExample.js +++ b/packages/rn-tester/js/examples/FlatList/FlatListExample.js @@ -59,6 +59,9 @@ type State = {| empty: boolean, useFlatListItemComponent: boolean, fadingEdgeLength: number, + onPressDisabled: boolean, + textSelectable: boolean, + enableSelectionOnKeyPress: boolean, // TODO(macOS GH#774)] |}; class FlatListExample extends React.PureComponent { @@ -74,6 +77,9 @@ class FlatListExample extends React.PureComponent { empty: false, useFlatListItemComponent: false, fadingEdgeLength: 0, + onPressDisabled: false, + textSelectable: true, + enableSelectionOnKeyPress: false, // TODO(macOS GH#774) }; _onChangeFilterText = filterText => { @@ -166,6 +172,13 @@ class FlatListExample extends React.PureComponent { this.state.useFlatListItemComponent, this._setBooleanValue('useFlatListItemComponent'), )} + {/* [TODO(macOS GH#774) */} + {renderSmallSwitchOption( + 'Keyboard Navigation', + this.state.enableSelectionOnKeyPress, + this._setBooleanValue('enableSelectionOnKeyPress'), + )} + {/* TODO(macOS GH#774)] */} {Platform.OS === 'android' && ( { } @@ -247,7 +261,8 @@ class FlatListExample extends React.PureComponent { /* $FlowFixMe[invalid-computed-prop] (>=0.111.0 site=react_native_fb) * This comment suppresses an error found when Flow v0.111 was deployed. * To see the error, delete this comment and run Flow. */ - [flatListPropKey]: ({item, separators}) => { + [flatListPropKey]: props => { + const {item, separators, isSelected} = props; // TODO(macOS GH#774) return ( { onPress={this._pressItem} onShowUnderlay={separators.highlight} onHideUnderlay={separators.unhighlight} + textSelectable={this.state.textSelectable} + isSelected={isSelected} // TODO(macOS GH#774) /> ); }, From 907998d21088a66e714511f4b24753c78d866453 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 21 Jul 2022 17:02:42 -0700 Subject: [PATCH 2/3] Flatlist keyboard navigation: Mouse can move selection (#1267) * add pull yml * match handleOpenURLNotification event payload with iOS (#755) (#2) Co-authored-by: Ryan Linton * [pull] master from microsoft:master (#11) * Deprecated api (#853) * Remove deprecated/unused context param * Update a few Mac deprecated APIs * Packing RN dependencies, hermes and ignoring javadoc failure, (#852) * Ignore javadoc failure * Bringing few more changes from 0.63-stable * Fixing a patch in engine selection * Fixing a patch in nuget spec * Fixing the output directory of nuget pack * Packaging dependencies in the nuget * Fix onMouseEnter/onMouseLeave callbacks not firing on Pressable (#855) * add pull yml * match handleOpenURLNotification event payload with iOS (#755) (#2) Co-authored-by: Ryan Linton * fix mouse evetns on pressable * delete extra yml from this branch * Add macOS tags * reorder props to have onMouseEnter/onMouseLeave always be before onPress Co-authored-by: pull[bot] <39814207+pull[bot]@users.noreply.github.com> Co-authored-by: Ryan Linton * Grammar fixes. (#856) Updates simple grammar issues. Co-authored-by: Nick Trescases <42704557+ntre@users.noreply.github.com> Co-authored-by: Anandraj Co-authored-by: Saad Najmi Co-authored-by: pull[bot] <39814207+pull[bot]@users.noreply.github.com> Co-authored-by: Ryan Linton Co-authored-by: Muhammad Hamza Zaman * mouse selection works too * remove pull.yml Co-authored-by: pull[bot] <39814207+pull[bot]@users.noreply.github.com> Co-authored-by: Ryan Linton Co-authored-by: Nick Trescases <42704557+ntre@users.noreply.github.com> Co-authored-by: Anandraj Co-authored-by: Muhammad Hamza Zaman --- Libraries/Lists/FlatList.js | 13 +++++++++++++ Libraries/Lists/VirtualizedList.js | 4 ++++ .../js/examples/FlatList/FlatListExample.js | 6 +++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Libraries/Lists/FlatList.js b/Libraries/Lists/FlatList.js index bda4951e24687b..d0c120d83593b0 100644 --- a/Libraries/Lists/FlatList.js +++ b/Libraries/Lists/FlatList.js @@ -369,6 +369,19 @@ class FlatList extends React.PureComponent, void> { } } + // [TODO(macOS GH#750) + /** + * Move selection to the specified index + * + * @platform ios + */ + selectRowAtIndex(index: number) { + if (this._listRef) { + this._listRef.selectRowAtIndex(index); + } + } + // ]TODO(macOS GH#750) + /** * Provides a handle to the underlying scroll responder. */ diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index e04fc2179c0155..4f44a655a68606 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -592,6 +592,10 @@ class VirtualizedList extends React.PureComponent { this.scrollToOffset({offset: newOffset}); } } + + selectRowAtIndex(rowIndex: number) { + this._selectRowAtIndex(rowIndex); + } // ]TODO(macOS GH#774) recordInteraction() { diff --git a/packages/rn-tester/js/examples/FlatList/FlatListExample.js b/packages/rn-tester/js/examples/FlatList/FlatListExample.js index ffd38c288343d4..5b979d404079f7 100644 --- a/packages/rn-tester/js/examples/FlatList/FlatListExample.js +++ b/packages/rn-tester/js/examples/FlatList/FlatListExample.js @@ -61,7 +61,7 @@ type State = {| fadingEdgeLength: number, onPressDisabled: boolean, textSelectable: boolean, - enableSelectionOnKeyPress: boolean, // TODO(macOS GH#774)] + enableSelectionOnKeyPress: boolean, // TODO(macOS GH#774) |}; class FlatListExample extends React.PureComponent { @@ -303,6 +303,10 @@ class FlatListExample extends React.PureComponent { _pressItem = (key: string) => { this._listRef && this._listRef.recordInteraction(); const index = Number(key); + // [TODO(macOS GH#774) + if (this.state.enableSelectionOnKeyPress) { + this._listRef && this._listRef.selectRowAtIndex(index); + } // ]TODO(macOS GH#774) const itemState = pressItem(this.state.data[index]); this.setState(state => ({ ...state, From 45f88a310b8cb71b5771ea883c3de451aa0d5d7a Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 21 Jul 2022 17:12:13 -0700 Subject: [PATCH 3/3] Update FlatList.js --- Libraries/Lists/FlatList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/Lists/FlatList.js b/Libraries/Lists/FlatList.js index d0c120d83593b0..604ee53041852c 100644 --- a/Libraries/Lists/FlatList.js +++ b/Libraries/Lists/FlatList.js @@ -373,7 +373,7 @@ class FlatList extends React.PureComponent, void> { /** * Move selection to the specified index * - * @platform ios + * @platform macos */ selectRowAtIndex(index: number) { if (this._listRef) {