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] add support for option tooltips #7715

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
2a961aa
feat(EuiToolTip): add controlled isOpen support
mgadewoll Apr 26, 2024
1fe33d4
feat(EuiSelectable): add support for toolTipContent and toolTipProps …
mgadewoll Apr 26, 2024
ae9cf1d
test(EuiSelectable): add test for tooltips on options
mgadewoll Apr 26, 2024
5cd93d4
docs(storybook): add standalone tooltip story for EuiSelectable
mgadewoll Apr 26, 2024
f78cabc
docs: add EUI docs example
mgadewoll Apr 26, 2024
1929ac4
chore: add changelog
mgadewoll Apr 26, 2024
79e4776
fix: ensure to cancel requestAnimationFrame on EuiSelectableList on u…
mgadewoll Apr 29, 2024
4df1f0b
chore: add changelog
mgadewoll Apr 29, 2024
06e62cc
refactor: remove isOpen from EuiTooltip
mgadewoll May 2, 2024
9fc40ab
refactor: use EuiToolTip ref show/hideToolTip API
mgadewoll May 2, 2024
6142110
docs: add alternatice tooltip position to EUI docs example
mgadewoll May 2, 2024
1dd28bc
docs(storybook): use include instead of hide for selected controls
mgadewoll May 2, 2024
c5d30a4
test(VRT): add references for EuiSelectable stories
mgadewoll May 2, 2024
196c785
Merge branch 'main' into feat/7690-selectable-option-tooltip-support
cee-chen May 6, 2024
f5cb35c
Merge branch 'main' into feat/7690-selectable-option-tooltip-support
cee-chen May 7, 2024
e629294
[opinionated] Remove `selectable_list.test.tsx` changes
cee-chen May 7, 2024
efe7a6b
[opinionated refactor] move a11y attrs back to `<li>`, add manual `ar…
cee-chen May 7, 2024
a357263
Docs pass
cee-chen May 7, 2024
a784e8f
[storybook] misc cleanup
cee-chen May 7, 2024
4851587
[opinionated refactor] Convert EuiSelectableListItem from a class com…
cee-chen May 8, 2024
bcf9e6d
Merge branch 'main' into feat/7690-selectable-option-tooltip-support
cee-chen May 9, 2024
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions changelogs/upcoming/7715.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
- Added support for `toolTipContent` and `toolTipProps` props on `EuiSelectable` options

**Bug fixes**

- Fixed issue with unmounted component state updates on requestAnimationFrame for `EuiSelectable`

55 changes: 55 additions & 0 deletions src-docs/src/views/selectable/selectable_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
EuiSelectableMessage,
EuiText,
EuiTextTruncate,
EuiToolTip,
EuiCallOut,
EuiLink,
} from '../../../../src';
Expand Down Expand Up @@ -42,6 +43,9 @@ const selectableSizingSource = require('!!raw-loader!./selectable_sizing');
import Truncation from './selectable_truncation';
const truncationSource = require('!!raw-loader!./selectable_truncation');

import SelectableToolTips from './selectable_tool_tips';
const selectableToolTipsSource = require('!!raw-loader!./selectable_tool_tips');

import SelectableCustomRender from './selectable_custom_render';
const selectableCustomRenderSource = require('!!raw-loader!./selectable_custom_render');

Expand Down Expand Up @@ -439,6 +443,57 @@ export const SelectableExample = {
</EuiSelectable>`,
demo: <Truncation />,
},

