react 0.13.3 → 0.14.0-beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/README.md +5 -2
  2. package/addons.js +7 -0
  3. package/dist/JSXTransformer.js +4101 -2432
  4. package/dist/react-with-addons.js +4389 -6277
  5. package/dist/react-with-addons.min.js +6 -8
  6. package/dist/react.js +4028 -5697
  7. package/dist/react.min.js +5 -6
  8. package/lib/{AutoFocusMixin.js → AutoFocusUtils.js} +16 -5
  9. package/lib/BeforeInputEventPlugin.js +30 -118
  10. package/lib/CSSCore.js +12 -23
  11. package/lib/CSSProperty.js +4 -3
  12. package/lib/CSSPropertyOperations.js +14 -30
  13. package/lib/CallbackQueue.js +7 -10
  14. package/lib/ChangeEventPlugin.js +26 -88
  15. package/lib/ClientReactRootIndex.js +2 -2
  16. package/lib/DOMChildrenOperations.js +13 -33
  17. package/lib/DOMProperty.js +86 -147
  18. package/lib/DOMPropertyOperations.js +91 -67
  19. package/lib/Danger.js +19 -62
  20. package/lib/DefaultEventPluginOrder.js +2 -12
  21. package/lib/EnterLeaveEventPlugin.js +11 -33
  22. package/lib/EventConstants.js +2 -2
  23. package/lib/EventListener.js +11 -13
  24. package/lib/EventPluginHub.js +44 -47
  25. package/lib/EventPluginRegistry.js +18 -74
  26. package/lib/EventPluginUtils.js +33 -44
  27. package/lib/EventPropagators.js +23 -26
  28. package/lib/ExecutionEnvironment.js +4 -8
  29. package/lib/FallbackCompositionState.js +3 -3
  30. package/lib/HTMLDOMPropertyConfig.js +15 -20
  31. package/lib/LinkedStateMixin.js +3 -6
  32. package/lib/LinkedValueUtils.js +71 -89
  33. package/lib/Object.assign.js +1 -1
  34. package/lib/PooledClass.js +20 -11
  35. package/lib/React.js +9 -129
  36. package/lib/ReactBrowserComponentMixin.js +9 -2
  37. package/lib/ReactBrowserEventEmitter.js +26 -82
  38. package/lib/ReactCSSTransitionGroup.js +13 -24
  39. package/lib/ReactCSSTransitionGroupChild.js +26 -28
  40. package/lib/ReactChildReconciler.js +11 -19
  41. package/lib/ReactChildren.js +24 -31
  42. package/lib/ReactClass.js +96 -267
  43. package/lib/ReactComponent.js +28 -57
  44. package/lib/ReactComponentBrowserEnvironment.js +4 -8
  45. package/lib/ReactComponentEnvironment.js +6 -12
  46. package/lib/ReactComponentWithPureRenderMixin.js +6 -7
  47. package/lib/ReactCompositeComponent.js +115 -381
  48. package/lib/ReactCurrentOwner.js +1 -3
  49. package/lib/ReactDOM.js +4 -2
  50. package/lib/ReactDOMButton.js +16 -28
  51. package/lib/ReactDOMClient.js +90 -0
  52. package/lib/ReactDOMComponent.js +468 -156
  53. package/lib/ReactDOMIDOperations.js +25 -22
  54. package/lib/ReactDOMInput.js +79 -108
  55. package/lib/ReactDOMOption.js +58 -20
  56. package/lib/ReactDOMSelect.js +95 -83
  57. package/lib/ReactDOMSelection.js +5 -20
  58. package/lib/ReactDOMServer.js +24 -0
  59. package/lib/ReactDOMTextComponent.js +17 -18
  60. package/lib/ReactDOMTextarea.js +44 -69
  61. package/lib/ReactDefaultBatchingStrategy.js +9 -13
  62. package/lib/ReactDefaultInjection.js +20 -76
  63. package/lib/ReactDefaultPerf.js +36 -69
  64. package/lib/ReactDefaultPerfAnalysis.js +8 -14
  65. package/lib/ReactElement.js +26 -120
  66. package/lib/ReactElementValidator.js +56 -192
  67. package/lib/ReactEmptyComponent.js +7 -11
  68. package/lib/ReactErrorUtils.js +3 -3
  69. package/lib/ReactEventEmitterMixin.js +3 -13
  70. package/lib/ReactEventListener.js +58 -40
  71. package/lib/ReactFragment.js +33 -59
  72. package/lib/ReactInjection.js +1 -1
  73. package/lib/ReactInputSelection.js +14 -23
  74. package/lib/ReactInstanceHandles.js +29 -58
  75. package/lib/ReactInstanceMap.js +5 -5
  76. package/lib/ReactIsomorphic.js +70 -0
  77. package/lib/ReactLink.js +2 -4
  78. package/lib/ReactMarkupChecksum.js +5 -10
  79. package/lib/ReactMount.js +142 -285
  80. package/lib/ReactMultiChild.js +19 -45
  81. package/lib/ReactMultiChildUpdateTypes.js +1 -1
  82. package/lib/ReactNativeComponent.js +6 -15
  83. package/lib/ReactNoopUpdateQueue.js +118 -0
  84. package/lib/ReactOwner.js +7 -24
  85. package/lib/ReactPerf.js +8 -12
  86. package/lib/ReactPropTransferer.js +4 -4
  87. package/lib/ReactPropTypeLocationNames.js +2 -2
  88. package/lib/ReactPropTypeLocations.js +1 -1
  89. package/lib/ReactPropTypes.js +41 -61
  90. package/lib/ReactReconcileTransaction.js +11 -36
  91. package/lib/ReactReconciler.js +14 -26
  92. package/lib/ReactRef.js +5 -8
  93. package/lib/ReactRootIndex.js +2 -2
  94. package/lib/ReactServerBatchingStrategy.js +23 -0
  95. package/lib/ReactServerRendering.js +20 -15
  96. package/lib/ReactServerRenderingTransaction.js +9 -34
  97. package/lib/ReactStateSetters.js +6 -6
  98. package/lib/ReactTestUtils.js +137 -190
  99. package/lib/ReactTransitionChildMapping.js +5 -7
  100. package/lib/ReactTransitionEvents.js +5 -5
  101. package/lib/ReactTransitionGroup.js +30 -52
  102. package/lib/ReactUpdateQueue.js +69 -107
  103. package/lib/ReactUpdates.js +26 -81
  104. package/lib/ReactWithAddons.js +5 -6
  105. package/lib/SVGDOMPropertyConfig.js +39 -4
  106. package/lib/SelectEventPlugin.js +31 -33
  107. package/lib/ServerReactRootIndex.js +2 -2
  108. package/lib/SimpleEventPlugin.js +138 -130
  109. package/lib/SyntheticClipboardEvent.js +5 -9
  110. package/lib/SyntheticCompositionEvent.js +4 -10
  111. package/lib/SyntheticDragEvent.js +3 -3
  112. package/lib/SyntheticEvent.js +14 -15
  113. package/lib/SyntheticFocusEvent.js +3 -3
  114. package/lib/SyntheticInputEvent.js +4 -10
  115. package/lib/SyntheticKeyboardEvent.js +6 -6
  116. package/lib/SyntheticMouseEvent.js +10 -16
  117. package/lib/SyntheticTouchEvent.js +3 -3
  118. package/lib/SyntheticUIEvent.js +5 -5
  119. package/lib/SyntheticWheelEvent.js +13 -17
  120. package/lib/Transaction.js +22 -28
  121. package/lib/ViewportMetrics.js +2 -2
  122. package/lib/accumulateInto.js +2 -5
  123. package/lib/adler32.js +2 -4
  124. package/lib/camelize.js +4 -2
  125. package/lib/camelizeStyleName.js +2 -2
  126. package/lib/cloneWithProps.js +6 -12
  127. package/lib/containsNode.js +29 -16
  128. package/lib/createArrayFromMixed.js +17 -16
  129. package/lib/createNodesFromMarkup.js +6 -8
  130. package/lib/dangerousStyleValue.js +2 -3
  131. package/lib/deprecated.js +47 -0
  132. package/lib/emptyFunction.js +10 -4
  133. package/lib/emptyObject.js +1 -1
  134. package/lib/escapeTextContentForBrowser.js +1 -1
  135. package/lib/findDOMNode.js +7 -27
  136. package/lib/flattenChildren.js +4 -10
  137. package/lib/focusNode.js +2 -3
  138. package/lib/forEachAccumulated.js +3 -3
  139. package/lib/getActiveElement.js +4 -2
  140. package/lib/getEventCharCode.js +2 -2
  141. package/lib/getEventKey.js +1 -1
  142. package/lib/getEventModifierState.js +1 -2
  143. package/lib/getEventTarget.js +1 -1
  144. package/lib/getIteratorFn.js +2 -4
  145. package/lib/getMarkupWrap.js +18 -40
  146. package/lib/getNodeForCharacterOffset.js +1 -1
  147. package/lib/getTextContentAccessor.js +2 -4
  148. package/lib/getUnboundedScrollPosition.js +1 -1
  149. package/lib/hyphenate.js +3 -1
  150. package/lib/hyphenateStyleName.js +2 -2
  151. package/lib/instantiateReactComponent.js +23 -43
  152. package/lib/invariant.js +8 -12
  153. package/lib/isEventSupported.js +7 -10
  154. package/lib/isNode.js +4 -6
  155. package/lib/isTextInputElement.js +3 -4
  156. package/lib/isTextNode.js +3 -1
  157. package/lib/joinClasses.js +3 -3
  158. package/lib/keyMirror.js +3 -6
  159. package/lib/keyOf.js +4 -3
  160. package/lib/mapObject.js +1 -1
  161. package/lib/memoizeStringOnly.js +2 -2
  162. package/lib/onlyChild.js +2 -5
  163. package/lib/performance.js +2 -5
  164. package/lib/performanceNow.js +3 -1
  165. package/lib/quoteAttributeValueForBrowser.js +1 -1
  166. package/lib/renderSubtreeIntoContainer.js +16 -0
  167. package/lib/setInnerHTML.js +11 -8
  168. package/lib/setTextContent.js +3 -3
  169. package/lib/shallowCompare.js +24 -0
  170. package/lib/shallowEqual.js +17 -11
  171. package/lib/shouldUpdateReactComponent.js +3 -64
  172. package/lib/toArray.js +8 -19
  173. package/lib/traverseAllChildren.js +23 -90
  174. package/lib/update.js +25 -85
  175. package/lib/validateDOMNesting.js +363 -0
  176. package/lib/warning.js +15 -17
  177. package/package.json +3 -3
  178. package/react.js +53 -1
  179. package/lib/LocalEventTrapMixin.js +0 -53
  180. package/lib/MobileSafariClickEventPlugin.js +0 -56
  181. package/lib/ReactContext.js +0 -74
  182. package/lib/ReactDOMForm.js +0 -47
  183. package/lib/ReactDOMIframe.js +0 -43
  184. package/lib/ReactDOMImg.js +0 -44
  185. package/lib/ReactLifeCycle.js +0 -35
  186. package/lib/ReactPutListenerQueue.js +0 -54
  187. package/lib/createFullPageComponent.js +0 -58
  188. package/lib/cx.js +0 -52
  189. package/lib/getReactRootElementInContainer.js +0 -33
