change(ui) - autocomplete improvements with custom textfield
This commit is contained in:
parent
66dfb50a5c
commit
c264c49d05
3 changed files with 88 additions and 26 deletions
|
|
@ -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}>
|
||||
|
|
|
|||
|
|
@ -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 _;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,4 +6,9 @@
|
|||
|
||||
.capitalize-first::first-letter {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
input.no-focus:focus {
|
||||
outline: none !important;
|
||||
border: solid thin transparent !important;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue