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