Skip to content

Commit

Permalink
[EuiComboBox] Added option.prepend and option.append support (#6953)
Browse files Browse the repository at this point in the history
* added icon as an option

* add changelog

* fix

* Remove `renderPill` types

* Change `option.icon` prop to `option.prepend` and `option.append`

* Add styles for margins + vertical alignment

+ cleanup - flatten more `euiComboBoxOption` selectors

* Fix new `option` keys being spread to pill DOM

+ other misc cleanup - remove unnecessary eslint disable (accounts for rest spread), add some newlines

* Revert EuiBadge changes

* Documentation

- Use just one demo that switches between single selection and multi selection

- Reuse as much copy from `EuiSelectable` as possible

- misc cleanup - remove `Fragment`s

* changelog

* [PR feedback] Pill line height

---------

Co-authored-by: Cee Chen <[email protected]>
  • Loading branch information
shahzad31 and cee-chen authored Jul 21, 2023
1 parent 951f049 commit 0fc3700
Show file tree
Hide file tree
Showing 11 changed files with 442 additions and 41 deletions.
80 changes: 64 additions & 16 deletions src-docs/src/views/combo_box/combo_box_example.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { Fragment } from 'react';
import React from 'react';

import { Link } from 'react-router-dom';

Expand Down Expand Up @@ -49,6 +49,27 @@ const colorsSnippet = `<EuiComboBox
isClearable={true}
/>`;

import OptionPrependAppend from './option_prepend_append';
const optionPrependAppendSource = require('!!raw-loader!./option_prepend_append');
const optionsPrependAppendSnippet = `<EuiComboBox
aria-label="Accessible screen reader label"
placeholder="Select or create options"
options={[
{
label: 'Titan',
prepend: <EuiIcon type="bell" size="s" />,
},
{
label: 'Mimas',
append: '(5)',
},
]}
selectedOptions={selectedOptions}
onChange={onChange}
onCreateOption={onCreateOption}
isClearable={true}
/>`;

import RenderOption from './render_option';
const renderOptionSource = require('!!raw-loader!./render_option');
const renderOptionSnippet = `<EuiComboBox
Expand Down Expand Up @@ -224,7 +245,7 @@ const labelledbySnippet = `<EuiComboBox
export const ComboBoxExample = {
title: 'Combo box',
intro: (
<Fragment>
<>
<EuiText>
<p>
Use a <strong>EuiComboBox</strong> when the input has so many options
Expand All @@ -248,7 +269,7 @@ export const ComboBoxExample = {
<EuiCode>aria-labelledby</EuiCode> prop.
</EuiCallOut>
</EuiText>
</Fragment>
</>
),
sections: [
{
Expand Down Expand Up @@ -364,33 +385,60 @@ export const ComboBoxExample = {
},
{
title: 'Option rendering',
text: (
<p>
There are two object properties you can add to enhance the content of
your options, <EuiCode>option.prepend</EuiCode> and{' '}
<EuiCode>option.append</EuiCode>. These will add nodes before and
after the option label respectively, to both the dropdown option and
selected pill. They will not be included in the searchable content as
this only matches against the label property.
</p>
),
props: { EuiComboBox, EuiComboBoxOptionOption },
snippet: optionsPrependAppendSnippet,
demo: <OptionPrependAppend />,
source: [
{
type: GuideSectionTypes.JS,
code: renderOptionSource,
code: optionPrependAppendSource,
},
],
},
{
text: (
<Fragment>
<>
<h3 id="renderOption">Custom dropdown content</h3>
<p>
While it is best to stick to the <EuiCode>option.label</EuiCode>,{' '}
<EuiCode>option.append</EuiCode>, and{' '}
<EuiCode>option.prepend</EuiCode> props, you can pass a custom{' '}
<EuiCode>renderOption</EuiCode> function which will pass back the
single option <EuiCode>option</EuiCode> and the{' '}
<EuiCode>searchValue</EuiCode> to use for highlighting.
</p>
<p>
You can provide a <EuiCode>renderOption</EuiCode> prop which will
accept <EuiCode>option</EuiCode> and <EuiCode>searchValue</EuiCode>{' '}
arguments. Use the <EuiCode>value</EuiCode> prop of the{' '}
You can use the <EuiCode>value</EuiCode> prop of the{' '}
<EuiCode>option</EuiCode> object to store metadata about the option
for use in this callback.
</p>

<p>
<strong>Note:</strong> virtualization (above) requires that each
option have the same height. Ensure that you render the options so
that wrapping text is truncated instead of causing the height of the
option to change.
</p>
</Fragment>
</>
),
props: { EuiComboBox, EuiComboBoxOptionOption },
snippet: renderOptionSnippet,
demo: <RenderOption />,
source: [
{
type: GuideSectionTypes.JS,
code: renderOptionSource,
},
],
},
{
title: 'Groups',
Expand Down Expand Up @@ -419,7 +467,7 @@ export const ComboBoxExample = {
},
],
text: (
<Fragment>
<>
<p>
To only allow the user to select a single option, provide the{' '}
<EuiCode>singleSelection</EuiCode> prop. You may want to render the
Expand All @@ -428,7 +476,7 @@ export const ComboBoxExample = {
{'singleSelection={{ asPlainText: true }}'}
</EuiCode>
</p>
</Fragment>
</>
),
props: { EuiComboBox, EuiComboBoxOptionOption },
snippet: singleSelectionSnippet,
Expand All @@ -443,7 +491,7 @@ export const ComboBoxExample = {
},
],
text: (
<Fragment>
<>
<p>
<EuiCode>append</EuiCode> and <EuiCode>prepend</EuiCode> props only
work if
Expand All @@ -452,7 +500,7 @@ export const ComboBoxExample = {
height greater than that of <EuiCode>append</EuiCode> and{' '}
<EuiCode>prepend</EuiCode>.
</p>
</Fragment>
</>
),
props: { EuiComboBox, EuiComboBoxOptionOption },
snippet: singleSelectionPrependSnippet,
Expand All @@ -467,7 +515,7 @@ export const ComboBoxExample = {
},
],
text: (
<Fragment>
<>
<p>
You can allow the user to select a single option and also allow the
creation of custom options. To do that, use the{' '}
Expand All @@ -480,7 +528,7 @@ export const ComboBoxExample = {
available. You can also customize the custom option text by passing
a text to <EuiCode>customOptionText</EuiCode> prop.
</p>
</Fragment>
</>
),
props: { EuiComboBox, EuiComboBoxOptionOption },
snippet: singleSelectionCustomOptionsSnippet,
Expand Down
76 changes: 76 additions & 0 deletions src-docs/src/views/combo_box/option_prepend_append.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React, { useState, useMemo } from 'react';

import {
EuiComboBox,
EuiIcon,
EuiSwitch,
EuiSpacer,
} from '../../../../src/components';

const options = [
{
label: 'Titan',
'data-test-subj': 'titanOption',
prepend: <EuiIcon size="s" type="bell" />,
},
{
label: 'Enceladus',
prepend: <EuiIcon size="s" type="bolt" />,
},
{
label: 'Mimas',
prepend: <EuiIcon size="s" type="bug" />,
},
{
label:
"Pandora is one of Saturn's moons, named for a Titaness of Greek mythology",
prepend: <EuiIcon size="s" type="discuss" />,
append: '(10)',
},
{
label: 'Iapetus',
prepend: <EuiIcon size="s" type="flag" color="danger" />,
append: '(2)',
},
{
label: 'Phoebe',
prepend: <EuiIcon size="s" type="tag" color="success" />,
append: '(5)',
},
];

export default () => {
const [selectedOptions, setSelected] = useState([options[0], options[5]]);
const [singleSelection, setSingleSelection] = useState(false);

const singleSelectedOption = useMemo(() => {
return selectedOptions.length ? [selectedOptions[0]] : [];
}, [selectedOptions]);

const onChange = (selectedOptions) => {
setSelected(selectedOptions);
};

return (
<>
<EuiSwitch
checked={singleSelection}
onChange={() => setSingleSelection(!singleSelection)}
label="Single selection"
/>
<EuiSpacer />
<EuiComboBox
aria-label="Combo box demo with option prepend/append nodes"
options={options}
onChange={onChange}
singleSelection={singleSelection ? { asPlainText: true } : false}
selectedOptions={
singleSelection ? singleSelectedOption : selectedOptions
}
placeholder={`Select one ${
singleSelection ? 'option' : 'or more options'
}`}
/>
</>
);
};
Loading

0 comments on commit 0fc3700

Please sign in to comment.