mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Merge branch '15-dev' into 15-stable
I would prefer to rebase but was not able to. 1) There were a couple of conflicts; addons/create-react-class/package.json src/isomorphic/classic/class/__tests__/create-react-class-integration-test.js 2) Force pushing the result of the rebase was a no-go because `15-stable` is a protected branch. So merging is ok too. For more details about all the commits in this merge, see the `15-dev` branch commit history fromcef396d092tod095bc8391
This commit is contained in:
+1
-3
@@ -1,4 +1,5 @@
|
||||
# We can probably lint these later but not important at this point
|
||||
addons/
|
||||
src/renderers/art
|
||||
src/shared/vendor
|
||||
# But not in docs/_js/examples/*
|
||||
@@ -9,11 +10,8 @@ docs/_site/
|
||||
docs/vendor/bundle/
|
||||
# This should be more like examples/**/thirdparty/** but
|
||||
# we should fix https://github.com/facebook/esprima/pull/85 first
|
||||
<<<<<<< HEAD
|
||||
examples/
|
||||
=======
|
||||
fixtures/
|
||||
>>>>>>> 4a37718... Remove examples/ folder (#9323)
|
||||
# Ignore built files.
|
||||
build/
|
||||
coverage/
|
||||
|
||||
+3
-3
@@ -1,14 +1,14 @@
|
||||
[ignore]
|
||||
|
||||
<<<<<<< HEAD
|
||||
<PROJECT_ROOT>/examples/.*
|
||||
=======
|
||||
<PROJECT_ROOT>/fixtures/.*
|
||||
>>>>>>> 4a37718... Remove examples/ folder (#9323)
|
||||
<PROJECT_ROOT>/build/.*
|
||||
<PROJECT_ROOT>/node_modules/chrome-devtools-frontend/.*
|
||||
<PROJECT_ROOT>/.*/node_modules/chrome-devtools-frontend/.*
|
||||
<PROJECT_ROOT>/.*/node_modules/y18n/.*
|
||||
<PROJECT_ROOT>/.*/__mocks__/.*
|
||||
<PROJECT_ROOT>/.*/__tests__/.*
|
||||
<PROJECT_ROOT>/addons/.*
|
||||
|
||||
# Ignore Docs
|
||||
<PROJECT_ROOT>/docs/.*
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-react-class",
|
||||
"version": "15.5.3",
|
||||
"version": "15.5.4",
|
||||
"description": "Deprecated, legacy API for creating React components.",
|
||||
"main": "index.js",
|
||||
"license": "BSD-3-Clause",
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
typeof exports === "object" &&
|
||||
typeof module !== "undefined"
|
||||
) {
|
||||
module.exports=f()
|
||||
module.exports=f(require('react'))
|
||||
} else if (
|
||||
typeof define === "function" &&
|
||||
define.amd
|
||||
) {
|
||||
define([],f)
|
||||
define(['react'],f)
|
||||
} else {
|
||||
var g;
|
||||
if (typeof window !== "undefined") {
|
||||
@@ -27,9 +27,9 @@
|
||||
g.React.addons = {};
|
||||
}
|
||||
|
||||
g.React.addons.createFragment = f()
|
||||
g.React.addons.createFragment = f(g.React)
|
||||
}
|
||||
})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||||
})(function(React){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||||
/**
|
||||
* Copyright 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
@@ -390,7 +390,7 @@ module.exports = createReactFragment;
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
function makeEmptyFunction(arg) {
|
||||
@@ -542,4 +542,4 @@ if ("development" !== 'production') {
|
||||
|
||||
module.exports = warning;
|
||||
},{"./emptyFunction":2}]},{},[1])(1)
|
||||
});
|
||||
});
|
||||
|
||||
+350
-209
@@ -1,5 +1,65 @@
|
||||
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.LinkedInput = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||||
/**
|
||||
(function(f) {
|
||||
if (typeof exports === 'object' && typeof module !== 'undefined') {
|
||||
module.exports = f(require('react'));
|
||||
} else if (typeof define === 'function' && define.amd) {
|
||||
define(['react'], f);
|
||||
} else {
|
||||
var g;
|
||||
if (typeof window !== 'undefined') {
|
||||
g = window;
|
||||
} else if (typeof global !== 'undefined') {
|
||||
g = global;
|
||||
} else if (typeof self !== 'undefined') {
|
||||
g = self;
|
||||
} else {
|
||||
g = this;
|
||||
}
|
||||
|
||||
if (typeof g.React === 'undefined') {
|
||||
throw Error('React module should be required before createFragment');
|
||||
} else if (typeof g.React.addons === 'undefined') {
|
||||
g.React.addons = {};
|
||||
}
|
||||
|
||||
g.LinkedInput = f(g.React);
|
||||
}
|
||||
})(function(React) {
|
||||
var define, module, exports;
|
||||
return (function e(t, n, r) {
|
||||
function s(o, u) {
|
||||
if (!n[o]) {
|
||||
if (!t[o]) {
|
||||
var a = typeof require == 'function' && require;
|
||||
if (!u && a) return a(o, !0);
|
||||
if (i) return i(o, !0);
|
||||
var f = new Error("Cannot find module '" + o + "'");
|
||||
throw ((f.code = 'MODULE_NOT_FOUND'), f);
|
||||
}
|
||||
var l = (n[o] = { exports: {} });
|
||||
t[o][0].call(
|
||||
l.exports,
|
||||
function(e) {
|
||||
var n = t[o][1][e];
|
||||
return s(n ? n : e);
|
||||
},
|
||||
l,
|
||||
l.exports,
|
||||
e,
|
||||
t,
|
||||
n,
|
||||
r
|
||||
);
|
||||
}
|
||||
return n[o].exports;
|
||||
}
|
||||
var i = typeof require == 'function' && require;
|
||||
for (var o = 0; o < r.length; o++) s(r[o]);
|
||||
return s;
|
||||
})(
|
||||
{
|
||||
1: [
|
||||
function(require, module, exports) {
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -8,147 +68,193 @@
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
'use strict';
|
||||
var emptyFunction = require('fbjs/lib/emptyFunction');
|
||||
var invariant = require('fbjs/lib/invariant');
|
||||
var warning = require('fbjs/lib/warning');
|
||||
|
||||
var emptyFunction = require('fbjs/lib/emptyFunction');
|
||||
var invariant = require('fbjs/lib/invariant');
|
||||
var warning = require('fbjs/lib/warning');
|
||||
var hasReadOnlyValue = {
|
||||
button: true,
|
||||
checkbox: true,
|
||||
image: true,
|
||||
hidden: true,
|
||||
radio: true,
|
||||
reset: true,
|
||||
submit: true
|
||||
};
|
||||
|
||||
var hasReadOnlyValue = {
|
||||
'button': true,
|
||||
'checkbox': true,
|
||||
'image': true,
|
||||
'hidden': true,
|
||||
'radio': true,
|
||||
'reset': true,
|
||||
'submit': true,
|
||||
};
|
||||
function _assertSingleLink(inputProps) {
|
||||
invariant(
|
||||
inputProps.checkedLink == null || inputProps.valueLink == null,
|
||||
'Cannot provide a checkedLink and a valueLink. If you want to use ' +
|
||||
"checkedLink, you probably don't want to use valueLink and vice versa."
|
||||
);
|
||||
}
|
||||
function _assertValueLink(inputProps) {
|
||||
_assertSingleLink(inputProps);
|
||||
invariant(
|
||||
inputProps.value == null && inputProps.onChange == null,
|
||||
'Cannot provide a valueLink and a value or onChange event. If you want ' +
|
||||
"to use value or onChange, you probably don't want to use valueLink."
|
||||
);
|
||||
}
|
||||
|
||||
function _assertSingleLink(inputProps) {
|
||||
invariant(
|
||||
inputProps.checkedLink == null || inputProps.valueLink == null,
|
||||
'Cannot provide a checkedLink and a valueLink. If you want to use ' +
|
||||
'checkedLink, you probably don\'t want to use valueLink and vice versa.'
|
||||
);
|
||||
}
|
||||
function _assertValueLink(inputProps) {
|
||||
_assertSingleLink(inputProps);
|
||||
invariant(
|
||||
inputProps.value == null && inputProps.onChange == null,
|
||||
'Cannot provide a valueLink and a value or onChange event. If you want ' +
|
||||
'to use value or onChange, you probably don\'t want to use valueLink.'
|
||||
);
|
||||
}
|
||||
function _assertCheckedLink(inputProps) {
|
||||
_assertSingleLink(inputProps);
|
||||
invariant(
|
||||
inputProps.checked == null && inputProps.onChange == null,
|
||||
'Cannot provide a checkedLink and a checked property or onChange event. ' +
|
||||
"If you want to use checked or onChange, you probably don't want to " +
|
||||
'use checkedLink'
|
||||
);
|
||||
}
|
||||
|
||||
function _assertCheckedLink(inputProps) {
|
||||
_assertSingleLink(inputProps);
|
||||
invariant(
|
||||
inputProps.checked == null && inputProps.onChange == null,
|
||||
'Cannot provide a checkedLink and a checked property or onChange event. ' +
|
||||
'If you want to use checked or onChange, you probably don\'t want to ' +
|
||||
'use checkedLink'
|
||||
);
|
||||
}
|
||||
var loggedTypeFailures = {};
|
||||
function getDeclarationErrorAddendum(owner) {
|
||||
if (owner) {
|
||||
var name = owner.getName();
|
||||
if (name) {
|
||||
return ' Check the render method of `' + name + '`.';
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
var loggedTypeFailures = {};
|
||||
function getDeclarationErrorAddendum(owner) {
|
||||
if (owner) {
|
||||
var name = owner.getName();
|
||||
if (name) {
|
||||
return ' Check the render method of `' + name + '`.';
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Provide a linked `value` attribute for controlled forms. You should not use
|
||||
* this outside of the ReactDOM controlled form components.
|
||||
*/
|
||||
var LinkedValueUtils = {
|
||||
/**
|
||||
var LinkedValueUtils = {
|
||||
/**
|
||||
* @param {object} inputProps Props for form component
|
||||
* @return {*} current value of the input either from value prop or link.
|
||||
*/
|
||||
getValue: function(inputProps) {
|
||||
if (inputProps.valueLink) {
|
||||
_assertValueLink(inputProps);
|
||||
return inputProps.valueLink.value;
|
||||
}
|
||||
return inputProps.value;
|
||||
},
|
||||
getValue: function(inputProps) {
|
||||
if (inputProps.valueLink) {
|
||||
_assertValueLink(inputProps);
|
||||
return inputProps.valueLink.value;
|
||||
}
|
||||
return inputProps.value;
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* @param {object} inputProps Props for form component
|
||||
* @return {*} current checked status of the input either from checked prop
|
||||
* or link.
|
||||
*/
|
||||
getChecked: function(inputProps) {
|
||||
if (inputProps.checkedLink) {
|
||||
_assertCheckedLink(inputProps);
|
||||
return inputProps.checkedLink.value;
|
||||
}
|
||||
return inputProps.checked;
|
||||
},
|
||||
getChecked: function(inputProps) {
|
||||
if (inputProps.checkedLink) {
|
||||
_assertCheckedLink(inputProps);
|
||||
return inputProps.checkedLink.value;
|
||||
}
|
||||
return inputProps.checked;
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* @param {object} inputProps Props for form component
|
||||
* @param {SyntheticEvent} event change event to handle
|
||||
*/
|
||||
executeOnChange: function(inputProps, event) {
|
||||
if (inputProps.valueLink) {
|
||||
_assertValueLink(inputProps);
|
||||
return inputProps.valueLink.requestChange(event.target.value);
|
||||
} else if (inputProps.checkedLink) {
|
||||
_assertCheckedLink(inputProps);
|
||||
return inputProps.checkedLink.requestChange(event.target.checked);
|
||||
} else if (inputProps.onChange) {
|
||||
return inputProps.onChange.call(undefined, event);
|
||||
}
|
||||
},
|
||||
};
|
||||
executeOnChange: function(inputProps, event) {
|
||||
if (inputProps.valueLink) {
|
||||
_assertValueLink(inputProps);
|
||||
return inputProps.valueLink.requestChange(event.target.value);
|
||||
} else if (inputProps.checkedLink) {
|
||||
_assertCheckedLink(inputProps);
|
||||
return inputProps.checkedLink.requestChange(
|
||||
event.target.checked
|
||||
);
|
||||
} else if (inputProps.onChange) {
|
||||
return inputProps.onChange.call(undefined, event);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
function _classCallCheck(instance, Constructor) {
|
||||
if (!(instance instanceof Constructor)) {
|
||||
throw new TypeError('Cannot call a class as a function');
|
||||
}
|
||||
}
|
||||
|
||||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
||||
function _possibleConstructorReturn(self, call) {
|
||||
if (!self) {
|
||||
throw new ReferenceError(
|
||||
"this hasn't been initialised - super() hasn't been called"
|
||||
);
|
||||
}
|
||||
return call &&
|
||||
(typeof call === 'object' || typeof call === 'function')
|
||||
? call
|
||||
: self;
|
||||
}
|
||||
|
||||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
||||
function _inherits(subClass, superClass) {
|
||||
if (typeof superClass !== 'function' && superClass !== null) {
|
||||
throw new TypeError(
|
||||
'Super expression must either be null or a function, not ' +
|
||||
typeof superClass
|
||||
);
|
||||
}
|
||||
subClass.prototype = Object.create(
|
||||
superClass && superClass.prototype,
|
||||
{
|
||||
constructor: {
|
||||
value: subClass,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true
|
||||
}
|
||||
}
|
||||
);
|
||||
if (superClass)
|
||||
Object.setPrototypeOf
|
||||
? Object.setPrototypeOf(subClass, superClass)
|
||||
: (subClass.__proto__ = superClass);
|
||||
}
|
||||
|
||||
var LinkedInput = function (_React$Component) {
|
||||
_inherits(LinkedInput, _React$Component);
|
||||
var LinkedInput = (function(_React$Component) {
|
||||
_inherits(LinkedInput, _React$Component);
|
||||
|
||||
function LinkedInput() {
|
||||
_classCallCheck(this, LinkedInput);
|
||||
function LinkedInput() {
|
||||
_classCallCheck(this, LinkedInput);
|
||||
|
||||
var _this = _possibleConstructorReturn(this, _React$Component.call(this));
|
||||
var _this = _possibleConstructorReturn(
|
||||
this,
|
||||
_React$Component.call(this)
|
||||
);
|
||||
|
||||
_this.handleChange = _this.handleChange.bind(_this);
|
||||
return _this;
|
||||
}
|
||||
_this.handleChange = _this.handleChange.bind(_this);
|
||||
return _this;
|
||||
}
|
||||
|
||||
LinkedInput.prototype.handleChange = function handleChange(e) {
|
||||
LinkedValueUtils.executeOnChange(this.props, e);
|
||||
};
|
||||
LinkedInput.prototype.handleChange = function handleChange(e) {
|
||||
LinkedValueUtils.executeOnChange(this.props, e);
|
||||
};
|
||||
|
||||
LinkedInput.prototype.render = function render() {
|
||||
var newProps = Object.assign({}, this.props);
|
||||
newProps.value = LinkedValueUtils.getValue(this.props);
|
||||
newProps.checked = LinkedValueUtils.getChecked(this.props);
|
||||
newProps.onChange = this.handleChange;
|
||||
delete newProps.valueLink;
|
||||
delete newProps.checkedLink;
|
||||
return React.createElement('input', newProps);
|
||||
};
|
||||
LinkedInput.prototype.render = function render() {
|
||||
var newProps = Object.assign({}, this.props);
|
||||
newProps.value = LinkedValueUtils.getValue(this.props);
|
||||
newProps.checked = LinkedValueUtils.getChecked(this.props);
|
||||
newProps.onChange = this.handleChange;
|
||||
delete newProps.valueLink;
|
||||
delete newProps.checkedLink;
|
||||
return React.createElement('input', newProps);
|
||||
};
|
||||
|
||||
return LinkedInput;
|
||||
}(React.Component);
|
||||
return LinkedInput;
|
||||
})(React.Component);
|
||||
|
||||
module.exports = LinkedInput;
|
||||
|
||||
},{"fbjs/lib/emptyFunction":2,"fbjs/lib/invariant":3,"fbjs/lib/warning":4}],2:[function(require,module,exports){
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
module.exports = LinkedInput;
|
||||
},
|
||||
{
|
||||
'fbjs/lib/emptyFunction': 2,
|
||||
'fbjs/lib/invariant': 3,
|
||||
'fbjs/lib/warning': 4
|
||||
}
|
||||
],
|
||||
2: [
|
||||
function(require, module, exports) {
|
||||
'use strict';
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -156,36 +262,40 @@ module.exports = LinkedInput;
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
function makeEmptyFunction(arg) {
|
||||
return function () {
|
||||
return arg;
|
||||
};
|
||||
}
|
||||
function makeEmptyFunction(arg) {
|
||||
return function() {
|
||||
return arg;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* This function accepts and discards inputs; it has no side effects. This is
|
||||
* primarily useful idiomatically for overridable function endpoints which
|
||||
* always need to be callable, since JS lacks a null-call idiom ala Cocoa.
|
||||
*/
|
||||
var emptyFunction = function emptyFunction() {};
|
||||
var emptyFunction = function emptyFunction() {};
|
||||
|
||||
emptyFunction.thatReturns = makeEmptyFunction;
|
||||
emptyFunction.thatReturnsFalse = makeEmptyFunction(false);
|
||||
emptyFunction.thatReturnsTrue = makeEmptyFunction(true);
|
||||
emptyFunction.thatReturnsNull = makeEmptyFunction(null);
|
||||
emptyFunction.thatReturnsThis = function () {
|
||||
return this;
|
||||
};
|
||||
emptyFunction.thatReturnsArgument = function (arg) {
|
||||
return arg;
|
||||
};
|
||||
emptyFunction.thatReturns = makeEmptyFunction;
|
||||
emptyFunction.thatReturnsFalse = makeEmptyFunction(false);
|
||||
emptyFunction.thatReturnsTrue = makeEmptyFunction(true);
|
||||
emptyFunction.thatReturnsNull = makeEmptyFunction(null);
|
||||
emptyFunction.thatReturnsThis = function() {
|
||||
return this;
|
||||
};
|
||||
emptyFunction.thatReturnsArgument = function(arg) {
|
||||
return arg;
|
||||
};
|
||||
|
||||
module.exports = emptyFunction;
|
||||
},{}],3:[function(require,module,exports){
|
||||
/**
|
||||
module.exports = emptyFunction;
|
||||
},
|
||||
{}
|
||||
],
|
||||
3: [
|
||||
function(require, module, exports) {
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -195,9 +305,8 @@ module.exports = emptyFunction;
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
'use strict';
|
||||
/**
|
||||
* Use invariant() to assert state which your program assumes to be true.
|
||||
*
|
||||
* Provide sprintf-style format (only %s is supported) and arguments
|
||||
@@ -208,40 +317,49 @@ module.exports = emptyFunction;
|
||||
* will remain to ensure logic does not differ in production.
|
||||
*/
|
||||
|
||||
var validateFormat = function validateFormat(format) {};
|
||||
var validateFormat = function validateFormat(format) {};
|
||||
|
||||
if ("development" !== 'production') {
|
||||
validateFormat = function validateFormat(format) {
|
||||
if (format === undefined) {
|
||||
throw new Error('invariant requires an error message argument');
|
||||
}
|
||||
};
|
||||
}
|
||||
if ('development' !== 'production') {
|
||||
validateFormat = function validateFormat(format) {
|
||||
if (format === undefined) {
|
||||
throw new Error('invariant requires an error message argument');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function invariant(condition, format, a, b, c, d, e, f) {
|
||||
validateFormat(format);
|
||||
function invariant(condition, format, a, b, c, d, e, f) {
|
||||
validateFormat(format);
|
||||
|
||||
if (!condition) {
|
||||
var error;
|
||||
if (format === undefined) {
|
||||
error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.');
|
||||
} else {
|
||||
var args = [a, b, c, d, e, f];
|
||||
var argIndex = 0;
|
||||
error = new Error(format.replace(/%s/g, function () {
|
||||
return args[argIndex++];
|
||||
}));
|
||||
error.name = 'Invariant Violation';
|
||||
}
|
||||
if (!condition) {
|
||||
var error;
|
||||
if (format === undefined) {
|
||||
error = new Error(
|
||||
'Minified exception occurred; use the non-minified dev environment ' +
|
||||
'for the full error message and additional helpful warnings.'
|
||||
);
|
||||
} else {
|
||||
var args = [a, b, c, d, e, f];
|
||||
var argIndex = 0;
|
||||
error = new Error(
|
||||
format.replace(/%s/g, function() {
|
||||
return args[argIndex++];
|
||||
})
|
||||
);
|
||||
error.name = 'Invariant Violation';
|
||||
}
|
||||
|
||||
error.framesToPop = 1; // we don't care about invariant's own frame
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
error.framesToPop = 1; // we don't care about invariant's own frame
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = invariant;
|
||||
},{}],4:[function(require,module,exports){
|
||||
/**
|
||||
module.exports = invariant;
|
||||
},
|
||||
{}
|
||||
],
|
||||
4: [
|
||||
function(require, module, exports) {
|
||||
/**
|
||||
* Copyright 2014-2015, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -251,61 +369,84 @@ module.exports = invariant;
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
'use strict';
|
||||
var emptyFunction = require('./emptyFunction');
|
||||
|
||||
var emptyFunction = require('./emptyFunction');
|
||||
|
||||
/**
|
||||
/**
|
||||
* Similar to invariant but only logs a warning if the condition is not met.
|
||||
* This can be used to log issues in development environments in critical
|
||||
* paths. Removing the logging code for production environments will keep the
|
||||
* same logic and follow the same code paths.
|
||||
*/
|
||||
|
||||
var warning = emptyFunction;
|
||||
var warning = emptyFunction;
|
||||
|
||||
if ("development" !== 'production') {
|
||||
(function () {
|
||||
var printWarning = function printWarning(format) {
|
||||
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
||||
args[_key - 1] = arguments[_key];
|
||||
}
|
||||
if ('development' !== 'production') {
|
||||
(function() {
|
||||
var printWarning = function printWarning(format) {
|
||||
for (
|
||||
var _len = arguments.length,
|
||||
args = Array(_len > 1 ? _len - 1 : 0),
|
||||
_key = 1;
|
||||
_key < _len;
|
||||
_key++
|
||||
) {
|
||||
args[_key - 1] = arguments[_key];
|
||||
}
|
||||
|
||||
var argIndex = 0;
|
||||
var message = 'Warning: ' + format.replace(/%s/g, function () {
|
||||
return args[argIndex++];
|
||||
});
|
||||
if (typeof console !== 'undefined') {
|
||||
console.error(message);
|
||||
}
|
||||
try {
|
||||
// --- Welcome to debugging React ---
|
||||
// This error was thrown as a convenience so that you can use this stack
|
||||
// to find the callsite that caused this warning to fire.
|
||||
throw new Error(message);
|
||||
} catch (x) {}
|
||||
};
|
||||
var argIndex = 0;
|
||||
var message =
|
||||
'Warning: ' +
|
||||
format.replace(/%s/g, function() {
|
||||
return args[argIndex++];
|
||||
});
|
||||
if (typeof console !== 'undefined') {
|
||||
console.error(message);
|
||||
}
|
||||
try {
|
||||
// --- Welcome to debugging React ---
|
||||
// This error was thrown as a convenience so that you can use this stack
|
||||
// to find the callsite that caused this warning to fire.
|
||||
throw new Error(message);
|
||||
} catch (x) {}
|
||||
};
|
||||
|
||||
warning = function warning(condition, format) {
|
||||
if (format === undefined) {
|
||||
throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument');
|
||||
}
|
||||
warning = function warning(condition, format) {
|
||||
if (format === undefined) {
|
||||
throw new Error(
|
||||
'`warning(condition, format, ...args)` requires a warning ' +
|
||||
'message argument'
|
||||
);
|
||||
}
|
||||
|
||||
if (format.indexOf('Failed Composite propType: ') === 0) {
|
||||
return; // Ignore CompositeComponent proptype check.
|
||||
}
|
||||
if (format.indexOf('Failed Composite propType: ') === 0) {
|
||||
return; // Ignore CompositeComponent proptype check.
|
||||
}
|
||||
|
||||
if (!condition) {
|
||||
for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
|
||||
args[_key2 - 2] = arguments[_key2];
|
||||
}
|
||||
if (!condition) {
|
||||
for (
|
||||
var _len2 = arguments.length,
|
||||
args = Array(_len2 > 2 ? _len2 - 2 : 0),
|
||||
_key2 = 2;
|
||||
_key2 < _len2;
|
||||
_key2++
|
||||
) {
|
||||
args[_key2 - 2] = arguments[_key2];
|
||||
}
|
||||
|
||||
printWarning.apply(undefined, [format].concat(args));
|
||||
}
|
||||
};
|
||||
})();
|
||||
}
|
||||
printWarning.apply(undefined, [format].concat(args));
|
||||
}
|
||||
};
|
||||
})();
|
||||
}
|
||||
|
||||
module.exports = warning;
|
||||
},
|
||||
{ './emptyFunction': 2 }
|
||||
]
|
||||
},
|
||||
{},
|
||||
[1]
|
||||
)(1);
|
||||
});
|
||||
|
||||
module.exports = warning;
|
||||
},{"./emptyFunction":2}]},{},[1])(1)
|
||||
});
|
||||
@@ -23,6 +23,7 @@ The add-ons below are considered legacy and their use is discouraged.
|
||||
- [`PureRenderMixin`](pure-render-mixin.html). Use [`React.PureComponent`](/react/docs/react-api.html#react.purecomponent) instead.
|
||||
- [`shallowCompare`](shallow-compare.html), a helper function that performs a shallow comparison for props and state in a component to decide if a component should update.
|
||||
- [`update`](update.html). Use [`kolodny/immutability-helper`](https://github.com/kolodny/immutability-helper) instead.
|
||||
- [`ReactDOMFactories`](dom-factories.html), pre-configured DOM factories to make React easier to use without JSX.
|
||||
|
||||
### Deprecated Add-ons
|
||||
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
import { parse, stringify } from 'query-string';
|
||||
import getVersionTags from '../tags';
|
||||
const React = window.React;
|
||||
|
||||
const Header = React.createClass({
|
||||
getInitialState() {
|
||||
const query = parse(window.location.search);
|
||||
const version = query.version || 'local';
|
||||
const versions = [version];
|
||||
return { version, versions };
|
||||
},
|
||||
componentWillMount() {
|
||||
getVersionTags()
|
||||
.then(tags => {
|
||||
let versions = tags.map(tag => tag.name.slice(1));
|
||||
versions = [`local`, ...versions];
|
||||
this.setState({ versions });
|
||||
})
|
||||
},
|
||||
handleVersionChange(event) {
|
||||
const query = parse(window.location.search);
|
||||
query.version = event.target.value;
|
||||
if (query.version === 'local') {
|
||||
delete query.version;
|
||||
}
|
||||
window.location.search = stringify(query);
|
||||
},
|
||||
handleFixtureChange(event) {
|
||||
window.location.pathname = event.target.value;
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<header className="header">
|
||||
<div className="header__inner">
|
||||
<span className="header__logo">
|
||||
<img src="https://facebook.github.io/react/img/logo.svg" alt="" width="32" height="32" />
|
||||
React Sandbox (v{React.version})
|
||||
</span>
|
||||
|
||||
<div className="header-controls">
|
||||
<label htmlFor="example">
|
||||
<span className="sr-only">Select an example</span>
|
||||
<select value={window.location.pathname} onChange={this.handleFixtureChange}>
|
||||
<option value="/">Select a Fixture</option>
|
||||
<option value="/range-inputs">Range Inputs</option>
|
||||
<option value="/text-inputs">Text Inputs</option>
|
||||
<option value="/number-inputs">Number Input</option>
|
||||
<option value="/selects">Selects</option>
|
||||
<option value="/textareas">Textareas</option>
|
||||
<option value="/input-change-events">Input change events</option>
|
||||
</select>
|
||||
</label>
|
||||
<label htmlFor="react_version">
|
||||
<span className="sr-only">Select a version to test</span>
|
||||
<select
|
||||
value={this.state.version}
|
||||
onChange={this.handleVersionChange}>
|
||||
{this.state.versions.map(version => (
|
||||
<option key={version} value={version}>{version}</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default Header;
|
||||
@@ -1,34 +0,0 @@
|
||||
const React = window.React;
|
||||
import RangeInputFixtures from './range-inputs';
|
||||
import TextInputFixtures from './text-inputs';
|
||||
import SelectFixtures from './selects';
|
||||
import TextAreaFixtures from './textareas';
|
||||
import InputChangeEvents from './input-change-events';
|
||||
import NumberInputFixtures from './number-inputs/';
|
||||
|
||||
/**
|
||||
* A simple routing component that renders the appropriate
|
||||
* fixture based on the location pathname.
|
||||
*/
|
||||
const FixturesPage = React.createClass({
|
||||
render() {
|
||||
switch (window.location.pathname) {
|
||||
case '/text-inputs':
|
||||
return <TextInputFixtures />;
|
||||
case '/range-inputs':
|
||||
return <RangeInputFixtures />;
|
||||
case '/selects':
|
||||
return <SelectFixtures />;
|
||||
case '/textareas':
|
||||
return <TextAreaFixtures />;
|
||||
case '/input-change-events':
|
||||
return <InputChangeEvents />;
|
||||
case '/number-inputs':
|
||||
return <NumberInputFixtures />;
|
||||
default:
|
||||
return <p>Please select a test fixture.</p>;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = FixturesPage;
|
||||
@@ -0,0 +1,33 @@
|
||||
const React = window.React;
|
||||
|
||||
import Fixture from '../../Fixture';
|
||||
|
||||
class NumberInputDecimal extends React.Component {
|
||||
state = { value: '.98' };
|
||||
changeValue = () => {
|
||||
this.setState({
|
||||
value: '0.98',
|
||||
});
|
||||
}
|
||||
render() {
|
||||
const {value} = this.state;
|
||||
return (
|
||||
<Fixture>
|
||||
<div>{this.props.children}</div>
|
||||
|
||||
<div className="control-box">
|
||||
<input
|
||||
type="number"
|
||||
value={value}
|
||||
onChange={(e) => {
|
||||
this.setState({value: e.target.value});
|
||||
}}
|
||||
/>
|
||||
<button onClick={this.changeValue}>change.98 to 0.98</button>
|
||||
</div>
|
||||
</Fixture>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default NumberInputDecimal;
|
||||
@@ -1,37 +0,0 @@
|
||||
const React = window.React;
|
||||
|
||||
import Fixture from '../../Fixture';
|
||||
|
||||
const NumberTestCase = React.createClass({
|
||||
getInitialState() {
|
||||
return { value: '' };
|
||||
},
|
||||
onChange(event) {
|
||||
const parsed = parseFloat(event.target.value, 10)
|
||||
const value = isNaN(parsed) ? '' : parsed
|
||||
|
||||
this.setState({ value })
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Fixture>
|
||||
<div>{this.props.children}</div>
|
||||
|
||||
<div className="control-box">
|
||||
<fieldset>
|
||||
<legend>Controlled</legend>
|
||||
<input type="number" value={this.state.value} onChange={this.onChange} />
|
||||
<span className="hint"> Value: {JSON.stringify(this.state.value)}</span>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>Uncontrolled</legend>
|
||||
<input type="number" defaultValue={0.5} />
|
||||
</fieldset>
|
||||
</div>
|
||||
</Fixture>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default NumberTestCase;
|
||||
@@ -1,167 +0,0 @@
|
||||
const React = window.React;
|
||||
|
||||
import FixtureSet from '../../FixtureSet';
|
||||
import TestCase from '../../TestCase';
|
||||
import NumberTestCase from './NumberTestCase';
|
||||
|
||||
const NumberInputs = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<FixtureSet
|
||||
title="Number inputs"
|
||||
description="Number inputs inconsistently assign and report the value
|
||||
property depending on the browser."
|
||||
>
|
||||
<TestCase
|
||||
title="Backspacing"
|
||||
description="The decimal place should not be lost"
|
||||
>
|
||||
<TestCase.Steps>
|
||||
<li>Type "3.1"</li>
|
||||
<li>Press backspace, eliminating the "1"</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should read "3.", preserving the decimal place
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<NumberTestCase />
|
||||
|
||||
<p className="footnote">
|
||||
<b>Notes:</b> Chrome and Safari clear trailing
|
||||
decimals on blur. React makes this concession so that the
|
||||
value attribute remains in sync with the value property.
|
||||
</p>
|
||||
</TestCase>
|
||||
|
||||
<TestCase
|
||||
title="Decimal precision"
|
||||
description="Supports decimal precision greater than 2 places"
|
||||
>
|
||||
<TestCase.Steps>
|
||||
<li>Type "0.01"</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should read "0.01"
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<NumberTestCase />
|
||||
</TestCase>
|
||||
|
||||
<TestCase
|
||||
title="Exponent form"
|
||||
description="Supports exponent form ('2e4')"
|
||||
>
|
||||
<TestCase.Steps>
|
||||
<li>Type "2e"</li>
|
||||
<li>Type 4, to read "2e4"</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should read "2e4". The parsed value should read "20000"
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<NumberTestCase />
|
||||
</TestCase>
|
||||
|
||||
<TestCase
|
||||
title="Exponent Form"
|
||||
description="Pressing 'e' at the end"
|
||||
>
|
||||
<TestCase.Steps>
|
||||
<li>Type "3.14"</li>
|
||||
<li>Press "e", so that the input reads "3.14e"</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should read "3.14e", the parsed value should be empty
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<NumberTestCase />
|
||||
</TestCase>
|
||||
|
||||
<TestCase
|
||||
title="Exponent Form"
|
||||
description="Supports pressing 'ee' in the middle of a number"
|
||||
>
|
||||
<TestCase.Steps>
|
||||
<li>Type "3.14"</li>
|
||||
<li>Move the text cursor to after the decimal place</li>
|
||||
<li>Press "e" twice, so that the value reads "3.ee14"</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should read "3.ee14"
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<NumberTestCase />
|
||||
</TestCase>
|
||||
|
||||
<TestCase
|
||||
title="Trailing Zeroes"
|
||||
description="Typing '3.0' preserves the trailing zero"
|
||||
>
|
||||
<TestCase.Steps>
|
||||
<li>Type "3.0"</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should read "3.0"
|
||||
</TestCase.ExpectedResult>
|
||||
|
||||
<NumberTestCase />
|
||||
</TestCase>
|
||||
|
||||
<TestCase
|
||||
title="Inserting decimals precision"
|
||||
description="Inserting '.' in to '300' maintains the trailing zeroes"
|
||||
>
|
||||
<TestCase.Steps>
|
||||
<li>Type "300"</li>
|
||||
<li>Move the cursor to after the "3"</li>
|
||||
<li>Type "."</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should read "3.00", not "3"
|
||||
</TestCase.ExpectedResult>
|
||||
<NumberTestCase />
|
||||
</TestCase>
|
||||
|
||||
<TestCase
|
||||
title="Replacing numbers with -"
|
||||
description="Replacing a number with the '-' sign should not clear the value"
|
||||
>
|
||||
<TestCase.Steps>
|
||||
<li>Type "3"</li>
|
||||
<li>Select the entire value"</li>
|
||||
<li>Type '-' to replace '3' with '-'</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should read "-", not be blank.
|
||||
</TestCase.ExpectedResult>
|
||||
<NumberTestCase />
|
||||
</TestCase>
|
||||
|
||||
<TestCase
|
||||
title="Negative numbers"
|
||||
description="Typing minus when inserting a negative number should work"
|
||||
>
|
||||
<TestCase.Steps>
|
||||
<li>Type "-"</li>
|
||||
<li>Type '3'</li>
|
||||
</TestCase.Steps>
|
||||
|
||||
<TestCase.ExpectedResult>
|
||||
The field should read "-3".
|
||||
</TestCase.ExpectedResult>
|
||||
<NumberTestCase />
|
||||
</TestCase>
|
||||
</FixtureSet>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default NumberInputs;
|
||||
+6
-3
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "react-build",
|
||||
"private": true,
|
||||
"version": "15.5.4",
|
||||
"version": "15.6.0-rc.1",
|
||||
"devDependencies": {
|
||||
"aliasify": "^2.0.0",
|
||||
"art": "^0.10.1",
|
||||
@@ -40,7 +40,6 @@
|
||||
"coffee-script": "^1.8.0",
|
||||
"core-js": "^2.2.1",
|
||||
"coveralls": "^2.11.6",
|
||||
"create-react-class": "15.5.0",
|
||||
"del": "^2.0.2",
|
||||
"derequire": "^2.0.3",
|
||||
"eslint": "^3.10.2",
|
||||
@@ -71,7 +70,7 @@
|
||||
"merge-stream": "^1.0.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"platform": "^1.1.0",
|
||||
"prop-types": "15.5.7",
|
||||
"prettier": "^1.2.2",
|
||||
"run-sequence": "^1.1.4",
|
||||
"through2": "^2.0.0",
|
||||
"tmp": "~0.0.28",
|
||||
@@ -84,6 +83,10 @@
|
||||
"node": "4.x || 5.x || 6.x || 7.x",
|
||||
"npm": "2.x || 3.x || 4.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"create-react-class": "^15.5.2",
|
||||
"prop-types": "15.5.7"
|
||||
},
|
||||
"commonerConfig": {
|
||||
"version": 7
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-addons-template",
|
||||
"version": "15.5.4",
|
||||
"version": "15.6.0-rc.1",
|
||||
"main": "index.js",
|
||||
"repository": "facebook/react",
|
||||
"keywords": [
|
||||
@@ -13,7 +13,7 @@
|
||||
"object-assign": "^4.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^15.5.4"
|
||||
"react": "^15.6.0-rc.1"
|
||||
},
|
||||
"files": [
|
||||
"LICENSE",
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# `react-dom-factories`
|
||||
|
||||
> Note:
|
||||
> `ReactDOMFactories` is a legacy add-on. Consider using
|
||||
> `React.createFactory` or JSX instead.
|
||||
|
||||
Prior to version 16.0.0, React maintained a whitelist of
|
||||
pre-configured DOM factories. These predefined factories have been
|
||||
moved to the `react-dom-factories` library.
|
||||
|
||||
## Example
|
||||
|
||||
```javascript
|
||||
import ReactDOM from 'react-dom';
|
||||
import DOM from 'react-dom-factories';
|
||||
|
||||
const greeting = DOM.div({ className: 'greeting' }, DOM.p(null, 'Hello, world!'));
|
||||
|
||||
ReactDOM.render(greeting, document.getElementById('app'))
|
||||
```
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Copyright 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
(function(f) {
|
||||
if (typeof exports === 'object' && typeof module !== 'undefined') {
|
||||
module.exports = f(require('react'));
|
||||
/* global define */
|
||||
} else if (typeof define === 'function' && define.amd) {
|
||||
define(['react'], f);
|
||||
} else {
|
||||
var g;
|
||||
if (typeof window !== 'undefined') {
|
||||
g = window;
|
||||
} else if (typeof global !== 'undefined') {
|
||||
g = global;
|
||||
} else if (typeof self !== 'undefined') {
|
||||
g = self;
|
||||
} else {
|
||||
g = this;
|
||||
}
|
||||
|
||||
if (typeof g.React === 'undefined') {
|
||||
throw Error('React module should be required before ReactDOMFactories');
|
||||
}
|
||||
|
||||
g.ReactDOMFactories = f(g.React);
|
||||
}
|
||||
})(function(React) {
|
||||
/**
|
||||
* Create a factory that creates HTML tag elements.
|
||||
*/
|
||||
var createDOMFactory = React.createFactory;
|
||||
|
||||
/**
|
||||
* Creates a mapping from supported HTML tags to `ReactDOMComponent` classes.
|
||||
*/
|
||||
var ReactDOMFactories = {
|
||||
a: createDOMFactory('a'),
|
||||
abbr: createDOMFactory('abbr'),
|
||||
address: createDOMFactory('address'),
|
||||
area: createDOMFactory('area'),
|
||||
article: createDOMFactory('article'),
|
||||
aside: createDOMFactory('aside'),
|
||||
audio: createDOMFactory('audio'),
|
||||
b: createDOMFactory('b'),
|
||||
base: createDOMFactory('base'),
|
||||
bdi: createDOMFactory('bdi'),
|
||||
bdo: createDOMFactory('bdo'),
|
||||
big: createDOMFactory('big'),
|
||||
blockquote: createDOMFactory('blockquote'),
|
||||
body: createDOMFactory('body'),
|
||||
br: createDOMFactory('br'),
|
||||
button: createDOMFactory('button'),
|
||||
canvas: createDOMFactory('canvas'),
|
||||
caption: createDOMFactory('caption'),
|
||||
cite: createDOMFactory('cite'),
|
||||
code: createDOMFactory('code'),
|
||||
col: createDOMFactory('col'),
|
||||
colgroup: createDOMFactory('colgroup'),
|
||||
data: createDOMFactory('data'),
|
||||
datalist: createDOMFactory('datalist'),
|
||||
dd: createDOMFactory('dd'),
|
||||
del: createDOMFactory('del'),
|
||||
details: createDOMFactory('details'),
|
||||
dfn: createDOMFactory('dfn'),
|
||||
dialog: createDOMFactory('dialog'),
|
||||
div: createDOMFactory('div'),
|
||||
dl: createDOMFactory('dl'),
|
||||
dt: createDOMFactory('dt'),
|
||||
em: createDOMFactory('em'),
|
||||
embed: createDOMFactory('embed'),
|
||||
fieldset: createDOMFactory('fieldset'),
|
||||
figcaption: createDOMFactory('figcaption'),
|
||||
figure: createDOMFactory('figure'),
|
||||
footer: createDOMFactory('footer'),
|
||||
form: createDOMFactory('form'),
|
||||
h1: createDOMFactory('h1'),
|
||||
h2: createDOMFactory('h2'),
|
||||
h3: createDOMFactory('h3'),
|
||||
h4: createDOMFactory('h4'),
|
||||
h5: createDOMFactory('h5'),
|
||||
h6: createDOMFactory('h6'),
|
||||
head: createDOMFactory('head'),
|
||||
header: createDOMFactory('header'),
|
||||
hgroup: createDOMFactory('hgroup'),
|
||||
hr: createDOMFactory('hr'),
|
||||
html: createDOMFactory('html'),
|
||||
i: createDOMFactory('i'),
|
||||
iframe: createDOMFactory('iframe'),
|
||||
img: createDOMFactory('img'),
|
||||
input: createDOMFactory('input'),
|
||||
ins: createDOMFactory('ins'),
|
||||
kbd: createDOMFactory('kbd'),
|
||||
keygen: createDOMFactory('keygen'),
|
||||
label: createDOMFactory('label'),
|
||||
legend: createDOMFactory('legend'),
|
||||
li: createDOMFactory('li'),
|
||||
link: createDOMFactory('link'),
|
||||
main: createDOMFactory('main'),
|
||||
map: createDOMFactory('map'),
|
||||
mark: createDOMFactory('mark'),
|
||||
menu: createDOMFactory('menu'),
|
||||
menuitem: createDOMFactory('menuitem'),
|
||||
meta: createDOMFactory('meta'),
|
||||
meter: createDOMFactory('meter'),
|
||||
nav: createDOMFactory('nav'),
|
||||
noscript: createDOMFactory('noscript'),
|
||||
object: createDOMFactory('object'),
|
||||
ol: createDOMFactory('ol'),
|
||||
optgroup: createDOMFactory('optgroup'),
|
||||
option: createDOMFactory('option'),
|
||||
output: createDOMFactory('output'),
|
||||
p: createDOMFactory('p'),
|
||||
param: createDOMFactory('param'),
|
||||
picture: createDOMFactory('picture'),
|
||||
pre: createDOMFactory('pre'),
|
||||
progress: createDOMFactory('progress'),
|
||||
q: createDOMFactory('q'),
|
||||
rp: createDOMFactory('rp'),
|
||||
rt: createDOMFactory('rt'),
|
||||
ruby: createDOMFactory('ruby'),
|
||||
s: createDOMFactory('s'),
|
||||
samp: createDOMFactory('samp'),
|
||||
script: createDOMFactory('script'),
|
||||
section: createDOMFactory('section'),
|
||||
select: createDOMFactory('select'),
|
||||
small: createDOMFactory('small'),
|
||||
source: createDOMFactory('source'),
|
||||
span: createDOMFactory('span'),
|
||||
strong: createDOMFactory('strong'),
|
||||
style: createDOMFactory('style'),
|
||||
sub: createDOMFactory('sub'),
|
||||
summary: createDOMFactory('summary'),
|
||||
sup: createDOMFactory('sup'),
|
||||
table: createDOMFactory('table'),
|
||||
tbody: createDOMFactory('tbody'),
|
||||
td: createDOMFactory('td'),
|
||||
textarea: createDOMFactory('textarea'),
|
||||
tfoot: createDOMFactory('tfoot'),
|
||||
th: createDOMFactory('th'),
|
||||
thead: createDOMFactory('thead'),
|
||||
time: createDOMFactory('time'),
|
||||
title: createDOMFactory('title'),
|
||||
tr: createDOMFactory('tr'),
|
||||
track: createDOMFactory('track'),
|
||||
u: createDOMFactory('u'),
|
||||
ul: createDOMFactory('ul'),
|
||||
var: createDOMFactory('var'),
|
||||
video: createDOMFactory('video'),
|
||||
wbr: createDOMFactory('wbr'),
|
||||
|
||||
// SVG
|
||||
circle: createDOMFactory('circle'),
|
||||
clipPath: createDOMFactory('clipPath'),
|
||||
defs: createDOMFactory('defs'),
|
||||
ellipse: createDOMFactory('ellipse'),
|
||||
g: createDOMFactory('g'),
|
||||
image: createDOMFactory('image'),
|
||||
line: createDOMFactory('line'),
|
||||
linearGradient: createDOMFactory('linearGradient'),
|
||||
mask: createDOMFactory('mask'),
|
||||
path: createDOMFactory('path'),
|
||||
pattern: createDOMFactory('pattern'),
|
||||
polygon: createDOMFactory('polygon'),
|
||||
polyline: createDOMFactory('polyline'),
|
||||
radialGradient: createDOMFactory('radialGradient'),
|
||||
rect: createDOMFactory('rect'),
|
||||
stop: createDOMFactory('stop'),
|
||||
svg: createDOMFactory('svg'),
|
||||
text: createDOMFactory('text'),
|
||||
tspan: createDOMFactory('tspan'),
|
||||
};
|
||||
|
||||
// due to wrapper and conditionals at the top, this will either become
|
||||
// `module.exports ReactDOMFactories` if that is available,
|
||||
// otherwise it will be defined via `define(['react'], ReactDOMFactories)`
|
||||
// if that is available,
|
||||
// otherwise it will be defined as global variable.
|
||||
return ReactDOMFactories;
|
||||
});
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "react-dom-factories",
|
||||
"version": "15.6.0-rc",
|
||||
"description": "React package for DOM factory methods.",
|
||||
"main": "index.js",
|
||||
"repository": "facebook/react",
|
||||
"keywords": [
|
||||
"react"
|
||||
],
|
||||
"license": "BSD-3-Clause",
|
||||
"bugs": {
|
||||
"url": "https://github.com/facebook/react/issues"
|
||||
},
|
||||
"homepage": "https://facebook.github.io/react/",
|
||||
"peerDependencies": {
|
||||
"react": "^15.6.0-rc.1"
|
||||
},
|
||||
"files": [
|
||||
"LICENSE",
|
||||
"PATENTS",
|
||||
"README.md",
|
||||
"index.js",
|
||||
"lib/"
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-dom",
|
||||
"version": "15.5.4",
|
||||
"version": "15.6.0-rc.1",
|
||||
"description": "React package for working with the DOM.",
|
||||
"main": "index.js",
|
||||
"repository": "facebook/react",
|
||||
@@ -19,7 +19,7 @@
|
||||
"prop-types": "~15.5.7"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^15.5.4"
|
||||
"react": "^15.6.0-rc.1"
|
||||
},
|
||||
"files": [
|
||||
"LICENSE",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-renderer",
|
||||
"version": "15.5.4",
|
||||
"version": "15.6.0-rc.1",
|
||||
"description": "React package for use inside react-native.",
|
||||
"main": "index.js",
|
||||
"repository": "facebook/react",
|
||||
@@ -18,7 +18,7 @@
|
||||
"object-assign": "^4.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^15.5.4"
|
||||
"react": "^15.6.0-rc.1"
|
||||
},
|
||||
"files": [
|
||||
"LICENSE",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-test-renderer",
|
||||
"version": "15.5.4",
|
||||
"version": "15.6.0-rc.1",
|
||||
"description": "React package for snapshot testing.",
|
||||
"main": "index.js",
|
||||
"repository": "facebook/react",
|
||||
@@ -19,7 +19,7 @@
|
||||
"object-assign": "^4.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^15.5.4"
|
||||
"react": "^15.6.0-rc.1"
|
||||
},
|
||||
"files": [
|
||||
"LICENSE",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "react",
|
||||
"description": "React is a JavaScript library for building user interfaces.",
|
||||
"version": "15.5.4",
|
||||
"version": "15.6.0-rc.1",
|
||||
"keywords": [
|
||||
"react"
|
||||
],
|
||||
@@ -23,6 +23,7 @@
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"create-react-class": "^15.5.2",
|
||||
"fbjs": "^0.8.9",
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.0",
|
||||
|
||||
@@ -28,7 +28,7 @@ function compile(content, contentFilename) {
|
||||
// the file path into backslashes on Windows.
|
||||
filename = path.normalize(filename);
|
||||
var reactRegex = new RegExp(
|
||||
path.join('/', '(?:React|ReactDOM)(?:\.d)?\.ts$')
|
||||
path.join('/', '(?:React|ReactDOM|PropTypes)(?:\.d)?\.ts$')
|
||||
);
|
||||
|
||||
var jestRegex = /jest\.d\.ts/;
|
||||
|
||||
+1
-1
@@ -11,4 +11,4 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = '15.5.4';
|
||||
module.exports = '15.6.0-rc.1';
|
||||
|
||||
+1
-2
@@ -26,7 +26,6 @@ if (__DEV__) {
|
||||
|
||||
/**
|
||||
* Creates a mapping from supported HTML tags to `ReactDOMComponent` classes.
|
||||
* This is also accessible via `React.DOM`.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
@@ -141,7 +140,7 @@ var ReactDOMFactories = {
|
||||
track: createDOMFactory('track'),
|
||||
u: createDOMFactory('u'),
|
||||
ul: createDOMFactory('ul'),
|
||||
'var': createDOMFactory('var'),
|
||||
var: createDOMFactory('var'),
|
||||
video: createDOMFactory('video'),
|
||||
wbr: createDOMFactory('wbr'),
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
var LinkedStateMixin = require('LinkedStateMixin');
|
||||
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');
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @emails react-core
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var React = require('React');
|
||||
var {div} = require('ReactDOMFactories');
|
||||
|
||||
describe('ReactDOMFactories', () => {
|
||||
it('allow factories to be called without warnings', () => {
|
||||
spyOn(console, 'error');
|
||||
spyOn(console, 'warn');
|
||||
var element = div();
|
||||
expect(element.type).toBe('div');
|
||||
expect(console.error).not.toHaveBeenCalled();
|
||||
expect(console.warn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('warns once when accessing React.DOM methods', () => {
|
||||
spyOn(console, 'warn');
|
||||
|
||||
var a = React.DOM.a();
|
||||
var p = React.DOM.p();
|
||||
|
||||
expect(a.type).toBe('a');
|
||||
expect(p.type).toBe('p');
|
||||
|
||||
expect(console.warn).toHaveBeenCalledTimes(1);
|
||||
expect(console.warn.calls.first().args[0]).toContain(
|
||||
'Warning: Accessing factories like React.DOM.a has been deprecated',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -16,7 +16,6 @@ var ReactDOM;
|
||||
var ReactFragment;
|
||||
|
||||
describe('ReactFragment', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
React = require('React');
|
||||
ReactDOM = require('ReactDOM');
|
||||
@@ -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. Check 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. Check the render method of `Foo`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -64,9 +63,9 @@ describe('ReactFragment', () => {
|
||||
var container = document.createElement('div');
|
||||
expect(() => ReactDOM.render(<div>{oldEl}</div>, container)).toThrowError(
|
||||
'Objects are not valid as a React child (found: object with keys ' +
|
||||
'{_isReactElement, type, props}). It looks like you\'re using an ' +
|
||||
'element created by a different version of React. Make sure to use ' +
|
||||
'only one copy of React.'
|
||||
"{_isReactElement, type, props}). It looks like you're using an " +
|
||||
'element created by a different version of React. Make sure to use ' +
|
||||
'only one copy of React.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -77,7 +76,7 @@ describe('ReactFragment', () => {
|
||||
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -86,7 +85,7 @@ describe('ReactFragment', () => {
|
||||
ReactFragment.create(null);
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'React.addons.createFragment only accepts a single object.'
|
||||
'React.addons.createFragment only accepts a single object.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -95,7 +94,7 @@ describe('ReactFragment', () => {
|
||||
ReactFragment.create([]);
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'React.addons.createFragment only accepts a single object.'
|
||||
'React.addons.createFragment only accepts a single object.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -105,8 +104,7 @@ describe('ReactFragment', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'React.addons.createFragment does not accept a ReactElement without a ' +
|
||||
'wrapper object.'
|
||||
'wrapper object.',
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -11,19 +11,19 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var PropTypes = require('prop-types');
|
||||
var React = require('React');
|
||||
var ReactDOM = require('ReactDOM');
|
||||
var ReactTestUtils = require('ReactTestUtils');
|
||||
var renderSubtreeIntoContainer = require('renderSubtreeIntoContainer');
|
||||
|
||||
describe('renderSubtreeIntoContainer', () => {
|
||||
|
||||
it('should pass context when rendering subtree elsewhere', () => {
|
||||
var portal = document.createElement('div');
|
||||
|
||||
class Component extends React.Component {
|
||||
static contextTypes = {
|
||||
foo: React.PropTypes.string.isRequired,
|
||||
foo: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
@@ -33,7 +33,7 @@ describe('renderSubtreeIntoContainer', () => {
|
||||
|
||||
class Parent extends React.Component {
|
||||
static childContextTypes = {
|
||||
foo: React.PropTypes.string.isRequired,
|
||||
foo: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
getChildContext() {
|
||||
@@ -47,9 +47,11 @@ describe('renderSubtreeIntoContainer', () => {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
expect(function() {
|
||||
renderSubtreeIntoContainer(this, <Component />, portal);
|
||||
}.bind(this)).not.toThrow();
|
||||
expect(
|
||||
function() {
|
||||
renderSubtreeIntoContainer(this, <Component />, portal);
|
||||
}.bind(this),
|
||||
).not.toThrow();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +64,7 @@ describe('renderSubtreeIntoContainer', () => {
|
||||
|
||||
class Component extends React.Component {
|
||||
static contextTypes = {
|
||||
foo: React.PropTypes.string.isRequired,
|
||||
foo: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
@@ -75,7 +77,7 @@ describe('renderSubtreeIntoContainer', () => {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
class Parent extends React.Component {
|
||||
static childContextTypes = {
|
||||
foo: React.PropTypes.string.isRequired,
|
||||
foo: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
getChildContext() {
|
||||
@@ -103,8 +105,8 @@ describe('renderSubtreeIntoContainer', () => {
|
||||
|
||||
class Component extends React.Component {
|
||||
static contextTypes = {
|
||||
foo: React.PropTypes.string.isRequired,
|
||||
getFoo: React.PropTypes.func.isRequired,
|
||||
foo: PropTypes.string.isRequired,
|
||||
getFoo: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
@@ -114,8 +116,8 @@ describe('renderSubtreeIntoContainer', () => {
|
||||
|
||||
class Parent extends React.Component {
|
||||
static childContextTypes = {
|
||||
foo: React.PropTypes.string.isRequired,
|
||||
getFoo: React.PropTypes.func.isRequired,
|
||||
foo: PropTypes.string.isRequired,
|
||||
getFoo: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
@@ -155,8 +157,8 @@ describe('renderSubtreeIntoContainer', () => {
|
||||
|
||||
class Component extends React.Component {
|
||||
static contextTypes = {
|
||||
foo: React.PropTypes.string.isRequired,
|
||||
getFoo: React.PropTypes.func.isRequired,
|
||||
foo: PropTypes.string.isRequired,
|
||||
getFoo: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
@@ -166,8 +168,8 @@ describe('renderSubtreeIntoContainer', () => {
|
||||
|
||||
class Parent extends React.Component {
|
||||
static childContextTypes = {
|
||||
foo: React.PropTypes.string.isRequired,
|
||||
getFoo: React.PropTypes.func.isRequired,
|
||||
foo: PropTypes.string.isRequired,
|
||||
getFoo: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
getChildContext() {
|
||||
@@ -195,5 +197,4 @@ describe('renderSubtreeIntoContainer', () => {
|
||||
ReactDOM.render(<Parent bar="changed" />, container);
|
||||
expect(portal.firstChild.innerHTML).toBe('changed-changed');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -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',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -30,7 +30,7 @@ var LinkedStateMixin = {
|
||||
linkState: function(key) {
|
||||
return new ReactLink(
|
||||
this.state[key],
|
||||
ReactStateSetters.createStateKeySetter(this, key)
|
||||
ReactStateSetters.createStateKeySetter(this, key),
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -48,26 +48,4 @@ function ReactLink(value, requestChange) {
|
||||
this.requestChange = requestChange;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PropType that enforces the ReactLink API and optionally checks the
|
||||
* type of the value being passed inside the link. Example:
|
||||
*
|
||||
* MyComponent.propTypes = {
|
||||
* tabIndexLink: ReactLink.PropTypes.link(React.PropTypes.number)
|
||||
* }
|
||||
*/
|
||||
function createLinkTypeChecker(linkType) {
|
||||
var shapes = {
|
||||
value: linkType === undefined ?
|
||||
React.PropTypes.any.isRequired :
|
||||
linkType.isRequired,
|
||||
requestChange: React.PropTypes.func.isRequired,
|
||||
};
|
||||
return React.PropTypes.shape(shapes);
|
||||
}
|
||||
|
||||
ReactLink.PropTypes = {
|
||||
link: createLinkTypeChecker,
|
||||
};
|
||||
|
||||
module.exports = ReactLink;
|
||||
|
||||
@@ -28,16 +28,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)',
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -68,7 +71,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.
|
||||
@@ -83,14 +86,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}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ var ReactAddonsDOMDependencies = require('ReactAddonsDOMDependencies');
|
||||
var propTypesFactory = require('prop-types/factory');
|
||||
var PropTypes = propTypesFactory(React.isValidElement);
|
||||
|
||||
|
||||
var CSSCore = require('CSSCore');
|
||||
var ReactTransitionEvents = require('ReactTransitionEvents');
|
||||
|
||||
@@ -67,8 +66,10 @@ class ReactCSSTransitionGroupChild extends React.Component {
|
||||
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) {
|
||||
@@ -149,29 +150,29 @@ class ReactCSSTransitionGroupChild extends React.Component {
|
||||
this.classNameAndNodeQueue.length = 0;
|
||||
}
|
||||
|
||||
componentWillAppear = (done) => {
|
||||
componentWillAppear = done => {
|
||||
if (this.props.appear) {
|
||||
this.transition('appear', done, this.props.appearTimeout);
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
componentWillEnter = (done) => {
|
||||
componentWillEnter = done => {
|
||||
if (this.props.enter) {
|
||||
this.transition('enter', done, this.props.enterTimeout);
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
componentWillLeave = (done) => {
|
||||
componentWillLeave = done => {
|
||||
if (this.props.leave) {
|
||||
this.transition('leave', done, this.props.leaveTimeout);
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return onlyChild(this.props.children);
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,14 +59,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,
|
||||
),
|
||||
});
|
||||
|
||||
@@ -74,16 +74,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);
|
||||
}
|
||||
}
|
||||
@@ -101,21 +107,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();
|
||||
@@ -124,7 +128,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)) {
|
||||
@@ -133,21 +137,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();
|
||||
@@ -156,7 +158,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)) {
|
||||
@@ -165,7 +167,7 @@ class ReactTransitionGroup extends React.Component {
|
||||
}
|
||||
};
|
||||
|
||||
performLeave = (key) => {
|
||||
performLeave = key => {
|
||||
this.currentlyTransitioningKeys[key] = true;
|
||||
|
||||
var component = this.refs[key];
|
||||
@@ -179,7 +181,7 @@ class ReactTransitionGroup extends React.Component {
|
||||
}
|
||||
};
|
||||
|
||||
_handleDoneLeaving = (key) => {
|
||||
_handleDoneLeaving = key => {
|
||||
var component = this.refs[key];
|
||||
|
||||
if (component.componentDidLeave) {
|
||||
@@ -189,7 +191,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)) {
|
||||
@@ -216,10 +218,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,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,11 +239,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
+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);
|
||||
}
|
||||
|
||||
+76
-23
@@ -11,23 +11,22 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var ReactBaseClasses = require('ReactBaseClasses');
|
||||
var ReactChildren = require('ReactChildren');
|
||||
var ReactComponent = require('ReactComponent');
|
||||
var ReactPureComponent = require('ReactPureComponent');
|
||||
var ReactClass = require('ReactClass');
|
||||
var ReactDOMFactories = require('ReactDOMFactories');
|
||||
var ReactElement = require('ReactElement');
|
||||
var ReactPropTypes = require('ReactPropTypes');
|
||||
var ReactVersion = require('ReactVersion');
|
||||
|
||||
var createReactClass = require('createClass');
|
||||
var onlyChild = require('onlyChild');
|
||||
var warning = require('warning');
|
||||
|
||||
var createElement = ReactElement.createElement;
|
||||
var createFactory = ReactElement.createFactory;
|
||||
var cloneElement = ReactElement.cloneElement;
|
||||
|
||||
if (__DEV__) {
|
||||
var lowPriorityWarning = require('lowPriorityWarning');
|
||||
var canDefineProperty = require('canDefineProperty');
|
||||
var ReactElementValidator = require('ReactElementValidator');
|
||||
var didWarnPropTypesDeprecated = false;
|
||||
@@ -37,24 +36,39 @@ if (__DEV__) {
|
||||
}
|
||||
|
||||
var __spread = Object.assign;
|
||||
var createMixin = function(mixin) {
|
||||
return mixin;
|
||||
};
|
||||
|
||||
if (__DEV__) {
|
||||
var warned = false;
|
||||
var warnedForSpread = false;
|
||||
var warnedForCreateMixin = false;
|
||||
__spread = function() {
|
||||
warning(
|
||||
warned,
|
||||
lowPriorityWarning(
|
||||
warnedForSpread,
|
||||
'React.__spread is deprecated and should not be used. Use ' +
|
||||
'Object.assign directly or another helper function with similar ' +
|
||||
'semantics. You may be seeing this warning due to your compiler. ' +
|
||||
'See https://fb.me/react-spread-deprecation for more details.'
|
||||
'Object.assign directly or another helper function with similar ' +
|
||||
'semantics. You may be seeing this warning due to your compiler. ' +
|
||||
'See https://fb.me/react-spread-deprecation for more details.',
|
||||
);
|
||||
warned = true;
|
||||
warnedForSpread = true;
|
||||
return Object.assign.apply(null, arguments);
|
||||
};
|
||||
|
||||
createMixin = function(mixin) {
|
||||
lowPriorityWarning(
|
||||
warnedForCreateMixin,
|
||||
'React.createMixin is deprecated and should not be used. ' +
|
||||
'In React v16.0, it will be removed. ' +
|
||||
'You can use this mixin directly instead. ' +
|
||||
'See https://fb.me/createmixin-was-never-implemented for more info.',
|
||||
);
|
||||
warnedForCreateMixin = true;
|
||||
return mixin;
|
||||
};
|
||||
}
|
||||
|
||||
var React = {
|
||||
|
||||
// Modern
|
||||
|
||||
Children: {
|
||||
@@ -65,8 +79,8 @@ var React = {
|
||||
only: onlyChild,
|
||||
},
|
||||
|
||||
Component: ReactComponent,
|
||||
PureComponent: ReactPureComponent,
|
||||
Component: ReactBaseClasses.Component,
|
||||
PureComponent: ReactBaseClasses.PureComponent,
|
||||
|
||||
createElement: createElement,
|
||||
cloneElement: cloneElement,
|
||||
@@ -75,12 +89,9 @@ var React = {
|
||||
// Classic
|
||||
|
||||
PropTypes: ReactPropTypes,
|
||||
createClass: ReactClass.createClass,
|
||||
createClass: createReactClass,
|
||||
createFactory: createFactory,
|
||||
createMixin: function(mixin) {
|
||||
// Currently a noop. Will be used to validate and trace mixins.
|
||||
return mixin;
|
||||
},
|
||||
createMixin: createMixin,
|
||||
|
||||
// This looks DOM specific but these are actually isomorphic helpers
|
||||
// since they are just generating DOM strings.
|
||||
@@ -92,21 +103,63 @@ var React = {
|
||||
__spread: __spread,
|
||||
};
|
||||
|
||||
// TODO: Fix tests so that this deprecation warning doesn't cause failures.
|
||||
if (__DEV__) {
|
||||
let warnedForCreateClass = false;
|
||||
if (canDefineProperty) {
|
||||
Object.defineProperty(React, 'PropTypes', {
|
||||
get() {
|
||||
warning(
|
||||
lowPriorityWarning(
|
||||
didWarnPropTypesDeprecated,
|
||||
'Accessing PropTypes via the main React package is deprecated. Use ' +
|
||||
'the prop-types package from npm instead.'
|
||||
'Accessing PropTypes via the main React package is deprecated,' +
|
||||
' and will be removed in React v16.0.' +
|
||||
' Use the latest available v15.* prop-types package from npm instead.' +
|
||||
' For info on usage, compatibility, migration and more, see ' +
|
||||
'https://fb.me/prop-types-docs',
|
||||
);
|
||||
didWarnPropTypesDeprecated = true;
|
||||
return ReactPropTypes;
|
||||
},
|
||||
});
|
||||
|
||||
Object.defineProperty(React, 'createClass', {
|
||||
get: function() {
|
||||
lowPriorityWarning(
|
||||
warnedForCreateClass,
|
||||
'Accessing createClass via the main React package is deprecated,' +
|
||||
' and will be removed in React v16.0.' +
|
||||
" Use a plain JavaScript class instead. If you're not yet " +
|
||||
'ready to migrate, create-react-class v15.* is available ' +
|
||||
'on npm as a temporary, drop-in replacement. ' +
|
||||
'For more info see https://fb.me/react-create-class',
|
||||
);
|
||||
warnedForCreateClass = true;
|
||||
return createReactClass;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// React.DOM factories are deprecated. Wrap these methods so that
|
||||
// invocations of the React.DOM namespace and alert users to switch
|
||||
// to the `react-dom-factories` package.
|
||||
React.DOM = {};
|
||||
var warnedForFactories = false;
|
||||
Object.keys(ReactDOMFactories).forEach(function(factory) {
|
||||
React.DOM[factory] = function(...args) {
|
||||
if (!warnedForFactories) {
|
||||
lowPriorityWarning(
|
||||
false,
|
||||
'Accessing factories like React.DOM.%s has been deprecated ' +
|
||||
'and will be removed in v16.0+. Use the ' +
|
||||
'react-dom-factories package instead. ' +
|
||||
' Version 1.0 provides a drop-in replacement.' +
|
||||
' For more info, see https://fb.me/react-dom-factories',
|
||||
factory,
|
||||
);
|
||||
warnedForFactories = true;
|
||||
}
|
||||
return ReactDOMFactories[factory](...args);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = React;
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @emails react-core
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
describe('React', () => {
|
||||
var React;
|
||||
|
||||
beforeEach(() => {
|
||||
React = require('React');
|
||||
});
|
||||
|
||||
it('should log a deprecation warning once when using React.__spread', () => {
|
||||
spyOn(console, 'warn');
|
||||
React.__spread({});
|
||||
React.__spread({});
|
||||
expect(console.warn.calls.count()).toBe(1);
|
||||
expect(console.warn.calls.argsFor(0)[0]).toContain(
|
||||
'React.__spread is deprecated and should not be used',
|
||||
);
|
||||
});
|
||||
|
||||
it('should log a deprecation warning once when using React.createMixin', () => {
|
||||
spyOn(console, 'warn');
|
||||
React.createMixin();
|
||||
React.createMixin();
|
||||
expect(console.warn.calls.count()).toBe(1);
|
||||
expect(console.warn.calls.argsFor(0)[0]).toContain(
|
||||
'React.createMixin is deprecated and should not be used',
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn once when attempting to access React.createClass', () => {
|
||||
spyOn(console, 'warn');
|
||||
let createClass = React.createClass;
|
||||
createClass = React.createClass;
|
||||
expect(createClass).not.toBe(undefined);
|
||||
expect(console.warn.calls.count()).toBe(1);
|
||||
expect(console.warn.calls.argsFor(0)[0]).toContain(
|
||||
'Warning: Accessing createClass via the main React package is ' +
|
||||
'deprecated, and will be removed in React v16.0. ' +
|
||||
"Use a plain JavaScript class instead. If you're not yet ready " +
|
||||
'to migrate, create-react-class v15.* is available on npm as ' +
|
||||
'a temporary, drop-in replacement. ' +
|
||||
'For more info see https://fb.me/react-create-class',
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn once when attempting to access React.PropTypes', () => {
|
||||
spyOn(console, 'warn');
|
||||
let PropTypes = React.PropTypes;
|
||||
PropTypes = React.PropTypes;
|
||||
expect(PropTypes).not.toBe(undefined);
|
||||
expect(console.warn.calls.count()).toBe(1);
|
||||
expect(console.warn.calls.argsFor(0)[0]).toContain(
|
||||
'Warning: Accessing PropTypes via the main React package is ' +
|
||||
'deprecated, and will be removed in React v16.0. ' +
|
||||
'Use the latest available v15.* prop-types package from ' +
|
||||
'npm instead. For info on usage, compatibility, migration ' +
|
||||
'and more, see https://fb.me/prop-types-docs',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -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,
|
||||
|
||||
@@ -69,7 +69,6 @@ describe('ReactChildren', () => {
|
||||
var mappedChildren = ReactChildren.map(instance.props.children, callback);
|
||||
expect(callback).toHaveBeenCalledWith(simpleKid, 0);
|
||||
expect(mappedChildren[0]).toEqual(<span key=".$simple" />);
|
||||
|
||||
});
|
||||
|
||||
it('should pass key to returned component', () => {
|
||||
@@ -103,8 +102,11 @@ describe('ReactChildren', () => {
|
||||
ReactChildren.forEach(instance.props.children, callback, scopeTester);
|
||||
expect(lastContext).toBe(scopeTester);
|
||||
|
||||
var mappedChildren =
|
||||
ReactChildren.map(instance.props.children, callback, scopeTester);
|
||||
var mappedChildren = ReactChildren.map(
|
||||
instance.props.children,
|
||||
callback,
|
||||
scopeTester,
|
||||
);
|
||||
|
||||
expect(ReactChildren.count(mappedChildren)).toBe(1);
|
||||
expect(mappedChildren[0]).toBe(scopeTester);
|
||||
@@ -118,9 +120,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" />,
|
||||
];
|
||||
@@ -146,8 +148,7 @@ describe('ReactChildren', () => {
|
||||
expect(callback).toHaveBeenCalledWith(four, 4);
|
||||
callback.calls.reset();
|
||||
|
||||
var mappedChildren =
|
||||
ReactChildren.map(instance.props.children, callback);
|
||||
var mappedChildren = ReactChildren.map(instance.props.children, callback);
|
||||
expect(callback.calls.count()).toBe(5);
|
||||
expect(ReactChildren.count(mappedChildren)).toBe(4);
|
||||
// Keys default to indices.
|
||||
@@ -156,9 +157,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);
|
||||
@@ -185,15 +184,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({
|
||||
@@ -203,12 +202,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',
|
||||
@@ -244,9 +238,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" />);
|
||||
});
|
||||
|
||||
@@ -271,21 +269,24 @@ describe('ReactChildren', () => {
|
||||
);
|
||||
|
||||
var expectedForcedKeys = ['giraffe/.$keyZero', '.$keyOne'];
|
||||
var mappedChildrenForcedKeys =
|
||||
ReactChildren.map(forcedKeys.props.children, mapFn);
|
||||
var mappedForcedKeys = mappedChildrenForcedKeys.map((c) => c.key);
|
||||
var mappedChildrenForcedKeys = ReactChildren.map(
|
||||
forcedKeys.props.children,
|
||||
mapFn,
|
||||
);
|
||||
var mappedForcedKeys = mappedChildrenForcedKeys.map(c => c.key);
|
||||
expect(mappedForcedKeys).toEqual(expectedForcedKeys);
|
||||
|
||||
var expectedRemappedForcedKeys = [
|
||||
'giraffe/.$giraffe/.$keyZero',
|
||||
'.$.$keyOne',
|
||||
];
|
||||
var remappedChildrenForcedKeys =
|
||||
ReactChildren.map(mappedChildrenForcedKeys, mapFn);
|
||||
expect(
|
||||
remappedChildrenForcedKeys.map((c) => c.key)
|
||||
).toEqual(expectedRemappedForcedKeys);
|
||||
|
||||
var remappedChildrenForcedKeys = ReactChildren.map(
|
||||
mappedChildrenForcedKeys,
|
||||
mapFn,
|
||||
);
|
||||
expect(remappedChildrenForcedKeys.map(c => c.key)).toEqual(
|
||||
expectedRemappedForcedKeys,
|
||||
);
|
||||
});
|
||||
|
||||
it('should not throw if key provided is a dupe with array key', () => {
|
||||
@@ -315,14 +316,10 @@ describe('ReactChildren', () => {
|
||||
</div>
|
||||
);
|
||||
|
||||
var mapped = ReactChildren.map(
|
||||
instance.props.children,
|
||||
element => element,
|
||||
);
|
||||
var mapped = ReactChildren.map(instance.props.children, element => element);
|
||||
|
||||
var mappedWithClone = ReactChildren.map(
|
||||
instance.props.children,
|
||||
element => React.cloneElement(element),
|
||||
var mappedWithClone = ReactChildren.map(instance.props.children, element =>
|
||||
React.cloneElement(element),
|
||||
);
|
||||
|
||||
expect(mapped[0].key).toBe(mappedWithClone[0].key);
|
||||
@@ -335,14 +332,10 @@ describe('ReactChildren', () => {
|
||||
</div>
|
||||
);
|
||||
|
||||
var mapped = ReactChildren.map(
|
||||
instance.props.children,
|
||||
element => element,
|
||||
);
|
||||
var mapped = ReactChildren.map(instance.props.children, element => element);
|
||||
|
||||
var mappedWithClone = ReactChildren.map(
|
||||
instance.props.children,
|
||||
element => React.cloneElement(element, {key: 'unique'}),
|
||||
var mappedWithClone = ReactChildren.map(instance.props.children, element =>
|
||||
React.cloneElement(element, {key: 'unique'}),
|
||||
);
|
||||
|
||||
expect(mapped[0].key).toBe(mappedWithClone[0].key);
|
||||
@@ -399,14 +392,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 = ReactChildren.count(instance.props.children);
|
||||
expect(numberOfChildren).toBe(5);
|
||||
@@ -418,10 +413,8 @@ describe('ReactChildren', () => {
|
||||
|
||||
expect(ReactChildren.toArray(<div />).length).toBe(1);
|
||||
expect(ReactChildren.toArray([<div />]).length).toBe(1);
|
||||
expect(
|
||||
ReactChildren.toArray(<div />)[0].key
|
||||
).toBe(
|
||||
ReactChildren.toArray([<div />])[0].key
|
||||
expect(ReactChildren.toArray(<div />)[0].key).toBe(
|
||||
ReactChildren.toArray([<div />])[0].key,
|
||||
);
|
||||
|
||||
var flattened = ReactChildren.toArray([
|
||||
@@ -445,9 +438,9 @@ describe('ReactChildren', () => {
|
||||
expect(flattened[5].key).toBe(reversed[3].key);
|
||||
|
||||
// null/undefined/bool are all omitted
|
||||
expect(ReactChildren.toArray([1, 'two', null, undefined, true])).toEqual(
|
||||
[1, 'two']
|
||||
);
|
||||
expect(ReactChildren.toArray([1, 'two', null, undefined, true])).toEqual([
|
||||
1,
|
||||
'two',
|
||||
]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
'use strict';
|
||||
|
||||
describe('onlyChild', () => {
|
||||
|
||||
var React;
|
||||
var ReactFragment;
|
||||
var onlyChild;
|
||||
@@ -35,63 +34,66 @@ 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', () => {
|
||||
expect(function() {
|
||||
var instance =
|
||||
var instance = (
|
||||
<WrapComponent>
|
||||
<span />
|
||||
</WrapComponent>;
|
||||
</WrapComponent>
|
||||
);
|
||||
onlyChild(instance.props.children);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
'use strict';
|
||||
|
||||
describe('sliceChildren', () => {
|
||||
|
||||
var React;
|
||||
|
||||
var sliceChildren;
|
||||
@@ -24,11 +23,7 @@ describe('sliceChildren', () => {
|
||||
});
|
||||
|
||||
it('should render the whole set if start zero is supplied', () => {
|
||||
var fullSet = [
|
||||
<div key="A" />,
|
||||
<div key="B" />,
|
||||
<div key="C" />,
|
||||
];
|
||||
var fullSet = [<div key="A" />, <div key="B" />, <div key="C" />];
|
||||
var children = sliceChildren(fullSet, 0);
|
||||
expect(children).toEqual([
|
||||
<div key=".$A" />,
|
||||
@@ -38,16 +33,9 @@ describe('sliceChildren', () => {
|
||||
});
|
||||
|
||||
it('should render the remaining set if no end index is supplied', () => {
|
||||
var fullSet = [
|
||||
<div key="A" />,
|
||||
<div key="B" />,
|
||||
<div key="C" />,
|
||||
];
|
||||
var fullSet = [<div key="A" />, <div key="B" />, <div key="C" />];
|
||||
var children = sliceChildren(fullSet, 1);
|
||||
expect(children).toEqual([
|
||||
<div key=".$B" />,
|
||||
<div key=".$C" />,
|
||||
]);
|
||||
expect(children).toEqual([<div key=".$B" />, <div key=".$C" />]);
|
||||
});
|
||||
|
||||
it('should exclude everything at or after the end index', () => {
|
||||
@@ -58,9 +46,7 @@ describe('sliceChildren', () => {
|
||||
<div key="D" />,
|
||||
];
|
||||
var children = sliceChildren(fullSet, 1, 2);
|
||||
expect(children).toEqual([
|
||||
<div key=".$B" />,
|
||||
]);
|
||||
expect(children).toEqual([<div key=".$B" />]);
|
||||
});
|
||||
|
||||
it('should allow static children to be sliced', () => {
|
||||
@@ -70,24 +56,16 @@ describe('sliceChildren', () => {
|
||||
|
||||
var el = <div>{a}{b}{c}</div>;
|
||||
var children = sliceChildren(el.props.children, 1, 2);
|
||||
expect(children).toEqual([
|
||||
<b key=".1" />,
|
||||
]);
|
||||
expect(children).toEqual([<b key=".1" />]);
|
||||
});
|
||||
|
||||
it('should slice nested children', () => {
|
||||
var fullSet = [
|
||||
<div key="A" />,
|
||||
[
|
||||
<div key="B" />,
|
||||
<div key="C" />,
|
||||
],
|
||||
[<div key="B" />, <div key="C" />],
|
||||
<div key="D" />,
|
||||
];
|
||||
var children = sliceChildren(fullSet, 1, 2);
|
||||
expect(children).toEqual([
|
||||
<div key=".1:$B" />,
|
||||
]);
|
||||
expect(children).toEqual([<div key=".1:$B" />]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -31,7 +31,7 @@ var invariant = require('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;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var PropTypes;
|
||||
var React;
|
||||
var ReactDOM;
|
||||
var ReactTestUtils;
|
||||
@@ -34,6 +35,7 @@ describe('ReactContextValidator', () => {
|
||||
React = require('React');
|
||||
ReactDOM = require('ReactDOM');
|
||||
ReactTestUtils = require('ReactTestUtils');
|
||||
PropTypes = require('prop-types');
|
||||
reactComponentExpect = require('reactComponentExpect');
|
||||
});
|
||||
|
||||
@@ -47,7 +49,7 @@ describe('ReactContextValidator', () => {
|
||||
}
|
||||
}
|
||||
Component.contextTypes = {
|
||||
foo: React.PropTypes.string,
|
||||
foo: PropTypes.string,
|
||||
};
|
||||
|
||||
class ComponentInFooBarContext extends React.Component {
|
||||
@@ -63,12 +65,16 @@ describe('ReactContextValidator', () => {
|
||||
}
|
||||
}
|
||||
ComponentInFooBarContext.childContextTypes = {
|
||||
foo: React.PropTypes.string,
|
||||
bar: React.PropTypes.number,
|
||||
foo: PropTypes.string,
|
||||
bar: PropTypes.number,
|
||||
};
|
||||
|
||||
var instance = ReactTestUtils.renderIntoDocument(<ComponentInFooBarContext />);
|
||||
reactComponentExpect(instance).expectRenderedChild().scalarContextEqual({foo: 'abc'});
|
||||
var instance = ReactTestUtils.renderIntoDocument(
|
||||
<ComponentInFooBarContext />,
|
||||
);
|
||||
reactComponentExpect(instance)
|
||||
.expectRenderedChild()
|
||||
.scalarContextEqual({foo: 'abc'});
|
||||
});
|
||||
|
||||
it('should filter context properly in callbacks', () => {
|
||||
@@ -90,8 +96,8 @@ describe('ReactContextValidator', () => {
|
||||
}
|
||||
}
|
||||
Parent.childContextTypes = {
|
||||
foo: React.PropTypes.string.isRequired,
|
||||
bar: React.PropTypes.string.isRequired,
|
||||
foo: PropTypes.string.isRequired,
|
||||
bar: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
class Component extends React.Component {
|
||||
@@ -118,10 +124,9 @@ describe('ReactContextValidator', () => {
|
||||
}
|
||||
}
|
||||
Component.contextTypes = {
|
||||
foo: React.PropTypes.string,
|
||||
foo: PropTypes.string,
|
||||
};
|
||||
|
||||
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(<Parent foo="abc" />, container);
|
||||
ReactDOM.render(<Parent foo="def" />, container);
|
||||
@@ -140,7 +145,7 @@ describe('ReactContextValidator', () => {
|
||||
}
|
||||
}
|
||||
Component.contextTypes = {
|
||||
foo: React.PropTypes.string.isRequired,
|
||||
foo: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
ReactTestUtils.renderIntoDocument(<Component />);
|
||||
@@ -148,9 +153,9 @@ describe('ReactContextValidator', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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 **)',
|
||||
);
|
||||
|
||||
class ComponentInFooStringContext extends React.Component {
|
||||
@@ -165,11 +170,11 @@ describe('ReactContextValidator', () => {
|
||||
}
|
||||
}
|
||||
ComponentInFooStringContext.childContextTypes = {
|
||||
foo: React.PropTypes.string,
|
||||
foo: PropTypes.string,
|
||||
};
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
<ComponentInFooStringContext fooValue={'bar'} />
|
||||
<ComponentInFooStringContext fooValue={'bar'} />,
|
||||
);
|
||||
|
||||
// Previous call should not error
|
||||
@@ -187,18 +192,20 @@ describe('ReactContextValidator', () => {
|
||||
}
|
||||
}
|
||||
ComponentInFooNumberContext.childContextTypes = {
|
||||
foo: React.PropTypes.number,
|
||||
foo: PropTypes.number,
|
||||
};
|
||||
|
||||
ReactTestUtils.renderIntoDocument(<ComponentInFooNumberContext fooValue={123} />);
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
<ComponentInFooNumberContext fooValue={123} />,
|
||||
);
|
||||
|
||||
expect(console.error.calls.count()).toBe(2);
|
||||
expect(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 **)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -215,17 +222,17 @@ describe('ReactContextValidator', () => {
|
||||
}
|
||||
}
|
||||
Component.childContextTypes = {
|
||||
foo: React.PropTypes.string.isRequired,
|
||||
bar: React.PropTypes.number,
|
||||
foo: PropTypes.string.isRequired,
|
||||
bar: PropTypes.number,
|
||||
};
|
||||
|
||||
ReactTestUtils.renderIntoDocument(<Component testContext={{bar: 123}} />);
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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}} />);
|
||||
@@ -233,21 +240,18 @@ describe('ReactContextValidator', () => {
|
||||
expect(console.error.calls.count()).toBe(2);
|
||||
expect(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
|
||||
expect(console.error.calls.count()).toBe(2);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1,902 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactClass
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var ReactComponent = require('ReactComponent');
|
||||
var ReactElement = require('ReactElement');
|
||||
var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
|
||||
var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue');
|
||||
|
||||
var emptyObject = require('emptyObject');
|
||||
var invariant = require('invariant');
|
||||
var warning = require('warning');
|
||||
|
||||
import type { ReactPropTypeLocations } from 'ReactPropTypeLocations';
|
||||
|
||||
var MIXINS_KEY = 'mixins';
|
||||
|
||||
// Helper function to allow the creation of anonymous functions which do not
|
||||
// have .name set to the name of the variable being assigned to.
|
||||
function identity(fn) {
|
||||
return fn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Policies that describe methods in `ReactClassInterface`.
|
||||
*/
|
||||
type SpecPolicy =
|
||||
/**
|
||||
* These methods may be defined only once by the class specification or mixin.
|
||||
*/
|
||||
'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' |
|
||||
/**
|
||||
* These methods are overriding the base class.
|
||||
*/
|
||||
'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';
|
||||
|
||||
|
||||
var injectedMixins = [];
|
||||
|
||||
/**
|
||||
* Composite components are higher-level components that compose other composite
|
||||
* or host components.
|
||||
*
|
||||
* To create a new type of `ReactClass`, pass a specification of
|
||||
* your new class to `React.createClass`. The only requirement of your class
|
||||
* specification is that you implement a `render` method.
|
||||
*
|
||||
* var MyComponent = React.createClass({
|
||||
* render: function() {
|
||||
* return <div>Hello World</div>;
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* The class specification supports a specific protocol of methods that have
|
||||
* special meaning (e.g. `render`). See `ReactClassInterface` for
|
||||
* more the comprehensive protocol. Any other properties and methods in the
|
||||
* class specification will be available on the prototype.
|
||||
*
|
||||
* @interface ReactClassInterface
|
||||
* @internal
|
||||
*/
|
||||
var ReactClassInterface: {[key: string]: SpecPolicy} = {
|
||||
|
||||
/**
|
||||
* An array of Mixin objects to include when defining your component.
|
||||
*
|
||||
* @type {array}
|
||||
* @optional
|
||||
*/
|
||||
mixins: 'DEFINE_MANY',
|
||||
|
||||
/**
|
||||
* An object containing properties and methods that should be defined on
|
||||
* the component's constructor instead of its prototype (static methods).
|
||||
*
|
||||
* @type {object}
|
||||
* @optional
|
||||
*/
|
||||
statics: 'DEFINE_MANY',
|
||||
|
||||
/**
|
||||
* Definition of prop types for this component.
|
||||
*
|
||||
* @type {object}
|
||||
* @optional
|
||||
*/
|
||||
propTypes: 'DEFINE_MANY',
|
||||
|
||||
/**
|
||||
* Definition of context types for this component.
|
||||
*
|
||||
* @type {object}
|
||||
* @optional
|
||||
*/
|
||||
contextTypes: 'DEFINE_MANY',
|
||||
|
||||
/**
|
||||
* Definition of context types this component sets for its children.
|
||||
*
|
||||
* @type {object}
|
||||
* @optional
|
||||
*/
|
||||
childContextTypes: 'DEFINE_MANY',
|
||||
|
||||
// ==== Definition methods ====
|
||||
|
||||
/**
|
||||
* Invoked when the component is mounted. Values in the mapping will be set on
|
||||
* `this.props` if that prop is not specified (i.e. using an `in` check).
|
||||
*
|
||||
* This method is invoked before `getInitialState` and therefore cannot rely
|
||||
* on `this.state` or use `this.setState`.
|
||||
*
|
||||
* @return {object}
|
||||
* @optional
|
||||
*/
|
||||
getDefaultProps: 'DEFINE_MANY_MERGED',
|
||||
|
||||
/**
|
||||
* Invoked once before the component is mounted. The return value will be used
|
||||
* as the initial value of `this.state`.
|
||||
*
|
||||
* getInitialState: function() {
|
||||
* return {
|
||||
* isOn: false,
|
||||
* fooBaz: new BazFoo()
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @return {object}
|
||||
* @optional
|
||||
*/
|
||||
getInitialState: 'DEFINE_MANY_MERGED',
|
||||
|
||||
/**
|
||||
* @return {object}
|
||||
* @optional
|
||||
*/
|
||||
getChildContext: 'DEFINE_MANY_MERGED',
|
||||
|
||||
/**
|
||||
* Uses props from `this.props` and state from `this.state` to render the
|
||||
* structure of the component.
|
||||
*
|
||||
* No guarantees are made about when or how often this method is invoked, so
|
||||
* it must not have side effects.
|
||||
*
|
||||
* render: function() {
|
||||
* var name = this.props.name;
|
||||
* return <div>Hello, {name}!</div>;
|
||||
* }
|
||||
*
|
||||
* @return {ReactComponent}
|
||||
* @required
|
||||
*/
|
||||
render: 'DEFINE_ONCE',
|
||||
|
||||
|
||||
|
||||
// ==== Delegate methods ====
|
||||
|
||||
/**
|
||||
* Invoked when the component is initially created and about to be mounted.
|
||||
* This may have side effects, but any external subscriptions or data created
|
||||
* by this method must be cleaned up in `componentWillUnmount`.
|
||||
*
|
||||
* @optional
|
||||
*/
|
||||
componentWillMount: 'DEFINE_MANY',
|
||||
|
||||
/**
|
||||
* Invoked when the component has been mounted and has a DOM representation.
|
||||
* However, there is no guarantee that the DOM node is in the document.
|
||||
*
|
||||
* Use this as an opportunity to operate on the DOM when the component has
|
||||
* been mounted (initialized and rendered) for the first time.
|
||||
*
|
||||
* @param {DOMElement} rootNode DOM element representing the component.
|
||||
* @optional
|
||||
*/
|
||||
componentDidMount: 'DEFINE_MANY',
|
||||
|
||||
/**
|
||||
* Invoked before the component receives new props.
|
||||
*
|
||||
* Use this as an opportunity to react to a prop transition by updating the
|
||||
* state using `this.setState`. Current props are accessed via `this.props`.
|
||||
*
|
||||
* componentWillReceiveProps: function(nextProps, nextContext) {
|
||||
* this.setState({
|
||||
* likesIncreasing: nextProps.likeCount > this.props.likeCount
|
||||
* });
|
||||
* }
|
||||
*
|
||||
* NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop
|
||||
* transition may cause a state change, but the opposite is not true. If you
|
||||
* need it, you are probably looking for `componentWillUpdate`.
|
||||
*
|
||||
* @param {object} nextProps
|
||||
* @optional
|
||||
*/
|
||||
componentWillReceiveProps: 'DEFINE_MANY',
|
||||
|
||||
/**
|
||||
* Invoked while deciding if the component should be updated as a result of
|
||||
* receiving new props, state and/or context.
|
||||
*
|
||||
* Use this as an opportunity to `return false` when you're certain that the
|
||||
* transition to the new props/state/context will not require a component
|
||||
* update.
|
||||
*
|
||||
* shouldComponentUpdate: function(nextProps, nextState, nextContext) {
|
||||
* return !equal(nextProps, this.props) ||
|
||||
* !equal(nextState, this.state) ||
|
||||
* !equal(nextContext, this.context);
|
||||
* }
|
||||
*
|
||||
* @param {object} nextProps
|
||||
* @param {?object} nextState
|
||||
* @param {?object} nextContext
|
||||
* @return {boolean} True if the component should update.
|
||||
* @optional
|
||||
*/
|
||||
shouldComponentUpdate: 'DEFINE_ONCE',
|
||||
|
||||
/**
|
||||
* Invoked when the component is about to update due to a transition from
|
||||
* `this.props`, `this.state` and `this.context` to `nextProps`, `nextState`
|
||||
* and `nextContext`.
|
||||
*
|
||||
* Use this as an opportunity to perform preparation before an update occurs.
|
||||
*
|
||||
* NOTE: You **cannot** use `this.setState()` in this method.
|
||||
*
|
||||
* @param {object} nextProps
|
||||
* @param {?object} nextState
|
||||
* @param {?object} nextContext
|
||||
* @param {ReactReconcileTransaction} transaction
|
||||
* @optional
|
||||
*/
|
||||
componentWillUpdate: 'DEFINE_MANY',
|
||||
|
||||
/**
|
||||
* Invoked when the component's DOM representation has been updated.
|
||||
*
|
||||
* Use this as an opportunity to operate on the DOM when the component has
|
||||
* been updated.
|
||||
*
|
||||
* @param {object} prevProps
|
||||
* @param {?object} prevState
|
||||
* @param {?object} prevContext
|
||||
* @param {DOMElement} rootNode DOM element representing the component.
|
||||
* @optional
|
||||
*/
|
||||
componentDidUpdate: 'DEFINE_MANY',
|
||||
|
||||
/**
|
||||
* Invoked when the component is about to be removed from its parent and have
|
||||
* its DOM representation destroyed.
|
||||
*
|
||||
* Use this as an opportunity to deallocate any external resources.
|
||||
*
|
||||
* NOTE: There is no `componentDidUnmount` since your component will have been
|
||||
* destroyed by that point.
|
||||
*
|
||||
* @optional
|
||||
*/
|
||||
componentWillUnmount: 'DEFINE_MANY',
|
||||
|
||||
|
||||
|
||||
// ==== Advanced methods ====
|
||||
|
||||
/**
|
||||
* Updates the component's currently mounted DOM representation.
|
||||
*
|
||||
* By default, this implements React's rendering and reconciliation algorithm.
|
||||
* Sophisticated clients may wish to override this.
|
||||
*
|
||||
* @param {ReactReconcileTransaction} transaction
|
||||
* @internal
|
||||
* @overridable
|
||||
*/
|
||||
updateComponent: 'OVERRIDE_BASE',
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Mapping from class specification keys to special processing functions.
|
||||
*
|
||||
* Although these are declared like instance properties in the specification
|
||||
* when defining classes using `React.createClass`, they are actually static
|
||||
* and are accessible on the constructor instead of the prototype. Despite
|
||||
* being static, they must be defined outside of the "statics" key under
|
||||
* which all other static methods are defined.
|
||||
*/
|
||||
var RESERVED_SPEC_KEYS = {
|
||||
displayName: function(Constructor, displayName) {
|
||||
Constructor.displayName = displayName;
|
||||
},
|
||||
mixins: function(Constructor, mixins) {
|
||||
if (mixins) {
|
||||
for (var i = 0; i < mixins.length; i++) {
|
||||
mixSpecIntoComponent(Constructor, mixins[i]);
|
||||
}
|
||||
}
|
||||
},
|
||||
childContextTypes: function(Constructor, childContextTypes) {
|
||||
if (__DEV__) {
|
||||
validateTypeDef(
|
||||
Constructor,
|
||||
childContextTypes,
|
||||
'childContext'
|
||||
);
|
||||
}
|
||||
Constructor.childContextTypes = Object.assign(
|
||||
{},
|
||||
Constructor.childContextTypes,
|
||||
childContextTypes
|
||||
);
|
||||
},
|
||||
contextTypes: function(Constructor, contextTypes) {
|
||||
if (__DEV__) {
|
||||
validateTypeDef(
|
||||
Constructor,
|
||||
contextTypes,
|
||||
'context'
|
||||
);
|
||||
}
|
||||
Constructor.contextTypes = Object.assign(
|
||||
{},
|
||||
Constructor.contextTypes,
|
||||
contextTypes
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Special case getDefaultProps which should move into statics but requires
|
||||
* automatic merging.
|
||||
*/
|
||||
getDefaultProps: function(Constructor, getDefaultProps) {
|
||||
if (Constructor.getDefaultProps) {
|
||||
Constructor.getDefaultProps = createMergedResultFunction(
|
||||
Constructor.getDefaultProps,
|
||||
getDefaultProps
|
||||
);
|
||||
} else {
|
||||
Constructor.getDefaultProps = getDefaultProps;
|
||||
}
|
||||
},
|
||||
propTypes: function(Constructor, propTypes) {
|
||||
if (__DEV__) {
|
||||
validateTypeDef(
|
||||
Constructor,
|
||||
propTypes,
|
||||
'prop'
|
||||
);
|
||||
}
|
||||
Constructor.propTypes = Object.assign(
|
||||
{},
|
||||
Constructor.propTypes,
|
||||
propTypes
|
||||
);
|
||||
},
|
||||
statics: function(Constructor, statics) {
|
||||
mixStaticSpecIntoComponent(Constructor, statics);
|
||||
},
|
||||
autobind: function() {}, // noop
|
||||
};
|
||||
|
||||
function validateTypeDef(
|
||||
Constructor,
|
||||
typeDef,
|
||||
location: ReactPropTypeLocations,
|
||||
) {
|
||||
for (var propName in typeDef) {
|
||||
if (typeDef.hasOwnProperty(propName)) {
|
||||
// use a warning instead of an invariant so components
|
||||
// don't show up in prod but only in __DEV__
|
||||
warning(
|
||||
typeof typeDef[propName] === 'function',
|
||||
'%s: %s type `%s` is invalid; it must be a function, usually from ' +
|
||||
'React.PropTypes.',
|
||||
Constructor.displayName || 'ReactClass',
|
||||
ReactPropTypeLocationNames[location],
|
||||
propName
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function validateMethodOverride(isAlreadyDefined, name) {
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
// Disallow defining methods more than once unless explicitly allowed.
|
||||
if (isAlreadyDefined) {
|
||||
invariant(
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixin helper which handles policy validation and reserved
|
||||
* specification keys when building React classes.
|
||||
*/
|
||||
function mixSpecIntoComponent(Constructor, spec) {
|
||||
if (!spec) {
|
||||
if (__DEV__) {
|
||||
var typeofSpec = typeof spec;
|
||||
var isMixinValid = typeofSpec === 'object' && spec !== null;
|
||||
|
||||
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.',
|
||||
Constructor.displayName || 'ReactClass',
|
||||
spec === null ? null : typeofSpec
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
invariant(
|
||||
typeof spec !== 'function',
|
||||
'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.'
|
||||
);
|
||||
|
||||
var proto = Constructor.prototype;
|
||||
var autoBindPairs = proto.__reactAutoBindPairs;
|
||||
|
||||
// By handling mixins before any other properties, we ensure the same
|
||||
// chaining order is applied to methods with DEFINE_MANY policy, whether
|
||||
// mixins are listed before or after these methods in the spec.
|
||||
if (spec.hasOwnProperty(MIXINS_KEY)) {
|
||||
RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins);
|
||||
}
|
||||
|
||||
for (var name in spec) {
|
||||
if (!spec.hasOwnProperty(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (name === MIXINS_KEY) {
|
||||
// We have already handled mixins in a special case above.
|
||||
continue;
|
||||
}
|
||||
|
||||
var property = spec[name];
|
||||
var isAlreadyDefined = proto.hasOwnProperty(name);
|
||||
validateMethodOverride(isAlreadyDefined, name);
|
||||
|
||||
if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
|
||||
RESERVED_SPEC_KEYS[name](Constructor, property);
|
||||
} else {
|
||||
// Setup methods on prototype:
|
||||
// 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 isFunction = typeof property === 'function';
|
||||
var shouldAutoBind =
|
||||
isFunction &&
|
||||
!isReactClassMethod &&
|
||||
!isAlreadyDefined &&
|
||||
spec.autobind !== false;
|
||||
|
||||
if (shouldAutoBind) {
|
||||
autoBindPairs.push(name, property);
|
||||
proto[name] = property;
|
||||
} else {
|
||||
if (isAlreadyDefined) {
|
||||
var specPolicy = ReactClassInterface[name];
|
||||
|
||||
// These cases should already be caught by validateMethodOverride.
|
||||
invariant(
|
||||
isReactClassMethod && (
|
||||
specPolicy === 'DEFINE_MANY_MERGED' ||
|
||||
specPolicy === 'DEFINE_MANY'
|
||||
),
|
||||
'ReactClass: Unexpected spec policy %s for key %s ' +
|
||||
'when mixing in component specs.',
|
||||
specPolicy,
|
||||
name
|
||||
);
|
||||
|
||||
// For methods which are defined more than once, call the existing
|
||||
// methods before calling the new property, merging if appropriate.
|
||||
if (specPolicy === 'DEFINE_MANY_MERGED') {
|
||||
proto[name] = createMergedResultFunction(proto[name], property);
|
||||
} else if (specPolicy === 'DEFINE_MANY') {
|
||||
proto[name] = createChainedFunction(proto[name], property);
|
||||
}
|
||||
} else {
|
||||
proto[name] = property;
|
||||
if (__DEV__) {
|
||||
// Add verbose displayName to the function, which helps when looking
|
||||
// at profiling tools.
|
||||
if (typeof property === 'function' && spec.displayName) {
|
||||
proto[name].displayName = spec.displayName + '_' + name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function mixStaticSpecIntoComponent(Constructor, statics) {
|
||||
if (!statics) {
|
||||
return;
|
||||
}
|
||||
for (var name in statics) {
|
||||
var property = statics[name];
|
||||
if (!statics.hasOwnProperty(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var isReserved = name in RESERVED_SPEC_KEYS;
|
||||
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
|
||||
);
|
||||
|
||||
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
|
||||
);
|
||||
Constructor[name] = property;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge two objects, but throw if both contain the same key.
|
||||
*
|
||||
* @param {object} one The first object, which is mutated.
|
||||
* @param {object} two The second object
|
||||
* @return {object} one after it has been mutated to contain everything in two.
|
||||
*/
|
||||
function mergeIntoWithNoDuplicateKeys(one, two) {
|
||||
invariant(
|
||||
one && two && typeof one === 'object' && typeof two === 'object',
|
||||
'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.'
|
||||
);
|
||||
|
||||
for (var key in two) {
|
||||
if (two.hasOwnProperty(key)) {
|
||||
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
|
||||
);
|
||||
one[key] = two[key];
|
||||
}
|
||||
}
|
||||
return one;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that invokes two functions and merges their return values.
|
||||
*
|
||||
* @param {function} one Function to invoke first.
|
||||
* @param {function} two Function to invoke second.
|
||||
* @return {function} Function that invokes the two argument functions.
|
||||
* @private
|
||||
*/
|
||||
function createMergedResultFunction(one, two) {
|
||||
return function mergedResult() {
|
||||
var a = one.apply(this, arguments);
|
||||
var b = two.apply(this, arguments);
|
||||
if (a == null) {
|
||||
return b;
|
||||
} else if (b == null) {
|
||||
return a;
|
||||
}
|
||||
var c = {};
|
||||
mergeIntoWithNoDuplicateKeys(c, a);
|
||||
mergeIntoWithNoDuplicateKeys(c, b);
|
||||
return c;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that invokes two functions and ignores their return vales.
|
||||
*
|
||||
* @param {function} one Function to invoke first.
|
||||
* @param {function} two Function to invoke second.
|
||||
* @return {function} Function that invokes the two argument functions.
|
||||
* @private
|
||||
*/
|
||||
function createChainedFunction(one, two) {
|
||||
return function chainedFunction() {
|
||||
one.apply(this, arguments);
|
||||
two.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds a method to the component.
|
||||
*
|
||||
* @param {object} component Component whose method is going to be bound.
|
||||
* @param {function} method Method to be bound.
|
||||
* @return {function} The bound method.
|
||||
*/
|
||||
function bindAutoBindMethod(component, method) {
|
||||
var boundMethod = method.bind(component);
|
||||
if (__DEV__) {
|
||||
boundMethod.__reactBoundContext = component;
|
||||
boundMethod.__reactBoundMethod = method;
|
||||
boundMethod.__reactBoundArguments = null;
|
||||
var componentName = component.constructor.displayName;
|
||||
var _bind = boundMethod.bind;
|
||||
boundMethod.bind = function(newThis, ...args) {
|
||||
// User is trying to bind() an autobound method; we effectively will
|
||||
// ignore the value of "this" that the user is trying to use, so
|
||||
// let's warn.
|
||||
if (newThis !== component && newThis !== null) {
|
||||
warning(
|
||||
false,
|
||||
'bind(): React component methods may only be bound to the ' +
|
||||
'component instance. See %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. See %s',
|
||||
componentName
|
||||
);
|
||||
return boundMethod;
|
||||
}
|
||||
var reboundMethod = _bind.apply(boundMethod, arguments);
|
||||
reboundMethod.__reactBoundContext = component;
|
||||
reboundMethod.__reactBoundMethod = method;
|
||||
reboundMethod.__reactBoundArguments = args;
|
||||
return reboundMethod;
|
||||
};
|
||||
}
|
||||
return boundMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds all auto-bound methods in a component.
|
||||
*
|
||||
* @param {object} component Component whose method is going to be bound.
|
||||
*/
|
||||
function bindAutoBindMethods(component) {
|
||||
var pairs = component.__reactAutoBindPairs;
|
||||
for (var i = 0; i < pairs.length; i += 2) {
|
||||
var autoBindKey = pairs[i];
|
||||
var method = pairs[i + 1];
|
||||
component[autoBindKey] = bindAutoBindMethod(
|
||||
component,
|
||||
method
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add more to the ReactClass base class. These are all legacy features and
|
||||
* 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.
|
||||
*/
|
||||
replaceState: function(newState, callback) {
|
||||
this.updater.enqueueReplaceState(this, newState);
|
||||
if (callback) {
|
||||
this.updater.enqueueCallback(this, callback, 'replaceState');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks whether or not this composite component is mounted.
|
||||
* @return {boolean} True if mounted, false otherwise.
|
||||
* @protected
|
||||
* @final
|
||||
*/
|
||||
isMounted: function() {
|
||||
return this.updater.isMounted(this);
|
||||
},
|
||||
};
|
||||
|
||||
var ReactClassComponent = function() {};
|
||||
Object.assign(
|
||||
ReactClassComponent.prototype,
|
||||
ReactComponent.prototype,
|
||||
ReactClassMixin
|
||||
);
|
||||
|
||||
let didWarnDeprecated = false;
|
||||
|
||||
/**
|
||||
* Module for creating composite components.
|
||||
*
|
||||
* @class ReactClass
|
||||
*/
|
||||
var ReactClass = {
|
||||
|
||||
/**
|
||||
* Creates a composite component class given a class specification.
|
||||
* See https://facebook.github.io/react/docs/top-level-api.html#react.createclass
|
||||
*
|
||||
* @param {object} spec Class specification (which must define `render`).
|
||||
* @return {function} Component constructor function.
|
||||
* @public
|
||||
*/
|
||||
createClass: function(spec) {
|
||||
if (__DEV__) {
|
||||
warning(
|
||||
didWarnDeprecated,
|
||||
'%s: React.createClass is deprecated and will be removed in version 16. ' +
|
||||
'Use plain JavaScript classes instead. If you\'re not yet ready to ' +
|
||||
'migrate, create-react-class is available on npm as a ' +
|
||||
'drop-in replacement.',
|
||||
(spec && spec.displayName) || 'A Component',
|
||||
);
|
||||
didWarnDeprecated = true;
|
||||
}
|
||||
|
||||
// To keep our warnings more understandable, we'll use a little hack here to
|
||||
// ensure that Constructor.name !== 'Constructor'. This makes sure we don't
|
||||
// unnecessarily identify a class without displayName as 'Constructor'.
|
||||
var Constructor = identity(function(props, context, updater) {
|
||||
// This constructor gets overridden by mocks. The argument is used
|
||||
// by mocks to assert on what gets mounted.
|
||||
|
||||
if (__DEV__) {
|
||||
warning(
|
||||
this instanceof Constructor,
|
||||
'Something is calling a React component directly. Use a factory or ' +
|
||||
'JSX instead. See: https://fb.me/react-legacyfactory'
|
||||
);
|
||||
}
|
||||
|
||||
// Wire up auto-binding
|
||||
if (this.__reactAutoBindPairs.length) {
|
||||
bindAutoBindMethods(this);
|
||||
}
|
||||
|
||||
this.props = props;
|
||||
this.context = context;
|
||||
this.refs = emptyObject;
|
||||
this.updater = updater || ReactNoopUpdateQueue;
|
||||
|
||||
this.state = null;
|
||||
|
||||
// ReactClasses doesn't have constructors. Instead, they use the
|
||||
// getInitialState and componentWillMount methods for initialization.
|
||||
|
||||
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) {
|
||||
// This is probably bad practice. Consider warning here and
|
||||
// deprecating this convenience.
|
||||
initialState = null;
|
||||
}
|
||||
}
|
||||
invariant(
|
||||
typeof initialState === 'object' && !Array.isArray(initialState),
|
||||
'%s.getInitialState(): must return an object or null',
|
||||
Constructor.displayName || 'ReactCompositeComponent'
|
||||
);
|
||||
|
||||
this.state = initialState;
|
||||
});
|
||||
Constructor.prototype = new ReactClassComponent();
|
||||
Constructor.prototype.constructor = Constructor;
|
||||
Constructor.prototype.__reactAutoBindPairs = [];
|
||||
|
||||
injectedMixins.forEach(
|
||||
mixSpecIntoComponent.bind(null, Constructor)
|
||||
);
|
||||
|
||||
mixSpecIntoComponent(Constructor, spec);
|
||||
|
||||
// Initialize the defaultProps property after all mixins have been merged.
|
||||
if (Constructor.getDefaultProps) {
|
||||
Constructor.defaultProps = Constructor.getDefaultProps();
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
// This is a tag to indicate that the use of these method names is ok,
|
||||
// since it's used with createClass. If it's not, then it's likely a
|
||||
// mistake so we'll warn you to use the static property, property
|
||||
// initializer or constructor respectively.
|
||||
if (Constructor.getDefaultProps) {
|
||||
Constructor.getDefaultProps.isReactClassApproved = {};
|
||||
}
|
||||
if (Constructor.prototype.getInitialState) {
|
||||
Constructor.prototype.getInitialState.isReactClassApproved = {};
|
||||
}
|
||||
}
|
||||
|
||||
invariant(
|
||||
Constructor.prototype.render,
|
||||
'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'
|
||||
);
|
||||
warning(
|
||||
!Constructor.prototype.componentWillRecieveProps,
|
||||
'%s has a method called ' +
|
||||
'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?',
|
||||
spec.displayName || 'A component'
|
||||
);
|
||||
}
|
||||
|
||||
// Reduce time spent doing lookups by setting these on the prototype.
|
||||
for (var methodName in ReactClassInterface) {
|
||||
if (!Constructor.prototype[methodName]) {
|
||||
Constructor.prototype[methodName] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return Constructor;
|
||||
},
|
||||
|
||||
injection: {
|
||||
injectMixin: function(mixin) {
|
||||
injectedMixins.push(mixin);
|
||||
},
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
module.exports = ReactClass;
|
||||
@@ -11,14 +11,15 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var PropTypes;
|
||||
var React;
|
||||
var ReactDOM;
|
||||
var ReactTestUtils;
|
||||
var createReactClass;
|
||||
|
||||
describe('ReactClass-spec', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
PropTypes = require('prop-types');
|
||||
React = require('React');
|
||||
ReactDOM = require('ReactDOM');
|
||||
ReactTestUtils = require('ReactTestUtils');
|
||||
@@ -34,7 +35,7 @@ describe('ReactClass-spec', () => {
|
||||
expect(function() {
|
||||
createReactClass({});
|
||||
}).toThrowError(
|
||||
'createClass(...): Class specification must implement a `render` method.'
|
||||
'createClass(...): Class specification must implement a `render` method.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -46,8 +47,7 @@ describe('ReactClass-spec', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(TestComponent.displayName)
|
||||
.toBe('TestComponent');
|
||||
expect(TestComponent.displayName).toBe('TestComponent');
|
||||
});
|
||||
|
||||
it('should copy prop types onto the Constructor', () => {
|
||||
@@ -62,8 +62,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', () => {
|
||||
@@ -80,7 +79,7 @@ describe('ReactClass-spec', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -98,7 +97,7 @@ describe('ReactClass-spec', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -116,7 +115,7 @@ describe('ReactClass-spec', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -134,8 +133,8 @@ describe('ReactClass-spec', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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.',
|
||||
);
|
||||
|
||||
createReactClass({
|
||||
@@ -150,8 +149,8 @@ describe('ReactClass-spec', () => {
|
||||
expect(console.error.calls.count()).toBe(2);
|
||||
expect(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.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -168,7 +167,7 @@ describe('ReactClass-spec', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: A component has a method called componentWillRecieveProps(). Did you ' +
|
||||
'mean componentWillReceiveProps()?'
|
||||
'mean componentWillReceiveProps()?',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -189,9 +188,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.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -202,13 +201,13 @@ describe('ReactClass-spec', () => {
|
||||
createReactClass({
|
||||
mixins: [{}],
|
||||
propTypes: {
|
||||
foo: React.PropTypes.string,
|
||||
foo: PropTypes.string,
|
||||
},
|
||||
contextTypes: {
|
||||
foo: React.PropTypes.string,
|
||||
foo: PropTypes.string,
|
||||
},
|
||||
childContextTypes: {
|
||||
foo: React.PropTypes.string,
|
||||
foo: PropTypes.string,
|
||||
},
|
||||
render: function() {
|
||||
return <div />;
|
||||
@@ -217,19 +216,19 @@ describe('ReactClass-spec', () => {
|
||||
expect(console.error.calls.count()).toBe(4);
|
||||
expect(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'createClass(...): `mixins` is now a static property and should ' +
|
||||
'be defined inside "statics".'
|
||||
'be defined inside "statics".',
|
||||
);
|
||||
expect(console.error.calls.argsFor(1)[0]).toBe(
|
||||
'createClass(...): `propTypes` is now a static property and should ' +
|
||||
'be defined inside "statics".'
|
||||
'be defined inside "statics".',
|
||||
);
|
||||
expect(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".',
|
||||
);
|
||||
expect(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".',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -282,7 +281,7 @@ describe('ReactClass-spec', () => {
|
||||
it('renders based on context getInitialState', () => {
|
||||
var Foo = createReactClass({
|
||||
contextTypes: {
|
||||
className: React.PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
},
|
||||
getInitialState() {
|
||||
return {className: this.context.className};
|
||||
@@ -294,7 +293,7 @@ describe('ReactClass-spec', () => {
|
||||
|
||||
var Outer = createReactClass({
|
||||
childContextTypes: {
|
||||
className: React.PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
},
|
||||
getChildContext() {
|
||||
return {className: 'foo'};
|
||||
@@ -323,7 +322,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',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -337,8 +336,8 @@ describe('ReactClass-spec', () => {
|
||||
return <span />;
|
||||
},
|
||||
});
|
||||
expect(
|
||||
() => ReactTestUtils.renderIntoDocument(<Component />)
|
||||
expect(() =>
|
||||
ReactTestUtils.renderIntoDocument(<Component />),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
@@ -354,7 +353,7 @@ describe('ReactClass-spec', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -362,23 +361,19 @@ describe('ReactClass-spec', () => {
|
||||
var ops = [];
|
||||
var Component = createReactClass({
|
||||
getInitialState() {
|
||||
return { step: 0 };
|
||||
return {step: 0};
|
||||
},
|
||||
render() {
|
||||
ops.push('Render: ' + this.state.step);
|
||||
return <div />;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
var instance = ReactTestUtils.renderIntoDocument(<Component />);
|
||||
instance.replaceState({ step: 1 }, () => {
|
||||
instance.replaceState({step: 1}, () => {
|
||||
ops.push('Callback: ' + instance.state.step);
|
||||
});
|
||||
expect(ops).toEqual([
|
||||
'Render: 0',
|
||||
'Render: 1',
|
||||
'Callback: 1',
|
||||
]);
|
||||
expect(ops).toEqual(['Render: 0', 'Render: 1', 'Callback: 1']);
|
||||
});
|
||||
|
||||
it('isMounted works', () => {
|
||||
@@ -414,7 +409,7 @@ describe('ReactClass-spec', () => {
|
||||
instance = this;
|
||||
this.log('render');
|
||||
return <div />;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
var container = document.createElement('div');
|
||||
@@ -437,8 +432,8 @@ describe('ReactClass-spec', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toEqual(
|
||||
'Warning: MyComponent: isMounted is deprecated. Instead, make sure to ' +
|
||||
'clean up subscriptions and pending requests in componentWillUnmount ' +
|
||||
'to prevent memory leaks.'
|
||||
'clean up subscriptions and pending requests in componentWillUnmount ' +
|
||||
'to prevent memory leaks.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,426 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @emails react-core
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var React;
|
||||
var ReactDOM;
|
||||
var ReactTestUtils;
|
||||
var createReactClass;
|
||||
|
||||
describe('create-react-class-integration', () => {
|
||||
beforeEach(() => {
|
||||
React = require('React');
|
||||
ReactDOM = require('ReactDOM');
|
||||
ReactTestUtils = require('ReactTestUtils');
|
||||
var createReactClassFactory = require('create-react-class/factory');
|
||||
createReactClass = createReactClassFactory(
|
||||
React.Component,
|
||||
React.isValidElement,
|
||||
require('ReactNoopUpdateQueue'),
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw when `render` is not specified', () => {
|
||||
expect(function() {
|
||||
createReactClass({});
|
||||
}).toThrowError(
|
||||
'createClass(...): Class specification must implement a `render` method.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should copy prop types onto the Constructor', () => {
|
||||
var propValidator = jest.fn();
|
||||
var TestComponent = createReactClass({
|
||||
propTypes: {
|
||||
value: propValidator,
|
||||
},
|
||||
render: function() {
|
||||
return <div />;
|
||||
},
|
||||
});
|
||||
|
||||
expect(TestComponent.propTypes).toBeDefined();
|
||||
expect(TestComponent.propTypes.value).toBe(propValidator);
|
||||
});
|
||||
|
||||
it('should warn on invalid prop types', () => {
|
||||
spyOn(console, 'error');
|
||||
createReactClass({
|
||||
displayName: 'Component',
|
||||
propTypes: {
|
||||
prop: null,
|
||||
},
|
||||
render: function() {
|
||||
return <span>{this.props.prop}</span>;
|
||||
},
|
||||
});
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: Component: prop type `prop` is invalid; ' +
|
||||
'it must be a function, usually from React.PropTypes.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn on invalid context types', () => {
|
||||
spyOn(console, 'error');
|
||||
createReactClass({
|
||||
displayName: 'Component',
|
||||
contextTypes: {
|
||||
prop: null,
|
||||
},
|
||||
render: function() {
|
||||
return <span>{this.props.prop}</span>;
|
||||
},
|
||||
});
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: Component: context type `prop` is invalid; ' +
|
||||
'it must be a function, usually from React.PropTypes.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw on invalid child context types', () => {
|
||||
spyOn(console, 'error');
|
||||
createReactClass({
|
||||
displayName: 'Component',
|
||||
childContextTypes: {
|
||||
prop: null,
|
||||
},
|
||||
render: function() {
|
||||
return <span>{this.props.prop}</span>;
|
||||
},
|
||||
});
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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('should warn when mispelling shouldComponentUpdate', () => {
|
||||
spyOn(console, 'error');
|
||||
|
||||
createReactClass({
|
||||
componentShouldUpdate: function() {
|
||||
return false;
|
||||
},
|
||||
render: function() {
|
||||
return <div />;
|
||||
},
|
||||
});
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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.',
|
||||
);
|
||||
|
||||
createReactClass({
|
||||
displayName: 'NamedComponent',
|
||||
componentShouldUpdate: function() {
|
||||
return false;
|
||||
},
|
||||
render: function() {
|
||||
return <div />;
|
||||
},
|
||||
});
|
||||
expect(console.error.calls.count()).toBe(2);
|
||||
expect(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.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn when mispelling componentWillReceiveProps', () => {
|
||||
spyOn(console, 'error');
|
||||
createReactClass({
|
||||
componentWillRecieveProps: function() {
|
||||
return false;
|
||||
},
|
||||
render: function() {
|
||||
return <div />;
|
||||
},
|
||||
});
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: A component has a method called componentWillRecieveProps(). Did you ' +
|
||||
'mean componentWillReceiveProps()?',
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw if a reserved property is in statics', () => {
|
||||
expect(function() {
|
||||
createReactClass({
|
||||
statics: {
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
foo: 0,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return <span />;
|
||||
},
|
||||
});
|
||||
}).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.',
|
||||
);
|
||||
});
|
||||
|
||||
// TODO: Consider actually moving these to statics or drop this unit test.
|
||||
|
||||
xit('should warn when using deprecated non-static spec keys', () => {
|
||||
spyOn(console, 'error');
|
||||
createReactClass({
|
||||
mixins: [{}],
|
||||
propTypes: {
|
||||
foo: React.PropTypes.string,
|
||||
},
|
||||
contextTypes: {
|
||||
foo: React.PropTypes.string,
|
||||
},
|
||||
childContextTypes: {
|
||||
foo: React.PropTypes.string,
|
||||
},
|
||||
render: function() {
|
||||
return <div />;
|
||||
},
|
||||
});
|
||||
expect(console.error.calls.count()).toBe(4);
|
||||
expect(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'createClass(...): `mixins` is now a static property and should ' +
|
||||
'be defined inside "statics".',
|
||||
);
|
||||
expect(console.error.calls.argsFor(1)[0]).toBe(
|
||||
'createClass(...): `propTypes` is now a static property and should ' +
|
||||
'be defined inside "statics".',
|
||||
);
|
||||
expect(console.error.calls.argsFor(2)[0]).toBe(
|
||||
'createClass(...): `contextTypes` is now a static property and ' +
|
||||
'should be defined inside "statics".',
|
||||
);
|
||||
expect(console.error.calls.argsFor(3)[0]).toBe(
|
||||
'createClass(...): `childContextTypes` is now a static property and ' +
|
||||
'should be defined inside "statics".',
|
||||
);
|
||||
});
|
||||
|
||||
it('should support statics', () => {
|
||||
var Component = createReactClass({
|
||||
statics: {
|
||||
abc: 'def',
|
||||
def: 0,
|
||||
ghi: null,
|
||||
jkl: 'mno',
|
||||
pqr: function() {
|
||||
return this;
|
||||
},
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return <span />;
|
||||
},
|
||||
});
|
||||
var instance = <Component />;
|
||||
instance = ReactTestUtils.renderIntoDocument(instance);
|
||||
expect(instance.constructor.abc).toBe('def');
|
||||
expect(Component.abc).toBe('def');
|
||||
expect(instance.constructor.def).toBe(0);
|
||||
expect(Component.def).toBe(0);
|
||||
expect(instance.constructor.ghi).toBe(null);
|
||||
expect(Component.ghi).toBe(null);
|
||||
expect(instance.constructor.jkl).toBe('mno');
|
||||
expect(Component.jkl).toBe('mno');
|
||||
expect(instance.constructor.pqr()).toBe(Component);
|
||||
expect(Component.pqr()).toBe(Component);
|
||||
});
|
||||
|
||||
it('should work with object getInitialState() return values', () => {
|
||||
var Component = createReactClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
occupation: 'clown',
|
||||
};
|
||||
},
|
||||
render: function() {
|
||||
return <span />;
|
||||
},
|
||||
});
|
||||
var instance = <Component />;
|
||||
instance = ReactTestUtils.renderIntoDocument(instance);
|
||||
expect(instance.state.occupation).toEqual('clown');
|
||||
});
|
||||
|
||||
it('renders based on context getInitialState', () => {
|
||||
var Foo = createReactClass({
|
||||
contextTypes: {
|
||||
className: React.PropTypes.string,
|
||||
},
|
||||
getInitialState() {
|
||||
return {className: this.context.className};
|
||||
},
|
||||
render() {
|
||||
return <span className={this.state.className} />;
|
||||
},
|
||||
});
|
||||
|
||||
var Outer = createReactClass({
|
||||
childContextTypes: {
|
||||
className: React.PropTypes.string,
|
||||
},
|
||||
getChildContext() {
|
||||
return {className: 'foo'};
|
||||
},
|
||||
render() {
|
||||
return <Foo />;
|
||||
},
|
||||
});
|
||||
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(<Outer />, container);
|
||||
expect(container.firstChild.className).toBe('foo');
|
||||
});
|
||||
|
||||
it('should throw with non-object getInitialState() return values', () => {
|
||||
[['an array'], 'a string', 1234].forEach(function(state) {
|
||||
var Component = createReactClass({
|
||||
getInitialState: function() {
|
||||
return state;
|
||||
},
|
||||
render: function() {
|
||||
return <span />;
|
||||
},
|
||||
});
|
||||
var instance = <Component />;
|
||||
expect(function() {
|
||||
instance = ReactTestUtils.renderIntoDocument(instance);
|
||||
}).toThrowError(
|
||||
'Component.getInitialState(): must return an object or null',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should work with a null getInitialState() return value', () => {
|
||||
var Component = createReactClass({
|
||||
getInitialState: function() {
|
||||
return null;
|
||||
},
|
||||
render: function() {
|
||||
return <span />;
|
||||
},
|
||||
});
|
||||
expect(() =>
|
||||
ReactTestUtils.renderIntoDocument(<Component />),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
it('should throw when using legacy factories', () => {
|
||||
spyOn(console, 'error');
|
||||
var Component = createReactClass({
|
||||
render() {
|
||||
return <div />;
|
||||
},
|
||||
});
|
||||
|
||||
expect(() => Component()).toThrow();
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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',
|
||||
);
|
||||
});
|
||||
|
||||
it('replaceState and callback works', () => {
|
||||
var ops = [];
|
||||
var Component = createReactClass({
|
||||
getInitialState() {
|
||||
return {step: 0};
|
||||
},
|
||||
render() {
|
||||
ops.push('Render: ' + this.state.step);
|
||||
return <div />;
|
||||
},
|
||||
});
|
||||
|
||||
var instance = ReactTestUtils.renderIntoDocument(<Component />);
|
||||
instance.replaceState({step: 1}, () => {
|
||||
ops.push('Callback: ' + instance.state.step);
|
||||
});
|
||||
expect(ops).toEqual(['Render: 0', 'Render: 1', 'Callback: 1']);
|
||||
});
|
||||
|
||||
it('isMounted works', () => {
|
||||
spyOn(console, 'error');
|
||||
|
||||
var ops = [];
|
||||
var instance;
|
||||
var Component = createReactClass({
|
||||
displayName: 'MyComponent',
|
||||
log(name) {
|
||||
ops.push(`${name}: ${this.isMounted()}`);
|
||||
},
|
||||
getInitialState() {
|
||||
this.log('getInitialState');
|
||||
return {};
|
||||
},
|
||||
componentWillMount() {
|
||||
this.log('componentWillMount');
|
||||
},
|
||||
componentDidMount() {
|
||||
this.log('componentDidMount');
|
||||
},
|
||||
componentWillUpdate() {
|
||||
this.log('componentWillUpdate');
|
||||
},
|
||||
componentDidUpdate() {
|
||||
this.log('componentDidUpdate');
|
||||
},
|
||||
componentWillUnmount() {
|
||||
this.log('componentWillUnmount');
|
||||
},
|
||||
render() {
|
||||
instance = this;
|
||||
this.log('render');
|
||||
return <div />;
|
||||
},
|
||||
});
|
||||
|
||||
var container = document.createElement('div');
|
||||
ReactDOM.render(<Component />, container);
|
||||
ReactDOM.render(<Component />, container);
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
instance.log('after unmount');
|
||||
expect(ops).toEqual([
|
||||
'getInitialState: false',
|
||||
'componentWillMount: false',
|
||||
'render: false',
|
||||
'componentDidMount: true',
|
||||
'componentWillUpdate: true',
|
||||
'render: true',
|
||||
'componentDidUpdate: true',
|
||||
'componentWillUnmount: false',
|
||||
'after unmount: false',
|
||||
]);
|
||||
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toEqual(
|
||||
'Warning: MyComponent: isMounted is deprecated. Instead, make sure to ' +
|
||||
'clean up subscriptions and pending requests in componentWillUnmount ' +
|
||||
'to prevent memory leaks.',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule createClass
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var {Component} = require('ReactBaseClasses');
|
||||
var {isValidElement} = require('ReactElement');
|
||||
var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue');
|
||||
var factory = require('create-react-class/factory');
|
||||
|
||||
module.exports = factory(Component, isValidElement, ReactNoopUpdateQueue);
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import type { ReactInstance } from 'ReactInstanceType';
|
||||
import type {ReactInstance} from 'ReactInstanceType';
|
||||
|
||||
/**
|
||||
* Keeps track of the current owner.
|
||||
@@ -21,13 +21,11 @@ import type { ReactInstance } from 'ReactInstanceType';
|
||||
* currently being constructed.
|
||||
*/
|
||||
var ReactCurrentOwner = {
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @type {ReactComponent}
|
||||
*/
|
||||
current: (null: null | ReactInstance),
|
||||
|
||||
};
|
||||
|
||||
module.exports = ReactCurrentOwner;
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import type { ReactInstance } from 'ReactInstanceType';
|
||||
import type {ReactInstance} from 'ReactInstanceType';
|
||||
|
||||
export type Source = {
|
||||
fileName: string,
|
||||
|
||||
@@ -27,6 +27,7 @@ var checkReactTypeSpec = require('checkReactTypeSpec');
|
||||
var canDefineProperty = require('canDefineProperty');
|
||||
var getIteratorFn = require('getIteratorFn');
|
||||
var warning = require('warning');
|
||||
var lowPriorityWarning = require('lowPriorityWarning');
|
||||
|
||||
function getDeclarationErrorAddendum() {
|
||||
if (ReactCurrentOwner.current) {
|
||||
@@ -63,8 +64,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 = ` Check the top-level render call using <${parentName}>.`;
|
||||
}
|
||||
@@ -89,9 +91,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]) {
|
||||
@@ -103,21 +104,22 @@ 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 ${element._owner.getName()}.`;
|
||||
childOwner = ` It was passed a child from ${element._owner.getName()}.`;
|
||||
}
|
||||
|
||||
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,
|
||||
ReactComponentTreeHook.getCurrentStackAddendum(element)
|
||||
ReactComponentTreeHook.getCurrentStackAddendum(element),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -182,39 +184,35 @@ function validatePropTypes(element) {
|
||||
'prop',
|
||||
name,
|
||||
element,
|
||||
null
|
||||
null,
|
||||
);
|
||||
}
|
||||
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';
|
||||
// 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) {
|
||||
if (
|
||||
typeof type !== 'function' &&
|
||||
typeof type !== 'string'
|
||||
) {
|
||||
if (typeof type !== 'function' && typeof type !== 'string') {
|
||||
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.';
|
||||
"it's defined in.";
|
||||
}
|
||||
|
||||
var sourceInfo = getSourceInfoErrorAddendum(props);
|
||||
@@ -226,14 +224,21 @@ var ReactElementValidator = {
|
||||
|
||||
info += ReactComponentTreeHook.getCurrentStackAddendum();
|
||||
|
||||
var currentSource = props !== null &&
|
||||
props !== undefined &&
|
||||
props.__source !== undefined
|
||||
? props.__source
|
||||
: null;
|
||||
ReactComponentTreeHook.pushNonStandardWarningStack(true, currentSource);
|
||||
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,
|
||||
);
|
||||
ReactComponentTreeHook.popNonStandardWarningStack();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,37 +267,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() {
|
||||
lowPriorityWarning(
|
||||
false,
|
||||
'Factory.type is deprecated. Access the class directly ' +
|
||||
'before passing it to createFactory.',
|
||||
);
|
||||
Object.defineProperty(this, 'type', {
|
||||
value: type,
|
||||
});
|
||||
return type;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return validatedFactory;
|
||||
},
|
||||
|
||||
@@ -304,7 +301,6 @@ var ReactElementValidator = {
|
||||
validatePropTypes(newElement);
|
||||
return newElement;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
module.exports = ReactElementValidator;
|
||||
|
||||
@@ -81,9 +81,9 @@ describe('ReactElement', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -95,9 +95,9 @@ describe('ReactElement', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -123,9 +123,9 @@ describe('ReactElement', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -141,7 +141,7 @@ describe('ReactElement', () => {
|
||||
|
||||
it('returns an immutable element', () => {
|
||||
var element = React.createFactory(ComponentClass)();
|
||||
expect(() => element.type = 'div').toThrow();
|
||||
expect(() => (element.type = 'div')).toThrow();
|
||||
});
|
||||
|
||||
it('does not reuse the original config object', () => {
|
||||
@@ -233,7 +233,7 @@ describe('ReactElement', () => {
|
||||
}
|
||||
|
||||
var instance = ReactTestUtils.renderIntoDocument(
|
||||
React.createElement(Wrapper)
|
||||
React.createElement(Wrapper),
|
||||
);
|
||||
|
||||
expect(element._owner.getPublicInstance()).toBe(instance);
|
||||
@@ -242,9 +242,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);
|
||||
expect(console.error.calls.count()).toBe(0);
|
||||
});
|
||||
@@ -260,9 +263,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);
|
||||
expect(console.error.calls.count()).toBe(0);
|
||||
});
|
||||
@@ -303,18 +309,16 @@ 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);
|
||||
expect(React.isValidElement({})).toEqual(false);
|
||||
expect(React.isValidElement('string')).toEqual(false);
|
||||
expect(React.isValidElement(React.DOM.div)).toEqual(false);
|
||||
expect(React.isValidElement(React.createFactory('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);
|
||||
@@ -341,7 +345,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');
|
||||
|
||||
@@ -360,12 +364,12 @@ describe('ReactElement', () => {
|
||||
Component.defaultProps = {prop: 'testKey'};
|
||||
|
||||
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);
|
||||
});
|
||||
@@ -448,23 +452,20 @@ 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);
|
||||
expect(React.isValidElement({})).toEqual(false);
|
||||
expect(React.isValidElement('string')).toEqual(false);
|
||||
expect(React.isValidElement(React.DOM.div)).toEqual(false);
|
||||
expect(React.isValidElement(React.createFactory('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()', () => {
|
||||
@@ -478,7 +479,6 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
|
||||
Child = jest.genMockFromModule('ReactElementTestChild');
|
||||
});
|
||||
|
||||
|
||||
describe('when using jsx only', () => {
|
||||
var Parent, instance;
|
||||
beforeEach(() => {
|
||||
@@ -491,11 +491,14 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
|
||||
);
|
||||
}
|
||||
};
|
||||
instance = ReactTestUtils.renderIntoDocument(<Parent/>);
|
||||
instance = ReactTestUtils.renderIntoDocument(<Parent />);
|
||||
});
|
||||
|
||||
it('should scry children but cannot', () => {
|
||||
var children = ReactTestUtils.scryRenderedComponentsWithType(instance, Child);
|
||||
var children = ReactTestUtils.scryRenderedComponentsWithType(
|
||||
instance,
|
||||
Child,
|
||||
);
|
||||
expect(children.length).toBe(1);
|
||||
});
|
||||
|
||||
@@ -504,7 +507,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',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -514,7 +520,11 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
|
||||
var childFactory = React.createFactory(Child);
|
||||
class Parent extends React.Component {
|
||||
render() {
|
||||
return React.DOM.div({}, childFactory({ ref: 'child', foo: 'foo value' }, 'children value'));
|
||||
return React.createElement(
|
||||
'div',
|
||||
{},
|
||||
childFactory({ref: 'child', foo: 'foo value'}, 'children value'),
|
||||
);
|
||||
}
|
||||
}
|
||||
factory = React.createFactory(Parent);
|
||||
@@ -522,7 +532,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);
|
||||
});
|
||||
|
||||
@@ -531,7 +544,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',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -540,7 +556,15 @@ describe('comparing jsx vs .createFactory() vs .createElement()', () => {
|
||||
beforeEach(() => {
|
||||
class Parent extends React.Component {
|
||||
render() {
|
||||
return React.DOM.div({}, React.createElement(Child, { ref: 'child', foo: 'foo value' }, 'children value'));
|
||||
return React.createElement(
|
||||
'div',
|
||||
{},
|
||||
React.createElement(
|
||||
Child,
|
||||
{ref: 'child', foo: 'foo value'},
|
||||
'children value',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
factory = React.createFactory(Parent);
|
||||
@@ -548,7 +572,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);
|
||||
});
|
||||
|
||||
@@ -557,8 +584,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',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var PropTypes;
|
||||
var React;
|
||||
var ReactDOM;
|
||||
var ReactTestUtils;
|
||||
@@ -22,6 +23,7 @@ describe('ReactElementClone', () => {
|
||||
React = require('React');
|
||||
ReactDOM = require('ReactDOM');
|
||||
ReactTestUtils = require('ReactTestUtils');
|
||||
PropTypes = require('prop-types');
|
||||
|
||||
// NOTE: We're explicitly not using JSX here. This is intended to test
|
||||
// classic JS without JSX.
|
||||
@@ -42,7 +44,7 @@ describe('ReactElementClone', () => {
|
||||
render() {
|
||||
return (
|
||||
<div className="parent">
|
||||
{React.cloneElement(this.props.child, { className: 'xyz' })}
|
||||
{React.cloneElement(this.props.child, {className: 'xyz'})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -66,7 +68,7 @@ describe('ReactElementClone', () => {
|
||||
render() {
|
||||
return (
|
||||
<div className="parent">
|
||||
{React.cloneElement(this.props.child, { className: 'xyz' })}
|
||||
{React.cloneElement(this.props.child, {className: 'xyz'})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -91,7 +93,7 @@ describe('ReactElementClone', () => {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{React.cloneElement(this.props.child, { className: 'xyz' })}
|
||||
{React.cloneElement(this.props.child, {className: 'xyz'})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -120,7 +122,7 @@ describe('ReactElementClone', () => {
|
||||
}
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
React.cloneElement(<Component />, {children: 'xyz'})
|
||||
React.cloneElement(<Component />, {children: 'xyz'}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -133,7 +135,7 @@ describe('ReactElementClone', () => {
|
||||
}
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
React.cloneElement(<Component>xyz</Component>, {})
|
||||
React.cloneElement(<Component>xyz</Component>, {}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -146,34 +148,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', () => {
|
||||
class Parent extends React.Component {
|
||||
render() {
|
||||
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 +227,7 @@ describe('ReactElementClone', () => {
|
||||
}
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
React.cloneElement(<Component myprop="abc" />, {myprop: 'xyz'})
|
||||
React.cloneElement(<Component myprop="abc" />, {myprop: 'xyz'}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -250,7 +259,7 @@ describe('ReactElementClone', () => {
|
||||
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -286,7 +295,7 @@ describe('ReactElementClone', () => {
|
||||
}
|
||||
}
|
||||
Component.propTypes = {
|
||||
color: React.PropTypes.string.isRequired,
|
||||
color: PropTypes.string.isRequired,
|
||||
};
|
||||
class Parent extends React.Component {
|
||||
render() {
|
||||
@@ -295,21 +304,20 @@ describe('ReactElementClone', () => {
|
||||
}
|
||||
class GrandParent extends React.Component {
|
||||
render() {
|
||||
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));
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -359,5 +367,4 @@ describe('ReactElementClone', () => {
|
||||
expect(Object.isFrozen(element.props)).toBe(true);
|
||||
expect(clone.props).toEqual({foo: 'ef'});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
// NOTE: We're explicitly not using JSX in this file. This is intended to test
|
||||
// classic JS without JSX.
|
||||
|
||||
var PropTypes;
|
||||
var React;
|
||||
var ReactDOM;
|
||||
var ReactTestUtils;
|
||||
@@ -31,6 +32,7 @@ describe('ReactElementValidator', () => {
|
||||
React = require('React');
|
||||
ReactDOM = require('ReactDOM');
|
||||
ReactTestUtils = require('ReactTestUtils');
|
||||
PropTypes = require('prop-types');
|
||||
ComponentClass = class extends React.Component {
|
||||
render() {
|
||||
return React.createElement('div');
|
||||
@@ -46,7 +48,7 @@ describe('ReactElementValidator', () => {
|
||||
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -64,19 +66,17 @@ describe('ReactElementValidator', () => {
|
||||
|
||||
class ComponentWrapper extends React.Component {
|
||||
render() {
|
||||
return InnerComponent({childSet: [Component(), Component()] });
|
||||
return InnerComponent({childSet: [Component(), Component()]});
|
||||
}
|
||||
}
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
React.createElement(ComponentWrapper)
|
||||
);
|
||||
ReactTestUtils.renderIntoDocument(React.createElement(ComponentWrapper));
|
||||
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Each child in an array or iterator should have a unique "key" prop. ' +
|
||||
'Check the render method of `InnerClass`. ' +
|
||||
'It was passed a child from ComponentWrapper. '
|
||||
'Check the render method of `InnerClass`. ' +
|
||||
'It was passed a child from ComponentWrapper. ',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -86,37 +86,31 @@ describe('ReactElementValidator', () => {
|
||||
function Anonymous() {
|
||||
return <div />;
|
||||
}
|
||||
Object.defineProperty(Anonymous, 'name', { value: undefined });
|
||||
Object.defineProperty(Anonymous, 'name', {value: undefined});
|
||||
|
||||
var divs = [
|
||||
<div />,
|
||||
<div />,
|
||||
];
|
||||
var divs = [<div />, <div />];
|
||||
ReactTestUtils.renderIntoDocument(<Anonymous>{divs}</Anonymous>);
|
||||
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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>);
|
||||
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
|
||||
'Warning: Each child in an array or iterator should have a unique ' +
|
||||
'"key" prop. Check the top-level render call using <div>. See ' +
|
||||
'https://fb.me/react-warning-keys for more information.\n' +
|
||||
' in div (at **)'
|
||||
'"key" prop. Check the top-level render call using <div>. See ' +
|
||||
'https://fb.me/react-warning-keys for more information.\n' +
|
||||
' in div (at **)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -140,12 +134,12 @@ describe('ReactElementValidator', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
|
||||
'Warning: Each child in an array or iterator should have a unique ' +
|
||||
'"key" prop. Check 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. Check 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 **)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -165,7 +159,7 @@ describe('ReactElementValidator', () => {
|
||||
<Wrapper>
|
||||
<span />
|
||||
<span />
|
||||
</Wrapper>
|
||||
</Wrapper>,
|
||||
);
|
||||
|
||||
expect(console.error.calls.count()).toBe(0);
|
||||
@@ -191,7 +185,7 @@ describe('ReactElementValidator', () => {
|
||||
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -258,7 +252,7 @@ describe('ReactElementValidator', () => {
|
||||
return React.createElement('div', null, 'My color is ' + props.color);
|
||||
}
|
||||
MyComp.propTypes = {
|
||||
color: React.PropTypes.string,
|
||||
color: PropTypes.string,
|
||||
};
|
||||
function ParentComp() {
|
||||
return React.createElement(MyComp, {color: 123});
|
||||
@@ -266,10 +260,10 @@ describe('ReactElementValidator', () => {
|
||||
ReactTestUtils.renderIntoDocument(React.createElement(ParentComp));
|
||||
expect(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',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -284,35 +278,35 @@ describe('ReactElementValidator', () => {
|
||||
expect(console.error.calls.count()).toBe(6);
|
||||
expect(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.",
|
||||
);
|
||||
expect(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.',
|
||||
);
|
||||
expect(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.',
|
||||
);
|
||||
expect(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.',
|
||||
);
|
||||
expect(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.',
|
||||
);
|
||||
expect(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');
|
||||
expect(console.error.calls.count()).toBe(6);
|
||||
@@ -327,15 +321,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. Check ' +
|
||||
'the render method of `ParentComp`.'
|
||||
'or a class/function (for composite components) but got: null. Check ' +
|
||||
'the render method of `ParentComp`.',
|
||||
);
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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. Check the render method of `ParentComp`.' +
|
||||
'\n in ParentComp'
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: null. Check the render method of `ParentComp`.' +
|
||||
'\n in ParentComp',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -347,7 +341,7 @@ describe('ReactElementValidator', () => {
|
||||
return React.createElement('span', null, this.props.prop);
|
||||
}
|
||||
}
|
||||
Component.propTypes = {prop: React.PropTypes.string.isRequired};
|
||||
Component.propTypes = {prop: PropTypes.string.isRequired};
|
||||
Component.defaultProps = {prop: null};
|
||||
|
||||
ReactTestUtils.renderIntoDocument(React.createElement(Component));
|
||||
@@ -355,8 +349,8 @@ describe('ReactElementValidator', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -368,18 +362,18 @@ describe('ReactElementValidator', () => {
|
||||
return React.createElement('span', null, this.props.prop);
|
||||
}
|
||||
}
|
||||
Component.propTypes = {prop: React.PropTypes.string.isRequired};
|
||||
Component.propTypes = {prop: PropTypes.string.isRequired};
|
||||
Component.defaultProps = {prop: 'text'};
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
React.createElement(Component, {prop:null})
|
||||
React.createElement(Component, {prop: null}),
|
||||
);
|
||||
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -392,33 +386,31 @@ describe('ReactElementValidator', () => {
|
||||
}
|
||||
}
|
||||
Component.propTypes = {
|
||||
prop: React.PropTypes.string.isRequired,
|
||||
prop: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
ReactTestUtils.renderIntoDocument(React.createElement(Component));
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
React.createElement(Component)
|
||||
);
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
React.createElement(Component, {prop: 42})
|
||||
React.createElement(Component, {prop: 42}),
|
||||
);
|
||||
|
||||
expect(console.error.calls.count()).toBe(2);
|
||||
expect(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',
|
||||
);
|
||||
|
||||
expect(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
|
||||
@@ -431,42 +423,41 @@ describe('ReactElementValidator', () => {
|
||||
class Component extends React.Component {
|
||||
render() {
|
||||
return React.createElement('span', null, this.props.myProp.value);
|
||||
|
||||
}
|
||||
}
|
||||
Component.propTypes = {
|
||||
myProp: React.PropTypes.shape,
|
||||
myProp: PropTypes.shape,
|
||||
};
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
React.createElement(Component, {myProp: {value: 'hi'}})
|
||||
React.createElement(Component, {myProp: {value: 'hi'}}),
|
||||
);
|
||||
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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).',
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn when accessing .type on an element factory', () => {
|
||||
spyOn(console, 'error');
|
||||
spyOn(console, 'warn');
|
||||
function TestComponent() {
|
||||
return <div />;
|
||||
}
|
||||
var TestFactory = React.createFactory(TestComponent);
|
||||
expect(TestFactory.type).toBe(TestComponent);
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toBe(
|
||||
expect(console.warn.calls.count()).toBe(1);
|
||||
expect(console.warn.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);
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.warn.calls.count()).toBe(1);
|
||||
});
|
||||
|
||||
it('does not warn when using DOM node as children', () => {
|
||||
@@ -511,7 +502,7 @@ describe('ReactElementValidator', () => {
|
||||
// shouldn't blow up either.
|
||||
|
||||
var child = {
|
||||
$$typeof: (<div />).$$typeof,
|
||||
$$typeof: <div />.$$typeof,
|
||||
type: 'span',
|
||||
key: null,
|
||||
ref: null,
|
||||
@@ -529,10 +520,60 @@ describe('ReactElementValidator', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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. Check 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. Check your code at **.",
|
||||
);
|
||||
});
|
||||
|
||||
it('provides stack via non-standard console.reactStack for invalid types', () => {
|
||||
spyOn(console, 'error');
|
||||
|
||||
function Foo() {
|
||||
var Bad = undefined;
|
||||
return React.createElement(Bad);
|
||||
}
|
||||
|
||||
function App() {
|
||||
return React.createElement('div', null, React.createElement(Foo));
|
||||
}
|
||||
|
||||
try {
|
||||
console.reactStack = jest.fn();
|
||||
console.reactStackEnd = jest.fn();
|
||||
|
||||
expect(() => {
|
||||
ReactTestUtils.renderIntoDocument(React.createElement(App));
|
||||
}).toThrow(
|
||||
'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. Check the render method of `Foo`.',
|
||||
);
|
||||
|
||||
expect(console.reactStack.mock.calls.length).toBe(1);
|
||||
expect(console.reactStackEnd.mock.calls.length).toBe(1);
|
||||
|
||||
var stack = console.reactStack.mock.calls[0][0];
|
||||
expect(Array.isArray(stack)).toBe(true);
|
||||
expect(stack.map(frame => frame.name)).toEqual([
|
||||
'Foo', // <Bad> is inside Foo
|
||||
'App', // <Foo> is inside App
|
||||
'App', // <div> is inside App
|
||||
null, // <App> is outside a component
|
||||
]);
|
||||
expect(
|
||||
stack.map(frame => frame.fileName && frame.fileName.slice(-8)),
|
||||
).toEqual([null, null, null, null]);
|
||||
expect(stack.map(frame => frame.lineNumber)).toEqual([
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
]);
|
||||
} finally {
|
||||
delete console.reactStack;
|
||||
delete console.reactStackEnd;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -28,16 +28,18 @@ function typeCheckFail(declaration, value, message) {
|
||||
'testComponent',
|
||||
'prop',
|
||||
null,
|
||||
ReactPropTypesSecret
|
||||
ReactPropTypesSecret,
|
||||
);
|
||||
expect(error instanceof Error).toBe(true);
|
||||
expect(error.message).toBe(message);
|
||||
}
|
||||
|
||||
function typeCheckFailRequiredValues(declaration) {
|
||||
var specifiedButIsNullMsg = 'The prop `testProp` is marked as required in ' +
|
||||
var specifiedButIsNullMsg =
|
||||
'The prop `testProp` is marked as required in ' +
|
||||
'`testComponent`, but its value is `null`.';
|
||||
var unspecifiedMsg = 'The prop `testProp` is marked as required in ' +
|
||||
var unspecifiedMsg =
|
||||
'The prop `testProp` is marked as required in ' +
|
||||
'`testComponent`, but its value is \`undefined\`.';
|
||||
var props1 = {testProp: null};
|
||||
var error1 = declaration(
|
||||
@@ -46,7 +48,7 @@ function typeCheckFailRequiredValues(declaration) {
|
||||
'testComponent',
|
||||
'prop',
|
||||
null,
|
||||
ReactPropTypesSecret
|
||||
ReactPropTypesSecret,
|
||||
);
|
||||
expect(error1 instanceof Error).toBe(true);
|
||||
expect(error1.message).toBe(specifiedButIsNullMsg);
|
||||
@@ -57,7 +59,7 @@ function typeCheckFailRequiredValues(declaration) {
|
||||
'testComponent',
|
||||
'prop',
|
||||
null,
|
||||
ReactPropTypesSecret
|
||||
ReactPropTypesSecret,
|
||||
);
|
||||
expect(error2 instanceof Error).toBe(true);
|
||||
expect(error2.message).toBe(unspecifiedMsg);
|
||||
@@ -68,7 +70,7 @@ function typeCheckFailRequiredValues(declaration) {
|
||||
'testComponent',
|
||||
'prop',
|
||||
null,
|
||||
ReactPropTypesSecret
|
||||
ReactPropTypesSecret,
|
||||
);
|
||||
expect(error3 instanceof Error).toBe(true);
|
||||
expect(error3.message).toBe(unspecifiedMsg);
|
||||
@@ -82,7 +84,7 @@ function typeCheckPass(declaration, value) {
|
||||
'testComponent',
|
||||
'prop',
|
||||
null,
|
||||
ReactPropTypesSecret
|
||||
ReactPropTypesSecret,
|
||||
);
|
||||
expect(error).toBe(null);
|
||||
}
|
||||
@@ -92,16 +94,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();
|
||||
}
|
||||
@@ -121,31 +118,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`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -154,13 +151,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`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -260,9 +257,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.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -276,14 +273,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', () => {
|
||||
@@ -291,7 +288,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`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -303,7 +300,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 +
|
||||
'`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -312,19 +311,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.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -339,26 +338,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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -384,25 +389,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.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -443,7 +448,6 @@ describe('ReactPropTypes', () => {
|
||||
expectWarningInDevelopment(PropTypes.element.isRequired, null);
|
||||
expectWarningInDevelopment(PropTypes.element.isRequired, undefined);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Instance Types', () => {
|
||||
@@ -458,43 +462,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 +
|
||||
'`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -524,9 +542,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', () => {
|
||||
@@ -539,7 +559,8 @@ describe('ReactPropTypes', () => {
|
||||
});
|
||||
|
||||
it('should warn for invalid values', () => {
|
||||
var failMessage = 'Invalid prop `testProp` supplied to ' +
|
||||
var failMessage =
|
||||
'Invalid prop `testProp` supplied to ' +
|
||||
'`testComponent`, expected a ReactNode.';
|
||||
typeCheckFail(PropTypes.node, true, failMessage);
|
||||
typeCheckFail(PropTypes.node, function() {}, failMessage);
|
||||
@@ -565,18 +586,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,
|
||||
}));
|
||||
);
|
||||
expect(console.error.calls.count()).toBe(0);
|
||||
});
|
||||
|
||||
@@ -603,7 +627,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,
|
||||
};
|
||||
},
|
||||
};
|
||||
},
|
||||
@@ -634,45 +661,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', () => {
|
||||
@@ -680,7 +708,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`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -692,7 +720,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 +
|
||||
'`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -701,25 +731,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.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -734,23 +764,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,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -761,8 +794,9 @@ describe('ReactPropTypes', () => {
|
||||
PropTypes.oneOf('red', 'blue');
|
||||
|
||||
expect(console.error).toHaveBeenCalled();
|
||||
expect(console.error.calls.argsFor(0)[0])
|
||||
.toContain('Invalid argument supplied to oneOf, expected an instance of array.');
|
||||
expect(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Invalid argument supplied to oneOf, expected an instance of array.',
|
||||
);
|
||||
|
||||
typeCheckPass(PropTypes.oneOf('red', 'blue'), 'red');
|
||||
});
|
||||
@@ -772,25 +806,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"].',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -824,8 +858,9 @@ describe('ReactPropTypes', () => {
|
||||
PropTypes.oneOfType(PropTypes.string, PropTypes.number);
|
||||
|
||||
expect(console.error).toHaveBeenCalled();
|
||||
expect(console.error.calls.argsFor(0)[0])
|
||||
.toContain('Invalid argument supplied to oneOfType, expected an instance of array.');
|
||||
expect(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Invalid argument supplied to oneOfType, expected an instance of array.',
|
||||
);
|
||||
|
||||
typeCheckPass(PropTypes.oneOf(PropTypes.string, PropTypes.number), []);
|
||||
});
|
||||
@@ -834,7 +869,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([
|
||||
@@ -844,15 +879,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);
|
||||
@@ -867,16 +899,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,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -884,18 +918,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', () => {
|
||||
@@ -904,13 +937,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`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -937,7 +970,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`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -949,44 +982,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 />);
|
||||
});
|
||||
@@ -998,13 +1036,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,
|
||||
@@ -1012,7 +1050,7 @@ describe('ReactPropTypes', () => {
|
||||
'@@toStringTag': 'Katana',
|
||||
},
|
||||
'Invalid prop `testProp` of type `object` supplied to ' +
|
||||
'`testComponent`, expected `symbol`.'
|
||||
'`testComponent`, expected `symbol`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1061,15 +1099,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};
|
||||
|
||||
@@ -1082,33 +1120,31 @@ describe('ReactPropTypes', () => {
|
||||
ReactTestUtils.renderIntoDocument(instance);
|
||||
expect(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 instance = <Component num={5} />;
|
||||
ReactTestUtils.renderIntoDocument(instance);
|
||||
expect(console.error.calls.count()).toBe(0);
|
||||
}
|
||||
);
|
||||
var instance = <Component num={5} />;
|
||||
ReactTestUtils.renderIntoDocument(instance);
|
||||
expect(console.error.calls.count()).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,23 +17,26 @@ var ReactCurrentOwner = require('ReactCurrentOwner');
|
||||
var invariant = require('invariant');
|
||||
var warning = require('warning');
|
||||
|
||||
import type { ReactElement, Source } from 'ReactElementType';
|
||||
import type { DebugID } from 'ReactInstanceType';
|
||||
import type {ReactElement, Source} from 'ReactElementType';
|
||||
import type {DebugID} from 'ReactInstanceType';
|
||||
|
||||
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);
|
||||
@@ -43,7 +46,7 @@ function isNative(fn) {
|
||||
}
|
||||
}
|
||||
|
||||
var canUseCollections = (
|
||||
var canUseCollections =
|
||||
// Array.from
|
||||
typeof Array.from === 'function' &&
|
||||
// Map
|
||||
@@ -59,8 +62,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;
|
||||
@@ -96,7 +98,6 @@ if (canUseCollections) {
|
||||
getRootIDs = function() {
|
||||
return Array.from(rootIDSet.keys());
|
||||
};
|
||||
|
||||
} else {
|
||||
var itemByKey = {};
|
||||
var rootByKey = {};
|
||||
@@ -151,13 +152,16 @@ function purgeDeep(id) {
|
||||
}
|
||||
|
||||
function describeComponentFrame(name, source, ownerName) {
|
||||
return '\n in ' + (name || 'Unknown') + (
|
||||
source ?
|
||||
' (at ' + source.fileName.replace(/^.*[\\\/]/, '') + ':' +
|
||||
source.lineNumber + ')' :
|
||||
ownerName ?
|
||||
' (created by ' + ownerName + ')' :
|
||||
''
|
||||
return (
|
||||
'\n in ' +
|
||||
(name || 'Unknown') +
|
||||
(source
|
||||
? ' (at ' +
|
||||
source.fileName.replace(/^.*[\\\/]/, '') +
|
||||
':' +
|
||||
source.lineNumber +
|
||||
')'
|
||||
: ownerName ? ' (created by ' + ownerName + ')' : '')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -184,8 +188,8 @@ 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);
|
||||
}
|
||||
@@ -202,19 +206,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;
|
||||
@@ -225,15 +229,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,
|
||||
@@ -318,7 +326,7 @@ var ReactComponentTreeHook = {
|
||||
info += describeComponentFrame(
|
||||
name,
|
||||
topElement._source,
|
||||
owner && owner.getName()
|
||||
owner && owner.getName(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -394,6 +402,57 @@ var ReactComponentTreeHook = {
|
||||
|
||||
getRootIDs,
|
||||
getRegisteredIDs: getItemIDs,
|
||||
|
||||
pushNonStandardWarningStack(
|
||||
isCreatingElement: boolean,
|
||||
currentSource: ?Source,
|
||||
) {
|
||||
if (typeof console.reactStack !== 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
var stack = [];
|
||||
var currentOwner = ReactCurrentOwner.current;
|
||||
var id = currentOwner && currentOwner._debugID;
|
||||
|
||||
try {
|
||||
if (isCreatingElement) {
|
||||
stack.push({
|
||||
name: id ? ReactComponentTreeHook.getDisplayName(id) : null,
|
||||
fileName: currentSource ? currentSource.fileName : null,
|
||||
lineNumber: currentSource ? currentSource.lineNumber : null,
|
||||
});
|
||||
}
|
||||
|
||||
while (id) {
|
||||
var element = ReactComponentTreeHook.getElement(id);
|
||||
var parentID = ReactComponentTreeHook.getParentID(id);
|
||||
var ownerID = ReactComponentTreeHook.getOwnerID(id);
|
||||
var ownerName = ownerID
|
||||
? ReactComponentTreeHook.getDisplayName(ownerID)
|
||||
: null;
|
||||
var source = element && element._source;
|
||||
stack.push({
|
||||
name: ownerName,
|
||||
fileName: source ? source.fileName : null,
|
||||
lineNumber: source ? source.lineNumber : null,
|
||||
});
|
||||
id = parentID;
|
||||
}
|
||||
} catch (err) {
|
||||
// Internal state is messed up.
|
||||
// Stop building the stack (it's just a nice to have).
|
||||
}
|
||||
|
||||
console.reactStack(stack);
|
||||
},
|
||||
|
||||
popNonStandardWarningStack() {
|
||||
if (typeof console.reactStackEnd !== 'function') {
|
||||
return;
|
||||
}
|
||||
console.reactStackEnd();
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = ReactComponentTreeHook;
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/*!
|
||||
* Copyright 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
/**
|
||||
* TypeScript Definition File for React.
|
||||
*
|
||||
* Full type definitions are not yet officially supported. These are mostly
|
||||
* just helpers for the unit test.
|
||||
*/
|
||||
|
||||
declare module 'prop-types' {
|
||||
export var string : any;
|
||||
}
|
||||
+34
-10
@@ -6,7 +6,7 @@
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactComponent
|
||||
* @providesModule ReactBaseClasses
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
@@ -16,7 +16,7 @@ var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue');
|
||||
var canDefineProperty = require('canDefineProperty');
|
||||
var emptyObject = require('emptyObject');
|
||||
var invariant = require('invariant');
|
||||
var warning = require('warning');
|
||||
var lowPriorityWarning = require('lowPriorityWarning');
|
||||
|
||||
/**
|
||||
* Base class helpers for the updating state of a component.
|
||||
@@ -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);
|
||||
if (callback) {
|
||||
@@ -102,23 +102,23 @@ 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) {
|
||||
if (canDefineProperty) {
|
||||
Object.defineProperty(ReactComponent.prototype, methodName, {
|
||||
get: function() {
|
||||
warning(
|
||||
lowPriorityWarning(
|
||||
false,
|
||||
'%s(...) is deprecated in plain JavaScript React classes. %s',
|
||||
info[0],
|
||||
info[1]
|
||||
info[1],
|
||||
);
|
||||
return undefined;
|
||||
},
|
||||
@@ -132,4 +132,28 @@ if (__DEV__) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ReactComponent;
|
||||
/**
|
||||
* Base class helpers for the updating state of a component.
|
||||
*/
|
||||
function ReactPureComponent(props, context, updater) {
|
||||
// Duplicated from ReactComponent.
|
||||
this.props = props;
|
||||
this.context = context;
|
||||
this.refs = emptyObject;
|
||||
// We initialize the default updater but the real one gets injected by the
|
||||
// renderer.
|
||||
this.updater = updater || ReactNoopUpdateQueue;
|
||||
}
|
||||
|
||||
function ComponentDummy() {}
|
||||
ComponentDummy.prototype = ReactComponent.prototype;
|
||||
ReactPureComponent.prototype = new ComponentDummy();
|
||||
ReactPureComponent.prototype.constructor = ReactPureComponent;
|
||||
// Avoid an extra prototype jump for these methods.
|
||||
Object.assign(ReactPureComponent.prototype, ReactComponent.prototype);
|
||||
ReactPureComponent.prototype.isPureReactComponent = true;
|
||||
|
||||
module.exports = {
|
||||
Component: ReactComponent,
|
||||
PureComponent: ReactPureComponent,
|
||||
};
|
||||
@@ -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. Please check the code for the %s component.',
|
||||
'This usually means you called %s() on an unmounted component. ' +
|
||||
'This is a no-op. Please 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.
|
||||
@@ -52,7 +52,7 @@ var ReactNoopUpdateQueue = {
|
||||
* @param {?function} callback Called after state is updated.
|
||||
* @internal
|
||||
*/
|
||||
enqueueCallback: function(publicInstance, callback) { },
|
||||
enqueueCallback: function(publicInstance, callback) {},
|
||||
|
||||
/**
|
||||
* Forces an update. This should only be invoked when it is known with
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactPureComponent
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var ReactComponent = require('ReactComponent');
|
||||
var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue');
|
||||
|
||||
var emptyObject = require('emptyObject');
|
||||
|
||||
/**
|
||||
* Base class helpers for the updating state of a component.
|
||||
*/
|
||||
function ReactPureComponent(props, context, updater) {
|
||||
// Duplicated from ReactComponent.
|
||||
this.props = props;
|
||||
this.context = context;
|
||||
this.refs = emptyObject;
|
||||
// We initialize the default updater but the real one gets injected by the
|
||||
// renderer.
|
||||
this.updater = updater || ReactNoopUpdateQueue;
|
||||
}
|
||||
|
||||
function ComponentDummy() {}
|
||||
ComponentDummy.prototype = ReactComponent.prototype;
|
||||
ReactPureComponent.prototype = new ComponentDummy();
|
||||
ReactPureComponent.prototype.constructor = ReactPureComponent;
|
||||
// Avoid an extra prototype jump for these methods.
|
||||
Object.assign(ReactPureComponent.prototype, ReactComponent.prototype);
|
||||
ReactPureComponent.prototype.isPureReactComponent = true;
|
||||
|
||||
module.exports = ReactPureComponent;
|
||||
@@ -26,7 +26,6 @@ describe('ReactClassEquivalence', () => {
|
||||
var result2 = runJest('ReactES6Class-test.js');
|
||||
compareResults(result1, result2);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function runJest(testFile) {
|
||||
@@ -35,14 +34,13 @@ function runJest(testFile) {
|
||||
var setupFile = path.resolve(
|
||||
'scripts',
|
||||
'jest',
|
||||
'setupSpecEquivalenceReporter.js'
|
||||
'setupSpecEquivalenceReporter.js',
|
||||
);
|
||||
var result = spawnSync(
|
||||
'node',
|
||||
[jestBin, testFile, '--setupTestFrameworkScriptFile', setupFile],
|
||||
{cwd},
|
||||
);
|
||||
var result = spawnSync('node', [
|
||||
jestBin,
|
||||
testFile,
|
||||
'--setupTestFrameworkScriptFile',
|
||||
setupFile,
|
||||
], {cwd});
|
||||
|
||||
if (result.error) {
|
||||
throw result.error;
|
||||
@@ -51,12 +49,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(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ LICENSE file in the root directory of this source tree. An additional grant
|
||||
of patent rights can be found in the PATENTS file in the same directory.
|
||||
###
|
||||
|
||||
PropTypes = null
|
||||
React = null
|
||||
ReactDOM = null
|
||||
|
||||
@@ -21,6 +22,7 @@ describe 'ReactCoffeeScriptClass', ->
|
||||
beforeEach ->
|
||||
React = require 'React'
|
||||
ReactDOM = require 'ReactDOM'
|
||||
PropTypes = require 'prop-types'
|
||||
container = document.createElement 'div'
|
||||
attachedListener = null
|
||||
renderedName = null
|
||||
@@ -102,8 +104,8 @@ describe 'ReactCoffeeScriptClass', ->
|
||||
it 'renders based on context in the constructor', ->
|
||||
class Foo extends React.Component
|
||||
@contextTypes:
|
||||
tag: React.PropTypes.string
|
||||
className: React.PropTypes.string
|
||||
tag: PropTypes.string
|
||||
className: PropTypes.string
|
||||
|
||||
constructor: (props, context) ->
|
||||
super props, context
|
||||
@@ -118,8 +120,8 @@ describe 'ReactCoffeeScriptClass', ->
|
||||
|
||||
class Outer extends React.Component
|
||||
@childContextTypes:
|
||||
tag: React.PropTypes.string
|
||||
className: React.PropTypes.string
|
||||
tag: PropTypes.string
|
||||
className: PropTypes.string
|
||||
|
||||
getChildContext: ->
|
||||
tag: 'span'
|
||||
@@ -376,16 +378,16 @@ describe 'ReactCoffeeScriptClass', ->
|
||||
undefined
|
||||
|
||||
it 'should throw AND warn when trying to access classic APIs', ->
|
||||
spyOn console, 'error'
|
||||
spyOn console, 'warn'
|
||||
instance =
|
||||
test Inner(name: 'foo'), 'DIV', 'foo'
|
||||
expect(-> instance.replaceState {}).toThrow()
|
||||
expect(-> instance.isMounted()).toThrow()
|
||||
expect(console.error.calls.count()).toBe 2
|
||||
expect(console.error.calls.argsFor(0)[0]).toContain(
|
||||
expect(console.warn.calls.count()).toBe 2
|
||||
expect(console.warn.calls.argsFor(0)[0]).toContain(
|
||||
'replaceState(...) is deprecated in plain JavaScript React classes'
|
||||
)
|
||||
expect(console.error.calls.argsFor(1)[0]).toContain(
|
||||
expect(console.warn.calls.argsFor(1)[0]).toContain(
|
||||
'isMounted(...) is deprecated in plain JavaScript React classes'
|
||||
)
|
||||
undefined
|
||||
@@ -393,13 +395,13 @@ describe 'ReactCoffeeScriptClass', ->
|
||||
it 'supports this.context passed via getChildContext', ->
|
||||
class Bar extends React.Component
|
||||
@contextTypes:
|
||||
bar: React.PropTypes.string
|
||||
bar: PropTypes.string
|
||||
render: ->
|
||||
div className: @context.bar
|
||||
|
||||
class Foo extends React.Component
|
||||
@childContextTypes:
|
||||
bar: React.PropTypes.string
|
||||
bar: PropTypes.string
|
||||
getChildContext: ->
|
||||
bar: 'bar-through-context'
|
||||
render: ->
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var PropTypes;
|
||||
var React;
|
||||
var ReactDOM;
|
||||
|
||||
describe('ReactES6Class', () => {
|
||||
|
||||
var container;
|
||||
var freeze = function(expectation) {
|
||||
Object.freeze(expectation);
|
||||
@@ -28,6 +28,7 @@ describe('ReactES6Class', () => {
|
||||
beforeEach(() => {
|
||||
React = require('React');
|
||||
ReactDOM = require('ReactDOM');
|
||||
PropTypes = require('prop-types');
|
||||
container = document.createElement('div');
|
||||
attachedListener = null;
|
||||
renderedName = null;
|
||||
@@ -52,19 +53,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`.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -124,8 +125,8 @@ describe('ReactES6Class', () => {
|
||||
}
|
||||
}
|
||||
Foo.contextTypes = {
|
||||
tag: React.PropTypes.string,
|
||||
className: React.PropTypes.string,
|
||||
tag: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
class Outer extends React.Component {
|
||||
@@ -137,8 +138,8 @@ describe('ReactES6Class', () => {
|
||||
}
|
||||
}
|
||||
Outer.childContextTypes = {
|
||||
tag: React.PropTypes.string,
|
||||
className: React.PropTypes.string,
|
||||
tag: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
test(<Outer />, 'SPAN', 'foo');
|
||||
});
|
||||
@@ -174,7 +175,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 +204,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 +223,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,23 +288,25 @@ 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');
|
||||
expect(lifeCycles).toEqual([
|
||||
'receive-props', freeze({value: 'bar'}),
|
||||
'should-update', freeze({value: 'bar'}), {},
|
||||
'will-update', freeze({value: 'bar'}), {},
|
||||
'did-update', freeze({value: 'foo'}), {},
|
||||
'receive-props',
|
||||
freeze({value: 'bar'}),
|
||||
'should-update',
|
||||
freeze({value: 'bar'}),
|
||||
{},
|
||||
'will-update',
|
||||
freeze({value: 'bar'}),
|
||||
{},
|
||||
'did-update',
|
||||
freeze({value: 'foo'}),
|
||||
{},
|
||||
]);
|
||||
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 +336,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 +380,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,22 +402,22 @@ 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()?',
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw AND warn when trying to access classic APIs', () => {
|
||||
spyOn(console, 'error');
|
||||
spyOn(console, 'warn');
|
||||
var instance = test(<Inner name="foo" />, 'DIV', 'foo');
|
||||
expect(() => instance.replaceState({})).toThrow();
|
||||
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'
|
||||
expect(console.warn.calls.count()).toBe(2);
|
||||
expect(console.warn.calls.argsFor(0)[0]).toContain(
|
||||
'replaceState(...) is deprecated in plain JavaScript React classes',
|
||||
);
|
||||
expect(console.error.calls.argsFor(1)[0]).toContain(
|
||||
'isMounted(...) is deprecated in plain JavaScript React classes'
|
||||
expect(console.warn.calls.argsFor(1)[0]).toContain(
|
||||
'isMounted(...) is deprecated in plain JavaScript React classes',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -432,7 +427,7 @@ describe('ReactES6Class', () => {
|
||||
return <div className={this.context.bar} />;
|
||||
}
|
||||
}
|
||||
Bar.contextTypes = {bar: React.PropTypes.string};
|
||||
Bar.contextTypes = {bar: PropTypes.string};
|
||||
class Foo extends React.Component {
|
||||
getChildContext() {
|
||||
return {bar: 'bar-through-context'};
|
||||
@@ -441,7 +436,7 @@ describe('ReactES6Class', () => {
|
||||
return <Bar />;
|
||||
}
|
||||
}
|
||||
Foo.childContextTypes = {bar: React.PropTypes.string};
|
||||
Foo.childContextTypes = {bar: PropTypes.string};
|
||||
test(<Foo />, 'DIV', 'bar-through-context');
|
||||
});
|
||||
|
||||
@@ -460,5 +455,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);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/// <reference path="../PropTypes.d.ts" />
|
||||
/// <reference path="../React.d.ts" />
|
||||
/// <reference path="../ReactDOM.d.ts" />
|
||||
|
||||
@@ -12,6 +13,7 @@
|
||||
|
||||
import React = require('React');
|
||||
import ReactDOM = require('ReactDOM');
|
||||
import PropTypes = require('prop-types');
|
||||
|
||||
// Before Each
|
||||
|
||||
@@ -85,8 +87,8 @@ class StateBasedOnProps extends React.Component {
|
||||
// it renders based on context in the constructor
|
||||
class StateBasedOnContext extends React.Component {
|
||||
static contextTypes = {
|
||||
tag: React.PropTypes.string,
|
||||
className: React.PropTypes.string
|
||||
tag: PropTypes.string,
|
||||
className: PropTypes.string
|
||||
};
|
||||
state = {
|
||||
tag: this.context.tag,
|
||||
@@ -100,8 +102,8 @@ class StateBasedOnContext extends React.Component {
|
||||
|
||||
class ProvideChildContextTypes extends React.Component {
|
||||
static childContextTypes = {
|
||||
tag: React.PropTypes.string,
|
||||
className: React.PropTypes.string
|
||||
tag: PropTypes.string,
|
||||
className: PropTypes.string
|
||||
};
|
||||
getChildContext() {
|
||||
return { tag: 'span', className: 'foo' };
|
||||
@@ -278,13 +280,13 @@ class MisspelledComponent2 extends React.Component {
|
||||
|
||||
// it supports this.context passed via getChildContext
|
||||
class ReadContext extends React.Component {
|
||||
static contextTypes = { bar: React.PropTypes.string };
|
||||
static contextTypes = { bar: PropTypes.string };
|
||||
render() {
|
||||
return React.createElement('div', { className: this.context.bar });
|
||||
}
|
||||
}
|
||||
class ProvideContext extends React.Component {
|
||||
static childContextTypes = { bar: React.PropTypes.string };
|
||||
static childContextTypes = { bar: PropTypes.string };
|
||||
getChildContext() {
|
||||
return { bar: 'bar-through-context' };
|
||||
}
|
||||
@@ -500,18 +502,18 @@ describe('ReactTypeScriptClass', function() {
|
||||
});
|
||||
|
||||
it('should throw AND warn when trying to access classic APIs', function() {
|
||||
spyOn(console, 'error');
|
||||
spyOn(console, 'warn');
|
||||
var instance = test(
|
||||
React.createElement(Inner, {name: 'foo'}),
|
||||
'DIV','foo'
|
||||
);
|
||||
expect(() => instance.replaceState({})).toThrow();
|
||||
expect(() => instance.isMounted()).toThrow();
|
||||
expect((<any>console.error).calls.count()).toBe(2);
|
||||
expect((<any>console.error).calls.argsFor(0)[0]).toContain(
|
||||
expect((<any>console.warn).calls.count()).toBe(2);
|
||||
expect((<any>console.warn).calls.argsFor(0)[0]).toContain(
|
||||
'replaceState(...) is deprecated in plain JavaScript React classes'
|
||||
);
|
||||
expect((<any>console.error).calls.argsFor(1)[0]).toContain(
|
||||
expect((<any>console.warn).calls.argsFor(1)[0]).toContain(
|
||||
'isMounted(...) is deprecated in plain JavaScript React classes'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -64,7 +64,7 @@ describe('ReactJSXElement', () => {
|
||||
|
||||
it('returns an immutable element', () => {
|
||||
var element = <Component />;
|
||||
expect(() => element.type = 'div').toThrow();
|
||||
expect(() => (element.type = 'div')).toThrow();
|
||||
});
|
||||
|
||||
it('does not reuse the object that is spread into props', () => {
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
// TODO: All these warnings should become static errors using Flow instead
|
||||
// of dynamic errors when using JSX with Flow.
|
||||
|
||||
var PropTypes;
|
||||
var React;
|
||||
var ReactDOM;
|
||||
var ReactTestUtils;
|
||||
@@ -32,6 +33,7 @@ describe('ReactJSXElementValidator', () => {
|
||||
React = require('React');
|
||||
ReactDOM = require('ReactDOM');
|
||||
ReactTestUtils = require('ReactTestUtils');
|
||||
PropTypes = require('prop-types');
|
||||
|
||||
Component = class extends React.Component {
|
||||
render() {
|
||||
@@ -45,7 +47,7 @@ describe('ReactJSXElementValidator', () => {
|
||||
}
|
||||
};
|
||||
RequiredPropComponent.displayName = 'RequiredPropComponent';
|
||||
RequiredPropComponent.propTypes = {prop: React.PropTypes.string.isRequired};
|
||||
RequiredPropComponent.propTypes = {prop: PropTypes.string.isRequired};
|
||||
});
|
||||
|
||||
it('warns for keys for arrays of elements in children position', () => {
|
||||
@@ -55,7 +57,7 @@ describe('ReactJSXElementValidator', () => {
|
||||
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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 +72,7 @@ describe('ReactJSXElementValidator', () => {
|
||||
|
||||
class ComponentWrapper extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<InnerComponent
|
||||
childSet={[<Component />, <Component />]}
|
||||
/>
|
||||
);
|
||||
return <InnerComponent childSet={[<Component />, <Component />]} />;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,8 +81,8 @@ describe('ReactJSXElementValidator', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Each child in an array or iterator should have a unique "key" prop. ' +
|
||||
'Check the render method of `InnerComponent`. ' +
|
||||
'It was passed a child from ComponentWrapper. '
|
||||
'Check the render method of `InnerComponent`. ' +
|
||||
'It was passed a child from ComponentWrapper. ',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -107,14 +105,16 @@ describe('ReactJSXElementValidator', () => {
|
||||
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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>
|
||||
);
|
||||
|
||||
expect(console.error.calls.count()).toBe(0);
|
||||
});
|
||||
@@ -193,7 +193,7 @@ describe('ReactJSXElementValidator', () => {
|
||||
}
|
||||
}
|
||||
MyComp.propTypes = {
|
||||
color: React.PropTypes.string,
|
||||
color: PropTypes.string,
|
||||
};
|
||||
class ParentComp extends React.Component {
|
||||
render() {
|
||||
@@ -203,10 +203,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 **)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -216,7 +216,7 @@ describe('ReactJSXElementValidator', () => {
|
||||
return null;
|
||||
}
|
||||
MyComp.propTypes = {
|
||||
color: React.PropTypes.string,
|
||||
color: PropTypes.string,
|
||||
};
|
||||
function MiddleComp(props) {
|
||||
return <MyComp color={props.color} />;
|
||||
@@ -239,11 +239,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 **)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -261,28 +261,28 @@ describe('ReactJSXElementValidator', () => {
|
||||
expect(console.error.calls.count()).toBe(4);
|
||||
expect(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. ' +
|
||||
'Check 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. " +
|
||||
'Check your code at **.',
|
||||
);
|
||||
expect(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. ' +
|
||||
'Check your code at **.'
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: null. ' +
|
||||
'Check your code at **.',
|
||||
);
|
||||
expect(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. ' +
|
||||
'Check your code at **.'
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: boolean. ' +
|
||||
'Check your code at **.',
|
||||
);
|
||||
expect(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. ' +
|
||||
'Check your code at **.'
|
||||
'(for built-in components) or a class/function (for composite ' +
|
||||
'components) but got: number. ' +
|
||||
'Check your code at **.',
|
||||
);
|
||||
void <Div />;
|
||||
expect(console.error.calls.count()).toBe(4);
|
||||
@@ -298,8 +298,8 @@ describe('ReactJSXElementValidator', () => {
|
||||
expect(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 **)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -311,8 +311,8 @@ describe('ReactJSXElementValidator', () => {
|
||||
expect(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 **)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -325,16 +325,16 @@ describe('ReactJSXElementValidator', () => {
|
||||
expect(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" />);
|
||||
@@ -361,7 +361,7 @@ describe('ReactJSXElementValidator', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -379,7 +379,7 @@ describe('ReactJSXElementValidator', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -397,8 +397,58 @@ describe('ReactJSXElementValidator', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(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.',
|
||||
);
|
||||
});
|
||||
|
||||
it('provides stack via non-standard console.reactStack for invalid types', () => {
|
||||
spyOn(console, 'error');
|
||||
|
||||
function Foo() {
|
||||
var Bad = undefined;
|
||||
return <Bad />;
|
||||
}
|
||||
|
||||
function App() {
|
||||
return <div><Foo /></div>;
|
||||
}
|
||||
|
||||
try {
|
||||
console.reactStack = jest.fn();
|
||||
console.reactStackEnd = jest.fn();
|
||||
|
||||
expect(() => {
|
||||
ReactTestUtils.renderIntoDocument(<App />);
|
||||
}).toThrow(
|
||||
'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. Check the render method of `Foo`.',
|
||||
);
|
||||
|
||||
expect(console.reactStack.mock.calls.length).toBe(1);
|
||||
expect(console.reactStackEnd.mock.calls.length).toBe(1);
|
||||
|
||||
var stack = console.reactStack.mock.calls[0][0];
|
||||
expect(Array.isArray(stack)).toBe(true);
|
||||
expect(stack.map(frame => frame.name)).toEqual([
|
||||
'Foo', // <Bad> is inside Foo
|
||||
'App', // <Foo> is inside App
|
||||
'App', // <div> is inside App
|
||||
null, // <App> is outside a component
|
||||
]);
|
||||
expect(
|
||||
stack.map(frame => frame.fileName && frame.fileName.slice(-8)),
|
||||
).toEqual(['-test.js', '-test.js', '-test.js', '-test.js']);
|
||||
expect(stack.map(frame => typeof frame.lineNumber)).toEqual([
|
||||
'number',
|
||||
'number',
|
||||
'number',
|
||||
'number',
|
||||
]);
|
||||
} finally {
|
||||
delete console.reactStack;
|
||||
delete console.reactStackEnd;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
+93
-104
@@ -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');
|
||||
@@ -24,6 +24,7 @@ const ReactInstanceMap = require('ReactInstanceMap');
|
||||
const ReactMultiChild = require('ReactMultiChild');
|
||||
const ReactUpdates = require('ReactUpdates');
|
||||
|
||||
const createReactClass = require('createClass');
|
||||
const emptyObject = require('emptyObject');
|
||||
const invariant = require('invariant');
|
||||
|
||||
@@ -67,8 +68,10 @@ 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 +86,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 +97,6 @@ function injectAfter(parentNode, referenceNode, node) {
|
||||
// ContainerMixin for components that can hold ART nodes
|
||||
|
||||
const ContainerMixin = assign({}, ReactMultiChild.Mixin, {
|
||||
|
||||
/**
|
||||
* Moves a child component to the supplied index.
|
||||
*
|
||||
@@ -153,11 +155,7 @@ const ContainerMixin = assign({}, ReactMultiChild.Mixin, {
|
||||
// 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 +166,13 @@ const ContainerMixin = assign({}, ReactMultiChild.Mixin, {
|
||||
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({
|
||||
|
||||
const Surface = createReactClass({
|
||||
displayName: 'Surface',
|
||||
|
||||
mixins: [ContainerMixin],
|
||||
@@ -192,15 +188,17 @@ 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 +208,7 @@ const Surface = React.createClass({
|
||||
this,
|
||||
this.props.children,
|
||||
transaction,
|
||||
ReactInstanceMap.get(this)._context
|
||||
ReactInstanceMap.get(this)._context,
|
||||
);
|
||||
ReactUpdates.ReactReconcileTransaction.release(transaction);
|
||||
|
||||
@@ -241,8 +239,7 @@ const Surface = React.createClass({
|
||||
title={props.title}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
// Various nodes that can go into a surface
|
||||
@@ -253,11 +250,10 @@ const EventTypes = {
|
||||
onMouseOut: 'mouseout',
|
||||
onMouseUp: 'mouseup',
|
||||
onMouseDown: 'mousedown',
|
||||
onClick: 'click'
|
||||
onClick: 'click',
|
||||
};
|
||||
|
||||
const NodeMixin = {
|
||||
|
||||
construct: function(element) {
|
||||
this._currentElement = element;
|
||||
},
|
||||
@@ -312,10 +308,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)
|
||||
@@ -327,9 +325,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);
|
||||
}
|
||||
|
||||
@@ -357,21 +360,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;
|
||||
@@ -397,55 +398,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) {
|
||||
@@ -468,7 +468,7 @@ const RenderableMixin = assign({}, NodeMixin, {
|
||||
props.strokeWidth,
|
||||
props.strokeCap,
|
||||
props.strokeJoin,
|
||||
props.strokeDash
|
||||
props.strokeDash,
|
||||
);
|
||||
}
|
||||
this.applyNodeProps(oldProps, props);
|
||||
@@ -476,14 +476,12 @@ const RenderableMixin = assign({}, NodeMixin, {
|
||||
|
||||
unmountComponent: function() {
|
||||
this.destroyEventListeners();
|
||||
}
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
// Shape
|
||||
|
||||
const Shape = createComponent('Shape', RenderableMixin, {
|
||||
|
||||
construct: function(element) {
|
||||
this._currentElement = element;
|
||||
this._oldDelta = null;
|
||||
@@ -494,7 +492,7 @@ const Shape = createComponent('Shape', RenderableMixin, {
|
||||
transaction,
|
||||
nativeParent,
|
||||
nativeContainerInfo,
|
||||
context
|
||||
context,
|
||||
) {
|
||||
this.node = Mode.Shape();
|
||||
const props = this._currentElement.props;
|
||||
@@ -514,30 +512,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;
|
||||
@@ -547,7 +540,7 @@ const Text = createComponent('Text', RenderableMixin, {
|
||||
transaction,
|
||||
nativeParent,
|
||||
nativeContainerInfo,
|
||||
context
|
||||
context,
|
||||
) {
|
||||
const props = this._currentElement.props;
|
||||
const newString = childrenAsString(props.children);
|
||||
@@ -580,23 +573,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);
|
||||
});
|
||||
@@ -294,5 +298,4 @@ describe('ReactART', () => {
|
||||
ReactDOM.render(<Outer mountCustomShape={true} />, container);
|
||||
expect(ref.constructor).toBe(CustomShape);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -43,11 +43,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) {
|
||||
@@ -68,21 +68,25 @@ if (
|
||||
if (__DEV__) {
|
||||
var ExecutionEnvironment = require('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 &&
|
||||
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',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -90,10 +94,10 @@ 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
|
||||
@@ -104,8 +108,8 @@ if (__DEV__) {
|
||||
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 = [
|
||||
@@ -126,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');
|
||||
|
||||
@@ -62,7 +62,7 @@ describe('ReactDOMProduction', () => {
|
||||
<Component key={2}>B</Component>
|
||||
<Component key={3}>C</Component>
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
|
||||
expect(container.firstChild).toBe(inst);
|
||||
@@ -75,7 +75,7 @@ describe('ReactDOMProduction', () => {
|
||||
<Component key={1}>A</Component>
|
||||
<Component key={3}>C</Component>
|
||||
</div>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
|
||||
expect(inst.className).toBe('red');
|
||||
@@ -119,10 +119,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'],
|
||||
@@ -140,15 +137,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}],
|
||||
@@ -158,10 +150,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}],
|
||||
@@ -169,9 +158,7 @@ describe('ReactDOMProduction', () => {
|
||||
log = [];
|
||||
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
expect(log).toEqual([
|
||||
['componentWillUnmount'],
|
||||
]);
|
||||
expect(log).toEqual([['componentWillUnmount']]);
|
||||
});
|
||||
|
||||
it('should throw with an error code in production', () => {
|
||||
@@ -186,9 +173,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.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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',
|
||||
topCanPlay: 'canplay',
|
||||
topCanPlayThrough: 'canplaythrough',
|
||||
@@ -142,7 +144,8 @@ var topEventMapping = {
|
||||
topTouchEnd: 'touchend',
|
||||
topTouchMove: 'touchmove',
|
||||
topTouchStart: 'touchstart',
|
||||
topTransitionEnd: getVendorPrefixedEventName('transitionend') || 'transitionend',
|
||||
topTransitionEnd: getVendorPrefixedEventName('transitionend') ||
|
||||
'transitionend',
|
||||
topVolumeChange: 'volumechange',
|
||||
topWaiting: 'waiting',
|
||||
topWheel: 'wheel',
|
||||
@@ -174,7 +177,6 @@ function getListeningForDocument(mountAt) {
|
||||
* @internal
|
||||
*/
|
||||
var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
|
||||
/**
|
||||
* Injectable event backend
|
||||
*/
|
||||
@@ -186,7 +188,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
*/
|
||||
injectReactEventListener: function(ReactEventListener) {
|
||||
ReactEventListener.setHandleTopLevel(
|
||||
ReactBrowserEventEmitter.handleTopLevel
|
||||
ReactBrowserEventEmitter.handleTopLevel,
|
||||
);
|
||||
ReactBrowserEventEmitter.ReactEventListener = ReactEventListener;
|
||||
},
|
||||
@@ -207,10 +209,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());
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -242,22 +242,21 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
|
||||
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.
|
||||
@@ -265,37 +264,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.
|
||||
@@ -303,12 +299,12 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
|
||||
'topFocus',
|
||||
'focusin',
|
||||
mountAt
|
||||
mountAt,
|
||||
);
|
||||
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
|
||||
'topBlur',
|
||||
'focusout',
|
||||
mountAt
|
||||
mountAt,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -319,7 +315,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
|
||||
dependency,
|
||||
topEventMapping[dependency],
|
||||
mountAt
|
||||
mountAt,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -332,7 +328,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
return ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
|
||||
topLevelType,
|
||||
handlerBaseName,
|
||||
handle
|
||||
handle,
|
||||
);
|
||||
},
|
||||
|
||||
@@ -340,7 +336,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
return ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
|
||||
topLevelType,
|
||||
handlerBaseName,
|
||||
handle
|
||||
handle,
|
||||
);
|
||||
},
|
||||
|
||||
@@ -378,7 +374,6 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
|
||||
isMonitoringScrollValue = true;
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
module.exports = ReactBrowserEventEmitter;
|
||||
|
||||
@@ -26,12 +26,12 @@ var internalInstanceKey =
|
||||
* Check if a given node should be cached.
|
||||
*/
|
||||
function shouldPrecacheNode(node, nodeID) {
|
||||
return (node.nodeType === 1 &&
|
||||
node.getAttribute(ATTR_NAME) === String(nodeID)) ||
|
||||
(node.nodeType === 8 &&
|
||||
node.nodeValue === ' react-text: ' + nodeID + ' ') ||
|
||||
(node.nodeType === 8 &&
|
||||
node.nodeValue === ' react-empty: ' + nodeID + ' ');
|
||||
return (
|
||||
(node.nodeType === 1 && node.getAttribute(ATTR_NAME) === String(nodeID)) ||
|
||||
(node.nodeType === 8 &&
|
||||
node.nodeValue === ' react-text: ' + nodeID + ' ') ||
|
||||
(node.nodeType === 8 && node.nodeValue === ' react-empty: ' + nodeID + ' ')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,7 +166,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) {
|
||||
@@ -179,7 +179,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;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ var ReactDOMComponentTree = require('ReactDOMComponentTree');
|
||||
* Operations used to process updates to DOM nodes.
|
||||
*/
|
||||
var ReactDOMIDOperations = {
|
||||
|
||||
/**
|
||||
* Updates a component's children by processing a series of updates.
|
||||
*
|
||||
|
||||
@@ -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,10 @@ function setModernOffsets(node, offsets) {
|
||||
}
|
||||
}
|
||||
|
||||
var useIEOffsets = (
|
||||
var useIEOffsets =
|
||||
ExecutionEnvironment.canUseDOM &&
|
||||
'selection' in document &&
|
||||
!('getSelection' in window)
|
||||
);
|
||||
!('getSelection' in window);
|
||||
|
||||
var ReactDOMSelection = {
|
||||
/**
|
||||
|
||||
@@ -89,7 +89,7 @@ function traverseTwoPhase(inst, fn, arg) {
|
||||
inst = inst._hostParent;
|
||||
}
|
||||
var i;
|
||||
for (i = path.length; i-- > 0;) {
|
||||
for (i = path.length; i-- > 0; ) {
|
||||
fn(path[i], 'captured', arg);
|
||||
}
|
||||
for (i = 0; i < path.length; i++) {
|
||||
@@ -120,7 +120,7 @@ function traverseEnterLeave(from, to, fn, argFrom, argTo) {
|
||||
for (i = 0; i < pathFrom.length; i++) {
|
||||
fn(pathFrom[i], 'bubbled', argFrom);
|
||||
}
|
||||
for (i = pathTo.length; i-- > 0;) {
|
||||
for (i = pathTo.length; i-- > 0; ) {
|
||||
fn(pathTo[i], 'captured', argTo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,13 +52,13 @@ Object.assign(TopLevelCallbackBookKeeping.prototype, {
|
||||
});
|
||||
PooledClass.addPoolingTo(
|
||||
TopLevelCallbackBookKeeping,
|
||||
PooledClass.twoArgumentPooler
|
||||
PooledClass.twoArgumentPooler,
|
||||
);
|
||||
|
||||
function handleTopLevelImpl(bookKeeping) {
|
||||
var nativeEventTarget = getEventTarget(bookKeeping.nativeEvent);
|
||||
var targetInst = ReactDOMComponentTree.getClosestInstanceFromNode(
|
||||
nativeEventTarget
|
||||
nativeEventTarget,
|
||||
);
|
||||
|
||||
// Loop through the hierarchy, in case there's any nested components.
|
||||
@@ -77,7 +77,7 @@ function handleTopLevelImpl(bookKeeping) {
|
||||
bookKeeping.topLevelType,
|
||||
targetInst,
|
||||
bookKeeping.nativeEvent,
|
||||
getEventTarget(bookKeeping.nativeEvent)
|
||||
getEventTarget(bookKeeping.nativeEvent),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,6 @@ var ReactEventListener = {
|
||||
return ReactEventListener._enabled;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Traps top-level events by using event bubbling.
|
||||
*
|
||||
@@ -123,7 +122,7 @@ var ReactEventListener = {
|
||||
return EventListener.listen(
|
||||
element,
|
||||
handlerBaseName,
|
||||
ReactEventListener.dispatchEvent.bind(null, topLevelType)
|
||||
ReactEventListener.dispatchEvent.bind(null, topLevelType),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -144,7 +143,7 @@ var ReactEventListener = {
|
||||
return EventListener.capture(
|
||||
element,
|
||||
handlerBaseName,
|
||||
ReactEventListener.dispatchEvent.bind(null, topLevelType)
|
||||
ReactEventListener.dispatchEvent.bind(null, topLevelType),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -160,7 +159,7 @@ var ReactEventListener = {
|
||||
|
||||
var bookKeeping = TopLevelCallbackBookKeeping.getPooled(
|
||||
topLevelType,
|
||||
nativeEvent
|
||||
nativeEvent,
|
||||
);
|
||||
try {
|
||||
// Event queue being processed in the same cycle allows
|
||||
|
||||
@@ -28,13 +28,13 @@ function isInDocument(node) {
|
||||
* Input selection module for React.
|
||||
*/
|
||||
var ReactInputSelection = {
|
||||
|
||||
hasSelectionCapabilities: function(elem) {
|
||||
var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase();
|
||||
return nodeName && (
|
||||
(nodeName === 'input' && elem.type === 'text') ||
|
||||
nodeName === 'textarea' ||
|
||||
elem.contentEditable === 'true'
|
||||
return (
|
||||
nodeName &&
|
||||
((nodeName === 'input' && elem.type === 'text') ||
|
||||
nodeName === 'textarea' ||
|
||||
elem.contentEditable === 'true')
|
||||
);
|
||||
},
|
||||
|
||||
@@ -42,10 +42,9 @@ var ReactInputSelection = {
|
||||
var focusedElem = getActiveElement();
|
||||
return {
|
||||
focusedElem: focusedElem,
|
||||
selectionRange:
|
||||
ReactInputSelection.hasSelectionCapabilities(focusedElem) ?
|
||||
ReactInputSelection.getSelection(focusedElem) :
|
||||
null,
|
||||
selectionRange: ReactInputSelection.hasSelectionCapabilities(focusedElem)
|
||||
? ReactInputSelection.getSelection(focusedElem)
|
||||
: null,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -58,13 +57,9 @@ var ReactInputSelection = {
|
||||
var curFocusedElem = getActiveElement();
|
||||
var priorFocusedElem = priorSelectionInformation.focusedElem;
|
||||
var priorSelectionRange = priorSelectionInformation.selectionRange;
|
||||
if (curFocusedElem !== priorFocusedElem &&
|
||||
isInDocument(priorFocusedElem)) {
|
||||
if (curFocusedElem !== priorFocusedElem && isInDocument(priorFocusedElem)) {
|
||||
if (ReactInputSelection.hasSelectionCapabilities(priorFocusedElem)) {
|
||||
ReactInputSelection.setSelection(
|
||||
priorFocusedElem,
|
||||
priorSelectionRange
|
||||
);
|
||||
ReactInputSelection.setSelection(priorFocusedElem, priorSelectionRange);
|
||||
}
|
||||
focusNode(priorFocusedElem);
|
||||
}
|
||||
@@ -85,8 +80,10 @@ var ReactInputSelection = {
|
||||
start: input.selectionStart,
|
||||
end: input.selectionEnd,
|
||||
};
|
||||
} else if (document.selection &&
|
||||
(input.nodeName && input.nodeName.toLowerCase() === 'input')) {
|
||||
} else if (
|
||||
document.selection &&
|
||||
(input.nodeName && input.nodeName.toLowerCase() === 'input')
|
||||
) {
|
||||
// IE8 input.
|
||||
var range = document.selection.createRange();
|
||||
// There can only be one selection per document in IE, so it must
|
||||
@@ -121,8 +118,10 @@ var ReactInputSelection = {
|
||||
if ('selectionStart' in input) {
|
||||
input.selectionStart = start;
|
||||
input.selectionEnd = Math.min(end, input.value.length);
|
||||
} else if (document.selection &&
|
||||
(input.nodeName && input.nodeName.toLowerCase() === 'input')) {
|
||||
} else if (
|
||||
document.selection &&
|
||||
(input.nodeName && input.nodeName.toLowerCase() === 'input')
|
||||
) {
|
||||
var range = input.createTextRange();
|
||||
range.collapse(true);
|
||||
range.moveStart('character', start);
|
||||
|
||||
@@ -80,7 +80,7 @@ function internalGetID(node) {
|
||||
// If node is something like a window, document, or text node, none of
|
||||
// which support attributes or a .getAttribute method, gracefully return
|
||||
// the empty string, as if the attribute were missing.
|
||||
return node.getAttribute && node.getAttribute(ATTR_NAME) || '';
|
||||
return (node.getAttribute && node.getAttribute(ATTR_NAME)) || '';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,16 +96,15 @@ function mountComponentIntoNode(
|
||||
container,
|
||||
transaction,
|
||||
shouldReuseMarkup,
|
||||
context
|
||||
context,
|
||||
) {
|
||||
var markerName;
|
||||
if (ReactFeatureFlags.logTopLevelRenders) {
|
||||
var wrappedElement = wrapperInstance._currentElement.props.child;
|
||||
var type = wrappedElement.type;
|
||||
markerName = 'React mount: ' + (
|
||||
typeof type === 'string' ? type :
|
||||
type.displayName || type.name
|
||||
);
|
||||
markerName =
|
||||
'React mount: ' +
|
||||
(typeof type === 'string' ? type : type.displayName || type.name);
|
||||
console.time(markerName);
|
||||
}
|
||||
|
||||
@@ -115,7 +114,7 @@ function mountComponentIntoNode(
|
||||
null,
|
||||
ReactDOMContainerInfo(wrapperInstance, container),
|
||||
context,
|
||||
0 /* parentDebugID */
|
||||
0 /* parentDebugID */,
|
||||
);
|
||||
|
||||
if (markerName) {
|
||||
@@ -128,7 +127,7 @@ function mountComponentIntoNode(
|
||||
container,
|
||||
wrapperInstance,
|
||||
shouldReuseMarkup,
|
||||
transaction
|
||||
transaction,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -143,11 +142,11 @@ function batchedMountComponentIntoNode(
|
||||
componentInstance,
|
||||
container,
|
||||
shouldReuseMarkup,
|
||||
context
|
||||
context,
|
||||
) {
|
||||
var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(
|
||||
/* useCreateElement */
|
||||
!shouldReuseMarkup && ReactDOMFeatureFlags.useCreateElement
|
||||
!shouldReuseMarkup && ReactDOMFeatureFlags.useCreateElement,
|
||||
);
|
||||
transaction.perform(
|
||||
mountComponentIntoNode,
|
||||
@@ -156,7 +155,7 @@ function batchedMountComponentIntoNode(
|
||||
container,
|
||||
transaction,
|
||||
shouldReuseMarkup,
|
||||
context
|
||||
context,
|
||||
);
|
||||
ReactUpdates.ReactReconcileTransaction.release(transaction);
|
||||
}
|
||||
@@ -217,7 +216,9 @@ function hasNonRootReactChild(container) {
|
||||
*/
|
||||
function nodeIsRenderedByOtherInstance(container) {
|
||||
var rootEl = getReactRootElementInContainer(container);
|
||||
return !!(rootEl && isReactNode(rootEl) && !ReactDOMComponentTree.getInstanceFromNode(rootEl));
|
||||
return !!(rootEl &&
|
||||
isReactNode(rootEl) &&
|
||||
!ReactDOMComponentTree.getInstanceFromNode(rootEl));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,11 +229,10 @@ function nodeIsRenderedByOtherInstance(container) {
|
||||
* @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));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,17 +243,19 @@ function isValidContainer(node) {
|
||||
* @internal
|
||||
*/
|
||||
function isReactNode(node) {
|
||||
return isValidContainer(node) && (node.hasAttribute(ROOT_ATTR_NAME) || node.hasAttribute(ATTR_NAME));
|
||||
return (
|
||||
isValidContainer(node) &&
|
||||
(node.hasAttribute(ROOT_ATTR_NAME) || node.hasAttribute(ATTR_NAME))
|
||||
);
|
||||
}
|
||||
|
||||
function getHostRootInstanceInContainer(container) {
|
||||
var rootEl = getReactRootElementInContainer(container);
|
||||
var prevHostInstance =
|
||||
rootEl && ReactDOMComponentTree.getInstanceFromNode(rootEl);
|
||||
return (
|
||||
prevHostInstance && !prevHostInstance._hostParent ?
|
||||
prevHostInstance : null
|
||||
);
|
||||
return prevHostInstance && !prevHostInstance._hostParent
|
||||
? prevHostInstance
|
||||
: null;
|
||||
}
|
||||
|
||||
function getTopLevelWrapperInContainer(container) {
|
||||
@@ -298,7 +300,6 @@ TopLevelWrapper.isReactTopLevelWrapper = true;
|
||||
* Inside of `container`, the first element rendered is the "reactRoot".
|
||||
*/
|
||||
var ReactMount = {
|
||||
|
||||
TopLevelWrapper: TopLevelWrapper,
|
||||
|
||||
/**
|
||||
@@ -326,13 +327,18 @@ var ReactMount = {
|
||||
* @param {?function} callback function triggered on completion
|
||||
*/
|
||||
_updateRootComponent: function(
|
||||
prevComponent,
|
||||
nextElement,
|
||||
nextContext,
|
||||
container,
|
||||
callback) {
|
||||
prevComponent,
|
||||
nextElement,
|
||||
nextContext,
|
||||
container,
|
||||
callback,
|
||||
) {
|
||||
ReactMount.scrollMonitor(container, function() {
|
||||
ReactUpdateQueue.enqueueElementInternal(prevComponent, nextElement, nextContext);
|
||||
ReactUpdateQueue.enqueueElementInternal(
|
||||
prevComponent,
|
||||
nextElement,
|
||||
nextContext,
|
||||
);
|
||||
if (callback) {
|
||||
ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback);
|
||||
}
|
||||
@@ -353,7 +359,7 @@ var ReactMount = {
|
||||
nextElement,
|
||||
container,
|
||||
shouldReuseMarkup,
|
||||
context
|
||||
context,
|
||||
) {
|
||||
// Various parts of our code (such as ReactCompositeComponent's
|
||||
// _renderValidatedComponent) assume that calls to render aren't nested;
|
||||
@@ -361,16 +367,16 @@ var ReactMount = {
|
||||
warning(
|
||||
ReactCurrentOwner.current == null,
|
||||
'_renderNewRootComponent(): 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. Check the render method of %s.',
|
||||
ReactCurrentOwner.current && ReactCurrentOwner.current.getName() ||
|
||||
'ReactCompositeComponent'
|
||||
'of props and state; triggering nested component updates from ' +
|
||||
'render is not allowed. If necessary, trigger nested updates in ' +
|
||||
'componentDidUpdate. Check the render method of %s.',
|
||||
(ReactCurrentOwner.current && ReactCurrentOwner.current.getName()) ||
|
||||
'ReactCompositeComponent',
|
||||
);
|
||||
|
||||
invariant(
|
||||
isValidContainer(container),
|
||||
'_registerComponent(...): Target container is not a DOM element.'
|
||||
'_registerComponent(...): Target container is not a DOM element.',
|
||||
);
|
||||
|
||||
ReactBrowserEventEmitter.ensureScrollValueMonitoring();
|
||||
@@ -385,7 +391,7 @@ var ReactMount = {
|
||||
componentInstance,
|
||||
container,
|
||||
shouldReuseMarkup,
|
||||
context
|
||||
context,
|
||||
);
|
||||
|
||||
var wrapperID = componentInstance._instance.rootID;
|
||||
@@ -407,53 +413,61 @@ var ReactMount = {
|
||||
* @param {?function} callback function triggered on completion
|
||||
* @return {ReactComponent} Component instance rendered in `container`.
|
||||
*/
|
||||
renderSubtreeIntoContainer: function(parentComponent, nextElement, container, callback) {
|
||||
renderSubtreeIntoContainer: function(
|
||||
parentComponent,
|
||||
nextElement,
|
||||
container,
|
||||
callback,
|
||||
) {
|
||||
invariant(
|
||||
parentComponent != null && ReactInstanceMap.has(parentComponent),
|
||||
'parentComponent must be a valid React Component'
|
||||
'parentComponent must be a valid React Component',
|
||||
);
|
||||
return ReactMount._renderSubtreeIntoContainer(
|
||||
parentComponent,
|
||||
nextElement,
|
||||
container,
|
||||
callback
|
||||
callback,
|
||||
);
|
||||
},
|
||||
|
||||
_renderSubtreeIntoContainer: function(parentComponent, nextElement, container, callback) {
|
||||
_renderSubtreeIntoContainer: function(
|
||||
parentComponent,
|
||||
nextElement,
|
||||
container,
|
||||
callback,
|
||||
) {
|
||||
ReactUpdateQueue.validateCallback(callback, 'ReactDOM.render');
|
||||
invariant(
|
||||
React.isValidElement(nextElement),
|
||||
'ReactDOM.render(): Invalid component element.%s',
|
||||
(
|
||||
typeof nextElement === 'string' ?
|
||||
' Instead of passing a string like \'div\', pass ' +
|
||||
'React.createElement(\'div\') or <div />.' :
|
||||
typeof nextElement === 'function' ?
|
||||
' Instead of passing a class like Foo, pass ' +
|
||||
'React.createElement(Foo) or <Foo />.' :
|
||||
// Check if it quacks like an element
|
||||
nextElement != null && nextElement.props !== undefined ?
|
||||
' This may be caused by unintentionally loading two independent ' +
|
||||
'copies of React.' :
|
||||
''
|
||||
)
|
||||
typeof nextElement === 'string'
|
||||
? " Instead of passing a string like 'div', pass " +
|
||||
"React.createElement('div') or <div />."
|
||||
: typeof nextElement === 'function'
|
||||
? ' Instead of passing a class like Foo, pass ' +
|
||||
'React.createElement(Foo) or <Foo />.'
|
||||
: // Check if it quacks like an element
|
||||
nextElement != null && nextElement.props !== undefined
|
||||
? ' This may be caused by unintentionally loading two independent ' +
|
||||
'copies of React.'
|
||||
: '',
|
||||
);
|
||||
|
||||
warning(
|
||||
!container || !container.tagName ||
|
||||
container.tagName.toUpperCase() !== 'BODY',
|
||||
!container ||
|
||||
!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.',
|
||||
);
|
||||
|
||||
var nextWrappedElement = React.createElement(
|
||||
TopLevelWrapper,
|
||||
{ child: nextElement }
|
||||
);
|
||||
var nextWrappedElement = React.createElement(TopLevelWrapper, {
|
||||
child: nextElement,
|
||||
});
|
||||
|
||||
var nextContext;
|
||||
if (parentComponent) {
|
||||
@@ -470,15 +484,17 @@ var ReactMount = {
|
||||
var prevElement = prevWrappedElement.props.child;
|
||||
if (shouldUpdateReactComponent(prevElement, nextElement)) {
|
||||
var publicInst = prevComponent._renderedComponent.getPublicInstance();
|
||||
var updatedCallback = callback && function() {
|
||||
callback.call(publicInst);
|
||||
};
|
||||
var updatedCallback =
|
||||
callback &&
|
||||
function() {
|
||||
callback.call(publicInst);
|
||||
};
|
||||
ReactMount._updateRootComponent(
|
||||
prevComponent,
|
||||
nextWrappedElement,
|
||||
nextContext,
|
||||
container,
|
||||
updatedCallback
|
||||
updatedCallback,
|
||||
);
|
||||
return publicInst;
|
||||
} else {
|
||||
@@ -495,9 +511,9 @@ var ReactMount = {
|
||||
warning(
|
||||
!containerHasNonRootReactChild,
|
||||
'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.',
|
||||
);
|
||||
|
||||
if (!containerHasReactMarkup || reactRootElement.nextSibling) {
|
||||
@@ -507,8 +523,8 @@ var ReactMount = {
|
||||
warning(
|
||||
false,
|
||||
'render(): Target node has markup rendered by React, but there ' +
|
||||
'are unrelated nodes as well. This is most commonly caused by ' +
|
||||
'white-space inserted around server-rendered markup.'
|
||||
'are unrelated nodes as well. This is most commonly caused by ' +
|
||||
'white-space inserted around server-rendered markup.',
|
||||
);
|
||||
break;
|
||||
}
|
||||
@@ -525,7 +541,7 @@ var ReactMount = {
|
||||
nextWrappedElement,
|
||||
container,
|
||||
shouldReuseMarkup,
|
||||
nextContext
|
||||
nextContext,
|
||||
)._renderedComponent.getPublicInstance();
|
||||
if (callback) {
|
||||
callback.call(component);
|
||||
@@ -533,7 +549,6 @@ var ReactMount = {
|
||||
return component;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Renders a React component into the DOM in the supplied `container`.
|
||||
* See https://facebook.github.io/react/docs/top-level-api.html#reactdom.render
|
||||
@@ -548,7 +563,12 @@ var ReactMount = {
|
||||
* @return {ReactComponent} Component instance rendered in `container`.
|
||||
*/
|
||||
render: function(nextElement, container, callback) {
|
||||
return ReactMount._renderSubtreeIntoContainer(null, nextElement, container, callback);
|
||||
return ReactMount._renderSubtreeIntoContainer(
|
||||
null,
|
||||
nextElement,
|
||||
container,
|
||||
callback,
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -567,23 +587,23 @@ var ReactMount = {
|
||||
warning(
|
||||
ReactCurrentOwner.current == null,
|
||||
'unmountComponentAtNode(): 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. Check the render method of %s.',
|
||||
ReactCurrentOwner.current && ReactCurrentOwner.current.getName() ||
|
||||
'ReactCompositeComponent'
|
||||
'of props and state; triggering nested component updates from render ' +
|
||||
'is not allowed. If necessary, trigger nested updates in ' +
|
||||
'componentDidUpdate. Check the render method of %s.',
|
||||
(ReactCurrentOwner.current && ReactCurrentOwner.current.getName()) ||
|
||||
'ReactCompositeComponent',
|
||||
);
|
||||
|
||||
invariant(
|
||||
isValidContainer(container),
|
||||
'unmountComponentAtNode(...): Target container is not a DOM element.'
|
||||
'unmountComponentAtNode(...): Target container is not a DOM element.',
|
||||
);
|
||||
|
||||
if (__DEV__) {
|
||||
warning(
|
||||
!nodeIsRenderedByOtherInstance(container),
|
||||
'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.',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -600,15 +620,13 @@ var ReactMount = {
|
||||
if (__DEV__) {
|
||||
warning(
|
||||
!containerHasNonRootReactChild,
|
||||
'unmountComponentAtNode(): The node you\'re attempting to unmount ' +
|
||||
'was rendered by React and is not a top-level container. %s',
|
||||
(
|
||||
isContainerReactRoot ?
|
||||
'You may have accidentally passed in a React root node instead ' +
|
||||
'of its container.' :
|
||||
'Instead, have the parent component update its state and ' +
|
||||
'rerender in order to remove this component.'
|
||||
)
|
||||
"unmountComponentAtNode(): The node you're attempting to unmount " +
|
||||
'was rendered by React and is not a top-level container. %s',
|
||||
isContainerReactRoot
|
||||
? 'You may have accidentally passed in a React root node instead ' +
|
||||
'of its container.'
|
||||
: 'Instead, have the parent component update its state and ' +
|
||||
'rerender in order to remove this component.',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -619,7 +637,7 @@ var ReactMount = {
|
||||
unmountComponentFromNode,
|
||||
prevComponent,
|
||||
container,
|
||||
false
|
||||
false,
|
||||
);
|
||||
return true;
|
||||
},
|
||||
@@ -629,11 +647,11 @@ var ReactMount = {
|
||||
container,
|
||||
instance,
|
||||
shouldReuseMarkup,
|
||||
transaction
|
||||
transaction,
|
||||
) {
|
||||
invariant(
|
||||
isValidContainer(container),
|
||||
'mountComponentIntoNode(...): Target container is not valid.'
|
||||
'mountComponentIntoNode(...): Target container is not valid.',
|
||||
);
|
||||
|
||||
if (shouldReuseMarkup) {
|
||||
@@ -643,14 +661,14 @@ var ReactMount = {
|
||||
return;
|
||||
} else {
|
||||
var checksum = rootElement.getAttribute(
|
||||
ReactMarkupChecksum.CHECKSUM_ATTR_NAME
|
||||
ReactMarkupChecksum.CHECKSUM_ATTR_NAME,
|
||||
);
|
||||
rootElement.removeAttribute(ReactMarkupChecksum.CHECKSUM_ATTR_NAME);
|
||||
|
||||
var rootMarkup = rootElement.outerHTML;
|
||||
rootElement.setAttribute(
|
||||
ReactMarkupChecksum.CHECKSUM_ATTR_NAME,
|
||||
checksum
|
||||
checksum,
|
||||
);
|
||||
|
||||
var normalizedMarkup = markup;
|
||||
@@ -668,41 +686,44 @@ var ReactMount = {
|
||||
normalizer = document.createElement('iframe');
|
||||
document.body.appendChild(normalizer);
|
||||
normalizer.contentDocument.write(markup);
|
||||
normalizedMarkup = normalizer.contentDocument.documentElement.outerHTML;
|
||||
normalizedMarkup =
|
||||
normalizer.contentDocument.documentElement.outerHTML;
|
||||
document.body.removeChild(normalizer);
|
||||
}
|
||||
}
|
||||
|
||||
var diffIndex = firstDifferenceIndex(normalizedMarkup, rootMarkup);
|
||||
var difference = ' (client) ' +
|
||||
var difference =
|
||||
' (client) ' +
|
||||
normalizedMarkup.substring(diffIndex - 20, diffIndex + 20) +
|
||||
'\n (server) ' + rootMarkup.substring(diffIndex - 20, diffIndex + 20);
|
||||
'\n (server) ' +
|
||||
rootMarkup.substring(diffIndex - 20, diffIndex + 20);
|
||||
|
||||
invariant(
|
||||
container.nodeType !== DOC_NODE_TYPE,
|
||||
'You\'re trying to render a component to the document using ' +
|
||||
'server rendering but the checksum was invalid. This usually ' +
|
||||
'means you rendered a different component type or props on ' +
|
||||
'the client from the one on the server, or your render() ' +
|
||||
'methods are impure. React cannot handle this case due to ' +
|
||||
'cross-browser quirks by rendering at the document root. You ' +
|
||||
'should look for environment dependent code in your components ' +
|
||||
'and ensure the props are the same client and server side:\n%s',
|
||||
difference
|
||||
"You're trying to render a component to the document using " +
|
||||
'server rendering but the checksum was invalid. This usually ' +
|
||||
'means you rendered a different component type or props on ' +
|
||||
'the client from the one on the server, or your render() ' +
|
||||
'methods are impure. React cannot handle this case due to ' +
|
||||
'cross-browser quirks by rendering at the document root. You ' +
|
||||
'should look for environment dependent code in your components ' +
|
||||
'and ensure the props are the same client and server side:\n%s',
|
||||
difference,
|
||||
);
|
||||
|
||||
if (__DEV__) {
|
||||
warning(
|
||||
false,
|
||||
'React attempted to reuse markup in a container but the ' +
|
||||
'checksum was invalid. This generally means that you are ' +
|
||||
'using server rendering and the markup generated on the ' +
|
||||
'server was not what the client was expecting. React injected ' +
|
||||
'new markup to compensate which works but you have lost many ' +
|
||||
'of the benefits of server rendering. Instead, figure out ' +
|
||||
'why the markup being generated is different on the client ' +
|
||||
'or server:\n%s',
|
||||
difference
|
||||
'checksum was invalid. This generally means that you are ' +
|
||||
'using server rendering and the markup generated on the ' +
|
||||
'server was not what the client was expecting. React injected ' +
|
||||
'new markup to compensate which works but you have lost many ' +
|
||||
'of the benefits of server rendering. Instead, figure out ' +
|
||||
'why the markup being generated is different on the client ' +
|
||||
'or server:\n%s',
|
||||
difference,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -710,10 +731,10 @@ var ReactMount = {
|
||||
|
||||
invariant(
|
||||
container.nodeType !== DOC_NODE_TYPE,
|
||||
'You\'re trying to render a component to the document but ' +
|
||||
'you didn\'t use server rendering. We can\'t do this ' +
|
||||
"You're trying to render a component to the document but " +
|
||||
"you didn't use server rendering. We can't do this " +
|
||||
'without using server rendering due to cross-browser quirks. ' +
|
||||
'See ReactDOMServer.renderToString() for server rendering.'
|
||||
'See ReactDOMServer.renderToString() for server rendering.',
|
||||
);
|
||||
|
||||
if (transaction.useCreateElement) {
|
||||
@@ -727,7 +748,9 @@ var ReactMount = {
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
var hostNode = ReactDOMComponentTree.getInstanceFromNode(container.firstChild);
|
||||
var hostNode = ReactDOMComponentTree.getInstanceFromNode(
|
||||
container.firstChild,
|
||||
);
|
||||
if (hostNode._debugID !== 0) {
|
||||
ReactInstrumentation.debugTool.onHostOperation({
|
||||
instanceID: hostNode._debugID,
|
||||
|
||||
@@ -19,7 +19,6 @@ var ReactInstrumentation = require('ReactInstrumentation');
|
||||
var Transaction = require('Transaction');
|
||||
var ReactUpdateQueue = require('ReactUpdateQueue');
|
||||
|
||||
|
||||
/**
|
||||
* Ensures that, when possible, the selection range (currently selected text
|
||||
* input) is not disturbed by performing the transaction.
|
||||
@@ -174,7 +173,6 @@ var Mixin = {
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
Object.assign(ReactReconcileTransaction.prototype, Transaction, Mixin);
|
||||
|
||||
PooledClass.addPoolingTo(ReactReconcileTransaction);
|
||||
|
||||
@@ -54,7 +54,6 @@ function getInternal(node) {
|
||||
return ReactDOMComponentTree.getInstanceFromNode(node);
|
||||
}
|
||||
|
||||
|
||||
describe('ReactBrowserEventEmitter', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModuleRegistry();
|
||||
@@ -69,11 +68,11 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
TapEventPlugin = require('TapEventPlugin');
|
||||
|
||||
ReactTestUtils.renderIntoDocument(
|
||||
<div ref={(c) => GRANDPARENT = c}>
|
||||
<div ref={(c) => PARENT = c}>
|
||||
<div ref={(c) => CHILD = c} />
|
||||
<div ref={c => (GRANDPARENT = c)}>
|
||||
<div ref={c => (PARENT = c)}>
|
||||
<div ref={c => (CHILD = c)} />
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
|
||||
idCallOrder = [];
|
||||
@@ -108,34 +107,31 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
expect(LISTENER.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
it(
|
||||
'should not invoke handlers if ReactBrowserEventEmitter is disabled',
|
||||
() => {
|
||||
registerSimpleTestHandler();
|
||||
ReactBrowserEventEmitter.setEnabled(false);
|
||||
ReactTestUtils.SimulateNative.click(CHILD);
|
||||
expect(LISTENER.mock.calls.length).toBe(0);
|
||||
ReactBrowserEventEmitter.setEnabled(true);
|
||||
ReactTestUtils.SimulateNative.click(CHILD);
|
||||
expect(LISTENER.mock.calls.length).toBe(1);
|
||||
}
|
||||
);
|
||||
it('should not invoke handlers if ReactBrowserEventEmitter is disabled', () => {
|
||||
registerSimpleTestHandler();
|
||||
ReactBrowserEventEmitter.setEnabled(false);
|
||||
ReactTestUtils.SimulateNative.click(CHILD);
|
||||
expect(LISTENER.mock.calls.length).toBe(0);
|
||||
ReactBrowserEventEmitter.setEnabled(true);
|
||||
ReactTestUtils.SimulateNative.click(CHILD);
|
||||
expect(LISTENER.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should bubble simply', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(CHILD))
|
||||
recordID.bind(null, getInternal(CHILD)),
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(PARENT),
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(PARENT))
|
||||
recordID.bind(null, getInternal(PARENT)),
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(GRANDPARENT),
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(GRANDPARENT))
|
||||
recordID.bind(null, getInternal(GRANDPARENT)),
|
||||
);
|
||||
ReactTestUtils.Simulate.click(CHILD);
|
||||
expect(idCallOrder.length).toBe(3);
|
||||
@@ -148,20 +144,16 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(CHILD))
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(PARENT),
|
||||
ON_CLICK_KEY,
|
||||
function() {
|
||||
recordID(getInternal(PARENT));
|
||||
throw new Error('Handler interrupted');
|
||||
}
|
||||
recordID.bind(null, getInternal(CHILD)),
|
||||
);
|
||||
EventPluginHub.putListener(getInternal(PARENT), ON_CLICK_KEY, function() {
|
||||
recordID(getInternal(PARENT));
|
||||
throw new Error('Handler interrupted');
|
||||
});
|
||||
EventPluginHub.putListener(
|
||||
getInternal(GRANDPARENT),
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(GRANDPARENT))
|
||||
recordID.bind(null, getInternal(GRANDPARENT)),
|
||||
);
|
||||
expect(function() {
|
||||
ReactTestUtils.Simulate.click(CHILD);
|
||||
@@ -173,30 +165,24 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
});
|
||||
|
||||
it('should set currentTarget', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
ON_CLICK_KEY,
|
||||
function(event) {
|
||||
recordID(getInternal(CHILD));
|
||||
expect(event.currentTarget).toBe(CHILD);
|
||||
}
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(PARENT),
|
||||
ON_CLICK_KEY,
|
||||
function(event) {
|
||||
recordID(getInternal(PARENT));
|
||||
expect(event.currentTarget).toBe(PARENT);
|
||||
}
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(GRANDPARENT),
|
||||
ON_CLICK_KEY,
|
||||
function(event) {
|
||||
recordID(getInternal(GRANDPARENT));
|
||||
expect(event.currentTarget).toBe(GRANDPARENT);
|
||||
}
|
||||
);
|
||||
EventPluginHub.putListener(getInternal(CHILD), ON_CLICK_KEY, function(
|
||||
event,
|
||||
) {
|
||||
recordID(getInternal(CHILD));
|
||||
expect(event.currentTarget).toBe(CHILD);
|
||||
});
|
||||
EventPluginHub.putListener(getInternal(PARENT), ON_CLICK_KEY, function(
|
||||
event,
|
||||
) {
|
||||
recordID(getInternal(PARENT));
|
||||
expect(event.currentTarget).toBe(PARENT);
|
||||
});
|
||||
EventPluginHub.putListener(getInternal(GRANDPARENT), ON_CLICK_KEY, function(
|
||||
event,
|
||||
) {
|
||||
recordID(getInternal(GRANDPARENT));
|
||||
expect(event.currentTarget).toBe(GRANDPARENT);
|
||||
});
|
||||
ReactTestUtils.Simulate.click(CHILD);
|
||||
expect(idCallOrder.length).toBe(3);
|
||||
expect(idCallOrder[0]).toBe(getInternal(CHILD));
|
||||
@@ -208,17 +194,17 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(CHILD))
|
||||
recordID.bind(null, getInternal(CHILD)),
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(PARENT),
|
||||
ON_CLICK_KEY,
|
||||
recordIDAndStopPropagation.bind(null, getInternal(PARENT))
|
||||
recordIDAndStopPropagation.bind(null, getInternal(PARENT)),
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(GRANDPARENT),
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(GRANDPARENT))
|
||||
recordID.bind(null, getInternal(GRANDPARENT)),
|
||||
);
|
||||
ReactTestUtils.Simulate.click(CHILD);
|
||||
expect(idCallOrder.length).toBe(2);
|
||||
@@ -230,17 +216,17 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
ON_CLICK_KEY,
|
||||
recordIDAndStopPropagation.bind(null, getInternal(CHILD))
|
||||
recordIDAndStopPropagation.bind(null, getInternal(CHILD)),
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(PARENT),
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(PARENT))
|
||||
recordID.bind(null, getInternal(PARENT)),
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(GRANDPARENT),
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(GRANDPARENT))
|
||||
recordID.bind(null, getInternal(GRANDPARENT)),
|
||||
);
|
||||
ReactTestUtils.Simulate.click(CHILD);
|
||||
expect(idCallOrder.length).toBe(1);
|
||||
@@ -251,17 +237,17 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
ON_CLICK_KEY,
|
||||
recordIDAndReturnFalse.bind(null, getInternal(CHILD))
|
||||
recordIDAndReturnFalse.bind(null, getInternal(CHILD)),
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(PARENT),
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(PARENT))
|
||||
recordID.bind(null, getInternal(PARENT)),
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(GRANDPARENT),
|
||||
ON_CLICK_KEY,
|
||||
recordID.bind(null, getInternal(GRANDPARENT))
|
||||
recordID.bind(null, getInternal(GRANDPARENT)),
|
||||
);
|
||||
spyOn(console, 'error');
|
||||
ReactTestUtils.Simulate.click(CHILD);
|
||||
@@ -289,12 +275,12 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
ON_CLICK_KEY,
|
||||
handleChildClick
|
||||
handleChildClick,
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(PARENT),
|
||||
ON_CLICK_KEY,
|
||||
handleParentClick
|
||||
handleParentClick,
|
||||
);
|
||||
ReactTestUtils.Simulate.click(CHILD);
|
||||
expect(handleParentClick.mock.calls.length).toBe(1);
|
||||
@@ -306,13 +292,13 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(PARENT),
|
||||
ON_CLICK_KEY,
|
||||
handleParentClick
|
||||
handleParentClick,
|
||||
);
|
||||
};
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
ON_CLICK_KEY,
|
||||
handleChildClick
|
||||
handleChildClick,
|
||||
);
|
||||
ReactTestUtils.Simulate.click(CHILD);
|
||||
expect(handleParentClick.mock.calls.length).toBe(0);
|
||||
@@ -322,7 +308,7 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
ON_MOUSE_ENTER_KEY,
|
||||
recordID.bind(null, getInternal(CHILD))
|
||||
recordID.bind(null, getInternal(CHILD)),
|
||||
);
|
||||
ReactTestUtils.Simulate.mouseEnter(CHILD);
|
||||
expect(idCallOrder.length).toBe(1);
|
||||
@@ -333,15 +319,15 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
ON_TOUCH_TAP_KEY,
|
||||
recordID.bind(null, getInternal(CHILD))
|
||||
recordID.bind(null, getInternal(CHILD)),
|
||||
);
|
||||
ReactTestUtils.SimulateNative.touchStart(
|
||||
CHILD,
|
||||
ReactTestUtils.nativeTouchData(0, 0)
|
||||
ReactTestUtils.nativeTouchData(0, 0),
|
||||
);
|
||||
ReactTestUtils.SimulateNative.touchEnd(
|
||||
CHILD,
|
||||
ReactTestUtils.nativeTouchData(0, 0)
|
||||
ReactTestUtils.nativeTouchData(0, 0),
|
||||
);
|
||||
expect(idCallOrder.length).toBe(1);
|
||||
expect(idCallOrder[0]).toBe(getInternal(CHILD));
|
||||
@@ -351,15 +337,15 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
ON_TOUCH_TAP_KEY,
|
||||
recordID.bind(null, getInternal(CHILD))
|
||||
recordID.bind(null, getInternal(CHILD)),
|
||||
);
|
||||
ReactTestUtils.SimulateNative.touchStart(
|
||||
CHILD,
|
||||
ReactTestUtils.nativeTouchData(0, 0)
|
||||
ReactTestUtils.nativeTouchData(0, 0),
|
||||
);
|
||||
ReactTestUtils.SimulateNative.touchEnd(
|
||||
CHILD,
|
||||
ReactTestUtils.nativeTouchData(0, tapMoveThreshold - 1)
|
||||
ReactTestUtils.nativeTouchData(0, tapMoveThreshold - 1),
|
||||
);
|
||||
expect(idCallOrder.length).toBe(1);
|
||||
expect(idCallOrder[0]).toBe(getInternal(CHILD));
|
||||
@@ -369,15 +355,15 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
ON_TOUCH_TAP_KEY,
|
||||
recordID.bind(null, getInternal(CHILD))
|
||||
recordID.bind(null, getInternal(CHILD)),
|
||||
);
|
||||
ReactTestUtils.SimulateNative.touchStart(
|
||||
CHILD,
|
||||
ReactTestUtils.nativeTouchData(0, 0)
|
||||
ReactTestUtils.nativeTouchData(0, 0),
|
||||
);
|
||||
ReactTestUtils.SimulateNative.touchEnd(
|
||||
CHILD,
|
||||
ReactTestUtils.nativeTouchData(0, tapMoveThreshold + 1)
|
||||
ReactTestUtils.nativeTouchData(0, tapMoveThreshold + 1),
|
||||
);
|
||||
expect(idCallOrder.length).toBe(0);
|
||||
});
|
||||
@@ -426,25 +412,25 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
EventPluginHub.putListener(
|
||||
getInternal(CHILD),
|
||||
ON_TOUCH_TAP_KEY,
|
||||
recordID.bind(null, getInternal(CHILD))
|
||||
recordID.bind(null, getInternal(CHILD)),
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(PARENT),
|
||||
ON_TOUCH_TAP_KEY,
|
||||
recordID.bind(null, getInternal(PARENT))
|
||||
recordID.bind(null, getInternal(PARENT)),
|
||||
);
|
||||
EventPluginHub.putListener(
|
||||
getInternal(GRANDPARENT),
|
||||
ON_TOUCH_TAP_KEY,
|
||||
recordID.bind(null, getInternal(GRANDPARENT))
|
||||
recordID.bind(null, getInternal(GRANDPARENT)),
|
||||
);
|
||||
ReactTestUtils.SimulateNative.touchStart(
|
||||
CHILD,
|
||||
ReactTestUtils.nativeTouchData(0, 0)
|
||||
ReactTestUtils.nativeTouchData(0, 0),
|
||||
);
|
||||
ReactTestUtils.SimulateNative.touchEnd(
|
||||
CHILD,
|
||||
ReactTestUtils.nativeTouchData(0, 0)
|
||||
ReactTestUtils.nativeTouchData(0, 0),
|
||||
);
|
||||
expect(idCallOrder.length).toBe(3);
|
||||
expect(idCallOrder[0]).toBe(getInternal(CHILD));
|
||||
@@ -467,5 +453,4 @@ describe('ReactBrowserEventEmitter', () => {
|
||||
document.createEvent = originalCreateEvent;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -53,16 +53,14 @@ describe('ReactDOM', () => {
|
||||
});
|
||||
|
||||
it('should allow children to be passed as an argument', () => {
|
||||
var argDiv = ReactTestUtils.renderIntoDocument(
|
||||
div(null, 'child')
|
||||
);
|
||||
var argDiv = ReactTestUtils.renderIntoDocument(div(null, 'child'));
|
||||
var argNode = ReactDOM.findDOMNode(argDiv);
|
||||
expect(argNode.innerHTML).toBe('child');
|
||||
});
|
||||
|
||||
it('should overwrite props.children with children argument', () => {
|
||||
var conflictDiv = ReactTestUtils.renderIntoDocument(
|
||||
div({children: 'fakechild'}, 'child')
|
||||
div({children: 'fakechild'}, 'child'),
|
||||
);
|
||||
var conflictNode = ReactDOM.findDOMNode(conflictDiv);
|
||||
expect(conflictNode.innerHTML).toBe('child');
|
||||
@@ -77,45 +75,45 @@ describe('ReactDOM', () => {
|
||||
<div>
|
||||
<div key="theDog" className="dog" />,
|
||||
<div key="theBird" className="bird" />
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
// Warm the cache with theDog
|
||||
myDiv = ReactTestUtils.renderIntoDocument(
|
||||
<div>
|
||||
<div key="theDog" className="dogbeforedelete" />,
|
||||
<div key="theBird" className="bird" />,
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
// Remove theDog - this should purge the cache
|
||||
myDiv = ReactTestUtils.renderIntoDocument(
|
||||
<div>
|
||||
<div key="theBird" className="bird" />,
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
// Now, put theDog back. It's now a different DOM node.
|
||||
myDiv = ReactTestUtils.renderIntoDocument(
|
||||
<div>
|
||||
<div key="theDog" className="dog" />,
|
||||
<div key="theBird" className="bird" />,
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
// Change the className of theDog. It will use the same element
|
||||
myDiv = ReactTestUtils.renderIntoDocument(
|
||||
<div>
|
||||
<div key="theDog" className="bigdog" />,
|
||||
<div key="theBird" className="bird" />,
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
var root = ReactDOM.findDOMNode(myDiv);
|
||||
var dog = root.childNodes[0];
|
||||
expect(dog.className).toBe('bigdog');
|
||||
});
|
||||
|
||||
it('allow React.DOM factories to be called without warnings', () => {
|
||||
spyOn(console, 'error');
|
||||
it('throws warning when React.DOM factories are called', () => {
|
||||
spyOn(console, 'warn');
|
||||
var element = React.DOM.div();
|
||||
expect(element.type).toBe('div');
|
||||
expect(console.error.calls.count()).toBe(0);
|
||||
expect(console.warn.calls.count()).toBe(1);
|
||||
});
|
||||
|
||||
it('throws in render() if the mount callback is not a function', () => {
|
||||
@@ -135,15 +133,15 @@ describe('ReactDOM', () => {
|
||||
var myDiv = document.createElement('div');
|
||||
expect(() => ReactDOM.render(<A />, myDiv, 'no')).toThrowError(
|
||||
'ReactDOM.render(...): Expected the last optional `callback` argument ' +
|
||||
'to be a function. Instead received: string.'
|
||||
'to be a function. Instead received: string.',
|
||||
);
|
||||
expect(() => ReactDOM.render(<A />, myDiv, {})).toThrowError(
|
||||
'ReactDOM.render(...): Expected the last optional `callback` argument ' +
|
||||
'to be a function. Instead received: Object.'
|
||||
'to be a function. Instead received: Object.',
|
||||
);
|
||||
expect(() => ReactDOM.render(<A />, myDiv, new Foo())).toThrowError(
|
||||
'ReactDOM.render(...): Expected the last optional `callback` argument ' +
|
||||
'to be a function. Instead received: Foo (keys: a, b).'
|
||||
'to be a function. Instead received: Foo (keys: a, b).',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -166,15 +164,15 @@ describe('ReactDOM', () => {
|
||||
|
||||
expect(() => ReactDOM.render(<A />, myDiv, 'no')).toThrowError(
|
||||
'ReactDOM.render(...): Expected the last optional `callback` argument ' +
|
||||
'to be a function. Instead received: string.'
|
||||
'to be a function. Instead received: string.',
|
||||
);
|
||||
expect(() => ReactDOM.render(<A />, myDiv, {})).toThrowError(
|
||||
'ReactDOM.render(...): Expected the last optional `callback` argument ' +
|
||||
'to be a function. Instead received: Object.'
|
||||
'to be a function. Instead received: Object.',
|
||||
);
|
||||
expect(() => ReactDOM.render(<A />, myDiv, new Foo())).toThrowError(
|
||||
'ReactDOM.render(...): Expected the last optional `callback` argument ' +
|
||||
'to be a function. Instead received: Foo (keys: a, b).'
|
||||
'to be a function. Instead received: Foo (keys: a, b).',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -88,7 +88,7 @@ describe('ReactDOMComponentTree', () => {
|
||||
|
||||
function renderAndGetClosest(sel) {
|
||||
return ReactDOMComponentTree.getClosestInstanceFromNode(
|
||||
renderAndQuery(sel)
|
||||
renderAndQuery(sel),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -101,11 +101,12 @@ describe('ReactDOMComponentTree', () => {
|
||||
|
||||
// This one's a text component!
|
||||
var root = renderAndQuery(null);
|
||||
var inst = ReactDOMComponentTree.getInstanceFromNode(root.children[0].childNodes[2]);
|
||||
var inst = ReactDOMComponentTree.getInstanceFromNode(
|
||||
root.children[0].childNodes[2],
|
||||
);
|
||||
expect(inst._stringText).toBe('goodbye.');
|
||||
|
||||
expect(renderAndGetClosest('b')._currentElement.type).toBe('main');
|
||||
expect(renderAndGetClosest('img')._currentElement.type).toBe('main');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -23,13 +23,15 @@ describe('ReactDOMIDOperations', () => {
|
||||
var html = '\n \t <span> \n testContent \t </span> \n \t';
|
||||
ReactDOMIDOperations.dangerouslyProcessChildrenUpdates(
|
||||
stubInstance,
|
||||
[{
|
||||
type: 'SET_MARKUP',
|
||||
content: html,
|
||||
fromIndex: null,
|
||||
toIndex: null,
|
||||
}],
|
||||
[]
|
||||
[
|
||||
{
|
||||
type: 'SET_MARKUP',
|
||||
content: html,
|
||||
fromIndex: null,
|
||||
toIndex: null,
|
||||
},
|
||||
],
|
||||
[],
|
||||
);
|
||||
|
||||
expect(stubNode.innerHTML).toBe(html);
|
||||
|
||||
@@ -15,7 +15,6 @@ var React;
|
||||
var ReactDOMServer;
|
||||
|
||||
describe('ReactDOMSVG', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
React = require('React');
|
||||
ReactDOMServer = require('ReactDOMServer');
|
||||
@@ -25,9 +24,8 @@ describe('ReactDOMSVG', () => {
|
||||
var markup = ReactDOMServer.renderToString(
|
||||
<svg>
|
||||
<image xlinkHref="http://i.imgur.com/w7GCRPb.png" />
|
||||
</svg>
|
||||
</svg>,
|
||||
);
|
||||
expect(markup).toContain('xlink:href="http://i.imgur.com/w7GCRPb.png"');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -113,7 +113,11 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
var target = null;
|
||||
var expectedAggregation = [];
|
||||
ReactDOMTreeTraversal.traverseEnterLeave(
|
||||
target, target, argAggregator, ARG, ARG2
|
||||
target,
|
||||
target,
|
||||
argAggregator,
|
||||
ARG,
|
||||
ARG2,
|
||||
);
|
||||
expect(aggregatedArgs).toEqual(expectedAggregation);
|
||||
});
|
||||
@@ -124,7 +128,11 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
var enter = getInst(parent.refs.P_P1_C1.refs.DIV_1);
|
||||
var expectedAggregation = [];
|
||||
ReactDOMTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, argAggregator, ARG, ARG2
|
||||
leave,
|
||||
enter,
|
||||
argAggregator,
|
||||
ARG,
|
||||
ARG2,
|
||||
);
|
||||
expect(aggregatedArgs).toEqual(expectedAggregation);
|
||||
});
|
||||
@@ -139,7 +147,11 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
{node: parent.refs.P_P1_C1.refs.DIV_2, phase: 'captured', arg: ARG2},
|
||||
];
|
||||
ReactDOMTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, argAggregator, ARG, ARG2
|
||||
leave,
|
||||
enter,
|
||||
argAggregator,
|
||||
ARG,
|
||||
ARG2,
|
||||
);
|
||||
expect(aggregatedArgs).toEqual(expectedAggregation);
|
||||
});
|
||||
@@ -152,7 +164,11 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
{node: parent.refs.P_P1_C1.refs.DIV_1, phase: 'bubbled', arg: ARG},
|
||||
];
|
||||
ReactDOMTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, argAggregator, ARG, ARG2
|
||||
leave,
|
||||
enter,
|
||||
argAggregator,
|
||||
ARG,
|
||||
ARG2,
|
||||
);
|
||||
expect(aggregatedArgs).toEqual(expectedAggregation);
|
||||
});
|
||||
@@ -167,7 +183,11 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
{node: parent.refs.P_P1_C1.refs.DIV, phase: 'captured', arg: ARG2},
|
||||
];
|
||||
ReactDOMTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, argAggregator, ARG, ARG2
|
||||
leave,
|
||||
enter,
|
||||
argAggregator,
|
||||
ARG,
|
||||
ARG2,
|
||||
);
|
||||
expect(aggregatedArgs).toEqual(expectedAggregation);
|
||||
});
|
||||
@@ -180,7 +200,11 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
{node: parent.refs.P, phase: 'captured', arg: ARG2},
|
||||
];
|
||||
ReactDOMTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, argAggregator, ARG, ARG2
|
||||
leave,
|
||||
enter,
|
||||
argAggregator,
|
||||
ARG,
|
||||
ARG2,
|
||||
);
|
||||
expect(aggregatedArgs).toEqual(expectedAggregation);
|
||||
});
|
||||
@@ -195,7 +219,11 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
{node: parent.refs.P, phase: 'bubbled', arg: ARG},
|
||||
];
|
||||
ReactDOMTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, argAggregator, ARG, ARG2
|
||||
leave,
|
||||
enter,
|
||||
argAggregator,
|
||||
ARG,
|
||||
ARG2,
|
||||
);
|
||||
expect(aggregatedArgs).toEqual(expectedAggregation);
|
||||
});
|
||||
@@ -210,7 +238,11 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
{node: parent.refs.P, phase: 'bubbled', arg: ARG},
|
||||
];
|
||||
ReactDOMTreeTraversal.traverseEnterLeave(
|
||||
leave, enter, argAggregator, ARG, ARG2
|
||||
leave,
|
||||
enter,
|
||||
argAggregator,
|
||||
ARG,
|
||||
ARG2,
|
||||
);
|
||||
expect(aggregatedArgs).toEqual(expectedAggregation);
|
||||
});
|
||||
@@ -221,7 +253,8 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
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,
|
||||
},
|
||||
@@ -263,11 +296,10 @@ describe('ReactDOMTreeTraversal', () => {
|
||||
var plan = ancestors[i];
|
||||
var firstCommon = ReactDOMTreeTraversal.getLowestCommonAncestor(
|
||||
getInst(plan.one),
|
||||
getInst(plan.two)
|
||||
getInst(plan.two),
|
||||
);
|
||||
expect(firstCommon).toBe(getInst(plan.com));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -32,7 +32,7 @@ describe('ReactEventIndependence', () => {
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: '<button data-reactid=".z">click me</div>',
|
||||
}}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
ReactTestUtils.SimulateNative.click(div.firstChild);
|
||||
expect(clicks).toBe(1);
|
||||
@@ -44,7 +44,7 @@ describe('ReactEventIndependence', () => {
|
||||
outer.setAttribute('data-reactid', '.z');
|
||||
var inner = ReactDOM.render(
|
||||
<button onClick={() => clicks++}>click me</button>,
|
||||
outer
|
||||
outer,
|
||||
);
|
||||
ReactTestUtils.SimulateNative.click(inner);
|
||||
expect(clicks).toBe(1);
|
||||
@@ -55,7 +55,7 @@ describe('ReactEventIndependence', () => {
|
||||
var container = document.createElement('div');
|
||||
var button = ReactDOM.render(
|
||||
<button onClick={() => clicks++}>click me</button>,
|
||||
container
|
||||
container,
|
||||
);
|
||||
|
||||
// Now we unmount the component, as if caused by a non-React event handler
|
||||
@@ -66,5 +66,4 @@ describe('ReactEventIndependence', () => {
|
||||
// Since the tree is unmounted, we don't dispatch the click event.
|
||||
expect(clicks).toBe(0);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
|
||||
var EVENT_TARGET_PARAM = 1;
|
||||
|
||||
describe('ReactEventListener', () => {
|
||||
@@ -38,19 +37,16 @@ describe('ReactEventListener', () => {
|
||||
var otherNode = document.createElement('h1');
|
||||
var component = ReactDOM.render(<div />, document.createElement('div'));
|
||||
expect(handleTopLevel.mock.calls.length).toBe(0);
|
||||
ReactEventListener.dispatchEvent(
|
||||
'topMouseOut',
|
||||
{
|
||||
type: 'mouseout',
|
||||
fromElement: otherNode,
|
||||
target: otherNode,
|
||||
srcElement: otherNode,
|
||||
toElement: ReactDOM.findDOMNode(component),
|
||||
relatedTarget: ReactDOM.findDOMNode(component),
|
||||
view: window,
|
||||
path: [otherNode, otherNode],
|
||||
},
|
||||
);
|
||||
ReactEventListener.dispatchEvent('topMouseOut', {
|
||||
type: 'mouseout',
|
||||
fromElement: otherNode,
|
||||
target: otherNode,
|
||||
srcElement: otherNode,
|
||||
toElement: ReactDOM.findDOMNode(component),
|
||||
relatedTarget: ReactDOM.findDOMNode(component),
|
||||
view: window,
|
||||
path: [otherNode, otherNode],
|
||||
});
|
||||
expect(handleTopLevel.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
@@ -61,8 +57,7 @@ describe('ReactEventListener', () => {
|
||||
var parentContainer = document.createElement('div');
|
||||
var parentControl = <div>Parent</div>;
|
||||
childControl = ReactDOM.render(childControl, childContainer);
|
||||
parentControl =
|
||||
ReactDOM.render(parentControl, parentContainer);
|
||||
parentControl = ReactDOM.render(parentControl, parentContainer);
|
||||
ReactDOM.findDOMNode(parentControl).appendChild(childContainer);
|
||||
|
||||
var callback = ReactEventListener.dispatchEvent.bind(null, 'test');
|
||||
@@ -72,10 +67,12 @@ describe('ReactEventListener', () => {
|
||||
|
||||
var calls = handleTopLevel.mock.calls;
|
||||
expect(calls.length).toBe(2);
|
||||
expect(calls[0][EVENT_TARGET_PARAM])
|
||||
.toBe(ReactDOMComponentTree.getInstanceFromNode(childControl));
|
||||
expect(calls[1][EVENT_TARGET_PARAM])
|
||||
.toBe(ReactDOMComponentTree.getInstanceFromNode(parentControl));
|
||||
expect(calls[0][EVENT_TARGET_PARAM]).toBe(
|
||||
ReactDOMComponentTree.getInstanceFromNode(childControl),
|
||||
);
|
||||
expect(calls[1][EVENT_TARGET_PARAM]).toBe(
|
||||
ReactDOMComponentTree.getInstanceFromNode(parentControl),
|
||||
);
|
||||
});
|
||||
|
||||
it('should propagate events two levels down', () => {
|
||||
@@ -86,10 +83,11 @@ describe('ReactEventListener', () => {
|
||||
var grandParentContainer = document.createElement('div');
|
||||
var grandParentControl = <div>Parent</div>;
|
||||
childControl = ReactDOM.render(childControl, childContainer);
|
||||
parentControl =
|
||||
ReactDOM.render(parentControl, parentContainer);
|
||||
grandParentControl =
|
||||
ReactDOM.render(grandParentControl, grandParentContainer);
|
||||
parentControl = ReactDOM.render(parentControl, parentContainer);
|
||||
grandParentControl = ReactDOM.render(
|
||||
grandParentControl,
|
||||
grandParentContainer,
|
||||
);
|
||||
ReactDOM.findDOMNode(parentControl).appendChild(childContainer);
|
||||
ReactDOM.findDOMNode(grandParentControl).appendChild(parentContainer);
|
||||
|
||||
@@ -100,12 +98,15 @@ describe('ReactEventListener', () => {
|
||||
|
||||
var calls = handleTopLevel.mock.calls;
|
||||
expect(calls.length).toBe(3);
|
||||
expect(calls[0][EVENT_TARGET_PARAM])
|
||||
.toBe(ReactDOMComponentTree.getInstanceFromNode(childControl));
|
||||
expect(calls[1][EVENT_TARGET_PARAM])
|
||||
.toBe(ReactDOMComponentTree.getInstanceFromNode(parentControl));
|
||||
expect(calls[2][EVENT_TARGET_PARAM])
|
||||
.toBe(ReactDOMComponentTree.getInstanceFromNode(grandParentControl));
|
||||
expect(calls[0][EVENT_TARGET_PARAM]).toBe(
|
||||
ReactDOMComponentTree.getInstanceFromNode(childControl),
|
||||
);
|
||||
expect(calls[1][EVENT_TARGET_PARAM]).toBe(
|
||||
ReactDOMComponentTree.getInstanceFromNode(parentControl),
|
||||
);
|
||||
expect(calls[2][EVENT_TARGET_PARAM]).toBe(
|
||||
ReactDOMComponentTree.getInstanceFromNode(grandParentControl),
|
||||
);
|
||||
});
|
||||
|
||||
it('should not get confused by disappearing elements', () => {
|
||||
@@ -114,8 +115,7 @@ describe('ReactEventListener', () => {
|
||||
var parentContainer = document.createElement('div');
|
||||
var parentControl = <div>Parent</div>;
|
||||
childControl = ReactDOM.render(childControl, childContainer);
|
||||
parentControl =
|
||||
ReactDOM.render(parentControl, parentContainer);
|
||||
parentControl = ReactDOM.render(parentControl, parentContainer);
|
||||
ReactDOM.findDOMNode(parentControl).appendChild(childContainer);
|
||||
|
||||
// ReactBrowserEventEmitter.handleTopLevel might remove the
|
||||
@@ -123,13 +123,16 @@ describe('ReactEventListener', () => {
|
||||
// node when the first event handlers are called; we'll still
|
||||
// expect to receive a second call for the parent control.
|
||||
var childNode = ReactDOM.findDOMNode(childControl);
|
||||
handleTopLevel.mockImplementation(
|
||||
function(topLevelType, topLevelTarget, topLevelTargetID, nativeEvent) {
|
||||
if (topLevelTarget === childNode) {
|
||||
ReactDOM.unmountComponentAtNode(childContainer);
|
||||
}
|
||||
handleTopLevel.mockImplementation(function(
|
||||
topLevelType,
|
||||
topLevelTarget,
|
||||
topLevelTargetID,
|
||||
nativeEvent,
|
||||
) {
|
||||
if (topLevelTarget === childNode) {
|
||||
ReactDOM.unmountComponentAtNode(childContainer);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
var callback = ReactEventListener.dispatchEvent.bind(null, 'test');
|
||||
callback({
|
||||
@@ -138,41 +141,42 @@ describe('ReactEventListener', () => {
|
||||
|
||||
var calls = handleTopLevel.mock.calls;
|
||||
expect(calls.length).toBe(2);
|
||||
expect(calls[0][EVENT_TARGET_PARAM])
|
||||
.toBe(ReactDOMComponentTree.getInstanceFromNode(childNode));
|
||||
expect(calls[1][EVENT_TARGET_PARAM])
|
||||
.toBe(ReactDOMComponentTree.getInstanceFromNode(parentControl));
|
||||
expect(calls[0][EVENT_TARGET_PARAM]).toBe(
|
||||
ReactDOMComponentTree.getInstanceFromNode(childNode),
|
||||
);
|
||||
expect(calls[1][EVENT_TARGET_PARAM]).toBe(
|
||||
ReactDOMComponentTree.getInstanceFromNode(parentControl),
|
||||
);
|
||||
});
|
||||
|
||||
it('should batch between handlers from different roots', () => {
|
||||
var childContainer = document.createElement('div');
|
||||
var parentContainer = document.createElement('div');
|
||||
var childControl = ReactDOM.render(
|
||||
<div>Child</div>,
|
||||
childContainer
|
||||
);
|
||||
var parentControl = ReactDOM.render(
|
||||
<div>Parent</div>,
|
||||
parentContainer
|
||||
);
|
||||
var childControl = ReactDOM.render(<div>Child</div>, childContainer);
|
||||
var parentControl = ReactDOM.render(<div>Parent</div>, parentContainer);
|
||||
ReactDOM.findDOMNode(parentControl).appendChild(childContainer);
|
||||
|
||||
// Suppose an event handler in each root enqueues an update to the
|
||||
// childControl element -- the two updates should get batched together.
|
||||
var childNode = ReactDOM.findDOMNode(childControl);
|
||||
handleTopLevel.mockImplementation(
|
||||
function(topLevelType, topLevelTarget, topLevelTargetID, nativeEvent) {
|
||||
ReactDOM.render(
|
||||
<div>{topLevelTarget === childNode ? '1' : '2'}</div>,
|
||||
childContainer
|
||||
);
|
||||
// Since we're batching, neither update should yet have gone through.
|
||||
expect(childNode.textContent).toBe('Child');
|
||||
}
|
||||
);
|
||||
handleTopLevel.mockImplementation(function(
|
||||
topLevelType,
|
||||
topLevelTarget,
|
||||
topLevelTargetID,
|
||||
nativeEvent,
|
||||
) {
|
||||
ReactDOM.render(
|
||||
<div>{topLevelTarget === childNode ? '1' : '2'}</div>,
|
||||
childContainer,
|
||||
);
|
||||
// Since we're batching, neither update should yet have gone through.
|
||||
expect(childNode.textContent).toBe('Child');
|
||||
});
|
||||
|
||||
var callback =
|
||||
ReactEventListener.dispatchEvent.bind(ReactEventListener, 'test');
|
||||
var callback = ReactEventListener.dispatchEvent.bind(
|
||||
ReactEventListener,
|
||||
'test',
|
||||
);
|
||||
callback({
|
||||
target: childNode,
|
||||
});
|
||||
@@ -204,7 +208,8 @@ describe('ReactEventListener', () => {
|
||||
|
||||
var calls = handleTopLevel.mock.calls;
|
||||
expect(calls.length).toBe(1);
|
||||
expect(calls[0][EVENT_TARGET_PARAM])
|
||||
.toBe(ReactDOMComponentTree.getInstanceFromNode(instance.getInner()));
|
||||
expect(calls[0][EVENT_TARGET_PARAM]).toBe(
|
||||
ReactDOMComponentTree.getInstanceFromNode(instance.getInner()),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -45,7 +45,7 @@ describe('ReactMount', () => {
|
||||
expect(function() {
|
||||
ReactDOM.unmountComponentAtNode(nodeArray);
|
||||
}).toThrowError(
|
||||
'unmountComponentAtNode(...): Target container is not a DOM element.'
|
||||
'unmountComponentAtNode(...): Target container is not a DOM element.',
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -55,7 +55,7 @@ describe('ReactMount', () => {
|
||||
ReactTestUtils.renderIntoDocument('div');
|
||||
}).toThrowError(
|
||||
'ReactDOM.render(): Invalid component element. Instead of passing a ' +
|
||||
'string like \'div\', pass React.createElement(\'div\') or <div />.'
|
||||
"string like 'div', pass React.createElement('div') or <div />.",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -70,7 +70,7 @@ describe('ReactMount', () => {
|
||||
ReactTestUtils.renderIntoDocument(Component);
|
||||
}).toThrowError(
|
||||
'ReactDOM.render(): Invalid component element. Instead of passing a ' +
|
||||
'class like Foo, pass React.createElement(Foo) or <Foo />.'
|
||||
'class like Foo, pass React.createElement(Foo) or <Foo />.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -160,25 +160,26 @@ describe('ReactMount', () => {
|
||||
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toContain(
|
||||
'Rendering components directly into document.body is discouraged'
|
||||
'Rendering components directly into document.body is discouraged',
|
||||
);
|
||||
});
|
||||
|
||||
it('should account for escaping on a checksum mismatch', () => {
|
||||
var div = document.createElement('div');
|
||||
var markup = ReactDOMServer.renderToString(
|
||||
<div>This markup contains an nbsp entity: server text</div>);
|
||||
<div>This markup contains an nbsp entity: server text</div>,
|
||||
);
|
||||
div.innerHTML = markup;
|
||||
|
||||
spyOn(console, 'error');
|
||||
ReactDOM.render(
|
||||
<div>This markup contains an nbsp entity: client text</div>,
|
||||
div
|
||||
div,
|
||||
);
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toContain(
|
||||
' (client) nbsp entity: client text</div>\n' +
|
||||
' (server) nbsp entity: server text</div>'
|
||||
' (server) nbsp entity: server text</div>',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -223,9 +224,9 @@ describe('ReactMount', () => {
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: 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.'
|
||||
'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.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -248,8 +249,8 @@ describe('ReactMount', () => {
|
||||
ReactDOMOther.unmountComponentAtNode(container);
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: unmountComponentAtNode(): The node you\'re attempting to unmount ' +
|
||||
'was rendered by another copy of React.'
|
||||
"Warning: unmountComponentAtNode(): The node you're attempting to unmount " +
|
||||
'was rendered by another copy of React.',
|
||||
);
|
||||
|
||||
// Don't throw a warning if the correct React copy unmounts the node
|
||||
|
||||
@@ -43,10 +43,11 @@ describe('ReactMount', () => {
|
||||
it('should warn when unmounting a non-container root node', () => {
|
||||
var mainContainerDiv = document.createElement('div');
|
||||
|
||||
var component =
|
||||
var component = (
|
||||
<div>
|
||||
<div />
|
||||
</div>;
|
||||
</div>
|
||||
);
|
||||
ReactDOM.render(component, mainContainerDiv);
|
||||
|
||||
// Test that unmounting at a root node gives a helpful warning
|
||||
@@ -55,22 +56,23 @@ describe('ReactMount', () => {
|
||||
ReactDOM.unmountComponentAtNode(rootDiv);
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: unmountComponentAtNode(): The node you\'re attempting to ' +
|
||||
'unmount was rendered by React and is not a top-level container. You ' +
|
||||
'may have accidentally passed in a React root node instead of its ' +
|
||||
'container.'
|
||||
"Warning: unmountComponentAtNode(): The node you're attempting to " +
|
||||
'unmount was rendered by React and is not a top-level container. You ' +
|
||||
'may have accidentally passed in a React root node instead of its ' +
|
||||
'container.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn when unmounting a non-container, non-root node', () => {
|
||||
var mainContainerDiv = document.createElement('div');
|
||||
|
||||
var component =
|
||||
var component = (
|
||||
<div>
|
||||
<div>
|
||||
<div />
|
||||
</div>
|
||||
</div>;
|
||||
</div>
|
||||
);
|
||||
ReactDOM.render(component, mainContainerDiv);
|
||||
|
||||
// Test that unmounting at a non-root node gives a different warning
|
||||
@@ -79,10 +81,10 @@ describe('ReactMount', () => {
|
||||
ReactDOM.unmountComponentAtNode(nonRootDiv);
|
||||
expect(console.error.calls.count()).toBe(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: unmountComponentAtNode(): The node you\'re attempting to ' +
|
||||
'unmount was rendered by React and is not a top-level container. ' +
|
||||
'Instead, have the parent component update its state and rerender in ' +
|
||||
'order to remove this component.'
|
||||
"Warning: unmountComponentAtNode(): The node you're attempting to " +
|
||||
'unmount was rendered by React and is not a top-level container. ' +
|
||||
'Instead, have the parent component update its state and rerender in ' +
|
||||
'order to remove this component.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -166,7 +166,7 @@ describe('rendering React components at document', () => {
|
||||
}
|
||||
|
||||
var markup = ReactDOMServer.renderToString(
|
||||
<Component text="Hello world" />
|
||||
<Component text="Hello world" />,
|
||||
);
|
||||
testDocument = getTestDocument(markup);
|
||||
|
||||
@@ -194,7 +194,7 @@ describe('rendering React components at document', () => {
|
||||
}
|
||||
|
||||
var markup = ReactDOMServer.renderToString(
|
||||
<Component text="Goodbye world" />
|
||||
<Component text="Goodbye world" />,
|
||||
);
|
||||
testDocument = getTestDocument(markup);
|
||||
|
||||
@@ -202,16 +202,16 @@ describe('rendering React components at document', () => {
|
||||
// Notice the text is different!
|
||||
ReactDOM.render(<Component text="Hello world" />, testDocument);
|
||||
}).toThrowError(
|
||||
'You\'re trying to render a component to the document using ' +
|
||||
'server rendering but the checksum was invalid. This usually ' +
|
||||
'means you rendered a different component type or props on ' +
|
||||
'the client from the one on the server, or your render() methods ' +
|
||||
'are impure. React cannot handle this case due to cross-browser ' +
|
||||
'quirks by rendering at the document root. You should look for ' +
|
||||
'environment dependent code in your components and ensure ' +
|
||||
'the props are the same client and server side:\n' +
|
||||
' (client) dy data-reactid="4">Hello world</body></\n' +
|
||||
' (server) dy data-reactid="4">Goodbye world</body>'
|
||||
"You're trying to render a component to the document using " +
|
||||
'server rendering but the checksum was invalid. This usually ' +
|
||||
'means you rendered a different component type or props on ' +
|
||||
'the client from the one on the server, or your render() methods ' +
|
||||
'are impure. React cannot handle this case due to cross-browser ' +
|
||||
'quirks by rendering at the document root. You should look for ' +
|
||||
'environment dependent code in your components and ensure ' +
|
||||
'the props are the same client and server side:\n' +
|
||||
' (client) dy data-reactid="4">Hello world</body></\n' +
|
||||
' (server) dy data-reactid="4">Goodbye world</body>',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -238,15 +238,15 @@ describe('rendering React components at document', () => {
|
||||
expect(function() {
|
||||
ReactDOM.render(<Component />, container);
|
||||
}).toThrowError(
|
||||
'You\'re trying to render a component to the document but you didn\'t ' +
|
||||
'use server rendering. We can\'t do this without using server ' +
|
||||
'rendering due to cross-browser quirks. See ' +
|
||||
'ReactDOMServer.renderToString() for server rendering.'
|
||||
"You're trying to render a component to the document but you didn't " +
|
||||
"use server rendering. We can't do this without using server " +
|
||||
'rendering due to cross-browser quirks. See ' +
|
||||
'ReactDOMServer.renderToString() for server rendering.',
|
||||
);
|
||||
});
|
||||
|
||||
it('supports findDOMNode on full-page components', () => {
|
||||
var tree =
|
||||
var tree = (
|
||||
<html>
|
||||
<head>
|
||||
<title>Hello World</title>
|
||||
@@ -254,7 +254,8 @@ describe('rendering React components at document', () => {
|
||||
<body>
|
||||
Hello world
|
||||
</body>
|
||||
</html>;
|
||||
</html>
|
||||
);
|
||||
|
||||
var markup = ReactDOMServer.renderToString(tree);
|
||||
testDocument = getTestDocument(markup);
|
||||
|
||||
@@ -38,7 +38,7 @@ describe('findDOMNode', () => {
|
||||
expect(function() {
|
||||
ReactDOM.findDOMNode({foo: 'bar'});
|
||||
}).toThrowError(
|
||||
'Element appears to be neither ReactComponent nor DOMNode (keys: foo)'
|
||||
'Element appears to be neither ReactComponent nor DOMNode (keys: foo)',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -54,7 +54,7 @@ describe('findDOMNode', () => {
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
|
||||
expect(() => ReactDOM.findDOMNode(inst)).toThrowError(
|
||||
'findDOMNode was called on an unmounted component.'
|
||||
'findDOMNode was called on an unmounted component.',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -65,11 +65,10 @@ describe('findDOMNode', () => {
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div/>;
|
||||
return <div />;
|
||||
}
|
||||
}
|
||||
|
||||
expect(() => ReactTestUtils.renderIntoDocument(<Bar/>)).not.toThrow();
|
||||
expect(() => ReactTestUtils.renderIntoDocument(<Bar />)).not.toThrow();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @emails react-core
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('React');
|
||||
var ReactTestUtils = require('ReactTestUtils');
|
||||
var inputValueTracking = require('inputValueTracking');
|
||||
|
||||
describe('inputValueTracking', function() {
|
||||
var input, checkbox, mockComponent;
|
||||
|
||||
beforeEach(function() {
|
||||
input = document.createElement('input');
|
||||
input.type = 'text';
|
||||
checkbox = document.createElement('input');
|
||||
checkbox.type = 'checkbox';
|
||||
mockComponent = {_hostNode: input, _wrapperState: {}};
|
||||
});
|
||||
|
||||
it('should attach tracker to wrapper state', function() {
|
||||
inputValueTracking.track(mockComponent);
|
||||
|
||||
expect(mockComponent._wrapperState.hasOwnProperty('valueTracker')).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
it('should define `value` on the instance node', function() {
|
||||
inputValueTracking.track(mockComponent);
|
||||
|
||||
expect(input.hasOwnProperty('value')).toBe(true);
|
||||
});
|
||||
|
||||
it('should define `checked` on the instance node', function() {
|
||||
mockComponent._hostNode = checkbox;
|
||||
inputValueTracking.track(mockComponent);
|
||||
|
||||
expect(checkbox.hasOwnProperty('checked')).toBe(true);
|
||||
});
|
||||
|
||||
it('should initialize with the current value', function() {
|
||||
input.value = 'foo';
|
||||
|
||||
inputValueTracking.track(mockComponent);
|
||||
|
||||
var tracker = mockComponent._wrapperState.valueTracker;
|
||||
|
||||
expect(tracker.getValue()).toEqual('foo');
|
||||
});
|
||||
|
||||
it('should initialize with the current `checked`', function() {
|
||||
mockComponent._hostNode = checkbox;
|
||||
checkbox.checked = true;
|
||||
inputValueTracking.track(mockComponent);
|
||||
|
||||
var tracker = mockComponent._wrapperState.valueTracker;
|
||||
|
||||
expect(tracker.getValue()).toEqual('true');
|
||||
});
|
||||
|
||||
it('should track value changes', function() {
|
||||
input.value = 'foo';
|
||||
|
||||
inputValueTracking.track(mockComponent);
|
||||
|
||||
var tracker = mockComponent._wrapperState.valueTracker;
|
||||
|
||||
input.value = 'bar';
|
||||
expect(tracker.getValue()).toEqual('bar');
|
||||
});
|
||||
|
||||
it('should tracked`checked` changes', function() {
|
||||
mockComponent._hostNode = checkbox;
|
||||
checkbox.checked = true;
|
||||
inputValueTracking.track(mockComponent);
|
||||
|
||||
var tracker = mockComponent._wrapperState.valueTracker;
|
||||
|
||||
checkbox.checked = false;
|
||||
expect(tracker.getValue()).toEqual('false');
|
||||
});
|
||||
|
||||
it('should update value manually', function() {
|
||||
input.value = 'foo';
|
||||
inputValueTracking.track(mockComponent);
|
||||
|
||||
var tracker = mockComponent._wrapperState.valueTracker;
|
||||
|
||||
tracker.setValue('bar');
|
||||
expect(tracker.getValue()).toEqual('bar');
|
||||
});
|
||||
|
||||
it('should coerce value to a string', function() {
|
||||
input.value = 'foo';
|
||||
inputValueTracking.track(mockComponent);
|
||||
|
||||
var tracker = mockComponent._wrapperState.valueTracker;
|
||||
|
||||
tracker.setValue(500);
|
||||
expect(tracker.getValue()).toEqual('500');
|
||||
});
|
||||
|
||||
it('should update value if it changed and return result', function() {
|
||||
inputValueTracking.track(mockComponent);
|
||||
input.value = 'foo';
|
||||
|
||||
var tracker = mockComponent._wrapperState.valueTracker;
|
||||
|
||||
expect(inputValueTracking.updateValueIfChanged(mockComponent)).toBe(false);
|
||||
|
||||
tracker.setValue('bar');
|
||||
|
||||
expect(inputValueTracking.updateValueIfChanged(mockComponent)).toBe(true);
|
||||
|
||||
expect(tracker.getValue()).toEqual('foo');
|
||||
});
|
||||
|
||||
it('should track value and return true when updating untracked instance', function() {
|
||||
input.value = 'foo';
|
||||
|
||||
expect(inputValueTracking.updateValueIfChanged(mockComponent)).toBe(true);
|
||||
|
||||
var tracker = mockComponent._wrapperState.valueTracker;
|
||||
expect(tracker.getValue()).toEqual('foo');
|
||||
});
|
||||
|
||||
it('should return tracker from node', function() {
|
||||
var node = ReactTestUtils.renderIntoDocument(
|
||||
<input type="text" defaultValue="foo" />,
|
||||
);
|
||||
var tracker = inputValueTracking._getTrackerFromNode(node);
|
||||
expect(tracker.getValue()).toEqual('foo');
|
||||
});
|
||||
|
||||
it('should stop tracking', function() {
|
||||
inputValueTracking.track(mockComponent);
|
||||
|
||||
expect(mockComponent._wrapperState.hasOwnProperty('valueTracker')).toBe(
|
||||
true,
|
||||
);
|
||||
|
||||
inputValueTracking.stopTracking(mockComponent);
|
||||
|
||||
expect(mockComponent._wrapperState.hasOwnProperty('valueTracker')).toBe(
|
||||
false,
|
||||
);
|
||||
|
||||
expect(input.hasOwnProperty('value')).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -15,22 +15,107 @@ var validateDOMNesting;
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/syntax.html#special
|
||||
var specialTags = [
|
||||
'address', 'applet', 'area', 'article', 'aside', 'base', 'basefont',
|
||||
'bgsound', 'blockquote', 'body', 'br', 'button', 'caption', 'center', 'col',
|
||||
'colgroup', 'dd', 'details', 'dir', 'div', 'dl', 'dt', 'embed', 'fieldset',
|
||||
'figcaption', 'figure', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2',
|
||||
'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'iframe',
|
||||
'img', 'input', 'isindex', 'li', 'link', 'listing', 'main', 'marquee', 'menu',
|
||||
'menuitem', 'meta', 'nav', 'noembed', 'noframes', 'noscript', 'object', 'ol',
|
||||
'p', 'param', 'plaintext', 'pre', 'script', 'section', 'select', 'source',
|
||||
'style', 'summary', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot',
|
||||
'th', 'thead', 'title', 'tr', 'track', 'ul', 'wbr', 'xmp',
|
||||
'address',
|
||||
'applet',
|
||||
'area',
|
||||
'article',
|
||||
'aside',
|
||||
'base',
|
||||
'basefont',
|
||||
'bgsound',
|
||||
'blockquote',
|
||||
'body',
|
||||
'br',
|
||||
'button',
|
||||
'caption',
|
||||
'center',
|
||||
'col',
|
||||
'colgroup',
|
||||
'dd',
|
||||
'details',
|
||||
'dir',
|
||||
'div',
|
||||
'dl',
|
||||
'dt',
|
||||
'embed',
|
||||
'fieldset',
|
||||
'figcaption',
|
||||
'figure',
|
||||
'footer',
|
||||
'form',
|
||||
'frame',
|
||||
'frameset',
|
||||
'h1',
|
||||
'h2',
|
||||
'h3',
|
||||
'h4',
|
||||
'h5',
|
||||
'h6',
|
||||
'head',
|
||||
'header',
|
||||
'hgroup',
|
||||
'hr',
|
||||
'html',
|
||||
'iframe',
|
||||
'img',
|
||||
'input',
|
||||
'isindex',
|
||||
'li',
|
||||
'link',
|
||||
'listing',
|
||||
'main',
|
||||
'marquee',
|
||||
'menu',
|
||||
'menuitem',
|
||||
'meta',
|
||||
'nav',
|
||||
'noembed',
|
||||
'noframes',
|
||||
'noscript',
|
||||
'object',
|
||||
'ol',
|
||||
'p',
|
||||
'param',
|
||||
'plaintext',
|
||||
'pre',
|
||||
'script',
|
||||
'section',
|
||||
'select',
|
||||
'source',
|
||||
'style',
|
||||
'summary',
|
||||
'table',
|
||||
'tbody',
|
||||
'td',
|
||||
'template',
|
||||
'textarea',
|
||||
'tfoot',
|
||||
'th',
|
||||
'thead',
|
||||
'title',
|
||||
'tr',
|
||||
'track',
|
||||
'ul',
|
||||
'wbr',
|
||||
'xmp',
|
||||
];
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/syntax.html#formatting
|
||||
var formattingTags = [
|
||||
'a', 'b', 'big', 'code', 'em', 'font', 'i', 'nobr', 's', 'small', 'strike',
|
||||
'strong', 'tt', 'u',
|
||||
'a',
|
||||
'b',
|
||||
'big',
|
||||
'code',
|
||||
'em',
|
||||
'font',
|
||||
'i',
|
||||
'nobr',
|
||||
's',
|
||||
'small',
|
||||
'strike',
|
||||
'strong',
|
||||
'tt',
|
||||
'u',
|
||||
];
|
||||
|
||||
function isTagStackValid(stack) {
|
||||
@@ -39,8 +124,11 @@ function isTagStackValid(stack) {
|
||||
if (!validateDOMNesting.isTagValidInContext(stack[i], ancestorInfo)) {
|
||||
return false;
|
||||
}
|
||||
ancestorInfo =
|
||||
validateDOMNesting.updatedAncestorInfo(ancestorInfo, stack[i], null);
|
||||
ancestorInfo = validateDOMNesting.updatedAncestorInfo(
|
||||
ancestorInfo,
|
||||
stack[i],
|
||||
null,
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -17,15 +17,13 @@ var FallbackCompositionState = require('FallbackCompositionState');
|
||||
var SyntheticCompositionEvent = require('SyntheticCompositionEvent');
|
||||
var SyntheticInputEvent = require('SyntheticInputEvent');
|
||||
|
||||
import type { TopLevelTypes } from 'EventConstants';
|
||||
import type {TopLevelTypes} from 'EventConstants';
|
||||
|
||||
var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space
|
||||
var START_KEYCODE = 229;
|
||||
|
||||
var canUseCompositionEvent = (
|
||||
ExecutionEnvironment.canUseDOM &&
|
||||
'CompositionEvent' in window
|
||||
);
|
||||
var canUseCompositionEvent =
|
||||
ExecutionEnvironment.canUseDOM && 'CompositionEvent' in window;
|
||||
|
||||
var documentMode = null;
|
||||
if (ExecutionEnvironment.canUseDOM && 'documentMode' in document) {
|
||||
@@ -35,23 +33,19 @@ if (ExecutionEnvironment.canUseDOM && 'documentMode' in document) {
|
||||
// Webkit offers a very useful `textInput` event that can be used to
|
||||
// directly represent `beforeInput`. The IE `textinput` event is not as
|
||||
// useful, so we don't use it.
|
||||
var canUseTextInputEvent = (
|
||||
var canUseTextInputEvent =
|
||||
ExecutionEnvironment.canUseDOM &&
|
||||
'TextEvent' in window &&
|
||||
!documentMode &&
|
||||
!isPresto()
|
||||
);
|
||||
!isPresto();
|
||||
|
||||
// In IE9+, we have access to composition events, but the data supplied
|
||||
// by the native compositionend event may be incorrect. Japanese ideographic
|
||||
// spaces, for instance (\u3000) are not recorded correctly.
|
||||
var useFallbackCompositionData = (
|
||||
var useFallbackCompositionData =
|
||||
ExecutionEnvironment.canUseDOM &&
|
||||
(
|
||||
!canUseCompositionEvent ||
|
||||
(documentMode && documentMode > 8 && documentMode <= 11)
|
||||
)
|
||||
);
|
||||
(!canUseCompositionEvent ||
|
||||
(documentMode && documentMode > 8 && documentMode <= 11));
|
||||
|
||||
/**
|
||||
* Opera <= 12 includes TextEvent in window, but does not fire
|
||||
@@ -143,7 +137,6 @@ function isKeypressCommand(nativeEvent) {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Translate native top level events into event types.
|
||||
*
|
||||
@@ -170,10 +163,7 @@ function getCompositionEventType(topLevelType) {
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isFallbackCompositionStart(topLevelType, nativeEvent) {
|
||||
return (
|
||||
topLevelType === 'topKeyDown' &&
|
||||
nativeEvent.keyCode === START_KEYCODE
|
||||
);
|
||||
return topLevelType === 'topKeyDown' && nativeEvent.keyCode === START_KEYCODE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,11 +177,11 @@ function isFallbackCompositionEnd(topLevelType, nativeEvent) {
|
||||
switch (topLevelType) {
|
||||
case 'topKeyUp':
|
||||
// Command keys insert or clear IME input.
|
||||
return (END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1);
|
||||
return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1;
|
||||
case 'topKeyDown':
|
||||
// Expect IME keyCode on each keydown. If we get any other
|
||||
// code we must have exited earlier.
|
||||
return (nativeEvent.keyCode !== START_KEYCODE);
|
||||
return nativeEvent.keyCode !== START_KEYCODE;
|
||||
case 'topKeyPress':
|
||||
case 'topMouseDown':
|
||||
case 'topBlur':
|
||||
@@ -229,7 +219,7 @@ function extractCompositionEvent(
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
nativeEventTarget,
|
||||
) {
|
||||
var eventType;
|
||||
var fallbackData;
|
||||
@@ -252,8 +242,9 @@ function extractCompositionEvent(
|
||||
// The current composition is stored statically and must not be
|
||||
// overwritten while composition continues.
|
||||
if (!currentComposition && eventType === eventTypes.compositionStart) {
|
||||
currentComposition =
|
||||
FallbackCompositionState.getPooled(nativeEventTarget);
|
||||
currentComposition = FallbackCompositionState.getPooled(
|
||||
nativeEventTarget,
|
||||
);
|
||||
} else if (eventType === eventTypes.compositionEnd) {
|
||||
if (currentComposition) {
|
||||
fallbackData = currentComposition.getData();
|
||||
@@ -265,7 +256,7 @@ function extractCompositionEvent(
|
||||
eventType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
nativeEventTarget,
|
||||
);
|
||||
|
||||
if (fallbackData) {
|
||||
@@ -348,9 +339,11 @@ function getFallbackBeforeInputChars(topLevelType: TopLevelTypes, nativeEvent) {
|
||||
// If composition event is available, we extract a string only at
|
||||
// compositionevent, otherwise extract it at fallback events.
|
||||
if (currentComposition) {
|
||||
if (topLevelType === 'topCompositionEnd'
|
||||
|| (!canUseCompositionEvent
|
||||
&& isFallbackCompositionEnd(topLevelType, nativeEvent))) {
|
||||
if (
|
||||
topLevelType === 'topCompositionEnd' ||
|
||||
(!canUseCompositionEvent &&
|
||||
isFallbackCompositionEnd(topLevelType, nativeEvent))
|
||||
) {
|
||||
var chars = currentComposition.getData();
|
||||
FallbackCompositionState.release(currentComposition);
|
||||
currentComposition = null;
|
||||
@@ -402,7 +395,7 @@ function extractBeforeInputEvent(
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
nativeEventTarget,
|
||||
) {
|
||||
var chars;
|
||||
|
||||
@@ -422,7 +415,7 @@ function extractBeforeInputEvent(
|
||||
eventTypes.beforeInput,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
nativeEventTarget,
|
||||
);
|
||||
|
||||
event.data = chars;
|
||||
@@ -449,27 +442,26 @@ function extractBeforeInputEvent(
|
||||
* `composition` event types.
|
||||
*/
|
||||
var BeforeInputEventPlugin = {
|
||||
|
||||
eventTypes: eventTypes,
|
||||
|
||||
extractEvents: function(
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
nativeEventTarget,
|
||||
) {
|
||||
return [
|
||||
extractCompositionEvent(
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
nativeEventTarget,
|
||||
),
|
||||
extractBeforeInputEvent(
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
nativeEventTarget,
|
||||
),
|
||||
];
|
||||
},
|
||||
|
||||
@@ -18,6 +18,7 @@ var ReactDOMComponentTree = require('ReactDOMComponentTree');
|
||||
var ReactUpdates = require('ReactUpdates');
|
||||
var SyntheticEvent = require('SyntheticEvent');
|
||||
|
||||
var inputValueTracking = require('inputValueTracking');
|
||||
var getEventTarget = require('getEventTarget');
|
||||
var isEventSupported = require('isEventSupported');
|
||||
var isTextInputElement = require('isTextInputElement');
|
||||
@@ -41,13 +42,22 @@ var eventTypes = {
|
||||
},
|
||||
};
|
||||
|
||||
function createAndAccumulateChangeEvent(inst, nativeEvent, target) {
|
||||
var event = SyntheticEvent.getPooled(
|
||||
eventTypes.change,
|
||||
inst,
|
||||
nativeEvent,
|
||||
target,
|
||||
);
|
||||
event.type = 'change';
|
||||
EventPropagators.accumulateTwoPhaseDispatches(event);
|
||||
return event;
|
||||
}
|
||||
/**
|
||||
* For IE shims
|
||||
*/
|
||||
var activeElement = null;
|
||||
var activeElementInst = null;
|
||||
var activeElementValue = null;
|
||||
var activeElementValueProp = null;
|
||||
|
||||
/**
|
||||
* SECTION: handle `change` event
|
||||
@@ -55,27 +65,24 @@ var activeElementValueProp = null;
|
||||
function shouldUseChangeEvent(elem) {
|
||||
var nodeName = elem.nodeName && elem.nodeName.toLowerCase();
|
||||
return (
|
||||
nodeName === 'select' ||
|
||||
(nodeName === 'input' && elem.type === 'file')
|
||||
nodeName === 'select' || (nodeName === 'input' && elem.type === 'file')
|
||||
);
|
||||
}
|
||||
|
||||
var doesChangeEventBubble = false;
|
||||
if (ExecutionEnvironment.canUseDOM) {
|
||||
// See `handleChange` comment below
|
||||
doesChangeEventBubble = isEventSupported('change') && (
|
||||
!document.documentMode || document.documentMode > 8
|
||||
);
|
||||
doesChangeEventBubble =
|
||||
isEventSupported('change') &&
|
||||
(!document.documentMode || document.documentMode > 8);
|
||||
}
|
||||
|
||||
function manualDispatchChangeEvent(nativeEvent) {
|
||||
var event = SyntheticEvent.getPooled(
|
||||
eventTypes.change,
|
||||
var event = createAndAccumulateChangeEvent(
|
||||
activeElementInst,
|
||||
nativeEvent,
|
||||
getEventTarget(nativeEvent)
|
||||
getEventTarget(nativeEvent),
|
||||
);
|
||||
EventPropagators.accumulateTwoPhaseDispatches(event);
|
||||
|
||||
// If change and propertychange bubbled, we'd just bind to it like all the
|
||||
// other events and have it go through ReactBrowserEventEmitter. Since it
|
||||
@@ -111,19 +118,24 @@ function stopWatchingForChangeEventIE8() {
|
||||
activeElementInst = null;
|
||||
}
|
||||
|
||||
function getTargetInstForChangeEvent(
|
||||
topLevelType,
|
||||
targetInst
|
||||
) {
|
||||
function getInstIfValueChanged(targetInst, nativeEvent) {
|
||||
var updated = inputValueTracking.updateValueIfChanged(targetInst);
|
||||
var simulated =
|
||||
nativeEvent.simulated === true &&
|
||||
ChangeEventPlugin._allowSimulatedPassThrough;
|
||||
|
||||
if (updated || simulated) {
|
||||
return targetInst;
|
||||
}
|
||||
}
|
||||
|
||||
function getTargetInstForChangeEvent(topLevelType, targetInst) {
|
||||
if (topLevelType === 'topChange') {
|
||||
return targetInst;
|
||||
}
|
||||
}
|
||||
function handleEventsForChangeEventIE8(
|
||||
topLevelType,
|
||||
target,
|
||||
targetInst
|
||||
) {
|
||||
|
||||
function handleEventsForChangeEventIE8(topLevelType, target, targetInst) {
|
||||
if (topLevelType === 'topFocus') {
|
||||
// stopWatching() should be a noop here but we call it just in case we
|
||||
// missed a blur event somehow.
|
||||
@@ -134,7 +146,6 @@ function handleEventsForChangeEventIE8(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* SECTION: handle `input` event
|
||||
*/
|
||||
@@ -142,117 +153,56 @@ var isInputEventSupported = false;
|
||||
if (ExecutionEnvironment.canUseDOM) {
|
||||
// IE9 claims to support the input event but fails to trigger it when
|
||||
// deleting text, so we ignore its input events.
|
||||
// IE10+ fire input events to often, such when a placeholder
|
||||
// changes or when an input with a placeholder is focused.
|
||||
isInputEventSupported = isEventSupported('input') && (
|
||||
!document.documentMode || document.documentMode > 11
|
||||
);
|
||||
|
||||
isInputEventSupported =
|
||||
isEventSupported('input') &&
|
||||
(!('documentMode' in document) || document.documentMode > 9);
|
||||
}
|
||||
|
||||
/**
|
||||
* (For IE <=11) Replacement getter/setter for the `value` property that gets
|
||||
* set on the active element.
|
||||
*/
|
||||
var newValueProp = {
|
||||
get: function() {
|
||||
return activeElementValueProp.get.call(this);
|
||||
},
|
||||
set: function(val) {
|
||||
// Cast to a string so we can do equality checks.
|
||||
activeElementValue = '' + val;
|
||||
activeElementValueProp.set.call(this, val);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* (For IE <=11) Starts tracking propertychange events on the passed-in element
|
||||
* (For IE <=9) Starts tracking propertychange events on the passed-in element
|
||||
* and override the value property so that we can distinguish user events from
|
||||
* value changes in JS.
|
||||
*/
|
||||
function startWatchingForValueChange(target, targetInst) {
|
||||
activeElement = target;
|
||||
activeElementInst = targetInst;
|
||||
activeElementValue = target.value;
|
||||
activeElementValueProp = Object.getOwnPropertyDescriptor(
|
||||
target.constructor.prototype,
|
||||
'value'
|
||||
);
|
||||
|
||||
// Not guarded in a canDefineProperty check: IE8 supports defineProperty only
|
||||
// on DOM elements
|
||||
Object.defineProperty(activeElement, 'value', newValueProp);
|
||||
if (activeElement.attachEvent) {
|
||||
activeElement.attachEvent('onpropertychange', handlePropertyChange);
|
||||
} else {
|
||||
activeElement.addEventListener('propertychange', handlePropertyChange, false);
|
||||
}
|
||||
activeElement.attachEvent('onpropertychange', handlePropertyChange);
|
||||
}
|
||||
|
||||
/**
|
||||
* (For IE <=11) Removes the event listeners from the currently-tracked element,
|
||||
* (For IE <=9) Removes the event listeners from the currently-tracked element,
|
||||
* if any exists.
|
||||
*/
|
||||
function stopWatchingForValueChange() {
|
||||
if (!activeElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// delete restores the original property definition
|
||||
delete activeElement.value;
|
||||
|
||||
if (activeElement.detachEvent) {
|
||||
activeElement.detachEvent('onpropertychange', handlePropertyChange);
|
||||
} else {
|
||||
activeElement.removeEventListener('propertychange', handlePropertyChange, false);
|
||||
}
|
||||
activeElement.detachEvent('onpropertychange', handlePropertyChange);
|
||||
|
||||
activeElement = null;
|
||||
activeElementInst = null;
|
||||
activeElementValue = null;
|
||||
activeElementValueProp = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* (For IE <=11) Handles a propertychange event, sending a `change` event if
|
||||
* (For IE <=9) Handles a propertychange event, sending a `change` event if
|
||||
* the value of the active element has changed.
|
||||
*/
|
||||
function handlePropertyChange(nativeEvent) {
|
||||
if (nativeEvent.propertyName !== 'value') {
|
||||
return;
|
||||
}
|
||||
var value = nativeEvent.srcElement.value;
|
||||
if (value === activeElementValue) {
|
||||
return;
|
||||
}
|
||||
activeElementValue = value;
|
||||
|
||||
manualDispatchChangeEvent(nativeEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* If a `change` event should be fired, returns the target's ID.
|
||||
*/
|
||||
function getTargetInstForInputEvent(
|
||||
topLevelType,
|
||||
targetInst
|
||||
) {
|
||||
if (topLevelType === 'topInput') {
|
||||
// In modern browsers (i.e., not IE8 or IE9), the input event is exactly
|
||||
// what we want so fall through here and trigger an abstract event
|
||||
return targetInst;
|
||||
if (getInstIfValueChanged(activeElementInst, nativeEvent)) {
|
||||
manualDispatchChangeEvent(nativeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
function handleEventsForInputEventIE(
|
||||
topLevelType,
|
||||
target,
|
||||
targetInst
|
||||
) {
|
||||
function handleEventsForInputEventPolyfill(topLevelType, target, targetInst) {
|
||||
if (topLevelType === 'topFocus') {
|
||||
// In IE8, we can capture almost all .value changes by adding a
|
||||
// propertychange handler and looking for events with propertyName
|
||||
// equal to 'value'
|
||||
// In IE9-11, propertychange fires for most input events but is buggy and
|
||||
// In IE9, propertychange fires for most input events but is buggy and
|
||||
// doesn't fire when text is deleted, but conveniently, selectionchange
|
||||
// appears to fire in all of the remaining cases so we catch those and
|
||||
// forward the event if the value has changed
|
||||
@@ -270,13 +220,16 @@ function handleEventsForInputEventIE(
|
||||
}
|
||||
|
||||
// For IE8 and IE9.
|
||||
function getTargetInstForInputEventIE(
|
||||
function getTargetInstForInputEventPolyfill(
|
||||
topLevelType,
|
||||
targetInst
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
) {
|
||||
if (topLevelType === 'topSelectionChange' ||
|
||||
topLevelType === 'topKeyUp' ||
|
||||
topLevelType === 'topKeyDown') {
|
||||
if (
|
||||
topLevelType === 'topSelectionChange' ||
|
||||
topLevelType === 'topKeyUp' ||
|
||||
topLevelType === 'topKeyDown'
|
||||
) {
|
||||
// On the selectionchange event, the target is just document which isn't
|
||||
// helpful for us so just check activeElement instead.
|
||||
//
|
||||
@@ -287,14 +240,10 @@ function getTargetInstForInputEventIE(
|
||||
// keystroke if user does a key repeat (it'll be a little delayed: right
|
||||
// before the second keystroke). Other input methods (e.g., paste) seem to
|
||||
// fire selectionchange normally.
|
||||
if (activeElement && activeElement.value !== activeElementValue) {
|
||||
activeElementValue = activeElement.value;
|
||||
return activeElementInst;
|
||||
}
|
||||
return getInstIfValueChanged(activeElementInst, nativeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* SECTION: handle `click` event
|
||||
*/
|
||||
@@ -302,18 +251,27 @@ function shouldUseClickEvent(elem) {
|
||||
// Use the `click` event to detect changes to checkbox and radio inputs.
|
||||
// This approach works across all browsers, whereas `change` does not fire
|
||||
// until `blur` in IE8.
|
||||
var nodeName = elem.nodeName;
|
||||
return (
|
||||
(elem.nodeName && elem.nodeName.toLowerCase() === 'input') &&
|
||||
nodeName &&
|
||||
nodeName.toLowerCase() === 'input' &&
|
||||
(elem.type === 'checkbox' || elem.type === 'radio')
|
||||
);
|
||||
}
|
||||
|
||||
function getTargetInstForClickEvent(
|
||||
topLevelType,
|
||||
targetInst
|
||||
) {
|
||||
function getTargetInstForClickEvent(topLevelType, targetInst, nativeEvent) {
|
||||
if (topLevelType === 'topClick') {
|
||||
return targetInst;
|
||||
return getInstIfValueChanged(targetInst, nativeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
function getTargetInstForInputOrChangeEvent(
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
) {
|
||||
if (topLevelType === 'topInput' || topLevelType === 'topChange') {
|
||||
return getInstIfValueChanged(targetInst, nativeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,17 +306,20 @@ function handleControlledInputBlur(inst, node) {
|
||||
* - select
|
||||
*/
|
||||
var ChangeEventPlugin = {
|
||||
|
||||
eventTypes: eventTypes,
|
||||
|
||||
_allowSimulatedPassThrough: true,
|
||||
_isInputEventSupported: isInputEventSupported,
|
||||
|
||||
extractEvents: function(
|
||||
topLevelType,
|
||||
targetInst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
nativeEventTarget,
|
||||
) {
|
||||
var targetNode = targetInst ?
|
||||
ReactDOMComponentTree.getNodeFromInstance(targetInst) : window;
|
||||
var targetNode = targetInst
|
||||
? ReactDOMComponentTree.getNodeFromInstance(targetInst)
|
||||
: window;
|
||||
|
||||
var getTargetInstFunc, handleEventFunc;
|
||||
if (shouldUseChangeEvent(targetNode)) {
|
||||
@@ -369,36 +330,29 @@ var ChangeEventPlugin = {
|
||||
}
|
||||
} else if (isTextInputElement(targetNode)) {
|
||||
if (isInputEventSupported) {
|
||||
getTargetInstFunc = getTargetInstForInputEvent;
|
||||
getTargetInstFunc = getTargetInstForInputOrChangeEvent;
|
||||
} else {
|
||||
getTargetInstFunc = getTargetInstForInputEventIE;
|
||||
handleEventFunc = handleEventsForInputEventIE;
|
||||
getTargetInstFunc = getTargetInstForInputEventPolyfill;
|
||||
handleEventFunc = handleEventsForInputEventPolyfill;
|
||||
}
|
||||
} else if (shouldUseClickEvent(targetNode)) {
|
||||
getTargetInstFunc = getTargetInstForClickEvent;
|
||||
}
|
||||
|
||||
if (getTargetInstFunc) {
|
||||
var inst = getTargetInstFunc(topLevelType, targetInst);
|
||||
var inst = getTargetInstFunc(topLevelType, targetInst, nativeEvent);
|
||||
if (inst) {
|
||||
var event = SyntheticEvent.getPooled(
|
||||
eventTypes.change,
|
||||
var event = createAndAccumulateChangeEvent(
|
||||
inst,
|
||||
nativeEvent,
|
||||
nativeEventTarget
|
||||
nativeEventTarget,
|
||||
);
|
||||
event.type = 'change';
|
||||
EventPropagators.accumulateTwoPhaseDispatches(event);
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
||||
if (handleEventFunc) {
|
||||
handleEventFunc(
|
||||
topLevelType,
|
||||
targetNode,
|
||||
targetInst
|
||||
);
|
||||
handleEventFunc(topLevelType, targetNode, targetInst);
|
||||
}
|
||||
|
||||
// When blurring, set the value attribute for number inputs
|
||||
@@ -406,7 +360,6 @@ var ChangeEventPlugin = {
|
||||
handleControlledInputBlur(targetInst, targetNode);
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
module.exports = ChangeEventPlugin;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user