react 0.13.3 → 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 (189) hide show
  1. package/README.md +5 -2
  2. package/addons.js +7 -0
  3. package/dist/JSXTransformer.js +4101 -2432
  4. package/dist/react-with-addons.js +4389 -6277
  5. package/dist/react-with-addons.min.js +6 -8
  6. package/dist/react.js +4028 -5697
  7. package/dist/react.min.js +5 -6
  8. package/lib/{AutoFocusMixin.js → AutoFocusUtils.js} +16 -5
  9. package/lib/BeforeInputEventPlugin.js +30 -118
  10. package/lib/CSSCore.js +12 -23
  11. package/lib/CSSProperty.js +4 -3
  12. package/lib/CSSPropertyOperations.js +14 -30
  13. package/lib/CallbackQueue.js +7 -10
  14. package/lib/ChangeEventPlugin.js +26 -88
  15. package/lib/ClientReactRootIndex.js +2 -2
  16. package/lib/DOMChildrenOperations.js +13 -33
  17. package/lib/DOMProperty.js +86 -147
  18. package/lib/DOMPropertyOperations.js +91 -67
  19. package/lib/Danger.js +19 -62
  20. package/lib/DefaultEventPluginOrder.js +2 -12
  21. package/lib/EnterLeaveEventPlugin.js +11 -33
  22. package/lib/EventConstants.js +2 -2
  23. package/lib/EventListener.js +11 -13
  24. package/lib/EventPluginHub.js +44 -47
  25. package/lib/EventPluginRegistry.js +18 -74
  26. package/lib/EventPluginUtils.js +33 -44
  27. package/lib/EventPropagators.js +23 -26
  28. package/lib/ExecutionEnvironment.js +4 -8
  29. package/lib/FallbackCompositionState.js +3 -3
  30. package/lib/HTMLDOMPropertyConfig.js +15 -20
  31. package/lib/LinkedStateMixin.js +3 -6
  32. package/lib/LinkedValueUtils.js +71 -89
  33. package/lib/Object.assign.js +1 -1
  34. package/lib/PooledClass.js +20 -11
  35. package/lib/React.js +9 -129
  36. package/lib/ReactBrowserComponentMixin.js +9 -2
  37. package/lib/ReactBrowserEventEmitter.js +26 -82
  38. package/lib/ReactCSSTransitionGroup.js +13 -24
  39. package/lib/ReactCSSTransitionGroupChild.js +26 -28
  40. package/lib/ReactChildReconciler.js +11 -19
  41. package/lib/ReactChildren.js +24 -31
  42. package/lib/ReactClass.js +96 -267
  43. package/lib/ReactComponent.js +28 -57
  44. package/lib/ReactComponentBrowserEnvironment.js +4 -8
  45. package/lib/ReactComponentEnvironment.js +6 -12
  46. package/lib/ReactComponentWithPureRenderMixin.js +6 -7
  47. package/lib/ReactCompositeComponent.js +115 -381
  48. package/lib/ReactCurrentOwner.js +1 -3
  49. package/lib/ReactDOM.js +4 -2
  50. package/lib/ReactDOMButton.js +16 -28
  51. package/lib/ReactDOMClient.js +90 -0
  52. package/lib/ReactDOMComponent.js +468 -156
  53. package/lib/ReactDOMIDOperations.js +25 -22
  54. package/lib/ReactDOMInput.js +79 -108
  55. package/lib/ReactDOMOption.js +58 -20
  56. package/lib/ReactDOMSelect.js +95 -83
  57. package/lib/ReactDOMSelection.js +5 -20
  58. package/lib/ReactDOMServer.js +24 -0
  59. package/lib/ReactDOMTextComponent.js +17 -18
  60. package/lib/ReactDOMTextarea.js +44 -69
  61. package/lib/ReactDefaultBatchingStrategy.js +9 -13
  62. package/lib/ReactDefaultInjection.js +20 -76
  63. package/lib/ReactDefaultPerf.js +36 -69
  64. package/lib/ReactDefaultPerfAnalysis.js +8 -14
  65. package/lib/ReactElement.js +26 -120
  66. package/lib/ReactElementValidator.js +56 -192
  67. package/lib/ReactEmptyComponent.js +7 -11
  68. package/lib/ReactErrorUtils.js +3 -3
  69. package/lib/ReactEventEmitterMixin.js +3 -13
  70. package/lib/ReactEventListener.js +58 -40
  71. package/lib/ReactFragment.js +33 -59
  72. package/lib/ReactInjection.js +1 -1
  73. package/lib/ReactInputSelection.js +14 -23
  74. package/lib/ReactInstanceHandles.js +29 -58
  75. package/lib/ReactInstanceMap.js +5 -5
  76. package/lib/ReactIsomorphic.js +70 -0
  77. package/lib/ReactLink.js +2 -4
  78. package/lib/ReactMarkupChecksum.js +5 -10
  79. package/lib/ReactMount.js +142 -285
  80. package/lib/ReactMultiChild.js +19 -45
  81. package/lib/ReactMultiChildUpdateTypes.js +1 -1
  82. package/lib/ReactNativeComponent.js +6 -15
  83. package/lib/ReactNoopUpdateQueue.js +118 -0
  84. package/lib/ReactOwner.js +7 -24
  85. package/lib/ReactPerf.js +8 -12
  86. package/lib/ReactPropTransferer.js +4 -4
  87. package/lib/ReactPropTypeLocationNames.js +2 -2
  88. package/lib/ReactPropTypeLocations.js +1 -1
  89. package/lib/ReactPropTypes.js +41 -61
  90. package/lib/ReactReconcileTransaction.js +11 -36
  91. package/lib/ReactReconciler.js +14 -26
  92. package/lib/ReactRef.js +5 -8
  93. package/lib/ReactRootIndex.js +2 -2
  94. package/lib/ReactServerBatchingStrategy.js +23 -0
  95. package/lib/ReactServerRendering.js +20 -15
  96. package/lib/ReactServerRenderingTransaction.js +9 -34
  97. package/lib/ReactStateSetters.js +6 -6
  98. package/lib/ReactTestUtils.js +137 -190
  99. package/lib/ReactTransitionChildMapping.js +5 -7
  100. package/lib/ReactTransitionEvents.js +5 -5
  101. package/lib/ReactTransitionGroup.js +30 -52
  102. package/lib/ReactUpdateQueue.js +69 -107
  103. package/lib/ReactUpdates.js +26 -81
  104. package/lib/ReactWithAddons.js +5 -6
  105. package/lib/SVGDOMPropertyConfig.js +39 -4
  106. package/lib/SelectEventPlugin.js +31 -33
  107. package/lib/ServerReactRootIndex.js +2 -2
  108. package/lib/SimpleEventPlugin.js +138 -130
  109. package/lib/SyntheticClipboardEvent.js +5 -9
  110. package/lib/SyntheticCompositionEvent.js +4 -10
  111. package/lib/SyntheticDragEvent.js +3 -3
  112. package/lib/SyntheticEvent.js +14 -15
  113. package/lib/SyntheticFocusEvent.js +3 -3
  114. package/lib/SyntheticInputEvent.js +4 -10
  115. package/lib/SyntheticKeyboardEvent.js +6 -6
  116. package/lib/SyntheticMouseEvent.js +10 -16
  117. package/lib/SyntheticTouchEvent.js +3 -3
  118. package/lib/SyntheticUIEvent.js +5 -5
  119. package/lib/SyntheticWheelEvent.js +13 -17
  120. package/lib/Transaction.js +22 -28
  121. package/lib/ViewportMetrics.js +2 -2
  122. package/lib/accumulateInto.js +2 -5
  123. package/lib/adler32.js +2 -4
  124. package/lib/camelize.js +4 -2
  125. package/lib/camelizeStyleName.js +2 -2
  126. package/lib/cloneWithProps.js +6 -12
  127. package/lib/containsNode.js +29 -16
  128. package/lib/createArrayFromMixed.js +17 -16
  129. package/lib/createNodesFromMarkup.js +6 -8
  130. package/lib/dangerousStyleValue.js +2 -3
  131. package/lib/deprecated.js +47 -0
  132. package/lib/emptyFunction.js +10 -4
  133. package/lib/emptyObject.js +1 -1
  134. package/lib/escapeTextContentForBrowser.js +1 -1
  135. package/lib/findDOMNode.js +7 -27
  136. package/lib/flattenChildren.js +4 -10
  137. package/lib/focusNode.js +2 -3
  138. package/lib/forEachAccumulated.js +3 -3
  139. package/lib/getActiveElement.js +4 -2
  140. package/lib/getEventCharCode.js +2 -2
  141. package/lib/getEventKey.js +1 -1
  142. package/lib/getEventModifierState.js +1 -2
  143. package/lib/getEventTarget.js +1 -1
  144. package/lib/getIteratorFn.js +2 -4
  145. package/lib/getMarkupWrap.js +18 -40
  146. package/lib/getNodeForCharacterOffset.js +1 -1
  147. package/lib/getTextContentAccessor.js +2 -4
  148. package/lib/getUnboundedScrollPosition.js +1 -1
  149. package/lib/hyphenate.js +3 -1
  150. package/lib/hyphenateStyleName.js +2 -2
  151. package/lib/instantiateReactComponent.js +23 -43
  152. package/lib/invariant.js +8 -12
  153. package/lib/isEventSupported.js +7 -10
  154. package/lib/isNode.js +4 -6
  155. package/lib/isTextInputElement.js +3 -4
  156. package/lib/isTextNode.js +3 -1
  157. package/lib/joinClasses.js +3 -3
  158. package/lib/keyMirror.js +3 -6
  159. package/lib/keyOf.js +4 -3
  160. package/lib/mapObject.js +1 -1
  161. package/lib/memoizeStringOnly.js +2 -2
  162. package/lib/onlyChild.js +2 -5
  163. package/lib/performance.js +2 -5
  164. package/lib/performanceNow.js +3 -1
  165. package/lib/quoteAttributeValueForBrowser.js +1 -1
  166. package/lib/renderSubtreeIntoContainer.js +16 -0
  167. package/lib/setInnerHTML.js +11 -8
  168. package/lib/setTextContent.js +3 -3
  169. package/lib/shallowCompare.js +24 -0
  170. package/lib/shallowEqual.js +17 -11
  171. package/lib/shouldUpdateReactComponent.js +3 -64
  172. package/lib/toArray.js +8 -19
  173. package/lib/traverseAllChildren.js +23 -90
  174. package/lib/update.js +25 -85
  175. package/lib/validateDOMNesting.js +363 -0
  176. package/lib/warning.js +15 -17
  177. package/package.json +3 -3
  178. package/react.js +53 -1
  179. package/lib/LocalEventTrapMixin.js +0 -53
  180. package/lib/MobileSafariClickEventPlugin.js +0 -56
  181. package/lib/ReactContext.js +0 -74
  182. package/lib/ReactDOMForm.js +0 -47
  183. package/lib/ReactDOMIframe.js +0 -43
  184. package/lib/ReactDOMImg.js +0 -44
  185. package/lib/ReactLifeCycle.js +0 -35
  186. package/lib/ReactPutListenerQueue.js +0 -54
  187. package/lib/createFullPageComponent.js +0 -58
  188. package/lib/cx.js +0 -52
  189. package/lib/getReactRootElementInContainer.js +0 -33
