console: searchable select UX fix (close #5246) (#5254)

This commit is contained in:
soorajshankar 2020-07-08 15:21:41 +05:30 committed by GitHub
parent b26e023483
commit b1c686f303
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,4 +1,4 @@
import React, { ReactText, useState, useMemo } from 'react';
import React, { ReactText, useState, useMemo, useEffect, useRef } from 'react';
import Select, {
components,
createFilter,
@ -33,6 +33,7 @@ export interface SearchableSelectProps {
placeholder: string;
filterOption: 'prefix' | 'fulltext';
isCreatable?: boolean;
onSearchValueChange?: (v: string | undefined | null) => void;
createNewOption?: (v: string) => ValueType<OptionTypeBase>;
}
const SearchableSelect: React.FC<SearchableSelectProps> = ({
@ -45,25 +46,46 @@ const SearchableSelect: React.FC<SearchableSelectProps> = ({
filterOption,
isCreatable,
createNewOption,
onSearchValueChange,
}) => {
const [searchValue, setSearchValue] = useState<string | null>(null);
const [isFocused, setIsFocused] = useState(false);
const selectedItem = useRef<ValueType<OptionTypeBase> | string>(null);
const inputValue = useMemo(() => {
// if input is not focused we don't want to show inputValue
if (!isFocused) return;
// if user is searching we don't want to control the input
if (searchValue !== null) return;
if (searchValue !== null) return searchValue; // when the user focus back to input
// otherwise we display last selected option
// this way typing after selecting an options is allowed
return typeof value === 'string' ? value : value?.label;
}, [searchValue, value, isFocused]);
useEffect(() => {
if (onSearchValueChange) onSearchValueChange(searchValue);
}, [searchValue]);
const onMenuClose = () => {
if (searchValue && createNewOption) onChange(createNewOption(searchValue));
if (selectedItem.current) onChange(selectedItem.current);
else if (createNewOption) onChange(createNewOption(searchValue || ''));
setIsFocused(false);
setSearchValue(null);
selectedItem.current = null;
};
const onSelect = (v: ValueType<OptionTypeBase> | string) => {
selectedItem.current = v;
};
const onFocus = () => {
setIsFocused(true);
let ipValue;
if (!inputValue) {
if (typeof value === 'string') ipValue = value;
else ipValue = value?.label || '';
setSearchValue(String(ipValue));
}
};
const customStyles: Record<string, any> = {};
@ -113,15 +135,15 @@ const SearchableSelect: React.FC<SearchableSelectProps> = ({
classNamePrefix={bsClass}
placeholder={placeholder}
options={options as Option[]}
onChange={onChange}
onChange={onSelect}
value={value as Option}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
onFocus={onFocus}
onBlur={onMenuClose}
inputValue={inputValue}
onInputChange={s => setSearchValue(s)}
onMenuClose={onMenuClose}
onInputChange={(s: string) => setSearchValue(s)}
styles={customStyles}
filterOption={searchValue ? customFilter : null}
className="search-select"
/>
);
};