mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
+3
-2
@@ -23,7 +23,7 @@ module.exports = {
|
||||
'dot-notation': ERROR,
|
||||
'eol-last': ERROR,
|
||||
'eqeqeq': [ERROR, 'allow-null'],
|
||||
'indent': [ERROR, 2, {SwitchCase: 1}],
|
||||
'indent': OFF,
|
||||
'jsx-quotes': [ERROR, 'prefer-double'],
|
||||
'keyword-spacing': [ERROR, {after: true, before: true}],
|
||||
'no-bitwise': OFF,
|
||||
@@ -33,9 +33,10 @@ module.exports = {
|
||||
'no-shadow': ERROR,
|
||||
'no-unused-expressions': ERROR,
|
||||
'no-unused-vars': [ERROR, {args: 'none'}],
|
||||
'no-useless-concat': OFF,
|
||||
'quotes': [ERROR, 'single', {avoidEscape: true, allowTemplateLiterals: true }],
|
||||
'space-before-blocks': ERROR,
|
||||
'space-before-function-paren': [ERROR, {anonymous: 'never', named: 'never'}],
|
||||
'space-before-function-paren': OFF,
|
||||
|
||||
// React & JSX
|
||||
// Our transforms set this automatically
|
||||
|
||||
+3
-1
@@ -71,6 +71,7 @@
|
||||
"merge-stream": "^1.0.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"platform": "^1.1.0",
|
||||
"prettier": "^0.22.0",
|
||||
"run-sequence": "^1.1.4",
|
||||
"through2": "^2.0.0",
|
||||
"tmp": "~0.0.28",
|
||||
@@ -92,7 +93,8 @@
|
||||
"lint": "grunt lint",
|
||||
"postinstall": "node node_modules/fbjs-scripts/node/check-dev-engines.js package.json",
|
||||
"test": "jest",
|
||||
"flow": "flow"
|
||||
"flow": "flow",
|
||||
"prettier": "prettier --write --no-bracket-spacing --single-quote --jsx-bracket-same-line --trailing-comma all --print-width 80 \"src/**/!(third_party)/*.js\""
|
||||
},
|
||||
"jest": {
|
||||
"modulePathIgnorePatterns": [
|
||||
|
||||
@@ -12,3 +12,4 @@
|
||||
// Noop
|
||||
|
||||
// TODO #10932517: Move all initialization callers back into react-native
|
||||
|
||||
|
||||
@@ -16,15 +16,15 @@ var deepDiffer = function(one: any, two: any): boolean {
|
||||
// Short circuit on identical object references instead of traversing them.
|
||||
return false;
|
||||
}
|
||||
if ((typeof one === 'function') && (typeof two === 'function')) {
|
||||
if (typeof one === 'function' && typeof two === 'function') {
|
||||
// We consider all functions equal
|
||||
return false;
|
||||
}
|
||||
if ((typeof one !== 'object') || (one === null)) {
|
||||
if (typeof one !== 'object' || one === null) {
|
||||
// Primitives can be directly compared
|
||||
return one !== two;
|
||||
}
|
||||
if ((typeof two !== 'object') || (two === null)) {
|
||||
if (typeof two !== 'object' || two === null) {
|
||||
// We know they are different because the previous case would have triggered
|
||||
// otherwise.
|
||||
return true;
|
||||
|
||||
@@ -11,6 +11,6 @@
|
||||
|
||||
// TODO: move into react or fbjs
|
||||
|
||||
var deepFreezeAndThrowOnMutationInDev = function() { };
|
||||
var deepFreezeAndThrowOnMutationInDev = function() {};
|
||||
|
||||
module.exports = deepFreezeAndThrowOnMutationInDev;
|
||||
|
||||
@@ -11,6 +11,6 @@
|
||||
|
||||
// TODO: Move flattenStyle into react
|
||||
|
||||
var flattenStyle = function() { };
|
||||
var flattenStyle = function() {};
|
||||
|
||||
module.exports = flattenStyle;
|
||||
|
||||
@@ -41,7 +41,7 @@ var ReactFragment = {
|
||||
warning(
|
||||
false,
|
||||
'React.addons.createFragment only accepts a single object. Got: %s',
|
||||
object
|
||||
object,
|
||||
);
|
||||
return object;
|
||||
}
|
||||
@@ -49,7 +49,7 @@ var ReactFragment = {
|
||||
warning(
|
||||
false,
|
||||
'React.addons.createFragment does not accept a ReactElement ' +
|
||||
'without a wrapper object.'
|
||||
'without a wrapper object.',
|
||||
);
|
||||
return object;
|
||||
}
|
||||
@@ -57,7 +57,7 @@ var ReactFragment = {
|
||||
invariant(
|
||||
object.nodeType !== 1,
|
||||
'React.addons.createFragment(...): Encountered an invalid child; DOM ' +
|
||||
'elements are not valid children of React components.'
|
||||
'elements are not valid children of React components.',
|
||||
);
|
||||
|
||||
var result = [];
|
||||
@@ -68,7 +68,7 @@ var ReactFragment = {
|
||||
warning(
|
||||
false,
|
||||
'React.addons.createFragment(...): Child objects should have ' +
|
||||
'non-numeric keys so ordering is preserved.'
|
||||
'non-numeric keys so ordering is preserved.',
|
||||
);
|
||||
warnedAboutNumeric = true;
|
||||
}
|
||||
@@ -77,7 +77,7 @@ var ReactFragment = {
|
||||
object[key],
|
||||
result,
|
||||
key,
|
||||
emptyFunction.thatReturnsArgument
|
||||
emptyFunction.thatReturnsArgument,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,7 @@
|
||||
|
||||
var React = require('react');
|
||||
var ReactAddonsDOMDependencies = require('ReactAddonsDOMDependencies');
|
||||
var ReactComponentWithPureRenderMixin =
|
||||
require('ReactComponentWithPureRenderMixin');
|
||||
var ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
|
||||
var ReactCSSTransitionGroup = require('ReactCSSTransitionGroup');
|
||||
var ReactFragment = require('ReactFragment');
|
||||
var ReactTransitionGroup = require('ReactTransitionGroup');
|
||||
|
||||
@@ -16,11 +16,9 @@ var ReactComponentWithPureRenderMixin;
|
||||
var ReactTestUtils;
|
||||
|
||||
describe('ReactComponentWithPureRenderMixin', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
React = require('react');
|
||||
ReactComponentWithPureRenderMixin =
|
||||
require('ReactComponentWithPureRenderMixin');
|
||||
ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
|
||||
ReactTestUtils = require('ReactTestUtils');
|
||||
});
|
||||
|
||||
@@ -35,12 +33,7 @@ describe('ReactComponentWithPureRenderMixin', () => {
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Apple
|
||||
color={this.state.color}
|
||||
ref="apple"
|
||||
/>
|
||||
);
|
||||
return <Apple color={this.state.color} ref="apple" />;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,5 +134,4 @@ describe('ReactComponentWithPureRenderMixin', () => {
|
||||
instance.setState(getInitialState());
|
||||
expect(renderCalls).toBe(3);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -16,7 +16,6 @@ var ReactDOM;
|
||||
var ReactFragment;
|
||||
|
||||
describe('ReactFragment', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
@@ -33,9 +32,9 @@ describe('ReactFragment', () => {
|
||||
var container = document.createElement('div');
|
||||
expect(() => ReactDOM.render(element, container)).toThrowError(
|
||||
'Objects are not valid as a React child (found: object with keys ' +
|
||||
'{x, y, z}). If you meant to render a collection of children, use an ' +
|
||||
'array instead or wrap the object using createFragment(object) from ' +
|
||||
'the React add-ons.'
|
||||
'{x, y, z}). If you meant to render a collection of children, use an ' +
|
||||
'array instead or wrap the object using createFragment(object) from ' +
|
||||
'the React add-ons.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -53,9 +52,9 @@ describe('ReactFragment', () => {
|
||||
var container = document.createElement('div');
|
||||
expect(() => ReactDOM.render(<Foo />, container)).toThrowError(
|
||||
'Objects are not valid as a React child (found: object with keys ' +
|
||||
'{a, b, c}). If you meant to render a collection of children, use an ' +
|
||||
'array instead or wrap the object using createFragment(object) from ' +
|
||||
'the React add-ons.\n\nCheck the render method of `Foo`.'
|
||||
'{a, b, c}). If you meant to render a collection of children, use an ' +
|
||||
'array instead or wrap the object using createFragment(object) from ' +
|
||||
'the React add-ons.\n\nCheck the render method of `Foo`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -66,7 +65,7 @@ describe('ReactFragment', () => {
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Child objects should have non-numeric keys so ordering is preserved.'
|
||||
'Child objects should have non-numeric keys so ordering is preserved.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -75,7 +74,7 @@ describe('ReactFragment', () => {
|
||||
ReactFragment.create(null);
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'React.addons.createFragment only accepts a single object.'
|
||||
'React.addons.createFragment only accepts a single object.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -84,7 +83,7 @@ describe('ReactFragment', () => {
|
||||
ReactFragment.create([]);
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'React.addons.createFragment only accepts a single object.'
|
||||
'React.addons.createFragment only accepts a single object.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -94,8 +93,7 @@ describe('ReactFragment', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'React.addons.createFragment does not accept a ReactElement without a ' +
|
||||
'wrapper object.'
|
||||
'wrapper object.',
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -17,7 +17,6 @@ var ReactTestUtils = require('ReactTestUtils');
|
||||
var renderSubtreeIntoContainer = require('renderSubtreeIntoContainer');
|
||||
|
||||
describe('renderSubtreeIntoContainer', () => {
|
||||
|
||||
it('should pass context when rendering subtree elsewhere', () => {
|
||||
var portal = document.createElement('div');
|
||||
|
||||
@@ -47,9 +46,11 @@ describe('renderSubtreeIntoContainer', () => {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
expect(function() {
|
||||
renderSubtreeIntoContainer(this, <Component />, portal);
|
||||
}.bind(this)).not.toThrow();
|
||||
expect(
|
||||
function() {
|
||||
renderSubtreeIntoContainer(this, <Component />, portal);
|
||||
}.bind(this),
|
||||
).not.toThrow();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,5 +297,4 @@ describe('renderSubtreeIntoContainer', () => {
|
||||
ReactDOM.render(<Parent value="foo" />, container);
|
||||
expect(portal2.textContent).toBe('foo');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
var update = require('update');
|
||||
|
||||
describe('update', () => {
|
||||
|
||||
describe('$push', () => {
|
||||
it('pushes', () => {
|
||||
expect(update([1], {$push: [7]})).toEqual([1, 7]);
|
||||
@@ -27,12 +26,12 @@ describe('update', () => {
|
||||
it('only pushes an array', () => {
|
||||
expect(update.bind(null, [], {$push: 7})).toThrowError(
|
||||
'update(): expected spec of $push to be an array; got 7. Did you ' +
|
||||
'forget to wrap your parameter in an array?'
|
||||
'forget to wrap your parameter in an array?',
|
||||
);
|
||||
});
|
||||
it('only pushes unto an array', () => {
|
||||
expect(update.bind(null, 1, {$push: 7})).toThrowError(
|
||||
'update(): expected target of $push to be an array; got 1.'
|
||||
'update(): expected target of $push to be an array; got 1.',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -49,12 +48,12 @@ describe('update', () => {
|
||||
it('only unshifts an array', () => {
|
||||
expect(update.bind(null, [], {$unshift: 7})).toThrowError(
|
||||
'update(): expected spec of $unshift to be an array; got 7. Did you ' +
|
||||
'forget to wrap your parameter in an array?'
|
||||
'forget to wrap your parameter in an array?',
|
||||
);
|
||||
});
|
||||
it('only unshifts unto an array', () => {
|
||||
expect(update.bind(null, 1, {$unshift: 7})).toThrowError(
|
||||
'update(): expected target of $unshift to be an array; got 1.'
|
||||
'update(): expected target of $unshift to be an array; got 1.',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -71,16 +70,16 @@ describe('update', () => {
|
||||
it('only splices an array of arrays', () => {
|
||||
expect(update.bind(null, [], {$splice: 1})).toThrowError(
|
||||
'update(): expected spec of $splice to be an array of arrays; got 1. ' +
|
||||
'Did you forget to wrap your parameters in an array?'
|
||||
'Did you forget to wrap your parameters in an array?',
|
||||
);
|
||||
expect(update.bind(null, [], {$splice: [1]})).toThrowError(
|
||||
'update(): expected spec of $splice to be an array of arrays; got 1. ' +
|
||||
'Did you forget to wrap your parameters in an array?'
|
||||
'Did you forget to wrap your parameters in an array?',
|
||||
);
|
||||
});
|
||||
it('only splices unto an array', () => {
|
||||
expect(update.bind(null, 1, {$splice: 7})).toThrowError(
|
||||
'Expected $splice target to be an array; got 1'
|
||||
'Expected $splice target to be an array; got 1',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -96,12 +95,12 @@ describe('update', () => {
|
||||
});
|
||||
it('only merges with an object', () => {
|
||||
expect(update.bind(null, {}, {$merge: 7})).toThrowError(
|
||||
'update(): $merge expects a spec of type \'object\'; got 7'
|
||||
"update(): $merge expects a spec of type 'object'; got 7",
|
||||
);
|
||||
});
|
||||
it('only merges with an object', () => {
|
||||
expect(update.bind(null, 7, {$merge: {a: 'b'}})).toThrowError(
|
||||
'update(): $merge expects a target of type \'object\'; got 7'
|
||||
"update(): $merge expects a target of type 'object'; got 7",
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -131,32 +130,37 @@ describe('update', () => {
|
||||
});
|
||||
it('only applies a function', () => {
|
||||
expect(update.bind(null, 2, {$apply: 123})).toThrowError(
|
||||
'update(): expected spec of $apply to be a function; got 123.'
|
||||
'update(): expected spec of $apply to be a function; got 123.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should support deep updates', () => {
|
||||
expect(update({
|
||||
a: 'b',
|
||||
c: {
|
||||
d: 'e',
|
||||
f: [1],
|
||||
g: [2],
|
||||
h: [3],
|
||||
i: {j: 'k'},
|
||||
l: 4,
|
||||
},
|
||||
}, {
|
||||
c: {
|
||||
d: {$set: 'm'},
|
||||
f: {$push: [5]},
|
||||
g: {$unshift: [6]},
|
||||
h: {$splice: [[0, 1, 7]]},
|
||||
i: {$merge: {n: 'o'}},
|
||||
l: {$apply: (x) => x * 2},
|
||||
},
|
||||
})).toEqual({
|
||||
expect(
|
||||
update(
|
||||
{
|
||||
a: 'b',
|
||||
c: {
|
||||
d: 'e',
|
||||
f: [1],
|
||||
g: [2],
|
||||
h: [3],
|
||||
i: {j: 'k'},
|
||||
l: 4,
|
||||
},
|
||||
},
|
||||
{
|
||||
c: {
|
||||
d: {$set: 'm'},
|
||||
f: {$push: [5]},
|
||||
g: {$unshift: [6]},
|
||||
h: {$splice: [[0, 1, 7]]},
|
||||
i: {$merge: {n: 'o'}},
|
||||
l: {$apply: x => x * 2},
|
||||
},
|
||||
},
|
||||
),
|
||||
).toEqual({
|
||||
a: 'b',
|
||||
c: {
|
||||
d: 'm',
|
||||
@@ -172,14 +176,14 @@ describe('update', () => {
|
||||
it('should require a command', () => {
|
||||
expect(update.bind(null, {a: 'b'}, {a: 'c'})).toThrowError(
|
||||
'update(): You provided a key path to update() that did not contain ' +
|
||||
'one of $push, $unshift, $splice, $set, $merge, $apply. Did you ' +
|
||||
'forget to include {$set: ...}?'
|
||||
'one of $push, $unshift, $splice, $set, $merge, $apply. Did you ' +
|
||||
'forget to include {$set: ...}?',
|
||||
);
|
||||
});
|
||||
|
||||
it('should perform safe hasOwnProperty check', () => {
|
||||
expect(update({}, {'hasOwnProperty': {$set: 'a'}})).toEqual({
|
||||
'hasOwnProperty': 'a',
|
||||
expect(update({}, {hasOwnProperty: {$set: 'a'}})).toEqual({
|
||||
hasOwnProperty: 'a',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -19,10 +19,8 @@ var shallowEqual = require('fbjs/lib/shallowEqual');
|
||||
* See also https://facebook.github.io/react/docs/shallow-compare.html
|
||||
*/
|
||||
function shallowCompare(instance, nextProps, nextState) {
|
||||
return (
|
||||
!shallowEqual(instance.props, nextProps) ||
|
||||
!shallowEqual(instance.state, nextState)
|
||||
);
|
||||
return !shallowEqual(instance.props, nextProps) ||
|
||||
!shallowEqual(instance.state, nextState);
|
||||
}
|
||||
|
||||
module.exports = shallowCompare;
|
||||
|
||||
@@ -26,16 +26,19 @@ function createTransitionTimeoutPropValidator(transitionType) {
|
||||
// If no timeout duration is provided
|
||||
if (props[timeoutPropName] == null) {
|
||||
return new Error(
|
||||
timeoutPropName + ' wasn\'t supplied to ReactCSSTransitionGroup: ' +
|
||||
'this can cause unreliable animations and won\'t be supported in ' +
|
||||
'a future version of React. See ' +
|
||||
'https://fb.me/react-animation-transition-group-timeout for more ' +
|
||||
'information.'
|
||||
timeoutPropName +
|
||||
" wasn't supplied to ReactCSSTransitionGroup: " +
|
||||
"this can cause unreliable animations and won't be supported in " +
|
||||
'a future version of React. See ' +
|
||||
'https://fb.me/react-animation-transition-group-timeout for more ' +
|
||||
'information.',
|
||||
);
|
||||
|
||||
// If the duration isn't a number
|
||||
// If the duration isn't a number
|
||||
} else if (typeof props[timeoutPropName] !== 'number') {
|
||||
return new Error(timeoutPropName + ' must be a number (in milliseconds)');
|
||||
return new Error(
|
||||
timeoutPropName + ' must be a number (in milliseconds)',
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -66,7 +69,7 @@ class ReactCSSTransitionGroup extends React.Component {
|
||||
transitionLeave: true,
|
||||
};
|
||||
|
||||
_wrapChild = (child) => {
|
||||
_wrapChild = child => {
|
||||
// We need to provide this childFactory so that
|
||||
// ReactCSSTransitionGroupChild can receive updates to name, enter, and
|
||||
// leave while it is leaving.
|
||||
@@ -81,14 +84,14 @@ class ReactCSSTransitionGroup extends React.Component {
|
||||
enterTimeout: this.props.transitionEnterTimeout,
|
||||
leaveTimeout: this.props.transitionLeaveTimeout,
|
||||
},
|
||||
child
|
||||
child,
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return React.createElement(
|
||||
ReactTransitionGroup,
|
||||
Object.assign({}, this.props, {childFactory: this._wrapChild})
|
||||
Object.assign({}, this.props, {childFactory: this._wrapChild}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,8 +63,10 @@ var ReactCSSTransitionGroupChild = React.createClass({
|
||||
return;
|
||||
}
|
||||
|
||||
var className = this.props.name[animationType] || this.props.name + '-' + animationType;
|
||||
var activeClassName = this.props.name[animationType + 'Active'] || className + '-active';
|
||||
var className = this.props.name[animationType] ||
|
||||
this.props.name + '-' + animationType;
|
||||
var activeClassName = this.props.name[animationType + 'Active'] ||
|
||||
className + '-active';
|
||||
var timeout = null;
|
||||
|
||||
var endListener = function(e) {
|
||||
|
||||
@@ -86,7 +86,7 @@ var ReactTransitionChildMapping = {
|
||||
for (i = 0; i < nextKeysPending[nextKey].length; i++) {
|
||||
var pendingNextKey = nextKeysPending[nextKey][i];
|
||||
childMapping[nextKeysPending[nextKey][i]] = getValueForKey(
|
||||
pendingNextKey
|
||||
pendingNextKey,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,14 +56,14 @@ class ReactTransitionGroup extends React.Component {
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
var nextChildMapping = ReactTransitionChildMapping.getChildMapping(
|
||||
nextProps.children
|
||||
nextProps.children,
|
||||
);
|
||||
var prevChildMapping = this.state.children;
|
||||
|
||||
this.setState({
|
||||
children: ReactTransitionChildMapping.mergeChildMappings(
|
||||
prevChildMapping,
|
||||
nextChildMapping
|
||||
nextChildMapping,
|
||||
),
|
||||
});
|
||||
|
||||
@@ -71,16 +71,22 @@ class ReactTransitionGroup extends React.Component {
|
||||
|
||||
for (key in nextChildMapping) {
|
||||
var hasPrev = prevChildMapping && prevChildMapping.hasOwnProperty(key);
|
||||
if (nextChildMapping[key] && !hasPrev &&
|
||||
!this.currentlyTransitioningKeys[key]) {
|
||||
if (
|
||||
nextChildMapping[key] &&
|
||||
!hasPrev &&
|
||||
!this.currentlyTransitioningKeys[key]
|
||||
) {
|
||||
this.keysToEnter.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
for (key in prevChildMapping) {
|
||||
var hasNext = nextChildMapping && nextChildMapping.hasOwnProperty(key);
|
||||
if (prevChildMapping[key] && !hasNext &&
|
||||
!this.currentlyTransitioningKeys[key]) {
|
||||
if (
|
||||
prevChildMapping[key] &&
|
||||
!hasNext &&
|
||||
!this.currentlyTransitioningKeys[key]
|
||||
) {
|
||||
this.keysToLeave.push(key);
|
||||
}
|
||||
}
|
||||
@@ -98,21 +104,19 @@ class ReactTransitionGroup extends React.Component {
|
||||
keysToLeave.forEach(this.performLeave);
|
||||
}
|
||||
|
||||
performAppear = (key) => {
|
||||
performAppear = key => {
|
||||
this.currentlyTransitioningKeys[key] = true;
|
||||
|
||||
var component = this.refs[key];
|
||||
|
||||
if (component.componentWillAppear) {
|
||||
component.componentWillAppear(
|
||||
this._handleDoneAppearing.bind(this, key)
|
||||
);
|
||||
component.componentWillAppear(this._handleDoneAppearing.bind(this, key));
|
||||
} else {
|
||||
this._handleDoneAppearing(key);
|
||||
}
|
||||
};
|
||||
|
||||
_handleDoneAppearing = (key) => {
|
||||
_handleDoneAppearing = key => {
|
||||
var component = this.refs[key];
|
||||
if (component.componentDidAppear) {
|
||||
component.componentDidAppear();
|
||||
@@ -121,7 +125,7 @@ class ReactTransitionGroup extends React.Component {
|
||||
delete this.currentlyTransitioningKeys[key];
|
||||
|
||||
var currentChildMapping = ReactTransitionChildMapping.getChildMapping(
|
||||
this.props.children
|
||||
this.props.children,
|
||||
);
|
||||
|
||||
if (!currentChildMapping || !currentChildMapping.hasOwnProperty(key)) {
|
||||
@@ -130,21 +134,19 @@ class ReactTransitionGroup extends React.Component {
|
||||
}
|
||||
};
|
||||
|
||||
performEnter = (key) => {
|
||||
performEnter = key => {
|
||||
this.currentlyTransitioningKeys[key] = true;
|
||||
|
||||
var component = this.refs[key];
|
||||
|
||||
if (component.componentWillEnter) {
|
||||
component.componentWillEnter(
|
||||
this._handleDoneEntering.bind(this, key)
|
||||
);
|
||||
component.componentWillEnter(this._handleDoneEntering.bind(this, key));
|
||||
} else {
|
||||
this._handleDoneEntering(key);
|
||||
}
|
||||
};
|
||||
|
||||
_handleDoneEntering = (key) => {
|
||||
_handleDoneEntering = key => {
|
||||
var component = this.refs[key];
|
||||
if (component.componentDidEnter) {
|
||||
component.componentDidEnter();
|
||||
@@ -153,7 +155,7 @@ class ReactTransitionGroup extends React.Component {
|
||||
delete this.currentlyTransitioningKeys[key];
|
||||
|
||||
var currentChildMapping = ReactTransitionChildMapping.getChildMapping(
|
||||
this.props.children
|
||||
this.props.children,
|
||||
);
|
||||
|
||||
if (!currentChildMapping || !currentChildMapping.hasOwnProperty(key)) {
|
||||
@@ -162,7 +164,7 @@ class ReactTransitionGroup extends React.Component {
|
||||
}
|
||||
};
|
||||
|
||||
performLeave = (key) => {
|
||||
performLeave = key => {
|
||||
this.currentlyTransitioningKeys[key] = true;
|
||||
|
||||
var component = this.refs[key];
|
||||
@@ -176,7 +178,7 @@ class ReactTransitionGroup extends React.Component {
|
||||
}
|
||||
};
|
||||
|
||||
_handleDoneLeaving = (key) => {
|
||||
_handleDoneLeaving = key => {
|
||||
var component = this.refs[key];
|
||||
|
||||
if (component.componentDidLeave) {
|
||||
@@ -186,7 +188,7 @@ class ReactTransitionGroup extends React.Component {
|
||||
delete this.currentlyTransitioningKeys[key];
|
||||
|
||||
var currentChildMapping = ReactTransitionChildMapping.getChildMapping(
|
||||
this.props.children
|
||||
this.props.children,
|
||||
);
|
||||
|
||||
if (currentChildMapping && currentChildMapping.hasOwnProperty(key)) {
|
||||
@@ -213,10 +215,12 @@ class ReactTransitionGroup extends React.Component {
|
||||
// already been removed. In case you need this behavior you can provide
|
||||
// a childFactory function to wrap every child, even the ones that are
|
||||
// leaving.
|
||||
childrenToRender.push(React.cloneElement(
|
||||
this.props.childFactory(child),
|
||||
{ref: key, key: key}
|
||||
));
|
||||
childrenToRender.push(
|
||||
React.cloneElement(this.props.childFactory(child), {
|
||||
ref: key,
|
||||
key: key,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,11 +236,7 @@ class ReactTransitionGroup extends React.Component {
|
||||
delete props.transitionAppearTimeout;
|
||||
delete props.component;
|
||||
|
||||
return React.createElement(
|
||||
this.props.component,
|
||||
props,
|
||||
childrenToRender
|
||||
);
|
||||
return React.createElement(this.props.component, props, childrenToRender);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,16 +32,15 @@ describe('ReactCSSTransitionGroup', () => {
|
||||
spyOn(console, 'error');
|
||||
});
|
||||
|
||||
it('should warn if timeouts aren\'t specified', () => {
|
||||
it("should warn if timeouts aren't specified", () => {
|
||||
ReactDOM.render(
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="yolo"
|
||||
transitionEnter={false}
|
||||
transitionLeave={true}
|
||||
>
|
||||
transitionLeave={true}>
|
||||
<span key="one" id="one" />
|
||||
</ReactCSSTransitionGroup>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
|
||||
// Warning about the missing transitionLeaveTimeout prop
|
||||
@@ -54,11 +53,10 @@ describe('ReactCSSTransitionGroup', () => {
|
||||
transitionName="yolo"
|
||||
transitionEnter={false}
|
||||
transitionLeave={true}
|
||||
transitionLeaveTimeout={0}
|
||||
>
|
||||
transitionLeaveTimeout={0}>
|
||||
<span key="one" id="one" />
|
||||
</ReactCSSTransitionGroup>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(0);
|
||||
@@ -69,11 +67,10 @@ describe('ReactCSSTransitionGroup', () => {
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="yolo"
|
||||
transitionEnter={false}
|
||||
transitionLeaveTimeout={200}
|
||||
>
|
||||
transitionLeaveTimeout={200}>
|
||||
<span key="one" id="one" />
|
||||
</ReactCSSTransitionGroup>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
|
||||
|
||||
@@ -83,11 +80,10 @@ describe('ReactCSSTransitionGroup', () => {
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="yolo"
|
||||
transitionEnter={false}
|
||||
transitionLeaveTimeout={200}
|
||||
>
|
||||
transitionLeaveTimeout={200}>
|
||||
<span key="two" id="two" />
|
||||
</ReactCSSTransitionGroup>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
|
||||
expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('two');
|
||||
@@ -115,14 +111,14 @@ describe('ReactCSSTransitionGroup', () => {
|
||||
<ReactCSSTransitionGroup transitionName="yolo">
|
||||
<span key="one" id="one" />
|
||||
</ReactCSSTransitionGroup>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
|
||||
ReactDOM.render(
|
||||
<ReactCSSTransitionGroup transitionName="yolo">
|
||||
<span key="two" id="two" />
|
||||
</ReactCSSTransitionGroup>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
|
||||
expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('two');
|
||||
@@ -132,32 +128,32 @@ describe('ReactCSSTransitionGroup', () => {
|
||||
it('should switch transitionLeave from false to true', () => {
|
||||
var a = ReactDOM.render(
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="yolo"
|
||||
transitionEnter={false}
|
||||
transitionLeave={false}>
|
||||
transitionName="yolo"
|
||||
transitionEnter={false}
|
||||
transitionLeave={false}>
|
||||
<span key="one" id="one" />
|
||||
</ReactCSSTransitionGroup>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
|
||||
ReactDOM.render(
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="yolo"
|
||||
transitionEnter={false}
|
||||
transitionLeave={false}>
|
||||
transitionName="yolo"
|
||||
transitionEnter={false}
|
||||
transitionLeave={false}>
|
||||
<span key="two" id="two" />
|
||||
</ReactCSSTransitionGroup>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
|
||||
ReactDOM.render(
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="yolo"
|
||||
transitionEnter={false}
|
||||
transitionLeave={true}>
|
||||
transitionName="yolo"
|
||||
transitionEnter={false}
|
||||
transitionLeave={true}>
|
||||
<span key="three" id="three" />
|
||||
</ReactCSSTransitionGroup>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
|
||||
expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('three');
|
||||
@@ -167,7 +163,7 @@ describe('ReactCSSTransitionGroup', () => {
|
||||
it('should work with no children', () => {
|
||||
ReactDOM.render(
|
||||
<ReactCSSTransitionGroup transitionName="yolo" />,
|
||||
container
|
||||
container,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -176,7 +172,7 @@ describe('ReactCSSTransitionGroup', () => {
|
||||
<ReactCSSTransitionGroup transitionName="yolo">
|
||||
{[null]}
|
||||
</ReactCSSTransitionGroup>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -185,14 +181,14 @@ describe('ReactCSSTransitionGroup', () => {
|
||||
<ReactCSSTransitionGroup transitionName="yolo">
|
||||
<span key="one" id="one" />
|
||||
</ReactCSSTransitionGroup>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
|
||||
ReactDOM.render(
|
||||
<ReactCSSTransitionGroup transitionName="yolo">
|
||||
{null}
|
||||
</ReactCSSTransitionGroup>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
// (Here, we expect the original child to stick around but test that no
|
||||
// exception is thrown)
|
||||
@@ -205,20 +201,20 @@ describe('ReactCSSTransitionGroup', () => {
|
||||
<ReactCSSTransitionGroup transitionName="yolo">
|
||||
{false}
|
||||
</ReactCSSTransitionGroup>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(0);
|
||||
ReactDOM.render(
|
||||
<ReactCSSTransitionGroup transitionName="yolo">
|
||||
<span key="one" id="one" />
|
||||
</ReactCSSTransitionGroup>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
|
||||
expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('one');
|
||||
});
|
||||
|
||||
it('should use transition-type specific names when they\'re provided', () => {
|
||||
it("should use transition-type specific names when they're provided", () => {
|
||||
var customTransitionNames = {
|
||||
enter: 'custom-entering',
|
||||
leave: 'custom-leaving',
|
||||
@@ -228,11 +224,10 @@ describe('ReactCSSTransitionGroup', () => {
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName={customTransitionNames}
|
||||
transitionEnterTimeout={1}
|
||||
transitionLeaveTimeout={1}
|
||||
>
|
||||
transitionLeaveTimeout={1}>
|
||||
<span key="one" id="one" />
|
||||
</ReactCSSTransitionGroup>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
|
||||
|
||||
@@ -241,12 +236,11 @@ describe('ReactCSSTransitionGroup', () => {
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName={customTransitionNames}
|
||||
transitionEnterTimeout={1}
|
||||
transitionLeaveTimeout={1}
|
||||
>
|
||||
transitionLeaveTimeout={1}>
|
||||
<span key="one" id="one" />
|
||||
<span key="two" id="two" />
|
||||
</ReactCSSTransitionGroup>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
|
||||
|
||||
@@ -258,11 +252,10 @@ describe('ReactCSSTransitionGroup', () => {
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName={customTransitionNames}
|
||||
transitionEnterTimeout={1}
|
||||
transitionLeaveTimeout={1}
|
||||
>
|
||||
transitionLeaveTimeout={1}>
|
||||
<span key="two" id="two" />
|
||||
</ReactCSSTransitionGroup>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
|
||||
|
||||
@@ -284,7 +277,10 @@ describe('ReactCSSTransitionGroup', () => {
|
||||
}
|
||||
|
||||
ReactDOM.render(<Component />, container);
|
||||
ReactDOM.render(<Component><span key="yolo" id="yolo" /></Component>, container);
|
||||
ReactDOM.render(
|
||||
<Component><span key="yolo" id="yolo" /></Component>,
|
||||
container,
|
||||
);
|
||||
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
|
||||
@@ -303,10 +299,10 @@ describe('ReactCSSTransitionGroup', () => {
|
||||
}
|
||||
|
||||
class Component extends React.Component {
|
||||
state = { showChild: true };
|
||||
state = {showChild: true};
|
||||
|
||||
componentDidMount() {
|
||||
this.setState({ showChild: false });
|
||||
this.setState({showChild: false});
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -314,8 +310,7 @@ describe('ReactCSSTransitionGroup', () => {
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="yolo"
|
||||
transitionAppear={true}
|
||||
transitionAppearTimeout={0}
|
||||
>
|
||||
transitionAppearTimeout={0}>
|
||||
<Child show={this.state.showChild} />
|
||||
</ReactCSSTransitionGroup>
|
||||
);
|
||||
|
||||
@@ -27,7 +27,7 @@ describe('ReactTransitionChildMapping', () => {
|
||||
var two = <div key="two" />;
|
||||
var component = <div>{one}{two}</div>;
|
||||
expect(
|
||||
ReactTransitionChildMapping.getChildMapping(component.props.children)
|
||||
ReactTransitionChildMapping.getChildMapping(component.props.children),
|
||||
).toEqual({
|
||||
'.$one': one,
|
||||
'.$two': two,
|
||||
|
||||
@@ -28,7 +28,6 @@ describe('ReactTransitionGroup', () => {
|
||||
container = document.createElement('div');
|
||||
});
|
||||
|
||||
|
||||
it('should handle willEnter correctly', () => {
|
||||
var log = [];
|
||||
|
||||
@@ -37,7 +36,7 @@ describe('ReactTransitionGroup', () => {
|
||||
log.push('didMount');
|
||||
}
|
||||
|
||||
componentWillAppear = (cb) => {
|
||||
componentWillAppear = cb => {
|
||||
log.push('willAppear');
|
||||
cb();
|
||||
};
|
||||
@@ -46,7 +45,7 @@ describe('ReactTransitionGroup', () => {
|
||||
log.push('didAppear');
|
||||
};
|
||||
|
||||
componentWillEnter = (cb) => {
|
||||
componentWillEnter = cb => {
|
||||
log.push('willEnter');
|
||||
cb();
|
||||
};
|
||||
@@ -55,7 +54,7 @@ describe('ReactTransitionGroup', () => {
|
||||
log.push('didEnter');
|
||||
};
|
||||
|
||||
componentWillLeave = (cb) => {
|
||||
componentWillLeave = cb => {
|
||||
log.push('willLeave');
|
||||
cb();
|
||||
};
|
||||
@@ -108,7 +107,7 @@ describe('ReactTransitionGroup', () => {
|
||||
log.push('didMount');
|
||||
}
|
||||
|
||||
componentWillEnter = (cb) => {
|
||||
componentWillEnter = cb => {
|
||||
log.push('willEnter');
|
||||
willEnterCb = cb;
|
||||
};
|
||||
@@ -117,7 +116,7 @@ describe('ReactTransitionGroup', () => {
|
||||
log.push('didEnter');
|
||||
};
|
||||
|
||||
componentWillLeave = (cb) => {
|
||||
componentWillLeave = cb => {
|
||||
log.push('willLeave');
|
||||
cb();
|
||||
};
|
||||
@@ -159,8 +158,13 @@ describe('ReactTransitionGroup', () => {
|
||||
// other animations are blocked until willEnterCb is called
|
||||
willEnterCb();
|
||||
expect(log).toEqual([
|
||||
'didMount', 'didMount', 'willEnter',
|
||||
'didEnter', 'willLeave', 'didLeave', 'willUnmount',
|
||||
'didMount',
|
||||
'didMount',
|
||||
'willEnter',
|
||||
'didEnter',
|
||||
'willLeave',
|
||||
'didLeave',
|
||||
'willUnmount',
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -173,7 +177,7 @@ describe('ReactTransitionGroup', () => {
|
||||
log.push('didMount');
|
||||
}
|
||||
|
||||
componentWillEnter = (cb) => {
|
||||
componentWillEnter = cb => {
|
||||
log.push('willEnter');
|
||||
willEnterCb = cb;
|
||||
};
|
||||
@@ -182,7 +186,7 @@ describe('ReactTransitionGroup', () => {
|
||||
log.push('didEnter');
|
||||
};
|
||||
|
||||
componentWillLeave = (cb) => {
|
||||
componentWillLeave = cb => {
|
||||
log.push('willLeave');
|
||||
cb();
|
||||
};
|
||||
@@ -222,9 +226,7 @@ describe('ReactTransitionGroup', () => {
|
||||
instance.setState({count: 2});
|
||||
}
|
||||
willEnterCb();
|
||||
expect(log).toEqual([
|
||||
'didMount', 'didMount', 'willEnter', 'didEnter',
|
||||
]);
|
||||
expect(log).toEqual(['didMount', 'didMount', 'willEnter', 'didEnter']);
|
||||
});
|
||||
|
||||
it('should handle entering/leaving several elements at once', () => {
|
||||
@@ -235,7 +237,7 @@ describe('ReactTransitionGroup', () => {
|
||||
log.push('didMount' + this.props.id);
|
||||
}
|
||||
|
||||
componentWillEnter = (cb) => {
|
||||
componentWillEnter = cb => {
|
||||
log.push('willEnter' + this.props.id);
|
||||
cb();
|
||||
};
|
||||
@@ -244,7 +246,7 @@ describe('ReactTransitionGroup', () => {
|
||||
log.push('didEnter' + this.props.id);
|
||||
};
|
||||
|
||||
componentWillLeave = (cb) => {
|
||||
componentWillLeave = cb => {
|
||||
log.push('willLeave' + this.props.id);
|
||||
cb();
|
||||
};
|
||||
@@ -280,15 +282,26 @@ describe('ReactTransitionGroup', () => {
|
||||
|
||||
instance.setState({count: 3});
|
||||
expect(log).toEqual([
|
||||
'didMount1', 'didMount2', 'willEnter1', 'didEnter1',
|
||||
'willEnter2', 'didEnter2',
|
||||
'didMount1',
|
||||
'didMount2',
|
||||
'willEnter1',
|
||||
'didEnter1',
|
||||
'willEnter2',
|
||||
'didEnter2',
|
||||
]);
|
||||
log = [];
|
||||
|
||||
instance.setState({count: 0});
|
||||
expect(log).toEqual([
|
||||
'willLeave0', 'didLeave0', 'willLeave1', 'didLeave1',
|
||||
'willLeave2', 'didLeave2', 'willUnmount0', 'willUnmount1', 'willUnmount2',
|
||||
'willLeave0',
|
||||
'didLeave0',
|
||||
'willLeave1',
|
||||
'didLeave1',
|
||||
'willLeave2',
|
||||
'didLeave2',
|
||||
'willUnmount0',
|
||||
'willUnmount1',
|
||||
'willUnmount2',
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -307,15 +320,15 @@ describe('ReactTransitionGroup', () => {
|
||||
expectDev(console.error.calls.count()).toBe(2);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: flattenChildren(...): ' +
|
||||
'Encountered two children with the same key, `1`. ' +
|
||||
'Child keys must be unique; when two children share a key, ' +
|
||||
'only the first child will be used.'
|
||||
'Encountered two children with the same key, `1`. ' +
|
||||
'Child keys must be unique; when two children share a key, ' +
|
||||
'only the first child will be used.',
|
||||
);
|
||||
expectDev(console.error.calls.argsFor(1)[0]).toBe(
|
||||
'Warning: flattenChildren(...): ' +
|
||||
'Encountered two children with the same key, `1`. ' +
|
||||
'Child keys must be unique; when two children share a key, ' +
|
||||
'only the first child will be used.'
|
||||
'Encountered two children with the same key, `1`. ' +
|
||||
'Child keys must be unique; when two children share a key, ' +
|
||||
'only the first child will be used.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
+17
-17
@@ -9,7 +9,7 @@
|
||||
* @providesModule update
|
||||
*/
|
||||
|
||||
/* global hasOwnProperty:true */
|
||||
/* global hasOwnProperty:true */
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -53,15 +53,15 @@ function invariantArrayCase(value, spec, command) {
|
||||
Array.isArray(value),
|
||||
'update(): expected target of %s to be an array; got %s.',
|
||||
command,
|
||||
value
|
||||
value,
|
||||
);
|
||||
var specValue = spec[command];
|
||||
invariant(
|
||||
Array.isArray(specValue),
|
||||
'update(): expected spec of %s to be an array; got %s. ' +
|
||||
'Did you forget to wrap your parameter in an array?',
|
||||
'Did you forget to wrap your parameter in an array?',
|
||||
command,
|
||||
specValue
|
||||
specValue,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -73,16 +73,16 @@ function update(value, spec) {
|
||||
invariant(
|
||||
typeof spec === 'object',
|
||||
'update(): You provided a key path to update() that did not contain one ' +
|
||||
'of %s. Did you forget to include {%s: ...}?',
|
||||
'of %s. Did you forget to include {%s: ...}?',
|
||||
ALL_COMMANDS_LIST.join(', '),
|
||||
COMMAND_SET
|
||||
COMMAND_SET,
|
||||
);
|
||||
|
||||
if (hasOwnProperty.call(spec, COMMAND_SET)) {
|
||||
invariant(
|
||||
Object.keys(spec).length === 1,
|
||||
'Cannot have more than one key in an object with %s',
|
||||
COMMAND_SET
|
||||
COMMAND_SET,
|
||||
);
|
||||
|
||||
return spec[COMMAND_SET];
|
||||
@@ -94,15 +94,15 @@ function update(value, spec) {
|
||||
var mergeObj = spec[COMMAND_MERGE];
|
||||
invariant(
|
||||
mergeObj && typeof mergeObj === 'object',
|
||||
'update(): %s expects a spec of type \'object\'; got %s',
|
||||
"update(): %s expects a spec of type 'object'; got %s",
|
||||
COMMAND_MERGE,
|
||||
mergeObj
|
||||
mergeObj,
|
||||
);
|
||||
invariant(
|
||||
nextValue && typeof nextValue === 'object',
|
||||
'update(): %s expects a target of type \'object\'; got %s',
|
||||
"update(): %s expects a target of type 'object'; got %s",
|
||||
COMMAND_MERGE,
|
||||
nextValue
|
||||
nextValue,
|
||||
);
|
||||
Object.assign(nextValue, spec[COMMAND_MERGE]);
|
||||
}
|
||||
@@ -126,22 +126,22 @@ function update(value, spec) {
|
||||
Array.isArray(value),
|
||||
'Expected %s target to be an array; got %s',
|
||||
COMMAND_SPLICE,
|
||||
value
|
||||
value,
|
||||
);
|
||||
invariant(
|
||||
Array.isArray(spec[COMMAND_SPLICE]),
|
||||
'update(): expected spec of %s to be an array of arrays; got %s. ' +
|
||||
'Did you forget to wrap your parameters in an array?',
|
||||
'Did you forget to wrap your parameters in an array?',
|
||||
COMMAND_SPLICE,
|
||||
spec[COMMAND_SPLICE]
|
||||
spec[COMMAND_SPLICE],
|
||||
);
|
||||
spec[COMMAND_SPLICE].forEach(function(args) {
|
||||
invariant(
|
||||
Array.isArray(args),
|
||||
'update(): expected spec of %s to be an array of arrays; got %s. ' +
|
||||
'Did you forget to wrap your parameters in an array?',
|
||||
'Did you forget to wrap your parameters in an array?',
|
||||
COMMAND_SPLICE,
|
||||
spec[COMMAND_SPLICE]
|
||||
spec[COMMAND_SPLICE],
|
||||
);
|
||||
nextValue.splice.apply(nextValue, args);
|
||||
});
|
||||
@@ -152,7 +152,7 @@ function update(value, spec) {
|
||||
typeof spec[COMMAND_APPLY] === 'function',
|
||||
'update(): expected spec of %s to be a function; got %s.',
|
||||
COMMAND_APPLY,
|
||||
spec[COMMAND_APPLY]
|
||||
spec[COMMAND_APPLY],
|
||||
);
|
||||
nextValue = spec[COMMAND_APPLY](nextValue);
|
||||
}
|
||||
|
||||
@@ -45,16 +45,14 @@ if (__DEV__) {
|
||||
warning(
|
||||
warnedForCreateMixin,
|
||||
'React.createMixin is deprecated and should not be used. You ' +
|
||||
'can use this mixin directly instead.'
|
||||
'can use this mixin directly instead.',
|
||||
);
|
||||
warnedForCreateMixin = true;
|
||||
return mixin;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
var React = {
|
||||
|
||||
// Modern
|
||||
|
||||
Children: {
|
||||
@@ -86,7 +84,6 @@ var React = {
|
||||
DOM: ReactDOMFactories,
|
||||
|
||||
version: ReactVersion,
|
||||
|
||||
};
|
||||
|
||||
module.exports = React;
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
'use strict';
|
||||
|
||||
describe('React', () => {
|
||||
|
||||
var React;
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -25,8 +24,7 @@ describe('React', () => {
|
||||
React.createMixin();
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'React.createMixin is deprecated and should not be used'
|
||||
'React.createMixin is deprecated and should not be used',
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -20,13 +20,11 @@ var traverseAllChildren = require('traverseAllChildren');
|
||||
var twoArgumentPooler = PooledClass.twoArgumentPooler;
|
||||
var fourArgumentPooler = PooledClass.fourArgumentPooler;
|
||||
|
||||
|
||||
var userProvidedKeyEscapeRegex = /\/+/g;
|
||||
function escapeUserProvidedKey(text) {
|
||||
return ('' + text).replace(userProvidedKeyEscapeRegex, '$&/');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* PooledClass representing the bookkeeping associated with performing a child
|
||||
* traversal. Allows avoiding binding callbacks.
|
||||
@@ -68,13 +66,14 @@ function forEachChildren(children, forEachFunc, forEachContext) {
|
||||
if (children == null) {
|
||||
return children;
|
||||
}
|
||||
var traverseContext =
|
||||
ForEachBookKeeping.getPooled(forEachFunc, forEachContext);
|
||||
var traverseContext = ForEachBookKeeping.getPooled(
|
||||
forEachFunc,
|
||||
forEachContext,
|
||||
);
|
||||
traverseAllChildren(children, forEachSingleChild, traverseContext);
|
||||
ForEachBookKeeping.release(traverseContext);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* PooledClass representing the bookkeeping associated with performing a child
|
||||
* mapping. Allows avoiding binding callbacks.
|
||||
@@ -109,7 +108,7 @@ function mapSingleChildIntoContext(bookKeeping, child, childKey) {
|
||||
mappedChild,
|
||||
result,
|
||||
childKey,
|
||||
emptyFunction.thatReturnsArgument
|
||||
emptyFunction.thatReturnsArgument,
|
||||
);
|
||||
} else if (mappedChild != null) {
|
||||
if (ReactElement.isValidElement(mappedChild)) {
|
||||
@@ -118,12 +117,10 @@ function mapSingleChildIntoContext(bookKeeping, child, childKey) {
|
||||
// Keep both the (mapped) and old keys if they differ, just as
|
||||
// traverseAllChildren used to do for objects as children
|
||||
keyPrefix +
|
||||
(
|
||||
(mappedChild.key && (!child || (child.key !== mappedChild.key))) ?
|
||||
escapeUserProvidedKey(mappedChild.key) + '/' :
|
||||
''
|
||||
) +
|
||||
childKey
|
||||
(mappedChild.key && (!child || child.key !== mappedChild.key)
|
||||
? escapeUserProvidedKey(mappedChild.key) + '/'
|
||||
: '') +
|
||||
childKey,
|
||||
);
|
||||
}
|
||||
result.push(mappedChild);
|
||||
@@ -139,7 +136,7 @@ function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) {
|
||||
array,
|
||||
escapedPrefix,
|
||||
func,
|
||||
context
|
||||
context,
|
||||
);
|
||||
traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
|
||||
MapBookKeeping.release(traverseContext);
|
||||
@@ -167,8 +164,6 @@ function mapChildren(children, func, context) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function forEachSingleChildDummy(traverseContext, child, name) {
|
||||
return null;
|
||||
}
|
||||
@@ -186,7 +181,6 @@ function countChildren(children, context) {
|
||||
return traverseAllChildren(children, forEachSingleChildDummy, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Flatten a children object (typically specified as `props.children`) and
|
||||
* return an array with appropriately re-keyed children.
|
||||
@@ -199,12 +193,11 @@ function toArray(children) {
|
||||
children,
|
||||
result,
|
||||
null,
|
||||
emptyFunction.thatReturnsArgument
|
||||
emptyFunction.thatReturnsArgument,
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
var ReactChildren = {
|
||||
forEach: forEachChildren,
|
||||
map: mapChildren,
|
||||
|
||||
@@ -37,7 +37,11 @@ describe('ReactChildren', () => {
|
||||
React.Children.forEach(instance.props.children, callback, context);
|
||||
expect(callback).toHaveBeenCalledWith(simpleKid, 0);
|
||||
callback.calls.reset();
|
||||
var mappedChildren = React.Children.map(instance.props.children, callback, context);
|
||||
var mappedChildren = React.Children.map(
|
||||
instance.props.children,
|
||||
callback,
|
||||
context,
|
||||
);
|
||||
expect(callback).toHaveBeenCalledWith(simpleKid, 0);
|
||||
expect(mappedChildren[0]).toEqual(<span key=".$simple" />);
|
||||
});
|
||||
@@ -54,7 +58,11 @@ describe('ReactChildren', () => {
|
||||
React.Children.forEach(instance.props.children, callback, context);
|
||||
expect(callback).toHaveBeenCalledWith(simpleKid, 0);
|
||||
callback.calls.reset();
|
||||
var mappedChildren = React.Children.map(instance.props.children, callback, context);
|
||||
var mappedChildren = React.Children.map(
|
||||
instance.props.children,
|
||||
callback,
|
||||
context,
|
||||
);
|
||||
expect(callback).toHaveBeenCalledWith(simpleKid, 0);
|
||||
expect(mappedChildren[0]).toEqual(<span key=".0" />);
|
||||
});
|
||||
@@ -71,7 +79,11 @@ describe('ReactChildren', () => {
|
||||
React.Children.forEach(instance.props.children, callback, context);
|
||||
expect(callback).toHaveBeenCalledWith(simpleKid, 0);
|
||||
callback.calls.reset();
|
||||
var mappedChildren = React.Children.map(instance.props.children, callback, context);
|
||||
var mappedChildren = React.Children.map(
|
||||
instance.props.children,
|
||||
callback,
|
||||
context,
|
||||
);
|
||||
expect(callback).toHaveBeenCalledWith(simpleKid, 0);
|
||||
expect(mappedChildren[0]).toEqual(<span key=".$simple" />);
|
||||
});
|
||||
@@ -84,11 +96,10 @@ describe('ReactChildren', () => {
|
||||
var four = <div key="keyFour" />;
|
||||
var context = {};
|
||||
|
||||
var callback =
|
||||
jasmine.createSpy().and.callFake(function(kid) {
|
||||
expect(this).toBe(context);
|
||||
return kid;
|
||||
});
|
||||
var callback = jasmine.createSpy().and.callFake(function(kid) {
|
||||
expect(this).toBe(context);
|
||||
return kid;
|
||||
});
|
||||
|
||||
var instance = (
|
||||
<div>
|
||||
@@ -112,7 +123,11 @@ describe('ReactChildren', () => {
|
||||
React.Children.forEach(instance.props.children, callback, context);
|
||||
assertCalls();
|
||||
|
||||
var mappedChildren = React.Children.map(instance.props.children, callback, context);
|
||||
var mappedChildren = React.Children.map(
|
||||
instance.props.children,
|
||||
callback,
|
||||
context,
|
||||
);
|
||||
assertCalls();
|
||||
expect(mappedChildren).toEqual([
|
||||
<div key=".$keyZero" />,
|
||||
@@ -127,11 +142,10 @@ describe('ReactChildren', () => {
|
||||
var a = <a key="aNode" />;
|
||||
|
||||
var context = {};
|
||||
var callback =
|
||||
jasmine.createSpy().and.callFake(function(kid) {
|
||||
expect(this).toBe(context);
|
||||
return kid;
|
||||
});
|
||||
var callback = jasmine.createSpy().and.callFake(function(kid) {
|
||||
expect(this).toBe(context);
|
||||
return kid;
|
||||
});
|
||||
|
||||
var instance = (
|
||||
<div>
|
||||
@@ -164,7 +178,11 @@ describe('ReactChildren', () => {
|
||||
React.Children.forEach(instance.props.children, callback, context);
|
||||
assertCalls();
|
||||
|
||||
var mappedChildren = React.Children.map(instance.props.children, callback, context);
|
||||
var mappedChildren = React.Children.map(
|
||||
instance.props.children,
|
||||
callback,
|
||||
context,
|
||||
);
|
||||
assertCalls();
|
||||
expect(mappedChildren).toEqual([
|
||||
<div key=".$divNode" />,
|
||||
@@ -189,34 +207,51 @@ describe('ReactChildren', () => {
|
||||
// 2. If grouped in an Array, the `key` prop, falling back to array index
|
||||
|
||||
var context = {};
|
||||
var callback =
|
||||
jasmine.createSpy().and.callFake(function(kid) {
|
||||
return kid;
|
||||
});
|
||||
var callback = jasmine.createSpy().and.callFake(function(kid) {
|
||||
return kid;
|
||||
});
|
||||
|
||||
var instance = (
|
||||
<div>{[
|
||||
ReactFragment.create({
|
||||
firstHalfKey: [zero, one, two],
|
||||
secondHalfKey: [three, four],
|
||||
keyFive: five,
|
||||
}),
|
||||
]}</div>
|
||||
<div>
|
||||
{[
|
||||
ReactFragment.create({
|
||||
firstHalfKey: [zero, one, two],
|
||||
secondHalfKey: [three, four],
|
||||
keyFive: five,
|
||||
}),
|
||||
]}
|
||||
</div>
|
||||
);
|
||||
|
||||
function assertCalls() {
|
||||
expect(callback.calls.count()).toBe(4);
|
||||
expect(callback).toHaveBeenCalledWith(<div key="firstHalfKey/.$keyZero" />, 0);
|
||||
expect(callback).toHaveBeenCalledWith(<div key="firstHalfKey/.$keyTwo" />, 1);
|
||||
expect(callback).toHaveBeenCalledWith(<div key="secondHalfKey/.$keyFour" />, 2);
|
||||
expect(callback).toHaveBeenCalledWith(<div key="keyFive/.$keyFiveInner" />, 3);
|
||||
expect(callback).toHaveBeenCalledWith(
|
||||
<div key="firstHalfKey/.$keyZero" />,
|
||||
0,
|
||||
);
|
||||
expect(callback).toHaveBeenCalledWith(
|
||||
<div key="firstHalfKey/.$keyTwo" />,
|
||||
1,
|
||||
);
|
||||
expect(callback).toHaveBeenCalledWith(
|
||||
<div key="secondHalfKey/.$keyFour" />,
|
||||
2,
|
||||
);
|
||||
expect(callback).toHaveBeenCalledWith(
|
||||
<div key="keyFive/.$keyFiveInner" />,
|
||||
3,
|
||||
);
|
||||
callback.calls.reset();
|
||||
}
|
||||
|
||||
React.Children.forEach(instance.props.children, callback, context);
|
||||
assertCalls();
|
||||
|
||||
var mappedChildren = React.Children.map(instance.props.children, callback, context);
|
||||
var mappedChildren = React.Children.map(
|
||||
instance.props.children,
|
||||
callback,
|
||||
context,
|
||||
);
|
||||
assertCalls();
|
||||
expect(mappedChildren).toEqual([
|
||||
<div key=".0:$firstHalfKey/.$keyZero" />,
|
||||
@@ -230,11 +265,10 @@ describe('ReactChildren', () => {
|
||||
var zeroForceKey = <div key="keyZero" />;
|
||||
var oneForceKey = <div key="keyOne" />;
|
||||
var context = {};
|
||||
var callback =
|
||||
jasmine.createSpy().and.callFake(function(kid) {
|
||||
expect(this).toBe(context);
|
||||
return kid;
|
||||
});
|
||||
var callback = jasmine.createSpy().and.callFake(function(kid) {
|
||||
expect(this).toBe(context);
|
||||
return kid;
|
||||
});
|
||||
|
||||
var forcedKeys = (
|
||||
<div>
|
||||
@@ -252,7 +286,11 @@ describe('ReactChildren', () => {
|
||||
React.Children.forEach(forcedKeys.props.children, callback, context);
|
||||
assertCalls();
|
||||
|
||||
var mappedChildren = React.Children.map(forcedKeys.props.children, callback, context);
|
||||
var mappedChildren = React.Children.map(
|
||||
forcedKeys.props.children,
|
||||
callback,
|
||||
context,
|
||||
);
|
||||
assertCalls();
|
||||
expect(mappedChildren).toEqual([
|
||||
<div key=".$keyZero" />,
|
||||
@@ -278,11 +316,10 @@ describe('ReactChildren', () => {
|
||||
};
|
||||
|
||||
var context = {};
|
||||
var callback =
|
||||
jasmine.createSpy().and.callFake(function(kid) {
|
||||
expect(this).toBe(context);
|
||||
return kid;
|
||||
});
|
||||
var callback = jasmine.createSpy().and.callFake(function(kid) {
|
||||
expect(this).toBe(context);
|
||||
return kid;
|
||||
});
|
||||
|
||||
var instance = (
|
||||
<div>
|
||||
@@ -302,11 +339,15 @@ describe('ReactChildren', () => {
|
||||
assertCalls();
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Warning: Each child in an array or iterator should have a unique "key" prop.'
|
||||
'Warning: Each child in an array or iterator should have a unique "key" prop.',
|
||||
);
|
||||
console.error.calls.reset();
|
||||
|
||||
var mappedChildren = React.Children.map(instance.props.children, callback, context);
|
||||
var mappedChildren = React.Children.map(
|
||||
instance.props.children,
|
||||
callback,
|
||||
context,
|
||||
);
|
||||
assertCalls();
|
||||
expectDev(console.error.calls.count()).toBe(0);
|
||||
expect(mappedChildren).toEqual([
|
||||
@@ -333,11 +374,10 @@ describe('ReactChildren', () => {
|
||||
};
|
||||
|
||||
var context = {};
|
||||
var callback =
|
||||
jasmine.createSpy().and.callFake(function(kid) {
|
||||
expect(this).toBe(context);
|
||||
return kid;
|
||||
});
|
||||
var callback = jasmine.createSpy().and.callFake(function(kid) {
|
||||
expect(this).toBe(context);
|
||||
return kid;
|
||||
});
|
||||
|
||||
var instance = (
|
||||
<div>
|
||||
@@ -356,7 +396,11 @@ describe('ReactChildren', () => {
|
||||
React.Children.forEach(instance.props.children, callback, context);
|
||||
assertCalls();
|
||||
|
||||
var mappedChildren = React.Children.map(instance.props.children, callback, context);
|
||||
var mappedChildren = React.Children.map(
|
||||
instance.props.children,
|
||||
callback,
|
||||
context,
|
||||
);
|
||||
assertCalls();
|
||||
expect(mappedChildren).toEqual([
|
||||
<div key=".$#1" />,
|
||||
@@ -398,7 +442,11 @@ describe('ReactChildren', () => {
|
||||
React.Children.forEach(instance.props.children, callback, context);
|
||||
assertCalls();
|
||||
|
||||
var mappedChildren = React.Children.map(instance.props.children, callback, context);
|
||||
var mappedChildren = React.Children.map(
|
||||
instance.props.children,
|
||||
callback,
|
||||
context,
|
||||
);
|
||||
assertCalls();
|
||||
expect(mappedChildren).toEqual([5, 12, 13]);
|
||||
} finally {
|
||||
@@ -435,12 +483,13 @@ describe('ReactChildren', () => {
|
||||
React.Children.forEach(instance.props.children, callback, context);
|
||||
assertCalls();
|
||||
|
||||
var mappedChildren = React.Children.map(instance.props.children, callback, context);
|
||||
var mappedChildren = React.Children.map(
|
||||
instance.props.children,
|
||||
callback,
|
||||
context,
|
||||
);
|
||||
assertCalls();
|
||||
expect(mappedChildren).toEqual([
|
||||
'a',
|
||||
13,
|
||||
]);
|
||||
expect(mappedChildren).toEqual(['a', 13]);
|
||||
|
||||
delete String.prototype.key;
|
||||
delete Number.prototype.key;
|
||||
@@ -477,8 +526,11 @@ describe('ReactChildren', () => {
|
||||
React.Children.forEach(instance.props.children, callback, scopeTester);
|
||||
expect(lastContext).toBe(scopeTester);
|
||||
|
||||
var mappedChildren =
|
||||
React.Children.map(instance.props.children, callback, scopeTester);
|
||||
var mappedChildren = React.Children.map(
|
||||
instance.props.children,
|
||||
callback,
|
||||
scopeTester,
|
||||
);
|
||||
|
||||
expect(React.Children.count(mappedChildren)).toBe(1);
|
||||
expect(mappedChildren[0]).toBe(scopeTester);
|
||||
@@ -492,9 +544,9 @@ describe('ReactChildren', () => {
|
||||
var four = <div key="keyFour" />;
|
||||
|
||||
var mapped = [
|
||||
<div key="giraffe" />, // Key should be joined to obj key
|
||||
null, // Key should be added even if we don't supply it!
|
||||
<div />, // Key should be added even if not supplied!
|
||||
<div key="giraffe" />, // Key should be joined to obj key
|
||||
null, // Key should be added even if we don't supply it!
|
||||
<div />, // Key should be added even if not supplied!
|
||||
<span />, // Map from null to something.
|
||||
<div key="keyFour" />,
|
||||
];
|
||||
@@ -520,8 +572,7 @@ describe('ReactChildren', () => {
|
||||
expect(callback).toHaveBeenCalledWith(four, 4);
|
||||
callback.calls.reset();
|
||||
|
||||
var mappedChildren =
|
||||
React.Children.map(instance.props.children, callback);
|
||||
var mappedChildren = React.Children.map(instance.props.children, callback);
|
||||
expect(callback.calls.count()).toBe(5);
|
||||
expect(React.Children.count(mappedChildren)).toBe(4);
|
||||
// Keys default to indices.
|
||||
@@ -530,9 +581,7 @@ describe('ReactChildren', () => {
|
||||
mappedChildren[1].key,
|
||||
mappedChildren[2].key,
|
||||
mappedChildren[3].key,
|
||||
]).toEqual(
|
||||
['giraffe/.$keyZero', '.$keyTwo', '.3', '.$keyFour']
|
||||
);
|
||||
]).toEqual(['giraffe/.$keyZero', '.$keyTwo', '.3', '.$keyFour']);
|
||||
|
||||
expect(callback).toHaveBeenCalledWith(zero, 0);
|
||||
expect(callback).toHaveBeenCalledWith(one, 1);
|
||||
@@ -559,15 +608,15 @@ describe('ReactChildren', () => {
|
||||
// 1. If grouped in an Object, the object key combined with `key` prop
|
||||
// 2. If grouped in an Array, the `key` prop, falling back to array index
|
||||
|
||||
var zeroMapped = <div key="giraffe" />; // Key should be overridden
|
||||
var twoMapped = <div />; // Key should be added even if not supplied!
|
||||
var zeroMapped = <div key="giraffe" />; // Key should be overridden
|
||||
var twoMapped = <div />; // Key should be added even if not supplied!
|
||||
var fourMapped = <div key="keyFour" />;
|
||||
var fiveMapped = <div />;
|
||||
|
||||
var callback = jasmine.createSpy().and.callFake(function(kid, index) {
|
||||
return index === 0 ? zeroMapped :
|
||||
index === 1 ? twoMapped :
|
||||
index === 2 ? fourMapped : fiveMapped;
|
||||
return index === 0
|
||||
? zeroMapped
|
||||
: index === 1 ? twoMapped : index === 2 ? fourMapped : fiveMapped;
|
||||
});
|
||||
|
||||
var frag = ReactFragment.create({
|
||||
@@ -577,12 +626,7 @@ describe('ReactChildren', () => {
|
||||
});
|
||||
var instance = <div>{[frag]}</div>;
|
||||
|
||||
expect([
|
||||
frag[0].key,
|
||||
frag[1].key,
|
||||
frag[2].key,
|
||||
frag[3].key,
|
||||
]).toEqual([
|
||||
expect([frag[0].key, frag[1].key, frag[2].key, frag[3].key]).toEqual([
|
||||
'firstHalfKey/.$keyZero',
|
||||
'firstHalfKey/.$keyTwo',
|
||||
'secondHalfKey/.$keyFour',
|
||||
@@ -618,9 +662,13 @@ describe('ReactChildren', () => {
|
||||
'.0:$keyFive/.$keyFiveInner',
|
||||
]);
|
||||
|
||||
expect(mappedChildren[0]).toEqual(<div key="giraffe/.0:$firstHalfKey/.$keyZero" />);
|
||||
expect(mappedChildren[0]).toEqual(
|
||||
<div key="giraffe/.0:$firstHalfKey/.$keyZero" />,
|
||||
);
|
||||
expect(mappedChildren[1]).toEqual(<div key=".0:$firstHalfKey/.$keyTwo" />);
|
||||
expect(mappedChildren[2]).toEqual(<div key="keyFour/.0:$secondHalfKey/.$keyFour" />);
|
||||
expect(mappedChildren[2]).toEqual(
|
||||
<div key="keyFour/.0:$secondHalfKey/.$keyFour" />,
|
||||
);
|
||||
expect(mappedChildren[3]).toEqual(<div key=".0:$keyFive/.$keyFiveInner" />);
|
||||
});
|
||||
|
||||
@@ -645,21 +693,24 @@ describe('ReactChildren', () => {
|
||||
);
|
||||
|
||||
var expectedForcedKeys = ['giraffe/.$keyZero', '.$keyOne'];
|
||||
var mappedChildrenForcedKeys =
|
||||
React.Children.map(forcedKeys.props.children, mapFn);
|
||||
var mappedForcedKeys = mappedChildrenForcedKeys.map((c) => c.key);
|
||||
var mappedChildrenForcedKeys = React.Children.map(
|
||||
forcedKeys.props.children,
|
||||
mapFn,
|
||||
);
|
||||
var mappedForcedKeys = mappedChildrenForcedKeys.map(c => c.key);
|
||||
expect(mappedForcedKeys).toEqual(expectedForcedKeys);
|
||||
|
||||
var expectedRemappedForcedKeys = [
|
||||
'giraffe/.$giraffe/.$keyZero',
|
||||
'.$.$keyOne',
|
||||
];
|
||||
var remappedChildrenForcedKeys =
|
||||
React.Children.map(mappedChildrenForcedKeys, mapFn);
|
||||
expect(
|
||||
remappedChildrenForcedKeys.map((c) => c.key)
|
||||
).toEqual(expectedRemappedForcedKeys);
|
||||
|
||||
var remappedChildrenForcedKeys = React.Children.map(
|
||||
mappedChildrenForcedKeys,
|
||||
mapFn,
|
||||
);
|
||||
expect(remappedChildrenForcedKeys.map(c => c.key)).toEqual(
|
||||
expectedRemappedForcedKeys,
|
||||
);
|
||||
});
|
||||
|
||||
it('should not throw if key provided is a dupe with array key', () => {
|
||||
@@ -694,10 +745,8 @@ describe('ReactChildren', () => {
|
||||
element => element,
|
||||
);
|
||||
|
||||
var mappedWithClone = React.Children.map(
|
||||
instance.props.children,
|
||||
element => React.cloneElement(element),
|
||||
);
|
||||
var mappedWithClone = React.Children.map(instance.props.children, element =>
|
||||
React.cloneElement(element));
|
||||
|
||||
expect(mapped[0].key).toBe(mappedWithClone[0].key);
|
||||
});
|
||||
@@ -714,10 +763,8 @@ describe('ReactChildren', () => {
|
||||
element => element,
|
||||
);
|
||||
|
||||
var mappedWithClone = React.Children.map(
|
||||
instance.props.children,
|
||||
element => React.cloneElement(element, {key: 'unique'}),
|
||||
);
|
||||
var mappedWithClone = React.Children.map(instance.props.children, element =>
|
||||
React.cloneElement(element, {key: 'unique'}));
|
||||
|
||||
expect(mapped[0].key).toBe(mappedWithClone[0].key);
|
||||
});
|
||||
@@ -773,14 +820,16 @@ describe('ReactChildren', () => {
|
||||
// 2. If grouped in an Array, the `key` prop, falling back to array index
|
||||
|
||||
var instance = (
|
||||
<div>{[
|
||||
ReactFragment.create({
|
||||
firstHalfKey: [zero, one, two],
|
||||
secondHalfKey: [three, four],
|
||||
keyFive: five,
|
||||
}),
|
||||
null,
|
||||
]}</div>
|
||||
<div>
|
||||
{[
|
||||
ReactFragment.create({
|
||||
firstHalfKey: [zero, one, two],
|
||||
secondHalfKey: [three, four],
|
||||
keyFive: five,
|
||||
}),
|
||||
null,
|
||||
]}
|
||||
</div>
|
||||
);
|
||||
var numberOfChildren = React.Children.count(instance.props.children);
|
||||
expect(numberOfChildren).toBe(5);
|
||||
@@ -792,10 +841,8 @@ describe('ReactChildren', () => {
|
||||
|
||||
expect(React.Children.toArray(<div />).length).toBe(1);
|
||||
expect(React.Children.toArray([<div />]).length).toBe(1);
|
||||
expect(
|
||||
React.Children.toArray(<div />)[0].key
|
||||
).toBe(
|
||||
React.Children.toArray([<div />])[0].key
|
||||
expect(React.Children.toArray(<div />)[0].key).toBe(
|
||||
React.Children.toArray([<div />])[0].key,
|
||||
);
|
||||
|
||||
var flattened = React.Children.toArray([
|
||||
@@ -819,9 +866,10 @@ describe('ReactChildren', () => {
|
||||
expect(flattened[5].key).toBe(reversed[3].key);
|
||||
|
||||
// null/undefined/bool are all omitted
|
||||
expect(React.Children.toArray([1, 'two', null, undefined, true])).toEqual(
|
||||
[1, 'two']
|
||||
);
|
||||
expect(React.Children.toArray([1, 'two', null, undefined, true])).toEqual([
|
||||
1,
|
||||
'two',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should throw on object', () => {
|
||||
@@ -829,9 +877,9 @@ describe('ReactChildren', () => {
|
||||
React.Children.forEach({a: 1, b: 2}, function() {}, null);
|
||||
}).toThrowError(
|
||||
'Objects are not valid as a React child (found: object with keys ' +
|
||||
'{a, b}). If you meant to render a collection of children, use an ' +
|
||||
'array instead or wrap the object using createFragment(object) from ' +
|
||||
'the React add-ons.'
|
||||
'{a, b}). If you meant to render a collection of children, use an ' +
|
||||
'array instead or wrap the object using createFragment(object) from ' +
|
||||
'the React add-ons.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -842,8 +890,8 @@ describe('ReactChildren', () => {
|
||||
React.Children.forEach(/abc/, function() {}, null);
|
||||
}).toThrowError(
|
||||
'Objects are not valid as a React child (found: /abc/). If you meant ' +
|
||||
'to render a collection of children, use an array instead or wrap the ' +
|
||||
'object using createFragment(object) from the React add-ons.'
|
||||
'to render a collection of children, use an array instead or wrap the ' +
|
||||
'object using createFragment(object) from the React add-ons.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
'use strict';
|
||||
|
||||
describe('onlyChild', () => {
|
||||
|
||||
var React;
|
||||
var ReactFragment;
|
||||
var onlyChild;
|
||||
@@ -35,60 +34,64 @@ describe('onlyChild', () => {
|
||||
|
||||
it('should fail when passed two children', () => {
|
||||
expect(function() {
|
||||
var instance =
|
||||
var instance = (
|
||||
<WrapComponent>
|
||||
<div />
|
||||
<span />
|
||||
</WrapComponent>;
|
||||
</WrapComponent>
|
||||
);
|
||||
onlyChild(instance.props.children);
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('should fail when passed nully values', () => {
|
||||
expect(function() {
|
||||
var instance =
|
||||
var instance = (
|
||||
<WrapComponent>
|
||||
{null}
|
||||
</WrapComponent>;
|
||||
</WrapComponent>
|
||||
);
|
||||
onlyChild(instance.props.children);
|
||||
}).toThrow();
|
||||
|
||||
expect(function() {
|
||||
var instance =
|
||||
var instance = (
|
||||
<WrapComponent>
|
||||
{undefined}
|
||||
</WrapComponent>;
|
||||
</WrapComponent>
|
||||
);
|
||||
onlyChild(instance.props.children);
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('should fail when key/value objects', () => {
|
||||
expect(function() {
|
||||
var instance =
|
||||
var instance = (
|
||||
<WrapComponent>
|
||||
{ReactFragment.create({oneThing: <span />})}
|
||||
</WrapComponent>;
|
||||
</WrapComponent>
|
||||
);
|
||||
onlyChild(instance.props.children);
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
|
||||
it('should not fail when passed interpolated single child', () => {
|
||||
expect(function() {
|
||||
var instance =
|
||||
var instance = (
|
||||
<WrapComponent>
|
||||
{<span />}
|
||||
</WrapComponent>;
|
||||
</WrapComponent>
|
||||
);
|
||||
onlyChild(instance.props.children);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('should return the only child', () => {
|
||||
var instance =
|
||||
var instance = (
|
||||
<WrapComponent>
|
||||
<span />
|
||||
</WrapComponent>;
|
||||
</WrapComponent>
|
||||
);
|
||||
expect(onlyChild(instance.props.children)).toEqual(<span />);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -31,7 +31,7 @@ var invariant = require('fbjs/lib/invariant');
|
||||
function onlyChild(children) {
|
||||
invariant(
|
||||
ReactElement.isValidElement(children),
|
||||
'React.Children.only expected to receive a single React element child.'
|
||||
'React.Children.only expected to receive a single React element child.',
|
||||
);
|
||||
return children;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,9 @@ describe('ReactContextValidator', () => {
|
||||
},
|
||||
});
|
||||
|
||||
var instance = ReactTestUtils.renderIntoDocument(<ComponentInFooBarContext />);
|
||||
var instance = ReactTestUtils.renderIntoDocument(
|
||||
<ComponentInFooBarContext />,
|
||||
);
|
||||
expect(instance.refs.child.context).toEqual({foo: 'abc'});
|
||||
});
|
||||
|
||||
@@ -184,9 +186,9 @@ describe('ReactContextValidator', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
|
||||
'Warning: Failed context type: ' +
|
||||
'The context `foo` is marked as required in `Component`, but its value ' +
|
||||
'is `undefined`.\n' +
|
||||
' in Component (at **)'
|
||||
'The context `foo` is marked as required in `Component`, but its value ' +
|
||||
'is `undefined`.\n' +
|
||||
' in Component (at **)',
|
||||
);
|
||||
|
||||
var ComponentInFooStringContext = React.createClass({
|
||||
@@ -206,7 +208,7 @@ describe('ReactContextValidator', () => {
|
||||
});
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
<ComponentInFooStringContext fooValue={'bar'} />
|
||||
<ComponentInFooStringContext fooValue={'bar'} />,
|
||||
);
|
||||
|
||||
// Previous call should not error
|
||||
@@ -228,15 +230,17 @@ describe('ReactContextValidator', () => {
|
||||
},
|
||||
});
|
||||
|
||||
ReactTestUtils.renderIntoDocument(<ComponentInFooNumberContext fooValue={123} />);
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
<ComponentInFooNumberContext fooValue={123} />,
|
||||
);
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(2);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
|
||||
'Warning: Failed context type: ' +
|
||||
'Invalid context `foo` of type `number` supplied ' +
|
||||
'to `Component`, expected `string`.\n' +
|
||||
' in Component (at **)\n' +
|
||||
' in ComponentInFooNumberContext (at **)'
|
||||
'Invalid context `foo` of type `number` supplied ' +
|
||||
'to `Component`, expected `string`.\n' +
|
||||
' in Component (at **)\n' +
|
||||
' in ComponentInFooNumberContext (at **)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -262,9 +266,9 @@ describe('ReactContextValidator', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
|
||||
'Warning: Failed child context type: ' +
|
||||
'The child context `foo` is marked as required in `Component`, but its ' +
|
||||
'value is `undefined`.\n' +
|
||||
' in Component (at **)'
|
||||
'The child context `foo` is marked as required in `Component`, but its ' +
|
||||
'value is `undefined`.\n' +
|
||||
' in Component (at **)',
|
||||
);
|
||||
|
||||
ReactTestUtils.renderIntoDocument(<Component testContext={{foo: 123}} />);
|
||||
@@ -272,18 +276,16 @@ describe('ReactContextValidator', () => {
|
||||
expectDev(console.error.calls.count()).toBe(2);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
|
||||
'Warning: Failed child context type: ' +
|
||||
'Invalid child context `foo` of type `number` ' +
|
||||
'supplied to `Component`, expected `string`.\n' +
|
||||
' in Component (at **)'
|
||||
'Invalid child context `foo` of type `number` ' +
|
||||
'supplied to `Component`, expected `string`.\n' +
|
||||
' in Component (at **)',
|
||||
);
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
<Component testContext={{foo: 'foo', bar: 123}} />
|
||||
<Component testContext={{foo: 'foo', bar: 123}} />,
|
||||
);
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
<Component testContext={{foo: 'foo'}} />
|
||||
);
|
||||
ReactTestUtils.renderIntoDocument(<Component testContext={{foo: 'foo'}} />);
|
||||
|
||||
// Previous calls should not log errors
|
||||
expectDev(console.error.calls.count()).toBe(2);
|
||||
@@ -315,8 +317,8 @@ describe('ReactContextValidator', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
|
||||
'Warning: ComponentA.childContextTypes is specified but there is no ' +
|
||||
'getChildContext() method on the instance. You can either define ' +
|
||||
'getChildContext() on ComponentA or remove childContextTypes from it.'
|
||||
'getChildContext() method on the instance. You can either define ' +
|
||||
'getChildContext() on ComponentA or remove childContextTypes from it.',
|
||||
);
|
||||
|
||||
// Warnings should be deduped by component type
|
||||
@@ -326,8 +328,8 @@ describe('ReactContextValidator', () => {
|
||||
expectDev(console.error.calls.count()).toBe(2);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
|
||||
'Warning: ComponentB.childContextTypes is specified but there is no ' +
|
||||
'getChildContext() method on the instance. You can either define ' +
|
||||
'getChildContext() on ComponentB or remove childContextTypes from it.'
|
||||
'getChildContext() method on the instance. You can either define ' +
|
||||
'getChildContext() on ComponentB or remove childContextTypes from it.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -375,5 +377,4 @@ describe('ReactContextValidator', () => {
|
||||
expect(childContext.bar).toBeUndefined();
|
||||
expect(childContext.foo).toBe('FOO');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -36,23 +36,19 @@ type SpecPolicy =
|
||||
/**
|
||||
* These methods may be defined only once by the class specification or mixin.
|
||||
*/
|
||||
'DEFINE_ONCE' |
|
||||
/**
|
||||
| 'DEFINE_ONCE' /**
|
||||
* These methods may be defined by both the class specification and mixins.
|
||||
* Subsequent definitions will be chained. These methods must return void.
|
||||
*/
|
||||
'DEFINE_MANY' |
|
||||
/**
|
||||
| 'DEFINE_MANY' /**
|
||||
* These methods are overriding the base class.
|
||||
*/
|
||||
'OVERRIDE_BASE' |
|
||||
/**
|
||||
| 'OVERRIDE_BASE' /**
|
||||
* These methods are similar to DEFINE_MANY, except we assume they return
|
||||
* objects. We try to merge the keys of the return values of all the mixed in
|
||||
* functions. If there is a key conflict we throw.
|
||||
*/
|
||||
'DEFINE_MANY_MERGED';
|
||||
|
||||
| 'DEFINE_MANY_MERGED';
|
||||
|
||||
/**
|
||||
* Composite components are higher-level components that compose other composite
|
||||
@@ -77,7 +73,6 @@ type SpecPolicy =
|
||||
* @internal
|
||||
*/
|
||||
var ReactClassInterface: {[key: string]: SpecPolicy} = {
|
||||
|
||||
/**
|
||||
* An array of Mixin objects to include when defining your component.
|
||||
*
|
||||
@@ -172,8 +167,6 @@ var ReactClassInterface: {[key: string]: SpecPolicy} = {
|
||||
*/
|
||||
render: 'DEFINE_ONCE',
|
||||
|
||||
|
||||
|
||||
// ==== Delegate methods ====
|
||||
|
||||
/**
|
||||
@@ -284,8 +277,6 @@ var ReactClassInterface: {[key: string]: SpecPolicy} = {
|
||||
*/
|
||||
componentWillUnmount: 'DEFINE_MANY',
|
||||
|
||||
|
||||
|
||||
// ==== Advanced methods ====
|
||||
|
||||
/**
|
||||
@@ -299,7 +290,6 @@ var ReactClassInterface: {[key: string]: SpecPolicy} = {
|
||||
* @overridable
|
||||
*/
|
||||
updateComponent: 'OVERRIDE_BASE',
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -324,30 +314,22 @@ var RESERVED_SPEC_KEYS = {
|
||||
},
|
||||
childContextTypes: function(Constructor, childContextTypes) {
|
||||
if (__DEV__) {
|
||||
validateTypeDef(
|
||||
Constructor,
|
||||
childContextTypes,
|
||||
'child context'
|
||||
);
|
||||
validateTypeDef(Constructor, childContextTypes, 'child context');
|
||||
}
|
||||
Constructor.childContextTypes = Object.assign(
|
||||
{},
|
||||
Constructor.childContextTypes,
|
||||
childContextTypes
|
||||
childContextTypes,
|
||||
);
|
||||
},
|
||||
contextTypes: function(Constructor, contextTypes) {
|
||||
if (__DEV__) {
|
||||
validateTypeDef(
|
||||
Constructor,
|
||||
contextTypes,
|
||||
'context'
|
||||
);
|
||||
validateTypeDef(Constructor, contextTypes, 'context');
|
||||
}
|
||||
Constructor.contextTypes = Object.assign(
|
||||
{},
|
||||
Constructor.contextTypes,
|
||||
contextTypes
|
||||
contextTypes,
|
||||
);
|
||||
},
|
||||
/**
|
||||
@@ -358,7 +340,7 @@ var RESERVED_SPEC_KEYS = {
|
||||
if (Constructor.getDefaultProps) {
|
||||
Constructor.getDefaultProps = createMergedResultFunction(
|
||||
Constructor.getDefaultProps,
|
||||
getDefaultProps
|
||||
getDefaultProps,
|
||||
);
|
||||
} else {
|
||||
Constructor.getDefaultProps = getDefaultProps;
|
||||
@@ -366,17 +348,9 @@ var RESERVED_SPEC_KEYS = {
|
||||
},
|
||||
propTypes: function(Constructor, propTypes) {
|
||||
if (__DEV__) {
|
||||
validateTypeDef(
|
||||
Constructor,
|
||||
propTypes,
|
||||
'prop'
|
||||
);
|
||||
validateTypeDef(Constructor, propTypes, 'prop');
|
||||
}
|
||||
Constructor.propTypes = Object.assign(
|
||||
{},
|
||||
Constructor.propTypes,
|
||||
propTypes
|
||||
);
|
||||
Constructor.propTypes = Object.assign({}, Constructor.propTypes, propTypes);
|
||||
},
|
||||
statics: function(Constructor, statics) {
|
||||
mixStaticSpecIntoComponent(Constructor, statics);
|
||||
@@ -384,11 +358,7 @@ var RESERVED_SPEC_KEYS = {
|
||||
autobind: function() {}, // noop
|
||||
};
|
||||
|
||||
function validateTypeDef(
|
||||
Constructor,
|
||||
typeDef,
|
||||
location: string,
|
||||
) {
|
||||
function validateTypeDef(Constructor, typeDef, location: string) {
|
||||
for (var propName in typeDef) {
|
||||
if (typeDef.hasOwnProperty(propName)) {
|
||||
// use a warning instead of an invariant so components
|
||||
@@ -396,40 +366,39 @@ function validateTypeDef(
|
||||
warning(
|
||||
typeof typeDef[propName] === 'function',
|
||||
'%s: %s type `%s` is invalid; it must be a function, usually from ' +
|
||||
'React.PropTypes.',
|
||||
'React.PropTypes.',
|
||||
Constructor.displayName || 'ReactClass',
|
||||
location,
|
||||
propName
|
||||
propName,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function validateMethodOverride(isAlreadyDefined, name) {
|
||||
var specPolicy = ReactClassInterface.hasOwnProperty(name) ?
|
||||
ReactClassInterface[name] :
|
||||
null;
|
||||
var specPolicy = ReactClassInterface.hasOwnProperty(name)
|
||||
? ReactClassInterface[name]
|
||||
: null;
|
||||
|
||||
// Disallow overriding of base class methods unless explicitly allowed.
|
||||
if (ReactClassMixin.hasOwnProperty(name)) {
|
||||
invariant(
|
||||
specPolicy === 'OVERRIDE_BASE',
|
||||
'ReactClassInterface: You are attempting to override ' +
|
||||
'`%s` from your class specification. Ensure that your method names ' +
|
||||
'do not overlap with React methods.',
|
||||
name
|
||||
'`%s` from your class specification. Ensure that your method names ' +
|
||||
'do not overlap with React methods.',
|
||||
name,
|
||||
);
|
||||
}
|
||||
|
||||
// Disallow defining methods more than once unless explicitly allowed.
|
||||
if (isAlreadyDefined) {
|
||||
invariant(
|
||||
specPolicy === 'DEFINE_MANY' ||
|
||||
specPolicy === 'DEFINE_MANY_MERGED',
|
||||
specPolicy === 'DEFINE_MANY' || specPolicy === 'DEFINE_MANY_MERGED',
|
||||
'ReactClassInterface: You are attempting to define ' +
|
||||
'`%s` on your component more than once. This conflict may be due ' +
|
||||
'to a mixin.',
|
||||
name
|
||||
'`%s` on your component more than once. This conflict may be due ' +
|
||||
'to a mixin.',
|
||||
name,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -446,12 +415,12 @@ function mixSpecIntoComponent(Constructor, spec) {
|
||||
|
||||
warning(
|
||||
isMixinValid,
|
||||
'%s: You\'re attempting to include a mixin that is either null ' +
|
||||
'or not an object. Check the mixins included by the component, ' +
|
||||
'as well as any mixins they include themselves. ' +
|
||||
'Expected object but got %s.',
|
||||
"%s: You're attempting to include a mixin that is either null " +
|
||||
'or not an object. Check the mixins included by the component, ' +
|
||||
'as well as any mixins they include themselves. ' +
|
||||
'Expected object but got %s.',
|
||||
Constructor.displayName || 'ReactClass',
|
||||
spec === null ? null : typeofSpec
|
||||
spec === null ? null : typeofSpec,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -460,14 +429,14 @@ function mixSpecIntoComponent(Constructor, spec) {
|
||||
|
||||
invariant(
|
||||
typeof spec !== 'function',
|
||||
'ReactClass: You\'re attempting to ' +
|
||||
'use a component class or function as a mixin. Instead, just use a ' +
|
||||
'regular object.'
|
||||
"ReactClass: You're attempting to " +
|
||||
'use a component class or function as a mixin. Instead, just use a ' +
|
||||
'regular object.',
|
||||
);
|
||||
invariant(
|
||||
!ReactElement.isValidElement(spec),
|
||||
'ReactClass: You\'re attempting to ' +
|
||||
'use a component as a mixin. Instead, just use a regular object.'
|
||||
"ReactClass: You're attempting to " +
|
||||
'use a component as a mixin. Instead, just use a regular object.',
|
||||
);
|
||||
|
||||
var proto = Constructor.prototype;
|
||||
@@ -501,11 +470,9 @@ function mixSpecIntoComponent(Constructor, spec) {
|
||||
// The following member methods should not be automatically bound:
|
||||
// 1. Expected ReactClass methods (in the "interface").
|
||||
// 2. Overridden methods (that were mixed in).
|
||||
var isReactClassMethod =
|
||||
ReactClassInterface.hasOwnProperty(name);
|
||||
var isReactClassMethod = ReactClassInterface.hasOwnProperty(name);
|
||||
var isFunction = typeof property === 'function';
|
||||
var shouldAutoBind =
|
||||
isFunction &&
|
||||
var shouldAutoBind = isFunction &&
|
||||
!isReactClassMethod &&
|
||||
!isAlreadyDefined &&
|
||||
spec.autobind !== false;
|
||||
@@ -519,14 +486,13 @@ function mixSpecIntoComponent(Constructor, spec) {
|
||||
|
||||
// These cases should already be caught by validateMethodOverride.
|
||||
invariant(
|
||||
isReactClassMethod && (
|
||||
specPolicy === 'DEFINE_MANY_MERGED' ||
|
||||
specPolicy === 'DEFINE_MANY'
|
||||
),
|
||||
isReactClassMethod &&
|
||||
(specPolicy === 'DEFINE_MANY_MERGED' ||
|
||||
specPolicy === 'DEFINE_MANY'),
|
||||
'ReactClass: Unexpected spec policy %s for key %s ' +
|
||||
'when mixing in component specs.',
|
||||
'when mixing in component specs.',
|
||||
specPolicy,
|
||||
name
|
||||
name,
|
||||
);
|
||||
|
||||
// For methods which are defined more than once, call the existing
|
||||
@@ -565,19 +531,19 @@ function mixStaticSpecIntoComponent(Constructor, statics) {
|
||||
invariant(
|
||||
!isReserved,
|
||||
'ReactClass: You are attempting to define a reserved ' +
|
||||
'property, `%s`, that shouldn\'t be on the "statics" key. Define it ' +
|
||||
'as an instance property instead; it will still be accessible on the ' +
|
||||
'constructor.',
|
||||
name
|
||||
'property, `%s`, that shouldn\'t be on the "statics" key. Define it ' +
|
||||
'as an instance property instead; it will still be accessible on the ' +
|
||||
'constructor.',
|
||||
name,
|
||||
);
|
||||
|
||||
var isInherited = name in Constructor;
|
||||
invariant(
|
||||
!isInherited,
|
||||
'ReactClass: You are attempting to define ' +
|
||||
'`%s` on your component more than once. This conflict may be ' +
|
||||
'due to a mixin.',
|
||||
name
|
||||
'`%s` on your component more than once. This conflict may be ' +
|
||||
'due to a mixin.',
|
||||
name,
|
||||
);
|
||||
Constructor[name] = property;
|
||||
}
|
||||
@@ -593,7 +559,7 @@ function mixStaticSpecIntoComponent(Constructor, statics) {
|
||||
function mergeIntoWithNoDuplicateKeys(one, two) {
|
||||
invariant(
|
||||
one && two && typeof one === 'object' && typeof two === 'object',
|
||||
'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.'
|
||||
'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.',
|
||||
);
|
||||
|
||||
for (var key in two) {
|
||||
@@ -601,11 +567,11 @@ function mergeIntoWithNoDuplicateKeys(one, two) {
|
||||
invariant(
|
||||
one[key] === undefined,
|
||||
'mergeIntoWithNoDuplicateKeys(): ' +
|
||||
'Tried to merge two objects with the same key: `%s`. This conflict ' +
|
||||
'may be due to a mixin; in particular, this may be caused by two ' +
|
||||
'getInitialState() or getDefaultProps() methods returning objects ' +
|
||||
'with clashing keys.',
|
||||
key
|
||||
'Tried to merge two objects with the same key: `%s`. This conflict ' +
|
||||
'may be due to a mixin; in particular, this may be caused by two ' +
|
||||
'getInitialState() or getDefaultProps() methods returning objects ' +
|
||||
'with clashing keys.',
|
||||
key,
|
||||
);
|
||||
one[key] = two[key];
|
||||
}
|
||||
@@ -675,16 +641,16 @@ function bindAutoBindMethod(component, method) {
|
||||
warning(
|
||||
false,
|
||||
'bind(): React component methods may only be bound to the ' +
|
||||
'component instance.\n\nSee %s',
|
||||
componentName
|
||||
'component instance.\n\nSee %s',
|
||||
componentName,
|
||||
);
|
||||
} else if (!args.length) {
|
||||
warning(
|
||||
false,
|
||||
'bind(): You are binding a component method to the component. ' +
|
||||
'React does this for you automatically in a high-performance ' +
|
||||
'way, so you can safely remove this call.\n\nSee %s',
|
||||
componentName
|
||||
'React does this for you automatically in a high-performance ' +
|
||||
'way, so you can safely remove this call.\n\nSee %s',
|
||||
componentName,
|
||||
);
|
||||
return boundMethod;
|
||||
}
|
||||
@@ -708,10 +674,7 @@ function bindAutoBindMethods(component) {
|
||||
for (var i = 0; i < pairs.length; i += 2) {
|
||||
var autoBindKey = pairs[i];
|
||||
var method = pairs[i + 1];
|
||||
component[autoBindKey] = bindAutoBindMethod(
|
||||
component,
|
||||
method
|
||||
);
|
||||
component[autoBindKey] = bindAutoBindMethod(component, method);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -720,7 +683,6 @@ function bindAutoBindMethods(component) {
|
||||
* therefore not already part of the modern ReactComponent.
|
||||
*/
|
||||
var ReactClassMixin = {
|
||||
|
||||
/**
|
||||
* TODO: This will be deprecated because state should always keep a consistent
|
||||
* type signature and the only use case for this, is to avoid that.
|
||||
@@ -744,7 +706,7 @@ var ReactClassComponent = function() {};
|
||||
Object.assign(
|
||||
ReactClassComponent.prototype,
|
||||
ReactComponent.prototype,
|
||||
ReactClassMixin
|
||||
ReactClassMixin,
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -753,7 +715,6 @@ Object.assign(
|
||||
* @class ReactClass
|
||||
*/
|
||||
var ReactClass = {
|
||||
|
||||
/**
|
||||
* Creates a composite component class given a class specification.
|
||||
* See https://facebook.github.io/react/docs/react-api.html#createclass
|
||||
@@ -774,7 +735,7 @@ var ReactClass = {
|
||||
warning(
|
||||
this instanceof Constructor,
|
||||
'Something is calling a React component directly. Use a factory or ' +
|
||||
'JSX instead. See: https://fb.me/react-legacyfactory'
|
||||
'JSX instead. See: https://fb.me/react-legacyfactory',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -796,8 +757,9 @@ var ReactClass = {
|
||||
var initialState = this.getInitialState ? this.getInitialState() : null;
|
||||
if (__DEV__) {
|
||||
// We allow auto-mocks to proceed as if they're returning null.
|
||||
if (initialState === undefined &&
|
||||
this.getInitialState._isMockFunction) {
|
||||
if (
|
||||
initialState === undefined && this.getInitialState._isMockFunction
|
||||
) {
|
||||
// This is probably bad practice. Consider warning here and
|
||||
// deprecating this convenience.
|
||||
initialState = null;
|
||||
@@ -806,7 +768,7 @@ var ReactClass = {
|
||||
invariant(
|
||||
typeof initialState === 'object' && !Array.isArray(initialState),
|
||||
'%s.getInitialState(): must return an object or null',
|
||||
Constructor.displayName || 'ReactCompositeComponent'
|
||||
Constructor.displayName || 'ReactCompositeComponent',
|
||||
);
|
||||
|
||||
this.state = initialState;
|
||||
@@ -837,23 +799,23 @@ var ReactClass = {
|
||||
|
||||
invariant(
|
||||
Constructor.prototype.render,
|
||||
'createClass(...): Class specification must implement a `render` method.'
|
||||
'createClass(...): Class specification must implement a `render` method.',
|
||||
);
|
||||
|
||||
if (__DEV__) {
|
||||
warning(
|
||||
!Constructor.prototype.componentShouldUpdate,
|
||||
'%s has a method called ' +
|
||||
'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
|
||||
'The name is phrased as a question because the function is ' +
|
||||
'expected to return a value.',
|
||||
spec.displayName || 'A component'
|
||||
'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
|
||||
'The name is phrased as a question because the function is ' +
|
||||
'expected to return a value.',
|
||||
spec.displayName || 'A component',
|
||||
);
|
||||
warning(
|
||||
!Constructor.prototype.componentWillRecieveProps,
|
||||
'%s has a method called ' +
|
||||
'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?',
|
||||
spec.displayName || 'A component'
|
||||
'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?',
|
||||
spec.displayName || 'A component',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -866,7 +828,6 @@ var ReactClass = {
|
||||
|
||||
return Constructor;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
module.exports = ReactClass;
|
||||
|
||||
@@ -16,9 +16,7 @@ var ReactTestUtils = require('ReactTestUtils');
|
||||
|
||||
// TODO: Test render and all stock methods.
|
||||
describe('autobinding', () => {
|
||||
|
||||
it('Holds reference to instance', () => {
|
||||
|
||||
var mouseDidEnter = jest.fn();
|
||||
var mouseDidLeave = jest.fn();
|
||||
var mouseDidClick = jest.fn();
|
||||
@@ -115,7 +113,7 @@ describe('autobinding', () => {
|
||||
spyOn(console, 'error');
|
||||
|
||||
var TestBindComponent = React.createClass({
|
||||
handleClick: function() { },
|
||||
handleClick: function() {},
|
||||
render: function() {
|
||||
return <div onClick={this.handleClick.bind(this)} />;
|
||||
},
|
||||
@@ -126,8 +124,8 @@ describe('autobinding', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: bind(): You are binding a component method to the component. ' +
|
||||
'React does this for you automatically in a high-performance ' +
|
||||
'way, so you can safely remove this call.\n\nSee TestBindComponent'
|
||||
'React does this for you automatically in a high-performance ' +
|
||||
'way, so you can safely remove this call.\n\nSee TestBindComponent',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -141,9 +139,7 @@ describe('autobinding', () => {
|
||||
componentDidMount: function() {
|
||||
this.setState({foo: 2}, this.handleUpdate);
|
||||
},
|
||||
handleUpdate: function() {
|
||||
|
||||
},
|
||||
handleUpdate: function() {},
|
||||
render: function() {
|
||||
return <div onClick={this.handleClick} />;
|
||||
},
|
||||
@@ -153,5 +149,4 @@ describe('autobinding', () => {
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(0);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -16,9 +16,7 @@ var ReactTestUtils = require('ReactTestUtils');
|
||||
|
||||
// TODO: Test render and all stock methods.
|
||||
describe('autobind optout', () => {
|
||||
|
||||
it('should work with manual binding', () => {
|
||||
|
||||
var mouseDidEnter = jest.fn();
|
||||
var mouseDidLeave = jest.fn();
|
||||
var mouseDidClick = jest.fn();
|
||||
@@ -39,7 +37,7 @@ describe('autobind optout', () => {
|
||||
onMouseOver={this.onMouseEnter.bind(this)}
|
||||
onMouseOut={this.onMouseLeave.bind(this)}
|
||||
onClick={this.onClick.bind(this)}
|
||||
/>
|
||||
/>
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -95,12 +93,7 @@ describe('autobind optout', () => {
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div
|
||||
ref="child"
|
||||
onClick={this.onClick}
|
||||
/>
|
||||
);
|
||||
return <div ref="child" onClick={this.onClick} />;
|
||||
},
|
||||
});
|
||||
|
||||
@@ -178,7 +171,7 @@ describe('autobind optout', () => {
|
||||
|
||||
var TestBindComponent = React.createClass({
|
||||
autobind: false,
|
||||
handleClick: function() { },
|
||||
handleClick: function() {},
|
||||
render: function() {
|
||||
return <div onClick={this.handleClick.bind(this)} />;
|
||||
},
|
||||
@@ -200,9 +193,7 @@ describe('autobind optout', () => {
|
||||
componentDidMount: function() {
|
||||
this.setState({foo: 2}, this.handleUpdate.bind(this));
|
||||
},
|
||||
handleUpdate: function() {
|
||||
|
||||
},
|
||||
handleUpdate: function() {},
|
||||
render: function() {
|
||||
return <div />;
|
||||
},
|
||||
@@ -212,5 +203,4 @@ describe('autobind optout', () => {
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(0);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -16,7 +16,6 @@ var ReactDOM;
|
||||
var ReactTestUtils;
|
||||
|
||||
describe('ReactClass-spec', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
@@ -27,7 +26,7 @@ describe('ReactClass-spec', () => {
|
||||
expect(function() {
|
||||
React.createClass({});
|
||||
}).toThrowError(
|
||||
'createClass(...): Class specification must implement a `render` method.'
|
||||
'createClass(...): Class specification must implement a `render` method.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -38,8 +37,7 @@ describe('ReactClass-spec', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(TestComponent.displayName)
|
||||
.toBe('TestComponent');
|
||||
expect(TestComponent.displayName).toBe('TestComponent');
|
||||
});
|
||||
|
||||
it('should copy prop types onto the Constructor', () => {
|
||||
@@ -54,8 +52,7 @@ describe('ReactClass-spec', () => {
|
||||
});
|
||||
|
||||
expect(TestComponent.propTypes).toBeDefined();
|
||||
expect(TestComponent.propTypes.value)
|
||||
.toBe(propValidator);
|
||||
expect(TestComponent.propTypes.value).toBe(propValidator);
|
||||
});
|
||||
|
||||
it('should warn on invalid prop types', () => {
|
||||
@@ -72,7 +69,7 @@ describe('ReactClass-spec', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: Component: prop type `prop` is invalid; ' +
|
||||
'it must be a function, usually from React.PropTypes.'
|
||||
'it must be a function, usually from React.PropTypes.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -90,7 +87,7 @@ describe('ReactClass-spec', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: Component: context type `prop` is invalid; ' +
|
||||
'it must be a function, usually from React.PropTypes.'
|
||||
'it must be a function, usually from React.PropTypes.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -108,7 +105,7 @@ describe('ReactClass-spec', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: Component: child context type `prop` is invalid; ' +
|
||||
'it must be a function, usually from React.PropTypes.'
|
||||
'it must be a function, usually from React.PropTypes.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -126,8 +123,8 @@ describe('ReactClass-spec', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: A component has a method called componentShouldUpdate(). Did you ' +
|
||||
'mean shouldComponentUpdate()? The name is phrased as a question ' +
|
||||
'because the function is expected to return a value.'
|
||||
'mean shouldComponentUpdate()? The name is phrased as a question ' +
|
||||
'because the function is expected to return a value.',
|
||||
);
|
||||
|
||||
React.createClass({
|
||||
@@ -142,8 +139,8 @@ describe('ReactClass-spec', () => {
|
||||
expectDev(console.error.calls.count()).toBe(2);
|
||||
expectDev(console.error.calls.argsFor(1)[0]).toBe(
|
||||
'Warning: NamedComponent has a method called componentShouldUpdate(). Did you ' +
|
||||
'mean shouldComponentUpdate()? The name is phrased as a question ' +
|
||||
'because the function is expected to return a value.'
|
||||
'mean shouldComponentUpdate()? The name is phrased as a question ' +
|
||||
'because the function is expected to return a value.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -160,7 +157,7 @@ describe('ReactClass-spec', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: A component has a method called componentWillRecieveProps(). Did you ' +
|
||||
'mean componentWillReceiveProps()?'
|
||||
'mean componentWillReceiveProps()?',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -181,9 +178,9 @@ describe('ReactClass-spec', () => {
|
||||
});
|
||||
}).toThrowError(
|
||||
'ReactClass: You are attempting to define a reserved property, ' +
|
||||
'`getDefaultProps`, that shouldn\'t be on the "statics" key. Define ' +
|
||||
'it as an instance property instead; it will still be accessible on ' +
|
||||
'the constructor.'
|
||||
'`getDefaultProps`, that shouldn\'t be on the "statics" key. Define ' +
|
||||
'it as an instance property instead; it will still be accessible on ' +
|
||||
'the constructor.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -209,19 +206,19 @@ describe('ReactClass-spec', () => {
|
||||
expectDev(console.error.calls.count()).toBe(4);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'createClass(...): `mixins` is now a static property and should ' +
|
||||
'be defined inside "statics".'
|
||||
'be defined inside "statics".',
|
||||
);
|
||||
expectDev(console.error.calls.argsFor(1)[0]).toBe(
|
||||
'createClass(...): `propTypes` is now a static property and should ' +
|
||||
'be defined inside "statics".'
|
||||
'be defined inside "statics".',
|
||||
);
|
||||
expectDev(console.error.calls.argsFor(2)[0]).toBe(
|
||||
'createClass(...): `contextTypes` is now a static property and ' +
|
||||
'should be defined inside "statics".'
|
||||
'should be defined inside "statics".',
|
||||
);
|
||||
expectDev(console.error.calls.argsFor(3)[0]).toBe(
|
||||
'createClass(...): `childContextTypes` is now a static property and ' +
|
||||
'should be defined inside "statics".'
|
||||
'should be defined inside "statics".',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -315,7 +312,7 @@ describe('ReactClass-spec', () => {
|
||||
expect(function() {
|
||||
instance = ReactTestUtils.renderIntoDocument(instance);
|
||||
}).toThrowError(
|
||||
'Component.getInitialState(): must return an object or null'
|
||||
'Component.getInitialState(): must return an object or null',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -329,9 +326,8 @@ describe('ReactClass-spec', () => {
|
||||
return <span />;
|
||||
},
|
||||
});
|
||||
expect(
|
||||
() => ReactTestUtils.renderIntoDocument(<Component />)
|
||||
).not.toThrow();
|
||||
expect(() =>
|
||||
ReactTestUtils.renderIntoDocument(<Component />)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should throw when using legacy factories', () => {
|
||||
@@ -346,8 +342,7 @@ describe('ReactClass-spec', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: Something is calling a React component directly. Use a ' +
|
||||
'factory or JSX instead. See: https://fb.me/react-legacyfactory'
|
||||
'factory or JSX instead. See: https://fb.me/react-legacyfactory',
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -21,7 +21,6 @@ var mixinPropValidator;
|
||||
var componentPropValidator;
|
||||
|
||||
describe('ReactClass-mixin', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
React = require('react');
|
||||
ReactTestUtils = require('ReactTestUtils');
|
||||
@@ -149,23 +148,22 @@ describe('ReactClass-mixin', () => {
|
||||
|
||||
it('should validate prop types via mixins', () => {
|
||||
expect(TestComponent.propTypes).toBeDefined();
|
||||
expect(TestComponent.propTypes.value)
|
||||
.toBe(mixinPropValidator);
|
||||
expect(TestComponent.propTypes.value).toBe(mixinPropValidator);
|
||||
});
|
||||
|
||||
it('should override mixin prop types with class prop types', () => {
|
||||
// Sanity check...
|
||||
expect(componentPropValidator).not.toBe(mixinPropValidator);
|
||||
// Actually check...
|
||||
expect(TestComponentWithPropTypes.propTypes)
|
||||
.toBeDefined();
|
||||
expect(TestComponentWithPropTypes.propTypes.value)
|
||||
.not.toBe(mixinPropValidator);
|
||||
expect(TestComponentWithPropTypes.propTypes.value)
|
||||
.toBe(componentPropValidator);
|
||||
expect(TestComponentWithPropTypes.propTypes).toBeDefined();
|
||||
expect(TestComponentWithPropTypes.propTypes.value).not.toBe(
|
||||
mixinPropValidator,
|
||||
);
|
||||
expect(TestComponentWithPropTypes.propTypes.value).toBe(
|
||||
componentPropValidator,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
it('should support mixins with getInitialState()', () => {
|
||||
var Mixin = {
|
||||
getInitialState: function() {
|
||||
@@ -205,9 +203,9 @@ describe('ReactClass-mixin', () => {
|
||||
ReactTestUtils.renderIntoDocument(<Component />);
|
||||
}).toThrowError(
|
||||
'mergeIntoWithNoDuplicateKeys(): Tried to merge two objects with the ' +
|
||||
'same key: `x`. This conflict may be due to a mixin; in particular, ' +
|
||||
'this may be caused by two getInitialState() or getDefaultProps() ' +
|
||||
'methods returning objects with clashing keys.'
|
||||
'same key: `x`. This conflict may be due to a mixin; in particular, ' +
|
||||
'this may be caused by two getInitialState() or getDefaultProps() ' +
|
||||
'methods returning objects with clashing keys.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -276,7 +274,7 @@ describe('ReactClass-mixin', () => {
|
||||
});
|
||||
}).toThrowError(
|
||||
'ReactClass: You are attempting to define `abc` on your component more ' +
|
||||
'than once. This conflict may be due to a mixin.'
|
||||
'than once. This conflict may be due to a mixin.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -304,7 +302,7 @@ describe('ReactClass-mixin', () => {
|
||||
});
|
||||
}).toThrowError(
|
||||
'ReactClass: You are attempting to define `abc` on your component ' +
|
||||
'more than once. This conflict may be due to a mixin.'
|
||||
'more than once. This conflict may be due to a mixin.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -321,10 +319,10 @@ describe('ReactClass-mixin', () => {
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: ReactClass: You\'re attempting to include a mixin that is ' +
|
||||
'either null or not an object. Check the mixins included by the ' +
|
||||
'component, as well as any mixins they include themselves. ' +
|
||||
'Expected object but got undefined.'
|
||||
"Warning: ReactClass: You're attempting to include a mixin that is " +
|
||||
'either null or not an object. Check the mixins included by the ' +
|
||||
'component, as well as any mixins they include themselves. ' +
|
||||
'Expected object but got undefined.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -341,10 +339,10 @@ describe('ReactClass-mixin', () => {
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: ReactClass: You\'re attempting to include a mixin that is ' +
|
||||
'either null or not an object. Check the mixins included by the ' +
|
||||
'component, as well as any mixins they include themselves. ' +
|
||||
'Expected object but got null.'
|
||||
"Warning: ReactClass: You're attempting to include a mixin that is " +
|
||||
'either null or not an object. Check the mixins included by the ' +
|
||||
'component, as well as any mixins they include themselves. ' +
|
||||
'Expected object but got null.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -365,10 +363,10 @@ describe('ReactClass-mixin', () => {
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: ReactClass: You\'re attempting to include a mixin that is ' +
|
||||
'either null or not an object. Check the mixins included by the ' +
|
||||
'component, as well as any mixins they include themselves. ' +
|
||||
'Expected object but got undefined.'
|
||||
"Warning: ReactClass: You're attempting to include a mixin that is " +
|
||||
'either null or not an object. Check the mixins included by the ' +
|
||||
'component, as well as any mixins they include themselves. ' +
|
||||
'Expected object but got undefined.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -389,10 +387,10 @@ describe('ReactClass-mixin', () => {
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: ReactClass: You\'re attempting to include a mixin that is ' +
|
||||
'either null or not an object. Check the mixins included by the ' +
|
||||
'component, as well as any mixins they include themselves. ' +
|
||||
'Expected object but got null.'
|
||||
"Warning: ReactClass: You're attempting to include a mixin that is " +
|
||||
'either null or not an object. Check the mixins included by the ' +
|
||||
'component, as well as any mixins they include themselves. ' +
|
||||
'Expected object but got null.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -406,8 +404,8 @@ describe('ReactClass-mixin', () => {
|
||||
},
|
||||
});
|
||||
}).toThrowError(
|
||||
'ReactClass: You\'re attempting to use a component as a mixin. ' +
|
||||
'Instead, just use a regular object.'
|
||||
"ReactClass: You're attempting to use a component as a mixin. " +
|
||||
'Instead, just use a regular object.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -427,8 +425,8 @@ describe('ReactClass-mixin', () => {
|
||||
},
|
||||
});
|
||||
}).toThrowError(
|
||||
'ReactClass: You\'re attempting to use a component class or function ' +
|
||||
'as a mixin. Instead, just use a regular object.'
|
||||
"ReactClass: You're attempting to use a component class or function " +
|
||||
'as a mixin. Instead, just use a regular object.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -488,9 +486,8 @@ describe('ReactClass-mixin', () => {
|
||||
return <span />;
|
||||
},
|
||||
});
|
||||
expect(
|
||||
() => ReactTestUtils.renderIntoDocument(<Component />)
|
||||
).not.toThrow();
|
||||
expect(() =>
|
||||
ReactTestUtils.renderIntoDocument(<Component />)).not.toThrow();
|
||||
|
||||
instance = ReactTestUtils.renderIntoDocument(<Component />);
|
||||
expect(instance.state).toEqual({foo: 'bar'});
|
||||
@@ -510,9 +507,8 @@ describe('ReactClass-mixin', () => {
|
||||
return <span />;
|
||||
},
|
||||
});
|
||||
expect(
|
||||
() => ReactTestUtils.renderIntoDocument(<Component />)
|
||||
).not.toThrow();
|
||||
expect(() =>
|
||||
ReactTestUtils.renderIntoDocument(<Component />)).not.toThrow();
|
||||
|
||||
instance = ReactTestUtils.renderIntoDocument(<Component />);
|
||||
expect(instance.state).toEqual({foo: 'bar'});
|
||||
@@ -527,12 +523,10 @@ describe('ReactClass-mixin', () => {
|
||||
return <span />;
|
||||
},
|
||||
});
|
||||
expect(
|
||||
() => ReactTestUtils.renderIntoDocument(<Component />)
|
||||
).not.toThrow();
|
||||
expect(() =>
|
||||
ReactTestUtils.renderIntoDocument(<Component />)).not.toThrow();
|
||||
|
||||
instance = ReactTestUtils.renderIntoDocument(<Component />);
|
||||
expect(instance.state).toEqual({foo: 'bar', x: true});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import type { ReactInstance } from 'ReactInstanceType';
|
||||
import type { Fiber } from 'ReactFiber';
|
||||
import type {ReactInstance} from 'ReactInstanceType';
|
||||
import type {Fiber} from 'ReactFiber';
|
||||
|
||||
/**
|
||||
* Keeps track of the current owner.
|
||||
@@ -22,13 +22,11 @@ import type { Fiber } from 'ReactFiber';
|
||||
* currently being constructed.
|
||||
*/
|
||||
var ReactCurrentOwner = {
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @type {ReactComponent}
|
||||
*/
|
||||
current: (null: null | ReactInstance | Fiber),
|
||||
|
||||
};
|
||||
|
||||
module.exports = ReactCurrentOwner;
|
||||
|
||||
@@ -141,7 +141,7 @@ var ReactDOMFactories = {
|
||||
track: createDOMFactory('track'),
|
||||
u: createDOMFactory('u'),
|
||||
ul: createDOMFactory('ul'),
|
||||
'var': createDOMFactory('var'),
|
||||
var: createDOMFactory('var'),
|
||||
video: createDOMFactory('video'),
|
||||
wbr: createDOMFactory('wbr'),
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import type { Fiber } from 'ReactFiber';
|
||||
import type { DebugID } from 'ReactInstanceType';
|
||||
import type {Fiber} from 'ReactFiber';
|
||||
import type {DebugID} from 'ReactInstanceType';
|
||||
|
||||
const ReactDebugCurrentFrame = {};
|
||||
|
||||
@@ -27,12 +27,12 @@ if (__DEV__) {
|
||||
} = require('ReactFiberComponentTreeHook');
|
||||
|
||||
// Component that is being worked on
|
||||
ReactDebugCurrentFrame.current = (null : Fiber | DebugID | null);
|
||||
ReactDebugCurrentFrame.current = (null: Fiber | DebugID | null);
|
||||
|
||||
// Element that is being cloned or created
|
||||
ReactDebugCurrentFrame.element = (null : *);
|
||||
ReactDebugCurrentFrame.element = (null: *);
|
||||
|
||||
ReactDebugCurrentFrame.getStackAddendum = function() : string | null {
|
||||
ReactDebugCurrentFrame.getStackAddendum = function(): string | null {
|
||||
let stack = null;
|
||||
const current = ReactDebugCurrentFrame.current;
|
||||
const element = ReactDebugCurrentFrame.element;
|
||||
|
||||
@@ -59,10 +59,10 @@ function defineKeyPropWarningGetter(props, displayName) {
|
||||
warning(
|
||||
false,
|
||||
'%s: `key` is not a prop. Trying to access it will result ' +
|
||||
'in `undefined` being returned. If you need to access the same ' +
|
||||
'value within the child component, you should pass it as a different ' +
|
||||
'prop. (https://fb.me/react-special-props)',
|
||||
displayName
|
||||
'in `undefined` being returned. If you need to access the same ' +
|
||||
'value within the child component, you should pass it as a different ' +
|
||||
'prop. (https://fb.me/react-special-props)',
|
||||
displayName,
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -80,10 +80,10 @@ function defineRefPropWarningGetter(props, displayName) {
|
||||
warning(
|
||||
false,
|
||||
'%s: `ref` is not a prop. Trying to access it will result ' +
|
||||
'in `undefined` being returned. If you need to access the same ' +
|
||||
'value within the child component, you should pass it as a different ' +
|
||||
'prop. (https://fb.me/react-special-props)',
|
||||
displayName
|
||||
'in `undefined` being returned. If you need to access the same ' +
|
||||
'value within the child component, you should pass it as a different ' +
|
||||
'prop. (https://fb.me/react-special-props)',
|
||||
displayName,
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -203,8 +203,10 @@ ReactElement.createElement = function(type, config, children) {
|
||||
source = config.__source === undefined ? null : config.__source;
|
||||
// Remaining properties are added to a new props object
|
||||
for (propName in config) {
|
||||
if (hasOwnProperty.call(config, propName) &&
|
||||
!RESERVED_PROPS.hasOwnProperty(propName)) {
|
||||
if (
|
||||
hasOwnProperty.call(config, propName) &&
|
||||
!RESERVED_PROPS.hasOwnProperty(propName)
|
||||
) {
|
||||
props[propName] = config[propName];
|
||||
}
|
||||
}
|
||||
@@ -239,11 +241,13 @@ ReactElement.createElement = function(type, config, children) {
|
||||
}
|
||||
if (__DEV__) {
|
||||
if (key || ref) {
|
||||
if (typeof props.$$typeof === 'undefined' ||
|
||||
props.$$typeof !== REACT_ELEMENT_TYPE) {
|
||||
var displayName = typeof type === 'function' ?
|
||||
(type.displayName || type.name || 'Unknown') :
|
||||
type;
|
||||
if (
|
||||
typeof props.$$typeof === 'undefined' ||
|
||||
props.$$typeof !== REACT_ELEMENT_TYPE
|
||||
) {
|
||||
var displayName = typeof type === 'function'
|
||||
? type.displayName || type.name || 'Unknown'
|
||||
: type;
|
||||
if (key) {
|
||||
defineKeyPropWarningGetter(props, displayName);
|
||||
}
|
||||
@@ -260,7 +264,7 @@ ReactElement.createElement = function(type, config, children) {
|
||||
self,
|
||||
source,
|
||||
ReactCurrentOwner.current,
|
||||
props
|
||||
props,
|
||||
);
|
||||
};
|
||||
|
||||
@@ -287,7 +291,7 @@ ReactElement.cloneAndReplaceKey = function(oldElement, newKey) {
|
||||
oldElement._self,
|
||||
oldElement._source,
|
||||
oldElement._owner,
|
||||
oldElement.props
|
||||
oldElement.props,
|
||||
);
|
||||
|
||||
return newElement;
|
||||
@@ -332,8 +336,10 @@ ReactElement.cloneElement = function(element, config, children) {
|
||||
defaultProps = element.type.defaultProps;
|
||||
}
|
||||
for (propName in config) {
|
||||
if (hasOwnProperty.call(config, propName) &&
|
||||
!RESERVED_PROPS.hasOwnProperty(propName)) {
|
||||
if (
|
||||
hasOwnProperty.call(config, propName) &&
|
||||
!RESERVED_PROPS.hasOwnProperty(propName)
|
||||
) {
|
||||
if (config[propName] === undefined && defaultProps !== undefined) {
|
||||
// Resolve default props
|
||||
props[propName] = defaultProps[propName];
|
||||
@@ -357,15 +363,7 @@ ReactElement.cloneElement = function(element, config, children) {
|
||||
props.children = childArray;
|
||||
}
|
||||
|
||||
return ReactElement(
|
||||
element.type,
|
||||
key,
|
||||
ref,
|
||||
self,
|
||||
source,
|
||||
owner,
|
||||
props
|
||||
);
|
||||
return ReactElement(element.type, key, ref, self, source, owner, props);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -376,11 +374,9 @@ ReactElement.cloneElement = function(element, config, children) {
|
||||
* @final
|
||||
*/
|
||||
ReactElement.isValidElement = function(object) {
|
||||
return (
|
||||
typeof object === 'object' &&
|
||||
return typeof object === 'object' &&
|
||||
object !== null &&
|
||||
object.$$typeof === REACT_ELEMENT_TYPE
|
||||
);
|
||||
object.$$typeof === REACT_ELEMENT_TYPE;
|
||||
};
|
||||
|
||||
module.exports = ReactElement;
|
||||
|
||||
@@ -30,8 +30,8 @@ var getIteratorFn = require('getIteratorFn');
|
||||
if (__DEV__) {
|
||||
var warning = require('fbjs/lib/warning');
|
||||
var ReactDebugCurrentFrame = require('ReactDebugCurrentFrame');
|
||||
var {
|
||||
getCurrentStackAddendum,
|
||||
var {
|
||||
getCurrentStackAddendum,
|
||||
} = require('ReactComponentTreeHook');
|
||||
}
|
||||
|
||||
@@ -70,8 +70,9 @@ function getCurrentComponentErrorInfo(parentType) {
|
||||
var info = getDeclarationErrorAddendum();
|
||||
|
||||
if (!info) {
|
||||
var parentName = typeof parentType === 'string' ?
|
||||
parentType : parentType.displayName || parentType.name;
|
||||
var parentName = typeof parentType === 'string'
|
||||
? parentType
|
||||
: parentType.displayName || parentType.name;
|
||||
if (parentName) {
|
||||
info = `\n\nCheck the top-level render call using <${parentName}>.`;
|
||||
}
|
||||
@@ -96,9 +97,8 @@ function validateExplicitKey(element, parentType) {
|
||||
}
|
||||
element._store.validated = true;
|
||||
|
||||
var memoizer = ownerHasKeyUseWarning.uniqueKey || (
|
||||
ownerHasKeyUseWarning.uniqueKey = {}
|
||||
);
|
||||
var memoizer = ownerHasKeyUseWarning.uniqueKey ||
|
||||
(ownerHasKeyUseWarning.uniqueKey = {});
|
||||
|
||||
var currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType);
|
||||
if (memoizer[currentComponentErrorInfo]) {
|
||||
@@ -110,21 +110,20 @@ function validateExplicitKey(element, parentType) {
|
||||
// property, it may be the creator of the child that's responsible for
|
||||
// assigning it a key.
|
||||
var childOwner = '';
|
||||
if (element &&
|
||||
element._owner &&
|
||||
element._owner !== ReactCurrentOwner.current) {
|
||||
if (
|
||||
element && element._owner && element._owner !== ReactCurrentOwner.current
|
||||
) {
|
||||
// Give the component that originally created this child.
|
||||
childOwner =
|
||||
` It was passed a child from ${getComponentName(element._owner)}.`;
|
||||
childOwner = ` It was passed a child from ${getComponentName(element._owner)}.`;
|
||||
}
|
||||
|
||||
warning(
|
||||
false,
|
||||
'Each child in an array or iterator should have a unique "key" prop.' +
|
||||
'%s%s See https://fb.me/react-warning-keys for more information.%s',
|
||||
'%s%s See https://fb.me/react-warning-keys for more information.%s',
|
||||
currentComponentErrorInfo,
|
||||
childOwner,
|
||||
getCurrentStackAddendum(element)
|
||||
getCurrentStackAddendum(element),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -183,41 +182,32 @@ function validatePropTypes(element) {
|
||||
}
|
||||
var name = componentClass.displayName || componentClass.name;
|
||||
if (componentClass.propTypes) {
|
||||
checkReactTypeSpec(
|
||||
componentClass.propTypes,
|
||||
element.props,
|
||||
'prop',
|
||||
name
|
||||
);
|
||||
checkReactTypeSpec(componentClass.propTypes, element.props, 'prop', name);
|
||||
}
|
||||
if (typeof componentClass.getDefaultProps === 'function') {
|
||||
warning(
|
||||
componentClass.getDefaultProps.isReactClassApproved,
|
||||
'getDefaultProps is only used on classic React.createClass ' +
|
||||
'definitions. Use a static property named `defaultProps` instead.'
|
||||
'definitions. Use a static property named `defaultProps` instead.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var ReactElementValidator = {
|
||||
|
||||
createElement: function(type, props, children) {
|
||||
var validType =
|
||||
typeof type === 'string' ||
|
||||
typeof type === 'function';
|
||||
var validType = typeof type === 'string' || typeof type === 'function';
|
||||
// We warn in this case but don't throw. We expect the element creation to
|
||||
// succeed and there will likely be errors in render.
|
||||
if (!validType) {
|
||||
var info = '';
|
||||
if (
|
||||
type === undefined ||
|
||||
typeof type === 'object' &&
|
||||
type !== null &&
|
||||
Object.keys(type).length === 0
|
||||
(typeof type === 'object' &&
|
||||
type !== null &&
|
||||
Object.keys(type).length === 0)
|
||||
) {
|
||||
info +=
|
||||
' You likely forgot to export your component from the file ' +
|
||||
'it\'s defined in.';
|
||||
info += ' You likely forgot to export your component from the file ' +
|
||||
"it's defined in.";
|
||||
}
|
||||
|
||||
var sourceInfo = getSourceInfoErrorAddendum(props);
|
||||
@@ -232,8 +222,8 @@ var ReactElementValidator = {
|
||||
warning(
|
||||
false,
|
||||
'React.createElement: type is invalid -- expected a string (for ' +
|
||||
'built-in components) or a class/function (for composite ' +
|
||||
'components) but got: %s.%s',
|
||||
'built-in components) or a class/function (for composite ' +
|
||||
'components) but got: %s.%s',
|
||||
type == null ? type : typeof type,
|
||||
info,
|
||||
);
|
||||
@@ -272,37 +262,29 @@ var ReactElementValidator = {
|
||||
},
|
||||
|
||||
createFactory: function(type) {
|
||||
var validatedFactory = ReactElementValidator.createElement.bind(
|
||||
null,
|
||||
type
|
||||
);
|
||||
var validatedFactory = ReactElementValidator.createElement.bind(null, type);
|
||||
// Legacy hook TODO: Warn if this is accessed
|
||||
validatedFactory.type = type;
|
||||
|
||||
if (__DEV__) {
|
||||
if (canDefineProperty) {
|
||||
Object.defineProperty(
|
||||
validatedFactory,
|
||||
'type',
|
||||
{
|
||||
enumerable: false,
|
||||
get: function() {
|
||||
warning(
|
||||
false,
|
||||
'Factory.type is deprecated. Access the class directly ' +
|
||||
'before passing it to createFactory.'
|
||||
);
|
||||
Object.defineProperty(this, 'type', {
|
||||
value: type,
|
||||
});
|
||||
return type;
|
||||
},
|
||||
}
|
||||
);
|
||||
Object.defineProperty(validatedFactory, 'type', {
|
||||
enumerable: false,
|
||||
get: function() {
|
||||
warning(
|
||||
false,
|
||||
'Factory.type is deprecated. Access the class directly ' +
|
||||
'before passing it to createFactory.',
|
||||
);
|
||||
Object.defineProperty(this, 'type', {
|
||||
value: type,
|
||||
});
|
||||
return type;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return validatedFactory;
|
||||
},
|
||||
|
||||
@@ -320,7 +302,6 @@ var ReactElementValidator = {
|
||||
}
|
||||
return newElement;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
module.exports = ReactElementValidator;
|
||||
|
||||
@@ -83,9 +83,9 @@ describe('ReactElement', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Child: `key` is not a prop. Trying to access it will result ' +
|
||||
'in `undefined` being returned. If you need to access the same ' +
|
||||
'value within the child component, you should pass it as a different ' +
|
||||
'prop. (https://fb.me/react-special-props)'
|
||||
'in `undefined` being returned. If you need to access the same ' +
|
||||
'value within the child component, you should pass it as a different ' +
|
||||
'prop. (https://fb.me/react-special-props)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -113,9 +113,9 @@ describe('ReactElement', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Child: `key` is not a prop. Trying to access it will result ' +
|
||||
'in `undefined` being returned. If you need to access the same ' +
|
||||
'value within the child component, you should pass it as a different ' +
|
||||
'prop. (https://fb.me/react-special-props)'
|
||||
'in `undefined` being returned. If you need to access the same ' +
|
||||
'value within the child component, you should pass it as a different ' +
|
||||
'prop. (https://fb.me/react-special-props)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -127,9 +127,9 @@ describe('ReactElement', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'div: `key` is not a prop. Trying to access it will result ' +
|
||||
'in `undefined` being returned. If you need to access the same ' +
|
||||
'value within the child component, you should pass it as a different ' +
|
||||
'prop. (https://fb.me/react-special-props)'
|
||||
'in `undefined` being returned. If you need to access the same ' +
|
||||
'value within the child component, you should pass it as a different ' +
|
||||
'prop. (https://fb.me/react-special-props)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -155,9 +155,9 @@ describe('ReactElement', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Child: `ref` is not a prop. Trying to access it will result ' +
|
||||
'in `undefined` being returned. If you need to access the same ' +
|
||||
'value within the child component, you should pass it as a different ' +
|
||||
'prop. (https://fb.me/react-special-props)'
|
||||
'in `undefined` being returned. If you need to access the same ' +
|
||||
'value within the child component, you should pass it as a different ' +
|
||||
'prop. (https://fb.me/react-special-props)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -265,7 +265,7 @@ describe('ReactElement', () => {
|
||||
});
|
||||
|
||||
var instance = ReactTestUtils.renderIntoDocument(
|
||||
React.createElement(Wrapper)
|
||||
React.createElement(Wrapper),
|
||||
);
|
||||
|
||||
if (ReactDOMFeatureFlags.useFiber) {
|
||||
@@ -278,9 +278,12 @@ describe('ReactElement', () => {
|
||||
it('merges an additional argument onto the children prop', () => {
|
||||
spyOn(console, 'error');
|
||||
var a = 1;
|
||||
var element = React.createFactory(ComponentClass)({
|
||||
children: 'text',
|
||||
}, a);
|
||||
var element = React.createFactory(ComponentClass)(
|
||||
{
|
||||
children: 'text',
|
||||
},
|
||||
a,
|
||||
);
|
||||
expect(element.props.children).toBe(a);
|
||||
expectDev(console.error.calls.count()).toBe(0);
|
||||
});
|
||||
@@ -296,9 +299,12 @@ describe('ReactElement', () => {
|
||||
|
||||
it('overrides children if null is provided as an argument', () => {
|
||||
spyOn(console, 'error');
|
||||
var element = React.createFactory(ComponentClass)({
|
||||
children: 'text',
|
||||
}, null);
|
||||
var element = React.createFactory(ComponentClass)(
|
||||
{
|
||||
children: 'text',
|
||||
},
|
||||
null,
|
||||
);
|
||||
expect(element.props.children).toBe(null);
|
||||
expectDev(console.error.calls.count()).toBe(0);
|
||||
});
|
||||
@@ -346,10 +352,8 @@ describe('ReactElement', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(React.isValidElement(React.createElement('div')))
|
||||
.toEqual(true);
|
||||
expect(React.isValidElement(React.createElement(Component)))
|
||||
.toEqual(true);
|
||||
expect(React.isValidElement(React.createElement('div'))).toEqual(true);
|
||||
expect(React.isValidElement(React.createElement(Component))).toEqual(true);
|
||||
|
||||
expect(React.isValidElement(null)).toEqual(false);
|
||||
expect(React.isValidElement(true)).toEqual(false);
|
||||
@@ -357,7 +361,7 @@ describe('ReactElement', () => {
|
||||
expect(React.isValidElement('string')).toEqual(false);
|
||||
expect(React.isValidElement(React.DOM.div)).toEqual(false);
|
||||
expect(React.isValidElement(Component)).toEqual(false);
|
||||
expect(React.isValidElement({ type: 'div', props: {} })).toEqual(false);
|
||||
expect(React.isValidElement({type: 'div', props: {}})).toEqual(false);
|
||||
|
||||
var jsonElement = JSON.stringify(React.createElement('div'));
|
||||
expect(React.isValidElement(JSON.parse(jsonElement))).toBe(true);
|
||||
@@ -401,7 +405,7 @@ describe('ReactElement', () => {
|
||||
var container = document.createElement('div');
|
||||
var instance = ReactDOM.render(
|
||||
React.createElement(Component, {fruit: 'mango'}),
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(instance.props.fruit).toBe('mango');
|
||||
|
||||
@@ -422,12 +426,12 @@ describe('ReactElement', () => {
|
||||
});
|
||||
|
||||
var instance = ReactTestUtils.renderIntoDocument(
|
||||
React.createElement(Component)
|
||||
React.createElement(Component),
|
||||
);
|
||||
expect(instance.props.prop).toBe('testKey');
|
||||
|
||||
var inst2 = ReactTestUtils.renderIntoDocument(
|
||||
React.createElement(Component, {prop: null})
|
||||
React.createElement(Component, {prop: null}),
|
||||
);
|
||||
expect(inst2.props.prop).toBe(null);
|
||||
});
|
||||
@@ -510,10 +514,8 @@ describe('ReactElement', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(React.isValidElement(React.createElement('div')))
|
||||
.toEqual(true);
|
||||
expect(React.isValidElement(React.createElement(Component)))
|
||||
.toEqual(true);
|
||||
expect(React.isValidElement(React.createElement('div'))).toEqual(true);
|
||||
expect(React.isValidElement(React.createElement(Component))).toEqual(true);
|
||||
|
||||
expect(React.isValidElement(null)).toEqual(false);
|
||||
expect(React.isValidElement(true)).toEqual(false);
|
||||
@@ -521,12 +523,11 @@ describe('ReactElement', () => {
|
||||
expect(React.isValidElement('string')).toEqual(false);
|
||||
expect(React.isValidElement(React.DOM.div)).toEqual(false);
|
||||
expect(React.isValidElement(Component)).toEqual(false);
|
||||
expect(React.isValidElement({ type: 'div', props: {} })).toEqual(false);
|
||||
expect(React.isValidElement({type: 'div', props: {}})).toEqual(false);
|
||||
|
||||
var jsonElement = JSON.stringify(React.createElement('div'));
|
||||
expect(React.isValidElement(JSON.parse(jsonElement))).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('comparing jsx vs .createFactory() vs .createElement()', () => {
|
||||
@@ -540,7 +541,6 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
|
||||
Child = jest.genMockFromModule('ReactElementTestChild');
|
||||
});
|
||||
|
||||
|
||||
describe('when using jsx only', () => {
|
||||
var Parent, instance;
|
||||
beforeEach(() => {
|
||||
@@ -557,7 +557,10 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
|
||||
});
|
||||
|
||||
it('should scry children but cannot', () => {
|
||||
var children = ReactTestUtils.scryRenderedComponentsWithType(instance, Child);
|
||||
var children = ReactTestUtils.scryRenderedComponentsWithType(
|
||||
instance,
|
||||
Child,
|
||||
);
|
||||
expect(children.length).toBe(1);
|
||||
});
|
||||
|
||||
@@ -566,7 +569,10 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
|
||||
});
|
||||
|
||||
it('can capture Child instantiation calls', () => {
|
||||
expect(Child.mock.calls[0][0]).toEqual({ foo: 'foo value', children: 'children value' });
|
||||
expect(Child.mock.calls[0][0]).toEqual({
|
||||
foo: 'foo value',
|
||||
children: 'children value',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -576,7 +582,10 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
|
||||
var childFactory = React.createFactory(Child);
|
||||
var Parent = React.createClass({
|
||||
render: function() {
|
||||
return React.DOM.div({}, childFactory({ ref: 'child', foo: 'foo value' }, 'children value'));
|
||||
return React.DOM.div(
|
||||
{},
|
||||
childFactory({ref: 'child', foo: 'foo value'}, 'children value'),
|
||||
);
|
||||
},
|
||||
});
|
||||
factory = React.createFactory(Parent);
|
||||
@@ -584,7 +593,10 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
|
||||
});
|
||||
|
||||
it('can properly scry children', () => {
|
||||
var children = ReactTestUtils.scryRenderedComponentsWithType(instance, Child);
|
||||
var children = ReactTestUtils.scryRenderedComponentsWithType(
|
||||
instance,
|
||||
Child,
|
||||
);
|
||||
expect(children.length).toBe(1);
|
||||
});
|
||||
|
||||
@@ -593,7 +605,10 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
|
||||
});
|
||||
|
||||
it('can capture Child instantiation calls', () => {
|
||||
expect(Child.mock.calls[0][0]).toEqual({ foo: 'foo value', children: 'children value' });
|
||||
expect(Child.mock.calls[0][0]).toEqual({
|
||||
foo: 'foo value',
|
||||
children: 'children value',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -602,7 +617,14 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
|
||||
beforeEach(() => {
|
||||
var Parent = React.createClass({
|
||||
render: function() {
|
||||
return React.DOM.div({}, React.createElement(Child, { ref: 'child', foo: 'foo value' }, 'children value'));
|
||||
return React.DOM.div(
|
||||
{},
|
||||
React.createElement(
|
||||
Child,
|
||||
{ref: 'child', foo: 'foo value'},
|
||||
'children value',
|
||||
),
|
||||
);
|
||||
},
|
||||
});
|
||||
factory = React.createFactory(Parent);
|
||||
@@ -610,7 +632,10 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
|
||||
});
|
||||
|
||||
it('should scry children but cannot', () => {
|
||||
var children = ReactTestUtils.scryRenderedComponentsWithType(instance, Child);
|
||||
var children = ReactTestUtils.scryRenderedComponentsWithType(
|
||||
instance,
|
||||
Child,
|
||||
);
|
||||
expect(children.length).toBe(1);
|
||||
});
|
||||
|
||||
@@ -619,8 +644,10 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
|
||||
});
|
||||
|
||||
it('can capture Child instantiation calls', () => {
|
||||
expect(Child.mock.calls[0][0]).toEqual({ foo: 'foo value', children: 'children value' });
|
||||
expect(Child.mock.calls[0][0]).toEqual({
|
||||
foo: 'foo value',
|
||||
children: 'children value',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -42,7 +42,7 @@ describe('ReactElementClone', () => {
|
||||
render: function() {
|
||||
return (
|
||||
<div className="parent">
|
||||
{React.cloneElement(this.props.child, { className: 'xyz' })}
|
||||
{React.cloneElement(this.props.child, {className: 'xyz'})}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
@@ -66,7 +66,7 @@ describe('ReactElementClone', () => {
|
||||
render: function() {
|
||||
return (
|
||||
<div className="parent">
|
||||
{React.cloneElement(this.props.child, { className: 'xyz' })}
|
||||
{React.cloneElement(this.props.child, {className: 'xyz'})}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
@@ -91,7 +91,7 @@ describe('ReactElementClone', () => {
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
{React.cloneElement(this.props.child, { className: 'xyz' })}
|
||||
{React.cloneElement(this.props.child, {className: 'xyz'})}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
@@ -120,7 +120,7 @@ describe('ReactElementClone', () => {
|
||||
});
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
React.cloneElement(<Component />, {children: 'xyz'})
|
||||
React.cloneElement(<Component />, {children: 'xyz'}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -133,7 +133,7 @@ describe('ReactElementClone', () => {
|
||||
});
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
React.cloneElement(<Component>xyz</Component>, {})
|
||||
React.cloneElement(<Component>xyz</Component>, {}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -146,34 +146,41 @@ describe('ReactElementClone', () => {
|
||||
|
||||
var clone = React.cloneElement(
|
||||
<Component>xyz</Component>,
|
||||
{ children: <Component /> },
|
||||
<div />,
|
||||
<span />
|
||||
);
|
||||
|
||||
expect(clone.props.children).toEqual([
|
||||
{children: <Component />},
|
||||
<div />,
|
||||
<span />,
|
||||
]);
|
||||
);
|
||||
|
||||
expect(clone.props.children).toEqual([<div />, <span />]);
|
||||
});
|
||||
|
||||
it('should override children if undefined is provided as an argument', () => {
|
||||
var element = React.createElement(ComponentClass, {
|
||||
children: 'text',
|
||||
}, undefined);
|
||||
var element = React.createElement(
|
||||
ComponentClass,
|
||||
{
|
||||
children: 'text',
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
expect(element.props.children).toBe(undefined);
|
||||
|
||||
var element2 = React.cloneElement(React.createElement(ComponentClass, {
|
||||
children: 'text',
|
||||
}), {}, undefined);
|
||||
var element2 = React.cloneElement(
|
||||
React.createElement(ComponentClass, {
|
||||
children: 'text',
|
||||
}),
|
||||
{},
|
||||
undefined,
|
||||
);
|
||||
expect(element2.props.children).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should support keys and refs', () => {
|
||||
var Parent = React.createClass({
|
||||
render: function() {
|
||||
var clone =
|
||||
React.cloneElement(this.props.children, {key: 'xyz', ref: 'xyz'});
|
||||
var clone = React.cloneElement(this.props.children, {
|
||||
key: 'xyz',
|
||||
ref: 'xyz',
|
||||
});
|
||||
expect(clone.key).toBe('xyz');
|
||||
expect(clone.ref).toBe('xyz');
|
||||
return <div>{clone}</div>;
|
||||
@@ -218,7 +225,7 @@ describe('ReactElementClone', () => {
|
||||
});
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
React.cloneElement(<Component myprop="abc" />, {myprop: 'xyz'})
|
||||
React.cloneElement(<Component myprop="abc" />, {myprop: 'xyz'}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -252,7 +259,7 @@ describe('ReactElementClone', () => {
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Each child in an array or iterator should have a unique "key" prop.'
|
||||
'Each child in an array or iterator should have a unique "key" prop.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -297,21 +304,20 @@ describe('ReactElementClone', () => {
|
||||
});
|
||||
var GrandParent = React.createClass({
|
||||
render: function() {
|
||||
return React.createElement(
|
||||
Parent,
|
||||
{ child: React.createElement(Component, {color: 'red'}) }
|
||||
);
|
||||
return React.createElement(Parent, {
|
||||
child: React.createElement(Component, {color: 'red'}),
|
||||
});
|
||||
},
|
||||
});
|
||||
ReactTestUtils.renderIntoDocument(React.createElement(GrandParent));
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: Failed prop type: ' +
|
||||
'Invalid prop `color` of type `number` supplied to `Component`, ' +
|
||||
'expected `string`.\n' +
|
||||
' in Component (created by GrandParent)\n' +
|
||||
' in Parent (created by GrandParent)\n' +
|
||||
' in GrandParent'
|
||||
'Invalid prop `color` of type `number` supplied to `Component`, ' +
|
||||
'expected `string`.\n' +
|
||||
' in Component (created by GrandParent)\n' +
|
||||
' in Parent (created by GrandParent)\n' +
|
||||
' in GrandParent',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -361,5 +367,4 @@ describe('ReactElementClone', () => {
|
||||
expect(Object.isFrozen(element.props)).toBe(true);
|
||||
expect(clone.props).toEqual({foo: 'ef'});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -46,7 +46,7 @@ describe('ReactElementValidator', () => {
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Each child in an array or iterator should have a unique "key" prop.'
|
||||
'Each child in an array or iterator should have a unique "key" prop.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -66,19 +66,17 @@ describe('ReactElementValidator', () => {
|
||||
var ComponentWrapper = React.createClass({
|
||||
displayName: 'ComponentWrapper',
|
||||
render: function() {
|
||||
return InnerComponent({childSet: [Component(), Component()] });
|
||||
return InnerComponent({childSet: [Component(), Component()]});
|
||||
},
|
||||
});
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
React.createElement(ComponentWrapper)
|
||||
);
|
||||
ReactTestUtils.renderIntoDocument(React.createElement(ComponentWrapper));
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Each child in an array or iterator should have a unique "key" prop.' +
|
||||
'\n\nCheck the render method of `InnerClass`. ' +
|
||||
'It was passed a child from ComponentWrapper. '
|
||||
'\n\nCheck the render method of `InnerClass`. ' +
|
||||
'It was passed a child from ComponentWrapper. ',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -92,35 +90,29 @@ describe('ReactElementValidator', () => {
|
||||
},
|
||||
});
|
||||
|
||||
var divs = [
|
||||
<div />,
|
||||
<div />,
|
||||
];
|
||||
var divs = [<div />, <div />];
|
||||
ReactTestUtils.renderIntoDocument(<Anonymous>{divs}</Anonymous>);
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
|
||||
'Warning: Each child in an array or iterator should have a unique ' +
|
||||
'"key" prop. See https://fb.me/react-warning-keys for more information.\n' +
|
||||
' in div (at **)'
|
||||
'"key" prop. See https://fb.me/react-warning-keys for more information.\n' +
|
||||
' in div (at **)',
|
||||
);
|
||||
});
|
||||
|
||||
it('warns for keys for arrays of elements with no owner info', () => {
|
||||
spyOn(console, 'error');
|
||||
|
||||
var divs = [
|
||||
<div />,
|
||||
<div />,
|
||||
];
|
||||
var divs = [<div />, <div />];
|
||||
ReactTestUtils.renderIntoDocument(<div>{divs}</div>);
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
|
||||
'Warning: Each child in an array or iterator should have a unique ' +
|
||||
'"key" prop.\n\nCheck the top-level render call using <div>. See ' +
|
||||
'https://fb.me/react-warning-keys for more information.\n' +
|
||||
' in div (at **)'
|
||||
'"key" prop.\n\nCheck the top-level render call using <div>. See ' +
|
||||
'https://fb.me/react-warning-keys for more information.\n' +
|
||||
' in div (at **)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -150,12 +142,12 @@ describe('ReactElementValidator', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
|
||||
'Warning: Each child in an array or iterator should have a unique ' +
|
||||
'"key" prop.\n\nCheck the render method of `Component`. See ' +
|
||||
'https://fb.me/react-warning-keys for more information.\n' +
|
||||
' in div (at **)\n' +
|
||||
' in Component (at **)\n' +
|
||||
' in Parent (at **)\n' +
|
||||
' in GrandParent (at **)'
|
||||
'"key" prop.\n\nCheck the render method of `Component`. See ' +
|
||||
'https://fb.me/react-warning-keys for more information.\n' +
|
||||
' in div (at **)\n' +
|
||||
' in Component (at **)\n' +
|
||||
' in Parent (at **)\n' +
|
||||
' in GrandParent (at **)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -177,7 +169,7 @@ describe('ReactElementValidator', () => {
|
||||
<Wrapper>
|
||||
<span />
|
||||
<span />
|
||||
</Wrapper>
|
||||
</Wrapper>,
|
||||
);
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(0);
|
||||
@@ -203,7 +195,7 @@ describe('ReactElementValidator', () => {
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Each child in an array or iterator should have a unique "key" prop.'
|
||||
'Each child in an array or iterator should have a unique "key" prop.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -279,10 +271,10 @@ describe('ReactElementValidator', () => {
|
||||
ReactTestUtils.renderIntoDocument(React.createElement(ParentComp));
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: Failed prop type: ' +
|
||||
'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
|
||||
'expected `string`.\n' +
|
||||
' in MyComp (created by ParentComp)\n' +
|
||||
' in ParentComp'
|
||||
'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
|
||||
'expected `string`.\n' +
|
||||
' in MyComp (created by ParentComp)\n' +
|
||||
' in ParentComp',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -297,35 +289,35 @@ describe('ReactElementValidator', () => {
|
||||
expectDev(console.error.calls.count()).toBe(6);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: React.createElement: type is invalid -- expected a string ' +
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: undefined. You likely forgot to export your ' +
|
||||
'component from the file it\'s defined in.'
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: undefined. You likely forgot to export your ' +
|
||||
"component from the file it's defined in.",
|
||||
);
|
||||
expectDev(console.error.calls.argsFor(1)[0]).toBe(
|
||||
'Warning: React.createElement: type is invalid -- expected a string ' +
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: null.'
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: null.',
|
||||
);
|
||||
expectDev(console.error.calls.argsFor(2)[0]).toBe(
|
||||
'Warning: React.createElement: type is invalid -- expected a string ' +
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: boolean.'
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: boolean.',
|
||||
);
|
||||
expectDev(console.error.calls.argsFor(3)[0]).toBe(
|
||||
'Warning: React.createElement: type is invalid -- expected a string ' +
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: number.'
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: number.',
|
||||
);
|
||||
expectDev(console.error.calls.argsFor(4)[0]).toBe(
|
||||
'Warning: React.createElement: type is invalid -- expected a string ' +
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: object.'
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: object.',
|
||||
);
|
||||
expectDev(console.error.calls.argsFor(5)[0]).toBe(
|
||||
'Warning: React.createElement: type is invalid -- expected a string ' +
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: object. You likely forgot to export your ' +
|
||||
'component from the file it\'s defined in.'
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: object. You likely forgot to export your ' +
|
||||
"component from the file it's defined in.",
|
||||
);
|
||||
React.createElement('div');
|
||||
expectDev(console.error.calls.count()).toBe(6);
|
||||
@@ -342,15 +334,15 @@ describe('ReactElementValidator', () => {
|
||||
ReactTestUtils.renderIntoDocument(React.createElement(ParentComp));
|
||||
}).toThrowError(
|
||||
'Element type is invalid: expected a string (for built-in components) ' +
|
||||
'or a class/function (for composite components) but got: null.\n\nCheck ' +
|
||||
'the render method of `ParentComp`.'
|
||||
'or a class/function (for composite components) but got: null.\n\nCheck ' +
|
||||
'the render method of `ParentComp`.',
|
||||
);
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: React.createElement: type is invalid -- expected a string ' +
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: null.\n\nCheck the render method of `ParentComp`.' +
|
||||
'\n in ParentComp'
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: null.\n\nCheck the render method of `ParentComp`.' +
|
||||
'\n in ParentComp',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -372,8 +364,8 @@ describe('ReactElementValidator', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: Failed prop type: The prop `prop` is marked as required in ' +
|
||||
'`Component`, but its value is `null`.\n' +
|
||||
' in Component'
|
||||
'`Component`, but its value is `null`.\n' +
|
||||
' in Component',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -391,14 +383,14 @@ describe('ReactElementValidator', () => {
|
||||
});
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
React.createElement(Component, {prop:null})
|
||||
React.createElement(Component, {prop: null}),
|
||||
);
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: Failed prop type: The prop `prop` is marked as required in ' +
|
||||
'`Component`, but its value is `null`.\n' +
|
||||
' in Component'
|
||||
'`Component`, but its value is `null`.\n' +
|
||||
' in Component',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -414,30 +406,28 @@ describe('ReactElementValidator', () => {
|
||||
},
|
||||
});
|
||||
|
||||
ReactTestUtils.renderIntoDocument(React.createElement(Component));
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
React.createElement(Component)
|
||||
);
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
React.createElement(Component, {prop: 42})
|
||||
React.createElement(Component, {prop: 42}),
|
||||
);
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(2);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: Failed prop type: ' +
|
||||
'The prop `prop` is marked as required in `Component`, but its value ' +
|
||||
'is `undefined`.\n' +
|
||||
' in Component'
|
||||
'The prop `prop` is marked as required in `Component`, but its value ' +
|
||||
'is `undefined`.\n' +
|
||||
' in Component',
|
||||
);
|
||||
|
||||
expectDev(console.error.calls.argsFor(1)[0]).toBe(
|
||||
'Warning: Failed prop type: ' +
|
||||
'Invalid prop `prop` of type `number` supplied to ' +
|
||||
'`Component`, expected `string`.\n' +
|
||||
' in Component'
|
||||
'Invalid prop `prop` of type `number` supplied to ' +
|
||||
'`Component`, expected `string`.\n' +
|
||||
' in Component',
|
||||
);
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
React.createElement(Component, {prop: 'string'})
|
||||
React.createElement(Component, {prop: 'string'}),
|
||||
);
|
||||
|
||||
// Should not error for strings
|
||||
@@ -457,16 +447,16 @@ describe('ReactElementValidator', () => {
|
||||
});
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
React.createElement(Component, {myProp: {value: 'hi'}})
|
||||
React.createElement(Component, {myProp: {value: 'hi'}}),
|
||||
);
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: Component: type specification of prop `myProp` is invalid; ' +
|
||||
'the type checker function must return `null` or an `Error` but ' +
|
||||
'returned a function. You may have forgotten to pass an argument to ' +
|
||||
'the type checker creator (arrayOf, instanceOf, objectOf, oneOf, ' +
|
||||
'oneOfType, and shape all require an argument).'
|
||||
'the type checker function must return `null` or an `Error` but ' +
|
||||
'returned a function. You may have forgotten to pass an argument to ' +
|
||||
'the type checker creator (arrayOf, instanceOf, objectOf, oneOf, ' +
|
||||
'oneOfType, and shape all require an argument).',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -482,7 +472,7 @@ describe('ReactElementValidator', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: Factory.type is deprecated. Access the class directly before ' +
|
||||
'passing it to createFactory.'
|
||||
'passing it to createFactory.',
|
||||
);
|
||||
// Warn once, not again
|
||||
expect(TestFactory.type).toBe(TestComponent);
|
||||
@@ -531,7 +521,7 @@ describe('ReactElementValidator', () => {
|
||||
// shouldn't blow up either.
|
||||
|
||||
var child = {
|
||||
$$typeof: (<div />).$$typeof,
|
||||
$$typeof: <div />.$$typeof,
|
||||
type: 'span',
|
||||
key: null,
|
||||
ref: null,
|
||||
@@ -549,10 +539,9 @@ describe('ReactElementValidator', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
|
||||
'Warning: React.createElement: type is invalid -- expected a string ' +
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: undefined. You likely forgot to export your ' +
|
||||
'component from the file it\'s defined in.\n\nCheck your code at **.'
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: undefined. You likely forgot to export your ' +
|
||||
"component from the file it's defined in.\n\nCheck your code at **.",
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -95,7 +95,7 @@ if (__DEV__) {
|
||||
var productionTypeChecker = function() {
|
||||
invariant(
|
||||
false,
|
||||
'React.PropTypes type checking code is stripped in production.'
|
||||
'React.PropTypes type checking code is stripped in production.',
|
||||
);
|
||||
};
|
||||
productionTypeChecker.isRequired = productionTypeChecker;
|
||||
@@ -122,7 +122,6 @@ if (__DEV__) {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* inlined Object.is polyfill to avoid requiring consumers ship their own
|
||||
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
|
||||
@@ -130,7 +129,8 @@ if (__DEV__) {
|
||||
/*eslint-disable no-self-compare*/
|
||||
function is(x, y) {
|
||||
// SameValue algorithm
|
||||
if (x === y) { // Steps 1-5, 7-10
|
||||
if (x === y) {
|
||||
// Steps 1-5, 7-10
|
||||
// Steps 6.b-6.e: +0 != -0
|
||||
return x !== 0 || 1 / x === 1 / y;
|
||||
} else {
|
||||
@@ -165,27 +165,24 @@ function createChainableTypeChecker(validate) {
|
||||
componentName,
|
||||
location,
|
||||
propFullName,
|
||||
secret
|
||||
secret,
|
||||
) {
|
||||
componentName = componentName || ANONYMOUS;
|
||||
propFullName = propFullName || propName;
|
||||
if (__DEV__) {
|
||||
if (
|
||||
secret !== ReactPropTypesSecret &&
|
||||
typeof console !== 'undefined'
|
||||
) {
|
||||
if (secret !== ReactPropTypesSecret && typeof console !== 'undefined') {
|
||||
var cacheKey = `${componentName}:${propName}`;
|
||||
if (!manualPropTypeCallCache[cacheKey]) {
|
||||
warning(
|
||||
false,
|
||||
'You are manually calling a React.PropTypes validation ' +
|
||||
'function for the `%s` prop on `%s`. This is deprecated ' +
|
||||
'and will not work in production with the next major version. ' +
|
||||
'You may be seeing this warning due to a third-party PropTypes ' +
|
||||
'library. See https://fb.me/react-warning-dont-call-proptypes ' +
|
||||
'for details.',
|
||||
'function for the `%s` prop on `%s`. This is deprecated ' +
|
||||
'and will not work in production with the next major version. ' +
|
||||
'You may be seeing this warning due to a third-party PropTypes ' +
|
||||
'library. See https://fb.me/react-warning-dont-call-proptypes ' +
|
||||
'for details.',
|
||||
propFullName,
|
||||
componentName
|
||||
componentName,
|
||||
);
|
||||
manualPropTypeCallCache[cacheKey] = true;
|
||||
}
|
||||
@@ -196,23 +193,17 @@ function createChainableTypeChecker(validate) {
|
||||
if (props[propName] === null) {
|
||||
return new PropTypeError(
|
||||
`The ${location} \`${propFullName}\` is marked as required ` +
|
||||
`in \`${componentName}\`, but its value is \`null\`.`
|
||||
`in \`${componentName}\`, but its value is \`null\`.`,
|
||||
);
|
||||
}
|
||||
return new PropTypeError(
|
||||
`The ${location} \`${propFullName}\` is marked as required in ` +
|
||||
`\`${componentName}\`, but its value is \`undefined\`.`
|
||||
`\`${componentName}\`, but its value is \`undefined\`.`,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
return validate(
|
||||
props,
|
||||
propName,
|
||||
componentName,
|
||||
location,
|
||||
propFullName,
|
||||
);
|
||||
return validate(props, propName, componentName, location, propFullName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +220,7 @@ function createPrimitiveTypeChecker(expectedType) {
|
||||
componentName,
|
||||
location,
|
||||
propFullName,
|
||||
secret
|
||||
secret,
|
||||
) {
|
||||
var propValue = props[propName];
|
||||
var propType = getPropType(propValue);
|
||||
@@ -241,8 +232,8 @@ function createPrimitiveTypeChecker(expectedType) {
|
||||
|
||||
return new PropTypeError(
|
||||
`Invalid ${location} \`${propFullName}\` of type ` +
|
||||
`\`${preciseType}\` supplied to \`${componentName}\`, expected ` +
|
||||
`\`${expectedType}\`.`
|
||||
`\`${preciseType}\` supplied to \`${componentName}\`, expected ` +
|
||||
`\`${expectedType}\`.`,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
@@ -258,7 +249,7 @@ function createArrayOfTypeChecker(typeChecker) {
|
||||
function validate(props, propName, componentName, location, propFullName) {
|
||||
if (typeof typeChecker !== 'function') {
|
||||
return new PropTypeError(
|
||||
`Property \`${propFullName}\` of component \`${componentName}\` has invalid PropType notation inside arrayOf.`
|
||||
`Property \`${propFullName}\` of component \`${componentName}\` has invalid PropType notation inside arrayOf.`,
|
||||
);
|
||||
}
|
||||
var propValue = props[propName];
|
||||
@@ -266,7 +257,7 @@ function createArrayOfTypeChecker(typeChecker) {
|
||||
var propType = getPropType(propValue);
|
||||
return new PropTypeError(
|
||||
`Invalid ${location} \`${propFullName}\` of type ` +
|
||||
`\`${propType}\` supplied to \`${componentName}\`, expected an array.`
|
||||
`\`${propType}\` supplied to \`${componentName}\`, expected an array.`,
|
||||
);
|
||||
}
|
||||
for (var i = 0; i < propValue.length; i++) {
|
||||
@@ -276,7 +267,7 @@ function createArrayOfTypeChecker(typeChecker) {
|
||||
componentName,
|
||||
location,
|
||||
`${propFullName}[${i}]`,
|
||||
ReactPropTypesSecret
|
||||
ReactPropTypesSecret,
|
||||
);
|
||||
if (error instanceof Error) {
|
||||
return error;
|
||||
@@ -294,7 +285,7 @@ function createElementTypeChecker() {
|
||||
var propType = getPropType(propValue);
|
||||
return new PropTypeError(
|
||||
`Invalid ${location} \`${propFullName}\` of type ` +
|
||||
`\`${propType}\` supplied to \`${componentName}\`, expected a single ReactElement.`
|
||||
`\`${propType}\` supplied to \`${componentName}\`, expected a single ReactElement.`,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
@@ -309,8 +300,8 @@ function createInstanceTypeChecker(expectedClass) {
|
||||
var actualClassName = getClassName(props[propName]);
|
||||
return new PropTypeError(
|
||||
`Invalid ${location} \`${propFullName}\` of type ` +
|
||||
`\`${actualClassName}\` supplied to \`${componentName}\`, expected ` +
|
||||
`instance of \`${expectedClassName}\`.`
|
||||
`\`${actualClassName}\` supplied to \`${componentName}\`, expected ` +
|
||||
`instance of \`${expectedClassName}\`.`,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
@@ -320,7 +311,10 @@ function createInstanceTypeChecker(expectedClass) {
|
||||
|
||||
function createEnumTypeChecker(expectedValues) {
|
||||
if (!Array.isArray(expectedValues)) {
|
||||
warning(false, 'Invalid argument supplied to oneOf, expected an instance of array.');
|
||||
warning(
|
||||
false,
|
||||
'Invalid argument supplied to oneOf, expected an instance of array.',
|
||||
);
|
||||
return emptyFunction.thatReturnsNull;
|
||||
}
|
||||
|
||||
@@ -335,7 +329,7 @@ function createEnumTypeChecker(expectedValues) {
|
||||
var valuesString = JSON.stringify(expectedValues);
|
||||
return new PropTypeError(
|
||||
`Invalid ${location} \`${propFullName}\` of value \`${propValue}\` ` +
|
||||
`supplied to \`${componentName}\`, expected one of ${valuesString}.`
|
||||
`supplied to \`${componentName}\`, expected one of ${valuesString}.`,
|
||||
);
|
||||
}
|
||||
return createChainableTypeChecker(validate);
|
||||
@@ -345,7 +339,7 @@ function createObjectOfTypeChecker(typeChecker) {
|
||||
function validate(props, propName, componentName, location, propFullName) {
|
||||
if (typeof typeChecker !== 'function') {
|
||||
return new PropTypeError(
|
||||
`Property \`${propFullName}\` of component \`${componentName}\` has invalid PropType notation inside objectOf.`
|
||||
`Property \`${propFullName}\` of component \`${componentName}\` has invalid PropType notation inside objectOf.`,
|
||||
);
|
||||
}
|
||||
var propValue = props[propName];
|
||||
@@ -353,7 +347,7 @@ function createObjectOfTypeChecker(typeChecker) {
|
||||
if (propType !== 'object') {
|
||||
return new PropTypeError(
|
||||
`Invalid ${location} \`${propFullName}\` of type ` +
|
||||
`\`${propType}\` supplied to \`${componentName}\`, expected an object.`
|
||||
`\`${propType}\` supplied to \`${componentName}\`, expected an object.`,
|
||||
);
|
||||
}
|
||||
for (var key in propValue) {
|
||||
@@ -364,7 +358,7 @@ function createObjectOfTypeChecker(typeChecker) {
|
||||
componentName,
|
||||
location,
|
||||
`${propFullName}.${key}`,
|
||||
ReactPropTypesSecret
|
||||
ReactPropTypesSecret,
|
||||
);
|
||||
if (error instanceof Error) {
|
||||
return error;
|
||||
@@ -378,7 +372,10 @@ function createObjectOfTypeChecker(typeChecker) {
|
||||
|
||||
function createUnionTypeChecker(arrayOfTypeCheckers) {
|
||||
if (!Array.isArray(arrayOfTypeCheckers)) {
|
||||
warning(false, 'Invalid argument supplied to oneOfType, expected an instance of array.');
|
||||
warning(
|
||||
false,
|
||||
'Invalid argument supplied to oneOfType, expected an instance of array.',
|
||||
);
|
||||
return emptyFunction.thatReturnsNull;
|
||||
}
|
||||
|
||||
@@ -392,7 +389,7 @@ function createUnionTypeChecker(arrayOfTypeCheckers) {
|
||||
componentName,
|
||||
location,
|
||||
propFullName,
|
||||
ReactPropTypesSecret
|
||||
ReactPropTypesSecret,
|
||||
) == null
|
||||
) {
|
||||
return null;
|
||||
@@ -401,7 +398,7 @@ function createUnionTypeChecker(arrayOfTypeCheckers) {
|
||||
|
||||
return new PropTypeError(
|
||||
`Invalid ${location} \`${propFullName}\` supplied to ` +
|
||||
`\`${componentName}\`.`
|
||||
`\`${componentName}\`.`,
|
||||
);
|
||||
}
|
||||
return createChainableTypeChecker(validate);
|
||||
@@ -412,7 +409,7 @@ function createNodeChecker() {
|
||||
if (!isNode(props[propName])) {
|
||||
return new PropTypeError(
|
||||
`Invalid ${location} \`${propFullName}\` supplied to ` +
|
||||
`\`${componentName}\`, expected a ReactNode.`
|
||||
`\`${componentName}\`, expected a ReactNode.`,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
@@ -427,7 +424,7 @@ function createShapeTypeChecker(shapeTypes) {
|
||||
if (propType !== 'object') {
|
||||
return new PropTypeError(
|
||||
`Invalid ${location} \`${propFullName}\` of type \`${propType}\` ` +
|
||||
`supplied to \`${componentName}\`, expected \`object\`.`
|
||||
`supplied to \`${componentName}\`, expected \`object\`.`,
|
||||
);
|
||||
}
|
||||
for (var key in shapeTypes) {
|
||||
@@ -441,7 +438,7 @@ function createShapeTypeChecker(shapeTypes) {
|
||||
componentName,
|
||||
location,
|
||||
`${propFullName}.${key}`,
|
||||
ReactPropTypesSecret
|
||||
ReactPropTypesSecret,
|
||||
);
|
||||
if (error) {
|
||||
return error;
|
||||
|
||||
@@ -62,14 +62,22 @@ function typeCheckFailRequiredValues(declaration) {
|
||||
var unspecifiedMsg = 'The prop `testProp` is marked as required in ' +
|
||||
'`testComponent`, but its value is \`undefined\`.';
|
||||
|
||||
var propTypes = { testProp: declaration };
|
||||
var propTypes = {testProp: declaration};
|
||||
|
||||
// Required prop is null
|
||||
var message1 = getPropTypeWarningMessage(propTypes, { testProp: null }, 'testComponent');
|
||||
var message1 = getPropTypeWarningMessage(
|
||||
propTypes,
|
||||
{testProp: null},
|
||||
'testComponent',
|
||||
);
|
||||
expect(message1).toContain(specifiedButIsNullMsg);
|
||||
|
||||
// Required prop is undefined
|
||||
var message2 = getPropTypeWarningMessage(propTypes, { testProp: undefined }, 'testComponent');
|
||||
var message2 = getPropTypeWarningMessage(
|
||||
propTypes,
|
||||
{testProp: undefined},
|
||||
'testComponent',
|
||||
);
|
||||
expect(message2).toContain(unspecifiedMsg);
|
||||
|
||||
// Required prop is not a member of props object
|
||||
@@ -93,16 +101,11 @@ function expectWarningInDevelopment(declaration, value) {
|
||||
var propName = 'testProp' + Math.random().toString();
|
||||
var componentName = 'testComponent' + Math.random().toString();
|
||||
for (var i = 0; i < 3; i++) {
|
||||
declaration(
|
||||
props,
|
||||
propName,
|
||||
componentName,
|
||||
'prop'
|
||||
);
|
||||
declaration(props, propName, componentName, 'prop');
|
||||
}
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'You are manually calling a React.PropTypes validation '
|
||||
'You are manually calling a React.PropTypes validation ',
|
||||
);
|
||||
console.error.calls.reset();
|
||||
}
|
||||
@@ -124,8 +127,14 @@ describe('ReactPropTypes', () => {
|
||||
return new Error('some error');
|
||||
},
|
||||
};
|
||||
const props = { foo: 'foo' };
|
||||
const returnValue = checkPropTypes(propTypes, props, 'prop', 'testComponent', null);
|
||||
const props = {foo: 'foo'};
|
||||
const returnValue = checkPropTypes(
|
||||
propTypes,
|
||||
props,
|
||||
'prop',
|
||||
'testComponent',
|
||||
null,
|
||||
);
|
||||
expect(console.error.calls.argsFor(0)[0]).toContain('some error');
|
||||
expect(returnValue).toBe(undefined);
|
||||
});
|
||||
@@ -137,8 +146,14 @@ describe('ReactPropTypes', () => {
|
||||
throw new Error('some error');
|
||||
},
|
||||
};
|
||||
const props = { foo: 'foo' };
|
||||
const returnValue = checkPropTypes(propTypes, props, 'prop', 'testComponent', null);
|
||||
const props = {foo: 'foo'};
|
||||
const returnValue = checkPropTypes(
|
||||
propTypes,
|
||||
props,
|
||||
'prop',
|
||||
'testComponent',
|
||||
null,
|
||||
);
|
||||
expect(console.error.calls.argsFor(0)[0]).toContain('some error');
|
||||
expect(returnValue).toBe(undefined);
|
||||
});
|
||||
@@ -150,31 +165,31 @@ describe('ReactPropTypes', () => {
|
||||
PropTypes.string,
|
||||
[],
|
||||
'Invalid prop `testProp` of type `array` supplied to ' +
|
||||
'`testComponent`, expected `string`.'
|
||||
'`testComponent`, expected `string`.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.string,
|
||||
false,
|
||||
'Invalid prop `testProp` of type `boolean` supplied to ' +
|
||||
'`testComponent`, expected `string`.'
|
||||
'`testComponent`, expected `string`.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.string,
|
||||
0,
|
||||
'Invalid prop `testProp` of type `number` supplied to ' +
|
||||
'`testComponent`, expected `string`.'
|
||||
'`testComponent`, expected `string`.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.string,
|
||||
{},
|
||||
'Invalid prop `testProp` of type `object` supplied to ' +
|
||||
'`testComponent`, expected `string`.'
|
||||
'`testComponent`, expected `string`.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.string,
|
||||
Symbol(),
|
||||
'Invalid prop `testProp` of type `symbol` supplied to ' +
|
||||
'`testComponent`, expected `string`.'
|
||||
'`testComponent`, expected `string`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -183,13 +198,13 @@ describe('ReactPropTypes', () => {
|
||||
PropTypes.string,
|
||||
new Date(),
|
||||
'Invalid prop `testProp` of type `date` supplied to ' +
|
||||
'`testComponent`, expected `string`.'
|
||||
'`testComponent`, expected `string`.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.string,
|
||||
/please/,
|
||||
'Invalid prop `testProp` of type `regexp` supplied to ' +
|
||||
'`testComponent`, expected `string`.'
|
||||
'`testComponent`, expected `string`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -289,9 +304,9 @@ describe('ReactPropTypes', () => {
|
||||
describe('ArrayOf Type', () => {
|
||||
it('should fail for invalid argument', () => {
|
||||
typeCheckFail(
|
||||
PropTypes.arrayOf({ foo: PropTypes.string }),
|
||||
{ foo: 'bar' },
|
||||
'Property `testProp` of component `testComponent` has invalid PropType notation inside arrayOf.'
|
||||
PropTypes.arrayOf({foo: PropTypes.string}),
|
||||
{foo: 'bar'},
|
||||
'Property `testProp` of component `testComponent` has invalid PropType notation inside arrayOf.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -305,14 +320,14 @@ describe('ReactPropTypes', () => {
|
||||
it('should support arrayOf with complex types', () => {
|
||||
typeCheckPass(
|
||||
PropTypes.arrayOf(PropTypes.shape({a: PropTypes.number.isRequired})),
|
||||
[{a: 1}, {a: 2}]
|
||||
[{a: 1}, {a: 2}],
|
||||
);
|
||||
|
||||
function Thing() {}
|
||||
typeCheckPass(
|
||||
PropTypes.arrayOf(PropTypes.instanceOf(Thing)),
|
||||
[new Thing(), new Thing()]
|
||||
);
|
||||
typeCheckPass(PropTypes.arrayOf(PropTypes.instanceOf(Thing)), [
|
||||
new Thing(),
|
||||
new Thing(),
|
||||
]);
|
||||
});
|
||||
|
||||
it('should warn with invalid items in the array', () => {
|
||||
@@ -320,7 +335,7 @@ describe('ReactPropTypes', () => {
|
||||
PropTypes.arrayOf(PropTypes.number),
|
||||
[1, 2, 'b'],
|
||||
'Invalid prop `testProp[2]` of type `string` supplied to ' +
|
||||
'`testComponent`, expected `number`.'
|
||||
'`testComponent`, expected `number`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -332,7 +347,9 @@ describe('ReactPropTypes', () => {
|
||||
PropTypes.arrayOf(PropTypes.instanceOf(Thing)),
|
||||
[new Thing(), 'xyz'],
|
||||
'Invalid prop `testProp[1]` of type `String` supplied to ' +
|
||||
'`testComponent`, expected instance of `' + name + '`.'
|
||||
'`testComponent`, expected instance of `' +
|
||||
name +
|
||||
'`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -341,19 +358,19 @@ describe('ReactPropTypes', () => {
|
||||
PropTypes.arrayOf(PropTypes.number),
|
||||
{'0': 'maybe-array', length: 1},
|
||||
'Invalid prop `testProp` of type `object` supplied to ' +
|
||||
'`testComponent`, expected an array.'
|
||||
'`testComponent`, expected an array.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.arrayOf(PropTypes.number),
|
||||
123,
|
||||
'Invalid prop `testProp` of type `number` supplied to ' +
|
||||
'`testComponent`, expected an array.'
|
||||
'`testComponent`, expected an array.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.arrayOf(PropTypes.number),
|
||||
'string',
|
||||
'Invalid prop `testProp` of type `string` supplied to ' +
|
||||
'`testComponent`, expected an array.'
|
||||
'`testComponent`, expected an array.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -368,26 +385,32 @@ describe('ReactPropTypes', () => {
|
||||
|
||||
it('should warn for missing required values', () => {
|
||||
typeCheckFailRequiredValues(
|
||||
PropTypes.arrayOf(PropTypes.number).isRequired
|
||||
PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn if called manually in development', () => {
|
||||
spyOn(console, 'error');
|
||||
expectWarningInDevelopment(PropTypes.arrayOf({foo: PropTypes.string}), {
|
||||
foo: 'bar',
|
||||
});
|
||||
expectWarningInDevelopment(PropTypes.arrayOf(PropTypes.number), [
|
||||
1,
|
||||
2,
|
||||
'b',
|
||||
]);
|
||||
expectWarningInDevelopment(PropTypes.arrayOf(PropTypes.number), {
|
||||
'0': 'maybe-array',
|
||||
length: 1,
|
||||
});
|
||||
expectWarningInDevelopment(
|
||||
PropTypes.arrayOf({ foo: PropTypes.string }),
|
||||
{ foo: 'bar' }
|
||||
PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
null,
|
||||
);
|
||||
expectWarningInDevelopment(
|
||||
PropTypes.arrayOf(PropTypes.number),
|
||||
[1, 2, 'b']
|
||||
PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
undefined,
|
||||
);
|
||||
expectWarningInDevelopment(
|
||||
PropTypes.arrayOf(PropTypes.number),
|
||||
{'0': 'maybe-array', length: 1}
|
||||
);
|
||||
expectWarningInDevelopment(PropTypes.arrayOf(PropTypes.number).isRequired, null);
|
||||
expectWarningInDevelopment(PropTypes.arrayOf(PropTypes.number).isRequired, undefined);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -413,25 +436,25 @@ describe('ReactPropTypes', () => {
|
||||
PropTypes.element,
|
||||
[<div />, <div />],
|
||||
'Invalid prop `testProp` of type `array` supplied to `testComponent`, ' +
|
||||
'expected a single ReactElement.'
|
||||
'expected a single ReactElement.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.element,
|
||||
123,
|
||||
'Invalid prop `testProp` of type `number` supplied to `testComponent`, ' +
|
||||
'expected a single ReactElement.'
|
||||
'expected a single ReactElement.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.element,
|
||||
'foo',
|
||||
'Invalid prop `testProp` of type `string` supplied to `testComponent`, ' +
|
||||
'expected a single ReactElement.'
|
||||
'expected a single ReactElement.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.element,
|
||||
false,
|
||||
'Invalid prop `testProp` of type `boolean` supplied to `testComponent`, ' +
|
||||
'expected a single ReactElement.'
|
||||
'expected a single ReactElement.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -472,7 +495,6 @@ describe('ReactPropTypes', () => {
|
||||
expectWarningInDevelopment(PropTypes.element.isRequired, null);
|
||||
expectWarningInDevelopment(PropTypes.element.isRequired, undefined);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Instance Types', () => {
|
||||
@@ -487,43 +509,57 @@ describe('ReactPropTypes', () => {
|
||||
PropTypes.instanceOf(Person),
|
||||
false,
|
||||
'Invalid prop `testProp` of type `Boolean` supplied to ' +
|
||||
'`testComponent`, expected instance of `' + personName + '`.'
|
||||
'`testComponent`, expected instance of `' +
|
||||
personName +
|
||||
'`.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.instanceOf(Person),
|
||||
{},
|
||||
'Invalid prop `testProp` of type `Object` supplied to ' +
|
||||
'`testComponent`, expected instance of `' + personName + '`.'
|
||||
'`testComponent`, expected instance of `' +
|
||||
personName +
|
||||
'`.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.instanceOf(Person),
|
||||
'',
|
||||
'Invalid prop `testProp` of type `String` supplied to ' +
|
||||
'`testComponent`, expected instance of `' + personName + '`.'
|
||||
'`testComponent`, expected instance of `' +
|
||||
personName +
|
||||
'`.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.instanceOf(Date),
|
||||
{},
|
||||
'Invalid prop `testProp` of type `Object` supplied to ' +
|
||||
'`testComponent`, expected instance of `' + dateName + '`.'
|
||||
'`testComponent`, expected instance of `' +
|
||||
dateName +
|
||||
'`.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.instanceOf(RegExp),
|
||||
{},
|
||||
'Invalid prop `testProp` of type `Object` supplied to ' +
|
||||
'`testComponent`, expected instance of `' + regExpName + '`.'
|
||||
'`testComponent`, expected instance of `' +
|
||||
regExpName +
|
||||
'`.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.instanceOf(Person),
|
||||
new Cat(),
|
||||
'Invalid prop `testProp` of type `Cat` supplied to ' +
|
||||
'`testComponent`, expected instance of `' + personName + '`.'
|
||||
'`testComponent`, expected instance of `' +
|
||||
personName +
|
||||
'`.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.instanceOf(Person),
|
||||
Object.create(null),
|
||||
'Invalid prop `testProp` of type `<<anonymous>>` supplied to ' +
|
||||
'`testComponent`, expected instance of `' + personName + '`.'
|
||||
'`testComponent`, expected instance of `' +
|
||||
personName +
|
||||
'`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -553,9 +589,11 @@ describe('ReactPropTypes', () => {
|
||||
expectWarningInDevelopment(PropTypes.instanceOf(Date), {});
|
||||
expectWarningInDevelopment(PropTypes.instanceOf(Date), new Date());
|
||||
expectWarningInDevelopment(PropTypes.instanceOf(Date).isRequired, {});
|
||||
expectWarningInDevelopment(PropTypes.instanceOf(Date).isRequired, new Date());
|
||||
expectWarningInDevelopment(
|
||||
PropTypes.instanceOf(Date).isRequired,
|
||||
new Date(),
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('React Component Types', () => {
|
||||
@@ -594,18 +632,21 @@ describe('ReactPropTypes', () => {
|
||||
|
||||
// Object of renderable things
|
||||
var frag = ReactFragment.create;
|
||||
typeCheckPass(PropTypes.node, frag({
|
||||
k0: 123,
|
||||
k1: 'Some string',
|
||||
k2: <div />,
|
||||
k3: frag({
|
||||
k30: <MyComponent />,
|
||||
k31: frag({k310: <a />}),
|
||||
k32: 'Another string',
|
||||
typeCheckPass(
|
||||
PropTypes.node,
|
||||
frag({
|
||||
k0: 123,
|
||||
k1: 'Some string',
|
||||
k2: <div />,
|
||||
k3: frag({
|
||||
k30: <MyComponent />,
|
||||
k31: frag({k310: <a />}),
|
||||
k32: 'Another string',
|
||||
}),
|
||||
k4: null,
|
||||
k5: undefined,
|
||||
}),
|
||||
k4: null,
|
||||
k5: undefined,
|
||||
}));
|
||||
);
|
||||
expectDev(console.error.calls.count()).toBe(0);
|
||||
});
|
||||
|
||||
@@ -632,7 +673,10 @@ describe('ReactPropTypes', () => {
|
||||
return {
|
||||
next: function() {
|
||||
var done = ++i > 2;
|
||||
return {value: done ? undefined : ['#' + i, <MyComponent />], done: done};
|
||||
return {
|
||||
value: done ? undefined : ['#' + i, <MyComponent />],
|
||||
done: done,
|
||||
};
|
||||
},
|
||||
};
|
||||
},
|
||||
@@ -663,45 +707,46 @@ describe('ReactPropTypes', () => {
|
||||
expectWarningInDevelopment(PropTypes.node.isRequired, undefined);
|
||||
expectWarningInDevelopment(PropTypes.node.isRequired, undefined);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('ObjectOf Type', () => {
|
||||
it('should fail for invalid argument', () => {
|
||||
typeCheckFail(
|
||||
PropTypes.objectOf({ foo: PropTypes.string }),
|
||||
{ foo: 'bar' },
|
||||
'Property `testProp` of component `testComponent` has invalid PropType notation inside objectOf.'
|
||||
PropTypes.objectOf({foo: PropTypes.string}),
|
||||
{foo: 'bar'},
|
||||
'Property `testProp` of component `testComponent` has invalid PropType notation inside objectOf.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should support the objectOf propTypes', () => {
|
||||
typeCheckPass(PropTypes.objectOf(PropTypes.number), {a: 1, b: 2, c: 3});
|
||||
typeCheckPass(
|
||||
PropTypes.objectOf(PropTypes.string),
|
||||
{a: 'a', b: 'b', c: 'c'}
|
||||
);
|
||||
typeCheckPass(
|
||||
PropTypes.objectOf(PropTypes.oneOf(['a', 'b'])),
|
||||
{a: 'a', b: 'b'}
|
||||
);
|
||||
typeCheckPass(
|
||||
PropTypes.objectOf(PropTypes.symbol),
|
||||
{a: Symbol(), b: Symbol(), c: Symbol()}
|
||||
);
|
||||
typeCheckPass(PropTypes.objectOf(PropTypes.string), {
|
||||
a: 'a',
|
||||
b: 'b',
|
||||
c: 'c',
|
||||
});
|
||||
typeCheckPass(PropTypes.objectOf(PropTypes.oneOf(['a', 'b'])), {
|
||||
a: 'a',
|
||||
b: 'b',
|
||||
});
|
||||
typeCheckPass(PropTypes.objectOf(PropTypes.symbol), {
|
||||
a: Symbol(),
|
||||
b: Symbol(),
|
||||
c: Symbol(),
|
||||
});
|
||||
});
|
||||
|
||||
it('should support objectOf with complex types', () => {
|
||||
typeCheckPass(
|
||||
PropTypes.objectOf(PropTypes.shape({a: PropTypes.number.isRequired})),
|
||||
{a: {a: 1}, b: {a: 2}}
|
||||
{a: {a: 1}, b: {a: 2}},
|
||||
);
|
||||
|
||||
function Thing() {}
|
||||
typeCheckPass(
|
||||
PropTypes.objectOf(PropTypes.instanceOf(Thing)),
|
||||
{a: new Thing(), b: new Thing()}
|
||||
);
|
||||
typeCheckPass(PropTypes.objectOf(PropTypes.instanceOf(Thing)), {
|
||||
a: new Thing(),
|
||||
b: new Thing(),
|
||||
});
|
||||
});
|
||||
|
||||
it('should warn with invalid items in the object', () => {
|
||||
@@ -709,7 +754,7 @@ describe('ReactPropTypes', () => {
|
||||
PropTypes.objectOf(PropTypes.number),
|
||||
{a: 1, b: 2, c: 'b'},
|
||||
'Invalid prop `testProp.c` of type `string` supplied to `testComponent`, ' +
|
||||
'expected `number`.'
|
||||
'expected `number`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -721,7 +766,9 @@ describe('ReactPropTypes', () => {
|
||||
PropTypes.objectOf(PropTypes.instanceOf(Thing)),
|
||||
{a: new Thing(), b: 'xyz'},
|
||||
'Invalid prop `testProp.b` of type `String` supplied to ' +
|
||||
'`testComponent`, expected instance of `' + name + '`.'
|
||||
'`testComponent`, expected instance of `' +
|
||||
name +
|
||||
'`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -730,25 +777,25 @@ describe('ReactPropTypes', () => {
|
||||
PropTypes.objectOf(PropTypes.number),
|
||||
[1, 2],
|
||||
'Invalid prop `testProp` of type `array` supplied to ' +
|
||||
'`testComponent`, expected an object.'
|
||||
'`testComponent`, expected an object.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.objectOf(PropTypes.number),
|
||||
123,
|
||||
'Invalid prop `testProp` of type `number` supplied to ' +
|
||||
'`testComponent`, expected an object.'
|
||||
'`testComponent`, expected an object.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.objectOf(PropTypes.number),
|
||||
'string',
|
||||
'Invalid prop `testProp` of type `string` supplied to ' +
|
||||
'`testComponent`, expected an object.'
|
||||
'`testComponent`, expected an object.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.objectOf(PropTypes.symbol),
|
||||
Symbol(),
|
||||
'Invalid prop `testProp` of type `symbol` supplied to ' +
|
||||
'`testComponent`, expected an object.'
|
||||
'`testComponent`, expected an object.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -763,23 +810,26 @@ describe('ReactPropTypes', () => {
|
||||
|
||||
it('should warn for missing required values', () => {
|
||||
typeCheckFailRequiredValues(
|
||||
PropTypes.objectOf(PropTypes.number).isRequired
|
||||
PropTypes.objectOf(PropTypes.number).isRequired,
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn if called manually in development', () => {
|
||||
spyOn(console, 'error');
|
||||
expectWarningInDevelopment(
|
||||
PropTypes.objectOf({ foo: PropTypes.string }),
|
||||
{ foo: 'bar' }
|
||||
);
|
||||
expectWarningInDevelopment(
|
||||
PropTypes.objectOf(PropTypes.number),
|
||||
{a: 1, b: 2, c: 'b'}
|
||||
);
|
||||
expectWarningInDevelopment(PropTypes.objectOf({foo: PropTypes.string}), {
|
||||
foo: 'bar',
|
||||
});
|
||||
expectWarningInDevelopment(PropTypes.objectOf(PropTypes.number), {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 'b',
|
||||
});
|
||||
expectWarningInDevelopment(PropTypes.objectOf(PropTypes.number), [1, 2]);
|
||||
expectWarningInDevelopment(PropTypes.objectOf(PropTypes.number), null);
|
||||
expectWarningInDevelopment(PropTypes.objectOf(PropTypes.number), undefined);
|
||||
expectWarningInDevelopment(
|
||||
PropTypes.objectOf(PropTypes.number),
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -790,8 +840,9 @@ describe('ReactPropTypes', () => {
|
||||
PropTypes.oneOf('red', 'blue');
|
||||
|
||||
expectDev(console.error).toHaveBeenCalled();
|
||||
expectDev(console.error.calls.argsFor(0)[0])
|
||||
.toContain('Invalid argument supplied to oneOf, expected an instance of array.');
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Invalid argument supplied to oneOf, expected an instance of array.',
|
||||
);
|
||||
|
||||
typeCheckPass(PropTypes.oneOf('red', 'blue'), 'red');
|
||||
});
|
||||
@@ -801,25 +852,25 @@ describe('ReactPropTypes', () => {
|
||||
PropTypes.oneOf(['red', 'blue']),
|
||||
true,
|
||||
'Invalid prop `testProp` of value `true` supplied to ' +
|
||||
'`testComponent`, expected one of ["red","blue"].'
|
||||
'`testComponent`, expected one of ["red","blue"].',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.oneOf(['red', 'blue']),
|
||||
[],
|
||||
'Invalid prop `testProp` of value `` supplied to `testComponent`, ' +
|
||||
'expected one of ["red","blue"].'
|
||||
'expected one of ["red","blue"].',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.oneOf(['red', 'blue']),
|
||||
'',
|
||||
'Invalid prop `testProp` of value `` supplied to `testComponent`, ' +
|
||||
'expected one of ["red","blue"].'
|
||||
'expected one of ["red","blue"].',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.oneOf([0, 'false']),
|
||||
false,
|
||||
'Invalid prop `testProp` of value `false` supplied to ' +
|
||||
'`testComponent`, expected one of [0,"false"].'
|
||||
'`testComponent`, expected one of [0,"false"].',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -853,8 +904,9 @@ describe('ReactPropTypes', () => {
|
||||
PropTypes.oneOfType(PropTypes.string, PropTypes.number);
|
||||
|
||||
expectDev(console.error).toHaveBeenCalled();
|
||||
expectDev(console.error.calls.argsFor(0)[0])
|
||||
.toContain('Invalid argument supplied to oneOfType, expected an instance of array.');
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Invalid argument supplied to oneOfType, expected an instance of array.',
|
||||
);
|
||||
|
||||
typeCheckPass(PropTypes.oneOf(PropTypes.string, PropTypes.number), []);
|
||||
});
|
||||
@@ -863,7 +915,7 @@ describe('ReactPropTypes', () => {
|
||||
typeCheckFail(
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
[],
|
||||
'Invalid prop `testProp` supplied to `testComponent`.'
|
||||
'Invalid prop `testProp` supplied to `testComponent`.',
|
||||
);
|
||||
|
||||
var checker = PropTypes.oneOfType([
|
||||
@@ -873,15 +925,12 @@ describe('ReactPropTypes', () => {
|
||||
typeCheckFail(
|
||||
checker,
|
||||
{c: 1},
|
||||
'Invalid prop `testProp` supplied to `testComponent`.'
|
||||
'Invalid prop `testProp` supplied to `testComponent`.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should not warn if one of the types are valid', () => {
|
||||
var checker = PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.number,
|
||||
]);
|
||||
var checker = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
|
||||
typeCheckPass(checker, null);
|
||||
typeCheckPass(checker, 'foo');
|
||||
typeCheckPass(checker, 123);
|
||||
@@ -896,16 +945,18 @@ describe('ReactPropTypes', () => {
|
||||
|
||||
it('should be implicitly optional and not warn without values', () => {
|
||||
typeCheckPass(
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.number]), null
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
null,
|
||||
);
|
||||
typeCheckPass(
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.number]), undefined
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn for missing required values', () => {
|
||||
typeCheckFailRequiredValues(
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -913,18 +964,17 @@ describe('ReactPropTypes', () => {
|
||||
spyOn(console, 'error');
|
||||
expectWarningInDevelopment(
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
[]
|
||||
[],
|
||||
);
|
||||
expectWarningInDevelopment(
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
null
|
||||
null,
|
||||
);
|
||||
expectWarningInDevelopment(
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Shape Types', () => {
|
||||
@@ -933,13 +983,13 @@ describe('ReactPropTypes', () => {
|
||||
PropTypes.shape({}),
|
||||
'some string',
|
||||
'Invalid prop `testProp` of type `string` supplied to ' +
|
||||
'`testComponent`, expected `object`.'
|
||||
'`testComponent`, expected `object`.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.shape({}),
|
||||
['array'],
|
||||
'Invalid prop `testProp` of type `array` supplied to ' +
|
||||
'`testComponent`, expected `object`.'
|
||||
'`testComponent`, expected `object`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -966,7 +1016,7 @@ describe('ReactPropTypes', () => {
|
||||
PropTypes.shape({key: PropTypes.number.isRequired}),
|
||||
{},
|
||||
'The prop `testProp.key` is marked as required in `testComponent`, ' +
|
||||
'but its value is `undefined`.'
|
||||
'but its value is `undefined`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -978,44 +1028,49 @@ describe('ReactPropTypes', () => {
|
||||
}),
|
||||
{},
|
||||
'The prop `testProp.key` is marked as required in `testComponent`, ' +
|
||||
'but its value is `undefined`.'
|
||||
'but its value is `undefined`.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn for invalid key types', () => {
|
||||
typeCheckFail(PropTypes.shape({key: PropTypes.number}),
|
||||
typeCheckFail(
|
||||
PropTypes.shape({key: PropTypes.number}),
|
||||
{key: 'abc'},
|
||||
'Invalid prop `testProp.key` of type `string` supplied to `testComponent`, ' +
|
||||
'expected `number`.'
|
||||
'expected `number`.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should be implicitly optional and not warn without values', () => {
|
||||
typeCheckPass(
|
||||
PropTypes.shape(PropTypes.shape({key: PropTypes.number})), null
|
||||
PropTypes.shape(PropTypes.shape({key: PropTypes.number})),
|
||||
null,
|
||||
);
|
||||
typeCheckPass(
|
||||
PropTypes.shape(PropTypes.shape({key: PropTypes.number})), undefined
|
||||
PropTypes.shape(PropTypes.shape({key: PropTypes.number})),
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn for missing required values', () => {
|
||||
typeCheckFailRequiredValues(
|
||||
PropTypes.shape({key: PropTypes.number}).isRequired
|
||||
PropTypes.shape({key: PropTypes.number}).isRequired,
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn if called manually in development', () => {
|
||||
spyOn(console, 'error');
|
||||
expectWarningInDevelopment(PropTypes.shape({}), 'some string');
|
||||
expectWarningInDevelopment(PropTypes.shape({ foo: PropTypes.number }), { foo: 42 });
|
||||
expectWarningInDevelopment(PropTypes.shape({foo: PropTypes.number}), {
|
||||
foo: 42,
|
||||
});
|
||||
expectWarningInDevelopment(
|
||||
PropTypes.shape({key: PropTypes.number}).isRequired,
|
||||
null
|
||||
null,
|
||||
);
|
||||
expectWarningInDevelopment(
|
||||
PropTypes.shape({key: PropTypes.number}).isRequired,
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
expectWarningInDevelopment(PropTypes.element, <div />);
|
||||
});
|
||||
@@ -1027,13 +1082,13 @@ describe('ReactPropTypes', () => {
|
||||
PropTypes.symbol,
|
||||
'hello',
|
||||
'Invalid prop `testProp` of type `string` supplied to ' +
|
||||
'`testComponent`, expected `symbol`.'
|
||||
'`testComponent`, expected `symbol`.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.symbol,
|
||||
function() { },
|
||||
function() {},
|
||||
'Invalid prop `testProp` of type `function` supplied to ' +
|
||||
'`testComponent`, expected `symbol`.'
|
||||
'`testComponent`, expected `symbol`.',
|
||||
);
|
||||
typeCheckFail(
|
||||
PropTypes.symbol,
|
||||
@@ -1041,7 +1096,7 @@ describe('ReactPropTypes', () => {
|
||||
'@@toStringTag': 'Katana',
|
||||
},
|
||||
'Invalid prop `testProp` of type `object` supplied to ' +
|
||||
'`testComponent`, expected `symbol`.'
|
||||
'`testComponent`, expected `symbol`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1090,15 +1145,15 @@ describe('ReactPropTypes', () => {
|
||||
expect(spy.calls.argsFor(0)[1]).toBe('num');
|
||||
});
|
||||
|
||||
it('should have received the validator\'s return value', () => {
|
||||
it("should have received the validator's return value", () => {
|
||||
spyOn(console, 'error');
|
||||
var spy = jasmine.createSpy().and.callFake(
|
||||
function(props, propName, componentName) {
|
||||
var spy = jasmine
|
||||
.createSpy()
|
||||
.and.callFake(function(props, propName, componentName) {
|
||||
if (props[propName] !== 5) {
|
||||
return new Error('num must be 5!');
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
Component = class extends React.Component {
|
||||
static propTypes = {num: spy};
|
||||
|
||||
@@ -1111,33 +1166,31 @@ describe('ReactPropTypes', () => {
|
||||
ReactDOM.render(<Component num={6} />, container);
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expect(
|
||||
console.error.calls.argsFor(0)[0].replace(/\(at .+?:\d+\)/g, '(at **)')
|
||||
console.error.calls.argsFor(0)[0].replace(/\(at .+?:\d+\)/g, '(at **)'),
|
||||
).toBe(
|
||||
'Warning: Failed prop type: num must be 5!\n' +
|
||||
' in Component (at **)'
|
||||
' in Component (at **)',
|
||||
);
|
||||
});
|
||||
|
||||
it('should not warn if the validator returned null',
|
||||
() => {
|
||||
spyOn(console, 'error');
|
||||
var spy = jasmine.createSpy().and.callFake(
|
||||
function(props, propName, componentName) {
|
||||
return null;
|
||||
}
|
||||
);
|
||||
Component = class extends React.Component {
|
||||
static propTypes = {num: spy};
|
||||
it('should not warn if the validator returned null', () => {
|
||||
spyOn(console, 'error');
|
||||
var spy = jasmine
|
||||
.createSpy()
|
||||
.and.callFake(function(props, propName, componentName) {
|
||||
return null;
|
||||
});
|
||||
Component = class extends React.Component {
|
||||
static propTypes = {num: spy};
|
||||
|
||||
render() {
|
||||
return <div />;
|
||||
}
|
||||
};
|
||||
render() {
|
||||
return <div />;
|
||||
}
|
||||
};
|
||||
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(<Component num={5} />, container);
|
||||
expectDev(console.error.calls.count()).toBe(0);
|
||||
}
|
||||
);
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(<Component num={5} />, container);
|
||||
expectDev(console.error.calls.count()).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -42,15 +42,8 @@ describe('ReactPropTypesProduction', function() {
|
||||
function expectThrowsInProduction(declaration, value) {
|
||||
var props = {testProp: value};
|
||||
expect(() => {
|
||||
declaration(
|
||||
props,
|
||||
'testProp',
|
||||
'testComponent',
|
||||
'prop'
|
||||
);
|
||||
}).toThrowError(
|
||||
'Minified React error #144'
|
||||
);
|
||||
declaration(props, 'testProp', 'testComponent', 'prop');
|
||||
}).toThrowError('Minified React error #144');
|
||||
}
|
||||
|
||||
describe('Primitive Types', function() {
|
||||
@@ -96,20 +89,26 @@ describe('ReactPropTypesProduction', function() {
|
||||
|
||||
describe('ArrayOf Type', function() {
|
||||
it('should be a no-op', function() {
|
||||
expectThrowsInProduction(PropTypes.arrayOf({foo: PropTypes.string}), {
|
||||
foo: 'bar',
|
||||
});
|
||||
expectThrowsInProduction(PropTypes.arrayOf(PropTypes.number), [
|
||||
1,
|
||||
2,
|
||||
'b',
|
||||
]);
|
||||
expectThrowsInProduction(PropTypes.arrayOf(PropTypes.number), {
|
||||
'0': 'maybe-array',
|
||||
length: 1,
|
||||
});
|
||||
expectThrowsInProduction(
|
||||
PropTypes.arrayOf({ foo: PropTypes.string }),
|
||||
{ foo: 'bar' }
|
||||
PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
null,
|
||||
);
|
||||
expectThrowsInProduction(
|
||||
PropTypes.arrayOf(PropTypes.number),
|
||||
[1, 2, 'b']
|
||||
PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
undefined,
|
||||
);
|
||||
expectThrowsInProduction(
|
||||
PropTypes.arrayOf(PropTypes.number),
|
||||
{'0': 'maybe-array', length: 1}
|
||||
);
|
||||
expectThrowsInProduction(PropTypes.arrayOf(PropTypes.number).isRequired, null);
|
||||
expectThrowsInProduction(PropTypes.arrayOf(PropTypes.number).isRequired, undefined);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -141,14 +140,14 @@ describe('ReactPropTypesProduction', function() {
|
||||
|
||||
describe('ObjectOf Type', function() {
|
||||
it('should be a no-op', function() {
|
||||
expectThrowsInProduction(
|
||||
PropTypes.objectOf({ foo: PropTypes.string }),
|
||||
{ foo: 'bar' }
|
||||
);
|
||||
expectThrowsInProduction(
|
||||
PropTypes.objectOf(PropTypes.number),
|
||||
{a: 1, b: 2, c: 'b'}
|
||||
);
|
||||
expectThrowsInProduction(PropTypes.objectOf({foo: PropTypes.string}), {
|
||||
foo: 'bar',
|
||||
});
|
||||
expectThrowsInProduction(PropTypes.objectOf(PropTypes.number), {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 'b',
|
||||
});
|
||||
expectThrowsInProduction(PropTypes.objectOf(PropTypes.number), [1, 2]);
|
||||
expectThrowsInProduction(PropTypes.objectOf(PropTypes.number), null);
|
||||
expectThrowsInProduction(PropTypes.objectOf(PropTypes.number), undefined);
|
||||
@@ -168,19 +167,19 @@ describe('ReactPropTypesProduction', function() {
|
||||
it('should be a no-op', function() {
|
||||
expectThrowsInProduction(
|
||||
PropTypes.oneOfType(PropTypes.string, PropTypes.number),
|
||||
'red'
|
||||
'red',
|
||||
);
|
||||
expectThrowsInProduction(
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
[]
|
||||
[],
|
||||
);
|
||||
expectThrowsInProduction(
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
null
|
||||
null,
|
||||
);
|
||||
expectThrowsInProduction(
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -190,11 +189,11 @@ describe('ReactPropTypesProduction', function() {
|
||||
expectThrowsInProduction(PropTypes.shape({}), 'some string');
|
||||
expectThrowsInProduction(
|
||||
PropTypes.shape({key: PropTypes.number}).isRequired,
|
||||
null
|
||||
null,
|
||||
);
|
||||
expectThrowsInProduction(
|
||||
PropTypes.shape({key: PropTypes.number}).isRequired,
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -43,26 +43,33 @@ function checkPropTypes(typeSpecs, values, location, componentName, getStack) {
|
||||
invariant(
|
||||
typeof typeSpecs[typeSpecName] === 'function',
|
||||
'%s: %s type `%s` is invalid; it must be a function, usually from ' +
|
||||
'React.PropTypes.',
|
||||
'React.PropTypes.',
|
||||
componentName || 'React class',
|
||||
location,
|
||||
typeSpecName
|
||||
typeSpecName,
|
||||
);
|
||||
error = typeSpecs[typeSpecName](
|
||||
values,
|
||||
typeSpecName,
|
||||
componentName,
|
||||
location,
|
||||
null,
|
||||
ReactPropTypesSecret,
|
||||
);
|
||||
error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret);
|
||||
} catch (ex) {
|
||||
error = ex;
|
||||
}
|
||||
warning(
|
||||
!error || error instanceof Error,
|
||||
'%s: type specification of %s `%s` is invalid; the type checker ' +
|
||||
'function must return `null` or an `Error` but returned a %s. ' +
|
||||
'You may have forgotten to pass an argument to the type checker ' +
|
||||
'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' +
|
||||
'shape all require an argument).',
|
||||
'function must return `null` or an `Error` but returned a %s. ' +
|
||||
'You may have forgotten to pass an argument to the type checker ' +
|
||||
'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' +
|
||||
'shape all require an argument).',
|
||||
componentName || 'React class',
|
||||
location,
|
||||
typeSpecName,
|
||||
typeof error
|
||||
typeof error,
|
||||
);
|
||||
if (error instanceof Error && !(error.message in loggedTypeFailures)) {
|
||||
// Only monitor this failure once because there tends to be a lot of the
|
||||
|
||||
@@ -21,24 +21,27 @@ var invariant = require('fbjs/lib/invariant');
|
||||
var warning = require('fbjs/lib/warning');
|
||||
var getComponentName = require('getComponentName');
|
||||
|
||||
import type { ReactElement, Source } from 'ReactElementType';
|
||||
import type { DebugID } from 'ReactInstanceType';
|
||||
import type { Fiber } from 'ReactFiber';
|
||||
import type {ReactElement, Source} from 'ReactElementType';
|
||||
import type {DebugID} from 'ReactInstanceType';
|
||||
import type {Fiber} from 'ReactFiber';
|
||||
|
||||
function isNative(fn) {
|
||||
// Based on isNative() from Lodash
|
||||
var funcToString = Function.prototype.toString;
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
var reIsNative = RegExp('^' + funcToString
|
||||
// Take an example native function source for comparison
|
||||
.call(hasOwnProperty)
|
||||
// Strip regex characters so we can use it for regex
|
||||
.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
|
||||
// Remove hasOwnProperty from the template to make it generic
|
||||
.replace(
|
||||
/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,
|
||||
'$1.*?'
|
||||
) + '$'
|
||||
var reIsNative = RegExp(
|
||||
'^' +
|
||||
funcToString
|
||||
// Take an example native function source for comparison
|
||||
.call(hasOwnProperty)
|
||||
// Strip regex characters so we can use it for regex
|
||||
.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
|
||||
// Remove hasOwnProperty from the template to make it generic
|
||||
.replace(
|
||||
/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,
|
||||
'$1.*?',
|
||||
) +
|
||||
'$',
|
||||
);
|
||||
try {
|
||||
var source = funcToString.call(fn);
|
||||
@@ -48,7 +51,7 @@ function isNative(fn) {
|
||||
}
|
||||
}
|
||||
|
||||
var canUseCollections = (
|
||||
var canUseCollections =
|
||||
// Array.from
|
||||
typeof Array.from === 'function' &&
|
||||
// Map
|
||||
@@ -64,8 +67,7 @@ var canUseCollections = (
|
||||
// Set.prototype.keys
|
||||
Set.prototype != null &&
|
||||
typeof Set.prototype.keys === 'function' &&
|
||||
isNative(Set.prototype.keys)
|
||||
);
|
||||
isNative(Set.prototype.keys);
|
||||
|
||||
var setItem;
|
||||
var getItem;
|
||||
@@ -101,7 +103,6 @@ if (canUseCollections) {
|
||||
getRootIDs = function() {
|
||||
return Array.from(rootIDSet.keys());
|
||||
};
|
||||
|
||||
} else {
|
||||
var itemByKey = {};
|
||||
var rootByKey = {};
|
||||
@@ -179,10 +180,14 @@ function describeID(id: DebugID): string {
|
||||
warning(
|
||||
element,
|
||||
'ReactComponentTreeHook: Missing React element for debugID %s when ' +
|
||||
'building stack',
|
||||
id
|
||||
'building stack',
|
||||
id,
|
||||
);
|
||||
return describeComponentFrame(
|
||||
name || '',
|
||||
element && element._source,
|
||||
ownerName || '',
|
||||
);
|
||||
return describeComponentFrame(name || '', element && element._source, ownerName || '');
|
||||
}
|
||||
|
||||
var ReactComponentTreeHook = {
|
||||
@@ -197,19 +202,19 @@ var ReactComponentTreeHook = {
|
||||
invariant(
|
||||
nextChild,
|
||||
'Expected hook events to fire for the child ' +
|
||||
'before its parent includes it in onSetChildren().'
|
||||
'before its parent includes it in onSetChildren().',
|
||||
);
|
||||
invariant(
|
||||
nextChild.childIDs != null ||
|
||||
typeof nextChild.element !== 'object' ||
|
||||
nextChild.element == null,
|
||||
typeof nextChild.element !== 'object' ||
|
||||
nextChild.element == null,
|
||||
'Expected onSetChildren() to fire for a container child ' +
|
||||
'before its parent includes it in onSetChildren().'
|
||||
'before its parent includes it in onSetChildren().',
|
||||
);
|
||||
invariant(
|
||||
nextChild.isMounted,
|
||||
'Expected onMountComponent() to fire for the child ' +
|
||||
'before its parent includes it in onSetChildren().'
|
||||
'before its parent includes it in onSetChildren().',
|
||||
);
|
||||
if (nextChild.parentID == null) {
|
||||
nextChild.parentID = id;
|
||||
@@ -220,15 +225,19 @@ var ReactComponentTreeHook = {
|
||||
invariant(
|
||||
nextChild.parentID === id,
|
||||
'Expected onBeforeMountComponent() parent and onSetChildren() to ' +
|
||||
'be consistent (%s has parents %s and %s).',
|
||||
'be consistent (%s has parents %s and %s).',
|
||||
nextChildID,
|
||||
nextChild.parentID,
|
||||
id
|
||||
id,
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
onBeforeMountComponent(id: DebugID, element: ReactElement, parentID: DebugID): void {
|
||||
onBeforeMountComponent(
|
||||
id: DebugID,
|
||||
element: ReactElement,
|
||||
parentID: DebugID,
|
||||
): void {
|
||||
var item = {
|
||||
element,
|
||||
parentID,
|
||||
@@ -313,19 +322,21 @@ var ReactComponentTreeHook = {
|
||||
info += describeComponentFrame(
|
||||
name,
|
||||
topElement._source,
|
||||
owner && getComponentName(owner)
|
||||
owner && getComponentName(owner),
|
||||
);
|
||||
}
|
||||
|
||||
var currentOwner = ReactCurrentOwner.current;
|
||||
if (currentOwner) {
|
||||
if (typeof currentOwner.tag === 'number') {
|
||||
const workInProgress = ((currentOwner : any) : Fiber);
|
||||
const workInProgress = ((currentOwner: any): Fiber);
|
||||
// Safe because if current owner exists, we are reconciling,
|
||||
// and it is guaranteed to be the work-in-progress version.
|
||||
info += getStackAddendumByWorkInProgressFiber(workInProgress);
|
||||
} else if (typeof currentOwner._debugID === 'number') {
|
||||
info += ReactComponentTreeHook.getStackAddendumByID(currentOwner._debugID);
|
||||
info += ReactComponentTreeHook.getStackAddendumByID(
|
||||
currentOwner._debugID,
|
||||
);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
|
||||
@@ -60,10 +60,10 @@ ReactComponent.prototype.isReactComponent = {};
|
||||
ReactComponent.prototype.setState = function(partialState, callback) {
|
||||
invariant(
|
||||
typeof partialState === 'object' ||
|
||||
typeof partialState === 'function' ||
|
||||
partialState == null,
|
||||
typeof partialState === 'function' ||
|
||||
partialState == null,
|
||||
'setState(...): takes an object of state variables to update or a ' +
|
||||
'function which returns an object of state variables.'
|
||||
'function which returns an object of state variables.',
|
||||
);
|
||||
this.updater.enqueueSetState(this, partialState, callback, 'setState');
|
||||
};
|
||||
@@ -96,12 +96,12 @@ if (__DEV__) {
|
||||
isMounted: [
|
||||
'isMounted',
|
||||
'Instead, make sure to clean up subscriptions and pending requests in ' +
|
||||
'componentWillUnmount to prevent memory leaks.',
|
||||
'componentWillUnmount to prevent memory leaks.',
|
||||
],
|
||||
replaceState: [
|
||||
'replaceState',
|
||||
'Refactor your code to use setState instead (see ' +
|
||||
'https://github.com/facebook/react/issues/3236).',
|
||||
'https://github.com/facebook/react/issues/3236).',
|
||||
],
|
||||
};
|
||||
var defineDeprecationWarning = function(methodName, info) {
|
||||
@@ -112,7 +112,7 @@ if (__DEV__) {
|
||||
false,
|
||||
'%s(...) is deprecated in plain JavaScript React classes. %s',
|
||||
info[0],
|
||||
info[1]
|
||||
info[1],
|
||||
);
|
||||
return undefined;
|
||||
},
|
||||
|
||||
@@ -19,11 +19,12 @@ function warnNoop(publicInstance, callerName) {
|
||||
warning(
|
||||
false,
|
||||
'%s(...): Can only update a mounted or mounting component. ' +
|
||||
'This usually means you called %s() on an unmounted component. ' +
|
||||
'This is a no-op.\n\nPlease check the code for the %s component.',
|
||||
'This usually means you called %s() on an unmounted component. ' +
|
||||
'This is a no-op.\n\nPlease check the code for the %s component.',
|
||||
callerName,
|
||||
callerName,
|
||||
constructor && (constructor.displayName || constructor.name) || 'ReactClass'
|
||||
(constructor && (constructor.displayName || constructor.name)) ||
|
||||
'ReactClass',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -32,7 +33,6 @@ function warnNoop(publicInstance, callerName) {
|
||||
* This is the abstract API for an update queue.
|
||||
*/
|
||||
var ReactNoopUpdateQueue = {
|
||||
|
||||
/**
|
||||
* Checks whether or not this composite component is mounted.
|
||||
* @param {ReactClass} publicInstance The instance we want to test.
|
||||
@@ -76,7 +76,12 @@ var ReactNoopUpdateQueue = {
|
||||
* @param {?string} Name of the calling function in the public API.
|
||||
* @internal
|
||||
*/
|
||||
enqueueReplaceState: function(publicInstance, completeState, callback, callerName) {
|
||||
enqueueReplaceState: function(
|
||||
publicInstance,
|
||||
completeState,
|
||||
callback,
|
||||
callerName,
|
||||
) {
|
||||
warnNoop(publicInstance, 'replaceState');
|
||||
},
|
||||
|
||||
@@ -92,7 +97,12 @@ var ReactNoopUpdateQueue = {
|
||||
* @param {?string} Name of the calling function in the public API.
|
||||
* @internal
|
||||
*/
|
||||
enqueueSetState: function(publicInstance, partialState, callback, callerName) {
|
||||
enqueueSetState: function(
|
||||
publicInstance,
|
||||
partialState,
|
||||
callback,
|
||||
callerName,
|
||||
) {
|
||||
warnNoop(publicInstance, 'setState');
|
||||
},
|
||||
};
|
||||
|
||||
@@ -26,7 +26,6 @@ describe('ReactClassEquivalence', () => {
|
||||
var result2 = runJest('ReactES6Class-test.js');
|
||||
compareResults(result1, result2);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function runJest(testFile) {
|
||||
@@ -36,13 +35,13 @@ function runJest(testFile) {
|
||||
var setupFile = path.resolve(
|
||||
'scripts',
|
||||
'jest',
|
||||
'setupSpecEquivalenceReporter.js'
|
||||
'setupSpecEquivalenceReporter.js',
|
||||
);
|
||||
var result = spawnSync(
|
||||
jestBin,
|
||||
[testFile, '--setupTestFrameworkScriptFile', setupFile],
|
||||
{cwd},
|
||||
);
|
||||
var result = spawnSync(jestBin, [
|
||||
testFile,
|
||||
'--setupTestFrameworkScriptFile',
|
||||
setupFile,
|
||||
], {cwd});
|
||||
|
||||
if (result.error) {
|
||||
throw result.error;
|
||||
@@ -51,12 +50,12 @@ function runJest(testFile) {
|
||||
if (result.status !== 0) {
|
||||
throw new Error(
|
||||
'jest process exited with: ' +
|
||||
result.status +
|
||||
'\n' +
|
||||
'stdout: ' +
|
||||
result.stdout.toString() +
|
||||
'stderr: ' +
|
||||
result.stderr.toString()
|
||||
result.status +
|
||||
'\n' +
|
||||
'stdout: ' +
|
||||
result.stdout.toString() +
|
||||
'stderr: ' +
|
||||
result.stderr.toString(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ var React;
|
||||
var ReactDOM;
|
||||
|
||||
describe('ReactES6Class', () => {
|
||||
|
||||
var container;
|
||||
var freeze = function(expectation) {
|
||||
Object.freeze(expectation);
|
||||
@@ -52,19 +51,19 @@ describe('ReactES6Class', () => {
|
||||
}
|
||||
|
||||
it('preserves the name of the class for use in error messages', () => {
|
||||
class Foo extends React.Component { }
|
||||
class Foo extends React.Component {}
|
||||
expect(Foo.name).toBe('Foo');
|
||||
});
|
||||
|
||||
it('throws if no render function is defined', () => {
|
||||
spyOn(console, 'error');
|
||||
class Foo extends React.Component { }
|
||||
class Foo extends React.Component {}
|
||||
expect(() => ReactDOM.render(<Foo />, container)).toThrow();
|
||||
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: Foo(...): No `render` method found on the returned component ' +
|
||||
'instance: you may have forgotten to define `render`.'
|
||||
'instance: you may have forgotten to define `render`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -174,7 +173,7 @@ describe('ReactES6Class', () => {
|
||||
}
|
||||
}
|
||||
expect(() => test(<Foo />, 'span', '')).toThrowError(
|
||||
'Foo.state: must be set to an object or null'
|
||||
'Foo.state: must be set to an object or null',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -203,10 +202,7 @@ describe('ReactES6Class', () => {
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Inner
|
||||
name={this.state.bar}
|
||||
onClick={this.handleClick.bind(this)}
|
||||
/>
|
||||
<Inner name={this.state.bar} onClick={this.handleClick.bind(this)} />
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -225,12 +221,7 @@ describe('ReactES6Class', () => {
|
||||
this.setState({bar: 'bar'});
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Inner
|
||||
name={this.state.bar}
|
||||
onClick={this.handleClick}
|
||||
/>
|
||||
);
|
||||
return <Inner name={this.state.bar} onClick={this.handleClick} />;
|
||||
}
|
||||
}
|
||||
test(<Foo initialValue="foo" />, 'DIV', 'foo');
|
||||
@@ -295,12 +286,10 @@ describe('ReactES6Class', () => {
|
||||
}
|
||||
}
|
||||
test(<Foo value="foo" />, 'SPAN', 'foo');
|
||||
expect(lifeCycles).toEqual([
|
||||
'will-mount',
|
||||
'did-mount',
|
||||
]);
|
||||
expect(lifeCycles).toEqual(['will-mount', 'did-mount']);
|
||||
lifeCycles = []; // reset
|
||||
test(<Foo value="bar" />, 'SPAN', 'bar');
|
||||
// prettier-ignore
|
||||
expect(lifeCycles).toEqual([
|
||||
'receive-props', freeze({value: 'bar'}),
|
||||
'should-update', freeze({value: 'bar'}), {},
|
||||
@@ -309,9 +298,7 @@ describe('ReactES6Class', () => {
|
||||
]);
|
||||
lifeCycles = []; // reset
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
expect(lifeCycles).toEqual([
|
||||
'will-unmount',
|
||||
]);
|
||||
expect(lifeCycles).toEqual(['will-unmount']);
|
||||
});
|
||||
|
||||
it('warns when classic properties are defined on the instance, but does not invoke them.', () => {
|
||||
@@ -341,16 +328,16 @@ describe('ReactES6Class', () => {
|
||||
expect(getDefaultPropsWasCalled).toBe(false);
|
||||
expect(console.error.calls.count()).toBe(4);
|
||||
expect(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'getInitialState was defined on Foo, a plain JavaScript class.'
|
||||
'getInitialState was defined on Foo, a plain JavaScript class.',
|
||||
);
|
||||
expect(console.error.calls.argsFor(1)[0]).toContain(
|
||||
'getDefaultProps was defined on Foo, a plain JavaScript class.'
|
||||
'getDefaultProps was defined on Foo, a plain JavaScript class.',
|
||||
);
|
||||
expect(console.error.calls.argsFor(2)[0]).toContain(
|
||||
'propTypes was defined as an instance property on Foo.'
|
||||
'propTypes was defined as an instance property on Foo.',
|
||||
);
|
||||
expect(console.error.calls.argsFor(3)[0]).toContain(
|
||||
'contextTypes was defined as an instance property on Foo.'
|
||||
'contextTypes was defined as an instance property on Foo.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -385,9 +372,9 @@ describe('ReactES6Class', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: ' +
|
||||
'NamedComponent has a method called componentShouldUpdate(). Did you ' +
|
||||
'mean shouldComponentUpdate()? The name is phrased as a question ' +
|
||||
'because the function is expected to return a value.'
|
||||
'NamedComponent has a method called componentShouldUpdate(). Did you ' +
|
||||
'mean shouldComponentUpdate()? The name is phrased as a question ' +
|
||||
'because the function is expected to return a value.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -407,8 +394,8 @@ describe('ReactES6Class', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: ' +
|
||||
'NamedComponent has a method called componentWillRecieveProps(). Did ' +
|
||||
'you mean componentWillReceiveProps()?'
|
||||
'NamedComponent has a method called componentWillRecieveProps(). Did ' +
|
||||
'you mean componentWillReceiveProps()?',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -419,10 +406,10 @@ describe('ReactES6Class', () => {
|
||||
expect(() => instance.isMounted()).toThrow();
|
||||
expect(console.error.calls.count()).toBe(2);
|
||||
expect(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'replaceState(...) is deprecated in plain JavaScript React classes'
|
||||
'replaceState(...) is deprecated in plain JavaScript React classes',
|
||||
);
|
||||
expect(console.error.calls.argsFor(1)[0]).toContain(
|
||||
'isMounted(...) is deprecated in plain JavaScript React classes'
|
||||
'isMounted(...) is deprecated in plain JavaScript React classes',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -460,5 +447,4 @@ describe('ReactES6Class', () => {
|
||||
var node = ReactDOM.findDOMNode(instance);
|
||||
expect(node).toBe(container.firstChild);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -93,5 +93,4 @@ describe('ReactPureComponent', () => {
|
||||
ReactDOM.render(<Component />, document.createElement('div'));
|
||||
expect(renders).toBe(1);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -80,7 +80,7 @@ describe('ReactJSXElement', () => {
|
||||
expect(element.type).toBe(Component);
|
||||
expect(element.key).toBe('12');
|
||||
expect(element.ref).toBe('34');
|
||||
var expectation = {foo:'56'};
|
||||
var expectation = {foo: '56'};
|
||||
Object.freeze(expectation);
|
||||
expect(element.props).toEqual(expectation);
|
||||
});
|
||||
@@ -90,7 +90,7 @@ describe('ReactJSXElement', () => {
|
||||
expect(element.type).toBe(Component);
|
||||
expect(element.key).toBe('12');
|
||||
expect(element.ref).toBe(null);
|
||||
var expectation = {foo:'56'};
|
||||
var expectation = {foo: '56'};
|
||||
Object.freeze(expectation);
|
||||
expect(element.props).toEqual(expectation);
|
||||
});
|
||||
@@ -124,7 +124,7 @@ describe('ReactJSXElement', () => {
|
||||
var element2 = React.cloneElement(
|
||||
<Component children="text" />,
|
||||
{},
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
expect(element2.props.children).toBe(undefined);
|
||||
});
|
||||
@@ -165,7 +165,7 @@ describe('ReactJSXElement', () => {
|
||||
expect(React.isValidElement({})).toEqual(false);
|
||||
expect(React.isValidElement('string')).toEqual(false);
|
||||
expect(React.isValidElement(Component)).toEqual(false);
|
||||
expect(React.isValidElement({ type: 'div', props: {} })).toEqual(false);
|
||||
expect(React.isValidElement({type: 'div', props: {}})).toEqual(false);
|
||||
});
|
||||
|
||||
it('is indistinguishable from a plain object', () => {
|
||||
@@ -178,10 +178,7 @@ describe('ReactJSXElement', () => {
|
||||
Component.defaultProps = {fruit: 'persimmon'};
|
||||
|
||||
var container = document.createElement('div');
|
||||
var instance = ReactDOM.render(
|
||||
<Component fruit="mango" />,
|
||||
container
|
||||
);
|
||||
var instance = ReactDOM.render(<Component fruit="mango" />, container);
|
||||
expect(instance.props.fruit).toBe('mango');
|
||||
|
||||
ReactDOM.render(<Component />, container);
|
||||
@@ -199,9 +196,9 @@ describe('ReactJSXElement', () => {
|
||||
var instance = ReactTestUtils.renderIntoDocument(<NormalizingComponent />);
|
||||
expect(instance.props.prop).toBe('testKey');
|
||||
|
||||
var inst2 =
|
||||
ReactTestUtils.renderIntoDocument(<NormalizingComponent prop={null} />);
|
||||
var inst2 = ReactTestUtils.renderIntoDocument(
|
||||
<NormalizingComponent prop={null} />,
|
||||
);
|
||||
expect(inst2.props.prop).toBe(null);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -55,7 +55,7 @@ describe('ReactJSXElementValidator', () => {
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Each child in an array or iterator should have a unique "key" prop.'
|
||||
'Each child in an array or iterator should have a unique "key" prop.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -70,11 +70,7 @@ describe('ReactJSXElementValidator', () => {
|
||||
|
||||
class ComponentWrapper extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<InnerComponent
|
||||
childSet={[<Component />, <Component />]}
|
||||
/>
|
||||
);
|
||||
return <InnerComponent childSet={[<Component />, <Component />]} />;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,8 +79,8 @@ describe('ReactJSXElementValidator', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Each child in an array or iterator should have a unique "key" prop.' +
|
||||
'\n\nCheck the render method of `InnerComponent`. ' +
|
||||
'It was passed a child from ComponentWrapper. '
|
||||
'\n\nCheck the render method of `InnerComponent`. ' +
|
||||
'It was passed a child from ComponentWrapper. ',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -107,14 +103,16 @@ describe('ReactJSXElementValidator', () => {
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Each child in an array or iterator should have a unique "key" prop.'
|
||||
'Each child in an array or iterator should have a unique "key" prop.',
|
||||
);
|
||||
});
|
||||
|
||||
it('does not warns for arrays of elements with keys', () => {
|
||||
spyOn(console, 'error');
|
||||
|
||||
void <Component>{[<Component key="#1" />, <Component key="#2" />]}</Component>;
|
||||
void (
|
||||
<Component>{[<Component key="#1" />, <Component key="#2" />]}</Component>
|
||||
);
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(0);
|
||||
});
|
||||
@@ -200,10 +198,10 @@ describe('ReactJSXElementValidator', () => {
|
||||
ReactTestUtils.renderIntoDocument(<ParentComp />);
|
||||
expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
|
||||
'Warning: Failed prop type: ' +
|
||||
'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
|
||||
'expected `string`.\n' +
|
||||
' in MyComp (at **)\n' +
|
||||
' in ParentComp (at **)'
|
||||
'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
|
||||
'expected `string`.\n' +
|
||||
' in MyComp (at **)\n' +
|
||||
' in ParentComp (at **)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -236,11 +234,11 @@ describe('ReactJSXElementValidator', () => {
|
||||
// If it doesn't, it means we're using information from the old element.
|
||||
expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
|
||||
'Warning: Failed prop type: ' +
|
||||
'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
|
||||
'expected `string`.\n' +
|
||||
' in MyComp (at **)\n' +
|
||||
' in MiddleComp (at **)\n' +
|
||||
' in ParentComp (at **)'
|
||||
'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
|
||||
'expected `string`.\n' +
|
||||
' in MyComp (at **)\n' +
|
||||
' in MiddleComp (at **)\n' +
|
||||
' in ParentComp (at **)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -258,28 +256,28 @@ describe('ReactJSXElementValidator', () => {
|
||||
expectDev(console.error.calls.count()).toBe(4);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
|
||||
'Warning: React.createElement: type is invalid -- expected a string ' +
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: undefined. You likely forgot to export your ' +
|
||||
'component from the file it\'s defined in.' +
|
||||
'\n\nCheck your code at **.'
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: undefined. You likely forgot to export your ' +
|
||||
"component from the file it's defined in." +
|
||||
'\n\nCheck your code at **.',
|
||||
);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
|
||||
'Warning: React.createElement: type is invalid -- expected a string ' +
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: null.' +
|
||||
'\n\nCheck your code at **.'
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: null.' +
|
||||
'\n\nCheck your code at **.',
|
||||
);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(2)[0])).toBe(
|
||||
'Warning: React.createElement: type is invalid -- expected a string ' +
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: boolean.' +
|
||||
'\n\nCheck your code at **.'
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: boolean.' +
|
||||
'\n\nCheck your code at **.',
|
||||
);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(3)[0])).toBe(
|
||||
'Warning: React.createElement: type is invalid -- expected a string ' +
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: number.' +
|
||||
'\n\nCheck your code at **.'
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: number.' +
|
||||
'\n\nCheck your code at **.',
|
||||
);
|
||||
void <Div />;
|
||||
expectDev(console.error.calls.count()).toBe(4);
|
||||
@@ -295,8 +293,8 @@ describe('ReactJSXElementValidator', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
|
||||
'Warning: Failed prop type: The prop `prop` is marked as required in ' +
|
||||
'`RequiredPropComponent`, but its value is `null`.\n' +
|
||||
' in RequiredPropComponent (at **)'
|
||||
'`RequiredPropComponent`, but its value is `null`.\n' +
|
||||
' in RequiredPropComponent (at **)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -308,8 +306,8 @@ describe('ReactJSXElementValidator', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
|
||||
'Warning: Failed prop type: The prop `prop` is marked as required in ' +
|
||||
'`RequiredPropComponent`, but its value is `null`.\n' +
|
||||
' in RequiredPropComponent (at **)'
|
||||
'`RequiredPropComponent`, but its value is `null`.\n' +
|
||||
' in RequiredPropComponent (at **)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -322,16 +320,16 @@ describe('ReactJSXElementValidator', () => {
|
||||
expectDev(console.error.calls.count()).toBe(2);
|
||||
expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
|
||||
'Warning: Failed prop type: ' +
|
||||
'The prop `prop` is marked as required in `RequiredPropComponent`, but ' +
|
||||
'its value is `undefined`.\n' +
|
||||
' in RequiredPropComponent (at **)'
|
||||
'The prop `prop` is marked as required in `RequiredPropComponent`, but ' +
|
||||
'its value is `undefined`.\n' +
|
||||
' in RequiredPropComponent (at **)',
|
||||
);
|
||||
|
||||
expect(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
|
||||
'Warning: Failed prop type: ' +
|
||||
'Invalid prop `prop` of type `number` supplied to ' +
|
||||
'`RequiredPropComponent`, expected `string`.\n' +
|
||||
' in RequiredPropComponent (at **)'
|
||||
'Invalid prop `prop` of type `number` supplied to ' +
|
||||
'`RequiredPropComponent`, expected `string`.\n' +
|
||||
' in RequiredPropComponent (at **)',
|
||||
);
|
||||
|
||||
ReactTestUtils.renderIntoDocument(<RequiredPropComponent prop="string" />);
|
||||
@@ -358,7 +356,7 @@ describe('ReactJSXElementValidator', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'NullPropTypeComponent: prop type `prop` is invalid; it must be a ' +
|
||||
'function, usually from React.PropTypes.'
|
||||
'function, usually from React.PropTypes.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -376,7 +374,7 @@ describe('ReactJSXElementValidator', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'NullContextTypeComponent: context type `prop` is invalid; it must ' +
|
||||
'be a function, usually from React.PropTypes.'
|
||||
'be a function, usually from React.PropTypes.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -394,8 +392,7 @@ describe('ReactJSXElementValidator', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'getDefaultProps is only used on classic React.createClass definitions.' +
|
||||
' Use a static property named `defaultProps` instead.'
|
||||
' Use a static property named `defaultProps` instead.',
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -25,22 +25,19 @@ describe('EventPluginHub', () => {
|
||||
|
||||
it('should prevent non-function listeners, at dispatch', () => {
|
||||
var node = ReactTestUtils.renderIntoDocument(
|
||||
<div onClick="not a function" />
|
||||
<div onClick="not a function" />,
|
||||
);
|
||||
expect(function() {
|
||||
ReactTestUtils.SimulateNative.click(node);
|
||||
}).toThrowError(
|
||||
'Expected onClick listener to be a function, instead got type string'
|
||||
'Expected onClick listener to be a function, instead got type string',
|
||||
);
|
||||
});
|
||||
|
||||
it('should not prevent null listeners, at dispatch', () => {
|
||||
var node = ReactTestUtils.renderIntoDocument(
|
||||
<div onClick={null} />
|
||||
);
|
||||
var node = ReactTestUtils.renderIntoDocument(<div onClick={null} />);
|
||||
expect(function() {
|
||||
ReactTestUtils.SimulateNative.click(node);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -60,7 +60,7 @@ describe('ReactChildReconciler', () => {
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Child keys must be unique; when two children share a key, only the first child will be used.'
|
||||
'Child keys must be unique; when two children share a key, only the first child will be used.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -88,14 +88,16 @@ describe('ReactChildReconciler', () => {
|
||||
ReactTestUtils.renderIntoDocument(<GrandParent />);
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toContain(
|
||||
expectDev(
|
||||
normalizeCodeLocInfo(console.error.calls.argsFor(0)[0]),
|
||||
).toContain(
|
||||
'Encountered two children with the same key, `1`. ' +
|
||||
'Child keys must be unique; when two children share a key, ' +
|
||||
'only the first child will be used.\n' +
|
||||
' in div (at **)\n' +
|
||||
' in Component (at **)\n' +
|
||||
' in Parent (at **)\n' +
|
||||
' in GrandParent (at **)'
|
||||
'Child keys must be unique; when two children share a key, ' +
|
||||
'only the first child will be used.\n' +
|
||||
' in div (at **)\n' +
|
||||
' in Component (at **)\n' +
|
||||
' in Parent (at **)\n' +
|
||||
' in GrandParent (at **)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -112,7 +114,7 @@ describe('ReactChildReconciler', () => {
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Child keys must be unique; when two children share a key, only the first child will be used.'
|
||||
'Child keys must be unique; when two children share a key, only the first child will be used.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -140,14 +142,16 @@ describe('ReactChildReconciler', () => {
|
||||
ReactTestUtils.renderIntoDocument(<GrandParent />);
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toContain(
|
||||
expectDev(
|
||||
normalizeCodeLocInfo(console.error.calls.argsFor(0)[0]),
|
||||
).toContain(
|
||||
'Encountered two children with the same key, `1`. ' +
|
||||
'Child keys must be unique; when two children share a key, ' +
|
||||
'only the first child will be used.\n' +
|
||||
' in div (at **)\n' +
|
||||
' in Component (at **)\n' +
|
||||
' in Parent (at **)\n' +
|
||||
' in GrandParent (at **)'
|
||||
'Child keys must be unique; when two children share a key, ' +
|
||||
'only the first child will be used.\n' +
|
||||
' in div (at **)\n' +
|
||||
' in Component (at **)\n' +
|
||||
' in Parent (at **)\n' +
|
||||
' in GrandParent (at **)',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -29,15 +29,11 @@ describe('ReactComponent', () => {
|
||||
// jQuery objects are basically arrays; people often pass them in by mistake
|
||||
expect(function() {
|
||||
ReactDOM.render(<div />, [container]);
|
||||
}).toThrowError(
|
||||
/Target container is not a DOM element./
|
||||
);
|
||||
}).toThrowError(/Target container is not a DOM element./);
|
||||
|
||||
expect(function() {
|
||||
ReactDOM.render(<div />, null);
|
||||
}).toThrowError(
|
||||
/Target container is not a DOM element./
|
||||
);
|
||||
}).toThrowError(/Target container is not a DOM element./);
|
||||
});
|
||||
|
||||
it('should throw when supplying a ref outside of render method', () => {
|
||||
@@ -59,7 +55,7 @@ describe('ReactComponent', () => {
|
||||
<span key={0} />
|
||||
<span key={1} />
|
||||
<span key={2} />
|
||||
</Wrapper>
|
||||
</Wrapper>,
|
||||
);
|
||||
}).toThrowError(/Cannot assign to read only property.*/);
|
||||
});
|
||||
@@ -84,7 +80,7 @@ describe('ReactComponent', () => {
|
||||
<span key={0} />
|
||||
<span key={1} />
|
||||
<span key={2} />
|
||||
</Wrapper>
|
||||
</Wrapper>,
|
||||
);
|
||||
}).toThrowError(/Cannot assign to read only property.*/);
|
||||
});
|
||||
@@ -157,9 +153,9 @@ describe('ReactComponent', () => {
|
||||
|
||||
class Component extends React.Component {
|
||||
render() {
|
||||
var inner = <Wrapper object={innerObj} ref={(c) => this.innerRef = c} />;
|
||||
var inner = <Wrapper object={innerObj} ref={c => this.innerRef = c} />;
|
||||
var outer = (
|
||||
<Wrapper object={outerObj} ref={(c) => this.outerRef = c}>
|
||||
<Wrapper object={outerObj} ref={c => this.outerRef = c}>
|
||||
{inner}
|
||||
</Wrapper>
|
||||
);
|
||||
@@ -194,16 +190,16 @@ describe('ReactComponent', () => {
|
||||
getInner = () => {
|
||||
// (With old-style refs, it's impossible to get a ref to this div
|
||||
// because Wrapper is the current owner when this function is called.)
|
||||
return <div className="inner" ref={(c) => this.innerRef = c} />;
|
||||
return <div className="inner" ref={c => this.innerRef = c} />;
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Wrapper
|
||||
title="wrapper"
|
||||
ref={(c) => this.wrapperRef = c}
|
||||
ref={c => this.wrapperRef = c}
|
||||
getContent={this.getInner}
|
||||
/>
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -245,12 +241,18 @@ describe('ReactComponent', () => {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Inner id={1} ref={(c) => {
|
||||
log.push(`ref 1 got ${c ? `instance ${c.props.id}` : 'null'}`);
|
||||
}} />
|
||||
<Inner id={2} ref={(c) => {
|
||||
log.push(`ref 2 got ${c ? `instance ${c.props.id}` : 'null'}`);
|
||||
}} />
|
||||
<Inner
|
||||
id={1}
|
||||
ref={c => {
|
||||
log.push(`ref 1 got ${c ? `instance ${c.props.id}` : 'null'}`);
|
||||
}}
|
||||
/>
|
||||
<Inner
|
||||
id={2}
|
||||
ref={c => {
|
||||
log.push(`ref 2 got ${c ? `instance ${c.props.id}` : 'null'}`);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -280,39 +282,41 @@ describe('ReactComponent', () => {
|
||||
/* eslint-disable indent */
|
||||
expect(log).toEqual([
|
||||
'start mount',
|
||||
'inner 1 render',
|
||||
'inner 2 render',
|
||||
'inner 1 componentDidMount',
|
||||
'ref 1 got instance 1',
|
||||
'inner 2 componentDidMount',
|
||||
'ref 2 got instance 2',
|
||||
'outer componentDidMount',
|
||||
'inner 1 render',
|
||||
'inner 2 render',
|
||||
'inner 1 componentDidMount',
|
||||
'ref 1 got instance 1',
|
||||
'inner 2 componentDidMount',
|
||||
'ref 2 got instance 2',
|
||||
'outer componentDidMount',
|
||||
'start update',
|
||||
// Previous (equivalent) refs get cleared
|
||||
...(ReactDOMFeatureFlags.useFiber ? [
|
||||
// Fiber renders first, resets refs later
|
||||
'inner 1 render',
|
||||
'inner 2 render',
|
||||
'ref 1 got null',
|
||||
'ref 2 got null',
|
||||
] : [
|
||||
// Stack resets refs before rendering
|
||||
'ref 1 got null',
|
||||
'inner 1 render',
|
||||
'ref 2 got null',
|
||||
'inner 2 render',
|
||||
]),
|
||||
'inner 1 componentDidUpdate',
|
||||
'ref 1 got instance 1',
|
||||
'inner 2 componentDidUpdate',
|
||||
'ref 2 got instance 2',
|
||||
'outer componentDidUpdate',
|
||||
// Previous (equivalent) refs get cleared
|
||||
...(ReactDOMFeatureFlags.useFiber
|
||||
? [
|
||||
// Fiber renders first, resets refs later
|
||||
'inner 1 render',
|
||||
'inner 2 render',
|
||||
'ref 1 got null',
|
||||
'ref 2 got null',
|
||||
]
|
||||
: [
|
||||
// Stack resets refs before rendering
|
||||
'ref 1 got null',
|
||||
'inner 1 render',
|
||||
'ref 2 got null',
|
||||
'inner 2 render',
|
||||
]),
|
||||
'inner 1 componentDidUpdate',
|
||||
'ref 1 got instance 1',
|
||||
'inner 2 componentDidUpdate',
|
||||
'ref 2 got instance 2',
|
||||
'outer componentDidUpdate',
|
||||
'start unmount',
|
||||
'outer componentWillUnmount',
|
||||
'ref 1 got null',
|
||||
'inner 1 componentWillUnmount',
|
||||
'ref 2 got null',
|
||||
'inner 2 componentWillUnmount',
|
||||
'outer componentWillUnmount',
|
||||
'ref 1 got null',
|
||||
'inner 1 componentWillUnmount',
|
||||
'ref 2 got null',
|
||||
'inner 2 componentWillUnmount',
|
||||
]);
|
||||
/* eslint-enable indent */
|
||||
});
|
||||
@@ -334,15 +338,15 @@ describe('ReactComponent', () => {
|
||||
var X = undefined;
|
||||
expect(() => ReactTestUtils.renderIntoDocument(<X />)).toThrowError(
|
||||
'Element type is invalid: expected a string (for built-in components) ' +
|
||||
'or a class/function (for composite components) but got: undefined. ' +
|
||||
'You likely forgot to export your component from the file it\'s ' +
|
||||
'defined in.'
|
||||
'or a class/function (for composite components) but got: undefined. ' +
|
||||
"You likely forgot to export your component from the file it's " +
|
||||
'defined in.',
|
||||
);
|
||||
|
||||
var Y = null;
|
||||
expect(() => ReactTestUtils.renderIntoDocument(<Y />)).toThrowError(
|
||||
'Element type is invalid: expected a string (for built-in components) ' +
|
||||
'or a class/function (for composite components) but got: null.'
|
||||
'or a class/function (for composite components) but got: null.',
|
||||
);
|
||||
|
||||
// One warning for each element creation
|
||||
@@ -368,13 +372,12 @@ describe('ReactComponent', () => {
|
||||
|
||||
expect(() => ReactTestUtils.renderIntoDocument(<Foo />)).toThrowError(
|
||||
'Element type is invalid: expected a string (for built-in components) ' +
|
||||
'or a class/function (for composite components) but got: undefined. ' +
|
||||
'You likely forgot to export your component from the file it\'s ' +
|
||||
'defined in.\n\nCheck the render method of `Bar`.'
|
||||
'or a class/function (for composite components) but got: undefined. ' +
|
||||
"You likely forgot to export your component from the file it's " +
|
||||
'defined in.\n\nCheck the render method of `Bar`.',
|
||||
);
|
||||
|
||||
// One warning for each element creation
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -19,7 +19,6 @@ var clone = function(o) {
|
||||
return JSON.parse(JSON.stringify(o));
|
||||
};
|
||||
|
||||
|
||||
var GET_INIT_STATE_RETURN_VAL = {
|
||||
hasWillMountCompleted: false,
|
||||
hasRenderCompleted: false,
|
||||
@@ -70,16 +69,13 @@ type ComponentLifeCycle =
|
||||
* Mounted components have a DOM node representation and are capable of
|
||||
* receiving new props.
|
||||
*/
|
||||
'MOUNTED' |
|
||||
/**
|
||||
| 'MOUNTED' /**
|
||||
* Unmounted components are inactive and cannot receive new props.
|
||||
*/
|
||||
'UNMOUNTED';
|
||||
| 'UNMOUNTED';
|
||||
|
||||
function getLifeCycleState(instance): ComponentLifeCycle {
|
||||
return instance.updater.isMounted(instance) ?
|
||||
'MOUNTED' :
|
||||
'UNMOUNTED';
|
||||
return instance.updater.isMounted(instance) ? 'MOUNTED' : 'UNMOUNTED';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,9 +100,7 @@ describe('ReactComponentLifeCycle', () => {
|
||||
state = {};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div />
|
||||
);
|
||||
return <div />;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,11 +146,9 @@ describe('ReactComponentLifeCycle', () => {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>{
|
||||
this.state.showHasOnDOMReadyComponent ?
|
||||
<Child /> :
|
||||
<div />
|
||||
}</div>
|
||||
<div>
|
||||
{this.state.showHasOnDOMReadyComponent ? <Child /> : <div />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -178,9 +170,7 @@ describe('ReactComponentLifeCycle', () => {
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div />
|
||||
);
|
||||
return <div />;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,9 +187,7 @@ describe('ReactComponentLifeCycle', () => {
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div />
|
||||
);
|
||||
return <div />;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,9 +209,7 @@ describe('ReactComponentLifeCycle', () => {
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div />
|
||||
);
|
||||
return <div />;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,9 +217,9 @@ describe('ReactComponentLifeCycle', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: setState(...): Can only update a mounted or ' +
|
||||
'mounting component. This usually means you called setState() on an ' +
|
||||
'unmounted component. This is a no-op.\n\nPlease check the code for the ' +
|
||||
'StatefulComponent component.'
|
||||
'mounting component. This usually means you called setState() on an ' +
|
||||
'unmounted component. This is a no-op.\n\nPlease check the code for the ' +
|
||||
'StatefulComponent component.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -259,7 +245,7 @@ describe('ReactComponentLifeCycle', () => {
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Component is accessing isMounted inside its render()'
|
||||
'Component is accessing isMounted inside its render()',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -285,7 +271,7 @@ describe('ReactComponentLifeCycle', () => {
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Component is accessing isMounted inside its render()'
|
||||
'Component is accessing isMounted inside its render()',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -326,14 +312,13 @@ describe('ReactComponentLifeCycle', () => {
|
||||
ReactTestUtils.renderIntoDocument(<Component />);
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Component is accessing findDOMNode inside its render()'
|
||||
'Component is accessing findDOMNode inside its render()',
|
||||
);
|
||||
});
|
||||
|
||||
it('should carry through each of the phases of setup', () => {
|
||||
spyOn(console, 'error');
|
||||
|
||||
|
||||
class LifeCycleComponent extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
@@ -345,22 +330,21 @@ describe('ReactComponentLifeCycle', () => {
|
||||
hasWillUnmountCompleted: false,
|
||||
};
|
||||
this._testJournal.returnedFromGetInitialState = clone(initState);
|
||||
this._testJournal.lifeCycleAtStartOfGetInitialState =
|
||||
getLifeCycleState(this);
|
||||
this._testJournal.lifeCycleAtStartOfGetInitialState = getLifeCycleState(
|
||||
this,
|
||||
);
|
||||
this.state = initState;
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this._testJournal.stateAtStartOfWillMount = clone(this.state);
|
||||
this._testJournal.lifeCycleAtStartOfWillMount =
|
||||
getLifeCycleState(this);
|
||||
this._testJournal.lifeCycleAtStartOfWillMount = getLifeCycleState(this);
|
||||
this.state.hasWillMountCompleted = true;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._testJournal.stateAtStartOfDidMount = clone(this.state);
|
||||
this._testJournal.lifeCycleAtStartOfDidMount =
|
||||
getLifeCycleState(this);
|
||||
this._testJournal.lifeCycleAtStartOfDidMount = getLifeCycleState(this);
|
||||
this.setState({hasDidMountCompleted: true});
|
||||
}
|
||||
|
||||
@@ -384,8 +368,9 @@ describe('ReactComponentLifeCycle', () => {
|
||||
|
||||
componentWillUnmount() {
|
||||
this._testJournal.stateAtStartOfWillUnmount = clone(this.state);
|
||||
this._testJournal.lifeCycleAtStartOfWillUnmount =
|
||||
getLifeCycleState(this);
|
||||
this._testJournal.lifeCycleAtStartOfWillUnmount = getLifeCycleState(
|
||||
this,
|
||||
);
|
||||
this.state.hasWillUnmountCompleted = true;
|
||||
}
|
||||
}
|
||||
@@ -398,31 +383,29 @@ describe('ReactComponentLifeCycle', () => {
|
||||
|
||||
// getInitialState
|
||||
expect(instance._testJournal.returnedFromGetInitialState).toEqual(
|
||||
GET_INIT_STATE_RETURN_VAL
|
||||
GET_INIT_STATE_RETURN_VAL,
|
||||
);
|
||||
expect(instance._testJournal.lifeCycleAtStartOfGetInitialState).toBe(
|
||||
'UNMOUNTED',
|
||||
);
|
||||
expect(instance._testJournal.lifeCycleAtStartOfGetInitialState)
|
||||
.toBe('UNMOUNTED');
|
||||
|
||||
// componentWillMount
|
||||
expect(instance._testJournal.stateAtStartOfWillMount).toEqual(
|
||||
instance._testJournal.returnedFromGetInitialState
|
||||
instance._testJournal.returnedFromGetInitialState,
|
||||
);
|
||||
expect(instance._testJournal.lifeCycleAtStartOfWillMount)
|
||||
.toBe('UNMOUNTED');
|
||||
expect(instance._testJournal.lifeCycleAtStartOfWillMount).toBe('UNMOUNTED');
|
||||
|
||||
// componentDidMount
|
||||
expect(instance._testJournal.stateAtStartOfDidMount)
|
||||
.toEqual(DID_MOUNT_STATE);
|
||||
expect(instance._testJournal.lifeCycleAtStartOfDidMount).toBe(
|
||||
'MOUNTED'
|
||||
expect(instance._testJournal.stateAtStartOfDidMount).toEqual(
|
||||
DID_MOUNT_STATE,
|
||||
);
|
||||
expect(instance._testJournal.lifeCycleAtStartOfDidMount).toBe('MOUNTED');
|
||||
|
||||
// initial render
|
||||
expect(instance._testJournal.stateInInitialRender)
|
||||
.toEqual(INIT_RENDER_STATE);
|
||||
expect(instance._testJournal.lifeCycleInInitialRender).toBe(
|
||||
'UNMOUNTED'
|
||||
expect(instance._testJournal.stateInInitialRender).toEqual(
|
||||
INIT_RENDER_STATE,
|
||||
);
|
||||
expect(instance._testJournal.lifeCycleInInitialRender).toBe('UNMOUNTED');
|
||||
|
||||
expect(getLifeCycleState(instance)).toBe('MOUNTED');
|
||||
|
||||
@@ -430,22 +413,18 @@ describe('ReactComponentLifeCycle', () => {
|
||||
instance.forceUpdate();
|
||||
|
||||
// render 2nd time
|
||||
expect(instance._testJournal.stateInLaterRender)
|
||||
.toEqual(NEXT_RENDER_STATE);
|
||||
expect(instance._testJournal.lifeCycleInLaterRender).toBe(
|
||||
'MOUNTED'
|
||||
);
|
||||
expect(instance._testJournal.stateInLaterRender).toEqual(NEXT_RENDER_STATE);
|
||||
expect(instance._testJournal.lifeCycleInLaterRender).toBe('MOUNTED');
|
||||
|
||||
expect(getLifeCycleState(instance)).toBe('MOUNTED');
|
||||
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
|
||||
expect(instance._testJournal.stateAtStartOfWillUnmount)
|
||||
.toEqual(WILL_UNMOUNT_STATE);
|
||||
// componentWillUnmount called right before unmount.
|
||||
expect(instance._testJournal.lifeCycleAtStartOfWillUnmount).toBe(
|
||||
'MOUNTED'
|
||||
expect(instance._testJournal.stateAtStartOfWillUnmount).toEqual(
|
||||
WILL_UNMOUNT_STATE,
|
||||
);
|
||||
// componentWillUnmount called right before unmount.
|
||||
expect(instance._testJournal.lifeCycleAtStartOfWillUnmount).toBe('MOUNTED');
|
||||
|
||||
// But the current lifecycle of the component is unmounted.
|
||||
expect(getLifeCycleState(instance)).toBe('UNMOUNTED');
|
||||
@@ -453,7 +432,7 @@ describe('ReactComponentLifeCycle', () => {
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'LifeCycleComponent is accessing isMounted inside its render() function'
|
||||
'LifeCycleComponent is accessing isMounted inside its render() function',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -482,9 +461,7 @@ describe('ReactComponentLifeCycle', () => {
|
||||
class Component extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<Tooltip
|
||||
ref="tooltip"
|
||||
tooltip={<div>{this.props.tooltipText}</div>}>
|
||||
<Tooltip ref="tooltip" tooltip={<div>{this.props.tooltipText}</div>}>
|
||||
{this.props.text}
|
||||
</Tooltip>
|
||||
);
|
||||
@@ -492,17 +469,11 @@ describe('ReactComponentLifeCycle', () => {
|
||||
}
|
||||
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(
|
||||
<Component text="uno" tooltipText="one" />,
|
||||
container
|
||||
);
|
||||
ReactDOM.render(<Component text="uno" tooltipText="one" />, container);
|
||||
|
||||
// Since `instance` is a root component, we can set its props. This also
|
||||
// makes Tooltip rerender the tooltip component, which shouldn't throw.
|
||||
ReactDOM.render(
|
||||
<Component text="dos" tooltipText="two" />,
|
||||
container
|
||||
);
|
||||
ReactDOM.render(<Component text="dos" tooltipText="two" />, container);
|
||||
});
|
||||
|
||||
it('should allow state updates in componentDidMount', () => {
|
||||
@@ -519,15 +490,16 @@ describe('ReactComponentLifeCycle', () => {
|
||||
}
|
||||
|
||||
render() {
|
||||
return (<div />);
|
||||
return <div />;
|
||||
}
|
||||
}
|
||||
|
||||
var instance =
|
||||
var instance = (
|
||||
<SetStateInComponentDidMount
|
||||
valueToUseInitially="hello"
|
||||
valueToUseInOnDOMReady="goodbye"
|
||||
/>;
|
||||
/>
|
||||
);
|
||||
instance = ReactTestUtils.renderIntoDocument(instance);
|
||||
expect(instance.state.stateField).toBe('goodbye');
|
||||
});
|
||||
@@ -566,7 +538,6 @@ describe('ReactComponentLifeCycle', () => {
|
||||
componentWillUnmount: logger('inner componentWillUnmount'),
|
||||
});
|
||||
|
||||
|
||||
var container = document.createElement('div');
|
||||
log = [];
|
||||
ReactDOM.render(<Outer x={17} />, container);
|
||||
@@ -634,8 +605,8 @@ describe('ReactComponentLifeCycle', () => {
|
||||
};
|
||||
|
||||
const div = document.createElement('div');
|
||||
ReactDOM.render(<Parent ref={(c) => c && log.push('ref')} />, div);
|
||||
ReactDOM.render(<Parent ref={(c) => c && log.push('ref')} />, div);
|
||||
ReactDOM.render(<Parent ref={c => c && log.push('ref')} />, div);
|
||||
ReactDOM.render(<Parent ref={c => c && log.push('ref')} />, div);
|
||||
|
||||
expect(log).toEqual([
|
||||
'will mount',
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -22,7 +22,6 @@ var ReactPropTypes;
|
||||
var ReactTestUtils;
|
||||
|
||||
describe('ReactCompositeComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
React = require('react');
|
||||
@@ -42,9 +41,9 @@ describe('ReactCompositeComponent', () => {
|
||||
|
||||
render() {
|
||||
var toggleActivatedState = this._toggleActivatedState;
|
||||
return !this.state.activated ?
|
||||
<a ref="x" onClick={toggleActivatedState} /> :
|
||||
<b ref="x" onClick={toggleActivatedState} />;
|
||||
return !this.state.activated
|
||||
? <a ref="x" onClick={toggleActivatedState} />
|
||||
: <b ref="x" onClick={toggleActivatedState} />;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -59,9 +58,9 @@ describe('ReactCompositeComponent', () => {
|
||||
|
||||
render() {
|
||||
var className = this.props.anchorClassOn ? 'anchorClass' : '';
|
||||
return this.props.renderAnchor ?
|
||||
<a ref="anch" className={className} /> :
|
||||
<b />;
|
||||
return this.props.renderAnchor
|
||||
? <a ref="anch" className={className} />
|
||||
: <b />;
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -139,19 +138,22 @@ describe('ReactCompositeComponent', () => {
|
||||
var container = document.createElement('div');
|
||||
var instance = ReactDOM.render(
|
||||
<ChildUpdates renderAnchor={true} anchorClassOn={false} />,
|
||||
container
|
||||
container,
|
||||
);
|
||||
ReactDOM.render( // Warm any cache
|
||||
ReactDOM.render(
|
||||
// Warm any cache
|
||||
<ChildUpdates renderAnchor={true} anchorClassOn={true} />,
|
||||
container
|
||||
container,
|
||||
);
|
||||
ReactDOM.render( // Clear out the anchor
|
||||
ReactDOM.render(
|
||||
// Clear out the anchor
|
||||
<ChildUpdates renderAnchor={false} anchorClassOn={true} />,
|
||||
container
|
||||
container,
|
||||
);
|
||||
ReactDOM.render( // rerender
|
||||
ReactDOM.render(
|
||||
// rerender
|
||||
<ChildUpdates renderAnchor={true} anchorClassOn={false} />,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(instance.getAnchor().className).toBe('');
|
||||
});
|
||||
@@ -188,7 +190,7 @@ describe('ReactCompositeComponent', () => {
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
var explicitlyBound = mountedInstance.methodToBeExplicitlyBound.bind(
|
||||
mountedInstance
|
||||
mountedInstance,
|
||||
);
|
||||
expectDev(console.error.calls.count()).toBe(2);
|
||||
var autoBound = mountedInstance.methodAutoBound;
|
||||
@@ -199,7 +201,6 @@ describe('ReactCompositeComponent', () => {
|
||||
|
||||
expect(explicitlyBound.call(mountedInstance)).toBe(mountedInstance);
|
||||
expect(autoBound.call(mountedInstance)).toBe(mountedInstance);
|
||||
|
||||
});
|
||||
|
||||
it('should not pass this to getDefaultProps', () => {
|
||||
@@ -227,10 +228,14 @@ describe('ReactCompositeComponent', () => {
|
||||
var instance1 = ReactTestUtils.renderIntoDocument(<Component />);
|
||||
expect(instance1.props).toEqual({prop: 'testKey'});
|
||||
|
||||
var instance2 = ReactTestUtils.renderIntoDocument(<Component prop={undefined} />);
|
||||
var instance2 = ReactTestUtils.renderIntoDocument(
|
||||
<Component prop={undefined} />,
|
||||
);
|
||||
expect(instance2.props).toEqual({prop: 'testKey'});
|
||||
|
||||
var instance3 = ReactTestUtils.renderIntoDocument(<Component prop={null} />);
|
||||
var instance3 = ReactTestUtils.renderIntoDocument(
|
||||
<Component prop={null} />,
|
||||
);
|
||||
expect(instance3.props).toEqual({prop: null});
|
||||
});
|
||||
|
||||
@@ -279,9 +284,9 @@ describe('ReactCompositeComponent', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Can only update a mounted or mounting component. This usually means ' +
|
||||
'you called setState, replaceState, or forceUpdate on an unmounted ' +
|
||||
'component. This is a no-op.\n\nPlease check the code for the ' +
|
||||
'Component component.'
|
||||
'you called setState, replaceState, or forceUpdate on an unmounted ' +
|
||||
'component. This is a no-op.\n\nPlease check the code for the ' +
|
||||
'Component component.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -323,9 +328,9 @@ describe('ReactCompositeComponent', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Can only update a mounted or mounting component. This usually means ' +
|
||||
'you called setState, replaceState, or forceUpdate on an unmounted ' +
|
||||
'component. This is a no-op.\n\nPlease check the code for the ' +
|
||||
'Component component.'
|
||||
'you called setState, replaceState, or forceUpdate on an unmounted ' +
|
||||
'component. This is a no-op.\n\nPlease check the code for the ' +
|
||||
'Component component.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -357,7 +362,6 @@ describe('ReactCompositeComponent', () => {
|
||||
expect(cbCalled).toBe(false);
|
||||
});
|
||||
|
||||
|
||||
it('should warn about `setState` in render', () => {
|
||||
spyOn(console, 'error');
|
||||
|
||||
@@ -373,7 +377,7 @@ describe('ReactCompositeComponent', () => {
|
||||
renderPasses++;
|
||||
renderedState = this.state.value;
|
||||
if (this.state.value === 0) {
|
||||
this.setState({ value: 1 });
|
||||
this.setState({value: 1});
|
||||
}
|
||||
return <div />;
|
||||
}
|
||||
@@ -386,9 +390,9 @@ describe('ReactCompositeComponent', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Cannot update during an existing state transition (such as within ' +
|
||||
'`render` or another component\'s constructor). Render methods should ' +
|
||||
'be a pure function of props and state; constructor side-effects are ' +
|
||||
'an anti-pattern, but can be moved to `componentWillMount`.'
|
||||
"`render` or another component's constructor). Render methods should " +
|
||||
'be a pure function of props and state; constructor side-effects are ' +
|
||||
'an anti-pattern, but can be moved to `componentWillMount`.',
|
||||
);
|
||||
|
||||
// The setState call is queued and then executed as a second pass. This
|
||||
@@ -417,7 +421,7 @@ describe('ReactCompositeComponent', () => {
|
||||
|
||||
getChildContext() {
|
||||
if (this.state.value === 0) {
|
||||
this.setState({ value: 1 });
|
||||
this.setState({value: 1});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,7 +438,7 @@ describe('ReactCompositeComponent', () => {
|
||||
expect(instance.state.value).toBe(1);
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: setState(...): Cannot call setState() inside getChildContext()'
|
||||
'Warning: setState(...): Cannot call setState() inside getChildContext()',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -507,7 +511,7 @@ describe('ReactCompositeComponent', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: Component.shouldComponentUpdate(): Returned undefined instead of a ' +
|
||||
'boolean value. Make sure to return true or false.'
|
||||
'boolean value. Make sure to return true or false.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -515,8 +519,7 @@ describe('ReactCompositeComponent', () => {
|
||||
spyOn(console, 'error');
|
||||
|
||||
class Component extends React.Component {
|
||||
componentDidUnmount = () => {
|
||||
};
|
||||
componentDidUnmount = () => {};
|
||||
|
||||
render() {
|
||||
return <div />;
|
||||
@@ -528,8 +531,8 @@ describe('ReactCompositeComponent', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: Component has a method called ' +
|
||||
'componentDidUnmount(). But there is no such lifecycle method. ' +
|
||||
'Did you mean componentWillUnmount()?'
|
||||
'componentDidUnmount(). But there is no such lifecycle method. ' +
|
||||
'Did you mean componentWillUnmount()?',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -639,7 +642,7 @@ describe('ReactCompositeComponent', () => {
|
||||
}
|
||||
|
||||
parentInstance = ReactTestUtils.renderIntoDocument(
|
||||
<Parent><Middle><Child /></Middle></Parent>
|
||||
<Parent><Middle><Child /></Middle></Parent>,
|
||||
);
|
||||
|
||||
expect(parentInstance.state.flag).toBe(false);
|
||||
@@ -691,10 +694,7 @@ describe('ReactCompositeComponent', () => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var wrapper = ReactTestUtils.renderIntoDocument(
|
||||
<Wrapper />
|
||||
);
|
||||
var wrapper = ReactTestUtils.renderIntoDocument(<Wrapper />);
|
||||
|
||||
expect(wrapper.refs.parent.state.flag).toEqual(true);
|
||||
expect(wrapper.refs.child.context).toEqual({flag: true});
|
||||
@@ -999,7 +999,7 @@ describe('ReactCompositeComponent', () => {
|
||||
<GrandChild>B2</GrandChild>
|
||||
</ChildWithContext>
|
||||
</Parent>,
|
||||
div
|
||||
div,
|
||||
);
|
||||
|
||||
parentInstance.setState({
|
||||
@@ -1030,9 +1030,9 @@ describe('ReactCompositeComponent', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toMatch(
|
||||
'Render methods should be a pure function of props and state; ' +
|
||||
'triggering nested component updates from render is not allowed. If ' +
|
||||
'necessary, trigger nested updates in componentDidUpdate.\n\nCheck the ' +
|
||||
'render method of Outer.'
|
||||
'triggering nested component updates from render is not allowed. If ' +
|
||||
'necessary, trigger nested updates in componentDidUpdate.\n\nCheck the ' +
|
||||
'render method of Outer.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1295,7 +1295,7 @@ describe('ReactCompositeComponent', () => {
|
||||
|
||||
class Foo extends React.Component {
|
||||
constructor(props) {
|
||||
var _props = { idx: props.idx + '!' };
|
||||
var _props = {idx: props.idx + '!'};
|
||||
super(_props);
|
||||
}
|
||||
|
||||
@@ -1311,9 +1311,8 @@ describe('ReactCompositeComponent', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Foo(...): When calling super() in `Foo`, make sure to pass ' +
|
||||
'up the same props that your component\'s constructor was passed.'
|
||||
"up the same props that your component's constructor was passed.",
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
it('should only call componentWillUnmount once', () => {
|
||||
@@ -1344,7 +1343,7 @@ describe('ReactCompositeComponent', () => {
|
||||
|
||||
var container = document.createElement('div');
|
||||
|
||||
var setRef = (ref) => {
|
||||
var setRef = ref => {
|
||||
if (ref) {
|
||||
app = ref;
|
||||
}
|
||||
@@ -1397,5 +1396,4 @@ describe('ReactCompositeComponent', () => {
|
||||
'B componentDidMount',
|
||||
]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -28,7 +28,6 @@ var expectSingleChildlessDiv;
|
||||
* nodes.
|
||||
*/
|
||||
describe('ReactCompositeComponentDOMMinimalism', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
@@ -96,5 +95,4 @@ describe('ReactCompositeComponentDOMMinimalism', () => {
|
||||
expect(el.children[0].tagName).toBe('UL');
|
||||
expect(el.children[0].children.length).toBe(0);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -16,7 +16,6 @@ var ReactDOM;
|
||||
var ReactTestUtils;
|
||||
|
||||
describe('ReactCompositeComponentNestedState-state', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
@@ -27,7 +26,7 @@ describe('ReactCompositeComponentNestedState-state', () => {
|
||||
class ParentComponent extends React.Component {
|
||||
state = {color: 'blue'};
|
||||
|
||||
handleColor = (color) => {
|
||||
handleColor = color => {
|
||||
this.props.logger('parent-handleColor', this.state.color);
|
||||
this.setState({color: color}, function() {
|
||||
this.props.logger('parent-after-setState', this.state.color);
|
||||
@@ -56,13 +55,24 @@ describe('ReactCompositeComponentNestedState-state', () => {
|
||||
handleHue = (shade, color) => {
|
||||
this.props.logger('handleHue', this.state.hue, this.props.color);
|
||||
this.props.onSelectColor(color);
|
||||
this.setState(function(state, props) {
|
||||
this.props.logger('setState-this', this.state.hue, this.props.color);
|
||||
this.props.logger('setState-args', state.hue, props.color);
|
||||
return {hue: shade + ' ' + props.color};
|
||||
}, function() {
|
||||
this.props.logger('after-setState', this.state.hue, this.props.color);
|
||||
});
|
||||
this.setState(
|
||||
function(state, props) {
|
||||
this.props.logger(
|
||||
'setState-this',
|
||||
this.state.hue,
|
||||
this.props.color,
|
||||
);
|
||||
this.props.logger('setState-args', state.hue, props.color);
|
||||
return {hue: shade + ' ' + props.color};
|
||||
},
|
||||
function() {
|
||||
this.props.logger(
|
||||
'after-setState',
|
||||
this.state.hue,
|
||||
this.props.color,
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
@@ -91,15 +101,10 @@ describe('ReactCompositeComponentNestedState-state', () => {
|
||||
|
||||
var logger = jest.fn();
|
||||
|
||||
void ReactDOM.render(
|
||||
<ParentComponent logger={logger} />,
|
||||
container
|
||||
);
|
||||
void ReactDOM.render(<ParentComponent logger={logger} />, container);
|
||||
|
||||
// click "light green"
|
||||
ReactTestUtils.Simulate.click(
|
||||
container.childNodes[0].childNodes[3]
|
||||
);
|
||||
ReactTestUtils.Simulate.click(container.childNodes[0].childNodes[3]);
|
||||
|
||||
expect(logger.mock.calls).toEqual([
|
||||
['parent-render', 'blue'],
|
||||
|
||||
@@ -18,7 +18,6 @@ var ReactDOMFeatureFlags;
|
||||
var TestComponent;
|
||||
|
||||
describe('ReactCompositeComponent-state', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
React = require('react');
|
||||
|
||||
@@ -38,7 +37,7 @@ describe('ReactCompositeComponent-state', () => {
|
||||
setFavoriteColor: function(nextColor) {
|
||||
this.setState(
|
||||
{color: nextColor},
|
||||
this.peekAtCallback('setFavoriteColor')
|
||||
this.peekAtCallback('setFavoriteColor'),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -59,7 +58,7 @@ describe('ReactCompositeComponent-state', () => {
|
||||
});
|
||||
this.setState(
|
||||
{color: 'sunrise'},
|
||||
this.peekAtCallback('setState-sunrise')
|
||||
this.peekAtCallback('setState-sunrise'),
|
||||
);
|
||||
this.setState(function(state) {
|
||||
this.peekAtState('after-setState-sunrise', state);
|
||||
@@ -67,7 +66,7 @@ describe('ReactCompositeComponent-state', () => {
|
||||
this.peekAtState('componentWillMount-after-sunrise');
|
||||
this.setState(
|
||||
{color: 'orange'},
|
||||
this.peekAtCallback('setState-orange')
|
||||
this.peekAtCallback('setState-orange'),
|
||||
);
|
||||
this.setState(function(state) {
|
||||
this.peekAtState('after-setState-orange', state);
|
||||
@@ -79,7 +78,7 @@ describe('ReactCompositeComponent-state', () => {
|
||||
this.peekAtState('componentDidMount-start');
|
||||
this.setState(
|
||||
{color: 'yellow'},
|
||||
this.peekAtCallback('setState-yellow')
|
||||
this.peekAtCallback('setState-yellow'),
|
||||
);
|
||||
this.peekAtState('componentDidMount-end');
|
||||
},
|
||||
@@ -97,7 +96,7 @@ describe('ReactCompositeComponent-state', () => {
|
||||
this.peekAtState('before-setState-again-receiveProps', state);
|
||||
return {color: newProps.nextColor};
|
||||
},
|
||||
this.peekAtCallback('setState-receiveProps')
|
||||
this.peekAtCallback('setState-receiveProps'),
|
||||
);
|
||||
this.setState(function(state) {
|
||||
this.peekAtState('after-setState-receiveProps', state);
|
||||
@@ -138,12 +137,12 @@ describe('ReactCompositeComponent-state', () => {
|
||||
container,
|
||||
function peekAtInitialCallback() {
|
||||
this.peekAtState('initial-callback');
|
||||
}
|
||||
},
|
||||
);
|
||||
ReactDOM.render(
|
||||
<TestComponent stateListener={stateListener} nextColor="green" />,
|
||||
container,
|
||||
instance.peekAtCallback('setProps')
|
||||
instance.peekAtCallback('setProps'),
|
||||
);
|
||||
instance.setFavoriteColor('blue');
|
||||
instance.forceUpdate(instance.peekAtCallback('forceUpdate'));
|
||||
@@ -191,9 +190,7 @@ describe('ReactCompositeComponent-state', () => {
|
||||
// from the queue. In Fiber, we keep updates in the queue to support
|
||||
// replaceState(prevState => newState).
|
||||
// TODO: Fix Stack to match Fiber.
|
||||
expected.push(
|
||||
['before-setState-receiveProps', 'yellow'],
|
||||
);
|
||||
expected.push(['before-setState-receiveProps', 'yellow']);
|
||||
}
|
||||
|
||||
expected.push(
|
||||
@@ -232,7 +229,6 @@ describe('ReactCompositeComponent-state', () => {
|
||||
expect(stateListener.mock.calls.join('\n')).toEqual(expected.join('\n'));
|
||||
});
|
||||
|
||||
|
||||
it('should call componentDidUpdate of children first', () => {
|
||||
var container = document.createElement('div');
|
||||
|
||||
@@ -242,7 +238,7 @@ describe('ReactCompositeComponent-state', () => {
|
||||
var parent = null;
|
||||
|
||||
class Child extends React.Component {
|
||||
state = {bar:false};
|
||||
state = {bar: false};
|
||||
componentDidMount() {
|
||||
child = this;
|
||||
}
|
||||
@@ -266,7 +262,7 @@ describe('ReactCompositeComponent-state', () => {
|
||||
}
|
||||
|
||||
class Parent extends React.Component {
|
||||
state = {foo:false};
|
||||
state = {foo: false};
|
||||
componentDidMount() {
|
||||
parent = this;
|
||||
}
|
||||
@@ -281,40 +277,36 @@ describe('ReactCompositeComponent-state', () => {
|
||||
ReactDOM.render(<Parent />, container);
|
||||
|
||||
ReactDOM.unstable_batchedUpdates(() => {
|
||||
parent.setState({ foo: true });
|
||||
child.setState({ bar: true });
|
||||
parent.setState({foo: true});
|
||||
child.setState({bar: true});
|
||||
});
|
||||
// When we render changes top-down in a batch, children's componentDidUpdate
|
||||
// happens before the parent.
|
||||
expect(ops).toEqual([
|
||||
'child did update',
|
||||
'parent did update',
|
||||
]);
|
||||
expect(ops).toEqual(['child did update', 'parent did update']);
|
||||
|
||||
shouldUpdate = false;
|
||||
|
||||
ops = [];
|
||||
|
||||
ReactDOM.unstable_batchedUpdates(() => {
|
||||
parent.setState({ foo: false });
|
||||
child.setState({ bar: false });
|
||||
parent.setState({foo: false});
|
||||
child.setState({bar: false});
|
||||
});
|
||||
// We expect the same thing to happen if we bail out in the middle.
|
||||
expect(ops).toEqual(
|
||||
ReactDOMFeatureFlags.useFiber
|
||||
? [
|
||||
// Fiber works as expected
|
||||
'child did update',
|
||||
'parent did update',
|
||||
]
|
||||
// Fiber works as expected
|
||||
'child did update',
|
||||
'parent did update',
|
||||
]
|
||||
: [
|
||||
// Stack treats these as two separate updates and therefore the order
|
||||
// is inverse.
|
||||
'parent did update',
|
||||
'child did update',
|
||||
]
|
||||
// Stack treats these as two separate updates and therefore the order
|
||||
// is inverse.
|
||||
'parent did update',
|
||||
'child did update',
|
||||
],
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
it('should batch unmounts', () => {
|
||||
@@ -396,8 +388,10 @@ describe('ReactCompositeComponent-state', () => {
|
||||
}
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
log.push(
|
||||
'scu from ' + Object.keys(this.state) +
|
||||
' to ' + Object.keys(nextState)
|
||||
'scu from ' +
|
||||
Object.keys(this.state) +
|
||||
' to ' +
|
||||
Object.keys(nextState),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -409,10 +403,7 @@ describe('ReactCompositeComponent-state', () => {
|
||||
expect(log.length).toBe(1);
|
||||
test.setState({c: 0});
|
||||
expect(log.length).toBe(2);
|
||||
expect(log).toEqual([
|
||||
'scu from a to a,b',
|
||||
'scu from a,b to a,b,c',
|
||||
]);
|
||||
expect(log).toEqual(['scu from a to a,b', 'scu from a,b to a,b,c']);
|
||||
});
|
||||
|
||||
it('should treat assigning to this.state inside cWRP as a replaceState, with a warning', () => {
|
||||
@@ -420,17 +411,21 @@ describe('ReactCompositeComponent-state', () => {
|
||||
|
||||
let ops = [];
|
||||
class Test extends React.Component {
|
||||
state = { step: 1, extra: true };
|
||||
state = {step: 1, extra: true};
|
||||
componentWillReceiveProps() {
|
||||
this.setState({ step: 2 }, () => {
|
||||
this.setState({step: 2}, () => {
|
||||
// Tests that earlier setState callbacks are not dropped
|
||||
ops.push(`callback -- step: ${this.state.step}, extra: ${!!this.state.extra}`);
|
||||
ops.push(
|
||||
`callback -- step: ${this.state.step}, extra: ${!!this.state.extra}`,
|
||||
);
|
||||
});
|
||||
// Treat like replaceState
|
||||
this.state = { step: 3 };
|
||||
this.state = {step: 3};
|
||||
}
|
||||
render() {
|
||||
ops.push(`render -- step: ${this.state.step}, extra: ${!!this.state.extra}`);
|
||||
ops.push(
|
||||
`render -- step: ${this.state.step}, extra: ${!!this.state.extra}`,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -449,8 +444,8 @@ describe('ReactCompositeComponent-state', () => {
|
||||
expect(console.error.calls.count()).toEqual(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toEqual(
|
||||
'Warning: Test.componentWillReceiveProps(): Assigning directly to ' +
|
||||
'this.state is deprecated (except inside a component\'s constructor). ' +
|
||||
'Use setState instead.'
|
||||
"this.state is deprecated (except inside a component's constructor). " +
|
||||
'Use setState instead.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -80,21 +80,17 @@ describe('ReactEmptyComponent', () => {
|
||||
ReactTestUtils.renderIntoDocument(<Component />);
|
||||
}).toThrowError(
|
||||
'Component.render(): A valid React element (or null) must be returned. You may ' +
|
||||
'have returned undefined, an array or some other invalid object.'
|
||||
'have returned undefined, an array or some other invalid object.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to switch between rendering null and a normal tag', () => {
|
||||
var instance1 =
|
||||
<TogglingComponent
|
||||
firstComponent={null}
|
||||
secondComponent={'div'}
|
||||
/>;
|
||||
var instance2 =
|
||||
<TogglingComponent
|
||||
firstComponent={'div'}
|
||||
secondComponent={null}
|
||||
/>;
|
||||
var instance1 = (
|
||||
<TogglingComponent firstComponent={null} secondComponent={'div'} />
|
||||
);
|
||||
var instance2 = (
|
||||
<TogglingComponent firstComponent={'div'} secondComponent={null} />
|
||||
);
|
||||
|
||||
ReactTestUtils.renderIntoDocument(instance1);
|
||||
ReactTestUtils.renderIntoDocument(instance2);
|
||||
@@ -107,18 +103,16 @@ describe('ReactEmptyComponent', () => {
|
||||
});
|
||||
|
||||
it('should be able to switch in a list of children', () => {
|
||||
var instance1 =
|
||||
<TogglingComponent
|
||||
firstComponent={null}
|
||||
secondComponent={'div'}
|
||||
/>;
|
||||
var instance1 = (
|
||||
<TogglingComponent firstComponent={null} secondComponent={'div'} />
|
||||
);
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
<div>
|
||||
{instance1}
|
||||
{instance1}
|
||||
{instance1}
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
|
||||
expect(log.calls.count()).toBe(6);
|
||||
@@ -130,36 +124,31 @@ describe('ReactEmptyComponent', () => {
|
||||
expect(log.calls.argsFor(5)[0].tagName).toBe('DIV');
|
||||
});
|
||||
|
||||
it('should distinguish between a script placeholder and an actual script tag',
|
||||
() => {
|
||||
var instance1 =
|
||||
<TogglingComponent
|
||||
firstComponent={null}
|
||||
secondComponent={'script'}
|
||||
/>;
|
||||
var instance2 =
|
||||
<TogglingComponent
|
||||
firstComponent={'script'}
|
||||
secondComponent={null}
|
||||
/>;
|
||||
it('should distinguish between a script placeholder and an actual script tag', () => {
|
||||
var instance1 = (
|
||||
<TogglingComponent firstComponent={null} secondComponent={'script'} />
|
||||
);
|
||||
var instance2 = (
|
||||
<TogglingComponent firstComponent={'script'} secondComponent={null} />
|
||||
);
|
||||
|
||||
expect(function() {
|
||||
ReactTestUtils.renderIntoDocument(instance1);
|
||||
}).not.toThrow();
|
||||
expect(function() {
|
||||
ReactTestUtils.renderIntoDocument(instance2);
|
||||
}).not.toThrow();
|
||||
expect(function() {
|
||||
ReactTestUtils.renderIntoDocument(instance1);
|
||||
}).not.toThrow();
|
||||
expect(function() {
|
||||
ReactTestUtils.renderIntoDocument(instance2);
|
||||
}).not.toThrow();
|
||||
|
||||
expect(log.calls.count()).toBe(4);
|
||||
expect(log.calls.argsFor(0)[0]).toBe(null);
|
||||
expect(log.calls.argsFor(1)[0].tagName).toBe('SCRIPT');
|
||||
expect(log.calls.argsFor(2)[0].tagName).toBe('SCRIPT');
|
||||
expect(log.calls.argsFor(3)[0]).toBe(null);
|
||||
}
|
||||
);
|
||||
expect(log.calls.count()).toBe(4);
|
||||
expect(log.calls.argsFor(0)[0]).toBe(null);
|
||||
expect(log.calls.argsFor(1)[0].tagName).toBe('SCRIPT');
|
||||
expect(log.calls.argsFor(2)[0].tagName).toBe('SCRIPT');
|
||||
expect(log.calls.argsFor(3)[0]).toBe(null);
|
||||
});
|
||||
|
||||
it('should have findDOMNode return null when multiple layers of composite ' +
|
||||
'components render to the same null placeholder',
|
||||
it(
|
||||
'should have findDOMNode return null when multiple layers of composite ' +
|
||||
'components render to the same null placeholder',
|
||||
() => {
|
||||
class GrandChild extends React.Component {
|
||||
render() {
|
||||
@@ -173,16 +162,12 @@ describe('ReactEmptyComponent', () => {
|
||||
}
|
||||
}
|
||||
|
||||
var instance1 =
|
||||
<TogglingComponent
|
||||
firstComponent={'div'}
|
||||
secondComponent={Child}
|
||||
/>;
|
||||
var instance2 =
|
||||
<TogglingComponent
|
||||
firstComponent={Child}
|
||||
secondComponent={'div'}
|
||||
/>;
|
||||
var instance1 = (
|
||||
<TogglingComponent firstComponent={'div'} secondComponent={Child} />
|
||||
);
|
||||
var instance2 = (
|
||||
<TogglingComponent firstComponent={Child} secondComponent={'div'} />
|
||||
);
|
||||
|
||||
expect(function() {
|
||||
ReactTestUtils.renderIntoDocument(instance1);
|
||||
@@ -196,7 +181,7 @@ describe('ReactEmptyComponent', () => {
|
||||
expect(log.calls.argsFor(1)[0]).toBe(null);
|
||||
expect(log.calls.argsFor(2)[0]).toBe(null);
|
||||
expect(log.calls.argsFor(3)[0].tagName).toBe('DIV');
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it('works when switching components', () => {
|
||||
@@ -259,9 +244,7 @@ describe('ReactEmptyComponent', () => {
|
||||
// Stack does not implement this.
|
||||
expect(function() {
|
||||
ReactDOM.render(null, div);
|
||||
}).toThrowError(
|
||||
'ReactDOM.render(): Invalid component element.'
|
||||
);
|
||||
}).toThrowError('ReactDOM.render(): Invalid component element.');
|
||||
}
|
||||
} finally {
|
||||
ReactFeatureFlags.disableNewFiberFeatures = true;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -51,13 +51,15 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
ReactDOM.render(<div><p>Hi.</p></div>, node);
|
||||
|
||||
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: ReactDOMFeatureFlags.useCreateElement ?
|
||||
'DIV' :
|
||||
'<div data-reactroot="" data-reactid="1"><p data-reactid="2">Hi.</p></div>',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: ReactDOMFeatureFlags.useCreateElement
|
||||
? 'DIV'
|
||||
: '<div data-reactroot="" data-reactid="1"><p data-reactid="2">Hi.</p></div>',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('gets recorded for composite roots', () => {
|
||||
@@ -70,14 +72,16 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
ReactDOM.render(<Foo />, node);
|
||||
|
||||
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: ReactDOMFeatureFlags.useCreateElement ?
|
||||
'DIV' :
|
||||
'<div data-reactroot="" data-reactid="1">' +
|
||||
'<p data-reactid="2">Hi.</p></div>',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: ReactDOMFeatureFlags.useCreateElement
|
||||
? 'DIV'
|
||||
: '<div data-reactroot="" data-reactid="1">' +
|
||||
'<p data-reactid="2">Hi.</p></div>',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('gets ignored for composite roots that return null', () => {
|
||||
@@ -111,11 +115,13 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
|
||||
// Since empty components should be invisible to hooks,
|
||||
// we record a "mount" event rather than a "replace with".
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: 'SPAN',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: 'SPAN',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -124,32 +130,42 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
var node = document.createElement('div');
|
||||
|
||||
ReactHostOperationHistoryHook._preventClearing = true;
|
||||
ReactDOM.render(<div style={{
|
||||
color: 'red',
|
||||
backgroundColor: 'yellow',
|
||||
}} />, node);
|
||||
ReactDOM.render(
|
||||
<div
|
||||
style={{
|
||||
color: 'red',
|
||||
backgroundColor: 'yellow',
|
||||
}}
|
||||
/>,
|
||||
node,
|
||||
);
|
||||
|
||||
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
|
||||
if (ReactDOMFeatureFlags.useCreateElement) {
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update styles',
|
||||
payload: {
|
||||
color: 'red',
|
||||
backgroundColor: 'yellow',
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update styles',
|
||||
payload: {
|
||||
color: 'red',
|
||||
backgroundColor: 'yellow',
|
||||
},
|
||||
},
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: 'DIV',
|
||||
}]);
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: 'DIV',
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: '<div style="color:red;background-color:yellow;" ' +
|
||||
'data-reactroot="" data-reactid="1"></div>',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: '<div style="color:red;background-color:yellow;" ' +
|
||||
'data-reactroot="" data-reactid="1"></div>',
|
||||
},
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -159,31 +175,41 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
|
||||
|
||||
ReactHostOperationHistoryHook._preventClearing = true;
|
||||
ReactDOM.render(<div style={{ color: 'red' }} />, node);
|
||||
ReactDOM.render(<div style={{
|
||||
color: 'blue',
|
||||
backgroundColor: 'yellow',
|
||||
}} />, node);
|
||||
ReactDOM.render(<div style={{ backgroundColor: 'green' }} />, node);
|
||||
ReactDOM.render(<div style={{color: 'red'}} />, node);
|
||||
ReactDOM.render(
|
||||
<div
|
||||
style={{
|
||||
color: 'blue',
|
||||
backgroundColor: 'yellow',
|
||||
}}
|
||||
/>,
|
||||
node,
|
||||
);
|
||||
ReactDOM.render(<div style={{backgroundColor: 'green'}} />, node);
|
||||
ReactDOM.render(<div />, node);
|
||||
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update styles',
|
||||
payload: { color: 'red' },
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'update styles',
|
||||
payload: { color: 'blue', backgroundColor: 'yellow' },
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'update styles',
|
||||
payload: { color: '', backgroundColor: 'green' },
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'update styles',
|
||||
payload: { backgroundColor: '' },
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update styles',
|
||||
payload: {color: 'red'},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update styles',
|
||||
payload: {color: 'blue', backgroundColor: 'yellow'},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update styles',
|
||||
payload: {color: '', backgroundColor: 'green'},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update styles',
|
||||
payload: {backgroundColor: ''},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('gets ignored if the styles are shallowly equal', () => {
|
||||
@@ -192,23 +218,35 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
|
||||
|
||||
ReactHostOperationHistoryHook._preventClearing = true;
|
||||
ReactDOM.render(<div style={{
|
||||
color: 'red',
|
||||
backgroundColor: 'yellow',
|
||||
}} />, node);
|
||||
ReactDOM.render(<div style={{
|
||||
color: 'red',
|
||||
backgroundColor: 'yellow',
|
||||
}} />, node);
|
||||
ReactDOM.render(
|
||||
<div
|
||||
style={{
|
||||
color: 'red',
|
||||
backgroundColor: 'yellow',
|
||||
}}
|
||||
/>,
|
||||
node,
|
||||
);
|
||||
ReactDOM.render(
|
||||
<div
|
||||
style={{
|
||||
color: 'red',
|
||||
backgroundColor: 'yellow',
|
||||
}}
|
||||
/>,
|
||||
node,
|
||||
);
|
||||
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update styles',
|
||||
payload: {
|
||||
color: 'red',
|
||||
backgroundColor: 'yellow',
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update styles',
|
||||
payload: {
|
||||
color: 'red',
|
||||
backgroundColor: 'yellow',
|
||||
},
|
||||
},
|
||||
}]);
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -222,26 +260,32 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
|
||||
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
|
||||
if (ReactDOMFeatureFlags.useCreateElement) {
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: { className: 'rad' },
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: { tabIndex: 42 },
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: 'DIV',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: {className: 'rad'},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: {tabIndex: 42},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: 'DIV',
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: '<div class="rad" tabindex="42" data-reactroot="" ' +
|
||||
'data-reactid="1"></div>',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: '<div class="rad" tabindex="42" data-reactroot="" ' +
|
||||
'data-reactid="1"></div>',
|
||||
},
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -255,27 +299,33 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
ReactDOM.render(<div className="mad" tabIndex={42} />, node);
|
||||
ReactDOM.render(<div tabIndex={43} />, node);
|
||||
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: { className: 'rad' },
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: { className: 'mad' },
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: { tabIndex: 42 },
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'remove attribute',
|
||||
payload: 'className',
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: { tabIndex: 43 },
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: {className: 'rad'},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: {className: 'mad'},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: {tabIndex: 42},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'remove attribute',
|
||||
payload: 'className',
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: {tabIndex: 43},
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -289,15 +339,18 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
ReactDOM.render(<div disabled={true} />, node);
|
||||
ReactDOM.render(<div disabled={false} />, node);
|
||||
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: { disabled: true },
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'remove attribute',
|
||||
payload: 'disabled',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: {disabled: true},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'remove attribute',
|
||||
payload: 'disabled',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -310,26 +363,32 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
|
||||
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
|
||||
if (ReactDOMFeatureFlags.useCreateElement) {
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: { 'data-x': 'rad' },
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: { 'data-y': 42 },
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: 'DIV',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: {'data-x': 'rad'},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: {'data-y': 42},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: 'DIV',
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: '<div data-x="rad" data-y="42" data-reactroot="" ' +
|
||||
'data-reactid="1"></div>',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: '<div data-x="rad" data-y="42" data-reactroot="" ' +
|
||||
'data-reactid="1"></div>',
|
||||
},
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -343,27 +402,33 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
ReactDOM.render(<div data-x="mad" data-y={42} />, node);
|
||||
ReactDOM.render(<div data-y={43} />, node);
|
||||
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: { 'data-x': 'rad' },
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: { 'data-x': 'mad' },
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: { 'data-y': 42 },
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'remove attribute',
|
||||
payload: 'data-x',
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: { 'data-y': 43 },
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: {'data-x': 'rad'},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: {'data-x': 'mad'},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: {'data-y': 42},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'remove attribute',
|
||||
payload: 'data-x',
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: {'data-y': 43},
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -376,26 +441,32 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
|
||||
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
|
||||
if (ReactDOMFeatureFlags.useCreateElement) {
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: { className: 'rad' },
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: { tabIndex: 42 },
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: 'MY-COMPONENT',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: {className: 'rad'},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: {tabIndex: 42},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: 'MY-COMPONENT',
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: '<my-component className="rad" tabIndex="42" ' +
|
||||
'data-reactroot="" data-reactid="1"></my-component>',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'mount',
|
||||
payload: '<my-component className="rad" tabIndex="42" ' +
|
||||
'data-reactroot="" data-reactid="1"></my-component>',
|
||||
},
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -409,27 +480,33 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
ReactDOM.render(<my-component className="mad" tabIndex={42} />, node);
|
||||
ReactDOM.render(<my-component tabIndex={43} />, node);
|
||||
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: { className: 'rad' },
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: { className: 'mad' },
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: { tabIndex: 42 },
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'remove attribute',
|
||||
payload: 'className',
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: { tabIndex: 43 },
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: {className: 'rad'},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: {className: 'mad'},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: {tabIndex: 42},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'remove attribute',
|
||||
payload: 'className',
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'update attribute',
|
||||
payload: {tabIndex: 43},
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -444,26 +521,33 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
ReactHostOperationHistoryHook._preventClearing = true;
|
||||
ReactDOM.render(<div>Bye.</div>, node);
|
||||
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'replace text',
|
||||
payload: 'Bye.',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'replace text',
|
||||
payload: 'Bye.',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('gets recorded during an update from html', () => {
|
||||
var node = document.createElement('div');
|
||||
ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);
|
||||
ReactDOM.render(
|
||||
<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />,
|
||||
node,
|
||||
);
|
||||
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
|
||||
|
||||
ReactHostOperationHistoryHook._preventClearing = true;
|
||||
ReactDOM.render(<div>Bye.</div>, node);
|
||||
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'replace text',
|
||||
payload: 'Bye.',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'replace text',
|
||||
payload: 'Bye.',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('gets recorded during an update from children', () => {
|
||||
@@ -474,19 +558,23 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
ReactHostOperationHistoryHook._preventClearing = true;
|
||||
ReactDOM.render(<div>Bye.</div>, node);
|
||||
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'remove child',
|
||||
payload: {fromIndex: 0},
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'remove child',
|
||||
payload: {fromIndex: 1},
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'replace text',
|
||||
payload: 'Bye.',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'remove child',
|
||||
payload: {fromIndex: 0},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'remove child',
|
||||
payload: {fromIndex: 1},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'replace text',
|
||||
payload: 'Bye.',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('gets ignored if new text is equal', () => {
|
||||
@@ -504,21 +592,28 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
it('gets recorded during an update', () => {
|
||||
var node = document.createElement('div');
|
||||
ReactDOM.render(<div>{'Hi.'}{42}</div>, node);
|
||||
var inst1 = ReactDOMComponentTree.getInstanceFromNode(node.firstChild.childNodes[0]);
|
||||
var inst2 = ReactDOMComponentTree.getInstanceFromNode(node.firstChild.childNodes[3]);
|
||||
var inst1 = ReactDOMComponentTree.getInstanceFromNode(
|
||||
node.firstChild.childNodes[0],
|
||||
);
|
||||
var inst2 = ReactDOMComponentTree.getInstanceFromNode(
|
||||
node.firstChild.childNodes[3],
|
||||
);
|
||||
|
||||
ReactHostOperationHistoryHook._preventClearing = true;
|
||||
ReactDOM.render(<div>{'Bye.'}{43}</div>, node);
|
||||
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst1._debugID,
|
||||
type: 'replace text',
|
||||
payload: 'Bye.',
|
||||
}, {
|
||||
instanceID: inst2._debugID,
|
||||
type: 'replace text',
|
||||
payload: '43',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst1._debugID,
|
||||
type: 'replace text',
|
||||
payload: 'Bye.',
|
||||
},
|
||||
{
|
||||
instanceID: inst2._debugID,
|
||||
type: 'replace text',
|
||||
payload: '43',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('gets ignored if new text is equal', () => {
|
||||
@@ -550,11 +645,13 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
ReactHostOperationHistoryHook._preventClearing = true;
|
||||
ReactDOM.render(<Foo />, node);
|
||||
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'replace with',
|
||||
payload: 'SPAN',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'replace with',
|
||||
payload: 'SPAN',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('gets recorded when composite renders to null after a native', () => {
|
||||
@@ -573,11 +670,13 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
ReactHostOperationHistoryHook._preventClearing = true;
|
||||
ReactDOM.render(<Foo />, node);
|
||||
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'replace with',
|
||||
payload: '#comment',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'replace with',
|
||||
payload: '#comment',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('gets ignored if the type has not changed', () => {
|
||||
@@ -606,37 +705,32 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
|
||||
|
||||
ReactHostOperationHistoryHook._preventClearing = true;
|
||||
ReactDOM.render(
|
||||
<div dangerouslySetInnerHTML={{__html: 'Bye.'}} />,
|
||||
node
|
||||
);
|
||||
ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Bye.'}} />, node);
|
||||
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'replace children',
|
||||
payload: 'Bye.',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'replace children',
|
||||
payload: 'Bye.',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('gets recorded during an update from html', () => {
|
||||
var node = document.createElement('div');
|
||||
ReactDOM.render(
|
||||
<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />,
|
||||
node
|
||||
);
|
||||
ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);
|
||||
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
|
||||
|
||||
ReactHostOperationHistoryHook._preventClearing = true;
|
||||
ReactDOM.render(
|
||||
<div dangerouslySetInnerHTML={{__html: 'Bye.'}} />,
|
||||
node
|
||||
);
|
||||
ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Bye.'}} />, node);
|
||||
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'replace children',
|
||||
payload: 'Bye.',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'replace children',
|
||||
payload: 'Bye.',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('gets recorded during an update from children', () => {
|
||||
@@ -645,38 +739,33 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
|
||||
|
||||
ReactHostOperationHistoryHook._preventClearing = true;
|
||||
ReactDOM.render(
|
||||
<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />,
|
||||
node
|
||||
);
|
||||
ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);
|
||||
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'remove child',
|
||||
payload: {fromIndex: 0},
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'remove child',
|
||||
payload: {fromIndex: 1},
|
||||
}, {
|
||||
instanceID: inst._debugID,
|
||||
type: 'replace children',
|
||||
payload: 'Hi.',
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'remove child',
|
||||
payload: {fromIndex: 0},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'remove child',
|
||||
payload: {fromIndex: 1},
|
||||
},
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'replace children',
|
||||
payload: 'Hi.',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('gets ignored if new html is equal', () => {
|
||||
var node = document.createElement('div');
|
||||
ReactDOM.render(
|
||||
<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />,
|
||||
node
|
||||
);
|
||||
ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);
|
||||
|
||||
ReactHostOperationHistoryHook._preventClearing = true;
|
||||
ReactDOM.render(
|
||||
<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />,
|
||||
node
|
||||
);
|
||||
ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);
|
||||
|
||||
assertHistoryMatches([]);
|
||||
});
|
||||
@@ -691,11 +780,13 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
ReactHostOperationHistoryHook._preventClearing = true;
|
||||
ReactDOM.render(<div><span /><p /></div>, node);
|
||||
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'insert child',
|
||||
payload: {toIndex: 1, content: 'P'},
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'insert child',
|
||||
payload: {toIndex: 1, content: 'P'},
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -708,11 +799,13 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
ReactHostOperationHistoryHook._preventClearing = true;
|
||||
ReactDOM.render(<div><p key="b" /><span key="a" /></div>, node);
|
||||
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'move child',
|
||||
payload: {fromIndex: 0, toIndex: 1},
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'move child',
|
||||
payload: {fromIndex: 0, toIndex: 1},
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -725,11 +818,13 @@ describeStack('ReactHostOperationHistoryHook', () => {
|
||||
ReactHostOperationHistoryHook._preventClearing = true;
|
||||
ReactDOM.render(<div><span key="a" /></div>, node);
|
||||
|
||||
assertHistoryMatches([{
|
||||
instanceID: inst._debugID,
|
||||
type: 'remove child',
|
||||
payload: {fromIndex: 1},
|
||||
}]);
|
||||
assertHistoryMatches([
|
||||
{
|
||||
instanceID: inst._debugID,
|
||||
type: 'remove child',
|
||||
payload: {fromIndex: 1},
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,7 +17,6 @@ var ReactFragment;
|
||||
var ReactTestUtils;
|
||||
|
||||
describe('ReactIdentity', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
React = require('react');
|
||||
@@ -32,11 +31,12 @@ describe('ReactIdentity', () => {
|
||||
|
||||
it('should allow key property to express identity', () => {
|
||||
var node;
|
||||
var Component = (props) =>
|
||||
<div ref={(c) => node = c}>
|
||||
var Component = props => (
|
||||
<div ref={c => node = c}>
|
||||
<div key={props.swap ? 'banana' : 'apple'} />
|
||||
<div key={props.swap ? 'apple' : 'banana'} />
|
||||
</div>;
|
||||
</div>
|
||||
);
|
||||
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(<Component />, container);
|
||||
@@ -58,12 +58,12 @@ describe('ReactIdentity', () => {
|
||||
var node1;
|
||||
var node2;
|
||||
ReactDOM.render(
|
||||
<Wrapper key="wrap1"><span ref={(c) => node1 = c} /></Wrapper>,
|
||||
container
|
||||
<Wrapper key="wrap1"><span ref={c => node1 = c} /></Wrapper>,
|
||||
container,
|
||||
);
|
||||
ReactDOM.render(
|
||||
<Wrapper key="wrap2"><span ref={(c) => node2 = c} /></Wrapper>,
|
||||
container
|
||||
<Wrapper key="wrap2"><span ref={c => node2 = c} /></Wrapper>,
|
||||
container,
|
||||
);
|
||||
|
||||
expect(node1).not.toBe(node2);
|
||||
@@ -91,10 +91,7 @@ describe('ReactIdentity', () => {
|
||||
|
||||
it('should allow any character as a key, in a detached parent', () => {
|
||||
var detachedContainer = document.createElement('div');
|
||||
renderAComponentWithKeyIntoContainer(
|
||||
"<'WEIRD/&\\key'>",
|
||||
detachedContainer
|
||||
);
|
||||
renderAComponentWithKeyIntoContainer("<'WEIRD/&\\key'>", detachedContainer);
|
||||
});
|
||||
|
||||
it('should allow any character as a key, in an attached parent', () => {
|
||||
@@ -103,17 +100,13 @@ describe('ReactIdentity', () => {
|
||||
var attachedContainer = document.createElement('div');
|
||||
document.body.appendChild(attachedContainer);
|
||||
|
||||
renderAComponentWithKeyIntoContainer(
|
||||
"<'WEIRD/&\\key'>",
|
||||
attachedContainer
|
||||
);
|
||||
renderAComponentWithKeyIntoContainer("<'WEIRD/&\\key'>", attachedContainer);
|
||||
|
||||
document.body.removeChild(attachedContainer);
|
||||
});
|
||||
|
||||
it('should not allow scripts in keys to execute', () => {
|
||||
var h4x0rKey =
|
||||
'"><script>window[\'YOUVEBEENH4X0RED\']=true;</script><div id="';
|
||||
var h4x0rKey = '"><script>window[\'YOUVEBEENH4X0RED\']=true;</script><div id="';
|
||||
|
||||
var attachedContainer = document.createElement('div');
|
||||
document.body.appendChild(attachedContainer);
|
||||
@@ -150,9 +143,7 @@ describe('ReactIdentity', () => {
|
||||
}
|
||||
|
||||
expect(function() {
|
||||
|
||||
ReactTestUtils.renderIntoDocument(<TestContainer />);
|
||||
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
@@ -184,9 +175,7 @@ describe('ReactIdentity', () => {
|
||||
}
|
||||
|
||||
expect(function() {
|
||||
|
||||
ReactTestUtils.renderIntoDocument(<TestContainer />);
|
||||
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
@@ -209,9 +198,7 @@ describe('ReactIdentity', () => {
|
||||
}
|
||||
|
||||
expect(function() {
|
||||
|
||||
ReactTestUtils.renderIntoDocument(<TestContainer />);
|
||||
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
@@ -258,16 +245,15 @@ describe('ReactIdentity', () => {
|
||||
});
|
||||
|
||||
it('should not allow implicit and explicit keys to collide', () => {
|
||||
var component =
|
||||
var component = (
|
||||
<div>
|
||||
<span />
|
||||
<span key="0" />
|
||||
</div>;
|
||||
</div>
|
||||
);
|
||||
|
||||
expect(function() {
|
||||
ReactTestUtils.renderIntoDocument(component);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
@@ -18,13 +18,16 @@ var AutoMockedComponent;
|
||||
var MockedComponent;
|
||||
|
||||
describe('ReactMockedComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
React = require('react');
|
||||
ReactTestUtils = require('ReactTestUtils');
|
||||
|
||||
AutoMockedComponent = jest.genMockFromModule('ReactMockedComponentTestComponent');
|
||||
MockedComponent = jest.genMockFromModule('ReactMockedComponentTestComponent');
|
||||
AutoMockedComponent = jest.genMockFromModule(
|
||||
'ReactMockedComponentTestComponent',
|
||||
);
|
||||
MockedComponent = jest.genMockFromModule(
|
||||
'ReactMockedComponentTestComponent',
|
||||
);
|
||||
|
||||
ReactTestUtils.mockComponent(MockedComponent);
|
||||
});
|
||||
@@ -52,7 +55,7 @@ describe('ReactMockedComponent', () => {
|
||||
|
||||
var found = ReactTestUtils.findRenderedComponentWithType(
|
||||
instance,
|
||||
AutoMockedComponent
|
||||
AutoMockedComponent,
|
||||
);
|
||||
expect(typeof found).toBe('object');
|
||||
|
||||
@@ -85,7 +88,7 @@ describe('ReactMockedComponent', () => {
|
||||
|
||||
var found = ReactTestUtils.findRenderedComponentWithType(
|
||||
instance,
|
||||
MockedComponent
|
||||
MockedComponent,
|
||||
);
|
||||
expect(typeof found).toBe('object');
|
||||
|
||||
@@ -96,5 +99,4 @@ describe('ReactMockedComponent', () => {
|
||||
var instance = ReactTestUtils.renderIntoDocument(<MockedComponent />);
|
||||
expect(typeof instance.hasCustomMethod).toBe('function');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -119,7 +119,7 @@ describe('ReactMultiChild', () => {
|
||||
|
||||
ReactDOM.render(
|
||||
<WrapperComponent><MockComponent /></WrapperComponent>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
|
||||
expect(mockMount.mock.calls.length).toBe(1);
|
||||
@@ -177,25 +177,24 @@ describe('ReactMultiChild', () => {
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<Parent>{[<div key="1" />]}</Parent>,
|
||||
container
|
||||
);
|
||||
ReactDOM.render(<Parent>{[<div key="1" />]}</Parent>, container);
|
||||
|
||||
ReactDOM.render(
|
||||
<Parent>{[<div key="1" />, <div key="1" />]}</Parent>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toContain(
|
||||
expectDev(
|
||||
normalizeCodeLocInfo(console.error.calls.argsFor(0)[0]),
|
||||
).toContain(
|
||||
'Encountered two children with the same key, `1`. ' +
|
||||
'Child keys must be unique; when two children share a key, ' +
|
||||
'only the first child will be used.\n' +
|
||||
' in div (at **)\n' +
|
||||
' in WrapperComponent (at **)\n' +
|
||||
' in div (at **)\n' +
|
||||
' in Parent (at **)'
|
||||
'Child keys must be unique; when two children share a key, ' +
|
||||
'only the first child will be used.\n' +
|
||||
' in div (at **)\n' +
|
||||
' in WrapperComponent (at **)\n' +
|
||||
' in div (at **)\n' +
|
||||
' in Parent (at **)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -242,23 +241,25 @@ describe('ReactMultiChild', () => {
|
||||
|
||||
ReactDOM.render(
|
||||
<Parent>{createIterable([<div key="1" />])}</Parent>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
|
||||
ReactDOM.render(
|
||||
<Parent>{createIterable([<div key="1" />, <div key="1" />])}</Parent>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toContain(
|
||||
expectDev(
|
||||
normalizeCodeLocInfo(console.error.calls.argsFor(0)[0]),
|
||||
).toContain(
|
||||
'Encountered two children with the same key, `1`. ' +
|
||||
'Child keys must be unique; when two children share a key, ' +
|
||||
'only the first child will be used.\n' +
|
||||
' in div (at **)\n' +
|
||||
' in WrapperComponent (at **)\n' +
|
||||
' in div (at **)\n' +
|
||||
' in Parent (at **)'
|
||||
'Child keys must be unique; when two children share a key, ' +
|
||||
'only the first child will be used.\n' +
|
||||
' in div (at **)\n' +
|
||||
' in WrapperComponent (at **)\n' +
|
||||
' in div (at **)\n' +
|
||||
' in Parent (at **)',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -267,9 +268,7 @@ describe('ReactMultiChild', () => {
|
||||
spyOn(console, 'error');
|
||||
class Parent extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div>{new Map([['foo', 0], ['bar', 1]])}</div>
|
||||
);
|
||||
return <div>{new Map([['foo', 0], ['bar', 1]])}</div>;
|
||||
}
|
||||
}
|
||||
var container = document.createElement('div');
|
||||
@@ -277,8 +276,8 @@ describe('ReactMultiChild', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: Using Maps as children is unsupported and will likely yield ' +
|
||||
'unexpected results. Convert it to a sequence/iterable of keyed ' +
|
||||
'ReactElements instead.\n\nCheck the render method of `Parent`.'
|
||||
'unexpected results. Convert it to a sequence/iterable of keyed ' +
|
||||
'ReactElements instead.\n\nCheck the render method of `Parent`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -303,7 +302,7 @@ describe('ReactMultiChild', () => {
|
||||
class Letters extends React.Component {
|
||||
render() {
|
||||
const letters = this.props.letters.split('');
|
||||
return <div>{letters.map((c) => <Letter key={c} char={c} />)}</div>;
|
||||
return <div>{letters.map(c => <Letter key={c} char={c} />)}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,8 +336,8 @@ describe('ReactMultiChild', () => {
|
||||
|
||||
// These are reference-unequal so they will be swapped even if they have
|
||||
// matching keys
|
||||
var SpyA = (props) => <Spy {...props} />;
|
||||
var SpyB = (props) => <Spy {...props} />;
|
||||
var SpyA = props => <Spy {...props} />;
|
||||
var SpyB = props => <Spy {...props} />;
|
||||
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(
|
||||
@@ -346,14 +345,14 @@ describe('ReactMultiChild', () => {
|
||||
<SpyA key="one" name="oneA" />
|
||||
<SpyA key="two" name="twoA" />
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<SpyB key="one" name="oneB" />
|
||||
<SpyB key="two" name="twoB" />
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
|
||||
expect(log).toEqual([
|
||||
@@ -364,9 +363,8 @@ describe('ReactMultiChild', () => {
|
||||
'oneA componentDidMount',
|
||||
'twoA componentDidMount',
|
||||
|
||||
...(
|
||||
ReactDOMFeatureFlags.useFiber
|
||||
? [
|
||||
...(ReactDOMFeatureFlags.useFiber
|
||||
? [
|
||||
'oneB componentWillMount',
|
||||
'oneB render',
|
||||
'twoB componentWillMount',
|
||||
@@ -374,19 +372,17 @@ describe('ReactMultiChild', () => {
|
||||
'oneA componentWillUnmount',
|
||||
'twoA componentWillUnmount',
|
||||
]
|
||||
: [
|
||||
: [
|
||||
'oneB componentWillMount',
|
||||
'oneB render',
|
||||
'oneA componentWillUnmount',
|
||||
'twoB componentWillMount',
|
||||
'twoB render',
|
||||
'twoA componentWillUnmount',
|
||||
]
|
||||
),
|
||||
]),
|
||||
|
||||
'oneB componentDidMount',
|
||||
'twoB componentDidMount',
|
||||
]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -119,14 +119,15 @@ class FriendsStatusDisplay extends React.Component {
|
||||
for (var key in this.props.usernameToStatus) {
|
||||
var status = this.props.usernameToStatus[key];
|
||||
children.push(
|
||||
!status ? null :
|
||||
<StatusDisplay
|
||||
key={key}
|
||||
ref={key}
|
||||
contentKey={key}
|
||||
onFlush={this.verifyPreviousRefsResolved.bind(this, key)}
|
||||
status={status}
|
||||
/>
|
||||
!status
|
||||
? null
|
||||
: <StatusDisplay
|
||||
key={key}
|
||||
ref={key}
|
||||
contentKey={key}
|
||||
onFlush={this.verifyPreviousRefsResolved.bind(this, key)}
|
||||
status={status}
|
||||
/>,
|
||||
);
|
||||
}
|
||||
var childrenToRender = this.props.prepareChildren(children);
|
||||
@@ -138,12 +139,14 @@ class FriendsStatusDisplay extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getInternalStateByUserName(statusDisplays) {
|
||||
return Object.keys(statusDisplays).reduce((acc, key) => {
|
||||
acc[key] = statusDisplays[key].getInternalState();
|
||||
return acc;
|
||||
}, {});
|
||||
return Object.keys(statusDisplays).reduce(
|
||||
(acc, key) => {
|
||||
acc[key] = statusDisplays[key].getInternalState();
|
||||
return acc;
|
||||
},
|
||||
{},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,14 +158,16 @@ function verifyStatuses(statusDisplays, props) {
|
||||
var nonEmptyStatusDisplays = stripEmptyValues(statusDisplays);
|
||||
var nonEmptyStatusProps = stripEmptyValues(props.usernameToStatus);
|
||||
var username;
|
||||
expect(Object.keys(nonEmptyStatusDisplays).length)
|
||||
.toEqual(Object.keys(nonEmptyStatusProps).length);
|
||||
expect(Object.keys(nonEmptyStatusDisplays).length).toEqual(
|
||||
Object.keys(nonEmptyStatusProps).length,
|
||||
);
|
||||
for (username in nonEmptyStatusDisplays) {
|
||||
if (!nonEmptyStatusDisplays.hasOwnProperty(username)) {
|
||||
continue;
|
||||
}
|
||||
expect(nonEmptyStatusDisplays[username].getStatus())
|
||||
.toEqual(nonEmptyStatusProps[username]);
|
||||
expect(nonEmptyStatusDisplays[username].getStatus()).toEqual(
|
||||
nonEmptyStatusProps[username],
|
||||
);
|
||||
}
|
||||
|
||||
// now go the other way to make sure we got them all.
|
||||
@@ -170,12 +175,14 @@ function verifyStatuses(statusDisplays, props) {
|
||||
if (!nonEmptyStatusProps.hasOwnProperty(username)) {
|
||||
continue;
|
||||
}
|
||||
expect(nonEmptyStatusDisplays[username].getStatus())
|
||||
.toEqual(nonEmptyStatusProps[username]);
|
||||
expect(nonEmptyStatusDisplays[username].getStatus()).toEqual(
|
||||
nonEmptyStatusProps[username],
|
||||
);
|
||||
}
|
||||
|
||||
expect(Object.keys(nonEmptyStatusDisplays))
|
||||
.toEqual(Object.keys(nonEmptyStatusProps));
|
||||
expect(Object.keys(nonEmptyStatusDisplays)).toEqual(
|
||||
Object.keys(nonEmptyStatusProps),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,13 +198,13 @@ function verifyStatesPreserved(lastInternalStates, statusDisplays) {
|
||||
continue;
|
||||
}
|
||||
if (lastInternalStates[key]) {
|
||||
expect(lastInternalStates[key])
|
||||
.toEqual(statusDisplays[key].getInternalState());
|
||||
expect(lastInternalStates[key]).toEqual(
|
||||
statusDisplays[key].getInternalState(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Verifies that the internal representation of a set of `renderedChildren`
|
||||
* accurately reflects what is in the DOM.
|
||||
@@ -218,9 +225,7 @@ function verifyDomOrderingAccurate(outerContainer, statusDisplays) {
|
||||
continue;
|
||||
}
|
||||
var statusDisplay = statusDisplays[username];
|
||||
orderedLogicalKeys.push(
|
||||
statusDisplay.props.contentKey
|
||||
);
|
||||
orderedLogicalKeys.push(statusDisplay.props.contentKey);
|
||||
}
|
||||
expect(orderedDomKeys).toEqual(orderedLogicalKeys);
|
||||
}
|
||||
@@ -228,11 +233,8 @@ function verifyDomOrderingAccurate(outerContainer, statusDisplays) {
|
||||
function testPropsSequenceWithPreparedChildren(sequence, prepareChildren) {
|
||||
var container = document.createElement('div');
|
||||
var parentInstance = ReactDOM.render(
|
||||
<FriendsStatusDisplay
|
||||
{...sequence[0]}
|
||||
prepareChildren={prepareChildren}
|
||||
/>,
|
||||
container
|
||||
<FriendsStatusDisplay {...sequence[0]} prepareChildren={prepareChildren} />,
|
||||
container,
|
||||
);
|
||||
var statusDisplays = parentInstance.getStatusDisplays();
|
||||
var lastInternalStates = getInternalStateByUserName(statusDisplays);
|
||||
@@ -244,7 +246,7 @@ function testPropsSequenceWithPreparedChildren(sequence, prepareChildren) {
|
||||
{...sequence[i]}
|
||||
prepareChildren={prepareChildren}
|
||||
/>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
statusDisplays = parentInstance.getStatusDisplays();
|
||||
verifyStatuses(statusDisplays, sequence[i]);
|
||||
@@ -289,8 +291,11 @@ describe('ReactMultiChildReconcile', () => {
|
||||
|
||||
var container = document.createElement('div');
|
||||
var parentInstance = ReactDOM.render(
|
||||
<FriendsStatusDisplay {...props} prepareChildren={prepareChildrenArray} />,
|
||||
container
|
||||
<FriendsStatusDisplay
|
||||
{...props}
|
||||
prepareChildren={prepareChildrenArray}
|
||||
/>,
|
||||
container,
|
||||
);
|
||||
var statusDisplays = parentInstance.getStatusDisplays();
|
||||
var startingInternalState = statusDisplays.jcw.getInternalState();
|
||||
@@ -298,20 +303,24 @@ describe('ReactMultiChildReconcile', () => {
|
||||
// Now remove the child.
|
||||
ReactDOM.render(
|
||||
<FriendsStatusDisplay prepareChildren={prepareChildrenArray} />,
|
||||
container
|
||||
container,
|
||||
);
|
||||
statusDisplays = parentInstance.getStatusDisplays();
|
||||
expect(statusDisplays.jcw).toBeFalsy();
|
||||
|
||||
// Now reset the props that cause there to be a child
|
||||
ReactDOM.render(
|
||||
<FriendsStatusDisplay {...props} prepareChildren={prepareChildrenArray} />,
|
||||
container
|
||||
<FriendsStatusDisplay
|
||||
{...props}
|
||||
prepareChildren={prepareChildrenArray}
|
||||
/>,
|
||||
container,
|
||||
);
|
||||
statusDisplays = parentInstance.getStatusDisplays();
|
||||
expect(statusDisplays.jcw).toBeTruthy();
|
||||
expect(statusDisplays.jcw.getInternalState())
|
||||
.not.toBe(startingInternalState);
|
||||
expect(statusDisplays.jcw.getInternalState()).not.toBe(
|
||||
startingInternalState,
|
||||
);
|
||||
});
|
||||
|
||||
it('should reset internal state if removed then readded in an iterable', () => {
|
||||
@@ -324,8 +333,11 @@ describe('ReactMultiChildReconcile', () => {
|
||||
|
||||
var container = document.createElement('div');
|
||||
var parentInstance = ReactDOM.render(
|
||||
<FriendsStatusDisplay {...props} prepareChildren={prepareChildrenIterable} />,
|
||||
container
|
||||
<FriendsStatusDisplay
|
||||
{...props}
|
||||
prepareChildren={prepareChildrenIterable}
|
||||
/>,
|
||||
container,
|
||||
);
|
||||
var statusDisplays = parentInstance.getStatusDisplays();
|
||||
var startingInternalState = statusDisplays.jcw.getInternalState();
|
||||
@@ -333,20 +345,24 @@ describe('ReactMultiChildReconcile', () => {
|
||||
// Now remove the child.
|
||||
ReactDOM.render(
|
||||
<FriendsStatusDisplay prepareChildren={prepareChildrenIterable} />,
|
||||
container
|
||||
container,
|
||||
);
|
||||
statusDisplays = parentInstance.getStatusDisplays();
|
||||
expect(statusDisplays.jcw).toBeFalsy();
|
||||
|
||||
// Now reset the props that cause there to be a child
|
||||
ReactDOM.render(
|
||||
<FriendsStatusDisplay {...props} prepareChildren={prepareChildrenIterable} />,
|
||||
container
|
||||
<FriendsStatusDisplay
|
||||
{...props}
|
||||
prepareChildren={prepareChildrenIterable}
|
||||
/>,
|
||||
container,
|
||||
);
|
||||
statusDisplays = parentInstance.getStatusDisplays();
|
||||
expect(statusDisplays.jcw).toBeTruthy();
|
||||
expect(statusDisplays.jcw.getInternalState())
|
||||
.not.toBe(startingInternalState);
|
||||
expect(statusDisplays.jcw.getInternalState()).not.toBe(
|
||||
startingInternalState,
|
||||
);
|
||||
});
|
||||
|
||||
it('should create unique identity', () => {
|
||||
@@ -380,7 +396,7 @@ describe('ReactMultiChildReconcile', () => {
|
||||
|
||||
it('should transition from zero to one children correctly', () => {
|
||||
var PROPS_SEQUENCE = [
|
||||
{usernameToStatus: {} },
|
||||
{usernameToStatus: {}},
|
||||
{
|
||||
usernameToStatus: {
|
||||
first: 'firstStatus',
|
||||
@@ -397,7 +413,7 @@ describe('ReactMultiChildReconcile', () => {
|
||||
first: 'firstStatus',
|
||||
},
|
||||
},
|
||||
{usernameToStatus: {} },
|
||||
{usernameToStatus: {}},
|
||||
];
|
||||
testPropsSequence(PROPS_SEQUENCE);
|
||||
});
|
||||
@@ -442,8 +458,6 @@ describe('ReactMultiChildReconcile', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* `FriendsStatusDisplay` renders nulls as empty children (it's a convention
|
||||
* of `FriendsStatusDisplay`, nothing related to React or these test cases.
|
||||
@@ -557,7 +571,8 @@ describe('ReactMultiChildReconcile', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
usernameToStatus: { // Full circle!
|
||||
usernameToStatus: {
|
||||
// Full circle!
|
||||
userOne: 'userOneStatus',
|
||||
userTwo: 'userTwoStatus',
|
||||
userThree: 'userThreeStatus',
|
||||
@@ -603,7 +618,8 @@ describe('ReactMultiChildReconcile', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
usernameToStatus: { // Full circle!
|
||||
usernameToStatus: {
|
||||
// Full circle!
|
||||
userOne: 'userOneStatus',
|
||||
userTwo: 'userTwoStatus',
|
||||
userThree: 'userThreeStatus',
|
||||
@@ -614,7 +630,6 @@ describe('ReactMultiChildReconcile', () => {
|
||||
testPropsSequence(PROPS_SEQUENCE);
|
||||
});
|
||||
|
||||
|
||||
it('should remove nulled out children and ignore new null children', () => {
|
||||
var PROPS_SEQUENCE = [
|
||||
{
|
||||
@@ -640,7 +655,7 @@ describe('ReactMultiChildReconcile', () => {
|
||||
usernameToStatus: {
|
||||
jcw: 'jcwStatus',
|
||||
jordanjcw: 'jordanjcwStatus',
|
||||
john: 'johnStatus', // john will go away
|
||||
john: 'johnStatus', // john will go away
|
||||
joe: 'joeStatus',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -96,7 +96,6 @@ var expectChildren = function(container, children) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* ReactMultiChild DOM integration test. In ReactDOM components, we make sure
|
||||
* that single children that are strings are treated as "content" which is much
|
||||
@@ -105,6 +104,7 @@ var expectChildren = function(container, children) {
|
||||
describe('ReactMultiChildText', () => {
|
||||
it('should correctly handle all possible children for render and update', () => {
|
||||
spyOn(console, 'error');
|
||||
// prettier-ignore
|
||||
testAllPermutations([
|
||||
// basic values
|
||||
undefined, [],
|
||||
@@ -193,14 +193,14 @@ describe('ReactMultiChildText', () => {
|
||||
]);
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Warning: Each child in an array or iterator should have a unique "key" prop.'
|
||||
'Warning: Each child in an array or iterator should have a unique "key" prop.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if rendering both HTML and children', () => {
|
||||
expect(function() {
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
<div dangerouslySetInnerHTML={{__html: 'abcdef'}}>ghjkl</div>
|
||||
<div dangerouslySetInnerHTML={{__html: 'abcdef'}}>ghjkl</div>,
|
||||
);
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
@@ -104,17 +104,20 @@ describeStack('ReactPerf', () => {
|
||||
});
|
||||
|
||||
var summary = ReactPerf.getWasted(measurements);
|
||||
expect(summary).toEqual([{
|
||||
key: 'App',
|
||||
instanceCount: 1,
|
||||
inclusiveRenderDuration: 3,
|
||||
renderCount: 1,
|
||||
}, {
|
||||
key: 'App > Box',
|
||||
instanceCount: 2,
|
||||
inclusiveRenderDuration: 2,
|
||||
renderCount: 2,
|
||||
}]);
|
||||
expect(summary).toEqual([
|
||||
{
|
||||
key: 'App',
|
||||
instanceCount: 1,
|
||||
inclusiveRenderDuration: 3,
|
||||
renderCount: 1,
|
||||
},
|
||||
{
|
||||
key: 'App > Box',
|
||||
instanceCount: 2,
|
||||
inclusiveRenderDuration: 2,
|
||||
renderCount: 2,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should count no-op update in child as waste', () => {
|
||||
@@ -128,12 +131,14 @@ describeStack('ReactPerf', () => {
|
||||
});
|
||||
|
||||
var summary = ReactPerf.getWasted(measurements);
|
||||
expect(summary).toEqual([{
|
||||
key: 'App > Box',
|
||||
instanceCount: 1,
|
||||
inclusiveRenderDuration: 1,
|
||||
renderCount: 1,
|
||||
}]);
|
||||
expect(summary).toEqual([
|
||||
{
|
||||
key: 'App > Box',
|
||||
instanceCount: 1,
|
||||
inclusiveRenderDuration: 1,
|
||||
renderCount: 1,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
function expectNoWaste(fn) {
|
||||
@@ -208,12 +213,12 @@ describeStack('ReactPerf', () => {
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(
|
||||
<Div dangerouslySetInnerHTML={{__html: 'me'}} />,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expectNoWaste(() => {
|
||||
ReactDOM.render(
|
||||
<Div dangerouslySetInnerHTML={{__html: 'you'}} />,
|
||||
container
|
||||
container,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -266,13 +271,15 @@ describeStack('ReactPerf', () => {
|
||||
ReactDOM.render(<Div><Div key="a" /></Div>, container);
|
||||
ReactDOM.render(<Div><Div key="b" /></Div>, container);
|
||||
});
|
||||
expect(ReactPerf.getExclusive(measurements)).toEqual([{
|
||||
key: 'Div',
|
||||
instanceCount: 3,
|
||||
counts: { ctor: 3, render: 4 },
|
||||
durations: { ctor: 3, render: 4 },
|
||||
totalDuration: 7,
|
||||
}]);
|
||||
expect(ReactPerf.getExclusive(measurements)).toEqual([
|
||||
{
|
||||
key: 'Div',
|
||||
instanceCount: 3,
|
||||
counts: {ctor: 3, render: 4},
|
||||
durations: {ctor: 3, render: 4},
|
||||
totalDuration: 7,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should include lifecycle methods in measurements', () => {
|
||||
@@ -283,33 +290,35 @@ describeStack('ReactPerf', () => {
|
||||
instance.setState({});
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
});
|
||||
expect(ReactPerf.getExclusive(measurements)).toEqual([{
|
||||
key: 'LifeCycle',
|
||||
instanceCount: 1,
|
||||
totalDuration: 14,
|
||||
counts: {
|
||||
ctor: 1,
|
||||
shouldComponentUpdate: 2,
|
||||
componentWillMount: 1,
|
||||
componentDidMount: 1,
|
||||
componentWillReceiveProps: 1,
|
||||
componentWillUpdate: 2,
|
||||
componentDidUpdate: 2,
|
||||
componentWillUnmount: 1,
|
||||
render: 3,
|
||||
expect(ReactPerf.getExclusive(measurements)).toEqual([
|
||||
{
|
||||
key: 'LifeCycle',
|
||||
instanceCount: 1,
|
||||
totalDuration: 14,
|
||||
counts: {
|
||||
ctor: 1,
|
||||
shouldComponentUpdate: 2,
|
||||
componentWillMount: 1,
|
||||
componentDidMount: 1,
|
||||
componentWillReceiveProps: 1,
|
||||
componentWillUpdate: 2,
|
||||
componentDidUpdate: 2,
|
||||
componentWillUnmount: 1,
|
||||
render: 3,
|
||||
},
|
||||
durations: {
|
||||
ctor: 1,
|
||||
shouldComponentUpdate: 2,
|
||||
componentWillMount: 1,
|
||||
componentDidMount: 1,
|
||||
componentWillReceiveProps: 1,
|
||||
componentWillUpdate: 2,
|
||||
componentDidUpdate: 2,
|
||||
componentWillUnmount: 1,
|
||||
render: 3,
|
||||
},
|
||||
},
|
||||
durations: {
|
||||
ctor: 1,
|
||||
shouldComponentUpdate: 2,
|
||||
componentWillMount: 1,
|
||||
componentDidMount: 1,
|
||||
componentWillReceiveProps: 1,
|
||||
componentWillUpdate: 2,
|
||||
componentDidUpdate: 2,
|
||||
componentWillUnmount: 1,
|
||||
render: 3,
|
||||
},
|
||||
}]);
|
||||
]);
|
||||
});
|
||||
|
||||
it('should include render time of functional components', () => {
|
||||
@@ -321,17 +330,19 @@ describeStack('ReactPerf', () => {
|
||||
var measurements = measure(() => {
|
||||
ReactDOM.render(<Foo />, container);
|
||||
});
|
||||
expect(ReactPerf.getExclusive(measurements)).toEqual([{
|
||||
key: 'Foo',
|
||||
instanceCount: 1,
|
||||
totalDuration: 1,
|
||||
counts: {
|
||||
render: 1,
|
||||
expect(ReactPerf.getExclusive(measurements)).toEqual([
|
||||
{
|
||||
key: 'Foo',
|
||||
instanceCount: 1,
|
||||
totalDuration: 1,
|
||||
counts: {
|
||||
render: 1,
|
||||
},
|
||||
durations: {
|
||||
render: 1,
|
||||
},
|
||||
},
|
||||
durations: {
|
||||
render: 1,
|
||||
},
|
||||
}]);
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not count time in a portal towards lifecycle method', () => {
|
||||
@@ -354,40 +365,43 @@ describeStack('ReactPerf', () => {
|
||||
ReactDOM.render(<Portal />, container);
|
||||
});
|
||||
|
||||
expect(ReactPerf.getExclusive(measurements)).toEqual([{
|
||||
key: 'Portal',
|
||||
instanceCount: 1,
|
||||
totalDuration: 6,
|
||||
counts: {
|
||||
ctor: 1,
|
||||
componentDidMount: 1,
|
||||
render: 1,
|
||||
expect(ReactPerf.getExclusive(measurements)).toEqual([
|
||||
{
|
||||
key: 'Portal',
|
||||
instanceCount: 1,
|
||||
totalDuration: 6,
|
||||
counts: {
|
||||
ctor: 1,
|
||||
componentDidMount: 1,
|
||||
render: 1,
|
||||
},
|
||||
durations: {
|
||||
ctor: 1,
|
||||
// We want to exclude nested imperative ReactDOM.render() from lifecycle hook's own time.
|
||||
// Otherwise it would artificially float to the top even though its exclusive time is small.
|
||||
// This is how we get 4 as a number with the performanceNow() mock:
|
||||
// - we capture the time we enter componentDidMount (n = 0)
|
||||
// - we capture the time when we enter a nested flush (n = 1)
|
||||
// - in the nested flush, we call it twice: before and after <Foo /> rendering. (n = 3)
|
||||
// - we capture the time when we exit a nested flush (n = 4)
|
||||
// - we capture the time we exit componentDidMount (n = 5)
|
||||
// Time spent in componentDidMount = (5 - 0 - (4 - 3)) = 4.
|
||||
componentDidMount: 4,
|
||||
render: 1,
|
||||
},
|
||||
},
|
||||
durations: {
|
||||
ctor: 1,
|
||||
// We want to exclude nested imperative ReactDOM.render() from lifecycle hook's own time.
|
||||
// Otherwise it would artificially float to the top even though its exclusive time is small.
|
||||
// This is how we get 4 as a number with the performanceNow() mock:
|
||||
// - we capture the time we enter componentDidMount (n = 0)
|
||||
// - we capture the time when we enter a nested flush (n = 1)
|
||||
// - in the nested flush, we call it twice: before and after <Foo /> rendering. (n = 3)
|
||||
// - we capture the time when we exit a nested flush (n = 4)
|
||||
// - we capture the time we exit componentDidMount (n = 5)
|
||||
// Time spent in componentDidMount = (5 - 0 - (4 - 3)) = 4.
|
||||
componentDidMount: 4,
|
||||
render: 1,
|
||||
{
|
||||
key: 'Foo',
|
||||
instanceCount: 1,
|
||||
totalDuration: 1,
|
||||
counts: {
|
||||
render: 1,
|
||||
},
|
||||
durations: {
|
||||
render: 1,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
key: 'Foo',
|
||||
instanceCount: 1,
|
||||
totalDuration: 1,
|
||||
counts: {
|
||||
render: 1,
|
||||
},
|
||||
durations: {
|
||||
render: 1,
|
||||
},
|
||||
}]);
|
||||
]);
|
||||
});
|
||||
|
||||
it('warns once when using getMeasurementsSummaryMap', () => {
|
||||
@@ -397,7 +411,7 @@ describeStack('ReactPerf', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'`ReactPerf.getMeasurementsSummaryMap(...)` is deprecated. Use ' +
|
||||
'`ReactPerf.getWasted(...)` instead.'
|
||||
'`ReactPerf.getWasted(...)` instead.',
|
||||
);
|
||||
|
||||
ReactPerf.getMeasurementsSummaryMap(measurements);
|
||||
@@ -411,7 +425,7 @@ describeStack('ReactPerf', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'`ReactPerf.printDOM(...)` is deprecated. Use ' +
|
||||
'`ReactPerf.printOperations(...)` instead.'
|
||||
'`ReactPerf.printOperations(...)` instead.',
|
||||
);
|
||||
|
||||
ReactPerf.printDOM(measurements);
|
||||
@@ -504,22 +518,26 @@ describeStack('ReactPerf', () => {
|
||||
expect(ReactPerf.getWasted()).toEqual([]);
|
||||
|
||||
ReactDOM.render(<Measurer><App /></Measurer>, container);
|
||||
expect(ReactPerf.getWasted()).toEqual([{
|
||||
key: 'Measurer',
|
||||
instanceCount: 1,
|
||||
inclusiveRenderDuration: 4,
|
||||
renderCount: 1,
|
||||
}, {
|
||||
key: 'App',
|
||||
instanceCount: 1,
|
||||
inclusiveRenderDuration: 3,
|
||||
renderCount: 1,
|
||||
}, {
|
||||
key: 'App > Box',
|
||||
instanceCount: 2,
|
||||
inclusiveRenderDuration: 2,
|
||||
renderCount: 2,
|
||||
}]);
|
||||
expect(ReactPerf.getWasted()).toEqual([
|
||||
{
|
||||
key: 'Measurer',
|
||||
instanceCount: 1,
|
||||
inclusiveRenderDuration: 4,
|
||||
renderCount: 1,
|
||||
},
|
||||
{
|
||||
key: 'App',
|
||||
instanceCount: 1,
|
||||
inclusiveRenderDuration: 3,
|
||||
renderCount: 1,
|
||||
},
|
||||
{
|
||||
key: 'App > Box',
|
||||
instanceCount: 2,
|
||||
inclusiveRenderDuration: 2,
|
||||
renderCount: 2,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not print errant warnings if render() throws', () => {
|
||||
@@ -539,7 +557,7 @@ describeStack('ReactPerf', () => {
|
||||
<LifeCycle />
|
||||
<Evil />
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
} catch (err) {
|
||||
if (err !== thrownErr) {
|
||||
@@ -569,7 +587,7 @@ describeStack('ReactPerf', () => {
|
||||
<LifeCycle />
|
||||
<Evil />
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
} catch (err) {
|
||||
if (err !== thrownErr) {
|
||||
@@ -599,7 +617,7 @@ describeStack('ReactPerf', () => {
|
||||
<LifeCycle />
|
||||
<Evil />
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
} catch (err) {
|
||||
if (err !== thrownErr) {
|
||||
@@ -635,7 +653,7 @@ describeStack('ReactPerf', () => {
|
||||
<LifeCycle />
|
||||
<EvilPortal />
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
} catch (err) {
|
||||
if (err !== thrownErr) {
|
||||
@@ -675,7 +693,7 @@ describeStack('ReactPerf', () => {
|
||||
<LifeCycle />
|
||||
<EvilPortal />
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
} catch (err) {
|
||||
if (err !== thrownErr) {
|
||||
@@ -715,7 +733,7 @@ describeStack('ReactPerf', () => {
|
||||
<LifeCycle />
|
||||
<EvilPortal />
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
} catch (err) {
|
||||
if (err !== thrownErr) {
|
||||
|
||||
@@ -123,19 +123,19 @@ describe('ReactStatelessComponent', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'StatelessComponentWithChildContext(...): childContextTypes cannot ' +
|
||||
'be defined on a functional component.'
|
||||
'be defined on a functional component.',
|
||||
);
|
||||
} else {
|
||||
expectDev(console.error.calls.count()).toBe(2);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'StatelessComponentWithChildContext(...): childContextTypes cannot ' +
|
||||
'be defined on a functional component.'
|
||||
'be defined on a functional component.',
|
||||
);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
|
||||
'Warning: StatelessComponentWithChildContext.childContextTypes is specified ' +
|
||||
'but there is no getChildContext() method on the instance. You can either ' +
|
||||
'define getChildContext() on StatelessComponentWithChildContext or remove ' +
|
||||
'childContextTypes from it.'
|
||||
'but there is no getChildContext() method on the instance. You can either ' +
|
||||
'define getChildContext() on StatelessComponentWithChildContext or remove ' +
|
||||
'childContextTypes from it.',
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -150,19 +150,18 @@ describe('ReactStatelessComponent', () => {
|
||||
ReactTestUtils.renderIntoDocument(<div><NotAComponent /></div>);
|
||||
}).toThrowError(
|
||||
'NotAComponent(...): A valid React element (or null) must be returned. ' +
|
||||
'You may have returned undefined, an array or some other invalid object.'
|
||||
'You may have returned undefined, an array or some other invalid object.',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
it('should throw when stateless component returns undefined', () => {
|
||||
function NotAComponent() {
|
||||
}
|
||||
function NotAComponent() {}
|
||||
expect(function() {
|
||||
ReactTestUtils.renderIntoDocument(<div><NotAComponent /></div>);
|
||||
}).toThrowError(
|
||||
'NotAComponent(...): A valid React element (or null) must be returned. ' +
|
||||
'You may have returned undefined, an array or some other invalid object.'
|
||||
'You may have returned undefined, an array or some other invalid object.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -173,9 +172,7 @@ describe('ReactStatelessComponent', () => {
|
||||
|
||||
expect(function() {
|
||||
ReactTestUtils.renderIntoDocument(<Child test="test" />);
|
||||
}).toThrowError(
|
||||
'Stateless function components cannot have refs.'
|
||||
);
|
||||
}).toThrowError('Stateless function components cannot have refs.');
|
||||
});
|
||||
|
||||
it('should warn when given a string ref', () => {
|
||||
@@ -199,12 +196,12 @@ describe('ReactStatelessComponent', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
|
||||
'Warning: Stateless function components cannot be given refs. ' +
|
||||
'Attempts to access this ref will fail.\n\nCheck the render method ' +
|
||||
'of `ParentUsingStringRef`.\n' +
|
||||
' in StatelessComponent (at **)\n' +
|
||||
' in div (at **)\n' +
|
||||
' in Indirection (at **)\n' +
|
||||
' in ParentUsingStringRef (at **)'
|
||||
'Attempts to access this ref will fail.\n\nCheck the render method ' +
|
||||
'of `ParentUsingStringRef`.\n' +
|
||||
' in StatelessComponent (at **)\n' +
|
||||
' in div (at **)\n' +
|
||||
' in Indirection (at **)\n' +
|
||||
' in ParentUsingStringRef (at **)',
|
||||
);
|
||||
|
||||
ReactTestUtils.renderIntoDocument(<ParentUsingStringRef />);
|
||||
@@ -222,9 +219,12 @@ describe('ReactStatelessComponent', () => {
|
||||
render() {
|
||||
return (
|
||||
<Indirection>
|
||||
<StatelessComponent name="A" ref={(arg) => {
|
||||
expect(arg).toBe(null);
|
||||
}} />
|
||||
<StatelessComponent
|
||||
name="A"
|
||||
ref={arg => {
|
||||
expect(arg).toBe(null);
|
||||
}}
|
||||
/>
|
||||
</Indirection>
|
||||
);
|
||||
}
|
||||
@@ -234,12 +234,12 @@ describe('ReactStatelessComponent', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
|
||||
'Warning: Stateless function components cannot be given refs. ' +
|
||||
'Attempts to access this ref will fail.\n\nCheck the render method ' +
|
||||
'of `ParentUsingFunctionRef`.\n' +
|
||||
' in StatelessComponent (at **)\n' +
|
||||
' in div (at **)\n' +
|
||||
' in Indirection (at **)\n' +
|
||||
' in ParentUsingFunctionRef (at **)'
|
||||
'Attempts to access this ref will fail.\n\nCheck the render method ' +
|
||||
'of `ParentUsingFunctionRef`.\n' +
|
||||
' in StatelessComponent (at **)\n' +
|
||||
' in div (at **)\n' +
|
||||
' in Indirection (at **)\n' +
|
||||
' in ParentUsingFunctionRef (at **)',
|
||||
);
|
||||
|
||||
ReactTestUtils.renderIntoDocument(<ParentUsingFunctionRef />);
|
||||
@@ -258,10 +258,12 @@ describe('ReactStatelessComponent', () => {
|
||||
return <StatelessComponent name="A" ref={() => {}} />;
|
||||
},
|
||||
});
|
||||
const instance1 = ReactTestUtils.renderIntoDocument(<AnonymousParentUsingJSX />);
|
||||
const instance1 = ReactTestUtils.renderIntoDocument(
|
||||
<AnonymousParentUsingJSX />,
|
||||
);
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Warning: Stateless function components cannot be given refs.'
|
||||
'Warning: Stateless function components cannot be given refs.',
|
||||
);
|
||||
// Should be deduped (offending element is on the same line):
|
||||
instance1.forceUpdate();
|
||||
@@ -273,13 +275,18 @@ describe('ReactStatelessComponent', () => {
|
||||
// When owner doesn't use JSX, and is anonymous, we warn once per internal instance.
|
||||
var AnonymousParentNotUsingJSX = createClassWithoutDisplayName({
|
||||
render() {
|
||||
return React.createElement(StatelessComponent, {name: 'A', 'ref': () => {}});
|
||||
return React.createElement(StatelessComponent, {
|
||||
name: 'A',
|
||||
ref: () => {},
|
||||
});
|
||||
},
|
||||
});
|
||||
const instance2 = ReactTestUtils.renderIntoDocument(<AnonymousParentNotUsingJSX />);
|
||||
const instance2 = ReactTestUtils.renderIntoDocument(
|
||||
<AnonymousParentNotUsingJSX />,
|
||||
);
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Warning: Stateless function components cannot be given refs.'
|
||||
'Warning: Stateless function components cannot be given refs.',
|
||||
);
|
||||
// Should be deduped (same internal instance):
|
||||
instance2.forceUpdate();
|
||||
@@ -288,20 +295,25 @@ describe('ReactStatelessComponent', () => {
|
||||
ReactTestUtils.renderIntoDocument(<AnonymousParentNotUsingJSX />);
|
||||
expectDev(console.error.calls.count()).toBe(2);
|
||||
expectDev(console.error.calls.argsFor(1)[0]).toContain(
|
||||
'Warning: Stateless function components cannot be given refs.'
|
||||
'Warning: Stateless function components cannot be given refs.',
|
||||
);
|
||||
console.error.calls.reset();
|
||||
|
||||
// When owner doesn't use JSX, but is named, we warn once per owner name
|
||||
class NamedParentNotUsingJSX extends React.Component {
|
||||
render() {
|
||||
return React.createElement(StatelessComponent, {name: 'A', 'ref': () => {}});
|
||||
return React.createElement(StatelessComponent, {
|
||||
name: 'A',
|
||||
ref: () => {},
|
||||
});
|
||||
}
|
||||
}
|
||||
const instance3 = ReactTestUtils.renderIntoDocument(<NamedParentNotUsingJSX />);
|
||||
const instance3 = ReactTestUtils.renderIntoDocument(
|
||||
<NamedParentNotUsingJSX />,
|
||||
);
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Warning: Stateless function components cannot be given refs.'
|
||||
'Warning: Stateless function components cannot be given refs.',
|
||||
);
|
||||
// Should be deduped (same owner name):
|
||||
instance3.forceUpdate();
|
||||
@@ -329,7 +341,9 @@ describe('ReactStatelessComponent', () => {
|
||||
spyOn(console, 'error');
|
||||
ReactTestUtils.renderIntoDocument(<Child />);
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain('a unique "key" prop');
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'a unique "key" prop',
|
||||
);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain('Child');
|
||||
});
|
||||
|
||||
@@ -344,11 +358,11 @@ describe('ReactStatelessComponent', () => {
|
||||
ReactTestUtils.renderIntoDocument(<Child />);
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expect(
|
||||
console.error.calls.argsFor(0)[0].replace(/\(at .+?:\d+\)/g, '(at **)')
|
||||
console.error.calls.argsFor(0)[0].replace(/\(at .+?:\d+\)/g, '(at **)'),
|
||||
).toBe(
|
||||
'Warning: Failed prop type: Invalid prop `test` of type `number` ' +
|
||||
'supplied to `Child`, expected `string`.\n' +
|
||||
' in Child (at **)'
|
||||
'supplied to `Child`, expected `string`.\n' +
|
||||
' in Child (at **)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -401,5 +415,4 @@ describe('ReactStatelessComponent', () => {
|
||||
}
|
||||
expect(() => ReactTestUtils.renderIntoDocument(<Child />)).not.toThrow();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -94,10 +94,7 @@ describe('ReactTreeTraversal', () => {
|
||||
it('should traverse two phase at shallowest node', () => {
|
||||
var parent = renderParentIntoDocument();
|
||||
var target = getInst(parent.refs.P);
|
||||
var expectedCalls = [
|
||||
['P', 'captured', ARG],
|
||||
['P', 'bubbled', ARG],
|
||||
];
|
||||
var expectedCalls = [['P', 'captured', ARG], ['P', 'bubbled', ARG]];
|
||||
ReactTreeTraversal.traverseTwoPhase(target, callback, ARG);
|
||||
expect(mockFn.mock.calls).toEqual(expectedCalls);
|
||||
});
|
||||
@@ -105,9 +102,7 @@ describe('ReactTreeTraversal', () => {
|
||||
|
||||
describe('traverseEnterLeave', () => {
|
||||
it('should not traverse when enter/leaving outside DOM', () => {
|
||||
ReactTreeTraversal.traverseEnterLeave(
|
||||
null, null, callback, ARG, ARG2
|
||||
);
|
||||
ReactTreeTraversal.traverseEnterLeave(null, null, callback, ARG, ARG2);
|
||||
expect(mockFn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -115,9 +110,7 @@ describe('ReactTreeTraversal', () => {
|
||||
var parent = renderParentIntoDocument();
|
||||
var leave = getInst(parent.refs.P_P1_C1.refs.DIV_1);
|
||||
var enter = getInst(parent.refs.P_P1_C1.refs.DIV_1);
|
||||
ReactTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, callback, ARG, ARG2
|
||||
);
|
||||
ReactTreeTraversal.traverseEnterLeave(leave, enter, callback, ARG, ARG2);
|
||||
expect(mockFn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -130,9 +123,7 @@ describe('ReactTreeTraversal', () => {
|
||||
// enter/leave shouldn't fire anything on the parent
|
||||
['P_P1_C1__DIV_2', 'captured', ARG2],
|
||||
];
|
||||
ReactTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, callback, ARG, ARG2
|
||||
);
|
||||
ReactTreeTraversal.traverseEnterLeave(leave, enter, callback, ARG, ARG2);
|
||||
expect(mockFn.mock.calls).toEqual(expectedCalls);
|
||||
});
|
||||
|
||||
@@ -140,12 +131,8 @@ describe('ReactTreeTraversal', () => {
|
||||
var parent = renderParentIntoDocument();
|
||||
var leave = getInst(parent.refs.P_P1_C1.refs.DIV_1);
|
||||
var enter = getInst(parent.refs.P_P1_C1.refs.DIV);
|
||||
var expectedCalls = [
|
||||
['P_P1_C1__DIV_1', 'bubbled', ARG],
|
||||
];
|
||||
ReactTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, callback, ARG, ARG2
|
||||
);
|
||||
var expectedCalls = [['P_P1_C1__DIV_1', 'bubbled', ARG]];
|
||||
ReactTreeTraversal.traverseEnterLeave(leave, enter, callback, ARG, ARG2);
|
||||
expect(mockFn.mock.calls).toEqual(expectedCalls);
|
||||
});
|
||||
|
||||
@@ -158,9 +145,7 @@ describe('ReactTreeTraversal', () => {
|
||||
['P_P1', 'captured', ARG2],
|
||||
['P_P1_C1__DIV', 'captured', ARG2],
|
||||
];
|
||||
ReactTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, callback, ARG, ARG2
|
||||
);
|
||||
ReactTreeTraversal.traverseEnterLeave(leave, enter, callback, ARG, ARG2);
|
||||
expect(mockFn.mock.calls).toEqual(expectedCalls);
|
||||
});
|
||||
|
||||
@@ -168,12 +153,8 @@ describe('ReactTreeTraversal', () => {
|
||||
var parent = renderParentIntoDocument();
|
||||
var leave = null; // From the window or outside of the React sandbox.
|
||||
var enter = getInst(parent.refs.P);
|
||||
var expectedCalls = [
|
||||
['P', 'captured', ARG2],
|
||||
];
|
||||
ReactTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, callback, ARG, ARG2
|
||||
);
|
||||
var expectedCalls = [['P', 'captured', ARG2]];
|
||||
ReactTreeTraversal.traverseEnterLeave(leave, enter, callback, ARG, ARG2);
|
||||
expect(mockFn.mock.calls).toEqual(expectedCalls);
|
||||
});
|
||||
|
||||
@@ -186,9 +167,7 @@ describe('ReactTreeTraversal', () => {
|
||||
['P_P1', 'bubbled', ARG],
|
||||
['P', 'bubbled', ARG],
|
||||
];
|
||||
ReactTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, callback, ARG, ARG2
|
||||
);
|
||||
ReactTreeTraversal.traverseEnterLeave(leave, enter, callback, ARG, ARG2);
|
||||
expect(mockFn.mock.calls).toEqual(expectedCalls);
|
||||
});
|
||||
|
||||
@@ -201,9 +180,7 @@ describe('ReactTreeTraversal', () => {
|
||||
['P_P1', 'bubbled', ARG],
|
||||
['P', 'bubbled', ARG],
|
||||
];
|
||||
ReactTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, callback, ARG, ARG2
|
||||
);
|
||||
ReactTreeTraversal.traverseEnterLeave(leave, enter, callback, ARG, ARG2);
|
||||
expect(mockFn.mock.calls).toEqual(expectedCalls);
|
||||
});
|
||||
});
|
||||
@@ -213,7 +190,8 @@ describe('ReactTreeTraversal', () => {
|
||||
var parent = renderParentIntoDocument();
|
||||
var ancestors = [
|
||||
// Common ancestor with self is self.
|
||||
{one: parent.refs.P_P1_C1.refs.DIV_1,
|
||||
{
|
||||
one: parent.refs.P_P1_C1.refs.DIV_1,
|
||||
two: parent.refs.P_P1_C1.refs.DIV_1,
|
||||
com: parent.refs.P_P1_C1.refs.DIV_1,
|
||||
},
|
||||
@@ -255,11 +233,10 @@ describe('ReactTreeTraversal', () => {
|
||||
var plan = ancestors[i];
|
||||
var firstCommon = ReactTreeTraversal.getLowestCommonAncestor(
|
||||
getInst(plan.one),
|
||||
getInst(plan.two)
|
||||
getInst(plan.two),
|
||||
);
|
||||
expect(firstCommon).toBe(getInst(plan.com));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -487,21 +487,21 @@ describe('ReactUpdates', () => {
|
||||
[root.refs.switcher.refs.box, root.refs.switcher],
|
||||
// Owner-child relationships have inverse will and did
|
||||
['Switcher', 'Box'],
|
||||
['Box', 'Switcher']
|
||||
['Box', 'Switcher'],
|
||||
);
|
||||
|
||||
testUpdates(
|
||||
[root.refs.child, root.refs.switcher.refs.box],
|
||||
// Not owner-child so reconcile independently
|
||||
['Box', 'Child'],
|
||||
['Box', 'Child']
|
||||
['Box', 'Child'],
|
||||
);
|
||||
|
||||
testUpdates(
|
||||
[root.refs.child, root.refs.switcher],
|
||||
// Switcher owns Box and Child, Box does not own Child
|
||||
['Switcher', 'Box', 'Child'],
|
||||
['Box', 'Switcher', 'Child']
|
||||
['Box', 'Switcher', 'Child'],
|
||||
);
|
||||
});
|
||||
|
||||
@@ -531,7 +531,7 @@ describe('ReactUpdates', () => {
|
||||
if (ReactDOMFeatureFlags.useFiber) {
|
||||
portal = ReactDOM.unstable_createPortal(
|
||||
<B ref={n => b = n} />,
|
||||
bContainer
|
||||
bContainer,
|
||||
);
|
||||
}
|
||||
return <div>A{this.state.x}{portal}</div>;
|
||||
@@ -607,31 +607,31 @@ describe('ReactUpdates', () => {
|
||||
/* eslint-disable indent */
|
||||
expect(updates).toEqual([
|
||||
'Outer-render-0',
|
||||
'Inner-render-0-0',
|
||||
'Inner-render-0-0',
|
||||
|
||||
'Outer-setState-1',
|
||||
'Outer-render-1',
|
||||
'Inner-render-1-0',
|
||||
'Inner-didUpdate-1-0',
|
||||
'Outer-didUpdate-1',
|
||||
// Happens in a batch, so don't re-render yet
|
||||
'Inner-setState-1',
|
||||
'Outer-callback-1',
|
||||
'Outer-render-1',
|
||||
'Inner-render-1-0',
|
||||
'Inner-didUpdate-1-0',
|
||||
'Outer-didUpdate-1',
|
||||
// Happens in a batch, so don't re-render yet
|
||||
'Inner-setState-1',
|
||||
'Outer-callback-1',
|
||||
|
||||
// Happens in a batch
|
||||
'Outer-setState-2',
|
||||
// Happens in a batch
|
||||
'Outer-setState-2',
|
||||
|
||||
// Flush batched updates all at once
|
||||
'Outer-render-2',
|
||||
'Inner-render-2-1',
|
||||
'Inner-didUpdate-2-1',
|
||||
'Inner-callback-1',
|
||||
'Outer-didUpdate-2',
|
||||
'Inner-setState-2',
|
||||
'Outer-callback-2',
|
||||
'Inner-render-2-2',
|
||||
'Inner-didUpdate-2-2',
|
||||
'Inner-callback-2',
|
||||
// Flush batched updates all at once
|
||||
'Outer-render-2',
|
||||
'Inner-render-2-1',
|
||||
'Inner-didUpdate-2-1',
|
||||
'Inner-callback-1',
|
||||
'Outer-didUpdate-2',
|
||||
'Inner-setState-2',
|
||||
'Outer-callback-2',
|
||||
'Inner-render-2-2',
|
||||
'Inner-didUpdate-2-2',
|
||||
'Inner-callback-2',
|
||||
]);
|
||||
/* eslint-enable indent */
|
||||
});
|
||||
@@ -654,7 +654,7 @@ describe('ReactUpdates', () => {
|
||||
depth={this.props.depth + 1}
|
||||
count={this.props.count}
|
||||
/>,
|
||||
ReactDOM.findDOMNode(this)
|
||||
ReactDOM.findDOMNode(this),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -761,7 +761,7 @@ describe('ReactUpdates', () => {
|
||||
<div>
|
||||
<A />
|
||||
<B />
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -886,29 +886,29 @@ describe('ReactUpdates', () => {
|
||||
|
||||
expect(() => component.setState({}, 'no')).toThrowError(
|
||||
'Invalid argument passed as callback. Expected a function. Instead ' +
|
||||
'received: no',
|
||||
'received: no',
|
||||
);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'setState(...): Expected the last optional `callback` argument to be ' +
|
||||
'a function. Instead received: no.'
|
||||
'a function. Instead received: no.',
|
||||
);
|
||||
component = ReactTestUtils.renderIntoDocument(<A />);
|
||||
expect(() => component.setState({}, {foo: 'bar'})).toThrowError(
|
||||
'Invalid argument passed as callback. Expected a function. Instead ' +
|
||||
'received: [object Object]',
|
||||
'received: [object Object]',
|
||||
);
|
||||
expectDev(console.error.calls.argsFor(1)[0]).toContain(
|
||||
'setState(...): Expected the last optional `callback` argument to be ' +
|
||||
'a function. Instead received: [object Object].'
|
||||
'a function. Instead received: [object Object].',
|
||||
);
|
||||
component = ReactTestUtils.renderIntoDocument(<A />);
|
||||
expect(() => component.setState({}, new Foo())).toThrowError(
|
||||
'Invalid argument passed as callback. Expected a function. Instead ' +
|
||||
'received: [object Object]',
|
||||
'received: [object Object]',
|
||||
);
|
||||
expectDev(console.error.calls.argsFor(2)[0]).toContain(
|
||||
'setState(...): Expected the last optional `callback` argument to be ' +
|
||||
'a function. Instead received: [object Object].'
|
||||
'a function. Instead received: [object Object].',
|
||||
);
|
||||
expect(console.error.calls.count()).toBe(3);
|
||||
});
|
||||
@@ -932,29 +932,29 @@ describe('ReactUpdates', () => {
|
||||
|
||||
expect(() => component.replaceState({}, 'no')).toThrowError(
|
||||
'Invalid argument passed as callback. Expected a function. Instead ' +
|
||||
'received: no',
|
||||
'received: no',
|
||||
);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'replaceState(...): Expected the last optional `callback` argument to be ' +
|
||||
'a function. Instead received: no.'
|
||||
'a function. Instead received: no.',
|
||||
);
|
||||
component = ReactTestUtils.renderIntoDocument(<A />);
|
||||
expect(() => component.replaceState({}, {foo: 'bar'})).toThrowError(
|
||||
'Invalid argument passed as callback. Expected a function. Instead ' +
|
||||
'received: [object Object]',
|
||||
'received: [object Object]',
|
||||
);
|
||||
expectDev(console.error.calls.argsFor(1)[0]).toContain(
|
||||
'replaceState(...): Expected the last optional `callback` argument to be ' +
|
||||
'a function. Instead received: [object Object].'
|
||||
'a function. Instead received: [object Object].',
|
||||
);
|
||||
component = ReactTestUtils.renderIntoDocument(<A />);
|
||||
expect(() => component.replaceState({}, new Foo())).toThrowError(
|
||||
'Invalid argument passed as callback. Expected a function. Instead ' +
|
||||
'received: [object Object]',
|
||||
'received: [object Object]',
|
||||
);
|
||||
expectDev(console.error.calls.argsFor(2)[0]).toContain(
|
||||
'replaceState(...): Expected the last optional `callback` argument to be ' +
|
||||
'a function. Instead received: [object Object].'
|
||||
'a function. Instead received: [object Object].',
|
||||
);
|
||||
expect(console.error.calls.count()).toBe(3);
|
||||
});
|
||||
@@ -979,29 +979,29 @@ describe('ReactUpdates', () => {
|
||||
|
||||
expect(() => component.forceUpdate('no')).toThrowError(
|
||||
'Invalid argument passed as callback. Expected a function. Instead ' +
|
||||
'received: no',
|
||||
'received: no',
|
||||
);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'forceUpdate(...): Expected the last optional `callback` argument to be ' +
|
||||
'a function. Instead received: no.'
|
||||
'a function. Instead received: no.',
|
||||
);
|
||||
component = ReactTestUtils.renderIntoDocument(<A />);
|
||||
expect(() => component.forceUpdate({foo: 'bar'})).toThrowError(
|
||||
'Invalid argument passed as callback. Expected a function. Instead ' +
|
||||
'received: [object Object]',
|
||||
'received: [object Object]',
|
||||
);
|
||||
expectDev(console.error.calls.argsFor(1)[0]).toContain(
|
||||
'forceUpdate(...): Expected the last optional `callback` argument to be ' +
|
||||
'a function. Instead received: [object Object].'
|
||||
'a function. Instead received: [object Object].',
|
||||
);
|
||||
component = ReactTestUtils.renderIntoDocument(<A />);
|
||||
expect(() => component.forceUpdate(new Foo())).toThrowError(
|
||||
'Invalid argument passed as callback. Expected a function. Instead ' +
|
||||
'received: [object Object]',
|
||||
'received: [object Object]',
|
||||
);
|
||||
expectDev(console.error.calls.argsFor(2)[0]).toContain(
|
||||
'forceUpdate(...): Expected the last optional `callback` argument to be ' +
|
||||
'a function. Instead received: [object Object].'
|
||||
'a function. Instead received: [object Object].',
|
||||
);
|
||||
expect(console.error.calls.count()).toBe(3);
|
||||
});
|
||||
@@ -1065,10 +1065,10 @@ describe('ReactUpdates', () => {
|
||||
class App extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { showChild: true };
|
||||
this.state = {showChild: true};
|
||||
}
|
||||
componentDidMount() {
|
||||
this.setState({ showChild: false });
|
||||
this.setState({showChild: false});
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
@@ -1096,7 +1096,7 @@ describe('ReactUpdates', () => {
|
||||
callbacks.push(this.onChange);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
callbacks = callbacks.filter((c) => c !== this.onChange);
|
||||
callbacks = callbacks.filter(c => c !== this.onChange);
|
||||
}
|
||||
render() {
|
||||
return <div key={Math.random()} onClick={function() {}} />;
|
||||
@@ -1142,13 +1142,13 @@ describe('ReactUpdates', () => {
|
||||
function render() {
|
||||
ReactDOM.render(
|
||||
<Editor
|
||||
onChange={(newProps) => {
|
||||
onChange={newProps => {
|
||||
props = {...props, ...newProps};
|
||||
render();
|
||||
}}
|
||||
{...props}
|
||||
/>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,11 +29,11 @@ describe('refs-destruction', () => {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{this.props.destroy ? null :
|
||||
<div ref="theInnerDiv">
|
||||
Lets try to destroy this.
|
||||
</div>
|
||||
}
|
||||
{this.props.destroy
|
||||
? null
|
||||
: <div ref="theInnerDiv">
|
||||
Lets try to destroy this.
|
||||
</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -43,36 +43,38 @@ describe('refs-destruction', () => {
|
||||
it('should remove refs when destroying the parent', () => {
|
||||
var container = document.createElement('div');
|
||||
var testInstance = ReactDOM.render(<TestComponent />, container);
|
||||
expect(ReactTestUtils.isDOMComponent(testInstance.refs.theInnerDiv))
|
||||
.toBe(true);
|
||||
expect(ReactTestUtils.isDOMComponent(testInstance.refs.theInnerDiv)).toBe(
|
||||
true,
|
||||
);
|
||||
expect(
|
||||
Object.keys(testInstance.refs || {})
|
||||
.filter(key => testInstance.refs[key])
|
||||
.length
|
||||
Object.keys(testInstance.refs || {}).filter(
|
||||
key => testInstance.refs[key],
|
||||
).length,
|
||||
).toEqual(1);
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
expect(
|
||||
Object.keys(testInstance.refs || {})
|
||||
.filter(key => testInstance.refs[key])
|
||||
.length
|
||||
Object.keys(testInstance.refs || {}).filter(
|
||||
key => testInstance.refs[key],
|
||||
).length,
|
||||
).toEqual(0);
|
||||
});
|
||||
|
||||
it('should remove refs when destroying the child', () => {
|
||||
var container = document.createElement('div');
|
||||
var testInstance = ReactDOM.render(<TestComponent />, container);
|
||||
expect(ReactTestUtils.isDOMComponent(testInstance.refs.theInnerDiv))
|
||||
.toBe(true);
|
||||
expect(ReactTestUtils.isDOMComponent(testInstance.refs.theInnerDiv)).toBe(
|
||||
true,
|
||||
);
|
||||
expect(
|
||||
Object.keys(testInstance.refs || {})
|
||||
.filter(key => testInstance.refs[key])
|
||||
.length
|
||||
Object.keys(testInstance.refs || {}).filter(
|
||||
key => testInstance.refs[key],
|
||||
).length,
|
||||
).toEqual(1);
|
||||
ReactDOM.render(<TestComponent destroy={true} />, container);
|
||||
expect(
|
||||
Object.keys(testInstance.refs || {})
|
||||
.filter(key => testInstance.refs[key])
|
||||
.length
|
||||
Object.keys(testInstance.refs || {}).filter(
|
||||
key => testInstance.refs[key],
|
||||
).length,
|
||||
).toEqual(0);
|
||||
});
|
||||
|
||||
@@ -91,12 +93,15 @@ describe('refs-destruction', () => {
|
||||
componentWillUnmount() {
|
||||
var self = this;
|
||||
// some async animation
|
||||
setTimeout(function() {
|
||||
expect(function() {
|
||||
ReactDOM.unmountComponentAtNode(self.div);
|
||||
}).not.toThrow();
|
||||
document.body.removeChild(self.div);
|
||||
}, 0);
|
||||
setTimeout(
|
||||
function() {
|
||||
expect(function() {
|
||||
ReactDOM.unmountComponentAtNode(self.div);
|
||||
}).not.toThrow();
|
||||
document.body.removeChild(self.div);
|
||||
},
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -106,9 +111,11 @@ describe('refs-destruction', () => {
|
||||
|
||||
class AppModal extends React.Component {
|
||||
render() {
|
||||
return (<Modal>
|
||||
<a ref="ref" />
|
||||
</Modal>);
|
||||
return (
|
||||
<Modal>
|
||||
<a ref="ref" />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ class ClickCounter extends React.Component {
|
||||
className="clickLogDiv"
|
||||
key={'clickLog' + i}
|
||||
ref={'clickLog' + i}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
}
|
||||
return (
|
||||
@@ -88,8 +88,9 @@ class TestRefsComponent extends React.Component {
|
||||
* Render a TestRefsComponent and ensure that the main refs are wired up.
|
||||
*/
|
||||
var renderTestRefsComponent = function() {
|
||||
var testRefsComponent =
|
||||
ReactTestUtils.renderIntoDocument(<TestRefsComponent />);
|
||||
var testRefsComponent = ReactTestUtils.renderIntoDocument(
|
||||
<TestRefsComponent />,
|
||||
);
|
||||
expect(testRefsComponent instanceof TestRefsComponent).toBe(true);
|
||||
|
||||
var generalContainer = testRefsComponent.refs.myContainer;
|
||||
@@ -101,10 +102,11 @@ var renderTestRefsComponent = function() {
|
||||
return testRefsComponent;
|
||||
};
|
||||
|
||||
|
||||
var expectClickLogsLengthToBe = function(instance, length) {
|
||||
var clickLogs =
|
||||
ReactTestUtils.scryRenderedDOMComponentsWithClass(instance, 'clickLogDiv');
|
||||
var clickLogs = ReactTestUtils.scryRenderedDOMComponentsWithClass(
|
||||
instance,
|
||||
'clickLogDiv',
|
||||
);
|
||||
expect(clickLogs.length).toBe(length);
|
||||
expect(Object.keys(instance.refs.myCounter.refs).length).toBe(length);
|
||||
};
|
||||
@@ -122,11 +124,10 @@ describe('reactiverefs', () => {
|
||||
*/
|
||||
it('Should increase refs with an increase in divs', () => {
|
||||
var testRefsComponent = renderTestRefsComponent();
|
||||
var clickIncrementer =
|
||||
ReactTestUtils.findRenderedDOMComponentWithClass(
|
||||
testRefsComponent,
|
||||
'clickIncrementer'
|
||||
);
|
||||
var clickIncrementer = ReactTestUtils.findRenderedDOMComponentWithClass(
|
||||
testRefsComponent,
|
||||
'clickIncrementer',
|
||||
);
|
||||
|
||||
expectClickLogsLengthToBe(testRefsComponent, 1);
|
||||
|
||||
@@ -210,12 +211,18 @@ describe('ref swapping', () => {
|
||||
it('Allow refs to hop around children correctly', () => {
|
||||
var refHopsAround = ReactTestUtils.renderIntoDocument(<RefHopsAround />);
|
||||
|
||||
var firstDiv =
|
||||
ReactTestUtils.findRenderedDOMComponentWithClass(refHopsAround, 'first');
|
||||
var secondDiv =
|
||||
ReactTestUtils.findRenderedDOMComponentWithClass(refHopsAround, 'second');
|
||||
var thirdDiv =
|
||||
ReactTestUtils.findRenderedDOMComponentWithClass(refHopsAround, 'third');
|
||||
var firstDiv = ReactTestUtils.findRenderedDOMComponentWithClass(
|
||||
refHopsAround,
|
||||
'first',
|
||||
);
|
||||
var secondDiv = ReactTestUtils.findRenderedDOMComponentWithClass(
|
||||
refHopsAround,
|
||||
'second',
|
||||
);
|
||||
var thirdDiv = ReactTestUtils.findRenderedDOMComponentWithClass(
|
||||
refHopsAround,
|
||||
'third',
|
||||
);
|
||||
|
||||
expect(refHopsAround.refs.hopRef).toEqual(firstDiv);
|
||||
expect(refHopsAround.refs.divTwoRef).toEqual(secondDiv);
|
||||
@@ -241,7 +248,6 @@ describe('ref swapping', () => {
|
||||
expect(refHopsAround.refs.divThreeRef).toEqual(thirdDiv);
|
||||
});
|
||||
|
||||
|
||||
it('always has a value for this.refs', () => {
|
||||
class Component extends React.Component {
|
||||
render() {
|
||||
@@ -329,11 +335,11 @@ describe('string refs between fiber and stack', () => {
|
||||
ReactDOM.unstable_renderSubtreeIntoContainer(
|
||||
this,
|
||||
span,
|
||||
this._container = document.createElement('div'),
|
||||
(this._container = document.createElement('div')),
|
||||
() => {
|
||||
expect(this.refs.span.nodeName).toBe('SPAN');
|
||||
layerMounted = true;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
@@ -350,8 +356,8 @@ describe('string refs between fiber and stack', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: You are using React DOM Fiber which is an experimental ' +
|
||||
'renderer. It is likely to have bugs, breaking changes and is ' +
|
||||
'unsupported.'
|
||||
'renderer. It is likely to have bugs, breaking changes and is ' +
|
||||
'unsupported.',
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -376,11 +382,11 @@ describe('string refs between fiber and stack', () => {
|
||||
ReactDOMFiber.unstable_renderSubtreeIntoContainer(
|
||||
this,
|
||||
span,
|
||||
this._container = document.createElement('div'),
|
||||
(this._container = document.createElement('div')),
|
||||
() => {
|
||||
expect(this.refs.span.nodeName).toBe('SPAN');
|
||||
layerMounted = true;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
@@ -397,8 +403,8 @@ describe('string refs between fiber and stack', () => {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: You are using React DOM Fiber which is an experimental ' +
|
||||
'renderer. It is likely to have bugs, breaking changes and is ' +
|
||||
'unsupported.'
|
||||
'renderer. It is likely to have bugs, breaking changes and is ' +
|
||||
'unsupported.',
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -23,7 +23,7 @@ const React = require('react');
|
||||
const ReactFiberReconciler = require('ReactFiberReconciler');
|
||||
const ReactDOMFrameScheduling = require('ReactDOMFrameScheduling');
|
||||
|
||||
const { Component } = React;
|
||||
const {Component} = React;
|
||||
|
||||
const pooledTransform = new Transform();
|
||||
|
||||
@@ -133,19 +133,14 @@ function getScaleY(props) {
|
||||
function isSameFont(oldFont, newFont) {
|
||||
if (oldFont === newFont) {
|
||||
return true;
|
||||
} else if (
|
||||
typeof newFont === 'string' ||
|
||||
typeof oldFont === 'string'
|
||||
) {
|
||||
} else if (typeof newFont === 'string' || typeof oldFont === 'string') {
|
||||
return false;
|
||||
} else {
|
||||
return (
|
||||
newFont.fontSize === oldFont.fontSize &&
|
||||
return newFont.fontSize === oldFont.fontSize &&
|
||||
newFont.fontStyle === oldFont.fontStyle &&
|
||||
newFont.fontVariant === oldFont.fontVariant &&
|
||||
newFont.fontWeight === oldFont.fontWeight &&
|
||||
newFont.fontFamily === oldFont.fontFamily
|
||||
);
|
||||
newFont.fontFamily === oldFont.fontFamily;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,24 +175,21 @@ function applyNodeProps(instance, props, prevProps = {}) {
|
||||
}
|
||||
|
||||
if (
|
||||
instance.xx !== pooledTransform.xx || instance.yx !== pooledTransform.yx ||
|
||||
instance.xy !== pooledTransform.xy || instance.yy !== pooledTransform.yy ||
|
||||
instance.x !== pooledTransform.x || instance.y !== pooledTransform.y
|
||||
instance.xx !== pooledTransform.xx ||
|
||||
instance.yx !== pooledTransform.yx ||
|
||||
instance.xy !== pooledTransform.xy ||
|
||||
instance.yy !== pooledTransform.yy ||
|
||||
instance.x !== pooledTransform.x ||
|
||||
instance.y !== pooledTransform.y
|
||||
) {
|
||||
instance.transformTo(pooledTransform);
|
||||
}
|
||||
|
||||
if (
|
||||
props.cursor !== prevProps.cursor ||
|
||||
props.title !== prevProps.title
|
||||
) {
|
||||
if (props.cursor !== prevProps.cursor || props.title !== prevProps.title) {
|
||||
instance.indicate(props.cursor, props.title);
|
||||
}
|
||||
|
||||
if (
|
||||
instance.blend &&
|
||||
props.opacity !== prevProps.opacity
|
||||
) {
|
||||
if (instance.blend && props.opacity !== prevProps.opacity) {
|
||||
instance.blend(props.opacity == null ? 1 : props.opacity);
|
||||
}
|
||||
|
||||
@@ -256,11 +248,7 @@ function applyShapeProps(instance, props, prevProps = {}) {
|
||||
prevProps.height !== props.height ||
|
||||
prevProps.width !== props.width
|
||||
) {
|
||||
instance.draw(
|
||||
path,
|
||||
props.width,
|
||||
props.height,
|
||||
);
|
||||
instance.draw(path, props.width, props.height);
|
||||
|
||||
instance._prevDelta = path.delta;
|
||||
instance._prevPath = path;
|
||||
@@ -278,12 +266,7 @@ function applyTextProps(instance, props, prevProps = {}) {
|
||||
props.alignment !== prevProps.alignment ||
|
||||
props.path !== prevProps.path
|
||||
) {
|
||||
instance.draw(
|
||||
string,
|
||||
props.font,
|
||||
props.alignment,
|
||||
props.path,
|
||||
);
|
||||
instance.draw(string, props.font, props.alignment, props.path);
|
||||
|
||||
instance._currentString = string;
|
||||
}
|
||||
@@ -327,33 +310,22 @@ class Pattern {
|
||||
|
||||
class Surface extends Component {
|
||||
componentDidMount() {
|
||||
const { height, width } = this.props;
|
||||
const {height, width} = this.props;
|
||||
|
||||
this._surface = Mode.Surface(+width, +height, this._tagRef);
|
||||
|
||||
this._mountNode = ARTRenderer.createContainer(this._surface);
|
||||
ARTRenderer.updateContainer(
|
||||
this.props.children,
|
||||
this._mountNode,
|
||||
this,
|
||||
);
|
||||
ARTRenderer.updateContainer(this.props.children, this._mountNode, this);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
const props = this.props;
|
||||
|
||||
if (
|
||||
props.height !== prevProps.height ||
|
||||
props.width !== prevProps.width
|
||||
) {
|
||||
if (props.height !== prevProps.height || props.width !== prevProps.width) {
|
||||
this._surface.resize(+props.width, +props.height);
|
||||
}
|
||||
|
||||
ARTRenderer.updateContainer(
|
||||
this.props.children,
|
||||
this._mountNode,
|
||||
this,
|
||||
);
|
||||
ARTRenderer.updateContainer(this.props.children, this._mountNode, this);
|
||||
|
||||
if (this._surface.render) {
|
||||
this._surface.render();
|
||||
@@ -361,11 +333,7 @@ class Surface extends Component {
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
ARTRenderer.updateContainer(
|
||||
null,
|
||||
this._mountNode,
|
||||
this,
|
||||
);
|
||||
ARTRenderer.updateContainer(null, this._mountNode, this);
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -475,7 +443,7 @@ const ARTRenderer = ReactFiberReconciler({
|
||||
insertBefore(parentInstance, child, beforeChild) {
|
||||
invariant(
|
||||
child !== beforeChild,
|
||||
'ReactART: Can not insert node before itself'
|
||||
'ReactART: Can not insert node before itself',
|
||||
);
|
||||
|
||||
child.injectBefore(beforeChild);
|
||||
@@ -520,10 +488,8 @@ const ARTRenderer = ReactFiberReconciler({
|
||||
scheduleDeferredCallback: ReactDOMFrameScheduling.rIC,
|
||||
|
||||
shouldSetTextContent(props) {
|
||||
return (
|
||||
typeof props.children === 'string' ||
|
||||
typeof props.children === 'number'
|
||||
);
|
||||
return typeof props.children === 'string' ||
|
||||
typeof props.children === 'number';
|
||||
},
|
||||
|
||||
useSyncScheduling: true,
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
'use strict';
|
||||
|
||||
require('art/modes/current').setCurrent(
|
||||
require('art/modes/fast-noSideEffects') // Flip this to DOM mode for debugging
|
||||
require('art/modes/fast-noSideEffects'), // Flip this to DOM mode for debugging
|
||||
);
|
||||
|
||||
const Transform = require('art/core/transform');
|
||||
@@ -67,8 +67,9 @@ function createComponent(name) {
|
||||
*/
|
||||
function injectAfter(parentNode, referenceNode, node) {
|
||||
let beforeNode;
|
||||
if (node.parentNode === parentNode &&
|
||||
node.previousSibling === referenceNode) {
|
||||
if (
|
||||
node.parentNode === parentNode && node.previousSibling === referenceNode
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (referenceNode == null) {
|
||||
@@ -83,7 +84,7 @@ function injectAfter(parentNode, referenceNode, node) {
|
||||
// checks and the behavior isn't well-defined.
|
||||
invariant(
|
||||
node !== beforeNode,
|
||||
'ReactART: Can not insert node before itself'
|
||||
'ReactART: Can not insert node before itself',
|
||||
);
|
||||
node.injectBefore(beforeNode);
|
||||
} else if (node.parentNode !== parentNode) {
|
||||
@@ -94,7 +95,6 @@ function injectAfter(parentNode, referenceNode, node) {
|
||||
// ContainerMixin for components that can hold ART nodes
|
||||
|
||||
const ContainerMixin = assign({}, ReactMultiChild, {
|
||||
|
||||
/**
|
||||
* Moves a child component to the supplied index.
|
||||
*
|
||||
@@ -153,11 +153,7 @@ const ContainerMixin = assign({}, ReactMultiChild, {
|
||||
// Shorthands
|
||||
|
||||
mountAndInjectChildren: function(children, transaction, context) {
|
||||
const mountedImages = this.mountChildren(
|
||||
children,
|
||||
transaction,
|
||||
context
|
||||
);
|
||||
const mountedImages = this.mountChildren(children, transaction, context);
|
||||
// Each mount image corresponds to one of the flattened children
|
||||
let i = 0;
|
||||
for (let key in this._renderedChildren) {
|
||||
@@ -168,15 +164,13 @@ const ContainerMixin = assign({}, ReactMultiChild, {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
// Surface is a React DOM Component, not an ART component. It serves as the
|
||||
// entry point into the ART reconciler.
|
||||
|
||||
const Surface = React.createClass({
|
||||
|
||||
displayName: 'Surface',
|
||||
|
||||
mixins: [ContainerMixin],
|
||||
@@ -192,15 +186,16 @@ const Surface = React.createClass({
|
||||
this,
|
||||
this.props.children,
|
||||
transaction,
|
||||
ReactInstanceMap.get(this)._context
|
||||
ReactInstanceMap.get(this)._context,
|
||||
);
|
||||
ReactUpdates.ReactReconcileTransaction.release(transaction);
|
||||
},
|
||||
|
||||
componentDidUpdate: function(oldProps) {
|
||||
const node = this.node;
|
||||
if (this.props.width != oldProps.width ||
|
||||
this.props.height != oldProps.height) {
|
||||
if (
|
||||
this.props.width != oldProps.width || this.props.height != oldProps.height
|
||||
) {
|
||||
node.resize(+this.props.width, +this.props.height);
|
||||
}
|
||||
|
||||
@@ -210,7 +205,7 @@ const Surface = React.createClass({
|
||||
this,
|
||||
this.props.children,
|
||||
transaction,
|
||||
ReactInstanceMap.get(this)._context
|
||||
ReactInstanceMap.get(this)._context,
|
||||
);
|
||||
ReactUpdates.ReactReconcileTransaction.release(transaction);
|
||||
|
||||
@@ -243,8 +238,7 @@ const Surface = React.createClass({
|
||||
title={props.title}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
// Various nodes that can go into a surface
|
||||
@@ -255,11 +249,10 @@ const EventTypes = {
|
||||
onMouseOut: 'mouseout',
|
||||
onMouseUp: 'mouseup',
|
||||
onMouseDown: 'mousedown',
|
||||
onClick: 'click'
|
||||
onClick: 'click',
|
||||
};
|
||||
|
||||
const NodeMixin = {
|
||||
|
||||
construct: function(element) {
|
||||
this._currentElement = element;
|
||||
},
|
||||
@@ -314,10 +307,12 @@ const NodeMixin = {
|
||||
applyNodeProps: function(oldProps, props) {
|
||||
const node = this.node;
|
||||
|
||||
const scaleX = props.scaleX != null ? props.scaleX :
|
||||
props.scale != null ? props.scale : 1;
|
||||
const scaleY = props.scaleY != null ? props.scaleY :
|
||||
props.scale != null ? props.scale : 1;
|
||||
const scaleX = props.scaleX != null
|
||||
? props.scaleX
|
||||
: props.scale != null ? props.scale : 1;
|
||||
const scaleY = props.scaleY != null
|
||||
? props.scaleY
|
||||
: props.scale != null ? props.scale : 1;
|
||||
|
||||
pooledTransform
|
||||
.transformTo(1, 0, 0, 1, 0, 0)
|
||||
@@ -329,9 +324,14 @@ const NodeMixin = {
|
||||
pooledTransform.transform(props.transform);
|
||||
}
|
||||
|
||||
if (node.xx !== pooledTransform.xx || node.yx !== pooledTransform.yx ||
|
||||
node.xy !== pooledTransform.xy || node.yy !== pooledTransform.yy ||
|
||||
node.x !== pooledTransform.x || node.y !== pooledTransform.y) {
|
||||
if (
|
||||
node.xx !== pooledTransform.xx ||
|
||||
node.yx !== pooledTransform.yx ||
|
||||
node.xy !== pooledTransform.xy ||
|
||||
node.yy !== pooledTransform.yy ||
|
||||
node.x !== pooledTransform.x ||
|
||||
node.y !== pooledTransform.y
|
||||
) {
|
||||
node.transformTo(pooledTransform);
|
||||
}
|
||||
|
||||
@@ -359,21 +359,19 @@ const NodeMixin = {
|
||||
mountComponentIntoNode: function(rootID, container) {
|
||||
throw new Error(
|
||||
'You cannot render an ART component standalone. ' +
|
||||
'You need to wrap it in a Surface.'
|
||||
'You need to wrap it in a Surface.',
|
||||
);
|
||||
}
|
||||
|
||||
},
|
||||
};
|
||||
|
||||
// Group
|
||||
|
||||
const Group = createComponent('Group', NodeMixin, ContainerMixin, {
|
||||
|
||||
mountComponent: function(
|
||||
transaction,
|
||||
nativeParent,
|
||||
nativeContainerInfo,
|
||||
context
|
||||
context,
|
||||
) {
|
||||
this.node = Mode.Group();
|
||||
const props = this._currentElement.props;
|
||||
@@ -399,55 +397,54 @@ const Group = createComponent('Group', NodeMixin, ContainerMixin, {
|
||||
unmountComponent: function() {
|
||||
this.destroyEventListeners();
|
||||
this.unmountChildren();
|
||||
}
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
// ClippingRectangle
|
||||
const ClippingRectangle = createComponent(
|
||||
'ClippingRectangle', NodeMixin, ContainerMixin, {
|
||||
'ClippingRectangle',
|
||||
NodeMixin,
|
||||
ContainerMixin,
|
||||
{
|
||||
mountComponent: function(
|
||||
transaction,
|
||||
nativeParent,
|
||||
nativeContainerInfo,
|
||||
context,
|
||||
) {
|
||||
this.node = Mode.ClippingRectangle();
|
||||
const props = this._currentElement.props;
|
||||
this.applyClippingProps(emptyObject, props);
|
||||
this.mountAndInjectChildren(props.children, transaction, context);
|
||||
return this.node;
|
||||
},
|
||||
|
||||
mountComponent: function(
|
||||
transaction,
|
||||
nativeParent,
|
||||
nativeContainerInfo,
|
||||
context
|
||||
) {
|
||||
this.node = Mode.ClippingRectangle();
|
||||
const props = this._currentElement.props;
|
||||
this.applyClippingProps(emptyObject, props);
|
||||
this.mountAndInjectChildren(props.children, transaction, context);
|
||||
return this.node;
|
||||
receiveComponent: function(nextComponent, transaction, context) {
|
||||
const props = nextComponent.props;
|
||||
const oldProps = this._currentElement.props;
|
||||
this.applyClippingProps(oldProps, props);
|
||||
this.updateChildren(props.children, transaction, context);
|
||||
this._currentElement = nextComponent;
|
||||
},
|
||||
|
||||
applyClippingProps: function(oldProps, props) {
|
||||
this.node.width = props.width;
|
||||
this.node.height = props.height;
|
||||
this.node.x = props.x;
|
||||
this.node.y = props.y;
|
||||
this.applyNodeProps(oldProps, props);
|
||||
},
|
||||
|
||||
unmountComponent: function() {
|
||||
this.destroyEventListeners();
|
||||
this.unmountChildren();
|
||||
},
|
||||
},
|
||||
|
||||
receiveComponent: function(nextComponent, transaction, context) {
|
||||
const props = nextComponent.props;
|
||||
const oldProps = this._currentElement.props;
|
||||
this.applyClippingProps(oldProps, props);
|
||||
this.updateChildren(props.children, transaction, context);
|
||||
this._currentElement = nextComponent;
|
||||
},
|
||||
|
||||
applyClippingProps: function(oldProps, props) {
|
||||
this.node.width = props.width;
|
||||
this.node.height = props.height;
|
||||
this.node.x = props.x;
|
||||
this.node.y = props.y;
|
||||
this.applyNodeProps(oldProps, props);
|
||||
},
|
||||
|
||||
unmountComponent: function() {
|
||||
this.destroyEventListeners();
|
||||
this.unmountChildren();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
);
|
||||
|
||||
// Renderables
|
||||
|
||||
const RenderableMixin = assign({}, NodeMixin, {
|
||||
|
||||
applyRenderableProps: function(oldProps, props) {
|
||||
if (oldProps.fill !== props.fill) {
|
||||
if (props.fill && props.fill.applyFill) {
|
||||
@@ -470,7 +467,7 @@ const RenderableMixin = assign({}, NodeMixin, {
|
||||
props.strokeWidth,
|
||||
props.strokeCap,
|
||||
props.strokeJoin,
|
||||
props.strokeDash
|
||||
props.strokeDash,
|
||||
);
|
||||
}
|
||||
this.applyNodeProps(oldProps, props);
|
||||
@@ -478,14 +475,12 @@ const RenderableMixin = assign({}, NodeMixin, {
|
||||
|
||||
unmountComponent: function() {
|
||||
this.destroyEventListeners();
|
||||
}
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
// Shape
|
||||
|
||||
const Shape = createComponent('Shape', RenderableMixin, {
|
||||
|
||||
construct: function(element) {
|
||||
this._currentElement = element;
|
||||
this._oldDelta = null;
|
||||
@@ -496,7 +491,7 @@ const Shape = createComponent('Shape', RenderableMixin, {
|
||||
transaction,
|
||||
nativeParent,
|
||||
nativeContainerInfo,
|
||||
context
|
||||
context,
|
||||
) {
|
||||
this.node = Mode.Shape();
|
||||
const props = this._currentElement.props;
|
||||
@@ -516,30 +511,25 @@ const Shape = createComponent('Shape', RenderableMixin, {
|
||||
const oldPath = this._oldPath;
|
||||
const path = props.d || childrenAsString(props.children);
|
||||
|
||||
if (path.delta !== oldDelta ||
|
||||
path !== oldPath ||
|
||||
oldProps.width !== props.width ||
|
||||
oldProps.height !== props.height) {
|
||||
|
||||
this.node.draw(
|
||||
path,
|
||||
props.width,
|
||||
props.height
|
||||
);
|
||||
if (
|
||||
path.delta !== oldDelta ||
|
||||
path !== oldPath ||
|
||||
oldProps.width !== props.width ||
|
||||
oldProps.height !== props.height
|
||||
) {
|
||||
this.node.draw(path, props.width, props.height);
|
||||
|
||||
this._oldPath = path;
|
||||
this._oldDelta = path.delta;
|
||||
}
|
||||
|
||||
this.applyRenderableProps(oldProps, props);
|
||||
}
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
// Text
|
||||
|
||||
const Text = createComponent('Text', RenderableMixin, {
|
||||
|
||||
construct: function(element) {
|
||||
this._currentElement = element;
|
||||
this._oldString = null;
|
||||
@@ -549,7 +539,7 @@ const Text = createComponent('Text', RenderableMixin, {
|
||||
transaction,
|
||||
nativeParent,
|
||||
nativeContainerInfo,
|
||||
context
|
||||
context,
|
||||
) {
|
||||
const props = this._currentElement.props;
|
||||
const newString = childrenAsString(props.children);
|
||||
@@ -566,13 +556,11 @@ const Text = createComponent('Text', RenderableMixin, {
|
||||
if (typeof newFont === 'string' || typeof oldFont === 'string') {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
newFont.fontSize === oldFont.fontSize &&
|
||||
return newFont.fontSize === oldFont.fontSize &&
|
||||
newFont.fontStyle === oldFont.fontStyle &&
|
||||
newFont.fontVariant === oldFont.fontVariant &&
|
||||
newFont.fontWeight === oldFont.fontWeight &&
|
||||
newFont.fontFamily === oldFont.fontFamily
|
||||
);
|
||||
newFont.fontFamily === oldFont.fontFamily;
|
||||
},
|
||||
|
||||
receiveComponent: function(nextComponent, transaction, context) {
|
||||
@@ -582,23 +570,19 @@ const Text = createComponent('Text', RenderableMixin, {
|
||||
const oldString = this._oldString;
|
||||
const newString = childrenAsString(props.children);
|
||||
|
||||
if (oldString !== newString ||
|
||||
!this.isSameFont(oldProps.font, props.font) ||
|
||||
oldProps.alignment !== props.alignment ||
|
||||
oldProps.path !== props.path) {
|
||||
this.node.draw(
|
||||
newString,
|
||||
props.font,
|
||||
props.alignment,
|
||||
props.path
|
||||
);
|
||||
if (
|
||||
oldString !== newString ||
|
||||
!this.isSameFont(oldProps.font, props.font) ||
|
||||
oldProps.alignment !== props.alignment ||
|
||||
oldProps.path !== props.path
|
||||
) {
|
||||
this.node.draw(newString, props.font, props.alignment, props.path);
|
||||
this._oldString = newString;
|
||||
}
|
||||
|
||||
this.applyRenderableProps(oldProps, props);
|
||||
this._currentElement = nextComponent;
|
||||
}
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
// Declarative fill type objects - API design not finalized
|
||||
|
||||
@@ -49,7 +49,6 @@ function testDOMNodeStructure(domNode, expectedStructure) {
|
||||
}
|
||||
|
||||
describe('ReactART', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
ARTCurrentMode.setCurrent(ARTSVGMode);
|
||||
|
||||
@@ -59,29 +58,33 @@ describe('ReactART', () => {
|
||||
|
||||
TestComponent = class extends React.Component {
|
||||
render() {
|
||||
|
||||
var a =
|
||||
var a = (
|
||||
<Shape
|
||||
d="M0,0l50,0l0,50l-50,0z"
|
||||
fill={new ReactART.LinearGradient(["black", "white"])}
|
||||
fill={new ReactART.LinearGradient(['black', 'white'])}
|
||||
key="a"
|
||||
width={50} height={50}
|
||||
x={50} y={50}
|
||||
width={50}
|
||||
height={50}
|
||||
x={50}
|
||||
y={50}
|
||||
opacity={0.1}
|
||||
/>;
|
||||
/>
|
||||
);
|
||||
|
||||
var b =
|
||||
var b = (
|
||||
<Shape
|
||||
fill="#3C5A99"
|
||||
key="b"
|
||||
scale={0.5}
|
||||
x={50} y={50}
|
||||
x={50}
|
||||
y={50}
|
||||
title="This is an F"
|
||||
cursor="pointer">
|
||||
M64.564,38.583H54l0.008-5.834c0-3.035,0.293-4.666,4.657-4.666
|
||||
h5.833V16.429h-9.33c-11.213,0-15.159,5.654-15.159,15.16v6.994
|
||||
h-6.99v11.652h6.99v33.815H54V50.235h9.331L64.564,38.583z
|
||||
</Shape>;
|
||||
</Shape>
|
||||
);
|
||||
|
||||
var c = <Group key="c" />;
|
||||
|
||||
@@ -113,22 +116,20 @@ describe('ReactART', () => {
|
||||
width: '150',
|
||||
height: '200',
|
||||
children: [
|
||||
{ nodeName: 'defs' },
|
||||
{nodeName: 'defs'},
|
||||
{
|
||||
nodeName: 'g',
|
||||
children: [
|
||||
{
|
||||
nodeName: 'defs',
|
||||
children: [
|
||||
{ nodeName: 'linearGradient' }
|
||||
]
|
||||
children: [{nodeName: 'linearGradient'}],
|
||||
},
|
||||
{ nodeName: 'path' },
|
||||
{ nodeName: 'path' },
|
||||
{ nodeName: 'g' }
|
||||
]
|
||||
}
|
||||
]
|
||||
{nodeName: 'path'},
|
||||
{nodeName: 'path'},
|
||||
{nodeName: 'g'},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
var realNode = ReactDOM.findDOMNode(instance);
|
||||
@@ -137,22 +138,25 @@ describe('ReactART', () => {
|
||||
|
||||
it('should be able to reorder components', () => {
|
||||
var container = document.createElement('div');
|
||||
var instance = ReactDOM.render(<TestComponent flipped={false} />, container);
|
||||
var instance = ReactDOM.render(
|
||||
<TestComponent flipped={false} />,
|
||||
container,
|
||||
);
|
||||
|
||||
var expectedStructure = {
|
||||
nodeName: 'svg',
|
||||
children: [
|
||||
{ nodeName: 'defs' },
|
||||
{nodeName: 'defs'},
|
||||
{
|
||||
nodeName: 'g',
|
||||
children: [
|
||||
{ nodeName: 'defs' },
|
||||
{ nodeName: 'path', opacity: '0.1' },
|
||||
{ nodeName: 'path', opacity: Missing },
|
||||
{ nodeName: 'g' }
|
||||
]
|
||||
}
|
||||
]
|
||||
{nodeName: 'defs'},
|
||||
{nodeName: 'path', opacity: '0.1'},
|
||||
{nodeName: 'path', opacity: Missing},
|
||||
{nodeName: 'g'},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
var realNode = ReactDOM.findDOMNode(instance);
|
||||
@@ -163,17 +167,17 @@ describe('ReactART', () => {
|
||||
var expectedNewStructure = {
|
||||
nodeName: 'svg',
|
||||
children: [
|
||||
{ nodeName: 'defs' },
|
||||
{nodeName: 'defs'},
|
||||
{
|
||||
nodeName: 'g',
|
||||
children: [
|
||||
{ nodeName: 'defs' },
|
||||
{ nodeName: 'path', opacity: Missing },
|
||||
{ nodeName: 'path', opacity: '0.1' },
|
||||
{ nodeName: 'g' }
|
||||
]
|
||||
}
|
||||
]
|
||||
{nodeName: 'defs'},
|
||||
{nodeName: 'path', opacity: Missing},
|
||||
{nodeName: 'path', opacity: '0.1'},
|
||||
{nodeName: 'g'},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
testDOMNodeStructure(realNode, expectedNewStructure);
|
||||
@@ -187,7 +191,7 @@ describe('ReactART', () => {
|
||||
var chars = this.props.chars.split('');
|
||||
return (
|
||||
<Surface>
|
||||
{chars.map((text) => <Shape key={text} title={text} />)}
|
||||
{chars.map(text => <Shape key={text} title={text} />)}
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
@@ -225,7 +229,7 @@ describe('ReactART', () => {
|
||||
<Group>
|
||||
<CustomShape />
|
||||
</Group>
|
||||
</Surface>
|
||||
</Surface>,
|
||||
);
|
||||
expect(mounted).toBe(true);
|
||||
});
|
||||
|
||||
@@ -44,11 +44,11 @@ var ReactDOM = {
|
||||
// Allows for debugging when the hook is injected on the page.
|
||||
if (
|
||||
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' &&
|
||||
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function') {
|
||||
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function'
|
||||
) {
|
||||
__REACT_DEVTOOLS_GLOBAL_HOOK__.inject({
|
||||
ComponentTree: {
|
||||
getClosestInstanceFromNode:
|
||||
ReactDOMComponentTree.getClosestInstanceFromNode,
|
||||
getClosestInstanceFromNode: ReactDOMComponentTree.getClosestInstanceFromNode,
|
||||
getNodeFromInstance: function(inst) {
|
||||
// inst is an internal instance (but could be a composite)
|
||||
if (inst._renderedComponent) {
|
||||
@@ -69,21 +69,24 @@ if (
|
||||
if (__DEV__) {
|
||||
var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment');
|
||||
if (ExecutionEnvironment.canUseDOM && window.top === window.self) {
|
||||
|
||||
// First check if devtools is not installed
|
||||
if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {
|
||||
// If we're in Chrome or Firefox, provide a download link if not installed.
|
||||
if ((navigator.userAgent.indexOf('Chrome') > -1 &&
|
||||
if (
|
||||
(navigator.userAgent.indexOf('Chrome') > -1 &&
|
||||
navigator.userAgent.indexOf('Edge') === -1) ||
|
||||
navigator.userAgent.indexOf('Firefox') > -1) {
|
||||
navigator.userAgent.indexOf('Firefox') > -1
|
||||
) {
|
||||
// Firefox does not have the issue with devtools loaded over file://
|
||||
var showFileUrlMessage = window.location.protocol.indexOf('http') === -1 &&
|
||||
navigator.userAgent.indexOf('Firefox') === -1;
|
||||
var showFileUrlMessage = window.location.protocol.indexOf('http') ===
|
||||
-1 && navigator.userAgent.indexOf('Firefox') === -1;
|
||||
console.debug(
|
||||
'Download the React DevTools ' +
|
||||
(showFileUrlMessage ? 'and use an HTTP server (instead of a file: URL) ' : '') +
|
||||
'for a better development experience: ' +
|
||||
'https://fb.me/react-devtools'
|
||||
(showFileUrlMessage
|
||||
? 'and use an HTTP server (instead of a file: URL) '
|
||||
: '') +
|
||||
'for a better development experience: ' +
|
||||
'https://fb.me/react-devtools',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -91,22 +94,22 @@ if (__DEV__) {
|
||||
var testFunc = function testFn() {};
|
||||
warning(
|
||||
(testFunc.name || testFunc.toString()).indexOf('testFn') !== -1,
|
||||
'It looks like you\'re using a minified copy of the development build ' +
|
||||
'of React. When deploying React apps to production, make sure to use ' +
|
||||
'the production build which skips development warnings and is faster. ' +
|
||||
'See https://fb.me/react-minification for more details.'
|
||||
"It looks like you're using a minified copy of the development build " +
|
||||
'of React. When deploying React apps to production, make sure to use ' +
|
||||
'the production build which skips development warnings and is faster. ' +
|
||||
'See https://fb.me/react-minification for more details.',
|
||||
);
|
||||
|
||||
// If we're in IE8, check to see if we are in compatibility mode and provide
|
||||
// information on preventing compatibility mode
|
||||
var ieCompatibilityMode =
|
||||
document.documentMode && document.documentMode < 8;
|
||||
var ieCompatibilityMode = document.documentMode &&
|
||||
document.documentMode < 8;
|
||||
|
||||
warning(
|
||||
!ieCompatibilityMode,
|
||||
'Internet Explorer is running in compatibility mode; please add the ' +
|
||||
'following tag to your HTML to prevent this from happening: ' +
|
||||
'<meta http-equiv="X-UA-Compatible" content="IE=edge" />'
|
||||
'following tag to your HTML to prevent this from happening: ' +
|
||||
'<meta http-equiv="X-UA-Compatible" content="IE=edge" />',
|
||||
);
|
||||
|
||||
var expectedFeatures = [
|
||||
@@ -127,7 +130,7 @@ if (__DEV__) {
|
||||
warning(
|
||||
false,
|
||||
'One or more ES5 shims expected by React are not available: ' +
|
||||
'https://fb.me/react-warning-polyfills'
|
||||
'https://fb.me/react-warning-polyfills',
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -13,5 +13,6 @@ var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
|
||||
|
||||
var useFiber = ReactDOMFeatureFlags.useFiber;
|
||||
|
||||
module.exports =
|
||||
useFiber ? require('ReactDOMFiber') : require.requireActual('ReactDOM');
|
||||
module.exports = useFiber
|
||||
? require('ReactDOMFiber')
|
||||
: require.requireActual('ReactDOM');
|
||||
|
||||
@@ -69,7 +69,7 @@ describe('ReactDOMProduction', () => {
|
||||
<Component key={2}>B</Component>
|
||||
<Component key={3}>C</Component>
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
|
||||
expect(container.firstChild).toBe(inst);
|
||||
@@ -82,7 +82,7 @@ describe('ReactDOMProduction', () => {
|
||||
<Component key={1}>A</Component>
|
||||
<Component key={3}>C</Component>
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
|
||||
expect(inst.className).toBe('red');
|
||||
@@ -126,10 +126,7 @@ describe('ReactDOMProduction', () => {
|
||||
}
|
||||
|
||||
var container = document.createElement('div');
|
||||
var inst = ReactDOM.render(
|
||||
<Component x={1} />,
|
||||
container
|
||||
);
|
||||
var inst = ReactDOM.render(<Component x={1} />, container);
|
||||
expect(log).toEqual([
|
||||
['componentWillMount'],
|
||||
['render'],
|
||||
@@ -147,15 +144,10 @@ describe('ReactDOMProduction', () => {
|
||||
log = [];
|
||||
|
||||
inst.setState({y: 2});
|
||||
expect(log).toEqual([
|
||||
['shouldComponentUpdate', {x: 1}, {y: 2}],
|
||||
]);
|
||||
expect(log).toEqual([['shouldComponentUpdate', {x: 1}, {y: 2}]]);
|
||||
log = [];
|
||||
|
||||
ReactDOM.render(
|
||||
<Component x={2} />,
|
||||
container
|
||||
);
|
||||
ReactDOM.render(<Component x={2} />, container);
|
||||
expect(log).toEqual([
|
||||
['componentWillReceiveProps', {x: 2}],
|
||||
['shouldComponentUpdate', {x: 2}, {y: 2}],
|
||||
@@ -165,10 +157,7 @@ describe('ReactDOMProduction', () => {
|
||||
]);
|
||||
log = [];
|
||||
|
||||
ReactDOM.render(
|
||||
<Component x={2} />,
|
||||
container
|
||||
);
|
||||
ReactDOM.render(<Component x={2} />, container);
|
||||
expect(log).toEqual([
|
||||
['componentWillReceiveProps', {x: 2}],
|
||||
['shouldComponentUpdate', {x: 2}, {y: 2}],
|
||||
@@ -176,9 +165,7 @@ describe('ReactDOMProduction', () => {
|
||||
log = [];
|
||||
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
expect(log).toEqual([
|
||||
['componentWillUnmount'],
|
||||
]);
|
||||
expect(log).toEqual([['componentWillUnmount']]);
|
||||
});
|
||||
|
||||
it('should throw with an error code in production', () => {
|
||||
@@ -193,9 +180,9 @@ describe('ReactDOMProduction', () => {
|
||||
ReactDOM.render(<Component />, container);
|
||||
}).toThrowError(
|
||||
'Minified React error #109; visit ' +
|
||||
'http://facebook.github.io/react/docs/error-decoder.html?invariant=109&args[]=Component' +
|
||||
' for the full message or use the non-minified dev environment' +
|
||||
' for full errors and additional helpful warnings.'
|
||||
'http://facebook.github.io/react/docs/error-decoder.html?invariant=109&args[]=Component' +
|
||||
' for the full message or use the non-minified dev environment' +
|
||||
' for full errors and additional helpful warnings.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -232,7 +219,7 @@ describe('ReactDOMProduction', () => {
|
||||
var usePortal = function(tree) {
|
||||
return ReactDOM.unstable_createPortal(
|
||||
tree,
|
||||
document.createElement('div')
|
||||
document.createElement('div'),
|
||||
);
|
||||
};
|
||||
var assertNamespacesMatch = function(tree) {
|
||||
@@ -266,14 +253,14 @@ describe('ReactDOMProduction', () => {
|
||||
{usePortal(<p {...expectHTML} />)}
|
||||
</svg>
|
||||
<image {...expectSVG} />
|
||||
</svg>
|
||||
</svg>,
|
||||
)}
|
||||
<p {...expectHTML} />
|
||||
</foreignObject>
|
||||
<image {...expectSVG} />
|
||||
</svg>
|
||||
<p {...expectHTML} />
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import type { Fiber } from 'ReactFiber';
|
||||
import type { ReactNodeList } from 'ReactTypes';
|
||||
import type {Fiber} from 'ReactFiber';
|
||||
import type {ReactNodeList} from 'ReactTypes';
|
||||
|
||||
var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
|
||||
var ReactControlledComponent = require('ReactControlledComponent');
|
||||
@@ -28,8 +28,8 @@ var ReactFiberReconciler = require('ReactFiberReconciler');
|
||||
var ReactInputSelection = require('ReactInputSelection');
|
||||
var ReactInstanceMap = require('ReactInstanceMap');
|
||||
var ReactPortal = require('ReactPortal');
|
||||
var { isValidElement } = require('react');
|
||||
var { injectInternals } = require('ReactFiberDevToolsHook');
|
||||
var {isValidElement} = require('react');
|
||||
var {injectInternals} = require('ReactFiberDevToolsHook');
|
||||
|
||||
var findDOMNode = require('findDOMNode');
|
||||
var invariant = require('fbjs/lib/invariant');
|
||||
@@ -49,40 +49,39 @@ var {
|
||||
|
||||
if (__DEV__) {
|
||||
var validateDOMNesting = require('validateDOMNesting');
|
||||
var { updatedAncestorInfo } = validateDOMNesting;
|
||||
var {updatedAncestorInfo} = validateDOMNesting;
|
||||
}
|
||||
|
||||
|
||||
const DOCUMENT_NODE = 9;
|
||||
|
||||
ReactDOMInjection.inject();
|
||||
ReactControlledComponent.injection.injectFiberControlledHostComponent(
|
||||
ReactDOMFiberComponent
|
||||
ReactDOMFiberComponent,
|
||||
);
|
||||
findDOMNode._injectFiber(function(fiber: Fiber) {
|
||||
return DOMRenderer.findHostInstance(fiber);
|
||||
});
|
||||
|
||||
type DOMContainerElement = Element & { _reactRootContainer: ?Object };
|
||||
type DOMContainerElement = Element & {_reactRootContainer: ?Object};
|
||||
|
||||
type Container = Element;
|
||||
type Props = {
|
||||
autoFocus ?: boolean,
|
||||
children ?: mixed,
|
||||
hidden ?: boolean,
|
||||
autoFocus?: boolean,
|
||||
children?: mixed,
|
||||
hidden?: boolean,
|
||||
};
|
||||
type Instance = Element;
|
||||
type TextInstance = Text;
|
||||
|
||||
type HostContextDev = {
|
||||
namespace : string,
|
||||
ancestorInfo : mixed,
|
||||
namespace: string,
|
||||
ancestorInfo: mixed,
|
||||
};
|
||||
type HostContextProd = string;
|
||||
type HostContext = HostContextDev | HostContextProd;
|
||||
|
||||
let eventsEnabled : ?boolean = null;
|
||||
let selectionInformation : ?mixed = null;
|
||||
let eventsEnabled: ?boolean = null;
|
||||
let selectionInformation: ?mixed = null;
|
||||
|
||||
var ELEMENT_NODE_TYPE = 1;
|
||||
var DOC_NODE_TYPE = 9;
|
||||
@@ -96,11 +95,10 @@ var DOCUMENT_FRAGMENT_NODE_TYPE = 11;
|
||||
* @internal
|
||||
*/
|
||||
function isValidContainer(node) {
|
||||
return !!(node && (
|
||||
node.nodeType === ELEMENT_NODE_TYPE ||
|
||||
node.nodeType === DOC_NODE_TYPE ||
|
||||
node.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE
|
||||
));
|
||||
return !!(node &&
|
||||
(node.nodeType === ELEMENT_NODE_TYPE ||
|
||||
node.nodeType === DOC_NODE_TYPE ||
|
||||
node.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE));
|
||||
}
|
||||
|
||||
function validateContainer(container) {
|
||||
@@ -109,7 +107,7 @@ function validateContainer(container) {
|
||||
}
|
||||
}
|
||||
|
||||
function getReactRootElementInContainer(container : any) {
|
||||
function getReactRootElementInContainer(container: any) {
|
||||
if (!container) {
|
||||
return null;
|
||||
}
|
||||
@@ -121,10 +119,7 @@ function getReactRootElementInContainer(container : any) {
|
||||
}
|
||||
}
|
||||
|
||||
function shouldAutoFocusHostComponent(
|
||||
type : string,
|
||||
props : Props,
|
||||
) : boolean {
|
||||
function shouldAutoFocusHostComponent(type: string, props: Props): boolean {
|
||||
switch (type) {
|
||||
case 'button':
|
||||
case 'input':
|
||||
@@ -136,14 +131,16 @@ function shouldAutoFocusHostComponent(
|
||||
}
|
||||
|
||||
var DOMRenderer = ReactFiberReconciler({
|
||||
|
||||
getRootHostContext(rootContainerInstance : Container) : HostContext {
|
||||
getRootHostContext(rootContainerInstance: Container): HostContext {
|
||||
const ownNamespace = rootContainerInstance.namespaceURI || null;
|
||||
const type = rootContainerInstance.tagName;
|
||||
const namespace = getChildNamespace(ownNamespace, type);
|
||||
if (__DEV__) {
|
||||
const isMountingIntoDocument = rootContainerInstance.ownerDocument.documentElement === rootContainerInstance;
|
||||
const validatedTag = isMountingIntoDocument ? '#document' : type.toLowerCase();
|
||||
const isMountingIntoDocument = rootContainerInstance.ownerDocument.documentElement ===
|
||||
rootContainerInstance;
|
||||
const validatedTag = isMountingIntoDocument
|
||||
? '#document'
|
||||
: type.toLowerCase();
|
||||
const ancestorInfo = updatedAncestorInfo(null, validatedTag, null);
|
||||
return {namespace, ancestorInfo};
|
||||
}
|
||||
@@ -151,16 +148,20 @@ var DOMRenderer = ReactFiberReconciler({
|
||||
},
|
||||
|
||||
getChildHostContext(
|
||||
parentHostContext : HostContext,
|
||||
type : string,
|
||||
) : HostContext {
|
||||
parentHostContext: HostContext,
|
||||
type: string,
|
||||
): HostContext {
|
||||
if (__DEV__) {
|
||||
const parentHostContextDev = ((parentHostContext : any) : HostContextDev);
|
||||
const parentHostContextDev = ((parentHostContext: any): HostContextDev);
|
||||
const namespace = getChildNamespace(parentHostContextDev.namespace, type);
|
||||
const ancestorInfo = updatedAncestorInfo(parentHostContextDev.ancestorInfo, type, null);
|
||||
const ancestorInfo = updatedAncestorInfo(
|
||||
parentHostContextDev.ancestorInfo,
|
||||
type,
|
||||
null,
|
||||
);
|
||||
return {namespace, ancestorInfo};
|
||||
}
|
||||
const parentNamespace = ((parentHostContext : any) : HostContextProd);
|
||||
const parentNamespace = ((parentHostContext: any): HostContextProd);
|
||||
return getChildNamespace(parentNamespace, type);
|
||||
},
|
||||
|
||||
@@ -168,13 +169,13 @@ var DOMRenderer = ReactFiberReconciler({
|
||||
return instance;
|
||||
},
|
||||
|
||||
prepareForCommit() : void {
|
||||
prepareForCommit(): void {
|
||||
eventsEnabled = ReactBrowserEventEmitter.isEnabled();
|
||||
selectionInformation = ReactInputSelection.getSelectionInformation();
|
||||
ReactBrowserEventEmitter.setEnabled(false);
|
||||
},
|
||||
|
||||
resetAfterCommit() : void {
|
||||
resetAfterCommit(): void {
|
||||
ReactInputSelection.restoreSelection(selectionInformation);
|
||||
selectionInformation = null;
|
||||
ReactBrowserEventEmitter.setEnabled(eventsEnabled);
|
||||
@@ -182,88 +183,114 @@ var DOMRenderer = ReactFiberReconciler({
|
||||
},
|
||||
|
||||
createInstance(
|
||||
type : string,
|
||||
props : Props,
|
||||
rootContainerInstance : Container,
|
||||
hostContext : HostContext,
|
||||
internalInstanceHandle : Object,
|
||||
) : Instance {
|
||||
let parentNamespace : string;
|
||||
type: string,
|
||||
props: Props,
|
||||
rootContainerInstance: Container,
|
||||
hostContext: HostContext,
|
||||
internalInstanceHandle: Object,
|
||||
): Instance {
|
||||
let parentNamespace: string;
|
||||
if (__DEV__) {
|
||||
// TODO: take namespace into account when validating.
|
||||
const hostContextDev = ((hostContext : any) : HostContextDev);
|
||||
const hostContextDev = ((hostContext: any): HostContextDev);
|
||||
validateDOMNesting(type, null, null, hostContextDev.ancestorInfo);
|
||||
if (
|
||||
typeof props.children === 'string' ||
|
||||
typeof props.children === 'number'
|
||||
typeof props.children === 'string' || typeof props.children === 'number'
|
||||
) {
|
||||
const string = '' + props.children;
|
||||
const ownAncestorInfo = updatedAncestorInfo(hostContextDev.ancestorInfo, type, null);
|
||||
const ownAncestorInfo = updatedAncestorInfo(
|
||||
hostContextDev.ancestorInfo,
|
||||
type,
|
||||
null,
|
||||
);
|
||||
validateDOMNesting(null, string, null, ownAncestorInfo);
|
||||
}
|
||||
parentNamespace = hostContextDev.namespace;
|
||||
} else {
|
||||
parentNamespace = ((hostContext : any) : HostContextProd);
|
||||
parentNamespace = ((hostContext: any): HostContextProd);
|
||||
}
|
||||
const domElement : Instance = createElement(type, props, rootContainerInstance, parentNamespace);
|
||||
const domElement: Instance = createElement(
|
||||
type,
|
||||
props,
|
||||
rootContainerInstance,
|
||||
parentNamespace,
|
||||
);
|
||||
precacheFiberNode(internalInstanceHandle, domElement);
|
||||
updateFiberProps(domElement, props);
|
||||
return domElement;
|
||||
},
|
||||
|
||||
appendInitialChild(parentInstance : Instance, child : Instance | TextInstance) : void {
|
||||
appendInitialChild(
|
||||
parentInstance: Instance,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
parentInstance.appendChild(child);
|
||||
},
|
||||
|
||||
finalizeInitialChildren(
|
||||
domElement : Instance,
|
||||
type : string,
|
||||
props : Props,
|
||||
rootContainerInstance : Container,
|
||||
) : boolean {
|
||||
domElement: Instance,
|
||||
type: string,
|
||||
props: Props,
|
||||
rootContainerInstance: Container,
|
||||
): boolean {
|
||||
setInitialProperties(domElement, type, props, rootContainerInstance);
|
||||
return shouldAutoFocusHostComponent(type, props);
|
||||
},
|
||||
|
||||
prepareUpdate(
|
||||
domElement : Instance,
|
||||
type : string,
|
||||
oldProps : Props,
|
||||
newProps : Props,
|
||||
rootContainerInstance : Container,
|
||||
hostContext : HostContext,
|
||||
) : null | Array<mixed> {
|
||||
domElement: Instance,
|
||||
type: string,
|
||||
oldProps: Props,
|
||||
newProps: Props,
|
||||
rootContainerInstance: Container,
|
||||
hostContext: HostContext,
|
||||
): null | Array<mixed> {
|
||||
if (__DEV__) {
|
||||
const hostContextDev = ((hostContext : any) : HostContextDev);
|
||||
if (typeof newProps.children !== typeof oldProps.children && (
|
||||
typeof newProps.children === 'string' ||
|
||||
typeof newProps.children === 'number'
|
||||
)) {
|
||||
const hostContextDev = ((hostContext: any): HostContextDev);
|
||||
if (
|
||||
typeof newProps.children !== typeof oldProps.children &&
|
||||
(typeof newProps.children === 'string' ||
|
||||
typeof newProps.children === 'number')
|
||||
) {
|
||||
const string = '' + newProps.children;
|
||||
const ownAncestorInfo = updatedAncestorInfo(hostContextDev.ancestorInfo, type, null);
|
||||
const ownAncestorInfo = updatedAncestorInfo(
|
||||
hostContextDev.ancestorInfo,
|
||||
type,
|
||||
null,
|
||||
);
|
||||
validateDOMNesting(null, string, null, ownAncestorInfo);
|
||||
}
|
||||
}
|
||||
return diffProperties(domElement, type, oldProps, newProps, rootContainerInstance);
|
||||
return diffProperties(
|
||||
domElement,
|
||||
type,
|
||||
oldProps,
|
||||
newProps,
|
||||
rootContainerInstance,
|
||||
);
|
||||
},
|
||||
|
||||
commitMount(
|
||||
domElement : Instance,
|
||||
type : string,
|
||||
newProps : Props,
|
||||
internalInstanceHandle : Object,
|
||||
) : void {
|
||||
((domElement : any) : HTMLButtonElement | HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement).focus();
|
||||
domElement: Instance,
|
||||
type: string,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
): void {
|
||||
((domElement: any):
|
||||
| HTMLButtonElement
|
||||
| HTMLInputElement
|
||||
| HTMLSelectElement
|
||||
| HTMLTextAreaElement).focus();
|
||||
},
|
||||
|
||||
commitUpdate(
|
||||
domElement : Instance,
|
||||
updatePayload : Array<mixed>,
|
||||
type : string,
|
||||
oldProps : Props,
|
||||
newProps : Props,
|
||||
internalInstanceHandle : Object,
|
||||
) : void {
|
||||
domElement: Instance,
|
||||
updatePayload: Array<mixed>,
|
||||
type: string,
|
||||
oldProps: Props,
|
||||
newProps: Props,
|
||||
internalInstanceHandle: Object,
|
||||
): void {
|
||||
// Update the props handle so that we know which props are the ones with
|
||||
// with current event handlers.
|
||||
updateFiberProps(domElement, newProps);
|
||||
@@ -271,58 +298,64 @@ var DOMRenderer = ReactFiberReconciler({
|
||||
updateProperties(domElement, updatePayload, type, oldProps, newProps);
|
||||
},
|
||||
|
||||
shouldSetTextContent(props : Props) : boolean {
|
||||
return (
|
||||
typeof props.children === 'string' ||
|
||||
shouldSetTextContent(props: Props): boolean {
|
||||
return typeof props.children === 'string' ||
|
||||
typeof props.children === 'number' ||
|
||||
(
|
||||
typeof props.dangerouslySetInnerHTML === 'object' &&
|
||||
(typeof props.dangerouslySetInnerHTML === 'object' &&
|
||||
props.dangerouslySetInnerHTML !== null &&
|
||||
typeof props.dangerouslySetInnerHTML.__html === 'string'
|
||||
)
|
||||
);
|
||||
typeof props.dangerouslySetInnerHTML.__html === 'string');
|
||||
},
|
||||
|
||||
resetTextContent(domElement : Instance) : void {
|
||||
resetTextContent(domElement: Instance): void {
|
||||
domElement.textContent = '';
|
||||
},
|
||||
|
||||
shouldDeprioritizeSubtree(type : string, props : Props) : boolean {
|
||||
shouldDeprioritizeSubtree(type: string, props: Props): boolean {
|
||||
return !!props.hidden;
|
||||
},
|
||||
|
||||
createTextInstance(
|
||||
text : string,
|
||||
rootContainerInstance : Container,
|
||||
hostContext : HostContext,
|
||||
internalInstanceHandle : Object
|
||||
) : TextInstance {
|
||||
text: string,
|
||||
rootContainerInstance: Container,
|
||||
hostContext: HostContext,
|
||||
internalInstanceHandle: Object,
|
||||
): TextInstance {
|
||||
if (__DEV__) {
|
||||
const hostContextDev = ((hostContext : any) : HostContextDev);
|
||||
const hostContextDev = ((hostContext: any): HostContextDev);
|
||||
validateDOMNesting(null, text, null, hostContextDev.ancestorInfo);
|
||||
}
|
||||
var textNode : TextInstance = document.createTextNode(text);
|
||||
var textNode: TextInstance = document.createTextNode(text);
|
||||
precacheFiberNode(internalInstanceHandle, textNode);
|
||||
return textNode;
|
||||
},
|
||||
|
||||
commitTextUpdate(textInstance : TextInstance, oldText : string, newText : string) : void {
|
||||
commitTextUpdate(
|
||||
textInstance: TextInstance,
|
||||
oldText: string,
|
||||
newText: string,
|
||||
): void {
|
||||
textInstance.nodeValue = newText;
|
||||
},
|
||||
|
||||
appendChild(parentInstance : Instance | Container, child : Instance | TextInstance) : void {
|
||||
appendChild(
|
||||
parentInstance: Instance | Container,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
parentInstance.appendChild(child);
|
||||
},
|
||||
|
||||
insertBefore(
|
||||
parentInstance : Instance | Container,
|
||||
child : Instance | TextInstance,
|
||||
beforeChild : Instance | TextInstance
|
||||
) : void {
|
||||
parentInstance: Instance | Container,
|
||||
child: Instance | TextInstance,
|
||||
beforeChild: Instance | TextInstance,
|
||||
): void {
|
||||
parentInstance.insertBefore(child, beforeChild);
|
||||
},
|
||||
|
||||
removeChild(parentInstance : Instance | Container, child : Instance | TextInstance) : void {
|
||||
removeChild(
|
||||
parentInstance: Instance | Container,
|
||||
child: Instance | TextInstance,
|
||||
): void {
|
||||
parentInstance.removeChild(child);
|
||||
},
|
||||
|
||||
@@ -331,10 +364,11 @@ var DOMRenderer = ReactFiberReconciler({
|
||||
scheduleDeferredCallback: ReactDOMFrameScheduling.rIC,
|
||||
|
||||
useSyncScheduling: !ReactDOMFeatureFlags.fiberAsyncScheduling,
|
||||
|
||||
});
|
||||
|
||||
ReactGenericBatching.injection.injectFiberBatchedUpdates(DOMRenderer.batchedUpdates);
|
||||
ReactGenericBatching.injection.injectFiberBatchedUpdates(
|
||||
DOMRenderer.batchedUpdates,
|
||||
);
|
||||
|
||||
var warned = false;
|
||||
|
||||
@@ -343,21 +377,22 @@ function warnAboutUnstableUse() {
|
||||
warning(
|
||||
warned || ReactDOMFeatureFlags.useFiber,
|
||||
'You are using React DOM Fiber which is an experimental renderer. ' +
|
||||
'It is likely to have bugs, breaking changes and is unsupported.'
|
||||
'It is likely to have bugs, breaking changes and is unsupported.',
|
||||
);
|
||||
warned = true;
|
||||
}
|
||||
|
||||
function renderSubtreeIntoContainer(
|
||||
parentComponent : ?ReactComponent<any, any, any>,
|
||||
children : ReactNodeList,
|
||||
containerNode : DOMContainerElement | Document,
|
||||
callback: ?Function
|
||||
parentComponent: ?ReactComponent<any, any, any>,
|
||||
children: ReactNodeList,
|
||||
containerNode: DOMContainerElement | Document,
|
||||
callback: ?Function,
|
||||
) {
|
||||
validateContainer(containerNode);
|
||||
|
||||
let container : DOMContainerElement =
|
||||
containerNode.nodeType === DOCUMENT_NODE ? (containerNode : any).documentElement : (containerNode : any);
|
||||
let container: DOMContainerElement = containerNode.nodeType === DOCUMENT_NODE
|
||||
? (containerNode: any).documentElement
|
||||
: (containerNode: any);
|
||||
let root = container._reactRootContainer;
|
||||
if (!root) {
|
||||
// First clear any existing content.
|
||||
@@ -365,7 +400,7 @@ function renderSubtreeIntoContainer(
|
||||
container.removeChild(container.lastChild);
|
||||
}
|
||||
const newRoot = DOMRenderer.createContainer(container);
|
||||
root = container._reactRootContainer = newRoot;
|
||||
root = (container._reactRootContainer = newRoot);
|
||||
// Initial mount should not be batched.
|
||||
DOMRenderer.unbatchedUpdates(() => {
|
||||
DOMRenderer.updateContainer(children, newRoot, parentComponent, callback);
|
||||
@@ -377,8 +412,11 @@ function renderSubtreeIntoContainer(
|
||||
}
|
||||
|
||||
var ReactDOM = {
|
||||
|
||||
render(element : ReactElement<any>, container : DOMContainerElement, callback: ?Function) {
|
||||
render(
|
||||
element: ReactElement<any>,
|
||||
container: DOMContainerElement,
|
||||
callback: ?Function,
|
||||
) {
|
||||
validateContainer(container);
|
||||
|
||||
if (ReactFeatureFlags.disableNewFiberFeatures) {
|
||||
@@ -390,29 +428,26 @@ var ReactDOM = {
|
||||
invariant(
|
||||
false,
|
||||
'ReactDOM.render(): Invalid component element. Instead of ' +
|
||||
'passing a string like \'div\', pass ' +
|
||||
'React.createElement(\'div\') or <div />.'
|
||||
"passing a string like 'div', pass " +
|
||||
"React.createElement('div') or <div />.",
|
||||
);
|
||||
} else if (typeof element === 'function') {
|
||||
invariant(
|
||||
false,
|
||||
'ReactDOM.render(): Invalid component element. Instead of ' +
|
||||
'passing a class like Foo, pass React.createElement(Foo) ' +
|
||||
'or <Foo />.'
|
||||
'passing a class like Foo, pass React.createElement(Foo) ' +
|
||||
'or <Foo />.',
|
||||
);
|
||||
} else if (element != null && typeof element.props !== 'undefined') {
|
||||
// Check if it quacks like an element
|
||||
invariant(
|
||||
false,
|
||||
'ReactDOM.render(): Invalid component element. This may be ' +
|
||||
'caused by unintentionally loading two independent copies ' +
|
||||
'of React.'
|
||||
'caused by unintentionally loading two independent copies ' +
|
||||
'of React.',
|
||||
);
|
||||
} else {
|
||||
invariant(
|
||||
false,
|
||||
'ReactDOM.render(): Invalid component element.'
|
||||
);
|
||||
invariant(false, 'ReactDOM.render(): Invalid component element.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -420,24 +455,24 @@ var ReactDOM = {
|
||||
if (__DEV__) {
|
||||
const isRootRenderedBySomeReact = !!container._reactRootContainer;
|
||||
const rootEl = getReactRootElementInContainer(container);
|
||||
const hasNonRootReactChild = !!(rootEl && ReactDOMComponentTree.getInstanceFromNode(rootEl));
|
||||
const hasNonRootReactChild = !!(rootEl &&
|
||||
ReactDOMComponentTree.getInstanceFromNode(rootEl));
|
||||
|
||||
warning(
|
||||
!hasNonRootReactChild ||
|
||||
isRootRenderedBySomeReact,
|
||||
!hasNonRootReactChild || isRootRenderedBySomeReact,
|
||||
'render(...): Replacing React-rendered children with a new root ' +
|
||||
'component. If you intended to update the children of this node, ' +
|
||||
'you should instead have the existing children update their state ' +
|
||||
'and render the new components instead of calling ReactDOM.render.'
|
||||
'component. If you intended to update the children of this node, ' +
|
||||
'you should instead have the existing children update their state ' +
|
||||
'and render the new components instead of calling ReactDOM.render.',
|
||||
);
|
||||
|
||||
warning(
|
||||
!container.tagName || container.tagName.toUpperCase() !== 'BODY',
|
||||
'render(): Rendering components directly into document.body is ' +
|
||||
'discouraged, since its children are often manipulated by third-party ' +
|
||||
'scripts and browser extensions. This may lead to subtle ' +
|
||||
'reconciliation issues. Try rendering into a container element created ' +
|
||||
'for your app.'
|
||||
'discouraged, since its children are often manipulated by third-party ' +
|
||||
'scripts and browser extensions. This may lead to subtle ' +
|
||||
'reconciliation issues. Try rendering into a container element created ' +
|
||||
'for your app.',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -445,33 +480,39 @@ var ReactDOM = {
|
||||
},
|
||||
|
||||
unstable_renderSubtreeIntoContainer(
|
||||
parentComponent : ReactComponent<any, any, any>,
|
||||
element : ReactElement<any>,
|
||||
containerNode : DOMContainerElement | Document,
|
||||
callback: ?Function
|
||||
parentComponent: ReactComponent<any, any, any>,
|
||||
element: ReactElement<any>,
|
||||
containerNode: DOMContainerElement | Document,
|
||||
callback: ?Function,
|
||||
) {
|
||||
invariant(
|
||||
parentComponent != null && ReactInstanceMap.has(parentComponent),
|
||||
'parentComponent must be a valid React Component'
|
||||
'parentComponent must be a valid React Component',
|
||||
);
|
||||
return renderSubtreeIntoContainer(
|
||||
parentComponent,
|
||||
element,
|
||||
containerNode,
|
||||
callback,
|
||||
);
|
||||
return renderSubtreeIntoContainer(parentComponent, element, containerNode, callback);
|
||||
},
|
||||
|
||||
unmountComponentAtNode(container : DOMContainerElement) {
|
||||
unmountComponentAtNode(container: DOMContainerElement) {
|
||||
invariant(
|
||||
isValidContainer(container),
|
||||
'unmountComponentAtNode(...): Target container is not a DOM element.'
|
||||
'unmountComponentAtNode(...): Target container is not a DOM element.',
|
||||
);
|
||||
warnAboutUnstableUse();
|
||||
|
||||
if (container._reactRootContainer) {
|
||||
if (__DEV__) {
|
||||
const rootEl = getReactRootElementInContainer(container);
|
||||
const renderedByDifferentReact = rootEl && !ReactDOMComponentTree.getInstanceFromNode(rootEl);
|
||||
const renderedByDifferentReact = rootEl &&
|
||||
!ReactDOMComponentTree.getInstanceFromNode(rootEl);
|
||||
warning(
|
||||
!renderedByDifferentReact,
|
||||
'unmountComponentAtNode(): The node you\'re attempting to unmount ' +
|
||||
'was rendered by another copy of React.'
|
||||
"unmountComponentAtNode(): The node you're attempting to unmount " +
|
||||
'was rendered by another copy of React.',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -486,7 +527,11 @@ var ReactDOM = {
|
||||
|
||||
findDOMNode: findDOMNode,
|
||||
|
||||
unstable_createPortal(children: ReactNodeList, container : DOMContainerElement, key : ?string = null) {
|
||||
unstable_createPortal(
|
||||
children: ReactNodeList,
|
||||
container: DOMContainerElement,
|
||||
key: ?string = null,
|
||||
) {
|
||||
// TODO: pass ReactDOM portal implementation as third argument
|
||||
return ReactPortal.createPortal(children, container, null, key);
|
||||
},
|
||||
@@ -494,7 +539,6 @@ var ReactDOM = {
|
||||
unstable_batchedUpdates: ReactGenericBatching.batchedUpdates,
|
||||
|
||||
unstable_deferredUpdates: DOMRenderer.deferredUpdates,
|
||||
|
||||
};
|
||||
|
||||
if (typeof injectInternals === 'function') {
|
||||
|
||||
@@ -24,7 +24,7 @@ var ReactDOMFiberInput = require('ReactDOMFiberInput');
|
||||
var ReactDOMFiberOption = require('ReactDOMFiberOption');
|
||||
var ReactDOMFiberSelect = require('ReactDOMFiberSelect');
|
||||
var ReactDOMFiberTextarea = require('ReactDOMFiberTextarea');
|
||||
var { getCurrentFiberOwnerName } = require('ReactDebugCurrentFiber');
|
||||
var {getCurrentFiberOwnerName} = require('ReactDebugCurrentFiber');
|
||||
|
||||
var emptyFunction = require('fbjs/lib/emptyFunction');
|
||||
var invariant = require('fbjs/lib/invariant');
|
||||
@@ -38,9 +38,13 @@ if (__DEV__) {
|
||||
var ReactDOMInvalidARIAHook = require('ReactDOMInvalidARIAHook');
|
||||
var ReactDOMNullInputValuePropHook = require('ReactDOMNullInputValuePropHook');
|
||||
var ReactDOMUnknownPropertyHook = require('ReactDOMUnknownPropertyHook');
|
||||
var { validateProperties: validateARIAProperties } = ReactDOMInvalidARIAHook;
|
||||
var { validateProperties: validateInputPropertes } = ReactDOMNullInputValuePropHook;
|
||||
var { validateProperties: validateUnknownPropertes } = ReactDOMUnknownPropertyHook;
|
||||
var {validateProperties: validateARIAProperties} = ReactDOMInvalidARIAHook;
|
||||
var {
|
||||
validateProperties: validateInputPropertes,
|
||||
} = ReactDOMNullInputValuePropHook;
|
||||
var {
|
||||
validateProperties: validateUnknownPropertes,
|
||||
} = ReactDOMUnknownPropertyHook;
|
||||
}
|
||||
|
||||
var didWarnShadyDOM = false;
|
||||
@@ -63,7 +67,6 @@ var {
|
||||
// Node type for document fragments (Node.DOCUMENT_FRAGMENT_NODE).
|
||||
var DOC_FRAGMENT_TYPE = 11;
|
||||
|
||||
|
||||
function getDeclarationErrorAddendum() {
|
||||
var ownerName = getCurrentFiberOwnerName();
|
||||
if (ownerName) {
|
||||
@@ -73,7 +76,7 @@ function getDeclarationErrorAddendum() {
|
||||
return '';
|
||||
}
|
||||
|
||||
function assertValidProps(tag : string, props : ?Object) {
|
||||
function assertValidProps(tag: string, props: ?Object) {
|
||||
if (!props) {
|
||||
return;
|
||||
}
|
||||
@@ -82,53 +85,52 @@ function assertValidProps(tag : string, props : ?Object) {
|
||||
invariant(
|
||||
props.children == null && props.dangerouslySetInnerHTML == null,
|
||||
'%s is a void element tag and must neither have `children` nor ' +
|
||||
'use `dangerouslySetInnerHTML`.%s',
|
||||
'use `dangerouslySetInnerHTML`.%s',
|
||||
tag,
|
||||
getDeclarationErrorAddendum()
|
||||
getDeclarationErrorAddendum(),
|
||||
);
|
||||
}
|
||||
if (props.dangerouslySetInnerHTML != null) {
|
||||
invariant(
|
||||
props.children == null,
|
||||
'Can only set one of `children` or `props.dangerouslySetInnerHTML`.'
|
||||
'Can only set one of `children` or `props.dangerouslySetInnerHTML`.',
|
||||
);
|
||||
invariant(
|
||||
typeof props.dangerouslySetInnerHTML === 'object' &&
|
||||
HTML in props.dangerouslySetInnerHTML,
|
||||
HTML in props.dangerouslySetInnerHTML,
|
||||
'`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' +
|
||||
'Please visit https://fb.me/react-invariant-dangerously-set-inner-html ' +
|
||||
'for more information.'
|
||||
'Please visit https://fb.me/react-invariant-dangerously-set-inner-html ' +
|
||||
'for more information.',
|
||||
);
|
||||
}
|
||||
if (__DEV__) {
|
||||
warning(
|
||||
props.innerHTML == null,
|
||||
'Directly setting property `innerHTML` is not permitted. ' +
|
||||
'For more information, lookup documentation on `dangerouslySetInnerHTML`.'
|
||||
'For more information, lookup documentation on `dangerouslySetInnerHTML`.',
|
||||
);
|
||||
warning(
|
||||
props.suppressContentEditableWarning ||
|
||||
!props.contentEditable ||
|
||||
props.children == null,
|
||||
!props.contentEditable ||
|
||||
props.children == null,
|
||||
'A component is `contentEditable` and contains `children` managed by ' +
|
||||
'React. It is now your responsibility to guarantee that none of ' +
|
||||
'those nodes are unexpectedly modified or duplicated. This is ' +
|
||||
'probably not intentional.'
|
||||
'React. It is now your responsibility to guarantee that none of ' +
|
||||
'those nodes are unexpectedly modified or duplicated. This is ' +
|
||||
'probably not intentional.',
|
||||
);
|
||||
warning(
|
||||
props.onFocusIn == null &&
|
||||
props.onFocusOut == null,
|
||||
props.onFocusIn == null && props.onFocusOut == null,
|
||||
'React uses onFocus and onBlur instead of onFocusIn and onFocusOut. ' +
|
||||
'All React events are normalized to bubble, so onFocusIn and onFocusOut ' +
|
||||
'are not needed/supported by React.'
|
||||
'All React events are normalized to bubble, so onFocusIn and onFocusOut ' +
|
||||
'are not needed/supported by React.',
|
||||
);
|
||||
}
|
||||
invariant(
|
||||
props.style == null || typeof props.style === 'object',
|
||||
'The `style` prop expects a mapping from style properties to values, ' +
|
||||
'not a string. For example, style={{marginRight: spacing + \'em\'}} when ' +
|
||||
'using JSX.%s',
|
||||
getDeclarationErrorAddendum()
|
||||
"not a string. For example, style={{marginRight: spacing + 'em'}} when " +
|
||||
'using JSX.%s',
|
||||
getDeclarationErrorAddendum(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -146,11 +148,13 @@ function ensureListeningTo(rootContainerElement, registrationName) {
|
||||
// bubble.
|
||||
warning(
|
||||
registrationName !== 'onScroll' || isEventSupported('scroll', true),
|
||||
'This browser doesn\'t support the `onScroll` event'
|
||||
"This browser doesn't support the `onScroll` event",
|
||||
);
|
||||
}
|
||||
var isDocumentFragment = rootContainerElement.nodeType === DOC_FRAGMENT_TYPE;
|
||||
var doc = isDocumentFragment ? rootContainerElement : rootContainerElement.ownerDocument;
|
||||
var doc = isDocumentFragment
|
||||
? rootContainerElement
|
||||
: rootContainerElement.ownerDocument;
|
||||
listenTo(registrationName, doc);
|
||||
}
|
||||
|
||||
@@ -182,7 +186,7 @@ var mediaEvents = {
|
||||
topWaiting: 'waiting',
|
||||
};
|
||||
|
||||
function trapClickOnNonInteractiveElement(node : HTMLElement) {
|
||||
function trapClickOnNonInteractiveElement(node: HTMLElement) {
|
||||
// Mobile Safari does not fire properly bubble click events on
|
||||
// non-interactive elements, which means delegated click listeners do not
|
||||
// fire. The workaround for this bug involves attaching an empty click
|
||||
@@ -195,7 +199,7 @@ function trapClickOnNonInteractiveElement(node : HTMLElement) {
|
||||
node.onclick = emptyFunction;
|
||||
}
|
||||
|
||||
function trapBubbledEventsLocal(node : Element, tag : string) {
|
||||
function trapBubbledEventsLocal(node: Element, tag: string) {
|
||||
// If a component renders to null or if another component fatals and causes
|
||||
// the state of the tree to be corrupted, `node` here can be null.
|
||||
|
||||
@@ -205,11 +209,7 @@ function trapBubbledEventsLocal(node : Element, tag : string) {
|
||||
switch (tag) {
|
||||
case 'iframe':
|
||||
case 'object':
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topLoad',
|
||||
'load',
|
||||
node
|
||||
);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent('topLoad', 'load', node);
|
||||
break;
|
||||
case 'video':
|
||||
case 'audio':
|
||||
@@ -219,58 +219,30 @@ function trapBubbledEventsLocal(node : Element, tag : string) {
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
event,
|
||||
mediaEvents[event],
|
||||
node
|
||||
node,
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'source':
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topError',
|
||||
'error',
|
||||
node
|
||||
);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent('topError', 'error', node);
|
||||
break;
|
||||
case 'img':
|
||||
case 'image':
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topError',
|
||||
'error',
|
||||
node
|
||||
);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topLoad',
|
||||
'load',
|
||||
node
|
||||
);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent('topError', 'error', node);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent('topLoad', 'load', node);
|
||||
break;
|
||||
case 'form':
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topReset',
|
||||
'reset',
|
||||
node
|
||||
);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topSubmit',
|
||||
'submit',
|
||||
node
|
||||
);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent('topReset', 'reset', node);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent('topSubmit', 'submit', node);
|
||||
break;
|
||||
case 'input':
|
||||
case 'select':
|
||||
case 'textarea':
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topInvalid',
|
||||
'invalid',
|
||||
node
|
||||
);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent('topInvalid', 'invalid', node);
|
||||
break;
|
||||
case 'details':
|
||||
ReactBrowserEventEmitter.trapBubbledEvent(
|
||||
'topToggle',
|
||||
'toggle',
|
||||
node
|
||||
);
|
||||
ReactBrowserEventEmitter.trapBubbledEvent('topToggle', 'toggle', node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -279,21 +251,21 @@ function trapBubbledEventsLocal(node : Element, tag : string) {
|
||||
// those special-case tags.
|
||||
|
||||
var omittedCloseTags = {
|
||||
'area': true,
|
||||
'base': true,
|
||||
'br': true,
|
||||
'col': true,
|
||||
'embed': true,
|
||||
'hr': true,
|
||||
'img': true,
|
||||
'input': true,
|
||||
'keygen': true,
|
||||
'link': true,
|
||||
'meta': true,
|
||||
'param': true,
|
||||
'source': true,
|
||||
'track': true,
|
||||
'wbr': true,
|
||||
area: true,
|
||||
base: true,
|
||||
br: true,
|
||||
col: true,
|
||||
embed: true,
|
||||
hr: true,
|
||||
img: true,
|
||||
input: true,
|
||||
keygen: true,
|
||||
link: true,
|
||||
meta: true,
|
||||
param: true,
|
||||
source: true,
|
||||
track: true,
|
||||
wbr: true,
|
||||
// NOTE: menuitem's close tag should be omitted, but that causes problems.
|
||||
};
|
||||
|
||||
@@ -301,7 +273,7 @@ var omittedCloseTags = {
|
||||
// `omittedCloseTags` except that `menuitem` should still have its closing tag.
|
||||
|
||||
var voidElementTags = {
|
||||
'menuitem': true,
|
||||
menuitem: true,
|
||||
...omittedCloseTags,
|
||||
};
|
||||
|
||||
@@ -310,11 +282,11 @@ function isCustomComponent(tagName, props) {
|
||||
}
|
||||
|
||||
function setInitialDOMProperties(
|
||||
domElement : Element,
|
||||
rootContainerElement : Element,
|
||||
nextProps : Object,
|
||||
isCustomComponentTag : boolean,
|
||||
) : void {
|
||||
domElement: Element,
|
||||
rootContainerElement: Element,
|
||||
nextProps: Object,
|
||||
isCustomComponentTag: boolean,
|
||||
): void {
|
||||
for (var propKey in nextProps) {
|
||||
var nextProp = nextProps[propKey];
|
||||
if (!nextProps.hasOwnProperty(propKey)) {
|
||||
@@ -330,10 +302,7 @@ function setInitialDOMProperties(
|
||||
}
|
||||
// Relies on `updateStylesByID` not mutating `styleUpdates`.
|
||||
// TODO: call ReactInstrumentation.debugTool.onHostOperation in DEV.
|
||||
CSSPropertyOperations.setValueForStyles(
|
||||
domElement,
|
||||
nextProp,
|
||||
);
|
||||
CSSPropertyOperations.setValueForStyles(domElement, nextProp);
|
||||
} else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
|
||||
var nextHtml = nextProp ? nextProp[HTML] : undefined;
|
||||
if (nextHtml != null) {
|
||||
@@ -352,40 +321,37 @@ function setInitialDOMProperties(
|
||||
ensureListeningTo(rootContainerElement, propKey);
|
||||
}
|
||||
} else if (isCustomComponentTag) {
|
||||
DOMPropertyOperations.setValueForAttribute(
|
||||
domElement,
|
||||
propKey,
|
||||
nextProp
|
||||
);
|
||||
DOMPropertyOperations.setValueForAttribute(domElement, propKey, nextProp);
|
||||
} else if (
|
||||
DOMProperty.properties[propKey] ||
|
||||
DOMProperty.isCustomAttribute(propKey)) {
|
||||
DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)
|
||||
) {
|
||||
// If we're updating to null or undefined, we should remove the property
|
||||
// from the DOM node instead of inadvertently setting to a string. This
|
||||
// brings us in line with the same behavior we have on initial render.
|
||||
if (nextProp != null) {
|
||||
DOMPropertyOperations.setValueForProperty(domElement, propKey, nextProp);
|
||||
DOMPropertyOperations.setValueForProperty(
|
||||
domElement,
|
||||
propKey,
|
||||
nextProp,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateDOMProperties(
|
||||
domElement : Element,
|
||||
updatePayload : Array<any>,
|
||||
wasCustomComponentTag : boolean,
|
||||
isCustomComponentTag : boolean,
|
||||
) : void {
|
||||
domElement: Element,
|
||||
updatePayload: Array<any>,
|
||||
wasCustomComponentTag: boolean,
|
||||
isCustomComponentTag: boolean,
|
||||
): void {
|
||||
// TODO: Handle wasCustomComponentTag
|
||||
for (var i = 0; i < updatePayload.length; i += 2) {
|
||||
var propKey = updatePayload[i];
|
||||
var propValue = updatePayload[i + 1];
|
||||
if (propKey === STYLE) {
|
||||
// TODO: call ReactInstrumentation.debugTool.onHostOperation in DEV.
|
||||
CSSPropertyOperations.setValueForStyles(
|
||||
domElement,
|
||||
propValue,
|
||||
);
|
||||
CSSPropertyOperations.setValueForStyles(domElement, propValue);
|
||||
} else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
|
||||
setInnerHTML(domElement, propValue);
|
||||
} else if (propKey === CHILDREN) {
|
||||
@@ -395,22 +361,23 @@ function updateDOMProperties(
|
||||
DOMPropertyOperations.setValueForAttribute(
|
||||
domElement,
|
||||
propKey,
|
||||
propValue
|
||||
propValue,
|
||||
);
|
||||
} else {
|
||||
DOMPropertyOperations.deleteValueForAttribute(
|
||||
domElement,
|
||||
propKey
|
||||
);
|
||||
DOMPropertyOperations.deleteValueForAttribute(domElement, propKey);
|
||||
}
|
||||
} else if (
|
||||
DOMProperty.properties[propKey] ||
|
||||
DOMProperty.isCustomAttribute(propKey)) {
|
||||
DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)
|
||||
) {
|
||||
// If we're updating to null or undefined, we should remove the property
|
||||
// from the DOM node instead of inadvertently setting to a string. This
|
||||
// brings us in line with the same behavior we have on initial render.
|
||||
if (propValue != null) {
|
||||
DOMPropertyOperations.setValueForProperty(domElement, propKey, propValue);
|
||||
DOMPropertyOperations.setValueForProperty(
|
||||
domElement,
|
||||
propKey,
|
||||
propValue,
|
||||
);
|
||||
} else {
|
||||
DOMPropertyOperations.deleteValueForProperty(domElement, propKey);
|
||||
}
|
||||
@@ -419,7 +386,7 @@ function updateDOMProperties(
|
||||
}
|
||||
|
||||
// Assumes there is no parent namespace.
|
||||
function getIntrinsicNamespace(type : string) : string {
|
||||
function getIntrinsicNamespace(type: string): string {
|
||||
switch (type) {
|
||||
case 'svg':
|
||||
return SVG_NAMESPACE;
|
||||
@@ -431,7 +398,7 @@ function getIntrinsicNamespace(type : string) : string {
|
||||
}
|
||||
|
||||
var ReactDOMFiberComponent = {
|
||||
getChildNamespace(parentNamespace : string | null, type : string) : string {
|
||||
getChildNamespace(parentNamespace: string | null, type: string): string {
|
||||
if (parentNamespace == null || parentNamespace === HTML_NAMESPACE) {
|
||||
// No (or default) parent namespace: potential entry point.
|
||||
return getIntrinsicNamespace(type);
|
||||
@@ -445,15 +412,15 @@ var ReactDOMFiberComponent = {
|
||||
},
|
||||
|
||||
createElement(
|
||||
type : string,
|
||||
props : Object,
|
||||
rootContainerElement : Element,
|
||||
parentNamespace : string
|
||||
) : Element {
|
||||
type: string,
|
||||
props: Object,
|
||||
rootContainerElement: Element,
|
||||
parentNamespace: string,
|
||||
): Element {
|
||||
// We create tags in the namespace of their parent container, except HTML
|
||||
// tags get no namespace.
|
||||
var ownerDocument = rootContainerElement.ownerDocument;
|
||||
var domElement : Element;
|
||||
var domElement: Element;
|
||||
var namespaceURI = parentNamespace;
|
||||
if (namespaceURI === HTML_NAMESPACE) {
|
||||
namespaceURI = getIntrinsicNamespace(type);
|
||||
@@ -461,11 +428,10 @@ var ReactDOMFiberComponent = {
|
||||
if (namespaceURI === HTML_NAMESPACE) {
|
||||
if (__DEV__) {
|
||||
warning(
|
||||
type === type.toLowerCase() ||
|
||||
isCustomComponent(type, props),
|
||||
type === type.toLowerCase() || isCustomComponent(type, props),
|
||||
'<%s /> is using uppercase HTML. Always use lowercase HTML tags ' +
|
||||
'in React.',
|
||||
type
|
||||
'in React.',
|
||||
type,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -473,9 +439,9 @@ var ReactDOMFiberComponent = {
|
||||
// Create the script via .innerHTML so its "parser-inserted" flag is
|
||||
// set to true and it does not execute
|
||||
var div = ownerDocument.createElement('div');
|
||||
div.innerHTML = '<script><' + '/script>'; // eslint-disable-line
|
||||
div.innerHTML = '<script><' + '/script>'; // eslint-disable-line
|
||||
// This is guaranteed to yield a script element.
|
||||
var firstChild = ((div.firstChild : any) : HTMLScriptElement);
|
||||
var firstChild = ((div.firstChild: any): HTMLScriptElement);
|
||||
domElement = div.removeChild(firstChild);
|
||||
} else if (props.is) {
|
||||
domElement = ownerDocument.createElement(type, props.is);
|
||||
@@ -486,22 +452,18 @@ var ReactDOMFiberComponent = {
|
||||
domElement = ownerDocument.createElement(type);
|
||||
}
|
||||
} else {
|
||||
domElement = ownerDocument.createElementNS(
|
||||
namespaceURI,
|
||||
type
|
||||
);
|
||||
domElement = ownerDocument.createElementNS(namespaceURI, type);
|
||||
}
|
||||
|
||||
return domElement;
|
||||
},
|
||||
|
||||
setInitialProperties(
|
||||
domElement : Element,
|
||||
tag : string,
|
||||
rawProps : Object,
|
||||
rootContainerElement : Element
|
||||
) : void {
|
||||
|
||||
domElement: Element,
|
||||
tag: string,
|
||||
rawProps: Object,
|
||||
rootContainerElement: Element,
|
||||
): void {
|
||||
var isCustomComponentTag = isCustomComponent(tag, rawProps);
|
||||
if (__DEV__) {
|
||||
validatePropertiesInDevelopment(tag, rawProps);
|
||||
@@ -509,14 +471,14 @@ var ReactDOMFiberComponent = {
|
||||
warning(
|
||||
false,
|
||||
'%s is using shady DOM. Using shady DOM with React can ' +
|
||||
'cause things to break subtly.',
|
||||
getCurrentFiberOwnerName() || 'A component'
|
||||
'cause things to break subtly.',
|
||||
getCurrentFiberOwnerName() || 'A component',
|
||||
);
|
||||
didWarnShadyDOM = true;
|
||||
}
|
||||
}
|
||||
|
||||
var props : Object;
|
||||
var props: Object;
|
||||
switch (tag) {
|
||||
case 'audio':
|
||||
case 'form':
|
||||
@@ -569,20 +531,20 @@ var ReactDOMFiberComponent = {
|
||||
domElement,
|
||||
rootContainerElement,
|
||||
props,
|
||||
isCustomComponentTag
|
||||
isCustomComponentTag,
|
||||
);
|
||||
|
||||
switch (tag) {
|
||||
case 'input':
|
||||
// TODO: Make sure we check if this is still unmounted or do any clean
|
||||
// up necessary since we never stop tracking anymore.
|
||||
inputValueTracking.trackNode((domElement : any));
|
||||
inputValueTracking.trackNode((domElement: any));
|
||||
ReactDOMFiberInput.postMountWrapper(domElement, rawProps);
|
||||
break;
|
||||
case 'textarea':
|
||||
// TODO: Make sure we check if this is still unmounted or do any clean
|
||||
// up necessary since we never stop tracking anymore.
|
||||
inputValueTracking.trackNode((domElement : any));
|
||||
inputValueTracking.trackNode((domElement: any));
|
||||
ReactDOMFiberTextarea.postMountWrapper(domElement, rawProps);
|
||||
break;
|
||||
case 'option':
|
||||
@@ -591,7 +553,7 @@ var ReactDOMFiberComponent = {
|
||||
default:
|
||||
if (typeof props.onClick === 'function') {
|
||||
// TODO: This cast may not be sound for SVG, MathML or custom elements.
|
||||
trapClickOnNonInteractiveElement(((domElement : any) : HTMLElement));
|
||||
trapClickOnNonInteractiveElement(((domElement: any): HTMLElement));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -599,20 +561,20 @@ var ReactDOMFiberComponent = {
|
||||
|
||||
// Calculate the diff between the two objects.
|
||||
diffProperties(
|
||||
domElement : Element,
|
||||
tag : string,
|
||||
lastRawProps : Object,
|
||||
nextRawProps : Object,
|
||||
rootContainerElement : Element,
|
||||
) : null | Array<mixed> {
|
||||
domElement: Element,
|
||||
tag: string,
|
||||
lastRawProps: Object,
|
||||
nextRawProps: Object,
|
||||
rootContainerElement: Element,
|
||||
): null | Array<mixed> {
|
||||
if (__DEV__) {
|
||||
validatePropertiesInDevelopment(tag, nextRawProps);
|
||||
}
|
||||
|
||||
var updatePayload : null | Array<any> = null;
|
||||
var updatePayload: null | Array<any> = null;
|
||||
|
||||
var lastProps : Object;
|
||||
var nextProps : Object;
|
||||
var lastProps: Object;
|
||||
var nextProps: Object;
|
||||
switch (tag) {
|
||||
case 'input':
|
||||
lastProps = ReactDOMFiberInput.getHostProps(domElement, lastRawProps);
|
||||
@@ -630,17 +592,25 @@ var ReactDOMFiberComponent = {
|
||||
updatePayload = [];
|
||||
break;
|
||||
case 'textarea':
|
||||
lastProps = ReactDOMFiberTextarea.getHostProps(domElement, lastRawProps);
|
||||
nextProps = ReactDOMFiberTextarea.getHostProps(domElement, nextRawProps);
|
||||
lastProps = ReactDOMFiberTextarea.getHostProps(
|
||||
domElement,
|
||||
lastRawProps,
|
||||
);
|
||||
nextProps = ReactDOMFiberTextarea.getHostProps(
|
||||
domElement,
|
||||
nextRawProps,
|
||||
);
|
||||
updatePayload = [];
|
||||
break;
|
||||
default:
|
||||
lastProps = lastRawProps;
|
||||
nextProps = nextRawProps;
|
||||
if (typeof lastProps.onClick !== 'function' &&
|
||||
typeof nextProps.onClick === 'function') {
|
||||
if (
|
||||
typeof lastProps.onClick !== 'function' &&
|
||||
typeof nextProps.onClick === 'function'
|
||||
) {
|
||||
// TODO: This cast may not be sound for SVG, MathML or custom elements.
|
||||
trapClickOnNonInteractiveElement(((domElement : any) : HTMLElement));
|
||||
trapClickOnNonInteractiveElement(((domElement: any): HTMLElement));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -651,9 +621,11 @@ var ReactDOMFiberComponent = {
|
||||
var styleName;
|
||||
var styleUpdates = null;
|
||||
for (propKey in lastProps) {
|
||||
if (nextProps.hasOwnProperty(propKey) ||
|
||||
!lastProps.hasOwnProperty(propKey) ||
|
||||
lastProps[propKey] == null) {
|
||||
if (
|
||||
nextProps.hasOwnProperty(propKey) ||
|
||||
!lastProps.hasOwnProperty(propKey) ||
|
||||
lastProps[propKey] == null
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
if (propKey === STYLE) {
|
||||
@@ -666,8 +638,9 @@ var ReactDOMFiberComponent = {
|
||||
styleUpdates[styleName] = '';
|
||||
}
|
||||
}
|
||||
} else if (propKey === DANGEROUSLY_SET_INNER_HTML ||
|
||||
propKey === CHILDREN) {
|
||||
} else if (
|
||||
propKey === DANGEROUSLY_SET_INNER_HTML || propKey === CHILDREN
|
||||
) {
|
||||
// Noop. This is handled by the clear text mechanism.
|
||||
} else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING) {
|
||||
// Noop
|
||||
@@ -686,11 +659,12 @@ var ReactDOMFiberComponent = {
|
||||
}
|
||||
for (propKey in nextProps) {
|
||||
var nextProp = nextProps[propKey];
|
||||
var lastProp =
|
||||
lastProps != null ? lastProps[propKey] : undefined;
|
||||
if (!nextProps.hasOwnProperty(propKey) ||
|
||||
nextProp === lastProp ||
|
||||
nextProp == null && lastProp == null) {
|
||||
var lastProp = lastProps != null ? lastProps[propKey] : undefined;
|
||||
if (
|
||||
!nextProps.hasOwnProperty(propKey) ||
|
||||
nextProp === lastProp ||
|
||||
(nextProp == null && lastProp == null)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
if (propKey === STYLE) {
|
||||
@@ -704,8 +678,10 @@ var ReactDOMFiberComponent = {
|
||||
if (lastProp) {
|
||||
// Unset styles on `lastProp` but not on `nextProp`.
|
||||
for (styleName in lastProp) {
|
||||
if (lastProp.hasOwnProperty(styleName) &&
|
||||
(!nextProp || !nextProp.hasOwnProperty(styleName))) {
|
||||
if (
|
||||
lastProp.hasOwnProperty(styleName) &&
|
||||
(!nextProp || !nextProp.hasOwnProperty(styleName))
|
||||
) {
|
||||
if (!styleUpdates) {
|
||||
styleUpdates = {};
|
||||
}
|
||||
@@ -714,8 +690,10 @@ var ReactDOMFiberComponent = {
|
||||
}
|
||||
// Update styles that changed since `lastProp`.
|
||||
for (styleName in nextProp) {
|
||||
if (nextProp.hasOwnProperty(styleName) &&
|
||||
lastProp[styleName] !== nextProp[styleName]) {
|
||||
if (
|
||||
nextProp.hasOwnProperty(styleName) &&
|
||||
lastProp[styleName] !== nextProp[styleName]
|
||||
) {
|
||||
if (!styleUpdates) {
|
||||
styleUpdates = {};
|
||||
}
|
||||
@@ -744,9 +722,10 @@ var ReactDOMFiberComponent = {
|
||||
// inserted already.
|
||||
}
|
||||
} else if (propKey === CHILDREN) {
|
||||
if (lastProp !== nextProp && (
|
||||
typeof nextProp === 'string' || typeof nextProp === 'number'
|
||||
)) {
|
||||
if (
|
||||
lastProp !== nextProp &&
|
||||
(typeof nextProp === 'string' || typeof nextProp === 'number')
|
||||
) {
|
||||
(updatePayload = updatePayload || []).push(propKey, '' + nextProp);
|
||||
}
|
||||
} else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING) {
|
||||
@@ -776,12 +755,12 @@ var ReactDOMFiberComponent = {
|
||||
|
||||
// Apply the diff.
|
||||
updateProperties(
|
||||
domElement : Element,
|
||||
updatePayload : Array<any>,
|
||||
tag : string,
|
||||
lastRawProps : Object,
|
||||
nextRawProps : Object
|
||||
) : void {
|
||||
domElement: Element,
|
||||
updatePayload: Array<any>,
|
||||
tag: string,
|
||||
lastRawProps: Object,
|
||||
nextRawProps: Object,
|
||||
): void {
|
||||
var wasCustomComponentTag = isCustomComponent(tag, lastRawProps);
|
||||
var isCustomComponentTag = isCustomComponent(tag, nextRawProps);
|
||||
// Apply the diff.
|
||||
@@ -789,7 +768,7 @@ var ReactDOMFiberComponent = {
|
||||
domElement,
|
||||
updatePayload,
|
||||
wasCustomComponentTag,
|
||||
isCustomComponentTag
|
||||
isCustomComponentTag,
|
||||
);
|
||||
|
||||
// TODO: Ensure that an update gets scheduled if any of the special props
|
||||
@@ -812,7 +791,11 @@ var ReactDOMFiberComponent = {
|
||||
}
|
||||
},
|
||||
|
||||
restoreControlledState(domElement : Element, tag : string, props : Object) : void {
|
||||
restoreControlledState(
|
||||
domElement: Element,
|
||||
tag: string,
|
||||
props: Object,
|
||||
): void {
|
||||
switch (tag) {
|
||||
case 'input':
|
||||
ReactDOMFiberInput.restoreControlledState(domElement, props);
|
||||
@@ -825,7 +808,6 @@ var ReactDOMFiberComponent = {
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
module.exports = ReactDOMFiberComponent;
|
||||
|
||||
@@ -20,18 +20,18 @@
|
||||
// layout, paint and other browser work is counted against the available time.
|
||||
// The frame rate is dynamically adjusted.
|
||||
|
||||
import type { Deadline } from 'ReactFiberReconciler';
|
||||
import type {Deadline} from 'ReactFiberReconciler';
|
||||
|
||||
var invariant = require('fbjs/lib/invariant');
|
||||
|
||||
// TODO: There's no way to cancel these, because Fiber doesn't atm.
|
||||
let rAF : (callback : (time : number) => void) => number;
|
||||
let rIC : (callback : (deadline : Deadline) => void) => number;
|
||||
let rAF: (callback: (time: number) => void) => number;
|
||||
let rIC: (callback: (deadline: Deadline) => void) => number;
|
||||
if (typeof requestAnimationFrame !== 'function') {
|
||||
invariant(
|
||||
false,
|
||||
'React depends on requestAnimationFrame. Make sure that you load a ' +
|
||||
'polyfill in older browsers.'
|
||||
'polyfill in older browsers.',
|
||||
);
|
||||
} else if (typeof requestIdleCallback !== 'function') {
|
||||
// Wrap requestAnimationFrame and polyfill requestIdleCallback.
|
||||
@@ -50,22 +50,21 @@ if (typeof requestAnimationFrame !== 'function') {
|
||||
var activeFrameTime = 33;
|
||||
|
||||
var frameDeadlineObject = {
|
||||
timeRemaining: (
|
||||
typeof performance === 'object' &&
|
||||
typeof performance.now === 'function' ? function() {
|
||||
// We assume that if we have a performance timer that the rAF callback
|
||||
// gets a performance timer value. Not sure if this is always true.
|
||||
return frameDeadline - performance.now();
|
||||
} : function() {
|
||||
// As a fallback we use Date.now.
|
||||
return frameDeadline - Date.now();
|
||||
}
|
||||
),
|
||||
timeRemaining: typeof performance === 'object' &&
|
||||
typeof performance.now === 'function'
|
||||
? function() {
|
||||
// We assume that if we have a performance timer that the rAF callback
|
||||
// gets a performance timer value. Not sure if this is always true.
|
||||
return frameDeadline - performance.now();
|
||||
}
|
||||
: function() {
|
||||
// As a fallback we use Date.now.
|
||||
return frameDeadline - Date.now();
|
||||
},
|
||||
};
|
||||
|
||||
// We use the postMessage trick to defer idle work until after the repaint.
|
||||
var messageKey =
|
||||
'__reactIdleCallback$' + Math.random().toString(36).slice(2);
|
||||
var messageKey = '__reactIdleCallback$' + Math.random().toString(36).slice(2);
|
||||
var idleTick = function(event) {
|
||||
if (event.source !== window || event.data !== messageKey) {
|
||||
return;
|
||||
@@ -84,7 +83,9 @@ if (typeof requestAnimationFrame !== 'function') {
|
||||
var animationTick = function(rafTime) {
|
||||
isAnimationFrameScheduled = false;
|
||||
var nextFrameTime = rafTime - frameDeadline + activeFrameTime;
|
||||
if (nextFrameTime < activeFrameTime && previousFrameTime < activeFrameTime) {
|
||||
if (
|
||||
nextFrameTime < activeFrameTime && previousFrameTime < activeFrameTime
|
||||
) {
|
||||
if (nextFrameTime < 8) {
|
||||
// Defensive coding. We don't support higher frame rates than 120hz.
|
||||
// If we get lower than that, it is probably a bug.
|
||||
@@ -97,8 +98,9 @@ if (typeof requestAnimationFrame !== 'function') {
|
||||
// running on 120hz display or 90hz VR display.
|
||||
// Take the max of the two in case one of them was an anomaly due to
|
||||
// missed frame deadlines.
|
||||
activeFrameTime = nextFrameTime < previousFrameTime ?
|
||||
previousFrameTime : nextFrameTime;
|
||||
activeFrameTime = nextFrameTime < previousFrameTime
|
||||
? previousFrameTime
|
||||
: nextFrameTime;
|
||||
} else {
|
||||
previousFrameTime = nextFrameTime;
|
||||
}
|
||||
@@ -114,7 +116,7 @@ if (typeof requestAnimationFrame !== 'function') {
|
||||
}
|
||||
};
|
||||
|
||||
rAF = function(callback : (time : number) => void) : number {
|
||||
rAF = function(callback: (time: number) => void): number {
|
||||
// This assumes that we only schedule one callback at a time because that's
|
||||
// how Fiber uses it.
|
||||
scheduledRAFCallback = callback;
|
||||
@@ -126,7 +128,7 @@ if (typeof requestAnimationFrame !== 'function') {
|
||||
return 0;
|
||||
};
|
||||
|
||||
rIC = function(callback : (deadline : Deadline) => void) : number {
|
||||
rIC = function(callback: (deadline: Deadline) => void): number {
|
||||
// This assumes that we only schedule one callback at a time because that's
|
||||
// how Fiber uses it.
|
||||
scheduledRICCallback = callback;
|
||||
|
||||
@@ -34,20 +34,14 @@ describe('ReactDOMFiber', () => {
|
||||
it('should render strings as children', () => {
|
||||
const Box = ({value}) => <div>{value}</div>;
|
||||
|
||||
ReactDOM.render(
|
||||
<Box value="foo" />,
|
||||
container
|
||||
);
|
||||
ReactDOM.render(<Box value="foo" />, container);
|
||||
expect(container.textContent).toEqual('foo');
|
||||
});
|
||||
|
||||
it('should render numbers as children', () => {
|
||||
const Box = ({value}) => <div>{value}</div>;
|
||||
|
||||
ReactDOM.render(
|
||||
<Box value={10} />,
|
||||
container
|
||||
);
|
||||
ReactDOM.render(<Box value={10} />, container);
|
||||
|
||||
expect(container.textContent).toEqual('10');
|
||||
});
|
||||
@@ -55,20 +49,12 @@ describe('ReactDOMFiber', () => {
|
||||
it('should be called a callback argument', () => {
|
||||
// mounting phase
|
||||
let called = false;
|
||||
ReactDOM.render(
|
||||
<div>Foo</div>,
|
||||
container,
|
||||
() => called = true
|
||||
);
|
||||
ReactDOM.render(<div>Foo</div>, container, () => called = true);
|
||||
expect(called).toEqual(true);
|
||||
|
||||
// updating phase
|
||||
called = false;
|
||||
ReactDOM.render(
|
||||
<div>Foo</div>,
|
||||
container,
|
||||
() => called = true
|
||||
);
|
||||
ReactDOM.render(<div>Foo</div>, container, () => called = true);
|
||||
expect(called).toEqual(true);
|
||||
});
|
||||
|
||||
@@ -82,21 +68,13 @@ describe('ReactDOMFiber', () => {
|
||||
|
||||
// mounting phase
|
||||
let called = false;
|
||||
ReactDOM.render(
|
||||
element,
|
||||
container,
|
||||
() => called = true
|
||||
);
|
||||
ReactDOM.render(element, container, () => called = true);
|
||||
expect(called).toEqual(true);
|
||||
|
||||
// updating phase
|
||||
called = false;
|
||||
ReactDOM.unstable_batchedUpdates(() => {
|
||||
ReactDOM.render(
|
||||
element,
|
||||
container,
|
||||
() => called = true
|
||||
);
|
||||
ReactDOM.render(element, container, () => called = true);
|
||||
});
|
||||
expect(called).toEqual(true);
|
||||
});
|
||||
@@ -105,20 +83,14 @@ describe('ReactDOMFiber', () => {
|
||||
it('should render a component returning strings directly from render', () => {
|
||||
const Text = ({value}) => value;
|
||||
|
||||
ReactDOM.render(
|
||||
<Text value="foo" />,
|
||||
container
|
||||
);
|
||||
ReactDOM.render(<Text value="foo" />, container);
|
||||
expect(container.textContent).toEqual('foo');
|
||||
});
|
||||
|
||||
it('should render a component returning numbers directly from render', () => {
|
||||
const Text = ({value}) => value;
|
||||
|
||||
ReactDOM.render(
|
||||
<Text value={10} />,
|
||||
container
|
||||
);
|
||||
ReactDOM.render(<Text value={10} />, container);
|
||||
|
||||
expect(container.textContent).toEqual('10');
|
||||
});
|
||||
@@ -133,7 +105,7 @@ describe('ReactDOMFiber', () => {
|
||||
let instance = null;
|
||||
ReactDOM.render(
|
||||
<Text value="foo" ref={ref => instance = ref} />,
|
||||
container
|
||||
container,
|
||||
);
|
||||
|
||||
const textNode = ReactDOM.findDOMNode(instance);
|
||||
@@ -145,18 +117,12 @@ describe('ReactDOMFiber', () => {
|
||||
it('finds the first child when a component returns a fragment', () => {
|
||||
class Fragment extends React.Component {
|
||||
render() {
|
||||
return [
|
||||
<div />,
|
||||
<span />,
|
||||
];
|
||||
return [<div />, <span />];
|
||||
}
|
||||
}
|
||||
|
||||
let instance = null;
|
||||
ReactDOM.render(
|
||||
<Fragment ref={ref => instance = ref} />,
|
||||
container
|
||||
);
|
||||
ReactDOM.render(<Fragment ref={ref => instance = ref} />, container);
|
||||
|
||||
expect(container.childNodes.length).toBe(2);
|
||||
|
||||
@@ -174,18 +140,12 @@ describe('ReactDOMFiber', () => {
|
||||
|
||||
class Fragment extends React.Component {
|
||||
render() {
|
||||
return [
|
||||
<Wrapper><div /></Wrapper>,
|
||||
<span />,
|
||||
];
|
||||
return [<Wrapper><div /></Wrapper>, <span />];
|
||||
}
|
||||
}
|
||||
|
||||
let instance = null;
|
||||
ReactDOM.render(
|
||||
<Fragment ref={ref => instance = ref} />,
|
||||
container
|
||||
);
|
||||
ReactDOM.render(<Fragment ref={ref => instance = ref} />, container);
|
||||
|
||||
expect(container.childNodes.length).toBe(2);
|
||||
|
||||
@@ -203,19 +163,12 @@ describe('ReactDOMFiber', () => {
|
||||
|
||||
class Fragment extends React.Component {
|
||||
render() {
|
||||
return [
|
||||
<NullComponent />,
|
||||
<div />,
|
||||
<span />,
|
||||
];
|
||||
return [<NullComponent />, <div />, <span />];
|
||||
}
|
||||
}
|
||||
|
||||
let instance = null;
|
||||
ReactDOM.render(
|
||||
<Fragment ref={ref => instance = ref} />,
|
||||
container
|
||||
);
|
||||
ReactDOM.render(<Fragment ref={ref => instance = ref} />, container);
|
||||
|
||||
expect(container.childNodes.length).toBe(2);
|
||||
|
||||
@@ -234,7 +187,7 @@ describe('ReactDOMFiber', () => {
|
||||
var usePortal = function(tree) {
|
||||
return ReactDOM.unstable_createPortal(
|
||||
tree,
|
||||
document.createElement('div')
|
||||
document.createElement('div'),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -264,12 +217,9 @@ describe('ReactDOMFiber', () => {
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
{ReactDOM.unstable_createPortal(
|
||||
<div>portal</div>,
|
||||
portalContainer
|
||||
)}
|
||||
{ReactDOM.unstable_createPortal(<div>portal</div>, portalContainer)}
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(portalContainer.innerHTML).toBe('<div>portal</div>');
|
||||
expect(container.innerHTML).toBe('<div></div>');
|
||||
@@ -315,7 +265,7 @@ describe('ReactDOMFiber', () => {
|
||||
<Child name={`normal[0]:${step}`} />,
|
||||
ReactDOM.unstable_createPortal(
|
||||
<Child name={`portal1[0]:${step}`} />,
|
||||
portalContainer1
|
||||
portalContainer1,
|
||||
),
|
||||
<Child name={`normal[1]:${step}`} />,
|
||||
ReactDOM.unstable_createPortal(
|
||||
@@ -323,7 +273,7 @@ describe('ReactDOMFiber', () => {
|
||||
<Child name={`portal2[0]:${step}`} />,
|
||||
<Child name={`portal2[1]:${step}`} />,
|
||||
],
|
||||
portalContainer2
|
||||
portalContainer2,
|
||||
),
|
||||
];
|
||||
}
|
||||
@@ -331,8 +281,12 @@ describe('ReactDOMFiber', () => {
|
||||
|
||||
ReactDOM.render(<Parent step="a" />, container);
|
||||
expect(portalContainer1.innerHTML).toBe('<div>portal1[0]:a</div>');
|
||||
expect(portalContainer2.innerHTML).toBe('<div>portal2[0]:a</div><div>portal2[1]:a</div>');
|
||||
expect(container.innerHTML).toBe('<div>normal[0]:a</div><div>normal[1]:a</div>');
|
||||
expect(portalContainer2.innerHTML).toBe(
|
||||
'<div>portal2[0]:a</div><div>portal2[1]:a</div>',
|
||||
);
|
||||
expect(container.innerHTML).toBe(
|
||||
'<div>normal[0]:a</div><div>normal[1]:a</div>',
|
||||
);
|
||||
expect(ops).toEqual([
|
||||
'normal[0]:a componentDidMount',
|
||||
'portal1[0]:a componentDidMount',
|
||||
@@ -345,8 +299,12 @@ describe('ReactDOMFiber', () => {
|
||||
ops.length = 0;
|
||||
ReactDOM.render(<Parent step="b" />, container);
|
||||
expect(portalContainer1.innerHTML).toBe('<div>portal1[0]:b</div>');
|
||||
expect(portalContainer2.innerHTML).toBe('<div>portal2[0]:b</div><div>portal2[1]:b</div>');
|
||||
expect(container.innerHTML).toBe('<div>normal[0]:b</div><div>normal[1]:b</div>');
|
||||
expect(portalContainer2.innerHTML).toBe(
|
||||
'<div>portal2[0]:b</div><div>portal2[1]:b</div>',
|
||||
);
|
||||
expect(container.innerHTML).toBe(
|
||||
'<div>normal[0]:b</div><div>normal[1]:b</div>',
|
||||
);
|
||||
expect(ops).toEqual([
|
||||
'normal[0]:b componentDidUpdate',
|
||||
'portal1[0]:b componentDidUpdate',
|
||||
@@ -376,26 +334,36 @@ describe('ReactDOMFiber', () => {
|
||||
var portalContainer2 = document.createElement('div');
|
||||
var portalContainer3 = document.createElement('div');
|
||||
|
||||
ReactDOM.render([
|
||||
<div>normal[0]</div>,
|
||||
ReactDOM.unstable_createPortal([
|
||||
<div>portal1[0]</div>,
|
||||
ReactDOM.render(
|
||||
[
|
||||
<div>normal[0]</div>,
|
||||
ReactDOM.unstable_createPortal(
|
||||
<div>portal2[0]</div>,
|
||||
portalContainer2
|
||||
[
|
||||
<div>portal1[0]</div>,
|
||||
ReactDOM.unstable_createPortal(
|
||||
<div>portal2[0]</div>,
|
||||
portalContainer2,
|
||||
),
|
||||
ReactDOM.unstable_createPortal(
|
||||
<div>portal3[0]</div>,
|
||||
portalContainer3,
|
||||
),
|
||||
<div>portal1[1]</div>,
|
||||
],
|
||||
portalContainer1,
|
||||
),
|
||||
ReactDOM.unstable_createPortal(
|
||||
<div>portal3[0]</div>,
|
||||
portalContainer3
|
||||
),
|
||||
<div>portal1[1]</div>,
|
||||
], portalContainer1),
|
||||
<div>normal[1]</div>,
|
||||
], container);
|
||||
expect(portalContainer1.innerHTML).toBe('<div>portal1[0]</div><div>portal1[1]</div>');
|
||||
<div>normal[1]</div>,
|
||||
],
|
||||
container,
|
||||
);
|
||||
expect(portalContainer1.innerHTML).toBe(
|
||||
'<div>portal1[0]</div><div>portal1[1]</div>',
|
||||
);
|
||||
expect(portalContainer2.innerHTML).toBe('<div>portal2[0]</div>');
|
||||
expect(portalContainer3.innerHTML).toBe('<div>portal3[0]</div>');
|
||||
expect(container.innerHTML).toBe('<div>normal[0]</div><div>normal[1]</div>');
|
||||
expect(container.innerHTML).toBe(
|
||||
'<div>normal[0]</div><div>normal[1]</div>',
|
||||
);
|
||||
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
expect(portalContainer1.innerHTML).toBe('');
|
||||
@@ -409,72 +377,54 @@ describe('ReactDOMFiber', () => {
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
{ReactDOM.unstable_createPortal(
|
||||
<div>portal:1</div>,
|
||||
portalContainer
|
||||
)}
|
||||
{ReactDOM.unstable_createPortal(<div>portal:1</div>, portalContainer)}
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(portalContainer.innerHTML).toBe('<div>portal:1</div>');
|
||||
expect(container.innerHTML).toBe('<div></div>');
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
{ReactDOM.unstable_createPortal(
|
||||
<div>portal:2</div>,
|
||||
portalContainer
|
||||
)}
|
||||
{ReactDOM.unstable_createPortal(<div>portal:2</div>, portalContainer)}
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(portalContainer.innerHTML).toBe('<div>portal:2</div>');
|
||||
expect(container.innerHTML).toBe('<div></div>');
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
{ReactDOM.unstable_createPortal(
|
||||
<p>portal:3</p>,
|
||||
portalContainer
|
||||
)}
|
||||
{ReactDOM.unstable_createPortal(<p>portal:3</p>, portalContainer)}
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(portalContainer.innerHTML).toBe('<p>portal:3</p>');
|
||||
expect(container.innerHTML).toBe('<div></div>');
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
{ReactDOM.unstable_createPortal(
|
||||
['Hi', 'Bye'],
|
||||
portalContainer
|
||||
)}
|
||||
{ReactDOM.unstable_createPortal(['Hi', 'Bye'], portalContainer)}
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(portalContainer.innerHTML).toBe('HiBye');
|
||||
expect(container.innerHTML).toBe('<div></div>');
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
{ReactDOM.unstable_createPortal(
|
||||
['Bye', 'Hi'],
|
||||
portalContainer
|
||||
)}
|
||||
{ReactDOM.unstable_createPortal(['Bye', 'Hi'], portalContainer)}
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(portalContainer.innerHTML).toBe('ByeHi');
|
||||
expect(container.innerHTML).toBe('<div></div>');
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
{ReactDOM.unstable_createPortal(
|
||||
null,
|
||||
portalContainer
|
||||
)}
|
||||
{ReactDOM.unstable_createPortal(null, portalContainer)}
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
expect(portalContainer.innerHTML).toBe('');
|
||||
expect(container.innerHTML).toBe('<div></div>');
|
||||
@@ -484,20 +434,16 @@ describe('ReactDOMFiber', () => {
|
||||
assertNamespacesMatch(
|
||||
<svg {...expectSVG}>
|
||||
<image {...expectSVG} />
|
||||
{usePortal(
|
||||
<div {...expectHTML} />
|
||||
)}
|
||||
{usePortal(<div {...expectHTML} />)}
|
||||
<image {...expectSVG} />
|
||||
</svg>
|
||||
</svg>,
|
||||
);
|
||||
assertNamespacesMatch(
|
||||
<math {...expectMath}>
|
||||
<mi {...expectMath} />
|
||||
{usePortal(
|
||||
<div {...expectHTML} />
|
||||
)}
|
||||
{usePortal(<div {...expectHTML} />)}
|
||||
<mi {...expectMath} />
|
||||
</math>
|
||||
</math>,
|
||||
);
|
||||
assertNamespacesMatch(
|
||||
<div {...expectHTML}>
|
||||
@@ -505,10 +451,10 @@ describe('ReactDOMFiber', () => {
|
||||
{usePortal(
|
||||
<svg {...expectSVG}>
|
||||
<image {...expectSVG} />
|
||||
</svg>
|
||||
</svg>,
|
||||
)}
|
||||
<p {...expectHTML} />
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -516,15 +462,11 @@ describe('ReactDOMFiber', () => {
|
||||
assertNamespacesMatch(
|
||||
<svg {...expectSVG}>
|
||||
<image {...expectSVG} />
|
||||
{usePortal(
|
||||
<div {...expectHTML} />
|
||||
)}
|
||||
{usePortal(<div {...expectHTML} />)}
|
||||
<image {...expectSVG} />
|
||||
{usePortal(
|
||||
<div {...expectHTML} />
|
||||
)}
|
||||
{usePortal(<div {...expectHTML} />)}
|
||||
<image {...expectSVG} />
|
||||
</svg>
|
||||
</svg>,
|
||||
);
|
||||
assertNamespacesMatch(
|
||||
<div {...expectHTML}>
|
||||
@@ -533,11 +475,11 @@ describe('ReactDOMFiber', () => {
|
||||
{usePortal(
|
||||
<svg {...expectSVG}>
|
||||
<image {...expectSVG} />
|
||||
</svg>
|
||||
</svg>,
|
||||
)}
|
||||
</math>
|
||||
<p {...expectHTML} />
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
assertNamespacesMatch(
|
||||
<math {...expectMath}>
|
||||
@@ -553,34 +495,30 @@ describe('ReactDOMFiber', () => {
|
||||
<p {...expectHTML} />
|
||||
</foreignObject>
|
||||
<image {...expectSVG} />
|
||||
</svg>
|
||||
</svg>,
|
||||
)}
|
||||
<mi {...expectMath} />
|
||||
</math>
|
||||
</math>,
|
||||
);
|
||||
assertNamespacesMatch(
|
||||
<div {...expectHTML}>
|
||||
{usePortal(
|
||||
<svg {...expectSVG}>
|
||||
{usePortal(
|
||||
<div {...expectHTML} />
|
||||
)}
|
||||
{usePortal(<div {...expectHTML} />)}
|
||||
<image {...expectSVG} />
|
||||
</svg>
|
||||
</svg>,
|
||||
)}
|
||||
<p {...expectHTML} />
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
assertNamespacesMatch(
|
||||
<svg {...expectSVG}>
|
||||
<svg {...expectSVG}>
|
||||
{usePortal(
|
||||
<div {...expectHTML} />
|
||||
)}
|
||||
{usePortal(<div {...expectHTML} />)}
|
||||
<image {...expectSVG} />
|
||||
</svg>
|
||||
<image {...expectSVG} />
|
||||
</svg>
|
||||
</svg>,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -590,7 +528,7 @@ describe('ReactDOMFiber', () => {
|
||||
{usePortal(
|
||||
<svg {...expectSVG}>
|
||||
<image {...expectSVG} />
|
||||
</svg>
|
||||
</svg>,
|
||||
)}
|
||||
<p {...expectHTML} />
|
||||
<svg {...expectSVG}>
|
||||
@@ -603,7 +541,7 @@ describe('ReactDOMFiber', () => {
|
||||
<image {...expectSVG} />
|
||||
</svg>
|
||||
<p {...expectHTML} />
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
assertNamespacesMatch(
|
||||
<div {...expectHTML}>
|
||||
@@ -617,7 +555,7 @@ describe('ReactDOMFiber', () => {
|
||||
<image {...expectSVG} />
|
||||
</svg>
|
||||
<image {...expectSVG} />
|
||||
</svg>
|
||||
</svg>,
|
||||
)}
|
||||
<image {...expectSVG} />
|
||||
<foreignObject {...expectSVG}>
|
||||
@@ -629,7 +567,7 @@ describe('ReactDOMFiber', () => {
|
||||
<image {...expectSVG} />
|
||||
</svg>
|
||||
<p {...expectHTML} />
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
assertNamespacesMatch(
|
||||
<div {...expectHTML}>
|
||||
@@ -647,14 +585,14 @@ describe('ReactDOMFiber', () => {
|
||||
{usePortal(<p {...expectHTML} />)}
|
||||
</svg>
|
||||
<image {...expectSVG} />
|
||||
</svg>
|
||||
</svg>,
|
||||
)}
|
||||
<p {...expectHTML} />
|
||||
</foreignObject>
|
||||
<image {...expectSVG} />
|
||||
</svg>
|
||||
<p {...expectHTML} />
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -667,12 +605,10 @@ describe('ReactDOMFiber', () => {
|
||||
assertNamespacesMatch(
|
||||
<svg {...expectSVG}>
|
||||
<BrokenRender />
|
||||
</svg>
|
||||
</svg>,
|
||||
);
|
||||
}).toThrow('Hello');
|
||||
assertNamespacesMatch(
|
||||
<div {...expectHTML} />
|
||||
);
|
||||
assertNamespacesMatch(<div {...expectHTML} />);
|
||||
});
|
||||
|
||||
it('should unwind namespaces on caught errors', () => {
|
||||
@@ -703,11 +639,9 @@ describe('ReactDOMFiber', () => {
|
||||
</ErrorBoundary>
|
||||
</foreignObject>
|
||||
<image {...expectSVG} />
|
||||
</svg>
|
||||
);
|
||||
assertNamespacesMatch(
|
||||
<div {...expectHTML} />
|
||||
</svg>,
|
||||
);
|
||||
assertNamespacesMatch(<div {...expectHTML} />);
|
||||
});
|
||||
|
||||
it('should unwind namespaces on caught errors in a portal', () => {
|
||||
@@ -736,13 +670,11 @@ describe('ReactDOMFiber', () => {
|
||||
<math {...expectMath}>
|
||||
<BrokenRender />)
|
||||
</math>
|
||||
</div>
|
||||
</div>,
|
||||
)}
|
||||
</ErrorBoundary>
|
||||
{usePortal(
|
||||
<div {...expectHTML} />
|
||||
)}
|
||||
</svg>
|
||||
{usePortal(<div {...expectHTML} />)}
|
||||
</svg>,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -771,10 +703,7 @@ describe('ReactDOMFiber', () => {
|
||||
}
|
||||
|
||||
render() {
|
||||
return ReactDOM.unstable_createPortal(
|
||||
<Component />,
|
||||
portalContainer
|
||||
);
|
||||
return ReactDOM.unstable_createPortal(<Component />, portalContainer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -815,10 +744,7 @@ describe('ReactDOMFiber', () => {
|
||||
}
|
||||
|
||||
render() {
|
||||
return ReactDOM.unstable_createPortal(
|
||||
<Component />,
|
||||
portalContainer
|
||||
);
|
||||
return ReactDOM.unstable_createPortal(<Component />, portalContainer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -858,10 +784,7 @@ describe('ReactDOMFiber', () => {
|
||||
}
|
||||
|
||||
render() {
|
||||
return ReactDOM.unstable_createPortal(
|
||||
<Component />,
|
||||
portalContainer
|
||||
);
|
||||
return ReactDOM.unstable_createPortal(<Component />, portalContainer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -876,11 +799,9 @@ describe('ReactDOMFiber', () => {
|
||||
it('findDOMNode should find dom element after expanding a fragment', () => {
|
||||
class MyNode extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
!this.props.flag ?
|
||||
[<div key="a" />] :
|
||||
[<span key="b" />, <div key="a" />]
|
||||
);
|
||||
return !this.props.flag
|
||||
? [<div key="a" />]
|
||||
: [<span key="b" />, <div key="a" />];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -904,13 +825,15 @@ describe('ReactDOMFiber', () => {
|
||||
ReactDOM.render(
|
||||
<div onClick={() => ops.push('parent clicked')}>
|
||||
{ReactDOM.unstable_createPortal(
|
||||
<div onClick={() => ops.push('portal clicked')} ref={n => portal = n}>
|
||||
<div
|
||||
onClick={() => ops.push('portal clicked')}
|
||||
ref={n => portal = n}>
|
||||
portal
|
||||
</div>,
|
||||
portalContainer
|
||||
portalContainer,
|
||||
)}
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
|
||||
expect(portal.tagName).toBe('DIV');
|
||||
@@ -919,13 +842,10 @@ describe('ReactDOMFiber', () => {
|
||||
ReactTestUtils.simulateNativeEventOnNode(
|
||||
'topClick',
|
||||
portal,
|
||||
fakeNativeEvent
|
||||
fakeNativeEvent,
|
||||
);
|
||||
|
||||
expect(ops).toEqual([
|
||||
'portal clicked',
|
||||
'parent clicked',
|
||||
]);
|
||||
expect(ops).toEqual(['portal clicked', 'parent clicked']);
|
||||
});
|
||||
|
||||
it('should not onMouseLeave when staying in the portal', () => {
|
||||
@@ -938,24 +858,16 @@ describe('ReactDOMFiber', () => {
|
||||
|
||||
function simulateMouseMove(from, to) {
|
||||
if (from) {
|
||||
ReactTestUtils.simulateNativeEventOnNode(
|
||||
'topMouseOut',
|
||||
from,
|
||||
{
|
||||
target: from,
|
||||
relatedTarget: to,
|
||||
}
|
||||
);
|
||||
ReactTestUtils.simulateNativeEventOnNode('topMouseOut', from, {
|
||||
target: from,
|
||||
relatedTarget: to,
|
||||
});
|
||||
}
|
||||
if (to) {
|
||||
ReactTestUtils.simulateNativeEventOnNode(
|
||||
'topMouseOver',
|
||||
to,
|
||||
{
|
||||
target: to,
|
||||
relatedTarget: from,
|
||||
}
|
||||
);
|
||||
ReactTestUtils.simulateNativeEventOnNode('topMouseOver', to, {
|
||||
target: to,
|
||||
relatedTarget: from,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -972,18 +884,16 @@ describe('ReactDOMFiber', () => {
|
||||
ref={n => secondTarget = n}>
|
||||
portal
|
||||
</div>,
|
||||
portalContainer
|
||||
portalContainer,
|
||||
)}
|
||||
</div>
|
||||
<div ref={n => thirdTarget = n} />
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
|
||||
simulateMouseMove(null, firstTarget);
|
||||
expect(ops).toEqual([
|
||||
'enter parent',
|
||||
]);
|
||||
expect(ops).toEqual(['enter parent']);
|
||||
|
||||
ops = [];
|
||||
|
||||
@@ -1008,18 +918,16 @@ describe('ReactDOMFiber', () => {
|
||||
const handlerB = () => ops.push('B');
|
||||
|
||||
class Example extends React.Component {
|
||||
state = { flip: false, count: 0 };
|
||||
state = {flip: false, count: 0};
|
||||
flip() {
|
||||
this.setState({ flip: true, count: this.state.count + 1 });
|
||||
this.setState({flip: true, count: this.state.count + 1});
|
||||
}
|
||||
tick() {
|
||||
this.setState({ count: this.state.count + 1 });
|
||||
this.setState({count: this.state.count + 1});
|
||||
}
|
||||
render() {
|
||||
const useB = !this.props.forceA && this.state.flip;
|
||||
return (
|
||||
<div onClick={useB ? handlerB : handlerA} />
|
||||
);
|
||||
return <div onClick={useB ? handlerB : handlerA} />;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1043,7 +951,7 @@ describe('ReactDOMFiber', () => {
|
||||
ReactTestUtils.simulateNativeEventOnNode(
|
||||
'topClick',
|
||||
target,
|
||||
fakeNativeEvent
|
||||
fakeNativeEvent,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1082,7 +990,6 @@ describe('ReactDOMFiber', () => {
|
||||
// Any click that happens after commit, should invoke A.
|
||||
click(node);
|
||||
expect(ops).toEqual(['A']);
|
||||
|
||||
});
|
||||
|
||||
it('should not crash encountering low-priority tree', () => {
|
||||
@@ -1090,7 +997,7 @@ describe('ReactDOMFiber', () => {
|
||||
<div hidden={true}>
|
||||
<div />
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -1115,11 +1022,17 @@ describe('disableNewFiberFeatures', () => {
|
||||
it('throws if non-element passed to top-level render', () => {
|
||||
const message = 'render(): Invalid component element.';
|
||||
expect(() => ReactDOM.render(null, container)).toThrow(message, container);
|
||||
expect(() => ReactDOM.render(undefined, container)).toThrow(message, container);
|
||||
expect(() => ReactDOM.render(undefined, container)).toThrow(
|
||||
message,
|
||||
container,
|
||||
);
|
||||
expect(() => ReactDOM.render(false, container)).toThrow(message, container);
|
||||
expect(() => ReactDOM.render('Hi', container)).toThrow(message, container);
|
||||
expect(() => ReactDOM.render(999, container)).toThrow(message, container);
|
||||
expect(() => ReactDOM.render([<div />], container)).toThrow(message, container);
|
||||
expect(() => ReactDOM.render([<div />], container)).toThrow(
|
||||
message,
|
||||
container,
|
||||
);
|
||||
});
|
||||
|
||||
it('throws if something other than false, null, or an element is returned from render', () => {
|
||||
@@ -1127,9 +1040,16 @@ describe('disableNewFiberFeatures', () => {
|
||||
return props.children;
|
||||
}
|
||||
|
||||
expect(() => ReactDOM.render(<Render>Hi</Render>, container)).toThrow(/You may have returned undefined/);
|
||||
expect(() => ReactDOM.render(<Render>{999}</Render>, container)).toThrow(/You may have returned undefined/);
|
||||
expect(() => ReactDOM.render(<Render>[<div />]</Render>, container)).toThrow(/You may have returned undefined/);
|
||||
expect(() => ReactDOM.render(<Render>Hi</Render>, container)).toThrow(
|
||||
/You may have returned undefined/,
|
||||
);
|
||||
expect(() => ReactDOM.render(<Render>{999}</Render>, container)).toThrow(
|
||||
/You may have returned undefined/,
|
||||
);
|
||||
expect(() =>
|
||||
ReactDOM.render(<Render>[<div />]</Render>, container)).toThrow(
|
||||
/You may have returned undefined/,
|
||||
);
|
||||
});
|
||||
|
||||
it('treats mocked render functions as if they return null', () => {
|
||||
|
||||
@@ -16,14 +16,14 @@ type InputWithWrapperState = HTMLInputElement & {
|
||||
_wrapperState: {
|
||||
initialValue: ?string,
|
||||
initialChecked: ?boolean,
|
||||
controlled?: boolean
|
||||
}
|
||||
controlled?: boolean,
|
||||
},
|
||||
};
|
||||
|
||||
var DOMPropertyOperations = require('DOMPropertyOperations');
|
||||
var ReactControlledValuePropTypes = require('ReactControlledValuePropTypes');
|
||||
var ReactDOMComponentTree = require('ReactDOMComponentTree');
|
||||
var { getCurrentFiberOwnerName } = require('ReactDebugCurrentFiber');
|
||||
var {getCurrentFiberOwnerName} = require('ReactDebugCurrentFiber');
|
||||
|
||||
var invariant = require('fbjs/lib/invariant');
|
||||
var warning = require('fbjs/lib/warning');
|
||||
@@ -55,38 +55,42 @@ function isControlled(props) {
|
||||
* See http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html
|
||||
*/
|
||||
var ReactDOMInput = {
|
||||
getHostProps: function(element : Element, props : Object) {
|
||||
var node = ((element : any) : InputWithWrapperState);
|
||||
getHostProps: function(element: Element, props: Object) {
|
||||
var node = ((element: any): InputWithWrapperState);
|
||||
var value = props.value;
|
||||
var checked = props.checked;
|
||||
|
||||
var hostProps = Object.assign({
|
||||
// Make sure we set .type before any other properties (setting .value
|
||||
// before .type means .value is lost in IE11 and below)
|
||||
type: undefined,
|
||||
// Make sure we set .step before .value (setting .value before .step
|
||||
// means .value is rounded on mount, based upon step precision)
|
||||
step: undefined,
|
||||
// Make sure we set .min & .max before .value (to ensure proper order
|
||||
// in corner cases such as min or max deriving from value, e.g. Issue #7170)
|
||||
min: undefined,
|
||||
max: undefined,
|
||||
}, props, {
|
||||
defaultChecked: undefined,
|
||||
defaultValue: undefined,
|
||||
value: value != null ? value : node._wrapperState.initialValue,
|
||||
checked: checked != null ? checked : node._wrapperState.initialChecked,
|
||||
});
|
||||
var hostProps = Object.assign(
|
||||
{
|
||||
// Make sure we set .type before any other properties (setting .value
|
||||
// before .type means .value is lost in IE11 and below)
|
||||
type: undefined,
|
||||
// Make sure we set .step before .value (setting .value before .step
|
||||
// means .value is rounded on mount, based upon step precision)
|
||||
step: undefined,
|
||||
// Make sure we set .min & .max before .value (to ensure proper order
|
||||
// in corner cases such as min or max deriving from value, e.g. Issue #7170)
|
||||
min: undefined,
|
||||
max: undefined,
|
||||
},
|
||||
props,
|
||||
{
|
||||
defaultChecked: undefined,
|
||||
defaultValue: undefined,
|
||||
value: value != null ? value : node._wrapperState.initialValue,
|
||||
checked: checked != null ? checked : node._wrapperState.initialChecked,
|
||||
},
|
||||
);
|
||||
|
||||
return hostProps;
|
||||
},
|
||||
|
||||
mountWrapper: function(element : Element, props : Object) {
|
||||
mountWrapper: function(element: Element, props: Object) {
|
||||
if (__DEV__) {
|
||||
ReactControlledValuePropTypes.checkPropTypes(
|
||||
'input',
|
||||
props,
|
||||
getCurrentFiberOwnerName()
|
||||
getCurrentFiberOwnerName(),
|
||||
);
|
||||
|
||||
if (
|
||||
@@ -97,13 +101,13 @@ var ReactDOMInput = {
|
||||
warning(
|
||||
false,
|
||||
'%s contains an input of type %s with both checked and defaultChecked props. ' +
|
||||
'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',
|
||||
'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',
|
||||
getCurrentFiberOwnerName() || 'A component',
|
||||
props.type
|
||||
props.type,
|
||||
);
|
||||
didWarnCheckedDefaultChecked = true;
|
||||
}
|
||||
@@ -115,22 +119,24 @@ var ReactDOMInput = {
|
||||
warning(
|
||||
false,
|
||||
'%s contains an input of type %s with both value and defaultValue props. ' +
|
||||
'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',
|
||||
'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',
|
||||
getCurrentFiberOwnerName() || 'A component',
|
||||
props.type
|
||||
props.type,
|
||||
);
|
||||
didWarnValueDefaultValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
var defaultValue = props.defaultValue;
|
||||
var node = ((element : any) : InputWithWrapperState);
|
||||
var node = ((element: any): InputWithWrapperState);
|
||||
node._wrapperState = {
|
||||
initialChecked: props.checked != null ? props.checked : props.defaultChecked,
|
||||
initialChecked: props.checked != null
|
||||
? props.checked
|
||||
: props.defaultChecked,
|
||||
initialValue: props.value != null ? props.value : defaultValue,
|
||||
};
|
||||
|
||||
@@ -139,32 +145,40 @@ var ReactDOMInput = {
|
||||
}
|
||||
},
|
||||
|
||||
updateWrapper: function(element : Element, props : Object) {
|
||||
var node = ((element : any) : InputWithWrapperState);
|
||||
updateWrapper: function(element: Element, props: Object) {
|
||||
var node = ((element: any): InputWithWrapperState);
|
||||
if (__DEV__) {
|
||||
var controlled = isControlled(props);
|
||||
|
||||
if (!node._wrapperState.controlled && controlled && !didWarnUncontrolledToControlled) {
|
||||
if (
|
||||
!node._wrapperState.controlled &&
|
||||
controlled &&
|
||||
!didWarnUncontrolledToControlled
|
||||
) {
|
||||
warning(
|
||||
false,
|
||||
'%s is changing an uncontrolled input of type %s to be controlled. ' +
|
||||
'Input elements should not switch from uncontrolled to controlled (or vice versa). ' +
|
||||
'Decide between using a controlled or uncontrolled input ' +
|
||||
'element for the lifetime of the component. More info: https://fb.me/react-controlled-components',
|
||||
'Input elements should not switch from uncontrolled to controlled (or vice versa). ' +
|
||||
'Decide between using a controlled or uncontrolled input ' +
|
||||
'element for the lifetime of the component. More info: https://fb.me/react-controlled-components',
|
||||
getCurrentFiberOwnerName() || 'A component',
|
||||
props.type
|
||||
props.type,
|
||||
);
|
||||
didWarnUncontrolledToControlled = true;
|
||||
}
|
||||
if (node._wrapperState.controlled && !controlled && !didWarnControlledToUncontrolled) {
|
||||
if (
|
||||
node._wrapperState.controlled &&
|
||||
!controlled &&
|
||||
!didWarnControlledToUncontrolled
|
||||
) {
|
||||
warning(
|
||||
false,
|
||||
'%s is changing a controlled input of type %s to be uncontrolled. ' +
|
||||
'Input elements should not switch from controlled to uncontrolled (or vice versa). ' +
|
||||
'Decide between using a controlled or uncontrolled input ' +
|
||||
'element for the lifetime of the component. More info: https://fb.me/react-controlled-components',
|
||||
'Input elements should not switch from controlled to uncontrolled (or vice versa). ' +
|
||||
'Decide between using a controlled or uncontrolled input ' +
|
||||
'element for the lifetime of the component. More info: https://fb.me/react-controlled-components',
|
||||
getCurrentFiberOwnerName() || 'A component',
|
||||
props.type
|
||||
props.type,
|
||||
);
|
||||
didWarnControlledToUncontrolled = true;
|
||||
}
|
||||
@@ -175,13 +189,12 @@ var ReactDOMInput = {
|
||||
DOMPropertyOperations.setValueForProperty(
|
||||
node,
|
||||
'checked',
|
||||
checked || false
|
||||
checked || false,
|
||||
);
|
||||
}
|
||||
|
||||
var value = props.value;
|
||||
if (value != null) {
|
||||
|
||||
// Cast `value` to a string to ensure the value is set correctly. While
|
||||
// browsers typically do this as necessary, jsdom doesn't.
|
||||
var newValue = '' + value;
|
||||
@@ -210,8 +223,8 @@ var ReactDOMInput = {
|
||||
}
|
||||
},
|
||||
|
||||
postMountWrapper: function(element : Element, props : Object) {
|
||||
var node = ((element : any) : InputWithWrapperState);
|
||||
postMountWrapper: function(element: Element, props: Object) {
|
||||
var node = ((element: any): InputWithWrapperState);
|
||||
|
||||
// Detach value from defaultValue. We won't do anything if we're working on
|
||||
// submit or reset inputs as those values & defaultValues are linked. They
|
||||
@@ -256,8 +269,8 @@ var ReactDOMInput = {
|
||||
}
|
||||
},
|
||||
|
||||
restoreControlledState: function(element : Element, props : Object) {
|
||||
var node = ((element : any) : InputWithWrapperState);
|
||||
restoreControlledState: function(element: Element, props: Object) {
|
||||
var node = ((element: any): InputWithWrapperState);
|
||||
ReactDOMInput.updateWrapper(node, props);
|
||||
updateNamedCousins(node, props);
|
||||
},
|
||||
@@ -266,10 +279,10 @@ var ReactDOMInput = {
|
||||
function updateNamedCousins(rootNode, props) {
|
||||
var name = props.name;
|
||||
if (props.type === 'radio' && name != null) {
|
||||
var queryRoot : Element = rootNode;
|
||||
var queryRoot: Element = rootNode;
|
||||
|
||||
while (queryRoot.parentNode) {
|
||||
queryRoot = ((queryRoot.parentNode : any) : Element);
|
||||
queryRoot = ((queryRoot.parentNode: any): Element);
|
||||
}
|
||||
|
||||
// If `rootNode.form` was non-null, then we could try `form.elements`,
|
||||
@@ -280,23 +293,25 @@ function updateNamedCousins(rootNode, props) {
|
||||
// document. Let's just use the local `querySelectorAll` to ensure we don't
|
||||
// miss anything.
|
||||
var group = queryRoot.querySelectorAll(
|
||||
'input[name=' + JSON.stringify('' + name) + '][type="radio"]');
|
||||
'input[name=' + JSON.stringify('' + name) + '][type="radio"]',
|
||||
);
|
||||
|
||||
for (var i = 0; i < group.length; i++) {
|
||||
var otherNode = ((group[i] : any) : HTMLInputElement);
|
||||
if (otherNode === rootNode ||
|
||||
otherNode.form !== rootNode.form) {
|
||||
var otherNode = ((group[i]: any): HTMLInputElement);
|
||||
if (otherNode === rootNode || otherNode.form !== rootNode.form) {
|
||||
continue;
|
||||
}
|
||||
// This will throw if radio buttons rendered by different copies of React
|
||||
// and the same name are rendered into the same form (same as #1939).
|
||||
// That's probably okay; we don't support it just as we don't support
|
||||
// mixing React radio buttons with non-React ones.
|
||||
var otherProps = ReactDOMComponentTree.getFiberCurrentPropsFromNode(otherNode);
|
||||
var otherProps = ReactDOMComponentTree.getFiberCurrentPropsFromNode(
|
||||
otherNode,
|
||||
);
|
||||
invariant(
|
||||
otherProps,
|
||||
'ReactDOMInput: Mixing React and non-React radio inputs with the ' +
|
||||
'same `name` is not supported.'
|
||||
'same `name` is not supported.',
|
||||
);
|
||||
// If this is a controlled radio button group, forcing the input that
|
||||
// was previously checked to update will cause it to be come re-checked
|
||||
|
||||
@@ -39,25 +39,25 @@ function flattenChildren(children) {
|
||||
* Implements an <option> host component that warns when `selected` is set.
|
||||
*/
|
||||
var ReactDOMOption = {
|
||||
mountWrapper: function(element : Element, props : Object) {
|
||||
mountWrapper: function(element: Element, props: Object) {
|
||||
// TODO (yungsters): Remove support for `selected` in <option>.
|
||||
if (__DEV__) {
|
||||
warning(
|
||||
props.selected == null,
|
||||
'Use the `defaultValue` or `value` props on <select> instead of ' +
|
||||
'setting `selected` on <option>.'
|
||||
'setting `selected` on <option>.',
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
postMountWrapper: function(element : Element, props : Object) {
|
||||
postMountWrapper: function(element: Element, props: Object) {
|
||||
// value="" should make a value attribute (#6219)
|
||||
if (props.value != null) {
|
||||
element.setAttribute('value', props.value);
|
||||
}
|
||||
},
|
||||
|
||||
getHostProps: function(element : Element, props : Object) {
|
||||
getHostProps: function(element: Element, props: Object) {
|
||||
var hostProps = Object.assign({children: undefined}, props);
|
||||
|
||||
var content = flattenChildren(props.children);
|
||||
@@ -68,7 +68,6 @@ var ReactDOMOption = {
|
||||
|
||||
return hostProps;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
module.exports = ReactDOMOption;
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
type SelectWithWrapperState = HTMLSelectElement & {
|
||||
_wrapperState: {
|
||||
initialValue: ?string,
|
||||
wasMultiple: boolean
|
||||
}
|
||||
wasMultiple: boolean,
|
||||
},
|
||||
};
|
||||
|
||||
var ReactControlledValuePropTypes = require('ReactControlledValuePropTypes');
|
||||
var { getCurrentFiberOwnerName } = require('ReactDebugCurrentFiber');
|
||||
var {getCurrentFiberOwnerName} = require('ReactDebugCurrentFiber');
|
||||
var warning = require('fbjs/lib/warning');
|
||||
|
||||
var didWarnValueDefaultValue = false;
|
||||
@@ -42,7 +42,7 @@ function checkSelectPropTypes(props) {
|
||||
ReactControlledValuePropTypes.checkPropTypes(
|
||||
'select',
|
||||
props,
|
||||
getCurrentFiberOwnerName()
|
||||
getCurrentFiberOwnerName(),
|
||||
);
|
||||
|
||||
for (var i = 0; i < valuePropNames.length; i++) {
|
||||
@@ -55,28 +55,34 @@ function checkSelectPropTypes(props) {
|
||||
warning(
|
||||
false,
|
||||
'The `%s` prop supplied to <select> must be an array if ' +
|
||||
'`multiple` is true.%s',
|
||||
'`multiple` is true.%s',
|
||||
propName,
|
||||
getDeclarationErrorAddendum()
|
||||
getDeclarationErrorAddendum(),
|
||||
);
|
||||
} else if (!props.multiple && isArray) {
|
||||
warning(
|
||||
false,
|
||||
'The `%s` prop supplied to <select> must be a scalar ' +
|
||||
'value if `multiple` is false.%s',
|
||||
'value if `multiple` is false.%s',
|
||||
propName,
|
||||
getDeclarationErrorAddendum()
|
||||
getDeclarationErrorAddendum(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateOptions(node : HTMLSelectElement, multiple : boolean, propValue : any) {
|
||||
type IndexableHTMLOptionsCollection = HTMLOptionsCollection & { [key:number]: HTMLOptionElement };
|
||||
var options : IndexableHTMLOptionsCollection = node.options;
|
||||
function updateOptions(
|
||||
node: HTMLSelectElement,
|
||||
multiple: boolean,
|
||||
propValue: any,
|
||||
) {
|
||||
type IndexableHTMLOptionsCollection = HTMLOptionsCollection & {
|
||||
[key: number]: HTMLOptionElement,
|
||||
};
|
||||
var options: IndexableHTMLOptionsCollection = node.options;
|
||||
|
||||
if (multiple) {
|
||||
let selectedValues = (propValue : Array<string>);
|
||||
let selectedValues = (propValue: Array<string>);
|
||||
let selectedValue = {};
|
||||
for (let i = 0; i < selectedValues.length; i++) {
|
||||
selectedValue['' + selectedValues[i]] = true;
|
||||
@@ -90,7 +96,7 @@ function updateOptions(node : HTMLSelectElement, multiple : boolean, propValue :
|
||||
} else {
|
||||
// Do not set `select.value` as exact behavior isn't consistent across all
|
||||
// browsers for all cases.
|
||||
let selectedValue = '' + (propValue : string);
|
||||
let selectedValue = '' + (propValue: string);
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
if (options[i].value === selectedValue) {
|
||||
options[i].selected = true;
|
||||
@@ -119,14 +125,14 @@ function updateOptions(node : HTMLSelectElement, multiple : boolean, propValue :
|
||||
* selected.
|
||||
*/
|
||||
var ReactDOMSelect = {
|
||||
getHostProps: function(element : Element, props : Object) {
|
||||
getHostProps: function(element: Element, props: Object) {
|
||||
return Object.assign({}, props, {
|
||||
value: undefined,
|
||||
});
|
||||
},
|
||||
|
||||
mountWrapper: function(element : Element, props : Object) {
|
||||
var node = ((element : any) : SelectWithWrapperState);
|
||||
mountWrapper: function(element: Element, props: Object) {
|
||||
var node = ((element: any): SelectWithWrapperState);
|
||||
if (__DEV__) {
|
||||
checkSelectPropTypes(props);
|
||||
}
|
||||
@@ -145,10 +151,10 @@ var ReactDOMSelect = {
|
||||
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'
|
||||
'(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',
|
||||
);
|
||||
didWarnValueDefaultValue = true;
|
||||
}
|
||||
@@ -161,8 +167,8 @@ var ReactDOMSelect = {
|
||||
}
|
||||
},
|
||||
|
||||
postUpdateWrapper: function(element : Element, props : Object) {
|
||||
var node = ((element : any) : SelectWithWrapperState);
|
||||
postUpdateWrapper: function(element: Element, props: Object) {
|
||||
var node = ((element: any): SelectWithWrapperState);
|
||||
// After the initial mount, we control selected-ness manually so don't pass
|
||||
// this value down
|
||||
node._wrapperState.initialValue = undefined;
|
||||
@@ -184,8 +190,8 @@ var ReactDOMSelect = {
|
||||
}
|
||||
},
|
||||
|
||||
restoreControlledState: function(element : Element, props : Object) {
|
||||
var node = ((element : any) : SelectWithWrapperState);
|
||||
restoreControlledState: function(element: Element, props: Object) {
|
||||
var node = ((element: any): SelectWithWrapperState);
|
||||
var value = props.value;
|
||||
|
||||
if (value != null) {
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
type TextAreaWithWrapperState = HTMLTextAreaElement & {
|
||||
_wrapperState: {
|
||||
initialValue: string,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
var ReactControlledValuePropTypes = require('ReactControlledValuePropTypes');
|
||||
var { getCurrentFiberOwnerName } = require('ReactDebugCurrentFiber');
|
||||
var {getCurrentFiberOwnerName} = require('ReactDebugCurrentFiber');
|
||||
|
||||
var invariant = require('fbjs/lib/invariant');
|
||||
var warning = require('fbjs/lib/warning');
|
||||
@@ -42,11 +42,11 @@ var didWarnValDefaultVal = false;
|
||||
* `defaultValue` if specified, or the children content (deprecated).
|
||||
*/
|
||||
var ReactDOMTextarea = {
|
||||
getHostProps: function(element : Element, props : Object) {
|
||||
var node = ((element : any) : TextAreaWithWrapperState);
|
||||
getHostProps: function(element: Element, props: Object) {
|
||||
var node = ((element: any): TextAreaWithWrapperState);
|
||||
invariant(
|
||||
props.dangerouslySetInnerHTML == null,
|
||||
'`dangerouslySetInnerHTML` does not make sense on <textarea>.'
|
||||
'`dangerouslySetInnerHTML` does not make sense on <textarea>.',
|
||||
);
|
||||
|
||||
// Always set children to the same thing. In IE9, the selection range will
|
||||
@@ -63,13 +63,13 @@ var ReactDOMTextarea = {
|
||||
return hostProps;
|
||||
},
|
||||
|
||||
mountWrapper: function(element : Element, props : Object) {
|
||||
var node = ((element : any) : TextAreaWithWrapperState);
|
||||
mountWrapper: function(element: Element, props: Object) {
|
||||
var node = ((element: any): TextAreaWithWrapperState);
|
||||
if (__DEV__) {
|
||||
ReactControlledValuePropTypes.checkPropTypes(
|
||||
'textarea',
|
||||
props,
|
||||
getCurrentFiberOwnerName()
|
||||
getCurrentFiberOwnerName(),
|
||||
);
|
||||
if (
|
||||
props.value !== undefined &&
|
||||
@@ -79,16 +79,15 @@ var ReactDOMTextarea = {
|
||||
warning(
|
||||
false,
|
||||
'Textarea 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 textarea ' +
|
||||
'and remove one of these props. More info: ' +
|
||||
'https://fb.me/react-controlled-components'
|
||||
'(specify either the value prop, or the defaultValue prop, but not ' +
|
||||
'both). Decide between using a controlled or uncontrolled textarea ' +
|
||||
'and remove one of these props. More info: ' +
|
||||
'https://fb.me/react-controlled-components',
|
||||
);
|
||||
didWarnValDefaultVal = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var value = props.value;
|
||||
var initialValue = value;
|
||||
|
||||
@@ -102,17 +101,17 @@ var ReactDOMTextarea = {
|
||||
warning(
|
||||
false,
|
||||
'Use the `defaultValue` or `value` props instead of setting ' +
|
||||
'children on <textarea>.'
|
||||
'children on <textarea>.',
|
||||
);
|
||||
}
|
||||
invariant(
|
||||
defaultValue == null,
|
||||
'If you supply `defaultValue` on a <textarea>, do not pass children.'
|
||||
'If you supply `defaultValue` on a <textarea>, do not pass children.',
|
||||
);
|
||||
if (Array.isArray(children)) {
|
||||
invariant(
|
||||
children.length <= 1,
|
||||
'<textarea> can only have at most one child.'
|
||||
'<textarea> can only have at most one child.',
|
||||
);
|
||||
children = children[0];
|
||||
}
|
||||
@@ -130,8 +129,8 @@ var ReactDOMTextarea = {
|
||||
};
|
||||
},
|
||||
|
||||
updateWrapper: function(element : Element, props : Object) {
|
||||
var node = ((element : any) : TextAreaWithWrapperState);
|
||||
updateWrapper: function(element: Element, props: Object) {
|
||||
var node = ((element: any): TextAreaWithWrapperState);
|
||||
var value = props.value;
|
||||
if (value != null) {
|
||||
// Cast `value` to a string to ensure the value is set correctly. While
|
||||
@@ -151,8 +150,8 @@ var ReactDOMTextarea = {
|
||||
}
|
||||
},
|
||||
|
||||
postMountWrapper: function(element : Element, props : Object) {
|
||||
var node = ((element : any) : TextAreaWithWrapperState);
|
||||
postMountWrapper: function(element: Element, props: Object) {
|
||||
var node = ((element: any): TextAreaWithWrapperState);
|
||||
// This is in postMount because we need access to the DOM node, which is not
|
||||
// available until after the component has mounted.
|
||||
var textContent = node.textContent;
|
||||
@@ -166,11 +165,10 @@ var ReactDOMTextarea = {
|
||||
}
|
||||
},
|
||||
|
||||
restoreControlledState: function(element : Element, props : Object) {
|
||||
restoreControlledState: function(element: Element, props: Object) {
|
||||
// DOM component is still mounted; update
|
||||
ReactDOMTextarea.updateWrapper(element, props);
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
module.exports = ReactDOMTextarea;
|
||||
|
||||
@@ -22,7 +22,7 @@ var memoizeStringOnly = require('fbjs/lib/memoizeStringOnly');
|
||||
var warning = require('fbjs/lib/warning');
|
||||
|
||||
if (__DEV__) {
|
||||
var { getCurrentFiberOwnerName } = require('ReactDebugCurrentFiber');
|
||||
var {getCurrentFiberOwnerName} = require('ReactDebugCurrentFiber');
|
||||
}
|
||||
|
||||
var processStyleName = memoizeStringOnly(function(styleName) {
|
||||
@@ -67,7 +67,7 @@ if (__DEV__) {
|
||||
'Unsupported style property %s. Did you mean %s?%s',
|
||||
name,
|
||||
camelizeStyleName(name),
|
||||
checkRenderMessage(owner)
|
||||
checkRenderMessage(owner),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -82,7 +82,7 @@ if (__DEV__) {
|
||||
'Unsupported vendor-prefixed style property %s. Did you mean %s?%s',
|
||||
name,
|
||||
name.charAt(0).toUpperCase() + name.slice(1),
|
||||
checkRenderMessage(owner)
|
||||
checkRenderMessage(owner),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -94,11 +94,11 @@ if (__DEV__) {
|
||||
warnedStyleValues[value] = true;
|
||||
warning(
|
||||
false,
|
||||
'Style property values shouldn\'t contain a semicolon.%s ' +
|
||||
'Try "%s: %s" instead.',
|
||||
"Style property values shouldn't contain a semicolon.%s " +
|
||||
'Try "%s: %s" instead.',
|
||||
checkRenderMessage(owner),
|
||||
name,
|
||||
value.replace(badStyleValueWithSemicolonPattern, '')
|
||||
value.replace(badStyleValueWithSemicolonPattern, ''),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -112,7 +112,7 @@ if (__DEV__) {
|
||||
false,
|
||||
'`NaN` is an invalid value for the `%s` css style property.%s',
|
||||
name,
|
||||
checkRenderMessage(owner)
|
||||
checkRenderMessage(owner),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -161,7 +161,6 @@ if (__DEV__) {
|
||||
* Operations for dealing with CSS properties.
|
||||
*/
|
||||
var CSSPropertyOperations = {
|
||||
|
||||
/**
|
||||
* Serializes a mapping of style properties for use as inline styles:
|
||||
*
|
||||
@@ -187,8 +186,8 @@ var CSSPropertyOperations = {
|
||||
}
|
||||
if (styleValue != null) {
|
||||
serialized += processStyleName(styleName) + ':';
|
||||
serialized +=
|
||||
dangerousStyleValue(styleName, styleValue, component) + ';';
|
||||
serialized += dangerousStyleValue(styleName, styleValue, component) +
|
||||
';';
|
||||
}
|
||||
}
|
||||
return serialized || null;
|
||||
@@ -214,7 +213,7 @@ var CSSPropertyOperations = {
|
||||
var styleValue = dangerousStyleValue(
|
||||
styleName,
|
||||
styles[styleName],
|
||||
component
|
||||
component,
|
||||
);
|
||||
if (styleName === 'float' || styleName === 'cssFloat') {
|
||||
styleName = styleFloatAccessor;
|
||||
@@ -222,8 +221,7 @@ var CSSPropertyOperations = {
|
||||
if (styleValue) {
|
||||
style[styleName] = styleValue;
|
||||
} else {
|
||||
var expansion =
|
||||
hasShorthandPropertyBug &&
|
||||
var expansion = hasShorthandPropertyBug &&
|
||||
CSSProperty.shorthandPropertyExpansions[styleName];
|
||||
if (expansion) {
|
||||
// Shorthand property that IE8 won't like unsetting, so unset each
|
||||
@@ -237,7 +235,6 @@ var CSSPropertyOperations = {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
module.exports = CSSPropertyOperations;
|
||||
|
||||
@@ -66,18 +66,18 @@ var DOMPropertyInjection = {
|
||||
|
||||
if (domPropertyConfig.isCustomAttribute) {
|
||||
DOMProperty._isCustomAttributeFunctions.push(
|
||||
domPropertyConfig.isCustomAttribute
|
||||
domPropertyConfig.isCustomAttribute,
|
||||
);
|
||||
}
|
||||
|
||||
for (var propName in Properties) {
|
||||
invariant(
|
||||
!DOMProperty.properties.hasOwnProperty(propName),
|
||||
'injectDOMPropertyConfig(...): You\'re trying to inject DOM property ' +
|
||||
'\'%s\' which has already been injected. You may be accidentally ' +
|
||||
'injecting the same DOM property config twice, or you may be ' +
|
||||
'injecting two configs that have conflicting property names.',
|
||||
propName
|
||||
"injectDOMPropertyConfig(...): You're trying to inject DOM property " +
|
||||
"'%s' which has already been injected. You may be accidentally " +
|
||||
'injecting the same DOM property config twice, or you may be ' +
|
||||
'injecting two configs that have conflicting property names.',
|
||||
propName,
|
||||
);
|
||||
|
||||
var lowerCased = propName.toLowerCase();
|
||||
@@ -92,17 +92,23 @@ var DOMPropertyInjection = {
|
||||
mustUseProperty: checkMask(propConfig, Injection.MUST_USE_PROPERTY),
|
||||
hasBooleanValue: checkMask(propConfig, Injection.HAS_BOOLEAN_VALUE),
|
||||
hasNumericValue: checkMask(propConfig, Injection.HAS_NUMERIC_VALUE),
|
||||
hasPositiveNumericValue:
|
||||
checkMask(propConfig, Injection.HAS_POSITIVE_NUMERIC_VALUE),
|
||||
hasOverloadedBooleanValue:
|
||||
checkMask(propConfig, Injection.HAS_OVERLOADED_BOOLEAN_VALUE),
|
||||
hasPositiveNumericValue: checkMask(
|
||||
propConfig,
|
||||
Injection.HAS_POSITIVE_NUMERIC_VALUE,
|
||||
),
|
||||
hasOverloadedBooleanValue: checkMask(
|
||||
propConfig,
|
||||
Injection.HAS_OVERLOADED_BOOLEAN_VALUE,
|
||||
),
|
||||
};
|
||||
invariant(
|
||||
propertyInfo.hasBooleanValue + propertyInfo.hasNumericValue +
|
||||
propertyInfo.hasOverloadedBooleanValue <= 1,
|
||||
propertyInfo.hasBooleanValue +
|
||||
propertyInfo.hasNumericValue +
|
||||
propertyInfo.hasOverloadedBooleanValue <=
|
||||
1,
|
||||
'DOMProperty: Value can be one of boolean, overloaded boolean, or ' +
|
||||
'numeric value, but not a combination: %s',
|
||||
propName
|
||||
'numeric value, but not a combination: %s',
|
||||
propName,
|
||||
);
|
||||
|
||||
if (__DEV__) {
|
||||
@@ -138,7 +144,6 @@ var DOMPropertyInjection = {
|
||||
var ATTRIBUTE_NAME_START_CHAR = ':A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD';
|
||||
/* eslint-enable max-len */
|
||||
|
||||
|
||||
/**
|
||||
* DOMProperty exports lookup objects that can be used like functions:
|
||||
*
|
||||
@@ -153,12 +158,12 @@ var ATTRIBUTE_NAME_START_CHAR = ':A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\
|
||||
* @see http://jsperf.com/key-missing
|
||||
*/
|
||||
var DOMProperty = {
|
||||
|
||||
ID_ATTRIBUTE_NAME: 'data-reactid',
|
||||
ROOT_ATTRIBUTE_NAME: 'data-reactroot',
|
||||
|
||||
ATTRIBUTE_NAME_START_CHAR: ATTRIBUTE_NAME_START_CHAR,
|
||||
ATTRIBUTE_NAME_CHAR: ATTRIBUTE_NAME_START_CHAR + '\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040',
|
||||
ATTRIBUTE_NAME_CHAR: ATTRIBUTE_NAME_START_CHAR +
|
||||
'\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040',
|
||||
|
||||
/**
|
||||
* Map from property "standard name" to an object with info about how to set
|
||||
|
||||
@@ -19,7 +19,11 @@ var quoteAttributeValueForBrowser = require('quoteAttributeValueForBrowser');
|
||||
var warning = require('fbjs/lib/warning');
|
||||
|
||||
var VALID_ATTRIBUTE_NAME_REGEX = new RegExp(
|
||||
'^[' + DOMProperty.ATTRIBUTE_NAME_START_CHAR + '][' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$'
|
||||
'^[' +
|
||||
DOMProperty.ATTRIBUTE_NAME_START_CHAR +
|
||||
'][' +
|
||||
DOMProperty.ATTRIBUTE_NAME_CHAR +
|
||||
']*$',
|
||||
);
|
||||
var illegalAttributeNameCache = {};
|
||||
var validatedAttributeNameCache = {};
|
||||
@@ -36,11 +40,7 @@ function isAttributeNameSafe(attributeName) {
|
||||
return true;
|
||||
}
|
||||
illegalAttributeNameCache[attributeName] = true;
|
||||
warning(
|
||||
false,
|
||||
'Invalid attribute name: `%s`',
|
||||
attributeName
|
||||
);
|
||||
warning(false, 'Invalid attribute name: `%s`', attributeName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ function shouldIgnoreValue(propertyInfo, value) {
|
||||
return value == null ||
|
||||
(propertyInfo.hasBooleanValue && !value) ||
|
||||
(propertyInfo.hasNumericValue && isNaN(value)) ||
|
||||
(propertyInfo.hasPositiveNumericValue && (value < 1)) ||
|
||||
(propertyInfo.hasPositiveNumericValue && value < 1) ||
|
||||
(propertyInfo.hasOverloadedBooleanValue && value === false);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,6 @@ function shouldIgnoreValue(propertyInfo, value) {
|
||||
* Operations for dealing with DOM properties.
|
||||
*/
|
||||
var DOMPropertyOperations = {
|
||||
|
||||
/**
|
||||
* Creates markup for the ID property.
|
||||
*
|
||||
@@ -64,7 +63,8 @@ var DOMPropertyOperations = {
|
||||
* @return {string} Markup string.
|
||||
*/
|
||||
createMarkupForID: function(id) {
|
||||
return DOMProperty.ID_ATTRIBUTE_NAME + '=' +
|
||||
return DOMProperty.ID_ATTRIBUTE_NAME +
|
||||
'=' +
|
||||
quoteAttributeValueForBrowser(id);
|
||||
},
|
||||
|
||||
@@ -88,15 +88,18 @@ var DOMPropertyOperations = {
|
||||
* @return {?string} Markup string, or null if the property was invalid.
|
||||
*/
|
||||
createMarkupForProperty: function(name, value) {
|
||||
var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ?
|
||||
DOMProperty.properties[name] : null;
|
||||
var propertyInfo = DOMProperty.properties.hasOwnProperty(name)
|
||||
? DOMProperty.properties[name]
|
||||
: null;
|
||||
if (propertyInfo) {
|
||||
if (shouldIgnoreValue(propertyInfo, value)) {
|
||||
return '';
|
||||
}
|
||||
var attributeName = propertyInfo.attributeName;
|
||||
if (propertyInfo.hasBooleanValue ||
|
||||
(propertyInfo.hasOverloadedBooleanValue && value === true)) {
|
||||
if (
|
||||
propertyInfo.hasBooleanValue ||
|
||||
(propertyInfo.hasOverloadedBooleanValue && value === true)
|
||||
) {
|
||||
return attributeName + '=""';
|
||||
}
|
||||
return attributeName + '=' + quoteAttributeValueForBrowser(value);
|
||||
@@ -131,8 +134,9 @@ var DOMPropertyOperations = {
|
||||
* @param {*} value
|
||||
*/
|
||||
setValueForProperty: function(node, name, value) {
|
||||
var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ?
|
||||
DOMProperty.properties[name] : null;
|
||||
var propertyInfo = DOMProperty.properties.hasOwnProperty(name)
|
||||
? DOMProperty.properties[name]
|
||||
: null;
|
||||
if (propertyInfo) {
|
||||
var mutationMethod = propertyInfo.mutationMethod;
|
||||
if (mutationMethod) {
|
||||
@@ -151,8 +155,10 @@ var DOMPropertyOperations = {
|
||||
// ('' + value) makes it output the correct toString()-value.
|
||||
if (namespace) {
|
||||
node.setAttributeNS(namespace, attributeName, '' + value);
|
||||
} else if (propertyInfo.hasBooleanValue ||
|
||||
(propertyInfo.hasOverloadedBooleanValue && value === true)) {
|
||||
} else if (
|
||||
propertyInfo.hasBooleanValue ||
|
||||
(propertyInfo.hasOverloadedBooleanValue && value === true)
|
||||
) {
|
||||
node.setAttribute(attributeName, '');
|
||||
} else {
|
||||
node.setAttribute(attributeName, '' + value);
|
||||
@@ -219,8 +225,9 @@ var DOMPropertyOperations = {
|
||||
* @param {string} name
|
||||
*/
|
||||
deleteValueForProperty: function(node, name) {
|
||||
var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ?
|
||||
DOMProperty.properties[name] : null;
|
||||
var propertyInfo = DOMProperty.properties.hasOwnProperty(name)
|
||||
? DOMProperty.properties[name]
|
||||
: null;
|
||||
if (propertyInfo) {
|
||||
var mutationMethod = propertyInfo.mutationMethod;
|
||||
if (mutationMethod) {
|
||||
@@ -247,7 +254,6 @@ var DOMPropertyOperations = {
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
module.exports = DOMPropertyOperations;
|
||||
|
||||
@@ -16,14 +16,12 @@ var DOMProperty = require('DOMProperty');
|
||||
var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY;
|
||||
var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE;
|
||||
var HAS_NUMERIC_VALUE = DOMProperty.injection.HAS_NUMERIC_VALUE;
|
||||
var HAS_POSITIVE_NUMERIC_VALUE =
|
||||
DOMProperty.injection.HAS_POSITIVE_NUMERIC_VALUE;
|
||||
var HAS_OVERLOADED_BOOLEAN_VALUE =
|
||||
DOMProperty.injection.HAS_OVERLOADED_BOOLEAN_VALUE;
|
||||
var HAS_POSITIVE_NUMERIC_VALUE = DOMProperty.injection.HAS_POSITIVE_NUMERIC_VALUE;
|
||||
var HAS_OVERLOADED_BOOLEAN_VALUE = DOMProperty.injection.HAS_OVERLOADED_BOOLEAN_VALUE;
|
||||
|
||||
var HTMLDOMPropertyConfig = {
|
||||
isCustomAttribute: RegExp.prototype.test.bind(
|
||||
new RegExp('^(data|aria)-[' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$')
|
||||
new RegExp('^(data|aria)-[' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$'),
|
||||
),
|
||||
Properties: {
|
||||
/**
|
||||
@@ -211,8 +209,7 @@ var HTMLDOMPropertyConfig = {
|
||||
htmlFor: 'for',
|
||||
httpEquiv: 'http-equiv',
|
||||
},
|
||||
DOMPropertyNames: {
|
||||
},
|
||||
DOMPropertyNames: {},
|
||||
};
|
||||
|
||||
module.exports = HTMLDOMPropertyConfig;
|
||||
|
||||
@@ -84,8 +84,10 @@ var reactTopListenersCounter = 0;
|
||||
var topEventMapping = {
|
||||
topAbort: 'abort',
|
||||
topAnimationEnd: getVendorPrefixedEventName('animationend') || 'animationend',
|
||||
topAnimationIteration: getVendorPrefixedEventName('animationiteration') || 'animationiteration',
|
||||
topAnimationStart: getVendorPrefixedEventName('animationstart') || 'animationstart',
|
||||
topAnimationIteration: getVendorPrefixedEventName('animationiteration') ||
|
||||
'animationiteration',
|
||||
topAnimationStart: getVendorPrefixedEventName('animationstart') ||
|
||||
'animationstart',
|
||||
topBlur: 'blur',
|
||||
topCancel: 'cancel',
|
||||
topCanPlay: 'canplay',
|
||||
@@ -145,7 +147,8 @@ var topEventMapping = {
|
||||
topTouchEnd: 'touchend',
|
||||
topTouchMove: 'touchmove',
|
||||
topTouchStart: 'touchstart',
|
||||
topTransitionEnd: getVendorPrefixedEventName('transitionend') || 'transitionend',
|
||||
topTransitionEnd: getVendorPrefixedEventName('transitionend') ||
|
||||
'transitionend',
|
||||
topVolumeChange: 'volumechange',
|
||||
topWaiting: 'waiting',
|
||||
topWheel: 'wheel',
|
||||
@@ -167,7 +170,6 @@ function getListeningForDocument(mountAt) {
|
||||
}
|
||||
|
||||
var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
|
||||
/**
|
||||
* Injectable event backend
|
||||
*/
|
||||
@@ -179,7 +181,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
*/
|
||||
injectReactEventListener: function(ReactEventListener) {
|
||||
ReactEventListener.setHandleTopLevel(
|
||||
ReactBrowserEventEmitter.handleTopLevel
|
||||
ReactBrowserEventEmitter.handleTopLevel,
|
||||
);
|
||||
ReactBrowserEventEmitter.ReactEventListener = ReactEventListener;
|
||||
},
|
||||
@@ -200,10 +202,8 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
* @return {boolean} True if callbacks are enabled.
|
||||
*/
|
||||
isEnabled: function() {
|
||||
return !!(
|
||||
ReactBrowserEventEmitter.ReactEventListener &&
|
||||
ReactBrowserEventEmitter.ReactEventListener.isEnabled()
|
||||
);
|
||||
return !!(ReactBrowserEventEmitter.ReactEventListener &&
|
||||
ReactBrowserEventEmitter.ReactEventListener.isEnabled());
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -230,27 +230,27 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
listenTo: function(registrationName, contentDocumentHandle) {
|
||||
var mountAt = contentDocumentHandle;
|
||||
var isListening = getListeningForDocument(mountAt);
|
||||
var dependencies =
|
||||
EventPluginRegistry.registrationNameDependencies[registrationName];
|
||||
var dependencies = EventPluginRegistry.registrationNameDependencies[
|
||||
registrationName
|
||||
];
|
||||
|
||||
for (var i = 0; i < dependencies.length; i++) {
|
||||
var dependency = dependencies[i];
|
||||
if (!(
|
||||
isListening.hasOwnProperty(dependency) &&
|
||||
isListening[dependency]
|
||||
)) {
|
||||
if (
|
||||
!(isListening.hasOwnProperty(dependency) && isListening[dependency])
|
||||
) {
|
||||
if (dependency === 'topWheel') {
|
||||
if (isEventSupported('wheel')) {
|
||||
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
|
||||
'topWheel',
|
||||
'wheel',
|
||||
mountAt
|
||||
mountAt,
|
||||
);
|
||||
} else if (isEventSupported('mousewheel')) {
|
||||
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
|
||||
'topWheel',
|
||||
'mousewheel',
|
||||
mountAt
|
||||
mountAt,
|
||||
);
|
||||
} else {
|
||||
// Firefox needs to capture a different mouse scroll event.
|
||||
@@ -258,37 +258,34 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
|
||||
'topWheel',
|
||||
'DOMMouseScroll',
|
||||
mountAt
|
||||
mountAt,
|
||||
);
|
||||
}
|
||||
} else if (dependency === 'topScroll') {
|
||||
|
||||
if (isEventSupported('scroll', true)) {
|
||||
ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
|
||||
'topScroll',
|
||||
'scroll',
|
||||
mountAt
|
||||
mountAt,
|
||||
);
|
||||
} else {
|
||||
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
|
||||
'topScroll',
|
||||
'scroll',
|
||||
ReactBrowserEventEmitter.ReactEventListener.WINDOW_HANDLE
|
||||
ReactBrowserEventEmitter.ReactEventListener.WINDOW_HANDLE,
|
||||
);
|
||||
}
|
||||
} else if (dependency === 'topFocus' ||
|
||||
dependency === 'topBlur') {
|
||||
|
||||
} else if (dependency === 'topFocus' || dependency === 'topBlur') {
|
||||
if (isEventSupported('focus', true)) {
|
||||
ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
|
||||
'topFocus',
|
||||
'focus',
|
||||
mountAt
|
||||
mountAt,
|
||||
);
|
||||
ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
|
||||
'topBlur',
|
||||
'blur',
|
||||
mountAt
|
||||
mountAt,
|
||||
);
|
||||
} else if (isEventSupported('focusin')) {
|
||||
// IE has `focusin` and `focusout` events which bubble.
|
||||
@@ -296,12 +293,12 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
|
||||
'topFocus',
|
||||
'focusin',
|
||||
mountAt
|
||||
mountAt,
|
||||
);
|
||||
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
|
||||
'topBlur',
|
||||
'focusout',
|
||||
mountAt
|
||||
mountAt,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -313,7 +310,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
|
||||
'topCancel',
|
||||
'cancel',
|
||||
mountAt
|
||||
mountAt,
|
||||
);
|
||||
}
|
||||
isListening.topCancel = true;
|
||||
@@ -322,7 +319,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
|
||||
'topClose',
|
||||
'close',
|
||||
mountAt
|
||||
mountAt,
|
||||
);
|
||||
}
|
||||
isListening.topClose = true;
|
||||
@@ -330,7 +327,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
|
||||
dependency,
|
||||
topEventMapping[dependency],
|
||||
mountAt
|
||||
mountAt,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -341,14 +338,14 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
|
||||
isListeningToAllDependencies: function(registrationName, mountAt) {
|
||||
var isListening = getListeningForDocument(mountAt);
|
||||
var dependencies =
|
||||
EventPluginRegistry.registrationNameDependencies[registrationName];
|
||||
var dependencies = EventPluginRegistry.registrationNameDependencies[
|
||||
registrationName
|
||||
];
|
||||
for (var i = 0; i < dependencies.length; i++) {
|
||||
var dependency = dependencies[i];
|
||||
if (!(
|
||||
isListening.hasOwnProperty(dependency) &&
|
||||
isListening[dependency]
|
||||
)) {
|
||||
if (
|
||||
!(isListening.hasOwnProperty(dependency) && isListening[dependency])
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -359,7 +356,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
return ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
|
||||
topLevelType,
|
||||
handlerBaseName,
|
||||
handle
|
||||
handle,
|
||||
);
|
||||
},
|
||||
|
||||
@@ -367,7 +364,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
return ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
|
||||
topLevelType,
|
||||
handlerBaseName,
|
||||
handle
|
||||
handle,
|
||||
);
|
||||
},
|
||||
|
||||
@@ -405,7 +402,6 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
isMonitoringScrollValue = true;
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
module.exports = ReactBrowserEventEmitter;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
var DOMProperty = require('DOMProperty');
|
||||
var ReactDOMComponentFlags = require('ReactDOMComponentFlags');
|
||||
var { HostComponent, HostText } = require('ReactTypeOfWork');
|
||||
var {HostComponent, HostText} = require('ReactTypeOfWork');
|
||||
|
||||
var invariant = require('fbjs/lib/invariant');
|
||||
|
||||
@@ -31,11 +31,10 @@ var internalEventHandlersKey = '__reactEventHandlers$' + randomKey;
|
||||
*/
|
||||
function shouldPrecacheNode(node, nodeID) {
|
||||
return (node.nodeType === 1 &&
|
||||
node.getAttribute(ATTR_NAME) === ('' + nodeID)) ||
|
||||
(node.nodeType === 8 &&
|
||||
node.nodeValue === ' react-text: ' + nodeID + ' ') ||
|
||||
(node.nodeType === 8 &&
|
||||
node.nodeValue === ' react-empty: ' + nodeID + ' ');
|
||||
node.getAttribute(ATTR_NAME) === '' + nodeID) ||
|
||||
(node.nodeType === 8 &&
|
||||
node.nodeValue === ' react-text: ' + nodeID + ' ') ||
|
||||
(node.nodeType === 8 && node.nodeValue === ' react-empty: ' + nodeID + ' ');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,7 +193,7 @@ function getNodeFromInstance(inst) {
|
||||
// invariant for a missing parent, which is super confusing.
|
||||
invariant(
|
||||
inst._hostNode !== undefined,
|
||||
'getNodeFromInstance: Invalid argument.'
|
||||
'getNodeFromInstance: Invalid argument.',
|
||||
);
|
||||
|
||||
if (inst._hostNode) {
|
||||
@@ -207,7 +206,7 @@ function getNodeFromInstance(inst) {
|
||||
parents.push(inst);
|
||||
invariant(
|
||||
inst._hostParent,
|
||||
'React DOM tree root should always have a node reference.'
|
||||
'React DOM tree root should always have a node reference.',
|
||||
);
|
||||
inst = inst._hostParent;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ function inject() {
|
||||
alreadyInjected = true;
|
||||
|
||||
ReactBrowserEventEmitter.injection.injectReactEventListener(
|
||||
ReactEventListener
|
||||
ReactEventListener,
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -99,7 +99,7 @@ function getModernOffsets(node) {
|
||||
selection.anchorNode,
|
||||
selection.anchorOffset,
|
||||
selection.focusNode,
|
||||
selection.focusOffset
|
||||
selection.focusOffset,
|
||||
);
|
||||
|
||||
var rangeLength = isSelectionCollapsed ? 0 : currentRange.toString().length;
|
||||
@@ -112,7 +112,7 @@ function getModernOffsets(node) {
|
||||
tempRange.startContainer,
|
||||
tempRange.startOffset,
|
||||
tempRange.endContainer,
|
||||
tempRange.endOffset
|
||||
tempRange.endOffset,
|
||||
);
|
||||
|
||||
var start = isTempRangeCollapsed ? 0 : tempRange.toString().length;
|
||||
@@ -176,8 +176,7 @@ function setModernOffsets(node, offsets) {
|
||||
var selection = window.getSelection();
|
||||
var length = node[getTextContentAccessor()].length;
|
||||
var start = Math.min(offsets.start, length);
|
||||
var end = offsets.end === undefined ?
|
||||
start : Math.min(offsets.end, length);
|
||||
var end = offsets.end === undefined ? start : Math.min(offsets.end, length);
|
||||
|
||||
// IE 11 uses modern selection, but doesn't support the extend method.
|
||||
// Flip backward selections, so we can set with a single range.
|
||||
@@ -205,11 +204,9 @@ function setModernOffsets(node, offsets) {
|
||||
}
|
||||
}
|
||||
|
||||
var useIEOffsets = (
|
||||
ExecutionEnvironment.canUseDOM &&
|
||||
var useIEOffsets = ExecutionEnvironment.canUseDOM &&
|
||||
'selection' in document &&
|
||||
!('getSelection' in window)
|
||||
);
|
||||
!('getSelection' in window);
|
||||
|
||||
var ReactDOMSelection = {
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,7 @@ var ReactTypeOfWork = require('ReactTypeOfWork');
|
||||
var getEventTarget = require('getEventTarget');
|
||||
var getUnboundedScrollPosition = require('fbjs/lib/getUnboundedScrollPosition');
|
||||
|
||||
var { HostRoot } = ReactTypeOfWork;
|
||||
var {HostRoot} = ReactTypeOfWork;
|
||||
|
||||
/**
|
||||
* Find the deepest React component completely containing the root of the
|
||||
@@ -67,7 +67,7 @@ Object.assign(TopLevelCallbackBookKeeping.prototype, {
|
||||
});
|
||||
PooledClass.addPoolingTo(
|
||||
TopLevelCallbackBookKeeping,
|
||||
PooledClass.threeArgumentPooler
|
||||
PooledClass.threeArgumentPooler,
|
||||
);
|
||||
|
||||
function handleTopLevelImpl(bookKeeping) {
|
||||
@@ -88,9 +88,7 @@ function handleTopLevelImpl(bookKeeping) {
|
||||
break;
|
||||
}
|
||||
bookKeeping.ancestors.push(ancestor);
|
||||
ancestor = ReactDOMComponentTree.getClosestInstanceFromNode(
|
||||
root
|
||||
);
|
||||
ancestor = ReactDOMComponentTree.getClosestInstanceFromNode(root);
|
||||
} while (ancestor);
|
||||
|
||||
for (var i = 0; i < bookKeeping.ancestors.length; i++) {
|
||||
@@ -99,7 +97,7 @@ function handleTopLevelImpl(bookKeeping) {
|
||||
bookKeeping.topLevelType,
|
||||
targetInst,
|
||||
bookKeeping.nativeEvent,
|
||||
getEventTarget(bookKeeping.nativeEvent)
|
||||
getEventTarget(bookKeeping.nativeEvent),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -127,7 +125,6 @@ var ReactEventListener = {
|
||||
return ReactEventListener._enabled;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Traps top-level events by using event bubbling.
|
||||
*
|
||||
@@ -145,7 +142,7 @@ var ReactEventListener = {
|
||||
return EventListener.listen(
|
||||
element,
|
||||
handlerBaseName,
|
||||
ReactEventListener.dispatchEvent.bind(null, topLevelType)
|
||||
ReactEventListener.dispatchEvent.bind(null, topLevelType),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -166,7 +163,7 @@ var ReactEventListener = {
|
||||
return EventListener.capture(
|
||||
element,
|
||||
handlerBaseName,
|
||||
ReactEventListener.dispatchEvent.bind(null, topLevelType)
|
||||
ReactEventListener.dispatchEvent.bind(null, topLevelType),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -182,13 +179,13 @@ var ReactEventListener = {
|
||||
|
||||
var nativeEventTarget = getEventTarget(nativeEvent);
|
||||
var targetInst = ReactDOMComponentTree.getClosestInstanceFromNode(
|
||||
nativeEventTarget
|
||||
nativeEventTarget,
|
||||
);
|
||||
|
||||
var bookKeeping = TopLevelCallbackBookKeeping.getPooled(
|
||||
topLevelType,
|
||||
nativeEvent,
|
||||
targetInst
|
||||
targetInst,
|
||||
);
|
||||
|
||||
try {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user