Skip to content

Commit

Permalink
[EuiFilterGroup][FieldValueSelectionFilter] Use EuiSelectable (#5387)
Browse files Browse the repository at this point in the history
* use euiselectable

* update docs text

* use message props

* isVirtualized, labelProps support

* refactor search filters to use euiselectable

* CL

* clean up

* add docs for new configuration options

* CL fix

* review feedback

* fragment

* docs

* convert tests to cypress

* update filter count based on exclusions

* add recommendation for sizing

* use errorMessage

* fix cypress tests

* docs

* update docs
  • Loading branch information
thompsongl authored Feb 11, 2022
1 parent a5b0e11 commit 90a003c
Show file tree
Hide file tree
Showing 9 changed files with 280 additions and 783 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## [`main`](https://github.com/elastic/eui/tree/main)

- Improved `EuiSelectable` keypress scenarios ([#5613](https://github.com/elastic/eui/pull/5613))
- Converted `FieldValueSelectionFilter` in `EuiSearchBar` to use `EuiSelectable` ([#5387](https://github.com/elastic/eui/issues/5387))

## [`48.0.0`](https://github.com/elastic/eui/tree/v48.0.0)

Expand Down
16 changes: 11 additions & 5 deletions src-docs/src/views/filter_group/filter_group_example.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { Fragment } from 'react';
import { Link } from 'react-router-dom';

import { GuideSectionTypes } from '../../components';

Expand Down Expand Up @@ -74,11 +75,16 @@ export const FilterGroupExample = {
text: (
<Fragment>
<p>
To provide a long list of grouped filter, use a popover for
filtering an array of passed items. This mostly uses standard
popover mechanics, but the component{' '}
<strong>EuiFilterSelectItem</strong> is used for the items
themselves.
To provide a long list of grouped filters, we recommend wrapping the
filter button within an{' '}
<Link to="/layout/popover">
<strong>EuiPopover</strong>
</Link>{' '}
and passing the items to a searchable{' '}
<Link to="/forms/selectable">
<strong>EuiSelectable</strong>
</Link>
.
</p>
<h3>Indicating number of filters</h3>
<p>
Expand Down
169 changes: 76 additions & 93 deletions src-docs/src/views/filter_group/filter_group_multi.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
import React, { useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';

import {
EuiPopover,
EuiPopoverTitle,
EuiFieldSearch,
EuiFilterSelectItem,
EuiLoadingChart,
EuiSpacer,
EuiIcon,
EuiFilterGroup,
EuiFilterButton,
EuiSelectable,
EuiSpacer,
EuiSwitch,
} from '../../../../src/components';
import { useGeneratedHtmlId } from '../../../../src/services';

export default () => {
const timeoutRef = useRef();
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const [withLoading, setWithLoading] = useState(false);
const [isLoading, setIsLoading] = useState(false);

useEffect(() => {
return () => clearTimeout(timeoutRef.current);
}, []);

const onButtonClick = () => {
if (withLoading && !isPopoverOpen) {
setIsLoading(true);
timeoutRef.current = setTimeout(() => {
setIsLoading(false);
}, 1500);
}
setIsPopoverOpen(!isPopoverOpen);
};

Expand All @@ -29,56 +40,32 @@ export default () => {
});

const [items, setItems] = useState([
{ name: 'Johann Sebastian Bach', checked: 'on' },
{ name: 'Wolfgang Amadeus Mozart', checked: 'on' },
{ name: 'Antonín Dvořák', checked: 'off' },
{ name: 'Dmitri Shostakovich' },
{ name: 'Felix Mendelssohn-Bartholdy' },
{ name: 'Franz Liszt' },
{ name: 'Franz Schubert' },
{ name: 'Frédéric Chopin' },
{ name: 'Georg Friedrich Händel' },
{ name: 'Giuseppe Verdi' },
{ name: 'Gustav Mahler' },
{ name: 'Igor Stravinsky' },
{ name: 'Johannes Brahms' },
{ name: 'Joseph Haydn' },
{ name: 'Ludwig van Beethoven' },
{ name: 'Piotr Illitch Tchaïkovsky' },
{ name: 'Robert Schumann' },
{ name: 'Sergej S. Prokofiew' },
{ name: 'Wolfgang Amadeus Mozart' },
{ label: 'Johann Sebastian Bach', checked: 'on' },
{ label: 'Wolfgang Amadeus Mozart', checked: 'on' },
{ label: 'Antonín Dvořák', checked: 'off' },
{ label: 'Dmitri Shostakovich' },
{ label: 'Felix Mendelssohn-Bartholdy' },
{ label: 'Franz Liszt' },
{ label: 'Franz Schubert' },
{ label: 'Frédéric Chopin' },
{ label: 'Georg Friedrich Händel' },
{ label: 'Giuseppe Verdi' },
{ label: 'Gustav Mahler' },
{ label: 'Igor Stravinsky' },
{ label: 'Johannes Brahms' },
{ label: 'Joseph Haydn' },
{ label: 'Ludwig van Beethoven' },
{ label: 'Piotr Illitch Tchaïkovsky' },
{ label: 'Robert Schumann' },
{ label: 'Sergej S. Prokofiew' },
]);

function updateItem(index) {
if (!items[index]) {
return;
}

const newItems = [...items];

switch (newItems[index].checked) {
case 'on':
newItems[index].checked = 'off';
break;

case 'off':
newItems[index].checked = undefined;
break;

default:
newItems[index].checked = 'on';
}

setItems(newItems);
}

const button = (
<EuiFilterButton
iconType="arrowDown"
onClick={onButtonClick}
isSelected={isPopoverOpen}
numFilters={items.length}
numFilters={items.filter((item) => item.checked !== 'off').length}
hasActiveFilters={!!items.find((item) => item.checked === 'on')}
numActiveFilters={items.filter((item) => item.checked === 'on').length}
>
Expand All @@ -87,49 +74,45 @@ export default () => {
);

return (
<EuiFilterGroup>
<EuiPopover
id={filterGroupPopoverId}
button={button}
isOpen={isPopoverOpen}
closePopover={closePopover}
panelPaddingSize="none"
>
<EuiPopoverTitle paddingSize="s">
<EuiFieldSearch compressed />
</EuiPopoverTitle>
<div className="euiFilterSelect__items">
{items.map((item, index) => (
<EuiFilterSelectItem
checked={item.checked}
key={index}
onClick={() => updateItem(index)}
>
{item.name}
</EuiFilterSelectItem>
))}
{/*
Use when loading items initially
*/}
<div className="euiFilterSelect__note">
<div className="euiFilterSelect__noteContent">
<EuiLoadingChart size="m" />
<EuiSpacer size="xs" />
<p>Loading filters</p>
</div>
</div>
{/*
Use when no results are returned
*/}
<div className="euiFilterSelect__note">
<div className="euiFilterSelect__noteContent">
<EuiIcon type="minusInCircle" />
<EuiSpacer size="xs" />
<p>No filters found</p>
</div>
</div>
</div>
</EuiPopover>
</EuiFilterGroup>
<>
<EuiSwitch
checked={withLoading}
onChange={(e) => setWithLoading(e.target.checked)}
label="Simulate dynamic loading"
/>
<EuiSpacer />
<EuiFilterGroup>
<EuiPopover
id={filterGroupPopoverId}
button={button}
isOpen={isPopoverOpen}
closePopover={closePopover}
panelPaddingSize="none"
>
<EuiSelectable
allowExclusions
searchable
searchProps={{
placeholder: 'Filter list',
compressed: true,
}}
aria-label="Composers"
options={items}
onChange={(newOptions) => setItems(newOptions)}
isLoading={isLoading}
loadingMessage="Loading filters"
emptyMessage="No filters available"
noMatchesMessage="No filters found"
>
{(list, search) => (
<div style={{ width: 300 }}>
<EuiPopoverTitle paddingSize="s">{search}</EuiPopoverTitle>
{list}
</div>
)}
</EuiSelectable>
</EuiPopover>
</EuiFilterGroup>
</>
);
};
15 changes: 10 additions & 5 deletions src-docs/src/views/selectable/selectable_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,11 +225,16 @@ export const SelectableExample = {
<h3>Width and height</h3>
<p>
The width has been made to always be 100% of its container,
including stretching the search input. By default, the height is
capped at showing up to 7.5 items. It shows half of the last one to
help indicate that there are more options to scroll to. To stretch
the box to fill its container, pass &apos;full&apos; to the{' '}
<EuiCode>height</EuiCode> prop.
including stretching the search input. When used inside of{' '}
<Link to="layout/popover">
<strong>EuiPopover</strong>
</Link>
, we recommend setting a width (or min/max values) via CSS on the
element containing the list to avoid expansion and contraction. By
default, the height is capped at showing up to 7.5 items. It shows
half of the last one to help indicate that there are more options to
scroll to. To stretch the box to fill its container, pass
&apos;full&apos; to the <EuiCode>height</EuiCode> prop.
</p>
<h3>Flexbox</h3>
<p>
Expand Down
Loading

0 comments on commit 90a003c

Please sign in to comment.