1- import React from 'react' ;
1+ import React , { useEffect } from 'react' ;
22import PropTypes from 'prop-types' ;
33import lodashIsEmpty from 'lodash/isEmpty' ;
4- import { FormSpy } from 'react-final-form' ;
54import get from 'lodash/get' ;
5+ import isEqual from 'lodash/isEqual' ;
6+
7+ import useFormApi from '../files/use-form-api' ;
68
79const isEmptyValue = ( value ) => ( typeof value === 'number' || value === true ? false : lodashIsEmpty ( value ) ) ;
810
@@ -27,48 +29,125 @@ const fieldCondition = (value, { is, isNotEmpty, isEmpty, pattern, notMatch, fla
2729} ;
2830
2931export 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+
3042 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 ;
3244 }
3345
3446 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+ ) ;
3662 }
3763
3864 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 ;
4066 }
4167
4268 if ( condition . not ) {
43- return ! parseCondition ( condition . not , values ) ;
69+ return ! parseCondition ( condition . not , values ) ? positiveResult : negativeResult ;
4470 }
4571
4672 if ( typeof condition . when === 'string' ) {
47- return fieldCondition ( get ( values , condition . when ) , condition ) ;
73+ return fieldCondition ( get ( values , condition . when ) , condition ) ? positiveResult : negativeResult ;
4874 }
4975
5076 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 ;
5280 }
5381
54- return false ;
82+ return negativeResult ;
5583} ;
5684
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 ) ;
58117
59118const 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 ] ) ,
62121 isNotEmpty : PropTypes . bool ,
63122 isEmpty : PropTypes . bool ,
64- children : PropTypes . oneOf ( [ PropTypes . node , PropTypes . arrayOf ( PropTypes . node ) ] ) . isRequired ,
65123 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
67145} ;
68146
69147Condition . 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
72151} ;
73152
74153export default Condition ;
0 commit comments