parent
e1d6567097
commit
ce2fad66c7
1 changed files with 96 additions and 0 deletions
@ -0,0 +1,96 @@ |
||||
import { OutlinedInputProps } from '@mui/material'; |
||||
import { FormikValues, useFormik } from 'formik'; |
||||
import { useCallback, useMemo } from 'react'; |
||||
|
||||
import debounce from '../lib/debounce'; |
||||
import getFormikErrorMessages from '../lib/getFormikErrorMessages'; |
||||
|
||||
type UseFormik<Values extends FormikValues> = typeof useFormik<Values>; |
||||
|
||||
type Formik<Values extends FormikValues> = ReturnType<UseFormik<Values>>; |
||||
|
||||
type FormikChangeHandler<Values extends FormikValues> = |
||||
Formik<Values>['handleChange']; |
||||
|
||||
const useFormikUtils = <Values extends FormikValues = FormikValues>( |
||||
...formikArgs: Parameters<UseFormik<Values>> |
||||
): { |
||||
disableAutocomplete: ( |
||||
overwrite?: Partial<OutlinedInputProps>, |
||||
) => OutlinedInputProps; |
||||
disabledSubmit: boolean; |
||||
formik: Formik<Values>; |
||||
formikErrors: Messages; |
||||
handleChange: FormikChangeHandler<Values>; |
||||
} => { |
||||
const [formikConfig, ...restFormikArgs] = formikArgs; |
||||
|
||||
const formik = useFormik<Values>({ ...formikConfig }, ...restFormikArgs); |
||||
|
||||
const getFieldChanged = useCallback( |
||||
(field: string) => { |
||||
const parts = field.split('.'); |
||||
|
||||
const traverse = (values: Tree<unknown>): boolean => |
||||
parts.reduce<boolean>((previous, part) => { |
||||
if (!(part in values)) { |
||||
return false; |
||||
} |
||||
|
||||
const value = values[part]; |
||||
|
||||
if (value !== null && typeof value === 'object') { |
||||
return traverse(value as Tree<unknown>); |
||||
} |
||||
|
||||
return value === formik.initialValues[part]; |
||||
}, false); |
||||
|
||||
return traverse(formik.values); |
||||
}, |
||||
[formik.initialValues, formik.values], |
||||
); |
||||
|
||||
const disableAutocomplete = useCallback( |
||||
(overwrite?: Partial<OutlinedInputProps>): OutlinedInputProps => ({ |
||||
readOnly: true, |
||||
onFocus: (event) => { |
||||
event.target.readOnly = false; |
||||
}, |
||||
...overwrite, |
||||
}), |
||||
[], |
||||
); |
||||
|
||||
const debounceHandleChange = useMemo( |
||||
() => debounce(formik.handleChange), |
||||
[formik.handleChange], |
||||
); |
||||
|
||||
const disabledSubmit = useMemo( |
||||
() => |
||||
!formik.dirty || |
||||
!formik.isValid || |
||||
formik.isValidating || |
||||
formik.isSubmitting, |
||||
[formik.dirty, formik.isSubmitting, formik.isValid, formik.isValidating], |
||||
); |
||||
|
||||
const formikErrors = useMemo<Messages>( |
||||
() => |
||||
getFormikErrorMessages(formik.errors, { |
||||
skip: (field) => !getFieldChanged(field), |
||||
}), |
||||
[formik.errors, getFieldChanged], |
||||
); |
||||
|
||||
return { |
||||
disableAutocomplete, |
||||
disabledSubmit, |
||||
formik, |
||||
formikErrors, |
||||
handleChange: debounceHandleChange, |
||||
}; |
||||
}; |
||||
|
||||
export default useFormikUtils; |
Loading…
Reference in new issue