@@ -8,35 +8,25 @@ import React, {
8
8
import { func } from 'prop-types'
9
9
export const FormContext = createContext ( null )
10
10
11
- const getElement = ( search , elements , mapper = ( x ) => x ) =>
12
- elements [
13
- Array . from ( elements )
14
- . map ( mapper )
15
- . findIndex ( ( x ) => x === search || x . id === search || x . name === search )
16
- ]
11
+ const getName = ( ref ) => ref . id || ref . name
17
12
18
13
const Form = forwardRef ( ( { onSubmit, ...rest } , ref ) => {
19
14
const formRef = useRef ( ref )
20
15
const touched = useRef ( { } )
21
- const fields = useRef ( [ ] )
16
+ const fields = useRef ( { } )
22
17
23
18
/**
24
19
* This is invoked from `useValidation`
25
20
* Each element, as it's mounted, must register with us so we can do things with them
26
21
* This happens in a `useEffect` - the disposable will call the unregister function.
27
22
*/
28
- const register = useCallback (
29
- ( field , details ) => fields . current . push ( { field, details } ) ,
30
- [ ]
31
- )
23
+ const register = useCallback ( ( ref , ctx ) => {
24
+ fields . current [ getName ( ref ) ] = { ref, ctx }
25
+ } , [ ] )
32
26
33
- const unregister = useCallback (
34
- ( field ) =>
35
- ( fields . current = fields . current . filter (
36
- ( f ) => f . field . name !== field . name
37
- ) ) ,
38
- [ ]
39
- )
27
+ const unregister = useCallback ( ( ref ) => {
28
+ delete fields . current [ getName ( ref ) ]
29
+ } , [ ] )
40
30
41
31
/**
42
32
* Validates a single input.
@@ -54,29 +44,27 @@ const Form = forwardRef(({ onSubmit, ...rest }, ref) => {
54
44
* @param {HtmlInputElement } formInput the input to validate
55
45
* @param {boolean } [force=false] whether to bypass touched check.
56
46
*/
57
- const validateSingle = useCallback ( ( formInput , force = false ) => {
58
- const isTouched = touched . current [ formInput . name ]
47
+ const validateSingle = useCallback ( ( ref , force = false ) => {
48
+ const isTouched = touched . current [ ref . name ]
59
49
if ( ! force && ! isTouched ) return
60
50
61
- formInput . setCustomValidity ( '' )
62
- if ( ! formInput . checkValidity ( ) ) return
51
+ ref . setCustomValidity ( '' )
52
+ if ( ! ref . checkValidity ( ) ) return // the invalid event will have fired.
63
53
64
- let error = null
65
- const field = getElement ( formInput , fields . current , ( x ) => x . field )
66
- const others = fields . current . map ( ( x ) => x . field )
54
+ const { ctx } = fields . current [ getName ( ref ) ]
55
+ const refs = Object . entries ( fields . current ) . map ( ( [ , { ref } ] ) => ref )
67
56
68
- for ( const fn of field . details . validation ?? [ ] ) {
69
- let err = fn ( formInput , others )
70
- if ( typeof err === 'string' ) error = new Error ( err )
71
- else if ( err instanceof Error ) error = err
72
- if ( error ) break
73
- }
57
+ let [ error ] = ( ctx . validation ?? [ ] )
58
+ . map ( ( fn ) => fn ( ref , refs ) )
59
+ . filter ( ( valResult ) => valResult != null )
60
+
61
+ if ( typeof error === 'string' ) error = new Error ( error )
74
62
75
- if ( error ) {
76
- formInput . setCustomValidity ( error . message )
77
- formInput . checkValidity ( )
63
+ if ( error != null ) {
64
+ ref . setCustomValidity ( error . message )
65
+ ref . checkValidity ( )
78
66
} else {
79
- field . details . updateState ( error , formInput . validity )
67
+ ctx . updateState ( null , ref . validity )
80
68
}
81
69
} , [ ] )
82
70
@@ -86,12 +74,17 @@ const Form = forwardRef(({ onSubmit, ...rest }, ref) => {
86
74
*/
87
75
const validate = useCallback (
88
76
( { target : element } ) => {
89
- const field = getElement ( element , fields . current , ( x ) => x . field )
90
- validateSingle ( element )
91
- for ( const item of field . details . otherArray ) {
92
- const other = getElement ( item , element . form . elements )
93
- if ( other ) validateSingle ( other )
94
- }
77
+ const { ctx } = fields . current [ getName ( element ) ]
78
+ const allFields = ctx . otherArray . reduce (
79
+ ( acc , item ) => {
80
+ const other = fields . current [ item ]
81
+ if ( other ) acc . push ( other . ref )
82
+ return acc
83
+ } ,
84
+ [ element ]
85
+ )
86
+
87
+ allFields . forEach ( ( field ) => validateSingle ( field ) )
95
88
} ,
96
89
[ validateSingle ]
97
90
)
@@ -103,8 +96,8 @@ const Form = forwardRef(({ onSubmit, ...rest }, ref) => {
103
96
*/
104
97
const handleSubmit = useCallback (
105
98
( e ) => {
106
- for ( const { field } of fields . current ) {
107
- validateSingle ( field , true )
99
+ for ( const [ , { ref } ] of Object . entries ( fields . current ) ) {
100
+ validateSingle ( ref , true )
108
101
}
109
102
if ( e . target . checkValidity ( ) ) {
110
103
onSubmit ?. ( e )
0 commit comments