react 0.14.0-alpha3 → 0.14.0-beta1

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 (103) hide show
  1. package/README.md +5 -2
  2. package/addons.js +2 -2
  3. package/dist/JSXTransformer.js +69 -70
  4. package/dist/react-with-addons.js +2047 -2078
  5. package/dist/react-with-addons.min.js +6 -6
  6. package/dist/react.js +1861 -1904
  7. package/dist/react.min.js +5 -5
  8. package/lib/{AutoFocusMixin.js → AutoFocusUtils.js} +13 -3
  9. package/lib/ChangeEventPlugin.js +4 -2
  10. package/lib/DOMProperty.js +81 -116
  11. package/lib/DOMPropertyOperations.js +70 -25
  12. package/lib/EnterLeaveEventPlugin.js +3 -3
  13. package/lib/EventPluginHub.js +2 -2
  14. package/lib/EventPluginUtils.js +6 -6
  15. package/lib/HTMLDOMPropertyConfig.js +8 -1
  16. package/lib/LinkedValueUtils.js +45 -33
  17. package/lib/PooledClass.js +12 -0
  18. package/lib/React.js +1 -1
  19. package/lib/ReactCSSTransitionGroupChild.js +8 -0
  20. package/lib/ReactChildren.js +3 -3
  21. package/lib/ReactClass.js +29 -47
  22. package/lib/ReactComponent.js +11 -6
  23. package/lib/ReactComponentWithPureRenderMixin.js +2 -2
  24. package/lib/ReactCompositeComponent.js +45 -72
  25. package/lib/ReactDOM.js +1 -0
  26. package/lib/ReactDOMButton.js +15 -26
  27. package/lib/ReactDOMClient.js +9 -4
  28. package/lib/ReactDOMComponent.js +302 -24
  29. package/lib/ReactDOMIDOperations.js +14 -0
  30. package/lib/ReactDOMInput.js +78 -94
  31. package/lib/ReactDOMOption.js +19 -38
  32. package/lib/ReactDOMSelect.js +85 -95
  33. package/lib/ReactDOMTextarea.js +39 -52
  34. package/lib/ReactDefaultInjection.js +0 -47
  35. package/lib/ReactElement.js +18 -79
  36. package/lib/ReactElementValidator.js +29 -98
  37. package/lib/ReactErrorUtils.js +1 -1
  38. package/lib/ReactEventEmitterMixin.js +2 -3
  39. package/lib/ReactEventListener.js +43 -3
  40. package/lib/ReactFragment.js +12 -7
  41. package/lib/ReactInputSelection.js +4 -3
  42. package/lib/ReactInstanceHandles.js +3 -2
  43. package/lib/ReactMount.js +20 -40
  44. package/lib/ReactNativeComponent.js +0 -5
  45. package/lib/ReactNoopUpdateQueue.js +118 -0
  46. package/lib/ReactPropTypes.js +3 -3
  47. package/lib/ReactReconcileTransaction.js +2 -2
  48. package/lib/ReactReconciler.js +8 -10
  49. package/lib/ReactServerBatchingStrategy.js +23 -0
  50. package/lib/ReactServerRendering.js +13 -0
  51. package/lib/ReactServerRenderingTransaction.js +2 -2
  52. package/lib/ReactTestUtils.js +56 -33
  53. package/lib/ReactUpdateQueue.js +51 -26
  54. package/lib/ReactUpdates.js +0 -3
  55. package/lib/ReactWithAddons.js +0 -2
  56. package/lib/SelectEventPlugin.js +6 -7
  57. package/lib/SimpleEventPlugin.js +4 -4
  58. package/lib/SyntheticClipboardEvent.js +2 -2
  59. package/lib/SyntheticCompositionEvent.js +2 -2
  60. package/lib/SyntheticDragEvent.js +2 -2
  61. package/lib/SyntheticEvent.js +6 -5
  62. package/lib/SyntheticFocusEvent.js +2 -2
  63. package/lib/SyntheticInputEvent.js +2 -2
  64. package/lib/SyntheticKeyboardEvent.js +2 -2
  65. package/lib/SyntheticMouseEvent.js +2 -2
  66. package/lib/SyntheticTouchEvent.js +2 -2
  67. package/lib/SyntheticUIEvent.js +2 -2
  68. package/lib/SyntheticWheelEvent.js +2 -2
  69. package/lib/Transaction.js +10 -4
  70. package/lib/cloneWithProps.js +1 -1
  71. package/lib/deprecated.js +47 -0
  72. package/lib/findDOMNode.js +2 -3
  73. package/lib/forEachAccumulated.js +1 -1
  74. package/lib/getEventCharCode.js +1 -1
  75. package/lib/getEventModifierState.js +0 -1
  76. package/lib/getMarkupWrap.js +13 -35
  77. package/lib/instantiateReactComponent.js +13 -9
  78. package/lib/isTextInputElement.js +2 -1
  79. package/lib/joinClasses.js +1 -1
  80. package/lib/setInnerHTML.js +1 -1
  81. package/lib/traverseAllChildren.js +1 -1
  82. package/lib/warning.js +0 -4
  83. package/package.json +1 -1
  84. package/react.js +53 -1
  85. package/addons/CSSTransitionGroup.js +0 -1
  86. package/addons/LinkedStateMixin.js +0 -1
  87. package/addons/Perf.js +0 -1
  88. package/addons/PureRenderMixin.js +0 -1
  89. package/addons/TestUtils.js +0 -1
  90. package/addons/TransitionGroup.js +0 -1
  91. package/addons/batchedUpdates.js +0 -1
  92. package/addons/cloneWithProps.js +0 -1
  93. package/addons/createFragment.js +0 -1
  94. package/addons/renderSubtreeIntoContainer.js +0 -1
  95. package/addons/shallowCompare.js +0 -1
  96. package/addons/update.js +0 -1
  97. package/lib/LocalEventTrapMixin.js +0 -46
  98. package/lib/ReactContext.js +0 -32
  99. package/lib/ReactDOMForm.js +0 -47
  100. package/lib/ReactDOMIframe.js +0 -43
  101. package/lib/ReactDOMImg.js +0 -44
  102. package/lib/ReactLifeCycle.js +0 -35
  103. package/lib/createFullPageComponent.js +0 -51
@@ -11,17 +11,22 @@
11
11
 
12
12
  'use strict';
13
13
 
14
- var ReactUpdateQueue = require("./ReactUpdateQueue");
14
+ var ReactNoopUpdateQueue = require("./ReactNoopUpdateQueue");
15
15
 
16
+ var emptyObject = require("./emptyObject");
16
17
  var invariant = require("./invariant");
