react 0.14.0-beta3 → 0.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/README.md +4 -4
  2. package/addons.js +2 -0
  3. package/dist/react-with-addons.js +1941 -1364
  4. package/dist/react-with-addons.min.js +6 -6
  5. package/dist/react.js +1704 -1242
  6. package/dist/react.min.js +6 -6
  7. package/lib/CSSProperty.js +15 -3
  8. package/lib/CSSPropertyOperations.js +15 -2
  9. package/lib/ChangeEventPlugin.js +5 -2
  10. package/lib/DOMChildrenOperations.js +12 -1
  11. package/lib/DOMPropertyOperations.js +14 -1
  12. package/lib/Danger.js +9 -4
  13. package/lib/EnterLeaveEventPlugin.js +13 -5
  14. package/lib/EventConstants.js +1 -1
  15. package/lib/EventPluginHub.js +18 -10
  16. package/lib/EventPluginUtils.js +23 -27
  17. package/lib/EventPropagators.js +1 -1
  18. package/lib/FallbackCompositionState.js +6 -0
  19. package/lib/HTMLDOMPropertyConfig.js +26 -2
  20. package/lib/PooledClass.js +1 -3
  21. package/lib/React.js +14 -3
  22. package/lib/ReactBrowserComponentMixin.js +1 -1
  23. package/lib/ReactBrowserEventEmitter.js +9 -3
  24. package/lib/ReactCSSTransitionGroup.js +33 -18
  25. package/lib/ReactCSSTransitionGroupChild.js +42 -25
  26. package/lib/ReactChildReconciler.js +3 -5
  27. package/lib/ReactChildren.js +70 -30
  28. package/lib/ReactClass.js +6 -6
  29. package/lib/ReactComponent.js +7 -6
  30. package/lib/ReactCompositeComponent.js +58 -7
  31. package/lib/ReactDOM.js +7 -5
  32. package/lib/ReactDOMComponent.js +146 -46
  33. package/lib/ReactDOMFeatureFlags.js +18 -0
  34. package/lib/ReactDOMIDOperations.js +1 -60
  35. package/lib/ReactDOMInput.js +10 -1
  36. package/lib/ReactDOMSelect.js +1 -1
  37. package/lib/ReactDOMSelection.js +16 -0
  38. package/lib/ReactDOMServer.js +3 -1
  39. package/lib/ReactDOMTextComponent.js +23 -10
  40. package/lib/ReactDOMTextarea.js +3 -1
  41. package/lib/ReactDefaultInjection.js +0 -2
  42. package/lib/ReactDefaultPerf.js +10 -4
  43. package/lib/ReactDefaultPerfAnalysis.js +7 -3
  44. package/lib/ReactElement.js +72 -35
  45. package/lib/ReactElementValidator.js +31 -75
  46. package/lib/ReactEmptyComponent.js +25 -61
  47. package/lib/ReactEmptyComponentRegistry.js +48 -0
  48. package/lib/ReactErrorUtils.js +56 -9
  49. package/lib/ReactEventEmitterMixin.js +1 -1
  50. package/lib/ReactEventListener.js +16 -9
  51. package/lib/ReactFragment.js +25 -116
  52. package/lib/ReactInjection.js +0 -2
  53. package/lib/ReactIsomorphic.js +4 -0
  54. package/lib/ReactLink.js +1 -1
  55. package/lib/ReactMount.js +127 -41
  56. package/lib/ReactMultiChild.js +37 -4
  57. package/lib/ReactOwner.js +2 -2
  58. package/lib/ReactPropTransferer.js +1 -1
  59. package/lib/ReactPropTypes.js +11 -8
  60. package/lib/ReactReconcileTransaction.js +4 -2
  61. package/lib/ReactReconciler.js +16 -17
  62. package/lib/ReactRef.js +13 -1
  63. package/lib/ReactServerRenderingTransaction.js +1 -0
  64. package/lib/ReactTestUtils.js +27 -15
  65. package/lib/ReactTransitionChildMapping.js +3 -6
  66. package/lib/ReactUpdateQueue.js +4 -4
  67. package/lib/ReactUpdates.js +1 -1
  68. package/lib/ReactVersion.js +14 -0
  69. package/lib/ReactWithAddons.js +10 -1
  70. package/lib/ResponderEventPlugin.js +1 -1
  71. package/lib/SelectEventPlugin.js +11 -1
  72. package/lib/SimpleEventPlugin.js +2 -23
  73. package/lib/SyntheticEvent.js +15 -1
  74. package/lib/Transaction.js +1 -1
  75. package/lib/canDefineProperty.js +24 -0
  76. package/lib/createHierarchyRenderer.js +1 -1
  77. package/lib/deprecated.js +3 -2
  78. package/lib/findDOMNode.js +1 -1
  79. package/lib/getTestDocument.js +4 -11
  80. package/lib/instantiateReactComponent.js +3 -5
  81. package/lib/reactComponentExpect.js +6 -0
  82. package/lib/shouldUpdateReactComponent.js +12 -8
  83. package/lib/sliceChildren.js +3 -20
  84. package/lib/traverseAllChildren.js +15 -9
  85. package/package.json +2 -2
  86. package/react.js +1 -51
  87. package/dist/JSXTransformer.js +0 -17949
  88. package/lib/joinClasses.js +0 -39
  89. package/lib/memoizeStringOnly.js +0 -31