@@ -10,8 +10,6 @@
10
10
  * @typechecks static-only
11
11
  */
12
12
 
13
- /*jslint evil: true */
14
-
15
13
  'use strict';
16
14
 
17
15
  var CSSPropertyOperations = require("./CSSPropertyOperations");
@@ -30,8 +28,7 @@ var setInnerHTML = require("./setInnerHTML");
30
28
  * @private
31
29
  */
32
30
  var INVALID_PROPERTY_ERRORS = {
33
- dangerouslySetInnerHTML:
34
- '`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.',
31
+ dangerouslySetInnerHTML: '`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.',
35
32
  style: '`style` must be set using `updateStylesByID()`.'
36
33
  };
37
34
 
@@ -50,13 +47,9 @@ var ReactDOMIDOperations = {
50
47
  * @param {*} value New value of the property.
51
48
  * @internal
52
49
  */
53
- updatePropertyByID: function(id, name, value) {
50
+ updatePropertyByID: function (id, name, value) {
54
51
  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)));
52
+ !!INVALID_PROPERTY_ERRORS.hasOwnProperty(name) ? 'production' !== process.env.NODE_ENV ? invariant(false, 'updatePropertyByID(...): %s', INVALID_PROPERTY_ERRORS[name]) : invariant(false) : undefined;
60
53
 
