mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-15 01:12:56 +03:00
parent
b26e023483
commit
b1c686f303
@ -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"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user