react 0.14.0-alpha1 → 0.14.0-beta2
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 +5 -2
- package/addons.js +5 -2
- package/dist/JSXTransformer.js +634 -274
- package/dist/react-with-addons.js +5376 -4800
- package/dist/react-with-addons.min.js +6 -6
- package/dist/react.js +5175 -4626
- package/dist/react.min.js +6 -5
- package/lib/{AutoFocusMixin.js → AutoFocusUtils.js} +15 -5
- package/lib/BeforeInputEventPlugin.js +13 -13
- package/lib/CSSProperty.js +3 -0
- package/lib/CSSPropertyOperations.js +13 -13
- package/lib/CallbackQueue.js +4 -4
- package/lib/ChangeEventPlugin.js +16 -14
- package/lib/DOMChildrenOperations.js +10 -6
- package/lib/DOMProperty.js +82 -119
- package/lib/DOMPropertyOperations.js +78 -33
- package/lib/Danger.js +14 -16
- package/lib/DefaultEventPluginOrder.js +2 -2
- package/lib/EnterLeaveEventPlugin.js +8 -8
- package/lib/EventConstants.js +23 -1
- package/lib/EventPluginHub.js +13 -13
- package/lib/EventPluginRegistry.js +8 -8
- package/lib/EventPluginUtils.js +17 -17
- package/lib/EventPropagators.js +7 -7
- package/lib/FallbackCompositionState.js +3 -3
- package/lib/HTMLDOMPropertyConfig.js +14 -5
- package/lib/LinkedStateMixin.js +2 -2
- package/lib/LinkedValueUtils.js +50 -38
- package/lib/MetaMatchers.js +118 -0
- package/lib/OrderedMap.js +453 -0
- package/lib/PooledClass.js +14 -2
- package/lib/React.js +9 -111
- package/lib/ReactBrowserComponentMixin.js +4 -4
- package/lib/ReactBrowserEventEmitter.js +30 -7
- package/lib/ReactCSSTransitionGroup.js +16 -5
- package/lib/ReactCSSTransitionGroupChild.js +20 -11
- package/lib/ReactChildReconciler.js +25 -18
- package/lib/ReactChildren.js +24 -22
- package/lib/ReactClass.js +68 -86
- package/lib/ReactComponent.js +22 -17
- package/lib/ReactComponentBrowserEnvironment.js +2 -4
- package/lib/ReactComponentEnvironment.js +2 -2
- package/lib/ReactComponentWithPureRenderMixin.js +3 -3
- package/lib/ReactCompositeComponent.js +80 -111
- package/lib/ReactDOM.js +72 -158
- package/lib/ReactDOMButton.js +15 -26
- package/lib/ReactDOMComponent.js +384 -62
- package/lib/ReactDOMFactories.js +177 -0
- package/lib/ReactDOMIDOperations.js +23 -25
- package/lib/ReactDOMInput.js +83 -99
- package/lib/ReactDOMOption.js +38 -42
- package/lib/ReactDOMSelect.js +88 -98
- package/lib/ReactDOMSelection.js +3 -3
- package/lib/ReactDOMServer.js +24 -0
- package/lib/ReactDOMTextComponent.js +13 -13
- package/lib/ReactDOMTextarea.js +48 -61
- package/lib/ReactDefaultBatchingStrategy.js +4 -4
- package/lib/ReactDefaultInjection.js +34 -71
- package/lib/ReactDefaultPerf.js +7 -7
- package/lib/ReactDefaultPerfAnalysis.js +6 -9
- package/lib/ReactElement.js +35 -92
- package/lib/ReactElementValidator.js +53 -130
- package/lib/ReactEmptyComponent.js +4 -4
- package/lib/ReactErrorUtils.js +1 -1
- package/lib/ReactEventEmitterMixin.js +3 -4
- package/lib/ReactEventListener.js +57 -12
- package/lib/ReactFragment.js +22 -17
- package/lib/ReactInjection.js +11 -11
- package/lib/ReactInputSelection.js +8 -7
- package/lib/ReactInstanceHandles.js +12 -12
- package/lib/ReactIsomorphic.js +70 -0
- package/lib/ReactLink.js +1 -1
- package/lib/ReactMarkupChecksum.js +6 -2
- package/lib/ReactMount.js +90 -89
- package/lib/ReactMultiChild.js +83 -22
- package/lib/ReactMultiChildUpdateTypes.js +2 -1
- package/lib/ReactNativeComponent.js +3 -8
- package/lib/ReactNoopUpdateQueue.js +118 -0
- package/lib/ReactOwner.js +3 -3
- package/lib/ReactPerf.js +2 -2
- package/lib/ReactPropTransferer.js +3 -3
- package/lib/ReactPropTypeLocationNames.js +1 -1
- package/lib/ReactPropTypeLocations.js +1 -1
- package/lib/ReactPropTypes.js +72 -33
- package/lib/ReactReconcileTransaction.js +8 -8
- package/lib/ReactReconciler.js +18 -20
- package/lib/ReactRef.js +1 -1
- package/lib/ReactServerBatchingStrategy.js +23 -0
- package/lib/ReactServerRendering.js +22 -9
- package/lib/ReactServerRenderingTransaction.js +7 -7
- package/lib/ReactTestUtils.js +80 -58
- package/lib/ReactTransitionChildMapping.js +2 -2
- package/lib/ReactTransitionEvents.js +1 -1
- package/lib/ReactTransitionGroup.js +5 -6
- package/lib/ReactUpdateQueue.js +61 -36
- package/lib/ReactUpdates.js +14 -17
- package/lib/ReactWithAddons.js +14 -16
- package/lib/ResponderEventPlugin.js +514 -0
- package/lib/ResponderSyntheticEvent.js +40 -0
- package/lib/ResponderTouchHistoryStore.js +180 -0
- package/lib/SVGDOMPropertyConfig.js +1 -3
- package/lib/SelectEventPlugin.js +14 -15
- package/lib/SimpleEventPlugin.js +205 -29
- package/lib/SyntheticClipboardEvent.js +3 -3
- package/lib/SyntheticCompositionEvent.js +3 -3
- package/lib/SyntheticDragEvent.js +3 -3
- package/lib/SyntheticEvent.js +9 -8
- package/lib/SyntheticFocusEvent.js +3 -3
- package/lib/SyntheticInputEvent.js +3 -3
- package/lib/SyntheticKeyboardEvent.js +6 -6
- package/lib/SyntheticMouseEvent.js +5 -5
- package/lib/SyntheticTouchEvent.js +4 -4
- package/lib/SyntheticUIEvent.js +4 -4
- package/lib/SyntheticWheelEvent.js +3 -3
- package/lib/TapEventPlugin.js +119 -0
- package/lib/Transaction.js +16 -10
- package/lib/accumulate.js +44 -0
- package/lib/accumulateInto.js +2 -2
- package/lib/adler32.js +19 -9
- package/lib/cloneWithProps.js +12 -7
- package/lib/createHierarchyRenderer.js +85 -0
- package/lib/dangerousStyleValue.js +1 -1
- package/lib/deprecated.js +47 -0
- package/lib/findDOMNode.js +11 -12
- package/lib/flattenChildren.js +4 -4
- package/lib/forEachAccumulated.js +1 -1
- package/lib/getEventCharCode.js +1 -1
- package/lib/getEventKey.js +1 -1
- package/lib/getEventModifierState.js +0 -1
- package/lib/getTestDocument.js +28 -0
- package/lib/getTextContentAccessor.js +1 -1
- package/lib/instantiateReactComponent.js +24 -20
- package/lib/isEventSupported.js +1 -1
- package/lib/isTextInputElement.js +2 -1
- package/lib/joinClasses.js +1 -1
- package/lib/onlyChild.js +3 -3
- package/lib/quoteAttributeValueForBrowser.js +1 -1
- package/lib/reactComponentExpect.js +210 -0
- package/lib/renderSubtreeIntoContainer.js +1 -1
- package/lib/setInnerHTML.js +2 -2
- package/lib/setTextContent.js +3 -3
- package/lib/shallowCompare.js +1 -1
- package/lib/sliceChildren.js +51 -0
- package/lib/traverseAllChildren.js +24 -27
- package/lib/update.js +13 -13
- package/lib/validateDOMNesting.js +199 -100
- package/lib/webcomponents.js +6379 -0
- package/package.json +4 -6
- package/react.js +53 -1
- package/addons/CSSTransitionGroup.js +0 -1
- package/addons/LinkedStateMixin.js +0 -1
- package/addons/Perf.js +0 -1
- package/addons/PureRenderMixin.js +0 -1
- package/addons/TestUtils.js +0 -1
- package/addons/TransitionGroup.js +0 -1
- package/addons/batchedUpdates.js +0 -1
- package/addons/cloneWithProps.js +0 -1
- package/addons/createFragment.js +0 -1
- package/addons/renderSubtreeIntoContainer.js +0 -1
- package/addons/shallowCompare.js +0 -1
- package/addons/update.js +0 -1
- package/lib/CSSCore.js +0 -97
- package/lib/EventListener.js +0 -84
- package/lib/ExecutionEnvironment.js +0 -38
- package/lib/LocalEventTrapMixin.js +0 -46
- package/lib/ReactContext.js +0 -32
- package/lib/ReactDOMForm.js +0 -47
- package/lib/ReactDOMIframe.js +0 -43
- package/lib/ReactDOMImg.js +0 -44
- package/lib/ReactLifeCycle.js +0 -35
- package/lib/camelize.js +0 -32
- package/lib/camelizeStyleName.js +0 -40
- package/lib/containsNode.js +0 -55
- package/lib/createArrayFromMixed.js +0 -85
- package/lib/createFullPageComponent.js +0 -51
- package/lib/createNodesFromMarkup.js +0 -84
- package/lib/emptyFunction.js +0 -38
- package/lib/emptyObject.js +0 -20
- package/lib/focusNode.js +0 -26
- package/lib/getActiveElement.js +0 -29
- package/lib/getMarkupWrap.js +0 -115
- package/lib/getUnboundedScrollPosition.js +0 -38
- package/lib/hyphenate.js +0 -33
- package/lib/hyphenateStyleName.js +0 -39
- package/lib/invariant.js +0 -49
- package/lib/isNode.js +0 -23
- package/lib/isTextNode.js +0 -25
- package/lib/keyMirror.js +0 -48
- package/lib/keyOf.js +0 -35
- package/lib/mapObject.js +0 -51
- package/lib/performance.js +0 -23
- package/lib/performanceNow.js +0 -28
- package/lib/shallowEqual.js +0 -48
- package/lib/toArray.js +0 -57
- package/lib/warning.js +0 -61
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
|
|
12
12
|
'use strict';
|
|
13
13
|
|
|
14
|
-
var ReactElement = require(
|
|
15
|
-
var ReactFragment = require(
|
|
16
|
-
var ReactInstanceHandles = require(
|
|
14
|
+
var ReactElement = require('./ReactElement');
|
|
15
|
+
var ReactFragment = require('./ReactFragment');
|
|
16
|
+
var ReactInstanceHandles = require('./ReactInstanceHandles');
|
|
17
17
|
|
|
18
|
-
var getIteratorFn = require(
|
|
19
|
-
var invariant = require(
|
|
20
|
-
var warning = require(
|
|
18
|
+
var getIteratorFn = require('./getIteratorFn');
|
|
19
|
+
var invariant = require('fbjs/lib/invariant');
|
|
20
|
+
var warning = require('fbjs/lib/warning');
|
|
21
21
|
|
|
22
22
|
var SEPARATOR = ReactInstanceHandles.SEPARATOR;
|
|
23
23
|
var SUBSEPARATOR = ':';
|
|
@@ -60,7 +60,7 @@ function getComponentKey(component, index) {
|
|
|
60
60
|
/**
|
|
61
61
|
* Escape a component key so that it is safe to use in a reactid.
|
|
62
62
|
*
|
|
63
|
-
* @param {*}
|
|
63
|
+
* @param {*} text Component key to be escaped.
|
|
64
64
|
* @return {string} An escaped string.
|
|
65
65
|
*/
|
|
66
66
|
function escapeUserProvidedKey(text) {
|
|
@@ -81,13 +81,12 @@ function wrapUserProvidedKey(key) {
|
|
|
81
81
|
/**
|
|
82
82
|
* @param {?*} children Children tree container.
|
|
83
83
|
* @param {!string} nameSoFar Name of the key path so far.
|
|
84
|
-
* @param {!number} indexSoFar Number of children encountered until this point.
|
|
85
84
|
* @param {!function} callback Callback to invoke with each child found.
|
|
86
85
|
* @param {?*} traverseContext Used to pass information throughout the traversal
|
|
87
86
|
* process.
|
|
88
87
|
* @return {!number} The number of children in this subtree.
|
|
89
88
|
*/
|
|
90
|
-
function traverseAllChildrenImpl(children, nameSoFar,
|
|
89
|
+
function traverseAllChildrenImpl(children, nameSoFar, callback, traverseContext) {
|
|
91
90
|
var type = typeof children;
|
|
92
91
|
|
|
93
92
|
if (type === 'undefined' || type === 'boolean') {
|
|
@@ -99,19 +98,20 @@ function traverseAllChildrenImpl(children, nameSoFar, indexSoFar, callback, trav
|
|
|
99
98
|
callback(traverseContext, children,
|
|
100
99
|
// If it's the only child, treat the name as if it was wrapped in an array
|
|
101
100
|
// so that it's consistent if the number of children grows.
|
|
102
|
-
nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar
|
|
101
|
+
nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar);
|
|
103
102
|
return 1;
|
|
104
103
|
}
|
|
105
104
|
|
|
106
|
-
var child
|
|
105
|
+
var child;
|
|
106
|
+
var nextName;
|
|
107
107
|
var subtreeCount = 0; // Count of children found in the current subtree.
|
|
108
|
+
var nextNamePrefix = nameSoFar !== '' ? nameSoFar + SUBSEPARATOR : SEPARATOR;
|
|
108
109
|
|
|
109
110
|
if (Array.isArray(children)) {
|
|
110
111
|
for (var i = 0; i < children.length; i++) {
|
|
111
112
|
child = children[i];
|
|
112
|
-
nextName =
|
|
113
|
-
|
|
114
|
-
subtreeCount += traverseAllChildrenImpl(child, nextName, nextIndex, callback, traverseContext);
|
|
113
|
+
nextName = nextNamePrefix + getComponentKey(child, i);
|
|
114
|
+
subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
|
|
115
115
|
}
|
|
116
116
|
} else {
|
|
117
117
|
var iteratorFn = getIteratorFn(children);
|
|
@@ -122,13 +122,12 @@ function traverseAllChildrenImpl(children, nameSoFar, indexSoFar, callback, trav
|
|
|
122
122
|
var ii = 0;
|
|
123
123
|
while (!(step = iterator.next()).done) {
|
|
124
124
|
child = step.value;
|
|
125
|
-
nextName =
|
|
126
|
-
|
|
127
|
-
subtreeCount += traverseAllChildrenImpl(child, nextName, nextIndex, callback, traverseContext);
|
|
125
|
+
nextName = nextNamePrefix + getComponentKey(child, ii++);
|
|
126
|
+
subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
|
|
128
127
|
}
|
|
129
128
|
} else {
|
|
130
|
-
if (
|
|
131
|
-
|
|
129
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
130
|
+
process.env.NODE_ENV !== 'production' ? warning(didWarnAboutMaps, 'Using Maps as children is not yet fully supported. It is an ' + 'experimental feature that might be removed. Convert it to a ' + 'sequence / iterable of keyed ReactElements instead.') : undefined;
|
|
132
131
|
didWarnAboutMaps = true;
|
|
133
132
|
}
|
|
134
133
|
// Iterator will provide entry [k,v] tuples rather than values.
|
|
@@ -136,21 +135,19 @@ function traverseAllChildrenImpl(children, nameSoFar, indexSoFar, callback, trav
|
|
|
136
135
|
var entry = step.value;
|
|
137
136
|
if (entry) {
|
|
138
137
|
child = entry[1];
|
|
139
|
-
nextName =
|
|
140
|
-
|
|
141
|
-
subtreeCount += traverseAllChildrenImpl(child, nextName, nextIndex, callback, traverseContext);
|
|
138
|
+
nextName = nextNamePrefix + wrapUserProvidedKey(entry[0]) + SUBSEPARATOR + getComponentKey(child, 0);
|
|
139
|
+
subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
|
|
142
140
|
}
|
|
143
141
|
}
|
|
144
142
|
}
|
|
145
143
|
} else if (type === 'object') {
|
|
146
|
-
|
|
144
|
+
!(children.nodeType !== 1) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'traverseAllChildren(...): Encountered an invalid child; DOM ' + 'elements are not valid children of React components.') : invariant(false) : undefined;
|
|
147
145
|
var fragment = ReactFragment.extract(children);
|
|
148
146
|
for (var key in fragment) {
|
|
149
147
|
if (fragment.hasOwnProperty(key)) {
|
|
150
148
|
child = fragment[key];
|
|
151
|
-
nextName =
|
|
152
|
-
|
|
153
|
-
subtreeCount += traverseAllChildrenImpl(child, nextName, nextIndex, callback, traverseContext);
|
|
149
|
+
nextName = nextNamePrefix + wrapUserProvidedKey(key) + SUBSEPARATOR + getComponentKey(child, 0);
|
|
150
|
+
subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
|
|
154
151
|
}
|
|
155
152
|
}
|
|
156
153
|
}
|
|
@@ -180,7 +177,7 @@ function traverseAllChildren(children, callback, traverseContext) {
|
|
|
180
177
|
return 0;
|
|
181
178
|
}
|
|
182
179
|
|
|
183
|
-
return traverseAllChildrenImpl(children, '',
|
|
180
|
+
return traverseAllChildrenImpl(children, '', callback, traverseContext);
|
|
184
181
|
}
|
|
185
182
|
|
|
186
183
|
module.exports = traverseAllChildren;
|
package/lib/update.js
CHANGED
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
|
|
14
14
|
'use strict';
|
|
15
15
|
|
|
16
|
-
var assign = require(
|
|
17
|
-
var keyOf = require(
|
|
18
|
-
var invariant = require(
|
|
16
|
+
var assign = require('./Object.assign');
|
|
17
|
+
var keyOf = require('fbjs/lib/keyOf');
|
|
18
|
+
var invariant = require('fbjs/lib/invariant');
|
|
19
19
|
var hasOwnProperty = ({}).hasOwnProperty;
|
|
20
20
|
|
|
21
21
|
function shallowCopy(x) {
|
|
@@ -44,16 +44,16 @@ ALL_COMMANDS_LIST.forEach(function (command) {
|
|
|
44
44
|
});
|
|
45
45
|
|
|
46
46
|
function invariantArrayCase(value, spec, command) {
|
|
47
|
-
|
|
47
|
+
!Array.isArray(value) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'update(): expected target of %s to be an array; got %s.', command, value) : invariant(false) : undefined;
|
|
48
48
|
var specValue = spec[command];
|
|
49
|
-
|
|
49
|
+
!Array.isArray(specValue) ? process.env.NODE_ENV !== 'production' ? 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;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
function update(value, spec) {
|
|
53
|
-
'
|
|
53
|
+
!(typeof spec === 'object') ? process.env.NODE_ENV !== 'production' ? 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;
|
|
54
54
|
|
|
55
55
|
if (hasOwnProperty.call(spec, COMMAND_SET)) {
|
|
56
|
-
|
|
56
|
+
!(Object.keys(spec).length === 1) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Cannot have more than one key in an object with %s', COMMAND_SET) : invariant(false) : undefined;
|
|
57
57
|
|
|
58
58
|
return spec[COMMAND_SET];
|
|
59
59
|
}
|
|
@@ -62,8 +62,8 @@ function update(value, spec) {
|
|
|
62
62
|
|
|
63
63
|
if (hasOwnProperty.call(spec, COMMAND_MERGE)) {
|
|
64
64
|
var mergeObj = spec[COMMAND_MERGE];
|
|
65
|
-
'
|
|
66
|
-
'
|
|
65
|
+
!(mergeObj && typeof mergeObj === 'object') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'update(): %s expects a spec of type \'object\'; got %s', COMMAND_MERGE, mergeObj) : invariant(false) : undefined;
|
|
66
|
+
!(nextValue && typeof nextValue === 'object') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'update(): %s expects a target of type \'object\'; got %s', COMMAND_MERGE, nextValue) : invariant(false) : undefined;
|
|
67
67
|
assign(nextValue, spec[COMMAND_MERGE]);
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -82,16 +82,16 @@ function update(value, spec) {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
if (hasOwnProperty.call(spec, COMMAND_SPLICE)) {
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
!Array.isArray(value) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Expected %s target to be an array; got %s', COMMAND_SPLICE, value) : invariant(false) : undefined;
|
|
86
|
+
!Array.isArray(spec[COMMAND_SPLICE]) ? process.env.NODE_ENV !== 'production' ? 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
87
|
spec[COMMAND_SPLICE].forEach(function (args) {
|
|
88
|
-
|
|
88
|
+
!Array.isArray(args) ? process.env.NODE_ENV !== 'production' ? 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;
|
|
89
89
|
nextValue.splice.apply(nextValue, args);
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
if (hasOwnProperty.call(spec, COMMAND_APPLY)) {
|
|
94
|
-
'
|
|
94
|
+
!(typeof spec[COMMAND_APPLY] === 'function') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'update(): expected spec of %s to be a function; got %s.', COMMAND_APPLY, spec[COMMAND_APPLY]) : invariant(false) : undefined;
|
|
95
95
|
nextValue = spec[COMMAND_APPLY](nextValue);
|
|
96
96
|
}
|
|
97
97
|
|
|
@@ -11,12 +11,13 @@
|
|
|
11
11
|
|
|
12
12
|
'use strict';
|
|
13
13
|
|
|
14
|
-
var
|
|
15
|
-
var
|
|
14
|
+
var assign = require('./Object.assign');
|
|
15
|
+
var emptyFunction = require('fbjs/lib/emptyFunction');
|
|
16
|
+
var warning = require('fbjs/lib/warning');
|
|
16
17
|
|
|
17
18
|
var validateDOMNesting = emptyFunction;
|
|
18
19
|
|
|
19
|
-
if (
|
|
20
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
20
21
|
// This validation code was written based on the HTML5 parsing spec:
|
|
21
22
|
// https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-scope
|
|
22
23
|
//
|
|
@@ -31,81 +32,86 @@ if ('production' !== process.env.NODE_ENV) {
|
|
|
31
32
|
// https://html.spec.whatwg.org/multipage/syntax.html#special
|
|
32
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'];
|
|
33
34
|
|
|
34
|
-
/**
|
|
35
|
-
* Return whether `stack` contains `tag` and the last occurrence of `tag` is
|
|
36
|
-
* deeper than any element in the `scope` array.
|
|
37
|
-
*
|
|
38
|
-
* https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-the-specific-scope
|
|
39
|
-
*
|
|
40
|
-
* Examples:
|
|
41
|
-
* stackHasTagInSpecificScope(['p', 'quote'], 'p', ['button']) is true
|
|
42
|
-
* stackHasTagInSpecificScope(['p', 'button'], 'p', ['button']) is false
|
|
43
|
-
*
|
|
44
|
-
* @param {Array<string>} stack
|
|
45
|
-
* @param {string} tag
|
|
46
|
-
* @param {Array<string>} scope
|
|
47
|
-
*/
|
|
48
|
-
var stackHasTagInSpecificScope = function (stack, tag, scope) {
|
|
49
|
-
for (var i = stack.length - 1; i >= 0; i--) {
|
|
50
|
-
if (stack[i] === tag) {
|
|
51
|
-
return true;
|
|
52
|
-
}
|
|
53
|
-
if (scope.indexOf(stack[i]) !== -1) {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return false;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
35
|
// https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-scope
|
|
61
36
|
var inScopeTags = ['applet', 'caption', 'html', 'table', 'td', 'th', 'marquee', 'object', 'template',
|
|
62
37
|
|
|
63
38
|
// https://html.spec.whatwg.org/multipage/syntax.html#html-integration-point
|
|
64
|
-
// TODO: Distinguish by namespace here
|
|
39
|
+
// TODO: Distinguish by namespace here -- for <title>, including it here
|
|
40
|
+
// errs on the side of fewer warnings
|
|
65
41
|
'foreignObject', 'desc', 'title'];
|
|
66
|
-
var stackHasTagInScope = function (stack, tag) {
|
|
67
|
-
return stackHasTagInSpecificScope(stack, tag, inScopeTags);
|
|
68
|
-
};
|
|
69
42
|
|
|
70
43
|
// https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-button-scope
|
|
71
44
|
var buttonScopeTags = inScopeTags.concat(['button']);
|
|
72
|
-
|
|
73
|
-
|
|
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
|
|
74
60
|
};
|
|
75
61
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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;
|
|
86
73
|
}
|
|
87
|
-
return true;
|
|
88
|
-
};
|
|
89
74
|
|
|
90
|
-
|
|
91
|
-
|
|
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
|
+
};
|
|
92
108
|
|
|
93
109
|
/**
|
|
94
|
-
* Returns whether
|
|
95
|
-
* of open tags is `openTagStack`.
|
|
96
|
-
*
|
|
97
|
-
* Examples:
|
|
98
|
-
* isTagValidInContext('tr', [..., 'table', 'tbody']) is true
|
|
99
|
-
* isTagValidInContext('tr', [..., 'table']) is false
|
|
100
|
-
*
|
|
101
|
-
* @param {string} tag Lowercase HTML tag name or node name like '#text'
|
|
102
|
-
* @param {Array<string>} openTagStack
|
|
110
|
+
* Returns whether
|
|
103
111
|
*/
|
|
104
|
-
var
|
|
105
|
-
var currentTag = openTagStack[openTagStack.length - 1];
|
|
106
|
-
|
|
112
|
+
var isTagValidWithParent = function (tag, parentTag) {
|
|
107
113
|
// First, let's check if we're in an unusual parsing mode...
|
|
108
|
-
switch (
|
|
114
|
+
switch (parentTag) {
|
|
109
115
|
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inselect
|
|
110
116
|
case 'select':
|
|
111
117
|
return tag === 'option' || tag === 'optgroup' || tag === '#text';
|
|
@@ -151,6 +157,44 @@ if ('production' !== process.env.NODE_ENV) {
|
|
|
151
157
|
// Probably in the "in body" parsing mode, so we outlaw only tag combos
|
|
152
158
|
// where the parsing rules cause implicit opens or closes to be added.
|
|
153
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) {
|
|
154
198
|
switch (tag) {
|
|
155
199
|
case 'address':
|
|
156
200
|
case 'article':
|
|
@@ -185,7 +229,6 @@ if ('production' !== process.env.NODE_ENV) {
|
|
|
185
229
|
case 'hr':
|
|
186
230
|
|
|
187
231
|
case 'xmp':
|
|
188
|
-
return !stackHasTagInButtonScope(openTagStack, 'p');
|
|
189
232
|
|
|
190
233
|
case 'h1':
|
|
191
234
|
case 'h2':
|
|
@@ -193,72 +236,128 @@ if ('production' !== process.env.NODE_ENV) {
|
|
|
193
236
|
case 'h4':
|
|
194
237
|
case 'h5':
|
|
195
238
|
case 'h6':
|
|
196
|
-
return
|
|
239
|
+
return ancestorInfo.pTagInButtonScope;
|
|
197
240
|
|
|
198
241
|
case 'form':
|
|
199
|
-
return
|
|
242
|
+
return ancestorInfo.formTag || ancestorInfo.pTagInButtonScope;
|
|
200
243
|
|
|
201
244
|
case 'li':
|
|
202
|
-
return
|
|
245
|
+
return ancestorInfo.listItemTagAutoclosing;
|
|
203
246
|
|
|
204
247
|
case 'dd':
|
|
205
248
|
case 'dt':
|
|
206
|
-
return
|
|
249
|
+
return ancestorInfo.dlItemTagAutoclosing;
|
|
207
250
|
|
|
208
251
|
case 'button':
|
|
209
|
-
return
|
|
252
|
+
return ancestorInfo.buttonTagInScope;
|
|
210
253
|
|
|
211
254
|
case 'a':
|
|
212
255
|
// Spec says something about storing a list of markers, but it sounds
|
|
213
256
|
// equivalent to this check.
|
|
214
|
-
return
|
|
257
|
+
return ancestorInfo.aTagInScope;
|
|
215
258
|
|
|
216
259
|
case 'nobr':
|
|
217
|
-
return
|
|
260
|
+
return ancestorInfo.nobrTagInScope;
|
|
261
|
+
}
|
|
218
262
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
return impliedEndTags.indexOf(currentTag) === -1;
|
|
263
|
+
return null;
|
|
264
|
+
};
|
|
222
265
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
case 'tfoot':
|
|
231
|
-
case 'th':
|
|
232
|
-
case 'thead':
|
|
233
|
-
case 'tr':
|
|
234
|
-
return currentTag === undefined;
|
|
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 [];
|
|
235
273
|
}
|
|
236
274
|
|
|
237
|
-
|
|
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;
|
|
238
283
|
};
|
|
239
284
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
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;
|
|
251
315
|
}
|
|
252
316
|
}
|
|
253
317
|
|
|
254
|
-
|
|
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
|
+
process.env.NODE_ENV !== 'production' ? warning(false, 'validateDOMNesting(...): <%s> cannot appear as a child of <%s>. ' + 'See %s.%s', childTag, ancestorTag, ownerInfo, info) : undefined;
|
|
344
|
+
} else {
|
|
345
|
+
process.env.NODE_ENV !== 'production' ? warning(false, 'validateDOMNesting(...): <%s> cannot appear as a descendant of ' + '<%s>. See %s.', childTag, ancestorTag, ownerInfo) : undefined;
|
|
346
|
+
}
|
|
255
347
|
}
|
|
256
348
|
};
|
|
257
349
|
|
|
258
|
-
validateDOMNesting.
|
|
350
|
+
validateDOMNesting.ancestorInfoContextKey = '__validateDOMNesting_ancestorInfo$' + Math.random().toString(36).slice(2);
|
|
351
|
+
|
|
352
|
+
validateDOMNesting.updatedAncestorInfo = updatedAncestorInfo;
|
|
259
353
|
|
|
260
354
|
// For testing
|
|
261
|
-
validateDOMNesting.isTagValidInContext =
|
|
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
|
+
};
|
|
262
361
|
}
|
|
263
362
|
|
|
264
363
|
module.exports = validateDOMNesting;
|