react 0.14.0-alpha3 → 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 (103) hide show
  1. package/README.md +5 -2
  2. package/addons.js +2 -2
  3. package/dist/JSXTransformer.js +69 -70
  4. package/dist/react-with-addons.js +2047 -2078
  5. package/dist/react-with-addons.min.js +6 -6
  6. package/dist/react.js +1861 -1904
  7. package/dist/react.min.js +5 -5
  8. package/lib/{AutoFocusMixin.js → AutoFocusUtils.js} +13 -3
  9. package/lib/ChangeEventPlugin.js +4 -2
  10. package/lib/DOMProperty.js +81 -116
  11. package/lib/DOMPropertyOperations.js +70 -25
  12. package/lib/EnterLeaveEventPlugin.js +3 -3
  13. package/lib/EventPluginHub.js +2 -2
  14. package/lib/EventPluginUtils.js +6 -6
  15. package/lib/HTMLDOMPropertyConfig.js +8 -1
  16. package/lib/LinkedValueUtils.js +45 -33
  17. package/lib/PooledClass.js +12 -0
  18. package/lib/React.js +1 -1
  19. package/lib/ReactCSSTransitionGroupChild.js +8 -0
  20. package/lib/ReactChildren.js +3 -3
  21. package/lib/ReactClass.js +29 -47
  22. package/lib/ReactComponent.js +11 -6
  23. package/lib/ReactComponentWithPureRenderMixin.js +2 -2
  24. package/lib/ReactCompositeComponent.js +45 -72
  25. package/lib/ReactDOM.js +1 -0
  26. package/lib/ReactDOMButton.js +15 -26
  27. package/lib/ReactDOMClient.js +9 -4
  28. package/lib/ReactDOMComponent.js +302 -24
  29. package/lib/ReactDOMIDOperations.js +14 -0
  30. package/lib/ReactDOMInput.js +78 -94
  31. package/lib/ReactDOMOption.js +19 -38
  32. package/lib/ReactDOMSelect.js +85 -95
  33. package/lib/ReactDOMTextarea.js +39 -52
  34. package/lib/ReactDefaultInjection.js +0 -47
  35. package/lib/ReactElement.js +18 -79
  36. package/lib/ReactElementValidator.js +29 -98
  37. package/lib/ReactErrorUtils.js +1 -1
  38. package/lib/ReactEventEmitterMixin.js +2 -3
  39. package/lib/ReactEventListener.js +43 -3
  40. package/lib/ReactFragment.js +12 -7
  41. package/lib/ReactInputSelection.js +4 -3
  42. package/lib/ReactInstanceHandles.js +3 -2
  43. package/lib/ReactMount.js +20 -40
  44. package/lib/ReactNativeComponent.js +0 -5
  45. package/lib/ReactNoopUpdateQueue.js +118 -0
  46. package/lib/ReactPropTypes.js +3 -3
  47. package/lib/ReactReconcileTransaction.js +2 -2
  48. package/lib/ReactReconciler.js +8 -10
  49. package/lib/ReactServerBatchingStrategy.js +23 -0
  50. package/lib/ReactServerRendering.js +13 -0
  51. package/lib/ReactServerRenderingTransaction.js +2 -2
  52. package/lib/ReactTestUtils.js +56 -33
  53. package/lib/ReactUpdateQueue.js +51 -26
  54. package/lib/ReactUpdates.js +0 -3
  55. package/lib/ReactWithAddons.js +0 -2
  56. package/lib/SelectEventPlugin.js +6 -7
  57. package/lib/SimpleEventPlugin.js +4 -4
  58. package/lib/SyntheticClipboardEvent.js +2 -2
  59. package/lib/SyntheticCompositionEvent.js +2 -2
  60. package/lib/SyntheticDragEvent.js +2 -2
  61. package/lib/SyntheticEvent.js +6 -5
  62. package/lib/SyntheticFocusEvent.js +2 -2
  63. package/lib/SyntheticInputEvent.js +2 -2
  64. package/lib/SyntheticKeyboardEvent.js +2 -2
  65. package/lib/SyntheticMouseEvent.js +2 -2
  66. package/lib/SyntheticTouchEvent.js +2 -2
  67. package/lib/SyntheticUIEvent.js +2 -2
  68. package/lib/SyntheticWheelEvent.js +2 -2
  69. package/lib/Transaction.js +10 -4
  70. package/lib/cloneWithProps.js +1 -1
  71. package/lib/deprecated.js +47 -0
  72. package/lib/findDOMNode.js +2 -3
  73. package/lib/forEachAccumulated.js +1 -1
  74. package/lib/getEventCharCode.js +1 -1
  75. package/lib/getEventModifierState.js +0 -1
  76. package/lib/getMarkupWrap.js +13 -35
  77. package/lib/instantiateReactComponent.js +13 -9
  78. package/lib/isTextInputElement.js +2 -1
  79. package/lib/joinClasses.js +1 -1
  80. package/lib/setInnerHTML.js +1 -1
  81. package/lib/traverseAllChildren.js +1 -1
  82. package/lib/warning.js +0 -4
  83. package/package.json +1 -1
  84. package/react.js +53 -1
  85. package/addons/CSSTransitionGroup.js +0 -1
  86. package/addons/LinkedStateMixin.js +0 -1
  87. package/addons/Perf.js +0 -1
  88. package/addons/PureRenderMixin.js +0 -1
  89. package/addons/TestUtils.js +0 -1
  90. package/addons/TransitionGroup.js +0 -1
  91. package/addons/batchedUpdates.js +0 -1
  92. package/addons/cloneWithProps.js +0 -1
  93. package/addons/createFragment.js +0 -1
  94. package/addons/renderSubtreeIntoContainer.js +0 -1
  95. package/addons/shallowCompare.js +0 -1
  96. package/addons/update.js +0 -1
  97. package/lib/LocalEventTrapMixin.js +0 -46
  98. package/lib/ReactContext.js +0 -32
  99. package/lib/ReactDOMForm.js +0 -47
  100. package/lib/ReactDOMIframe.js +0 -43
  101. package/lib/ReactDOMImg.js +0 -44
  102. package/lib/ReactLifeCycle.js +0 -35
  103. package/lib/createFullPageComponent.js +0 -51
