1
- import React from 'react' ;
1
+ import React , { useEffect } from 'react' ;
2
2
import PropTypes from 'prop-types' ;
3
3
import lodashIsEmpty from 'lodash/isEmpty' ;
4
- import { FormSpy } from 'react-final-form' ;
5
4
import get from 'lodash/get' ;
5
+ import isEqual from 'lodash/isEqual' ;
6
+
7
+ import useFormApi from '../files/use-form-api' ;
6
8
7
9
const isEmptyValue = ( value ) => ( typeof value === 'number' || value === true ? false : lodashIsEmpty ( value ) ) ;
8
10
@@ -27,48 +29,125 @@ const fieldCondition = (value, { is, isNotEmpty, isEmpty, pattern, notMatch, fla
27
29
} ;
28
30
29
31
export const parseCondition = ( condition , values ) => {
32
+ let positiveResult = {
33
+ visible : true ,
34
+ ...condition . then
35
+ } ;
36
+
37
+ let negativeResult = {
38
+ visible : false ,
39
+ ...condition . else
40
+ } ;
41
+
30
42
if ( Array . isArray ( condition ) ) {
31
- return ! condition . map ( ( condition ) => parseCondition ( condition , values ) ) . some ( ( result ) => result === false ) ;
43
+ return ! condition . map ( ( condition ) => parseCondition ( condition , values ) ) . some ( ( result ) => result === false ) ? positiveResult : negativeResult ;
32
44
}
33
45
34
46
if ( condition . and ) {
35
- return condition . and . map ( ( condition ) => parseCondition ( condition , values ) ) . every ( ( result ) => result === true ) ;
47
+ return ! condition . and . map ( ( condition ) => parseCondition ( condition , values ) ) . some ( ( result ) => result === false ) ? positiveResult : negativeResult ;
48
+ }
49
+
50
+ if ( condition . sequence ) {
51
+ return condition . sequence . reduce (
52
+ ( acc , curr ) => {
53
+ const result = parseCondition ( curr , values ) ;
54
+
55
+ return {
56
+ sets : [ ...acc . sets , ...[ result . set ? result . set : [ ] ] ] ,
57
+ visible : acc . visible || result . visible
58
+ } ;
59
+ } ,
60
+ { ...negativeResult , sets : [ ] }
61
+ ) ;
36
62
}
37
63
38
64
if ( condition . or ) {
39
- return condition . or . map ( ( condition ) => parseCondition ( condition , values ) ) . some ( ( result ) => result === true ) ;
65
+ return condition . or . map ( ( condition ) => parseCondition ( condition , values ) ) . some ( ( result ) => result === true ) ? positiveResult : negativeResult ;
40
66
}
41
67
42
68
if ( condition . not ) {
43
- return ! parseCondition ( condition . not , values ) ;
69
+ return ! parseCondition ( condition . not , values ) ? positiveResult : negativeResult ;
44
70
}
45
71
46
72
if ( typeof condition . when === 'string' ) {
47
- return fieldCondition ( get ( values , condition . when ) , condition ) ;
73
+ return fieldCondition ( get ( values , condition . when ) , condition ) ? positiveResult : negativeResult ;
48
74
}
49
75
50
76
if ( Array . isArray ( condition . when ) ) {
51
- return ! ! condition . when . map ( ( fieldName ) => fieldCondition ( get ( values , fieldName ) , condition ) ) . find ( ( condition ) => ! ! condition ) ;
77
+ return condition . when . map ( ( fieldName ) => fieldCondition ( get ( values , fieldName ) , condition ) ) . find ( ( condition ) => ! ! condition )
78
+ ? positiveResult
79
+ : negativeResult ;
52
80
}
53
81
54
- return false ;
82
+ return negativeResult ;
55
83
} ;
56
84
57
- const Condition = ( { condition, children } ) => < FormSpy > { ( { values } ) => ( parseCondition ( condition , values ) ? children : null ) } </ FormSpy > ;
85
+ const Condition = React . memo ( ( { condition, children, values } ) => {
86
+ const formOptions = useFormApi ( ) ;
87
+ const dirty = formOptions . getState ( ) . dirty ;
88
+
89
+ const [ lastSets , setSets ] = React . useState ( [ ] ) ;
90
+
91
+ const conditionResult = parseCondition ( condition , values , formOptions ) ;
92
+ const setters = conditionResult . set ? [ conditionResult . set ] : conditionResult . sets ;
93
+
94
+ useEffect ( ( ) => {
95
+ if ( ! dirty ) {
96
+ setSets ( [ ] ) ;
97
+ }
98
+ } , [ dirty ] ) ;
99
+
100
+ useEffect ( ( ) => {
101
+ if ( setters && setters . length > 0 && ( ! dirty || ! isEqual ( setters , lastSets ) ) ) {
102
+ setters . forEach ( ( setter , index ) => {
103
+ if ( setter && ( ! dirty || ! isEqual ( setter , lastSets [ index ] ) ) ) {
104
+ formOptions . batch ( ( ) => {
105
+ Object . entries ( setter ) . forEach ( ( [ name , value ] ) => {
106
+ formOptions . change ( name , value ) ;
107
+ } ) ;
108
+ } ) ;
109
+ }
110
+ } ) ;
111
+ setSets ( setters ) ;
112
+ }
113
+ } , [ setters , dirty ] ) ;
114
+
115
+ return conditionResult . visible ? children : null ;
116
+ } , isEqual ) ;
58
117
59
118
const conditionProps = {
60
- when : PropTypes . string . isRequired ,
61
- is : PropTypes . oneOfType ( [ PropTypes . array , PropTypes . string , PropTypes . object , PropTypes . number , PropTypes . bool ] ) . isRequired ,
119
+ when : PropTypes . string ,
120
+ is : PropTypes . oneOfType ( [ PropTypes . array , PropTypes . string , PropTypes . object , PropTypes . number , PropTypes . bool ] ) ,
62
121
isNotEmpty : PropTypes . bool ,
63
122
isEmpty : PropTypes . bool ,
64
- children : PropTypes . oneOf ( [ PropTypes . node , PropTypes . arrayOf ( PropTypes . node ) ] ) . isRequired ,
65
123
pattern : PropTypes . oneOf ( [ PropTypes . string , PropTypes . instanceOf ( RegExp ) ] ) ,
66
- notMatch : PropTypes . any
124
+ notMatch : PropTypes . any ,
125
+ then : PropTypes . shape ( {
126
+ visible : PropTypes . bool ,
127
+ set : PropTypes . object
128
+ } ) ,
129
+ else : PropTypes . shape ( {
130
+ visible : PropTypes . bool ,
131
+ set : PropTypes . object
132
+ } )
133
+ } ;
134
+
135
+ const nestedConditions = {
136
+ or : PropTypes . oneOfType ( [ PropTypes . shape ( conditionProps ) , PropTypes . arrayOf ( PropTypes . shape ( conditionProps ) ) ] ) ,
137
+ and : PropTypes . oneOfType ( [ PropTypes . shape ( conditionProps ) , PropTypes . arrayOf ( PropTypes . shape ( conditionProps ) ) ] ) ,
138
+ not : PropTypes . oneOfType ( [ PropTypes . shape ( conditionProps ) , PropTypes . arrayOf ( PropTypes . shape ( conditionProps ) ) ] ) ,
139
+ sequence : PropTypes . arrayOf ( PropTypes . shape ( conditionProps ) )
140
+ } ;
141
+
142
+ const conditionsProps = {
143
+ ...conditionProps ,
144
+ ...nestedConditions
67
145
} ;
68
146
69
147
Condition . propTypes = {
70
- condition : PropTypes . oneOfType ( [ PropTypes . shape ( conditionProps ) , PropTypes . arrayOf ( PropTypes . shape ( conditionProps ) ) ] ) ,
71
- children : PropTypes . oneOf ( [ PropTypes . node , PropTypes . arrayOf ( PropTypes . node ) ] ) . isRequired
148
+ condition : PropTypes . oneOfType ( [ PropTypes . shape ( conditionsProps ) , PropTypes . arrayOf ( PropTypes . shape ( conditionsProps ) ) ] ) ,
149
+ children : PropTypes . oneOfType ( [ PropTypes . node , PropTypes . arrayOf ( PropTypes . node ) ] ) . isRequired ,
150
+ values : PropTypes . object . isRequired
72
151
} ;
73
152
74
153
export default Condition ;
0 commit comments