Merge pull request #6266 from tchak/fix-autocomplete

Correction des bugs sur les select avec autocomplétion
This commit is contained in:
Paul Chavard 2021-06-15 10:37:32 +02:00 committed by GitHub
commit 352b92b35c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 99 additions and 41 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;
}
@ -45,17 +47,23 @@ function ComboSearch({
const [debouncedSearchTerm] = useDebounce(searchTerm, 300);
const [value, setValue] = useState(initialValue);
const resultsMap = useRef({});
const setExternalValue = useCallback((value) => {
if (hiddenValueField) {
hiddenValueField.setAttribute('value', value);
fire(hiddenValueField, 'autosave:trigger');
}
});
const setExternalId = useCallback((key) => {
if (hiddenIdField) {
hiddenIdField.setAttribute('value', key);
}
});
const setExternalValue = useCallback(
(value) => {
if (hiddenValueField) {
hiddenValueField.setAttribute('value', value);
fire(hiddenValueField, 'autosave:trigger');
}
},
[hiddenValueField]
);
const setExternalId = useCallback(
(key) => {
if (hiddenIdField) {
hiddenIdField.setAttribute('value', key);
}
},
[hiddenIdField]
);
const setExternalValueAndId = useCallback((value) => {
const [key, result] = resultsMap.current[value];
setExternalId(key);
@ -63,7 +71,8 @@ function ComboSearch({
if (onChange) {
onChange(value, result);
}
});
}, []);
const awaitFormSubmit = useDeferredSubmit(hiddenValueField);
const handleOnChange = useCallback(
({ target: { value } }) => {
@ -82,7 +91,9 @@ function ComboSearch({
const handleOnSelect = useCallback((value) => {
setExternalValueAndId(value);
setValue(value);
});
setSearchTerm('');
awaitFormSubmit.done();
}, []);
const { isSuccess, data } = useQuery([scope, debouncedSearchTerm], {
enabled: !!debouncedSearchTerm,
@ -91,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;
}