package/lib/ReactClass.js CHANGED
@@ -13,7 +13,6 @@
13
13
 
14
14
  var ReactComponent = require('./ReactComponent');
15
15
  var ReactElement = require('./ReactElement');
16
- var ReactErrorUtils = require('./ReactErrorUtils');
17
16
  var ReactPropTypeLocations = require('./ReactPropTypeLocations');
18
17
  var ReactPropTypeLocationNames = require('./ReactPropTypeLocationNames');
19
18
  var ReactNoopUpdateQueue = require('./ReactNoopUpdateQueue');
@@ -58,7 +57,7 @@ var warnedSetProps = false;
58
57
  function warnSetProps() {
59
58
  if (!warnedSetProps) {
60
59
  warnedSetProps = true;
61
- process.env.NODE_ENV !== 'production' ? warning(false, 'setProps(...) and replaceProps(...) are deprecated. ' + 'Instead, call React.render again at the top level.') : undefined;
60
+ process.env.NODE_ENV !== 'production' ? warning(false, 'setProps(...) and replaceProps(...) are deprecated. ' + 'Instead, call render again at the top level.') : undefined;
62
61
  }
63
62
  }
64
63
 
@@ -358,9 +357,10 @@ var RESERVED_SPEC_KEYS = {
358
357
  },
359
358
  statics: function (Constructor, statics) {
360
359
  mixStaticSpecIntoComponent(Constructor, statics);
361
- }
362
- };
360
+ },
361
+ autobind: function () {} };
363
362
 
