diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e7c59596c8..f376fc8af96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ ## [`master`](https://github.com/elastic/eui/tree/master) - Fixed `EuiHeader` responsive styles ([#1009](https://github.com/elastic/eui/pull/1009)) +- Added `prepend` and `append` props to `EuiFormControlLayout` ([#961](https://github.com/elastic/eui/pull/961)) +- Updated style implementation of `EuiFilterGroup` and `EuiFilterGroupButton` ([#961](https://github.com/elastic/eui/pull/961)) +- Added `EuiDatePickerRange` as a way to layout two `EuiDatePicker`s. ([#961](https://github.com/elastic/eui/pull/961)) **Breaking changes** diff --git a/src-docs/src/views/button/button_icon.js b/src-docs/src/views/button/button_icon.js index 524b1ff4c2b..8fb87a60d00 100644 --- a/src-docs/src/views/button/button_icon.js +++ b/src-docs/src/views/button/button_icon.js @@ -19,8 +19,8 @@ const colors = [ export default () => ( { - colors.map(color => ( - + colors.map((color) => ( + By passing startDate and endDate props - you can provide styling the range in between two dates. + you can provide styling the range in between two dates. To further style the + group as a single control, use EuiDatePickerRange and pass + the date picker controls into + the startDateControl and endDateControl props.

), demo: , + props: { EuiDatePickerRange }, }, { title: 'Only allow specific dates and times', source: [{ diff --git a/src-docs/src/views/date_picker/range.js b/src-docs/src/views/date_picker/range.js index 6226ef56084..27e96d224e3 100644 --- a/src-docs/src/views/date_picker/range.js +++ b/src-docs/src/views/date_picker/range.js @@ -7,9 +7,7 @@ import moment from 'moment'; import { EuiDatePicker, - EuiFlexGroup, - EuiFlexItem, - EuiFormRow, + EuiDatePickerRange, } from '../../../../src/components'; export default class extends Component { @@ -39,30 +37,30 @@ export default class extends Component { render() { return ( - - - - - - - - - - - - + this.state.endDate} + aria-label="Start date" + showTimeSelect + /> + } + endDateControl={ + this.state.endDate} + aria-label="End date" + showTimeSelect + /> + } + /> ); } } diff --git a/src-docs/src/views/filter_group/filter_group.js b/src-docs/src/views/filter_group/filter_group.js index 48a0a2b2f21..ee1da0bb927 100644 --- a/src-docs/src/views/filter_group/filter_group.js +++ b/src-docs/src/views/filter_group/filter_group.js @@ -21,9 +21,32 @@ export default class extends Component { this.state = { isPopoverOpen: false, + isFilterOn: false, + isOnFilterOn: false, + isOffFilterOn: false, }; } + toggleFilter = () => { + this.setState(prevState => ({ + isFilterOn: !prevState.isFilterOn, + })); + } + + toggleOnFilter = () => { + this.setState(prevState => ({ + isOnFilterOn: !prevState.isOnFilterOn, + isOffFilterOn: prevState.isOffFilterOn && !prevState.isOnFilterOn ? false : prevState.isOffFilterOn, + })); + } + + toggleOffFilter = () => { + this.setState(prevState => ({ + isOffFilterOn: !prevState.isOffFilterOn, + isOnFilterOn: prevState.isOnFilterOn && !prevState.isOffFilterOn ? false : prevState.isOnFilterOn, + })); + } + onButtonClick() { this.setState({ isPopoverOpen: !this.state.isPopoverOpen, @@ -66,6 +89,8 @@ export default class extends Component { onClick={this.onButtonClick.bind(this)} isSelected={this.state.isPopoverOpen} hasActiveFilters={true} + numFilters={2} + grow={true} > Composers @@ -73,11 +98,14 @@ export default class extends Component { return ( - - Filter on + + Filter + + + On - - Filter off + + Off + + + + %} + placeholder="0 - 100" + value={this.state.value} + onChange={this.onChange} + aria-label="Use aria labels when no actual label is in use" + /> ); } diff --git a/src-docs/src/views/form_controls/form_control_layout.js b/src-docs/src/views/form_controls/form_control_layout.js index d63f24ae602..cc0022853f8 100644 --- a/src-docs/src/views/form_controls/form_control_layout.js +++ b/src-docs/src/views/form_controls/form_control_layout.js @@ -5,6 +5,9 @@ import React, { import { EuiFormControlLayout, EuiSpacer, + EuiFormLabel, + EuiButtonEmpty, + EuiText, } from '../../../../src/components'; export default () => ( @@ -106,5 +109,31 @@ export default () => ( > + + + + Label} + > + + + + + + %} + > + + + + + + {} }} + prepend={Button} + > + + ); diff --git a/src/components/button/button_empty/_button_empty.scss b/src/components/button/button_empty/_button_empty.scss index 55da7f4b277..1e6eab90fcd 100644 --- a/src/components/button/button_empty/_button_empty.scss +++ b/src/components/button/button_empty/_button_empty.scss @@ -1,6 +1,7 @@ /** * 1. We don't want any of the animations that come inherited from the mixin. * These should act like normal links instead. + * 2. Change the easing, quickness to not bounce so lighter backgrounds don't flash */ .euiButtonEmpty { @include euiButton; @@ -8,8 +9,10 @@ border-color: transparent; background-color: transparent; box-shadow: none; - transform: none !important; // 1 - animation: none !important; // 1 + transform: none !important; /* 1 */ + animation: none !important; /* 1 */ + transition-timing-function: ease-in; /* 2 */ + transition-duration: $euiAnimSpeedFast; /* 2 */ .euiButtonEmpty__content { @include euiButtonContent; diff --git a/src/components/button/button_empty/index.js b/src/components/button/button_empty/index.js index 97b0e080c31..53d74ff8cb2 100644 --- a/src/components/button/button_empty/index.js +++ b/src/components/button/button_empty/index.js @@ -1,3 +1,5 @@ export { + COLORS, + ICON_SIDES, EuiButtonEmpty, } from './button_empty'; diff --git a/src/components/button/index.js b/src/components/button/index.js index 31fa83f805c..96feec44188 100644 --- a/src/components/button/index.js +++ b/src/components/button/index.js @@ -1,4 +1,7 @@ -export { EuiButton } from './button'; +export { + COLORS, + EuiButton +} from './button'; export { EuiButtonEmpty, diff --git a/src/components/combo_box/__snapshots__/combo_box.test.js.snap b/src/components/combo_box/__snapshots__/combo_box.test.js.snap index 61d5b2c3973..a2ff123759b 100644 --- a/src/components/combo_box/__snapshots__/combo_box.test.js.snap +++ b/src/components/combo_box/__snapshots__/combo_box.test.js.snap @@ -10,54 +10,58 @@ exports[`EuiComboBox is rendered 1`] = ` class="euiFormControlLayout" >
-
+ class="euiComboBox__input" + style="font-size:14px;display:inline-block" + > + +
+
-
-
- + + +
diff --git a/src/components/combo_box/_combo_box.scss b/src/components/combo_box/_combo_box.scss index 12d59569efb..d448f90bbb4 100644 --- a/src/components/combo_box/_combo_box.scss +++ b/src/components/combo_box/_combo_box.scss @@ -8,7 +8,7 @@ * 3. The height on combo can be larger than normal text inputs. */ .euiComboBox__inputWrap { - @include euiFormControlStyle($includeStates: false); + @include euiFormControlStyle($includeStates: false, $includeSizes:false); @include euiFormControlWithIcon($isIconOptional: true); @include euiFormControlSize(auto); /* 3 */ diff --git a/src/components/date_picker/__snapshots__/date_picker_range.test.js.snap b/src/components/date_picker/__snapshots__/date_picker_range.test.js.snap new file mode 100644 index 00000000000..2549a3bfedb --- /dev/null +++ b/src/components/date_picker/__snapshots__/date_picker_range.test.js.snap @@ -0,0 +1,94 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`EuiDatePickerRange is rendered 1`] = ` +
+ + + + + + + +
+
+
+
+
+ +
+
+
+
+
+
+
+
+ + → + +
+ + +
+
+
+
+
+ +
+
+
+
+
+
+
+
+`; diff --git a/src/components/date_picker/_date_picker_range.scss b/src/components/date_picker/_date_picker_range.scss new file mode 100644 index 00000000000..8c931a14db5 --- /dev/null +++ b/src/components/date_picker/_date_picker_range.scss @@ -0,0 +1,34 @@ +@import '../form/variables'; +@import '../form/mixins'; + +/** + * 1. Account for inner box-shadow style border + */ + + .euiDatePickerRange { + @include euiFormControlSize(auto, $includeAlternates: true); + // Match just the regular drop shadow of inputs + @include euiFormControlDefaultShadow(); + display: flex; + align-items: center; + padding: 1px; /* 1 */ + + > span { + flex-grow: 1; + } + + .euiDatePicker { + box-shadow: none !important; // including all states + text-align: center; + } +} + +.euiDatePickerRange__icon { + padding-left: $euiFormControlPadding; + padding-right: $euiFormControlPadding; +} + +.euiDatePickerRange__delimeter { + padding-left: $euiFormControlPadding/2; + padding-right: $euiFormControlPadding/2; +} diff --git a/src/components/date_picker/_index.scss b/src/components/date_picker/_index.scss index f44d6770ed1..65219322767 100644 --- a/src/components/date_picker/_index.scss +++ b/src/components/date_picker/_index.scss @@ -1,2 +1,3 @@ // Uses some form mixins @import 'date_picker'; +@import 'date_picker_range'; diff --git a/src/components/date_picker/date_picker.js b/src/components/date_picker/date_picker.js index 332e74ed4c4..bb279fd8ec9 100644 --- a/src/components/date_picker/date_picker.js +++ b/src/components/date_picker/date_picker.js @@ -49,6 +49,7 @@ export class EuiDatePicker extends Component { selected, shadow, shouldCloseOnSelect, + showIcon, showTimeSelect, showTimeSelectOnly, timeFormat, @@ -70,14 +71,14 @@ export class EuiDatePicker extends Component { { 'euiFieldText--fullWidth': fullWidth, 'euiFieldText-isLoading': isLoading, - 'euiFieldText--withIcon': !inline, + 'euiFieldText--withIcon': !inline && showIcon, 'euiFieldText-isInvalid': isInvalid, }, className ); let optionalIcon; - if (inline || customInput) { + if (inline || customInput || !showIcon) { optionalIcon = null; } else if (showTimeSelectOnly) { optionalIcon = 'clock'; @@ -268,6 +269,10 @@ EuiDatePicker.propTypes = { * Will close the popup on selection */ shouldCloseOnSelect: PropTypes.bool, + /** + * Show the icon in input + */ + showIcon: PropTypes.bool, /** * Show the time selection alongside the calendar */ @@ -288,5 +293,6 @@ EuiDatePicker.defaultProps = { isLoading: false, shadow: true, shouldCloseOnSelect: true, + showIcon: true, timeFormat: 'hh:mm A', }; diff --git a/src/components/date_picker/date_picker_range.js b/src/components/date_picker/date_picker_range.js new file mode 100644 index 00000000000..4ff4a15bcca --- /dev/null +++ b/src/components/date_picker/date_picker_range.js @@ -0,0 +1,78 @@ +import React, { + cloneElement, +} from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; + +import { EuiText } from '../text'; +import { + ICON_TYPES, + EuiIcon, +} from '../icon'; + +export const EuiDatePickerRange = ({ + className, + startDateControl, + endDateControl, + iconType, + ...rest +}) => { + + const classes = classNames( + 'euiDatePickerRange', + className + ); + + // Set the icon for the entire group instead of per control + let optionalIcon; + if (iconType) { + const icon = typeof iconType === 'string' ? iconType : 'calendar'; + optionalIcon = ( + + ); + } else { + optionalIcon = null; + } + + const clonedStartDate = cloneElement(startDateControl, { + showIcon: false, + }); + + const clonedEndDate = cloneElement(endDateControl, { + showIcon: false, + }); + + return ( +
+ {optionalIcon} + {clonedStartDate} + + {clonedEndDate} +
+ ); +}; + +EuiDatePickerRange.propTypes = { + /** + * The start date `EuiDatePicker` element + */ + startDateControl: PropTypes.node.isRequired, + /** + * The end date `EuiDatePicker` element + */ + endDateControl: PropTypes.node.isRequired, + /** + * Pass either an icon type or set to `false` to remove icon entirely + */ + iconType: PropTypes.oneOfType([ + PropTypes.bool, + PropTypes.oneOf(ICON_TYPES), + ]), +}; + +EuiDatePickerRange.defaultProps = { + iconType: true, +}; diff --git a/src/components/date_picker/date_picker_range.test.js b/src/components/date_picker/date_picker_range.test.js new file mode 100644 index 00000000000..72b0fea7e97 --- /dev/null +++ b/src/components/date_picker/date_picker_range.test.js @@ -0,0 +1,21 @@ +import React from 'react'; +import { render } from 'enzyme'; +import { requiredProps } from '../../test'; + +import { EuiDatePickerRange } from './date_picker_range'; +import { EuiDatePicker } from './date_picker'; + +describe('EuiDatePickerRange', () => { + test('is rendered', () => { + const component = render( + } + endDateControl={} + {...requiredProps} + /> + ); + + expect(component) + .toMatchSnapshot(); + }); +}); diff --git a/src/components/date_picker/index.js b/src/components/date_picker/index.js index a50b7176468..eb720402eec 100644 --- a/src/components/date_picker/index.js +++ b/src/components/date_picker/index.js @@ -1,3 +1,7 @@ export { EuiDatePicker, } from './date_picker'; + +export { + EuiDatePickerRange, +} from './date_picker_range'; diff --git a/src/components/filter_group/__snapshots__/filter_button.test.js.snap b/src/components/filter_group/__snapshots__/filter_button.test.js.snap index 320e2570a0d..cf3e8aaf2bc 100644 --- a/src/components/filter_group/__snapshots__/filter_button.test.js.snap +++ b/src/components/filter_group/__snapshots__/filter_button.test.js.snap @@ -3,16 +3,18 @@ exports[`EuiFilterButton is rendered 1`] = ` `; diff --git a/src/components/filter_group/__snapshots__/filter_select_item.test.js.snap b/src/components/filter_group/__snapshots__/filter_select_item.test.js.snap index 10494b47fc4..78de8ac186d 100644 --- a/src/components/filter_group/__snapshots__/filter_select_item.test.js.snap +++ b/src/components/filter_group/__snapshots__/filter_select_item.test.js.snap @@ -8,7 +8,7 @@ exports[`EuiFilterSelectItem is rendered 1`] = ` type="button" >
* + * { - border-left: $euiBorderThin; + // Match just the regular drop shadow of inputs + @include euiFormControlDefaultShadow; + @include euiFormControlSize; + max-width: none; + display: flex; + align-items: center; + padding: 1px; /* 1 */ + + > * { + // defaults to growing children + // though filter buttons don't grow by default + flex-grow: 1; + } + + // Force popover anchors to expand for now + .euiPopover__anchor { + display: block; } } .euiFilterGroup__popoverPanel { - width: $euiSize * 20; + max-width: $euiSize * 20; } diff --git a/src/components/filter_group/filter_button.js b/src/components/filter_group/filter_button.js index 7050f750934..433099ccaf2 100644 --- a/src/components/filter_group/filter_button.js +++ b/src/components/filter_group/filter_button.js @@ -2,30 +2,18 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import { getSecureRelForTarget } from '../../services'; +// import { getSecureRelForTarget } from '../../services'; +import { EuiNotificationBadge } from '../badge/notification_badge'; +import { + COLORS, + ICON_SIDES, + EuiButtonEmpty, +} from '../button/button_empty'; import { ICON_TYPES, - EuiIcon, } from '../icon'; -const colorToClassNameMap = { - primary: 'euiFilterButton--primary', - danger: 'euiFilterButton--danger', - disabled: 'euiFilterButton--disabled', - text: 'euiFilterButton--text', - ghost: 'euiFilterButton--ghost', -}; - -export const COLORS = Object.keys(colorToClassNameMap); - -const iconSideToClassNameMap = { - left: '', - right: 'euiFilterButton--iconRight', -}; - -export const ICON_SIDES = Object.keys(iconSideToClassNameMap); - export const EuiFilterButton = ({ children, className, @@ -33,72 +21,48 @@ export const EuiFilterButton = ({ iconSide, color, hasActiveFilters, + numFilters, isDisabled, isSelected, - href, - target, - rel, type, + grow, + noDivider, ...rest }) => { const classes = classNames( 'euiFilterButton', - colorToClassNameMap[color], - iconSideToClassNameMap[iconSide], { 'euiFilterButton-isSelected': isSelected, 'euiFilterButton-hasActiveFilters': hasActiveFilters, + 'euiFilterButton--grow': grow, + 'euiFilterButton--noDivider': noDivider, }, className, ); - // Add an icon to the button if one exists. - let buttonIcon; - - if (iconType) { - buttonIcon = ( -
`; @@ -15,34 +19,38 @@ exports[`EuiFormControlLayout props clear onClick is rendered 1`] = ` class="euiFormControlLayout" >
- + + +
`; @@ -50,7 +58,11 @@ exports[`EuiFormControlLayout props clear onClick is rendered 1`] = ` exports[`EuiFormControlLayout props fullWidth is rendered 1`] = `
+> +
+
`; exports[`EuiFormControlLayout props icon is rendered as a string 1`] = ` @@ -58,32 +70,36 @@ exports[`EuiFormControlLayout props icon is rendered as a string 1`] = ` class="euiFormControlLayout" >
- - - + + + + + + +
`; @@ -93,33 +109,37 @@ exports[`EuiFormControlLayout props icon is rendered as an object 1`] = ` class="euiFormControlLayout" >
- - - + + + + + + +
`; @@ -129,32 +149,36 @@ exports[`EuiFormControlLayout props icon side left is rendered 1`] = ` class="euiFormControlLayout" >
- - - + + + + + + +
`; @@ -164,32 +188,36 @@ exports[`EuiFormControlLayout props icon side right is rendered 1`] = ` class="euiFormControlLayout" >
- - - + + + + + + +
`; @@ -199,11 +227,85 @@ exports[`EuiFormControlLayout props isLoading is rendered 1`] = ` class="euiFormControlLayout" >
+ class="euiFormControlLayoutIcons euiFormControlLayoutIcons--right" + > +
+
`; + +exports[`EuiFormControlLayout props multiple appends are rendered 1`] = ` +
+
+ + 1 + + + 2 + +
+`; + +exports[`EuiFormControlLayout props multiple prepends are rendered 1`] = ` +
+ + 1 + + + 2 + +
+
+`; + +exports[`EuiFormControlLayout props one append is rendered 1`] = ` +
+
+ + 1 + +
+`; + +exports[`EuiFormControlLayout props one prepend is rendered 1`] = ` +
+ + 1 + +
+
+`; diff --git a/src/components/form/form_control_layout/_form_control_layout.scss b/src/components/form/form_control_layout/_form_control_layout.scss index 76d745fee8d..30f6ec1c8f0 100644 --- a/src/components/form/form_control_layout/_form_control_layout.scss +++ b/src/components/form/form_control_layout/_form_control_layout.scss @@ -1,14 +1,77 @@ @import '../variables'; +@import '../mixins'; .euiFormControlLayout { // Let the height expand as needed - @include euiFormControlSize(auto); + @include euiFormControlSize(auto, $includeAlternates: true); +} - display: inline-block; +.euiFormControlLayout__childrenWrapper { position: relative; } -.euiFormControlLayout--fullWidth { - width: 100%; - max-width: 100%; +/** + * 1. Account for inner box-shadow style border + */ + +.euiFormControlLayout--group { + // Match just the regular drop shadow of inputs + @include euiFormControlDefaultShadow(); + display: flex; + align-items: center; + padding: 1px; /* 1 */ + + .euiFormControlLayout__childrenWrapper { + flex-grow: 1; + } + + .euiFormControlLayout__prepend, + .euiFormControlLayout__append { + flex-shrink: 0; + height: $euiFormControlHeight - 2px; /* 1 */ + line-height: $euiFontSize; + + &:disabled { + background-color: $euiFormBackgroundDisabledColor; + color: $euiFormControlDisabledColor; // ensures established contrast + } + + // This is the only way to target specific components to override styling + &.euiFormLabel, + &.euiText { + white-space: nowrap; + margin-bottom: 0; + padding: $euiFormControlPadding; + border: none; + background-color: shadeOrTint($euiFormBackgroundDisabledColor, 0, 3%); + line-height: $euiFontSize; + } + } + + // + // Borders + + .euiFormControlLayout__prepend { + border-right: 1px solid $euiFormBorderColor; + } + + .euiFormControlLayout__append { + border-left: 1px solid $euiFormBorderColor; + } + + // + // Compressed alterations + + &.euiFormControlLayout--compressed { + .euiFormControlLayout__prepend, + .euiFormControlLayout__append { + height: $euiFormControlCompressedHeight - 2px; /* 1 */ + + &.euiFormLabel, + &.euiText { + padding-top: $euiFormControlCompressedPadding; + padding-bottom: $euiFormControlCompressedPadding; + } + } + } } diff --git a/src/components/form/form_control_layout/form_control_layout.js b/src/components/form/form_control_layout/form_control_layout.js index eff135c3235..8a09f79f8c6 100644 --- a/src/components/form/form_control_layout/form_control_layout.js +++ b/src/components/form/form_control_layout/form_control_layout.js @@ -1,4 +1,7 @@ -import React from 'react'; +import React, { + cloneElement, + Component, +} from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; @@ -6,37 +9,109 @@ import { EuiFormControlLayoutIcons } from './form_control_layout_icons'; export const ICON_SIDES = ['left', 'right']; -export const EuiFormControlLayout = ({ - children, - icon, - clear, - fullWidth, - isLoading, - compressed, - className, - ...rest -}) => { - const classes = classNames( - 'euiFormControlLayout', - { - 'euiFormControlLayout--fullWidth': fullWidth, - 'euiFormControlLayout--compressed': compressed, - }, - className - ); - - return ( -
- {children} - - -
- ); -}; +export class EuiFormControlLayout extends Component { + render() { + const { + children, + icon, + clear, + fullWidth, + isLoading, + compressed, + className, + prepend, + append, + ...rest + } = this.props; + + const classes = classNames( + 'euiFormControlLayout', + { + 'euiFormControlLayout--fullWidth': fullWidth, + 'euiFormControlLayout--compressed': compressed, + 'euiFormControlLayout--group': prepend || append, + }, + className + ); + + const prependNodes = this.renderPrepends(); + const appendNodes = this.renderAppends(); + + let clonedChildren; + if ((prepend || append) && children) { + clonedChildren = cloneElement(children, { + className: `${children.props.className} euiFormControlLayout__child--noStyle`, + }); + } + + return ( +
+ {prependNodes} +
+ {clonedChildren || children} + + +
+ {appendNodes} +
+ ); + } + + renderPrepends() { + const { prepend } = this.props; + + if (!prepend) { + return; + } + + let prependNodes; + + if (Array.isArray(prepend)) { + prependNodes = prepend.map((item, index) => { + return this.createSideNode(item, 'prepend', index); + }); + } + + else { + prependNodes = this.createSideNode(prepend, 'prepend'); + } + + return prependNodes; + } + + renderAppends() { + const { append } = this.props; + + if (!append) { + return; + } + + let appendNodes; + + if (Array.isArray(append)) { + appendNodes = append.map((item, index) => { + return this.createSideNode(item, 'append', index); + }); + } + + else { + appendNodes = this.createSideNode(append, 'append'); + } + + return appendNodes; + } + + createSideNode(node, side, key) { + return cloneElement(node, { + className: `euiFormControlLayout__${side}`, + key: key + }); + } +} EuiFormControlLayout.propTypes = { children: PropTypes.node, @@ -55,6 +130,20 @@ EuiFormControlLayout.propTypes = { isLoading: PropTypes.bool, className: PropTypes.string, compressed: PropTypes.bool, + /** + * Creates an input group with element(s) coming before children + */ + prepend: PropTypes.oneOfType([ + PropTypes.node, + PropTypes.arrayOf(PropTypes.node), + ]), + /** + * Creates an input group with element(s) coming after children + */ + append: PropTypes.oneOfType([ + PropTypes.node, + PropTypes.arrayOf(PropTypes.node), + ]), }; EuiFormControlLayout.defaultProps = { diff --git a/src/components/form/form_control_layout/form_control_layout.test.js b/src/components/form/form_control_layout/form_control_layout.test.js index 33749c6677d..08afabf4d58 100644 --- a/src/components/form/form_control_layout/form_control_layout.test.js +++ b/src/components/form/form_control_layout/form_control_layout.test.js @@ -135,5 +135,51 @@ describe('EuiFormControlLayout', () => { expect(component).toMatchSnapshot(); }); + + test('one prepend is rendered', () => { + const component = render( + 1} + /> + ); + + expect(component).toMatchSnapshot(); + }); + + test('one append is rendered', () => { + const component = render( + 1} + /> + ); + + expect(component).toMatchSnapshot(); + }); + + test('multiple prepends are rendered', () => { + const component = render( + 1, + 2 + ]} + /> + ); + + expect(component).toMatchSnapshot(); + }); + + test('multiple appends are rendered', () => { + const component = render( + 1, + 2 + ]} + /> + ); + + expect(component).toMatchSnapshot(); + }); }); }); diff --git a/src/components/form/range/__snapshots__/range.test.js.snap b/src/components/form/range/__snapshots__/range.test.js.snap index e9539ebbf9b..8115936460c 100644 --- a/src/components/form/range/__snapshots__/range.test.js.snap +++ b/src/components/form/range/__snapshots__/range.test.js.snap @@ -62,17 +62,21 @@ exports[`EuiRange props extra input should render 1`] = `
- +
+ +
`; diff --git a/src/components/form/select/_select.scss b/src/components/form/select/_select.scss index 6b3933fa782..bc59c84edda 100644 --- a/src/components/form/select/_select.scss +++ b/src/components/form/select/_select.scss @@ -19,6 +19,14 @@ padding-bottom: 0; /* 2 */ } + &--inGroup { + line-height: $euiFormControlHeight - 2px; /* 2 */ + } + + &--inGroup#{&}--compressed { + line-height: $euiFormControlCompressedHeight - 2px; /* 2 */ + } + &::-ms-expand { display: none; } diff --git a/src/components/form/select/select.js b/src/components/form/select/select.js index a442597f18f..032c2be7d54 100644 --- a/src/components/form/select/select.js +++ b/src/components/form/select/select.js @@ -23,6 +23,8 @@ export const EuiSelect = ({ defaultValue, compressed, value, + prepend, + append, ...rest }) => { const classes = classNames( @@ -30,6 +32,7 @@ export const EuiSelect = ({ { 'euiSelect--fullWidth': fullWidth, 'euiSelect--compressed': compressed, + 'euiSelect--inGroup': prepend || append, 'euiSelect-isLoading': isLoading, }, className @@ -60,6 +63,8 @@ export const EuiSelect = ({ fullWidth={fullWidth} isLoading={isLoading} compressed={compressed} + prepend={prepend} + append={append} >