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