@@ -6,27 +6,42 @@ import {
6
6
type FormikErrors ,
7
7
type FormikProps ,
8
8
} from "formik"
9
- import { type ReactNode , type FC , useRef , useEffect } from "react"
9
+ import {
10
+ type ReactNode ,
11
+ type FC ,
12
+ useRef ,
13
+ useEffect ,
14
+ type RefObject ,
15
+ } from "react"
10
16
import type { TypedUseMutation } from "@reduxjs/toolkit/query/react"
11
17
18
+ import { getKeyPaths } from "../../utils/general"
12
19
import {
13
20
submitForm ,
14
21
type SubmitFormOptions ,
15
22
type FormValues ,
16
23
} from "../../utils/form"
17
24
18
- type NonFieldErrorsProps = Omit < FormHelperTextProps , "error" | "ref" >
25
+ const SCROLL_INTO_VIEW_OPTIONS : ScrollIntoViewOptions = {
26
+ behavior : "smooth" ,
27
+ block : "start" ,
28
+ }
29
+
30
+ type NonFieldErrorsProps = Omit < FormHelperTextProps , "error" | "ref" > & {
31
+ scrollIntoViewOptions ?: ScrollIntoViewOptions
32
+ }
19
33
20
- const NonFieldErrors : FC < NonFieldErrorsProps > = props => {
34
+ const NonFieldErrors : FC < NonFieldErrorsProps > = ( {
35
+ scrollIntoViewOptions = SCROLL_INTO_VIEW_OPTIONS ,
36
+ ...formHelperTextProps
37
+ } ) => {
21
38
const pRef = useRef < HTMLParagraphElement > ( null )
22
39
23
40
useEffect ( ( ) => {
24
- if ( pRef . current ) {
25
- pRef . current . scrollIntoView ( { behavior : "smooth" , block : "start" } )
26
- }
27
- } , [ ] )
41
+ if ( pRef . current ) pRef . current . scrollIntoView ( scrollIntoViewOptions )
42
+ } , [ scrollIntoViewOptions ] )
28
43
29
- return < FormHelperText ref = { pRef } error { ...props } />
44
+ return < FormHelperText ref = { pRef } error { ...formHelperTextProps } />
30
45
}
31
46
32
47
export type FormErrors < Values > = FormikErrors <
@@ -37,38 +52,61 @@ type _FormikProps<Values> = Omit<FormikProps<Values>, "errors"> & {
37
52
errors : FormErrors < Values >
38
53
}
39
54
40
- type _FormikConfig < Values > = Omit < FormikConfig < Values > , "children" > & {
55
+ type BaseFormProps < Values > = Omit < FormikConfig < Values > , "children" > & {
41
56
children : ReactNode | ( ( props : _FormikProps < Values > ) => ReactNode )
57
+ scrollIntoViewOptions ?: ScrollIntoViewOptions
42
58
nonFieldErrorsProps ?: Omit < NonFieldErrorsProps , "children" >
59
+ order ?: Array < { name : string ; inputRef : RefObject < HTMLInputElement > } >
43
60
}
44
61
45
- const _ = < Values extends FormValues > ( {
62
+ const BaseForm = < Values extends FormValues > ( {
46
63
children,
64
+ scrollIntoViewOptions = SCROLL_INTO_VIEW_OPTIONS ,
47
65
nonFieldErrorsProps,
66
+ order,
48
67
...otherFormikProps
49
- } : _FormikConfig < Values > ) => (
68
+ } : BaseFormProps < Values > ) => (
50
69
< Formik { ...otherFormikProps } >
51
70
{ /* @ts -expect-error */ }
52
- { ( formik : _FormikProps < Values > ) => (
53
- < >
54
- { typeof formik . errors . non_field_errors === "string" && (
55
- < NonFieldErrors { ...nonFieldErrorsProps } >
56
- { formik . errors . non_field_errors }
57
- </ NonFieldErrors >
58
- ) }
59
- < FormikForm >
60
- { typeof children === "function" ? children ( formik ) : children }
61
- </ FormikForm >
62
- </ >
63
- ) }
71
+ { ( formik : _FormikProps < Values > ) => {
72
+ let nonFieldErrors : undefined | JSX . Element = undefined
73
+ if ( Object . keys ( formik . errors ) . length ) {
74
+ if ( typeof formik . errors . non_field_errors === "string" ) {
75
+ nonFieldErrors = (
76
+ < NonFieldErrors { ...nonFieldErrorsProps } >
77
+ { formik . errors . non_field_errors }
78
+ </ NonFieldErrors >
79
+ )
80
+ } else if ( order && order . length ) {
81
+ const errorNames = getKeyPaths ( formik . errors )
82
+
83
+ const inputRef = order . find ( ( { name } ) =>
84
+ errorNames . includes ( name ) ,
85
+ ) ?. inputRef
86
+
87
+ if ( inputRef ?. current ) {
88
+ inputRef . current . scrollIntoView ( scrollIntoViewOptions )
89
+ }
90
+ }
91
+ }
92
+
93
+ return (
94
+ < >
95
+ { nonFieldErrors }
96
+ < FormikForm >
97
+ { typeof children === "function" ? children ( formik ) : children }
98
+ </ FormikForm >
99
+ </ >
100
+ )
101
+ } }
64
102
</ Formik >
65
103
)
66
104
67
105
type SubmitFormProps <
68
106
Values extends FormValues ,
69
107
QueryArg extends FormValues ,
70
108
ResultType ,
71
- > = Omit < _FormikConfig < Values > , "onSubmit" > & {
109
+ > = Omit < BaseFormProps < Values > , "onSubmit" > & {
72
110
useMutation : TypedUseMutation < ResultType , QueryArg , any >
73
111
} & ( Values extends QueryArg
74
112
? { submitOptions ?: SubmitFormOptions < Values , QueryArg , ResultType > }
@@ -81,16 +119,16 @@ const SubmitForm = <
81
119
> ( {
82
120
useMutation,
83
121
submitOptions,
84
- ...formikProps
122
+ ...baseFormProps
85
123
} : SubmitFormProps < Values , QueryArg , ResultType > ) : JSX . Element => {
86
124
const [ trigger ] = useMutation ( )
87
125
88
126
return (
89
- < _
90
- { ...formikProps }
127
+ < BaseForm
128
+ { ...baseFormProps }
91
129
onSubmit = { submitForm < Values , QueryArg , ResultType > (
92
130
trigger ,
93
- formikProps . initialValues ,
131
+ baseFormProps . initialValues ,
94
132
submitOptions as SubmitFormOptions < Values , QueryArg , ResultType > ,
95
133
) }
96
134
/>
@@ -101,10 +139,10 @@ export type FormProps<
101
139
Values extends FormValues ,
102
140
QueryArg extends FormValues ,
103
141
ResultType ,
104
- > = _FormikConfig < Values > | SubmitFormProps < Values , QueryArg , ResultType >
142
+ > = BaseFormProps < Values > | SubmitFormProps < Values , QueryArg , ResultType >
105
143
106
144
const Form : {
107
- < Values extends FormValues > ( props : _FormikConfig < Values > ) : JSX . Element
145
+ < Values extends FormValues > ( props : BaseFormProps < Values > ) : JSX . Element
108
146
< Values extends FormValues , QueryArg extends FormValues , ResultType > (
109
147
props : SubmitFormProps < Values , QueryArg , ResultType > ,
110
148
) : JSX . Element
@@ -115,7 +153,7 @@ const Form: {
115
153
> (
116
154
props : FormProps < Values , QueryArg , ResultType > ,
117
155
) : JSX . Element => {
118
- return "onSubmit" in props ? < _ { ...props } /> : SubmitForm ( props )
156
+ return "onSubmit" in props ? < BaseForm { ...props } /> : SubmitForm ( props )
119
157
}
120
158
121
159
export default Form
0 commit comments