react 0.14.9 → 15.0.0-rc.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 (183) hide show
  1. package/LICENSE +1 -1
  2. package/addons.js +2 -0
  3. package/dist/react-with-addons.js +4299 -4138
  4. package/dist/react-with-addons.min.js +7 -7
  5. package/dist/react.js +4059 -3644
  6. package/dist/react.min.js +7 -7
  7. package/lib/AutoFocusUtils.js +3 -15
  8. package/lib/BeforeInputEventPlugin.js +8 -25
  9. package/lib/CSSProperty.js +10 -1
  10. package/lib/CSSPropertyOperations.js +21 -7
  11. package/lib/CallbackQueue.js +12 -1
  12. package/lib/ChangeEventPlugin.js +58 -54
  13. package/lib/DOMChildrenOperations.js +93 -60
  14. package/lib/DOMLazyTree.js +105 -0
  15. package/lib/{ClientReactRootIndex.js → DOMNamespaces.js} +7 -10
  16. package/lib/DOMProperty.js +15 -36
  17. package/lib/DOMPropertyOperations.js +40 -52
  18. package/lib/Danger.js +6 -7
  19. package/lib/DefaultEventPluginOrder.js +1 -1
  20. package/lib/EnterLeaveEventPlugin.js +24 -43
  21. package/lib/EventConstants.js +6 -1
  22. package/lib/EventPluginHub.js +20 -64
  23. package/lib/EventPluginRegistry.js +23 -2
  24. package/lib/EventPluginUtils.js +60 -35
  25. package/lib/EventPropagators.js +19 -17
  26. package/lib/FallbackCompositionState.js +1 -2
  27. package/lib/HTMLDOMPropertyConfig.js +131 -152
  28. package/lib/LinkedStateMixin.js +1 -2
  29. package/lib/LinkedValueUtils.js +2 -3
  30. package/lib/MetaMatchers.js +2 -2
  31. package/lib/Object.assign.js +1 -1
  32. package/lib/OrderedMap.js +1 -1
  33. package/lib/PooledClass.js +1 -1
  34. package/lib/React.js +1 -13
  35. package/lib/ReactBrowserEventEmitter.js +16 -24
  36. package/lib/ReactCSSTransitionGroup.js +1 -2
  37. package/lib/ReactCSSTransitionGroupChild.js +1 -6
  38. package/lib/ReactChildReconciler.js +14 -12
  39. package/lib/ReactChildren.js +5 -4
  40. package/lib/ReactClass.js +21 -70
  41. package/lib/ReactComponent.js +4 -5
  42. package/lib/ReactComponentBrowserEnvironment.js +9 -6
  43. package/lib/ReactComponentEnvironment.js +3 -3
  44. package/lib/ReactComponentWithPureRenderMixin.js +2 -2
  45. package/lib/ReactCompositeComponent.js +146 -55
  46. package/lib/ReactCurrentOwner.js +2 -1
  47. package/lib/ReactDOM.js +26 -14
  48. package/lib/ReactDOMButton.js +2 -2
  49. package/lib/ReactDOMComponent.js +162 -231
  50. package/lib/ReactDOMComponentFlags.js +18 -0
  51. package/lib/ReactDOMComponentTree.js +186 -0
  52. package/lib/ReactDOMContainerInfo.js +32 -0
  53. package/lib/ReactDOMDebugTool.js +61 -0
  54. package/lib/ReactDOMEmptyComponent.js +60 -0
  55. package/lib/ReactDOMFactories.js +1 -2
  56. package/lib/ReactDOMFeatureFlags.js +2 -2
  57. package/lib/ReactDOMIDOperations.js +5 -60
  58. package/lib/ReactDOMInput.js +71 -22
  59. package/lib/ReactDOMInstrumentation.js +16 -0
  60. package/lib/ReactDOMOption.js +9 -8
  61. package/lib/ReactDOMSelect.js +38 -15
  62. package/lib/ReactDOMSelection.js +4 -4
  63. package/lib/ReactDOMServer.js +1 -1
  64. package/lib/ReactDOMTextComponent.js +84 -43
  65. package/lib/ReactDOMTextarea.js +32 -5
  66. package/lib/ReactDOMTreeTraversal.js +134 -0
  67. package/lib/ReactDOMUnknownPropertyDevtool.js +64 -0
  68. package/lib/ReactDebugTool.js +72 -0
  69. package/lib/ReactDefaultBatchingStrategy.js +1 -1
  70. package/lib/ReactDefaultInjection.js +11 -15
  71. package/lib/ReactDefaultPerf.js +59 -19
  72. package/lib/ReactDefaultPerfAnalysis.js +17 -9
  73. package/lib/ReactElement.js +60 -21
  74. package/lib/ReactElementValidator.js +2 -2
  75. package/lib/ReactEmptyComponent.js +8 -33
  76. package/lib/ReactErrorUtils.js +1 -2
  77. package/lib/ReactEventEmitterMixin.js +3 -8
  78. package/lib/ReactEventListener.js +20 -75
  79. package/lib/ReactFeatureFlags.js +21 -0
  80. package/lib/ReactFragment.js +2 -2
  81. package/lib/ReactInjection.js +3 -3
  82. package/lib/ReactInputSelection.js +4 -4
  83. package/lib/ReactInstanceHandles.js +4 -6
  84. package/lib/ReactInstanceMap.js +2 -1
  85. package/lib/ReactInstrumentation.js +16 -0
  86. package/lib/ReactInvalidSetStateWarningDevTool.js +36 -0
  87. package/lib/ReactIsomorphic.js +1 -1
  88. package/lib/ReactLink.js +2 -3
  89. package/lib/ReactMarkupChecksum.js +8 -3
  90. package/lib/ReactMount.js +74 -447
  91. package/lib/ReactMultiChild.js +106 -200
  92. package/lib/ReactMultiChildUpdateTypes.js +1 -1
  93. package/lib/ReactNativeComponent.js +2 -2
  94. package/lib/ReactNodeTypes.js +37 -0
  95. package/lib/ReactNoopUpdateQueue.js +1 -24
  96. package/lib/ReactOwner.js +5 -4
  97. package/lib/ReactPerf.js +2 -2
  98. package/lib/ReactPropTransferer.js +1 -1
  99. package/lib/ReactPropTypeLocationNames.js +1 -1
  100. package/lib/ReactPropTypeLocations.js +1 -1
  101. package/lib/ReactPropTypes.js +31 -7
  102. package/lib/ReactReconcileTransaction.js +17 -6
  103. package/lib/ReactReconciler.js +29 -6
  104. package/lib/ReactRef.js +1 -1
  105. package/lib/ReactServerBatchingStrategy.js +1 -2
  106. package/lib/ReactServerRendering.js +16 -34
  107. package/lib/ReactServerRenderingTransaction.js +8 -26
  108. package/lib/ReactSimpleEmptyComponent.js +36 -0
  109. package/lib/ReactStateSetters.js +1 -1
  110. package/lib/ReactTestUtils.js +30 -21
  111. package/lib/ReactTransitionChildMapping.js +1 -2
  112. package/lib/ReactTransitionEvents.js +8 -44
  113. package/lib/ReactTransitionGroup.js +1 -1
  114. package/lib/ReactUpdateQueue.js +4 -63
  115. package/lib/ReactUpdates.js +19 -2
  116. package/lib/ReactVersion.js +2 -2
  117. package/lib/ReactWithAddons.js +1 -14
  118. package/lib/ResponderEventPlugin.js +53 -65
  119. package/lib/ResponderSyntheticEvent.js +2 -3
  120. package/lib/ResponderTouchHistoryStore.js +1 -1
  121. package/lib/SVGDOMPropertyConfig.js +267 -94
  122. package/lib/SelectEventPlugin.js +13 -18
  123. package/lib/SimpleEventPlugin.js +56 -16
  124. package/lib/SyntheticAnimationEvent.js +39 -0
  125. package/lib/SyntheticClipboardEvent.js +2 -3
  126. package/lib/SyntheticCompositionEvent.js +2 -3
  127. package/lib/SyntheticDragEvent.js +2 -3
  128. package/lib/SyntheticEvent.js +97 -17
  129. package/lib/SyntheticFocusEvent.js +2 -3
  130. package/lib/SyntheticInputEvent.js +2 -3
  131. package/lib/SyntheticKeyboardEvent.js +2 -3
  132. package/lib/SyntheticMouseEvent.js +2 -3
  133. package/lib/SyntheticTouchEvent.js +2 -3
  134. package/lib/SyntheticTransitionEvent.js +39 -0
  135. package/lib/SyntheticUIEvent.js +2 -3
  136. package/lib/SyntheticWheelEvent.js +2 -3
  137. package/lib/TapEventPlugin.js +3 -12
  138. package/lib/Transaction.js +1 -1
  139. package/lib/ViewportMetrics.js +1 -1
  140. package/lib/accumulate.js +1 -1
  141. package/lib/accumulateInto.js +1 -1
  142. package/lib/adler32.js +3 -2
  143. package/lib/canDefineProperty.js +1 -1
  144. package/lib/createHierarchyRenderer.js +1 -1
  145. package/lib/createMicrosoftUnsafeLocalFunction.js +32 -0
  146. package/lib/dangerousStyleValue.js +25 -3
  147. package/lib/deprecated.js +3 -1
  148. package/lib/escapeTextContentForBrowser.js +1 -1
  149. package/lib/findDOMNode.js +15 -8
  150. package/lib/flattenChildren.js +1 -1
  151. package/lib/forEachAccumulated.js +2 -1
  152. package/lib/getEventCharCode.js +2 -2
  153. package/lib/getEventKey.js +1 -2
  154. package/lib/getEventModifierState.js +1 -2
  155. package/lib/getEventTarget.js +8 -2
  156. package/lib/getIteratorFn.js +2 -2
  157. package/lib/getNativeComponentFromComposite.js +30 -0
  158. package/lib/getNodeForCharacterOffset.js +2 -1
  159. package/lib/getTestDocument.js +1 -1
  160. package/lib/getTextContentAccessor.js +1 -1
  161. package/lib/getVendorPrefixedEventName.js +101 -0
  162. package/lib/instantiateReactComponent.js +7 -9
  163. package/lib/isEventSupported.js +2 -2
  164. package/lib/isTextInputElement.js +2 -1
  165. package/lib/onlyChild.js +1 -1
  166. package/lib/quoteAttributeValueForBrowser.js +1 -1
  167. package/lib/reactComponentExpect.js +1 -1
  168. package/lib/renderSubtreeIntoContainer.js +1 -1
  169. package/lib/setInnerHTML.js +5 -14
  170. package/lib/setTextContent.js +1 -1
  171. package/lib/shallowCompare.js +1 -1
  172. package/lib/shouldUpdateReactComponent.js +2 -3
  173. package/lib/sliceChildren.js +1 -1
  174. package/lib/traverseAllChildren.js +6 -6
  175. package/lib/update.js +2 -2
  176. package/lib/validateDOMNesting.js +15 -11
  177. package/package.json +2 -2
  178. package/lib/ReactBrowserComponentMixin.js +0 -36
  179. package/lib/ReactEmptyComponentRegistry.js +0 -48
  180. package/lib/ReactRootIndex.js +0 -29
  181. package/lib/ServerReactRootIndex.js +0 -29
  182. package/lib/cloneWithProps.js +0 -54
  183. package/lib/webcomponents.js +0 -6379
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright 2013-2015, Facebook, Inc.
2
+ * Copyright 2013-present, Facebook, Inc.
3
3
  * All rights reserved.
