react 0.7.0 → 0.9.0

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 (217) hide show
  1. package/README.md +10 -231
  2. package/addons.js +1 -0
  3. package/lib/AutoFocusMixin.js +30 -0
  4. package/lib/CSSCore.js +115 -0
  5. package/lib/CSSProperty.js +121 -0
  6. package/lib/CSSPropertyOperations.js +97 -0
  7. package/lib/ChangeEventPlugin.js +387 -0
  8. package/lib/ClientReactRootIndex.js +30 -0
  9. package/lib/CompositionEventPlugin.js +260 -0
  10. package/lib/DOMChildrenOperations.js +165 -0
  11. package/lib/DOMProperty.js +268 -0
  12. package/lib/DOMPropertyOperations.js +181 -0
  13. package/lib/Danger.js +187 -0
  14. package/lib/DefaultDOMPropertyConfig.js +203 -0
  15. package/lib/DefaultEventPluginOrder.js +44 -0
  16. package/lib/EnterLeaveEventPlugin.js +145 -0
  17. package/lib/EventConstants.js +76 -0
  18. package/lib/EventListener.js +69 -0
  19. package/lib/EventPluginHub.js +293 -0
  20. package/lib/EventPluginRegistry.js +281 -0
  21. package/lib/EventPluginUtils.js +214 -0
  22. package/lib/EventPropagators.js +143 -0
  23. package/lib/ExecutionEnvironment.js +44 -0
  24. package/lib/LinkedStateMixin.js +46 -0
  25. package/lib/LinkedValueUtils.js +161 -0
  26. package/lib/MobileSafariClickEventPlugin.js +63 -0
  27. package/lib/PooledClass.js +119 -0
  28. package/lib/React.js +95 -0
  29. package/lib/ReactCSSTransitionGroup.js +65 -0
  30. package/lib/ReactCSSTransitionGroupChild.js +138 -0
  31. package/lib/ReactChildren.js +132 -0
  32. package/lib/ReactComponent.js +550 -0
  33. package/lib/ReactComponentBrowserEnvironment.js +158 -0
  34. package/lib/ReactComponentEnvironment.js +26 -0
  35. package/lib/ReactCompositeComponent.js +1455 -0
  36. package/lib/ReactContext.js +67 -0
  37. package/lib/ReactCurrentOwner.js +39 -0
  38. package/lib/ReactDOM.js +207 -0
  39. package/lib/ReactDOMButton.js +68 -0
  40. package/lib/ReactDOMComponent.js +399 -0
  41. package/lib/ReactDOMForm.js +59 -0
  42. package/lib/ReactDOMIDOperations.js +218 -0
  43. package/lib/ReactDOMImg.js +58 -0
  44. package/lib/ReactDOMInput.js +181 -0
  45. package/lib/ReactDOMOption.js +51 -0
  46. package/lib/ReactDOMSelect.js +179 -0
  47. package/lib/ReactDOMSelection.js +189 -0
  48. package/lib/ReactDOMTextarea.js +140 -0
  49. package/lib/ReactDefaultBatchingStrategy.js +75 -0
  50. package/lib/ReactDefaultInjection.js +115 -0
  51. package/lib/ReactDefaultPerf.js +244 -0
  52. package/lib/ReactDefaultPerfAnalysis.js +199 -0
  53. package/lib/ReactErrorUtils.js +37 -0
  54. package/lib/ReactEventEmitter.js +339 -0
  55. package/lib/ReactEventEmitterMixin.js +57 -0
  56. package/lib/ReactEventTopLevelCallback.js +149 -0
  57. package/lib/ReactInjection.js +39 -0
  58. package/lib/ReactInputSelection.js +140 -0
  59. package/lib/ReactInstanceHandles.js +338 -0
  60. package/lib/ReactLink.js +54 -0
  61. package/lib/ReactMarkupChecksum.js +53 -0
  62. package/lib/ReactMount.js +641 -0
  63. package/lib/ReactMountReady.js +95 -0
  64. package/lib/ReactMultiChild.js +425 -0
  65. package/lib/ReactMultiChildUpdateTypes.js +38 -0
  66. package/lib/ReactOwner.js +154 -0
  67. package/lib/ReactPerf.js +85 -0
  68. package/lib/ReactPropTransferer.js +147 -0
  69. package/lib/ReactPropTypeLocationNames.js +31 -0
  70. package/lib/ReactPropTypeLocations.js +29 -0
  71. package/lib/ReactPropTypes.js +359 -0
  72. package/lib/ReactPutListenerQueue.js +61 -0
  73. package/lib/ReactReconcileTransaction.js +181 -0
  74. package/lib/ReactRootIndex.js +36 -0
  75. package/lib/ReactServerRendering.js +59 -0
  76. package/lib/ReactStateSetters.js +111 -0
  77. package/lib/ReactTestUtils.js +394 -0
  78. package/lib/ReactTextComponent.js +99 -0
  79. package/lib/ReactTransitionChildMapping.js +106 -0
  80. package/lib/ReactTransitionEvents.js +97 -0
  81. package/lib/ReactTransitionGroup.js +187 -0
  82. package/lib/ReactUpdates.js +148 -0
  83. package/lib/ReactWithAddons.js +51 -0
  84. package/lib/SelectEventPlugin.js +200 -0
  85. package/lib/ServerReactRootIndex.js +36 -0
  86. package/lib/SimpleEventPlugin.js +413 -0
  87. package/lib/SyntheticClipboardEvent.js +51 -0
  88. package/lib/SyntheticCompositionEvent.js +51 -0
  89. package/lib/SyntheticDragEvent.js +44 -0
  90. package/lib/SyntheticEvent.js +164 -0
  91. package/lib/SyntheticFocusEvent.js +44 -0
  92. package/lib/SyntheticKeyboardEvent.js +58 -0
  93. package/lib/SyntheticMouseEvent.js +85 -0
  94. package/lib/SyntheticTouchEvent.js +50 -0
  95. package/lib/SyntheticUIEvent.js +45 -0
  96. package/lib/SyntheticWheelEvent.js +66 -0
  97. package/lib/Transaction.js +276 -0
  98. package/lib/ViewportMetrics.js +37 -0
  99. package/lib/accumulate.js +54 -0
  100. package/lib/adler32.js +39 -0
  101. package/lib/cloneWithProps.js +59 -0
  102. package/lib/containsNode.js +49 -0
  103. package/lib/copyProperties.js +54 -0
  104. package/lib/createArrayFrom.js +91 -0
  105. package/lib/createFullPageComponent.js +63 -0
  106. package/lib/createNodesFromMarkup.js +93 -0
  107. package/lib/createObjectFrom.js +61 -0
  108. package/lib/cx.js +44 -0
  109. package/lib/dangerousStyleValue.js +57 -0
  110. package/lib/emptyFunction.js +43 -0
  111. package/lib/escapeTextForBrowser.js +47 -0
  112. package/lib/flattenChildren.js +57 -0
  113. package/lib/forEachAccumulated.js +36 -0
  114. package/lib/getActiveElement.js +34 -0
  115. package/lib/getEventKey.js +85 -0
  116. package/lib/getEventTarget.js +36 -0
  117. package/lib/getMarkupWrap.js +118 -0
  118. package/lib/getNodeForCharacterOffset.js +80 -0
  119. package/lib/getReactRootElementInContainer.js +40 -0
  120. package/lib/getTextContentAccessor.js +42 -0
  121. package/lib/getUnboundedScrollPosition.js +45 -0
  122. package/lib/hyphenate.js +35 -0
  123. package/lib/invariant.js +62 -0
  124. package/lib/isEventSupported.js +70 -0
  125. package/lib/isNode.js +33 -0
  126. package/lib/isTextInputElement.js +49 -0
  127. package/lib/isTextNode.js +30 -0
  128. package/lib/joinClasses.js +44 -0
  129. package/lib/keyMirror.js +58 -0
  130. package/lib/keyOf.js +41 -0
  131. package/lib/memoizeStringOnly.js +39 -0
  132. package/lib/merge.js +37 -0
  133. package/lib/mergeHelpers.js +136 -0
  134. package/lib/mergeInto.js +45 -0
  135. package/lib/mixInto.js +34 -0
  136. package/lib/objMap.js +47 -0
  137. package/lib/objMapKeyVal.js +47 -0
  138. package/lib/onlyChild.js +43 -0
  139. package/lib/performanceNow.js +42 -0
  140. package/lib/shallowEqual.js +49 -0
  141. package/lib/shouldUpdateReactComponent.js +58 -0
  142. package/lib/toArray.js +75 -0
  143. package/lib/traverseAllChildren.js +189 -0
  144. package/lib/warning.js +48 -0
  145. package/package.json +33 -21
  146. package/react.js +1 -0
  147. package/.npmignore +0 -7
  148. package/.travis.yml +0 -7
  149. package/Jakefile.js +0 -39
  150. package/LICENSE +0 -19
  151. package/browser-test/dist.html +0 -90
  152. package/browser-test/index.html +0 -86
  153. package/browser-test/min.html +0 -90
  154. package/dist/react.js +0 -3141
  155. package/dist/react.min.js +0 -22
  156. package/doc/advanced.md +0 -174
  157. package/doc/color-def.graffle +0 -938
  158. package/doc/color-def.png +0 -0
  159. package/doc/simple.dot +0 -25
  160. package/doc/simple.png +0 -0
  161. package/examples/longer-example.js +0 -41
  162. package/examples/simple.js +0 -45
  163. package/examples/using-ast-directly.js +0 -30
  164. package/examples/using-events1.js +0 -79
  165. package/examples/using-log-events.js +0 -43
  166. package/lib/base-task.js +0 -120
  167. package/lib/cb-task.js +0 -84
  168. package/lib/core.js +0 -138
  169. package/lib/dsl.js +0 -138
  170. package/lib/error.js +0 -55
  171. package/lib/event-collector.js +0 -81
  172. package/lib/event-manager.js +0 -89
  173. package/lib/eventemitter.js +0 -20
  174. package/lib/finalcb-first-task.js +0 -68
  175. package/lib/finalcb-task.js +0 -65
  176. package/lib/id.js +0 -22
  177. package/lib/input-parser.js +0 -56
  178. package/lib/log-events.js +0 -101
  179. package/lib/parse.js +0 -41
  180. package/lib/promise-resolve.js +0 -50
  181. package/lib/promise-task.js +0 -93
  182. package/lib/react.js +0 -59
  183. package/lib/ret-task.js +0 -71
  184. package/lib/sprintf.js +0 -18
  185. package/lib/status.js +0 -14
  186. package/lib/task.js +0 -251
  187. package/lib/track-tasks.js +0 -74
  188. package/lib/validate.js +0 -159
  189. package/lib/vcon.js +0 -113
  190. package/lib/when-task.js +0 -84
  191. package/src/dist.build.requirejs +0 -20
  192. package/test/ast.mocha.js +0 -136
  193. package/test/cb-task.mocha.js +0 -220
  194. package/test/core-deferred.mocha.js +0 -143
  195. package/test/core-when.mocha.js +0 -96
  196. package/test/core.mocha.js +0 -589
  197. package/test/dsl.mocha.js +0 -352
  198. package/test/event-manager.mocha.js +0 -119
  199. package/test/exec-options.mocha.js +0 -48
  200. package/test/finalcb-task.mocha.js +0 -58
  201. package/test/input-parser.mocha.js +0 -86
  202. package/test/log-events.mocha.js +0 -88
  203. package/test/mocha.opts +0 -2
  204. package/test/module-use.mocha.js +0 -164
  205. package/test/promise-auto-resolve.mocha.js +0 -68
  206. package/test/ret-task.mocha.js +0 -220
  207. package/test/task.mocha.js +0 -42
  208. package/test/validate-cb-task.mocha.js +0 -100
  209. package/test/validate-ret-task.mocha.js +0 -110
  210. package/test/validate.mocha.js +0 -324
  211. package/test/vcon.mocha.js +0 -193
  212. package/vendor/chai/chai.js +0 -4251
  213. package/vendor/jquery/jquery-1.7.1.js +0 -9266
  214. package/vendor/jquery/jquery-1.7.1.min.js +0 -4
  215. package/vendor/node/util.js +0 -531
  216. package/vendor/requirejs/require.js +0 -2045
  217. package/vendor/requirejs/require.min.js +0 -36
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Copyright 2013-2014 Facebook, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ * @providesModule ReactComponentBrowserEnvironment
17
+ */
18
+
19
+ /*jslint evil: true */
20
+
21
+ "use strict";
22
+
23
+ var ReactDOMIDOperations = require("./ReactDOMIDOperations");
24
+ var ReactMarkupChecksum = require("./ReactMarkupChecksum");
25
+ var ReactMount = require("./ReactMount");
26
+ var ReactPerf = require("./ReactPerf");
27
+ var ReactReconcileTransaction = require("./ReactReconcileTransaction");
28
+
29
+ var getReactRootElementInContainer = require("./getReactRootElementInContainer");
30
+ var invariant = require("./invariant");
31
+
32
+
33
+ var ELEMENT_NODE_TYPE = 1;
34
+ var DOC_NODE_TYPE = 9;
35
+
36
+
37
+ /**
38
+ * Abstracts away all functionality of `ReactComponent` requires knowledge of
39
+ * the browser context.
40
+ */
41
+ var ReactComponentBrowserEnvironment = {
42
+ /**
43
+ * Mixed into every component instance.
44
+ */
45
+ Mixin: {
46
+ /**
47
+ * Returns the DOM node rendered by this component.
48
+ *
49
+ * @return {DOMElement} The root node of this component.
50
+ * @final
51
+ * @protected
52
+ */
53
+ getDOMNode: function() {
54
+ ("production" !== process.env.NODE_ENV ? invariant(
55
+ this.isMounted(),
56
+ 'getDOMNode(): A component must be mounted to have a DOM node.'
57
+ ) : invariant(this.isMounted()));
58
+ return ReactMount.getNode(this._rootNodeID);
59
+ }
60
+ },
61
+
62
+ ReactReconcileTransaction: ReactReconcileTransaction,
63
+
64
+ BackendIDOperations: ReactDOMIDOperations,
65
+
66
+ /**
67
+ * If a particular environment requires that some resources be cleaned up,
68
+ * specify this in the injected Mixin. In the DOM, we would likely want to
69
+ * purge any cached node ID lookups.
70
+ *
71
+ * @private
72
+ */
73
+ unmountIDFromEnvironment: function(rootNodeID) {
74
+ ReactMount.purgeID(rootNodeID);
75
+ },
76
+
77
+ /**
78
+ * @param {string} markup Markup string to place into the DOM Element.
79
+ * @param {DOMElement} container DOM Element to insert markup into.
80
+ * @param {boolean} shouldReuseMarkup Should reuse the existing markup in the
81
+ * container if possible.
82
+ */
83
+ mountImageIntoNode: ReactPerf.measure(
84
+ 'ReactComponentBrowserEnvironment',
85
+ 'mountImageIntoNode',
86
+ function(markup, container, shouldReuseMarkup) {
87
+ ("production" !== process.env.NODE_ENV ? invariant(
88
+ container && (
89
+ container.nodeType === ELEMENT_NODE_TYPE ||
90
+ container.nodeType === DOC_NODE_TYPE
91
+ ),
92
+ 'mountComponentIntoNode(...): Target container is not valid.'
93
+ ) : invariant(container && (
94
+ container.nodeType === ELEMENT_NODE_TYPE ||
95
+ container.nodeType === DOC_NODE_TYPE
96
+ )));
97
+
98
+ if (shouldReuseMarkup) {
99
+ if (ReactMarkupChecksum.canReuseMarkup(
100
+ markup,
101
+ getReactRootElementInContainer(container))) {
102
+ return;
103
+ } else {
104
+ ("production" !== process.env.NODE_ENV ? invariant(
105
+ container.nodeType !== DOC_NODE_TYPE,
106
+ 'You\'re trying to render a component to the document using ' +
107
+ 'server rendering but the checksum was invalid. This usually ' +
108
+ 'means you rendered a different component type or props on ' +
109
+ 'the client from the one on the server, or your render() ' +
110
+ 'methods are impure. React cannot handle this case due to ' +
111
+ 'cross-browser quirks by rendering at the document root. You ' +
112
+ 'should look for environment dependent code in your components ' +
113
+ 'and ensure the props are the same client and server side.'
114
+ ) : invariant(container.nodeType !== DOC_NODE_TYPE));
115
+
116
+ if ("production" !== process.env.NODE_ENV) {
117
+ console.warn(
118
+ 'React attempted to use reuse markup in a container but the ' +
119
+ 'checksum was invalid. This generally means that you are ' +
120
+ 'using server rendering and the markup generated on the ' +
121
+ 'server was not what the client was expecting. React injected' +
122
+ 'new markup to compensate which works but you have lost many ' +
123
+ 'of the benefits of server rendering. Instead, figure out ' +
124
+ 'why the markup being generated is different on the client ' +
125
+ 'or server.'
126
+ );
127
+ }
128
+ }
129
+ }
130
+
131
+ ("production" !== process.env.NODE_ENV ? invariant(
132
+ container.nodeType !== DOC_NODE_TYPE,
133
+ 'You\'re trying to render a component to the document but ' +
134
+ 'you didn\'t use server rendering. We can\'t do this ' +
135
+ 'without using server rendering due to cross-browser quirks. ' +
136
+ 'See renderComponentToString() for server rendering.'
137
+ ) : invariant(container.nodeType !== DOC_NODE_TYPE));
138
+
139
+ // Asynchronously inject markup by ensuring that the container is not in
140
+ // the document when settings its `innerHTML`.
141
+ var parent = container.parentNode;
142
+ if (parent) {
143
+ var next = container.nextSibling;
144
+ parent.removeChild(container);
145
+ container.innerHTML = markup;
146
+ if (next) {
147
+ parent.insertBefore(container, next);
148
+ } else {
149
+ parent.appendChild(container);
150
+ }
151
+ } else {
152
+ container.innerHTML = markup;
153
+ }
154
+ }
155
+ )
156
+ };
157
+
158
+ module.exports = ReactComponentBrowserEnvironment;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Copyright 2013-2014 Facebook, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ * @providesModule ReactComponentEnvironment
17
+ */
18
+
19
+ "use strict";
20
+
21
+ var ReactComponentBrowserEnvironment =
22
+ require("./ReactComponentBrowserEnvironment");
23
+
24
+ var ReactComponentEnvironment = ReactComponentBrowserEnvironment;
25
+
26
+ module.exports = ReactComponentEnvironment;
@@ -0,0 +1,1455 @@
1
+ /**
2
+ * Copyright 2013-2014 Facebook, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ * @providesModule ReactCompositeComponent
17
+ */
18
+
19
+ "use strict";
20
+
21
+ var ReactComponent = require("./ReactComponent");
22
+ var ReactContext = require("./ReactContext");
23
+ var ReactCurrentOwner = require("./ReactCurrentOwner");
24
+ var ReactErrorUtils = require("./ReactErrorUtils");
25
+ var ReactOwner = require("./ReactOwner");
26
+ var ReactPerf = require("./ReactPerf");
27
+ var ReactPropTransferer = require("./ReactPropTransferer");
28
+ var ReactPropTypeLocations = require("./ReactPropTypeLocations");
29
+ var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames");
30
+ var ReactUpdates = require("./ReactUpdates");
31
+
32
+ var invariant = require("./invariant");
33
+ var keyMirror = require("./keyMirror");
34
+ var merge = require("./merge");
35
+ var mixInto = require("./mixInto");
36
+ var objMap = require("./objMap");
37
+ var shouldUpdateReactComponent = require("./shouldUpdateReactComponent");
38
+
39
+ /**
40
+ * Policies that describe methods in `ReactCompositeComponentInterface`.
41
+ */
42
+ var SpecPolicy = keyMirror({
43
+ /**
44
+ * These methods may be defined only once by the class specification or mixin.
45
+ */
46
+ DEFINE_ONCE: null,
47
+ /**
48
+ * These methods may be defined by both the class specification and mixins.
49
+ * Subsequent definitions will be chained. These methods must return void.
50
+ */
51
+ DEFINE_MANY: null,
52
+ /**
53
+ * These methods are overriding the base ReactCompositeComponent class.
54
+ */
55
+ OVERRIDE_BASE: null,
56
+ /**
57
+ * These methods are similar to DEFINE_MANY, except we assume they return
58
+ * objects. We try to merge the keys of the return values of all the mixed in
59
+ * functions. If there is a key conflict we throw.
60
+ */
61
+ DEFINE_MANY_MERGED: null
62
+ });
63
+
64
+ /**
65
+ * Composite components are higher-level components that compose other composite
66
+ * or native components.
67
+ *
68
+ * To create a new type of `ReactCompositeComponent`, pass a specification of
69
+ * your new class to `React.createClass`. The only requirement of your class
70
+ * specification is that you implement a `render` method.
71
+ *
72
+ * var MyComponent = React.createClass({
73
+ * render: function() {
74
+ * return <div>Hello World</div>;
75
+ * }
76
+ * });
77
+ *
78
+ * The class specification supports a specific protocol of methods that have
79
+ * special meaning (e.g. `render`). See `ReactCompositeComponentInterface` for
80
+ * more the comprehensive protocol. Any other properties and methods in the
81
+ * class specification will available on the prototype.
82
+ *
83
+ * @interface ReactCompositeComponentInterface
84
+ * @internal
85
+ */
86
+ var ReactCompositeComponentInterface = {
87
+
88
+ /**
89
+ * An array of Mixin objects to include when defining your component.
90
+ *
91
+ * @type {array}
92
+ * @optional
93
+ */
94
+ mixins: SpecPolicy.DEFINE_MANY,
95
+
96
+ /**
97
+ * An object containing properties and methods that should be defined on
98
+ * the component's constructor instead of its prototype (static methods).
99
+ *
100
+ * @type {object}
101
+ * @optional
102
+ */
103
+ statics: SpecPolicy.DEFINE_MANY,
104
+
105
+ /**
106
+ * Definition of prop types for this component.
107
+ *
108
+ * @type {object}
109
+ * @optional
110
+ */
111
+ propTypes: SpecPolicy.DEFINE_MANY,
112
+
113
+ /**
114
+ * Definition of context types for this component.
115
+ *
116
+ * @type {object}
117
+ * @optional
118
+ */
119
+ contextTypes: SpecPolicy.DEFINE_MANY,
120
+
121
+ /**
122
+ * Definition of context types this component sets for its children.
123
+ *
124
+ * @type {object}
125
+ * @optional
126
+ */
127
+ childContextTypes: SpecPolicy.DEFINE_MANY,
128
+
129
+ // ==== Definition methods ====
130
+
131
+ /**
132
+ * Invoked when the component is mounted. Values in the mapping will be set on
133
+ * `this.props` if that prop is not specified (i.e. using an `in` check).
134
+ *
135
+ * This method is invoked before `getInitialState` and therefore cannot rely
136
+ * on `this.state` or use `this.setState`.
137
+ *
138
+ * @return {object}
139
+ * @optional
140
+ */
141
+ getDefaultProps: SpecPolicy.DEFINE_MANY_MERGED,
142
+
143
+ /**
144
+ * Invoked once before the component is mounted. The return value will be used
145
+ * as the initial value of `this.state`.
146
+ *
147
+ * getInitialState: function() {
148
+ * return {
149
+ * isOn: false,
150
+ * fooBaz: new BazFoo()
151
+ * }
152
+ * }
153
+ *
154
+ * @return {object}
155
+ * @optional
156
+ */
157
+ getInitialState: SpecPolicy.DEFINE_MANY_MERGED,
158
+
159
+ /**
160
+ * @return {object}
161
+ * @optional
162
+ */
163
+ getChildContext: SpecPolicy.DEFINE_MANY_MERGED,
164
+
165
+ /**
166
+ * Uses props from `this.props` and state from `this.state` to render the
167
+ * structure of the component.
168
+ *
169
+ * No guarantees are made about when or how often this method is invoked, so
170
+ * it must not have side effects.
171
+ *
172
+ * render: function() {
173
+ * var name = this.props.name;
174
+ * return <div>Hello, {name}!</div>;
175
+ * }
176
+ *
177
+ * @return {ReactComponent}
178
+ * @nosideeffects
179
+ * @required
180
+ */
181
+ render: SpecPolicy.DEFINE_ONCE,
182
+
183
+
184
+
185
+ // ==== Delegate methods ====
186
+
187
+ /**
188
+ * Invoked when the component is initially created and about to be mounted.
189
+ * This may have side effects, but any external subscriptions or data created
190
+ * by this method must be cleaned up in `componentWillUnmount`.
191
+ *
192
+ * @optional
193
+ */
194
+ componentWillMount: SpecPolicy.DEFINE_MANY,
195
+
196
+ /**
197
+ * Invoked when the component has been mounted and has a DOM representation.
198
+ * However, there is no guarantee that the DOM node is in the document.
199
+ *
200
+ * Use this as an opportunity to operate on the DOM when the component has
201
+ * been mounted (initialized and rendered) for the first time.
202
+ *
203
+ * @param {DOMElement} rootNode DOM element representing the component.
204
+ * @optional
205
+ */
206
+ componentDidMount: SpecPolicy.DEFINE_MANY,
207
+
208
+ /**
209
+ * Invoked before the component receives new props.
210
+ *
211
+ * Use this as an opportunity to react to a prop transition by updating the
212
+ * state using `this.setState`. Current props are accessed via `this.props`.
213
+ *
214
+ * componentWillReceiveProps: function(nextProps, nextContext) {
215
+ * this.setState({
216
+ * likesIncreasing: nextProps.likeCount > this.props.likeCount
217
+ * });
218
+ * }
219
+ *
220
+ * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop
221
+ * transition may cause a state change, but the opposite is not true. If you
222
+ * need it, you are probably looking for `componentWillUpdate`.
223
+ *
224
+ * @param {object} nextProps
225
+ * @optional
226
+ */
227
+ componentWillReceiveProps: SpecPolicy.DEFINE_MANY,
228
+
229
+ /**
230
+ * Invoked while deciding if the component should be updated as a result of
231
+ * receiving new props, state and/or context.
232
+ *
233
+ * Use this as an opportunity to `return false` when you're certain that the
234
+ * transition to the new props/state/context will not require a component
235
+ * update.
236
+ *
237
+ * shouldComponentUpdate: function(nextProps, nextState, nextContext) {
238
+ * return !equal(nextProps, this.props) ||
239
+ * !equal(nextState, this.state) ||
240
+ * !equal(nextContext, this.context);
241
+ * }
242
+ *
243
+ * @param {object} nextProps
244
+ * @param {?object} nextState
245
+ * @param {?object} nextContext
246
+ * @return {boolean} True if the component should update.
247
+ * @optional
248
+ */
249
+ shouldComponentUpdate: SpecPolicy.DEFINE_ONCE,
250
+
251
+ /**
252
+ * Invoked when the component is about to update due to a transition from
253
+ * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState`
254
+ * and `nextContext`.
255
+ *
256
+ * Use this as an opportunity to perform preparation before an update occurs.
257
+ *
258
+ * NOTE: You **cannot** use `this.setState()` in this method.
259
+ *
260
+ * @param {object} nextProps
261
+ * @param {?object} nextState
262
+ * @param {?object} nextContext
263
+ * @param {ReactReconcileTransaction} transaction
264
+ * @optional
265
+ */
266
+ componentWillUpdate: SpecPolicy.DEFINE_MANY,
267
+
268
+ /**
269
+ * Invoked when the component's DOM representation has been updated.
270
+ *
271
+ * Use this as an opportunity to operate on the DOM when the component has
272
+ * been updated.
273
+ *
274
+ * @param {object} prevProps
275
+ * @param {?object} prevState
276
+ * @param {?object} prevContext
277
+ * @param {DOMElement} rootNode DOM element representing the component.
278
+ * @optional
279
+ */
280
+ componentDidUpdate: SpecPolicy.DEFINE_MANY,
281
+
282
+ /**
283
+ * Invoked when the component is about to be removed from its parent and have
284
+ * its DOM representation destroyed.
285
+ *
286
+ * Use this as an opportunity to deallocate any external resources.
287
+ *
288
+ * NOTE: There is no `componentDidUnmount` since your component will have been
289
+ * destroyed by that point.
290
+ *
291
+ * @optional
292
+ */
293
+ componentWillUnmount: SpecPolicy.DEFINE_MANY,
294
+
295
+
296
+
297
+ // ==== Advanced methods ====
298
+
299
+ /**
300
+ * Updates the component's currently mounted DOM representation.
301
+ *
302
+ * By default, this implements React's rendering and reconciliation algorithm.
303
+ * Sophisticated clients may wish to override this.
304
+ *
305
+ * @param {ReactReconcileTransaction} transaction
306
+ * @internal
307
+ * @overridable
308
+ */
309
+ updateComponent: SpecPolicy.OVERRIDE_BASE
310
+
311
+ };
312
+
313
+ /**
314
+ * Mapping from class specification keys to special processing functions.
315
+ *
316
+ * Although these are declared like instance properties in the specification
317
+ * when defining classes using `React.createClass`, they are actually static
318
+ * and are accessible on the constructor instead of the prototype. Despite
319
+ * being static, they must be defined outside of the "statics" key under
320
+ * which all other static methods are defined.
321
+ */
322
+ var RESERVED_SPEC_KEYS = {
323
+ displayName: function(ConvenienceConstructor, displayName) {
324
+ ConvenienceConstructor.componentConstructor.displayName = displayName;
325
+ },
326
+ mixins: function(ConvenienceConstructor, mixins) {
327
+ if (mixins) {
328
+ for (var i = 0; i < mixins.length; i++) {
329
+ mixSpecIntoComponent(ConvenienceConstructor, mixins[i]);
330
+ }
331
+ }
332
+ },
333
+ childContextTypes: function(ConvenienceConstructor, childContextTypes) {
334
+ var Constructor = ConvenienceConstructor.componentConstructor;
335
+ validateTypeDef(
336
+ Constructor,
337
+ childContextTypes,
338
+ ReactPropTypeLocations.childContext
339
+ );
340
+ Constructor.childContextTypes = merge(
341
+ Constructor.childContextTypes,
342
+ childContextTypes
343
+ );
344
+ },
345
+ contextTypes: function(ConvenienceConstructor, contextTypes) {
346
+ var Constructor = ConvenienceConstructor.componentConstructor;
347
+ validateTypeDef(
348
+ Constructor,
349
+ contextTypes,
350
+ ReactPropTypeLocations.context
351
+ );
352
+ Constructor.contextTypes = merge(Constructor.contextTypes, contextTypes);
353
+ },
354
+ propTypes: function(ConvenienceConstructor, propTypes) {
355
+ var Constructor = ConvenienceConstructor.componentConstructor;
356
+ validateTypeDef(
357
+ Constructor,
358
+ propTypes,
359
+ ReactPropTypeLocations.prop
360
+ );
361
+ Constructor.propTypes = merge(Constructor.propTypes, propTypes);
362
+ },
363
+ statics: function(ConvenienceConstructor, statics) {
364
+ mixStaticSpecIntoComponent(ConvenienceConstructor, statics);
365
+ }
366
+ };
367
+
368
+ function validateTypeDef(Constructor, typeDef, location) {
369
+ for (var propName in typeDef) {
370
+ if (typeDef.hasOwnProperty(propName)) {
371
+ ("production" !== process.env.NODE_ENV ? invariant(
372
+ typeof typeDef[propName] == 'function',
373
+ '%s: %s type `%s` is invalid; it must be a function, usually from ' +
374
+ 'React.PropTypes.',
375
+ Constructor.displayName || 'ReactCompositeComponent',
376
+ ReactPropTypeLocationNames[location],
377
+ propName
378
+ ) : invariant(typeof typeDef[propName] == 'function'));
379
+ }
380
+ }
381
+ }
382
+
383
+ function validateMethodOverride(proto, name) {
384
+ var specPolicy = ReactCompositeComponentInterface[name];
385
+
386
+ // Disallow overriding of base class methods unless explicitly allowed.
387
+ if (ReactCompositeComponentMixin.hasOwnProperty(name)) {
388
+ ("production" !== process.env.NODE_ENV ? invariant(
389
+ specPolicy === SpecPolicy.OVERRIDE_BASE,
390
+ 'ReactCompositeComponentInterface: You are attempting to override ' +
391
+ '`%s` from your class specification. Ensure that your method names ' +
392
+ 'do not overlap with React methods.',
393
+ name
394
+ ) : invariant(specPolicy === SpecPolicy.OVERRIDE_BASE));
395
+ }
396
+
397
+ // Disallow defining methods more than once unless explicitly allowed.
398
+ if (proto.hasOwnProperty(name)) {
399
+ ("production" !== process.env.NODE_ENV ? invariant(
400
+ specPolicy === SpecPolicy.DEFINE_MANY ||
401
+ specPolicy === SpecPolicy.DEFINE_MANY_MERGED,
402
+ 'ReactCompositeComponentInterface: You are attempting to define ' +
403
+ '`%s` on your component more than once. This conflict may be due ' +
404
+ 'to a mixin.',
405
+ name
406
+ ) : invariant(specPolicy === SpecPolicy.DEFINE_MANY ||
407
+ specPolicy === SpecPolicy.DEFINE_MANY_MERGED));
408
+ }
409
+ }
410
+
411
+ function validateLifeCycleOnReplaceState(instance) {
412
+ var compositeLifeCycleState = instance._compositeLifeCycleState;
413
+ ("production" !== process.env.NODE_ENV ? invariant(
414
+ instance.isMounted() ||
415
+ compositeLifeCycleState === CompositeLifeCycle.MOUNTING,
416
+ 'replaceState(...): Can only update a mounted or mounting component.'
417
+ ) : invariant(instance.isMounted() ||
418
+ compositeLifeCycleState === CompositeLifeCycle.MOUNTING));
419
+ ("production" !== process.env.NODE_ENV ? invariant(compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE,
420
+ 'replaceState(...): Cannot update during an existing state transition ' +
421
+ '(such as within `render`). This could potentially cause an infinite ' +
422
+ 'loop so it is forbidden.'
423
+ ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE));
424
+ ("production" !== process.env.NODE_ENV ? invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING,
425
+ 'replaceState(...): Cannot update while unmounting component. This ' +
426
+ 'usually means you called setState() on an unmounted component.'
427
+ ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING));
428
+ }
429
+
430
+ /**
431
+ * Custom version of `mixInto` which handles policy validation and reserved
432
+ * specification keys when building `ReactCompositeComponent` classses.
433
+ */
434
+ function mixSpecIntoComponent(ConvenienceConstructor, spec) {
435
+ ("production" !== process.env.NODE_ENV ? invariant(
436
+ !isValidClass(spec),
437
+ 'ReactCompositeComponent: You\'re attempting to ' +
438
+ 'use a component class as a mixin. Instead, just use a regular object.'
439
+ ) : invariant(!isValidClass(spec)));
440
+ ("production" !== process.env.NODE_ENV ? invariant(
441
+ !ReactComponent.isValidComponent(spec),
442
+ 'ReactCompositeComponent: You\'re attempting to ' +
443
+ 'use a component as a mixin. Instead, just use a regular object.'
444
+ ) : invariant(!ReactComponent.isValidComponent(spec)));
445
+
446
+ var Constructor = ConvenienceConstructor.componentConstructor;
447
+ var proto = Constructor.prototype;
448
+ for (var name in spec) {
449
+ var property = spec[name];
450
+ if (!spec.hasOwnProperty(name)) {
451
+ continue;
452
+ }
453
+
454
+ validateMethodOverride(proto, name);
455
+
456
+ if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
457
+ RESERVED_SPEC_KEYS[name](ConvenienceConstructor, property);
458
+ } else {
459
+ // Setup methods on prototype:
460
+ // The following member methods should not be automatically bound:
461
+ // 1. Expected ReactCompositeComponent methods (in the "interface").
462
+ // 2. Overridden methods (that were mixed in).
463
+ var isCompositeComponentMethod = name in ReactCompositeComponentInterface;
464
+ var isInherited = name in proto;
465
+ var markedDontBind = property && property.__reactDontBind;
466
+ var isFunction = typeof property === 'function';
467
+ var shouldAutoBind =
468
+ isFunction &&
469
+ !isCompositeComponentMethod &&
470
+ !isInherited &&
471
+ !markedDontBind;
472
+
473
+ if (shouldAutoBind) {
474
+ if (!proto.__reactAutoBindMap) {
475
+ proto.__reactAutoBindMap = {};
476
+ }
477
+ proto.__reactAutoBindMap[name] = property;
478
+ proto[name] = property;
479
+ } else {
480
+ if (isInherited) {
481
+ // For methods which are defined more than once, call the existing
482
+ // methods before calling the new property.
483
+ if (ReactCompositeComponentInterface[name] ===
484
+ SpecPolicy.DEFINE_MANY_MERGED) {
485
+ proto[name] = createMergedResultFunction(proto[name], property);
486
+ } else {
487
+ proto[name] = createChainedFunction(proto[name], property);
488
+ }
489
+ } else {
490
+ proto[name] = property;
491
+ }
492
+ }
493
+ }
494
+ }
495
+ }
496
+
497
+ function mixStaticSpecIntoComponent(ConvenienceConstructor, statics) {
498
+ if (!statics) {
499
+ return;
500
+ }
501
+ for (var name in statics) {
502
+ var property = statics[name];
503
+ if (!statics.hasOwnProperty(name) || !property) {
504
+ return;
505
+ }
506
+
507
+ var isInherited = name in ConvenienceConstructor;
508
+ var result = property;
509
+ if (isInherited) {
510
+ var existingProperty = ConvenienceConstructor[name];
511
+ var existingType = typeof existingProperty;
512
+ var propertyType = typeof property;
513
+ ("production" !== process.env.NODE_ENV ? invariant(
514
+ existingType === 'function' && propertyType === 'function',
515
+ 'ReactCompositeComponent: You are attempting to define ' +
516
+ '`%s` on your component more than once, but that is only supported ' +
517
+ 'for functions, which are chained together. This conflict may be ' +
518
+ 'due to a mixin.',
519
+ name
520
+ ) : invariant(existingType === 'function' && propertyType === 'function'));
521
+ result = createChainedFunction(existingProperty, property);
522
+ }
523
+ ConvenienceConstructor[name] = result;
524
+ ConvenienceConstructor.componentConstructor[name] = result;
525
+ }
526
+ }
527
+
528
+ /**
529
+ * Merge two objects, but throw if both contain the same key.
530
+ *
531
+ * @param {object} one The first object, which is mutated.
532
+ * @param {object} two The second object
533
+ * @return {object} one after it has been mutated to contain everything in two.
534
+ */
535
+ function mergeObjectsWithNoDuplicateKeys(one, two) {
536
+ ("production" !== process.env.NODE_ENV ? invariant(
537
+ one && two && typeof one === 'object' && typeof two === 'object',
538
+ 'mergeObjectsWithNoDuplicateKeys(): Cannot merge non-objects'
539
+ ) : invariant(one && two && typeof one === 'object' && typeof two === 'object'));
540
+
541
+ objMap(two, function(value, key) {
542
+ ("production" !== process.env.NODE_ENV ? invariant(
543
+ one[key] === undefined,
544
+ 'mergeObjectsWithNoDuplicateKeys(): ' +
545
+ 'Tried to merge two objects with the same key: %s',
546
+ key
547
+ ) : invariant(one[key] === undefined));
548
+ one[key] = value;
549
+ });
550
+ return one;
551
+ }
552
+
553
+ /**
554
+ * Creates a function that invokes two functions and merges their return values.
555
+ *
556
+ * @param {function} one Function to invoke first.
557
+ * @param {function} two Function to invoke second.
558
+ * @return {function} Function that invokes the two argument functions.
559
+ * @private
560
+ */
561
+ function createMergedResultFunction(one, two) {
562
+ return function mergedResult() {
563
+ var a = one.apply(this, arguments);
564
+ var b = two.apply(this, arguments);
565
+ if (a == null) {
566
+ return b;
567
+ } else if (b == null) {
568
+ return a;
569
+ }
570
+ return mergeObjectsWithNoDuplicateKeys(a, b);
571
+ };
572
+ }
573
+
574
+ /**
575
+ * Creates a function that invokes two functions and ignores their return vales.
576
+ *
577
+ * @param {function} one Function to invoke first.
578
+ * @param {function} two Function to invoke second.
579
+ * @return {function} Function that invokes the two argument functions.
580
+ * @private
581
+ */
582
+ function createChainedFunction(one, two) {
583
+ return function chainedFunction() {
584
+ one.apply(this, arguments);
585
+ two.apply(this, arguments);
586
+ };
587
+ }
588
+
589
+ if ("production" !== process.env.NODE_ENV) {
590
+
591
+ var unmountedPropertyWhitelist = {
592
+ constructor: true,
593
+ construct: true,
594
+ isOwnedBy: true, // should be deprecated but can have code mod (internal)
595
+ mountComponent: true,
596
+ mountComponentIntoNode: true,
597
+ props: true,
598
+ type: true,
599
+ _checkPropTypes: true,
600
+ _mountComponentIntoNode: true,
601
+ _processContext: true
602
+ };
603
+
604
+ var hasWarnedOnComponentType = {};
605
+
606
+ var warnIfUnmounted = function(instance, key) {
607
+ if (instance.__hasBeenMounted) {
608
+ return;
609
+ }
610
+ var name = instance.constructor.displayName || 'Unknown';
611
+ var owner = ReactCurrentOwner.current;
612
+ var ownerName = (owner && owner.constructor.displayName) || 'Unknown';
613
+ var warningKey = key + '|' + name + '|' + ownerName;
614
+ if (hasWarnedOnComponentType.hasOwnProperty(warningKey)) {
615
+ // We have already warned for this combination. Skip it this time.
616
+ return;
617
+ }
618
+ hasWarnedOnComponentType[warningKey] = true;
619
+
620
+ var context = owner ? ' in ' + ownerName + '.' : ' at the top level.';
621
+ var staticMethodExample = '<' + name + ' />.type.' + key + '(...)';
622
+
623
+ console.warn(
624
+ 'Invalid access to component property "' + key + '" on ' + name +
625
+ context + ' See http://fb.me/react-warning-descriptors .' +
626
+ ' Use a static method instead: ' + staticMethodExample
627
+ );
628
+ };
629
+
630
+ var defineMembraneProperty = function(membrane, prototype, key) {
631
+ Object.defineProperty(membrane, key, {
632
+
633
+ configurable: false,
634
+ enumerable: true,
635
+
636
+ get: function() {
637
+ if (this !== membrane) {
638
+ // When this is accessed through a prototype chain we need to check if
639
+ // this component was mounted.
640
+ warnIfUnmounted(this, key);
641
+ }
642
+ return prototype[key];
643
+ },
644
+
645
+ set: function(value) {
646
+ if (this !== membrane) {
647
+ // When this is accessed through a prototype chain, we first check if
648
+ // this component was mounted. Then we define a value on "this"
649
+ // instance, effectively disabling the membrane on that prototype
650
+ // chain.
651
+ warnIfUnmounted(this, key);
652
+ Object.defineProperty(this, key, {
653
+ enumerable: true,
654
+ configurable: true,
655
+ writable: true,
656
+ value: value
657
+ });
658
+ } else {
659
+ // Otherwise, this should modify the prototype
660
+ prototype[key] = value;
661
+ }
662
+ }
663
+
664
+ });
665
+ };
666
+
667
+ /**
668
+ * Creates a membrane prototype which wraps the original prototype. If any
669
+ * property is accessed in an unmounted state, a warning is issued.
670
+ *
671
+ * @param {object} prototype Original prototype.
672
+ * @return {object} The membrane prototype.
673
+ * @private
674
+ */
675
+ var createMountWarningMembrane = function(prototype) {
676
+ try {
677
+ var membrane = Object.create(prototype);
678
+ for (var key in prototype) {
679
+ if (unmountedPropertyWhitelist.hasOwnProperty(key)) {
680
+ continue;
681
+ }
682
+ defineMembraneProperty(membrane, prototype, key);
683
+ }
684
+
685
+ membrane.mountComponent = function() {
686
+ this.__hasBeenMounted = true;
687
+ return prototype.mountComponent.apply(this, arguments);
688
+ };
689
+
690
+ return membrane;
691
+ } catch(x) {
692
+ // In IE8 define property will fail on non-DOM objects. If anything in
693
+ // the membrane creation fails, we'll bail out and just use the prototype
694
+ // without warnings.
695
+ return prototype;
696
+ }
697
+ };
698
+
699
+ }
700
+
701
+ /**
702
+ * `ReactCompositeComponent` maintains an auxiliary life cycle state in
703
+ * `this._compositeLifeCycleState` (which can be null).
704
+ *
705
+ * This is different from the life cycle state maintained by `ReactComponent` in
706
+ * `this._lifeCycleState`. The following diagram shows how the states overlap in
707
+ * time. There are times when the CompositeLifeCycle is null - at those times it
708
+ * is only meaningful to look at ComponentLifeCycle alone.
709
+ *
710
+ * Top Row: ReactComponent.ComponentLifeCycle
711
+ * Low Row: ReactComponent.CompositeLifeCycle
712
+ *
713
+ * +-------+------------------------------------------------------+--------+
714
+ * | UN | MOUNTED | UN |
715
+ * |MOUNTED| | MOUNTED|
716
+ * +-------+------------------------------------------------------+--------+
717
+ * | ^--------+ +------+ +------+ +------+ +--------^ |
718
+ * | | | | | | | | | | | |
719
+ * | 0--|MOUNTING|-0-|RECEIV|-0-|RECEIV|-0-|RECEIV|-0-| UN |--->0 |
720
+ * | | | |PROPS | | PROPS| | STATE| |MOUNTING| |
721
+ * | | | | | | | | | | | |
722
+ * | | | | | | | | | | | |
723
+ * | +--------+ +------+ +------+ +------+ +--------+ |
724
+ * | | | |
725
+ * +-------+------------------------------------------------------+--------+
726
+ */
727
+ var CompositeLifeCycle = keyMirror({
728
+ /**
729
+ * Components in the process of being mounted respond to state changes
730
+ * differently.
731
+ */
732
+ MOUNTING: null,
733
+ /**
734
+ * Components in the process of being unmounted are guarded against state
735
+ * changes.
736
+ */
737
+ UNMOUNTING: null,
738
+ /**
739
+ * Components that are mounted and receiving new props respond to state
740
+ * changes differently.
741
+ */
742
+ RECEIVING_PROPS: null,
743
+ /**
744
+ * Components that are mounted and receiving new state are guarded against
745
+ * additional state changes.
746
+ */
747
+ RECEIVING_STATE: null
748
+ });
749
+
750
+ /**
751
+ * @lends {ReactCompositeComponent.prototype}
752
+ */
753
+ var ReactCompositeComponentMixin = {
754
+
755
+ /**
756
+ * Base constructor for all composite component.
757
+ *
758
+ * @param {?object} initialProps
759
+ * @param {*} children
760
+ * @final
761
+ * @internal
762
+ */
763
+ construct: function(initialProps, children) {
764
+ // Children can be either an array or more than one argument
765
+ ReactComponent.Mixin.construct.apply(this, arguments);
766
+
767
+ this.state = null;
768
+ this._pendingState = null;
769
+
770
+ this.context = this._processContext(ReactContext.current);
771
+ this._currentContext = ReactContext.current;
772
+ this._pendingContext = null;
773
+
774
+ this._compositeLifeCycleState = null;
775
+ },
776
+
777
+ /**
778
+ * Checks whether or not this composite component is mounted.
779
+ * @return {boolean} True if mounted, false otherwise.
780
+ * @protected
781
+ * @final
782
+ */
783
+ isMounted: function() {
784
+ return ReactComponent.Mixin.isMounted.call(this) &&
785
+ this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING;
786
+ },
787
+
788
+ /**
789
+ * Initializes the component, renders markup, and registers event listeners.
790
+ *
791
+ * @param {string} rootID DOM ID of the root node.
792
+ * @param {ReactReconcileTransaction} transaction
793
+ * @param {number} mountDepth number of components in the owner hierarchy
794
+ * @return {?string} Rendered markup to be inserted into the DOM.
795
+ * @final
796
+ * @internal
797
+ */
798
+ mountComponent: ReactPerf.measure(
799
+ 'ReactCompositeComponent',
800
+ 'mountComponent',
801
+ function(rootID, transaction, mountDepth) {
802
+ ReactComponent.Mixin.mountComponent.call(
803
+ this,
804
+ rootID,
805
+ transaction,
806
+ mountDepth
807
+ );
808
+ this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING;
809
+
810
+ this._defaultProps = this.getDefaultProps ? this.getDefaultProps() : null;
811
+ this.props = this._processProps(this.props);
812
+
813
+ if (this.__reactAutoBindMap) {
814
+ this._bindAutoBindMethods();
815
+ }
816
+
817
+ this.state = this.getInitialState ? this.getInitialState() : null;
818
+ ("production" !== process.env.NODE_ENV ? invariant(
819
+ typeof this.state === 'object' && !Array.isArray(this.state),
820
+ '%s.getInitialState(): must return an object or null',
821
+ this.constructor.displayName || 'ReactCompositeComponent'
822
+ ) : invariant(typeof this.state === 'object' && !Array.isArray(this.state)));
823
+
824
+ this._pendingState = null;
825
+ this._pendingForceUpdate = false;
826
+
827
+ if (this.componentWillMount) {
828
+ this.componentWillMount();
829
+ // When mounting, calls to `setState` by `componentWillMount` will set
830
+ // `this._pendingState` without triggering a re-render.
831
+ if (this._pendingState) {
832
+ this.state = this._pendingState;
833
+ this._pendingState = null;
834
+ }
835
+ }
836
+
837
+ this._renderedComponent = this._renderValidatedComponent();
838
+
839
+ // Done with mounting, `setState` will now trigger UI changes.
840
+ this._compositeLifeCycleState = null;
841
+ var markup = this._renderedComponent.mountComponent(
842
+ rootID,
843
+ transaction,
844
+ mountDepth + 1
845
+ );
846
+ if (this.componentDidMount) {
847
+ transaction.getReactMountReady().enqueue(this, this.componentDidMount);
848
+ }
849
+ return markup;
850
+ }
851
+ ),
852
+
853
+ /**
854
+ * Releases any resources allocated by `mountComponent`.
855
+ *
856
+ * @final
857
+ * @internal
858
+ */
859
+ unmountComponent: function() {
860
+ this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING;
861
+ if (this.componentWillUnmount) {
862
+ this.componentWillUnmount();
863
+ }
864
+ this._compositeLifeCycleState = null;
865
+
866
+ this._defaultProps = null;
867
+
868
+ this._renderedComponent.unmountComponent();
869
+ this._renderedComponent = null;
870
+
871
+ ReactComponent.Mixin.unmountComponent.call(this);
872
+
873
+ if (this.refs) {
874
+ this.refs = null;
875
+ }
876
+
877
+ // Some existing components rely on this.props even after they've been
878
+ // destroyed (in event handlers).
879
+ // TODO: this.props = null;
880
+ // TODO: this.state = null;
881
+ },
882
+
883
+ /**
884
+ * Sets a subset of the state. Always use this or `replaceState` to mutate
885
+ * state. You should treat `this.state` as immutable.
886
+ *
887
+ * There is no guarantee that `this.state` will be immediately updated, so
888
+ * accessing `this.state` after calling this method may return the old value.
889
+ *
890
+ * There is no guarantee that calls to `setState` will run synchronously,
891
+ * as they may eventually be batched together. You can provide an optional
892
+ * callback that will be executed when the call to setState is actually
893
+ * completed.
894
+ *
895
+ * @param {object} partialState Next partial state to be merged with state.
896
+ * @param {?function} callback Called after state is updated.
897
+ * @final
898
+ * @protected
899
+ */
900
+ setState: function(partialState, callback) {
901
+ ("production" !== process.env.NODE_ENV ? invariant(
902
+ typeof partialState === 'object' || partialState == null,
903
+ 'setState(...): takes an object of state variables to update.'
904
+ ) : invariant(typeof partialState === 'object' || partialState == null));
905
+ if ("production" !== process.env.NODE_ENV) {
906
+ if (partialState == null) {
907
+ console.warn(
908
+ 'setState(...): You passed an undefined or null state object; ' +
909
+ 'instead, use forceUpdate().'
910
+ );
911
+ }
912
+ }
913
+ // Merge with `_pendingState` if it exists, otherwise with existing state.
914
+ this.replaceState(
915
+ merge(this._pendingState || this.state, partialState),
916
+ callback
917
+ );
918
+ },
919
+
920
+ /**
921
+ * Replaces all of the state. Always use this or `setState` to mutate state.
922
+ * You should treat `this.state` as immutable.
923
+ *
924
+ * There is no guarantee that `this.state` will be immediately updated, so
925
+ * accessing `this.state` after calling this method may return the old value.
926
+ *
927
+ * @param {object} completeState Next state.
928
+ * @param {?function} callback Called after state is updated.
929
+ * @final
930
+ * @protected
931
+ */
932
+ replaceState: function(completeState, callback) {
933
+ validateLifeCycleOnReplaceState(this);
934
+ this._pendingState = completeState;
935
+ ReactUpdates.enqueueUpdate(this, callback);
936
+ },
937
+
938
+ /**
939
+ * Filters the context object to only contain keys specified in
940
+ * `contextTypes`, and asserts that they are valid.
941
+ *
942
+ * @param {object} context
943
+ * @return {?object}
944
+ * @private
945
+ */
946
+ _processContext: function(context) {
947
+ var maskedContext = null;
948
+ var contextTypes = this.constructor.contextTypes;
949
+ if (contextTypes) {
950
+ maskedContext = {};
951
+ for (var contextName in contextTypes) {
952
+ maskedContext[contextName] = context[contextName];
953
+ }
954
+ if ("production" !== process.env.NODE_ENV) {
955
+ this._checkPropTypes(
956
+ contextTypes,
957
+ maskedContext,
958
+ ReactPropTypeLocations.context
959
+ );
960
+ }
961
+ }
962
+ return maskedContext;
963
+ },
964
+
965
+ /**
966
+ * @param {object} currentContext
967
+ * @return {object}
968
+ * @private
969
+ */
970
+ _processChildContext: function(currentContext) {
971
+ var childContext = this.getChildContext && this.getChildContext();
972
+ var displayName = this.constructor.displayName || 'ReactCompositeComponent';
973
+ if (childContext) {
974
+ ("production" !== process.env.NODE_ENV ? invariant(
975
+ typeof this.constructor.childContextTypes === 'object',
976
+ '%s.getChildContext(): childContextTypes must be defined in order to ' +
977
+ 'use getChildContext().',
978
+ displayName
979
+ ) : invariant(typeof this.constructor.childContextTypes === 'object'));
980
+ if ("production" !== process.env.NODE_ENV) {
981
+ this._checkPropTypes(
982
+ this.constructor.childContextTypes,
983
+ childContext,
984
+ ReactPropTypeLocations.childContext
985
+ );
986
+ }
987
+ for (var name in childContext) {
988
+ ("production" !== process.env.NODE_ENV ? invariant(
989
+ name in this.constructor.childContextTypes,
990
+ '%s.getChildContext(): key "%s" is not defined in childContextTypes.',
991
+ displayName,
992
+ name
993
+ ) : invariant(name in this.constructor.childContextTypes));
994
+ }
995
+ return merge(currentContext, childContext);
996
+ }
997
+ return currentContext;
998
+ },
999
+
1000
+ /**
1001
+ * Processes props by setting default values for unspecified props and
1002
+ * asserting that the props are valid. Does not mutate its argument; returns
1003
+ * a new props object with defaults merged in.
1004
+ *
1005
+ * @param {object} newProps
1006
+ * @return {object}
1007
+ * @private
1008
+ */
1009
+ _processProps: function(newProps) {
1010
+ var props = merge(newProps);
1011
+ var defaultProps = this._defaultProps;
1012
+ for (var propName in defaultProps) {
1013
+ if (typeof props[propName] === 'undefined') {
1014
+ props[propName] = defaultProps[propName];
1015
+ }
1016
+ }
1017
+ if ("production" !== process.env.NODE_ENV) {
1018
+ var propTypes = this.constructor.propTypes;
1019
+ if (propTypes) {
1020
+ this._checkPropTypes(propTypes, props, ReactPropTypeLocations.prop);
1021
+ }
1022
+ }
1023
+ return props;
1024
+ },
1025
+
1026
+ /**
1027
+ * Assert that the props are valid
1028
+ *
1029
+ * @param {object} propTypes Map of prop name to a ReactPropType
1030
+ * @param {object} props
1031
+ * @param {string} location e.g. "prop", "context", "child context"
1032
+ * @private
1033
+ */
1034
+ _checkPropTypes: function(propTypes, props, location) {
1035
+ var componentName = this.constructor.displayName;
1036
+ for (var propName in propTypes) {
1037
+ if (propTypes.hasOwnProperty(propName)) {
1038
+ propTypes[propName](props, propName, componentName, location);
1039
+ }
1040
+ }
1041
+ },
1042
+
1043
+ performUpdateIfNecessary: function() {
1044
+ var compositeLifeCycleState = this._compositeLifeCycleState;
1045
+ // Do not trigger a state transition if we are in the middle of mounting or
1046
+ // receiving props because both of those will already be doing this.
1047
+ if (compositeLifeCycleState === CompositeLifeCycle.MOUNTING ||
1048
+ compositeLifeCycleState === CompositeLifeCycle.RECEIVING_PROPS) {
1049
+ return;
1050
+ }
1051
+ ReactComponent.Mixin.performUpdateIfNecessary.call(this);
1052
+ },
1053
+
1054
+ /**
1055
+ * If any of `_pendingProps`, `_pendingState`, or `_pendingForceUpdate` is
1056
+ * set, update the component.
1057
+ *
1058
+ * @param {ReactReconcileTransaction} transaction
1059
+ * @internal
1060
+ */
1061
+ _performUpdateIfNecessary: function(transaction) {
1062
+ if (this._pendingProps == null &&
1063
+ this._pendingState == null &&
1064
+ this._pendingContext == null &&
1065
+ !this._pendingForceUpdate) {
1066
+ return;
1067
+ }
1068
+
1069
+ var nextFullContext = this._pendingContext || this._currentContext;
1070
+ var nextContext = this._processContext(nextFullContext);
1071
+ this._pendingContext = null;
1072
+
1073
+ var nextProps = this.props;
1074
+ if (this._pendingProps != null) {
1075
+ nextProps = this._processProps(this._pendingProps);
1076
+ this._pendingProps = null;
1077
+
1078
+ this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS;
1079
+ if (this.componentWillReceiveProps) {
1080
+ this.componentWillReceiveProps(nextProps, nextContext);
1081
+ }
1082
+ }
1083
+
1084
+ this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_STATE;
1085
+
1086
+ // Unlike props, state, and context, we specifically don't want to set
1087
+ // _pendingOwner to null here because it's possible for a component to have
1088
+ // a null owner, so we instead make `this._owner === this._pendingOwner`
1089
+ // mean that there's no owner change pending.
1090
+ var nextOwner = this._pendingOwner;
1091
+
1092
+ var nextState = this._pendingState || this.state;
1093
+ this._pendingState = null;
1094
+
1095
+ try {
1096
+ if (this._pendingForceUpdate ||
1097
+ !this.shouldComponentUpdate ||
1098
+ this.shouldComponentUpdate(nextProps, nextState, nextContext)) {
1099
+ this._pendingForceUpdate = false;
1100
+ // Will set `this.props`, `this.state` and `this.context`.
1101
+ this._performComponentUpdate(
1102
+ nextProps,
1103
+ nextOwner,
1104
+ nextState,
1105
+ nextFullContext,
1106
+ nextContext,
1107
+ transaction
1108
+ );
1109
+ } else {
1110
+ // If it's determined that a component should not update, we still want
1111
+ // to set props and state.
1112
+ this.props = nextProps;
1113
+ this._owner = nextOwner;
1114
+ this.state = nextState;
1115
+ this._currentContext = nextFullContext;
1116
+ this.context = nextContext;
1117
+ }
1118
+ } finally {
1119
+ this._compositeLifeCycleState = null;
1120
+ }
1121
+ },
1122
+
1123
+ /**
1124
+ * Merges new props and state, notifies delegate methods of update and
1125
+ * performs update.
1126
+ *
1127
+ * @param {object} nextProps Next object to set as properties.
1128
+ * @param {?ReactComponent} nextOwner Next component to set as owner
1129
+ * @param {?object} nextState Next object to set as state.
1130
+ * @param {?object} nextFullContext Next object to set as _currentContext.
1131
+ * @param {?object} nextContext Next object to set as context.
1132
+ * @param {ReactReconcileTransaction} transaction
1133
+ * @private
1134
+ */
1135
+ _performComponentUpdate: function(
1136
+ nextProps,
1137
+ nextOwner,
1138
+ nextState,
1139
+ nextFullContext,
1140
+ nextContext,
1141
+ transaction
1142
+ ) {
1143
+ var prevProps = this.props;
1144
+ var prevOwner = this._owner;
1145
+ var prevState = this.state;
1146
+ var prevContext = this.context;
1147
+
1148
+ if (this.componentWillUpdate) {
1149
+ this.componentWillUpdate(nextProps, nextState, nextContext);
1150
+ }
1151
+
1152
+ this.props = nextProps;
1153
+ this._owner = nextOwner;
1154
+ this.state = nextState;
1155
+ this._currentContext = nextFullContext;
1156
+ this.context = nextContext;
1157
+
1158
+ this.updateComponent(
1159
+ transaction,
1160
+ prevProps,
1161
+ prevOwner,
1162
+ prevState,
1163
+ prevContext
1164
+ );
1165
+
1166
+ if (this.componentDidUpdate) {
1167
+ transaction.getReactMountReady().enqueue(
1168
+ this,
1169
+ this.componentDidUpdate.bind(this, prevProps, prevState, prevContext)
1170
+ );
1171
+ }
1172
+ },
1173
+
1174
+ receiveComponent: function(nextComponent, transaction) {
1175
+ if (nextComponent === this) {
1176
+ // Since props and context are immutable after the component is
1177
+ // mounted, we can do a cheap identity compare here to determine
1178
+ // if this is a superfluous reconcile.
1179
+ return;
1180
+ }
1181
+
1182
+ this._pendingContext = nextComponent._currentContext;
1183
+ ReactComponent.Mixin.receiveComponent.call(
1184
+ this,
1185
+ nextComponent,
1186
+ transaction
1187
+ );
1188
+ },
1189
+
1190
+ /**
1191
+ * Updates the component's currently mounted DOM representation.
1192
+ *
1193
+ * By default, this implements React's rendering and reconciliation algorithm.
1194
+ * Sophisticated clients may wish to override this.
1195
+ *
1196
+ * @param {ReactReconcileTransaction} transaction
1197
+ * @param {object} prevProps
1198
+ * @param {?ReactComponent} prevOwner
1199
+ * @param {?object} prevState
1200
+ * @param {?object} prevContext
1201
+ * @internal
1202
+ * @overridable
1203
+ */
1204
+ updateComponent: ReactPerf.measure(
1205
+ 'ReactCompositeComponent',
1206
+ 'updateComponent',
1207
+ function(transaction, prevProps, prevOwner, prevState, prevContext) {
1208
+ ReactComponent.Mixin.updateComponent.call(
1209
+ this,
1210
+ transaction,
1211
+ prevProps,
1212
+ prevOwner
1213
+ );
1214
+ var prevComponent = this._renderedComponent;
1215
+ var nextComponent = this._renderValidatedComponent();
1216
+ if (shouldUpdateReactComponent(prevComponent, nextComponent)) {
1217
+ prevComponent.receiveComponent(nextComponent, transaction);
1218
+ } else {
1219
+ // These two IDs are actually the same! But nothing should rely on that.
1220
+ var thisID = this._rootNodeID;
1221
+ var prevComponentID = prevComponent._rootNodeID;
1222
+ prevComponent.unmountComponent();
1223
+ this._renderedComponent = nextComponent;
1224
+ var nextMarkup = nextComponent.mountComponent(
1225
+ thisID,
1226
+ transaction,
1227
+ this._mountDepth + 1
1228
+ );
1229
+ ReactComponent.BackendIDOperations.dangerouslyReplaceNodeWithMarkupByID(
1230
+ prevComponentID,
1231
+ nextMarkup
1232
+ );
1233
+ }
1234
+ }
1235
+ ),
1236
+
1237
+ /**
1238
+ * Forces an update. This should only be invoked when it is known with
1239
+ * certainty that we are **not** in a DOM transaction.
1240
+ *
1241
+ * You may want to call this when you know that some deeper aspect of the
1242
+ * component's state has changed but `setState` was not called.
1243
+ *
1244
+ * This will not invoke `shouldUpdateComponent`, but it will invoke
1245
+ * `componentWillUpdate` and `componentDidUpdate`.
1246
+ *
1247
+ * @param {?function} callback Called after update is complete.
1248
+ * @final
1249
+ * @protected
1250
+ */
1251
+ forceUpdate: function(callback) {
1252
+ var compositeLifeCycleState = this._compositeLifeCycleState;
1253
+ ("production" !== process.env.NODE_ENV ? invariant(
1254
+ this.isMounted() ||
1255
+ compositeLifeCycleState === CompositeLifeCycle.MOUNTING,
1256
+ 'forceUpdate(...): Can only force an update on mounted or mounting ' +
1257
+ 'components.'
1258
+ ) : invariant(this.isMounted() ||
1259
+ compositeLifeCycleState === CompositeLifeCycle.MOUNTING));
1260
+ ("production" !== process.env.NODE_ENV ? invariant(
1261
+ compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE &&
1262
+ compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING,
1263
+ 'forceUpdate(...): Cannot force an update while unmounting component ' +
1264
+ 'or during an existing state transition (such as within `render`).'
1265
+ ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE &&
1266
+ compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING));
1267
+ this._pendingForceUpdate = true;
1268
+ ReactUpdates.enqueueUpdate(this, callback);
1269
+ },
1270
+
1271
+ /**
1272
+ * @private
1273
+ */
1274
+ _renderValidatedComponent: ReactPerf.measure(
1275
+ 'ReactCompositeComponent',
1276
+ '_renderValidatedComponent',
1277
+ function() {
1278
+ var renderedComponent;
1279
+ var previousContext = ReactContext.current;
1280
+ ReactContext.current = this._processChildContext(this._currentContext);
1281
+ ReactCurrentOwner.current = this;
1282
+ try {
1283
+ renderedComponent = this.render();
1284
+ } finally {
1285
+ ReactContext.current = previousContext;
1286
+ ReactCurrentOwner.current = null;
1287
+ }
1288
+ ("production" !== process.env.NODE_ENV ? invariant(
1289
+ ReactComponent.isValidComponent(renderedComponent),
1290
+ '%s.render(): A valid ReactComponent must be returned. You may have ' +
1291
+ 'returned null, undefined, an array, or some other invalid object.',
1292
+ this.constructor.displayName || 'ReactCompositeComponent'
1293
+ ) : invariant(ReactComponent.isValidComponent(renderedComponent)));
1294
+ return renderedComponent;
1295
+ }
1296
+ ),
1297
+
1298
+ /**
1299
+ * @private
1300
+ */
1301
+ _bindAutoBindMethods: function() {
1302
+ for (var autoBindKey in this.__reactAutoBindMap) {
1303
+ if (!this.__reactAutoBindMap.hasOwnProperty(autoBindKey)) {
1304
+ continue;
1305
+ }
1306
+ var method = this.__reactAutoBindMap[autoBindKey];
1307
+ this[autoBindKey] = this._bindAutoBindMethod(ReactErrorUtils.guard(
1308
+ method,
1309
+ this.constructor.displayName + '.' + autoBindKey
1310
+ ));
1311
+ }
1312
+ },
1313
+
1314
+ /**
1315
+ * Binds a method to the component.
1316
+ *
1317
+ * @param {function} method Method to be bound.
1318
+ * @private
1319
+ */
1320
+ _bindAutoBindMethod: function(method) {
1321
+ var component = this;
1322
+ var boundMethod = function() {
1323
+ return method.apply(component, arguments);
1324
+ };
1325
+ if ("production" !== process.env.NODE_ENV) {
1326
+ boundMethod.__reactBoundContext = component;
1327
+ boundMethod.__reactBoundMethod = method;
1328
+ boundMethod.__reactBoundArguments = null;
1329
+ var componentName = component.constructor.displayName;
1330
+ var _bind = boundMethod.bind;
1331
+ boundMethod.bind = function(newThis ) {var args=Array.prototype.slice.call(arguments,1);
1332
+ // User is trying to bind() an autobound method; we effectively will
1333
+ // ignore the value of "this" that the user is trying to use, so
1334
+ // let's warn.
1335
+ if (newThis !== component && newThis !== null) {
1336
+ console.warn(
1337
+ 'bind(): React component methods may only be bound to the ' +
1338
+ 'component instance. See ' + componentName
1339
+ );
1340
+ } else if (!args.length) {
1341
+ console.warn(
1342
+ 'bind(): You are binding a component method to the component. ' +
1343
+ 'React does this for you automatically in a high-performance ' +
1344
+ 'way, so you can safely remove this call. See ' + componentName
1345
+ );
1346
+ return boundMethod;
1347
+ }
1348
+ var reboundMethod = _bind.apply(boundMethod, arguments);
1349
+ reboundMethod.__reactBoundContext = component;
1350
+ reboundMethod.__reactBoundMethod = method;
1351
+ reboundMethod.__reactBoundArguments = args;
1352
+ return reboundMethod;
1353
+ };
1354
+ }
1355
+ return boundMethod;
1356
+ }
1357
+ };
1358
+
1359
+ var ReactCompositeComponentBase = function() {};
1360
+ mixInto(ReactCompositeComponentBase, ReactComponent.Mixin);
1361
+ mixInto(ReactCompositeComponentBase, ReactOwner.Mixin);
1362
+ mixInto(ReactCompositeComponentBase, ReactPropTransferer.Mixin);
1363
+ mixInto(ReactCompositeComponentBase, ReactCompositeComponentMixin);
1364
+
1365
+ /**
1366
+ * Checks if a value is a valid component constructor.
1367
+ *
1368
+ * @param {*}
1369
+ * @return {boolean}
1370
+ * @public
1371
+ */
1372
+ function isValidClass(componentClass) {
1373
+ return componentClass instanceof Function &&
1374
+ 'componentConstructor' in componentClass &&
1375
+ componentClass.componentConstructor instanceof Function;
1376
+ }
1377
+ /**
1378
+ * Module for creating composite components.
1379
+ *
1380
+ * @class ReactCompositeComponent
1381
+ * @extends ReactComponent
1382
+ * @extends ReactOwner
1383
+ * @extends ReactPropTransferer
1384
+ */
1385
+ var ReactCompositeComponent = {
1386
+
1387
+ LifeCycle: CompositeLifeCycle,
1388
+
1389
+ Base: ReactCompositeComponentBase,
1390
+
1391
+ /**
1392
+ * Creates a composite component class given a class specification.
1393
+ *
1394
+ * @param {object} spec Class specification (which must define `render`).
1395
+ * @return {function} Component constructor function.
1396
+ * @public
1397
+ */
1398
+ createClass: function(spec) {
1399
+ var Constructor = function() {};
1400
+ Constructor.prototype = new ReactCompositeComponentBase();
1401
+ Constructor.prototype.constructor = Constructor;
1402
+
1403
+ var ConvenienceConstructor = function(props, children) {
1404
+ var instance = new Constructor();
1405
+ instance.construct.apply(instance, arguments);
1406
+ return instance;
1407
+ };
1408
+ ConvenienceConstructor.componentConstructor = Constructor;
1409
+ Constructor.ConvenienceConstructor = ConvenienceConstructor;
1410
+ ConvenienceConstructor.originalSpec = spec;
1411
+
1412
+ mixSpecIntoComponent(ConvenienceConstructor, spec);
1413
+
1414
+ ("production" !== process.env.NODE_ENV ? invariant(
1415
+ Constructor.prototype.render,
1416
+ 'createClass(...): Class specification must implement a `render` method.'
1417
+ ) : invariant(Constructor.prototype.render));
1418
+
1419
+ if ("production" !== process.env.NODE_ENV) {
1420
+ if (Constructor.prototype.componentShouldUpdate) {
1421
+ console.warn(
1422
+ (spec.displayName || 'A component') + ' has a method called ' +
1423
+ 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
1424
+ 'The name is phrased as a question because the function is ' +
1425
+ 'expected to return a value.'
1426
+ );
1427
+ }
1428
+ }
1429
+
1430
+ // Expose the convience constructor on the prototype so that it can be
1431
+ // easily accessed on descriptors. E.g. <Foo />.type === Foo.type and for
1432
+ // static methods like <Foo />.type.staticMethod();
1433
+ // This should not be named constructor since this may not be the function
1434
+ // that created the descriptor, and it may not even be a constructor.
1435
+ ConvenienceConstructor.type = Constructor;
1436
+ Constructor.prototype.type = Constructor;
1437
+
1438
+ // Reduce time spent doing lookups by setting these on the prototype.
1439
+ for (var methodName in ReactCompositeComponentInterface) {
1440
+ if (!Constructor.prototype[methodName]) {
1441
+ Constructor.prototype[methodName] = null;
1442
+ }
1443
+ }
1444
+
1445
+ if ("production" !== process.env.NODE_ENV) {
1446
+ Constructor.prototype = createMountWarningMembrane(Constructor.prototype);
1447
+ }
1448
+
1449
+ return ConvenienceConstructor;
1450
+ },
1451
+
1452
+ isValidClass: isValidClass
1453
+ };
1454
+
1455
+ module.exports = ReactCompositeComponent;