Skip to content

Commit 8821b1d

Browse files
committed
fix(forms): reset FormAutocomplete internal state when value is empty
1 parent bd6b345 commit 8821b1d

File tree

4 files changed

+82
-47
lines changed

4 files changed

+82
-47
lines changed

demo/FormExamples.jsx

+5-2
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,15 @@ export function FormExamples() {
3434
}, 1000);
3535
});
3636
}}
37-
transform={(formData, pathUpdated, update) => {
37+
transform={(formData, _, update) => {
3838
formData.__v = formData.__v ? formData.__v + 1 : 1;
3939

4040
update(formData);
4141
}}
42-
onCancel={() => console.log('onCancel')}
42+
onCancel={(resetForm) => {
43+
console.log('onCancel');
44+
resetForm();
45+
}}
4346
customValidation={true}
4447
validations={{
4548
numberField: [

src/forms/Form.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export function Form({
5555

5656
function handleCancel() {
5757
//TODO: improve cancel options
58-
onCancel();
58+
onCancel(resetForm);
5959
}
6060

6161
const formProps = {

src/forms/FormAutocomplete.jsx

+68-44
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Dropdown } from '../mixed/Dropdown';
55
import { useOpenState } from '../utils/useOpenState';
66
import { formatClasses } from '../utils/attributes';
77
import { useFormControl } from './helpers/useFormControl';
8+
import { isEmpty } from '../utils/types';
89

910
export function FormAutocomplete({
1011
onSearch,
@@ -40,6 +41,68 @@ export function FormAutocomplete({
4041
searchInputRef.current.setCustomValidity(controlFeedback === 'is-invalid' ? 'invalid' : '');
4142
}, [controlFeedback]);
4243

44+
useEffect(() => {
45+
if (isEmpty(value) && !isFocused) {
46+
setSearchValue('');
47+
setSelectedItem(null);
48+
}
49+
}, [isFocused, value]);
50+
51+
const onSearchInputType = useCallback(
52+
(_, nextSearchValue) => {
53+
setSearchValue(nextSearchValue);
54+
onSearch(nextSearchValue);
55+
open();
56+
57+
if (nextSearchValue && value) {
58+
setValue(null);
59+
}
60+
},
61+
[onSearch, open, setValue, value]
62+
);
63+
64+
const onSearchInputFocus = useCallback(() => {
65+
if (openOnFocus) {
66+
setTimeout(() => {
67+
open();
68+
}, 100);
69+
}
70+
}, []);
71+
72+
const onSearchInputBlur = useCallback(() => {
73+
if (ignoreBlur) {
74+
searchInputRef.current.focus();
75+
} else {
76+
close();
77+
setFocus(false);
78+
}
79+
}, [close, ignoreBlur]);
80+
81+
const enableSearchInput = useCallback(() => {
82+
if (disabled) {
83+
return;
84+
}
85+
86+
setFocus(true);
87+
setTimeout(() => {
88+
searchInputRef.current.focus();
89+
});
90+
}, [disabled]);
91+
92+
const onSelectItem = useCallback(
93+
({ value, label }) => {
94+
setValue(value);
95+
setSearchValue(label);
96+
setSelectedItem({ value, label });
97+
setIgnoreBlur(false);
98+
setTimeout(() => {
99+
setFocus(false);
100+
close();
101+
}, 60);
102+
},
103+
[close, setValue]
104+
);
105+
43106
return (
44107
<>
45108
<input
@@ -48,31 +111,10 @@ export function FormAutocomplete({
48111
ref={searchInputRef}
49112
className={`form-control ${isFocused ? '' : 'd-none'} ${controlFeedback}`}
50113
onChange={handleInputChange.bind(null, {
51-
update(_, nextSearchValue) {
52-
setSearchValue(nextSearchValue);
53-
onSearch(nextSearchValue);
54-
open();
55-
56-
if (nextSearchValue && value) {
57-
setValue(null);
58-
}
59-
},
114+
update: onSearchInputType,
60115
})}
61-
onFocus={() => {
62-
if (openOnFocus) {
63-
setTimeout(() => {
64-
open();
65-
}, 100);
66-
}
67-
}}
68-
onBlur={() => {
69-
if (ignoreBlur) {
70-
searchInputRef.current.focus();
71-
} else {
72-
close();
73-
setFocus(false);
74-
}
75-
}}
116+
onFocus={onSearchInputFocus}
117+
onBlur={onSearchInputBlur}
76118
value={searchValue}
77119
role="combobox"
78120
aria-autocomplete="list"
@@ -84,16 +126,7 @@ export function FormAutocomplete({
84126
<div
85127
className={formatClasses(['form-control', controlFeedback])}
86128
disabled={disabled}
87-
onClick={() => {
88-
if (disabled) {
89-
return;
90-
}
91-
92-
setFocus(true);
93-
setTimeout(() => {
94-
searchInputRef.current.focus();
95-
});
96-
}}
129+
onClick={enableSearchInput}
97130
>
98131
{selectedItem ? (template ? template(selectedItem.label) : selectedItem.label) : placeholder}
99132
</div>
@@ -110,16 +143,7 @@ export function FormAutocomplete({
110143
<Dropdown
111144
isOpen={isOpen()}
112145
items={items.filter(filter(searchValue))}
113-
onSelect={({ value, label }) => {
114-
setValue(value);
115-
setSearchValue(label);
116-
setSelectedItem({ value, label });
117-
setIgnoreBlur(false);
118-
setTimeout(() => {
119-
setFocus(false);
120-
close();
121-
}, 60);
122-
}}
146+
onSelect={onSelectItem}
123147
template={template}
124148
onClick={(e) => e.stopPropation()}
125149
onTouchStart={() => setIgnoreBlur(true)}

src/utils/types.js

+8
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,11 @@ export function isNull(value) {
2525
export function isFunction(value) {
2626
return typeof value === 'function';
2727
}
28+
29+
export function isEmpty(value) {
30+
return isUndefined(value) || isNull(value) || (isString(value) && value.length === 0);
31+
}
32+
33+
export function isUndefined(value) {
34+
return typeof value === 'undefined';
35+
}

0 commit comments

Comments
 (0)