react 0.12.0 → 0.13.0-alpha.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 (153) hide show
  1. package/dist/JSXTransformer.js +2345 -910
  2. package/dist/react-with-addons.js +5273 -4111
  3. package/dist/react-with-addons.min.js +5 -6
  4. package/dist/react.js +4840 -3940
  5. package/dist/react.min.js +5 -6
  6. package/lib/AutoFocusMixin.js +1 -1
  7. package/lib/BeforeInputEventPlugin.js +389 -112
  8. package/lib/CSSProperty.js +6 -3
  9. package/lib/CSSPropertyOperations.js +21 -1
  10. package/lib/CallbackQueue.js +2 -2
  11. package/lib/ChangeEventPlugin.js +3 -3
  12. package/lib/ClientReactRootIndex.js +1 -1
  13. package/lib/DOMChildrenOperations.js +6 -4
  14. package/lib/DOMProperty.js +1 -1
  15. package/lib/DOMPropertyOperations.js +1 -1
  16. package/lib/Danger.js +7 -6
  17. package/lib/DefaultEventPluginOrder.js +1 -2
  18. package/lib/EnterLeaveEventPlugin.js +1 -1
  19. package/lib/EventConstants.js +1 -1
  20. package/lib/EventPluginHub.js +9 -7
  21. package/lib/EventPluginRegistry.js +1 -1
  22. package/lib/EventPluginUtils.js +1 -1
  23. package/lib/EventPropagators.js +1 -1
  24. package/lib/ExecutionEnvironment.js +2 -3
  25. package/lib/FallbackCompositionState.js +89 -0
  26. package/lib/HTMLDOMPropertyConfig.js +19 -7
  27. package/lib/LinkedStateMixin.js +1 -1
  28. package/lib/LinkedValueUtils.js +3 -3
  29. package/lib/LocalEventTrapMixin.js +1 -1
  30. package/lib/MobileSafariClickEventPlugin.js +1 -1
  31. package/lib/Object.assign.js +3 -1
  32. package/lib/PooledClass.js +1 -1
  33. package/lib/React.js +17 -50
  34. package/lib/ReactBrowserComponentMixin.js +3 -13
  35. package/lib/ReactBrowserEventEmitter.js +4 -6
  36. package/lib/ReactCSSTransitionGroup.js +4 -1
  37. package/lib/ReactCSSTransitionGroupChild.js +12 -2
  38. package/lib/ReactChildReconciler.js +121 -0
  39. package/lib/ReactChildren.js +10 -8
  40. package/lib/ReactClass.js +874 -0
  41. package/lib/ReactComponent.js +45 -286
  42. package/lib/ReactComponentBase.js +126 -0
  43. package/lib/ReactComponentBrowserEnvironment.js +10 -83
  44. package/lib/ReactComponentEnvironment.js +57 -0
  45. package/lib/ReactComponentWithPureRenderMixin.js +1 -1
  46. package/lib/ReactCompositeComponent.js +700 -1045
  47. package/lib/ReactContext.js +6 -2
  48. package/lib/ReactCurrentOwner.js +1 -1
  49. package/lib/ReactDOM.js +3 -8
  50. package/lib/ReactDOMButton.js +5 -6
  51. package/lib/ReactDOMComponent.js +120 -77
  52. package/lib/ReactDOMForm.js +5 -6
  53. package/lib/ReactDOMIDOperations.js +56 -74
  54. package/lib/ReactDOMImg.js +4 -6
  55. package/lib/ReactDOMInput.js +5 -6
  56. package/lib/ReactDOMOption.js +5 -6
  57. package/lib/ReactDOMSelect.js +57 -65
  58. package/lib/ReactDOMSelection.js +6 -2
  59. package/lib/ReactDOMTextComponent.js +124 -0
  60. package/lib/ReactDOMTextarea.js +5 -6
  61. package/lib/ReactDefaultBatchingStrategy.js +1 -1
  62. package/lib/ReactDefaultInjection.js +14 -8
  63. package/lib/ReactDefaultPerf.js +8 -7
  64. package/lib/ReactDefaultPerfAnalysis.js +1 -1
  65. package/lib/ReactElement.js +22 -15
  66. package/lib/ReactElementValidator.js +192 -53
  67. package/lib/ReactEmptyComponent.js +29 -11
  68. package/lib/ReactEventEmitterMixin.js +1 -1
  69. package/lib/ReactEventListener.js +3 -3
  70. package/lib/ReactInjection.js +7 -5
  71. package/lib/ReactInputSelection.js +3 -4
  72. package/lib/ReactInstanceHandles.js +3 -2
  73. package/lib/ReactInstanceMap.js +47 -0
  74. package/lib/ReactLink.js +1 -1
  75. package/lib/ReactMarkupChecksum.js +1 -1
  76. package/lib/ReactMount.js +202 -66
  77. package/lib/ReactMultiChild.js +44 -45
  78. package/lib/ReactMultiChildUpdateTypes.js +1 -1
  79. package/lib/ReactNativeComponent.js +47 -10
  80. package/lib/ReactOwner.js +4 -48
  81. package/lib/ReactPerf.js +21 -1
  82. package/lib/ReactPropTransferer.js +2 -57
  83. package/lib/ReactPropTypeLocationNames.js +1 -1
  84. package/lib/ReactPropTypeLocations.js +1 -1
  85. package/lib/ReactPropTypes.js +14 -22
  86. package/lib/ReactPutListenerQueue.js +1 -1
  87. package/lib/ReactReconcileTransaction.js +1 -1
  88. package/lib/ReactRef.js +96 -0
  89. package/lib/ReactRootIndex.js +1 -1
  90. package/lib/ReactServerRendering.js +5 -3
  91. package/lib/ReactServerRenderingTransaction.js +1 -1
  92. package/lib/ReactStateSetters.js +1 -1
  93. package/lib/ReactTestUtils.js +83 -26
  94. package/lib/ReactTransitionChildMapping.js +1 -1
  95. package/lib/ReactTransitionEvents.js +1 -1
  96. package/lib/ReactTransitionGroup.js +48 -7
  97. package/lib/ReactUpdates.js +46 -45
  98. package/lib/ReactWithAddons.js +1 -1
  99. package/lib/SVGDOMPropertyConfig.js +1 -1
  100. package/lib/SelectEventPlugin.js +3 -3
  101. package/lib/ServerReactRootIndex.js +1 -1
  102. package/lib/SimpleEventPlugin.js +1 -1
  103. package/lib/SyntheticClipboardEvent.js +1 -2
  104. package/lib/SyntheticCompositionEvent.js +1 -2
  105. package/lib/SyntheticDragEvent.js +1 -1
  106. package/lib/SyntheticEvent.js +11 -3
  107. package/lib/SyntheticFocusEvent.js +1 -1
  108. package/lib/SyntheticInputEvent.js +1 -2
  109. package/lib/SyntheticKeyboardEvent.js +1 -1
  110. package/lib/SyntheticMouseEvent.js +2 -4
  111. package/lib/SyntheticTouchEvent.js +1 -1
  112. package/lib/SyntheticUIEvent.js +1 -1
  113. package/lib/SyntheticWheelEvent.js +1 -1
  114. package/lib/Transaction.js +3 -3
  115. package/lib/ViewportMetrics.js +2 -5
  116. package/lib/accumulate.js +47 -0
  117. package/lib/accumulateInto.js +1 -1
  118. package/lib/adler32.js +1 -1
  119. package/lib/cloneWithProps.js +3 -3
  120. package/lib/copyProperties.js +2 -0
  121. package/lib/createFullPageComponent.js +3 -3
  122. package/lib/dangerousStyleValue.js +1 -1
  123. package/lib/escapeTextForBrowser.js +6 -6
  124. package/lib/findDOMNode.js +51 -0
  125. package/lib/flattenChildren.js +11 -22
  126. package/lib/forEachAccumulated.js +1 -1
  127. package/lib/getEventCharCode.js +1 -1
  128. package/lib/getEventKey.js +1 -1
  129. package/lib/getEventModifierState.js +1 -1
  130. package/lib/getEventTarget.js +1 -1
  131. package/lib/getIteratorFn.js +42 -0
  132. package/lib/getNodeForCharacterOffset.js +2 -2
  133. package/lib/getReactRootElementInContainer.js +1 -1
  134. package/lib/getTextContentAccessor.js +1 -1
  135. package/lib/instantiateReactComponent.js +89 -66
  136. package/lib/isEventSupported.js +1 -1
  137. package/lib/isNode.js +3 -4
  138. package/lib/isTextInputElement.js +2 -3
  139. package/lib/joinClasses.js +1 -1
  140. package/lib/keyMirror.js +1 -1
  141. package/lib/memoizeStringOnly.js +4 -5
  142. package/lib/onlyChild.js +1 -1
  143. package/lib/setInnerHTML.js +12 -1
  144. package/lib/shallowEqual.js +1 -1
  145. package/lib/shouldUpdateReactComponent.js +48 -6
  146. package/lib/traverseAllChildren.js +111 -55
  147. package/lib/update.js +1 -1
  148. package/lib/warning.js +9 -2
  149. package/package.json +1 -1
  150. package/lib/CompositionEventPlugin.js +0 -257
  151. package/lib/ReactLegacyElement.js +0 -243
  152. package/lib/ReactTextComponent.js +0 -104
  153. package/lib/deprecated.js +0 -47
