From 8f27db0518583cc4294ded082ef191d83b27cbbf Mon Sep 17 00:00:00 2001 From: cchaos Date: Mon, 11 Jun 2018 22:30:05 -0400 Subject: [PATCH] Moving super_select to super_select_control and putting popover stuff into super_select --- .../src/views/super_select/super_select.js | 103 +++++----- .../collapsed_item_actions.test.js.snap | 2 + .../context_menu_panel.test.js.snap | 16 +- .../context_menu/_context_menu.scss | 5 - .../context_menu/_context_menu_item.scss | 16 ++ .../context_menu/context_menu_item.js | 20 +- src/components/form/index.js | 5 +- .../__snapshots__/super_select.test.js.snap | 80 ++++---- .../super_select_control.test.js.snap | 52 +++++ src/components/form/super_select/_index.scss | 1 + .../form/super_select/_super_select.scss | 44 ++--- .../super_select/_super_select_control.scss | 36 ++++ src/components/form/super_select/_test.scss | 3 + src/components/form/super_select/index.js | 4 + .../form/super_select/super_select.js | 179 ++++++++---------- .../form/super_select/super_select_control.js | 129 +++++++++++++ .../super_select/super_select_control.test.js | 16 ++ src/components/index.js | 1 + src/components/popover/_popover.scss | 1 - src/components/text/_text.scss | 3 +- 20 files changed, 475 insertions(+), 241 deletions(-) create mode 100644 src/components/form/super_select/__snapshots__/super_select_control.test.js.snap create mode 100644 src/components/form/super_select/_super_select_control.scss create mode 100644 src/components/form/super_select/_test.scss create mode 100644 src/components/form/super_select/super_select_control.js create mode 100644 src/components/form/super_select/super_select_control.test.js diff --git a/src-docs/src/views/super_select/super_select.js b/src-docs/src/views/super_select/super_select.js index ef7d91bb53e..c7a52bd15ff 100644 --- a/src-docs/src/views/super_select/super_select.js +++ b/src-docs/src/views/super_select/super_select.js @@ -6,11 +6,10 @@ import React, { import { EuiSuperSelect, EuiSpacer, - EuiContextMenuItem, - EuiContextMenuPanel, - EuiPopover, EuiText, EuiIcon, + EuiContextMenuItem, + EuiHorizontalRule, } from '../../../../src/components'; export default class extends Component { @@ -23,9 +22,10 @@ export default class extends Component { text: 'Option one', display: ( - -

Option one

-

Has a short description giving more detail to the option.

+ Option one + + +

Has a short description giving more detail to the option.

), @@ -39,9 +39,10 @@ export default class extends Component { ), display: ( - -

Option Two

-

Has a short description giving more detail to the option.

+ Option two + + +

Has a short description giving more detail to the option.

), @@ -51,9 +52,10 @@ export default class extends Component { text: 'Option three has a super long text to see if it will truncate or what', display: ( - -

Option Three

-

Has a short description giving more detail to the option.

+ Option three + + +

Has a short description giving more detail to the option.

), @@ -66,18 +68,6 @@ export default class extends Component { }; } - onButtonClick = () => { - this.setState(prevState => ({ - isPopoverOpen: !prevState.isPopoverOpen, - })); - }; - - closePopover = () => { - this.setState({ - isPopoverOpen: false, - }); - }; - onChange = e => { this.setState({ value: e.target.value, @@ -92,44 +82,35 @@ export default class extends Component { }; render() { - const button = ( - - ); - const items = this.options.map((option, index) => { return ( - this.itemClicked(option.value)} - > - {option.display} - + + this.itemClicked(option.value)} + layoutAlign="top" + > + {option.display} + + {index < this.options.length - 1 && + + } + ); }); return ( - - - + {items} + @@ -139,7 +120,9 @@ export default class extends Component { onChange={this.onChange} disabled aria-label="Use aria labels when no actual label is in use" - /> + > + {items} + @@ -149,7 +132,9 @@ export default class extends Component { onChange={this.onChange} isLoading aria-label="Use aria labels when no actual label is in use" - /> + > + {items} + @@ -160,7 +145,9 @@ export default class extends Component { isLoading disabled aria-label="Use aria labels when no actual label is in use" - /> + > + {items} + @@ -169,7 +156,9 @@ export default class extends Component { value={this.state.value} onChange={this.onChange} compressed - /> + > + {items} + ); } diff --git a/src/components/basic_table/__snapshots__/collapsed_item_actions.test.js.snap b/src/components/basic_table/__snapshots__/collapsed_item_actions.test.js.snap index 3e3483542f8..99fb827f551 100644 --- a/src/components/basic_table/__snapshots__/collapsed_item_actions.test.js.snap +++ b/src/components/basic_table/__snapshots__/collapsed_item_actions.test.js.snap @@ -29,12 +29,14 @@ exports[`CollapsedItemActions render 1`] = ` default1 , , diff --git a/src/components/context_menu/__snapshots__/context_menu_panel.test.js.snap b/src/components/context_menu/__snapshots__/context_menu_panel.test.js.snap index ff0f3034929..2b6b82b3b93 100644 --- a/src/components/context_menu/__snapshots__/context_menu_panel.test.js.snap +++ b/src/components/context_menu/__snapshots__/context_menu_panel.test.js.snap @@ -116,7 +116,7 @@ exports[`EuiContextMenuPanel updating items and content updates to items should "
- + - + - + - + - +
, +] +`; diff --git a/src/components/form/super_select/_index.scss b/src/components/form/super_select/_index.scss index f0f96af1339..ce308688e46 100644 --- a/src/components/form/super_select/_index.scss +++ b/src/components/form/super_select/_index.scss @@ -1 +1,2 @@ @import 'super_select'; +@import 'super_select_control'; diff --git a/src/components/form/super_select/_super_select.scss b/src/components/form/super_select/_super_select.scss index 4babd22305d..f6ec500598c 100644 --- a/src/components/form/super_select/_super_select.scss +++ b/src/components/form/super_select/_super_select.scss @@ -1,36 +1,24 @@ -/** - * 1. Leave room for caret. - * 2. Ensure the descenders don't get cut off +/* + * 1. Make popover the same width as the form control + * 2. Style popover similar to combobox + * 3. Specificity to override default popover */ - .euiSuperSelect { - @include euiFormControlStyle; - @include euiFormControlWithIcon($side: "right"); /* 1 */ - @include euiFormControlIsLoading($isNextToIcon: true); - text-align: left; + .euiSuperSelect .euiSuperSelect__popoverPanel { /* 3 */ + width: calc(100% + 2px); /* 1 */ - line-height: $euiFormControlHeight; /* 2 */ - padding-top: 0; /* 2 */ - padding-bottom: 0; /* 2 */ - - &--compressed { - line-height: $euiFormControlHeight--compressed; /* 2 */ - padding-top: 0; /* 2 */ - padding-bottom: 0; /* 2 */ + &::before, + &::after { + content: none; /* 2 */ } +} - // Truncate the text - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - - &:active { // since this is a button, we also want the visual indicator of active when options are shown - @include euiFormControlFocusStyle; - } +.euiSuperSelect .euiPopover--anchorDownCenter .euiSuperSelect__popoverPanel { /* 3 */ + border-top-color: transparentize($euiBorderColor, .2); + border-top-right-radius: 0; /* 2 */ + border-top-left-radius: 0; /* 2 */ } -.euiSuperSelect__hiddenField { - // This should be completely hidden even from screen readers, - // it's meant only to allow submission of a form. - display: none; +.euiSuperSelect .euiPopover--anchorDownCenter.euiPopover-isOpen .euiSuperSelect__popoverPanel { /* 3 */ + transform: translateX(-50%) translateY(0) translateZ(0); /* 2 */ } diff --git a/src/components/form/super_select/_super_select_control.scss b/src/components/form/super_select/_super_select_control.scss new file mode 100644 index 00000000000..96a16d0ee8a --- /dev/null +++ b/src/components/form/super_select/_super_select_control.scss @@ -0,0 +1,36 @@ +/** + * 1. Leave room for caret. + * 2. Ensure the descenders don't get cut off + */ + + .euiSuperSelectControl { + @include euiFormControlStyle; + @include euiFormControlWithIcon($side: "right"); /* 1 */ + @include euiFormControlIsLoading($isNextToIcon: true); + text-align: left; + + line-height: $euiFormControlHeight; /* 2 */ + padding-top: 0; /* 2 */ + padding-bottom: 0; /* 2 */ + + &--compressed { + line-height: $euiFormControlHeight--compressed; /* 2 */ + padding-top: 0; /* 2 */ + padding-bottom: 0; /* 2 */ + } + + // Truncate the text + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + &.euiSuperSelect--isOpen__button { // since this is a button, we also want the visual indicator of active when options are shown + @include euiFormControlFocusStyle; + } +} + +.euiSuperSelectControl__hiddenField { + // This should be completely hidden even from screen readers, + // it's meant only to allow submission of a form. + display: none; +} diff --git a/src/components/form/super_select/_test.scss b/src/components/form/super_select/_test.scss new file mode 100644 index 00000000000..c8976df1730 --- /dev/null +++ b/src/components/form/super_select/_test.scss @@ -0,0 +1,3 @@ +.euiTest { + +} diff --git a/src/components/form/super_select/index.js b/src/components/form/super_select/index.js index c07dc183a55..18075be5062 100644 --- a/src/components/form/super_select/index.js +++ b/src/components/form/super_select/index.js @@ -1,3 +1,7 @@ export { EuiSuperSelect, } from './super_select'; + +export { + EuiSuperSelectControl, +} from './super_select_control'; diff --git a/src/components/form/super_select/super_select.js b/src/components/form/super_select/super_select.js index ce59f39f3b9..a37037765b8 100644 --- a/src/components/form/super_select/super_select.js +++ b/src/components/form/super_select/super_select.js @@ -1,127 +1,100 @@ -import React, { Fragment } from 'react'; +import React, { + Component, +} from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import { - EuiFormControlLayout, -} from '../form_control_layout'; +import { EuiSuperSelectControl } from './super_select_control'; +import { EuiPopover } from '../../popover'; -export const EuiSuperSelect = ({ - className, - options, - id, - name, - inputRef, - fullWidth, - isLoading, - hasNoInitialSelection, - defaultValue, - compressed, - value, - ...rest -}) => { - const classes = classNames( - 'euiSuperSelect', - { - 'euiSuperSelect--fullWidth': fullWidth, - 'euiSuperSelect--compressed': compressed, - 'euiSuperSelect-isLoading': isLoading, - }, - className - ); +export class EuiSuperSelect extends Component { + constructor(props) { + super(props); - let emptyOptionNode; - if (hasNoInitialSelection) { - emptyOptionNode = ( - - ); + this.state = { + isPopoverOpen: props.isOpen || false, + }; } - // React HTML input can not have both value and defaultValue properties. - // https://reactjs.org/docs/uncontrolled-components.html#default-values - let selectDefaultValue; - if (!value) { - selectDefaultValue = defaultValue || ''; - } + onButtonClick = () => { + this.setState(prevState => ({ + isPopoverOpen: !prevState.isPopoverOpen, + })); + }; - let selectedValue; - if (value) { - const selectedOption = options.find(option => option.value === value); - selectedValue = selectedOption.text; - } + closePopover = () => { + this.setState({ + isPopoverOpen: false, + }); + }; - const icon = { - type: 'arrowDown', - side: 'right', + itemClicked = () => { + this.setState({ + isPopoverOpen: false, + }); + + this.props.onChange(); }; - return ( - - - - + /> + ); - - - - - ); -}; + {children} + +
+ ); + } +} EuiSuperSelect.propTypes = { name: PropTypes.string, - id: PropTypes.string, - options: PropTypes.arrayOf(PropTypes.shape({ - value: PropTypes.node.isRequired, - text: PropTypes.node.isRequired - })).isRequired, - isInvalid: PropTypes.bool, - fullWidth: PropTypes.bool, - isLoading: PropTypes.bool, - - /** - * Simulates no selection by creating an empty, selected, hidden first option - */ - hasNoInitialSelection: PropTypes.bool, - inputRef: PropTypes.func, /** - * when `true` creates a shorter height input + * You must pass an onChange function to hande the update of the value */ - compressed: PropTypes.bool, + onChange: PropTypes.func, }; EuiSuperSelect.defaultProps = { - options: [], - fullWidth: false, - isLoading: false, - hasNoInitialSelection: false, - compressed: false, }; diff --git a/src/components/form/super_select/super_select_control.js b/src/components/form/super_select/super_select_control.js new file mode 100644 index 00000000000..590c95b0918 --- /dev/null +++ b/src/components/form/super_select/super_select_control.js @@ -0,0 +1,129 @@ +import React, { Fragment } from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; + +import { + EuiFormControlLayout, +} from '../form_control_layout'; + +export const EuiSuperSelectControl = ({ + className, + options, + id, + name, + inputRef, + fullWidth, + isLoading, + hasNoInitialSelection, + defaultValue, + compressed, + value, + ...rest +}) => { + const classes = classNames( + 'euiSuperSelectControl', + { + 'euiSuperSelectControl--fullWidth': fullWidth, + 'euiSuperSelectControl--compressed': compressed, + 'euiSuperSelectControl-isLoading': isLoading, + }, + className + ); + + let emptyOptionNode; + if (hasNoInitialSelection) { + emptyOptionNode = ( + + ); + } + + // React HTML input can not have both value and defaultValue properties. + // https://reactjs.org/docs/uncontrolled-components.html#default-values + let selectDefaultValue; + if (!value) { + selectDefaultValue = defaultValue || ''; + } + + let selectedValue; + if (value) { + const selectedOption = options.find(option => option.value === value); + selectedValue = selectedOption.text; + } + + const icon = { + type: 'arrowDown', + side: 'right', + }; + + return ( + + + + + + + + + + ); +}; + +EuiSuperSelectControl.propTypes = { + name: PropTypes.string, + id: PropTypes.string, + options: PropTypes.arrayOf(PropTypes.shape({ + value: PropTypes.node.isRequired, + text: PropTypes.node.isRequired + })).isRequired, + isInvalid: PropTypes.bool, + fullWidth: PropTypes.bool, + isLoading: PropTypes.bool, + + /** + * Simulates no selection by creating an empty, selected, hidden first option + */ + hasNoInitialSelection: PropTypes.bool, + inputRef: PropTypes.func, + /** + * when `true` creates a shorter height input + */ + compressed: PropTypes.bool, +}; + +EuiSuperSelectControl.defaultProps = { + options: [], + fullWidth: false, + isLoading: false, + hasNoInitialSelection: false, + compressed: false, +}; diff --git a/src/components/form/super_select/super_select_control.test.js b/src/components/form/super_select/super_select_control.test.js new file mode 100644 index 00000000000..5448c47ffcd --- /dev/null +++ b/src/components/form/super_select/super_select_control.test.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { render } from 'enzyme'; +import { requiredProps } from '../../../test'; + +import { EuiSuperSelectControl } from './super_select_control'; + +describe('EuiSuperSelectControl', () => { + test('is rendered', () => { + const component = render( + + ); + + expect(component) + .toMatchSnapshot(); + }); +}); diff --git a/src/components/index.js b/src/components/index.js index 610529115ff..468baee28a5 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -130,6 +130,7 @@ export { EuiRange, EuiSelect, EuiSuperSelect, + EuiSuperSelectControl, EuiSwitch, EuiTextArea, EuiValidatableControl, diff --git a/src/components/popover/_popover.scss b/src/components/popover/_popover.scss index d444245bce2..ff92f348e59 100644 --- a/src/components/popover/_popover.scss +++ b/src/components/popover/_popover.scss @@ -25,7 +25,6 @@ * 2. Animation happens on the panel. */ .euiPopover__panel { - width: 100%; position: absolute; z-index: $euiZContentMenu; min-width: $euiButtonMinWidth; /* 1 */ diff --git a/src/components/text/_text.scss b/src/components/text/_text.scss index 6488daf7587..b579cd125f6 100644 --- a/src/components/text/_text.scss +++ b/src/components/text/_text.scss @@ -224,7 +224,8 @@ @include euiScaleText($euiFontSizeXS); } - > :last-child { + > :last-child, + .euiTextColor > :last-child { margin-bottom: 0 !important; } }