1
1
/**
2
2
* @license
3
- * Copyright (C) 2016 Chi Vinh Le and contributors.
3
+ * Copyright (C) 2016-present Chi Vinh Le and contributors.
4
4
*
5
5
* This software may be modified and distributed under the terms
6
6
* of the MIT license. See the LICENSE file for details.
7
7
*/
8
8
9
- /* tslint:disable: variable-name no-switch-case-fall-through */
10
-
11
9
import * as React from "react" ;
12
10
import {
13
11
CSSProperties , Component , ComponentClass , ReactNode ,
14
12
StatelessComponent , ReactElement , HTMLAttributes ,
15
13
} from "react" ;
16
14
17
- import { resolveTransit } from "./transit " ;
15
+ import { ActionID , CSSTransitionState , reduce } from "./csstransitionstate " ;
18
16
import { TransitionObserver } from "./transitionobserver" ;
19
- import { TransitionDelay , getEnterDelay , getLeaveDelay } from "./utils" ;
20
-
21
- const TICK = 17 ;
17
+ import { TransitionDelay , runInFrame } from "./utils" ;
22
18
23
19
export type CSSTransitionDelay = TransitionDelay ;
24
20
export type CSSTransitionEventHandler = ( ) => void ;
@@ -44,95 +40,31 @@ export interface CSSTransitionProps
44
40
// leaveInitStyle?: CSSProperties;
45
41
}
46
42
47
- export interface CSSTransitionState {
48
- id ?: StateID ;
49
- style ?: CSSProperties ;
50
- }
51
-
52
- export enum StateID {
53
- Active ,
54
- TransitToDefaultRunning ,
55
- TransitToDefaultStarted ,
56
- TransitToActiveAppearing ,
57
- TransitToActiveRunning ,
58
- TransitToActiveStarted ,
59
- Default ,
60
- }
61
-
62
- enum Action {
63
- InitActive ,
64
- InitDefault ,
65
- TransitionAppear ,
66
- TransitionSkip ,
67
- TransitionRun ,
68
- TransitionStart ,
69
- TransitionComplete ,
70
- }
71
-
72
- const activeState = ( props : CSSTransitionProps ) => ( {
73
- id : StateID . Active ,
74
- style : { ...props . style , ...props . activeStyle } ,
75
- } ) ;
76
-
77
- const defaultState = ( props : CSSTransitionProps ) => ( {
78
- id : StateID . Default ,
79
- style : { ...props . style , ...props . defaultStyle } ,
80
- } ) ;
81
-
82
- const transitToActiveAppearingState = ( props : CSSTransitionProps ) => ( {
83
- id : StateID . TransitToActiveAppearing ,
84
- style : { ...props . style , ...props . defaultStyle } ,
85
- } ) ;
86
-
87
- const transitToActiveRunningState = ( props : CSSTransitionProps ) => ( {
88
- id : StateID . TransitToActiveRunning ,
89
- style : { ...props . style , ...resolveTransit ( props . enterStyle , getEnterDelay ( props . transitionDelay ) ) } ,
90
- } ) ;
91
-
92
- const transitToActiveStartedState = ( props : CSSTransitionProps ) => ( {
93
- id : StateID . TransitToActiveStarted ,
94
- style : { ...props . style , ...resolveTransit ( props . enterStyle , getEnterDelay ( props . transitionDelay ) ) } ,
95
- } ) ;
96
-
97
- const transitToDefaultRunningState = ( props : CSSTransitionProps ) => ( {
98
- id : StateID . TransitToDefaultRunning ,
99
- style : { ...props . style , ...resolveTransit ( props . leaveStyle , getLeaveDelay ( props . transitionDelay ) ) } ,
100
- } ) ;
101
-
102
- const transitToDefaultStartedState = ( props : CSSTransitionProps ) => ( {
103
- id : StateID . TransitToDefaultStarted ,
104
- style : { ...props . style , ...resolveTransit ( props . leaveStyle , getLeaveDelay ( props . transitionDelay ) ) } ,
105
- } ) ;
106
-
107
43
export class CSSTransition extends Component < CSSTransitionProps , CSSTransitionState > {
108
44
public static defaultProps : any = {
109
45
component : "div" ,
110
46
} ;
111
47
112
- private appearTimer : any ;
48
+ private cancelPending : any ;
113
49
114
50
constructor ( props : CSSTransitionProps ) {
115
51
super ( props ) ;
116
- let stateAction = Action . InitDefault ;
117
- if ( ! props . transitionAppear && props . active ) {
118
- stateAction = Action . InitActive ;
119
- }
120
- this . dispatch ( stateAction , props ) ;
52
+ this . dispatch ( ActionID . Init , props ) ;
121
53
}
122
54
123
55
public componentDidMount ( ) : void {
124
56
if ( this . props . transitionAppear && this . props . active ) {
125
- this . dispatch ( Action . TransitionAppear ) ;
57
+ this . dispatch ( ActionID . TransitionTrigger ) ;
126
58
}
127
59
}
128
60
129
61
public componentWillUnmount ( ) : void {
130
- clearTimeout ( this . appearTimer ) ;
62
+ if ( this . cancelPending ) { this . cancelPending ( ) ; this . cancelPending = null ; }
131
63
}
132
64
133
65
public componentWillReceiveProps ( nextProps : CSSTransitionProps ) : void {
134
66
if ( this . props . active === nextProps . active ) { return ; }
135
- this . dispatch ( Action . TransitionRun , nextProps ) ;
67
+ this . dispatch ( ActionID . TransitionTrigger , nextProps ) ;
136
68
}
137
69
138
70
public render ( ) : ReactElement < any > {
@@ -165,77 +97,20 @@ export class CSSTransition extends Component<CSSTransitionProps, CSSTransitionSt
165
97
) ;
166
98
}
167
99
168
- private handleTransitionComplete = ( ) => this . dispatch ( Action . TransitionComplete ) ;
169
- private handleTransitionBegin = ( ) => this . dispatch ( Action . TransitionStart ) ;
170
-
171
- private dispatch ( action : Action , props = this . props , state = this . state ) : void {
172
- switch ( action ) {
173
- case Action . InitActive :
174
- if ( state !== undefined ) { throw new Error ( "invalid state transition" ) ; }
175
- this . state = activeState ( props ) ;
176
- return ;
177
- case Action . InitDefault :
178
- if ( state !== undefined ) { throw new Error ( "invalid state transition" ) ; }
179
- this . state = defaultState ( props ) ;
180
- return ;
181
- case Action . TransitionAppear :
182
- if ( state . id !== StateID . Default ) {
183
- throw new Error ( "invalid state transition" ) ;
184
- }
185
- this . appearTimer = setTimeout ( ( ) => {
186
- this . dispatch ( Action . TransitionRun , props ) ;
187
- } , TICK ) ;
188
- return this . setState ( transitToActiveAppearingState ( props ) ) ;
189
- case Action . TransitionRun :
190
- switch ( state . id ) {
191
- case StateID . TransitToActiveAppearing :
192
- clearTimeout ( this . appearTimer ) ;
193
- if ( props . active ) {
194
- return this . setState ( transitToActiveRunningState ( props ) ) ;
195
- }
196
- if ( props . onTransitionComplete ) { props . onTransitionComplete ( ) ; }
197
- return this . setState ( defaultState ( props ) ) ;
198
- case StateID . Active :
199
- case StateID . TransitToActiveStarted :
200
- return this . setState ( transitToDefaultRunningState ( props ) ) ;
201
- case StateID . Default :
202
- case StateID . TransitToDefaultStarted :
203
- return this . setState ( transitToActiveRunningState ( props ) ) ;
204
- case StateID . TransitToActiveRunning :
205
- if ( props . onTransitionComplete ) { props . onTransitionComplete ( ) ; }
206
- return this . setState ( defaultState ( props ) ) ;
207
- case StateID . TransitToDefaultRunning :
208
- if ( props . onTransitionComplete ) { props . onTransitionComplete ( ) ; }
209
- return this . setState ( activeState ( props ) ) ;
210
- default :
211
- throw new Error ( "invalid state transition" ) ;
212
- }
213
- case Action . TransitionStart :
214
- switch ( state . id ) {
215
- case StateID . TransitToActiveRunning :
216
- return this . setState ( transitToActiveStartedState ( props ) ) ;
217
- case StateID . TransitToDefaultRunning :
218
- return this . setState ( transitToDefaultStartedState ( props ) ) ;
219
- default :
220
- // We don't error out, because the workaround for transitionstart
221
- // could happen after transitionend.
222
- return ;
223
- }
224
- case Action . TransitionComplete :
225
- switch ( state . id ) {
226
- case StateID . TransitToActiveRunning :
227
- case StateID . TransitToActiveStarted :
228
- if ( props . onTransitionComplete ) { props . onTransitionComplete ( ) ; }
229
- return this . setState ( activeState ( props ) ) ;
230
- case StateID . TransitToDefaultRunning :
231
- case StateID . TransitToDefaultStarted :
232
- if ( props . onTransitionComplete ) { props . onTransitionComplete ( ) ; }
233
- return this . setState ( defaultState ( props ) ) ;
234
- default :
235
- throw new Error ( "invalid state transition" ) ;
236
- }
237
- default :
100
+ private handleTransitionComplete = ( ) => this . dispatch ( ActionID . TransitionComplete ) ;
101
+ private handleTransitionBegin = ( ) => this . dispatch ( ActionID . TransitionStart ) ;
102
+
103
+ private dispatch ( action : ActionID , props = this . props ) : void {
104
+ const result = reduce ( this . state , action , props ) ;
105
+ if ( ! result ) { return ; }
106
+ const { state, pending} = result ;
107
+ let callback : any = undefined ;
108
+ if ( this . cancelPending ) { this . cancelPending ( ) ; this . cancelPending = null ; }
109
+ if ( pending ) { callback = ( ) => { this . cancelPending = runInFrame ( 1 , ( ) => this . dispatch ( pending ) ) ; } ; }
110
+ if ( this . state === undefined ) {
111
+ this . state = state ;
112
+ return ;
238
113
}
239
- throw new Error ( "unexpected error" ) ;
114
+ this . setState ( state , callback ) ;
240
115
}
241
116
}
0 commit comments