17
18
  var warning = require("./warning");
18
19
 
19
20
  /**
20
21
  * Base class helpers for the updating state of a component.
21
22
  */
22
- function ReactComponent(props, context) {
23
+ function ReactComponent(props, context, updater) {
23
24
  this.props = props;
24
25
  this.context = context;
26
+ this.refs = emptyObject;
27
+ // We initialize the default updater but the real one gets injected by the
28
+ // renderer.
29
+ this.updater = updater || ReactNoopUpdateQueue;
25
30
  }
26
31
 
27
32
  /**
@@ -54,9 +59,9 @@ ReactComponent.prototype.setState = function (partialState, callback) {
54
59
  if ('production' !== process.env.NODE_ENV) {
55
60
  'production' !== process.env.NODE_ENV ? warning(partialState != null, 'setState(...): You passed an undefined or null state object; ' + 'instead, use forceUpdate().') : undefined;
56
61
  }
57
- ReactUpdateQueue.enqueueSetState(this, partialState);
62
+ this.updater.enqueueSetState(this, partialState);
58
63
  if (callback) {
59
- ReactUpdateQueue.enqueueCallback(this, callback);
64
+ this.updater.enqueueCallback(this, callback);
60
65
  }
61
66
  };
62
67
 
@@ -75,9 +80,9 @@ ReactComponent.prototype.setState = function (partialState, callback) {
75
80
  * @protected
76
81
  */
77
82
  ReactComponent.prototype.forceUpdate = function (callback) {
78
- ReactUpdateQueue.enqueueForceUpdate(this);
83
+ this.updater.enqueueForceUpdate(this);
79
84
  if (callback) {
80
- ReactUpdateQueue.enqueueCallback(this, callback);
85
+ this.updater.enqueueCallback(this, callback);
81
86
  }
82
87
  };
83
88
 
@@ -6,8 +6,8 @@
6
6
  * LICENSE file in the root directory of this source tree. An additional grant
7
7
  * of patent rights can be found in the PATENTS file in the same directory.
8
8
  *
9
- * @providesModule ReactComponentWithPureRenderMixin
10
- */
9
+ * @providesModule ReactComponentWithPureRenderMixin
10
+ */
11
11
 
12
12
  'use strict';
13
13
 
@@ -12,18 +12,14 @@
12
12
  'use strict';
13
13
 
14
14
  var ReactComponentEnvironment = require("./ReactComponentEnvironment");
15
- var ReactContext = require("./ReactContext");
16
15
  var ReactCurrentOwner = require("./ReactCurrentOwner");
17
16
  var ReactElement = require("./ReactElement");
18
- var ReactElementValidator = require("./ReactElementValidator");
19
17
  var ReactInstanceMap = require("./ReactInstanceMap");
20
- var ReactLifeCycle = require("./ReactLifeCycle");
21
- var ReactNativeComponent = require("./ReactNativeComponent");
22
18
  var ReactPerf = require("./ReactPerf");
23
19
  var ReactPropTypeLocations = require("./ReactPropTypeLocations");
24
20
  var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames");
25
21
  var ReactReconciler = require("./ReactReconciler");
26
- var ReactUpdates = require("./ReactUpdates");
22
+ var ReactUpdateQueue = require("./ReactUpdateQueue");
27
23
 
28
24
  var assign = require("./Object.assign");
29
25
  var emptyObject = require("./emptyObject");
@@ -104,7 +100,7 @@ var ReactCompositeComponentMixin = {
104
100
 
105
101
  this._context = null;
106
102
  this._mountOrder = 0;
107
- this._isTopLevel = false;
103
+ this._topLevelWrapper = null;
108
104
 
109
105
  // See ReactUpdates and ReactUpdateQueue.
110
106
  this._pendingCallbacks = null;
@@ -127,10 +123,10 @@ var ReactCompositeComponentMixin = {
127
123
  var publicProps = this._processProps(this._currentElement.props);
128
124
  var publicContext = this._processContext(context);
129
125
 
130
- var Component = ReactNativeComponent.getComponentClassForElement(this._currentElement);
126
+ var Component = this._currentElement.type;
131
127
 
132
128
  // Initialize the public class
133
- var inst = new Component(publicProps, publicContext);
129
+ var inst = new Component(publicProps, publicContext, ReactUpdateQueue);
134
130
 
135
131
  if ('production' !== process.env.NODE_ENV) {
136
132
  // This will throw later in _renderValidatedComponent, but add an early
@@ -143,6 +139,7 @@ var ReactCompositeComponentMixin = {
143
139
  inst.props = publicProps;
144
140
  inst.context = publicContext;
145
141
  inst.refs = emptyObject;
142
+ inst.updater = ReactUpdateQueue;
146
143
 
147
144
  this._instance = inst;
148
145
 
@@ -158,6 +155,8 @@ var ReactCompositeComponentMixin = {
158
155
  'production' !== process.env.NODE_ENV ? warning(!inst.propTypes, 'propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', this.getName() || 'a component') : undefined;
159
156
  'production' !== process.env.NODE_ENV ? warning(!inst.contextTypes, 'contextTypes was defined as an instance property on %s. Use a ' + 'static property to define contextTypes instead.', this.getName() || 'a component') : undefined;
160
157
  'production' !== process.env.NODE_ENV ? warning(typeof inst.componentShouldUpdate !== 'function', '%s has a method called ' + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + 'The name is phrased as a question because the function is ' + 'expected to return a value.', this.getName() || 'A component') : undefined;
158
+ 'production' !== process.env.NODE_ENV ? warning(typeof inst.componentDidUnmount !== 'function', '%s has a method called ' + 'componentDidUnmount(). But there is no such lifecycle method. ' + 'Did you mean componentWillUnmount()?', this.getName() || 'A component') : undefined;
159
+ 'production' !== process.env.NODE_ENV ? warning(typeof inst.componentWillRecieveProps !== 'function', '%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', this.getName() || 'A component') : undefined;
161
160
  }
162
161
 
163
162
  var initialState = inst.state;
@@ -170,27 +169,18 @@ var ReactCompositeComponentMixin = {
170
169
  this._pendingReplaceState = false;
171
170
  this._pendingForceUpdate = false;
172
171
 
173
- var renderedElement;
174
-
175
- var previouslyMounting = ReactLifeCycle.currentlyMountingInstance;
176
- ReactLifeCycle.currentlyMountingInstance = this;
177
- try {
178
- if (inst.componentWillMount) {
179
- inst.componentWillMount();
180
- // When mounting, calls to `setState` by `componentWillMount` will set
181
- // `this._pendingStateQueue` without triggering a re-render.
182
- if (this._pendingStateQueue) {
183
- inst.state = this._processPendingState(inst.props, inst.context);
184
- }
172
+ if (inst.componentWillMount) {
173
+ inst.componentWillMount();
174
+ // When mounting, calls to `setState` by `componentWillMount` will set
175
+ // `this._pendingStateQueue` without triggering a re-render.
176
+ if (this._pendingStateQueue) {
177
+ inst.state = this._processPendingState(inst.props, inst.context);
185
178
  }
186
-
187
- renderedElement = this._renderValidatedComponent();
188
- } finally {
189
- ReactLifeCycle.currentlyMountingInstance = previouslyMounting;
190
179
  }
191
180
 
192
- this._renderedComponent = this._instantiateReactComponent(renderedElement, this._currentElement.type // The wrapping type
193
- );
181
+ var renderedElement = this._renderValidatedComponent();
182
+
183
+ this._renderedComponent = this._instantiateReactComponent(renderedElement);
194
184
 
195
185
  var markup = ReactReconciler.mountComponent(this._renderedComponent, rootID, transaction, this._processChildContext(context));
196
186
  if (inst.componentDidMount) {
@@ -210,19 +200,15 @@ var ReactCompositeComponentMixin = {
210
200
  var inst = this._instance;
211
201
 
212
202
  if (inst.componentWillUnmount) {
213
- var previouslyUnmounting = ReactLifeCycle.currentlyUnmountingInstance;
214
- ReactLifeCycle.currentlyUnmountingInstance = this;
215
- try {
216
- inst.componentWillUnmount();
217
- } finally {
218
- ReactLifeCycle.currentlyUnmountingInstance = previouslyUnmounting;
219
- }
203
+ inst.componentWillUnmount();
220
204
  }
221
205
 
222
206
  ReactReconciler.unmountComponent(this._renderedComponent);
223
207
  this._renderedComponent = null;
224
208
 
225
209
  // Reset pending fields
210
+ // Even if this component is scheduled for another update in ReactUpdates,
211
+ // it would still be ignored because these fields are reset.
226
212
  this._pendingStateQueue = null;
227
213
  this._pendingReplaceState = false;
228
214
  this._pendingForceUpdate = false;
@@ -233,6 +219,7 @@ var ReactCompositeComponentMixin = {
233
219
  // longer accessible.
234
220
  this._context = null;
235
221
  this._rootNodeID = null;
222
+ this._topLevelWrapper = null;
236
223
 
237
224
  // Delete the reference from the instance to this internal representation
238
225
  // which allow the internals to be properly cleaned up even if the user
@@ -246,22 +233,6 @@ var ReactCompositeComponentMixin = {
246
233
  // TODO: inst.context = null;
247
234
  },
248
235
 
249
- /**
250
- * Schedule a partial update to the props. Only used for internal testing.
251
- *
252
- * @param {object} partialProps Subset of the next props.
253
- * @param {?function} callback Called after props are updated.
254
- * @final
255
- * @internal
256
- */
257
- _setPropsInternal: function (partialProps, callback) {
258
- // This is a deoptimized path. We optimize for always having an element.
259
- // This creates an extra internal element.
260
- var element = this._pendingElement || this._currentElement;
261
- this._pendingElement = ReactElement.cloneAndReplaceProps(element, assign({}, element.props, partialProps));
262
- ReactUpdates.enqueueUpdate(this, callback);
263
- },
264
-
265
236
  /**
266
237
  * Filters the context object to only contain keys specified in
267
238
  * `contextTypes`
@@ -272,7 +243,7 @@ var ReactCompositeComponentMixin = {
272
243
  */
273
244
  _maskContext: function (context) {
274
245
  var maskedContext = null;
275
- var Component = ReactNativeComponent.getComponentClassForElement(this._currentElement);
246
+ var Component = this._currentElement.type;
276
247
  var contextTypes = Component.contextTypes;
277
248
  if (!contextTypes) {
278
249
  return emptyObject;
@@ -295,7 +266,7 @@ var ReactCompositeComponentMixin = {
295
266
  _processContext: function (context) {
296
267
  var maskedContext = this._maskContext(context);
297
268
  if ('production' !== process.env.NODE_ENV) {
298
- var Component = ReactNativeComponent.getComponentClassForElement(this._currentElement);
269
+ var Component = this._currentElement.type;
299
270
  if (Component.contextTypes) {
300
271
  this._checkPropTypes(Component.contextTypes, maskedContext, ReactPropTypeLocations.context);
301
272
  }
@@ -309,15 +280,16 @@ var ReactCompositeComponentMixin = {
309
280
  * @private
310
281
  */
311
282
  _processChildContext: function (currentContext) {
283
+ var Component = this._currentElement.type;
312
284
  var inst = this._instance;
313
285
  var childContext = inst.getChildContext && inst.getChildContext();
314
286
  if (childContext) {
315
- !(typeof inst.constructor.childContextTypes === 'object') ? 'production' !== process.env.NODE_ENV ? invariant(false, '%s.getChildContext(): childContextTypes must be defined in order to ' + 'use getChildContext().', this.getName() || 'ReactCompositeComponent') : invariant(false) : undefined;
287
+ !(typeof Component.childContextTypes === 'object') ? 'production' !== process.env.NODE_ENV ? invariant(false, '%s.getChildContext(): childContextTypes must be defined in order to ' + 'use getChildContext().', this.getName() || 'ReactCompositeComponent') : invariant(false) : undefined;
316
288
  if ('production' !== process.env.NODE_ENV) {
317
- this._checkPropTypes(inst.constructor.childContextTypes, childContext, ReactPropTypeLocations.childContext);
289
+ this._checkPropTypes(Component.childContextTypes, childContext, ReactPropTypeLocations.childContext);
318
290
  }
319
291
  for (var name in childContext) {
320
- !(name in inst.constructor.childContextTypes) ? 'production' !== process.env.NODE_ENV ? invariant(false, '%s.getChildContext(): key "%s" is not defined in childContextTypes.', this.getName() || 'ReactCompositeComponent', name) : invariant(false) : undefined;
292
+ !(name in Component.childContextTypes) ? 'production' !== process.env.NODE_ENV ? invariant(false, '%s.getChildContext(): key "%s" is not defined in childContextTypes.', this.getName() || 'ReactCompositeComponent', name) : invariant(false) : undefined;
321
293
  }
322
294
  return assign({}, currentContext, childContext);
323
295
  }
@@ -335,7 +307,7 @@ var ReactCompositeComponentMixin = {
335
307
  */
336
308
  _processProps: function (newProps) {
337
309
  if ('production' !== process.env.NODE_ENV) {
338
- var Component = ReactNativeComponent.getComponentClassForElement(this._currentElement);
310
+ var Component = this._currentElement.type;
339
311
  if (Component.propTypes) {
340
312
  this._checkPropTypes(Component.propTypes, newProps, ReactPropTypeLocations.prop);
341
313
  }
@@ -405,10 +377,6 @@ var ReactCompositeComponentMixin = {
405
377
  }
406
378
 
407
379
  if (this._pendingStateQueue !== null || this._pendingForceUpdate) {
408
- if ('production' !== process.env.NODE_ENV) {
409
- ReactElementValidator.checkAndWarnForMutatedProps(this._currentElement);
410
- }
411
-
412
380
  this.updateComponent(transaction, this._currentElement, this._currentElement, this._context, this._context);
413
381
  }
414
382
  },
@@ -431,14 +399,16 @@ var ReactCompositeComponentMixin = {
431
399
  updateComponent: function (transaction, prevParentElement, nextParentElement, prevUnmaskedContext, nextUnmaskedContext) {
432
400
  var inst = this._instance;
433
401
 
434
- var nextContext = inst.context;
435
- var nextProps = inst.props;
402
+ var nextContext = this._context === nextUnmaskedContext ? inst.context : this._processContext(nextUnmaskedContext);
403
+ var nextProps;
436
404
 
437
405
  // Distinguish between a props update versus a simple state update
438
- if (prevParentElement !== nextParentElement) {
439
- nextContext = this._processContext(nextUnmaskedContext);
406
+ if (prevParentElement === nextParentElement) {
407
+ // Skip checking prop types again -- we don't read inst.props to avoid
408
+ // warning for DOM component props in this upgrade
409
+ nextProps = nextParentElement.props;
410
+ } else {
440
411
  nextProps = this._processProps(nextParentElement.props);
441
-
442
412
  // An update here will schedule an update but immediately set
443
413
  // _pendingStateQueue which will ensure that any state updates gets
444
414
  // immediately reconciled instead of waiting for the next batch.
@@ -510,9 +480,15 @@ var ReactCompositeComponentMixin = {
510
480
  _performComponentUpdate: function (nextElement, nextProps, nextState, nextContext, transaction, unmaskedContext) {
511
481
  var inst = this._instance;
512
482
 
513
- var prevProps = inst.props;
514
- var prevState = inst.state;
515
- var prevContext = inst.context;
483
+ var hasComponentDidUpdate = Boolean(inst.componentDidUpdate);
484
+ var prevProps;
485
+ var prevState;
486
+ var prevContext;
487
+ if (hasComponentDidUpdate) {
488
+ prevProps = inst.props;
489
+ prevState = inst.state;
490
+ prevContext = inst.context;
491
+ }
516
492
 
517
493
  if (inst.componentWillUpdate) {
518
494
  inst.componentWillUpdate(nextProps, nextState, nextContext);
@@ -526,7 +502,7 @@ var ReactCompositeComponentMixin = {
526
502
 
527
503
  this._updateRenderedComponent(transaction, unmaskedContext);
528
504
 
529
- if (inst.componentDidUpdate) {
505
+ if (hasComponentDidUpdate) {
530
506
  transaction.getReactMountReady().enqueue(inst.componentDidUpdate.bind(inst, prevProps, prevState, prevContext), inst);
531
507
  }
532
508
  },
@@ -549,7 +525,7 @@ var ReactCompositeComponentMixin = {
549
525
  var prevComponentID = prevComponentInstance._rootNodeID;
550
526
  ReactReconciler.unmountComponent(prevComponentInstance);
551
527
 
552
- this._renderedComponent = this._instantiateReactComponent(nextRenderedElement, this._currentElement.type);
528
+ this._renderedComponent = this._instantiateReactComponent(nextRenderedElement);
553
529
  var nextMarkup = ReactReconciler.mountComponent(this._renderedComponent, thisID, transaction, this._processChildContext(context));
554
530
  this._replaceNodeWithMarkupByID(prevComponentID, nextMarkup);
555
531
  }
@@ -585,13 +561,10 @@ var ReactCompositeComponentMixin = {
585
561
  */
586
562
  _renderValidatedComponent: function () {
587
563
  var renderedComponent;
588
- var previousContext = ReactContext.current;
589
- ReactContext.current = this._processChildContext(this._currentElement._context);
590
564
  ReactCurrentOwner.current = this;
591
565
  try {
592
566
  renderedComponent = this._renderValidatedComponentWithoutOwnerOrContext();
593
567
  } finally {
594
- ReactContext.current = previousContext;
595
568
  ReactCurrentOwner.current = null;
596
569
  }
597
570
  !(
package/lib/ReactDOM.js CHANGED
@@ -157,6 +157,7 @@ var ReactDOM = mapObject({
157
157
  defs: 'defs',
158
158
  ellipse: 'ellipse',
159
159
  g: 'g',
160
+ image: 'image',
160
161
  line: 'line',
161
162
  linearGradient: 'linearGradient',
162
163
  mask: 'mask',
@@ -11,51 +11,40 @@
11
11
 
12
12
  'use strict';
13
13
 
14
- var AutoFocusMixin = require("./AutoFocusMixin");
15
- var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
16
- var ReactClass = require("./ReactClass");
17
- var ReactElement = require("./ReactElement");
18
-
19
- var keyMirror = require("./keyMirror");
20
-
21
- var button = ReactElement.createFactory('button');
22
-
23
- var mouseListenerNames = keyMirror({
14
+ var mouseListenerNames = {
24
15
  onClick: true,
25
16
  onDoubleClick: true,
26
17
  onMouseDown: true,
27
18
  onMouseMove: true,
28
19
  onMouseUp: true,
20
+
29
21
  onClickCapture: true,
30
22
  onDoubleClickCapture: true,
31
23
  onMouseDownCapture: true,
32
24
  onMouseMoveCapture: true,
33
25
  onMouseUpCapture: true
34
- });
26
+ };
35
27
 
36
28
  /**
37
29
  * Implements a <button> native component that does not receive mouse events
38
30
  * when `disabled` is set.
39
31
  */
40
- var ReactDOMButton = ReactClass.createClass({
41
- displayName: 'ReactDOMButton',
42
- tagName: 'BUTTON',
43
-
44
- mixins: [AutoFocusMixin, ReactBrowserComponentMixin],
45
-
46
- render: function () {
47
- var props = {};
32
+ var ReactDOMButton = {
33
+ getNativeProps: function (inst, props, context) {
34
+ if (!props.disabled) {
35
+ return props;
36
+ }
48
37
 
49
- // Copy the props; except the mouse listeners if we're disabled
50
- for (var key in this.props) {
51
- if (this.props.hasOwnProperty(key) && (!this.props.disabled || !mouseListenerNames[key])) {
52
- props[key] = this.props[key];
38
+ // Copy the props, except the mouse listeners
39
+ var nativeProps = {};
40
+ for (var key in props) {
41
+ if (props.hasOwnProperty(key) && !mouseListenerNames[key]) {
42
+ nativeProps[key] = props[key];
53
43
  }
54
44
  }
55
45
 
56
- return button(props, this.props.children);
46
+ return nativeProps;
57
47
  }
58
-
59
- });
48
+ };
60
49
 
61
50
  module.exports = ReactDOMButton;
@@ -20,8 +20,10 @@ var ReactInstanceHandles = require("./ReactInstanceHandles");
20
20
  var ReactMount = require("./ReactMount");
21
21
  var ReactPerf = require("./ReactPerf");
22
22
  var ReactReconciler = require("./ReactReconciler");
23
+ var ReactUpdates = require("./ReactUpdates");
23
24
 
24
25
  var findDOMNode = require("./findDOMNode");
26
+ var renderSubtreeIntoContainer = require("./renderSubtreeIntoContainer");
25
27
  var warning = require("./warning");
26
28
 
27
29
  ReactDefaultInjection.inject();
@@ -29,11 +31,13 @@ ReactDefaultInjection.inject();
29
31
  var render = ReactPerf.measure('React', 'render', ReactMount.render);
30
32
 
31
33
  var React = {
32
- constructAndRenderComponent: ReactMount.constructAndRenderComponent,
33
- constructAndRenderComponentByID: ReactMount.constructAndRenderComponentByID,
34
34
  findDOMNode: findDOMNode,
35
35
  render: render,
36
- unmountComponentAtNode: ReactMount.unmountComponentAtNode
36
+ unmountComponentAtNode: ReactMount.unmountComponentAtNode,
37
+
38
+ /* eslint-disable camelcase */
39
+ unstable_batchedUpdates: ReactUpdates.batchedUpdates,
40
+ unstable_renderSubtreeIntoContainer: renderSubtreeIntoContainer
37
41
  };
38
42
 
39
43
  // Inject the runtime into a devtools global hook regardless of browser.
@@ -82,4 +86,5 @@ if ('production' !== process.env.NODE_ENV) {
82
86
  }
83
87
  }
84
88
 
85
- module.exports = React;
89
+ module.exports = React;
90
+ /* eslint-enable camelcase */
@@ -14,14 +14,22 @@
14
14
 
15
15
  'use strict';
16
16
 
17
+ var AutoFocusUtils = require("./AutoFocusUtils");
17
18
  var CSSPropertyOperations = require("./CSSPropertyOperations");
18
19
  var DOMProperty = require("./DOMProperty");
19
20
  var DOMPropertyOperations = require("./DOMPropertyOperations");
21
+ var EventConstants = require("./EventConstants");
20
22
  var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
21
23
  var ReactComponentBrowserEnvironment = require("./ReactComponentBrowserEnvironment");
24
+ var ReactDOMButton = require("./ReactDOMButton");
25
+ var ReactDOMInput = require("./ReactDOMInput");
26
+ var ReactDOMOption = require("./ReactDOMOption");
27
+ var ReactDOMSelect = require("./ReactDOMSelect");
28
+ var ReactDOMTextarea = require("./ReactDOMTextarea");
22
29
  var ReactMount = require("./ReactMount");
23
30
  var ReactMultiChild = require("./ReactMultiChild");
24
31
  var ReactPerf = require("./ReactPerf");
32
+ var ReactUpdateQueue = require("./ReactUpdateQueue");
25
33
 
26
34
  var assign = require("./Object.assign");
27
35
  var escapeTextContentForBrowser = require("./escapeTextContentForBrowser");
@@ -43,6 +51,90 @@ var STYLE = keyOf({ style: null });
43
51
 
44
52
  var ELEMENT_NODE_TYPE = 1;
45
53
 
54
+ var canDefineProperty = false;
55
+ try {
56
+ Object.defineProperty({}, 'test', { get: function () {} });
57
+ canDefineProperty = true;
58
+ } catch (e) {}
59
+
60
+ function getDeclarationErrorAddendum(internalInstance) {
61
+ if (internalInstance) {
62
+ var owner = internalInstance._currentElement._owner || null;
63
+ if (owner) {
64
+ var name = owner.getName();
65
+ if (name) {
66
+ return ' This DOM node was rendered by `' + name + '`.';
67
+ }
68
+ }
69
+ }
70
+ return '';
71
+ }
72
+
73
+ var legacyPropsDescriptor;
74
+ if ('production' !== process.env.NODE_ENV) {
75
+ legacyPropsDescriptor = {
76
+ props: {
77
+ enumerable: false,
78
+ get: function () {
79
+ var component = this._reactInternalComponent;
80
+ 'production' !== process.env.NODE_ENV ? warning(false, 'ReactDOMComponent: Do not access .props of a DOM node; instead, ' + 'recreate the props as `render` did originally or read the DOM ' + 'properties/attributes directly from this node (e.g., ' + 'this.refs.box.className).%s', getDeclarationErrorAddendum(component)) : undefined;
81
+ return component._currentElement.props;
82
+ }
83
+ }
84
+ };
85
+ }
86
+
87
+ function legacyGetDOMNode() {
88
+ if ('production' !== process.env.NODE_ENV) {
89
+ var component = this._reactInternalComponent;
90
+ 'production' !== process.env.NODE_ENV ? warning(false, 'ReactDOMComponent: Do not access .getDOMNode() of a DOM node; ' + 'instead, use the node directly.%s', getDeclarationErrorAddendum(component)) : undefined;
91
+ }
92
+ return this;
93
+ }
94
+
95
+ function legacyIsMounted() {
96
+ var component = this._reactInternalComponent;
97
+ if ('production' !== process.env.NODE_ENV) {
98
+ 'production' !== process.env.NODE_ENV ? warning(false, 'ReactDOMComponent: Do not access .isMounted() of a DOM node.%s', getDeclarationErrorAddendum(component)) : undefined;
99
+ }
100
+ return !!component;
101
+ }
102
+
103
+ function legacySetStateEtc() {
104
+ if ('production' !== process.env.NODE_ENV) {
105
+ var component = this._reactInternalComponent;
106
+ 'production' !== process.env.NODE_ENV ? warning(false, 'ReactDOMComponent: Do not access .setState(), .replaceState(), or ' + '.forceUpdate() of a DOM node. This is a no-op.%s', getDeclarationErrorAddendum(component)) : undefined;
107
+ }
108
+ }
109
+
110
+ function legacySetProps(partialProps, callback) {
111
+ var component = this._reactInternalComponent;
112
+ if ('production' !== process.env.NODE_ENV) {
113
+ 'production' !== process.env.NODE_ENV ? warning(false, 'ReactDOMComponent: Do not access .setProps() of a DOM node. ' + 'Instead, call React.render again at the top level.%s', getDeclarationErrorAddendum(component)) : undefined;
114
+ }
115
+ if (!component) {
116
+ return;
117
+ }
118
+ ReactUpdateQueue.enqueueSetPropsInternal(component, partialProps);
119
+ if (callback) {
120
+ ReactUpdateQueue.enqueueCallbackInternal(component, callback);
121
+ }
122
+ }
123
+
124
+ function legacyReplaceProps(partialProps, callback) {
125
+ var component = this._reactInternalComponent;
126
+ if ('production' !== process.env.NODE_ENV) {
127
+ 'production' !== process.env.NODE_ENV ? warning(false, 'ReactDOMComponent: Do not access .replaceProps() of a DOM node. ' + 'Instead, call React.render again at the top level.%s', getDeclarationErrorAddendum(component)) : undefined;
128
+ }
129
+ if (!component) {
130
+ return;
131
+ }
132
+ ReactUpdateQueue.enqueueReplacePropsInternal(component, partialProps);
133
+ if (callback) {
134
+ ReactUpdateQueue.enqueueCallbackInternal(component, callback);
135
+ }
136
+ }
137
+
46
138
  var styleMutationWarning = {};
47
139
 
48
140
  function checkAndWarnForMutatedStyle(style1, style2, component) {
@@ -77,6 +169,7 @@ function checkAndWarnForMutatedStyle(style1, style2, component) {
77
169
  var BackendIDOperations = null;
78
170
 
79
171
  /**
172
+ * @param {object} component
80
173
  * @param {?object} props
81
174
  */
82
175
  function assertValidProps(component, props) {
@@ -86,7 +179,7 @@ function assertValidProps(component, props) {
86
179
  // Note the use of `==` which checks for null or undefined.
87
180
  if ('production' !== process.env.NODE_ENV) {
88
181
  if (voidElementTags[component._tag]) {
89
- 'production' !== process.env.NODE_ENV ? warning(props.children == null && props.dangerouslySetInnerHTML == null, '%s is a void element tag and must not have `children` or ' + 'use `props.dangerouslySetInnerHTML`.', component._tag) : undefined;
182
+ 'production' !== process.env.NODE_ENV ? warning(props.children == null && props.dangerouslySetInnerHTML == null, '%s is a void element tag and must not have `children` or ' + 'use `props.dangerouslySetInnerHTML`.%s', component._tag, component._currentElement._owner ? ' Check the render method of ' + component._currentElement._owner.getName() + '.' : '') : undefined;
90
183
  }
91
184
  }
92
185
  if (props.dangerouslySetInnerHTML != null) {
@@ -123,6 +216,31 @@ function putListener() {
123
216
  ReactBrowserEventEmitter.putListener(listenerToPut.id, listenerToPut.registrationName, listenerToPut.listener);
124
217
  }
125
218
 
219
+ function trapBubbledEventsLocal() {
220
+ var inst = this;
221
+ // If a component renders to null or if another component fatals and causes
222
+ // the state of the tree to be corrupted, `node` here can be null.
223
+ !inst._rootNodeID ? 'production' !== process.env.NODE_ENV ? invariant(false, 'Must be mounted to trap events') : invariant(false) : undefined;
224
+ var node = ReactMount.getNode(inst._rootNodeID);
225
+ !node ? 'production' !== process.env.NODE_ENV ? invariant(false, 'trapBubbledEvent(...): Requires node to be rendered.') : invariant(false) : undefined;
226
+
227
+ switch (inst._tag) {
228
+ case 'iframe':
229
+ inst._wrapperState.listeners = [ReactBrowserEventEmitter.trapBubbledEvent(EventConstants.topLevelTypes.topLoad, 'load', node)];
230
+ break;
231
+ case 'img':
232
+ inst._wrapperState.listeners = [ReactBrowserEventEmitter.trapBubbledEvent(EventConstants.topLevelTypes.topError, 'error', node), ReactBrowserEventEmitter.trapBubbledEvent(EventConstants.topLevelTypes.topLoad, 'load', node)];
233
+ break;
234
+ case 'form':
235
+ inst._wrapperState.listeners = [ReactBrowserEventEmitter.trapBubbledEvent(EventConstants.topLevelTypes.topReset, 'reset', node), ReactBrowserEventEmitter.trapBubbledEvent(EventConstants.topLevelTypes.topSubmit, 'submit', node)];
236
+ break;
237
+ }
238
+ }
239
+
240
+ function postUpdateSelectWrapper() {
241
+ ReactDOMSelect.postUpdateWrapper(this);
242
+ }
243
+
126
244
  // For HTML, certain tags should omit their close tag. We keep a whitelist for
127
245
  // those special cased tags.
128
246
 
@@ -142,7 +260,6 @@ var omittedCloseTags = {
142
260
  'source': true,
143
261
  'track': true,
144
262
  'wbr': true
145
- // NOTE: menuitem's close tag should be omitted, but that causes problems.
146
263
  };
147
264
 
148
265
  var newlineEatingTags = {
@@ -183,6 +300,10 @@ function processChildContext(context, inst) {
183
300
  return context;
184
301
  }
185
302
 
303
+ function isCustomComponent(tagName, props) {
304
+ return tagName.indexOf('-') >= 0 || props.is != null;
305
+ }
306
+
186
307
  /**
187
308
  * Creates a new React class that is idempotent and capable of containing other
188
309
  * React components. It accepts event listeners and DOM properties that are
@@ -199,11 +320,14 @@ function processChildContext(context, inst) {
199
320
  */
200
321
  function ReactDOMComponent(tag) {
201
322
  validateDangerousTag(tag);
202
- this._tag = tag;
323
+ this._tag = tag.toLowerCase();
203
324
  this._renderedChildren = null;
204
325
  this._previousStyle = null;
205
326
  this._previousStyleCopy = null;
206
327
  this._rootNodeID = null;
328
+ this._wrapperState = null;
329
+ this._topLevelWrapper = null;
330
+ this._nodeWithLegacyProperties = null;
207
331
  }
208
332
 
209
333
  ReactDOMComponent.displayName = 'ReactDOMComponent';
@@ -227,19 +351,64 @@ ReactDOMComponent.Mixin = {
227
351
  mountComponent: function (rootID, transaction, context) {
228
352
  this._rootNodeID = rootID;
229
353
 
230
- assertValidProps(this, this._currentElement.props);
354
+ var props = this._currentElement.props;
355
+
356
+ switch (this._tag) {
357
+ case 'iframe':
358
+ case 'img':
359
+ case 'form':
360
+ this._wrapperState = {
361
+ listeners: null
362
+ };
363
+ transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this);
364
+ break;
365
+ case 'button':
366
+ props = ReactDOMButton.getNativeProps(this, props, context);
367
+ break;
368
+ case 'input':
369
+ ReactDOMInput.mountWrapper(this, props, context);
370
+ props = ReactDOMInput.getNativeProps(this, props, context);
371
+ break;
372
+ case 'option':
373
+ ReactDOMOption.mountWrapper(this, props, context);
374
+ props = ReactDOMOption.getNativeProps(this, props, context);
375
+ break;
376
+ case 'select':
377
+ ReactDOMSelect.mountWrapper(this, props, context);
378
+ props = ReactDOMSelect.getNativeProps(this, props, context);
379
+ context = ReactDOMSelect.processChildContext(this, props, context);
380
+ break;
381
+ case 'textarea':
382
+ ReactDOMTextarea.mountWrapper(this, props, context);
383
+ props = ReactDOMTextarea.getNativeProps(this, props, context);
384
+ break;
385
+ }
386
+
387
+ assertValidProps(this, props);
231
388
  if ('production' !== process.env.NODE_ENV) {
232
389
  if (context[validateDOMNesting.ancestorInfoContextKey]) {
233
390
  validateDOMNesting(this._tag, this, context[validateDOMNesting.ancestorInfoContextKey]);
234
391
  }
235
392
  }
236
393
 
237
- var tagOpen = this._createOpenTagMarkupAndPutListeners(transaction);
238
- var tagContent = this._createContentMarkup(transaction, context);
394
+ var tagOpen = this._createOpenTagMarkupAndPutListeners(transaction, props);
395
+ var tagContent = this._createContentMarkup(transaction, props, context);
396
+
397
+ switch (this._tag) {
398
+ case 'button':
399
+ case 'input':
400
+ case 'select':
401
+ case 'textarea':
402
+ if (props.autoFocus) {
403
+ transaction.getReactMountReady().enqueue(AutoFocusUtils.focusDOMComponent, this);
404
+ }
405
+ break;
406
+ }
407
+
239
408
  if (!tagContent && omittedCloseTags[this._tag]) {
240
409
  return tagOpen + '/>';
241
410
  }
242
- return tagOpen + '>' + tagContent + '</' + this._tag + '>';
411
+ return tagOpen + '>' + tagContent + '</' + this._currentElement.type + '>';
243
412
  },
244
413
 
245
414
  /**
@@ -252,11 +421,11 @@ ReactDOMComponent.Mixin = {
252
421
  *
253
422
  * @private
254
423
  * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
424
+ * @param {object} props
255
425
  * @return {string} Markup of opening tag.
256
426
  */
257
- _createOpenTagMarkupAndPutListeners: function (transaction) {
258
- var props = this._currentElement.props;
259
- var ret = '<' + this._tag;
427
+ _createOpenTagMarkupAndPutListeners: function (transaction, props) {
428
+ var ret = '<' + this._currentElement.type;
260
429
 
261
430
  for (var propKey in props) {
262
431
  if (!props.hasOwnProperty(propKey)) {
@@ -279,7 +448,12 @@ ReactDOMComponent.Mixin = {
279
448
  }
280
449
  propValue = CSSPropertyOperations.createMarkupForStyles(propValue);
281
450
  }
282
- var markup = DOMPropertyOperations.createMarkupForProperty(propKey, propValue);
451
+ var markup = null;
452
+ if (this._tag != null && isCustomComponent(this._tag, props)) {
453
+ markup = DOMPropertyOperations.createMarkupForCustomAttribute(propKey, propValue);
454
+ } else {
455
+ markup = DOMPropertyOperations.createMarkupForProperty(propKey, propValue);
456
+ }
283
457
  if (markup) {
284
458
  ret += ' ' + markup;
285
459
  }
@@ -301,12 +475,12 @@ ReactDOMComponent.Mixin = {
301
475
  *
302
476
  * @private
303
477
  * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
478
+ * @param {object} props
304
479
  * @param {object} context
305
480
  * @return {string} Content markup.
306
481
  */
307
- _createContentMarkup: function (transaction, context) {
482
+ _createContentMarkup: function (transaction, props, context) {
308
483
  var ret = '';
309
- var props = this._currentElement.props;
310
484
 
311
485
  // Intentional use of != to avoid catching zero/false.
312
486
  var innerHTML = props.dangerouslySetInnerHTML;
@@ -367,9 +541,47 @@ ReactDOMComponent.Mixin = {
367
541
  * @overridable
368
542
  */
369
543
  updateComponent: function (transaction, prevElement, nextElement, context) {
370
- assertValidProps(this, this._currentElement.props);
371
- this._updateDOMProperties(prevElement.props, transaction);
372
- this._updateDOMChildren(prevElement.props, transaction, processChildContext(context, this));
544
+ var lastProps = prevElement.props;
545
+ var nextProps = this._currentElement.props;
546
+
547
+ switch (this._tag) {
548
+ case 'button':
549
+ lastProps = ReactDOMButton.getNativeProps(this, lastProps);
550
+ nextProps = ReactDOMButton.getNativeProps(this, nextProps);
551
+ break;
552
+ case 'input':
553
+ ReactDOMInput.updateWrapper(this);
554
+ lastProps = ReactDOMInput.getNativeProps(this, lastProps);
555
+ nextProps = ReactDOMInput.getNativeProps(this, nextProps);
556
+ break;
557
+ case 'option':
558
+ lastProps = ReactDOMOption.getNativeProps(this, lastProps);
559
+ nextProps = ReactDOMOption.getNativeProps(this, nextProps);
560
+ break;
561
+ case 'select':
562
+ lastProps = ReactDOMSelect.getNativeProps(this, lastProps);
563
+ nextProps = ReactDOMSelect.getNativeProps(this, nextProps);
564
+ break;
565
+ case 'textarea':
566
+ ReactDOMTextarea.updateWrapper(this);
567
+ lastProps = ReactDOMTextarea.getNativeProps(this, lastProps);
568
+ nextProps = ReactDOMTextarea.getNativeProps(this, nextProps);
569
+ break;
570
+ }
571
+
572
+ assertValidProps(this, nextProps);
573
+ this._updateDOMProperties(lastProps, nextProps, transaction);
574
+ this._updateDOMChildren(lastProps, nextProps, transaction, processChildContext(context, this));
575
+
576
+ if (!canDefineProperty && this._nodeWithLegacyProperties) {
577
+ this._nodeWithLegacyProperties.props = nextProps;
578
+ }
579
+
580
+ if (this._tag === 'select') {
581
+ // <select> value update needs to occur after <option> children
582
+ // reconciliation
583
+ transaction.getReactMountReady().enqueue(postUpdateSelectWrapper, this);
584
+ }
373
585
  },
374
586
 
375
587
  /**
@@ -385,10 +597,10 @@ ReactDOMComponent.Mixin = {
385
597
  *
386
598
  * @private
387
599
  * @param {object} lastProps
600
+ * @param {object} nextProps
388
601
  * @param {ReactReconcileTransaction} transaction
389
602
  */
390
- _updateDOMProperties: function (lastProps, transaction) {
391
- var nextProps = this._currentElement.props;
603
+ _updateDOMProperties: function (lastProps, nextProps, transaction) {
392
604
  var propKey;
393
605
  var styleName;
394
606
  var styleUpdates;
@@ -412,7 +624,7 @@ ReactDOMComponent.Mixin = {
412
624
  // listener (e.g., onClick={null})
413
625
  deleteListener(this._rootNodeID, propKey);
414
626
  }
415
- } else if (DOMProperty.isStandardName[propKey] || DOMProperty.isCustomAttribute(propKey)) {
627
+ } else if (DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)) {
416
628
  BackendIDOperations.deletePropertyByID(this._rootNodeID, propKey);
417
629
  }
418
630
  }
@@ -457,7 +669,9 @@ ReactDOMComponent.Mixin = {
457
669
  } else if (lastProp) {
458
670
  deleteListener(this._rootNodeID, propKey);
459
671
  }
460
- } else if (DOMProperty.isStandardName[propKey] || DOMProperty.isCustomAttribute(propKey)) {
672
+ } else if (isCustomComponent(this._tag, nextProps)) {
673
+ BackendIDOperations.updateAttributeByID(this._rootNodeID, propKey, nextProp);
674
+ } else if (DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)) {
461
675
  BackendIDOperations.updatePropertyByID(this._rootNodeID, propKey, nextProp);
462
676
  }
463
677
  }
@@ -471,11 +685,11 @@ ReactDOMComponent.Mixin = {
471
685
  * children content.
472
686
  *
473
687
  * @param {object} lastProps
688
+ * @param {object} nextProps
474
689
  * @param {ReactReconcileTransaction} transaction
690
+ * @param {object} context
475
691
  */
476
- _updateDOMChildren: function (lastProps, transaction, context) {
477
- var nextProps = this._currentElement.props;
478
-
692
+ _updateDOMChildren: function (lastProps, nextProps, transaction, context) {
479
693
  var lastContent = CONTENT_TYPES[typeof lastProps.children] ? lastProps.children : null;
480
694
  var nextContent = CONTENT_TYPES[typeof nextProps.children] ? nextProps.children : null;
481
695
 
@@ -516,10 +730,73 @@ ReactDOMComponent.Mixin = {
516
730
  * @internal
517
731
  */
518
732
  unmountComponent: function () {
733
+ switch (this._tag) {
734
+ case 'iframe':
735
+ case 'img':
736
+ case 'form':
737
+ var listeners = this._wrapperState.listeners;
738
+ if (listeners) {
739
+ for (var i = 0; i < listeners.length; i++) {
740
+ listeners[i].remove();
741
+ }
742
+ }
743
+ break;
744
+ case 'input':
745
+ ReactDOMInput.unmountWrapper(this);
746
+ break;
747
+ case 'html':
748
+ case 'head':
749
+ case 'body':
750
+ /**
751
+ * Components like <html> <head> and <body> can't be removed or added
752
+ * easily in a cross-browser way, however it's valuable to be able to
753
+ * take advantage of React's reconciliation for styling and <title>
754
+ * management. So we just document it and throw in dangerous cases.
755
+ */
756
+ !false ? 'production' !== process.env.NODE_ENV ? invariant(false, '<%s> tried to unmount. Because of cross-browser quirks it is ' + 'impossible to unmount some top-level components (eg <html>, ' + '<head>, and <body>) reliably and efficiently. To fix this, have a ' + 'single top-level component that never unmounts render these ' + 'elements.', this._tag) : invariant(false) : undefined;
757
+ break;
758
+ }
759
+
519
760
  this.unmountChildren();
520
761
  ReactBrowserEventEmitter.deleteAllListeners(this._rootNodeID);
521
762
  ReactComponentBrowserEnvironment.unmountIDFromEnvironment(this._rootNodeID);
522
763
  this._rootNodeID = null;
764
+ this._wrapperState = null;
765
+ if (this._nodeWithLegacyProperties) {
766
+ var node = this._nodeWithLegacyProperties;
767
+ node._reactInternalComponent = null;
768
+ this._nodeWithLegacyProperties = null;
769
+ }
770
+ },
771
+
772
+ getPublicInstance: function () {
773
+ if (!this._nodeWithLegacyProperties) {
774
+ var node = ReactMount.getNode(this._rootNodeID);
775
+
776
+ node._reactInternalComponent = this;
777
+ node.getDOMNode = legacyGetDOMNode;
778
+ node.isMounted = legacyIsMounted;
779
+ node.setState = legacySetStateEtc;
780
+ node.replaceState = legacySetStateEtc;
781
+ node.forceUpdate = legacySetStateEtc;
782
+ node.setProps = legacySetProps;
783
+ node.replaceProps = legacyReplaceProps;
784
+
785
+ if ('production' !== process.env.NODE_ENV) {
786
+ if (canDefineProperty) {
787
+ Object.defineProperties(node, legacyPropsDescriptor);
788
+ } else {
789
+ // updateComponent will update this property on subsequent renders
790
+ node.props = this._currentElement.props;
791
+ }
792
+ } else {
793
+ // updateComponent will update this property on subsequent renders
794
+ node.props = this._currentElement.props;
795
+ }
796
+
797
+ this._nodeWithLegacyProperties = node;
798
+ }
799
+ return this._nodeWithLegacyProperties;
523
800
  }
524
801
 
525
802
  };
@@ -537,4 +814,5 @@ ReactDOMComponent.injection = {
537
814
  }
538
815
  };
539
816
 
540
- module.exports = ReactDOMComponent;
817
+ module.exports = ReactDOMComponent;
818
+ // NOTE: menuitem's close tag should be omitted, but that causes problems.