363
+ // noop
364
364
  function validateTypeDef(Constructor, typeDef, location) {
365
365
  for (var propName in typeDef) {
366
366
  if (typeDef.hasOwnProperty(propName)) {
@@ -429,7 +429,7 @@ function mixSpecIntoComponent(Constructor, spec) {
429
429
  var isReactClassMethod = ReactClassInterface.hasOwnProperty(name);
430
430
  var isAlreadyDefined = proto.hasOwnProperty(name);
431
431
  var isFunction = typeof property === 'function';
432
- var shouldAutoBind = isFunction && !isReactClassMethod && !isAlreadyDefined;
432
+ var shouldAutoBind = isFunction && !isReactClassMethod && !isAlreadyDefined && spec.autobind !== false;
433
433
 
434
434
  if (shouldAutoBind) {
435
435
  if (!proto.__reactAutoBindMap) {
@@ -593,7 +593,7 @@ function bindAutoBindMethods(component) {
593
593
  for (var autoBindKey in component.__reactAutoBindMap) {
594
594
  if (component.__reactAutoBindMap.hasOwnProperty(autoBindKey)) {
595
595
  var method = component.__reactAutoBindMap[autoBindKey];
596
- component[autoBindKey] = bindAutoBindMethod(component, ReactErrorUtils.guard(method, component.constructor.displayName + '.' + autoBindKey));
596
+ component[autoBindKey] = bindAutoBindMethod(component, method);
597
597
  }
598
598
  }
599
599
  }
@@ -13,6 +13,7 @@
13
13
 
14
14
  var ReactNoopUpdateQueue = require('./ReactNoopUpdateQueue');
15
15
 
16
+ var canDefineProperty = require('./canDefineProperty');
16
17
  var emptyObject = require('fbjs/lib/emptyObject');
17
18
  var invariant = require('fbjs/lib/invariant');
18
19
  var warning = require('fbjs/lib/warning');
@@ -29,6 +30,8 @@ function ReactComponent(props, context, updater) {
29
30
  this.updater = updater || ReactNoopUpdateQueue;
30
31
  }
31
32
 
33
+ ReactComponent.prototype.isReactComponent = {};
34
+
32
35
  /**
33
36
  * Sets a subset of the state. Always use this to mutate
34
37
  * state. You should treat `this.state` as immutable.
@@ -93,22 +96,20 @@ ReactComponent.prototype.forceUpdate = function (callback) {
93
96
  */
94
97
  if (process.env.NODE_ENV !== 'production') {
95
98
  var deprecatedAPIs = {
96
- getDOMNode: ['getDOMNode', 'Use React.findDOMNode(component) instead.'],
99
+ getDOMNode: ['getDOMNode', 'Use ReactDOM.findDOMNode(component) instead.'],
97
100
  isMounted: ['isMounted', 'Instead, make sure to clean up subscriptions and pending requests in ' + 'componentWillUnmount to prevent memory leaks.'],
98
- replaceProps: ['replaceProps', 'Instead, call React.render again at the top level.'],
101
+ replaceProps: ['replaceProps', 'Instead, call render again at the top level.'],
99
102
  replaceState: ['replaceState', 'Refactor your code to use setState instead (see ' + 'https://github.com/facebook/react/issues/3236).'],
100
- setProps: ['setProps', 'Instead, call React.render again at the top level.']
103
+ setProps: ['setProps', 'Instead, call render again at the top level.']
101
104
  };
102
105
  var defineDeprecationWarning = function (methodName, info) {
103
- try {
106
+ if (canDefineProperty) {
104
107
  Object.defineProperty(ReactComponent.prototype, methodName, {
105
108
  get: function () {
106
109
  process.env.NODE_ENV !== 'production' ? warning(false, '%s(...) is deprecated in plain JavaScript React classes. %s', info[0], info[1]) : undefined;
107
110
  return undefined;
108
111
  }
109
112
  });
110
- } catch (x) {
111
- // IE will fail on defineProperty (es5-shim/sham too)
112
113
  }
113
114
  };
114
115
  for (var fnName in deprecatedAPIs) {
@@ -38,6 +38,12 @@ function getDeclarationErrorAddendum(component) {
38
38
  return '';
39
39
  }
40
40
 
41
+ function StatelessComponent(Component) {}
42
+ StatelessComponent.prototype.render = function () {
43
+ var Component = ReactInstanceMap.get(this)._currentElement.type;
44
+ return Component(this.props, this.context, this.updater);
45
+ };
46
+
41
47
  /**
42
48
  * ------------------ The Life-Cycle of a Composite Component ------------------
43
49
  *
@@ -126,12 +132,43 @@ var ReactCompositeComponentMixin = {
126
132
  var Component = this._currentElement.type;
127
133
 
128
134
  // Initialize the public class
129
- var inst = new Component(publicProps, publicContext, ReactUpdateQueue);
135
+ var inst;
136
+ var renderedElement;
137
+
138
+ // This is a way to detect if Component is a stateless arrow function
139
+ // component, which is not newable. It might not be 100% reliable but is
140
+ // something we can do until we start detecting that Component extends
141
+ // React.Component. We already assume that typeof Component === 'function'.
142
+ var canInstantiate = ('prototype' in Component);
143
+
144
+ if (canInstantiate) {
145
+ if (process.env.NODE_ENV !== 'production') {
146
+ ReactCurrentOwner.current = this;
147
+ try {
148
+ inst = new Component(publicProps, publicContext, ReactUpdateQueue);
149
+ } finally {
150
+ ReactCurrentOwner.current = null;
151
+ }
152
+ } else {
153
+ inst = new Component(publicProps, publicContext, ReactUpdateQueue);
154
+ }
155
+ }
156
+
157
+ if (!canInstantiate || inst === null || inst === false || ReactElement.isValidElement(inst)) {
158
+ renderedElement = inst;
159
+ inst = new StatelessComponent(Component);
160
+ }
130
161
 
131
162
  if (process.env.NODE_ENV !== 'production') {
132
163
  // This will throw later in _renderValidatedComponent, but add an early
133
164
  // warning now to help debugging
134
- process.env.NODE_ENV !== 'production' ? warning(inst.render != null, '%s(...): No `render` method found on the returned component ' + 'instance: you may have forgotten to define `render` in your ' + 'component or you may have accidentally tried to render an element ' + 'whose type is a function that isn\'t a React component.', Component.displayName || Component.name || 'Component') : undefined;
165
+ if (inst.render == null) {
166
+ process.env.NODE_ENV !== 'production' ? warning(false, '%s(...): No `render` method found on the returned component ' + 'instance: you may have forgotten to define `render`, returned ' + 'null/false from a stateless component, or tried to render an ' + 'element whose type is a function that isn\'t a React component.', Component.displayName || Component.name || 'Component') : undefined;
167
+ } else {
168
+ // We support ES6 inheriting from React.Component, the module pattern,
169
+ // and stateless components, but not ES6 classes that don't extend
170
+ process.env.NODE_ENV !== 'production' ? warning(Component.prototype && Component.prototype.isReactComponent || !canInstantiate || !(inst instanceof Component), '%s(...): React component classes must extend React.Component.', Component.displayName || Component.name || 'Component') : undefined;
171
+ }
135
172
  }
136
173
 
137
174
  // These should be set up in the constructor, but as a convenience for
@@ -178,7 +215,10 @@ var ReactCompositeComponentMixin = {
178
215
  }
179
216
  }
180
217
 
181
- var renderedElement = this._renderValidatedComponent();
218
+ // If not a stateless component, we now render
219
+ if (renderedElement === undefined) {
220
+ renderedElement = this._renderValidatedComponent();
221
+ }
182
222
 
183
223
  this._renderedComponent = this._instantiateReactComponent(renderedElement);
184
224
 
@@ -205,6 +245,7 @@ var ReactCompositeComponentMixin = {
205
245
 
206
246
  ReactReconciler.unmountComponent(this._renderedComponent);
207
247
  this._renderedComponent = null;
248
+ this._instance = null;
208
249
 
209
250
  // Reset pending fields
210
251
  // Even if this component is scheduled for another update in ReactUpdates,
@@ -340,7 +381,7 @@ var ReactCompositeComponentMixin = {
340
381
  }
341
382
  if (error instanceof Error) {
342
383
  // We may want to extend this logic for similar errors in
343
- // React.render calls, so I'm abstracting it away into
384
+ // top-level render calls, so I'm abstracting it away into
344
385
  // a function to minimize refactoring in the future
345
386
  var addendum = getDeclarationErrorAddendum(this);
346
387
 
@@ -583,8 +624,14 @@ var ReactCompositeComponentMixin = {
583
624
  */
584
625
  attachRef: function (ref, component) {
585
626
  var inst = this.getPublicInstance();
627
+ !(inst != null) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Stateless function components cannot have refs.') : invariant(false) : undefined;
628
+ var publicComponentInstance = component.getPublicInstance();
629
+ if (process.env.NODE_ENV !== 'production') {
630
+ var componentName = component && component.getName ? component.getName() : 'a component';
631
+ process.env.NODE_ENV !== 'production' ? warning(publicComponentInstance != null, 'Stateless function components cannot be given refs ' + '(See ref "%s" in %s created by %s). ' + 'Attempts to access this ref will fail.', ref, componentName, this.getName()) : undefined;
632
+ }
586
633
  var refs = inst.refs === emptyObject ? inst.refs = {} : inst.refs;
587
- refs[ref] = component.getPublicInstance();
634
+ refs[ref] = publicComponentInstance;
588
635
  },
589
636
 
590
637
  /**
@@ -613,14 +660,18 @@ var ReactCompositeComponentMixin = {
613
660
 
614
661
  /**
615
662
  * Get the publicly accessible representation of this component - i.e. what
616
- * is exposed by refs and returned by React.render. Can be null for stateless
663
+ * is exposed by refs and returned by render. Can be null for stateless
617
664
  * components.
618
665
  *
619
666
  * @return {ReactComponent} the public component instance.
620
667
  * @internal
621
668
  */
622
669
  getPublicInstance: function () {
623
- return this._instance;
670
+ var inst = this._instance;
671
+ if (inst instanceof StatelessComponent) {
672
+ return null;
673
+ }
674
+ return inst;
624
675
  },
625
676
 
626
677
  // Stub
package/lib/ReactDOM.js CHANGED
@@ -21,6 +21,7 @@ var ReactMount = require('./ReactMount');
21
21
  var ReactPerf = require('./ReactPerf');
22
22
  var ReactReconciler = require('./ReactReconciler');
23
23
  var ReactUpdates = require('./ReactUpdates');
24
+ var ReactVersion = require('./ReactVersion');
24
25
 
25
26
  var findDOMNode = require('./findDOMNode');
26
27
  var renderSubtreeIntoContainer = require('./renderSubtreeIntoContainer');
@@ -34,6 +35,7 @@ var React = {
34
35
  findDOMNode: findDOMNode,
35
36
  render: render,
36
37
  unmountComponentAtNode: ReactMount.unmountComponentAtNode,
38
+ version: ReactVersion,
37
39
 
38
40
  /* eslint-disable camelcase */
39
41
  unstable_batchedUpdates: ReactUpdates.batchedUpdates,
@@ -57,15 +59,15 @@ if (process.env.NODE_ENV !== 'production') {
57
59
  var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment');
58
60
  if (ExecutionEnvironment.canUseDOM && window.top === window.self) {
59
61
 
60
- // If we're in Chrome, look for the devtools marker and provide a download
61
- // link if not installed.
62
- if (navigator.userAgent.indexOf('Chrome') > -1) {
63
- if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {
62
+ // First check if devtools is not installed
63
+ if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {
64
+ // If we're in Chrome or Firefox, provide a download link if not installed.
65
+ if (navigator.userAgent.indexOf('Chrome') > -1 && navigator.userAgent.indexOf('Edge') === -1 || navigator.userAgent.indexOf('Firefox') > -1) {
64
66
  console.debug('Download the React DevTools for a better development experience: ' + 'https://fb.me/react-devtools');
65
67
  }
66
68
  }
67
69
 
68
- // If we're in IE8, check to see if we are in combatibility mode and provide
70
+ // If we're in IE8, check to see if we are in compatibility mode and provide
69
71
  // information on preventing compatibility mode
70
72
  var ieCompatibilityMode = document.documentMode && document.documentMode < 8;
71
73
 
@@ -32,10 +32,13 @@ var ReactPerf = require('./ReactPerf');
32
32
  var ReactUpdateQueue = require('./ReactUpdateQueue');
33
33
 
34
34
  var assign = require('./Object.assign');
35
+ var canDefineProperty = require('./canDefineProperty');
35
36
  var escapeTextContentForBrowser = require('./escapeTextContentForBrowser');
36
37
  var invariant = require('fbjs/lib/invariant');
37
38
  var isEventSupported = require('./isEventSupported');
38
39
  var keyOf = require('fbjs/lib/keyOf');
40
+ var setInnerHTML = require('./setInnerHTML');
41
+ var setTextContent = require('./setTextContent');
39
42
  var shallowEqual = require('fbjs/lib/shallowEqual');
40
43
  var validateDOMNesting = require('./validateDOMNesting');
41
44
  var warning = require('fbjs/lib/warning');
@@ -47,16 +50,12 @@ var registrationNameModules = ReactBrowserEventEmitter.registrationNameModules;
47
50
  // For quickly matching children type, to test if can be treated as content.
48
51
  var CONTENT_TYPES = { 'string': true, 'number': true };
49
52
 
53
+ var CHILDREN = keyOf({ children: null });
50
54
  var STYLE = keyOf({ style: null });
55
+ var HTML = keyOf({ __html: null });
51
56
 
52
57
  var ELEMENT_NODE_TYPE = 1;
53
58
 
54
- var canDefineProperty = false;
55
- try {
56
- Object.defineProperty({}, 'test', { get: function () {} });
57
- canDefineProperty = true;
58
- } catch (e) {}
59
-
60
59
  function getDeclarationErrorAddendum(internalInstance) {
61
60
  if (internalInstance) {
62
61
  var owner = internalInstance._currentElement._owner || null;
@@ -110,7 +109,7 @@ function legacySetStateEtc() {
110
109
  function legacySetProps(partialProps, callback) {
111
110
  var component = this._reactInternalComponent;
112
111
  if (process.env.NODE_ENV !== 'production') {
113
- process.env.NODE_ENV !== 'production' ? warning(false, 'ReactDOMComponent: Do not access .setProps() of a DOM node. ' + 'Instead, call React.render again at the top level.%s', getDeclarationErrorAddendum(component)) : undefined;
112
+ process.env.NODE_ENV !== 'production' ? warning(false, 'ReactDOMComponent: Do not access .setProps() of a DOM node. ' + 'Instead, call ReactDOM.render again at the top level.%s', getDeclarationErrorAddendum(component)) : undefined;
114
113
  }
115
114
  if (!component) {
116
115
  return;
@@ -124,7 +123,7 @@ function legacySetProps(partialProps, callback) {
124
123
  function legacyReplaceProps(partialProps, callback) {
125
124
  var component = this._reactInternalComponent;
126
125
  if (process.env.NODE_ENV !== 'production') {
127
- process.env.NODE_ENV !== 'production' ? warning(false, 'ReactDOMComponent: Do not access .replaceProps() of a DOM node. ' + 'Instead, call React.render again at the top level.%s', getDeclarationErrorAddendum(component)) : undefined;
126
+ process.env.NODE_ENV !== 'production' ? warning(false, 'ReactDOMComponent: Do not access .replaceProps() of a DOM node. ' + 'Instead, call ReactDOM.render again at the top level.%s', getDeclarationErrorAddendum(component)) : undefined;
128
127
  }
129
128
  if (!component) {
130
129
  return;
@@ -135,6 +134,30 @@ function legacyReplaceProps(partialProps, callback) {
135
134
  }
136
135
  }
137
136
 
137
+ function friendlyStringify(obj) {
138
+ if (typeof obj === 'object') {
139
+ if (Array.isArray(obj)) {
140
+ return '[' + obj.map(friendlyStringify).join(', ') + ']';
141
+ } else {
142
+ var pairs = [];
143
+ for (var key in obj) {
144
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
145
+ var keyEscaped = /^[a-z$_][\w$_]*$/i.test(key) ? key : JSON.stringify(key);
146
+ pairs.push(keyEscaped + ': ' + friendlyStringify(obj[key]));
147
+ }
148
+ }
149
+ return '{' + pairs.join(', ') + '}';
150
+ }
151
+ } else if (typeof obj === 'string') {
152
+ return JSON.stringify(obj);
153
+ } else if (typeof obj === 'function') {
154
+ return '[function object]';
155
+ }
156
+ // Differs from JSON.stringify in that undefined becauses undefined and that
157
+ // inf and nan don't become null
158
+ return String(obj);
159
+ }
160
+
138
161
  var styleMutationWarning = {};
139
162
 
140
163
  function checkAndWarnForMutatedStyle(style1, style2, component) {
@@ -160,14 +183,9 @@ function checkAndWarnForMutatedStyle(style1, style2, component) {
160
183
 
161
184
  styleMutationWarning[hash] = true;
162
185
 
163
- process.env.NODE_ENV !== 'production' ? 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;
186
+ process.env.NODE_ENV !== 'production' ? 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 + '>', friendlyStringify(style1), friendlyStringify(style2)) : undefined;
164
187
  }
165
188
 
166
- /**
167
- * Optionally injectable operations for mutating the DOM
168
- */
169
- var BackendIDOperations = null;
170
-
171
189
  /**
172
190
  * @param {object} component
173
191
  * @param {?object} props
@@ -184,13 +202,13 @@ function assertValidProps(component, props) {
184
202
  }
185
203
  if (props.dangerouslySetInnerHTML != null) {
186
204
  !(props.children == null) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.') : invariant(false) : undefined;
187
- !(typeof props.dangerouslySetInnerHTML === 'object' && '__html' in props.dangerouslySetInnerHTML) ? process.env.NODE_ENV !== 'production' ? 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;
205
+ !(typeof props.dangerouslySetInnerHTML === 'object' && HTML in props.dangerouslySetInnerHTML) ? process.env.NODE_ENV !== 'production' ? 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;
188
206
  }
189
207
  if (process.env.NODE_ENV !== 'production') {
190
208
  process.env.NODE_ENV !== 'production' ? warning(props.innerHTML == null, 'Directly setting property `innerHTML` is not permitted. ' + 'For more information, lookup documentation on `dangerouslySetInnerHTML`.') : undefined;
191
209
  process.env.NODE_ENV !== 'production' ? 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;
192
210
  }
193
- !(props.style == null || typeof props.style === 'object') ? process.env.NODE_ENV !== 'production' ? 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;
211
+ !(props.style == null || typeof props.style === 'object') ? process.env.NODE_ENV !== 'production' ? 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.%s', getDeclarationErrorAddendum(component)) : invariant(false) : undefined;
194
212
  }
195
213
 
196
214
  function enqueuePutListener(id, registrationName, listener, transaction) {
@@ -277,6 +295,10 @@ function trapBubbledEventsLocal() {
277
295
  }
278
296
  }
279
297
 
298
+ function mountReadyInputWrapper() {
299
+ ReactDOMInput.mountReadyWrapper(this);
300
+ }
301
+
280
302
  function postUpdateSelectWrapper() {
281
303
  ReactDOMSelect.postUpdateWrapper(this);
282
304
  }
@@ -331,13 +353,11 @@ function validateDangerousTag(tag) {
331
353
  }
332
354
  }
333
355
 
334
- function processChildContext(context, inst) {
335
- if (process.env.NODE_ENV !== 'production') {
336
- // Pass down our tag name to child components for validation purposes
337
- context = assign({}, context);
338
- var info = context[validateDOMNesting.ancestorInfoContextKey];
339
- context[validateDOMNesting.ancestorInfoContextKey] = validateDOMNesting.updatedAncestorInfo(info, inst._tag, inst);
340
- }
356
+ function processChildContextDev(context, inst) {
357
+ // Pass down our tag name to child components for validation purposes
358
+ context = assign({}, context);
359
+ var info = context[validateDOMNesting.ancestorInfoContextKey];
360
+ context[validateDOMNesting.ancestorInfoContextKey] = validateDOMNesting.updatedAncestorInfo(info, inst._tag, inst);
341
361
  return context;
342
362
  }
343
363
 
@@ -369,6 +389,10 @@ function ReactDOMComponent(tag) {
369
389
  this._wrapperState = null;
370
390
  this._topLevelWrapper = null;
371
391
  this._nodeWithLegacyProperties = null;
392
+ if (process.env.NODE_ENV !== 'production') {
393
+ this._unprocessedContextDev = null;
394
+ this._processedContextDev = null;
395
+ }
372
396
  }
373
397
 
374
398
  ReactDOMComponent.displayName = 'ReactDOMComponent';
@@ -434,12 +458,37 @@ ReactDOMComponent.Mixin = {
434
458
  }
435
459
  }
436
460
 
437
- var tagOpen = this._createOpenTagMarkupAndPutListeners(transaction, props);
438
- var tagContent = this._createContentMarkup(transaction, props, context);
461
+ if (process.env.NODE_ENV !== 'production') {
462
+ this._unprocessedContextDev = context;
463
+ this._processedContextDev = processChildContextDev(context, this);
464
+ context = this._processedContextDev;
465
+ }
466
+
467
+ var mountImage;
468
+ if (transaction.useCreateElement) {
469
+ var ownerDocument = context[ReactMount.ownerDocumentContextKey];
470
+ var el = ownerDocument.createElement(this._currentElement.type);
471
+ DOMPropertyOperations.setAttributeForID(el, this._rootNodeID);
472
+ // Populate node cache
473
+ ReactMount.getID(el);
474
+ this._updateDOMProperties({}, props, transaction, el);
475
+ this._createInitialChildren(transaction, props, context, el);
476
+ mountImage = el;
477
+ } else {
478
+ var tagOpen = this._createOpenTagMarkupAndPutListeners(transaction, props);
479
+ var tagContent = this._createContentMarkup(transaction, props, context);
480
+ if (!tagContent && omittedCloseTags[this._tag]) {
481
+ mountImage = tagOpen + '/>';
482
+ } else {
483
+ mountImage = tagOpen + '>' + tagContent + '</' + this._currentElement.type + '>';
484
+ }
485
+ }
439
486
 
440
487
  switch (this._tag) {
441
- case 'button':
442
488
  case 'input':
489
+ transaction.getReactMountReady().enqueue(mountReadyInputWrapper, this);
490
+ // falls through
491
+ case 'button':
443
492
  case 'select':
444
493
  case 'textarea':
445
494
  if (props.autoFocus) {
@@ -448,10 +497,7 @@ ReactDOMComponent.Mixin = {
448
497
  break;
449
498
  }
450
499
 
451
- if (!tagContent && omittedCloseTags[this._tag]) {
452
- return tagOpen + '/>';
453
- }
454
- return tagOpen + '>' + tagContent + '</' + this._currentElement.type + '>';
500
+ return mountImage;
455
501
  },
456
502
 
457
503
  /**
@@ -479,7 +525,9 @@ ReactDOMComponent.Mixin = {
479
525
  continue;
480
526
  }
481
527
  if (registrationNameModules.hasOwnProperty(propKey)) {
482
- enqueuePutListener(this._rootNodeID, propKey, propValue, transaction);
528
+ if (propValue) {
529
+ enqueuePutListener(this._rootNodeID, propKey, propValue, transaction);
530
+ }
483
531
  } else {
484
532
  if (propKey === STYLE) {
485
533
  if (propValue) {
@@ -493,7 +541,9 @@ ReactDOMComponent.Mixin = {
493
541
  }
494
542
  var markup = null;
495
543
  if (this._tag != null && isCustomComponent(this._tag, props)) {
496
- markup = DOMPropertyOperations.createMarkupForCustomAttribute(propKey, propValue);
544
+ if (propKey !== CHILDREN) {
545
+ markup = DOMPropertyOperations.createMarkupForCustomAttribute(propKey, propValue);
546
+ }
497
547
  } else {
498
548
  markup = DOMPropertyOperations.createMarkupForProperty(propKey, propValue);
499
549
  }
@@ -538,7 +588,7 @@ ReactDOMComponent.Mixin = {
538
588
  // TODO: Validate that text is allowed as a child of this node
539
589
  ret = escapeTextContentForBrowser(contentToUse);
540
590
  } else if (childrenToUse != null) {
541
- var mountImages = this.mountChildren(childrenToUse, transaction, processChildContext(context, this));
591
+ var mountImages = this.mountChildren(childrenToUse, transaction, context);
542
592
  ret = mountImages.join('');
543
593
  }
544
594
  }
@@ -559,6 +609,28 @@ ReactDOMComponent.Mixin = {
559
609
  }
560
610
  },
561
611
 
612
+ _createInitialChildren: function (transaction, props, context, el) {
613
+ // Intentional use of != to avoid catching zero/false.
614
+ var innerHTML = props.dangerouslySetInnerHTML;
615
+ if (innerHTML != null) {
616
+ if (innerHTML.__html != null) {
617
+ setInnerHTML(el, innerHTML.__html);
618
+ }
619
+ } else {
620
+ var contentToUse = CONTENT_TYPES[typeof props.children] ? props.children : null;
621
+ var childrenToUse = contentToUse != null ? null : props.children;
622
+ if (contentToUse != null) {
623
+ // TODO: Validate that text is allowed as a child of this node
624
+ setTextContent(el, contentToUse);
625
+ } else if (childrenToUse != null) {
626
+ var mountImages = this.mountChildren(childrenToUse, transaction, context);
627
+ for (var i = 0; i < mountImages.length; i++) {
628
+ el.appendChild(mountImages[i]);
629
+ }
630
+ }
631
+ }
632
+ },
633
+
562
634
  /**
563
635
  * Receives a next element and updates the component.
564
636
  *
@@ -612,9 +684,20 @@ ReactDOMComponent.Mixin = {
612
684
  break;
613
685
  }
614
686
 
687
+ if (process.env.NODE_ENV !== 'production') {
688
+ // If the context is reference-equal to the old one, pass down the same
689
+ // processed object so the update bailout in ReactReconciler behaves
690
+ // correctly (and identically in dev and prod). See #5005.
691
+ if (this._unprocessedContextDev !== context) {
692
+ this._unprocessedContextDev = context;
693
+ this._processedContextDev = processChildContextDev(context, this);
694
+ }
695
+ context = this._processedContextDev;
696
+ }
697
+
615
698
  assertValidProps(this, nextProps);
616
- this._updateDOMProperties(lastProps, nextProps, transaction);
617
- this._updateDOMChildren(lastProps, nextProps, transaction, processChildContext(context, this));
699
+ this._updateDOMProperties(lastProps, nextProps, transaction, null);
700
+ this._updateDOMChildren(lastProps, nextProps, transaction, context);
618
701
 
619
702
  if (!canDefineProperty && this._nodeWithLegacyProperties) {
620
703
  this._nodeWithLegacyProperties.props = nextProps;
@@ -642,8 +725,9 @@ ReactDOMComponent.Mixin = {
642
725
  * @param {object} lastProps
643
726
  * @param {object} nextProps
644
727
  * @param {ReactReconcileTransaction} transaction
728
+ * @param {?DOMElement} node
645
729
  */
646
- _updateDOMProperties: function (lastProps, nextProps, transaction) {
730
+ _updateDOMProperties: function (lastProps, nextProps, transaction, node) {
647
731
  var propKey;
648
732
  var styleName;
649
733
  var styleUpdates;
@@ -668,7 +752,10 @@ ReactDOMComponent.Mixin = {
668
752
  deleteListener(this._rootNodeID, propKey);
669
753
  }
670
754
  } else if (DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)) {
671
- BackendIDOperations.deletePropertyByID(this._rootNodeID, propKey);
755
+ if (!node) {
756
+ node = ReactMount.getNode(this._rootNodeID);
757
+ }
758
+ DOMPropertyOperations.deleteValueForProperty(node, propKey);
672
759
  }
673
760
  }
674
761
  for (propKey in nextProps) {
@@ -713,13 +800,32 @@ ReactDOMComponent.Mixin = {
713
800
  deleteListener(this._rootNodeID, propKey);
714
801
  }
715
802
  } else if (isCustomComponent(this._tag, nextProps)) {
716
- BackendIDOperations.updateAttributeByID(this._rootNodeID, propKey, nextProp);
803
+ if (!node) {
804
+ node = ReactMount.getNode(this._rootNodeID);
805
+ }
806
+ if (propKey === CHILDREN) {
807
+ nextProp = null;
808
+ }
809
+ DOMPropertyOperations.setValueForAttribute(node, propKey, nextProp);
717
810
  } else if (DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)) {
718
- BackendIDOperations.updatePropertyByID(this._rootNodeID, propKey, nextProp);
811
+ if (!node) {
812
+ node = ReactMount.getNode(this._rootNodeID);
813
+ }
814
+ // If we're updating to null or undefined, we should remove the property
815
+ // from the DOM node instead of inadvertantly setting to a string. This
816
+ // brings us in line with the same behavior we have on initial render.
817
+ if (nextProp != null) {
818
+ DOMPropertyOperations.setValueForProperty(node, propKey, nextProp);
819
+ } else {
820
+ DOMPropertyOperations.deleteValueForProperty(node, propKey);
821
+ }
719
822
  }
720
823
  }
721
824
  if (styleUpdates) {
722
- BackendIDOperations.updateStylesByID(this._rootNodeID, styleUpdates);
825
+ if (!node) {
826
+ node = ReactMount.getNode(this._rootNodeID);
827
+ }
828
+ CSSPropertyOperations.setValueForStyles(node, styleUpdates);
723
829
  }
724
830
  },
725
831
 
@@ -853,10 +959,4 @@ ReactPerf.measureMethods(ReactDOMComponent, 'ReactDOMComponent', {
853
959
 
854
960
  assign(ReactDOMComponent.prototype, ReactDOMComponent.Mixin, ReactMultiChild.Mixin);
855
961
 
856
- ReactDOMComponent.injection = {
857
- injectIDOperations: function (IDOperations) {
858
- ReactDOMComponent.BackendIDOperations = BackendIDOperations = IDOperations;
859
- }
860
- };
861
-
862
962
  module.exports = ReactDOMComponent;