@@ -16,8 +16,6 @@
16
16
  *
17
17
  * The current owner is the component who should own any components that are
18
18
  * currently being constructed.
19
- *
20
- * The depth indicate how many composite components are above this render level.
21
19
  */
22
20
  var ReactCurrentOwner = {
23
21
 
@@ -29,4 +27,4 @@ var ReactCurrentOwner = {
29
27
 
30
28
  };
31
29
 
32
- module.exports = ReactCurrentOwner;
30
+ module.exports = ReactCurrentOwner;
package/lib/ReactDOM.js CHANGED
@@ -24,7 +24,7 @@ var mapObject = require("./mapObject");
24
24
  * @private
25
25
  */
26
26
  function createDOMFactory(tag) {
27
- if ("production" !== process.env.NODE_ENV) {
27
+ if ('production' !== process.env.NODE_ENV) {
28
28
  return ReactElementValidator.createFactory(tag);
29
29
  }
30
30
  return ReactElement.createFactory(tag);
@@ -84,6 +84,7 @@ var ReactDOM = mapObject({
84
84
  h6: 'h6',
85
85
  head: 'head',
86
86
  header: 'header',
87
+ hgroup: 'hgroup',
87
88
  hr: 'hr',
88
89
  html: 'html',
89
90
  i: 'i',
@@ -156,6 +157,7 @@ var ReactDOM = mapObject({
156
157
  defs: 'defs',
157
158
  ellipse: 'ellipse',
158
159
  g: 'g',
160
+ image: 'image',
159
161
  line: 'line',
160
162
  linearGradient: 'linearGradient',
161
163
  mask: 'mask',
@@ -172,4 +174,4 @@ var ReactDOM = mapObject({
172
174
 
173
175
  }, createDOMFactory);
174
176
 
175
- module.exports = ReactDOM;
177
+ module.exports = ReactDOM;
@@ -11,52 +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) &&
52
- (!this.props.disabled || !mouseListenerNames[key])) {
53
- 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];
54
43
  }
55
44
  }
56
45
 
57
- return button(props, this.props.children);
46
+ return nativeProps;
58
47
  }
48
+ };
59
49
 
60
- });
61
-
62
- module.exports = ReactDOMButton;
50
+ module.exports = ReactDOMButton;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Copyright 2013-2015, 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 ReactDOMClient
10
+ */
11
+
12
+ /* globals __REACT_DEVTOOLS_GLOBAL_HOOK__*/
13
+
14
+ 'use strict';
15
+
16
+ var ReactCurrentOwner = require("./ReactCurrentOwner");
17
+ var ReactDOMTextComponent = require("./ReactDOMTextComponent");
18
+ var ReactDefaultInjection = require("./ReactDefaultInjection");
19
+ var ReactInstanceHandles = require("./ReactInstanceHandles");
20
+ var ReactMount = require("./ReactMount");
21
+ var ReactPerf = require("./ReactPerf");
22
+ var ReactReconciler = require("./ReactReconciler");
23
+ var ReactUpdates = require("./ReactUpdates");
24
+
25
+ var findDOMNode = require("./findDOMNode");
26
+ var renderSubtreeIntoContainer = require("./renderSubtreeIntoContainer");
27
+ var warning = require("./warning");
28
+
29
+ ReactDefaultInjection.inject();
30
+
31
+ var render = ReactPerf.measure('React', 'render', ReactMount.render);
32
+
33
+ var React = {
34
+ findDOMNode: findDOMNode,
35
+ render: render,
36
+ unmountComponentAtNode: ReactMount.unmountComponentAtNode,
37
+
38
+ /* eslint-disable camelcase */
39
+ unstable_batchedUpdates: ReactUpdates.batchedUpdates,
40
+ unstable_renderSubtreeIntoContainer: renderSubtreeIntoContainer
41
+ };
42
+
43
+ // Inject the runtime into a devtools global hook regardless of browser.
44
+ // Allows for debugging when the hook is injected on the page.
45
+ if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function') {
46
+ __REACT_DEVTOOLS_GLOBAL_HOOK__.inject({
47
+ CurrentOwner: ReactCurrentOwner,
48
+ InstanceHandles: ReactInstanceHandles,
49
+ Mount: ReactMount,
50
+ Reconciler: ReactReconciler,
51
+ TextComponent: ReactDOMTextComponent
52
+ });
53
+ }
54
+
55
+ if ('production' !== process.env.NODE_ENV) {
56
+ var ExecutionEnvironment = require("./ExecutionEnvironment");
57
+ if (ExecutionEnvironment.canUseDOM && window.top === window.self) {
58
+
59
+ // If we're in Chrome, look for the devtools marker and provide a download
60
+ // link if not installed.
61
+ if (navigator.userAgent.indexOf('Chrome') > -1) {
62
+ if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {
63
+ console.debug('Download the React DevTools for a better development experience: ' + 'https://fb.me/react-devtools');
64
+ }
65
+ }
66
+
67
+ // If we're in IE8, check to see if we are in combatibility mode and provide
68
+ // information on preventing compatibility mode
69
+ var ieCompatibilityMode = document.documentMode && document.documentMode < 8;
70
+
71
+ 'production' !== process.env.NODE_ENV ? warning(!ieCompatibilityMode, 'Internet Explorer is running in compatibility mode; please add the ' + 'following tag to your HTML to prevent this from happening: ' + '<meta http-equiv="X-UA-Compatible" content="IE=edge" />') : undefined;
72
+
73
+ var expectedFeatures = [
74
+ // shims
75
+ Array.isArray, Array.prototype.every, Array.prototype.forEach, Array.prototype.indexOf, Array.prototype.map, Date.now, Function.prototype.bind, Object.keys, String.prototype.split, String.prototype.trim,
76
+
77
+ // shams
78
+ Object.create, Object.freeze];
79
+
80
+ for (var i = 0; i < expectedFeatures.length; i++) {
81
+ if (!expectedFeatures[i]) {
82
+ console.error('One or more ES5 shim/shams expected by React are not available: ' + 'https://fb.me/react-warning-polyfills');
83
+ break;
84
+ }
85
+ }
86
+ }
87
+ }
88
+
89
+ module.exports = React;
90
+ /* eslint-enable camelcase */
@@ -14,21 +14,30 @@
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
- var ReactComponentBrowserEnvironment =
22
- require("./ReactComponentBrowserEnvironment");
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");
23
29
  var ReactMount = require("./ReactMount");
