Skip to content

Commit 5696ccf

Browse files
committed
Merge pull request facebook#6005 from milesj/synthetic-transition
Added support for synthetic animation/transition events.
2 parents adc9104 + 260353e commit 5696ccf

File tree

8 files changed

+287
-43
lines changed

8 files changed

+287
-43
lines changed

docs/docs/ref-05-events.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ DOMEventTarget relatedTarget
139139

140140
These focus events work on all elements in the React DOM, not just form elements.
141141

142+
142143
### Form Events
143144

144145
Event names:
@@ -246,6 +247,7 @@ number deltaY
246247
number deltaZ
247248
```
248249

250+
249251
### Media Events
250252

251253
Event names:
@@ -254,10 +256,45 @@ Event names:
254256
onAbort onCanPlay onCanPlayThrough onDurationChange onEmptied onEncrypted onEnded onError onLoadedData onLoadedMetadata onLoadStart onPause onPlay onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting
255257
```
256258

259+
257260
### Image Events
258261

259262
Event names:
260263

261264
```
262265
onLoad onError
263266
```
267+
268+
269+
### Animation Events
270+
271+
Event names:
272+
273+
```
274+
onAnimationStart onAnimationEnd onAnimationIteration
275+
```
276+
277+
Properties:
278+
279+
```javascript
280+
string animationName
281+
string pseudoElement
282+
float elapsedTime
283+
```
284+
285+
286+
### Transition Events
287+
288+
Event names:
289+
290+
```
291+
onTransitionEnd
292+
```
293+
294+
Properties:
295+
296+
```javascript
297+
string propertyName
298+
string pseudoElement
299+
float elapsedTime
300+
```

src/addons/transitions/ReactTransitionEvents.js

Lines changed: 7 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -13,56 +13,20 @@
1313

1414
var ExecutionEnvironment = require('ExecutionEnvironment');
1515

16-
/**
17-
* EVENT_NAME_MAP is used to determine which event fired when a
18-
* transition/animation ends, based on the style property used to
19-
* define that event.
20-
*/
21-
var EVENT_NAME_MAP = {
22-
transitionend: {
23-
'transition': 'transitionend',
24-
'WebkitTransition': 'webkitTransitionEnd',
25-
'MozTransition': 'mozTransitionEnd',
26-
'OTransition': 'oTransitionEnd',
27-
'msTransition': 'MSTransitionEnd',
28-
},
29-
30-
animationend: {
31-
'animation': 'animationend',
32-
'WebkitAnimation': 'webkitAnimationEnd',
33-
'MozAnimation': 'mozAnimationEnd',
34-
'OAnimation': 'oAnimationEnd',
35-
'msAnimation': 'MSAnimationEnd',
36-
},
37-
};
16+
var getVendorPrefixedEventName = require('getVendorPrefixedEventName');
3817

3918
var endEvents = [];
4019