@@ -61,6 +61,20 @@ var ReactDOMIDOperations = {
61
61
  }
62
62
  },
63
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
+
64
78
  /**
65
79
  * Updates a DOM node to remove a property. This should only be used to remove
66
80
  * DOM properties in `DOMProperty`.
@@ -11,27 +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
- var findDOMNode = require("./findDOMNode");
25
20
  var invariant = require("./invariant");
26
21
 
27
- var input = ReactElement.createFactory('input');
28
-
29
22
  var instancesByReactID = {};
30
23
 
31
24
  function forceUpdateIfMounted() {
32
- /*jshint validthis:true */
33
- if (this.isMounted()) {
34
- this.forceUpdate();
25
+ if (this._rootNodeID) {
26
+ // DOM component is still mounted; update
27
+ ReactDOMInput.updateWrapper(this);
35
28
  }
36
29
  }
37
30
 
@@ -51,110 +44,101 @@ function forceUpdateIfMounted() {
51
44
  *
52
45
  * @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html
53
46
  */
54
- var ReactDOMInput = ReactClass.createClass({
55
- displayName: 'ReactDOMInput',
56
- tagName: 'INPUT',
57
-
58
- mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
59
-
60
- getInitialState: function () {
61
- var defaultValue = this.props.defaultValue;
62
- return {
63
- initialChecked: this.props.defaultChecked || false,
64
- initialValue: defaultValue != null ? defaultValue : null
65
- };
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;
66
61
  },
67
62
 
68
- render: function () {
69
- // Clone `this.props` so we don't mutate the input.
70
- var props = assign({}, this.props);
71
-
72
- props.defaultChecked = null;
73
- props.defaultValue = null;
63
+ mountWrapper: function (inst, props) {
64
+ LinkedValueUtils.checkPropTypes('input', props, inst._currentElement._owner);
74
65
 
75
- var value = LinkedValueUtils.getValue(this.props);
76
- props.value = value != null ? value : this.state.initialValue;
77
-
78
- var checked = LinkedValueUtils.getChecked(this.props);
79
- props.checked = checked != null ? checked : this.state.initialChecked;
80
-
81
- 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
+ };
82
72
 
83
- return input(props, this.props.children);
73
+ instancesByReactID[inst._rootNodeID] = inst;
84
74
  },
85
75
 
86
- componentDidMount: function () {
87
- var id = ReactMount.getID(findDOMNode(this));
88
- instancesByReactID[id] = this;
76
+ unmountWrapper: function (inst) {
77
+ delete instancesByReactID[inst._rootNodeID];
89
78
  },
90
79
 
91
- componentWillUnmount: function () {
92
- var rootNode = findDOMNode(this);
93
- var id = ReactMount.getID(rootNode);
94
- delete instancesByReactID[id];
95
- },
80
+ updateWrapper: function (inst) {
81
+ var props = inst._currentElement.props;
96
82
 
97
- componentDidUpdate: function (prevProps, prevState, prevContext) {
98
- var rootNode = findDOMNode(this);
99
- if (this.props.checked != null) {
100
- DOMPropertyOperations.setValueForProperty(rootNode, 'checked', this.props.checked || false);
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);
101
87
  }
102
88
 
103
- var value = LinkedValueUtils.getValue(this.props);
89
+ var value = LinkedValueUtils.getValue(props);
104
90
  if (value != null) {
105
91
  // Cast `value` to a string to ensure the value is set correctly. While
106
92
  // browsers typically do this as necessary, jsdom doesn't.
107
- DOMPropertyOperations.setValueForProperty(rootNode, 'value', '' + value);
93
+ ReactDOMIDOperations.updatePropertyByID(inst._rootNodeID, 'value', '' + value);
108
94
  }
109
- },
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);
110
107
 
111
- _handleChange: function (event) {
112
- var returnValue;
113
- var onChange = LinkedValueUtils.getOnChange(this.props);
114
- if (onChange) {
115
- 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;
116
115
  }
117
- // Here we use asap to wait until all updates have propagated, which
118
- // is important when using controlled components within layers:
119
- // https://github.com/facebook/react/issues/1698
120
- ReactUpdates.asap(forceUpdateIfMounted, this);
121
-
122
- var name = this.props.name;
123
- if (this.props.type === 'radio' && name != null) {
124
- var rootNode = findDOMNode(this);
125
- var queryRoot = rootNode;
126
-
127
- while (queryRoot.parentNode) {
128
- queryRoot = queryRoot.parentNode;
129
- }
130
116
 
131
- // If `rootNode.form` was non-null, then we could try `form.elements`,
132
- // but that sometimes behaves strangely in IE8. We could also try using
133
- // `form.getElementsByName`, but that will only return direct children
134
- // and won't include inputs that use the HTML5 `form=` attribute. Since
135
- // the input might not even be in a form, let's just use the global
136
- // `querySelectorAll` to ensure we don't miss anything.
137
- var group = queryRoot.querySelectorAll('input[name=' + JSON.stringify('' + name) + '][type="radio"]');
138
-
139
- for (var i = 0; i < group.length; i++) {
140
- var otherNode = group[i];
141
- if (otherNode === rootNode || otherNode.form !== rootNode.form) {
142
- continue;
143
- }
144
- var otherID = ReactMount.getID(otherNode);
145
- !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;
146
- var otherInstance = instancesByReactID[otherID];
147
- !otherInstance ? 'production' !== process.env.NODE_ENV ? invariant(false, 'ReactDOMInput: Unknown radio button ID %s.', otherID) : invariant(false) : undefined;
148
- // If this is a controlled radio button group, forcing the input that
149
- // was previously checked to update will cause it to be come re-checked
150
- // as appropriate.
151
- 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;
152
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);
153
138
  }
154
-
155
- return returnValue;
156
139
  }
157
140
 
158
- });
141
+ return returnValue;
142
+ }
159
143
 