24
30
  var ReactMultiChild = require("./ReactMultiChild");
25
31
  var ReactPerf = require("./ReactPerf");
32
+ var ReactUpdateQueue = require("./ReactUpdateQueue");
26
33
 
27
34
  var assign = require("./Object.assign");
28
35
  var escapeTextContentForBrowser = require("./escapeTextContentForBrowser");
29
36
  var invariant = require("./invariant");
30
37
  var isEventSupported = require("./isEventSupported");
31
38
  var keyOf = require("./keyOf");
39
+ var shallowEqual = require("./shallowEqual");
40
+ var validateDOMNesting = require("./validateDOMNesting");
32
41
  var warning = require("./warning");
33
42
 
34
43
  var deleteListener = ReactBrowserEventEmitter.deleteListener;
@@ -36,82 +45,200 @@ var listenTo = ReactBrowserEventEmitter.listenTo;
36
45
  var registrationNameModules = ReactBrowserEventEmitter.registrationNameModules;
37
46
 
38
47
  // For quickly matching children type, to test if can be treated as content.
39
- var CONTENT_TYPES = {'string': true, 'number': true};
48
+ var CONTENT_TYPES = { 'string': true, 'number': true };
40
49
 
41
- var STYLE = keyOf({style: null});
50
+ var STYLE = keyOf({ style: null });
42
51
 
