Skip to content

Commit e097189

Browse files
authored
Merge pull request #89256 from bernhardoj/feat/84878-add-close-button-to-filter-chip
Add close button to filter chip to clear individual filter
2 parents 6632dbd + d73939c commit e097189

9 files changed

Lines changed: 113 additions & 36 deletions

File tree

src/components/Search/FilterDropdowns/DropdownButton.tsx

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@ import type {StyleProp, TextStyle, ViewStyle} from 'react-native';
55
import {View} from 'react-native';
66
import Button from '@components/Button';
77
import CaretWrapper from '@components/CaretWrapper';
8+
import Icon from '@components/Icon';
89
import PopoverWithMeasuredContent from '@components/PopoverWithMeasuredContent';
910
import Text from '@components/Text';
1011
import withViewportOffsetTop from '@components/withViewportOffsetTop';
12+
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
1113
import useOnyx from '@hooks/useOnyx';
1214
import usePopoverPosition from '@hooks/usePopoverPosition';
1315
import useResponsiveLayout from '@hooks/useResponsiveLayout';
1416
import useStyleUtils from '@hooks/useStyleUtils';
17+
import useTheme from '@hooks/useTheme';
1518
import useThemeStyles from '@hooks/useThemeStyles';
1619
import useWindowDimensions from '@hooks/useWindowDimensions';
1720
import variables from '@styles/variables';
@@ -56,6 +59,7 @@ type DropdownButtonProps = WithSentryLabel & {
5659

5760
/** Wrapper style for the outer view */
5861
wrapperStyle?: StyleProp<ViewStyle>;
62+
onClosePress?: () => void;
5963
};
6064