{
title: 'Tooltips',
source: [
{
type: GuideSectionTypes.TSX,
code: selectableToolTipsSource,
},
],
text: (
<>
<p>
If you have longer information that you need to make available to
users outside of truncated text, one approach could be adding
tooltip descriptions to individual options by passing{' '}
<EuiCode>toolTipContent</EuiCode>.
</p>
<p>
You can additionally customize individual tooltip behavior by
passing <EuiCode>toolTipProps</EuiCode>, which accepts any
configuration that{' '}
<Link to="/display/tooltip">
<strong>EuiToolTip</strong>
</Link>{' '}
accepts.
</p>
</>
),
props: {
EuiSelectableOptionProps,
EuiToolTip,
},
demo: <SelectableToolTips />,
snippet: `<EuiSelectable
aria-label="Example with option tooltips"
options={[
{
label: '',
checked: 'mixed',
toolTipContent: 'tooltip 1',
toolTipProps: {
position: 'bottom'
'data-test-subj': 'optionTooltip',
}
}
]}
onChange={newOptions => setOptions(newOptions)}
>
{list => list}
</EuiSelectable>`,
},
{
title: 'Rendering the options',
source: [
Expand Down
34 changes: 34 additions & 0 deletions src-docs/src/views/selectable/selectable_tool_tips.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React, { useState } from 'react';

import { EuiSelectable, EuiSelectableOption } from '../../../../src';

export default () => {
const [options, setOptions] = useState<EuiSelectableOption[]>([
{
label: 'Titan',
toolTipContent:
'Titan is the largest moon of Saturn and the second-largest in the Solar System',
},
{
label: 'Pandora',
toolTipContent:
"Pandora is one of Saturn's moons, named for a Titaness of Greek mythology",
},
{
label: 'Iapetus',
toolTipContent: "Iapetus is the outermost of Saturn's large moons",
toolTipProps: { position: 'bottom' },
},
]);

return (
<EuiSelectable
aria-label="Example with option tooltips"
options={options}
listProps={{ bordered: true, style: { maxInlineSize: 400 } }}
onChange={(newOptions) => setOptions(newOptions)}
>
{(list) => list}
</EuiSelectable>
);
};
150 changes: 150 additions & 0 deletions src/components/selectable/selectable.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import React, { useState } from 'react';
import type { Meta, StoryObj } from '@storybook/react';

import {
enableFunctionToggleControls,
hideStorybookControls,
} from '../../../.storybook/utils';

import { EuiSelectableOption } from './selectable_option';
import {
EuiSelectable,
EuiSelectableOnChangeEvent,
EuiSelectableProps,
} from './selectable';

const toolTipProps = {
toolTipContent: 'This is a tooltip!',
toolTipProps: { position: 'left' as const },
value: 4,
};

const options: EuiSelectableOption[] = [
{
label: 'Titan',
'data-test-subj': 'titanOption',
},
{
label: 'Enceladus is disabled',
disabled: true,
},
{
label: 'Mimas',
checked: 'on',
},
{
label: 'Dione',
},
{
label: 'Iapetus',
checked: 'on',
},
{
label: 'Phoebe',
},
{
label: 'Rhea',
},
{
label:
"Pandora is one of Saturn's moons, named for a Titaness of Greek mythology",
},
{
label: 'Tethys',
},
{
label: 'Hyperion',
},
];

const meta: Meta<EuiSelectableProps> = {
title: 'Forms/EuiSelectable',
component: EuiSelectable,
argTypes: {
singleSelection: { control: 'radio', options: [true, false, 'always'] },
emptyMessage: { control: 'text' },
loadingMessage: { control: 'text' },
noMatchesMessage: { control: 'text' },
selectableScreenReaderText: { control: 'text' },
},
args: {
searchable: false,
singleSelection: false,
isPreFiltered: false,
},
};
hideStorybookControls(meta, ['aria-label']);

export default meta;
type Story = StoryObj<EuiSelectableProps>;

export const Playground: Story = {
args: {
options,
// setting up for easier testing/QA
allowExclusions: false,
isLoading: false,
emptyMessage: '',
loadingMessage: '',
noMatchesMessage: '',
selectableScreenReaderText: '',
searchProps: {
'data-test-subj': 'selectableSearchHere',
},
},
render: ({ ...args }: EuiSelectableProps) => <StatefulSelectable {...args} />,
};
enableFunctionToggleControls(Playground, ['onChange', 'onActiveOptionChange']);

export const WithTooltip: Story = {
parameters: {
controls: {
include: ['options', 'singleSelection', 'searchable'],
},
},
args: {
options: options.map((option) => ({ ...option, ...toolTipProps })),
searchable: false,
},
render: ({ ...args }: EuiSelectableProps) => <StatefulSelectable {...args} />,
};

const StatefulSelectable = ({
options,
onChange,
...rest
}: EuiSelectableProps) => {
const [selectableOptions, setOptions] = useState(options);

const handleOnChange = (
options: EuiSelectableOption[],
event: EuiSelectableOnChangeEvent,
changedOption: EuiSelectableOption
) => {
setOptions(options);
onChange?.(options, event, changedOption);
};

return (
<EuiSelectable
{...rest}
options={selectableOptions}
onChange={handleOnChange}
>
{(list, search) => (
<>
{search}
{list}
</>
)}
</EuiSelectable>
);
};
Loading
Loading