Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EuiSelectable] List enhancements and a11y #5581

Merged
merged 22 commits into from
Feb 4, 2022
Merged
Show file tree
Hide file tree
Changes from 21 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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
## [`main`](https://github.com/elastic/eui/tree/main)

- Added the ability to control internal `EuiDataGrid` fullscreen, cell focus, and cell popover state via the `ref` prop ([#5590](https://github.com/elastic/eui/pull/5590))
- Added `paddingSize` prop to `EuiSelectableList` ([#5581](https://github.com/elastic/eui/pull/5581))
- Added `errorMessage` prop to `EuiSelectable` ([#5581](https://github.com/elastic/eui/pull/5581))
- Refactored `EuiSelectable` accessibility ([#5581](https://github.com/elastic/eui/pull/5581))

**Bug fixes**

Expand Down
10 changes: 6 additions & 4 deletions src-docs/src/views/selectable/selectable_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -283,10 +283,11 @@ export const SelectableExample = {
<p>
The component comes with pre-composed messages for loading, empty,
and no search result states. To display your own messages, pass{' '}
<EuiCode>loadingMessage</EuiCode>, <EuiCode>emptyMessage</EuiCode>,
or <EuiCode>noMatchesMessage</EuiCode> respectively. Alternatively,
you can replace the entire <EuiCode>list</EuiCode> display with your
own message for any state. In which case, we recommend wrapping your
<EuiCode>loadingMessage</EuiCode>, <EuiCode>emptyMessage</EuiCode>,{' '}
<EuiCode>errorMessage</EuiCode>, or{' '}
<EuiCode>noMatchesMessage</EuiCode> respectively. Alternatively, you
can replace the entire <EuiCode>list</EuiCode> display with your own
message for any state. In which case, we recommend wrapping your
custom message in an <strong>EuiSelectableMessage</strong>{' '}
component.
</p>
Expand All @@ -302,6 +303,7 @@ export const SelectableExample = {
isLoading={isLoading}
loadingMessage={customLoadingMessage}
emptyMessage={customEmptyMessage}
errorMessage={hasError ? errorMessage : undefined}
noMatchesMessage={customNoMatchesMessage}>
{list => list}
</EuiSelectable>`,
Expand Down
9 changes: 9 additions & 0 deletions src-docs/src/views/selectable/selectable_messages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import { EuiSpacer } from '../../../../src/components/spacer';
export default () => {
const [useCustomMessage, setUseCustomMessage] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [hasError, setHasError] = useState(false);

const emptyMessage = 'You have no spice';
const loadingMessage = "Hey, I'm loading here!";
const errorMessage = 'Error!';

return (
<Fragment>
Expand All @@ -24,6 +26,12 @@ export default () => {
onChange={(e) => setIsLoading(e.target.checked)}
checked={isLoading}
/>
&emsp;
<EuiSwitch
label="Show error"
onChange={(e) => setHasError(e.target.checked)}
checked={hasError}
/>
<EuiSpacer />
<EuiSelectable
aria-label="Messaging example"
Expand All @@ -33,6 +41,7 @@ export default () => {
isLoading={isLoading}
loadingMessage={useCustomMessage ? loadingMessage : undefined}
emptyMessage={useCustomMessage ? emptyMessage : undefined}
errorMessage={hasError ? errorMessage : undefined}
>
{(list) => list}
</EuiSelectable>
Expand Down
7 changes: 5 additions & 2 deletions src-docs/src/views/selectable/selectable_popover.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,10 @@ export default () => {

<EuiTitle size="xxs">
<h4>
Using <EuiCode language="js">listProps.bordered=true</EuiCode>
Using <EuiCode language="js">listProps.bordered=true</EuiCode> and{' '}
<EuiCode language="js">
listProps.paddingSize=&quot;none&quot;
</EuiCode>
</h4>
</EuiTitle>

Expand All @@ -157,7 +160,7 @@ export default () => {
options={options}
onChange={() => {}}
style={{ width: 300 }}
listProps={{ bordered: true }}
listProps={{ bordered: true, paddingSize: 'none' }}
>
{(list) => list}
</EuiSelectable>
Expand Down
187 changes: 179 additions & 8 deletions src/components/selectable/__snapshots__/selectable.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ exports[`EuiSelectable custom options with data 1`] = `
<div
class="euiSelectable"
>
<p
class="euiScreenReaderOnly"
id="generated-id-instructions"
>
Filter options
</p>
<div
class="euiSelectableList"
>
Expand All @@ -18,11 +24,12 @@ exports[`EuiSelectable custom options with data 1`] = `
style="height:96px;width:100%"
>
<li
aria-checked="false"
aria-posinset="1"
aria-selected="false"
aria-setsize="3"
class="euiSelectableListItem"
id="generated-id_listbox_option-0"
class="euiSelectableListItem euiSelectableListItem--paddingSmall"
id="generated-id_option-0"
role="option"
style="position:absolute;left:0;top:0;height:32px;width:100%"
title="Titan"
Expand All @@ -44,11 +51,12 @@ exports[`EuiSelectable custom options with data 1`] = `
</span>
</li>
<li
aria-checked="false"
aria-posinset="2"
aria-selected="false"
aria-setsize="3"
class="euiSelectableListItem"
id="generated-id_listbox_option-1"
class="euiSelectableListItem euiSelectableListItem--paddingSmall"
id="generated-id_option-1"
role="option"
style="position:absolute;left:0;top:32px;height:32px;width:100%"
title="Enceladus"
Expand All @@ -70,11 +78,12 @@ exports[`EuiSelectable custom options with data 1`] = `
</span>
</li>
<li
aria-checked="false"
aria-posinset="3"
aria-selected="false"
aria-setsize="3"
class="euiSelectableListItem"
id="generated-id_listbox_option-2"
class="euiSelectableListItem euiSelectableListItem--paddingSmall"
id="generated-id_option-2"
role="option"
style="position:absolute;left:0;top:64px;height:32px;width:100%"
title="Pandora is one of Saturn's moons, named for a Titaness of Greek mythology"
Expand Down Expand Up @@ -102,6 +111,168 @@ exports[`EuiSelectable custom options with data 1`] = `
</div>
`;

exports[`EuiSelectable errorMessage prop can render an element as the message 1`] = `
<div
class="euiSelectable"
>
<p
class="euiScreenReaderOnly"
id="generated-id-instructions"
>
Filter options
</p>
<div
class="euiText euiText--extraSmall euiSelectableMessage"
id="generated-id_messageContent"
>
<div
class="euiTextColor euiTextColor--subdued"
>
<span>
Element error!
</span>
</div>
</div>
</div>
`;

exports[`EuiSelectable errorMessage prop does not render the message when not defined 1`] = `
<div
class="euiSelectable"
>
<p
class="euiScreenReaderOnly"
id="generated-id-instructions"
>
Filter options
</p>
<div
class="euiSelectableList"
>
<div
data-eui="EuiAutoSizer"
>
<div
class="euiSelectableList__list"
style="position:relative;height:96px;width:600px;overflow:auto;-webkit-overflow-scrolling:touch;will-change:transform;direction:ltr"
>
<ul
style="height:96px;width:100%"
>
<li
aria-checked="false"
aria-posinset="1"
aria-selected="false"
aria-setsize="3"
class="euiSelectableListItem euiSelectableListItem--paddingSmall"
data-test-subj="titanOption"
id="generated-id_option-0"
role="option"
style="position:absolute;left:0;top:0;height:32px;width:100%"
title="Titan"
>
<span
class="euiSelectableListItem__content"
>
<span
class="euiSelectableListItem__icon"
data-euiicon-type="empty"
/>
<span
class="euiSelectableListItem__text"
>
<span>
Titan
</span>
</span>
</span>
</li>
<li
aria-checked="false"
aria-posinset="2"
aria-selected="false"
aria-setsize="3"
class="euiSelectableListItem euiSelectableListItem--paddingSmall"
id="generated-id_option-1"
role="option"
style="position:absolute;left:0;top:32px;height:32px;width:100%"
title="Enceladus"
>
<span
class="euiSelectableListItem__content"
>
<span
class="euiSelectableListItem__icon"
data-euiicon-type="empty"
/>
<span
class="euiSelectableListItem__text"
>
<span>
Enceladus
</span>
</span>
</span>
</li>
<li
aria-checked="false"
aria-posinset="3"
aria-selected="false"
aria-setsize="3"
class="euiSelectableListItem euiSelectableListItem--paddingSmall"
id="generated-id_option-2"
role="option"
style="position:absolute;left:0;top:64px;height:32px;width:100%"
title="Pandora is one of Saturn's moons, named for a Titaness of Greek mythology"
>
<span
class="euiSelectableListItem__content"
>
<span
class="euiSelectableListItem__icon"
data-euiicon-type="empty"
/>
<span
class="euiSelectableListItem__text"
>
<span>
Pandora is one of Saturn's moons, named for a Titaness of Greek mythology
</span>
</span>
</span>
</li>
</ul>
</div>
</div>
</div>
</div>
`;

exports[`EuiSelectable errorMessage prop does renders the message when defined 1`] = `
<div
class="euiSelectable"
>
<p
class="euiScreenReaderOnly"
id="generated-id-instructions"
>
Filter options
</p>
<div
class="euiText euiText--extraSmall euiSelectableMessage"
id="generated-id_messageContent"
>
<div
class="euiTextColor euiTextColor--subdued"
>
<p>
Error!
</p>
</div>
</div>
</div>
`;

exports[`EuiSelectable is rendered 1`] = `
<div
class="euiSelectable testClass1 testClass2"
Expand Down Expand Up @@ -179,8 +350,8 @@ Object {

exports[`EuiSelectable should not reset the activeOptionIndex nor isFocused when EuiSelectable is blurred in favour of its popover 2`] = `
Object {
"activeOptionIndex": 0,
"isFocused": true,
"activeOptionIndex": undefined,
"isFocused": false,
"searchValue": "",
"visibleOptions": Array [
Object {
Expand Down
35 changes: 35 additions & 0 deletions src/components/selectable/selectable.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -252,4 +252,39 @@ describe('EuiSelectable', () => {
expect(component).toMatchSnapshot();
});
});

describe('errorMessage prop', () => {
it('does not render the message when not defined', () => {
const component = render(
<EuiSelectable options={options} errorMessage={null}>
{(list) => list}
</EuiSelectable>
);

expect(component).toMatchSnapshot();
});

it('does renders the message when defined', () => {
const component = render(
<EuiSelectable options={options} errorMessage="Error!">
{(list) => list}
</EuiSelectable>
);

expect(component).toMatchSnapshot();
});

it('can render an element as the message', () => {
const component = render(
<EuiSelectable
options={options}
errorMessage={<span>Element error!</span>}
>
{(list) => list}
</EuiSelectable>
);

expect(component).toMatchSnapshot();
});
});
});
Loading