mirror of
https://github.com/hanzoai/react.git
synced 2026-09-24 17:02:27 +00:00
Added support for synthetic animation/transition events.
This commit is contained in:
@@ -139,6 +139,7 @@ DOMEventTarget relatedTarget
|
||||
|
||||
These focus events work on all elements in the React DOM, not just form elements.
|
||||
|
||||
|
||||
### Form Events
|
||||
|
||||
Event names:
|
||||
@@ -246,6 +247,7 @@ number deltaY
|
||||
number deltaZ
|
||||
```
|
||||
|
||||
|
||||
### Media Events
|
||||
|
||||
Event names:
|
||||
@@ -254,6 +256,7 @@ Event names:
|
||||
onAbort onCanPlay onCanPlayThrough onDurationChange onEmptied onEncrypted onEnded onError onLoadedData onLoadedMetadata onLoadStart onPause onPlay onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting
|
||||
```
|
||||
|
||||
|
||||
### Image Events
|
||||
|
||||
Event names:
|
||||
@@ -261,3 +264,37 @@ Event names:
|
||||
```
|
||||
onLoad onError
|
||||
```
|
||||
|
||||
|
||||
### Animation Events
|
||||
|
||||
Event names:
|
||||
|
||||
```
|
||||
onAnimationStart onAnimationEnd onAnimationIteration
|
||||
```
|
||||
|
||||
Properties:
|
||||
|
||||
```javascript
|
||||
string animationName
|
||||
string pseudoElement
|
||||
float elapsedTime
|
||||
```
|
||||
|
||||
|
||||
### Transition Events
|
||||
|
||||
Event names:
|
||||
|
||||
```
|
||||
onTransitionEnd
|
||||
```
|
||||
|
||||
Properties:
|
||||
|
||||
```javascript
|
||||
string propertyName
|
||||
string pseudoElement
|
||||
float elapsedTime
|
||||
```
|
||||
|
||||
@@ -13,56 +13,20 @@
|
||||
|
||||
var ExecutionEnvironment = require('ExecutionEnvironment');
|
||||
|
||||
/**
|
||||
* EVENT_NAME_MAP is used to determine which event fired when a
|
||||
* transition/animation ends, based on the style property used to
|
||||
* define that event.
|
||||
*/
|
||||
var EVENT_NAME_MAP = {
|
||||
transitionend: {
|
||||
'transition': 'transitionend',
|
||||
'WebkitTransition': 'webkitTransitionEnd',
|
||||
'MozTransition': 'mozTransitionEnd',
|
||||
'OTransition': 'oTransitionEnd',
|
||||
'msTransition': 'MSTransitionEnd',
|
||||
},
|
||||
|
||||
animationend: {
|
||||
'animation': 'animationend',
|
||||
'WebkitAnimation': 'webkitAnimationEnd',
|
||||
'MozAnimation': 'mozAnimationEnd',
|
||||
'OAnimation': 'oAnimationEnd',
|
||||
'msAnimation': 'MSAnimationEnd',
|
||||
},
|
||||
};
|
||||
var getVendorPrefixedEventName = require('getVendorPrefixedEventName');
|
||||
|
||||
var endEvents = [];
|
||||
|
||||
function detectEvents() {
|
||||
var testEl = document.createElement('div');
|
||||
var style = testEl.style;
|
||||
var animEnd = getVendorPrefixedEventName('animationend');
|
||||
var transEnd = getVendorPrefixedEventName('transitionend');
|
||||
|
||||
// On some platforms, in particular some releases of Android 4.x,
|
||||
// the un-prefixed "animation" and "transition" properties are defined on the
|
||||
// style object but the events that fire will still be prefixed, so we need
|
||||
// to check if the un-prefixed events are useable, and if not remove them
|
||||
// from the map
|
||||
if (!('AnimationEvent' in window)) {
|
||||
delete EVENT_NAME_MAP.animationend.animation;
|
||||
if (animEnd) {
|
||||
endEvents.push(animEnd);
|
||||
}
|
||||
|
||||
if (!('TransitionEvent' in window)) {
|
||||
delete EVENT_NAME_MAP.transitionend.transition;
|
||||
}
|
||||
|
||||
for (var baseEventName in EVENT_NAME_MAP) {
|
||||
var baseEvents = EVENT_NAME_MAP[baseEventName];
|
||||
for (var styleName in baseEvents) {
|
||||
if (styleName in style) {
|
||||
endEvents.push(baseEvents[styleName]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (transEnd) {
|
||||
endEvents.push(transEnd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ var ReactEventEmitterMixin = require('ReactEventEmitterMixin');
|
||||
var ViewportMetrics = require('ViewportMetrics');
|
||||
|
||||
var assign = require('Object.assign');
|
||||
var getVendorPrefixedEventName = require('getVendorPrefixedEventName');
|
||||
var isEventSupported = require('isEventSupported');
|
||||
|
||||
/**
|
||||
@@ -83,6 +84,9 @@ var reactTopListenersCounter = 0;
|
||||
// events so we don't include them here
|
||||
var topEventMapping = {
|
||||
topAbort: 'abort',
|
||||
topAnimationEnd: getVendorPrefixedEventName('animationend') || 'animationend',
|
||||
topAnimationIteration: getVendorPrefixedEventName('animationiteration') || 'animationiteration',
|
||||
topAnimationStart: getVendorPrefixedEventName('animationstart') || 'animationstart',
|
||||
topBlur: 'blur',
|
||||
topCanPlay: 'canplay',
|
||||
topCanPlayThrough: 'canplaythrough',
|
||||
@@ -139,6 +143,7 @@ var topEventMapping = {
|
||||
topTouchEnd: 'touchend',
|
||||
topTouchMove: 'touchmove',
|
||||
topTouchStart: 'touchstart',
|
||||
topTransitionEnd: getVendorPrefixedEventName('transitionend') || 'transitionend',
|
||||
topVolumeChange: 'volumechange',
|
||||
topWaiting: 'waiting',
|
||||
topWheel: 'wheel',
|
||||
|
||||
@@ -15,6 +15,7 @@ var EventConstants = require('EventConstants');
|
||||
var EventListener = require('EventListener');
|
||||
var EventPropagators = require('EventPropagators');
|
||||
var ReactDOMComponentTree = require('ReactDOMComponentTree');
|
||||
var SyntheticAnimationEvent = require('SyntheticAnimationEvent');
|
||||
var SyntheticClipboardEvent = require('SyntheticClipboardEvent');
|
||||
var SyntheticEvent = require('SyntheticEvent');
|
||||
var SyntheticFocusEvent = require('SyntheticFocusEvent');
|
||||
@@ -22,6 +23,7 @@ var SyntheticKeyboardEvent = require('SyntheticKeyboardEvent');
|
||||
var SyntheticMouseEvent = require('SyntheticMouseEvent');
|
||||
var SyntheticDragEvent = require('SyntheticDragEvent');
|
||||
var SyntheticTouchEvent = require('SyntheticTouchEvent');
|
||||
var SyntheticTransitionEvent = require('SyntheticTransitionEvent');
|
||||
var SyntheticUIEvent = require('SyntheticUIEvent');
|
||||
var SyntheticWheelEvent = require('SyntheticWheelEvent');
|
||||
|
||||
@@ -39,6 +41,24 @@ var eventTypes = {
|
||||
captured: keyOf({onAbortCapture: true}),
|
||||
},
|
||||
},
|
||||
animationEnd: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onAnimationEnd: true}),
|
||||
captured: keyOf({onAnimationEndCapture: true}),
|
||||
},
|
||||
},
|
||||
animationIteration: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onAnimationIteration: true}),
|
||||
captured: keyOf({onAnimationIterationCapture: true}),
|
||||
},
|
||||
},
|
||||
animationStart: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onAnimationStart: true}),
|
||||
captured: keyOf({onAnimationStartCapture: true}),
|
||||
},
|
||||
},
|
||||
blur: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onBlur: true}),
|
||||
@@ -365,6 +385,12 @@ var eventTypes = {
|
||||
captured: keyOf({onTouchStartCapture: true}),
|
||||
},
|
||||
},
|
||||
transitionEnd: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onTransitionEnd: true}),
|
||||
captured: keyOf({onTransitionEndCapture: true}),
|
||||
},
|
||||
},
|
||||
volumeChange: {
|
||||
phasedRegistrationNames: {
|
||||
bubbled: keyOf({onVolumeChange: true}),
|
||||
@@ -387,6 +413,9 @@ var eventTypes = {
|
||||
|
||||
var topLevelEventsToDispatchConfig = {
|
||||
topAbort: eventTypes.abort,
|
||||
topAnimationEnd: eventTypes.animationEnd,
|
||||
topAnimationIteration: eventTypes.animationIteration,
|
||||
topAnimationStart: eventTypes.animationStart,
|
||||
topBlur: eventTypes.blur,
|
||||
topCanPlay: eventTypes.canPlay,
|
||||
topCanPlayThrough: eventTypes.canPlayThrough,
|
||||
@@ -441,6 +470,7 @@ var topLevelEventsToDispatchConfig = {
|
||||
topTouchEnd: eventTypes.touchEnd,
|
||||
topTouchMove: eventTypes.touchMove,
|
||||
topTouchStart: eventTypes.touchStart,
|
||||
topTransitionEnd: eventTypes.transitionEnd,
|
||||
topVolumeChange: eventTypes.volumeChange,
|
||||
topWaiting: eventTypes.waiting,
|
||||
topWheel: eventTypes.wheel,
|
||||
@@ -549,6 +579,14 @@ var SimpleEventPlugin = {
|
||||
case topLevelTypes.topTouchStart:
|
||||
EventConstructor = SyntheticTouchEvent;
|
||||
break;
|
||||
case topLevelTypes.topAnimationEnd:
|
||||
case topLevelTypes.topAnimationIteration:
|
||||
case topLevelTypes.topAnimationStart:
|
||||
EventConstructor = SyntheticAnimationEvent;
|
||||
break;
|
||||
case topLevelTypes.topTransitionEnd:
|
||||
EventConstructor = SyntheticTransitionEvent;
|
||||
break;
|
||||
case topLevelTypes.topScroll:
|
||||
EventConstructor = SyntheticUIEvent;
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule SyntheticAnimationEvent
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var SyntheticEvent = require('SyntheticEvent');
|
||||
|
||||
/**
|
||||
* @interface Event
|
||||
* @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent
|
||||
*/
|
||||
var AnimationEventInterface = {
|
||||
animationName: null,
|
||||
elapsedTime: null,
|
||||
pseudoElement: null,
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {object} dispatchConfig Configuration used to dispatch this event.
|
||||
* @param {string} dispatchMarker Marker identifying the event target.
|
||||
* @param {object} nativeEvent Native browser event.
|
||||
* @extends {SyntheticEvent}
|
||||
*/
|
||||
function SyntheticAnimationEvent(
|
||||
dispatchConfig,
|
||||
dispatchMarker,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
) {
|
||||
return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
}
|
||||
|
||||
SyntheticEvent.augmentClass(
|
||||
SyntheticAnimationEvent,
|
||||
AnimationEventInterface
|
||||
);
|
||||
|
||||
module.exports = SyntheticAnimationEvent;
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule SyntheticTransitionEvent
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var SyntheticEvent = require('SyntheticEvent');
|
||||
|
||||
/**
|
||||
* @interface Event
|
||||
* @see http://www.w3.org/TR/2009/WD-css3-transitions-20090320/#transition-events-
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent
|
||||
*/
|
||||
var TransitionEventInterface = {
|
||||
propertyName: null,
|
||||
elapsedTime: null,
|
||||
pseudoElement: null,
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {object} dispatchConfig Configuration used to dispatch this event.
|
||||
* @param {string} dispatchMarker Marker identifying the event target.
|
||||
* @param {object} nativeEvent Native browser event.
|
||||
* @extends {SyntheticEvent}
|
||||
*/
|
||||
function SyntheticTransitionEvent(
|
||||
dispatchConfig,
|
||||
dispatchMarker,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
) {
|
||||
return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
|
||||
}
|
||||
|
||||
SyntheticEvent.augmentClass(
|
||||
SyntheticTransitionEvent,
|
||||
TransitionEventInterface
|
||||
);
|
||||
|
||||
module.exports = SyntheticTransitionEvent;
|
||||
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule getVendorPrefixedEventName
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var ExecutionEnvironment = require('ExecutionEnvironment');
|
||||
|
||||
/**
|
||||
* Generate a mapping of standard vendor prefixes using the defined style property and event name.
|
||||
*
|
||||
* @param {string} styleProp
|
||||
* @param {string} eventName
|
||||
* @returns {object}
|
||||
*/
|
||||
function makePrefixMap(styleProp, eventName) {
|
||||
var prefixes = {};
|
||||
|
||||
prefixes[styleProp.toLowerCase()] = eventName.toLowerCase();
|
||||
prefixes['Webkit' + styleProp] = 'webkit' + eventName;
|
||||
prefixes['Moz' + styleProp] = 'moz' + eventName;
|
||||
prefixes['ms' + styleProp] = 'MS' + eventName;
|
||||
prefixes['O' + styleProp] = 'o' + eventName.toLowerCase();
|
||||
|
||||
return prefixes;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of event names to a configurable list of vendor prefixes.
|
||||
*/
|
||||
var vendorPrefixes = {
|
||||
animationend: makePrefixMap('Animation', 'AnimationEnd'),
|
||||
animationiteration: makePrefixMap('Animation', 'AnimationIteration'),
|
||||
animationstart: makePrefixMap('Animation', 'AnimationStart'),
|
||||
transitionend: makePrefixMap('Transition', 'TransitionEnd'),
|
||||
};
|
||||
|
||||
/**
|
||||
* Event names that have already been detected and prefixed (if applicable).
|
||||
*/
|
||||
var prefixedEventNames = {};
|
||||
|
||||
/**
|
||||
* Element to check for prefixes on.
|
||||
*/
|
||||
var style = {};
|
||||
|
||||
/**
|
||||
* Bootstrap if a DOM exists.
|
||||
*/
|
||||
if (ExecutionEnvironment.canUseDOM) {
|
||||
style = document.createElement('div').style;
|
||||
|
||||
// On some platforms, in particular some releases of Android 4.x,
|
||||
// the un-prefixed "animation" and "transition" properties are defined on the
|
||||
// style object but the events that fire will still be prefixed, so we need
|
||||
// to check if the un-prefixed events are usable, and if not remove them from the map.
|
||||
if (!('AnimationEvent' in window)) {
|
||||
delete vendorPrefixes.animationend.animation;
|
||||
delete vendorPrefixes.animationiteration.animation;
|
||||
delete vendorPrefixes.animationstart.animation;
|
||||
}
|
||||
|
||||
// Same as above
|
||||
if (!('TransitionEvent' in window)) {
|
||||
delete vendorPrefixes.transitionend.transition;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to determine the correct vendor prefixed event name.
|
||||
*
|
||||
* @param {string} eventName
|
||||
* @returns {string}
|
||||
*/
|
||||
function getVendorPrefixedEventName(eventName) {
|
||||
if (prefixedEventNames[eventName]) {
|
||||
return prefixedEventNames[eventName];
|
||||
|
||||
} else if (!vendorPrefixes[eventName]) {
|
||||
return eventName;
|
||||
}
|
||||
|
||||
var prefixMap = vendorPrefixes[eventName];
|
||||
|
||||
for (var styleProp in prefixMap) {
|
||||
if (prefixMap.hasOwnProperty(styleProp) && styleProp in style) {
|
||||
return prefixedEventNames[eventName] = prefixMap[styleProp];
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
module.exports = getVendorPrefixedEventName;
|
||||
@@ -20,6 +20,9 @@ var PropagationPhases = keyMirror({bubbled: null, captured: null});
|
||||
*/
|
||||
var topLevelTypes = keyMirror({
|
||||
topAbort: null,
|
||||
topAnimationEnd: null,
|
||||
topAnimationIteration: null,
|
||||
topAnimationStart: null,
|
||||
topBlur: null,
|
||||
topCanPlay: null,
|
||||
topCanPlayThrough: null,
|
||||
@@ -80,6 +83,7 @@ var topLevelTypes = keyMirror({
|
||||
topTouchEnd: null,
|
||||
topTouchMove: null,
|
||||
topTouchStart: null,
|
||||
topTransitionEnd: null,
|
||||
topVolumeChange: null,
|
||||
topWaiting: null,
|
||||
topWheel: null,
|
||||
|
||||
Reference in New Issue
Block a user