react 0.13.0 → 0.14.0-alpha1

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 (194) hide show
  1. package/README.md +1 -1
  2. package/addons.js +7 -0
  3. package/addons/CSSTransitionGroup.js +1 -0
  4. package/addons/LinkedStateMixin.js +1 -0
  5. package/addons/Perf.js +1 -0
  6. package/addons/PureRenderMixin.js +1 -0
  7. package/addons/TestUtils.js +1 -0
  8. package/addons/TransitionGroup.js +1 -0
  9. package/addons/batchedUpdates.js +1 -0
  10. package/addons/cloneWithProps.js +1 -0
  11. package/addons/createFragment.js +1 -0
  12. package/addons/renderSubtreeIntoContainer.js +1 -0
  13. package/addons/shallowCompare.js +1 -0
  14. package/addons/update.js +1 -0
  15. package/dist/JSXTransformer.js +3336 -1671
  16. package/dist/react-with-addons.js +3134 -5113
  17. package/dist/react-with-addons.min.js +6 -6
  18. package/dist/react.js +2812 -4567
  19. package/dist/react.min.js +5 -5
  20. package/lib/AutoFocusMixin.js +4 -3
  21. package/lib/BeforeInputEventPlugin.js +30 -118
  22. package/lib/CSSCore.js +12 -23
  23. package/lib/CSSProperty.js +9 -4
  24. package/lib/CSSPropertyOperations.js +14 -30
  25. package/lib/CallbackQueue.js +7 -10
  26. package/lib/ChangeEventPlugin.js +24 -88
  27. package/lib/ClientReactRootIndex.js +2 -2
  28. package/lib/DOMChildrenOperations.js +13 -33
  29. package/lib/DOMProperty.js +41 -65
  30. package/lib/DOMPropertyOperations.js +30 -51
  31. package/lib/Danger.js +19 -60
  32. package/lib/DefaultEventPluginOrder.js +2 -12
  33. package/lib/EnterLeaveEventPlugin.js +11 -33
  34. package/lib/EventConstants.js +2 -2
  35. package/lib/EventListener.js +11 -13
  36. package/lib/EventPluginHub.js +44 -47
  37. package/lib/EventPluginRegistry.js +18 -74
  38. package/lib/EventPluginUtils.js +27 -38
  39. package/lib/EventPropagators.js +23 -26
  40. package/lib/ExecutionEnvironment.js +4 -8
  41. package/lib/FallbackCompositionState.js +3 -3
  42. package/lib/HTMLDOMPropertyConfig.js +12 -18
  43. package/lib/LinkedStateMixin.js +3 -6
  44. package/lib/LinkedValueUtils.js +34 -64
  45. package/lib/LocalEventTrapMixin.js +9 -16
  46. package/lib/Object.assign.js +1 -1
  47. package/lib/PooledClass.js +8 -11
  48. package/lib/React.js +20 -38
  49. package/lib/ReactBrowserComponentMixin.js +9 -2
  50. package/lib/ReactBrowserEventEmitter.js +26 -82
  51. package/lib/ReactCSSTransitionGroup.js +13 -24
  52. package/lib/ReactCSSTransitionGroupChild.js +18 -28
  53. package/lib/ReactChildReconciler.js +11 -19
  54. package/lib/ReactChildren.js +7 -16
  55. package/lib/ReactClass.js +78 -231
  56. package/lib/ReactComponent.js +17 -33
  57. package/lib/ReactComponentBrowserEnvironment.js +4 -6
  58. package/lib/ReactComponentEnvironment.js +6 -12
  59. package/lib/ReactComponentWithPureRenderMixin.js +4 -5
  60. package/lib/ReactCompositeComponent.js +85 -297
  61. package/lib/ReactContext.js +2 -44
  62. package/lib/ReactCurrentOwner.js +1 -3
  63. package/lib/ReactDOM.js +4 -2
  64. package/lib/ReactDOMButton.js +3 -4
  65. package/lib/ReactDOMComponent.js +185 -146
  66. package/lib/ReactDOMForm.js +3 -3
  67. package/lib/ReactDOMIDOperations.js +11 -20
  68. package/lib/ReactDOMIframe.js +3 -3
  69. package/lib/ReactDOMImg.js +3 -3
  70. package/lib/ReactDOMInput.js +22 -35
  71. package/lib/ReactDOMOption.js +52 -10
  72. package/lib/ReactDOMSelect.js +53 -29
  73. package/lib/ReactDOMSelection.js +5 -20
  74. package/lib/ReactDOMTextComponent.js +17 -18
  75. package/lib/ReactDOMTextarea.js +15 -27
  76. package/lib/ReactDefaultBatchingStrategy.js +9 -13
  77. package/lib/ReactDefaultInjection.js +21 -40
  78. package/lib/ReactDefaultPerf.js +41 -72
  79. package/lib/ReactDefaultPerfAnalysis.js +8 -14
  80. package/lib/ReactElement.js +35 -72
  81. package/lib/ReactElementValidator.js +51 -110
  82. package/lib/ReactEmptyComponent.js +7 -11
  83. package/lib/ReactErrorUtils.js +2 -2
  84. package/lib/ReactEventEmitterMixin.js +3 -12
  85. package/lib/ReactEventListener.js +16 -38
  86. package/lib/ReactFragment.js +23 -54
  87. package/lib/ReactInjection.js +1 -1
  88. package/lib/ReactInputSelection.js +11 -21
  89. package/lib/ReactInstanceHandles.js +27 -57
  90. package/lib/ReactInstanceMap.js +5 -5
  91. package/lib/ReactLifeCycle.js +1 -1
  92. package/lib/ReactLink.js +2 -4
  93. package/lib/ReactMarkupChecksum.js +5 -10
  94. package/lib/ReactMount.js +136 -260
  95. package/lib/ReactMultiChild.js +19 -45
  96. package/lib/ReactMultiChildUpdateTypes.js +1 -1
  97. package/lib/ReactNativeComponent.js +7 -11
  98. package/lib/ReactOwner.js +7 -24
  99. package/lib/ReactPerf.js +8 -12
  100. package/lib/ReactPropTransferer.js +4 -4
  101. package/lib/ReactPropTypeLocationNames.js +2 -2
  102. package/lib/ReactPropTypeLocations.js +1 -1
  103. package/lib/ReactPropTypes.js +13 -46
  104. package/lib/ReactReconcileTransaction.js +9 -34
  105. package/lib/ReactReconciler.js +9 -19
  106. package/lib/ReactRef.js +5 -8
  107. package/lib/ReactRootIndex.js +2 -2
  108. package/lib/ReactServerRendering.js +7 -15
  109. package/lib/ReactServerRenderingTransaction.js +7 -32
  110. package/lib/ReactStateSetters.js +6 -6
  111. package/lib/ReactTestUtils.js +94 -166
  112. package/lib/ReactTransitionChildMapping.js +5 -7
  113. package/lib/ReactTransitionEvents.js +5 -5
  114. package/lib/ReactTransitionGroup.js +30 -52
  115. package/lib/ReactUpdateQueue.js +27 -90
  116. package/lib/ReactUpdates.js +27 -79
  117. package/lib/ReactWithAddons.js +7 -6
  118. package/lib/SVGDOMPropertyConfig.js +41 -2
  119. package/lib/SelectEventPlugin.js +28 -29
  120. package/lib/ServerReactRootIndex.js +2 -2
  121. package/lib/SimpleEventPlugin.js +136 -128
  122. package/lib/SyntheticClipboardEvent.js +3 -7
  123. package/lib/SyntheticCompositionEvent.js +3 -9
  124. package/lib/SyntheticDragEvent.js +1 -1
  125. package/lib/SyntheticEvent.js +8 -10
  126. package/lib/SyntheticFocusEvent.js +1 -1
  127. package/lib/SyntheticInputEvent.js +3 -9
  128. package/lib/SyntheticKeyboardEvent.js +4 -4
  129. package/lib/SyntheticMouseEvent.js +8 -14
  130. package/lib/SyntheticTouchEvent.js +1 -1
  131. package/lib/SyntheticUIEvent.js +3 -3
  132. package/lib/SyntheticWheelEvent.js +11 -15
  133. package/lib/Transaction.js +12 -24
  134. package/lib/ViewportMetrics.js +2 -2
  135. package/lib/accumulateInto.js +2 -5
  136. package/lib/adler32.js +2 -2
  137. package/lib/camelize.js +4 -2
  138. package/lib/camelizeStyleName.js +2 -2
  139. package/lib/cloneWithProps.js +5 -11
  140. package/lib/containsNode.js +29 -16
  141. package/lib/createArrayFromMixed.js +17 -16
  142. package/lib/createFullPageComponent.js +5 -11
  143. package/lib/createNodesFromMarkup.js +6 -8
  144. package/lib/dangerousStyleValue.js +2 -3
  145. package/lib/emptyFunction.js +10 -4
  146. package/lib/emptyObject.js +1 -1
  147. package/lib/escapeTextContentForBrowser.js +1 -1
  148. package/lib/findDOMNode.js +5 -24
  149. package/lib/flattenChildren.js +4 -10
  150. package/lib/focusNode.js +2 -3
  151. package/lib/forEachAccumulated.js +2 -2
  152. package/lib/getActiveElement.js +4 -2
  153. package/lib/getEventCharCode.js +1 -1
  154. package/lib/getEventKey.js +1 -1
  155. package/lib/getEventModifierState.js +1 -1
  156. package/lib/getEventTarget.js +1 -1
  157. package/lib/getIteratorFn.js +2 -4
  158. package/lib/getMarkupWrap.js +7 -5
  159. package/lib/getNodeForCharacterOffset.js +1 -1
  160. package/lib/getTextContentAccessor.js +2 -4
  161. package/lib/getUnboundedScrollPosition.js +1 -1
  162. package/lib/hyphenate.js +3 -1
  163. package/lib/hyphenateStyleName.js +2 -2
  164. package/lib/instantiateReactComponent.js +14 -37
  165. package/lib/invariant.js +8 -12
  166. package/lib/isEventSupported.js +7 -10
  167. package/lib/isNode.js +4 -6
  168. package/lib/isTextInputElement.js +2 -4
  169. package/lib/isTextNode.js +3 -1
  170. package/lib/joinClasses.js +2 -2
  171. package/lib/keyMirror.js +3 -6
  172. package/lib/keyOf.js +4 -3
  173. package/lib/mapObject.js +1 -1
  174. package/lib/memoizeStringOnly.js +2 -2
  175. package/lib/onlyChild.js +2 -5
  176. package/lib/performance.js +2 -5
  177. package/lib/performanceNow.js +3 -1
  178. package/lib/quoteAttributeValueForBrowser.js +1 -1
  179. package/lib/renderSubtreeIntoContainer.js +16 -0
  180. package/lib/setInnerHTML.js +11 -8
  181. package/lib/setTextContent.js +3 -3
  182. package/lib/shallowCompare.js +24 -0
  183. package/lib/shallowEqual.js +17 -11
  184. package/lib/shouldUpdateReactComponent.js +3 -64
  185. package/lib/toArray.js +8 -19
  186. package/lib/traverseAllChildren.js +19 -82
  187. package/lib/update.js +33 -90
  188. package/lib/validateDOMNesting.js +264 -0
  189. package/lib/warning.js +17 -15
  190. package/package.json +3 -3
  191. package/lib/MobileSafariClickEventPlugin.js +0 -56
  192. package/lib/ReactPutListenerQueue.js +0 -54
  193. package/lib/cx.js +0 -52
  194. package/lib/getReactRootElementInContainer.js +0 -33
