react 0.10.0 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +3 -0
  2. package/dist/JSXTransformer.js +20344 -0
  3. package/dist/react-with-addons.js +20276 -0
  4. package/dist/react-with-addons.min.js +22 -0
  5. package/dist/react.js +18484 -0
  6. package/dist/react.min.js +21 -0
  7. package/lib/BeforeInputEventPlugin.js +222 -0
  8. package/lib/CSSPropertyOperations.js +3 -3
  9. package/lib/{ReactMountReady.js → CallbackQueue.js} +32 -24
  10. package/lib/ChangeEventPlugin.js +1 -1
  11. package/lib/CompositionEventPlugin.js +5 -1
  12. package/lib/DOMChildrenOperations.js +21 -14
  13. package/lib/DOMProperty.js +45 -17
  14. package/lib/DOMPropertyOperations.js +22 -10
  15. package/lib/DefaultEventPluginOrder.js +1 -0
  16. package/lib/EventConstants.js +1 -0
  17. package/lib/EventListener.js +5 -2
  18. package/lib/EventPluginHub.js +0 -5
  19. package/lib/EventPluginRegistry.js +6 -4
  20. package/lib/EventPluginUtils.js +11 -1
  21. package/lib/ExecutionEnvironment.js +8 -2
  22. package/lib/{DefaultDOMPropertyConfig.js → HTMLDOMPropertyConfig.js} +42 -49
  23. package/lib/LinkedValueUtils.js +21 -22
  24. package/lib/LocalEventTrapMixin.js +52 -0
  25. package/lib/React.js +57 -3
  26. package/lib/ReactBrowserComponentMixin.js +4 -0
  27. package/lib/{ReactEventEmitter.js → ReactBrowserEventEmitter.js} +115 -94
  28. package/lib/ReactCSSTransitionGroup.js +2 -0
  29. package/lib/ReactCSSTransitionGroupChild.js +2 -5
  30. package/lib/ReactChildren.js +31 -10
  31. package/lib/ReactComponent.js +88 -237
  32. package/lib/ReactComponentBrowserEnvironment.js +3 -2
  33. package/lib/ReactComponentWithPureRenderMixin.js +54 -0
  34. package/lib/ReactCompositeComponent.js +222 -384
  35. package/lib/ReactDOM.js +22 -18
  36. package/lib/ReactDOMComponent.js +26 -24
  37. package/lib/ReactDOMForm.js +5 -13
  38. package/lib/ReactDOMIDOperations.js +2 -31
  39. package/lib/ReactDOMImg.js +5 -14
  40. package/lib/ReactDOMSelect.js +16 -15
  41. package/lib/ReactDOMSelection.js +35 -10
  42. package/lib/ReactDOMTextarea.js +2 -4
  43. package/lib/ReactDefaultBatchingStrategy.js +3 -3
  44. package/lib/ReactDefaultInjection.js +18 -15
  45. package/lib/ReactDefaultPerf.js +28 -11
  46. package/lib/ReactDefaultPerfAnalysis.js +4 -0
  47. package/lib/ReactDescriptor.js +251 -0
  48. package/lib/ReactDescriptorValidator.js +283 -0
  49. package/lib/ReactEmptyComponent.js +78 -0
  50. package/lib/ReactEventEmitterMixin.js +1 -3
  51. package/lib/ReactEventListener.js +189 -0
  52. package/lib/ReactInjection.js +4 -2
  53. package/lib/ReactLink.js +24 -0
  54. package/lib/ReactMount.js +51 -19
  55. package/lib/ReactMultiChild.js +9 -11
  56. package/lib/ReactPropTransferer.js +44 -29
  57. package/lib/ReactPropTypes.js +226 -242
  58. package/lib/ReactPutListenerQueue.js +2 -2
  59. package/lib/ReactReconcileTransaction.js +14 -14
  60. package/lib/ReactServerRendering.js +5 -5
  61. package/lib/ReactServerRenderingTransaction.js +4 -5
  62. package/lib/ReactTestUtils.js +39 -21
  63. package/lib/ReactTextComponent.js +8 -22
  64. package/lib/ReactTransitionChildMapping.js +2 -2
  65. package/lib/ReactTransitionEvents.js +19 -0
  66. package/lib/ReactTransitionGroup.js +9 -6
  67. package/lib/ReactUpdates.js +139 -22
  68. package/lib/ReactWithAddons.js +5 -2
  69. package/lib/SVGDOMPropertyConfig.js +97 -0
  70. package/lib/SimpleEventPlugin.js +7 -1
  71. package/lib/SyntheticInputEvent.js +52 -0
  72. package/lib/SyntheticKeyboardEvent.js +33 -4
  73. package/lib/SyntheticMouseEvent.js +3 -0
  74. package/lib/SyntheticTouchEvent.js +4 -1
  75. package/lib/SyntheticUIEvent.js +24 -2
  76. package/lib/Transaction.js +0 -32
  77. package/lib/cloneWithProps.js +3 -1
  78. package/lib/createFullPageComponent.js +1 -1
  79. package/lib/dangerousStyleValue.js +11 -5
  80. package/lib/escapeTextForBrowser.js +2 -3
  81. package/lib/flattenChildren.js +9 -7
  82. package/lib/getEventKey.js +35 -5
  83. package/lib/getEventModifierState.js +52 -0
  84. package/lib/getMarkupWrap.js +2 -0
  85. package/lib/getTextContentAccessor.js +1 -1
  86. package/lib/hyphenate.js +3 -0
  87. package/lib/hyphenateStyleName.js +46 -0
  88. package/lib/instantiateReactComponent.js +13 -21
  89. package/lib/invariant.js +17 -19
  90. package/lib/{objMap.js → mapObject.js} +8 -3
  91. package/lib/mergeHelpers.js +11 -0
  92. package/lib/mergeInto.js +3 -2
  93. package/lib/onlyChild.js +3 -3
  94. package/lib/performance.js +33 -0
  95. package/lib/performanceNow.js +5 -14
  96. package/lib/setInnerHTML.js +85 -0
  97. package/lib/shouldUpdateReactComponent.js +12 -29
  98. package/lib/toArray.js +1 -1
  99. package/lib/traverseAllChildren.js +7 -4
  100. package/lib/update.js +57 -45
  101. package/package.json +4 -3
  102. package/lib/ReactEventTopLevelCallback.js +0 -149
  103. package/lib/createObjectFrom.js +0 -61
  104. package/lib/objMapKeyVal.js +0 -47
