Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions src/components/Search/SearchAutocompleteInput.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
/* eslint-disable rulesdir/no-acc-spread-in-reduce */
import type {ForwardedRef, RefObject} from 'react';
import React, {useCallback, useEffect, useMemo} from 'react';
import React, {useCallback, useEffect, useMemo, useRef} from 'react';
import type {StyleProp, TextInputProps, ViewStyle} from 'react-native';
import {View} from 'react-native';
import Animated, {interpolateColor, useAnimatedStyle, useSharedValue} from 'react-native-reanimated';
import FormHelpMessage from '@components/FormHelpMessage';
import type {AnimatedTextInputRef} from '@components/RNTextInput';
import type {SelectionListHandle} from '@components/SelectionListWithSections/types';
import TextInput from '@components/TextInput';
import type {BaseTextInputRef} from '@components/TextInput/BaseTextInput/types';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useFocusAfterNav from '@hooks/useFocusAfterNav';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useOnyx from '@hooks/useOnyx';
Expand Down Expand Up @@ -68,6 +70,9 @@ type SearchAutocompleteInputProps = {
/** Map of autocomplete suggestions. Required for highlighting to work properly */
substitutionMap: SubstitutionMap;

/** Whether the focus should be delayed */
shouldDelayFocus?: boolean;

/** Reference to the outer element */
ref?: ForwardedRef<BaseTextInputRef>;
} & Pick<TextInputProps, 'caretHidden' | 'autoFocus' | 'selection'>;
Expand All @@ -79,8 +84,9 @@ function SearchAutocompleteInput({
autocompleteListRef,
isFullWidth,
disabled = false,
shouldShowOfflineMessage = false,
shouldDelayFocus = false,
autoFocus = true,
shouldShowOfflineMessage = false,
onFocus,
onBlur,
caretHidden = false,
Expand All @@ -97,7 +103,8 @@ function SearchAutocompleteInput({
const {translate} = useLocalize();
const {isOffline} = useNetwork();
const currentUserPersonalDetails = useCurrentUserPersonalDetails();

const inputRef = useRef<AnimatedTextInputRef>(null);
const autoFocusAfterNav = useFocusAfterNav(inputRef, shouldDelayFocus);
const [currencyList] = useOnyx(ONYXKEYS.CURRENCY_LIST, {canBeMissing: false});
const currencyAutocompleteList = Object.keys(currencyList ?? {}).filter((currencyCode) => !currencyList?.[currencyCode]?.retired);
const currencySharedValue = useSharedValue(currencyAutocompleteList);
Expand Down Expand Up @@ -203,7 +210,7 @@ function SearchAutocompleteInput({
testID="search-autocomplete-text-input"
value={value}
onChangeText={onSearchQueryChange}
autoFocus={autoFocus}
autoFocus={shouldDelayFocus ? autoFocusAfterNav : autoFocus}
caretHidden={caretHidden}
role={CONST.ROLE.PRESENTATION}
placeholder={translate('search.searchPlaceholder')}
Expand Down Expand Up @@ -232,7 +239,21 @@ function SearchAutocompleteInput({
onBlur?.();
}}
isLoading={isSearchingForReports}
ref={ref}
ref={(element) => {
if (!ref) {
return;
}

inputRef.current = element as AnimatedTextInputRef;

if (typeof ref === 'function') {
ref(element);
return;
}

// eslint-disable-next-line no-param-reassign
ref.current = element;
}}
type="markdown"
multiline={false}
parser={parser}
Expand Down
4 changes: 1 addition & 3 deletions src/components/Search/SearchRouter/SearchRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import {isSearchQueryItem} from '@components/SelectionListWithSections/Search/SearchQueryListItem';
import type {SelectionListHandle} from '@components/SelectionListWithSections/types';
import useDebouncedState from '@hooks/useDebouncedState';
import useFocusAfterNav from '@hooks/useFocusAfterNav';
import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
Expand Down Expand Up @@ -198,7 +197,7 @@
},
];
},
[contextualReportID, styles.activeComponentBG, textInputValue, translate, isSearchRouterDisplayed],

Check warning on line 200 in src/components/Search/SearchRouter/SearchRouter.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

React Hook useCallback has missing dependencies: 'personalDetails' and 'reports'. Either include them or remove the dependency array

Check warning on line 200 in src/components/Search/SearchRouter/SearchRouter.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

React Hook useCallback has missing dependencies: 'personalDetails' and 'reports'. Either include them or remove the dependency array
);

const searchQueryItem = textInputValue
Expand Down Expand Up @@ -483,7 +482,6 @@
const updateAndScrollToFocusedIndex = useCallback(() => listRef.current?.updateAndScrollToFocusedIndex(1, true), []);

const modalWidth = shouldUseNarrowLayout ? styles.w100 : {width: variables.searchRouterPopoverWidth};
const autoFocus = useFocusAfterNav(textInputRef);

return (
<View
Expand Down Expand Up @@ -522,7 +520,7 @@
selection={selection}
substitutionMap={autocompleteSubstitutions}
ref={textInputRef}
autoFocus={autoFocus}
shouldDelayFocus
/>
</View>
{shouldShowList && (
Expand Down
6 changes: 5 additions & 1 deletion src/hooks/useFocusAfterNav/index.native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ import type UseFocusAfterNav from './type';

/** We added a delay to focus on text input to allow navigation/modal animations to get completed,
see issue https://github.com/Expensify/App/issues/65855 for more details */
const useFocusAfterNav: UseFocusAfterNav = (ref) => {
const useFocusAfterNav: UseFocusAfterNav = (ref, shouldDelayFocus = true) => {
useFocusEffect(() => {
if (!shouldDelayFocus) {
return;
}

const timeoutId = setTimeout(() => {
ref.current?.focus();
}, CONST.ANIMATED_TRANSITION);
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useFocusAfterNav/type.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type {RefObject} from 'react';
import type {AnimatedTextInputRef} from '@components/RNTextInput';

type UseFocusAfterNav = (ref: RefObject<AnimatedTextInputRef | null>) => boolean;
type UseFocusAfterNav = (ref: RefObject<AnimatedTextInputRef | null>, shouldDelayFocus: boolean) => boolean;

export default UseFocusAfterNav;
Loading