Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## [`master`](https://github.com/elastic/eui/tree/master)

No public interface changes since `27.1.0`.
- Updated `EuiComboBox` to allow the options list to open for single selection custom options ([#3706](https://github.com/elastic/eui/pull/3706))

## [`27.1.0`](https://github.com/elastic/eui/tree/v27.1.0)

Expand Down
40 changes: 39 additions & 1 deletion src-docs/src/views/combo_box/combo_box_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,19 @@ const singleSelectionSnippet = `<EuiComboBox
options={options}
selectedOptions={selectedOptions}
onChange={onChange}
isClearable={false}
/>`;

import SingleSelectionCustomOptions from './single_selection_custom_options';
const singleSelectionCustomOptionsSource = require('!!raw-loader!./single_selection_custom_options');
const singleSelectionCustomOptionsHtml = renderToHtml(
SingleSelectionCustomOptions
);
const singleSelectionCustomOptionsSnippet = `<EuiComboBox
placeholder="Select a single option"
singleSelection={{ asPlainText: true }}
options={options}
selectedOptions={selectedOptions}
onChange={onChange}
Comment thread
elizabetdev marked this conversation as resolved.
/>`;

import DisallowCustomOptions from './disallow_custom_options';
Expand Down Expand Up @@ -405,6 +417,32 @@ export const ComboBoxExample = {
snippet: singleSelectionSnippet,
demo: <SingleSelection />,
},
{
title: 'Single selection with custom options',
source: [
{
type: GuideSectionTypes.JS,
code: singleSelectionCustomOptionsSource,
},
{
type: GuideSectionTypes.HTML,
code: singleSelectionCustomOptionsHtml,
},
],
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{' '}
<EuiCode>singleSelection</EuiCode> in conjunction with the{' '}
<EuiCode>onCreateOption</EuiCode> prop.
</p>
</Fragment>
),
props: { EuiComboBox },
snippet: singleSelectionCustomOptionsSnippet,
demo: <SingleSelectionCustomOptions />,
},
{
title: 'Disallowing custom options',
source: [
Expand Down
91 changes: 91 additions & 0 deletions src-docs/src/views/combo_box/single_selection_custom_options.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React, { useState } from 'react';

import { EuiComboBox } from '../../../../src/components';
import { DisplayToggles } from '../form_controls/display_toggles';

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

export default () => {
const [selectedOptions, setSelected] = useState([options[2]]);

const onChange = selectedOptions => {
// We should only get back either 0 or 1 options.
setSelected(selectedOptions);
};

const onCreateOption = (searchValue, flattenedOptions = []) => {
const normalizedSearchValue = searchValue.trim().toLowerCase();

if (!normalizedSearchValue) {
return;
}

const newOption = {
label: searchValue,
};

// Create the option if it doesn't exist.
if (
Comment thread
elizabetdev marked this conversation as resolved.
Outdated
flattenedOptions.findIndex(
option => option.label.trim().toLowerCase() === normalizedSearchValue
) === -1
) {
options.push(newOption);
}

// Select the option.
setSelected([newOption]);
};

return (
<DisplayToggles
canDisabled={false}
canReadOnly={false}
canLoading={false}
canPrepend
canAppend>
<EuiComboBox
placeholder="Select a single option"
singleSelection={{ asPlainText: true }}
options={options}
selectedOptions={selectedOptions}
onChange={onChange}
onCreateOption={onCreateOption}
isClearable={false}
/>
</DisplayToggles>
);
};
27 changes: 4 additions & 23 deletions src/components/combo_box/combo_box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -473,10 +473,7 @@ export class EuiComboBox<T> extends Component<

this.clearSearchValue();

if (
this.isSingleSelectionCustomOption() ||
Comment thread
elizabetdev marked this conversation as resolved.
(Boolean(singleSelection) && matchingOptions.length < 1)
) {
if (Boolean(singleSelection) && matchingOptions.length < 1) {
// Adding a custom option to a single select that does not appear in the list of options
this.closeList();
}
Expand Down Expand Up @@ -516,29 +513,13 @@ export class EuiComboBox<T> extends Component<
return flattenOptions.length === numberOfSelectedOptions;
};

isSingleSelectionCustomOption = () => {
const {
onCreateOption,
options,
selectedOptions,
singleSelection,
} = this.props;
// The selected option of a single select is custom and does not appear in the list of options
return (
Boolean(singleSelection) &&
onCreateOption &&
selectedOptions.length > 0 &&
!options.includes(selectedOptions[0])
);
};

onComboBoxFocus: FocusEventHandler<HTMLInputElement> = event => {
if (this.props.onFocus) {
this.props.onFocus(event);
}
if (!this.isSingleSelectionCustomOption()) {
this.openList();
}

this.openList();

this.setState({ hasFocus: true });
};

Expand Down