Fix autocomplete on blur

This commit is contained in:
Paul Chavard 2021-06-09 17:13:26 +02:00
parent 7f4e174871
commit 7575f50d25
3 changed files with 80 additions and 28 deletions

View file

@ -21,6 +21,8 @@ import { fire } from '@utils';
import { XIcon } from '@heroicons/react/outline';
import isHotkey from 'is-hotkey';
import { useDeferredSubmit } from './shared/hooks';
const Context = createContext();
function ComboMultipleDropdownList({
@ -78,39 +80,12 @@ function ComboMultipleDropdownList({
() => document.querySelector(`input[data-uuid="${hiddenFieldId}"]`),
[hiddenFieldId]
);
const awaitFormSubmit = useDeferredSubmit(hiddenField);
const handleChange = (event) => {
setTerm(event.target.value);
};
const onKeyDown = (event) => {
if (
isHotkey('enter', event) ||
isHotkey(' ', event) ||
isHotkey(',', event) ||
isHotkey(';', event)
) {
if (
term &&
[...extraOptions, ...options].map(([label]) => label).includes(term)
) {
event.preventDefault();
return onSelect(term);
}
}
};
const onBlur = (event) => {
if (
acceptNewValues &&
term &&
[...extraOptions, ...options].map(([label]) => label).includes(term)
) {
event.preventDefault();
return onSelect(term);
}
};
const saveSelection = (fn) => {
setSelections((selections) => {
selections = fn(selections);
@ -138,6 +113,7 @@ function ComboMultipleDropdownList({
saveSelection((selections) => [...selections, selectedValue]);
}
setTerm('');
awaitFormSubmit.done();
};
const onRemove = (label) => {
@ -153,6 +129,34 @@ function ComboMultipleDropdownList({
inputRef.current.focus();
};
const onKeyDown = (event) => {
if (
isHotkey('enter', event) ||
isHotkey(' ', event) ||
isHotkey(',', event) ||
isHotkey(';', event)
) {
if (
term &&
[...extraOptions, ...options].map(([label]) => label).includes(term)
) {
event.preventDefault();
onSelect(term);
}
}
};
const onBlur = () => {
if (
term &&
[...extraOptions, ...options].map(([label]) => label).includes(term)
) {
awaitFormSubmit(() => {
onSelect(term);
});
}
};
return (
<Combobox openOnFocus={true} onSelect={onSelect} aria-label={label}>
<ComboboxTokenLabel onRemove={onRemove}>

View file

@ -12,6 +12,8 @@ import {
import '@reach/combobox/styles.css';
import { fire } from '@utils';
import { useDeferredSubmit } from './shared/hooks';
function defaultTransformResults(_, results) {
return results;
}
@ -70,6 +72,7 @@ function ComboSearch({
onChange(value, result);
}
}, []);
const awaitFormSubmit = useDeferredSubmit(hiddenValueField);
const handleOnChange = useCallback(
({ target: { value } }) => {
@ -88,6 +91,8 @@ function ComboSearch({
const handleOnSelect = useCallback((value) => {
setExternalValueAndId(value);
setValue(value);
setSearchTerm('');
awaitFormSubmit.done();
}, []);
const { isSuccess, data } = useQuery([scope, debouncedSearchTerm], {
@ -97,12 +102,22 @@ function ComboSearch({
});
const results = isSuccess ? transformResults(debouncedSearchTerm, data) : [];
const onBlur = useCallback(() => {
if (!allowInputValues && isSuccess && results[0]) {
const [, value] = transformResult(results[0]);
awaitFormSubmit(() => {
handleOnSelect(value);
});
}
}, [data]);
return (
<Combobox aria-label={label} onSelect={handleOnSelect}>
<ComboboxInput
className={className}
placeholder={placeholder}
onChange={handleOnChange}
onBlur={onBlur}
value={value}
required={required}
/>

View file

@ -0,0 +1,33 @@
import { useRef, useCallback } from 'react';
export function useDeferredSubmit(input) {
const calledRef = useRef(false);
const awaitFormSubmit = useCallback(
(callback) => {
const form = input.form;
if (!form) {
return;
}
const interceptFormSubmit = (event) => {
event.preventDefault();
runCallback();
form.submit();
};
calledRef.current = false;
form.addEventListener('submit', interceptFormSubmit);
const runCallback = () => {
form.removeEventListener('submit', interceptFormSubmit);
clearTimeout(timer);
if (!calledRef.current) {
callback();
}
};
const timer = setTimeout(runCallback, 400);
},
[input]
);
awaitFormSubmit.done = () => {
calledRef.current = true;
};
return awaitFormSubmit;
}