change(ui) - autocomplete improvements with custom textfield

This commit is contained in:
Shekar Siri 2022-07-01 20:18:33 +02:00
parent 66dfb50a5c
commit c264c49d05
3 changed files with 88 additions and 26 deletions

View file

@ -4,8 +4,9 @@ import APIClient from 'App/api_client';
import { debounce } from 'App/utils';
import stl from './FilterAutoComplete.module.css';
import { components, DropdownIndicatorProps } from 'react-select';
import AsyncCreatableSelect from 'react-select/async-creatable';
import colors from 'App/theme/colors';
import Select from 'react-select';
import cn from 'classnames';
const dropdownStyles = {
option: (provided: any, state: any) => ({
@ -22,7 +23,7 @@ const dropdownStyles = {
'&:focus': {
transition: 'all 0.2s',
backgroundColor: colors['active-blue'],
}
},
}),
control: (provided: any) => {
const obj = {
@ -45,9 +46,6 @@ const dropdownStyles = {
height: '26px',
padding: '0 3px',
}),
// placeholder: (provided: any) => ({
// ...provided,
// }),
indicatorsContainer: (provided: any) => ({
...provided,
padding: '0px',
@ -55,14 +53,29 @@ const dropdownStyles = {
}),
menu: (provided: any, state: any) => ({
...provided,
top: 20,
left: 0,
top: 0,
borderRadius: '3px',
border: `1px solid ${colors['gray-light']}`,
backgroundColor: '#fff',
boxShadow: '1px 1px 1px rgba(0, 0, 0, 0.1)',
position: 'absolute',
minWidth: 'fit-content',
overflow: 'hidden',
zIndex: 100,
}),
menuList: (provided: any, state: any) => ({
...provided,
padding: 0,
}),
noOptionsMessage: (provided: any) => ({
...provided,
whiteSpace: 'nowrap !important',
// minWidth: 'fit-content',
}),
container: (provided: any) => ({
...provided,
width: '100%',
top: '18px',
position: 'absolute',
}),
input: (provided: any) => ({
...provided,
@ -113,12 +126,17 @@ function FilterAutoComplete(props: Props) {
params = {},
value = '',
} = props;
const [options, setOptions] = useState<any>(value ? [{ label: value, value }] : []);
const [loading, setLoading] = useState(false);
const [options, setOptions] = useState<any>([]);
const [query, setQuery] = useState(value);
const [menuIsOpen, setMenuIsOpen] = useState(false);
const [initialFocus, setInitialFocus] = useState(false);
let selectRef: any = null;
let inputRef: any = null;
useEffect(() => {
setQuery(value);
}, [value, options])
}, [value])
const loadOptions = (inputValue: string, callback: (options: []) => void) => {
new APIClient()
@ -133,32 +151,71 @@ function FilterAutoComplete(props: Props) {
const _options = data.map((i: any) => ({ value: i.value, label: i.value })) || [];
setOptions(_options);
callback(_options);
})
setLoading(false);
});
};
const debouncedLoadOptions = React.useCallback(debounce(loadOptions, 1000), [params]);
const handleInputChange = (newValue: string) => {
const inputValue = newValue.replace(/\W/g, '');
setQuery(inputValue);
return inputValue;
// const inputValue = newValue.replace(/\W/g, '');
setLoading(true);
setInitialFocus(true);
setQuery(newValue);
debouncedLoadOptions(newValue, (opt: any) => {
selectRef?.focus();
});
};
const onChange = (item: any) => {
setMenuIsOpen(false);
setQuery(item);
props.onSelect(null, item);
// inputRef?.blur();
};
const onFocus = () => {
setMenuIsOpen(true);
};
const onBlur = () => {
setMenuIsOpen(false);
props.onSelect(null, query);
};
const selected = value ? options.find((i: any) => i.value === query) : null;
return (
<div className="relative flex items-center">
<div className={stl.wrapper}>
<AsyncCreatableSelect
cacheOptions
defaultOptions={options}
loadOptions={debouncedLoadOptions}
onInputChange={handleInputChange}
onChange={(obj: any) => props.onSelect(null, obj)}
styles={dropdownStyles}
<div className={cn(stl.wrapper, 'relative')}>
<input
ref={(ref: any) => (inputRef = ref)}
className="w-full rounded px-2 no-focus"
value={query}
onChange={({ target: { value } }: any) => handleInputChange(value)}
onClick={onFocus}
onFocus={onFocus}
onBlur={onBlur}
placeholder={placeholder}
value={value ? options.find((i: any) => i.value === query) : null}
/>
{loading && (
<div className="absolute top-0 right-0" style={{ marginTop: '5px', marginRight: !showCloseButton || (showCloseButton && !showOrButton) ? '34px' : '62px'}}>
<Icon name="spinner" className="animate-spin" size="14" />
</div>
)}
<Select
ref={(ref: any) => {
selectRef = ref;
}}
options={options}
value={selected}
onChange={(e: any) => onChange(e.value)}
menuIsOpen={initialFocus && menuIsOpen}
menuPlacement="auto"
noOptionsMessage={() => loading ? 'Loading...' : 'No results found'}
styles={dropdownStyles}
components={{
IndicatorSeparator: () => null,
DropdownIndicator,
Control: ({ children, ...props }: any) => <></>,
}}
/>
<div className={stl.right}>

View file

@ -35,7 +35,7 @@ function FilterValue(props: Props) {
const onChange = (e: any, item: any, valueIndex: any) => {
const newValues = filter.value.map((_: any, _index: any) => {
if (_index === valueIndex) {
return item.value;
return item;
}
return _;
});

View file

@ -6,4 +6,9 @@
.capitalize-first::first-letter {
text-transform: uppercase;
}
input.no-focus:focus {
outline: none !important;
border: solid thin transparent !important;
}