Skip to content

Commit 6a67e45

Browse files
committed
fix(FormAutocomplete): fix FormAutocomplete validation feedback
1 parent 4be36e2 commit 6a67e45

File tree

3 files changed

+52
-14
lines changed

3 files changed

+52
-14
lines changed

demo/FormExamples.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ export function FormExamples() {
100100
label="Autocomplete"
101101
options={['1234', '2345', '3456']}
102102
placeholder="Type some numbers"
103+
required
103104
/>
104105
</div>
105106
<div className="col">
@@ -109,7 +110,6 @@ export function FormExamples() {
109110
options={['Abcde', 'Fghij', 'klmno']}
110111
placeholder="Type some letters"
111112
openOnFocus={true}
112-
required
113113
/>
114114
</div>
115115
<div className="col">

src/forms/FormAutocomplete.jsx

+49-13
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState, useRef, useEffect } from 'react';
1+
import React, { useState, useRef, useCallback, useEffect } from 'react';
22
import PropTypes from 'prop-types';
33
import { handleInputChange, normalizeOptions } from './helpers/form-helpers';
44
import { Dropdown } from '../mixed/Dropdown';
@@ -19,27 +19,35 @@ export function FormAutocomplete({
1919
const [searchValue, setSearchValue] = useState('');
2020
const { isOpen, open, close } = useOpenState();
2121
const [ignoreBlur, setIgnoreBlur] = useState(false);
22-
const { getValue, setValue, register } = useFormControl(name);
23-
const inputRef = useRef(null);
22+
const [isFocused, setFocus] = useState(false);
23+
const { getValue, setValue, register, isValid, getFormSubmitedAttempted } = useFormControl(name);
24+
const registerRef = useCallback(register, []);
25+
const searchInputRef = useRef(null);
26+
27+
const items = normalizeOptions(options, FormData);
28+
const value = getValue();
29+
const selectedItem = items.find((item) => item.value === value);
30+
31+
const controlFeedback = `${getFormSubmitedAttempted() ? (isValid() ? 'is-valid' : 'is-invalid') : ''}`;
2432

2533
useEffect(() => {
26-
register(inputRef.current);
27-
}, []);
34+
searchInputRef.current.setCustomValidity(controlFeedback === 'is-invalid' ? 'invalid' : '');
35+
}, [controlFeedback]);
2836

2937
return (
3038
<>
3139
<input
32-
{...{ required, name, id, placeholder }}
40+
{...{ placeholder }}
3341
type="text"
34-
ref={inputRef}
35-
className="form-control"
42+
ref={searchInputRef}
43+
className={`form-control ${isFocused ? '' : 'd-none'} ${controlFeedback}`}
3644
onChange={handleInputChange.bind(null, {
3745
update(_, value) {
3846
setSearchValue(value);
3947
onSearch(value);
4048
open();
4149

42-
if (getValue()) {
50+
if (value) {
4351
setValue(null);
4452
}
4553
},
@@ -52,14 +60,15 @@ export function FormAutocomplete({
5260
}
5361
}}
5462
onBlur={() => {
55-
if (!getValue()) {
63+
if (!value) {
5664
setSearchValue('');
5765
}
5866

5967
if (ignoreBlur) {
60-
inputRef.current.focus();
68+
searchInputRef.current.focus();
6169
} else {
6270
close();
71+
setFocus(false);
6372
}
6473
}}
6574
value={searchValue}
@@ -68,13 +77,40 @@ export function FormAutocomplete({
6877
aria-expanded="false"
6978
autoComplete="off"
7079
/>
80+
81+
{!isFocused && (
82+
<div
83+
className={`form-control ${controlFeedback} `}
84+
onClick={() => {
85+
setFocus(true);
86+
setTimeout(() => {
87+
searchInputRef.current.focus();
88+
});
89+
}}
90+
>
91+
{selectedItem ? (template ? template(selectedItem.label) : selectedItem.label) : placeholder}
92+
</div>
93+
)}
94+
95+
<input
96+
type="text"
97+
className={`form-control d-none`}
98+
{...{ name, required, id }}
99+
onChange={() => {}}
100+
value={getValue()}
101+
ref={registerRef}
102+
/>
71103
<Dropdown
72104
isOpen={isOpen()}
73-
items={normalizeOptions(options, FormData).filter(filter(searchValue))}
105+
items={items.filter(filter(searchValue))}
74106
onSelect={({ value, label }) => {
75107
setValue(value);
76108
setSearchValue(label);
77-
close();
109+
setIgnoreBlur(false);
110+
setTimeout(() => {
111+
setFocus(false);
112+
close();
113+
}, 250);
78114
}}
79115
template={template}
80116
onTouchStart={() => setIgnoreBlur(true)}

src/forms/helpers/useFormControl.js

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ export function useFormControl(name, type) {
2020
formState.register(name, ref);
2121
},
2222
getFormData: () => formState.getFormData(),
23+
isValid: () => formState.getValidationMessage(name) === '',
24+
getFormSubmitedAttempted: () => formState.getSubmitedAttempted(),
2325
};
2426
}
2527

0 commit comments

Comments
 (0)