@@ -9,7 +9,7 @@
9
9
  * @providesModule ReactDOMSelection
10
10
  */
11
11
 
12
- "use strict";
12
+ 'use strict';
13
13
 
14
14
  var ExecutionEnvironment = require("./ExecutionEnvironment");
15
15
 
@@ -189,7 +189,11 @@ function setModernOffsets(node, offsets) {
189
189
  }
190
190
  }
191
191
 
192
- var useIEOffsets = ExecutionEnvironment.canUseDOM && document.selection;
192
+ var useIEOffsets = (
193
+ ExecutionEnvironment.canUseDOM &&
194
+ 'selection' in document &&
195
+ !('getSelection' in window)
196
+ );
193
197
 
194
198
  var ReactDOMSelection = {
195
199
  /**
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Copyright 2013-2014, 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 ReactDOMTextComponent
10
+ * @typechecks static-only
11
+ */
12
+
13
+ 'use strict';
14
+
15
+ var DOMPropertyOperations = require("./DOMPropertyOperations");
16
+ var ReactComponentBrowserEnvironment =
17
+ require("./ReactComponentBrowserEnvironment");
18
+ var ReactDOMComponent = require("./ReactDOMComponent");
19
+
20
+ var assign = require("./Object.assign");
21
+ var escapeTextForBrowser = require("./escapeTextForBrowser");
22
+ var invariant = require("./invariant");
23
+
24
+ /**
25
+ * Text nodes violate a couple assumptions that React makes about components:
26
+ *
27
+ * - When mounting text into the DOM, adjacent text nodes are merged.
28
+ * - Text nodes cannot be assigned a React root ID.
29
+ *
30
+ * This component is used to wrap strings in elements so that they can undergo
31
+ * the same reconciliation that is applied to elements.
32
+ *
33
+ * TODO: Investigate representing React components in the DOM with text nodes.
34
+ *
35
+ * @class ReactDOMTextComponent
36
+ * @extends ReactComponent
37
+ * @internal
38
+ */
39
+ var ReactDOMTextComponent = function(props) {
40
+ // This constructor and its argument is currently used by mocks.
41
+ };
42
+
43
+ assign(ReactDOMTextComponent.prototype, {
44
+
45
+ /**
46
+ * @param {ReactText} text
47
+ * @internal
48
+ */
49
+ construct: function(text) {
50
+ // TODO: This is really a ReactText (ReactNode), not a ReactElement
51
+ this._currentElement = text;
52
+ this._stringText = '' + text;
53
+
54
+ // Properties
55
+ this._rootNodeID = null;
56
+ this._mountIndex = 0;
57
+ },
58
+
59
+ /**
60
+ * Creates the markup for this text node. This node is not intended to have
61
+ * any features besides containing text content.
62
+ *
63
+ * @param {string} rootID DOM ID of the root node.
64
+ * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
65
+ * @return {string} Markup for this text node.
66
+ * @internal
67
+ */
68
+ mountComponent: function(rootID, transaction, context) {
69
+ this._rootNodeID = rootID;
70
+ var escapedText = escapeTextForBrowser(this._stringText);
71
+
72
+ if (transaction.renderToStaticMarkup) {
73
+ // Normally we'd wrap this in a `span` for the reasons stated above, but
74
+ // since this is a situation where React won't take over (static pages),
75
+ // we can simply return the text as it is.
76
+ return escapedText;
77
+ }
78
+
79
+ return (
80
+ '<span ' + DOMPropertyOperations.createMarkupForID(rootID) + '>' +
81
+ escapedText +
82
+ '</span>'
83
+ );
84
+ },
85
+
86
+ /**
87
+ * Updates this component by updating the text content.
88
+ *
89
+ * @param {ReactText} nextText The next text content
90
+ * @param {ReactReconcileTransaction} transaction
91
+ * @internal
92
+ */
93
+ receiveComponent: function(nextText, transaction) {
94
+ if (nextText !== this._currentElement) {
95
+ this._currentElement = nextText;
96
+ var nextStringText = '' + nextText;
97
+ if (nextStringText !== this._stringText) {
98
+ // TODO: Save this as pending props and use performUpdateIfNecessary
99
+ // and/or updateComponent to do the actual update for consistency with
100
+ // other component types?
101
+ this._stringText = nextStringText;
102
+ ReactDOMComponent.BackendIDOperations.updateTextContentByID(
103
+ this._rootNodeID,
104
+ nextStringText
105
+ );
106
+ }
107
+ }
108
+ },
109
+
110
+ updateComponent: function() {
111
+ ("production" !== process.env.NODE_ENV ? invariant(
112
+ false,
113
+ 'ReactDOMTextComponent: updateComponent() should never be called'
114
+ ) : invariant(false));
115
+ },
116
+
117
+ unmountComponent: function() {
118
+ // TODO: Is this necessary?
119
+ ReactComponentBrowserEnvironment.unmountIDFromEnvironment(this._rootNodeID);
120
+ }
121
+
122
+ });
123
+
124
+ module.exports = ReactDOMTextComponent;
@@ -9,15 +9,14 @@
9
9
  * @providesModule ReactDOMTextarea
10
10
  */
11
11
 
12
- "use strict";
12
+ 'use strict';
13
13
 
14
14
  var AutoFocusMixin = require("./AutoFocusMixin");
15
15
  var DOMPropertyOperations = require("./DOMPropertyOperations");
16
16
  var LinkedValueUtils = require("./LinkedValueUtils");
17
17
  var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
18
- var ReactCompositeComponent = require("./ReactCompositeComponent");
18
+ var ReactClass = require("./ReactClass");
19
19
  var ReactElement = require("./ReactElement");
20
- var ReactDOM = require("./ReactDOM");
21
20
  var ReactUpdates = require("./ReactUpdates");
22
21
 
23
22
  var assign = require("./Object.assign");
@@ -25,8 +24,7 @@ var invariant = require("./invariant");
25
24
 
26
25
  var warning = require("./warning");
27
26
 
28
- // Store a reference to the <textarea> `ReactDOMComponent`. TODO: use string
29
- var textarea = ReactElement.createFactory(ReactDOM.textarea.type);
27
+ var textarea = ReactElement.createFactory('textarea');
30
28
 
31
29
  function forceUpdateIfMounted() {
32
30
  /*jshint validthis:true */
@@ -50,8 +48,9 @@ function forceUpdateIfMounted() {
50
48
  * The rendered element will be initialized with an empty value, the prop
51
49
  * `defaultValue` if specified, or the children content (deprecated).
52
50
  */
53
- var ReactDOMTextarea = ReactCompositeComponent.createClass({
51
+ var ReactDOMTextarea = ReactClass.createClass({
54
52
  displayName: 'ReactDOMTextarea',
53
+ tagName: 'TEXTAREA',
55
54
 
56
55
  mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
57
56
 
@@ -9,7 +9,7 @@
9
9
  * @providesModule ReactDefaultBatchingStrategy
10
10
  */
11
11
 
12
- "use strict";
12
+ 'use strict';
13
13
 
14
14
  var ReactUpdates = require("./ReactUpdates");
15
15
  var Transaction = require("./Transaction");
@@ -9,12 +9,11 @@
9
9
  * @providesModule ReactDefaultInjection
10
10
  */
11
11
 
12
- "use strict";
12
+ 'use strict';
13
13
 
14
14
  var BeforeInputEventPlugin = require("./BeforeInputEventPlugin");
15
15
  var ChangeEventPlugin = require("./ChangeEventPlugin");
16
16
  var ClientReactRootIndex = require("./ClientReactRootIndex");
17
- var CompositionEventPlugin = require("./CompositionEventPlugin");
18
17
  var DefaultEventPluginOrder = require("./DefaultEventPluginOrder");
19
18
  var EnterLeaveEventPlugin = require("./EnterLeaveEventPlugin");
20
19
  var ExecutionEnvironment = require("./ExecutionEnvironment");
@@ -28,14 +27,17 @@ var ReactDOMComponent = require("./ReactDOMComponent");
28
27
  var ReactDOMButton = require("./ReactDOMButton");
29
28
  var ReactDOMForm = require("./ReactDOMForm");
30
29
  var ReactDOMImg = require("./ReactDOMImg");
30
+ var ReactDOMIDOperations = require("./ReactDOMIDOperations");
31
31
  var ReactDOMInput = require("./ReactDOMInput");
32
32
  var ReactDOMOption = require("./ReactDOMOption");
33
33
  var ReactDOMSelect = require("./ReactDOMSelect");
34
34
  var ReactDOMTextarea = require("./ReactDOMTextarea");
35
+ var ReactDOMTextComponent = require("./ReactDOMTextComponent");
35
36
  var ReactEventListener = require("./ReactEventListener");
36
37
  var ReactInjection = require("./ReactInjection");
37
38
  var ReactInstanceHandles = require("./ReactInstanceHandles");
38
39
  var ReactMount = require("./ReactMount");
40
+ var ReactReconcileTransaction = require("./ReactReconcileTransaction");
39
41
  var SelectEventPlugin = require("./SelectEventPlugin");
40
42
  var ServerReactRootIndex = require("./ServerReactRootIndex");
41
43
  var SimpleEventPlugin = require("./SimpleEventPlugin");
@@ -63,7 +65,6 @@ function inject() {
63
65
  SimpleEventPlugin: SimpleEventPlugin,
64
66
  EnterLeaveEventPlugin: EnterLeaveEventPlugin,
65
67
  ChangeEventPlugin: ChangeEventPlugin,
66
- CompositionEventPlugin: CompositionEventPlugin,
67
68
  MobileSafariClickEventPlugin: MobileSafariClickEventPlugin,
68
69
  SelectEventPlugin: SelectEventPlugin,
69
70
  BeforeInputEventPlugin: BeforeInputEventPlugin
@@ -73,6 +74,14 @@ function inject() {
73
74
  ReactDOMComponent
74
75
  );
75
76
 
77
+ ReactInjection.NativeComponent.injectTextComponentClass(
78
+ ReactDOMTextComponent
79
+ );
80
+
81
+ // This needs to happen before createFullPageComponent() otherwise the mixin
82
+ // won't be included.
83
+ ReactInjection.Class.injectMixin(ReactBrowserComponentMixin);
84
+
76
85
  ReactInjection.NativeComponent.injectComponentClasses({
77
86
  'button': ReactDOMButton,
78
87
  'form': ReactDOMForm,
@@ -87,17 +96,13 @@ function inject() {
87
96
  'body': createFullPageComponent('body')
88
97
  });
89
98
 
90
- // This needs to happen after createFullPageComponent() otherwise the mixin
91
- // gets double injected.
92
- ReactInjection.CompositeComponent.injectMixin(ReactBrowserComponentMixin);
93
-
94
99
  ReactInjection.DOMProperty.injectDOMPropertyConfig(HTMLDOMPropertyConfig);
95
100
  ReactInjection.DOMProperty.injectDOMPropertyConfig(SVGDOMPropertyConfig);
96
101
 
97
102
  ReactInjection.EmptyComponent.injectEmptyComponent('noscript');
98
103
 
99
104
  ReactInjection.Updates.injectReconcileTransaction(
100
- ReactComponentBrowserEnvironment.ReactReconcileTransaction
105
+ ReactReconcileTransaction
101
106
  );
102
107
  ReactInjection.Updates.injectBatchingStrategy(
103
108
  ReactDefaultBatchingStrategy
@@ -110,6 +115,7 @@ function inject() {
110
115
  );
111
116
 
112
117
  ReactInjection.Component.injectEnvironment(ReactComponentBrowserEnvironment);
118
+ ReactInjection.DOMComponent.injectIDOperations(ReactDOMIDOperations);
113
119
 
114
120
  if ("production" !== process.env.NODE_ENV) {
115
121
  var url = (ExecutionEnvironment.canUseDOM && window.location.href) || '';
@@ -10,7 +10,7 @@
10
10
  * @typechecks static-only
11
11
  */
12
12
 
13
- "use strict";
13
+ 'use strict';
14
14
 
15
15
  var DOMProperty = require("./DOMProperty");
16
16
  var ReactDefaultPerfAnalysis = require("./ReactDefaultPerfAnalysis");
@@ -137,7 +137,7 @@ var ReactDefaultPerf = {
137
137
  },
138
138
 
139
139
  measure: function(moduleName, fnName, func) {
140
- return function() {var args=Array.prototype.slice.call(arguments,0);
140
+ return function() {for (var args=[],$__0=0,$__1=arguments.length;$__0<$__1;$__0++) args.push(arguments[$__0]);
141
141
  var totalTime;
142
142
  var rv;
143
143
  var start;
@@ -169,7 +169,7 @@ var ReactDefaultPerf = {
169
169
  rv = func.apply(this, args);
170
170
  totalTime = performanceNow() - start;
171
171
 
172
- if (fnName === 'mountImageIntoNode') {
172
+ if (fnName === '_mountImageIntoNode') {
173
173
  var mountID = ReactMount.getID(args[1]);
174
174
  ReactDefaultPerf._recordWrite(mountID, fnName, totalTime, args[0]);
175
175
  } else if (fnName === 'dangerouslyProcessChildrenUpdates') {
@@ -206,9 +206,9 @@ var ReactDefaultPerf = {
206
206
  }
207
207
  return rv;
208
208
  } else if (moduleName === 'ReactCompositeComponent' && (
209
- fnName === 'mountComponent' ||
210
- fnName === 'updateComponent' || // TODO: receiveComponent()?
211
- fnName === '_renderValidatedComponent')) {
209
+ (// TODO: receiveComponent()?
210
+ (fnName === 'mountComponent' ||
211
+ fnName === 'updateComponent' || fnName === '_renderValidatedComponent')))) {
212
212
 
213
213
  var rootNodeID = fnName === 'mountComponent' ?
214
214
  args[0] :
@@ -244,7 +244,8 @@ var ReactDefaultPerf = {
244
244
 
245
245
  entry.displayNames[rootNodeID] = {
246
246
  current: this.constructor.displayName,
247
- owner: this._owner ? this._owner.constructor.displayName : '<root>'
247
+ owner: this._currentElement._owner ?
248
+ this._currentElement._owner.constructor.displayName : '<root>'
248
249
  };
249
250
 
250
251
  return rv;
@@ -14,7 +14,7 @@ var assign = require("./Object.assign");
14
14
  // Don't try to save users less than 1.2ms (a number I made up)
15
15
  var DONT_CARE_THRESHOLD = 1.2;
16
16
  var DOM_OPERATION_TYPES = {
17
- 'mountImageIntoNode': 'set innerHTML',
17
+ '_mountImageIntoNode': 'set innerHTML',
18
18
  INSERT_MARKUP: 'set innerHTML',
19
19
  MOVE_EXISTING: 'move',
20
20
  REMOVE_NODE: 'remove',
@@ -9,11 +9,12 @@
9
9
  * @providesModule ReactElement
10
10
  */
11
11
 
12
- "use strict";
12
+ 'use strict';
13
13
 
14
14
  var ReactContext = require("./ReactContext");
15
15
  var ReactCurrentOwner = require("./ReactCurrentOwner");
16
16
 
17
+ var assign = require("./Object.assign");
17
18
  var warning = require("./warning");
18
19
 
19
20
  var RESERVED_PROPS = {
@@ -44,8 +45,8 @@ function defineWarningProperty(object, key) {
44
45
  set: function(value) {
45
46
  ("production" !== process.env.NODE_ENV ? warning(
46
47
  false,
47
- 'Don\'t set the ' + key + ' property of the component. ' +
48
- 'Mutate the existing props object instead.'
48
+ 'Don\'t set the ' + key + ' property of the React element. Instead, ' +
49
+ 'specify the correct value when initially creating the element.'
49
50
  ) : null);
50
51
  this._store[key] = value;
51
52
  }
@@ -106,7 +107,21 @@ var ReactElement = function(type, key, ref, owner, context, props) {
106
107
  // an external backing store so that we can freeze the whole object.
107
108
  // This can be replaced with a WeakMap once they are implemented in
108
109
  // commonly used development environments.
109
- this._store = { validated: false, props: props };
110
+ this._store = { props: props, originalProps: assign({}, props) };
111
+
112
+ // To make comparing ReactElements easier for testing purposes, we make
113
+ // the validation flag non-enumerable (where possible, which should
114
+ // include every environment we run tests in), so the test framework
115
+ // ignores it.
116
+ try {
117
+ Object.defineProperty(this._store, 'validated', {
118
+ configurable: false,
119
+ enumerable: false,
120
+ writable: true
121
+ });
122
+ } catch (x) {
123
+ }
124
+ this._store.validated = false;
110
125
 
111
126
  // We're not allowed to set props directly on the object so we early
112
127
  // return and rely on the prototype membrane to forward to the backing
@@ -141,16 +156,7 @@ ReactElement.createElement = function(type, config, children) {
141
156
 
142
157
  if (config != null) {
143
158
  ref = config.ref === undefined ? null : config.ref;
144
- if ("production" !== process.env.NODE_ENV) {
145
- ("production" !== process.env.NODE_ENV ? warning(
146
- config.key !== null,
147
- 'createElement(...): Encountered component with a `key` of null. In ' +
148
- 'a future version, this will be treated as equivalent to the string ' +
149
- '\'null\'; instead, provide an explicit key or use undefined.'
150
- ) : null);
151
- }
152
- // TODO: Change this back to `config.key === undefined`
153
- key = config.key == null ? null : '' + config.key;
159
+ key = config.key === undefined ? null : '' + config.key;
154
160
  // Remaining properties are added to a new props object
155
161
  for (propName in config) {
156
162
  if (config.hasOwnProperty(propName) &&
@@ -174,7 +180,7 @@ ReactElement.createElement = function(type, config, children) {
174
180
  }
175
181
 
176
182
  // Resolve default props
177
- if (type.defaultProps) {
183
+ if (type && type.defaultProps) {
178
184
  var defaultProps = type.defaultProps;
179
185
  for (propName in defaultProps) {
180
186
  if (typeof props[propName] === 'undefined') {
@@ -199,6 +205,7 @@ ReactElement.createFactory = function(type) {
199
205
  // easily accessed on elements. E.g. <Foo />.type === Foo.type.
200
206
  // This should not be named `constructor` since this may not be the function
201
207
  // that created the element, and it may not even be a constructor.
208
+ // Legacy hook TODO: Warn if this is accessed
202
209
  factory.type = type;
203
210
  return factory;
204
211
  };
@@ -16,13 +16,17 @@
16
16
  * that support it.
17
17
  */
18
18
 
19
- "use strict";
19
+ 'use strict';
20
20
 
21
21
  var ReactElement = require("./ReactElement");
22
22
  var ReactPropTypeLocations = require("./ReactPropTypeLocations");
23
+ var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames");
23
24
  var ReactCurrentOwner = require("./ReactCurrentOwner");
24
25
 
26
+ var getIteratorFn = require("./getIteratorFn");
25
27
  var monitorCodeUse = require("./monitorCodeUse");
28
+ var invariant = require("./invariant");
29
+ var warning = require("./warning");
26
30
 
27
31
  /**
28
32
  * Warn if there's no key explicitly set on dynamic arrays of children or
@@ -39,6 +43,24 @@ var loggedTypeFailures = {};
39
43
 
40
44
  var NUMERIC_PROPERTY_REGEX = /^\d+$/;
41
45
 
46
+ /**
47
+ * Gets the instance's name for use in warnings.
48
+ *
49
+ * @internal
50
+ * @return {?string} Display name or undefined
51
+ */
52
+ function getName(instance) {
53
+ var publicInstance = instance && instance.getPublicInstance();
54
+ if (!publicInstance) {
55
+ return undefined;
56
+ }
57
+ var constructor = publicInstance.constructor;
58
+ if (!constructor) {
59
+ return undefined;
60
+ }
61
+ return constructor.displayName || constructor.name || undefined;
62
+ }
63
+
42
64
  /**
43
65
  * Gets the current owner's displayName for use in warnings.
44
66
  *
@@ -47,29 +69,31 @@ var NUMERIC_PROPERTY_REGEX = /^\d+$/;
47
69
  */
48
70
  function getCurrentOwnerDisplayName() {
49
71
  var current = ReactCurrentOwner.current;
50
- return current && current.constructor.displayName || undefined;
72
+ return (
73
+ current && getName(current) || undefined
74
+ );
51
75
  }
52
76
 
53
77
  /**
54
- * Warn if the component doesn't have an explicit key assigned to it.
55
- * This component is in an array. The array could grow and shrink or be
78
+ * Warn if the element doesn't have an explicit key assigned to it.
79
+ * This element is in an array. The array could grow and shrink or be
56
80
  * reordered. All children that haven't already been validated are required to
57
81
  * have a "key" property assigned to it.
58
82
  *
59
83
  * @internal
60
- * @param {ReactComponent} component Component that requires a key.
61
- * @param {*} parentType component's parent's type.
84
+ * @param {ReactElement} element Element that requires a key.
85
+ * @param {*} parentType element's parent's type.
62
86
  */
63
- function validateExplicitKey(component, parentType) {
64
- if (component._store.validated || component.key != null) {
87
+ function validateExplicitKey(element, parentType) {
88
+ if (element._store.validated || element.key != null) {
65
89
  return;
66
90
  }
67
- component._store.validated = true;
91
+ element._store.validated = true;
68
92
 
69
93
  warnAndMonitorForKeyUse(
70
94
  'react_key_warning',
71
- 'Each child in an array should have a unique "key" prop.',
72
- component,
95
+ 'Each child in an array or iterator should have a unique "key" prop.',
96
+ element,
73
97
  parentType
74
98
  );
75
99
  }
@@ -80,17 +104,17 @@ function validateExplicitKey(component, parentType) {
80
104
  *
81
105
  * @internal
82
106
  * @param {string} name Property name of the key.
83
- * @param {ReactComponent} component Component that requires a key.
84
- * @param {*} parentType component's parent's type.
107
+ * @param {ReactElement} element Component that requires a key.
108
+ * @param {*} parentType element's parent's type.
85
109
  */
86
- function validatePropertyKey(name, component, parentType) {
110
+ function validatePropertyKey(name, element, parentType) {
87
111
  if (!NUMERIC_PROPERTY_REGEX.test(name)) {
88
112
  return;
89
113
  }
90
114
  warnAndMonitorForKeyUse(
91
115
  'react_numeric_key_warning',
92
116
  'Child objects should have non-numeric keys so ordering is preserved.',
93
- component,
117
+ element,
94
118
  parentType
95
119
  );
96
120
  }
@@ -101,12 +125,12 @@ function validatePropertyKey(name, component, parentType) {
101
125
  * @internal
102
126
  * @param {string} warningID The id used when logging.
103
127
  * @param {string} message The base warning that gets output.
104
- * @param {ReactComponent} component Component that requires a key.
105
- * @param {*} parentType component's parent's type.
128
+ * @param {ReactElement} element Component that requires a key.
129
+ * @param {*} parentType element's parent's type.
106
130
  */
107
- function warnAndMonitorForKeyUse(warningID, message, component, parentType) {
131
+ function warnAndMonitorForKeyUse(warningID, message, element, parentType) {
108
132
  var ownerName = getCurrentOwnerDisplayName();
109
- var parentName = parentType.displayName;
133
+ var parentName = parentType.displayName || parentType.name;
110
134
 
111
135
  var useName = ownerName || parentName;
112
136
  var memoizer = ownerHasKeyUseWarning[warningID];
@@ -117,15 +141,17 @@ function warnAndMonitorForKeyUse(warningID, message, component, parentType) {
117
141
 
118
142
  message += ownerName ?
119
143
  (" Check the render method of " + ownerName + ".") :
120
- (" Check the renderComponent call using <" + parentName + ">.");
144
+ (" Check the React.render call using <" + parentName + ">.");
121
145
 
122
146
  // Usually the current owner is the offender, but if it accepts children as a
123
147
  // property, it may be the creator of the child that's responsible for
124
148
  // assigning it a key.
125
149
  var childOwnerName = null;
126
- if (component._owner && component._owner !== ReactCurrentOwner.current) {
150
+ if (element &&
151
+ element._owner &&
152
+ element._owner !== ReactCurrentOwner.current) {
127
153
  // Name of the component that originally created this child.
128
- childOwnerName = component._owner.constructor.displayName;
154
+ childOwnerName = getName(element._owner);
129
155
 
130
156
  message += (" It was passed a child from " + childOwnerName + ".");
131
157
  }
@@ -154,30 +180,43 @@ function monitorUseOfObjectMap() {
154
180
  }
155
181
 
156
182
  /**
157
- * Ensure that every component either is passed in a static location, in an
183
+ * Ensure that every element either is passed in a static location, in an
158
184
  * array with an explicit keys property defined, or in an object literal
159
185
  * with valid key property.
160
186
  *
161
187
  * @internal
162
- * @param {*} component Statically passed child of any type.
163
- * @param {*} parentType component's parent's type.
164
- * @return {boolean}
188
+ * @param {ReactNode} node Statically passed child of any type.
189
+ * @param {*} parentType node's parent's type.
165
190
  */
166
- function validateChildKeys(component, parentType) {
167
- if (Array.isArray(component)) {
168
- for (var i = 0; i < component.length; i++) {
169
- var child = component[i];
191
+ function validateChildKeys(node, parentType) {
192
+ if (Array.isArray(node)) {
193
+ for (var i = 0; i < node.length; i++) {
194
+ var child = node[i];
170
195
  if (ReactElement.isValidElement(child)) {
171
196
  validateExplicitKey(child, parentType);
172
197
  }
173
198
  }
174
- } else if (ReactElement.isValidElement(component)) {
175
- // This component was passed in a valid location.
176
- component._store.validated = true;
177
- } else if (component && typeof component === 'object') {
178
- monitorUseOfObjectMap();
179
- for (var name in component) {
180
- validatePropertyKey(name, component[name], parentType);
199
+ } else if (ReactElement.isValidElement(node)) {
200
+ // This element was passed in a valid location.
201
+ node._store.validated = true;
202
+ } else if (node) {
203
+ var iteratorFn = getIteratorFn(node);
204
+ // Entry iterators provide implicit keys.
205
+ if (iteratorFn && iteratorFn !== node.entries) {
206
+ var iterator = iteratorFn.call(node);
207
+ var step;
208
+ while (!(step = iterator.next()).done) {
209
+ if (ReactElement.isValidElement(step.value)) {
210
+ validateExplicitKey(step.value, parentType);
211
+ }
212
+ }
213
+ } else if (typeof node === 'object') {
214
+ monitorUseOfObjectMap();
215
+ for (var key in node) {
216
+ if (node.hasOwnProperty(key)) {
217
+ validatePropertyKey(key, node[key], parentType);
218
+ }
219
+ }
181
220
  }
182
221
  }
183
222
  }
@@ -199,6 +238,16 @@ function checkPropTypes(componentName, propTypes, props, location) {
199
238
  // fail the render phase where it didn't fail before. So we log it.
200
239
  // After these have been cleaned up, we'll let them throw.
201
240
  try {
241
+ // This is intentionally an invariant that gets caught. It's the same
242
+ // behavior as without this statement except with a better message.
243
+ ("production" !== process.env.NODE_ENV ? invariant(
244
+ typeof propTypes[propName] === 'function',
245
+ '%s: %s type `%s` is invalid; it must be a function, usually from ' +
246
+ 'React.PropTypes.',
247
+ componentName || 'React class',
248
+ ReactPropTypeLocationNames[location],
249
+ propName
250
+ ) : invariant(typeof propTypes[propName] === 'function'));
202
251
  error = propTypes[propName](props, propName, componentName, location);
203
252
  } catch (ex) {
204
253
  error = ex;
@@ -217,9 +266,88 @@ function checkPropTypes(componentName, propTypes, props, location) {
217
266
  }
218
267
  }
219
268
 
269
+ var warnedPropsMutations = {};
270
+
271
+ /**
272
+ * Warn about mutating props when setting `propName` on `element`.
273
+ *
274
+ * @param {string} propName The string key within props that was set
275
+ * @param {ReactElement} element
276
+ */
277
+ function warnForPropsMutation(propName, element) {
278
+ var type = element.type;
279
+ var elementName = typeof type === 'string' ? type : type.displayName;
280
+ var ownerName = element._owner ?
281
+ element._owner.getPublicInstance().constructor.displayName : null;
282
+
283
+ var warningKey = propName + '|' + elementName + '|' + ownerName;
284
+ if (warnedPropsMutations.hasOwnProperty(warningKey)) {
285
+ return;
286
+ }
287
+ warnedPropsMutations[warningKey] = true;
288
+
289
+ var elementInfo = '';
290
+ if (elementName) {
291
+ elementInfo = ' <' + elementName + ' />';
292
+ }
293
+ var ownerInfo = '';
294
+ if (ownerName) {
295
+ ownerInfo = ' The element was created by ' + ownerName + '.';
296
+ }
297
+
298
+ ("production" !== process.env.NODE_ENV ? warning(
299
+ false,
300
+ 'Don\'t set .props.' + propName + ' of the React component' +
301
+ elementInfo + '. Instead, specify the correct value when ' +
302
+ 'initially creating the element.' + ownerInfo
303
+ ) : null);
304
+ }
305
+
306
+ /**
307
+ * Given an element, check if its props have been mutated since element
308
+ * creation (or the last call to this function). In particular, check if any
309
+ * new props have been added, which we can't directly catch by defining warning
310
+ * properties on the props object.
311
+ *
312
+ * @param {ReactElement} element
313
+ */
314
+ function checkAndWarnForMutatedProps(element) {
315
+ if (!element._store) {
316
+ // Element was created using `new ReactElement` directly or with
317
+ // `ReactElement.createElement`; skip mutation checking
318
+ return;
319
+ }
320
+
321
+ var originalProps = element._store.originalProps;
322
+ var props = element.props;
323
+
324
+ for (var propName in props) {
325
+ if (props.hasOwnProperty(propName)) {
326
+ if (!originalProps.hasOwnProperty(propName) ||
327
+ originalProps[propName] !== props[propName]) {
328
+ warnForPropsMutation(propName, element);
329
+
330
+ // Copy over the new value so that the two props objects match again
331
+ originalProps[propName] = props[propName];
332
+ }
333
+ }
334
+ }
335
+ }
336
+
220
337
  var ReactElementValidator = {
221
338
 
339
+ checkAndWarnForMutatedProps: checkAndWarnForMutatedProps,
340
+
222
341
  createElement: function(type, props, children) {
342
+ // We warn in this case but don't throw. We expect the element creation to
343
+ // succeed and there will likely be errors in render.
344
+ ("production" !== process.env.NODE_ENV ? warning(
345
+ type != null,
346
+ 'React.createElement: type should not be null or undefined. It should ' +
347
+ 'be a string (for DOM elements) or a ReactClass (for composite ' +
348
+ 'components).'
349
+ ) : null);
350
+
223
351
  var element = ReactElement.createElement.apply(this, arguments);
224
352
 
225
353
  // The result can be nullish if a mock or a custom function is used.
@@ -232,23 +360,33 @@ var ReactElementValidator = {
232
360
  validateChildKeys(arguments[i], type);
233
361
  }
234
362
 
235
- var name = type.displayName;
236
- if (type.propTypes) {
237
- checkPropTypes(
238
- name,
239
- type.propTypes,
240
- element.props,
241
- ReactPropTypeLocations.prop
242
- );
243
- }
244
- if (type.contextTypes) {
245
- checkPropTypes(
246
- name,
247
- type.contextTypes,
248
- element._context,
249
- ReactPropTypeLocations.context
250
- );
363
+ if (type) {
364
+ var name = type.displayName || type.name;
365
+ if (type.propTypes) {
366
+ checkPropTypes(
367
+ name,
368
+ type.propTypes,
369
+ element.props,
370
+ ReactPropTypeLocations.prop
371
+ );
372
+ }
373
+ if (type.contextTypes) {
374
+ checkPropTypes(
375
+ name,
376
+ type.contextTypes,
377
+ element._context,
378
+ ReactPropTypeLocations.context
379
+ );
380
+ }
381
+ if (typeof type.getDefaultProps === 'function') {
382
+ ("production" !== process.env.NODE_ENV ? warning(
383
+ type.getDefaultProps.isReactClassApproved,
384
+ 'getDefaultProps is only used on classic React.createClass ' +
385
+ 'definitions. Use a static property named `defaultProps` instead.'
386
+ ) : null);
387
+ }
251
388
  }
389
+
252
390
  return element;
253
391
  },
254
392
 
@@ -257,6 +395,7 @@ var ReactElementValidator = {
257
395
  null,
258
396
  type
259
397
  );
398
+ // Legacy hook TODO: Warn if this is accessed
260
399
  validatedFactory.type = type;
261
400
  return validatedFactory;
262
401
  }