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] Add alert icon when isInvalid #6680

Merged
merged 5 commits into from
Apr 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 17 additions & 2 deletions src/components/combo_box/__snapshots__/combo_box.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ exports[`EuiComboBox is rendered 1`] = `
class="euiFormControlLayout__childrenWrapper"
>
<div
class="euiComboBox__inputWrap euiComboBox__inputWrap-isClearable"
class="euiComboBox__inputWrap euiFormControlLayout--1icons"
data-test-subj="comboBoxInput"
tabindex="-1"
>
Expand All @@ -24,6 +24,7 @@ exports[`EuiComboBox is rendered 1`] = `
aria-autocomplete="list"
aria-controls=""
aria-expanded="false"
aria-invalid="false"
aria-label="aria-label"
data-test-subj="comboBoxSearchInput"
id="generated-id__eui-combobox-id"
Expand Down Expand Up @@ -72,6 +73,7 @@ exports[`props aria-label attribute is rendered 1`] = `
hasSelectedOptions={false}
id="generated-id__eui-combobox-id"
inputRef={[Function]}
isInvalid={false}
isListOpen={false}
noIcon={false}
onChange={[Function]}
Expand Down Expand Up @@ -106,6 +108,7 @@ exports[`props aria-labelledby attribute is rendered 1`] = `
hasSelectedOptions={false}
id="generated-id__eui-combobox-id"
inputRef={[Function]}
isInvalid={false}
isListOpen={false}
noIcon={false}
onChange={[Function]}
Expand Down Expand Up @@ -139,6 +142,7 @@ exports[`props autoFocus is rendered 1`] = `
hasSelectedOptions={true}
id="generated-id__eui-combobox-id"
inputRef={[Function]}
isInvalid={false}
isListOpen={false}
noIcon={false}
onChange={[Function]}
Expand Down Expand Up @@ -181,6 +185,7 @@ exports[`props custom ID is rendered 1`] = `
hasSelectedOptions={true}
id="test-id-1"
inputRef={[Function]}
isInvalid={false}
isListOpen={false}
noIcon={false}
onChange={[Function]}
Expand Down Expand Up @@ -223,6 +228,7 @@ exports[`props delimiter is rendered 1`] = `
hasSelectedOptions={true}
id="generated-id__eui-combobox-id"
inputRef={[Function]}
isInvalid={false}
isListOpen={false}
noIcon={false}
onChange={[Function]}
Expand Down Expand Up @@ -265,6 +271,7 @@ exports[`props full width is rendered 1`] = `
hasSelectedOptions={true}
id="generated-id__eui-combobox-id"
inputRef={[Function]}
isInvalid={false}
isListOpen={false}
noIcon={false}
onChange={[Function]}
Expand Down Expand Up @@ -304,6 +311,7 @@ exports[`props isClearable=false disallows user from clearing input when no opti
hasSelectedOptions={false}
id="generated-id__eui-combobox-id"
inputRef={[Function]}
isInvalid={false}
isListOpen={false}
noIcon={false}
onChange={[Function]}
Expand Down Expand Up @@ -336,6 +344,7 @@ exports[`props isClearable=false disallows user from clearing input when options
hasSelectedOptions={true}
id="generated-id__eui-combobox-id"
inputRef={[Function]}
isInvalid={false}
isListOpen={false}
noIcon={false}
onChange={[Function]}
Expand Down Expand Up @@ -378,6 +387,7 @@ exports[`props isDisabled is rendered 1`] = `
id="generated-id__eui-combobox-id"
inputRef={[Function]}
isDisabled={true}
isInvalid={false}
isListOpen={false}
noIcon={false}
onChange={[Function]}
Expand Down Expand Up @@ -415,7 +425,7 @@ exports[`props options list is rendered 1`] = `
class="euiFormControlLayout__childrenWrapper"
>
<div
class="euiComboBox__inputWrap euiComboBox__inputWrap-isClearable"
class="euiComboBox__inputWrap euiFormControlLayout--1icons"
data-test-subj="comboBoxInput"
tabindex="-1"
>
Expand All @@ -427,6 +437,7 @@ exports[`props options list is rendered 1`] = `
aria-autocomplete="list"
aria-controls="generated-id_listbox"
aria-expanded="true"
aria-invalid="false"
data-test-subj="comboBoxSearchInput"
id="generated-id__eui-combobox-id"
role="combobox"
Expand Down Expand Up @@ -741,6 +752,7 @@ exports[`props selectedOptions are rendered 1`] = `
hasSelectedOptions={true}
id="generated-id__eui-combobox-id"
inputRef={[Function]}
isInvalid={false}
isListOpen={false}
noIcon={false}
onChange={[Function]}
Expand Down Expand Up @@ -783,6 +795,7 @@ exports[`props singleSelection is rendered 1`] = `
hasSelectedOptions={true}
id="generated-id__eui-combobox-id"
inputRef={[Function]}
isInvalid={false}
isListOpen={false}
noIcon={false}
onChange={[Function]}
Expand Down Expand Up @@ -823,6 +836,7 @@ exports[`props singleSelection prepend and append is rendered 1`] = `
hasSelectedOptions={false}
id="generated-id__eui-combobox-id"
inputRef={[Function]}
isInvalid={false}
isListOpen={true}
noIcon={false}
onChange={[Function]}
Expand Down Expand Up @@ -865,6 +879,7 @@ exports[`props singleSelection selects existing option when opened 1`] = `
hasSelectedOptions={true}
id="generated-id__eui-combobox-id"
inputRef={[Function]}
isInvalid={false}
isListOpen={true}
noIcon={false}
onChange={[Function]}
Expand Down
40 changes: 2 additions & 38 deletions src/components/combo_box/_combo_box.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,13 @@

.euiComboBox__inputWrap {
@include euiFormControlStyle($includeStates: false, $includeSizes: true);
@include euiFormControlWithIcon($isIconOptional: true);
@include euiFormControlSize(auto, $includeAlternates: true);

padding: $euiSizeXS $euiSizeS;
padding-right: var(--eui-form-control-layout-icons-padding, $euiSizeS); /* 2 */
display: flex; /* 1 */
outline: none; // Fixes an intermittent focus ring in Firefox

// to override the padding added above
@include euiFormControlLayoutPadding(1); /* 2 */

.euiComboBoxPill {
$inputMinWidth: $euiSize;

Expand All @@ -47,22 +45,6 @@
cursor: text;
}
}

&.euiComboBox__inputWrap-isClearable {
@include euiFormControlLayoutPadding(2); /* 2 */
}

&.euiComboBox__inputWrap-isLoading {
@include euiFormControlLayoutPadding(2); /* 2 */

.euiComboBoxPlaceholder {
@include euiFormControlLayoutPadding(2); /* 2 */
}
}

&.euiComboBox__inputWrap-isLoading.euiComboBox__inputWrap-isClearable {
@include euiFormControlLayoutPadding(3); /* 2 */
}
}

/**
Expand Down Expand Up @@ -130,24 +112,6 @@
line-height: $euiFormControlCompressedHeight; /* 2 */
padding-top: 0;
padding-bottom: 0;

@include euiFormControlLayoutPadding(1, $compressed: true); /* 2 */

&.euiComboBox__inputWrap-isClearable {
@include euiFormControlLayoutPadding(2, $compressed: true); /* 2 */
}

&.euiComboBox__inputWrap-isLoading {
@include euiFormControlLayoutPadding(2, $compressed: true); /* 2 */

.euiComboBoxPlaceholder {
@include euiFormControlLayoutPadding(2, $compressed: true); /* 2 */
}
}

&.euiComboBox__inputWrap-isLoading.euiComboBox__inputWrap-isClearable {
@include euiFormControlLayoutPadding(3, $compressed: true); /* 2 */
}
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/components/combo_box/combo_box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -971,9 +971,10 @@ export class EuiComboBox<T> extends Component<
// Visually indicate the combobox is in an invalid state if it has lost focus but there is text entered in the input.
// When custom options are disabled and the user leaves the combo box after entering text that does not match any
// options, this tells the user that they've entered invalid input.
const markAsInvalid =
const markAsInvalid = !!(
isInvalid ||
((hasFocus === false || isListOpen === false) && searchValue);
((hasFocus === false || isListOpen === false) && searchValue)
);

const classes = classNames('euiComboBox', className, {
'euiComboBox--compressed': compressed,
Expand Down Expand Up @@ -1094,6 +1095,7 @@ export class EuiComboBox<T> extends Component<
append={singleSelection ? append : undefined}
prepend={singleSelection ? prepend : undefined}
isLoading={isLoading}
isInvalid={markAsInvalid}
autoFocus={autoFocus}
aria-label={ariaLabel}
aria-labelledby={ariaLabelledby}
Expand Down
23 changes: 17 additions & 6 deletions src/components/combo_box/combo_box_input/combo_box_input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,23 @@ import React, {
import classNames from 'classnames';
import AutosizeInput from 'react-input-autosize';

import { CommonProps } from '../../common';
import { htmlIdGenerator } from '../../../services';
import { EuiScreenReaderOnly } from '../../accessibility';
import {
EuiFormControlLayout,
EuiFormControlLayoutProps,
} from '../../form/form_control_layout';
import { EuiComboBoxPill } from './combo_box_pill';
import { htmlIdGenerator } from '../../../services';
import { EuiFormControlLayoutIconsProps } from '../../form/form_control_layout/form_control_layout_icons';
import { getFormControlClassNameForIconCount } from '../../form/form_control_layout/_num_icons';

import { EuiComboBoxPill } from './combo_box_pill';
import {
EuiComboBoxOptionOption,
EuiComboBoxSingleSelectionShape,
OptionHandler,
UpdatePositionHandler,
} from '../types';
import { CommonProps } from '../../common';

export interface EuiComboBoxInputProps<T> extends CommonProps {
autoSizeInputRef?: RefCallback<AutosizeInput & HTMLInputElement>;
Expand Down Expand Up @@ -61,6 +63,7 @@ export interface EuiComboBoxInputProps<T> extends CommonProps {
prepend?: EuiFormControlLayoutProps['prepend'];
append?: EuiFormControlLayoutProps['append'];
isLoading?: boolean;
isInvalid?: boolean;
autoFocus?: boolean;
'aria-label'?: string;
'aria-labelledby'?: string;
Expand Down Expand Up @@ -151,6 +154,7 @@ export class EuiComboBoxInput<T> extends Component<
prepend,
append,
isLoading,
isInvalid,
autoFocus,
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledby,
Expand Down Expand Up @@ -256,12 +260,17 @@ export class EuiComboBoxInput<T> extends Component<
};
}

const wrapClasses = classNames('euiComboBox__inputWrap', {
const numIconsClass = getFormControlClassNameForIconCount({
isDropdown: !noIcon,
clear: !!clickProps.clear,
isInvalid,
isLoading,
});

const wrapClasses = classNames('euiComboBox__inputWrap', numIconsClass, {
'euiComboBox__inputWrap--compressed': compressed,
'euiComboBox__inputWrap--fullWidth': fullWidth,
'euiComboBox__inputWrap--noWrap': singleSelection,
'euiComboBox__inputWrap-isLoading': isLoading,
'euiComboBox__inputWrap-isClearable': onClear,
'euiComboBox__inputWrap--inGroup': prepend || append,
});

Expand All @@ -271,6 +280,7 @@ export class EuiComboBoxInput<T> extends Component<
{...clickProps}
inputId={id}
isLoading={isLoading}
isInvalid={isInvalid}
compressed={compressed}
fullWidth={fullWidth}
prepend={prepend}
Expand All @@ -291,6 +301,7 @@ export class EuiComboBoxInput<T> extends Component<
aria-expanded={isListOpen}
aria-label={ariaLabel}
aria-labelledby={ariaLabelledby}
aria-invalid={isInvalid}
className="euiComboBox__input"
data-test-subj="comboBoxSearchInput"
disabled={isDisabled}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@
// we use a form control layout class on all form controls.
@for $i from 1 through 5 {
&--#{$i}icons {
padding-right: $iconPadding + ($iconSize + $marginBetweenIcons) * $i;
$paddingOffset: $iconPadding + ($iconSize + $marginBetweenIcons) * $i;

--eui-form-control-layout-icons-padding: #{$paddingOffset}; // Set this for flexible usage, e.g. components that need extra specificity
padding-right: $paddingOffset;

&[class*='compressed'] {
$iconSizeCompressed: map-get($euiFormControlIconSizes, 'small');
$iconPaddingCompressed: $euiFormControlCompressedPadding;
$paddingOffset: $iconPaddingCompressed + ($iconSizeCompressed + $marginBetweenIcons) * $i;

padding-right: $iconPaddingCompressed + ($iconSizeCompressed + $marginBetweenIcons) * $i;
--eui-form-control-layout-icons-padding: #{$paddingOffset};
padding-right: $paddingOffset;
}
}
}
Expand Down
1 change: 1 addition & 0 deletions upcoming_changelogs/6680.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Updated `EuiDatePicker` to display a warning icon and correctly set `aria-invalid` when `isInvalid` is passed