Skip to content

Commit

Permalink
EuiComboBox (#567)
Browse files Browse the repository at this point in the history
* Add EuiComboBox and EuiHighlight.
* calculatePopoverPosition service now accepts a positions argument so you can specify which positions are acceptable
* Added closeButtonProps prop to EuiBadge, hollow badge type, and support for arbitrary hex color
* Added support for arbitrary hex color to EuiIcon
  • Loading branch information
cjcenizal committed Mar 30, 2018
1 parent a64cc09 commit ff9d5aa
Show file tree
Hide file tree
Showing 78 changed files with 2,841 additions and 89 deletions.
19 changes: 14 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
# [`master`](https://github.com/elastic/eui/tree/master)

No public interface changes since `0.0.36`.
- Added `EuiComboBox` for selecting many options from a list of options ([567](https://github.com/elastic/eui/pull/567))
- Added `EuiHighlight` for highlighting a substring within text ([567](https://github.com/elastic/eui/pull/567))
- `calculatePopoverPosition` service now accepts a `positions` argument so you can specify which positions are acceptable ([567](https://github.com/elastic/eui/pull/567))
- Added `closeButtonProps` prop to `EuiBadge`, `hollow` badge type, and support for arbitrary hex color ([567](https://github.com/elastic/eui/pull/567))
- Added support for arbitrary hex color to `EuiIcon` ([567](https://github.com/elastic/eui/pull/567))

**Breaking changes**

- Renamed `euiBody-hasToolTip` class to `euiBody-hasPortalContent` ([567](https://github.com/elastic/eui/pull/567))

# [`0.0.36`](https://github.com/elastic/eui/tree/v0.0.36)

- Relaxed query syntax of `EuiSearchBar` to allow usage of hyphens without escaping ([#581](https://github.com/elastic/eui/pull/581))
- Added support for range queries in `EuiSearchBar` (works for numeric and date values) ([#485](https://github.com/elastic/eui/pull/485))
- Added support for emitting a `EuiSearchBar` query to an Elasticsearch query string ([#598](https://github.com/elastic/eui/pull/598))
- Add support for expandable rows to `EuiBasicTable` ([#585](https://github.com/elastic/eui/pull/585))
- Added support for expandable rows to `EuiBasicTable` ([#585](https://github.com/elastic/eui/pull/585))

**Bug fixes**
- Fix font-weight issue in K6 theme ([#596](https://github.com/elastic/eui/pull/596))

- Relaxed query syntax of `EuiSearchBar` to allow usage of hyphens without escaping ([#581](https://github.com/elastic/eui/pull/581))
- Fixed font-weight issue in K6 theme ([#596](https://github.com/elastic/eui/pull/596))

# [`0.0.35`](https://github.com/elastic/eui/tree/v0.0.35)

- Modified `link` and all buttons to support both href and onClick ([#554](https://github.com/elastic/eui/pull/554))
- Modified `EuiLink` and all buttons to support both href and onClick ([#554](https://github.com/elastic/eui/pull/554))
- Added `color` prop to `EuiIconTip` ([#580](https://github.com/elastic/eui/pull/580))

# [`0.0.34`](https://github.com/elastic/eui/tree/v0.0.34)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const <%= componentExampleName %>Example = {
Description needed: how to use the <EuiCode>Eui<%= componentExampleName %></EuiCode> component.
</p>
),
components: { <%= componentName %> },
props: { <%= componentName %> },
demo: <<%= componentExampleName %> />,
}],
};
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"prop-types": "^15.6.0",
"react-ace": "^5.5.0",
"react-color": "^2.13.8",
"react-input-autosize": "^2.2.1",
"serve": "^6.3.1",
"tabbable": "^1.1.0",
"uuid": "^3.1.0"
Expand Down
8 changes: 8 additions & 0 deletions src-docs/src/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ import { CodeExample }
import { ColorPickerExample }
from './views/color_picker/color_picker_example';

import { ComboBoxExample }
from './views/combo_box/combo_box_example';

import { ContextMenuExample }
from './views/context_menu/context_menu_example';

Expand Down Expand Up @@ -113,6 +116,9 @@ import { HeaderExample }
import { HealthExample }
from './views/health/health_example';

import { HighlightExample }
from './views/highlight/highlight_example';

import { HorizontalRuleExample }
from './views/horizontal_rule/horizontal_rule_example';

Expand Down Expand Up @@ -302,6 +308,7 @@ const navigation = [{
FormLayoutsExample,
FormControlsExample,
FormValidationExample,
ComboBoxExample,
ColorPickerExample,
CodeEditorExample,
ExpressionExample,
Expand All @@ -314,6 +321,7 @@ const navigation = [{
AccessibilityExample,
DelayHideExample,
ErrorBoundaryExample,
HighlightExample,
IsColorDarkExample,
OutsideClickDetectorExample,
PortalExample,
Expand Down
1 change: 1 addition & 0 deletions src-docs/src/views/badge/badge.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {

const badges = [
'default',
'hollow',
'primary',
'secondary',
'accent',
Expand Down
114 changes: 114 additions & 0 deletions src-docs/src/views/combo_box/async.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import React, { Component } from 'react';

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

const allOptions = [{
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 class extends Component {
constructor(props) {
super(props);

this.state = {
isLoading: false,
isPopoverOpen: false,
selectedOptions: [],
options: [],
};
}

onChange = (selectedOptions) => {
this.setState({
selectedOptions,
});
};

onSearchChange = (searchValue) => {
this.setState({
isLoading: true,
options: [],
});

clearTimeout(this.searchTimeout);

this.searchTimeout = setTimeout(() => {
// Simulate a remotely-executed search.
this.setState({
isLoading: false,
options: allOptions.filter(option => option.label.toLowerCase().includes(searchValue.toLowerCase())),
});
}, 1200);
}

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

if (!normalizedSearchValue) {
return;
}

const newOption = {
label: searchValue,
};

// Create the option if it doesn't exist.
if (flattenedOptions.findIndex(option =>
option.value.trim().toLowerCase() === normalizedSearchValue
) === -1) {
// Simulate creating this option on the server.
allOptions.push(newOption);
this.setState(prevState => ({
options: prevState.options.concat(newOption),
}));
}

// Select the option.
this.setState(prevState => ({
selectedOptions: prevState.selectedOptions.concat(newOption),
}));
};

componentDidMount() {
// Simulate initial load.
this.onSearchChange('');
}

render() {
const { selectedOptions, isLoading, options } = this.state;

return (
<EuiComboBox
placeholder="Search asynchronously"
async
options={options}
selectedOptions={selectedOptions}
isLoading={isLoading}
onChange={this.onChange}
onSearchChange={this.onSearchChange}
onCreateOption={this.onCreateOption}
/>
);
}
}
92 changes: 92 additions & 0 deletions src-docs/src/views/combo_box/colors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import React, { Component } from 'react';

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

export default class extends Component {
constructor(props) {
super(props);

this.options = [{
label: 'Titan',
'data-test-subj': 'titanOption',
color: 'primary',
}, {
label: 'Enceladus',
color: 'secondary',
}, {
label: 'Mimas',
color: '#DB1374',
}, {
label: 'Dione',
color: 'accent',
}, {
label: 'Iapetus',
color: 'primary',
color: 'warning',
}, {
label: 'Phoebe',
color: 'danger',
}, {
label: 'Rhea',
color: 'default',
}, {
label: 'Pandora is one of Saturn\'s moons, named for a Titaness of Greek mythology',
color: '#F98510',
}, {
label: 'Tethys',
color: '#FEB6DB',
}, {
label: 'Hyperion',
color: '#BFA180',
}];

this.state = {
selectedOptions: [this.options[2], this.options[4]],
};
}

onChange = (selectedOptions) => {
this.setState({
selectedOptions,
});
};

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

if (!normalizedSearchValue) {
return;
}

const newOption = {
label: searchValue,
};

// Create the option if it doesn't exist.
if (flattenedOptions.findIndex(option =>
option.value.trim().toLowerCase() === normalizedSearchValue
) === -1) {
this.options.push(newOption);
}

// Select the option.
this.setState(prevState => ({
selectedOptions: prevState.selectedOptions.concat(newOption),
}));
};

render() {
const { selectedOptions } = this.state;
return (
<EuiComboBox
placeholder="Select or create options"
options={this.options}
selectedOptions={selectedOptions}
onChange={this.onChange}
onCreateOption={this.onCreateOption}
/>
);
}
}
81 changes: 81 additions & 0 deletions src-docs/src/views/combo_box/combo_box.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React, { Component } from 'react';

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

export default class extends Component {
constructor(props) {
super(props);

this.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',
}];

this.state = {
selectedOptions: [this.options[2], this.options[4]],
};
}

onChange = (selectedOptions) => {
this.setState({
selectedOptions,
});
};

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

if (!normalizedSearchValue) {
return;
}

const newOption = {
label: searchValue,
};

// Create the option if it doesn't exist.
if (flattenedOptions.findIndex(option =>
option.label.trim().toLowerCase() === normalizedSearchValue
) === -1) {
this.options.push(newOption);
}

// Select the option.
this.setState(prevState => ({
selectedOptions: prevState.selectedOptions.concat(newOption),
}));
};

render() {
const { selectedOptions } = this.state;
return (
<EuiComboBox
placeholder="Select or create options"
options={this.options}
selectedOptions={selectedOptions}
onChange={this.onChange}
onCreateOption={this.onCreateOption}
/>
);
}
}
Loading

0 comments on commit ff9d5aa

Please sign in to comment.