Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
6a3f3fb
Reorganize Search filters into sections and add filter search
Krishna2323 Oct 22, 2026
562d237
Keep the Search filters string in en.ts only
Krishna2323 Oct 22, 2026
e6ee615
Add top spacing above the filter search input in the popover
Krishna2323 Oct 22, 2026
0e29a4c
Focus the filter search input when the popover opens and test the search
Krishna2323 Oct 22, 2026
6f4af1e
Show the first matching filter while searching and add a no-filters e…
Krishna2323 Oct 22, 2026
45ef077
Show the first matching filter after a search pause and add a no-filt…
Krishna2323 Oct 22, 2026
39bccde
Show the first filter as soon as the filter search is cleared
Krishna2323 Oct 22, 2026
9454003
Focus the filter search input once the popover has opened
Krishna2323 Oct 22, 2026
afcd3d0
Keep the search input unfocused on touch screens and keep a hovered f…
Krishna2323 Oct 25, 2026
2cb47a5
Clarify the first-match comment and the invoice filter order test
Krishna2323 Oct 25, 2026
5bccadd
Move the filter search input above Describe your search
Krishna2323 Oct 26, 2026
2dd6fe4
Let the filter search hide Describe your search when it does not match
Krishna2323 Oct 26, 2026
b67cb79
Merge remote-tracking branch 'upstream/main' into krishna2323/104330-…
Krishna2323 Oct 27, 2026
61f25c8
add translations.
Krishna2323 Oct 27, 2026
b2f9daf
Let the first tap on a filter row work while the keyboard is open
Krishna2323 Oct 27, 2026
a0e4f81
Open on Describe your search and stop its input from taking the focus
Krishna2323 Oct 27, 2026
4660c6a
Let Describe your search scroll with the other filters
Krishna2323 Oct 27, 2026
8cc7ec5
Restore the GitHub Actions bundles rebuilt by the merge hook
Krishna2323 Oct 27, 2026
c540729
Merge branch 'Expensify:main' into krishna2323/104330-reorganize-filters
Krishna2323 Oct 27, 2026
a63361b
Match filter search words in any order with tokenizedSearch
Krishna2323 Oct 27, 2026
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
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import Icon from '@components/Icon';
import {PressableWithFeedback} from '@components/Pressable';
import ScrollView from '@components/ScrollView';
import CompactSearchBar from '@components/SearchBar/CompactSearchBar';
import SpacerView from '@components/SpacerView';
import Text from '@components/Text';
import type {BaseTextInputRef} from '@components/TextInput/BaseTextInput/types';

import useAdvancedSearchFilters from '@hooks/useAdvancedSearchFilters';
import useDebouncedAccessibilityAnnouncement from '@hooks/useDebouncedAccessibilityAnnouncement';
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
import useStyleUtils from '@hooks/useStyleUtils';
Expand All @@ -19,6 +21,7 @@ import variables from '@styles/variables';

import type {SearchDataTypes} from '@src/types/onyx/SearchResults';

import type {ReactNode, Ref} from 'react';
import type {StyleProp, ViewStyle} from 'react-native';

import React from 'react';
Expand All @@ -37,6 +40,20 @@ type FilterListProps = FilterItemCallbacks & {
style?: StyleProp<ViewStyle>;
contentContainerStyle?: StyleProp<ViewStyle>;

/** The filters to list, in sections. */
filters: Array<Array<SearchFilter['key']>>;

/** Text in the search input above the list. */
searchValue: string;

onSearchValueChange: (searchValue: string) => void;

/** Ref to the search input above the list. */
searchInputRef?: Ref<BaseTextInputRef>;

/** Content at the top of the list, scrolled with its rows. Pass a falsy value when the search hides it, so the list knows nothing is listed. */
headerContent?: ReactNode;

/** Called as the cursor travels over the list. Web only - it reports the movement inside a row, which `onHoverIn` only reports entering. */
onPointerMove?: (event: {clientX: number; clientY: number}) => void;

Expand Down Expand Up @@ -108,40 +125,79 @@ function FilterItem({filterKey, isSelected, type, onPress, onHoverIn, onFocus}:
);
}

