Skip to content

Commit 47d6206

Browse files
authored
Merge pull request #567 from brocoders/renovate/wrapper-autocomplete
feat: add autocomplete input
2 parents 0adc296 + e2fef24 commit 47d6206

File tree

1 file changed

+111
-0
lines changed

1 file changed

+111
-0
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
"use client";
2+
3+
import { ForwardedRef, forwardRef } from "react";
4+
import {
5+
Controller,
6+
ControllerProps,
7+
FieldPath,
8+
FieldValues,
9+
} from "react-hook-form";
10+
import FormControl from "@mui/material/FormControl";
11+
import Autocomplete from "@mui/material/Autocomplete";
12+
import TextField from "@mui/material/TextField";
13+
import FormHelperText from "@mui/material/FormHelperText";
14+
15+
type AutocompleteInputProps<T> = {
16+
label: string;
17+
type?: string;
18+
autoFocus?: boolean;
19+
disabled?: boolean;
20+
readOnly?: boolean;
21+
error?: string;
22+
testId?: string;
23+
size?: "small" | "medium";
24+
keyValue: keyof T;
25+
value: T | null;
26+
options: T[];
27+
renderOption: (option: T) => React.ReactNode;
28+
};
29+
30+
function AutocompleteInputRaw<T>(
31+
props: AutocompleteInputProps<T> & {
32+
name: string;
33+
value: T[] | undefined | null;
34+
onChange: (value: T) => void;
35+
onBlur: () => void;
36+
},
37+
ref?: ForwardedRef<HTMLDivElement | null>
38+
) {
39+
return (
40+
<FormControl error={!!props.error} disabled={props.disabled}>
41+
<Autocomplete
42+
ref={ref}
43+
id={`autocomplete-${props.name}`}
44+
options={props.options}
45+
value={props.value}
46+
onChange={(_, newValue) => {
47+
if (!newValue) return;
48+
49+
props.onChange(newValue);
50+
}}
51+
onBlur={props.onBlur}
52+
data-testid={props.testId}
53+
getOptionLabel={(option) => option?.[props.keyValue]?.toString() ?? ""}
54+
renderOption={(htmlProps, option) => (
55+
<li {...htmlProps}>{props.renderOption(option)}</li>
56+
)}
57+
renderInput={(params) => (
58+
<TextField {...params} label={props.label} size={props.size} />
59+
)}
60+
/>
61+
{!!props.error && (
62+
<FormHelperText data-testid={`${props.testId}-error`}>
63+
{props.error}
64+
</FormHelperText>
65+
)}
66+
</FormControl>
67+
);
68+
}
69+
70+
const AutocompleteInput = forwardRef(AutocompleteInputRaw) as never as <T>(
71+
props: AutocompleteInputProps<T> & {
72+
name: string;
73+
value: T[] | undefined | null;
74+
onChange: (value: T[]) => void;
75+
onBlur: () => void;
76+
} & { ref?: ForwardedRef<HTMLDivElement | null> }
77+
) => ReturnType<typeof AutocompleteInputRaw>;
78+
79+
function FormAutocompleteInput<
80+
TFieldValues extends FieldValues = FieldValues,
81+
T = unknown,
82+
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
83+
>(
84+
props: AutocompleteInputProps<T> &
85+
Pick<ControllerProps<TFieldValues, TName>, "name" | "defaultValue">
86+
) {
87+
return (
88+
<Controller
89+
name={props.name}
90+
defaultValue={props.defaultValue}
91+
render={({ field, fieldState }) => (
92+
<AutocompleteInput<T>
93+
{...field}
94+
label={props.label}
95+
autoFocus={props.autoFocus}
96+
type={props.type}
97+
error={fieldState.error?.message}
98+
disabled={props.disabled}
99+
readOnly={props.readOnly}
100+
testId={props.testId}
101+
options={props.options}
102+
renderOption={props.renderOption}
103+
keyValue={props.keyValue}
104+
size={props.size}
105+
/>
106+
)}
107+
/>
108+
);
109+
}
110+
111+
export default FormAutocompleteInput;

0 commit comments

Comments
 (0)