react 0.12.0 → 0.13.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/dist/JSXTransformer.js +2345 -910
  2. package/dist/react-with-addons.js +5273 -4111
  3. package/dist/react-with-addons.min.js +5 -6
  4. package/dist/react.js +4840 -3940
  5. package/dist/react.min.js +5 -6
  6. package/lib/AutoFocusMixin.js +1 -1
  7. package/lib/BeforeInputEventPlugin.js +389 -112
  8. package/lib/CSSProperty.js +6 -3
  9. package/lib/CSSPropertyOperations.js +21 -1
  10. package/lib/CallbackQueue.js +2 -2
  11. package/lib/ChangeEventPlugin.js +3 -3
  12. package/lib/ClientReactRootIndex.js +1 -1
  13. package/lib/DOMChildrenOperations.js +6 -4
  14. package/lib/DOMProperty.js +1 -1
  15. package/lib/DOMPropertyOperations.js +1 -1
  16. package/lib/Danger.js +7 -6
  17. package/lib/DefaultEventPluginOrder.js +1 -2
  18. package/lib/EnterLeaveEventPlugin.js +1 -1
  19. package/lib/EventConstants.js +1 -1
  20. package/lib/EventPluginHub.js +9 -7
  21. package/lib/EventPluginRegistry.js +1 -1
  22. package/lib/EventPluginUtils.js +1 -1
  23. package/lib/EventPropagators.js +1 -1
  24. package/lib/ExecutionEnvironment.js +2 -3
  25. package/lib/FallbackCompositionState.js +89 -0
  26. package/lib/HTMLDOMPropertyConfig.js +19 -7
  27. package/lib/LinkedStateMixin.js +1 -1
  28. package/lib/LinkedValueUtils.js +3 -3
  29. package/lib/LocalEventTrapMixin.js +1 -1
  30. package/lib/MobileSafariClickEventPlugin.js +1 -1
  31. package/lib/Object.assign.js +3 -1
  32. package/lib/PooledClass.js +1 -1
  33. package/lib/React.js +17 -50
  34. package/lib/ReactBrowserComponentMixin.js +3 -13
  35. package/lib/ReactBrowserEventEmitter.js +4 -6
  36. package/lib/ReactCSSTransitionGroup.js +4 -1
  37. package/lib/ReactCSSTransitionGroupChild.js +12 -2
  38. package/lib/ReactChildReconciler.js +121 -0
  39. package/lib/ReactChildren.js +10 -8
  40. package/lib/ReactClass.js +874 -0
  41. package/lib/ReactComponent.js +45 -286
  42. package/lib/ReactComponentBase.js +126 -0
  43. package/lib/ReactComponentBrowserEnvironment.js +10 -83
  44. package/lib/ReactComponentEnvironment.js +57 -0
  45. package/lib/ReactComponentWithPureRenderMixin.js +1 -1
  46. package/lib/ReactCompositeComponent.js +700 -1045
  47. package/lib/ReactContext.js +6 -2
  48. package/lib/ReactCurrentOwner.js +1 -1
  49. package/lib/ReactDOM.js +3 -8
  50. package/lib/ReactDOMButton.js +5 -6
  51. package/lib/ReactDOMComponent.js +120 -77
  52. package/lib/ReactDOMForm.js +5 -6
  53. package/lib/ReactDOMIDOperations.js +56 -74
  54. package/lib/ReactDOMImg.js +4 -6
  55. package/lib/ReactDOMInput.js +5 -6
  56. package/lib/ReactDOMOption.js +5 -6
  57. package/lib/ReactDOMSelect.js +57 -65
  58. package/lib/ReactDOMSelection.js +6 -2
  59. package/lib/ReactDOMTextComponent.js +124 -0
  60. package/lib/ReactDOMTextarea.js +5 -6
  61. package/lib/ReactDefaultBatchingStrategy.js +1 -1
  62. package/lib/ReactDefaultInjection.js +14 -8
  63. package/lib/ReactDefaultPerf.js +8 -7
  64. package/lib/ReactDefaultPerfAnalysis.js +1 -1
  65. package/lib/ReactElement.js +22 -15
  66. package/lib/ReactElementValidator.js +192 -53
  67. package/lib/ReactEmptyComponent.js +29 -11
  68. package/lib/ReactEventEmitterMixin.js +1 -1
  69. package/lib/ReactEventListener.js +3 -3
  70. package/lib/ReactInjection.js +7 -5
  71. package/lib/ReactInputSelection.js +3 -4
  72. package/lib/ReactInstanceHandles.js +3 -2
  73. package/lib/ReactInstanceMap.js +47 -0
  74. package/lib/ReactLink.js +1 -1
  75. package/lib/ReactMarkupChecksum.js +1 -1
  76. package/lib/ReactMount.js +202 -66
  77. package/lib/ReactMultiChild.js +44 -45
  78. package/lib/ReactMultiChildUpdateTypes.js +1 -1
  79. package/lib/ReactNativeComponent.js +47 -10
  80. package/lib/ReactOwner.js +4 -48
  81. package/lib/ReactPerf.js +21 -1
  82. package/lib/ReactPropTransferer.js +2 -57
  83. package/lib/ReactPropTypeLocationNames.js +1 -1
  84. package/lib/ReactPropTypeLocations.js +1 -1
  85. package/lib/ReactPropTypes.js +14 -22
  86. package/lib/ReactPutListenerQueue.js +1 -1
  87. package/lib/ReactReconcileTransaction.js +1 -1
  88. package/lib/ReactRef.js +96 -0
  89. package/lib/ReactRootIndex.js +1 -1
  90. package/lib/ReactServerRendering.js +5 -3
  91. package/lib/ReactServerRenderingTransaction.js +1 -1
  92. package/lib/ReactStateSetters.js +1 -1
  93. package/lib/ReactTestUtils.js +83 -26
  94. package/lib/ReactTransitionChildMapping.js +1 -1
  95. package/lib/ReactTransitionEvents.js +1 -1
  96. package/lib/ReactTransitionGroup.js +48 -7
  97. package/lib/ReactUpdates.js +46 -45
  98. package/lib/ReactWithAddons.js +1 -1
  99. package/lib/SVGDOMPropertyConfig.js +1 -1
  100. package/lib/SelectEventPlugin.js +3 -3
  101. package/lib/ServerReactRootIndex.js +1 -1
  102. package/lib/SimpleEventPlugin.js +1 -1
  103. package/lib/SyntheticClipboardEvent.js +1 -2
  104. package/lib/SyntheticCompositionEvent.js +1 -2
  105. package/lib/SyntheticDragEvent.js +1 -1
  106. package/lib/SyntheticEvent.js +11 -3
  107. package/lib/SyntheticFocusEvent.js +1 -1
  108. package/lib/SyntheticInputEvent.js +1 -2
  109. package/lib/SyntheticKeyboardEvent.js +1 -1
  110. package/lib/SyntheticMouseEvent.js +2 -4
  111. package/lib/SyntheticTouchEvent.js +1 -1
  112. package/lib/SyntheticUIEvent.js +1 -1
  113. package/lib/SyntheticWheelEvent.js +1 -1
  114. package/lib/Transaction.js +3 -3
  115. package/lib/ViewportMetrics.js +2 -5
  116. package/lib/accumulate.js +47 -0
  117. package/lib/accumulateInto.js +1 -1
  118. package/lib/adler32.js +1 -1
  119. package/lib/cloneWithProps.js +3 -3
  120. package/lib/copyProperties.js +2 -0
  121. package/lib/createFullPageComponent.js +3 -3
  122. package/lib/dangerousStyleValue.js +1 -1
  123. package/lib/escapeTextForBrowser.js +6 -6
  124. package/lib/findDOMNode.js +51 -0
  125. package/lib/flattenChildren.js +11 -22
  126. package/lib/forEachAccumulated.js +1 -1
  127. package/lib/getEventCharCode.js +1 -1
  128. package/lib/getEventKey.js +1 -1
  129. package/lib/getEventModifierState.js +1 -1
  130. package/lib/getEventTarget.js +1 -1
  131. package/lib/getIteratorFn.js +42 -0
  132. package/lib/getNodeForCharacterOffset.js +2 -2
  133. package/lib/getReactRootElementInContainer.js +1 -1
  134. package/lib/getTextContentAccessor.js +1 -1
  135. package/lib/instantiateReactComponent.js +89 -66
  136. package/lib/isEventSupported.js +1 -1
  137. package/lib/isNode.js +3 -4
  138. package/lib/isTextInputElement.js +2 -3
  139. package/lib/joinClasses.js +1 -1
  140. package/lib/keyMirror.js +1 -1
  141. package/lib/memoizeStringOnly.js +4 -5
  142. package/lib/onlyChild.js +1 -1
  143. package/lib/setInnerHTML.js +12 -1
  144. package/lib/shallowEqual.js +1 -1
  145. package/lib/shouldUpdateReactComponent.js +48 -6
  146. package/lib/traverseAllChildren.js +111 -55
  147. package/lib/update.js +1 -1
  148. package/lib/warning.js +9 -2
  149. package/package.json +1 -1
  150. package/lib/CompositionEventPlugin.js +0 -257
  151. package/lib/ReactLegacyElement.js +0 -243
  152. package/lib/ReactTextComponent.js +0 -104
  153. package/lib/deprecated.js +0 -47