61
54
  // If we're updating to null or undefined, we should remove the property
62
55
  // from the DOM node instead of inadvertantly setting to a string. This
@@ -68,6 +61,20 @@ var ReactDOMIDOperations = {
68
61
  }
69
62
  },
70
63
 
64
+ /**
65
+ * Updates a DOM node with new property values.
66
+ *
67
+ * @param {string} id ID of the node to update.
68
+ * @param {string} name A valid property name.
69
+ * @param {*} value New value of the property.
70
+ * @internal
71
+ */
72
+ updateAttributeByID: function (id, name, value) {
73
+ var node = ReactMount.getNode(id);
74
+ !!INVALID_PROPERTY_ERRORS.hasOwnProperty(name) ? 'production' !== process.env.NODE_ENV ? invariant(false, 'updatePropertyByID(...): %s', INVALID_PROPERTY_ERRORS[name]) : invariant(false) : undefined;
75
+ DOMPropertyOperations.setValueForAttribute(node, name, value);
76
+ },
77
+
71
78
  /**
72
79
  * Updates a DOM node to remove a property. This should only be used to remove
73
80
  * DOM properties in `DOMProperty`.
@@ -76,13 +83,9 @@ var ReactDOMIDOperations = {
76
83
  * @param {string} name A property name to remove, see `DOMProperty`.
77
84
  * @internal
78
85
  */
79
- deletePropertyByID: function(id, name, value) {
86
+ deletePropertyByID: function (id, name, value) {
80
87
  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)));
88
+ !!INVALID_PROPERTY_ERRORS.hasOwnProperty(name) ? 'production' !== process.env.NODE_ENV ? invariant(false, 'updatePropertyByID(...): %s', INVALID_PROPERTY_ERRORS[name]) : invariant(false) : undefined;
86
89
  DOMPropertyOperations.deleteValueForProperty(node, name, value);
87
90
  },
88
91
 
