diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 6edffb9e7467..3606089024a3 100644 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -874,6 +874,8 @@ function MoneyRequestConfirmationList({ ], ); + const canEditParticipant = isFromGlobalCreateAndCanEditParticipant && !isTestReceipt && (!isRestrictedToPreferredPolicy || isTypeInvoice); + const sections = useMemo(() => { const options: Array> = []; if (isTypeSplit) { @@ -895,8 +897,8 @@ function MoneyRequestConfirmationList({ ...participant, isSelected: false, keyForList: `${participant.keyForList ?? participant.accountID ?? participant.reportID}`, - isInteractive: isFromGlobalCreateAndCanEditParticipant && !isTestReceipt && (!isRestrictedToPreferredPolicy || isTypeInvoice), - shouldShowRightCaret: isFromGlobalCreateAndCanEditParticipant && !isTestReceipt && (!isRestrictedToPreferredPolicy || isTypeInvoice), + isInteractive: canEditParticipant, + shouldShowRightCaret: canEditParticipant, })); options.push({ @@ -907,19 +909,7 @@ function MoneyRequestConfirmationList({ } return options; - }, [ - isTypeSplit, - translate, - payeePersonalDetails, - getSplitSectionHeader, - splitParticipants, - selectedParticipants, - isFromGlobalCreateAndCanEditParticipant, - isTestReceipt, - isRestrictedToPreferredPolicy, - isTypeInvoice, - shouldHideToSection, - ]); + }, [isTypeSplit, translate, payeePersonalDetails, getSplitSectionHeader, splitParticipants, selectedParticipants, canEditParticipant, shouldHideToSection]); useEffect(() => { if (!isDistanceRequest || (isMovingTransactionFromTrackExpense && !isPolicyExpenseChat) || !transactionID || isReadOnly) { @@ -1007,7 +997,7 @@ function MoneyRequestConfirmationList({ * Navigate to the participant step */ const navigateToParticipantPage = () => { - if (!isFromGlobalCreateAndCanEditParticipant) { + if (!canEditParticipant) { return; } diff --git a/src/components/SelectionList/BaseSelectionList.tsx b/src/components/SelectionList/BaseSelectionList.tsx index 2280563fa322..9a6d769e9bbf 100644 --- a/src/components/SelectionList/BaseSelectionList.tsx +++ b/src/components/SelectionList/BaseSelectionList.tsx @@ -257,7 +257,7 @@ function BaseSelectionList({ }, [data, focusedIndex, isItemSelected]); const selectFocusedOption = () => { - if (!focusedOption) { + if (!focusedOption || focusedOption.isInteractive === false) { return; } selectRow(focusedOption); @@ -363,6 +363,7 @@ function BaseSelectionList({ shouldSyncFocus={!isTextInputFocusedRef.current && hasKeyBeenPressed.current} shouldDisableHoverStyle={shouldDisableHoverStyle} shouldShowRightCaret={shouldShowRightCaret} + shouldPreventEnterKeySubmit={!disableKeyboardShortcuts} /> ); }; diff --git a/src/components/SelectionList/ListItem/BaseListItem.tsx b/src/components/SelectionList/ListItem/BaseListItem.tsx index a52a268a7844..acec05bc102b 100644 --- a/src/components/SelectionList/ListItem/BaseListItem.tsx +++ b/src/components/SelectionList/ListItem/BaseListItem.tsx @@ -103,6 +103,28 @@ function BaseListItem({ // Sync focus on an item useSyncFocus(pressableRef, !!isFocused, shouldSyncFocus); + + // List items use role="option" which doesn't natively respond to Enter key presses. + // When the list-level keyboard shortcut is disabled (disableKeyboardShortcuts), we handle + // Enter activation here at the item level so each row can still be activated individually + // without interfering with other focusable controls (e.g. footer inputs) on the same screen. + const handleKeyDown = (event: React.KeyboardEvent) => { + if ( + shouldPreventEnterKeySubmit || + accessible === false || + event.key !== CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey || + event.shiftKey || + event.metaKey || + event.ctrlKey || + item.isInteractive === false + ) { + return; + } + + event.preventDefault(); + onSelectRow(item); + }; + const handleMouseLeave = (e: React.MouseEvent) => { bind.onMouseLeave(); e.stopPropagation(); @@ -191,6 +213,9 @@ function BaseListItem({ {...accessibleAndAccessibilityLabel} accessibilityState={accessibilityState} onMouseLeave={handleMouseLeave} + // When the list-level Enter shortcut is disabled (disableKeyboardShortcuts), items with role="option" + // won't natively fire click on Enter, so we handle it manually via onKeyDown. + onKeyDown={!shouldPreventEnterKeySubmit ? handleKeyDown : undefined} wrapperStyle={pressableWrapperStyle} testID={`${CONST.BASE_LIST_ITEM_TEST_ID}${item.keyForList}`} > diff --git a/src/components/SelectionList/ListItem/ListItemRenderer.tsx b/src/components/SelectionList/ListItem/ListItemRenderer.tsx index 1d7b34385a9a..74273fe69189 100644 --- a/src/components/SelectionList/ListItem/ListItemRenderer.tsx +++ b/src/components/SelectionList/ListItem/ListItemRenderer.tsx @@ -17,6 +17,7 @@ type ListItemRendererProps = Omit; titleContainerStyles?: StyleProp; shouldHighlightSelectedItem: boolean; + shouldPreventEnterKeySubmit?: boolean; }; function ListItemRenderer({ @@ -53,6 +54,7 @@ function ListItemRenderer({ shouldDisableHoverStyle, shouldShowRightCaret, errorRowStyles, + shouldPreventEnterKeySubmit = true, }: ListItemRendererProps) { const handleOnCheckboxPress = () => { if (isTransactionGroupListItemType(item)) { @@ -81,8 +83,7 @@ function ListItemRenderer({ onCheckboxPress={handleOnCheckboxPress()} onDismissError={() => onDismissError?.(item)} shouldPreventDefaultFocusOnSelectRow={shouldPreventDefaultFocusOnSelectRow} - // We're already handling the Enter key press in the useKeyboardShortcut hook, so we don't want the list item to submit the form - shouldPreventEnterKeySubmit + shouldPreventEnterKeySubmit={shouldPreventEnterKeySubmit} rightHandSideComponent={rightHandSideComponent} keyForList={item.keyForList} shouldUseDefaultRightHandSideComponent={shouldUseDefaultRightHandSideComponent} diff --git a/src/components/SelectionList/SelectionListWithSections/BaseSelectionListWithSections.tsx b/src/components/SelectionList/SelectionListWithSections/BaseSelectionListWithSections.tsx index 29dc9f607c47..edbdbd2ea6e1 100644 --- a/src/components/SelectionList/SelectionListWithSections/BaseSelectionListWithSections.tsx +++ b/src/components/SelectionList/SelectionListWithSections/BaseSelectionListWithSections.tsx @@ -181,7 +181,7 @@ function BaseSelectionListWithSections({ const selectFocusedItem = () => { const focusedItem = getFocusedItem(); - if (!focusedItem) { + if (!focusedItem || focusedItem.isInteractive === false) { return; } selectRow(focusedItem); @@ -363,6 +363,7 @@ function BaseSelectionListWithSections({ titleNumberOfLines={titleNumberOfLines} shouldUseDefaultRightHandSideComponent={shouldUseDefaultRightHandSideComponent} shouldDisableHoverStyle={shouldDisableHoverStyle} + shouldPreventEnterKeySubmit={!disableKeyboardShortcuts} /> ); }