Skip to content

Commit

Permalink
[EuiComboBox] add support for option tooltips (#7700)
Browse files Browse the repository at this point in the history
Co-authored-by: Cee Chen <[email protected]>
Co-authored-by: Tomasz Kajtoch <[email protected]>
  • Loading branch information
3 people authored May 3, 2024
1 parent 67a0675 commit 079cce4
Show file tree
Hide file tree
Showing 14 changed files with 670 additions and 404 deletions.
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/7700.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
- Updated `EuiComboBox`'s `options` to support including tooltip details for selectable options. Use `toolTipContent` to render tooltip information, and `toolTipProps` to optionally customize the tooltip rendering behavior

**Bug fixes**

- Fixed a visual layout bug for `EuiComboBox` with `isLoading` in mobile views

1 change: 1 addition & 0 deletions changelogs/upcoming/7709.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Added a new, optional `optionMatcher` prop to `EuiSelectable` and `EuiComboBox` allowing passing a custom option matcher function to these components and controlling option filtering for given search string
39 changes: 39 additions & 0 deletions src-docs/src/views/combo_box/combo_box_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,26 @@ const renderOptionSnippet = `<EuiComboBox
renderOption={renderOption}
/>`;

import ToolTips from './tool_tips';
const toolTipsSource = require('!!raw-loader!./tool_tips');
const toolTipsSnippet = `<EuiComboBox
aria-label="Accessible screen reader label"
placeholder="Select or create options"
options={[
{
label: 'option 1',
tooltipContent: 'tooltip 1',
tooltipProps: {
position: 'bottom'
'data-test-subj': 'optionTooltip',
}
}
]}
onChange={onChange}
onCreateOption={onCreateOption}
isClearable={true}
/>`;

import Truncation from './truncation';
const truncationSource = require('!!raw-loader!./truncation');
const truncationSnippet = `<EuiComboBox
Expand Down Expand Up @@ -472,6 +492,25 @@ export const ComboBoxExample = {
},
],
},
{
title: 'Tooltips',
source: [
{
type: GuideSectionTypes.JS,
code: toolTipsSource,
},
],
text: (
<p>
You can add tooltips to the options by passing{' '}
<EuiCode>toolTipContent</EuiCode>. Use <EuiCode>toolTipProps</EuiCode>{' '}
to pass additional <EuiCode>EuiToolTipProps</EuiCode> to the tooltip.
</p>
),
props: { EuiComboBox, EuiComboBoxOptionOption },
snippet: toolTipsSnippet,
demo: <ToolTips />,
},
{
title: 'Truncation',
source: [
Expand Down
43 changes: 43 additions & 0 deletions src-docs/src/views/combo_box/tool_tips.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React, { useState } from 'react';

import {
EuiComboBox,
EuiComboBoxOptionOption,
} from '../../../../src/components';

const options: Array<EuiComboBoxOptionOption<string>> = [
{
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' },
},
];
export default () => {
const [selectedOptions, setSelected] = useState([options[2]]);

const onChange = (
selectedOptions: Array<EuiComboBoxOptionOption<string>>
) => {
setSelected(selectedOptions);
};

return (
<EuiComboBox
aria-label="Example of combobox options with tooltips"
options={options}
selectedOptions={selectedOptions}
onChange={onChange}
isClearable={true}
/>
);
};
92 changes: 57 additions & 35 deletions src/components/combo_box/combo_box.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@ import { EuiComboBox, EuiComboBoxProps } from './combo_box';
import { EuiComboBoxOptionMatcher } from './types';
import { EuiCode } from '../code';

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

const options = [
{ label: 'Item 1' },
{ label: 'Item 2' },
{ label: 'Item 3' },
{ label: 'Item 4' },
{ label: 'Item 4', disabled: true },
{ label: 'Item 5' },
];

Expand Down Expand Up @@ -64,41 +70,19 @@ export default meta;
type Story = StoryObj<EuiComboBoxProps<{}>>;

export const Playground: Story = {
render: function Render({ singleSelection, onCreateOption, ...args }) {
const [selectedOptions, setSelectedOptions] = useState(
args.selectedOptions
);
const onChange: EuiComboBoxProps<{}>['onChange'] = (options, ...args) => {
setSelectedOptions(options);
action('onChange')(options, ...args);
};
const _onCreateOption: EuiComboBoxProps<{}>['onCreateOption'] = (
searchValue,
...args
) => {
const createdOption = { label: searchValue };
setSelectedOptions((prevState) =>
!prevState || singleSelection
? [createdOption]
: [...prevState, createdOption]
);
action('onCreateOption')(searchValue, ...args);
};
return (
<EuiComboBox
singleSelection={
// @ts-ignore Specific to Storybook control
singleSelection === 'asPlainText'
? { asPlainText: true }
: Boolean(singleSelection)
}
{...args}
selectedOptions={selectedOptions}
onChange={onChange}
onCreateOption={onCreateOption ? _onCreateOption : undefined}
/>
);
render: (args) => <StatefulComboBox {...args} />,
};

export const WithTooltip: Story = {
parameters: {
controls: {
include: ['fullWidth', 'options', 'selectedOptions'],
},
},
args: {
options: options.map((option) => ({ ...option, ...toolTipProps })),
},
render: (args) => <StatefulComboBox {...args} />,
};

export const CustomMatcher: Story = {
Expand Down Expand Up @@ -142,3 +126,41 @@ export const CustomMatcher: Story = {
);
},
};

const StatefulComboBox = ({
singleSelection,
onCreateOption,
...args
}: EuiComboBoxProps<{}>) => {
const [selectedOptions, setSelectedOptions] = useState(args.selectedOptions);
const onChange: EuiComboBoxProps<{}>['onChange'] = (options, ...args) => {
setSelectedOptions(options);
action('onChange')(options, ...args);
};
const _onCreateOption: EuiComboBoxProps<{}>['onCreateOption'] = (
searchValue,
...args
) => {
const createdOption = { label: searchValue };
setSelectedOptions((prevState) =>
!prevState || singleSelection
? [createdOption]
: [...prevState, createdOption]
);
action('onCreateOption')(searchValue, ...args);
};
return (
<EuiComboBox
singleSelection={
// @ts-ignore Specific to Storybook control
singleSelection === 'asPlainText'
? { asPlainText: true }
: Boolean(singleSelection)
}
{...args}
selectedOptions={selectedOptions}
onChange={onChange}
onCreateOption={onCreateOption ? _onCreateOption : undefined}
/>
);
};
Loading

0 comments on commit 079cce4

Please sign in to comment.