@@ -6,9 +6,7 @@ import Collector, {
6
6
SupplyRefHandler ,
7
7
CollectorChildrenAsFunction ,
8
8
CollectorData ,
9
- CollectorChildrenProps ,
10
9
CollectorActions ,
11
- InlineStyles ,
12
10
TargetPropsFunc ,
13
11
AnimationData ,
14
12
AnimationCallback ,
@@ -18,69 +16,8 @@ import defer from '../lib/defer';
18
16
import noop from '../lib/noop' ;
19
17
import { precondition , warn } from '../lib/log' ;
20
18
import * as store from '../lib/animatorStore' ;
21
- import { InjectedProps , withVisibilityManagerContext } from '../VisibilityManager' ;
22
-
23
- export type AnimationFunc = ( ) => Promise < void > ;
24
-
25
- export interface MappedAnimation {
26
- animate : AnimationFunc ;
27
- beforeAnimate : AnimationFunc ;
28
- afterAnimate : AnimationFunc ;
29
- cleanup : ( ) => void ;
30
- }
31
-
32
- export type AnimationBlock = MappedAnimation [ ] ;
33
-
34
- export interface ChildProps {
35
- style ?: InlineStyles ;
36
- className ?: string ;
37
- }
38
-
39
- export interface AnimatorState {
40
- childProps : ChildProps ;
41
- animationsMarkup : React . ReactPortal [ ] ;
42
- }
43
-
44
- export interface AnimatorProps extends CollectorChildrenProps , InjectedProps {
45
- /**
46
- * Name of the animator, this should match the target animator.
47
- */
48
- name : string ;
49
-
50
- /**
51
- * Will trigger animations over itself when this prop changes.
52
- *
53
- * You can't use the with the "in" prop.
54
- */
55
- triggerSelfKey ?: string ;
56
-
57
- /**
58
- * Use if your element is expected to persist through an animation.
59
- * When you transition to the next state set your "in" to false and vice versa.
60
- * This lets the Animator components know when to execute the animations.
61
- *
62
- * You can't use this with the "triggerSelfKey".
63
- */
64
- in ?: boolean ;
65
-
66
- /**
67
- * Callback called when all animations have finished and been cleaned up. Fired from the triggering Animator
68
- * component.
69
- */
70
- onFinish : ( ) => void ;
71
-
72
- /**
73
- * Time this component will wait until it throws away the animation.
74
- * Defaults to 50ms, might want to bump it up if loading something that was code split.
75
- */
76
- timeToWaitForNextAnimator : number ;
77
-
78
- /**
79
- * HTMLElement container used when creating elements for animations,
80
- * generally only supporting animations will need this.
81
- */
82
- container : HTMLElement | ( ( ) => HTMLElement ) ;
83
- }
19
+ import { withVisibilityManagerContext } from '../VisibilityManager' ;
20
+ import { AnimatorProps , AnimatorState , AnimationBlock } from './types' ;
84
21
85
22
export default class Animator extends React . PureComponent < AnimatorProps , AnimatorState > {
86
23
static displayName = 'Animator' ;
@@ -89,6 +26,7 @@ export default class Animator extends React.PureComponent<AnimatorProps, Animato
89
26
onFinish : noop ,
90
27
timeToWaitForNextAnimator : 50 ,
91
28
container : document . body ,
29
+ name : '' ,
92
30
} ;
93
31
94
32
state : AnimatorState = {
@@ -111,7 +49,13 @@ export default class Animator extends React.PureComponent<AnimatorProps, Animato
111
49
abortAnimations : ( ) => void = ( ) => undefined ;
112
50
113
51
componentDidMount ( ) {
114
- const { in : componentIn , name } = this . props ;
52
+ const { in : componentIn , name, triggerSelfKey } = this . props ;
53
+
54
+ if ( process . env . NODE_ENV === 'development' && ( ! triggerSelfKey && ! name ) ) {
55
+ warn (
56
+ '"name" prop needs to be defined. Without it you may have problems matching up animator targets. You will not get this error when using "triggerSelfKey" prop.'
57
+ ) ;
58
+ }
115
59
116
60
if ( componentIn === undefined && store . has ( name ) ) {
117
61
// A child has already been stored, so this is probably the matching pair.
@@ -128,22 +72,23 @@ export default class Animator extends React.PureComponent<AnimatorProps, Animato
128
72
129
73
getSnapshotBeforeUpdate ( prevProps : AnimatorProps ) {
130
74
if ( prevProps . in === true && this . props . in === false ) {
131
- this . storeDOMData ( ) ;
75
+ this . snapshotDOMData ( ) ;
132
76
this . delayedClearStore ( ) ;
133
77
this . abortAnimations ( ) ;
134
78
}
135
79
136
80
if ( prevProps . triggerSelfKey !== this . props . triggerSelfKey ) {
137
- this . storeDOMData ( ) ;
138
- this . delayedClearStore ( ) ;
81
+ return this . snapshotDOMData ( 'return' ) ;
139
82
}
140
83
141
- // we can return snapshot here to circumvent the entire storing of dom data.
142
- // would remove the need for setting a name!
143
84
return null ;
144
85
}
145
86
146
- componentDidUpdate ( prevProps : AnimatorProps , _ : AnimatorState ) {
87
+ componentDidUpdate (
88
+ prevProps : AnimatorProps ,
89
+ _ : AnimatorState ,
90
+ DOMSnapshot : store . AnimatorData | null
91
+ ) {
147
92
const inPropSame = this . props . in === prevProps . in ;
148
93
const triggerSelfKeyPropSame = this . props . triggerSelfKey === prevProps . triggerSelfKey ;
149
94
@@ -192,7 +137,7 @@ export default class Animator extends React.PureComponent<AnimatorProps, Animato
192
137
// Make sure to keep react state the same for any inflight animations to be captured correctly.
193
138
requestAnimationFrame ( ( ) => {
194
139
this . abortAnimations ( ) ;
195
- this . executeAnimations ( ) ;
140
+ this . executeAnimations ( DOMSnapshot ) ;
196
141
} ) ;
197
142
}
198
143
}
@@ -204,7 +149,7 @@ export default class Animator extends React.PureComponent<AnimatorProps, Animato
204
149
return ;
205
150
}
206
151
207
- this . storeDOMData ( ) ;
152
+ this . snapshotDOMData ( ) ;
208
153
this . delayedClearStore ( ) ;
209
154
this . abortAnimations ( ) ;
210
155
this . unmounting = true ;
@@ -226,64 +171,69 @@ export default class Animator extends React.PureComponent<AnimatorProps, Animato
226
171
setTimeout ( ( ) => store . remove ( name ) , timeToWaitForNextAnimator ) ;
227
172
}
228
173
229
- storeDOMData ( ) {
230
- if ( this . unmounting ) {
231
- return ;
232
- }
233
-
174
+ snapshotDOMData ( action : 'store' | 'return' = 'store' ) : store . AnimatorData | null {
234
175
// If there is only a Animator target and no child animations
235
176
// data will be undefined, which means there are no animations to store.
236
- if ( this . data ) {
237
- if ( process . env . NODE_ENV === 'development' ) {
238
- precondition (
239
- this . element ,
240
- `The ref was not set when trying to store data, check that a child element has a ref passed. This needs to be set so we can take a snapshot of the origin DOM element.
177
+ if ( this . unmounting || ! this . data ) {
178
+ return null ;
179
+ }
180
+
181
+ if ( process . env . NODE_ENV === 'development' ) {
182
+ precondition (
183
+ this . element ,
184
+ `The ref was not set when trying to store data, check that a child element has a ref passed. This needs to be set so we can take a snapshot of the origin DOM element.
241
185
242
186
<${ Animator . displayName } name="${ this . props . name } ">
243
187
{props => <div ref={props.ref} />}
244
188
</${ Animator . displayName } >
245
189
`
246
- ) ;
247
- }
190
+ ) ;
191
+ }
248
192
249
- const elementBoundingBox = getElementBoundingBox ( this . element as HTMLElement ) ;
250
- const focalTargetElementBoundingBox = this . focalTargetElement
251
- ? getElementBoundingBox ( this . focalTargetElement )
252
- : undefined ;
193
+ const elementBoundingBox = getElementBoundingBox ( this . element as HTMLElement ) ;
194
+ const focalTargetElementBoundingBox = this . focalTargetElement
195
+ ? getElementBoundingBox ( this . focalTargetElement )
196
+ : undefined ;
253
197
254
- if ( process . env . NODE_ENV === 'development' && elementBoundingBox . size . height === 0 ) {
255
- warn ( `Your target child had a height of zero when capturing it's DOM data. This may affect the animation.
198
+ if ( process . env . NODE_ENV === 'development' && elementBoundingBox . size . height === 0 ) {
199
+ warn ( `Your target child had a height of zero when capturing it's DOM data. This may affect the animation.
256
200
If it's an image, try and have the image loaded before mounting, or set a static height.` ) ;
257
- }
258
-
259
- const { name } = this . props ;
201
+ }
260
202
261
- // NOTE: Currently in react 16.3 if the parent being unmounted is a Fragment
262
- // there is a chance for sibling elements to be removed from the DOM first
263
- // resulting in inaccurate calculations of location. Watch out!
264
- const data : store . AnimatorData = {
265
- elementData : {
266
- element : this . element as HTMLElement ,
267
- elementBoundingBox,
268
- focalTargetElement : this . focalTargetElement ,
269
- focalTargetElementBoundingBox,
270
- render : this . renderChildren ,
271
- } ,
272
- collectorData : this . data ,
273
- } ;
203
+ const { name } = this . props ;
204
+
205
+ // NOTE: Currently in react 16.3 if the parent being unmounted is a Fragment
206
+ // there is a chance for sibling elements to be removed from the DOM first
207
+ // resulting in inaccurate calculations of location. Watch out!
208
+ const data : store . AnimatorData = {
209
+ elementData : {
210
+ element : this . element as HTMLElement ,
211
+ elementBoundingBox,
212
+ focalTargetElement : this . focalTargetElement ,
213
+ focalTargetElementBoundingBox,
214
+ render : this . renderChildren ,
215
+ } ,
216
+ collectorData : this . data ,
217
+ } ;
218
+
219
+ if ( action === 'return' ) {
220
+ return data ;
221
+ }
274
222
223
+ if ( action === 'store' ) {
275
224
store . set ( name , data ) ;
276
225
}
226
+
227
+ return null ;
277
228
}
278
229
279
- executeAnimations = ( ) => {
230
+ executeAnimations = ( DOMSnapshot : store . AnimatorData | null = store . get ( this . props . name ) ) => {
280
231
const { name, container : getContainer , context } = this . props ;
281
232
const container = typeof getContainer === 'function' ? getContainer ( ) : getContainer ;
282
- const fromTarget = store . get ( name ) ;
283
233
let aborted = false ;
284
234
285
- if ( fromTarget ) {
286
- const { collectorData, elementData } = fromTarget ;
235
+ if ( DOMSnapshot ) {
236
+ const { collectorData, elementData } = DOMSnapshot ;
287
237
this . animating = true ;
288
238
289
239
// Calculate DOM data for the executing element to then be passed to the animation/s.
0 commit comments