react 0.13.2 → 0.14.0-alpha3
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.
- package/README.md +1 -1
- package/addons.js +7 -0
- package/addons/CSSTransitionGroup.js +1 -0
- package/addons/LinkedStateMixin.js +1 -0
- package/addons/Perf.js +1 -0
- package/addons/PureRenderMixin.js +1 -0
- package/addons/TestUtils.js +1 -0
- package/addons/TransitionGroup.js +1 -0
- package/addons/batchedUpdates.js +1 -0
- package/addons/cloneWithProps.js +1 -0
- package/addons/createFragment.js +1 -0
- package/addons/renderSubtreeIntoContainer.js +1 -0
- package/addons/shallowCompare.js +1 -0
- package/addons/update.js +1 -0
- package/dist/JSXTransformer.js +3355 -1685
- package/dist/react-with-addons.js +3320 -5133
- package/dist/react-with-addons.min.js +6 -7
- package/dist/react.js +2962 -4548
- package/dist/react.min.js +5 -5
- package/lib/AutoFocusMixin.js +4 -3
- package/lib/BeforeInputEventPlugin.js +30 -118
- package/lib/CSSCore.js +12 -23
- package/lib/CSSProperty.js +4 -3
- package/lib/CSSPropertyOperations.js +14 -30
- package/lib/CallbackQueue.js +7 -10
- package/lib/ChangeEventPlugin.js +24 -88
- package/lib/ClientReactRootIndex.js +2 -2
- package/lib/DOMChildrenOperations.js +13 -33
- package/lib/DOMProperty.js +41 -67
- package/lib/DOMPropertyOperations.js +30 -51
- package/lib/Danger.js +19 -62
- package/lib/DefaultEventPluginOrder.js +2 -12
- package/lib/EnterLeaveEventPlugin.js +11 -33
- package/lib/EventConstants.js +2 -2
- package/lib/EventListener.js +11 -13
- package/lib/EventPluginHub.js +44 -47
- package/lib/EventPluginRegistry.js +18 -74
- package/lib/EventPluginUtils.js +27 -38
- package/lib/EventPropagators.js +23 -26
- package/lib/ExecutionEnvironment.js +4 -8
- package/lib/FallbackCompositionState.js +3 -3
- package/lib/HTMLDOMPropertyConfig.js +7 -19
- package/lib/LinkedStateMixin.js +3 -6
- package/lib/LinkedValueUtils.js +34 -64
- package/lib/LocalEventTrapMixin.js +9 -16
- package/lib/Object.assign.js +1 -1
- package/lib/PooledClass.js +8 -11
- package/lib/React.js +9 -129
- package/lib/ReactBrowserComponentMixin.js +9 -2
- package/lib/ReactBrowserEventEmitter.js +26 -82
- package/lib/ReactCSSTransitionGroup.js +13 -24
- package/lib/ReactCSSTransitionGroupChild.js +18 -28
- package/lib/ReactChildReconciler.js +11 -19
- package/lib/ReactChildren.js +21 -28
- package/lib/ReactClass.js +81 -234
- package/lib/ReactComponent.js +17 -33
- package/lib/ReactComponentBrowserEnvironment.js +4 -8
- package/lib/ReactComponentEnvironment.js +6 -12
- package/lib/ReactComponentWithPureRenderMixin.js +4 -5
- package/lib/ReactCompositeComponent.js +87 -311
- package/lib/ReactContext.js +2 -44
- package/lib/ReactCurrentOwner.js +1 -3
- package/lib/ReactDOM.js +4 -2
- package/lib/ReactDOMButton.js +3 -4
- package/lib/ReactDOMClient.js +85 -0
- package/lib/ReactDOMComponent.js +182 -146
- package/lib/ReactDOMForm.js +3 -3
- package/lib/ReactDOMIDOperations.js +11 -22
- package/lib/ReactDOMIframe.js +3 -3
- package/lib/ReactDOMImg.js +3 -3
- package/lib/ReactDOMInput.js +22 -35
- package/lib/ReactDOMOption.js +67 -10
- package/lib/ReactDOMSelect.js +50 -28
- package/lib/ReactDOMSelection.js +5 -20
- package/lib/ReactDOMServer.js +24 -0
- package/lib/ReactDOMTextComponent.js +17 -18
- package/lib/ReactDOMTextarea.js +15 -27
- package/lib/ReactDefaultBatchingStrategy.js +9 -13
- package/lib/ReactDefaultInjection.js +31 -40
- package/lib/ReactDefaultPerf.js +36 -69
- package/lib/ReactDefaultPerfAnalysis.js +8 -14
- package/lib/ReactElement.js +24 -57
- package/lib/ReactElementValidator.js +38 -105
- package/lib/ReactEmptyComponent.js +7 -11
- package/lib/ReactErrorUtils.js +2 -2
- package/lib/ReactEventEmitterMixin.js +3 -12
- package/lib/ReactEventListener.js +16 -38
- package/lib/ReactFragment.js +23 -54
- package/lib/ReactInjection.js +1 -1
- package/lib/ReactInputSelection.js +11 -21
- package/lib/ReactInstanceHandles.js +27 -57
- package/lib/ReactInstanceMap.js +5 -5
- package/lib/ReactIsomorphic.js +70 -0
- package/lib/ReactLifeCycle.js +1 -1
- package/lib/ReactLink.js +2 -4
- package/lib/ReactMarkupChecksum.js +5 -10
- package/lib/ReactMount.js +137 -260
- package/lib/ReactMultiChild.js +19 -45
- package/lib/ReactMultiChildUpdateTypes.js +1 -1
- package/lib/ReactNativeComponent.js +7 -11
- package/lib/ReactOwner.js +7 -24
- package/lib/ReactPerf.js +8 -12
- package/lib/ReactPropTransferer.js +4 -4
- package/lib/ReactPropTypeLocationNames.js +2 -2
- package/lib/ReactPropTypeLocations.js +1 -1
- package/lib/ReactPropTypes.js +41 -61
- package/lib/ReactReconcileTransaction.js +9 -34
- package/lib/ReactReconciler.js +9 -19
- package/lib/ReactRef.js +5 -8
- package/lib/ReactRootIndex.js +2 -2
- package/lib/ReactServerRendering.js +7 -15
- package/lib/ReactServerRenderingTransaction.js +7 -32
- package/lib/ReactStateSetters.js +6 -6
- package/lib/ReactTestUtils.js +93 -165
- package/lib/ReactTransitionChildMapping.js +5 -7
- package/lib/ReactTransitionEvents.js +5 -5
- package/lib/ReactTransitionGroup.js +30 -52
- package/lib/ReactUpdateQueue.js +27 -90
- package/lib/ReactUpdates.js +27 -79
- package/lib/ReactWithAddons.js +7 -6
- package/lib/SVGDOMPropertyConfig.js +41 -4
- package/lib/SelectEventPlugin.js +28 -29
- package/lib/ServerReactRootIndex.js +2 -2
- package/lib/SimpleEventPlugin.js +136 -128
- package/lib/SyntheticClipboardEvent.js +3 -7
- package/lib/SyntheticCompositionEvent.js +3 -9
- package/lib/SyntheticDragEvent.js +1 -1
- package/lib/SyntheticEvent.js +8 -10
- package/lib/SyntheticFocusEvent.js +1 -1
- package/lib/SyntheticInputEvent.js +3 -9
- package/lib/SyntheticKeyboardEvent.js +4 -4
- package/lib/SyntheticMouseEvent.js +8 -14
- package/lib/SyntheticTouchEvent.js +1 -1
- package/lib/SyntheticUIEvent.js +3 -3
- package/lib/SyntheticWheelEvent.js +11 -15
- package/lib/Transaction.js +12 -24
- package/lib/ViewportMetrics.js +2 -2
- package/lib/accumulateInto.js +2 -5
- package/lib/adler32.js +2 -4
- package/lib/camelize.js +4 -2
- package/lib/camelizeStyleName.js +2 -2
- package/lib/cloneWithProps.js +5 -11
- package/lib/containsNode.js +29 -16
- package/lib/createArrayFromMixed.js +17 -16
- package/lib/createFullPageComponent.js +4 -11
- package/lib/createNodesFromMarkup.js +6 -8
- package/lib/dangerousStyleValue.js +2 -3
- package/lib/emptyFunction.js +10 -4
- package/lib/emptyObject.js +1 -1
- package/lib/escapeTextContentForBrowser.js +1 -1
- package/lib/findDOMNode.js +5 -24
- package/lib/flattenChildren.js +4 -10
- package/lib/focusNode.js +2 -3
- package/lib/forEachAccumulated.js +2 -2
- package/lib/getActiveElement.js +4 -2
- package/lib/getEventCharCode.js +1 -1
- package/lib/getEventKey.js +1 -1
- package/lib/getEventModifierState.js +1 -1
- package/lib/getEventTarget.js +1 -1
- package/lib/getIteratorFn.js +2 -4
- package/lib/getMarkupWrap.js +7 -5
- package/lib/getNodeForCharacterOffset.js +1 -1
- package/lib/getTextContentAccessor.js +2 -4
- package/lib/getUnboundedScrollPosition.js +1 -1
- package/lib/hyphenate.js +3 -1
- package/lib/hyphenateStyleName.js +2 -2
- package/lib/instantiateReactComponent.js +14 -38
- package/lib/invariant.js +8 -12
- package/lib/isEventSupported.js +7 -10
- package/lib/isNode.js +4 -6
- package/lib/isTextInputElement.js +2 -4
- package/lib/isTextNode.js +3 -1
- package/lib/joinClasses.js +2 -2
- package/lib/keyMirror.js +3 -6
- package/lib/keyOf.js +4 -3
- package/lib/mapObject.js +1 -1
- package/lib/memoizeStringOnly.js +2 -2
- package/lib/onlyChild.js +2 -5
- package/lib/performance.js +2 -5
- package/lib/performanceNow.js +3 -1
- package/lib/quoteAttributeValueForBrowser.js +1 -1
- package/lib/renderSubtreeIntoContainer.js +16 -0
- package/lib/setInnerHTML.js +11 -8
- package/lib/setTextContent.js +3 -3
- package/lib/shallowCompare.js +24 -0
- package/lib/shallowEqual.js +17 -11
- package/lib/shouldUpdateReactComponent.js +3 -64
- package/lib/toArray.js +8 -19
- package/lib/traverseAllChildren.js +22 -89
- package/lib/update.js +25 -85
- package/lib/validateDOMNesting.js +363 -0
- package/lib/warning.js +17 -15
- package/package.json +3 -3
- package/lib/MobileSafariClickEventPlugin.js +0 -56
- package/lib/ReactPutListenerQueue.js +0 -54
- package/lib/cx.js +0 -52
- package/lib/getReactRootElementInContainer.js +0 -33
package/lib/update.js
CHANGED
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
* @providesModule update
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
/* global hasOwnProperty:true */
|
|
13
13
|
|
|
14
14
|
'use strict';
|
|
15
15
|
|
|
16
16
|
var assign = require("./Object.assign");
|
|
17
17
|
var keyOf = require("./keyOf");
|
|
18
18
|
var invariant = require("./invariant");
|
|
19
|
-
var hasOwnProperty = {}.hasOwnProperty;
|
|
19
|
+
var hasOwnProperty = ({}).hasOwnProperty;
|
|
20
20
|
|
|
21
21
|
function shallowCopy(x) {
|
|
22
22
|
if (Array.isArray(x)) {
|
|
@@ -28,60 +28,32 @@ function shallowCopy(x) {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
var COMMAND_PUSH = keyOf({$push: null});
|
|
32
|
-
var COMMAND_UNSHIFT = keyOf({$unshift: null});
|
|
33
|
-
var COMMAND_SPLICE = keyOf({$splice: null});
|
|
34
|
-
var COMMAND_SET = keyOf({$set: null});
|
|
35
|
-
var COMMAND_MERGE = keyOf({$merge: null});
|
|
36
|
-
var COMMAND_APPLY = keyOf({$apply: null});
|
|
37
|
-
|
|
38
|
-
var ALL_COMMANDS_LIST = [
|
|
39
|
-
COMMAND_PUSH,
|
|
40
|
-
COMMAND_UNSHIFT,
|
|
41
|
-
COMMAND_SPLICE,
|
|
42
|
-
COMMAND_SET,
|
|
43
|
-
COMMAND_MERGE,
|
|
44
|
-
COMMAND_APPLY
|
|
45
|
-
];
|
|
31
|
+
var COMMAND_PUSH = keyOf({ $push: null });
|
|
32
|
+
var COMMAND_UNSHIFT = keyOf({ $unshift: null });
|
|
33
|
+
var COMMAND_SPLICE = keyOf({ $splice: null });
|
|
34
|
+
var COMMAND_SET = keyOf({ $set: null });
|
|
35
|
+
var COMMAND_MERGE = keyOf({ $merge: null });
|
|
36
|
+
var COMMAND_APPLY = keyOf({ $apply: null });
|
|
37
|
+
|
|
38
|
+
var ALL_COMMANDS_LIST = [COMMAND_PUSH, COMMAND_UNSHIFT, COMMAND_SPLICE, COMMAND_SET, COMMAND_MERGE, COMMAND_APPLY];
|
|
46
39
|
|
|
47
40
|
var ALL_COMMANDS_SET = {};
|
|
48
41
|
|
|
49
|
-
ALL_COMMANDS_LIST.forEach(function(command) {
|
|
42
|
+
ALL_COMMANDS_LIST.forEach(function (command) {
|
|
50
43
|
ALL_COMMANDS_SET[command] = true;
|
|
51
44
|
});
|
|
52
45
|
|
|
53
46
|
function invariantArrayCase(value, spec, command) {
|
|
54
|
-
(
|
|
55
|
-
Array.isArray(value),
|
|
56
|
-
'update(): expected target of %s to be an array; got %s.',
|
|
57
|
-
command,
|
|
58
|
-
value
|
|
59
|
-
) : invariant(Array.isArray(value)));
|
|
47
|
+
!Array.isArray(value) ? 'production' !== process.env.NODE_ENV ? invariant(false, 'update(): expected target of %s to be an array; got %s.', command, value) : invariant(false) : undefined;
|
|
60
48
|
var specValue = spec[command];
|
|
61
|
-
(
|
|
62
|
-
Array.isArray(specValue),
|
|
63
|
-
'update(): expected spec of %s to be an array; got %s. ' +
|
|
64
|
-
'Did you forget to wrap your parameter in an array?',
|
|
65
|
-
command,
|
|
66
|
-
specValue
|
|
67
|
-
) : invariant(Array.isArray(specValue)));
|
|
49
|
+
!Array.isArray(specValue) ? 'production' !== process.env.NODE_ENV ? invariant(false, 'update(): expected spec of %s to be an array; got %s. ' + 'Did you forget to wrap your parameter in an array?', command, specValue) : invariant(false) : undefined;
|
|
68
50
|
}
|
|
69
51
|
|
|
70
52
|
function update(value, spec) {
|
|
71
|
-
(
|
|
72
|
-
typeof spec === 'object',
|
|
73
|
-
'update(): You provided a key path to update() that did not contain one ' +
|
|
74
|
-
'of %s. Did you forget to include {%s: ...}?',
|
|
75
|
-
ALL_COMMANDS_LIST.join(', '),
|
|
76
|
-
COMMAND_SET
|
|
77
|
-
) : invariant(typeof spec === 'object'));
|
|
53
|
+
!(typeof spec === 'object') ? 'production' !== process.env.NODE_ENV ? invariant(false, 'update(): You provided a key path to update() that did not contain one ' + 'of %s. Did you forget to include {%s: ...}?', ALL_COMMANDS_LIST.join(', '), COMMAND_SET) : invariant(false) : undefined;
|
|
78
54
|
|
|
79
55
|
if (hasOwnProperty.call(spec, COMMAND_SET)) {
|
|
80
|
-
(
|
|
81
|
-
Object.keys(spec).length === 1,
|
|
82
|
-
'Cannot have more than one key in an object with %s',
|
|
83
|
-
COMMAND_SET
|
|
84
|
-
) : invariant(Object.keys(spec).length === 1));
|
|
56
|
+
!(Object.keys(spec).length === 1) ? 'production' !== process.env.NODE_ENV ? invariant(false, 'Cannot have more than one key in an object with %s', COMMAND_SET) : invariant(false) : undefined;
|
|
85
57
|
|
|
86
58
|
return spec[COMMAND_SET];
|
|
87
59
|
}
|
|
@@ -90,68 +62,36 @@ function update(value, spec) {
|
|
|
90
62
|
|
|
91
63
|
if (hasOwnProperty.call(spec, COMMAND_MERGE)) {
|
|
92
64
|
var mergeObj = spec[COMMAND_MERGE];
|
|
93
|
-
(
|
|
94
|
-
|
|
95
|
-
'update(): %s expects a spec of type \'object\'; got %s',
|
|
96
|
-
COMMAND_MERGE,
|
|
97
|
-
mergeObj
|
|
98
|
-
) : invariant(mergeObj && typeof mergeObj === 'object'));
|
|
99
|
-
("production" !== process.env.NODE_ENV ? invariant(
|
|
100
|
-
nextValue && typeof nextValue === 'object',
|
|
101
|
-
'update(): %s expects a target of type \'object\'; got %s',
|
|
102
|
-
COMMAND_MERGE,
|
|
103
|
-
nextValue
|
|
104
|
-
) : invariant(nextValue && typeof nextValue === 'object'));
|
|
65
|
+
!(mergeObj && typeof mergeObj === 'object') ? 'production' !== process.env.NODE_ENV ? invariant(false, 'update(): %s expects a spec of type \'object\'; got %s', COMMAND_MERGE, mergeObj) : invariant(false) : undefined;
|
|
66
|
+
!(nextValue && typeof nextValue === 'object') ? 'production' !== process.env.NODE_ENV ? invariant(false, 'update(): %s expects a target of type \'object\'; got %s', COMMAND_MERGE, nextValue) : invariant(false) : undefined;
|
|
105
67
|
assign(nextValue, spec[COMMAND_MERGE]);
|
|
106
68
|
}
|
|
107
69
|
|
|
108
70
|
if (hasOwnProperty.call(spec, COMMAND_PUSH)) {
|
|
109
71
|
invariantArrayCase(value, spec, COMMAND_PUSH);
|
|
110
|
-
spec[COMMAND_PUSH].forEach(function(item) {
|
|
72
|
+
spec[COMMAND_PUSH].forEach(function (item) {
|
|
111
73
|
nextValue.push(item);
|
|
112
74
|
});
|
|
113
75
|
}
|
|
114
76
|
|
|
115
77
|
if (hasOwnProperty.call(spec, COMMAND_UNSHIFT)) {
|
|
116
78
|
invariantArrayCase(value, spec, COMMAND_UNSHIFT);
|
|
117
|
-
spec[COMMAND_UNSHIFT].forEach(function(item) {
|
|
79
|
+
spec[COMMAND_UNSHIFT].forEach(function (item) {
|
|
118
80
|
nextValue.unshift(item);
|
|
119
81
|
});
|
|
120
82
|
}
|
|
121
83
|
|
|
122
84
|
if (hasOwnProperty.call(spec, COMMAND_SPLICE)) {
|
|
123
|
-
(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
COMMAND_SPLICE,
|
|
127
|
-
value
|
|
128
|
-
) : invariant(Array.isArray(value)));
|
|
129
|
-
("production" !== process.env.NODE_ENV ? invariant(
|
|
130
|
-
Array.isArray(spec[COMMAND_SPLICE]),
|
|
131
|
-
'update(): expected spec of %s to be an array of arrays; got %s. ' +
|
|
132
|
-
'Did you forget to wrap your parameters in an array?',
|
|
133
|
-
COMMAND_SPLICE,
|
|
134
|
-
spec[COMMAND_SPLICE]
|
|
135
|
-
) : invariant(Array.isArray(spec[COMMAND_SPLICE])));
|
|
136
|
-
spec[COMMAND_SPLICE].forEach(function(args) {
|
|
137
|
-
("production" !== process.env.NODE_ENV ? invariant(
|
|
138
|
-
Array.isArray(args),
|
|
139
|
-
'update(): expected spec of %s to be an array of arrays; got %s. ' +
|
|
140
|
-
'Did you forget to wrap your parameters in an array?',
|
|
141
|
-
COMMAND_SPLICE,
|
|
142
|
-
spec[COMMAND_SPLICE]
|
|
143
|
-
) : invariant(Array.isArray(args)));
|
|
85
|
+
!Array.isArray(value) ? 'production' !== process.env.NODE_ENV ? invariant(false, 'Expected %s target to be an array; got %s', COMMAND_SPLICE, value) : invariant(false) : undefined;
|
|
86
|
+
!Array.isArray(spec[COMMAND_SPLICE]) ? 'production' !== process.env.NODE_ENV ? invariant(false, 'update(): expected spec of %s to be an array of arrays; got %s. ' + 'Did you forget to wrap your parameters in an array?', COMMAND_SPLICE, spec[COMMAND_SPLICE]) : invariant(false) : undefined;
|
|
87
|
+
spec[COMMAND_SPLICE].forEach(function (args) {
|
|
88
|
+
!Array.isArray(args) ? 'production' !== process.env.NODE_ENV ? invariant(false, 'update(): expected spec of %s to be an array of arrays; got %s. ' + 'Did you forget to wrap your parameters in an array?', COMMAND_SPLICE, spec[COMMAND_SPLICE]) : invariant(false) : undefined;
|
|
144
89
|
nextValue.splice.apply(nextValue, args);
|
|
145
90
|
});
|
|
146
91
|
}
|
|
147
92
|
|
|
148
93
|
if (hasOwnProperty.call(spec, COMMAND_APPLY)) {
|
|
149
|
-
(
|
|
150
|
-
typeof spec[COMMAND_APPLY] === 'function',
|
|
151
|
-
'update(): expected spec of %s to be a function; got %s.',
|
|
152
|
-
COMMAND_APPLY,
|
|
153
|
-
spec[COMMAND_APPLY]
|
|
154
|
-
) : invariant(typeof spec[COMMAND_APPLY] === 'function'));
|
|
94
|
+
!(typeof spec[COMMAND_APPLY] === 'function') ? 'production' !== process.env.NODE_ENV ? invariant(false, 'update(): expected spec of %s to be a function; got %s.', COMMAND_APPLY, spec[COMMAND_APPLY]) : invariant(false) : undefined;
|
|
155
95
|
nextValue = spec[COMMAND_APPLY](nextValue);
|
|
156
96
|
}
|
|
157
97
|
|
|
@@ -164,4 +104,4 @@ function update(value, spec) {
|
|
|
164
104
|
return nextValue;
|
|
165
105
|
}
|
|
166
106
|
|
|
167
|
-
module.exports = update;
|
|
107
|
+
module.exports = update;
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2015, 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 validateDOMNesting
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
var assign = require("./Object.assign");
|
|
15
|
+
var emptyFunction = require("./emptyFunction");
|
|
16
|
+
var warning = require("./warning");
|
|
17
|
+
|
|
18
|
+
var validateDOMNesting = emptyFunction;
|
|
19
|
+
|
|
20
|
+
if ('production' !== process.env.NODE_ENV) {
|
|
21
|
+
// This validation code was written based on the HTML5 parsing spec:
|
|
22
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-scope
|
|
23
|
+
//
|
|
24
|
+
// Note: this does not catch all invalid nesting, nor does it try to (as it's
|
|
25
|
+
// not clear what practical benefit doing so provides); instead, we warn only
|
|
26
|
+
// for cases where the parser will give a parse tree differing from what React
|
|
27
|
+
// intended. For example, <b><div></div></b> is invalid but we don't warn
|
|
28
|
+
// because it still parses correctly; we do warn for other cases like nested
|
|
29
|
+
// <p> tags where the beginning of the second element implicitly closes the
|
|
30
|
+
// first, causing a confusing mess.
|
|
31
|
+
|
|
32
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#special
|
|
33
|
+
var specialTags = ['address', 'applet', 'area', 'article', 'aside', 'base', 'basefont', 'bgsound', 'blockquote', 'body', 'br', 'button', 'caption', 'center', 'col', 'colgroup', 'dd', 'details', 'dir', 'div', 'dl', 'dt', 'embed', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'iframe', 'img', 'input', 'isindex', 'li', 'link', 'listing', 'main', 'marquee', 'menu', 'menuitem', 'meta', 'nav', 'noembed', 'noframes', 'noscript', 'object', 'ol', 'p', 'param', 'plaintext', 'pre', 'script', 'section', 'select', 'source', 'style', 'summary', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'title', 'tr', 'track', 'ul', 'wbr', 'xmp'];
|
|
34
|
+
|
|
35
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-scope
|
|
36
|
+
var inScopeTags = ['applet', 'caption', 'html', 'table', 'td', 'th', 'marquee', 'object', 'template',
|
|
37
|
+
|
|
38
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#html-integration-point
|
|
39
|
+
// TODO: Distinguish by namespace here -- for <title>, including it here
|
|
40
|
+
// errs on the side of fewer warnings
|
|
41
|
+
'foreignObject', 'desc', 'title'];
|
|
42
|
+
|
|
43
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-button-scope
|
|
44
|
+
var buttonScopeTags = inScopeTags.concat(['button']);
|
|
45
|
+
|
|
46
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#generate-implied-end-tags
|
|
47
|
+
var impliedEndTags = ['dd', 'dt', 'li', 'option', 'optgroup', 'p', 'rp', 'rt'];
|
|
48
|
+
|
|
49
|
+
var emptyAncestorInfo = {
|
|
50
|
+
parentTag: null,
|
|
51
|
+
|
|
52
|
+
formTag: null,
|
|
53
|
+
aTagInScope: null,
|
|
54
|
+
buttonTagInScope: null,
|
|
55
|
+
nobrTagInScope: null,
|
|
56
|
+
pTagInButtonScope: null,
|
|
57
|
+
|
|
58
|
+
listItemTagAutoclosing: null,
|
|
59
|
+
dlItemTagAutoclosing: null
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
var updatedAncestorInfo = function (oldInfo, tag, instance) {
|
|
63
|
+
var ancestorInfo = assign({}, oldInfo || emptyAncestorInfo);
|
|
64
|
+
var info = { tag: tag, instance: instance };
|
|
65
|
+
|
|
66
|
+
if (inScopeTags.indexOf(tag) !== -1) {
|
|
67
|
+
ancestorInfo.aTagInScope = null;
|
|
68
|
+
ancestorInfo.buttonTagInScope = null;
|
|
69
|
+
ancestorInfo.nobrTagInScope = null;
|
|
70
|
+
}
|
|
71
|
+
if (buttonScopeTags.indexOf(tag) !== -1) {
|
|
72
|
+
ancestorInfo.pTagInButtonScope = null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// See rules for 'li', 'dd', 'dt' start tags in
|
|
76
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody
|
|
77
|
+
if (specialTags.indexOf(tag) !== -1 && tag !== 'address' && tag !== 'div' && tag !== 'p') {
|
|
78
|
+
ancestorInfo.listItemTagAutoclosing = null;
|
|
79
|
+
ancestorInfo.dlItemTagAutoclosing = null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
ancestorInfo.parentTag = info;
|
|
83
|
+
|
|
84
|
+
if (tag === 'form') {
|
|
85
|
+
ancestorInfo.formTag = info;
|
|
86
|
+
}
|
|
87
|
+
if (tag === 'a') {
|
|
88
|
+
ancestorInfo.aTagInScope = info;
|
|
89
|
+
}
|
|
90
|
+
if (tag === 'button') {
|
|
91
|
+
ancestorInfo.buttonTagInScope = info;
|
|
92
|
+
}
|
|
93
|
+
if (tag === 'nobr') {
|
|
94
|
+
ancestorInfo.nobrTagInScope = info;
|
|
95
|
+
}
|
|
96
|
+
if (tag === 'p') {
|
|
97
|
+
ancestorInfo.pTagInButtonScope = info;
|
|
98
|
+
}
|
|
99
|
+
if (tag === 'li') {
|
|
100
|
+
ancestorInfo.listItemTagAutoclosing = info;
|
|
101
|
+
}
|
|
102
|
+
if (tag === 'dd' || tag === 'dt') {
|
|
103
|
+
ancestorInfo.dlItemTagAutoclosing = info;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return ancestorInfo;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Returns whether
|
|
111
|
+
*/
|
|
112
|
+
var isTagValidWithParent = function (tag, parentTag) {
|
|
113
|
+
// First, let's check if we're in an unusual parsing mode...
|
|
114
|
+
switch (parentTag) {
|
|
115
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inselect
|
|
116
|
+
case 'select':
|
|
117
|
+
return tag === 'option' || tag === 'optgroup' || tag === '#text';
|
|
118
|
+
case 'optgroup':
|
|
119
|
+
return tag === 'option' || tag === '#text';
|
|
120
|
+
// Strictly speaking, seeing an <option> doesn't mean we're in a <select>
|
|
121
|
+
// but
|
|
122
|
+
case 'option':
|
|
123
|
+
return tag === '#text';
|
|
124
|
+
|
|
125
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intd
|
|
126
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-incaption
|
|
127
|
+
// No special behavior since these rules fall back to "in body" mode for
|
|
128
|
+
// all except special table nodes which cause bad parsing behavior anyway.
|
|
129
|
+
|
|
130
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intr
|
|
131
|
+
case 'tr':
|
|
132
|
+
return tag === 'th' || tag === 'td' || tag === 'style' || tag === 'script' || tag === 'template';
|
|
133
|
+
|
|
134
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intbody
|
|
135
|
+
case 'tbody':
|
|
136
|
+
case 'thead':
|
|
137
|
+
case 'tfoot':
|
|
138
|
+
return tag === 'tr' || tag === 'style' || tag === 'script' || tag === 'template';
|
|
139
|
+
|
|
140
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-incolgroup
|
|
141
|
+
case 'colgroup':
|
|
142
|
+
return tag === 'col' || tag === 'template';
|
|
143
|
+
|
|
144
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intable
|
|
145
|
+
case 'table':
|
|
146
|
+
return tag === 'caption' || tag === 'colgroup' || tag === 'tbody' || tag === 'tfoot' || tag === 'thead' || tag === 'style' || tag === 'script' || tag === 'template';
|
|
147
|
+
|
|
148
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inhead
|
|
149
|
+
case 'head':
|
|
150
|
+
return tag === 'base' || tag === 'basefont' || tag === 'bgsound' || tag === 'link' || tag === 'meta' || tag === 'title' || tag === 'noscript' || tag === 'noframes' || tag === 'style' || tag === 'script' || tag === 'template';
|
|
151
|
+
|
|
152
|
+
// https://html.spec.whatwg.org/multipage/semantics.html#the-html-element
|
|
153
|
+
case 'html':
|
|
154
|
+
return tag === 'head' || tag === 'body';
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Probably in the "in body" parsing mode, so we outlaw only tag combos
|
|
158
|
+
// where the parsing rules cause implicit opens or closes to be added.
|
|
159
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody
|
|
160
|
+
switch (tag) {
|
|
161
|
+
case 'h1':
|
|
162
|
+
case 'h2':
|
|
163
|
+
case 'h3':
|
|
164
|
+
case 'h4':
|
|
165
|
+
case 'h5':
|
|
166
|
+
case 'h6':
|
|
167
|
+
return parentTag !== 'h1' && parentTag !== 'h2' && parentTag !== 'h3' && parentTag !== 'h4' && parentTag !== 'h5' && parentTag !== 'h6';
|
|
168
|
+
|
|
169
|
+
case 'rp':
|
|
170
|
+
case 'rt':
|
|
171
|
+
return impliedEndTags.indexOf(parentTag) === -1;
|
|
172
|
+
|
|
173
|
+
case 'caption':
|
|
174
|
+
case 'col':
|
|
175
|
+
case 'colgroup':
|
|
176
|
+
case 'frame':
|
|
177
|
+
case 'head':
|
|
178
|
+
case 'tbody':
|
|
179
|
+
case 'td':
|
|
180
|
+
case 'tfoot':
|
|
181
|
+
case 'th':
|
|
182
|
+
case 'thead':
|
|
183
|
+
case 'tr':
|
|
184
|
+
// These tags are only valid with a few parents that have special child
|
|
185
|
+
// parsing rules -- if we're down here, then none of those matched and
|
|
186
|
+
// so we allow it only if we don't know what the parent is, as all other
|
|
187
|
+
// cases are invalid.
|
|
188
|
+
return parentTag == null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return true;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Returns whether
|
|
196
|
+
*/
|
|
197
|
+
var findInvalidAncestorForTag = function (tag, ancestorInfo) {
|
|
198
|
+
switch (tag) {
|
|
199
|
+
case 'address':
|
|
200
|
+
case 'article':
|
|
201
|
+
case 'aside':
|
|
202
|
+
case 'blockquote':
|
|
203
|
+
case 'center':
|
|
204
|
+
case 'details':
|
|
205
|
+
case 'dialog':
|
|
206
|
+
case 'dir':
|
|
207
|
+
case 'div':
|
|
208
|
+
case 'dl':
|
|
209
|
+
case 'fieldset':
|
|
210
|
+
case 'figcaption':
|
|
211
|
+
case 'figure':
|
|
212
|
+
case 'footer':
|
|
213
|
+
case 'header':
|
|
214
|
+
case 'hgroup':
|
|
215
|
+
case 'main':
|
|
216
|
+
case 'menu':
|
|
217
|
+
case 'nav':
|
|
218
|
+
case 'ol':
|
|
219
|
+
case 'p':
|
|
220
|
+
case 'section':
|
|
221
|
+
case 'summary':
|
|
222
|
+
case 'ul':
|
|
223
|
+
|
|
224
|
+
case 'pre':
|
|
225
|
+
case 'listing':
|
|
226
|
+
|
|
227
|
+
case 'table':
|
|
228
|
+
|
|
229
|
+
case 'hr':
|
|
230
|
+
|
|
231
|
+
case 'xmp':
|
|
232
|
+
|
|
233
|
+
case 'h1':
|
|
234
|
+
case 'h2':
|
|
235
|
+
case 'h3':
|
|
236
|
+
case 'h4':
|
|
237
|
+
case 'h5':
|
|
238
|
+
case 'h6':
|
|
239
|
+
return ancestorInfo.pTagInButtonScope;
|
|
240
|
+
|
|
241
|
+
case 'form':
|
|
242
|
+
return ancestorInfo.formTag || ancestorInfo.pTagInButtonScope;
|
|
243
|
+
|
|
244
|
+
case 'li':
|
|
245
|
+
return ancestorInfo.listItemTagAutoclosing;
|
|
246
|
+
|
|
247
|
+
case 'dd':
|
|
248
|
+
case 'dt':
|
|
249
|
+
return ancestorInfo.dlItemTagAutoclosing;
|
|
250
|
+
|
|
251
|
+
case 'button':
|
|
252
|
+
return ancestorInfo.buttonTagInScope;
|
|
253
|
+
|
|
254
|
+
case 'a':
|
|
255
|
+
// Spec says something about storing a list of markers, but it sounds
|
|
256
|
+
// equivalent to this check.
|
|
257
|
+
return ancestorInfo.aTagInScope;
|
|
258
|
+
|
|
259
|
+
case 'nobr':
|
|
260
|
+
return ancestorInfo.nobrTagInScope;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return null;
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Given a ReactCompositeComponent instance, return a list of its recursive
|
|
268
|
+
* owners, starting at the root and ending with the instance itself.
|
|
269
|
+
*/
|
|
270
|
+
var findOwnerStack = function (instance) {
|
|
271
|
+
if (!instance) {
|
|
272
|
+
return [];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
var stack = [];
|
|
276
|
+
/*eslint-disable space-after-keywords */
|
|
277
|
+
do {
|
|
278
|
+
/*eslint-enable space-after-keywords */
|
|
279
|
+
stack.push(instance);
|
|
280
|
+
} while (instance = instance._currentElement._owner);
|
|
281
|
+
stack.reverse();
|
|
282
|
+
return stack;
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
var didWarn = {};
|
|
286
|
+
|
|
287
|
+
validateDOMNesting = function (childTag, childInstance, ancestorInfo) {
|
|
288
|
+
ancestorInfo = ancestorInfo || emptyAncestorInfo;
|
|
289
|
+
var parentInfo = ancestorInfo.parentTag;
|
|
290
|
+
var parentTag = parentInfo && parentInfo.tag;
|
|
291
|
+
|
|
292
|
+
var invalidParent = isTagValidWithParent(childTag, parentTag) ? null : parentInfo;
|
|
293
|
+
var invalidAncestor = invalidParent ? null : findInvalidAncestorForTag(childTag, ancestorInfo);
|
|
294
|
+
var problematic = invalidParent || invalidAncestor;
|
|
295
|
+
|
|
296
|
+
if (problematic) {
|
|
297
|
+
var ancestorTag = problematic.tag;
|
|
298
|
+
var ancestorInstance = problematic.instance;
|
|
299
|
+
|
|
300
|
+
var childOwner = childInstance && childInstance._currentElement._owner;
|
|
301
|
+
var ancestorOwner = ancestorInstance && ancestorInstance._currentElement._owner;
|
|
302
|
+
|
|
303
|
+
var childOwners = findOwnerStack(childOwner);
|
|
304
|
+
var ancestorOwners = findOwnerStack(ancestorOwner);
|
|
305
|
+
|
|
306
|
+
var minStackLen = Math.min(childOwners.length, ancestorOwners.length);
|
|
307
|
+
var i;
|
|
308
|
+
|
|
309
|
+
var deepestCommon = -1;
|
|
310
|
+
for (i = 0; i < minStackLen; i++) {
|
|
311
|
+
if (childOwners[i] === ancestorOwners[i]) {
|
|
312
|
+
deepestCommon = i;
|
|
313
|
+
} else {
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
var UNKNOWN = '(unknown)';
|
|
319
|
+
var childOwnerNames = childOwners.slice(deepestCommon + 1).map(function (inst) {
|
|
320
|
+
return inst.getName() || UNKNOWN;
|
|
321
|
+
});
|
|
322
|
+
var ancestorOwnerNames = ancestorOwners.slice(deepestCommon + 1).map(function (inst) {
|
|
323
|
+
return inst.getName() || UNKNOWN;
|
|
324
|
+
});
|
|
325
|
+
var ownerInfo = [].concat(
|
|
326
|
+
// If the parent and child instances have a common owner ancestor, start
|
|
327
|
+
// with that -- otherwise we just start with the parent's owners.
|
|
328
|
+
deepestCommon !== -1 ? childOwners[deepestCommon].getName() || UNKNOWN : [], ancestorOwnerNames, ancestorTag,
|
|
329
|
+
// If we're warning about an invalid (non-parent) ancestry, add '...'
|
|
330
|
+
invalidAncestor ? ['...'] : [], childOwnerNames, childTag).join(' > ');
|
|
331
|
+
|
|
332
|
+
var warnKey = !!invalidParent + '|' + childTag + '|' + ancestorTag + '|' + ownerInfo;
|
|
333
|
+
if (didWarn[warnKey]) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
didWarn[warnKey] = true;
|
|
337
|
+
|
|
338
|
+
if (invalidParent) {
|
|
339
|
+
var info = '';
|
|
340
|
+
if (ancestorTag === 'table' && childTag === 'tr') {
|
|
341
|
+
info += ' Add a <tbody> to your code to match the DOM tree generated by ' + 'the browser.';
|
|
342
|
+
}
|
|
343
|
+
'production' !== process.env.NODE_ENV ? warning(false, 'validateDOMNesting(...): <%s> cannot appear as a child of <%s>. ' + 'See %s.%s', childTag, ancestorTag, ownerInfo, info) : undefined;
|
|
344
|
+
} else {
|
|
345
|
+
'production' !== process.env.NODE_ENV ? warning(false, 'validateDOMNesting(...): <%s> cannot appear as a descendant of ' + '<%s>. See %s.', childTag, ancestorTag, ownerInfo) : undefined;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
validateDOMNesting.ancestorInfoContextKey = '__validateDOMNesting_ancestorInfo$' + Math.random().toString(36).slice(2);
|
|
351
|
+
|
|
352
|
+
validateDOMNesting.updatedAncestorInfo = updatedAncestorInfo;
|
|
353
|
+
|
|
354
|
+
// For testing
|
|
355
|
+
validateDOMNesting.isTagValidInContext = function (tag, ancestorInfo) {
|
|
356
|
+
ancestorInfo = ancestorInfo || emptyAncestorInfo;
|
|
357
|
+
var parentInfo = ancestorInfo.parentTag;
|
|
358
|
+
var parentTag = parentInfo && parentInfo.tag;
|
|
359
|
+
return isTagValidWithParent(tag, parentTag) && !findInvalidAncestorForTag(tag, ancestorInfo);
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
module.exports = validateDOMNesting;
|