@@ -9,17 +9,15 @@
9
9
  * @providesModule ReactDOMForm
10
10
  */
11
11
 
12
- "use strict";
12
+ 'use strict';
13
13
 
14
14
  var EventConstants = require("./EventConstants");
15
15
  var LocalEventTrapMixin = require("./LocalEventTrapMixin");
16
16
  var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
17
- var ReactCompositeComponent = require("./ReactCompositeComponent");
17
+ var ReactClass = require("./ReactClass");
18
18
  var ReactElement = require("./ReactElement");
19
- var ReactDOM = require("./ReactDOM");
20
19
 
21
- // Store a reference to the <form> `ReactDOMComponent`. TODO: use string
22
- var form = ReactElement.createFactory(ReactDOM.form.type);
20
+ var form = ReactElement.createFactory('form');
23
21
 
24
22
  /**
25
23
  * Since onSubmit doesn't bubble OR capture on the top level in IE8, we need
@@ -27,8 +25,9 @@ var form = ReactElement.createFactory(ReactDOM.form.type);
27
25
  * do to accomplish this, but the most reliable is to make <form> a
28
26
  * composite component and use `componentDidMount` to attach the event handlers.
29
27
  */
30
- var ReactDOMForm = ReactCompositeComponent.createClass({
28
+ var ReactDOMForm = ReactClass.createClass({
31
29
  displayName: 'ReactDOMForm',
30
+ tagName: 'FORM',
32
31
 
33
32
  mixins: [ReactBrowserComponentMixin, LocalEventTrapMixin],
34
33
 
@@ -12,7 +12,7 @@
12
12
 
13
13
  /*jslint evil: true */
14
14
 
15
- "use strict";
15
+ 'use strict';
16
16
 
17
17
  var CSSPropertyOperations = require("./CSSPropertyOperations");
18
18
  var DOMChildrenOperations = require("./DOMChildrenOperations");
@@ -37,7 +37,7 @@ var INVALID_PROPERTY_ERRORS = {
37
37
 
38
38
  /**
39
39
  * Operations used to process updates to DOM nodes. This is made injectable via
40
- * `ReactComponent.BackendIDOperations`.
40
+ * `ReactDOMComponent.BackendIDOperations`.
41
41
  */
42
42
  var ReactDOMIDOperations = {
43
43
 
@@ -50,27 +50,23 @@ var ReactDOMIDOperations = {
50
50
  * @param {*} value New value of the property.
51
51
  * @internal
52
52
  */
53
- updatePropertyByID: ReactPerf.measure(
54
- 'ReactDOMIDOperations',
55
- 'updatePropertyByID',
56
- function(id, name, value) {
57
- var node = ReactMount.getNode(id);
58
- ("production" !== process.env.NODE_ENV ? invariant(
59
- !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
60
- 'updatePropertyByID(...): %s',
61
- INVALID_PROPERTY_ERRORS[name]
62
- ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
63
-
64
- // If we're updating to null or undefined, we should remove the property
65
- // from the DOM node instead of inadvertantly setting to a string. This
66
- // brings us in line with the same behavior we have on initial render.
67
- if (value != null) {
68
- DOMPropertyOperations.setValueForProperty(node, name, value);
69
- } else {
70
- DOMPropertyOperations.deleteValueForProperty(node, name);
71
- }
53
+ updatePropertyByID: function(id, name, value) {
54
+ 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)));
60
+
61
+ // If we're updating to null or undefined, we should remove the property
62
+ // from the DOM node instead of inadvertantly setting to a string. This
63
+ // brings us in line with the same behavior we have on initial render.
64
+ if (value != null) {
65
+ DOMPropertyOperations.setValueForProperty(node, name, value);
66
+ } else {
67
+ DOMPropertyOperations.deleteValueForProperty(node, name);
72
68
  }
73
- ),
69
+ },
74
70
 
75
71
  /**
76
72
  * Updates a DOM node to remove a property. This should only be used to remove
@@ -80,19 +76,15 @@ var ReactDOMIDOperations = {
80
76
  * @param {string} name A property name to remove, see `DOMProperty`.
81
77
  * @internal
82
78
  */
83
- deletePropertyByID: ReactPerf.measure(
84
- 'ReactDOMIDOperations',
85
- 'deletePropertyByID',
86
- function(id, name, value) {
87
- var node = ReactMount.getNode(id);
88
- ("production" !== process.env.NODE_ENV ? invariant(
89
- !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
90
- 'updatePropertyByID(...): %s',
91
- INVALID_PROPERTY_ERRORS[name]
92
- ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
93
- DOMPropertyOperations.deleteValueForProperty(node, name, value);
94
- }
95
- ),
79
+ deletePropertyByID: function(id, name, value) {
80
+ 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)));
86
+ DOMPropertyOperations.deleteValueForProperty(node, name, value);
87
+ },
96
88
 
97
89
  /**
98
90
  * Updates a DOM node with new style values. If a value is specified as '',
@@ -102,14 +94,10 @@ var ReactDOMIDOperations = {
102
94
  * @param {object} styles Mapping from styles to values.
103
95
  * @internal
104
96
  */
105
- updateStylesByID: ReactPerf.measure(
106
- 'ReactDOMIDOperations',
107
- 'updateStylesByID',
108
- function(id, styles) {
109
- var node = ReactMount.getNode(id);
110
- CSSPropertyOperations.setValueForStyles(node, styles);
111
- }
112
- ),
97
+ updateStylesByID: function(id, styles) {
98
+ var node = ReactMount.getNode(id);
99
+ CSSPropertyOperations.setValueForStyles(node, styles);
100
+ },
113
101
 
114
102
  /**
115
103
  * Updates a DOM node's innerHTML.
@@ -118,14 +106,10 @@ var ReactDOMIDOperations = {
118
106
  * @param {string} html An HTML string.
119
107
  * @internal
120
108
  */
121
- updateInnerHTMLByID: ReactPerf.measure(
122
- 'ReactDOMIDOperations',
123
- 'updateInnerHTMLByID',
124
- function(id, html) {
125
- var node = ReactMount.getNode(id);
126
- setInnerHTML(node, html);
127
- }
128
- ),
109
+ updateInnerHTMLByID: function(id, html) {
110
+ var node = ReactMount.getNode(id);
111
+ setInnerHTML(node, html);
112
+ },
129
113
 
130
114
  /**
131
115
  * Updates a DOM node's text content set by `props.content`.
@@ -134,14 +118,10 @@ var ReactDOMIDOperations = {
134
118
  * @param {string} content Text content.
135
119
  * @internal
136
120
  */
137
- updateTextContentByID: ReactPerf.measure(
138
- 'ReactDOMIDOperations',
139
- 'updateTextContentByID',
140
- function(id, content) {
141
- var node = ReactMount.getNode(id);
142
- DOMChildrenOperations.updateTextContent(node, content);
143
- }
144
- ),
121
+ updateTextContentByID: function(id, content) {
122
+ var node = ReactMount.getNode(id);
123
+ DOMChildrenOperations.updateTextContent(node, content);
124
+ },
145
125
 
146
126
  /**
147
127
  * Replaces a DOM node that exists in the document with markup.
@@ -151,14 +131,10 @@ var ReactDOMIDOperations = {
151
131
  * @internal
152
132
  * @see {Danger.dangerouslyReplaceNodeWithMarkup}
153
133
  */
154
- dangerouslyReplaceNodeWithMarkupByID: ReactPerf.measure(
155
- 'ReactDOMIDOperations',
156
- 'dangerouslyReplaceNodeWithMarkupByID',
157
- function(id, markup) {
134
+ dangerouslyReplaceNodeWithMarkupByID: function(id, markup) {
158
135
  var node = ReactMount.getNode(id);
159
136
  DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup);
160
- }
161
- ),
137
+ },
162
138
 
163
139
  /**
164
140
  * Updates a component's children by processing a series of updates.
@@ -167,16 +143,22 @@ var ReactDOMIDOperations = {
167
143
  * @param {array<string>} markup List of markup strings.
168
144
  * @internal
169
145
  */
170
- dangerouslyProcessChildrenUpdates: ReactPerf.measure(
171
- 'ReactDOMIDOperations',
172
- 'dangerouslyProcessChildrenUpdates',
173
- function(updates, markup) {
174
- for (var i = 0; i < updates.length; i++) {
175
- updates[i].parentNode = ReactMount.getNode(updates[i].parentID);
176
- }
177
- DOMChildrenOperations.processUpdates(updates, markup);
146
+ dangerouslyProcessChildrenUpdates: function(updates, markup) {
147
+ for (var i = 0; i < updates.length; i++) {
148
+ updates[i].parentNode = ReactMount.getNode(updates[i].parentID);
178
149
  }
179
- )
150
+ DOMChildrenOperations.processUpdates(updates, markup);
151
+ }
180
152
  };
181
153
 
154
+ ReactPerf.measureMethods(ReactDOMIDOperations, 'ReactDOMIDOperations', {
155
+ updatePropertyByID: 'updatePropertyByID',
156
+ deletePropertyByID: 'deletePropertyByID',
157
+ updateStylesByID: 'updateStylesByID',
158
+ updateInnerHTMLByID: 'updateInnerHTMLByID',
159
+ updateTextContentByID: 'updateTextContentByID',
160
+ dangerouslyReplaceNodeWithMarkupByID: 'dangerouslyReplaceNodeWithMarkupByID',
161
+ dangerouslyProcessChildrenUpdates: 'dangerouslyProcessChildrenUpdates'
162
+ });
163
+
182
164
  module.exports = ReactDOMIDOperations;
@@ -9,17 +9,15 @@
9
9
  * @providesModule ReactDOMImg
10
10
  */
11
11
 
12
- "use strict";
12
+ 'use strict';
13
13
 
14
14
  var EventConstants = require("./EventConstants");
15
15
  var LocalEventTrapMixin = require("./LocalEventTrapMixin");
16
16
  var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
17
- var ReactCompositeComponent = require("./ReactCompositeComponent");
17
+ var ReactClass = require("./ReactClass");
18
18
  var ReactElement = require("./ReactElement");
19
- var ReactDOM = require("./ReactDOM");
20
19
 
21
- // Store a reference to the <img> `ReactDOMComponent`. TODO: use string
22
- var img = ReactElement.createFactory(ReactDOM.img.type);
20
+ var img = ReactElement.createFactory('img');
23
21
 
24
22
  /**
25
23
  * Since onLoad doesn't bubble OR capture on the top level in IE8, we need to
@@ -27,7 +25,7 @@ var img = ReactElement.createFactory(ReactDOM.img.type);
27
25
  * to accomplish this, but the most reliable is to make <img> a composite
28
26
  * component and use `componentDidMount` to attach the event handlers.
29
27
  */
30
- var ReactDOMImg = ReactCompositeComponent.createClass({
28
+ var ReactDOMImg = ReactClass.createClass({
31
29
  displayName: 'ReactDOMImg',
32
30
  tagName: 'IMG',
33
31
 
@@ -9,23 +9,21 @@
9
9
  * @providesModule ReactDOMInput
10
10
  */
11
11
 
12
- "use strict";
12
+ 'use strict';
13
13
 
14
14
  var AutoFocusMixin = require("./AutoFocusMixin");
15
15
  var DOMPropertyOperations = require("./DOMPropertyOperations");
16
16
  var LinkedValueUtils = require("./LinkedValueUtils");
17
17
  var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
18
- var ReactCompositeComponent = require("./ReactCompositeComponent");
18
+ var ReactClass = require("./ReactClass");
19
19
  var ReactElement = require("./ReactElement");
20
- var ReactDOM = require("./ReactDOM");
21
20
  var ReactMount = require("./ReactMount");
22
21
  var ReactUpdates = require("./ReactUpdates");
23
22
 
24
23
  var assign = require("./Object.assign");
25
24
  var invariant = require("./invariant");
26
25
 
27
- // Store a reference to the <input> `ReactDOMComponent`. TODO: use string
28
- var input = ReactElement.createFactory(ReactDOM.input.type);
26
+ var input = ReactElement.createFactory('input');
29
27
 
30
28
  var instancesByReactID = {};
31
29
 
@@ -52,8 +50,9 @@ function forceUpdateIfMounted() {
52
50
  *
53
51
  * @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html
54
52
  */
55
- var ReactDOMInput = ReactCompositeComponent.createClass({
53
+ var ReactDOMInput = ReactClass.createClass({
56
54
  displayName: 'ReactDOMInput',
55
+ tagName: 'INPUT',
57
56
 
58
57
  mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
59
58
 
@@ -9,23 +9,22 @@
9
9
  * @providesModule ReactDOMOption
10
10
  */
11
11
 
12
- "use strict";
12
+ 'use strict';
13
13
 
14
14
  var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
15
- var ReactCompositeComponent = require("./ReactCompositeComponent");
15
+ var ReactClass = require("./ReactClass");
16
16
  var ReactElement = require("./ReactElement");
17
- var ReactDOM = require("./ReactDOM");
18
17
 
19
18
  var warning = require("./warning");
20
19
 
21
- // Store a reference to the <option> `ReactDOMComponent`. TODO: use string
22
- var option = ReactElement.createFactory(ReactDOM.option.type);
20
+ var option = ReactElement.createFactory('option');
23
21
 
24
22
  /**
25
23
  * Implements an <option> native component that warns when `selected` is set.
26
24
  */
27
- var ReactDOMOption = ReactCompositeComponent.createClass({
25
+ var ReactDOMOption = ReactClass.createClass({
28
26
  displayName: 'ReactDOMOption',
27
+ tagName: 'OPTION',
29
28
 
30
29
  mixins: [ReactBrowserComponentMixin],
31
30
 
@@ -9,26 +9,27 @@
9
9
  * @providesModule ReactDOMSelect
10
10
  */
11
11
 
12
- "use strict";
12
+ 'use strict';
13
13
 
14
14
  var AutoFocusMixin = require("./AutoFocusMixin");
15
15
  var LinkedValueUtils = require("./LinkedValueUtils");
16
16
  var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
17
- var ReactCompositeComponent = require("./ReactCompositeComponent");
17
+ var ReactClass = require("./ReactClass");
18
18
  var ReactElement = require("./ReactElement");
19
- var ReactDOM = require("./ReactDOM");
20
19
  var ReactUpdates = require("./ReactUpdates");
21
20
 
22
21
  var assign = require("./Object.assign");
23
22
 
24
- // Store a reference to the <select> `ReactDOMComponent`. TODO: use string
25
- var select = ReactElement.createFactory(ReactDOM.select.type);
23
+ var select = ReactElement.createFactory('select');
26
24
 
27
- function updateWithPendingValueIfMounted() {
25
+ function updateOptionsIfPendingUpdateAndMounted() {
28
26
  /*jshint validthis:true */
29
- if (this.isMounted()) {
30
- this.setState({value: this._pendingValue});
31
- this._pendingValue = 0;
27
+ if (this._pendingUpdate) {
28
+ this._pendingUpdate = false;
29
+ var value = LinkedValueUtils.getValue(this);
30
+ if (value != null && this.isMounted()) {
31
+ updateOptions(this, value);
32
+ }
32
33
  }
33
34
  }
34
35
 
@@ -38,7 +39,7 @@ function updateWithPendingValueIfMounted() {
38
39
  */
39
40
  function selectValueType(props, propName, componentName) {
40
41
  if (props[propName] == null) {
41
- return;
42
+ return null;
42
43
  }
43
44
  if (props.multiple) {
44
45
  if (!Array.isArray(props[propName])) {
@@ -58,40 +59,43 @@ function selectValueType(props, propName, componentName) {
58
59
  }
59
60
 
60
61
  /**
61
- * If `value` is supplied, updates <option> elements on mount and update.
62
62
  * @param {ReactComponent} component Instance of ReactDOMSelect
63
- * @param {?*} propValue For uncontrolled components, null/undefined. For
64
- * controlled components, a string (or with `multiple`, a list of strings).
63
+ * @param {*} propValue A stringable (with `multiple`, a list of stringables).
65
64
  * @private
66
65
  */
67
66
  function updateOptions(component, propValue) {
68
- var multiple = component.props.multiple;
69
- var value = propValue != null ? propValue : component.state.value;
70
- var options = component.getDOMNode().options;
71
67
  var selectedValue, i, l;
72
- if (multiple) {
68
+ var options = component.getDOMNode().options;
69
+
70
+ if (component.props.multiple) {
73
71
  selectedValue = {};
74
- for (i = 0, l = value.length; i < l; ++i) {
75
- selectedValue['' + value[i]] = true;
72
+ for (i = 0, l = propValue.length; i < l; i++) {
73
+ selectedValue['' + propValue[i]] = true;
74
+ }
75
+ for (i = 0, l = options.length; i < l; i++) {
76
+ var selected = selectedValue.hasOwnProperty(options[i].value);
77
+ if (options[i].selected !== selected) {
78
+ options[i].selected = selected;
79
+ }
76
80
  }
77
81
  } else {
78
- selectedValue = '' + value;
79
- }
80
- for (i = 0, l = options.length; i < l; i++) {
81
- var selected = multiple ?
82
- selectedValue.hasOwnProperty(options[i].value) :
83
- options[i].value === selectedValue;
84
-
85
- if (selected !== options[i].selected) {
86
- options[i].selected = selected;
82
+ // Do not set `select.value` as exact behavior isn't consistent across all
83
+ // browsers for all cases.
84
+ selectedValue = '' + propValue;
85
+ for (i = 0, l = options.length; i < l; i++) {
86
+ if (options[i].value === selectedValue) {
87
+ options[i].selected = true;
88
+ return;
89
+ }
87
90
  }
91
+ options[0].selected = true;
88
92
  }
89
93
  }
90
94
 
91
95
  /**
92
96
  * Implements a <select> native component that allows optionally setting the
93
97
  * props `value` and `defaultValue`. If `multiple` is false, the prop must be a
94
- * string. If `multiple` is true, the prop must be an array of strings.
98
+ * stringable. If `multiple` is true, the prop must be an array of stringables.
95
99
  *
96
100
  * If `value` is not supplied (or null/undefined), user actions that change the
97
101
  * selected option will trigger updates to the rendered options.
@@ -103,8 +107,9 @@ function updateOptions(component, propValue) {
103
107
  * If `defaultValue` is provided, any options with the supplied values will be
104
108
  * selected.
105
109
  */
106
- var ReactDOMSelect = ReactCompositeComponent.createClass({
110
+ var ReactDOMSelect = ReactClass.createClass({
107
111
  displayName: 'ReactDOMSelect',
112
+ tagName: 'SELECT',
108
113
 
109
114
  mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
110
115
 
@@ -113,22 +118,6 @@ var ReactDOMSelect = ReactCompositeComponent.createClass({
113
118
  value: selectValueType
114
119
  },
115
120
 
116
- getInitialState: function() {
117
- return {value: this.props.defaultValue || (this.props.multiple ? [] : '')};
118
- },
119
-
120
- componentWillMount: function() {
121
- this._pendingValue = null;
122
- },
123
-
124
- componentWillReceiveProps: function(nextProps) {
125
- if (!this.props.multiple && nextProps.multiple) {
126
- this.setState({value: [this.state.value]});
127
- } else if (this.props.multiple && !nextProps.multiple) {
128
- this.setState({value: this.state.value[0]});
129
- }
130
- },
131
-
132
121
  render: function() {
133
122
  // Clone `this.props` so we don't mutate the input.
134
123
  var props = assign({}, this.props);
@@ -139,16 +128,32 @@ var ReactDOMSelect = ReactCompositeComponent.createClass({
139
128
  return select(props, this.props.children);
140
129
  },
141
130
 
131
+ componentWillMount: function() {
132
+ this._pendingUpdate = false;
133
+ },
134
+
142
135
  componentDidMount: function() {
143
- updateOptions(this, LinkedValueUtils.getValue(this));
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
+ }
144
142
  },
145
143
 
146
144
  componentDidUpdate: function(prevProps) {
147
145
  var value = LinkedValueUtils.getValue(this);
148
- var prevMultiple = !!prevProps.multiple;
149
- var multiple = !!this.props.multiple;
150
- if (value != null || prevMultiple !== multiple) {
146
+ if (value != null) {
147
+ this._pendingUpdate = false;
151
148
  updateOptions(this, value);
149
+ } else if (!prevProps.multiple !== !this.props.multiple) {
150
+ // For simplicity, reapply `defaultValue` if `multiple` is toggled.
151
+ if (this.props.defaultValue != null) {
152
+ updateOptions(this, this.props.defaultValue);
153
+ } else {
154
+ // Revert the select back to its default unselected state.
155
+ updateOptions(this, this.props.multiple ? [] : '');
156
+ }
152
157
  }
153
158
  },
154
159
 
@@ -159,21 +164,8 @@ var ReactDOMSelect = ReactCompositeComponent.createClass({
159
164
  returnValue = onChange.call(this, event);
160
165
  }
161
166
 
162
- var selectedValue;
163
- if (this.props.multiple) {
164
- selectedValue = [];
165
- var options = event.target.options;
166
- for (var i = 0, l = options.length; i < l; i++) {
167
- if (options[i].selected) {
168
- selectedValue.push(options[i].value);
169
- }
170
- }
171
- } else {
172
- selectedValue = event.target.value;
173
- }
174
-
175
- this._pendingValue = selectedValue;
176
- ReactUpdates.asap(updateWithPendingValueIfMounted, this);
167
+ this._pendingUpdate = true;
168
+ ReactUpdates.asap(updateOptionsIfPendingUpdateAndMounted, this);
177
169
  return returnValue;
178
170
  }
179
171