43
52
  var ELEMENT_NODE_TYPE = 1;
44
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
+
138
+ var styleMutationWarning = {};
139
+
140
+ function checkAndWarnForMutatedStyle(style1, style2, component) {
141
+ if (style1 == null || style2 == null) {
142
+ return;
143
+ }
144
+ if (shallowEqual(style1, style2)) {
145
+ return;
146
+ }
147
+
148
+ var componentName = component._tag;
149
+ var owner = component._currentElement._owner;
150
+ var ownerName;
151
+ if (owner) {
152
+ ownerName = owner.getName();
153
+ }
154
+
155
+ var hash = ownerName + '|' + componentName;
156
+
157
+ if (styleMutationWarning.hasOwnProperty(hash)) {
158
+ return;
159
+ }
160
+
161
+ styleMutationWarning[hash] = true;
162
+
163
+ 'production' !== process.env.NODE_ENV ? warning(false, '`%s` was passed a style object that has previously been mutated. ' + 'Mutating `style` is deprecated. Consider cloning it beforehand. Check ' + 'the `render` %s. Previous style: %s. Mutated style: %s.', componentName, owner ? 'of `' + ownerName + '`' : 'using <' + componentName + '>', JSON.stringify(style1), JSON.stringify(style2)) : undefined;
164
+ }
165
+
45
166
  /**
46
167
  * Optionally injectable operations for mutating the DOM
47
168
  */
48
169
  var BackendIDOperations = null;
49
170
 
50
171
  /**
172
+ * @param {object} component
51
173
  * @param {?object} props
52
174
  */