@@ -94,7 +97,7 @@ var ReactDOMIDOperations = {
94
97
  * @param {object} styles Mapping from styles to values.
95
98
  * @internal
96
99
  */
97
- updateStylesByID: function(id, styles) {
100
+ updateStylesByID: function (id, styles) {
98
101
  var node = ReactMount.getNode(id);
99
102
  CSSPropertyOperations.setValueForStyles(node, styles);
100
103
  },
@@ -106,7 +109,7 @@ var ReactDOMIDOperations = {
106
109
  * @param {string} html An HTML string.
107
110
  * @internal
108
111
  */
109
- updateInnerHTMLByID: function(id, html) {
112
+ updateInnerHTMLByID: function (id, html) {
110
113
  var node = ReactMount.getNode(id);
111
114
  setInnerHTML(node, html);
112
115
  },
@@ -118,7 +121,7 @@ var ReactDOMIDOperations = {
118
121
  * @param {string} content Text content.
119
122
  * @internal
120
123
  */
121
- updateTextContentByID: function(id, content) {
124
+ updateTextContentByID: function (id, content) {
122
125
  var node = ReactMount.getNode(id);
123
126
  DOMChildrenOperations.updateTextContent(node, content);
124
127
  },
@@ -131,7 +134,7 @@ var ReactDOMIDOperations = {
131
134
  * @internal
132
135
  * @see {Danger.dangerouslyReplaceNodeWithMarkup}
133
136
  */
134
- dangerouslyReplaceNodeWithMarkupByID: function(id, markup) {
137
+ dangerouslyReplaceNodeWithMarkupByID: function (id, markup) {
135
138
  var node = ReactMount.getNode(id);
136
139
  DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup);
137
140
  },
@@ -143,7 +146,7 @@ var ReactDOMIDOperations = {
143
146
  * @param {array<string>} markup List of markup strings.
144
147
  * @internal
145
148
  */
146
- dangerouslyProcessChildrenUpdates: function(updates, markup) {
149
+ dangerouslyProcessChildrenUpdates: function (updates, markup) {
147
150
  for (var i = 0; i < updates.length; i++) {
148
151
  updates[i].parentNode = ReactMount.getNode(updates[i].parentID);
149
152
  }
@@ -161,4 +164,4 @@ ReactPerf.measureMethods(ReactDOMIDOperations, 'ReactDOMIDOperations', {
161
164
  dangerouslyProcessChildrenUpdates: 'dangerouslyProcessChildrenUpdates'
162
165
  });
163
166
 
164
- module.exports = ReactDOMIDOperations;
167
+ module.exports = ReactDOMIDOperations;
@@ -11,26 +11,20 @@
11
11
 
12
12
  'use strict';
13
13
 
14
- var AutoFocusMixin = require("./AutoFocusMixin");
15
- var DOMPropertyOperations = require("./DOMPropertyOperations");
14
+ var ReactDOMIDOperations = require("./ReactDOMIDOperations");
16
15
  var LinkedValueUtils = require("./LinkedValueUtils");
17
- var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
18
- var ReactClass = require("./ReactClass");
19
- var ReactElement = require("./ReactElement");
20
16
  var ReactMount = require("./ReactMount");
21
17
  var ReactUpdates = require("./ReactUpdates");
22
18
 
23
19
  var assign = require("./Object.assign");
24
20
  var invariant = require("./invariant");
25
21
 
26
- var input = ReactElement.createFactory('input');
27
-
28
22
  var instancesByReactID = {};
29
23
 
30
24
  function forceUpdateIfMounted() {
31
- /*jshint validthis:true */
32
- if (this.isMounted()) {
33
- this.forceUpdate();
25
+ if (this._rootNodeID) {
26
+ // DOM component is still mounted; update
27
+ ReactDOMInput.updateWrapper(this);
34
28
  }
35
29
  }
36
30
 
@@ -50,124 +44,101 @@ function forceUpdateIfMounted() {
50
44
  *
51
45
  * @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html
52
46
  */
53
- var ReactDOMInput = ReactClass.createClass({
54
- displayName: 'ReactDOMInput',
55
- tagName: 'INPUT',
56
-
57
- mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
58
-
59
- getInitialState: function() {
60
- var defaultValue = this.props.defaultValue;
61
- return {
62
- initialChecked: this.props.defaultChecked || false,
63
- initialValue: defaultValue != null ? defaultValue : null
64
- };
47
+ var ReactDOMInput = {
48
+ getNativeProps: function (inst, props, context) {
49
+ var value = LinkedValueUtils.getValue(props);
50
+ var checked = LinkedValueUtils.getChecked(props);
51
+
52
+ var nativeProps = assign({}, props, {
53
+ defaultChecked: undefined,
54
+ defaultValue: undefined,
55
+ value: value != null ? value : inst._wrapperState.initialValue,
56
+ checked: checked != null ? checked : inst._wrapperState.initialChecked,
57
+ onChange: inst._wrapperState.onChange
58
+ });
59
+
60
+ return nativeProps;
65
61
  },
66
62
 
67
- render: function() {
68
- // Clone `this.props` so we don't mutate the input.
69
- var props = assign({}, this.props);
70
-
71
- props.defaultChecked = null;
72
- props.defaultValue = null;
63
+ mountWrapper: function (inst, props) {
64
+ LinkedValueUtils.checkPropTypes('input', props, inst._currentElement._owner);
73
65
 
74
- var value = LinkedValueUtils.getValue(this);
75
- props.value = value != null ? value : this.state.initialValue;
76
-
77
- var checked = LinkedValueUtils.getChecked(this);
78
- props.checked = checked != null ? checked : this.state.initialChecked;
79
-
80
- props.onChange = this._handleChange;
66
+ var defaultValue = props.defaultValue;
67
+ inst._wrapperState = {
68
+ initialChecked: props.defaultChecked || false,
69
+ initialValue: defaultValue != null ? defaultValue : null,
70
+ onChange: _handleChange.bind(inst)
71
+ };
81
72
 
82
- return input(props, this.props.children);
73
+ instancesByReactID[inst._rootNodeID] = inst;
83
74
  },
84
75
 
85
- componentDidMount: function() {
86
- var id = ReactMount.getID(this.getDOMNode());
87
- instancesByReactID[id] = this;
76
+ unmountWrapper: function (inst) {
77
+ delete instancesByReactID[inst._rootNodeID];
88
78
  },
89
79
 
90
- componentWillUnmount: function() {
91
- var rootNode = this.getDOMNode();
92
- var id = ReactMount.getID(rootNode);
93
- delete instancesByReactID[id];
94
- },
80
+ updateWrapper: function (inst) {
81
+ var props = inst._currentElement.props;
95
82
 
96
- componentDidUpdate: function(prevProps, prevState, prevContext) {
97
- var rootNode = this.getDOMNode();
98
- if (this.props.checked != null) {
99
- DOMPropertyOperations.setValueForProperty(
100
- rootNode,
101
- 'checked',
102
- this.props.checked || false
103
- );
83
+ // TODO: Shouldn't this be getChecked(props)?
84
+ var checked = props.checked;
85
+ if (checked != null) {
86
+ ReactDOMIDOperations.updatePropertyByID(inst._rootNodeID, 'checked', checked || false);
104
87
  }
105
88
 
106
- var value = LinkedValueUtils.getValue(this);
89
+ var value = LinkedValueUtils.getValue(props);
107
90
  if (value != null) {
108
91
  // Cast `value` to a string to ensure the value is set correctly. While
109
92
  // browsers typically do this as necessary, jsdom doesn't.
110
- DOMPropertyOperations.setValueForProperty(rootNode, 'value', '' + value);
93
+ ReactDOMIDOperations.updatePropertyByID(inst._rootNodeID, 'value', '' + value);
111
94
  }
112
- },
95
+ }
96
+ };
97
+
98
+ function _handleChange(event) {
99
+ var props = this._currentElement.props;
100
+
101
+ var returnValue = LinkedValueUtils.executeOnChange(props, event);
102
+
103
+ // Here we use asap to wait until all updates have propagated, which
104
+ // is important when using controlled components within layers:
105
+ // https://github.com/facebook/react/issues/1698
106
+ ReactUpdates.asap(forceUpdateIfMounted, this);
113
107
 
114
- _handleChange: function(event) {
115
- var returnValue;
116
- var onChange = LinkedValueUtils.getOnChange(this);
117
- if (onChange) {
118
- returnValue = onChange.call(this, event);
108
+ var name = props.name;
109
+ if (props.type === 'radio' && name != null) {
110
+ var rootNode = ReactMount.getNode(this._rootNodeID);
111
+ var queryRoot = rootNode;
112
+
113
+ while (queryRoot.parentNode) {
114
+ queryRoot = queryRoot.parentNode;
119
115
  }
120
- // Here we use asap to wait until all updates have propagated, which
121
- // is important when using controlled components within layers:
122
- // https://github.com/facebook/react/issues/1698
123
- ReactUpdates.asap(forceUpdateIfMounted, this);
124
-
125
- var name = this.props.name;
126
- if (this.props.type === 'radio' && name != null) {
127
- var rootNode = this.getDOMNode();
128
- var queryRoot = rootNode;
129
-
130
- while (queryRoot.parentNode) {
131
- queryRoot = queryRoot.parentNode;
132
- }
133
116
 
134
- // If `rootNode.form` was non-null, then we could try `form.elements`,
135
- // but that sometimes behaves strangely in IE8. We could also try using
136
- // `form.getElementsByName`, but that will only return direct children
137
- // and won't include inputs that use the HTML5 `form=` attribute. Since
138
- // the input might not even be in a form, let's just use the global
139
- // `querySelectorAll` to ensure we don't miss anything.
140
- var group = queryRoot.querySelectorAll(
141
- 'input[name=' + JSON.stringify('' + name) + '][type="radio"]');
142
-
143
- for (var i = 0, groupLen = group.length; i < groupLen; i++) {
144
- var otherNode = group[i];
145
- if (otherNode === rootNode ||
146
- otherNode.form !== rootNode.form) {
147
- continue;
148
- }
149
- 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));
155
- 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));
161
- // If this is a controlled radio button group, forcing the input that
162
- // was previously checked to update will cause it to be come re-checked
163
- // as appropriate.
164
- ReactUpdates.asap(forceUpdateIfMounted, otherInstance);
117
+ // If `rootNode.form` was non-null, then we could try `form.elements`,
118
+ // but that sometimes behaves strangely in IE8. We could also try using
119
+ // `form.getElementsByName`, but that will only return direct children
120
+ // and won't include inputs that use the HTML5 `form=` attribute. Since
121
+ // the input might not even be in a form, let's just use the global
122
+ // `querySelectorAll` to ensure we don't miss anything.
123
+ var group = queryRoot.querySelectorAll('input[name=' + JSON.stringify('' + name) + '][type="radio"]');
124
+
125
+ for (var i = 0; i < group.length; i++) {
126
+ var otherNode = group[i];
127
+ if (otherNode === rootNode || otherNode.form !== rootNode.form) {
128
+ continue;
165
129
  }
130
+ var otherID = ReactMount.getID(otherNode);
131
+ !otherID ? 'production' !== process.env.NODE_ENV ? invariant(false, 'ReactDOMInput: Mixing React and non-React radio inputs with the ' + 'same `name` is not supported.') : invariant(false) : undefined;
132
+ var otherInstance = instancesByReactID[otherID];
133
+ !otherInstance ? 'production' !== process.env.NODE_ENV ? invariant(false, 'ReactDOMInput: Unknown radio button ID %s.', otherID) : invariant(false) : undefined;
134
+ // If this is a controlled radio button group, forcing the input that
135
+ // was previously checked to update will cause it to be come re-checked
136
+ // as appropriate.
137
+ ReactUpdates.asap(forceUpdateIfMounted, otherInstance);
166
138
  }
167
-
168
- return returnValue;
169
139
  }
170
140
 
171
- });
141
+ return returnValue;
142
+ }
172
143
 
173
- module.exports = ReactDOMInput;
144
+ module.exports = ReactDOMInput;
@@ -11,38 +11,76 @@
11
11
 
12
12
  'use strict';
13
13
 
14
- var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
15
- var ReactClass = require("./ReactClass");
16
- var ReactElement = require("./ReactElement");
14
+ var ReactChildren = require("./ReactChildren");
15
+ var ReactDOMSelect = require("./ReactDOMSelect");
17
16
 
17
+ var assign = require("./Object.assign");
18
18
  var warning = require("./warning");
19
19
 
20
- var option = ReactElement.createFactory('option');
20
+ var valueContextKey = ReactDOMSelect.valueContextKey;
21
21
 
22
22
  /**
23
23
  * Implements an <option> native component that warns when `selected` is set.
24
24
  */
25
- var ReactDOMOption = ReactClass.createClass({
26
- displayName: 'ReactDOMOption',
27
- tagName: 'OPTION',
25
+ var ReactDOMOption = {
26
+ mountWrapper: function (inst, props, context) {
27
+ // TODO (yungsters): Remove support for `selected` in <option>.
28
+ if ('production' !== process.env.NODE_ENV) {
29
+ 'production' !== process.env.NODE_ENV ? warning(props.selected == null, 'Use the `defaultValue` or `value` props on <select> instead of ' + 'setting `selected` on <option>.') : undefined;
30
+ }
28
31
 
29
- mixins: [ReactBrowserComponentMixin],
32
+ // Look up whether this option is 'selected' via context
33
+ var selectValue = context[valueContextKey];
30
34
 
31
- componentWillMount: function() {
32
- // 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);
35
+ // If context key is null (e.g., no specified value or after initial mount)
36
+ // or missing (e.g., for <datalist>), we don't change props.selected
37
+ var selected = null;
38
+ if (selectValue != null) {
39
+ selected = false;
40
+ if (Array.isArray(selectValue)) {
41
+ // multiple
42
+ for (var i = 0; i < selectValue.length; i++) {
43
+ if ('' + selectValue[i] === '' + props.value) {
44
+ selected = true;
45
+ break;
46
+ }
47
+ }
48
+ } else {
49
+ selected = '' + selectValue === '' + props.value;
50
+ }
39
51
  }
52
+
53
+ inst._wrapperState = { selected: selected };
40
54
  },
41
55
 
42
- render: function() {
43
- return option(this.props, this.props.children);
56
+ getNativeProps: function (inst, props, context) {
57
+ var nativeProps = assign({ selected: undefined, children: undefined }, props);
58
+
59
+ // Read state only from initial mount because <select> updates value
60
+ // manually; we need the initial state only for server rendering
61
+ if (inst._wrapperState.selected != null) {
62
+ nativeProps.selected = inst._wrapperState.selected;
63
+ }
64
+
65
+ var content = '';
66
+
67
+ // Flatten children and warn if they aren't strings or numbers;
68
+ // invalid types are ignored.
69
+ ReactChildren.forEach(props.children, function (child) {
70
+ if (child == null) {
71
+ return;
72
+ }
73
+ if (typeof child === 'string' || typeof child === 'number') {
74
+ content += child;
75
+ } else {
76
+ 'production' !== process.env.NODE_ENV ? warning(false, 'Only strings and numbers are supported as <option> children.') : undefined;
77
+ }
78
+ });
79
+
80
+ nativeProps.children = content;
81
+ return nativeProps;
44
82
  }
45
83
 
46
- });
84
+ };
47
85
 
48
- module.exports = ReactDOMOption;
86
+ module.exports = ReactDOMOption;
@@ -11,68 +11,77 @@
11
11
 
12
12
  'use strict';
13
13
 
14
- var AutoFocusMixin = require("./AutoFocusMixin");
15
14
  var LinkedValueUtils = require("./LinkedValueUtils");
16
- var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
17
- var ReactClass = require("./ReactClass");
18
- var ReactElement = require("./ReactElement");
15
+ var ReactMount = require("./ReactMount");
19
16
  var ReactUpdates = require("./ReactUpdates");
20
17
 
21
18
  var assign = require("./Object.assign");
19
+ var warning = require("./warning");
22
20
 
23
- var select = ReactElement.createFactory('select');
21
+ var valueContextKey = '__ReactDOMSelect_value$' + Math.random().toString(36).slice(2);
24
22
 
25
23
  function updateOptionsIfPendingUpdateAndMounted() {
26
- /*jshint validthis:true */
27
- if (this._pendingUpdate) {
28
- this._pendingUpdate = false;
29
- var value = LinkedValueUtils.getValue(this);
30
- if (value != null && this.isMounted()) {
31
- updateOptions(this, value);
24
+ if (this._wrapperState.pendingUpdate && this._rootNodeID) {
25
+ this._wrapperState.pendingUpdate = false;
26
+
27
+ var props = this._currentElement.props;
28
+ var value = LinkedValueUtils.getValue(props);
29
+
30
+ if (value != null) {
31
+ updateOptions(this, props, value);
32
+ }
33
+ }
34
+ }
35
+
36
+ function getDeclarationErrorAddendum(owner) {
37
+ if (owner) {
38
+ var name = owner.getName();
39
+ if (name) {
40
+ return ' Check the render method of `' + name + '`.';
32
41
  }
33
42
  }
43
+ return '';
34
44
  }
35
45
 
46
+ var valuePropNames = ['value', 'defaultValue'];
47
+
36
48
  /**
37
49
  * Validation function for `value` and `defaultValue`.
38
50
  * @private
39
51
  */
40
- function selectValueType(props, propName, componentName) {
41
- if (props[propName] == null) {
42
- return null;
43
- }
44
- if (props.multiple) {
45
- 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
- );
52
+ function checkSelectPropTypes(inst, props) {
53
+ var owner = inst._currentElement._owner;
54
+ LinkedValueUtils.checkPropTypes('select', props, owner);
55
+
56
+ for (var i = 0; i < valuePropNames.length; i++) {
57
+ var propName = valuePropNames[i];
58
+ if (props[propName] == null) {
59
+ continue;
50
60
  }
51
- } else {
52
- 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
- );
61
+ if (props.multiple) {
62
+ 'production' !== process.env.NODE_ENV ? warning(Array.isArray(props[propName]), 'The `%s` prop supplied to <select> must be an array if ' + '`multiple` is true.%s', propName, getDeclarationErrorAddendum(owner)) : undefined;
63
+ } else {
64
+ 'production' !== process.env.NODE_ENV ? warning(!Array.isArray(props[propName]), 'The `%s` prop supplied to <select> must be a scalar ' + 'value if `multiple` is false.%s', propName, getDeclarationErrorAddendum(owner)) : undefined;
57
65
  }
58
66
  }
59
67
  }
60
68
 
61
69
  /**
62
- * @param {ReactComponent} component Instance of ReactDOMSelect
70
+ * @param {ReactDOMComponent} inst
71
+ * @param {boolean} multiple
63
72
  * @param {*} propValue A stringable (with `multiple`, a list of stringables).
64
73
  * @private
65
74
  */
66
- function updateOptions(component, propValue) {
67
- var selectedValue, i, l;
68
- var options = component.getDOMNode().options;
75
+ function updateOptions(inst, multiple, propValue) {
76
+ var selectedValue, i;
77
+ var options = ReactMount.getNode(inst._rootNodeID).options;
69
78
 
70
- if (component.props.multiple) {
79
+ if (multiple) {
71
80
  selectedValue = {};
72
- for (i = 0, l = propValue.length; i < l; i++) {
81
+ for (i = 0; i < propValue.length; i++) {
73
82
  selectedValue['' + propValue[i]] = true;
74
83
  }
75
- for (i = 0, l = options.length; i < l; i++) {
84
+ for (i = 0; i < options.length; i++) {
76
85
  var selected = selectedValue.hasOwnProperty(options[i].value);
77
86
  if (options[i].selected !== selected) {
78
87
  options[i].selected = selected;
@@ -82,7 +91,7 @@ function updateOptions(component, propValue) {
82
91
  // Do not set `select.value` as exact behavior isn't consistent across all
83
92
  // browsers for all cases.
84
93
  selectedValue = '' + propValue;
85
- for (i = 0, l = options.length; i < l; i++) {
94
+ for (i = 0; i < options.length; i++) {
86
95
  if (options[i].value === selectedValue) {
87
96
  options[i].selected = true;
88
97
  return;
@@ -109,68 +118,71 @@ function updateOptions(component, propValue) {
109
118
  * If `defaultValue` is provided, any options with the supplied values will be
110
119
  * selected.
111
120
  */
112
- var ReactDOMSelect = ReactClass.createClass({
113
- displayName: 'ReactDOMSelect',
114
- tagName: 'SELECT',
115
-
116
- mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
117
-
118
- propTypes: {
119
- defaultValue: selectValueType,
120
- value: selectValueType
121
+ var ReactDOMSelect = {
122
+ valueContextKey: valueContextKey,
123
+
124
+ getNativeProps: function (inst, props, context) {
125
+ return assign({}, props, {
126
+ onChange: inst._wrapperState.onChange,
127
+ value: undefined
128
+ });
121
129
  },
122
130
 
123
- render: function() {
124
- // Clone `this.props` so we don't mutate the input.
125
- var props = assign({}, this.props);
126
-
127
- props.onChange = this._handleChange;
128
- props.value = null;
131
+ mountWrapper: function (inst, props) {
132
+ if ('production' !== process.env.NODE_ENV) {
133
+ checkSelectPropTypes(inst, props);
134
+ }
129
135
 
130
- return select(props, this.props.children);
136
+ var value = LinkedValueUtils.getValue(props);
137
+ inst._wrapperState = {
138
+ pendingUpdate: false,
139
+ initialValue: value != null ? value : props.defaultValue,
140
+ onChange: _handleChange.bind(inst),
141
+ wasMultiple: Boolean(props.multiple)
142
+ };
131
143
  },
132
144
 
133
- componentWillMount: function() {
134
- this._pendingUpdate = false;
145
+ processChildContext: function (inst, props, context) {
146
+ // Pass down initial value so initial generated markup has correct
147
+ // `selected` attributes
148
+ var childContext = assign({}, context);
149
+ childContext[valueContextKey] = inst._wrapperState.initialValue;
150
+ return childContext;
135
151
  },
136
152
 
137
- componentDidMount: function() {
138
- var value = LinkedValueUtils.getValue(this);
139
- if (value != null) {
140
- updateOptions(this, value);
141
- } else if (this.props.defaultValue != null) {
142
- updateOptions(this, this.props.defaultValue);
143
- }
144
- },
153
+ postUpdateWrapper: function (inst) {
154
+ var props = inst._currentElement.props;
155
+
156
+ // After the initial mount, we control selected-ness manually so don't pass
157
+ // the context value down
158
+ inst._wrapperState.initialValue = undefined;
159
+
160
+ var wasMultiple = inst._wrapperState.wasMultiple;
161
+ inst._wrapperState.wasMultiple = Boolean(props.multiple);
145
162
 
146
- componentDidUpdate: function(prevProps) {
147
- var value = LinkedValueUtils.getValue(this);
163
+ var value = LinkedValueUtils.getValue(props);
148
164
  if (value != null) {
149
- this._pendingUpdate = false;
150
- updateOptions(this, value);
151
- } else if (!prevProps.multiple !== !this.props.multiple) {
165
+ inst._wrapperState.pendingUpdate = false;
166
+ updateOptions(inst, Boolean(props.multiple), value);
167
+ } else if (wasMultiple !== Boolean(props.multiple)) {
152
168
  // For simplicity, reapply `defaultValue` if `multiple` is toggled.
153
- if (this.props.defaultValue != null) {
154
- updateOptions(this, this.props.defaultValue);
169
+ if (props.defaultValue != null) {
170
+ updateOptions(inst, Boolean(props.multiple), props.defaultValue);
155
171
  } else {
156
172
  // Revert the select back to its default unselected state.
157
- updateOptions(this, this.props.multiple ? [] : '');
173
+ updateOptions(inst, Boolean(props.multiple), props.multiple ? [] : '');
158
174
  }
159
175
  }
160
- },
161
-
162
- _handleChange: function(event) {
163
- var returnValue;
164
- var onChange = LinkedValueUtils.getOnChange(this);
165
- if (onChange) {
166
- returnValue = onChange.call(this, event);
167
- }
168
-
169
- this._pendingUpdate = true;
170
- ReactUpdates.asap(updateOptionsIfPendingUpdateAndMounted, this);
171
- return returnValue;
172
176
  }
177
+ };
178
+
179
+ function _handleChange(event) {
180
+ var props = this._currentElement.props;
181
+ var returnValue = LinkedValueUtils.executeOnChange(props, event);
173
182
 
174
- });
183
+ this._wrapperState.pendingUpdate = true;
184
+ ReactUpdates.asap(updateOptionsIfPendingUpdateAndMounted, this);
185
+ return returnValue;
186
+ }
175
187
 
176
- module.exports = ReactDOMSelect;
188
+ module.exports = ReactDOMSelect;