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

EuiComboBox #567

Merged
merged 61 commits into from
Mar 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
f07e1d7
Add EuiComboBox prototype.
cjcenizal Mar 22, 2018
27f3c3a
Refactor and remove footer.
cjcenizal Mar 23, 2018
b1935a8
Add/remove pill functionality.
cjcenizal Mar 23, 2018
51492d2
Truncate text for pills which are wider than container.
cjcenizal Mar 23, 2018
70a2bc8
Resize input to fill remaining width without spilling onto a newline.
cjcenizal Mar 23, 2018
e6257ae
Integrate combo box into the page's tab order.
cjcenizal Mar 23, 2018
d858b27
Prevent pills from overlapping with the caret.
cjcenizal Mar 23, 2018
a28fed2
Remove border from input in Safari.
cjcenizal Mar 23, 2018
f0f1127
Improve tab order logic and support up and down arrow keys for traver…
cjcenizal Mar 24, 2018
2d2c24e
Support arbitrary props on pills and options. Dynamically resize inpu…
cjcenizal Mar 24, 2018
17552db
Prevent up and down arrow navigation when there are no items in the l…
cjcenizal Mar 24, 2018
3640348
Add onCreateOption prop for when the user adds a new option based on …
cjcenizal Mar 24, 2018
e07a42a
Track focus correctly when an option is clicked and focused, but not …
cjcenizal Mar 24, 2018
73e58a1
Clear and reset focus to the input when the user selects an option, w…
cjcenizal Mar 25, 2018
ca37872
Remove periods from single-sentence empty state messages.
cjcenizal Mar 25, 2018
1b91ecb
Fix bug caused by trimming searchValue.
cjcenizal Mar 26, 2018
e4acf70
Add EuiHighlight. Highlight matches within EuiComboBox options.
cjcenizal Mar 26, 2018
0d624fb
Use EuiText to present empty state and refine copy.
cjcenizal Mar 26, 2018
ac58a60
Fix input styles.
cjcenizal Mar 26, 2018
b84f820
Delete pills with BACKSPACE. Prevent duplicate custom pills from bein…
cjcenizal Mar 26, 2018
b3aa88b
Fix linting errors.
cjcenizal Mar 27, 2018
2805e2d
Add support for grouping options.
cjcenizal Mar 27, 2018
cc0a52f
Support disallowing custom options.
cjcenizal Mar 27, 2018
4722425
Internalize searchValue. Refactor logic for updating matchingOptions …
cjcenizal Mar 27, 2018
a83bbde
Add comments, light cleanup.
cjcenizal Mar 27, 2018
0dfcbdf
Significantly simplify matchingOptions and activeOptionIndex logic.
cjcenizal Mar 27, 2018
ebd461a
Extract logic from EuiComboBox to shrink file length.
cjcenizal Mar 27, 2018
688985d
Fix bug: don't delete a pill if an option is active.
cjcenizal Mar 27, 2018
2c7f256
Fix bug: allow user to enter a custom input if it partially matches a…
cjcenizal Mar 27, 2018
9dca415
Extract logic out of key handler.
cjcenizal Mar 27, 2018
5fedaaf
Support async loading of options and creation of custom options.
cjcenizal Mar 27, 2018
0a3aa44
Add support for screen reader accessibility.
cjcenizal Mar 28, 2018
7b8c18c
Support hiding the options list and only allowing the user to add cus…
cjcenizal Mar 28, 2018
8da939d
Place options list inside of an EuiPortal.
cjcenizal Mar 28, 2018
194a734
Support single-selection.
cjcenizal Mar 28, 2018
6dc8fc7
Add title attribute for truncated pills.
cjcenizal Mar 28, 2018
1fde42f
Add placeholder prop.
cjcenizal Mar 28, 2018
cd00413
Update position on scroll.
cjcenizal Mar 28, 2018
189176a
Add warning to docs re duplicate option labels.
cjcenizal Mar 29, 2018
5ed53a8
Update CHANGELOG.
cjcenizal Mar 29, 2018
d7a88c6
Make options list z-index higher than modals.
cjcenizal Mar 29, 2018
5056e08
Fix some bugs by adding noSuggestions prop for when you don't want to…
cjcenizal Mar 29, 2018
3d643ca
use badge for combobox pilling
snide Mar 29, 2018
28b6ef7
some docs
snide Mar 29, 2018
212d13d
clean up group coloring
snide Mar 29, 2018
cd3c116
add docs for coloring
snide Mar 29, 2018
752887e
coloring now exists in dropdown
snide Mar 29, 2018
81ee5e2
update docs
snide Mar 29, 2018
ea1805e
remove color swatches, make euicon accept hex colors
snide Mar 29, 2018
25ba6ca
remove swatch css
snide Mar 29, 2018
c269908
prevent regression in badge sizing, make them slightly larger in comb…
snide Mar 29, 2018
2820022
Improve async example.
cjcenizal Mar 29, 2018
8595e43
Make single selection example clearer.
cjcenizal Mar 29, 2018
2a68bd7
Fix bug positioning options list.
cjcenizal Mar 29, 2018
838bcf7
Create example of EuiComboBox inside of EuiPopover and EuiModal.
cjcenizal Mar 29, 2018
31e07fa
Fix bugs with combo box inside of form rows, modals, and popovers.
cjcenizal Mar 29, 2018
7e353c4
Add renderOption prop.
cjcenizal Mar 29, 2018
1526835
Remove redundant value prop from options in examples.
cjcenizal Mar 29, 2018
be65646
Fix focus-tracking bug which caused the options list to close when yo…
cjcenizal Mar 30, 2018
d2a8e56
Update CHANGELOG.
cjcenizal Mar 30, 2018
e209b3f
Remove extraneous references to value.
cjcenizal Mar 30, 2018
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
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