53
- function assertValidProps(props) {
175
+ function assertValidProps(component, props) {
54
176
  if (!props) {
55
177
  return;
56
178
  }
57
179
  // Note the use of `==` which checks for null or undefined.
180
+ if ('production' !== process.env.NODE_ENV) {
181
+ if (voidElementTags[component._tag]) {
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;
183
+ }
184
+ }
58
185
  if (props.dangerouslySetInnerHTML != null) {
59
- ("production" !== process.env.NODE_ENV ? invariant(
60
- props.children == null,
61
- 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.'
62
- ) : invariant(props.children == null));
63
- ("production" !== process.env.NODE_ENV ? invariant(
64
- typeof props.dangerouslySetInnerHTML === 'object' &&
65
- '__html' in props.dangerouslySetInnerHTML,
66
- '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' +
67
- 'Please visit https://fb.me/react-invariant-dangerously-set-inner-html ' +
68
- 'for more information.'
69
- ) : invariant(typeof props.dangerouslySetInnerHTML === 'object' &&
70
- '__html' in props.dangerouslySetInnerHTML));
186
+ !(props.children == null) ? 'production' !== process.env.NODE_ENV ? invariant(false, 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.') : invariant(false) : undefined;
187
+ !(typeof props.dangerouslySetInnerHTML === 'object' && '__html' in props.dangerouslySetInnerHTML) ? 'production' !== process.env.NODE_ENV ? invariant(false, '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' + 'Please visit https://fb.me/react-invariant-dangerously-set-inner-html ' + 'for more information.') : invariant(false) : undefined;
71
188
  }
72
- if ("production" !== process.env.NODE_ENV) {
73
- ("production" !== process.env.NODE_ENV ? warning(
74
- props.innerHTML == null,
75
- 'Directly setting property `innerHTML` is not permitted. ' +
76
- 'For more information, lookup documentation on `dangerouslySetInnerHTML`.'
77
- ) : null);
78
- ("production" !== process.env.NODE_ENV ? warning(
79
- !props.contentEditable || props.children == null,
80
- 'A component is `contentEditable` and contains `children` managed by ' +
81
- 'React. It is now your responsibility to guarantee that none of ' +
82
- 'those nodes are unexpectedly modified or duplicated. This is ' +
83
- 'probably not intentional.'
84
- ) : null);
189
+ if ('production' !== process.env.NODE_ENV) {
190
+ 'production' !== process.env.NODE_ENV ? warning(props.innerHTML == null, 'Directly setting property `innerHTML` is not permitted. ' + 'For more information, lookup documentation on `dangerouslySetInnerHTML`.') : undefined;
191
+ 'production' !== process.env.NODE_ENV ? warning(!props.contentEditable || props.children == null, 'A component is `contentEditable` and contains `children` managed by ' + 'React. It is now your responsibility to guarantee that none of ' + 'those nodes are unexpectedly modified or duplicated. This is ' + 'probably not intentional.') : undefined;
85
192
  }
86
- ("production" !== process.env.NODE_ENV ? invariant(
87
- props.style == null || typeof props.style === 'object',
88
- 'The `style` prop expects a mapping from style properties to values, ' +
89
- 'not a string. For example, style={{marginRight: spacing + \'em\'}} when ' +
90
- 'using JSX.'
91
- ) : invariant(props.style == null || typeof props.style === 'object'));
193
+ !(props.style == null || typeof props.style === 'object') ? 'production' !== process.env.NODE_ENV ? invariant(false, 'The `style` prop expects a mapping from style properties to values, ' + 'not a string. For example, style={{marginRight: spacing + \'em\'}} when ' + 'using JSX.') : invariant(false) : undefined;
92
194
  }
93
195
 
94
- function putListener(id, registrationName, listener, transaction) {
95
- if ("production" !== process.env.NODE_ENV) {
196
+ function enqueuePutListener(id, registrationName, listener, transaction) {
197
+ if ('production' !== process.env.NODE_ENV) {
96
198
  // IE8 has no API for event capturing and the `onScroll` event doesn't
97
199
  // bubble.
98
- ("production" !== process.env.NODE_ENV ? warning(
99
- registrationName !== 'onScroll' || isEventSupported('scroll', true),
100
- 'This browser doesn\'t support the `onScroll` event'
101
- ) : null);
200
+ 'production' !== process.env.NODE_ENV ? warning(registrationName !== 'onScroll' || isEventSupported('scroll', true), 'This browser doesn\'t support the `onScroll` event') : undefined;
102
201
  }
103
202
  var container = ReactMount.findReactContainerForID(id);
104
203
  if (container) {
105
- var doc = container.nodeType === ELEMENT_NODE_TYPE ?
106
- container.ownerDocument :
107
- container;
204
+ var doc = container.nodeType === ELEMENT_NODE_TYPE ? container.ownerDocument : container;
108
205
  listenTo(registrationName, doc);
109
206
  }
110
- transaction.getPutListenerQueue().enqueuePutListener(
111
- id,
112
- registrationName,
113
- listener
114
- );
207
+ transaction.getReactMountReady().enqueue(putListener, {
208
+ id: id,
209
+ registrationName: registrationName,
210
+ listener: listener
211
+ });
212
+ }
213
+
214
+ function putListener() {
215
+ var listenerToPut = this;
216
+ ReactBrowserEventEmitter.putListener(listenerToPut.id, listenerToPut.registrationName, listenerToPut.listener);
217
+ }
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);
115
242
  }
116
243
 
117
244
  // For HTML, certain tags should omit their close tag. We keep a whitelist for
@@ -133,24 +260,50 @@ var omittedCloseTags = {
133
260
  'source': true,
134
261
  'track': true,
135
262
  'wbr': true
136
- // NOTE: menuitem's close tag should be omitted, but that causes problems.
137
263
  };
138
264
 
139
- // We accept any tag to be rendered but since this gets injected into abitrary
265
+ var newlineEatingTags = {
266
+ 'listing': true,
267
+ 'pre': true,
268
+ 'textarea': true
269
+ };
270
+
271
+ // For HTML, certain tags cannot have children. This has the same purpose as
272
+ // `omittedCloseTags` except that `menuitem` should still have its closing tag.
273
+
274
+ var voidElementTags = assign({
275
+ 'menuitem': true
276
+ }, omittedCloseTags);
277
+
278
+ // We accept any tag to be rendered but since this gets injected into arbitrary
140
279
  // HTML, we want to make sure that it's a safe tag.
141
280
  // http://www.w3.org/TR/REC-xml/#NT-Name
142
281
 
143
282
  var VALID_TAG_REGEX = /^[a-zA-Z][a-zA-Z:_\.\-\d]*$/; // Simplified subset
144
283
  var validatedTagCache = {};
145
- var hasOwnProperty = {}.hasOwnProperty;
284
+ var hasOwnProperty = ({}).hasOwnProperty;
146
285
 
147
286
  function validateDangerousTag(tag) {
148
287
  if (!hasOwnProperty.call(validatedTagCache, tag)) {
149
- ("production" !== process.env.NODE_ENV ? invariant(VALID_TAG_REGEX.test(tag), 'Invalid tag: %s', tag) : invariant(VALID_TAG_REGEX.test(tag)));
288
+ !VALID_TAG_REGEX.test(tag) ? 'production' !== process.env.NODE_ENV ? invariant(false, 'Invalid tag: %s', tag) : invariant(false) : undefined;
150
289
  validatedTagCache[tag] = true;
151
290
  }
152
291
  }
153
292
 
293
+ function processChildContext(context, inst) {
294
+ if ('production' !== process.env.NODE_ENV) {
295
+ // Pass down our tag name to child components for validation purposes
296
+ context = assign({}, context);
297
+ var info = context[validateDOMNesting.ancestorInfoContextKey];
298
+ context[validateDOMNesting.ancestorInfoContextKey] = validateDOMNesting.updatedAncestorInfo(info, inst._tag, inst);
299
+ }
300
+ return context;
301
+ }
302
+
303
+ function isCustomComponent(tagName, props) {
304
+ return tagName.indexOf('-') >= 0 || props.is != null;
305
+ }
306
+
154
307
  /**
155
308
  * Creates a new React class that is idempotent and capable of containing other
156
309
  * React components. It accepts event listeners and DOM properties that are
@@ -167,17 +320,21 @@ function validateDangerousTag(tag) {
167
320
  */
168
321
  function ReactDOMComponent(tag) {
169
322
  validateDangerousTag(tag);
170
- this._tag = tag;
323
+ this._tag = tag.toLowerCase();
171
324
  this._renderedChildren = null;
325
+ this._previousStyle = null;
172
326
  this._previousStyleCopy = null;
173
327
  this._rootNodeID = null;
328
+ this._wrapperState = null;
329
+ this._topLevelWrapper = null;
330
+ this._nodeWithLegacyProperties = null;
174
331
  }
175
332
 
176
333
  ReactDOMComponent.displayName = 'ReactDOMComponent';
177
334
 
178
335
  ReactDOMComponent.Mixin = {
179
336
 
180
- construct: function(element) {
337
+ construct: function (element) {
181
338
  this._currentElement = element;
182
339
  },
183
340
 
@@ -188,17 +345,70 @@ ReactDOMComponent.Mixin = {
188
345
  * @internal
189
346
  * @param {string} rootID The root DOM ID for this node.
190
347
  * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
348
+ * @param {object} context
191
349
  * @return {string} The computed markup.
192
350
  */
193
- mountComponent: function(rootID, transaction, context) {
351
+ mountComponent: function (rootID, transaction, context) {
194
352
  this._rootNodeID = rootID;
195
- assertValidProps(this._currentElement.props);
196
- var closeTag = omittedCloseTags[this._tag] ? '' : '</' + this._tag + '>';
197
- return (
198
- this._createOpenTagMarkupAndPutListeners(transaction) +
199
- this._createContentMarkup(transaction, context) +
200
- closeTag
201
- );
353
+
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);
388
+ if ('production' !== process.env.NODE_ENV) {
389
+ if (context[validateDOMNesting.ancestorInfoContextKey]) {
390
+ validateDOMNesting(this._tag, this, context[validateDOMNesting.ancestorInfoContextKey]);
391
+ }
392
+ }
393
+
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
+
408
+ if (!tagContent && omittedCloseTags[this._tag]) {
409
+ return tagOpen + '/>';
410
+ }
411
+ return tagOpen + '>' + tagContent + '</' + this._currentElement.type + '>';
202
412
  },
203
413
 
204
414
  /**
@@ -211,11 +421,11 @@ ReactDOMComponent.Mixin = {
211
421
  *
212
422
  * @private
213
423
  * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
424
+ * @param {object} props
214
425
  * @return {string} Markup of opening tag.
215
426
  */
216
- _createOpenTagMarkupAndPutListeners: function(transaction) {
217
- var props = this._currentElement.props;
218
- var ret = '<' + this._tag;
427
+ _createOpenTagMarkupAndPutListeners: function (transaction, props) {
428
+ var ret = '<' + this._currentElement.type;
219
429
 
220
430
  for (var propKey in props) {
221
431
  if (!props.hasOwnProperty(propKey)) {
@@ -226,16 +436,24 @@ ReactDOMComponent.Mixin = {
226
436
  continue;
227
437
  }
228
438
  if (registrationNameModules.hasOwnProperty(propKey)) {
229
- putListener(this._rootNodeID, propKey, propValue, transaction);
439
+ enqueuePutListener(this._rootNodeID, propKey, propValue, transaction);
230
440
  } else {
231
441
  if (propKey === STYLE) {
232
442
  if (propValue) {
443
+ if ('production' !== process.env.NODE_ENV) {
444
+ // See `_updateDOMProperties`. style block
445
+ this._previousStyle = propValue;
446
+ }
233
447
  propValue = this._previousStyleCopy = assign({}, props.style);
234
448
  }
235
449
  propValue = CSSPropertyOperations.createMarkupForStyles(propValue);
236
450
  }
237
- var markup =
238
- 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
+ }
239
457
  if (markup) {
240
458
  ret += ' ' + markup;
241
459
  }
@@ -245,11 +463,11 @@ ReactDOMComponent.Mixin = {
245
463
  // For static pages, no need to put React ID and checksum. Saves lots of
246
464
  // bytes.
247
465
  if (transaction.renderToStaticMarkup) {
248
- return ret + '>';
466
+ return ret;
249
467
  }
250
468
 
251
469
  var markupForID = DOMPropertyOperations.createMarkupForID(this._rootNodeID);
252
- return ret + ' ' + markupForID + '>';
470
+ return ret + ' ' + markupForID;
253
471
  },
254
472
 
255
473
  /**
@@ -257,47 +475,56 @@ ReactDOMComponent.Mixin = {
257
475
  *
258
476
  * @private
259
477
  * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
478
+ * @param {object} props
260
479
  * @param {object} context
261
480
  * @return {string} Content markup.
262
481
  */
263
- _createContentMarkup: function(transaction, context) {
264
- var prefix = '';
265
- if (this._tag === 'listing' ||
266
- this._tag === 'pre' ||
267
- this._tag === 'textarea') {
268
- // Add an initial newline because browsers ignore the first newline in
269
- // a <listing>, <pre>, or <textarea> as an "authoring convenience" -- see
270
- // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody.
271
- prefix = '\n';
272
- }
273
-
274
- var props = this._currentElement.props;
482
+ _createContentMarkup: function (transaction, props, context) {
483
+ var ret = '';
275
484
 
276
485
  // Intentional use of != to avoid catching zero/false.
277
486
  var innerHTML = props.dangerouslySetInnerHTML;
278
487
  if (innerHTML != null) {
279
488
  if (innerHTML.__html != null) {
280
- return prefix + innerHTML.__html;
489
+ ret = innerHTML.__html;
281
490
  }
282
491
  } else {
283
- var contentToUse =
284
- CONTENT_TYPES[typeof props.children] ? props.children : null;
492
+ var contentToUse = CONTENT_TYPES[typeof props.children] ? props.children : null;
285
493
  var childrenToUse = contentToUse != null ? null : props.children;
286
494
  if (contentToUse != null) {
287
- return prefix + escapeTextContentForBrowser(contentToUse);
495
+ // TODO: Validate that text is allowed as a child of this node
496
+ ret = escapeTextContentForBrowser(contentToUse);
288
497
  } else if (childrenToUse != null) {
289
- var mountImages = this.mountChildren(
290
- childrenToUse,
291
- transaction,
292
- context
293
- );
294
- return prefix + mountImages.join('');
498
+ var mountImages = this.mountChildren(childrenToUse, transaction, processChildContext(context, this));
499
+ ret = mountImages.join('');
295
500
  }
296
501
  }
297
- return prefix;
502
+ if (newlineEatingTags[this._tag] && ret.charAt(0) === '\n') {
503
+ // text/html ignores the first character in these tags if it's a newline
504
+ // Prefer to break application/xml over text/html (for now) by adding
505
+ // a newline specifically to get eaten by the parser. (Alternately for
506
+ // textareas, replacing "^\n" with "\r\n" doesn't get eaten, and the first
507
+ // \r is normalized out by HTMLTextAreaElement#value.)
508
+ // See: <http://www.w3.org/TR/html-polyglot/#newlines-in-textarea-and-pre>
509
+ // See: <http://www.w3.org/TR/html5/syntax.html#element-restrictions>
510
+ // See: <http://www.w3.org/TR/html5/syntax.html#newlines>
511
+ // See: Parsing of "textarea" "listing" and "pre" elements
512
+ // from <http://www.w3.org/TR/html5/syntax.html#parsing-main-inbody>
513
+ return '\n' + ret;
514
+ } else {
515
+ return ret;
516
+ }
298
517
  },
299
518
 
300
- receiveComponent: function(nextElement, transaction, context) {
519
+ /**
520
+ * Receives a next element and updates the component.
521
+ *
522
+ * @internal
523
+ * @param {ReactElement} nextElement
524
+ * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
525
+ * @param {object} context
526
+ */
527
+ receiveComponent: function (nextElement, transaction, context) {
301
528
  var prevElement = this._currentElement;
302
529
  this._currentElement = nextElement;
303
530
  this.updateComponent(transaction, prevElement, nextElement, context);
@@ -313,10 +540,48 @@ ReactDOMComponent.Mixin = {
313
540
  * @internal
314
541
  * @overridable
315
542
  */
316
- updateComponent: function(transaction, prevElement, nextElement, context) {
317
- assertValidProps(this._currentElement.props);
318
- this._updateDOMProperties(prevElement.props, transaction);
319
- this._updateDOMChildren(prevElement.props, transaction, context);
543
+ updateComponent: function (transaction, prevElement, nextElement, context) {
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
+ }
320
585
  },
321
586
 
322
587
  /**
@@ -332,16 +597,15 @@ ReactDOMComponent.Mixin = {
332
597
  *
333
598
  * @private
334
599
  * @param {object} lastProps
600
+ * @param {object} nextProps
335
601
  * @param {ReactReconcileTransaction} transaction
336
602
  */
337
- _updateDOMProperties: function(lastProps, transaction) {
338
- var nextProps = this._currentElement.props;
603
+ _updateDOMProperties: function (lastProps, nextProps, transaction) {
339
604
  var propKey;
340
605
  var styleName;
341
606
  var styleUpdates;
342
607
  for (propKey in lastProps) {
343
- if (nextProps.hasOwnProperty(propKey) ||
344
- !lastProps.hasOwnProperty(propKey)) {
608
+ if (nextProps.hasOwnProperty(propKey) || !lastProps.hasOwnProperty(propKey)) {
345
609
  continue;
346
610
  }
347
611
  if (propKey === STYLE) {
@@ -354,26 +618,28 @@ ReactDOMComponent.Mixin = {
354
618
  }
355
619
  this._previousStyleCopy = null;
356
620
  } else if (registrationNameModules.hasOwnProperty(propKey)) {
357
- deleteListener(this._rootNodeID, propKey);
358
- } else if (
359
- DOMProperty.isStandardName[propKey] ||
360
- DOMProperty.isCustomAttribute(propKey)) {
361
- BackendIDOperations.deletePropertyByID(
362
- this._rootNodeID,
363
- propKey
364
- );
621
+ if (lastProps[propKey]) {
622
+ // Only call deleteListener if there was a listener previously or
623
+ // else willDeleteListener gets called when there wasn't actually a
624
+ // listener (e.g., onClick={null})
625
+ deleteListener(this._rootNodeID, propKey);
626
+ }
627
+ } else if (DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)) {
628
+ BackendIDOperations.deletePropertyByID(this._rootNodeID, propKey);
365
629
  }
366
630
  }
367
631
  for (propKey in nextProps) {
368
632
  var nextProp = nextProps[propKey];
369
- var lastProp = propKey === STYLE ?
370
- this._previousStyleCopy :
371
- lastProps[propKey];
633
+ var lastProp = propKey === STYLE ? this._previousStyleCopy : lastProps[propKey];
372
634
  if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp) {
373
635
  continue;
374
636
  }
375
637
  if (propKey === STYLE) {
376
638
  if (nextProp) {
639
+ if ('production' !== process.env.NODE_ENV) {
640
+ checkAndWarnForMutatedStyle(this._previousStyleCopy, this._previousStyle, this);
641
+ this._previousStyle = nextProp;
642
+ }
377
643
  nextProp = this._previousStyleCopy = assign({}, nextProp);
378
644
  } else {
379
645
  this._previousStyleCopy = null;
@@ -381,16 +647,14 @@ ReactDOMComponent.Mixin = {
381
647
  if (lastProp) {
382
648
  // Unset styles on `lastProp` but not on `nextProp`.
383
649
  for (styleName in lastProp) {
384
- if (lastProp.hasOwnProperty(styleName) &&
385
- (!nextProp || !nextProp.hasOwnProperty(styleName))) {
650
+ if (lastProp.hasOwnProperty(styleName) && (!nextProp || !nextProp.hasOwnProperty(styleName))) {
386
651
  styleUpdates = styleUpdates || {};
387
652
  styleUpdates[styleName] = '';
388
653
  }
389
654
  }
390
655
  // Update styles that changed since `lastProp`.
391
656
  for (styleName in nextProp) {
392
- if (nextProp.hasOwnProperty(styleName) &&
393
- lastProp[styleName] !== nextProp[styleName]) {
657
+ if (nextProp.hasOwnProperty(styleName) && lastProp[styleName] !== nextProp[styleName]) {
394
658
  styleUpdates = styleUpdates || {};
395
659
  styleUpdates[styleName] = nextProp[styleName];
396
660
  }
@@ -400,22 +664,19 @@ ReactDOMComponent.Mixin = {
400
664
  styleUpdates = nextProp;
401
665
  }
402
666
  } else if (registrationNameModules.hasOwnProperty(propKey)) {
403
- putListener(this._rootNodeID, propKey, nextProp, transaction);
404
- } else if (
405
- DOMProperty.isStandardName[propKey] ||
406
- DOMProperty.isCustomAttribute(propKey)) {
407
- BackendIDOperations.updatePropertyByID(
408
- this._rootNodeID,
409
- propKey,
410
- nextProp
411
- );
667
+ if (nextProp) {
668
+ enqueuePutListener(this._rootNodeID, propKey, nextProp, transaction);
669
+ } else if (lastProp) {
670
+ deleteListener(this._rootNodeID, propKey);
671
+ }
672
+ } else if (isCustomComponent(this._tag, nextProps)) {
673
+ BackendIDOperations.updateAttributeByID(this._rootNodeID, propKey, nextProp);
674
+ } else if (DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)) {
675
+ BackendIDOperations.updatePropertyByID(this._rootNodeID, propKey, nextProp);
412
676
  }
413
677
  }
414
678
  if (styleUpdates) {
415
- BackendIDOperations.updateStylesByID(
416
- this._rootNodeID,
417
- styleUpdates
418
- );
679
+ BackendIDOperations.updateStylesByID(this._rootNodeID, styleUpdates);
419
680
  }
420
681
  },
421
682
 
@@ -424,22 +685,16 @@ ReactDOMComponent.Mixin = {
424
685
  * children content.
425
686
  *
426
687
  * @param {object} lastProps
688
+ * @param {object} nextProps
427
689
  * @param {ReactReconcileTransaction} transaction
690
+ * @param {object} context
428
691
  */
429
- _updateDOMChildren: function(lastProps, transaction, context) {
430
- var nextProps = this._currentElement.props;
431
-
432
- var lastContent =
433
- CONTENT_TYPES[typeof lastProps.children] ? lastProps.children : null;
434
- var nextContent =
435
- CONTENT_TYPES[typeof nextProps.children] ? nextProps.children : null;
692
+ _updateDOMChildren: function (lastProps, nextProps, transaction, context) {
693
+ var lastContent = CONTENT_TYPES[typeof lastProps.children] ? lastProps.children : null;
694
+ var nextContent = CONTENT_TYPES[typeof nextProps.children] ? nextProps.children : null;
436
695
 
437
- var lastHtml =
438
- lastProps.dangerouslySetInnerHTML &&
439
- lastProps.dangerouslySetInnerHTML.__html;
440
- var nextHtml =
441
- nextProps.dangerouslySetInnerHTML &&
442
- nextProps.dangerouslySetInnerHTML.__html;
696
+ var lastHtml = lastProps.dangerouslySetInnerHTML && lastProps.dangerouslySetInnerHTML.__html;
697
+ var nextHtml = nextProps.dangerouslySetInnerHTML && nextProps.dangerouslySetInnerHTML.__html;
443
698
 
444
699
  // Note the use of `!=` which checks for null or undefined.
445
700
  var lastChildren = lastContent != null ? null : lastProps.children;
@@ -461,10 +716,7 @@ ReactDOMComponent.Mixin = {
461
716
  }
462
717
  } else if (nextHtml != null) {
463
718
  if (lastHtml !== nextHtml) {
464
- BackendIDOperations.updateInnerHTMLByID(
465
- this._rootNodeID,
466
- nextHtml
467
- );
719
+ BackendIDOperations.updateInnerHTMLByID(this._rootNodeID, nextHtml);
468
720
  }
469
721
  } else if (nextChildren != null) {
470
722
  this.updateChildren(nextChildren, transaction, context);
@@ -477,11 +729,74 @@ ReactDOMComponent.Mixin = {
477
729
  *
478
730
  * @internal
479
731
  */
480
- unmountComponent: function() {
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
+
481
760
  this.unmountChildren();
482
761
  ReactBrowserEventEmitter.deleteAllListeners(this._rootNodeID);
483
762
  ReactComponentBrowserEnvironment.unmountIDFromEnvironment(this._rootNodeID);
484
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;
485
800
  }
486
801
 
487
802
  };
@@ -491,16 +806,13 @@ ReactPerf.measureMethods(ReactDOMComponent, 'ReactDOMComponent', {
491
806
  updateComponent: 'updateComponent'
492
807
  });
493
808
 
494
- assign(
495
- ReactDOMComponent.prototype,
496
- ReactDOMComponent.Mixin,
497
- ReactMultiChild.Mixin
498
- );
809
+ assign(ReactDOMComponent.prototype, ReactDOMComponent.Mixin, ReactMultiChild.Mixin);
499
810
 
500
811
  ReactDOMComponent.injection = {
501
- injectIDOperations: function(IDOperations) {
812
+ injectIDOperations: function (IDOperations) {
502
813
  ReactDOMComponent.BackendIDOperations = BackendIDOperations = IDOperations;
503
814
  }
504
815
  };
505
816
 
506
817
  module.exports = ReactDOMComponent;
818
+ // NOTE: menuitem's close tag should be omitted, but that causes problems.