4
4
  *
5
5
  * This source code is licensed under the BSD-style license found in the
@@ -11,15 +11,22 @@
11
11
 
12
12
  'use strict';
13
13
 
14
- var ReactDOMIDOperations = require('./ReactDOMIDOperations');
14
+ var DOMPropertyOperations = require('./DOMPropertyOperations');
15
15
  var LinkedValueUtils = require('./LinkedValueUtils');
16
- var ReactMount = require('./ReactMount');
16
+ var ReactDOMComponentTree = require('./ReactDOMComponentTree');
17
17
  var ReactUpdates = require('./ReactUpdates');
18
18
 
19
19
  var assign = require('./Object.assign');
20
20
  var invariant = require('fbjs/lib/invariant');
21
+ var warning = require('fbjs/lib/warning');
21
22
 
22
- var instancesByReactID = {};
23
+ var didWarnValueLink = false;
24
+ var didWarnCheckedLink = false;
25
+ var didWarnValueNull = false;
26
+ var didWarnValueDefaultValue = false;
27
+ var didWarnCheckedDefaultChecked = false;
28
+ var didWarnControlledToUncontrolled = false;
29
+ var didWarnUncontrolledToControlled = false;
23
30
 
24
31
  function forceUpdateIfMounted() {
25
32
  if (this._rootNodeID) {
@@ -28,6 +35,14 @@ function forceUpdateIfMounted() {
28
35
  }
29
36
  }
30
37
 
38
+ function warnIfValueIsNull(props) {
39
+ if (props != null && props.value === null && !didWarnValueNull) {
40
+ process.env.NODE_ENV !== 'production' ? warning(false, '`value` prop on `input` should not be null. ' + 'Consider using the empty string to clear the component or `undefined` ' + 'for uncontrolled components.') : undefined;
41
+
42
+ didWarnValueNull = true;
43
+ }
44
+ }
45
+
31
46
  /**
32
47
  * Implements an <input> native component that allows setting these optional
33
48
  * props: `checked`, `value`, `defaultChecked`, and `defaultValue`.
@@ -45,11 +60,15 @@ function forceUpdateIfMounted() {
45
60
  * @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html
46
61
  */
47
62
  var ReactDOMInput = {
48
- getNativeProps: function (inst, props, context) {
63
+ getNativeProps: function (inst, props) {
49
64
  var value = LinkedValueUtils.getValue(props);
50
65
  var checked = LinkedValueUtils.getChecked(props);
51
66
 
52
- var nativeProps = assign({}, props, {
67
+ var nativeProps = assign({
68
+ // Make sure we set .type before any other properties (setting .value
69
+ // before .type means .value is lost in IE11 and below)
70
+ type: undefined
71
+ }, props, {
53
72
  defaultChecked: undefined,
54
73
  defaultValue: undefined,
55
74
  value: value != null ? value : inst._wrapperState.initialValue,
@@ -63,39 +82,71 @@ var ReactDOMInput = {
63
82
  mountWrapper: function (inst, props) {
64
83
  if (process.env.NODE_ENV !== 'production') {
65
84
  LinkedValueUtils.checkPropTypes('input', props, inst._currentElement._owner);
85
+
86
+ if (props.valueLink !== undefined && !didWarnValueLink) {
87
+ process.env.NODE_ENV !== 'production' ? warning(false, '`valueLink` prop on `input` is deprecated; set `value` and `onChange` instead.') : undefined;
88
+ didWarnValueLink = true;
89
+ }
90
+ if (props.checkedLink !== undefined && !didWarnCheckedLink) {
91
+ process.env.NODE_ENV !== 'production' ? warning(false, '`checkedLink` prop on `input` is deprecated; set `value` and `onChange` instead.') : undefined;
92
+ didWarnCheckedLink = true;
93
+ }
94
+ if (props.checked !== undefined && props.defaultChecked !== undefined && !didWarnCheckedDefaultChecked) {
95
+ process.env.NODE_ENV !== 'production' ? warning(false, 'Input elements must be either controlled or uncontrolled ' + '(specify either the checked prop, or the defaultChecked prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components') : undefined;
96
+ didWarnCheckedDefaultChecked = true;
97
+ }
98
+ if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue) {
99
+ process.env.NODE_ENV !== 'production' ? warning(false, 'Input elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components') : undefined;
100
+ didWarnValueDefaultValue = true;
101
+ }
102
+ warnIfValueIsNull(props);
66
103
  }
67
104
 
68
105
  var defaultValue = props.defaultValue;
69
106
  inst._wrapperState = {
70
107
  initialChecked: props.defaultChecked || false,
71
108
  initialValue: defaultValue != null ? defaultValue : null,
109
+ listeners: null,
72
110
  onChange: _handleChange.bind(inst)
73
111
  };
74
- },
75
112
 
76
- mountReadyWrapper: function (inst) {
77
- // Can't be in mountWrapper or else server rendering leaks.
78
- instancesByReactID[inst._rootNodeID] = inst;
79
- },
80
-
81
- unmountWrapper: function (inst) {
82
- delete instancesByReactID[inst._rootNodeID];
113
+ if (process.env.NODE_ENV !== 'production') {
114
+ inst._wrapperState.controlled = props.checked !== undefined || props.value !== undefined;
115
+ }
83
116
  },
84
117
 
85
118
  updateWrapper: function (inst) {
86
119
  var props = inst._currentElement.props;
87
120
 
121
+ if (process.env.NODE_ENV !== 'production') {
122
+ warnIfValueIsNull(props);
123
+
124
+ var initialValue = inst._wrapperState.initialChecked || inst._wrapperState.initialValue;
125
+ var defaultValue = props.defaultChecked || props.defaultValue;
126
+ var controlled = props.checked !== undefined || props.value !== undefined;
127
+ var owner = inst._currentElement._owner;
128
+
129
+ if ((initialValue || !inst._wrapperState.controlled) && controlled && !didWarnUncontrolledToControlled) {
130
+ process.env.NODE_ENV !== 'production' ? warning(false, '%s is changing a uncontrolled input of type %s to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or viceversa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', owner && owner.getName() || 'A component', props.type) : undefined;
131
+ didWarnUncontrolledToControlled = true;
132
+ }
133
+ if (inst._wrapperState.controlled && (defaultValue || !controlled) && !didWarnControlledToUncontrolled) {
134
+ process.env.NODE_ENV !== 'production' ? warning(false, '%s is changing a controlled input of type %s to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or viceversa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', owner && owner.getName() || 'A component', props.type) : undefined;
135
+ didWarnControlledToUncontrolled = true;
136
+ }
137
+ }
138
+
88
139
  // TODO: Shouldn't this be getChecked(props)?
89
140
  var checked = props.checked;
90
141
  if (checked != null) {
91
- ReactDOMIDOperations.updatePropertyByID(inst._rootNodeID, 'checked', checked || false);
142
+ DOMPropertyOperations.setValueForProperty(ReactDOMComponentTree.getNodeFromInstance(inst), 'checked', checked || false);
92
143
  }
93
144
 
94
145
  var value = LinkedValueUtils.getValue(props);
95
146
  if (value != null) {
96
147
  // Cast `value` to a string to ensure the value is set correctly. While
97
148
  // browsers typically do this as necessary, jsdom doesn't.
98
- ReactDOMIDOperations.updatePropertyByID(inst._rootNodeID, 'value', '' + value);
149
+ DOMPropertyOperations.setValueForProperty(ReactDOMComponentTree.getNodeFromInstance(inst), 'value', '' + value);
99
150
  }
100
151
  }
101
152
  };
@@ -112,7 +163,7 @@ function _handleChange(event) {
112
163
 
113
164
  var name = props.name;
114
165
  if (props.type === 'radio' && name != null) {
115
- var rootNode = ReactMount.getNode(this._rootNodeID);
166
+ var rootNode = ReactDOMComponentTree.getNodeFromInstance(this);
116
167
  var queryRoot = rootNode;
117
168
 
118
169
  while (queryRoot.parentNode) {
@@ -135,11 +186,9 @@ function _handleChange(event) {
135
186
  // This will throw if radio buttons rendered by different copies of React
136
187
  // and the same name are rendered into the same form (same as #1939).
137
188
  // That's probably okay; we don't support it just as we don't support
138
- // mixing React with non-React.
139
- var otherID = ReactMount.getID(otherNode);
140
- !otherID ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactDOMInput: Mixing React and non-React radio inputs with the ' + 'same `name` is not supported.') : invariant(false) : undefined;
141
- var otherInstance = instancesByReactID[otherID];
142
- !otherInstance ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactDOMInput: Unknown radio button ID %s.', otherID) : invariant(false) : undefined;
189
+ // mixing React radio buttons with non-React ones.
190
+ var otherInstance = ReactDOMComponentTree.getInstanceFromNode(otherNode);
191
+ !otherInstance ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactDOMInput: Mixing React and non-React radio inputs with the ' + 'same `name` is not supported.') : invariant(false) : undefined;
143
192
  // If this is a controlled radio button group, forcing the input that
144
193
  // was previously checked to update will cause it to be come re-checked
145
194
  // as appropriate.
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Copyright 2013-present, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ *
9
+ * @providesModule ReactDOMInstrumentation
10
+ */
11
+
12
+ 'use strict';
13
+
14
+ var ReactDOMDebugTool = require('./ReactDOMDebugTool');
15
+
16
+ module.exports = { debugTool: ReactDOMDebugTool };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright 2013-2015, Facebook, Inc.
2
+ * Copyright 2013-present, Facebook, Inc.
3
3
  * All rights reserved.
4
4
  *
5
5
  * This source code is licensed under the BSD-style license found in the
@@ -17,22 +17,23 @@ var ReactDOMSelect = require('./ReactDOMSelect');
17
17
  var assign = require('./Object.assign');
18
18
  var warning = require('fbjs/lib/warning');
19
19
 
20
- var valueContextKey = ReactDOMSelect.valueContextKey;
21
-
22
20
  /**
23
21
  * Implements an <option> native component that warns when `selected` is set.
24
22
  */
25
23
  var ReactDOMOption = {
26
- mountWrapper: function (inst, props, context) {
24
+ mountWrapper: function (inst, props, nativeParent) {
27
25
  // TODO (yungsters): Remove support for `selected` in <option>.
28
26
  if (process.env.NODE_ENV !== 'production') {
29
27
  process.env.NODE_ENV !== 'production' ? warning(props.selected == null, 'Use the `defaultValue` or `value` props on <select> instead of ' + 'setting `selected` on <option>.') : undefined;
30
28
  }
31
29
 
32
- // Look up whether this option is 'selected' via context
33
- var selectValue = context[valueContextKey];
30
+ // Look up whether this option is 'selected'
31
+ var selectValue = null;
32
+ if (nativeParent != null && nativeParent._tag === 'select') {
33
+ selectValue = ReactDOMSelect.getSelectValueContext(nativeParent);
34
+ }
34
35
 
35
- // If context key is null (e.g., no specified value or after initial mount)
36
+ // If the value is null (e.g., no specified value or after initial mount)
36
37
  // or missing (e.g., for <datalist>), we don't change props.selected
37
38
  var selected = null;
38
39
  if (selectValue != null) {
@@ -53,7 +54,7 @@ var ReactDOMOption = {
53
54
  inst._wrapperState = { selected: selected };
54
55
  },
55
56
 
56
- getNativeProps: function (inst, props, context) {
57
+ getNativeProps: function (inst, props) {
57
58
  var nativeProps = assign({ selected: undefined, children: undefined }, props);
58
59
 
59
60
  // Read state only from initial mount because <select> updates value
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright 2013-2015, Facebook, Inc.
2
+ * Copyright 2013-present, Facebook, Inc.
3
3
  * All rights reserved.
4
4
  *
5
5
  * This source code is licensed under the BSD-style license found in the
@@ -12,13 +12,15 @@
12
12
  'use strict';
13
13
 
14
14
  var LinkedValueUtils = require('./LinkedValueUtils');
15
- var ReactMount = require('./ReactMount');
15
+ var ReactDOMComponentTree = require('./ReactDOMComponentTree');
16
16
  var ReactUpdates = require('./ReactUpdates');
17
17
 
18
18
  var assign = require('./Object.assign');
19
19
  var warning = require('fbjs/lib/warning');
20
20
 
21
- var valueContextKey = '__ReactDOMSelect_value$' + Math.random().toString(36).slice(2);
21
+ var didWarnValueLink = false;
22
+ var didWarnValueNull = false;
23
+ var didWarnValueDefaultValue = false;
22
24
 
23
25
  function updateOptionsIfPendingUpdateAndMounted() {
24
26
  if (this._rootNodeID && this._wrapperState.pendingUpdate) {
@@ -43,6 +45,14 @@ function getDeclarationErrorAddendum(owner) {
43
45
  return '';
44
46
  }
45
47
 
48
+ function warnIfValueIsNull(props) {
49
+ if (props != null && props.value === null && !didWarnValueNull) {
50
+ process.env.NODE_ENV !== 'production' ? warning(false, '`value` prop on `select` should not be null. ' + 'Consider using the empty string to clear the component or `undefined` ' + 'for uncontrolled components.') : undefined;
51
+
52
+ didWarnValueNull = true;
53
+ }
54
+ }
55
+
46
56
  var valuePropNames = ['value', 'defaultValue'];
47
57
 
48
58
  /**
@@ -53,6 +63,11 @@ function checkSelectPropTypes(inst, props) {
53
63
  var owner = inst._currentElement._owner;
54
64
  LinkedValueUtils.checkPropTypes('select', props, owner);
55
65
 
66
+ if (props.valueLink !== undefined && !didWarnValueLink) {
67
+ process.env.NODE_ENV !== 'production' ? warning(false, '`valueLink` prop on `select` is deprecated; set `value` and `onChange` instead.') : undefined;
68
+ didWarnValueLink = true;
69
+ }
70
+
56
71
  for (var i = 0; i < valuePropNames.length; i++) {
57
72
  var propName = valuePropNames[i];
58
73
  if (props[propName] == null) {
@@ -74,7 +89,7 @@ function checkSelectPropTypes(inst, props) {
74
89
  */
75
90
  function updateOptions(inst, multiple, propValue) {
76
91
  var selectedValue, i;
77
- var options = ReactMount.getNode(inst._rootNodeID).options;
92
+ var options = ReactDOMComponentTree.getNodeFromInstance(inst).options;
78
93
 
79
94
  if (multiple) {
80
95
  selectedValue = {};
@@ -119,9 +134,7 @@ function updateOptions(inst, multiple, propValue) {
119
134
  * selected.
120
135
  */
121
136
  var ReactDOMSelect = {
122
- valueContextKey: valueContextKey,
123
-
124
- getNativeProps: function (inst, props, context) {
137
+ getNativeProps: function (inst, props) {
125
138
  return assign({}, props, {
126
139
  onChange: inst._wrapperState.onChange,
127
140
  value: undefined
@@ -131,30 +144,38 @@ var ReactDOMSelect = {
131
144
  mountWrapper: function (inst, props) {
132
145
  if (process.env.NODE_ENV !== 'production') {
133
146
  checkSelectPropTypes(inst, props);
147
+ warnIfValueIsNull(props);
134
148
  }
135
149
 
136
150
  var value = LinkedValueUtils.getValue(props);
137
151
  inst._wrapperState = {
138
152
  pendingUpdate: false,
139
153
  initialValue: value != null ? value : props.defaultValue,
154
+ listeners: null,
140
155
  onChange: _handleChange.bind(inst),
141
156
  wasMultiple: Boolean(props.multiple)
142
157
  };
158
+
159
+ if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue) {
160
+ process.env.NODE_ENV !== 'production' ? warning(false, 'Select elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled select ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components') : undefined;
161
+ didWarnValueDefaultValue = true;
162
+ }
143
163
  },
144
164
 
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;
165
+ getSelectValueContext: function (inst) {
166
+ // ReactDOMOption looks at this initial value so the initial generated
167
+ // markup has correct `selected` attributes
168
+ return inst._wrapperState.initialValue;
151
169
  },
152
170
 
153
171
  postUpdateWrapper: function (inst) {
154
172
  var props = inst._currentElement.props;
173
+ if (process.env.NODE_ENV !== 'production') {
174
+ warnIfValueIsNull(props);
175
+ }
155
176
 
156
177
  // After the initial mount, we control selected-ness manually so don't pass
157
- // the context value down
178
+ // this value down
158
179
  inst._wrapperState.initialValue = undefined;
159
180
 
160
181
  var wasMultiple = inst._wrapperState.wasMultiple;
@@ -180,7 +201,9 @@ function _handleChange(event) {
180
201
  var props = this._currentElement.props;
181
202
  var returnValue = LinkedValueUtils.executeOnChange(props, event);
182
203
 
183
- this._wrapperState.pendingUpdate = true;
204
+ if (this._rootNodeID) {
205
+ this._wrapperState.pendingUpdate = true;
206
+ }
184
207
  ReactUpdates.asap(updateOptionsIfPendingUpdateAndMounted, this);
185
208
  return returnValue;
186
209
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright 2013-2015, Facebook, Inc.
2
+ * Copyright 2013-present, Facebook, Inc.
3
3
  * All rights reserved.
4
4
  *
5
5
  * This source code is licensed under the BSD-style license found in the
@@ -128,7 +128,7 @@ function setIEOffsets(node, offsets) {
128
128
  var range = document.selection.createRange().duplicate();
129
129
  var start, end;
130
130
 
131
- if (typeof offsets.end === 'undefined') {
131
+ if (offsets.end === undefined) {
132
132
  start = offsets.start;
133
133
  end = start;
134
134
  } else if (offsets.start > offsets.end) {
@@ -152,7 +152,7 @@ function setIEOffsets(node, offsets) {
152
152
  *
153
153
  * Note: IE10+ supports the Selection object, but it does not support
154
154
  * the `extend` method, which means that even in modern IE, it's not possible
155
- * to programatically create a backward selection. Thus, for all IE
155
+ * to programmatically create a backward selection. Thus, for all IE
156
156
  * versions, we use the old IE API to create our selections.
157
157
  *
158
158
  * @param {DOMElement|DOMTextNode} node
@@ -166,7 +166,7 @@ function setModernOffsets(node, offsets) {
166
166
  var selection = window.getSelection();
167
167
  var length = node[getTextContentAccessor()].length;
168
168
  var start = Math.min(offsets.start, length);
169
- var end = typeof offsets.end === 'undefined' ? start : Math.min(offsets.end, length);
169
+ var end = offsets.end === undefined ? start : Math.min(offsets.end, length);
170
170
 
171
171
  // IE 11 uses modern selection, but doesn't support the extend method.
172
172
  // Flip backward selections, so we can set with a single range.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright 2013-2015, Facebook, Inc.
2
+ * Copyright 2013-present, Facebook, Inc.
3
3
  * All rights reserved.
4
4
  *
5
5
  * This source code is licensed under the BSD-style license found in the
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright 2013-2015, Facebook, Inc.
2
+ * Copyright 2013-present, Facebook, Inc.
3
3
  * All rights reserved.
4
4
  *
5
5
  * This source code is licensed under the BSD-style license found in the
@@ -7,19 +7,18 @@
7
7
  * of patent rights can be found in the PATENTS file in the same directory.
8
8
  *
9
9
  * @providesModule ReactDOMTextComponent
10
- * @typechecks static-only
11
10
  */
12
11
 
13
12
  'use strict';
14
13
 
15
14
  var DOMChildrenOperations = require('./DOMChildrenOperations');
16
- var DOMPropertyOperations = require('./DOMPropertyOperations');
17
- var ReactComponentBrowserEnvironment = require('./ReactComponentBrowserEnvironment');
18
- var ReactMount = require('./ReactMount');
15
+ var DOMLazyTree = require('./DOMLazyTree');
16
+ var ReactDOMComponentTree = require('./ReactDOMComponentTree');
17
+ var ReactPerf = require('./ReactPerf');
19
18
 
20
19
  var assign = require('./Object.assign');
21
20
  var escapeTextContentForBrowser = require('./escapeTextContentForBrowser');
22
- var setTextContent = require('./setTextContent');
21
+ var invariant = require('fbjs/lib/invariant');
23
22
  var validateDOMNesting = require('./validateDOMNesting');
24
23
 
25
24
  /**
@@ -28,8 +27,8 @@ var validateDOMNesting = require('./validateDOMNesting');
28
27
  * - When mounting text into the DOM, adjacent text nodes are merged.
29
28
  * - Text nodes cannot be assigned a React root ID.
30
29
  *
31
- * This component is used to wrap strings in elements so that they can undergo
32
- * the same reconciliation that is applied to elements.
30
+ * This component is used to wrap strings between comment nodes so that they
31
+ * can undergo the same reconciliation that is applied to elements.
33
32
  *
34
33
  * TODO: Investigate representing React components in the DOM with text nodes.
35
34
  *
@@ -37,62 +36,75 @@ var validateDOMNesting = require('./validateDOMNesting');
37
36
  * @extends ReactComponent
38
37
  * @internal
39
38
  */
40
- var ReactDOMTextComponent = function (props) {
41
- // This constructor and its argument is currently used by mocks.
39
+ var ReactDOMTextComponent = function (text) {
40
+ // TODO: This is really a ReactText (ReactNode), not a ReactElement
41
+ this._currentElement = text;
42
+ this._stringText = '' + text;
43
+ // ReactDOMComponentTree uses these:
44
+ this._nativeNode = null;
45
+ this._nativeParent = null;
46
+
47
+ // Properties
48
+ this._domID = null;
49
+ this._mountIndex = 0;
50
+ this._closingComment = null;
51
+ this._commentNodes = null;
42
52
  };
43
53
 
44
54
  assign(ReactDOMTextComponent.prototype, {
45
55
 
46
- /**
47
- * @param {ReactText} text
48
- * @internal
49
- */
50
- construct: function (text) {
51
- // TODO: This is really a ReactText (ReactNode), not a ReactElement
52
- this._currentElement = text;
53
- this._stringText = '' + text;
54
-
55
- // Properties
56
- this._rootNodeID = null;
57
- this._mountIndex = 0;
58
- },
59
-
60
56
  /**
61
57
  * Creates the markup for this text node. This node is not intended to have
62
58
  * any features besides containing text content.
63
59
  *
64
- * @param {string} rootID DOM ID of the root node.
65
60
  * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
66
61
  * @return {string} Markup for this text node.
67
62
  * @internal
68
63
  */
69
- mountComponent: function (rootID, transaction, context) {
64
+ mountComponent: function (transaction, nativeParent, nativeContainerInfo, context) {
70
65
  if (process.env.NODE_ENV !== 'production') {
71
- if (context[validateDOMNesting.ancestorInfoContextKey]) {
72
- validateDOMNesting('span', null, context[validateDOMNesting.ancestorInfoContextKey]);
66
+ var parentInfo;
67
+ if (nativeParent != null) {
68
+ parentInfo = nativeParent._ancestorInfo;
69
+ } else if (nativeContainerInfo != null) {
70
+ parentInfo = nativeContainerInfo._ancestorInfo;
71
+ }
72
+ if (parentInfo) {
73
+ // parentInfo should always be present except for the top-level
74
+ // component when server rendering
75
+ validateDOMNesting('#text', this, parentInfo);
73
76
  }
74
77
  }
75
78
 
76
- this._rootNodeID = rootID;
79
+ var domID = nativeContainerInfo._idCounter++;
80
+ var openingValue = ' react-text: ' + domID + ' ';
81
+ var closingValue = ' /react-text ';
82
+ this._domID = domID;
83
+ this._nativeParent = nativeParent;
77
84
  if (transaction.useCreateElement) {
78
- var ownerDocument = context[ReactMount.ownerDocumentContextKey];
79
- var el = ownerDocument.createElement('span');
80
- DOMPropertyOperations.setAttributeForID(el, rootID);
81
- // Populate node cache
82
- ReactMount.getID(el);
83
- setTextContent(el, this._stringText);
84
- return el;
85
+ var ownerDocument = nativeContainerInfo._ownerDocument;
86
+ var openingComment = ownerDocument.createComment(openingValue);
87
+ var closingComment = ownerDocument.createComment(closingValue);
88
+ var lazyTree = DOMLazyTree(ownerDocument.createDocumentFragment());
89
+ DOMLazyTree.queueChild(lazyTree, DOMLazyTree(openingComment));
90
+ if (this._stringText) {
91
+ DOMLazyTree.queueChild(lazyTree, DOMLazyTree(ownerDocument.createTextNode(this._stringText)));
92
+ }
93
+ DOMLazyTree.queueChild(lazyTree, DOMLazyTree(closingComment));
94
+ ReactDOMComponentTree.precacheNode(this, openingComment);
95
+ this._closingComment = closingComment;
96
+ return lazyTree;
85
97
  } else {
86
98
  var escapedText = escapeTextContentForBrowser(this._stringText);
87
99
 
88
100
  if (transaction.renderToStaticMarkup) {
89
- // Normally we'd wrap this in a `span` for the reasons stated above, but
90
- // since this is a situation where React won't take over (static pages),
91
- // we can simply return the text as it is.
101
+ // Normally we'd wrap this between comment nodes for the reasons stated
102
+ // above, but since this is a situation where React won't take over
103
+ // (static pages), we can simply return the text as it is.
92
104
  return escapedText;
93
105
  }
94
106
 
95
- return '<span ' + DOMPropertyOperations.createMarkupForID(rootID) + '>' + escapedText + '</span>';
107
+ return '<!--' + openingValue + '-->' + escapedText + '<!--' + closingValue + '-->';
96
108
  }
97
109
  },
98
110
 
@@ -112,16 +124,45 @@ assign(ReactDOMTextComponent.prototype, {
112
124
  // and/or updateComponent to do the actual update for consistency with
113
125
  // other component types?
114
126
  this._stringText = nextStringText;
115
- var node = ReactMount.getNode(this._rootNodeID);
116
- DOMChildrenOperations.updateTextContent(node, nextStringText);
127
+ var commentNodes = this.getNativeNode();
128
+ DOMChildrenOperations.replaceDelimitedText(commentNodes[0], commentNodes[1], nextStringText);
117
129
  }
118
130
  }
119
131
  },
120
132
 
133
+ getNativeNode: function () {
134
+ var nativeNode = this._commentNodes;
135
+ if (nativeNode) {
136
+ return nativeNode;
137
+ }
138
+ if (!this._closingComment) {
139
+ var openingComment = ReactDOMComponentTree.getNodeFromInstance(this);
140
+ var node = openingComment.nextSibling;
141
+ while (true) {
142
+ !(node != null) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Missing closing comment for text component %s', this._domID) : invariant(false) : undefined;
143
+ if (node.nodeType === 8 && node.nodeValue === ' /react-text ') {
144
+ this._closingComment = node;
145
+ break;
146
+ }
147
+ node = node.nextSibling;
148
+ }
149
+ }
150
+ nativeNode = [this._nativeNode, this._closingComment];
151
+ this._commentNodes = nativeNode;
152
+ return nativeNode;
153
+ },
154
+
121
155
  unmountComponent: function () {
122
- ReactComponentBrowserEnvironment.unmountIDFromEnvironment(this._rootNodeID);
156
+ this._closingComment = null;
157
+ this._commentNodes = null;
158
+ ReactDOMComponentTree.uncacheNode(this);
123
159
  }
124
160
 
125
161
  });
126
162
 
163
+ ReactPerf.measureMethods(ReactDOMTextComponent.prototype, 'ReactDOMTextComponent', {
164
+ mountComponent: 'mountComponent',
165
+ receiveComponent: 'receiveComponent'
166
+ });
167
+
127
168
  module.exports = ReactDOMTextComponent;