@@ -31,17 +31,17 @@ var ReactDOMForm = ReactClass.createClass({
31
31
 
32
32
  mixins: [ReactBrowserComponentMixin, LocalEventTrapMixin],
33
33
 
34
- render: function() {
34
+ render: function () {
35
35
  // TODO: Instead of using `ReactDOM` directly, we should use JSX. However,
36
36
  // `jshint` fails to parse JSX so in order for linting to work in the open
37
37
  // source repo, we need to just use `ReactDOM.form`.
38
38
  return form(this.props);
39
39
  },
40
40
 
41
- componentDidMount: function() {
41
+ componentDidMount: function () {
42
42
  this.trapBubbledEvent(EventConstants.topLevelTypes.topReset, 'reset');
43
43
  this.trapBubbledEvent(EventConstants.topLevelTypes.topSubmit, 'submit');
44
44
  }
45
45
  });
46
46
 
47
- module.exports = ReactDOMForm;
47
+ module.exports = ReactDOMForm;
@@ -30,8 +30,7 @@ var setInnerHTML = require("./setInnerHTML");
30
30
  * @private
31
31
  */
32
32
  var INVALID_PROPERTY_ERRORS = {
33
- dangerouslySetInnerHTML:
34
- '`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.',
33
+ dangerouslySetInnerHTML: '`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.',
35
34
  style: '`style` must be set using `updateStylesByID()`.'
36
35
  };
37
36
 
@@ -50,13 +49,9 @@ var ReactDOMIDOperations = {
50
49
  * @param {*} value New value of the property.
51
50
  * @internal
52
51
  */
53
- updatePropertyByID: function(id, name, value) {
52
+ updatePropertyByID: function (id, name, value) {
54
53
  var node = ReactMount.getNode(id);
55
- ("production" !== process.env.NODE_ENV ? invariant(
56
- !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
57
- 'updatePropertyByID(...): %s',
58
- INVALID_PROPERTY_ERRORS[name]
59
- ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
54
+ 'production' !== process.env.NODE_ENV ? invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name), 'updatePropertyByID(...): %s', INVALID_PROPERTY_ERRORS[name]) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name));
60
55
 
61
56
  // If we're updating to null or undefined, we should remove the property
62
57
  // from the DOM node instead of inadvertantly setting to a string. This
@@ -76,13 +71,9 @@ var ReactDOMIDOperations = {
76
71
  * @param {string} name A property name to remove, see `DOMProperty`.
77
72
  * @internal
78
73
  */
79
- deletePropertyByID: function(id, name, value) {
74
+ deletePropertyByID: function (id, name, value) {
80
75
  var node = ReactMount.getNode(id);
81
- ("production" !== process.env.NODE_ENV ? invariant(
82
- !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
83
- 'updatePropertyByID(...): %s',
84
- INVALID_PROPERTY_ERRORS[name]
85
- ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
76
+ 'production' !== process.env.NODE_ENV ? invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name), 'updatePropertyByID(...): %s', INVALID_PROPERTY_ERRORS[name]) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name));
86
77
  DOMPropertyOperations.deleteValueForProperty(node, name, value);
87
78
  },
88
79
 
@@ -94,7 +85,7 @@ var ReactDOMIDOperations = {
94
85
  * @param {object} styles Mapping from styles to values.
95
86
  * @internal
96
87
  */
97
- updateStylesByID: function(id, styles) {
88
+ updateStylesByID: function (id, styles) {
98
89
  var node = ReactMount.getNode(id);
99
90
  CSSPropertyOperations.setValueForStyles(node, styles);
100
91
  },
@@ -106,7 +97,7 @@ var ReactDOMIDOperations = {
106
97
  * @param {string} html An HTML string.
107
98
  * @internal
108
99
  */
109
- updateInnerHTMLByID: function(id, html) {
100
+ updateInnerHTMLByID: function (id, html) {
110
101
  var node = ReactMount.getNode(id);
111
102
  setInnerHTML(node, html);
112
103
  },
@@ -118,7 +109,7 @@ var ReactDOMIDOperations = {
118
109
  * @param {string} content Text content.
119
110
  * @internal
120
111
  */
121
- updateTextContentByID: function(id, content) {
112
+ updateTextContentByID: function (id, content) {
122
113
  var node = ReactMount.getNode(id);
123
114
  DOMChildrenOperations.updateTextContent(node, content);
124
115
  },
@@ -131,7 +122,7 @@ var ReactDOMIDOperations = {
131
122
  * @internal
132
123
  * @see {Danger.dangerouslyReplaceNodeWithMarkup}
133
124
  */
134
- dangerouslyReplaceNodeWithMarkupByID: function(id, markup) {
125
+ dangerouslyReplaceNodeWithMarkupByID: function (id, markup) {
135
126
  var node = ReactMount.getNode(id);
136
127
  DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup);
137
128
  },
@@ -143,7 +134,7 @@ var ReactDOMIDOperations = {
143
134
  * @param {array<string>} markup List of markup strings.
144
135
  * @internal
145
136
  */
146
- dangerouslyProcessChildrenUpdates: function(updates, markup) {
137
+ dangerouslyProcessChildrenUpdates: function (updates, markup) {
147
138
  for (var i = 0; i < updates.length; i++) {
148
139
  updates[i].parentNode = ReactMount.getNode(updates[i].parentID);
149
140
  }
@@ -161,4 +152,4 @@ ReactPerf.measureMethods(ReactDOMIDOperations, 'ReactDOMIDOperations', {
161
152
  dangerouslyProcessChildrenUpdates: 'dangerouslyProcessChildrenUpdates'
162
153
  });
163
154
 
164
- module.exports = ReactDOMIDOperations;
155
+ module.exports = ReactDOMIDOperations;
@@ -31,13 +31,13 @@ var ReactDOMIframe = ReactClass.createClass({
31
31
 
32
32
  mixins: [ReactBrowserComponentMixin, LocalEventTrapMixin],
33
33
 
34
- render: function() {
34
+ render: function () {
35
35
  return iframe(this.props);
36
36
  },
37
37
 
38
- componentDidMount: function() {
38
+ componentDidMount: function () {
39
39
  this.trapBubbledEvent(EventConstants.topLevelTypes.topLoad, 'load');
40
40
  }
41
41
  });
42
42
 
43
- module.exports = ReactDOMIframe;
43
+ module.exports = ReactDOMIframe;
@@ -31,14 +31,14 @@ var ReactDOMImg = ReactClass.createClass({
31
31
 
32
32
  mixins: [ReactBrowserComponentMixin, LocalEventTrapMixin],
33
33
 
34
- render: function() {
34
+ render: function () {
35
35
  return img(this.props);
36
36
  },
37
37
 
38
- componentDidMount: function() {
38
+ componentDidMount: function () {
39
39
  this.trapBubbledEvent(EventConstants.topLevelTypes.topLoad, 'load');
40
40
  this.trapBubbledEvent(EventConstants.topLevelTypes.topError, 'error');
41
41
  }
42
42
  });
43
43
 
44
- module.exports = ReactDOMImg;
44
+ module.exports = ReactDOMImg;
@@ -21,6 +21,7 @@ var ReactMount = require("./ReactMount");
21
21
  var ReactUpdates = require("./ReactUpdates");
22
22
 
23
23
  var assign = require("./Object.assign");
24
+ var findDOMNode = require("./findDOMNode");
24
25
  var invariant = require("./invariant");
25
26
 
26
27
  var input = ReactElement.createFactory('input');
@@ -56,7 +57,7 @@ var ReactDOMInput = ReactClass.createClass({
56
57
 
57
58
  mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
58
59
 
59
- getInitialState: function() {
60
+ getInitialState: function () {
60
61
  var defaultValue = this.props.defaultValue;
61
62
  return {
62
63
  initialChecked: this.props.defaultChecked || false,
@@ -64,17 +65,17 @@ var ReactDOMInput = ReactClass.createClass({
64
65
  };
65
66
  },
66
67
 
67
- render: function() {
68
+ render: function () {
68
69
  // Clone `this.props` so we don't mutate the input.
69
70
  var props = assign({}, this.props);
70
71
 
71
72
  props.defaultChecked = null;
72
73
  props.defaultValue = null;
73
74
 
74
- var value = LinkedValueUtils.getValue(this);
75
+ var value = LinkedValueUtils.getValue(this.props);
75
76
  props.value = value != null ? value : this.state.initialValue;
76
77
 
77
- var checked = LinkedValueUtils.getChecked(this);
78
+ var checked = LinkedValueUtils.getChecked(this.props);
78
79
  props.checked = checked != null ? checked : this.state.initialChecked;
79
80
 
80
81
  props.onChange = this._handleChange;
@@ -82,28 +83,24 @@ var ReactDOMInput = ReactClass.createClass({
82
83
  return input(props, this.props.children);
83
84
  },
84
85
 
85
- componentDidMount: function() {
86
- var id = ReactMount.getID(this.getDOMNode());
86
+ componentDidMount: function () {
87
+ var id = ReactMount.getID(findDOMNode(this));
87
88
  instancesByReactID[id] = this;
88
89
  },
89
90
 
90
- componentWillUnmount: function() {
91
- var rootNode = this.getDOMNode();
91
+ componentWillUnmount: function () {
92
+ var rootNode = findDOMNode(this);
92
93
  var id = ReactMount.getID(rootNode);
93
94
  delete instancesByReactID[id];
94
95
  },
95
96
 
96
- componentDidUpdate: function(prevProps, prevState, prevContext) {
97
- var rootNode = this.getDOMNode();
97
+ componentDidUpdate: function (prevProps, prevState, prevContext) {
98
+ var rootNode = findDOMNode(this);
98
99
  if (this.props.checked != null) {
99
- DOMPropertyOperations.setValueForProperty(
100
- rootNode,
101
- 'checked',
102
- this.props.checked || false
103
- );
100
+ DOMPropertyOperations.setValueForProperty(rootNode, 'checked', this.props.checked || false);
104
101
  }
105
102
 
106
- var value = LinkedValueUtils.getValue(this);
103
+ var value = LinkedValueUtils.getValue(this.props);
107
104
  if (value != null) {
108
105
  // Cast `value` to a string to ensure the value is set correctly. While
109
106
  // browsers typically do this as necessary, jsdom doesn't.
@@ -111,9 +108,9 @@ var ReactDOMInput = ReactClass.createClass({
111
108
  }
112
109
  },
113
110
 
114
- _handleChange: function(event) {
111
+ _handleChange: function (event) {
115
112
  var returnValue;
116
- var onChange = LinkedValueUtils.getOnChange(this);
113
+ var onChange = LinkedValueUtils.getOnChange(this.props);
117
114
  if (onChange) {
118
115
  returnValue = onChange.call(this, event);
119
116
  }
@@ -124,7 +121,7 @@ var ReactDOMInput = ReactClass.createClass({
124
121
 
125
122
  var name = this.props.name;
126
123
  if (this.props.type === 'radio' && name != null) {
127
- var rootNode = this.getDOMNode();
124
+ var rootNode = findDOMNode(this);
128
125
  var queryRoot = rootNode;
129
126
 
130
127
  while (queryRoot.parentNode) {
@@ -137,27 +134,17 @@ var ReactDOMInput = ReactClass.createClass({
137
134
  // and won't include inputs that use the HTML5 `form=` attribute. Since
138
135
  // the input might not even be in a form, let's just use the global
139
136
  // `querySelectorAll` to ensure we don't miss anything.
140
- var group = queryRoot.querySelectorAll(
141
- 'input[name=' + JSON.stringify('' + name) + '][type="radio"]');
137
+ var group = queryRoot.querySelectorAll('input[name=' + JSON.stringify('' + name) + '][type="radio"]');
142
138
 
143
- for (var i = 0, groupLen = group.length; i < groupLen; i++) {
139
+ for (var i = 0; i < group.length; i++) {
144
140
  var otherNode = group[i];
145
- if (otherNode === rootNode ||
146
- otherNode.form !== rootNode.form) {
141
+ if (otherNode === rootNode || otherNode.form !== rootNode.form) {
147
142
  continue;
148
143
  }
149
144
  var otherID = ReactMount.getID(otherNode);
150
- ("production" !== process.env.NODE_ENV ? invariant(
151
- otherID,
152
- 'ReactDOMInput: Mixing React and non-React radio inputs with the ' +
153
- 'same `name` is not supported.'
154
- ) : invariant(otherID));
145
+ 'production' !== process.env.NODE_ENV ? invariant(otherID, 'ReactDOMInput: Mixing React and non-React radio inputs with the ' + 'same `name` is not supported.') : invariant(otherID);
155
146
  var otherInstance = instancesByReactID[otherID];
156
- ("production" !== process.env.NODE_ENV ? invariant(
157
- otherInstance,
158
- 'ReactDOMInput: Unknown radio button ID %s.',
159
- otherID
160
- ) : invariant(otherInstance));
147
+ 'production' !== process.env.NODE_ENV ? invariant(otherInstance, 'ReactDOMInput: Unknown radio button ID %s.', otherID) : invariant(otherInstance);
161
148
  // If this is a controlled radio button group, forcing the input that
162
149
  // was previously checked to update will cause it to be come re-checked
163
150
  // as appropriate.
@@ -170,4 +157,4 @@ var ReactDOMInput = ReactClass.createClass({
170
157
 
171
158
  });
172
159
 
173
- module.exports = ReactDOMInput;
160
+ module.exports = ReactDOMInput;
@@ -13,12 +13,18 @@
13
13
 
14
14
  var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
15
15
  var ReactClass = require("./ReactClass");
16
+ var ReactDOMSelect = require("./ReactDOMSelect");
16
17
  var ReactElement = require("./ReactElement");
18
+ var ReactInstanceMap = require("./ReactInstanceMap");
19
+ var ReactPropTypes = require("./ReactPropTypes");
17
20
 
21
+ var assign = require("./Object.assign");
18
22
  var warning = require("./warning");
19
23
 
20
24
  var option = ReactElement.createFactory('option');
21
25
 
26
+ var valueContextKey = ReactDOMSelect.valueContextKey;
27
+
22
28
  /**
23
29
  * Implements an <option> native component that warns when `selected` is set.
24
30
  */
@@ -28,21 +34,57 @@ var ReactDOMOption = ReactClass.createClass({
28
34
 
29
35
  mixins: [ReactBrowserComponentMixin],
30
36
 
31
- componentWillMount: function() {
37
+ getInitialState: function () {
38
+ return { selected: null };
39
+ },
40
+
41
+ contextTypes: (function () {
42
+ var obj = {};
43
+ obj[valueContextKey] = ReactPropTypes.any;
44
+ return obj;
45
+ })(),
46
+
47
+ componentWillMount: function () {
32
48
  // TODO (yungsters): Remove support for `selected` in <option>.
33
- if ("production" !== process.env.NODE_ENV) {
34
- ("production" !== process.env.NODE_ENV ? warning(
35
- this.props.selected == null,
36
- 'Use the `defaultValue` or `value` props on <select> instead of ' +
37
- 'setting `selected` on <option>.'
38
- ) : null);
49
+ if ('production' !== process.env.NODE_ENV) {
50
+ 'production' !== process.env.NODE_ENV ? warning(this.props.selected == null, 'Use the `defaultValue` or `value` props on <select> instead of ' + 'setting `selected` on <option>.') : null;
51
+ }
52
+
53
+ // Look up whether this option is 'selected' via parent-based context
54
+ var context = ReactInstanceMap.get(this)._context;
55
+ var selectValue = context[valueContextKey];
56
+
57
+ // If context key is null (e.g., no specified value or after initial mount)
58
+ // or missing (e.g., for <datalist>) skip props
59
+ if (selectValue != null) {
60
+ var selected = false;
61
+ if (Array.isArray(selectValue)) {
62
+ // multiple
63
+ for (var i = 0; i < selectValue.length; i++) {
64
+ if ('' + selectValue[i] === '' + this.props.value) {
65
+ selected = true;
66
+ break;
67
+ }
68
+ }
69
+ } else {
70
+ selected = '' + selectValue === '' + this.props.value;
71
+ }
72
+ this.setState({ selected: selected });
39
73
  }
40
74
  },
41
75
 
42
- render: function() {
43
- return option(this.props, this.props.children);
76
+ render: function () {
77
+ var props = this.props;
78
+
79
+ // Read state only from initial mount because <select> updates value
80
+ // manually; we need the initial state only for server rendering
81
+ if (this.state.selected != null) {
82
+ props = assign({}, props, { selected: this.state.selected });
83
+ }
84
+
85
+ return option(props, this.props.children);
44
86
  }
45
87
 
46
88
  });
47
89
 
48
- module.exports = ReactDOMOption;
90
+ module.exports = ReactDOMOption;
@@ -17,16 +17,20 @@ var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
17
17
  var ReactClass = require("./ReactClass");
18
18
  var ReactElement = require("./ReactElement");
19
19
  var ReactUpdates = require("./ReactUpdates");
20
+ var ReactPropTypes = require("./ReactPropTypes");
20
21
 
21
22
  var assign = require("./Object.assign");
23
+ var findDOMNode = require("./findDOMNode");
22
24
 
23
25
  var select = ReactElement.createFactory('select');
24
26
 
27
+ var valueContextKey = '__ReactDOMSelect_value$' + Math.random().toString(36).slice(2);
28
+
25
29
  function updateOptionsIfPendingUpdateAndMounted() {
26
30
  /*jshint validthis:true */
27
31
  if (this._pendingUpdate) {
28
32
  this._pendingUpdate = false;
29
- var value = LinkedValueUtils.getValue(this);
33
+ var value = LinkedValueUtils.getValue(this.props);
30
34
  if (value != null && this.isMounted()) {
31
35
  updateOptions(this, value);
32
36
  }
@@ -43,17 +47,11 @@ function selectValueType(props, propName, componentName) {
43
47
  }
44
48
  if (props.multiple) {
45
49
  if (!Array.isArray(props[propName])) {
46
- return new Error(
47
- ("The `" + propName + "` prop supplied to <select> must be an array if ") +
48
- ("`multiple` is true.")
49
- );
50
+ return new Error('The `' + propName + '` prop supplied to <select> must be an array if ' + '`multiple` is true.');
50
51
  }
51
52
  } else {
52
53
  if (Array.isArray(props[propName])) {
53
- return new Error(
54
- ("The `" + propName + "` prop supplied to <select> must be a scalar ") +
55
- ("value if `multiple` is false.")
56
- );
54
+ return new Error('The `' + propName + '` prop supplied to <select> must be a scalar ' + 'value if `multiple` is false.');
57
55
  }
58
56
  }
59
57
  }
@@ -64,15 +62,15 @@ function selectValueType(props, propName, componentName) {
64
62
  * @private
65
63
  */
66
64
  function updateOptions(component, propValue) {
67
- var selectedValue, i, l;
68
- var options = component.getDOMNode().options;
65
+ var selectedValue, i;
66
+ var options = findDOMNode(component).options;
69
67
 
70
68
  if (component.props.multiple) {
71
69
  selectedValue = {};
72
- for (i = 0, l = propValue.length; i < l; i++) {
70
+ for (i = 0; i < propValue.length; i++) {
73
71
  selectedValue['' + propValue[i]] = true;
74
72
  }
75
- for (i = 0, l = options.length; i < l; i++) {
73
+ for (i = 0; i < options.length; i++) {
76
74
  var selected = selectedValue.hasOwnProperty(options[i].value);
77
75
  if (options[i].selected !== selected) {
78
76
  options[i].selected = selected;
@@ -82,13 +80,15 @@ function updateOptions(component, propValue) {
82
80
  // Do not set `select.value` as exact behavior isn't consistent across all
83
81
  // browsers for all cases.
84
82
  selectedValue = '' + propValue;
85
- for (i = 0, l = options.length; i < l; i++) {
83
+ for (i = 0; i < options.length; i++) {
86
84
  if (options[i].value === selectedValue) {
87
85
  options[i].selected = true;
88
86
  return;
89
87
  }
90
88
  }
91
- options[0].selected = true;
89
+ if (options.length) {
90
+ options[0].selected = true;
91
+ }
92
92
  }
93
93
  }
94
94
 
@@ -113,12 +113,39 @@ var ReactDOMSelect = ReactClass.createClass({
113
113
 
114
114
  mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
115
115
 
116
+ statics: {
117
+ valueContextKey: valueContextKey
118
+ },
119
+
116
120
  propTypes: {
117
121
  defaultValue: selectValueType,
118
122
  value: selectValueType
119
123
  },
120
124
 
121
- render: function() {
125
+ getInitialState: function () {
126
+ // Pass down initial value so initial generated markup has correct
127
+ // `selected` attributes
128
+ var value = LinkedValueUtils.getValue(this.props);
129
+ if (value != null) {
130
+ return { initialValue: value };
131
+ } else {
132
+ return { initialValue: this.props.defaultValue };
133
+ }
134
+ },
135
+
136
+ childContextTypes: (function () {
137
+ var obj = {};
138
+ obj[valueContextKey] = ReactPropTypes.any;
139
+ return obj;
140
+ })(),
141
+
142
+ getChildContext: function () {
143
+ var obj = {};
144
+ obj[valueContextKey] = this.state.initialValue;
145
+ return obj;
146
+ },
147
+
148
+ render: function () {
122
149
  // Clone `this.props` so we don't mutate the input.
123
150
  var props = assign({}, this.props);
124
151
 
@@ -128,21 +155,18 @@ var ReactDOMSelect = ReactClass.createClass({
128
155
  return select(props, this.props.children);
129
156
  },
130
157
 
131
- componentWillMount: function() {
158
+ componentWillMount: function () {
132
159
  this._pendingUpdate = false;
133
160
  },
134
161
 
135
- componentDidMount: function() {
136
- var value = LinkedValueUtils.getValue(this);
137
- if (value != null) {
138
- updateOptions(this, value);
139
- } else if (this.props.defaultValue != null) {
140
- updateOptions(this, this.props.defaultValue);
141
- }
162
+ componentWillReceiveProps: function (nextProps) {
163
+ // After the initial mount, we control selected-ness manually so don't pass
164
+ // the context value down
165
+ this.setState({ initialValue: null });
142
166
  },
143
167
 
144
- componentDidUpdate: function(prevProps) {
145
- var value = LinkedValueUtils.getValue(this);
168
+ componentDidUpdate: function (prevProps) {
169
+ var value = LinkedValueUtils.getValue(this.props);
146
170
  if (value != null) {
147
171
  this._pendingUpdate = false;
148
172
  updateOptions(this, value);
@@ -157,9 +181,9 @@ var ReactDOMSelect = ReactClass.createClass({
157
181
  }
158
182
  },
159
183
 
160
- _handleChange: function(event) {
184
+ _handleChange: function (event) {
161
185
  var returnValue;
162
- var onChange = LinkedValueUtils.getOnChange(this);
186
+ var onChange = LinkedValueUtils.getOnChange(this.props);
163
187
  if (onChange) {
164
188
  returnValue = onChange.call(this, event);
165
189
  }
@@ -171,4 +195,4 @@ var ReactDOMSelect = ReactClass.createClass({
171
195
 
172
196
  });
173
197
 
174
- module.exports = ReactDOMSelect;
198
+ module.exports = ReactDOMSelect;