160
144
  module.exports = ReactDOMInput;
@@ -11,82 +11,62 @@
11
11
 
12
12
  'use strict';
13
13
 
14
- var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
15
14
  var ReactChildren = require("./ReactChildren");
16
- var ReactClass = require("./ReactClass");
17
15
  var ReactDOMSelect = require("./ReactDOMSelect");
18
- var ReactElement = require("./ReactElement");
19
- var ReactPropTypes = require("./ReactPropTypes");
20
16
 
21
17
  var assign = require("./Object.assign");
22
18
  var warning = require("./warning");
23
19
 
24
- var option = ReactElement.createFactory('option');
25
-
26
20
  var valueContextKey = ReactDOMSelect.valueContextKey;
27
21
 
28
22
  /**
29
23
  * Implements an <option> native component that warns when `selected` is set.
30
24
  */
31
- var ReactDOMOption = ReactClass.createClass({
32
- displayName: 'ReactDOMOption',
33
- tagName: 'OPTION',
34
-
35
- mixins: [ReactBrowserComponentMixin],
36
-
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 () {
25
+ var ReactDOMOption = {
26
+ mountWrapper: function (inst, props, context) {
48
27
  // TODO (yungsters): Remove support for `selected` in <option>.
49
28
  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>.') : undefined;
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;
51
30
  }
52
31
 
53
- // Look up whether this option is 'selected' via parent-based context
54
- var context = this.context;
32
+ // Look up whether this option is 'selected' via context
55
33
  var selectValue = context[valueContextKey];
56
34
 
57
35
  // If context key is null (e.g., no specified value or after initial mount)
58
- // or missing (e.g., for <datalist>) skip props
36
+ // or missing (e.g., for <datalist>), we don't change props.selected
37
+ var selected = null;
59
38
  if (selectValue != null) {
60
- var selected = false;
39
+ selected = false;
61
40
  if (Array.isArray(selectValue)) {
62
41
  // multiple
63
42
  for (var i = 0; i < selectValue.length; i++) {
64
- if ('' + selectValue[i] === '' + this.props.value) {
43
+ if ('' + selectValue[i] === '' + props.value) {
65
44
  selected = true;
66
45
  break;
67
46
  }
68
47
  }
69
48
  } else {
70
- selected = '' + selectValue === '' + this.props.value;
49
+ selected = '' + selectValue === '' + props.value;
71
50
  }
72
- this.setState({ selected: selected });
73
51
  }
52
+
53
+ inst._wrapperState = { selected: selected };
74
54
  },
75
55
 
76
- render: function () {
77
- var props = this.props;
56
+ getNativeProps: function (inst, props, context) {
57
+ var nativeProps = assign({ selected: undefined, children: undefined }, props);
78
58
 
79
59
  // Read state only from initial mount because <select> updates value
80
60
  // manually; we need the initial state only for server rendering
81
- if (this.state.selected != null) {
82
- props = assign({}, props, { selected: this.state.selected });
61
+ if (inst._wrapperState.selected != null) {
62
+ nativeProps.selected = inst._wrapperState.selected;
83
63
  }
84
64
 
85
65
  var content = '';
86
66
 
87
67
  // Flatten children and warn if they aren't strings or numbers;
88
68
  // invalid types are ignored.
89
- ReactChildren.forEach(this.props.children, function (child) {
69
+ ReactChildren.forEach(props.children, function (child) {
90
70
  if (child == null) {
91
71
  return;
92
72
  }
@@ -97,9 +77,10 @@ var ReactDOMOption = ReactClass.createClass({
97
77
  }
98
78
  });
99
79
 
100
- return option(props, content);
80
+ nativeProps.children = content;
81
+ return nativeProps;
101
82
  }
102
83
 
103
- });
84
+ };
104
85
 
105
86
  module.exports = ReactDOMOption;
@@ -11,61 +11,72 @@
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
- var ReactPropTypes = require("./ReactPropTypes");
21
17
 
22
18
  var assign = require("./Object.assign");
23
- var findDOMNode = require("./findDOMNode");
24
-
25
- var select = ReactElement.createFactory('select');
19
+ var warning = require("./warning");
26
20
 
27
21
  var valueContextKey = '__ReactDOMSelect_value$' + Math.random().toString(36).slice(2);
28
22
 
29
23
  function updateOptionsIfPendingUpdateAndMounted() {
30
- /*jshint validthis:true */
31
- if (this._pendingUpdate) {
32
- this._pendingUpdate = false;
33
- var value = LinkedValueUtils.getValue(this.props);
34
- if (value != null && this.isMounted()) {
35
- 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);
36
32
  }
37
33
  }
38
34
  }
39
35
 
36
+ function getDeclarationErrorAddendum(owner) {
37
+ if (owner) {
38
+ var name = owner.getName();
39
+ if (name) {
40
+ return ' Check the render method of `' + name + '`.';
41
+ }
42
+ }
43
+ return '';
44
+ }
45
+
46
+ var valuePropNames = ['value', 'defaultValue'];
47
+
40
48
  /**
41
49
  * Validation function for `value` and `defaultValue`.
42
50
  * @private
43
51
  */
44
- function selectValueType(props, propName, componentName) {
45
- if (props[propName] == null) {
46
- return null;
47
- }
48
- if (props.multiple) {
49
- if (!Array.isArray(props[propName])) {
50
- return new Error('The `' + propName + '` prop supplied to <select> must be an array if ' + '`multiple` is true.');
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;
51
60
  }
52
- } else {
53
- if (Array.isArray(props[propName])) {
54
- return new Error('The `' + propName + '` prop supplied to <select> must be a scalar ' + 'value if `multiple` is false.');
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;
55
65
  }
56
66
  }
57
67
  }
58
68
 
59
69
  /**
60
- * @param {ReactComponent} component Instance of ReactDOMSelect
70
+ * @param {ReactDOMComponent} inst
71
+ * @param {boolean} multiple
61
72
  * @param {*} propValue A stringable (with `multiple`, a list of stringables).
62
73
  * @private
63
74
  */
64
- function updateOptions(component, propValue) {
75
+ function updateOptions(inst, multiple, propValue) {
65
76
  var selectedValue, i;
66
- var options = findDOMNode(component).options;
77
+ var options = ReactMount.getNode(inst._rootNodeID).options;
67
78
 
68
- if (component.props.multiple) {
79
+ if (multiple) {
69
80
  selectedValue = {};
70
81
  for (i = 0; i < propValue.length; i++) {
71
82
  selectedValue['' + propValue[i]] = true;
@@ -107,92 +118,71 @@ function updateOptions(component, propValue) {
107
118
  * If `defaultValue` is provided, any options with the supplied values will be
108
119
  * selected.
109
120
  */
110
- var ReactDOMSelect = ReactClass.createClass({
111
- displayName: 'ReactDOMSelect',
112
- tagName: 'SELECT',
113
-
114
- mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
115
-
116
- statics: {
117
- valueContextKey: valueContextKey
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
+ });
118
129
  },
119
130
 
120
- propTypes: {
121
- defaultValue: selectValueType,
122
- value: selectValueType
123
- },
124
-
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 };
131
+ mountWrapper: function (inst, props) {
132
+ if ('production' !== process.env.NODE_ENV) {
133
+ checkSelectPropTypes(inst, props);
133
134
  }
134
- },
135
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;
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
+ };
146
143
  },
147
144
 
148
- render: function () {
149
- // Clone `this.props` so we don't mutate the input.
150
- var props = assign({}, this.props);
151
-
152
- props.onChange = this._handleChange;
153
- props.value = null;
154
-
155
- return select(props, this.props.children);
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;
156
151
  },
157
152
 
158
- componentWillMount: function () {
159
- this._pendingUpdate = false;
160
- },
153
+ postUpdateWrapper: function (inst) {
154
+ var props = inst._currentElement.props;
161
155
 
162
- componentWillReceiveProps: function (nextProps) {
163
156
  // After the initial mount, we control selected-ness manually so don't pass
164
157
  // the context value down
165
- this.setState({ initialValue: null });
166
- },
158
+ inst._wrapperState.initialValue = undefined;
159
+
160
+ var wasMultiple = inst._wrapperState.wasMultiple;
161
+ inst._wrapperState.wasMultiple = Boolean(props.multiple);
167
162
 
168
- componentDidUpdate: function (prevProps) {
169
- var value = LinkedValueUtils.getValue(this.props);
163
+ var value = LinkedValueUtils.getValue(props);
170
164
  if (value != null) {
171
- this._pendingUpdate = false;
172
- updateOptions(this, value);
173
- } 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)) {
174
168
  // For simplicity, reapply `defaultValue` if `multiple` is toggled.
175
- if (this.props.defaultValue != null) {
176
- updateOptions(this, this.props.defaultValue);
169
+ if (props.defaultValue != null) {
170
+ updateOptions(inst, Boolean(props.multiple), props.defaultValue);
177
171
  } else {
178
172
  // Revert the select back to its default unselected state.
179
- updateOptions(this, this.props.multiple ? [] : '');
173
+ updateOptions(inst, Boolean(props.multiple), props.multiple ? [] : '');
180
174
  }
181
175
  }
182
- },
183
-
184
- _handleChange: function (event) {
185
- var returnValue;
186
- var onChange = LinkedValueUtils.getOnChange(this.props);
187
- if (onChange) {
188
- returnValue = onChange.call(this, event);
189
- }
190
-
191
- this._pendingUpdate = true;
192
- ReactUpdates.asap(updateOptionsIfPendingUpdateAndMounted, this);
193
- return returnValue;
194
176
  }
177
+ };
195
178
 
196
- });
179
+ function _handleChange(event) {
180
+ var props = this._currentElement.props;
181
+ var returnValue = LinkedValueUtils.executeOnChange(props, event);
182
+
183
+ this._wrapperState.pendingUpdate = true;
184
+ ReactUpdates.asap(updateOptionsIfPendingUpdateAndMounted, this);
185
+ return returnValue;
186
+ }
197
187
 
198
188
  module.exports = ReactDOMSelect;