diff --git a/CHANGELOG.md b/CHANGELOG.md index faaa4067faa..634ee2b414f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,14 @@ - Add `compressed` option to `buttonSize` prop of EuiButtonGroup ([#2343](https://github.com/elastic/eui/pull/2343)) - Added disabled states to `EuiCard`, `EuiKeyPadMenuItem` and `EuiKeyPadMenuItemButton` ([#2333](https://github.com/elastic/eui/pull/2340)) +- Added missing `compressed` TS definitions to `EuiComboBox`, `EuiCheckboxGroup`, `EuiCheckbox`, `EuiFieldSearch`, `EuiRadioGroup`, `EuiSwitch` ([#2338](https://github.com/elastic/eui/pull/2338)) +- Added auto-margin between `EuiFormRow` and `EuiButton` ([#2338](https://github.com/elastic/eui/pull/2338)) +- Added border to `[readOnly]` inputs ([#2338](https://github.com/elastic/eui/pull/2338)) **Bug fixes** - Fixed default z-index of `EuiPopover` ([#2341](https://github.com/elastic/eui/pull/2341)) +- Fixed styling for `prepend` and `append` nodes that may be popovers or tooltips ([#2338](https://github.com/elastic/eui/pull/2338)) ## [`14.1.1`](https://github.com/elastic/eui/tree/v14.1.1) diff --git a/src-docs/src/views/form_controls/form_controls_example.js b/src-docs/src/views/form_controls/form_controls_example.js index cad4de36cfc..4c61e9ea9f4 100644 --- a/src-docs/src/views/form_controls/form_controls_example.js +++ b/src-docs/src/views/form_controls/form_controls_example.js @@ -75,6 +75,10 @@ import Switch from './switch'; const switchSource = require('!!raw-loader!./switch'); const switchHtml = renderToHtml(Switch); +import PrependAppend from './prepend_append'; +const PrependAppendSource = require('!!raw-loader!./prepend_append'); +const PrependAppendHtml = renderToHtml(PrependAppend); + import FormControlLayout from './form_control_layout'; const formControlLayoutSource = require('!!raw-loader!./form_control_layout'); const formControlLayoutHtml = renderToHtml(FormControlLayout); @@ -315,6 +319,59 @@ export const FormControlsExample = { }, demo: , }, + { + title: 'Prepend and Append', + text: ( + +

+ Most form controls accept a prepend and{' '} + append prop that allows passing a single + node/string or an array of nodes/strings. Strings will be converted + into form labels and connected to the input via{' '} + htmlFor for accessibility. +

+

+ These are great for demarcating the input's metric like + "px" or "ms". You can also pass buttons for + input settings or additional filters. Just be sure to use + <EuiButtonEmpty size="xs" />. +

+
+ ), + source: [ + { + type: GuideSectionTypes.JS, + code: PrependAppendSource, + }, + { + type: GuideSectionTypes.HTML, + code: PrependAppendHtml, + }, + ], + demo: , + snippet: [ + ``, + ` + Popover + + } + closePopover={() => {}} + /> + } + append={[ + , + "Label", + ]} +/>`, + ], + }, { title: 'Form control layout', source: [ diff --git a/src-docs/src/views/form_controls/prepend_append.js b/src-docs/src/views/form_controls/prepend_append.js new file mode 100644 index 00000000000..0abeceed18f --- /dev/null +++ b/src-docs/src/views/form_controls/prepend_append.js @@ -0,0 +1,171 @@ +import React, { Fragment, useState } from 'react'; + +import { + EuiButtonEmpty, + EuiButtonIcon, + EuiFieldText, + EuiIcon, + EuiIconTip, + EuiPopover, + EuiSpacer, + EuiSwitch, + EuiText, + EuiToolTip, +} from '../../../../src/components'; + +export default () => { + const [isCompressed, setCompressed] = useState(false); + const [isDisabled, setDisabled] = useState(false); + const [isReadOnly, setReadOnly] = useState(false); + + return ( + + setCompressed(e.target.checked)} + /> +   + setDisabled(e.target.checked)} + /> +   + setReadOnly(e.target.checked)} + /> + + + Tooltip + + } + compressed={isCompressed} + disabled={isDisabled} + readOnly={isReadOnly} + /> + + + Popover + + } + closePopover={() => {}} + /> + } + append={ + + Tooltip + + } + compressed={isCompressed} + disabled={isDisabled} + readOnly={isReadOnly} + /> + + + + + } + append={ + + Tooltip + + } + compressed={isCompressed} + disabled={isDisabled} + readOnly={isReadOnly} + /> + + } + append={} + compressed={isCompressed} + disabled={isDisabled} + readOnly={isReadOnly} + /> + + , + , + ]} + append={[ + } + closePopover={() => {}} + />, + , + ]} + compressed={isCompressed} + disabled={isDisabled} + readOnly={isReadOnly} + /> + + } + closePopover={() => {}} + /> + } + prepend={ + + + + } + compressed={isCompressed} + disabled={isDisabled} + readOnly={isReadOnly} + /> + + , 'String']} + append={[ + 'String', + , + ]} + compressed={isCompressed} + disabled={isDisabled} + readOnly={isReadOnly} + /> + + + + , + ]} + append={[ + } + closePopover={() => {}} + />, + 'String', + ]} + compressed={isCompressed} + disabled={isDisabled} + readOnly={isReadOnly} + /> + + ); +}; diff --git a/src/components/combo_box/index.d.ts b/src/components/combo_box/index.d.ts index 51a0d8e3c05..8edec07a3ad 100644 --- a/src/components/combo_box/index.d.ts +++ b/src/components/combo_box/index.d.ts @@ -79,6 +79,7 @@ declare module '@elastic/eui' { export interface EuiComboBoxProps { id?: string; isDisabled?: boolean; + compressed?: boolean; className?: string; placeholder?: string; isLoading?: boolean; diff --git a/src/components/date_picker/_date_picker_range.scss b/src/components/date_picker/_date_picker_range.scss index cedeb5772b4..6d169eb0744 100644 --- a/src/components/date_picker/_date_picker_range.scss +++ b/src/components/date_picker/_date_picker_range.scss @@ -48,6 +48,7 @@ } > .euiDatePickerRange__delimeter { + background-color: transparent !important; // override .euiFormControlLayout--group .euiText line-height: 1 !important; flex: 0 0 auto; padding-left: $euiFormControlPadding / 2; diff --git a/src/components/form/_mixins.scss b/src/components/form/_mixins.scss index d55408b48f8..cb8be957403 100644 --- a/src/components/form/_mixins.scss +++ b/src/components/form/_mixins.scss @@ -149,9 +149,9 @@ @mixin euiFormControlReadOnlyStyle { cursor: default; // Use transparency since there is no border and in case form is on a non-white background - background: transparentize(lightOrDarkTheme($euiColorLightShade, $euiColorInk), .88); + background: $euiFormBackgroundReadOnlyColor; border-color: transparent; - box-shadow: none; + box-shadow: inset 0 0 0 1px $euiFormBorderDisabledColor; } /** diff --git a/src/components/form/_variables.scss b/src/components/form/_variables.scss index c723b784d3e..c556fec274e 100644 --- a/src/components/form/_variables.scss +++ b/src/components/form/_variables.scss @@ -21,11 +21,13 @@ $euiSwitchThumbSizeCompressed: $euiSwitchHeightCompressed !default; // Coloring $euiFormBackgroundColor: tintOrShade($euiColorLightestShade, 60%, 40%) !default; $euiFormBackgroundDisabledColor: darken($euiColorLightestShade, 2%) !default; -$euiFormBorderOpaqueColor: shadeOrTint(desaturate(adjust-hue($euiColorPrimary, 22), 22.95), 26%, 60%) !default; +$euiFormBackgroundReadOnlyColor: transparentize(lightOrDarkTheme($euiColorLightShade, $euiColorInk), .95) !default; +$euiFormBorderOpaqueColor: shadeOrTint(desaturate(adjust-hue($euiColorPrimary, 22), 22.95), 26%, 100%) !default; $euiFormBorderColor: transparentize($euiFormBorderOpaqueColor, .9) !default; $euiFormBorderDisabledColor: transparentize($euiFormBorderOpaqueColor, .9) !default; $euiFormCustomControlDisabledIconColor: shadeOrTint($euiColorMediumShade, 38%, 48.5%) !default; // exact 508c foreground for $euiColorLightShade $euiFormCustomControlBorderColor: shadeOrTint($euiColorLightestShade, 18%, 30%) !default; $euiFormControlDisabledColor: $euiColorMediumShade !default; -$euiFormControlBoxShadow: 0 1px 1px -1px transparentize($euiShadowColor, .8), 0 3px 2px -2px transparentize($euiShadowColor, .8); -$euiFormInputGroupLabelBackground: shadeOrTint($euiFormBackgroundDisabledColor, 0, 3%); +$euiFormControlBoxShadow: 0 1px 1px -1px transparentize($euiShadowColor, .8), 0 3px 2px -2px transparentize($euiShadowColor, .8) !default; +$euiFormInputGroupLabelBackground: tintOrShade($euiColorLightShade, 65%, 40%) !default; +$euiFormInputGroupBorder: 1px solid shadeOrTint($euiFormInputGroupLabelBackground, 6%, 8%) !default; diff --git a/src/components/form/checkbox/index.d.ts b/src/components/form/checkbox/index.d.ts index 97a1a386f00..5a9f43ad112 100644 --- a/src/components/form/checkbox/index.d.ts +++ b/src/components/form/checkbox/index.d.ts @@ -24,6 +24,7 @@ declare module '@elastic/eui' { label?: ReactNode; type?: EuiCheckboxType; disabled?: boolean; + compressed?: boolean; indeterminate?: boolean; } @@ -50,6 +51,7 @@ declare module '@elastic/eui' { options: EuiCheckboxGroupOption[]; idToSelectedMap: EuiCheckboxGroupIdToSelectedMap; onChange: ChangeEventHandler; + compressed?: boolean; } export const EuiCheckboxGroup: FunctionComponent< diff --git a/src/components/form/field_search/index.d.ts b/src/components/form/field_search/index.d.ts index 0fb4de69332..24637df7066 100644 --- a/src/components/form/field_search/index.d.ts +++ b/src/components/form/field_search/index.d.ts @@ -1,6 +1,6 @@ import { CommonProps } from '../../common'; -import { FunctionComponent, InputHTMLAttributes } from 'react'; +import { FunctionComponent, InputHTMLAttributes, Ref } from 'react'; declare module '@elastic/eui' { /** @@ -17,8 +17,10 @@ declare module '@elastic/eui' { isInvalid?: boolean; fullWidth?: boolean; isLoading?: boolean; - incremental?: boolean; onSearch?: (value: string) => void; + incremental?: boolean; + compressed?: boolean; + inputRef?: Ref; } export const EuiFieldSearch: FunctionComponent< 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 e8f69276dd7..8e05136350a 100644 --- a/src/components/form/form_control_layout/_form_control_layout.scss +++ b/src/components/form/form_control_layout/_form_control_layout.scss @@ -21,6 +21,16 @@ align-items: stretch; padding: 1px; /* 1 */ + // Force the stretch of any children so they expand the full height of the control + > *, + .euiPopover__anchor, + .euiButtonEmpty, + .euiText, + .euiFormLabel, + .euiButtonIcon { + height: 100%; + } + .euiFormControlLayout__childrenWrapper { flex-grow: 1; } @@ -30,79 +40,97 @@ @include euiTextTruncate; flex-shrink: 0; height: 100%; - line-height: $euiFontSize - 1px; // The 1px less aligns the icons better - border: none; // remove any border in case it exists border-radius: 0; - &:first-child { - border-top-left-radius: $euiFormControlLayoutGroupInputCompressedBorderRadius; - border-bottom-left-radius: $euiFormControlLayoutGroupInputCompressedBorderRadius; - } + // ICONS - &:last-child { - border-top-right-radius: $euiFormControlLayoutGroupInputCompressedBorderRadius; - border-bottom-right-radius: $euiFormControlLayoutGroupInputCompressedBorderRadius; + &.euiIcon, + .euiIcon { + padding: 0 $euiSizeS; + width: $euiSizeXL; + border-radius: 0; + background-color: $euiFormInputGroupLabelBackground; } - &:disabled { - background-color: $euiFormBackgroundDisabledColor; - color: $euiFormControlDisabledColor; // ensures established contrast - } - // sass-lint:disable-block no-important - // This is the only way to target specific components to override styling - &.euiFormLabel, - &.euiText, &.euiButtonIcon, - &.euiIcon { - background-color: $euiFormInputGroupLabelBackground; - - & + .euiFormControlLayout__prepend, - & + .euiFormControlLayout__append { - padding-left: 0 !important; + &.euiButtonEmpty, + .euiButtonIcon, + .euiButtonEmpty { + transform: none !important; - &.euiButtonIcon, - &.euiIcon { - width: $euiSizeL; - } + // Undo sizing from icons inside buttons + .euiIcon { + background: none !important; + padding: 0; + width: $euiSize; } } + } - &.euiFormLabel, - &.euiText { - max-width: 50%; - white-space: nowrap; - margin-bottom: 0; - padding: $euiFormControlPadding; - border: none; - line-height: $euiFontSize; - } + .euiButtonIcon { + padding: 0 $euiSizeS; + width: $euiSizeXL; + border-radius: 0; + background-color: $euiFormInputGroupLabelBackground; - &.euiButtonIcon, - &.euiIcon { - padding: 0 $euiSizeS; - width: $euiSizeXL; - border: none; - transform: none !important; + &:focus { + box-shadow: inset 0 0 0 2px $euiFocusRingColor; } } - // In case a tooltip was passed as a pre/append - // The cloned element's classname would have been passed to the tooltip not the anchor - .euiToolTipAnchor { - padding: $euiSizeXS; + .euiToolTipAnchor > .euiIcon { + height: 100%; + background-color: $euiFormInputGroupLabelBackground; + padding: 0 $euiSizeS; + width: $euiSizeXL; + border-radius: 0; + } + + > .euiFormControlLayout__prepend, + > .euiFormControlLayout__append { + max-width: 50%; // Make sure max-width only applies to the outer most append/prepend element + } + + // sass-lint:disable-block no-important + // This is the only way to target specific components to override styling + + // TEXT + + .euiFormLabel, + .euiText { background-color: $euiFormInputGroupLabelBackground; + padding: $euiFormControlPadding; + line-height: $euiFontSize !important; + cursor: default !important; // pointer cursor on some form labels but not others is confusing + + // If the next sibiling is not the input, pull it closer to the text to reduce space + + *:not(.euiFormControlLayout__childrenWrapper) { + margin-left: -$euiFormControlPadding; + } + } + + // If any child that is not the input has a next sibling that is text, pull it closer to the text to reduce space + > *:not(.euiFormControlLayout__childrenWrapper) { + + .euiFormLabel, + + .euiText { + margin-left: -$euiFormControlPadding; + } } // - // Borders + // BORDERS on buttons only - .euiFormControlLayout__prepend { - border-right: 1px solid $euiFormBorderColor; + .euiButtonEmpty { + border-right: $euiFormInputGroupBorder; } - .euiFormControlLayout__append { - border-left: 1px solid $euiFormBorderColor; + // Any buttons after the children wrapper or inside any elements after the children wrapper + // Need to swap border sides + .euiFormControlLayout__childrenWrapper ~ .euiButtonEmpty, + .euiFormControlLayout__childrenWrapper ~ * .euiButtonEmpty { + border-right: none; + border-left: $euiFormInputGroupBorder; } // @@ -111,22 +139,24 @@ &.euiFormControlLayout--compressed { @include euiFormControlDefaultShadow($borderOnly: true); border-radius: $euiBorderRadius / 2; + overflow: hidden; // Keeps backgrounds inside border radius - .euiFormControlLayout__prepend, - .euiFormControlLayout__append { - &:first-child { - border-top-left-radius: $euiFormControlLayoutGroupInputCompressedBorderRadius; - border-bottom-left-radius: $euiFormControlLayoutGroupInputCompressedBorderRadius; - } + // Padding + .euiFormLabel, + .euiText { + padding: $euiFormControlCompressedPadding; - &:last-child { - border-top-right-radius: $euiFormControlLayoutGroupInputCompressedBorderRadius; - border-bottom-right-radius: $euiFormControlLayoutGroupInputCompressedBorderRadius; + // If the next sibiling is not the input, pull it closer to the text to reduce space + + *:not(.euiFormControlLayout__childrenWrapper) { + margin-left: -$euiFormControlCompressedPadding; } + } - &.euiFormLabel, - &.euiText { - padding: $euiFormControlCompressedPadding; + // If any child that is not the input has a next sibling that is text, pull it closer to the text to reduce space + > *:not(.euiFormControlLayout__childrenWrapper) { + + .euiFormLabel, + + .euiText { + margin-left: -$euiFormControlCompressedPadding; } } } @@ -135,28 +165,9 @@ // ReadOnly alterations &.euiFormControlLayout--readOnly { @include euiFormControlReadOnlyStyle; - padding: 0; /* 1 */ input { background-color: transparent; // Ensures the input and layout don't double up on background color } } - - // - // ReadOnly-Compressed alterations - - &.euiFormControlLayout--compressed.euiFormControlLayout--readOnly { - .euiFormControlLayout__prepend, - .euiFormControlLayout__append { - height: $euiFormControlCompressedHeight; - border-top-left-radius: $euiFormControlCompressedBorderRadius; - border-bottom-left-radius: $euiFormControlCompressedBorderRadius; - } - } -} - -.euiFormControlLayout-isDisabled, -.euiFormControlLayout-isDisabled .euiDatePickerRange--inGroup { - background-color: $euiFormBackgroundDisabledColor; - color: $euiColorDarkShade; } diff --git a/src/components/form/form_control_layout/_form_control_layout_delimited.scss b/src/components/form/form_control_layout/_form_control_layout_delimited.scss index 17a1c7dbafa..266c5567259 100644 --- a/src/components/form/form_control_layout/_form_control_layout_delimited.scss +++ b/src/components/form/form_control_layout/_form_control_layout_delimited.scss @@ -83,8 +83,8 @@ .euiFormControlLayoutDelimited__delimeter { // sass-lint:disable-block no-important - // Override EuiText line-height - line-height: 1 !important; + background-color: transparent !important; // Override .euiFormControlLayout--group > .euiFormLabel + line-height: 1 !important; // Override EuiText line-height flex: 0 0 auto; padding-left: $euiFormControlPadding / 2; padding-right: $euiFormControlPadding / 2; diff --git a/src/components/form/form_row/_form_row.scss b/src/components/form/form_row/_form_row.scss index 4f16dea7551..27a33eba7dc 100644 --- a/src/components/form/form_row/_form_row.scss +++ b/src/components/form/form_row/_form_row.scss @@ -7,7 +7,8 @@ flex-direction: column; /* 1 */ max-width: $euiFormMaxWidth; - + .euiFormRow { + + .euiFormRow, + + .euiButton { margin-top: $euiSize; } } diff --git a/src/components/form/form_row/index.d.ts b/src/components/form/form_row/index.d.ts index 564e4f58742..963a1b10aed 100644 --- a/src/components/form/form_row/index.d.ts +++ b/src/components/form/form_row/index.d.ts @@ -20,7 +20,6 @@ declare module '@elastic/eui' { label?: ReactNode; labelAppend?: ReactNode; describedByIds?: string[]; - compressed?: boolean; display?: | 'row' | 'rowCompressed' @@ -28,6 +27,9 @@ declare module '@elastic/eui' { | 'center' | 'centerCompressed' | 'columnCompressedSwitch'; + // **DEPRECATED: use `display: rowCompressed` instead.** + compressed?: boolean; + // **DEPRECATED: use `display: center` instead.** displayOnly?: boolean; }; diff --git a/src/components/form/radio/index.d.ts b/src/components/form/radio/index.d.ts index 25d1f103345..432612057fe 100644 --- a/src/components/form/radio/index.d.ts +++ b/src/components/form/radio/index.d.ts @@ -21,6 +21,7 @@ declare module '@elastic/eui' { export type EuiRadioGroupProps = CommonProps & Omit, 'onChange'> & { disabled?: boolean; + compressed?: boolean; name?: string; options?: EuiRadioGroupOption[]; idSelected?: string; diff --git a/src/components/form/switch/index.d.ts b/src/components/form/switch/index.d.ts index caaea6c1bdc..3afc67edcb7 100644 --- a/src/components/form/switch/index.d.ts +++ b/src/components/form/switch/index.d.ts @@ -9,6 +9,7 @@ declare module '@elastic/eui' { export type EuiSwitchProps = CommonProps & InputHTMLAttributes & { label?: ReactNode; + compressed?: boolean; }; export const EuiSwitch: FunctionComponent; diff --git a/src/components/suggest/__snapshots__/suggest_input.test.js.snap b/src/components/suggest/__snapshots__/suggest_input.test.js.snap index a3330c560fe..d4ee3bc430e 100644 --- a/src/components/suggest/__snapshots__/suggest_input.test.js.snap +++ b/src/components/suggest/__snapshots__/suggest_input.test.js.snap @@ -27,10 +27,10 @@ exports[`EuiSuggestInput is rendered 1`] = ` /> - + content={tooltipContent || statusMap[status].tooltip}> + );