in packages/eui/src/components/combo_box/combo_box_input/combo_box_input.tsx [223:415]
render() {
const {
compressed,
focusedOptionId,
fullWidth,
hasSelectedOptions,
id,
isDisabled,
isListOpen,
noIcon,
onChange,
onClear,
onClick,
onFocus,
onCloseListClick,
onOpenListClick,
placeholder,
rootId,
searchValue,
selectedOptions,
singleSelection,
value,
prepend,
append,
isLoading,
isInvalid,
autoFocus,
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledby,
} = this.props;
let removeOptionMessage: ReactNode;
let removeOptionMessageId;
if (this.state.hasFocus) {
const readPlaceholder = placeholder ? `${placeholder}.` : '';
const removeOptionMessageContent =
`Combo box. Selected. ${
searchValue ? `${searchValue}. Selected. ` : ''
}${
selectedOptions && selectedOptions.length > 0
? `${value}. Press Backspace to delete ${
selectedOptions[selectedOptions.length - 1].label
}. `
: ''
}Combo box input. ${readPlaceholder} Type some text or, to display a list of choices, press Down Arrow. ` +
'To exit the list of choices, press Escape.';
removeOptionMessageId = rootId('removeOptionMessage');
// aria-live="assertive" will read this message aloud immediately once it enters the DOM.
// We'll render to the DOM when the input gains focus and remove it when the input loses focus.
// We'll use aria-hidden to prevent default aria information from being read by the screen
// reader.
removeOptionMessage = (
<EuiScreenReaderOnly>
<span aria-live="polite" id={removeOptionMessageId}>
{removeOptionMessageContent}
</span>
</EuiScreenReaderOnly>
);
}
const isInGroup = singleSelection && (prepend || append);
const showPlaceholder =
placeholder && !selectedOptions?.length && !searchValue;
const clickProps: EuiFormControlLayoutIconsProps = {};
if (!isDisabled && onClear && hasSelectedOptions) {
clickProps.clear = {
'data-test-subj': 'comboBoxClearButton',
onClick: onClear,
};
}
let icon: EuiFormControlLayoutIconsProps['icon'];
if (!noIcon && !isDisabled) {
icon = {
'aria-label': isListOpen
? 'Close list of options'
: 'Open list of options',
'data-test-subj': 'comboBoxToggleListButton',
disabled: isDisabled,
onClick: isListOpen && !isDisabled ? onCloseListClick : onOpenListClick,
side: 'right',
tabIndex: -1,
type: 'arrowDown',
};
}
const wrapClasses = classNames('euiComboBox__inputWrap', {
'euiComboBox__inputWrap--plainText': this.asPlainText,
});
return (
<RenderWithEuiStylesMemoizer>
{(stylesMemoizer) => {
const styles = stylesMemoizer(euiComboBoxInputStyles);
const cssStyles = [
styles.euiComboBoxInputWrapper,
!singleSelection && styles.multiSelect,
compressed ? styles.compressed : styles.uncompressed,
...(this.asPlainText || showPlaceholder
? [
styles.plainText.plainText,
compressed
? styles.plainText.compressed
: styles.plainText.uncompressed,
]
: []),
isDisabled
? styles.disabled
: isInvalid
? styles.invalid
: isListOpen
? styles.open
: undefined,
isInGroup && styles.inGroup,
];
const formLayoutStyles = [
styles.formLayout.euiComboBox__formControlLayout,
!singleSelection && styles.formLayout.multiSelect,
];
return (
<EuiFormControlLayout
icon={icon}
{...clickProps}
inputId={id}
isLoading={isLoading}
isInvalid={isInvalid}
isDisabled={isDisabled}
compressed={compressed}
fullWidth={fullWidth}
prepend={prepend}
append={append}
css={formLayoutStyles}
>
<div
css={cssStyles}
className={wrapClasses}
data-test-subj="comboBoxInput"
onClick={onClick}
tabIndex={-1} // becomes onBlur event's relatedTarget, otherwise relatedTarget is null when clicking on this div
>
{this.renderPills()}
<EuiComboBoxOptionAppendPrepend
option={this.asPlainText ? selectedOptions?.[0] : undefined}
classNamePrefix="euiComboBoxPlainTextSelection"
marginSize="xxs"
>
<input
aria-activedescendant={focusedOptionId}
aria-autocomplete="list"
aria-controls={isListOpen ? rootId('listbox') : ''}
aria-expanded={isListOpen}
aria-label={ariaLabel}
aria-labelledby={ariaLabelledby}
aria-invalid={isInvalid}
aria-haspopup="listbox"
css={styles.euiComboBoxInput}
className="euiComboBox__input"
data-test-subj="comboBoxSearchInput"
disabled={isDisabled}
id={id}
onBlur={this.onBlur}
onChange={(event) => onChange(event.target.value)}
onFocus={this.onFocus}
onKeyDown={this.onKeyDown}
ref={this.inputRefCallback}
role="combobox"
style={{
inlineSize:
this.asPlainText || showPlaceholder
? '100%'
: this.state.inputWidth,
}}
placeholder={showPlaceholder ? placeholder : undefined}
value={this.searchValue}
autoFocus={autoFocus}
autoComplete="off"
// Force the menu to re-open on every input click - only necessary when plain text
onClick={this.asPlainText ? (onFocus as any) : undefined} // Type shenanigans - event should be mostly the same
/>
</EuiComboBoxOptionAppendPrepend>
{removeOptionMessage}
</div>
</EuiFormControlLayout>
);
}}
</RenderWithEuiStylesMemoizer>
);
}