Skip to content

Commit

Permalink
EuiComboBox: Add buttons for clearing and opening/closing the combo b…
Browse files Browse the repository at this point in the history
…ox (#698)

* add clear icon

* use shallow render in tests to avoid cascading diff changes when underlying componenets change

* update change log

* Added `onClear` prop to `EuiFormControlLayout` (#3)

* Added `onClear` prop to `EuiFormControlLayout`

This will allow these extras to properly position according to what is visible and allow for other inputs to utilize it as well.

* Adding `isClearable` back in

* Adding onClose/onOpen back in and allowing a

`onIconClick` prop on the EuiFormControlLayout that will then wrap the icon in a button.

* set isClearable to true for example

* move readme comment to master

* remove rebase garbage from changelog
  • Loading branch information
nreese authored May 1, 2018
1 parent d5178c7 commit cf9475c
Show file tree
Hide file tree
Showing 12 changed files with 179 additions and 87 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- Added `direction` prop to EuiFlexGroup ([#711](https://github.com/elastic/eui/pull/711))
- Added `EuiEmptyPrompt` which can be used as a placeholder over empty tables and lists ([#711](https://github.com/elastic/eui/pull/711))
- Added `EuiTabbedContent` ([#737](https://github.com/elastic/eui/pull/737))
- `EuiComboBox` added buttons for clearing and opening/closing the combo box. ([#698](https://github.com/elastic/eui/pull/698))

**Bug fixes**

Expand Down
1 change: 1 addition & 0 deletions src-docs/src/views/combo_box/combo_box.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export default class extends Component {
selectedOptions={selectedOptions}
onChange={this.onChange}
onCreateOption={this.onCreateOption}
isClearable={true}
/>
);
}
Expand Down
62 changes: 20 additions & 42 deletions src/components/combo_box/__snapshots__/combo_box.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,27 @@
exports[`EuiComboBox is rendered 1`] = `
<div
aria-label="aria-label"
class="euiComboBox testClass1 testClass2"
className="euiComboBox testClass1 testClass2"
data-test-subj="test subject string"
onFocus={[Function]}
onKeyDown={[Function]}
>
<div
class="euiFormControlLayout"
>
<div
class="euiComboBox__inputWrap"
data-test-subj="comboBoxInput"
>
<div
class="euiComboBox__input"
style="font-size:14px;display:inline-block"
>
<input
aria-hidden="true"
style="box-sizing:content-box;width:1px"
value=""
/>
<div
style="position:absolute;top:0;left:0;visibility:hidden;height:0;overflow:scroll;white-space:pre"
/>
</div>
</div>
<svg
class="euiIcon euiIcon--medium euiFormControlLayout__icon euiFormControlLayout__icon--right"
height="16"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<path
d="M13.069 5.157L8.384 9.768a.546.546 0 0 1-.768 0L2.93 5.158a.552.552 0 0 0-.771 0 .53.53 0 0 0 0 .759l4.684 4.61c.641.631 1.672.63 2.312 0l4.684-4.61a.53.53 0 0 0 0-.76.552.552 0 0 0-.771 0z"
id="arrow_down-a"
/>
</defs>
<use
fill-rule="nonzero"
href="#arrow_down-a"
/>
</svg>
</div>
<EuiComboBoxInput
autoSizeInputRef={[Function]}
hasSelectedOptions={false}
inputRef={[Function]}
isListOpen={false}
onChange={[Function]}
onClear={[Function]}
onClick={[Function]}
onClose={[Function]}
onFocus={[Function]}
onOpen={[Function]}
onRemoveOption={[Function]}
searchValue=""
selectedOptions={Array []}
updatePosition={[Function]}
value=""
/>
</div>
`;
4 changes: 2 additions & 2 deletions src/components/combo_box/_combo_box.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

/**
* 1. Allow pills to truncate their text with an ellipsis.
* 2. Don't allow pills to overlap with the caret.
* 2. Don't allow pills to overlap with the caret or clear button.
* 3.
*/
.euiComboBox__inputWrap {
Expand All @@ -13,7 +13,7 @@
$padding: $euiSizeXS;
display: flex; /* 1 */
flex-wrap: wrap; /* 1 */
padding: $padding $euiSizeXXL $padding $padding; /* 2 */
padding: $padding $euiSizeXL*2 $padding $padding; /* 2 */
align-content: flex-start;

&:hover {
Expand Down
12 changes: 12 additions & 0 deletions src/components/combo_box/combo_box.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@ export class EuiComboBox extends Component {
renderOption: PropTypes.func,
isInvalid: PropTypes.bool,
rowHeight: PropTypes.number,
isClearable: PropTypes.bool,
}

static defaultProps = {
options: [],
selectedOptions: [],
isClearable: true,
}

constructor(props) {
Expand Down Expand Up @@ -381,6 +383,10 @@ export class EuiComboBox extends Component {
this.focusSearchInput();
};

clearSelectedOptions = () => {
this.props.onChange([]);
}

onComboBoxClick = () => {
// When the user clicks anywhere on the box, enter the interaction state.
this.searchInput.focus();
Expand Down Expand Up @@ -497,6 +503,7 @@ export class EuiComboBox extends Component {
async, // eslint-disable-line no-unused-vars
isInvalid,
rowHeight,
isClearable,
...rest
} = this.props;

Expand Down Expand Up @@ -560,6 +567,11 @@ export class EuiComboBox extends Component {
autoSizeInputRef={this.autoSizeInputRef}
inputRef={this.searchInputRef}
updatePosition={this.updateListPosition}
onClear={isClearable && this.clearSelectedOptions ? this.clearSelectedOptions : undefined}
hasSelectedOptions={selectedOptions.length > 0}
isListOpen={isListOpen}
onOpen={this.openList}
onClose={this.closeList}
/>

{optionsList}
Expand Down
4 changes: 2 additions & 2 deletions src/components/combo_box/combo_box.test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React from 'react';
import { render } from 'enzyme';
import { shallow } from 'enzyme';
import { requiredProps } from '../../test';

import { EuiComboBox } from './combo_box';

describe('EuiComboBox', () => {
test('is rendered', () => {
const component = render(
const component = shallow(
<EuiComboBox {...requiredProps} />
);

Expand Down
12 changes: 12 additions & 0 deletions src/components/combo_box/combo_box_input/combo_box_input.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ export class EuiComboBoxInput extends Component {
autoSizeInputRef: PropTypes.func,
inputRef: PropTypes.func,
updatePosition: PropTypes.func.isRequired,
onClear: PropTypes.func,
hasSelectedOptions: PropTypes.bool.isRequired,
isListOpen: PropTypes.bool.isRequired,
onOpen: PropTypes.func.isRequired,
onClose: PropTypes.func.isRequired,
}

constructor(props) {
Expand Down Expand Up @@ -75,6 +80,11 @@ export class EuiComboBoxInput extends Component {
searchValue,
autoSizeInputRef,
inputRef,
onClear,
hasSelectedOptions,
isListOpen,
onOpen,
onClose,
} = this.props;

const pills = selectedOptions.map((option) => {
Expand Down Expand Up @@ -135,6 +145,8 @@ export class EuiComboBoxInput extends Component {
<EuiFormControlLayout
icon="arrowDown"
iconSide="right"
onIconClick={isListOpen ? onClose : onOpen}
onClear={hasSelectedOptions ? onClear : undefined}
>
<div
className="euiComboBox__inputWrap"
Expand Down
68 changes: 38 additions & 30 deletions src/components/date_picker/__snapshots__/date_picker.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,47 @@
exports[`EuiDatePicker is rendered 1`] = `
<span>
<span
class="euiDatePicker euiDatePicker--shadow"
className="euiDatePicker euiDatePicker--shadow"
>
<div
class="euiFormControlLayout"
<EuiFormControlLayout
fullWidth={false}
icon="calendar"
iconSide="left"
isLoading={false}
>
<div>
<div
class="react-datepicker-wrapper"
>
<div
class="react-datepicker__input-container"
>
<input
class="euiDatePicker euiFieldText euiFieldText--withIcon testClass1 testClass2"
type="text"
value=""
/>
</div>
</div>
</div>
<svg
class="euiIcon euiIcon--medium euiFormControlLayout__icon"
height="16"
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14 4v-.994C14 2.45 13.55 2 12.994 2H11v1h-1V2H6v1H5V2H3.006C2.45 2 2 2.45 2 3.006v9.988C2 13.55 2.45 14 3.006 14h9.988C13.55 14 14 13.55 14 12.994V5H2V4h12zm-3-3h1.994C14.102 1 15 1.897 15 3.006v9.988A2.005 2.005 0 0 1 12.994 15H3.006A2.005 2.005 0 0 1 1 12.994V3.006C1 1.898 1.897 1 3.006 1H5V0h1v1h4V0h1v1zM4 7h2v1H4V7zm3 0h2v1H7V7zm3 0h2v1h-2V7zM4 9h2v1H4V9zm3 0h2v1H7V9zm3 0h2v1h-2V9zm-6 2h2v1H4v-1zm3 0h2v1H7v-1zm3 0h2v1h-2v-1z"
fill-rule="evenodd"
<EuiValidatableControl>
<DatePicker
allowSameDay={false}
aria-label="aria-label"
className="euiDatePicker euiFieldText euiFieldText--withIcon testClass1 testClass2"
data-test-subj="test subject string"
dateFormat="MM/DD/YYYY hh:mm A"
dateFormatCalendar="MMMM YYYY"
disabled={false}
disabledKeyboardNavigation={false}
dropdownMode="scroll"
monthsShown={1}
onBlur={[Function]}
onChange={[Function]}
onClickOutside={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onMonthChange={[Function]}
onSelect={[Function]}
onYearChange={[Function]}
preventOpenOnFocus={false}
shouldCloseOnSelect={true}
showMonthDropdown={true}
showTimeSelect={false}
showYearDropdown={true}
timeCaption="Time"
timeFormat="hh:mm A"
timeIntervals={30}
withPortal={false}
yearDropdownItemNumber={7}
/>
</svg>
</div>
</EuiValidatableControl>
</EuiFormControlLayout>
</span>
</span>
`;
4 changes: 2 additions & 2 deletions src/components/date_picker/date_picker.test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React from 'react';
import { render } from 'enzyme';
import { shallow } from 'enzyme';
import { requiredProps } from '../../test';

import { EuiDatePicker } from './date_picker';

describe('EuiDatePicker', () => {
test('is rendered', () => {
const component = render(
const component = shallow(
<EuiDatePicker {...requiredProps} />
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ exports[`EuiFormControlLayout props icon is rendered 1`] = `
class="euiFormControlLayout"
>
<svg
aria-hidden="true"
class="euiIcon euiIcon--medium euiFormControlLayout__icon"
height="16"
viewBox="0 0 16 16"
Expand All @@ -44,6 +45,7 @@ exports[`EuiFormControlLayout props iconSide left is rendered 1`] = `
class="euiFormControlLayout"
>
<svg
aria-hidden="true"
class="euiIcon euiIcon--medium euiFormControlLayout__icon"
height="16"
viewBox="0 0 16 16"
Expand All @@ -69,6 +71,7 @@ exports[`EuiFormControlLayout props iconSide right is rendered 1`] = `
class="euiFormControlLayout"
>
<svg
aria-hidden="true"
class="euiIcon euiIcon--medium euiFormControlLayout__icon euiFormControlLayout__icon--right"
height="16"
viewBox="0 0 16 16"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,53 @@
pointer-events: none;
}

.euiFormControlLayout__iconButton {
pointer-events: all;
top: $euiSizeM - 1px;
}

.euiFormControlLayout__clear {
$clearSize: $euiSize;

position: absolute;
top: $euiSizeM;
right: $euiSizeM;

@include size($clearSize);
background-color: transparentize($euiColorMediumShade, .5);
border-radius: $clearSize;
line-height: $clearSize;

.euiFormControlLayout__clearIcon {
@include size($euiSizeS);
fill: $euiColorEmptyShade;
stroke: $euiColorEmptyShade;
stroke-width: 3px; // increase thickness of icon at such a small size
margin-top: -3px;
}

// Loading spinner needs adjustment if clear also exists
~ .euiFormControlLayout__loading {
right: $euiSizeM*3;
}
}

.euiFormControlLayout__icon--right {
left: auto;
right: $euiSizeM;

// Loading spinner needs adjustment if icon also exists like selects.
~ .euiFormControlLayout__loading {
right: $euiSizeXL;
right: $euiSizeM*3;
}

// Same with clear buttons
~ .euiFormControlLayout__clear {
right: $euiSizeM*3;

~ .euiFormControlLayout__loading {
right: $euiSizeM*5;
}
}
}

Expand Down
Loading

0 comments on commit cf9475c

Please sign in to comment.