function FilterList({type, selectedFilter, style, contentContainerStyle, onHoverIn, onFocus, onPress, onPointerMove, onPointerLeave}: FilterListProps) {
function FilterList({
type,
selectedFilter,
style,
contentContainerStyle,
filters,
searchValue,
onSearchValueChange,
searchInputRef,
headerContent,
onHoverIn,
onFocus,
onPress,
onPointerMove,
onPointerLeave,
}: FilterListProps) {
const styles = useThemeStyles();
const typeFiltersKeys = useAdvancedSearchFilters(type);
const {translate} = useLocalize();
const noResultsFoundText = translate('common.noResultsFound');
const shouldShowNoResultsFound = filters.length === 0 && !headerContent;

useDebouncedAccessibilityAnnouncement(noResultsFoundText, shouldShowNoResultsFound, searchValue);

return (
<ScrollView
style={[style]}
contentContainerStyle={[contentContainerStyle]}
showsVerticalScrollIndicator={false}
onMouseMove={onPointerMove}
onMouseLeave={onPointerLeave}
>
{typeFiltersKeys.map((section, index) => (
<View key={`${section.at(0)}`}>
{index !== 0 && (
<SpacerView
shouldShow
style={[styles.reportHorizontalRule]}
/>
)}
{section.map((item) => (
<FilterItem
key={item}
filterKey={item}
type={type}
isSelected={item === selectedFilter}
onHoverIn={onHoverIn}
onFocus={onFocus}
onPress={onPress}
/>
))}
<View style={[styles.flex1, style]}>
<CompactSearchBar
label={translate('search.filters.searchFilters')}
inputValue={searchValue}
onChangeText={onSearchValueChange}
style={styles.mb3}
ref={searchInputRef}
/>
{shouldShowNoResultsFound && (
<View style={[styles.ph5, styles.pb5]}>
<Text
style={[styles.textLabel, styles.colorMuted, styles.minHeight5]}
aria-hidden
>
{noResultsFoundText}
</Text>
</View>
))}
</ScrollView>
)}
<ScrollView
contentContainerStyle={[contentContainerStyle]}
showsVerticalScrollIndicator={false}
keyboardShouldPersistTaps="handled"
onMouseMove={onPointerMove}
onMouseLeave={onPointerLeave}
>
{headerContent}
{filters.map((section, index) => (
<View key={`${section.at(0)}`}>
{index !== 0 && (
<SpacerView
shouldShow
style={[styles.reportHorizontalRule]}
/>
)}
{section.map((item) => (
<FilterItem
key={item}
filterKey={item}
type={type}
isSelected={item === selectedFilter}
onHoverIn={onHoverIn}
onFocus={onFocus}
onPress={onPress}
/>
))}
</View>
))}
</ScrollView>
</View>
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,12 @@ type SearchNLFilterContentProps = {

/** Size of the submit button */
size?: Exclude<ValueOf<typeof CONST.BUTTON_SIZE>, typeof CONST.BUTTON_SIZE.SMALL>;

/** Whether the input takes the focus once it is shown */
autoFocus?: boolean;
};

function SearchNLFilterContent({onSuccess, containerStyle, buttonContainerStyle, size = CONST.BUTTON_SIZE.MEDIUM}: SearchNLFilterContentProps) {
function SearchNLFilterContent({onSuccess, containerStyle, buttonContainerStyle, size = CONST.BUTTON_SIZE.MEDIUM, autoFocus}: SearchNLFilterContentProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();
const [nlQuery, setNlQuery] = useState('');
Expand Down Expand Up @@ -129,7 +132,7 @@ function SearchNLFilterContent({onSuccess, containerStyle, buttonContainerStyle,
e.preventDefault();
handleSubmit();
}}
autoFocus
autoFocus={autoFocus}
autoGrowHeight
maxAutoGrowHeight={variables.textInputAutoGrowMaxHeight}
/>
Expand Down
5 changes: 5 additions & 0 deletions src/components/Search/FilterDropdowns/FilterPopupButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ type FilterPopupButtonProps = {

/** Called instead of opening the popover when device is in landscape mode */
onLandscapePress?: () => void;

/** Called once the popover has finished opening */
onModalShow?: () => void;
};

const ANCHOR_ORIGIN = {
Expand All @@ -60,6 +63,7 @@ function FilterPopupButton({
PopoverComponent,
renderButton,
onLandscapePress,
onModalShow,
}: FilterPopupButtonProps) {
// We need to use isSmallScreenWidth instead of shouldUseNarrowLayout to distinguish RHP and narrow layout
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
Expand Down Expand Up @@ -141,6 +145,7 @@ function FilterPopupButton({
avoidKeyboard
isVisible={isOverlayVisible}
onClose={toggleOverlay}
onModalShow={onModalShow}
anchorPosition={popoverTriggerPosition}
anchorAlignment={popoverAnchorAlignment}
restoreFocusType={CONST.MODAL.RESTORE_FOCUS_TYPE.DELETE}
Expand Down
Loading
Loading