import React from 'react'; import { FieldPath, FieldValues, useController, UseControllerProps } from 'react-hook-form'; import { Autocomplete, AutocompleteChangeDetails, AutocompleteChangeReason, AutocompleteProps, AutocompleteRenderInputParams, AutocompleteValue, ChipTypeMap, TextField, TextFieldProps } from '@mui/material'; import { isBoolean, isEqual, isFunction, isString } from 'lodash'; import { useDefaultProps } from '../../hooks'; import { useLocalization } from '../../localization'; export type RHFAutocompleteProps< TFieldValues extends FieldValues, TName extends FieldPath, TValue, TMultiple extends boolean | undefined, TDisableClearable extends boolean | undefined, TFreeSolo extends boolean | undefined, TChipComponent extends React.ElementType > = Omit< AutocompleteProps, 'name' | 'defaultValue' | 'onChange' | 'value' | 'disabled' | 'renderInput' | 'open' | 'onOpen' | 'onClose' > & { onChange?: (value: AutocompleteValue) => void; transform?: ( event: React.SyntheticEvent, value: AutocompleteValue, reason: AutocompleteChangeReason, details?: AutocompleteChangeDetails | undefined ) => AutocompleteValue; label?: TextFieldProps['label']; helperText?: TextFieldProps['helperText']; variant?: TextFieldProps['variant']; color?: TextFieldProps['color']; required?: TextFieldProps['required']; placeholder?: TextFieldProps['placeholder']; TextFieldProps?: TextFieldProps | ((params: AutocompleteRenderInputParams) => TextFieldProps); } & UseControllerProps; function RHFAutocomplete< TFieldValues extends FieldValues, TName extends FieldPath, TValue, TMultiple extends boolean | undefined = false, TDisableClearable extends boolean | undefined = true, TFreeSolo extends boolean | undefined = false, TChipComponent extends React.ElementType = ChipTypeMap['defaultComponent'] >(inProps: RHFAutocompleteProps) { const { /** React Hook Form */ name, rules, control, disabled, defaultValue, shouldUnregister, /** React Hook Form */ onChange, onBlur, multiple, options, transform, /** TextField Props */ required, label, helperText, variant, TextFieldProps, color, size, placeholder, /** TextField Props */ ...props } = useDefaultProps({ name: 'ReevolveRHFAutocomplete', props: inProps }); const { translate } = useLocalization(); const { field, fieldState: { error } } = useController({ name, defaultValue, disabled, shouldUnregister, control, rules: rules && { ...rules, required: rules?.required === true ? translate('validation.required', { label }) : rules?.required } }); function onBlurHandler(event: React.FocusEvent) { field.onBlur(); onBlur?.(event); } return ( isOptionEqualToValue={(option, currentValue) => isEqual(option, currentValue)} disableClearable={true as TDisableClearable} noOptionsText={translate(`autocomplete.noOptionsText`)} loadingText={translate('autocomplete.loadingText')} openText={translate('autocomplete.openText')} closeText={translate('autocomplete.closeText')} openOnFocus color={color} size={size} {...props} options={options || []} multiple={multiple} renderInput={(params) => { const _TextFieldProps = isFunction(TextFieldProps) ? TextFieldProps(params) : { ...TextFieldProps, ...params }; return ( ); }} onBlur={onBlurHandler} onChange={(event, value, reason, details) => { if (isFunction(transform)) { const transformedValue = transform(event, value, reason, details); field.onChange(transformedValue); onChange?.(transformedValue); } else { field.onChange(value); onChange?.(value); } }} value={(field.value ?? (multiple ? [] : null)) as any} disabled={field.disabled} /> ); } declare module '@mui/material' { interface Components { ReevolveRHFAutocomplete?: { defaultProps?: Partial>; }; } } export default RHFAutocomplete;