From c0f6dc7cd9dc82ef5dfc9c892e181042e8bc9c48 Mon Sep 17 00:00:00 2001 From: Carlos Miceli Date: Fri, 30 Jan 2026 15:05:33 -0800 Subject: [PATCH 1/5] add escape key behavior to Search Page bar --- .../SearchPageHeader/SearchPageHeaderInput.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx b/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx index 0eeaa34f1d2c2..5f42dc4b794f3 100644 --- a/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx +++ b/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx @@ -20,6 +20,7 @@ import {isSearchQueryItem} from '@components/SelectionListWithSections/Search/Se import type {SelectionListHandle} from '@components/SelectionListWithSections/types'; import SidePanelButton from '@components/SidePanel/SidePanelButton'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; +import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; import useOnyx from '@hooks/useOnyx'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; @@ -131,6 +132,17 @@ function SearchPageHeaderInput({queryJSON, searchRouterListVisible, hideSearchRo // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + const handleEscapeKey = useCallback(() => { + if (textInputRef.current?.isFocused()) { + textInputRef.current.blur(); + } + }, []); + + useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ESCAPE, handleEscapeKey, { + captureOnInputs: true, + shouldBubble: false, + }); + const handleSearchAction = useCallback( (value: string) => { // Skip calling handleSearch on the initial mount From 929027ed73f748da1d1b31a4a134f4702183fc46 Mon Sep 17 00:00:00 2001 From: Carlos Miceli Date: Fri, 30 Jan 2026 18:17:53 -0800 Subject: [PATCH 2/5] change method for onKeyPress --- .../Search/SearchAutocompleteInput.tsx | 4 ++- .../SearchPageHeaderInput.tsx | 25 +++++++++++-------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/components/Search/SearchAutocompleteInput.tsx b/src/components/Search/SearchAutocompleteInput.tsx index 173644f175e56..186086b2ecc6b 100644 --- a/src/components/Search/SearchAutocompleteInput.tsx +++ b/src/components/Search/SearchAutocompleteInput.tsx @@ -73,7 +73,7 @@ type SearchAutocompleteInputProps = { /** Reference to the outer element */ ref?: ForwardedRef; -} & Pick; +} & Pick; function SearchAutocompleteInput({ value, @@ -94,6 +94,7 @@ function SearchAutocompleteInput({ isSearchingForReports, selection, substitutionMap, + onKeyPress, ref, }: SearchAutocompleteInputProps) { const styles = useThemeStyles(); @@ -223,6 +224,7 @@ function SearchAutocompleteInput({ onBlur?.(); }} + onKeyPress={onKeyPress} isLoading={isSearchingForReports} ref={(element) => { if (!ref) { diff --git a/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx b/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx index 5f42dc4b794f3..72b9b7ec09f6b 100644 --- a/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx +++ b/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx @@ -3,6 +3,7 @@ import {accountIDSelector} from '@selectors/Session'; import {deepEqual} from 'fast-equals'; import isEmpty from 'lodash/isEmpty'; import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; +import type {TextInputKeyPressEvent} from 'react-native'; import {View} from 'react-native'; import Animated from 'react-native-reanimated'; import {usePersonalDetails} from '@components/OnyxListItemProvider'; @@ -20,7 +21,6 @@ import {isSearchQueryItem} from '@components/SelectionListWithSections/Search/Se import type {SelectionListHandle} from '@components/SelectionListWithSections/types'; import SidePanelButton from '@components/SidePanel/SidePanelButton'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; -import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; import useOnyx from '@hooks/useOnyx'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; @@ -132,16 +132,6 @@ function SearchPageHeaderInput({queryJSON, searchRouterListVisible, hideSearchRo // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const handleEscapeKey = useCallback(() => { - if (textInputRef.current?.isFocused()) { - textInputRef.current.blur(); - } - }, []); - - useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ESCAPE, handleEscapeKey, { - captureOnInputs: true, - shouldBubble: false, - }); const handleSearchAction = useCallback( (value: string) => { @@ -389,6 +379,7 @@ function SearchPageHeaderInput({queryJSON, searchRouterListVisible, hideSearchRo wrapperFocusedStyle={styles.searchAutocompleteInputResultsFocused} autocompleteListRef={listRef} ref={textInputRef} + onKeyPress={handleKeyPress} /> {showPopupButton && ( @@ -425,6 +416,17 @@ function SearchPageHeaderInput({queryJSON, searchRouterListVisible, hideSearchRo listRef.current?.updateAndScrollToFocusedIndex(0); setIsAutocompleteListVisible(true); }; + const handleKeyPress = useCallback( + (e: TextInputKeyPressEvent) => { + const keyEvent = e as unknown as KeyboardEvent; + + if (keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ESCAPE.shortcutKey && textInputRef.current?.isFocused()) { + keyEvent.preventDefault(); + textInputRef.current.blur(); + } + }, + [], + ); // we need `- BORDER_WIDTH` to achieve the effect that the input will not "jump" const leftPopoverHorizontalPosition = 12 - BORDER_WIDTH; const rightPopoverHorizontalPosition = 4 - BORDER_WIDTH; @@ -469,6 +471,7 @@ function SearchPageHeaderInput({queryJSON, searchRouterListVisible, hideSearchRo ref={textInputRef} selection={selection} substitutionMap={autocompleteSubstitutions} + onKeyPress={handleKeyPress} /> {isAutocompleteListVisible && ( From 46b12fe542ab39afed6fbdccb8d2ace16a6ea66e Mon Sep 17 00:00:00 2001 From: Carlos Miceli Date: Fri, 30 Jan 2026 18:19:10 -0800 Subject: [PATCH 3/5] prettier --- .../SearchPageHeader/SearchPageHeaderInput.tsx | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx b/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx index 72b9b7ec09f6b..6af8d9277dee5 100644 --- a/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx +++ b/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx @@ -132,7 +132,6 @@ function SearchPageHeaderInput({queryJSON, searchRouterListVisible, hideSearchRo // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const handleSearchAction = useCallback( (value: string) => { // Skip calling handleSearch on the initial mount @@ -416,17 +415,14 @@ function SearchPageHeaderInput({queryJSON, searchRouterListVisible, hideSearchRo listRef.current?.updateAndScrollToFocusedIndex(0); setIsAutocompleteListVisible(true); }; - const handleKeyPress = useCallback( - (e: TextInputKeyPressEvent) => { - const keyEvent = e as unknown as KeyboardEvent; + const handleKeyPress = useCallback((e: TextInputKeyPressEvent) => { + const keyEvent = e as unknown as KeyboardEvent; - if (keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ESCAPE.shortcutKey && textInputRef.current?.isFocused()) { - keyEvent.preventDefault(); - textInputRef.current.blur(); - } - }, - [], - ); + if (keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ESCAPE.shortcutKey && textInputRef.current?.isFocused()) { + keyEvent.preventDefault(); + textInputRef.current.blur(); + } + }, []); // we need `- BORDER_WIDTH` to achieve the effect that the input will not "jump" const leftPopoverHorizontalPosition = 12 - BORDER_WIDTH; const rightPopoverHorizontalPosition = 4 - BORDER_WIDTH; From 60e644f68ac817b3ed3a33fb124705105dc0c119 Mon Sep 17 00:00:00 2001 From: Carlos Miceli Date: Fri, 30 Jan 2026 18:29:03 -0800 Subject: [PATCH 4/5] lint --- .../SearchPageHeaderInput.tsx | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx b/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx index 6af8d9277dee5..6317a4b4bd914 100644 --- a/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx +++ b/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx @@ -132,6 +132,18 @@ function SearchPageHeaderInput({queryJSON, searchRouterListVisible, hideSearchRo // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + const handleKeyPress = useCallback( + (e: TextInputKeyPressEvent) => { + const keyEvent = e as unknown as KeyboardEvent; + + if (keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ESCAPE.shortcutKey && textInputRef.current?.isFocused()) { + keyEvent.preventDefault(); + textInputRef.current.blur(); + } + }, + [], + ); + const handleSearchAction = useCallback( (value: string) => { // Skip calling handleSearch on the initial mount @@ -415,14 +427,6 @@ function SearchPageHeaderInput({queryJSON, searchRouterListVisible, hideSearchRo listRef.current?.updateAndScrollToFocusedIndex(0); setIsAutocompleteListVisible(true); }; - const handleKeyPress = useCallback((e: TextInputKeyPressEvent) => { - const keyEvent = e as unknown as KeyboardEvent; - - if (keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ESCAPE.shortcutKey && textInputRef.current?.isFocused()) { - keyEvent.preventDefault(); - textInputRef.current.blur(); - } - }, []); // we need `- BORDER_WIDTH` to achieve the effect that the input will not "jump" const leftPopoverHorizontalPosition = 12 - BORDER_WIDTH; const rightPopoverHorizontalPosition = 4 - BORDER_WIDTH; From adaed024a7947bde9afb7fa5f313db756f4f936f Mon Sep 17 00:00:00 2001 From: Carlos Miceli Date: Fri, 30 Jan 2026 18:38:34 -0800 Subject: [PATCH 5/5] thought I commited this, prettier again --- .../SearchPageHeader/SearchPageHeaderInput.tsx | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx b/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx index 6317a4b4bd914..d9cb68e267727 100644 --- a/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx +++ b/src/components/Search/SearchPageHeader/SearchPageHeaderInput.tsx @@ -132,17 +132,14 @@ function SearchPageHeaderInput({queryJSON, searchRouterListVisible, hideSearchRo // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const handleKeyPress = useCallback( - (e: TextInputKeyPressEvent) => { - const keyEvent = e as unknown as KeyboardEvent; + const handleKeyPress = useCallback((e: TextInputKeyPressEvent) => { + const keyEvent = e as unknown as KeyboardEvent; - if (keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ESCAPE.shortcutKey && textInputRef.current?.isFocused()) { - keyEvent.preventDefault(); - textInputRef.current.blur(); - } - }, - [], - ); + if (keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ESCAPE.shortcutKey && textInputRef.current?.isFocused()) { + keyEvent.preventDefault(); + textInputRef.current.blur(); + } + }, []); const handleSearchAction = useCallback( (value: string) => {