4120
function detectEvents() {
42-
var testEl = document.createElement('div');
43-
var style = testEl.style;
44-
45-
// On some platforms, in particular some releases of Android 4.x,
46-
// the un-prefixed "animation" and "transition" properties are defined on the
47-
// style object but the events that fire will still be prefixed, so we need
48-
// to check if the un-prefixed events are useable, and if not remove them
49-
// from the map
50-
if (!('AnimationEvent' in window)) {
51-
delete EVENT_NAME_MAP.animationend.animation;
52-
}
21+
var animEnd = getVendorPrefixedEventName('animationend');
22+
var transEnd = getVendorPrefixedEventName('transitionend');
5323

54-
if (!('TransitionEvent' in window)) {
55-
delete EVENT_NAME_MAP.transitionend.transition;
24+
if (animEnd) {
25+
endEvents.push(animEnd);
5626
}
5727

58-
for (var baseEventName in EVENT_NAME_MAP) {
59-
var baseEvents = EVENT_NAME_MAP[baseEventName];
60-
for (var styleName in baseEvents) {
61-
if (styleName in style) {
62-
endEvents.push(baseEvents[styleName]);
63-
break;
64-
}
65-
}
28+
if (transEnd) {
29+
endEvents.push(transEnd);
6630
}
6731
}
6832

src/renderers/dom/client/ReactBrowserEventEmitter.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ var ReactEventEmitterMixin = require('ReactEventEmitterMixin');
1717
var ViewportMetrics = require('ViewportMetrics');
1818

1919
var assign = require('Object.assign');
20+
var getVendorPrefixedEventName = require('getVendorPrefixedEventName');
2021
var isEventSupported = require('isEventSupported');
2122

2223
/**
@@ -84,6 +85,9 @@ var reactTopListenersCounter = 0;
8485
// events so we don't include them here
8586
var topEventMapping = {
8687
topAbort: 'abort',
88+
topAnimationEnd: getVendorPrefixedEventName('animationend') || 'animationend',
89+
topAnimationIteration: getVendorPrefixedEventName('animationiteration') || 'animationiteration',
90+
topAnimationStart: getVendorPrefixedEventName('animationstart') || 'animationstart',
8791
topBlur: 'blur',
8892
topCanPlay: 'canplay',
8993
topCanPlayThrough: 'canplaythrough',
@@ -140,6 +144,7 @@ var topEventMapping = {
140144
topTouchEnd: 'touchend',
141145
topTouchMove: 'touchmove',
142146
topTouchStart: 'touchstart',
147+
topTransitionEnd: getVendorPrefixedEventName('transitionend') || 'transitionend',
143148
topVolumeChange: 'volumechange',
144149
topWaiting: 'waiting',
145150
topWheel: 'wheel',

src/renderers/dom/client/eventPlugins/SimpleEventPlugin.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@ var EventConstants = require('EventConstants');
1515
var EventListener = require('EventListener');
1616
var EventPropagators = require('EventPropagators');
1717
var ReactDOMComponentTree = require('ReactDOMComponentTree');
18+
var SyntheticAnimationEvent = require('SyntheticAnimationEvent');
1819
var SyntheticClipboardEvent = require('SyntheticClipboardEvent');
1920
var SyntheticEvent = require('SyntheticEvent');
2021
var SyntheticFocusEvent = require('SyntheticFocusEvent');
2122
var SyntheticKeyboardEvent = require('SyntheticKeyboardEvent');
2223
var SyntheticMouseEvent = require('SyntheticMouseEvent');
2324
var SyntheticDragEvent = require('SyntheticDragEvent');
2425
var SyntheticTouchEvent = require('SyntheticTouchEvent');
26+
var SyntheticTransitionEvent = require('SyntheticTransitionEvent');
2527
var SyntheticUIEvent = require('SyntheticUIEvent');
2628
var SyntheticWheelEvent = require('SyntheticWheelEvent');
2729

@@ -39,6 +41,24 @@ var eventTypes = {
3941
captured: keyOf({onAbortCapture: true}),
4042
},
4143
},
44+
animationEnd: {
45+
phasedRegistrationNames: {
46+
bubbled: keyOf({onAnimationEnd: true}),
47+
captured: keyOf({onAnimationEndCapture: true}),
48+
},
49+
},
50+
animationIteration: {
51+
phasedRegistrationNames: {
52+
bubbled: keyOf({onAnimationIteration: true}),
53+
captured: keyOf({onAnimationIterationCapture: true}),
54+
},
55+
},
56+
animationStart: {
57+
phasedRegistrationNames: {
58+
bubbled: keyOf({onAnimationStart: true}),
59+
captured: keyOf({onAnimationStartCapture: true}),
60+
},
61+
},
4262
blur: {
4363
phasedRegistrationNames: {
4464
bubbled: keyOf({onBlur: true}),
@@ -365,6 +385,12 @@ var eventTypes = {
365385
captured: keyOf({onTouchStartCapture: true}),
366386
},
367387
},
388+
transitionEnd: {
389+
phasedRegistrationNames: {
390+
bubbled: keyOf({onTransitionEnd: true}),
391+
captured: keyOf({onTransitionEndCapture: true}),
392+
},
393+
},
368394
volumeChange: {
369395
phasedRegistrationNames: {
370396
bubbled: keyOf({onVolumeChange: true}),
@@ -387,6 +413,9 @@ var eventTypes = {
387413

388414
var topLevelEventsToDispatchConfig = {
389415
topAbort: eventTypes.abort,
416+
topAnimationEnd: eventTypes.animationEnd,
417+
topAnimationIteration: eventTypes.animationIteration,
418+
topAnimationStart: eventTypes.animationStart,
390419
topBlur: eventTypes.blur,
391420
topCanPlay: eventTypes.canPlay,
392421
topCanPlayThrough: eventTypes.canPlayThrough,
@@ -441,6 +470,7 @@ var topLevelEventsToDispatchConfig = {
441470
topTouchEnd: eventTypes.touchEnd,
442471
topTouchMove: eventTypes.touchMove,
443472
topTouchStart: eventTypes.touchStart,
473+
topTransitionEnd: eventTypes.transitionEnd,
444474
topVolumeChange: eventTypes.volumeChange,
445475
topWaiting: eventTypes.waiting,
446476
topWheel: eventTypes.wheel,
@@ -549,6 +579,14 @@ var SimpleEventPlugin = {
549579
case topLevelTypes.topTouchStart:
550580
EventConstructor = SyntheticTouchEvent;
551581
break;
582+
case topLevelTypes.topAnimationEnd:
583+
case topLevelTypes.topAnimationIteration:
584+
case topLevelTypes.topAnimationStart:
585+
EventConstructor = SyntheticAnimationEvent;
586+
break;
587+
case topLevelTypes.topTransitionEnd:
588+
EventConstructor = SyntheticTransitionEvent;
589+
break;
552590
case topLevelTypes.topScroll:
553591
EventConstructor = SyntheticUIEvent;
554592
break;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* Copyright 2013-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
* @providesModule SyntheticAnimationEvent
10+
*/
11+
12+
'use strict';
13+
14+
var SyntheticEvent = require('SyntheticEvent');
15+
16+
/**
17+
* @interface Event
18+
* @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface
19+
* @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent
20+
*/
21+
var AnimationEventInterface = {
22+
animationName: null,
23+
elapsedTime: null,
24+
pseudoElement: null,
25+
};
26+
27+
/**
28+
* @param {object} dispatchConfig Configuration used to dispatch this event.
29+
* @param {string} dispatchMarker Marker identifying the event target.
30+
* @param {object} nativeEvent Native browser event.
31+
* @extends {SyntheticEvent}
32+
*/
33+
function SyntheticAnimationEvent(
34+
dispatchConfig,
35+
dispatchMarker,
36+
nativeEvent,
37+
nativeEventTarget
38+
) {
39+
return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
40+
}
41+
42+
SyntheticEvent.augmentClass(
43+
SyntheticAnimationEvent,
44+
AnimationEventInterface
45+
);
46+
47+
module.exports = SyntheticAnimationEvent;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* Copyright 2013-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
* @providesModule SyntheticTransitionEvent
10+
*/
11+
12+
'use strict';
13+
14+
var SyntheticEvent = require('SyntheticEvent');
15+
16+
/**
17+
* @interface Event
18+
* @see http://www.w3.org/TR/2009/WD-css3-transitions-20090320/#transition-events-
19+
* @see https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent
20+
*/
21+
var TransitionEventInterface = {
22+
propertyName: null,
23+
elapsedTime: null,
24+
pseudoElement: null,
25+
};
26+
27+
/**
28+
* @param {object} dispatchConfig Configuration used to dispatch this event.
29+
* @param {string} dispatchMarker Marker identifying the event target.
30+
* @param {object} nativeEvent Native browser event.
31+
* @extends {SyntheticEvent}
32+
*/
33+
function SyntheticTransitionEvent(
34+
dispatchConfig,
35+
dispatchMarker,
36+
nativeEvent,
37+
nativeEventTarget
38+
) {
39+
return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
40+
}
41+
42+
SyntheticEvent.augmentClass(
43+
SyntheticTransitionEvent,
44+
TransitionEventInterface
45+
);
46+
47+
module.exports = SyntheticTransitionEvent;

0 commit comments

Comments
 (0)