diff --git a/.changeset/serious-vans-sin.md b/.changeset/serious-vans-sin.md new file mode 100644 index 00000000000..9ba84efa91b --- /dev/null +++ b/.changeset/serious-vans-sin.md @@ -0,0 +1,5 @@ +--- +'@shopify/polaris': minor +--- + +[FiltersBar] Fixed bug where filters would disappear from the FiltersBar when clicking the Clear all button diff --git a/polaris-react/src/components/Filters/Filters.stories.tsx b/polaris-react/src/components/Filters/Filters.stories.tsx index dfefa8900db..338eb97c34a 100644 --- a/polaris-react/src/components/Filters/Filters.stories.tsx +++ b/polaris-react/src/components/Filters/Filters.stories.tsx @@ -1516,3 +1516,204 @@ export function WithFilterBarHidden() { ); } + +export function WithAllFiltersPinned() { + const [accountStatus, setAccountStatus] = useState(null); + const [moneySpent, setMoneySpent] = useState(null); + const [taggedWith, setTaggedWith] = useState(''); + const [queryValue, setQueryValue] = useState(''); + + const handleAccountStatusChange = useCallback( + (value) => setAccountStatus(value), + [], + ); + const handleMoneySpentChange = useCallback( + (value) => setMoneySpent(value), + [], + ); + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleFiltersQueryChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleAccountStatusRemove = useCallback( + () => setAccountStatus(null), + [], + ); + const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); + const handleFiltersClearAll = useCallback(() => { + handleAccountStatusRemove(); + handleMoneySpentRemove(); + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [ + handleAccountStatusRemove, + handleMoneySpentRemove, + handleQueryValueRemove, + handleTaggedWithRemove, + ]); + + const filters = [ + { + key: 'accountStatus', + label: 'Account status', + filter: ( + + ), + shortcut: true, + pinned: true, + }, + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + pinned: true, + }, + { + key: 'moneySpent', + label: 'Money spent', + filter: ( + + ), + shortcut: true, + pinned: true, + }, + ]; + + const appliedFilters: FiltersProps['appliedFilters'] = []; + if (!isEmpty(accountStatus)) { + const key = 'accountStatus'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, accountStatus), + onRemove: handleAccountStatusRemove, + }); + } + if (!isEmpty(moneySpent)) { + const key = 'moneySpent'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, moneySpent), + onRemove: handleMoneySpentRemove, + }); + } + if (!isEmpty(taggedWith)) { + const key = 'taggedWith'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, taggedWith), + onRemove: handleTaggedWithRemove, + }); + } + + return ( +
+ + + } + flushFilters + items={[ + { + id: '341', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: '256', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]} + renderItem={(item) => { + const {id, url, name, location} = item; + const media = ; + + return ( + + + {name} + +
{location}
+
+ ); + }} + /> +
+
+ ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'moneySpent': + return `Money spent is between $${value[0]} and $${value[1]}`; + case 'taggedWith': + return `Tagged with ${value}`; + case 'accountStatus': + return value.map((val) => `Customer ${val}`).join(', '); + default: + return value; + } + } + + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } + } +} diff --git a/polaris-react/src/components/Filters/components/FiltersBar/FiltersBar.tsx b/polaris-react/src/components/Filters/components/FiltersBar/FiltersBar.tsx index 019b6eb7299..489c14a9278 100644 --- a/polaris-react/src/components/Filters/components/FiltersBar/FiltersBar.tsx +++ b/polaris-react/src/components/Filters/components/FiltersBar/FiltersBar.tsx @@ -78,6 +78,10 @@ export function FiltersBar({ }; const appliedFilterKeys = appliedFilters?.map(({key}) => key); + const pinnedFromPropsKeys = filters + .filter(({pinned}) => pinned) + .map(({key}) => key); + const pinnedFiltersFromPropsAndAppliedFilters = filters.filter( ({pinned, key}) => { const isPinnedOrApplied = @@ -182,17 +186,23 @@ export function FiltersBar({ ); const handleClearAllFilters = () => { - setLocalPinnedFilters([]); + setLocalPinnedFilters(pinnedFromPropsKeys); onClearAll?.(); }; - const shouldShowAddButton = filters.some((filter) => !filter.pinned); + const shouldShowAddButton = + filters.some((filter) => !filter.pinned) || + filters.length !== localPinnedFilters.length; const pinnedFiltersMarkup = pinnedFilters.map( ({key: filterKey, ...pinnedFilter}) => { const appliedFilter = appliedFilters?.find(({key}) => key === filterKey); const handleFilterPillRemove = () => { setLocalPinnedFilters((currentLocalPinnedFilters) => - currentLocalPinnedFilters.filter((key) => key !== filterKey), + currentLocalPinnedFilters.filter((key) => { + const isMatchedFilters = key === filterKey; + const isPinnedFilterFromProps = pinnedFromPropsKeys.includes(key); + return !isMatchedFilters || isPinnedFilterFromProps; + }), ); appliedFilter?.onRemove(filterKey); }; @@ -236,26 +246,25 @@ export function FiltersBar({ ) : null; - const clearAllMarkup = - appliedFilters?.length || localPinnedFilters.length ? ( -
+ -
- ) : null; + {i18n.translate('Polaris.Filters.clearFilters')} + + + ) : null; return (
', () => { let originalScroll: any; @@ -388,4 +389,58 @@ describe('', () => { ], }); }); + + it('will keep a pinned filter from props pinned when clearing', () => { + const appliedFilters = [ + { + ...defaultProps.filters[1], + label: 'Bar 2', + value: ['Bar 2'], + onRemove: jest.fn(), + }, + ]; + const scrollSpy = jest.fn(); + HTMLElement.prototype.scroll = scrollSpy; + const wrapper = mountWithApp( + , + ); + + wrapper + .find(FilterPill, { + label: 'Bar 2', + })! + .trigger('onRemove'); + + expect(wrapper).toContainReactComponentTimes(FilterPill, 1); + }); + + it('will keep a pinned filter from props pinned when clearing all', () => { + const appliedFilters = [ + { + ...defaultProps.filters[0], + label: 'Bar 2', + value: ['Bar 2'], + onRemove: jest.fn(), + }, + { + ...defaultProps.filters[2], + label: 'Bar 2', + value: ['Bar 2'], + onRemove: jest.fn(), + }, + ]; + const scrollSpy = jest.fn(); + HTMLElement.prototype.scroll = scrollSpy; + const wrapper = mountWithApp( + , + ); + + wrapper + .find(Button, { + children: 'Clear all', + })! + .trigger('onClick'); + + expect(wrapper).toContainReactComponentTimes(FilterPill, 1); + }); });