@@ -19,7 +19,7 @@
19
19
  "use strict";
20
20
 
21
21
  var PooledClass = require("./PooledClass");
22
- var ReactEventEmitter = require("./ReactEventEmitter");
22
+ var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
23
23
 
24
24
  var mixInto = require("./mixInto");
25
25
 
@@ -39,7 +39,7 @@ mixInto(ReactPutListenerQueue, {
39
39
  putListeners: function() {
40
40
  for (var i = 0; i < this.listenersToPut.length; i++) {
41
41
  var listenerToPut = this.listenersToPut[i];
42
- ReactEventEmitter.putListener(
42
+ ReactBrowserEventEmitter.putListener(
43
43
  listenerToPut.rootNodeID,
44
44
  listenerToPut.propKey,
45
45
  listenerToPut.propValue
@@ -19,10 +19,10 @@
19
19
 
20
20
  "use strict";
21
21
 
22
+ var CallbackQueue = require("./CallbackQueue");
22
23
  var PooledClass = require("./PooledClass");
23
- var ReactEventEmitter = require("./ReactEventEmitter");
24
+ var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
24
25
  var ReactInputSelection = require("./ReactInputSelection");
25
- var ReactMountReady = require("./ReactMountReady");
26
26
  var ReactPutListenerQueue = require("./ReactPutListenerQueue");
27
27
  var Transaction = require("./Transaction");
28
28
 
@@ -50,27 +50,28 @@ var SELECTION_RESTORATION = {
50
50
  */
51
51
  var EVENT_SUPPRESSION = {
52
52
  /**
53
- * @return {boolean} The enabled status of `ReactEventEmitter` before the
54
- * reconciliation.
53
+ * @return {boolean} The enabled status of `ReactBrowserEventEmitter` before
54
+ * the reconciliation.
55
55
  */
56
56
  initialize: function() {
57
- var currentlyEnabled = ReactEventEmitter.isEnabled();
58
- ReactEventEmitter.setEnabled(false);
57
+ var currentlyEnabled = ReactBrowserEventEmitter.isEnabled();
58
+ ReactBrowserEventEmitter.setEnabled(false);
59
59
  return currentlyEnabled;
60
60
  },
61
61
 
62
62
  /**
63
- * @param {boolean} previouslyEnabled Enabled status of `ReactEventEmitter`
64
- * before the reconciliation occured. `close` restores the previous value.
63
+ * @param {boolean} previouslyEnabled Enabled status of
64
+ * `ReactBrowserEventEmitter` before the reconciliation occured. `close`
65
+ * restores the previous value.
65
66
  */
66
67
  close: function(previouslyEnabled) {
67
- ReactEventEmitter.setEnabled(previouslyEnabled);
68
+ ReactBrowserEventEmitter.setEnabled(previouslyEnabled);
68
69
  }
69
70
  };
70
71
 
71
72
  /**
72
- * Provides a `ReactMountReady` queue for collecting `onDOMReady` callbacks
73
- * during the performing of the transaction.
73
+ * Provides a queue for collecting `componentDidMount` and
74
+ * `componentDidUpdate` callbacks during the the transaction.
74
75
  */
75
76
  var ON_DOM_READY_QUEUEING = {
76
77
  /**
@@ -132,7 +133,7 @@ function ReactReconcileTransaction() {
132
133
  // accessible and defaults to false when `ReactDOMComponent` and
133
134
  // `ReactTextComponent` checks it in `mountComponent`.`
134
135
  this.renderToStaticMarkup = false;
135
- this.reactMountReady = ReactMountReady.getPooled(null);
136
+ this.reactMountReady = CallbackQueue.getPooled(null);
136
137
  this.putListenerQueue = ReactPutListenerQueue.getPooled();
137
138
  }
138
139
 
@@ -150,7 +151,6 @@ var Mixin = {
150
151
 
151
152
  /**
152
153
  * @return {object} The queue to collect `onDOMReady` callbacks with.
153
- * TODO: convert to ReactMountReady
154
154
  */
155
155
  getReactMountReady: function() {
156
156
  return this.reactMountReady;
@@ -165,7 +165,7 @@ var Mixin = {
165
165
  * instance to be resused.
166
166
  */
167
167
  destructor: function() {
168
- ReactMountReady.release(this.reactMountReady);
168
+ CallbackQueue.release(this.reactMountReady);
169
169
  this.reactMountReady = null;
170
170
 
171
171
  ReactPutListenerQueue.release(this.putListenerQueue);
@@ -18,7 +18,7 @@
18
18
  */
19
19
  "use strict";
20
20
 
21
- var ReactComponent = require("./ReactComponent");
21
+ var ReactDescriptor = require("./ReactDescriptor");
22
22
  var ReactInstanceHandles = require("./ReactInstanceHandles");
23
23
  var ReactMarkupChecksum = require("./ReactMarkupChecksum");
24
24
  var ReactServerRenderingTransaction =
@@ -33,9 +33,9 @@ var invariant = require("./invariant");
33
33
  */
34
34
  function renderComponentToString(component) {
35
35
  ("production" !== process.env.NODE_ENV ? invariant(
36
- ReactComponent.isValidComponent(component),
36
+ ReactDescriptor.isValidDescriptor(component),
37
37
  'renderComponentToString(): You must pass a valid ReactComponent.'
38
- ) : invariant(ReactComponent.isValidComponent(component)));
38
+ ) : invariant(ReactDescriptor.isValidDescriptor(component)));
39
39
 
40
40
  ("production" !== process.env.NODE_ENV ? invariant(
41
41
  !(arguments.length === 2 && typeof arguments[1] === 'function'),
@@ -65,9 +65,9 @@ function renderComponentToString(component) {
65
65
  */
66
66
  function renderComponentToStaticMarkup(component) {
67
67
  ("production" !== process.env.NODE_ENV ? invariant(
68
- ReactComponent.isValidComponent(component),
68
+ ReactDescriptor.isValidDescriptor(component),
69
69
  'renderComponentToStaticMarkup(): You must pass a valid ReactComponent.'
70
- ) : invariant(ReactComponent.isValidComponent(component)));
70
+ ) : invariant(ReactDescriptor.isValidDescriptor(component)));
71
71
 
72
72
  var transaction;
73
73
  try {
@@ -20,7 +20,7 @@
20
20
  "use strict";
21
21
 
22
22
  var PooledClass = require("./PooledClass");
23
- var ReactMountReady = require("./ReactMountReady");
23
+ var CallbackQueue = require("./CallbackQueue");
24
24
  var ReactPutListenerQueue = require("./ReactPutListenerQueue");
25
25
  var Transaction = require("./Transaction");
26
26
 
@@ -28,7 +28,7 @@ var emptyFunction = require("./emptyFunction");
28
28
  var mixInto = require("./mixInto");
29
29
 
30
30
  /**
31
- * Provides a `ReactMountReady` queue for collecting `onDOMReady` callbacks
31
+ * Provides a `CallbackQueue` queue for collecting `onDOMReady` callbacks
32
32
  * during the performing of the transaction.
33
33
  */
34
34
  var ON_DOM_READY_QUEUEING = {
@@ -67,7 +67,7 @@ var TRANSACTION_WRAPPERS = [
67
67
  function ReactServerRenderingTransaction(renderToStaticMarkup) {
68
68
  this.reinitializeTransaction();
69
69
  this.renderToStaticMarkup = renderToStaticMarkup;
70
- this.reactMountReady = ReactMountReady.getPooled(null);
70
+ this.reactMountReady = CallbackQueue.getPooled(null);
71
71
  this.putListenerQueue = ReactPutListenerQueue.getPooled();
72
72
  }
73
73
 
@@ -84,7 +84,6 @@ var Mixin = {
84
84
 
85
85
  /**
86
86
  * @return {object} The queue to collect `onDOMReady` callbacks with.
87
- * TODO: convert to ReactMountReady
88
87
  */
89
88
  getReactMountReady: function() {
90
89
  return this.reactMountReady;
@@ -99,7 +98,7 @@ var Mixin = {
99
98
  * instance to be resused.
100
99
  */
101
100
  destructor: function() {
102
- ReactMountReady.release(this.reactMountReady);
101
+ CallbackQueue.release(this.reactMountReady);
103
102
  this.reactMountReady = null;
104
103
 
105
104
  ReactPutListenerQueue.release(this.putListenerQueue);
@@ -22,9 +22,9 @@ var EventConstants = require("./EventConstants");
22
22
  var EventPluginHub = require("./EventPluginHub");
23
23
  var EventPropagators = require("./EventPropagators");
24
24
  var React = require("./React");
25
- var ReactComponent = require("./ReactComponent");
25
+ var ReactDescriptor = require("./ReactDescriptor");
26
26
  var ReactDOM = require("./ReactDOM");
27
- var ReactEventEmitter = require("./ReactEventEmitter");
27
+ var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
28
28
  var ReactMount = require("./ReactMount");
29
29
  var ReactTextComponent = require("./ReactTextComponent");
30
30
  var ReactUpdates = require("./ReactUpdates");
@@ -57,21 +57,39 @@ var ReactTestUtils = {
57
57
  return React.renderComponent(instance, div);
58
58
  },
59
59
 
60
- isComponentOfType: function(inst, convenienceConstructor) {
60
+ isDescriptor: function(descriptor) {
61
+ return ReactDescriptor.isValidDescriptor(descriptor);
62
+ },
63
+
64
+ isDescriptorOfType: function(inst, convenienceConstructor) {
61
65
  return (
62
- ReactComponent.isValidComponent(inst) &&
66
+ ReactDescriptor.isValidDescriptor(inst) &&
63
67
  inst.type === convenienceConstructor.type
64
68
  );
65
69
  },
66
70
 
67
71
  isDOMComponent: function(inst) {
72
+ return !!(inst && inst.mountComponent && inst.tagName);
73
+ },
74
+
75
+ isDOMComponentDescriptor: function(inst) {
68
76
  return !!(inst &&
69
- ReactComponent.isValidComponent(inst) &&
77
+ ReactDescriptor.isValidDescriptor(inst) &&
70
78
  !!inst.tagName);
71
79
  },
72
80
 
73
81
  isCompositeComponent: function(inst) {
74
- if (!ReactComponent.isValidComponent(inst)) {
82
+ return typeof inst.render === 'function' &&
83
+ typeof inst.setState === 'function';
84
+ },
85
+
86
+ isCompositeComponentWithType: function(inst, type) {
87
+ return !!(ReactTestUtils.isCompositeComponent(inst) &&
88
+ (inst.constructor === type.type));
89
+ },
90
+
91
+ isCompositeComponentDescriptor: function(inst) {
92
+ if (!ReactDescriptor.isValidDescriptor(inst)) {
75
93
  return false;
76
94
  }
77
95
  // We check the prototype of the type that will get mounted, not the
@@ -79,19 +97,17 @@ var ReactTestUtils = {
79
97
  var prototype = inst.type.prototype;
80
98
  return (
81
99
  typeof prototype.render === 'function' &&
82
- typeof prototype.setState === 'function' &&
83
- typeof prototype.updateComponent === 'function'
100
+ typeof prototype.setState === 'function'
84
101
  );
85
102
  },
86
103
 
87
- isCompositeComponentWithType: function(inst, type) {
88
- return !!(ReactTestUtils.isCompositeComponent(inst) &&
89
- (inst.constructor === type.componentConstructor ||
90
- inst.constructor === type));
104
+ isCompositeComponentDescriptorWithType: function(inst, type) {
105
+ return !!(ReactTestUtils.isCompositeComponentDescriptor(inst) &&
106
+ (inst.constructor === type));
91
107
  },
92
108
 
93
109
  isTextComponent: function(inst) {
94
- return inst instanceof ReactTextComponent;
110
+ return inst instanceof ReactTextComponent.type;
95
111
  },
96
112
 
97
113
  findAllInRenderedTree: function(inst, test) {
@@ -182,7 +198,10 @@ var ReactTestUtils = {
182
198
  */
183
199
  scryRenderedComponentsWithType: function(root, componentType) {
184
200
  return ReactTestUtils.findAllInRenderedTree(root, function(inst) {
185
- return ReactTestUtils.isCompositeComponentWithType(inst, componentType);
201
+ return ReactTestUtils.isCompositeComponentWithType(
202
+ inst,
203
+ componentType
204
+ );
186
205
  });
187
206
  },
188
207
 
@@ -240,12 +259,11 @@ var ReactTestUtils = {
240
259
  * @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
241
260
  */
242
261
  simulateNativeEventOnNode: function(topLevelType, node, fakeNativeEvent) {
243
- var virtualHandler =
244
- ReactEventEmitter.TopLevelCallbackCreator.createTopLevelCallback(
245
- topLevelType
246
- );
247
262
  fakeNativeEvent.target = node;
248
- virtualHandler(fakeNativeEvent);
263
+ ReactBrowserEventEmitter.ReactEventListener.dispatchEvent(
264
+ topLevelType,
265
+ fakeNativeEvent
266
+ );
249
267
  },
250
268
 
251
269
  /**
@@ -300,7 +318,7 @@ function makeSimulator(eventType) {
300
318
  // We don't use SyntheticEvent.getPooled in order to not have to worry about
301
319
  // properly destroying any properties assigned from `eventData` upon release
302
320
  var event = new SyntheticEvent(
303
- ReactEventEmitter.eventNameDispatchConfigs[eventType],
321
+ ReactBrowserEventEmitter.eventNameDispatchConfigs[eventType],
304
322
  ReactMount.getID(node),
305
323
  fakeNativeEvent
306
324
  );
@@ -318,7 +336,7 @@ function buildSimulators() {
318
336
  ReactTestUtils.Simulate = {};
319
337
 
320
338
  var eventType;
321
- for (eventType in ReactEventEmitter.eventNameDispatchConfigs) {
339
+ for (eventType in ReactBrowserEventEmitter.eventNameDispatchConfigs) {
322
340
  /**
323
341
  * @param {!Element || ReactDOMComponent} domComponentOrNode
324
342
  * @param {?object} eventData Fake event data to use in SyntheticEvent.
@@ -22,6 +22,7 @@
22
22
  var DOMPropertyOperations = require("./DOMPropertyOperations");
23
23
  var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
24
24
  var ReactComponent = require("./ReactComponent");
25
+ var ReactDescriptor = require("./ReactDescriptor");
25
26
 
26
27
  var escapeTextForBrowser = require("./escapeTextForBrowser");
27
28
  var mixInto = require("./mixInto");
@@ -41,18 +42,8 @@ var mixInto = require("./mixInto");
41
42
  * @extends ReactComponent
42
43
  * @internal
43
44
  */
44
- var ReactTextComponent = function(initialText) {
45
- this.construct({text: initialText});
46
- };
47
-
48
- /**
49
- * Used to clone the text descriptor object before it's mounted.
50
- *
51
- * @param {object} props
52
- * @return {object} A new ReactTextComponent instance
53
- */
54
- ReactTextComponent.ConvenienceConstructor = function(props) {
55
- return new ReactTextComponent(props.text);
45
+ var ReactTextComponent = function(descriptor) {
46
+ this.construct(descriptor);
56
47
  };
57
48
 
58
49
  mixInto(ReactTextComponent, ReactComponent.Mixin);
@@ -77,7 +68,7 @@ mixInto(ReactTextComponent, {
77
68
  mountDepth
78
69
  );
79
70
 
80
- var escapedText = escapeTextForBrowser(this.props.text);
71
+ var escapedText = escapeTextForBrowser(this.props);
81
72
 
82
73
  if (transaction.renderToStaticMarkup) {
83
74
  // Normally we'd wrap this in a `span` for the reasons stated above, but
@@ -102,20 +93,15 @@ mixInto(ReactTextComponent, {
102
93
  */
103
94
  receiveComponent: function(nextComponent, transaction) {
104
95
  var nextProps = nextComponent.props;
105
- if (nextProps.text !== this.props.text) {
106
- this.props.text = nextProps.text;
96
+ if (nextProps !== this.props) {
97
+ this.props = nextProps;
107
98
  ReactComponent.BackendIDOperations.updateTextContentByID(
108
99
  this._rootNodeID,
109
- nextProps.text
100
+ nextProps
110
101
  );
111
102
  }
112
103
  }
113
104
 
114
105
  });
115
106
 
116
- // Expose the constructor on itself and the prototype for consistency with other
117
- // descriptors.
118
- ReactTextComponent.type = ReactTextComponent;
119
- ReactTextComponent.prototype.type = ReactTextComponent;
120
-
121
- module.exports = ReactTextComponent;
107
+ module.exports = ReactDescriptor.createFactory(ReactTextComponent);
@@ -70,7 +70,7 @@ var ReactTransitionChildMapping = {
70
70
 
71
71
  var pendingKeys = [];
72
72
  for (var prevKey in prev) {
73
- if (next[prevKey]) {
73
+ if (next.hasOwnProperty(prevKey)) {
74
74
  if (pendingKeys.length) {
75
75
  nextKeysPending[prevKey] = pendingKeys;
76
76
  pendingKeys = [];
@@ -83,7 +83,7 @@ var ReactTransitionChildMapping = {
83
83
  var i;
84
84
  var childMapping = {};
85
85
  for (var nextKey in next) {
86
- if (nextKeysPending[nextKey]) {
86
+ if (nextKeysPending.hasOwnProperty(nextKey)) {
87
87
  for (i = 0; i < nextKeysPending[nextKey].length; i++) {
88
88
  var pendingNextKey = nextKeysPending[nextKey][i];
89
89
  childMapping[nextKeysPending[nextKey][i]] = getValueForKey(
@@ -20,6 +20,11 @@
20
20
 
21
21
  var ExecutionEnvironment = require("./ExecutionEnvironment");
22
22
 
23
+ /**
24
+ * EVENT_NAME_MAP is used to determine which event fired when a
25
+ * transition/animation ends, based on the style property used to
26
+ * define that event.
27
+ */
23
28
  var EVENT_NAME_MAP = {
24
29
  transitionend: {
25
30
  'transition': 'transitionend',
@@ -43,6 +48,20 @@ var endEvents = [];
43
48
  function detectEvents() {
44
49
  var testEl = document.createElement('div');
45
50
  var style = testEl.style;
51
+
52
+ // On some platforms, in particular some releases of Android 4.x,
53
+ // the un-prefixed "animation" and "transition" properties are defined on the
54
+ // style object but the events that fire will still be prefixed, so we need
55
+ // to check if the un-prefixed events are useable, and if not remove them
56
+ // from the map
57
+ if (!('AnimationEvent' in window)) {
58
+ delete EVENT_NAME_MAP.animationend.animation;
59
+ }
60
+
61
+ if (!('TransitionEvent' in window)) {
62
+ delete EVENT_NAME_MAP.transitionend.transition;
63
+ }
64
+
46
65
  for (var baseEventName in EVENT_NAME_MAP) {
47
66
  var baseEvents = EVENT_NAME_MAP[baseEventName];
48
67
  for (var styleName in baseEvents) {
@@ -26,6 +26,7 @@ var emptyFunction = require("./emptyFunction");
26
26
  var merge = require("./merge");
27
27
 
28
28
  var ReactTransitionGroup = React.createClass({
29
+ displayName: 'ReactTransitionGroup',
29
30
 
30
31
  propTypes: {
31
32
  component: React.PropTypes.func,
@@ -61,15 +62,17 @@ var ReactTransitionGroup = React.createClass({
61
62
  var key;
62
63
 
63
64
  for (key in nextChildMapping) {
64
- if (!prevChildMapping.hasOwnProperty(key) &&
65
- !this.currentlyTransitioningKeys[key]) {
65
+ var hasPrev = prevChildMapping && prevChildMapping.hasOwnProperty(key);
66
+ if (nextChildMapping[key] && !hasPrev &&
67
+ !this.currentlyTransitioningKeys[key]) {
66
68
  this.keysToEnter.push(key);
67
69
  }
68
70
  }
69
71
 
70
72
  for (key in prevChildMapping) {
71
- if (!nextChildMapping.hasOwnProperty(key) &&
72
- !this.currentlyTransitioningKeys[key]) {
73
+ var hasNext = nextChildMapping && nextChildMapping.hasOwnProperty(key);
74
+ if (prevChildMapping[key] && !hasNext &&
75
+ !this.currentlyTransitioningKeys[key]) {
73
76
  this.keysToLeave.push(key);
74
77
  }
75
78
  }
@@ -119,7 +122,7 @@ var ReactTransitionGroup = React.createClass({
119
122
  this.props.children
120
123
  );
121
124
 
122
- if (!currentChildMapping.hasOwnProperty(key)) {
125
+ if (!currentChildMapping || !currentChildMapping.hasOwnProperty(key)) {
123
126
  // This was removed before it had fully entered. Remove it.
124
127
  this.performLeave(key);
125
128
  }
@@ -152,7 +155,7 @@ var ReactTransitionGroup = React.createClass({
152
155
  this.props.children
153
156
  );
154
157
 
155
- if (currentChildMapping.hasOwnProperty(key)) {
158
+ if (currentChildMapping && currentChildMapping.hasOwnProperty(key)) {
156
159
  // This entered again before it fully left. Add it again.
157
160
  this.performEnter(key);
158
161
  } else {