6165
const ANCHOR_ORIGIN = {
@@ -75,13 +79,16 @@ function DropdownButton({
7579
caretWrapperStyle,
7680
wrapperStyle,
7781
sentryLabel,
82+
onClosePress,
7883
}: DropdownButtonProps) {
7984
// We need to use isSmallScreenWidth instead of shouldUseNarrowLayout to distinguish RHL and narrow layout
8085
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
8186
const {isSmallScreenWidth} = useResponsiveLayout();
87+
const icons = useMemoizedLazyExpensifyIcons(['Close']);
8288

8389
const styles = useThemeStyles();
8490
const StyleUtils = useStyleUtils();
91+
const theme = useTheme();
8592
const {windowHeight} = useWindowDimensions();
8693
const triggerRef = useRef<View | null>(null);
8794
const anchorRef = useRef<View | null>(null);
@@ -144,6 +151,8 @@ function DropdownButton({
144151
return PopoverComponent({closeOverlay: toggleOverlay, isExpanded: isOverlayVisible, setPopoverWidth: setCustomPopoverWidth});
145152
}, [PopoverComponent, toggleOverlay, isOverlayVisible]);
146153

154+
const shouldShowCloseButton = !!onClosePress;
155+
147156
return (
148157
<View
149158
ref={anchorRef}
@@ -156,28 +165,49 @@ function DropdownButton({
156165
onPress={calculatePopoverPositionAndToggleOverlay}
157166
/>
158167
) : (
159-
<Button
160-
ref={triggerRef}
161-
innerStyles={[isOverlayVisible && styles.buttonHoveredBG, {maxWidth: 256}, innerStyles]}
162-
onPress={calculatePopoverPositionAndToggleOverlay}
163-
sentryLabel={sentryLabel}
164-
// eslint-disable-next-line react/jsx-props-no-spreading
165-
{...(medium ? {medium: true} : {small: true})}
166-
>
167-
<CaretWrapper
168-
style={[styles.flex1, styles.mw100, caretWrapperStyle]}
169-
caretWidth={medium ? variables.iconSizeSmall : variables.iconSizeExtraSmall}
170-
caretHeight={medium ? variables.iconSizeSmall : variables.iconSizeExtraSmall}
171-
isActive={isOverlayVisible}
168+
<View style={[styles.flexRow]}>
169+
<Button
170+
ref={triggerRef}
171+
innerStyles={[isOverlayVisible && styles.buttonHoveredBG, {maxWidth: 256}, innerStyles, shouldShowCloseButton && styles.pr2]}
172+
onPress={calculatePopoverPositionAndToggleOverlay}
173+
sentryLabel={sentryLabel}
174+
shouldRemoveRightBorderRadius={shouldShowCloseButton}
175+
// eslint-disable-next-line react/jsx-props-no-spreading
176+
{...(medium ? {medium: true} : {small: true})}
172177
>
173-
<Text
174-
numberOfLines={1}
175-
style={[styles.textMicroBold, styles.flexShrink1, labelStyle]}
178+
<CaretWrapper
179+
style={[styles.flex1, styles.mw100, caretWrapperStyle]}
180+
caretWidth={medium ? variables.iconSizeSmall : variables.iconSizeExtraSmall}
181+
caretHeight={medium ? variables.iconSizeSmall : variables.iconSizeExtraSmall}
182+
isActive={isOverlayVisible}
176183
>
177-
{buttonText}
178-
</Text>
179-
</CaretWrapper>
180-
</Button>
184+
<Text
185+
numberOfLines={1}
186+
style={[styles.textMicroBold, styles.flexShrink1, labelStyle]}
187+
>
188+
{buttonText}
189+
</Text>
190+
</CaretWrapper>
191+
</Button>
192+
{shouldShowCloseButton && (
193+
<>
194+
<View style={[styles.buttonDivider]} />
195+
<Button
196+
small
197+
shouldRemoveLeftBorderRadius
198+
innerStyles={[styles.pl0, styles.pr0half, styles.filterDropDownCloseIcon]}
199+
onPress={onClosePress}
200+
>
201+
<Icon
202+
src={icons.Close}
203+
fill={theme.icon}
204+
width={variables.iconSizeXXSmall}
205+
height={variables.iconSizeXXSmall}
206+
/>
207+
</Button>
208+
</>
209+
)}
210+
</View>
181211
)}
182212

183213
{/* Dropdown overlay */}

src/components/Search/SearchAutocompleteInput.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,10 @@ type SearchAutocompleteInputProps = {
5858

5959
/** Any additional styles to apply to text input along with FormHelperMessage */
6060
outerWrapperStyle?: StyleProp<ViewStyle>;
61-
6261
inputStyle?: StyleProp<TextStyle>;
63-
6462
inputContainerStyle?: StyleProp<ViewStyle>;
65-
6663
touchableInputWrapperStyle?: StyleProp<ViewStyle>;
64+
clearButtonStyle?: StyleProp<ViewStyle>;
6765

6866
/** Whether the search reports API call is running */
6967
isSearchingForReports?: boolean;
@@ -96,6 +94,7 @@ function SearchAutocompleteInput({
9694
inputStyle,
9795
inputContainerStyle,
9896
touchableInputWrapperStyle,
97+
clearButtonStyle,
9998
isSearchingForReports,
10099
selection,
101100
substitutionMap,
@@ -222,6 +221,7 @@ function SearchAutocompleteInput({
222221
textInputContainerStyles={[styles.borderNone, styles.pb0, styles.ph3, inputContainerStyle]}
223222
inputStyle={[inputWidth, styles.lineHeightUndefined, inputStyle]}
224223
touchableInputWrapperStyle={touchableInputWrapperStyle}
224+
clearButtonStyle={clearButtonStyle}
225225
placeholderTextColor={theme.textSupporting}
226226
loadingSpinnerStyle={[styles.mt0, styles.mr1, styles.justifyContentCenter]}
227227
onFocus={() => {

src/components/Search/SearchPageHeader/SearchFilterBar.tsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,74 +14,80 @@ import type {FilterItem} from './useSearchFiltersBar';
1414

1515
type SearchDropdownProps = Omit<DropdownButtonProps, 'viewportOffsetTop'>;
1616

17-
function UserDropdown({label, value, PopoverComponent, sentryLabel}: SearchDropdownProps) {
17+
function UserDropdown({label, value, PopoverComponent, sentryLabel, onClosePress}: SearchDropdownProps) {
1818
const users = useFilterUserValue(value);
1919
return (
2020
<DropdownButton
2121
label={label}
2222
value={users ?? []}
2323
PopoverComponent={PopoverComponent}
2424
sentryLabel={sentryLabel}
25+
onClosePress={onClosePress}
2526
/>
2627
);
2728
}
2829

29-
function WorkspaceDropdown({label, value, PopoverComponent, sentryLabel}: SearchDropdownProps) {
30+
function WorkspaceDropdown({label, value, PopoverComponent, sentryLabel, onClosePress}: SearchDropdownProps) {
3031
const workspaceValue = useFilterWorkspaceValue(value);
3132
return (
3233
<DropdownButton
3334
label={label}
3435
value={workspaceValue ?? []}
3536
PopoverComponent={PopoverComponent}
3637
sentryLabel={sentryLabel}
38+
onClosePress={onClosePress}
3739
/>
3840
);
3941
}
4042

41-
function FeedDropdown({label, PopoverComponent, sentryLabel}: SearchDropdownProps) {
43+
function FeedDropdown({label, PopoverComponent, sentryLabel, onClosePress}: SearchDropdownProps) {
4244
const feedValue = useFilterFeedValue();
4345
return (
4446
<DropdownButton
4547
label={label}
4648
value={feedValue}
4749
PopoverComponent={PopoverComponent}
4850
sentryLabel={sentryLabel}
51+
onClosePress={onClosePress}
4952
/>
5053
);
5154
}
5255

53-
function CardDropdown({label, PopoverComponent, sentryLabel}: SearchDropdownProps) {
56+
function CardDropdown({label, PopoverComponent, sentryLabel, onClosePress}: SearchDropdownProps) {
5457
const cardValue = useFilterCardValue();
5558
return (
5659
<DropdownButton
5760
label={label}
5861
value={cardValue}
5962
PopoverComponent={PopoverComponent}
6063
sentryLabel={sentryLabel}
64+
onClosePress={onClosePress}
6165
/>
6266
);
6367
}
6468

65-
function TaxRateDropdown({label, PopoverComponent, sentryLabel}: SearchDropdownProps) {
69+
function TaxRateDropdown({label, PopoverComponent, sentryLabel, onClosePress}: SearchDropdownProps) {
6670
const taxRateValue = useFilterTaxRateValue();
6771
return (
6872
<DropdownButton
6973
label={label}
7074
value={taxRateValue}
7175
PopoverComponent={PopoverComponent}
7276
sentryLabel={sentryLabel}
77+
onClosePress={onClosePress}
7378
/>
7479
);
7580
}
7681

77-
function ReportDropdown({label, value, PopoverComponent, sentryLabel}: SearchDropdownProps) {
82+
function ReportDropdown({label, value, PopoverComponent, sentryLabel, onClosePress}: SearchDropdownProps) {
7883
const reportValue = useFilterReportValue(value);
7984
return (
8085
<DropdownButton
8186
label={label}
8287
value={reportValue}
8388
PopoverComponent={PopoverComponent}
8489
sentryLabel={sentryLabel}
90+
onClosePress={onClosePress}
8591
/>
8692
);
8793
}
@@ -111,6 +117,7 @@ function SearchFilterBar({item}: {item: SearchFilter & FilterItem}) {
111117
value={item.value}
112118
PopoverComponent={item.PopoverComponent}
113119
sentryLabel={item.sentryLabel}
120+
onClosePress={item.onClosePress}
114121
/>
115122
);
116123
}

src/components/Search/SearchPageHeader/SearchPageInputWide.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ function SearchPageInputWide({queryJSON, handleSearch}: SearchPageInputWideProps
7474
inputStyle={isAutocompleteListVisible ? undefined : styles.fontSizeLabel}
7575
inputContainerStyle={isAutocompleteListVisible ? undefined : styles.ph2}
7676
touchableInputWrapperStyle={isAutocompleteListVisible ? undefined : styles.searchPageInputWideTouchableWrapper}
77+
clearButtonStyle={isAutocompleteListVisible ? undefined : styles.mh0}
7778
onSubmit={() => {
7879
const focusedOption = listRef.current?.getFocusedOption();
7980
if (focusedOption) {

0 commit comments

Comments
 (0)