Last active
April 5, 2016 22:06
-
-
Save zpao/19f61818c4f1957f1853b95a31e4bcd3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/React.js b/src/React.js | |
deleted file mode 100644 | |
index 5aa15e8..0000000 | |
--- a/src/React.js | |
+++ /dev/null | |
@@ -1,28 +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 React | |
- */ | |
- | |
-'use strict'; | |
- | |
-var ReactDOM = require('ReactDOM'); | |
-var ReactDOMServer = require('ReactDOMServer'); | |
-var ReactIsomorphic = require('ReactIsomorphic'); | |
- | |
-var assign = require('Object.assign'); | |
- | |
-// `version` will be added here by ReactIsomorphic. | |
-var React = {}; | |
- | |
-assign(React, ReactIsomorphic); | |
- | |
-React.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = ReactDOM; | |
-React.__SECRET_DOM_SERVER_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = ReactDOMServer; | |
- | |
-module.exports = React; | |
diff --git a/src/addons/ReactWithAddons.js b/src/addons/ReactWithAddons.js | |
index 755a1dc..bd13ea4 100644 | |
--- a/src/addons/ReactWithAddons.js | |
+++ b/src/addons/ReactWithAddons.js | |
@@ -9,13 +9,6 @@ | |
* @providesModule ReactWithAddons | |
*/ | |
-/** | |
- * This module exists purely in the open source project, and is meant as a way | |
- * to create a separate standalone build of React. This build has "addons", or | |
- * functionality we've built and think might be useful but doesn't have a good | |
- * place to live inside React core. | |
- */ | |
- | |
'use strict'; | |
var LinkedStateMixin = require('LinkedStateMixin'); | |
diff --git a/src/addons/transitions/ReactCSSTransitionGroup.js b/src/addons/transitions/ReactCSSTransitionGroup.js | |
index 5320188..4177ec7 100644 | |
--- a/src/addons/transitions/ReactCSSTransitionGroup.js | |
+++ b/src/addons/transitions/ReactCSSTransitionGroup.js | |
@@ -13,8 +13,6 @@ | |
var React = require('React'); | |
-var assign = require('Object.assign'); | |
- | |
var ReactTransitionGroup = require('ReactTransitionGroup'); | |
var ReactCSSTransitionGroupChild = require('ReactCSSTransitionGroupChild'); | |
@@ -87,7 +85,7 @@ var ReactCSSTransitionGroup = React.createClass({ | |
render: function() { | |
return React.createElement( | |
ReactTransitionGroup, | |
- assign({}, this.props, {childFactory: this._wrapChild}) | |
+ Object.assign({}, this.props, {childFactory: this._wrapChild}) | |
); | |
}, | |
}); | |
diff --git a/src/addons/transitions/ReactTransitionGroup.js b/src/addons/transitions/ReactTransitionGroup.js | |
index 816edfa..6d6df1a 100644 | |
--- a/src/addons/transitions/ReactTransitionGroup.js | |
+++ b/src/addons/transitions/ReactTransitionGroup.js | |
@@ -14,7 +14,6 @@ | |
var React = require('React'); | |
var ReactTransitionChildMapping = require('ReactTransitionChildMapping'); | |
-var assign = require('Object.assign'); | |
var emptyFunction = require('emptyFunction'); | |
var ReactTransitionGroup = React.createClass({ | |
@@ -193,7 +192,7 @@ var ReactTransitionGroup = React.createClass({ | |
this.performEnter(key); | |
} else { | |
this.setState(function(state) { | |
- var newChildren = assign({}, state.children); | |
+ var newChildren = Object.assign({}, state.children); | |
delete newChildren[key]; | |
return {children: newChildren}; | |
}); | |
diff --git a/src/addons/update.js b/src/addons/update.js | |
index 7c8ba4e..cc2434e 100644 | |
--- a/src/addons/update.js | |
+++ b/src/addons/update.js | |
@@ -13,7 +13,6 @@ | |
'use strict'; | |
-var assign = require('Object.assign'); | |
var keyOf = require('keyOf'); | |
var invariant = require('invariant'); | |
var hasOwnProperty = {}.hasOwnProperty; | |
@@ -22,7 +21,7 @@ function shallowCopy(x) { | |
if (Array.isArray(x)) { | |
return x.concat(); | |
} else if (x && typeof x === 'object') { | |
- return assign(new x.constructor(), x); | |
+ return Object.assign(new x.constructor(), x); | |
} else { | |
return x; | |
} | |
@@ -102,7 +101,7 @@ function update(value, spec) { | |
COMMAND_MERGE, | |
nextValue | |
); | |
- assign(nextValue, spec[COMMAND_MERGE]); | |
+ Object.assign(nextValue, spec[COMMAND_MERGE]); | |
} | |
if (hasOwnProperty.call(spec, COMMAND_PUSH)) { | |
diff --git a/src/isomorphic/React.js b/src/isomorphic/React.js | |
new file mode 100644 | |
index 0000000..37109d6 | |
--- /dev/null | |
+++ b/src/isomorphic/React.js | |
@@ -0,0 +1,73 @@ | |
+/** | |
+ * 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 React | |
+ */ | |
+ | |
+'use strict'; | |
+ | |
+var ReactChildren = require('ReactChildren'); | |
+var ReactComponent = require('ReactComponent'); | |
+var ReactClass = require('ReactClass'); | |
+var ReactDOMFactories = require('ReactDOMFactories'); | |
+var ReactElement = require('ReactElement'); | |
+var ReactElementValidator = require('ReactElementValidator'); | |
+var ReactPropTypes = require('ReactPropTypes'); | |
+var ReactVersion = require('ReactVersion'); | |
+ | |
+var onlyChild = require('onlyChild'); | |
+ | |
+var createElement = ReactElement.createElement; | |
+var createFactory = ReactElement.createFactory; | |
+var cloneElement = ReactElement.cloneElement; | |
+ | |
+if (__DEV__) { | |
+ createElement = ReactElementValidator.createElement; | |
+ createFactory = ReactElementValidator.createFactory; | |
+ cloneElement = ReactElementValidator.cloneElement; | |
+} | |
+ | |
+var React = { | |
+ | |
+ // Modern | |
+ | |
+ Children: { | |
+ map: ReactChildren.map, | |
+ forEach: ReactChildren.forEach, | |
+ count: ReactChildren.count, | |
+ toArray: ReactChildren.toArray, | |
+ only: onlyChild, | |
+ }, | |
+ | |
+ Component: ReactComponent, | |
+ | |
+ createElement: createElement, | |
+ cloneElement: cloneElement, | |
+ isValidElement: ReactElement.isValidElement, | |
+ | |
+ // Classic | |
+ | |
+ PropTypes: ReactPropTypes, | |
+ createClass: ReactClass.createClass, | |
+ createFactory: createFactory, | |
+ createMixin: function(mixin) { | |
+ // Currently a noop. Will be used to validate and trace mixins. | |
+ return mixin; | |
+ }, | |
+ | |
+ // This looks DOM specific but these are actually isomorphic helpers | |
+ // since they are just generating DOM strings. | |
+ DOM: ReactDOMFactories, | |
+ | |
+ version: ReactVersion, | |
+ | |
+ // Hook for JSX spread, don't use this for anything else. | |
+ __spread: Object.assign, | |
+}; | |
+ | |
+module.exports = React; | |
diff --git a/src/isomorphic/ReactDebugInstanceMap.js b/src/isomorphic/ReactDebugInstanceMap.js | |
new file mode 100644 | |
index 0000000..50dddf4 | |
--- /dev/null | |
+++ b/src/isomorphic/ReactDebugInstanceMap.js | |
@@ -0,0 +1,124 @@ | |
+/** | |
+ * Copyright 2016-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 ReactDebugInstanceMap | |
+ */ | |
+ | |
+'use strict'; | |
+ | |
+var warning = require('warning'); | |
+ | |
+function checkValidInstance(internalInstance) { | |
+ if (!internalInstance) { | |
+ warning( | |
+ false, | |
+ 'There is an internal error in the React developer tools integration. ' + | |
+ 'Instead of an internal instance, received %s. ' + | |
+ 'Please report this as a bug in React.', | |
+ internalInstance | |
+ ); | |
+ return false; | |
+ } | |
+ var isValid = typeof internalInstance.mountComponent === 'function'; | |
+ warning( | |
+ isValid, | |
+ 'There is an internal error in the React developer tools integration. ' + | |
+ 'Instead of an internal instance, received an object with the following ' + | |
+ 'keys: %s. Please report this as a bug in React.', | |
+ Object.keys(internalInstance).join(', ') | |
+ ); | |
+ return isValid; | |
+} | |
+ | |
+var idCounter = 1; | |
+var instancesByIDs = {}; | |
+var instancesToIDs; | |
+ | |
+function getIDForInstance(internalInstance) { | |
+ if (!instancesToIDs) { | |
+ instancesToIDs = new WeakMap(); | |
+ } | |
+ if (instancesToIDs.has(internalInstance)) { | |
+ return instancesToIDs.get(internalInstance); | |
+ } else { | |
+ var instanceID = (idCounter++).toString(); | |
+ instancesToIDs.set(internalInstance, instanceID); | |
+ return instanceID; | |
+ } | |
+} | |
+ | |
+function getInstanceByID(instanceID) { | |
+ return instancesByIDs[instanceID] || null; | |
+} | |
+ | |
+function isRegisteredInstance(internalInstance) { | |
+ var instanceID = getIDForInstance(internalInstance); | |
+ if (instanceID) { | |
+ return instancesByIDs.hasOwnProperty(instanceID); | |
+ } else { | |
+ return false; | |
+ } | |
+} | |
+ | |
+function registerInstance(internalInstance) { | |
+ var instanceID = getIDForInstance(internalInstance); | |
+ if (instanceID) { | |
+ instancesByIDs[instanceID] = internalInstance; | |
+ } | |
+} | |
+ | |
+function unregisterInstance(internalInstance) { | |
+ var instanceID = getIDForInstance(internalInstance); | |
+ if (instanceID) { | |
+ delete instancesByIDs[instanceID]; | |
+ } | |
+} | |
+ | |
+var ReactDebugInstanceMap = { | |
+ getIDForInstance(internalInstance) { | |
+ if (!checkValidInstance(internalInstance)) { | |
+ return null; | |
+ } | |
+ return getIDForInstance(internalInstance); | |
+ }, | |
+ getInstanceByID(instanceID) { | |
+ return getInstanceByID(instanceID); | |
+ }, | |
+ isRegisteredInstance(internalInstance) { | |
+ if (!checkValidInstance(internalInstance)) { | |
+ return false; | |
+ } | |
+ return isRegisteredInstance(internalInstance); | |
+ }, | |
+ registerInstance(internalInstance) { | |
+ if (!checkValidInstance(internalInstance)) { | |
+ return; | |
+ } | |
+ warning( | |
+ !isRegisteredInstance(internalInstance), | |
+ 'There is an internal error in the React developer tools integration. ' + | |
+ 'A registered instance should not be registered again. ' + | |
+ 'Please report this as a bug in React.' | |
+ ); | |
+ registerInstance(internalInstance); | |
+ }, | |
+ unregisterInstance(internalInstance) { | |
+ if (!checkValidInstance(internalInstance)) { | |
+ return; | |
+ } | |
+ warning( | |
+ isRegisteredInstance(internalInstance), | |
+ 'There is an internal error in the React developer tools integration. ' + | |
+ 'An unregistered instance should not be unregistered again. ' + | |
+ 'Please report this as a bug in React.' | |
+ ); | |
+ unregisterInstance(internalInstance); | |
+ }, | |
+}; | |
+ | |
+module.exports = ReactDebugInstanceMap; | |
diff --git a/src/isomorphic/ReactIsomorphic.js b/src/isomorphic/ReactIsomorphic.js | |
deleted file mode 100644 | |
index 8eca054..0000000 | |
--- a/src/isomorphic/ReactIsomorphic.js | |
+++ /dev/null | |
@@ -1,74 +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 ReactIsomorphic | |
- */ | |
- | |
-'use strict'; | |
- | |
-var ReactChildren = require('ReactChildren'); | |
-var ReactComponent = require('ReactComponent'); | |
-var ReactClass = require('ReactClass'); | |
-var ReactDOMFactories = require('ReactDOMFactories'); | |
-var ReactElement = require('ReactElement'); | |
-var ReactElementValidator = require('ReactElementValidator'); | |
-var ReactPropTypes = require('ReactPropTypes'); | |
-var ReactVersion = require('ReactVersion'); | |
- | |
-var assign = require('Object.assign'); | |
-var onlyChild = require('onlyChild'); | |
- | |
-var createElement = ReactElement.createElement; | |
-var createFactory = ReactElement.createFactory; | |
-var cloneElement = ReactElement.cloneElement; | |
- | |
-if (__DEV__) { | |
- createElement = ReactElementValidator.createElement; | |
- createFactory = ReactElementValidator.createFactory; | |
- cloneElement = ReactElementValidator.cloneElement; | |
-} | |
- | |
-var React = { | |
- | |
- // Modern | |
- | |
- Children: { | |
- map: ReactChildren.map, | |
- forEach: ReactChildren.forEach, | |
- count: ReactChildren.count, | |
- toArray: ReactChildren.toArray, | |
- only: onlyChild, | |
- }, | |
- | |
- Component: ReactComponent, | |
- | |
- createElement: createElement, | |
- cloneElement: cloneElement, | |
- isValidElement: ReactElement.isValidElement, | |
- | |
- // Classic | |
- | |
- PropTypes: ReactPropTypes, | |
- createClass: ReactClass.createClass, | |
- createFactory: createFactory, | |
- createMixin: function(mixin) { | |
- // Currently a noop. Will be used to validate and trace mixins. | |
- return mixin; | |
- }, | |
- | |
- // This looks DOM specific but these are actually isomorphic helpers | |
- // since they are just generating DOM strings. | |
- DOM: ReactDOMFactories, | |
- | |
- version: ReactVersion, | |
- | |
- // Hook for JSX spread, don't use this for anything else. | |
- __spread: assign, | |
-}; | |
- | |
-module.exports = React; | |
diff --git a/src/isomorphic/__tests__/ReactDebugInstanceMap-test.js b/src/isomorphic/__tests__/ReactDebugInstanceMap-test.js | |
new file mode 100644 | |
index 0000000..d9a063e | |
--- /dev/null | |
+++ b/src/isomorphic/__tests__/ReactDebugInstanceMap-test.js | |
@@ -0,0 +1,173 @@ | |
+/** | |
+ * Copyright 2016-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('ReactDebugInstanceMap', function() { | |
+ var React; | |
+ var ReactDebugInstanceMap; | |
+ var ReactDOM; | |
+ | |
+ beforeEach(function() { | |
+ jest.resetModuleRegistry(); | |
+ React = require('React'); | |
+ ReactDebugInstanceMap = require('ReactDebugInstanceMap'); | |
+ ReactDOM = require('ReactDOM'); | |
+ }); | |
+ | |
+ function createStubInstance() { | |
+ return { mountComponent: () => {} }; | |
+ } | |
+ | |
+ it('should register and unregister instances', function() { | |
+ var inst1 = createStubInstance(); | |
+ var inst2 = createStubInstance(); | |
+ | |
+ expect(ReactDebugInstanceMap.isRegisteredInstance(inst1)).toBe(false); | |
+ expect(ReactDebugInstanceMap.isRegisteredInstance(inst2)).toBe(false); | |
+ | |
+ ReactDebugInstanceMap.registerInstance(inst1); | |
+ expect(ReactDebugInstanceMap.isRegisteredInstance(inst1)).toBe(true); | |
+ expect(ReactDebugInstanceMap.isRegisteredInstance(inst2)).toBe(false); | |
+ | |
+ ReactDebugInstanceMap.registerInstance(inst2); | |
+ expect(ReactDebugInstanceMap.isRegisteredInstance(inst1)).toBe(true); | |
+ expect(ReactDebugInstanceMap.isRegisteredInstance(inst2)).toBe(true); | |
+ | |
+ ReactDebugInstanceMap.unregisterInstance(inst2); | |
+ expect(ReactDebugInstanceMap.isRegisteredInstance(inst1)).toBe(true); | |
+ expect(ReactDebugInstanceMap.isRegisteredInstance(inst2)).toBe(false); | |
+ | |
+ ReactDebugInstanceMap.unregisterInstance(inst1); | |
+ expect(ReactDebugInstanceMap.isRegisteredInstance(inst1)).toBe(false); | |
+ expect(ReactDebugInstanceMap.isRegisteredInstance(inst2)).toBe(false); | |
+ }); | |
+ | |
+ it('should assign stable IDs', function() { | |
+ var inst1 = createStubInstance(); | |
+ var inst2 = createStubInstance(); | |
+ | |
+ var inst1ID = ReactDebugInstanceMap.getIDForInstance(inst1); | |
+ var inst2ID = ReactDebugInstanceMap.getIDForInstance(inst2); | |
+ expect(typeof inst1ID).toBe('string'); | |
+ expect(typeof inst2ID).toBe('string'); | |
+ expect(inst1ID).not.toBe(inst2ID); | |
+ | |
+ ReactDebugInstanceMap.registerInstance(inst1); | |
+ ReactDebugInstanceMap.registerInstance(inst2); | |
+ expect(ReactDebugInstanceMap.getIDForInstance(inst1)).toBe(inst1ID); | |
+ expect(ReactDebugInstanceMap.getIDForInstance(inst2)).toBe(inst2ID); | |
+ | |
+ ReactDebugInstanceMap.unregisterInstance(inst1); | |
+ ReactDebugInstanceMap.unregisterInstance(inst2); | |
+ expect(ReactDebugInstanceMap.getIDForInstance(inst1)).toBe(inst1ID); | |
+ expect(ReactDebugInstanceMap.getIDForInstance(inst2)).toBe(inst2ID); | |
+ }); | |
+ | |
+ it('should retrieve registered instance by its ID', function() { | |
+ var inst1 = createStubInstance(); | |
+ var inst2 = createStubInstance(); | |
+ | |
+ var inst1ID = ReactDebugInstanceMap.getIDForInstance(inst1); | |
+ var inst2ID = ReactDebugInstanceMap.getIDForInstance(inst2); | |
+ expect(ReactDebugInstanceMap.getInstanceByID(inst1ID)).toBe(null); | |
+ expect(ReactDebugInstanceMap.getInstanceByID(inst2ID)).toBe(null); | |
+ | |
+ ReactDebugInstanceMap.registerInstance(inst1); | |
+ ReactDebugInstanceMap.registerInstance(inst2); | |
+ expect(ReactDebugInstanceMap.getInstanceByID(inst1ID)).toBe(inst1); | |
+ expect(ReactDebugInstanceMap.getInstanceByID(inst2ID)).toBe(inst2); | |
+ | |
+ ReactDebugInstanceMap.unregisterInstance(inst1); | |
+ ReactDebugInstanceMap.unregisterInstance(inst2); | |
+ expect(ReactDebugInstanceMap.getInstanceByID(inst1ID)).toBe(null); | |
+ expect(ReactDebugInstanceMap.getInstanceByID(inst2ID)).toBe(null); | |
+ }); | |
+ | |
+ it('should warn when registering an instance twice', function() { | |
+ spyOn(console, 'error'); | |
+ | |
+ var inst = createStubInstance(); | |
+ ReactDebugInstanceMap.registerInstance(inst); | |
+ expect(console.error.argsForCall.length).toBe(0); | |
+ | |
+ ReactDebugInstanceMap.registerInstance(inst); | |
+ expect(console.error.argsForCall.length).toBe(1); | |
+ expect(console.error.argsForCall[0][0]).toContain( | |
+ 'There is an internal error in the React developer tools integration. ' + | |
+ 'A registered instance should not be registered again. ' + | |
+ 'Please report this as a bug in React.' | |
+ ); | |
+ | |
+ ReactDebugInstanceMap.unregisterInstance(inst); | |
+ ReactDebugInstanceMap.registerInstance(inst); | |
+ expect(console.error.argsForCall.length).toBe(1); | |
+ }); | |
+ | |
+ it('should warn when unregistering an instance twice', function() { | |
+ spyOn(console, 'error'); | |
+ var inst = createStubInstance(); | |
+ | |
+ ReactDebugInstanceMap.unregisterInstance(inst); | |
+ expect(console.error.argsForCall.length).toBe(1); | |
+ expect(console.error.argsForCall[0][0]).toContain( | |
+ 'There is an internal error in the React developer tools integration. ' + | |
+ 'An unregistered instance should not be unregistered again. ' + | |
+ 'Please report this as a bug in React.' | |
+ ); | |
+ | |
+ ReactDebugInstanceMap.registerInstance(inst); | |
+ ReactDebugInstanceMap.unregisterInstance(inst); | |
+ expect(console.error.argsForCall.length).toBe(1); | |
+ | |
+ ReactDebugInstanceMap.unregisterInstance(inst); | |
+ expect(console.error.argsForCall.length).toBe(2); | |
+ expect(console.error.argsForCall[1][0]).toContain( | |
+ 'There is an internal error in the React developer tools integration. ' + | |
+ 'An unregistered instance should not be unregistered again. ' + | |
+ 'Please report this as a bug in React.' | |
+ ); | |
+ }); | |
+ | |
+ it('should warn about anything than is not an internal instance', function() { | |
+ class Foo extends React.Component { | |
+ render() { | |
+ return <div />; | |
+ } | |
+ } | |
+ | |
+ spyOn(console, 'error'); | |
+ var warningCount = 0; | |
+ var div = document.createElement('div'); | |
+ var publicInst = ReactDOM.render(<Foo />, div); | |
+ | |
+ [false, null, undefined, {}, div, publicInst].forEach(falsyValue => { | |
+ ReactDebugInstanceMap.registerInstance(falsyValue); | |
+ warningCount++; | |
+ expect(ReactDebugInstanceMap.getIDForInstance(falsyValue)).toBe(null); | |
+ warningCount++; | |
+ expect(ReactDebugInstanceMap.isRegisteredInstance(falsyValue)).toBe(false); | |
+ warningCount++; | |
+ ReactDebugInstanceMap.unregisterInstance(falsyValue); | |
+ warningCount++; | |
+ }); | |
+ | |
+ expect(console.error.argsForCall.length).toBe(warningCount); | |
+ for (var i = 0; i < warningCount.length; i++) { | |
+ // Ideally we could check for the more detailed error message here | |
+ // but it depends on the input type and is meant for internal bugs | |
+ // anyway so I don't think it's worth complicating the test with it. | |
+ expect(console.error.argsForCall[i][0]).toContain( | |
+ 'There is an internal error in the React developer tools integration.' | |
+ ); | |
+ } | |
+ }); | |
+}); | |
diff --git a/src/isomorphic/classic/__tests__/ReactContextValidator-test.js b/src/isomorphic/classic/__tests__/ReactContextValidator-test.js | |
index 891cce6..cc09080 100644 | |
--- a/src/isomorphic/classic/__tests__/ReactContextValidator-test.js | |
+++ b/src/isomorphic/classic/__tests__/ReactContextValidator-test.js | |
@@ -31,8 +31,6 @@ describe('ReactContextValidator', function() { | |
ReactDOM = require('ReactDOM'); | |
ReactTestUtils = require('ReactTestUtils'); | |
reactComponentExpect = require('reactComponentExpect'); | |
- | |
- spyOn(console, 'error'); | |
}); | |
// TODO: This behavior creates a runtime dependency on propTypes. We should | |
@@ -133,6 +131,8 @@ describe('ReactContextValidator', function() { | |
}); | |
it('should check context types', function() { | |
+ spyOn(console, 'error'); | |
+ | |
var Component = React.createClass({ | |
contextTypes: { | |
foo: React.PropTypes.string.isRequired, | |
@@ -202,6 +202,8 @@ describe('ReactContextValidator', function() { | |
}); | |
it('should check child context types', function() { | |
+ spyOn(console, 'error'); | |
+ | |
var Component = React.createClass({ | |
childContextTypes: { | |
foo: React.PropTypes.string.isRequired, | |
diff --git a/src/isomorphic/classic/class/ReactClass.js b/src/isomorphic/classic/class/ReactClass.js | |
index 223e58b..56f479a 100644 | |
--- a/src/isomorphic/classic/class/ReactClass.js | |
+++ b/src/isomorphic/classic/class/ReactClass.js | |
@@ -17,7 +17,6 @@ var ReactPropTypeLocations = require('ReactPropTypeLocations'); | |
var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames'); | |
var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue'); | |
-var assign = require('Object.assign'); | |
var emptyObject = require('emptyObject'); | |
var invariant = require('invariant'); | |
var keyMirror = require('keyMirror'); | |
@@ -331,7 +330,7 @@ var RESERVED_SPEC_KEYS = { | |
ReactPropTypeLocations.childContext | |
); | |
} | |
- Constructor.childContextTypes = assign( | |
+ Constructor.childContextTypes = Object.assign( | |
{}, | |
Constructor.childContextTypes, | |
childContextTypes | |
@@ -345,7 +344,7 @@ var RESERVED_SPEC_KEYS = { | |
ReactPropTypeLocations.context | |
); | |
} | |
- Constructor.contextTypes = assign( | |
+ Constructor.contextTypes = Object.assign( | |
{}, | |
Constructor.contextTypes, | |
contextTypes | |
@@ -373,7 +372,7 @@ var RESERVED_SPEC_KEYS = { | |
ReactPropTypeLocations.prop | |
); | |
} | |
- Constructor.propTypes = assign( | |
+ Constructor.propTypes = Object.assign( | |
{}, | |
Constructor.propTypes, | |
propTypes | |
@@ -710,7 +709,7 @@ var ReactClassMixin = { | |
replaceState: function(newState, callback) { | |
this.updater.enqueueReplaceState(this, newState); | |
if (callback) { | |
- this.updater.enqueueCallback(this, callback); | |
+ this.updater.enqueueCallback(this, callback, 'replaceState'); | |
} | |
}, | |
@@ -726,7 +725,7 @@ var ReactClassMixin = { | |
}; | |
var ReactClassComponent = function() {}; | |
-assign( | |
+Object.assign( | |
ReactClassComponent.prototype, | |
ReactComponent.prototype, | |
ReactClassMixin | |
diff --git a/src/isomorphic/classic/class/__tests__/ReactClass-test.js b/src/isomorphic/classic/class/__tests__/ReactClass-test.js | |
index cce8554..07a1e4b 100644 | |
--- a/src/isomorphic/classic/class/__tests__/ReactClass-test.js | |
+++ b/src/isomorphic/classic/class/__tests__/ReactClass-test.js | |
@@ -21,7 +21,6 @@ describe('ReactClass-spec', function() { | |
React = require('React'); | |
ReactDOM = require('ReactDOM'); | |
ReactTestUtils = require('ReactTestUtils'); | |
- spyOn(console, 'error'); | |
}); | |
it('should throw when `render` is not specified', function() { | |
@@ -60,76 +59,62 @@ describe('ReactClass-spec', function() { | |
}); | |
it('should warn on invalid prop types', function() { | |
- var warn = console.error; | |
- console.error = jest.genMockFn(); | |
- try { | |
- | |
- React.createClass({ | |
- displayName: 'Component', | |
- propTypes: { | |
- prop: null, | |
- }, | |
- render: function() { | |
- return <span>{this.props.prop}</span>; | |
- }, | |
- }); | |
- expect(console.error.mock.calls.length).toBe(1); | |
- expect(console.error.mock.calls[0][0]).toBe( | |
- 'Warning: Component: prop type `prop` is invalid; ' + | |
- 'it must be a function, usually from React.PropTypes.' | |
- ); | |
- } finally { | |
- console.error = warn; | |
- } | |
+ spyOn(console, 'error'); | |
+ React.createClass({ | |
+ displayName: 'Component', | |
+ propTypes: { | |
+ prop: null, | |
+ }, | |
+ render: function() { | |
+ return <span>{this.props.prop}</span>; | |
+ }, | |
+ }); | |
+ expect(console.error.argsForCall.length).toBe(1); | |
+ expect(console.error.argsForCall[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', function() { | |
- var warn = console.error; | |
- console.error = jest.genMockFn(); | |
- try { | |
- React.createClass({ | |
- displayName: 'Component', | |
- contextTypes: { | |
- prop: null, | |
- }, | |
- render: function() { | |
- return <span>{this.props.prop}</span>; | |
- }, | |
- }); | |
- expect(console.error.mock.calls.length).toBe(1); | |
- expect(console.error.mock.calls[0][0]).toBe( | |
- 'Warning: Component: context type `prop` is invalid; ' + | |
- 'it must be a function, usually from React.PropTypes.' | |
- ); | |
- } finally { | |
- console.error = warn; | |
- } | |
+ spyOn(console, 'error'); | |
+ React.createClass({ | |
+ displayName: 'Component', | |
+ contextTypes: { | |
+ prop: null, | |
+ }, | |
+ render: function() { | |
+ return <span>{this.props.prop}</span>; | |
+ }, | |
+ }); | |
+ expect(console.error.argsForCall.length).toBe(1); | |
+ expect(console.error.argsForCall[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', function() { | |
- var warn = console.error; | |
- console.error = jest.genMockFn(); | |
- try { | |
- React.createClass({ | |
- displayName: 'Component', | |
- childContextTypes: { | |
- prop: null, | |
- }, | |
- render: function() { | |
- return <span>{this.props.prop}</span>; | |
- }, | |
- }); | |
- expect(console.error.mock.calls.length).toBe(1); | |
- expect(console.error.mock.calls[0][0]).toBe( | |
- 'Warning: Component: child context type `prop` is invalid; ' + | |
- 'it must be a function, usually from React.PropTypes.' | |
- ); | |
- } finally { | |
- console.error = warn; | |
- } | |
+ spyOn(console, 'error'); | |
+ React.createClass({ | |
+ displayName: 'Component', | |
+ childContextTypes: { | |
+ prop: null, | |
+ }, | |
+ render: function() { | |
+ return <span>{this.props.prop}</span>; | |
+ }, | |
+ }); | |
+ expect(console.error.argsForCall.length).toBe(1); | |
+ expect(console.error.argsForCall[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', function() { | |
+ spyOn(console, 'error'); | |
+ | |
React.createClass({ | |
componentShouldUpdate: function() { | |
return false; | |
@@ -163,6 +148,7 @@ describe('ReactClass-spec', function() { | |
}); | |
it('should warn when mispelling componentWillReceiveProps', function() { | |
+ spyOn(console, 'error'); | |
React.createClass({ | |
componentWillRecieveProps: function() { | |
return false; | |
@@ -204,6 +190,7 @@ describe('ReactClass-spec', function() { | |
// TODO: Consider actually moving these to statics or drop this unit test. | |
xit('should warn when using deprecated non-static spec keys', function() { | |
+ spyOn(console, 'error'); | |
React.createClass({ | |
mixins: [{}], | |
propTypes: { | |
@@ -348,6 +335,7 @@ describe('ReactClass-spec', function() { | |
}); | |
it('should throw when using legacy factories', function() { | |
+ spyOn(console, 'error'); | |
var Component = React.createClass({ | |
render() { | |
return <div />; | |
@@ -355,7 +343,7 @@ describe('ReactClass-spec', function() { | |
}); | |
expect(() => Component()).toThrow(); | |
- expect(console.error.calls.length).toBe(1); | |
+ expect(console.error.argsForCall.length).toBe(1); | |
expect(console.error.argsForCall[0][0]).toBe( | |
'Warning: Something is calling a React component directly. Use a ' + | |
'factory or JSX instead. See: https://fb.me/react-legacyfactory' | |
diff --git a/src/isomorphic/classic/element/ReactElement.js b/src/isomorphic/classic/element/ReactElement.js | |
index 6e37159..ee46a5f 100644 | |
--- a/src/isomorphic/classic/element/ReactElement.js | |
+++ b/src/isomorphic/classic/element/ReactElement.js | |
@@ -13,7 +13,6 @@ | |
var ReactCurrentOwner = require('ReactCurrentOwner'); | |
-var assign = require('Object.assign'); | |
var warning = require('warning'); | |
var canDefineProperty = require('canDefineProperty'); | |
@@ -253,7 +252,7 @@ ReactElement.cloneElement = function(element, config, children) { | |
var propName; | |
// Original props are copied | |
- var props = assign({}, element.props); | |
+ var props = Object.assign({}, element.props); | |
// Reserved names are extracted | |
var key = element.key; | |
diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js | |
index abfa976..9601e67 100644 | |
--- a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js | |
+++ b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js | |
@@ -241,7 +241,6 @@ describe('ReactPropTypes', function() { | |
return <div>{this.props.label}</div>; | |
}, | |
}); | |
- spyOn(console, 'error'); | |
}); | |
it('should support components', () => { | |
@@ -258,6 +257,8 @@ describe('ReactPropTypes', function() { | |
}); | |
it('should be able to define a single child as label', () => { | |
+ spyOn(console, 'error'); | |
+ | |
var instance = <Component label={<div />} />; | |
instance = ReactTestUtils.renderIntoDocument(instance); | |
@@ -265,6 +266,8 @@ describe('ReactPropTypes', function() { | |
}); | |
it('should warn when passing no label and isRequired is set', () => { | |
+ spyOn(console, 'error'); | |
+ | |
var instance = <Component />; | |
instance = ReactTestUtils.renderIntoDocument(instance); | |
@@ -782,7 +785,6 @@ describe('ReactPropTypes', function() { | |
describe('Custom validator', function() { | |
beforeEach(function() { | |
jest.resetModuleRegistry(); | |
- spyOn(console, 'error'); | |
}); | |
it('should have been called with the right params', function() { | |
@@ -820,6 +822,8 @@ describe('ReactPropTypes', function() { | |
}); | |
it('should have received the validator\'s return value', function() { | |
+ spyOn(console, 'error'); | |
+ | |
var spy = jasmine.createSpy().andCallFake( | |
function(props, propName, componentName) { | |
if (props[propName] !== 5) { | |
@@ -845,6 +849,8 @@ describe('ReactPropTypes', function() { | |
it('should not warn if the validator returned null', | |
function() { | |
+ spyOn(console, 'error'); | |
+ | |
var spy = jasmine.createSpy().andCallFake( | |
function(props, propName, componentName) { | |
return null; | |
diff --git a/src/isomorphic/deprecated/OrderedMap.js b/src/isomorphic/deprecated/OrderedMap.js | |
index 92cea05..4336cdc 100644 | |
--- a/src/isomorphic/deprecated/OrderedMap.js | |
+++ b/src/isomorphic/deprecated/OrderedMap.js | |
@@ -11,7 +11,6 @@ | |
'use strict'; | |
-var assign = require('Object.assign'); | |
var invariant = require('invariant'); | |
var PREFIX = 'key:'; | |
@@ -475,7 +474,7 @@ var OrderedMapMethods = { | |
}, | |
}; | |
-assign(OrderedMapImpl.prototype, OrderedMapMethods); | |
+Object.assign(OrderedMapImpl.prototype, OrderedMapMethods); | |
var OrderedMap = { | |
from: function(orderedMap) { | |
diff --git a/src/isomorphic/deprecated/ReactPropTransferer.js b/src/isomorphic/deprecated/ReactPropTransferer.js | |
index b3e2a82..da009ca 100644 | |
--- a/src/isomorphic/deprecated/ReactPropTransferer.js | |
+++ b/src/isomorphic/deprecated/ReactPropTransferer.js | |
@@ -11,7 +11,6 @@ | |
'use strict'; | |
-var assign = require('Object.assign'); | |
var emptyFunction = require('emptyFunction'); | |
var joinClasses = require('joinClasses'); | |
@@ -36,7 +35,7 @@ var transferStrategyMerge = createTransferStrategy(function(a, b) { | |
// `merge` overrides the first object's (`props[key]` above) keys using the | |
// second object's (`value`) keys. An object's style's existing `propA` would | |
// get overridden. Flip the order here. | |
- return assign({}, b, a); | |
+ return Object.assign({}, b, a); | |
}); | |
/** | |
@@ -100,7 +99,7 @@ var ReactPropTransferer = { | |
* @return {object} a new object containing both sets of props merged. | |
*/ | |
mergeProps: function(oldProps, newProps) { | |
- return transferInto(assign({}, oldProps), newProps); | |
+ return transferInto(Object.assign({}, oldProps), newProps); | |
}, | |
}; | |
diff --git a/src/isomorphic/modern/class/ReactComponent.js b/src/isomorphic/modern/class/ReactComponent.js | |
index a7d8b4b..a775abd 100644 | |
--- a/src/isomorphic/modern/class/ReactComponent.js | |
+++ b/src/isomorphic/modern/class/ReactComponent.js | |
@@ -76,7 +76,7 @@ ReactComponent.prototype.setState = function(partialState, callback) { | |
} | |
this.updater.enqueueSetState(this, partialState); | |
if (callback) { | |
- this.updater.enqueueCallback(this, callback); | |
+ this.updater.enqueueCallback(this, callback, 'setState'); | |
} | |
}; | |
@@ -97,7 +97,7 @@ ReactComponent.prototype.setState = function(partialState, callback) { | |
ReactComponent.prototype.forceUpdate = function(callback) { | |
this.updater.enqueueForceUpdate(this); | |
if (callback) { | |
- this.updater.enqueueCallback(this, callback); | |
+ this.updater.enqueueCallback(this, callback, 'forceUpdate'); | |
} | |
}; | |
diff --git a/src/renderers/dom/__tests__/ReactDOMProduction-test.js b/src/renderers/dom/__tests__/ReactDOMProduction-test.js | |
index 8850655..dd5a96a 100644 | |
--- a/src/renderers/dom/__tests__/ReactDOMProduction-test.js | |
+++ b/src/renderers/dom/__tests__/ReactDOMProduction-test.js | |
@@ -18,7 +18,7 @@ describe('ReactDOMProduction', function() { | |
var ReactDOM; | |
beforeEach(function() { | |
- __DEV__ = true; | |
+ __DEV__ = false; | |
oldProcess = process; | |
global.process = {env: {NODE_ENV: 'production'}}; | |
@@ -28,7 +28,7 @@ describe('ReactDOMProduction', function() { | |
}); | |
afterEach(function() { | |
- __DEV__ = false; | |
+ __DEV__ = true; | |
global.process = oldProcess; | |
}); | |
diff --git a/src/renderers/dom/client/ReactBrowserEventEmitter.js b/src/renderers/dom/client/ReactBrowserEventEmitter.js | |
index 5f5dc8d..dd7334f 100644 | |
--- a/src/renderers/dom/client/ReactBrowserEventEmitter.js | |
+++ b/src/renderers/dom/client/ReactBrowserEventEmitter.js | |
@@ -16,7 +16,6 @@ var EventPluginRegistry = require('EventPluginRegistry'); | |
var ReactEventEmitterMixin = require('ReactEventEmitterMixin'); | |
var ViewportMetrics = require('ViewportMetrics'); | |
-var assign = require('Object.assign'); | |
var getVendorPrefixedEventName = require('getVendorPrefixedEventName'); | |
var isEventSupported = require('isEventSupported'); | |
@@ -175,7 +174,7 @@ function getListeningForDocument(mountAt) { | |
* | |
* @internal | |
*/ | |
-var ReactBrowserEventEmitter = assign({}, ReactEventEmitterMixin, { | |
+var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, { | |
/** | |
* Injectable event backend | |
diff --git a/src/renderers/dom/client/ReactEventListener.js b/src/renderers/dom/client/ReactEventListener.js | |
index 1d69e02..bbdbbcf 100644 | |
--- a/src/renderers/dom/client/ReactEventListener.js | |
+++ b/src/renderers/dom/client/ReactEventListener.js | |
@@ -17,7 +17,6 @@ var PooledClass = require('PooledClass'); | |
var ReactDOMComponentTree = require('ReactDOMComponentTree'); | |
var ReactUpdates = require('ReactUpdates'); | |
-var assign = require('Object.assign'); | |
var getEventTarget = require('getEventTarget'); | |
var getUnboundedScrollPosition = require('getUnboundedScrollPosition'); | |
@@ -44,7 +43,7 @@ function TopLevelCallbackBookKeeping(topLevelType, nativeEvent) { | |
this.nativeEvent = nativeEvent; | |
this.ancestors = []; | |
} | |
-assign(TopLevelCallbackBookKeeping.prototype, { | |
+Object.assign(TopLevelCallbackBookKeeping.prototype, { | |
destructor: function() { | |
this.topLevelType = null; | |
this.nativeEvent = null; | |
diff --git a/src/renderers/dom/client/ReactMount.js b/src/renderers/dom/client/ReactMount.js | |
index ac6e684..7f6f8ca 100644 | |
--- a/src/renderers/dom/client/ReactMount.js | |
+++ b/src/renderers/dom/client/ReactMount.js | |
@@ -382,6 +382,7 @@ var ReactMount = { | |
}, | |
_renderSubtreeIntoContainer: function(parentComponent, nextElement, container, callback) { | |
+ ReactUpdateQueue.validateCallback(callback, 'ReactDOM.render'); | |
invariant( | |
ReactElement.isValidElement(nextElement), | |
'ReactDOM.render(): Invalid component element.%s', | |
diff --git a/src/renderers/dom/client/ReactReconcileTransaction.js b/src/renderers/dom/client/ReactReconcileTransaction.js | |
index 1835a2d..fedd883 100644 | |
--- a/src/renderers/dom/client/ReactReconcileTransaction.js | |
+++ b/src/renderers/dom/client/ReactReconcileTransaction.js | |
@@ -17,7 +17,6 @@ var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter'); | |
var ReactInputSelection = require('ReactInputSelection'); | |
var Transaction = require('Transaction'); | |
-var assign = require('Object.assign'); | |
/** | |
* Ensures that, when possible, the selection range (currently selected text | |
@@ -160,7 +159,7 @@ var Mixin = { | |
}; | |
-assign(ReactReconcileTransaction.prototype, Transaction.Mixin, Mixin); | |
+Object.assign(ReactReconcileTransaction.prototype, Transaction.Mixin, Mixin); | |
PooledClass.addPoolingTo(ReactReconcileTransaction); | |
diff --git a/src/renderers/dom/client/__tests__/ReactDOM-test.js b/src/renderers/dom/client/__tests__/ReactDOM-test.js | |
index b55381f..9c3cef5 100644 | |
--- a/src/renderers/dom/client/__tests__/ReactDOM-test.js | |
+++ b/src/renderers/dom/client/__tests__/ReactDOM-test.js | |
@@ -118,4 +118,63 @@ describe('ReactDOM', function() { | |
expect(console.error.argsForCall.length).toBe(0); | |
}); | |
+ it('throws in render() if the mount callback is not a function', function() { | |
+ function Foo() { | |
+ this.a = 1; | |
+ this.b = 2; | |
+ } | |
+ var A = React.createClass({ | |
+ getInitialState: function() { | |
+ return {}; | |
+ }, | |
+ render: function() { | |
+ return <div />; | |
+ }, | |
+ }); | |
+ | |
+ var myDiv = document.createElement('div'); | |
+ expect(() => ReactDOM.render(<A />, myDiv, 'no')).toThrow( | |
+ 'ReactDOM.render(...): Expected the last optional `callback` argument ' + | |
+ 'to be a function. Instead received: string.' | |
+ ); | |
+ expect(() => ReactDOM.render(<A />, myDiv, {})).toThrow( | |
+ 'ReactDOM.render(...): Expected the last optional `callback` argument ' + | |
+ 'to be a function. Instead received: Object.' | |
+ ); | |
+ expect(() => ReactDOM.render(<A />, myDiv, new Foo())).toThrow( | |
+ 'ReactDOM.render(...): Expected the last optional `callback` argument ' + | |
+ 'to be a function. Instead received: Foo (keys: a, b).' | |
+ ); | |
+ }); | |
+ | |
+ it('throws in render() if the update callback is not a function', function() { | |
+ function Foo() { | |
+ this.a = 1; | |
+ this.b = 2; | |
+ } | |
+ var A = React.createClass({ | |
+ getInitialState: function() { | |
+ return {}; | |
+ }, | |
+ render: function() { | |
+ return <div />; | |
+ }, | |
+ }); | |
+ | |
+ var myDiv = document.createElement('div'); | |
+ ReactDOM.render(<A />, myDiv); | |
+ | |
+ expect(() => ReactDOM.render(<A />, myDiv, 'no')).toThrow( | |
+ 'ReactDOM.render(...): Expected the last optional `callback` argument ' + | |
+ 'to be a function. Instead received: string.' | |
+ ); | |
+ expect(() => ReactDOM.render(<A />, myDiv, {})).toThrow( | |
+ 'ReactDOM.render(...): Expected the last optional `callback` argument ' + | |
+ 'to be a function. Instead received: Object.' | |
+ ); | |
+ expect(() => ReactDOM.render(<A />, myDiv, new Foo())).toThrow( | |
+ 'ReactDOM.render(...): Expected the last optional `callback` argument ' + | |
+ 'to be a function. Instead received: Foo (keys: a, b).' | |
+ ); | |
+ }); | |
}); | |
diff --git a/src/renderers/dom/client/__tests__/findDOMNode-test.js b/src/renderers/dom/client/__tests__/findDOMNode-test.js | |
index cdcc780..1f861dd 100644 | |
--- a/src/renderers/dom/client/__tests__/findDOMNode-test.js | |
+++ b/src/renderers/dom/client/__tests__/findDOMNode-test.js | |
@@ -58,4 +58,17 @@ describe('findDOMNode', function() { | |
); | |
}); | |
+ it('findDOMNode should not throw an error when called within a component that is not mounted', function() { | |
+ var Bar = React.createClass({ | |
+ componentWillMount: function() { | |
+ expect(ReactDOM.findDOMNode(this)).toBeNull(); | |
+ }, | |
+ render: function() { | |
+ return <div/>; | |
+ }, | |
+ }); | |
+ | |
+ expect(() => ReactTestUtils.renderIntoDocument(<Bar/>)).not.toThrow(); | |
+ }); | |
+ | |
}); | |
diff --git a/src/renderers/dom/client/eventPlugins/FallbackCompositionState.js b/src/renderers/dom/client/eventPlugins/FallbackCompositionState.js | |
index 68c1284..e26e259 100644 | |
--- a/src/renderers/dom/client/eventPlugins/FallbackCompositionState.js | |
+++ b/src/renderers/dom/client/eventPlugins/FallbackCompositionState.js | |
@@ -13,7 +13,6 @@ | |
var PooledClass = require('PooledClass'); | |
-var assign = require('Object.assign'); | |
var getTextContentAccessor = require('getTextContentAccessor'); | |
/** | |
@@ -33,7 +32,7 @@ function FallbackCompositionState(root) { | |
this._fallbackText = null; | |
} | |
-assign(FallbackCompositionState.prototype, { | |
+Object.assign(FallbackCompositionState.prototype, { | |
destructor: function() { | |
this._root = null; | |
this._startText = null; | |
diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticEvent.js | |
index daad64d..d3cdf3c 100644 | |
--- a/src/renderers/dom/client/syntheticEvents/SyntheticEvent.js | |
+++ b/src/renderers/dom/client/syntheticEvents/SyntheticEvent.js | |
@@ -13,7 +13,6 @@ | |
var PooledClass = require('PooledClass'); | |
-var assign = require('Object.assign'); | |
var emptyFunction = require('emptyFunction'); | |
var warning = require('warning'); | |
@@ -111,7 +110,7 @@ function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarg | |
return this; | |
} | |
-assign(SyntheticEvent.prototype, { | |
+Object.assign(SyntheticEvent.prototype, { | |
preventDefault: function() { | |
this.defaultPrevented = true; | |
@@ -229,11 +228,11 @@ SyntheticEvent.augmentClass = function(Class, Interface) { | |
E.prototype = Super.prototype; | |
var prototype = new E(); | |
- assign(prototype, Class.prototype); | |
+ Object.assign(prototype, Class.prototype); | |
Class.prototype = prototype; | |
Class.prototype.constructor = Class; | |
- Class.Interface = assign({}, Super.Interface, Interface); | |
+ Class.Interface = Object.assign({}, Super.Interface, Interface); | |
Class.augmentClass = Super.augmentClass; | |
PooledClass.addPoolingTo(Class, PooledClass.fourArgumentPooler); | |
diff --git a/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticClipboardEvent-test.js b/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticClipboardEvent-test.js | |
new file mode 100644 | |
index 0000000..7776f54 | |
--- /dev/null | |
+++ b/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticClipboardEvent-test.js | |
@@ -0,0 +1,74 @@ | |
+/** | |
+ * Copyright 2016-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 SyntheticClipboardEvent; | |
+ | |
+describe('SyntheticClipboardEvent', function() { | |
+ var createEvent; | |
+ | |
+ beforeEach(function() { | |
+ SyntheticClipboardEvent = require('SyntheticClipboardEvent'); | |
+ createEvent = function(nativeEvent) { | |
+ var target = require('getEventTarget')(nativeEvent); | |
+ return SyntheticClipboardEvent.getPooled({}, '', nativeEvent, target); | |
+ }; | |
+ }); | |
+ | |
+ describe('ClipboardEvent interface', function() { | |
+ describe('clipboardData', function() { | |
+ describe('when event has clipboardData', function() { | |
+ it("returns event's clipboardData", function() { | |
+ // Mock clipboardData since native implementation doesn't have a constructor | |
+ var clipboardData = jasmine.createSpyObj( | |
+ 'clipboardData', | |
+ ['dropEffect', 'effectAllowed', 'files', 'items', 'types'] | |
+ ); | |
+ var clipboardEvent = createEvent({clipboardData: clipboardData}); | |
+ | |
+ expect(clipboardEvent.clipboardData).toBe(clipboardData); | |
+ }); | |
+ }); | |
+ }); | |
+ }); | |
+ | |
+ describe('EventInterface', function() { | |
+ it('normalizes properties from the Event interface', function() { | |
+ var target = document.createElement('div'); | |
+ var syntheticEvent = createEvent({srcElement: target}); | |
+ | |
+ expect(syntheticEvent.target).toBe(target); | |
+ expect(syntheticEvent.type).toBe(undefined); | |
+ }); | |
+ | |
+ it('is able to `preventDefault` and `stopPropagation`', function() { | |
+ var nativeEvent = {}; | |
+ var syntheticEvent = createEvent(nativeEvent); | |
+ | |
+ expect(syntheticEvent.isDefaultPrevented()).toBe(false); | |
+ syntheticEvent.preventDefault(); | |
+ expect(syntheticEvent.isDefaultPrevented()).toBe(true); | |
+ | |
+ expect(syntheticEvent.isPropagationStopped()).toBe(false); | |
+ syntheticEvent.stopPropagation(); | |
+ expect(syntheticEvent.isPropagationStopped()).toBe(true); | |
+ }); | |
+ | |
+ it('is able to `persist`', function() { | |
+ var syntheticEvent = createEvent({}); | |
+ | |
+ expect(syntheticEvent.isPersistent()).toBe(false); | |
+ syntheticEvent.persist(); | |
+ expect(syntheticEvent.isPersistent()).toBe(true); | |
+ }); | |
+ }); | |
+}); | |
diff --git a/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticEvent-test.js b/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticEvent-test.js | |
index d05ebdf..a8799c8 100644 | |
--- a/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticEvent-test.js | |
+++ b/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticEvent-test.js | |
@@ -144,7 +144,10 @@ describe('SyntheticEvent', function() { | |
); | |
}); | |
- it('should properly log warnings when events simulated with rendered components', function() { | |
+ // TODO: reenable this test. We are currently silencing these warnings when | |
+ // using TestUtils.Simulate to avoid spurious warnings that result from the | |
+ // way we simulate events. | |
+ xit('should properly log warnings when events simulated with rendered components', function() { | |
spyOn(console, 'error'); | |
var event; | |
var element = document.createElement('div'); | |
diff --git a/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticKeyboardEvent-test.js b/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticKeyboardEvent-test.js | |
new file mode 100644 | |
index 0000000..9c75a70 | |
--- /dev/null | |
+++ b/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticKeyboardEvent-test.js | |
@@ -0,0 +1,123 @@ | |
+/** | |
+ * Copyright 2016-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 SyntheticKeyboardEvent; | |
+var getEventCharCode; | |
+ | |
+describe('SyntheticKeyboardEvent', function() { | |
+ var createEvent; | |
+ | |
+ beforeEach(function() { | |
+ // Mock getEventCharCode for proper unit testing | |
+ jest.mock('getEventCharCode'); | |
+ getEventCharCode = require('getEventCharCode'); | |
+ | |
+ SyntheticKeyboardEvent = require('SyntheticKeyboardEvent'); | |
+ createEvent = function(nativeEvent) { | |
+ var target = require('getEventTarget')(nativeEvent); | |
+ return SyntheticKeyboardEvent.getPooled({}, '', nativeEvent, target); | |
+ }; | |
+ }); | |
+ | |
+ describe('KeyboardEvent interface', function() { | |
+ describe('charCode', function() { | |
+ describe('when event is `keypress`', function() { | |
+ it('returns whatever getEventCharCode returns', function() { | |
+ getEventCharCode.mockReturnValue(100500); | |
+ var keyboardEvent = createEvent({type: 'keypress', charCode: 50}); | |
+ | |
+ expect(keyboardEvent.charCode).toBe(100500); | |
+ }); | |
+ }); | |
+ | |
+ describe('when event is not `keypress`', function() { | |
+ it('returns 0', function() { | |
+ var keyboardEvent = createEvent({type: 'keyup', charCode: 50}); | |
+ expect(keyboardEvent.charCode).toBe(0); | |
+ }); | |
+ }); | |
+ }); | |
+ | |
+ describe('keyCode', function() { | |
+ describe('when event is `keydown` or `keyup`', function() { | |
+ it('returns a passed keyCode', function() { | |
+ var keyboardEvent = createEvent({type: 'keyup', keyCode: 40}); | |
+ expect(keyboardEvent.keyCode).toBe(40); | |
+ }); | |
+ }); | |
+ | |
+ describe('when event is `keypress`', function() { | |
+ it('returns 0', function() { | |
+ var keyboardEvent = createEvent({type: 'keypress', charCode: 40}); | |
+ expect(keyboardEvent.keyCode).toBe(0); | |
+ }); | |
+ }); | |
+ }); | |
+ | |
+ describe('which', function() { | |
+ describe('when event is `keypress`', function() { | |
+ it('returns whatever getEventCharCode returns', function() { | |
+ getEventCharCode.mockReturnValue(9001); | |
+ var keyboardEvent = createEvent({type: 'keypress', charCode: 50}); | |
+ | |
+ expect(keyboardEvent.which).toBe(9001); | |
+ }); | |
+ }); | |
+ | |
+ describe('when event is `keydown` or `keyup`', function() { | |
+ it('returns a passed keyCode', function() { | |
+ var keyboardEvent = createEvent({type: 'keyup', keyCode: 40}); | |
+ expect(keyboardEvent.which).toBe(40); | |
+ }); | |
+ }); | |
+ | |
+ describe('when event type is unknown', function() { | |
+ it('returns 0', function() { | |
+ var keyboardEvent = createEvent({type: 'keysmack', keyCode: 40}); | |
+ expect(keyboardEvent.which).toBe(0); | |
+ }); | |
+ }); | |
+ }); | |
+ }); | |
+ | |
+ describe('EventInterface', function() { | |
+ it('normalizes properties from the Event interface', function() { | |
+ var target = document.createElement('div'); | |
+ var syntheticEvent = createEvent({srcElement: target}); | |
+ | |
+ expect(syntheticEvent.target).toBe(target); | |
+ expect(syntheticEvent.type).toBe(undefined); | |
+ }); | |
+ | |
+ it('is able to `preventDefault` and `stopPropagation`', function() { | |
+ var nativeEvent = {}; | |
+ var syntheticEvent = createEvent(nativeEvent); | |
+ | |
+ expect(syntheticEvent.isDefaultPrevented()).toBe(false); | |
+ syntheticEvent.preventDefault(); | |
+ expect(syntheticEvent.isDefaultPrevented()).toBe(true); | |
+ | |
+ expect(syntheticEvent.isPropagationStopped()).toBe(false); | |
+ syntheticEvent.stopPropagation(); | |
+ expect(syntheticEvent.isPropagationStopped()).toBe(true); | |
+ }); | |
+ | |
+ it('is able to `persist`', function() { | |
+ var syntheticEvent = createEvent({}); | |
+ | |
+ expect(syntheticEvent.isPersistent()).toBe(false); | |
+ syntheticEvent.persist(); | |
+ expect(syntheticEvent.isPersistent()).toBe(true); | |
+ }); | |
+ }); | |
+}); | |
diff --git a/src/renderers/dom/client/utils/DOMChildrenOperations.js b/src/renderers/dom/client/utils/DOMChildrenOperations.js | |
index 40bf13e..f123aef 100644 | |
--- a/src/renderers/dom/client/utils/DOMChildrenOperations.js | |
+++ b/src/renderers/dom/client/utils/DOMChildrenOperations.js | |
@@ -129,8 +129,6 @@ var DOMChildrenOperations = { | |
dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup, | |
- updateTextContent: setTextContent, | |
- | |
replaceDelimitedText: replaceDelimitedText, | |
/** | |
@@ -180,7 +178,6 @@ var DOMChildrenOperations = { | |
}; | |
ReactPerf.measureMethods(DOMChildrenOperations, 'DOMChildrenOperations', { | |
- updateTextContent: 'updateTextContent', | |
replaceDelimitedText: 'replaceDelimitedText', | |
}); | |
diff --git a/src/renderers/dom/client/utils/__tests__/getEventCharCode-test.js b/src/renderers/dom/client/utils/__tests__/getEventCharCode-test.js | |
new file mode 100644 | |
index 0000000..c375ffa | |
--- /dev/null | |
+++ b/src/renderers/dom/client/utils/__tests__/getEventCharCode-test.js | |
@@ -0,0 +1,89 @@ | |
+/** | |
+ * Copyright 2016-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 getEventCharCode = require('getEventCharCode'); | |
+ | |
+describe('getEventCharCode', function() { | |
+ describe('when charCode is present in nativeEvent', function() { | |
+ describe('when charCode is 0 and keyCode is 13', function() { | |
+ it('returns 13', function() { | |
+ var nativeEvent = new KeyboardEvent( | |
+ 'keypress', {charCode: 0, keyCode: 13} | |
+ ); | |
+ | |
+ expect(getEventCharCode(nativeEvent)).toBe(13); | |
+ }); | |
+ }); | |
+ | |
+ describe('when charCode is not 0 and/or keyCode is not 13', function() { | |
+ describe('when charCode is 32 or bigger', function() { | |
+ it('returns charCode', function() { | |
+ var nativeEvent = new KeyboardEvent('keypress', {charCode: 32}); | |
+ | |
+ expect(getEventCharCode(nativeEvent)).toBe(32); | |
+ }); | |
+ }); | |
+ | |
+ describe('when charCode is smaller than 32', function() { | |
+ describe('when charCode is 13', function() { | |
+ it('returns 13', function() { | |
+ var nativeEvent = new KeyboardEvent('keypress', {charCode: 13}); | |
+ | |
+ expect(getEventCharCode(nativeEvent)).toBe(13); | |
+ }); | |
+ }); | |
+ | |
+ describe('when charCode is not 13', function() { | |
+ it('returns 0', function() { | |
+ var nativeEvent = new KeyboardEvent('keypress', {charCode: 31}); | |
+ | |
+ expect(getEventCharCode(nativeEvent)).toBe(0); | |
+ }); | |
+ }); | |
+ }); | |
+ }); | |
+ }); | |
+ | |
+ /** | |
+ nativeEvent is represented as a plain object here to ease testing, because | |
+ KeyboardEvent's 'charCode' event key cannot be deleted to simulate a missing | |
+ charCode key. | |
+ */ | |
+ describe('when charCode is not present in nativeEvent', function() { | |
+ describe('when keyCode is 32 or bigger', function() { | |
+ it('returns keyCode', function() { | |
+ var nativeEvent = {'keyCode': 32}; | |
+ | |
+ expect(getEventCharCode(nativeEvent)).toBe(32); | |
+ }); | |
+ }); | |
+ | |
+ describe('when keyCode is smaller than 32', function() { | |
+ describe('when keyCode is 13', function() { | |
+ it('returns 13', function() { | |
+ var nativeEvent = {'keyCode': 13}; | |
+ | |
+ expect(getEventCharCode(nativeEvent)).toBe(13); | |
+ }); | |
+ }); | |
+ | |
+ describe('when keyCode is not 13', function() { | |
+ it('returns 0', function() { | |
+ var nativeEvent = {'keyCode': 31}; | |
+ | |
+ expect(getEventCharCode(nativeEvent)).toBe(0); | |
+ }); | |
+ }); | |
+ }); | |
+ }); | |
+}); | |
diff --git a/src/renderers/dom/client/utils/__tests__/getEventKey-test.js b/src/renderers/dom/client/utils/__tests__/getEventKey-test.js | |
new file mode 100644 | |
index 0000000..09644c6 | |
--- /dev/null | |
+++ b/src/renderers/dom/client/utils/__tests__/getEventKey-test.js | |
@@ -0,0 +1,80 @@ | |
+/** | |
+ * Copyright 2016-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 getEventKey = require('getEventKey'); | |
+ | |
+describe('getEventKey', function() { | |
+ describe('when key is implemented in a browser', function() { | |
+ describe('when key is not normalized', function() { | |
+ it('returns a normalized value', function() { | |
+ var nativeEvent = new KeyboardEvent('keypress', {key: 'Del'}); | |
+ | |
+ expect(getEventKey(nativeEvent)).toBe('Delete'); | |
+ }); | |
+ }); | |
+ | |
+ describe('when key is normalized', function() { | |
+ it('returns a key', function() { | |
+ var nativeEvent = new KeyboardEvent('keypress', {key: 'f'}); | |
+ | |
+ expect(getEventKey(nativeEvent)).toBe('f'); | |
+ }); | |
+ }); | |
+ }); | |
+ | |
+ describe('when key is not implemented in a browser', function() { | |
+ describe('when event type is keypress', function() { | |
+ describe('when charCode is 13', function() { | |
+ it("returns 'Enter'", function() { | |
+ var nativeEvent = new KeyboardEvent('keypress', {charCode: 13}); | |
+ | |
+ expect(getEventKey(nativeEvent)).toBe('Enter'); | |
+ }); | |
+ }); | |
+ | |
+ describe('when charCode is not 13', function() { | |
+ it('returns a string from a charCode', function() { | |
+ var nativeEvent = new KeyboardEvent('keypress', {charCode: 65}); | |
+ | |
+ expect(getEventKey(nativeEvent)).toBe('A'); | |
+ }); | |
+ }); | |
+ }); | |
+ | |
+ describe('when event type is keydown or keyup', function() { | |
+ describe('when keyCode is recognized', function() { | |
+ it('returns a translated key', function() { | |
+ var nativeEvent = new KeyboardEvent('keydown', {keyCode: 45}); | |
+ | |
+ expect(getEventKey(nativeEvent)).toBe('Insert'); | |
+ }); | |
+ }); | |
+ | |
+ describe('when keyCode is not recognized', function() { | |
+ it('returns Unidentified', function() { | |
+ var nativeEvent = new KeyboardEvent('keydown', {keyCode: 1337}); | |
+ | |
+ expect(getEventKey(nativeEvent)).toBe('Unidentified'); | |
+ }); | |
+ }); | |
+ }); | |
+ | |
+ describe('when event type is unknown', function() { | |
+ it('returns an empty string', function() { | |
+ var nativeEvent = new KeyboardEvent('keysmack'); | |
+ | |
+ expect(getEventKey(nativeEvent)).toBe(''); | |
+ }); | |
+ }); | |
+ }); | |
+}); | |
diff --git a/src/renderers/dom/client/utils/setInnerHTML.js b/src/renderers/dom/client/utils/setInnerHTML.js | |
index 222ddfb..1e491bf 100644 | |
--- a/src/renderers/dom/client/utils/setInnerHTML.js | |
+++ b/src/renderers/dom/client/utils/setInnerHTML.js | |
@@ -79,6 +79,7 @@ if (ExecutionEnvironment.canUseDOM) { | |
} | |
}; | |
} | |
+ testElement = null; | |
} | |
module.exports = setInnerHTML; | |
diff --git a/src/renderers/dom/client/validateDOMNesting.js b/src/renderers/dom/client/validateDOMNesting.js | |
index d479ea9..431d80f 100644 | |
--- a/src/renderers/dom/client/validateDOMNesting.js | |
+++ b/src/renderers/dom/client/validateDOMNesting.js | |
@@ -11,7 +11,6 @@ | |
'use strict'; | |
-var assign = require('Object.assign'); | |
var emptyFunction = require('emptyFunction'); | |
var warning = require('warning'); | |
@@ -76,7 +75,7 @@ if (__DEV__) { | |
}; | |
var updatedAncestorInfo = function(oldInfo, tag, instance) { | |
- var ancestorInfo = assign({}, oldInfo || emptyAncestorInfo); | |
+ var ancestorInfo = Object.assign({}, oldInfo || emptyAncestorInfo); | |
var info = {tag: tag, instance: instance}; | |
if (inScopeTags.indexOf(tag) !== -1) { | |
diff --git a/src/renderers/dom/client/wrappers/ReactDOMInput.js b/src/renderers/dom/client/wrappers/ReactDOMInput.js | |
index e52c199..e9cd9b5 100644 | |
--- a/src/renderers/dom/client/wrappers/ReactDOMInput.js | |
+++ b/src/renderers/dom/client/wrappers/ReactDOMInput.js | |
@@ -16,7 +16,6 @@ var LinkedValueUtils = require('LinkedValueUtils'); | |
var ReactDOMComponentTree = require('ReactDOMComponentTree'); | |
var ReactUpdates = require('ReactUpdates'); | |
-var assign = require('Object.assign'); | |
var invariant = require('invariant'); | |
var warning = require('warning'); | |
@@ -69,7 +68,7 @@ var ReactDOMInput = { | |
var value = LinkedValueUtils.getValue(props); | |
var checked = LinkedValueUtils.getChecked(props); | |
- var nativeProps = assign({ | |
+ var nativeProps = Object.assign({ | |
// Make sure we set .type before any other properties (setting .value | |
// before .type means .value is lost in IE11 and below) | |
type: undefined, | |
diff --git a/src/renderers/dom/client/wrappers/ReactDOMOption.js b/src/renderers/dom/client/wrappers/ReactDOMOption.js | |
index 31e6050..917ed0e 100644 | |
--- a/src/renderers/dom/client/wrappers/ReactDOMOption.js | |
+++ b/src/renderers/dom/client/wrappers/ReactDOMOption.js | |
@@ -14,7 +14,6 @@ | |
var ReactChildren = require('ReactChildren'); | |
var ReactDOMSelect = require('ReactDOMSelect'); | |
-var assign = require('Object.assign'); | |
var warning = require('warning'); | |
/** | |
@@ -59,7 +58,7 @@ var ReactDOMOption = { | |
}, | |
getNativeProps: function(inst, props) { | |
- var nativeProps = assign({selected: undefined, children: undefined}, props); | |
+ var nativeProps = Object.assign({selected: undefined, children: undefined}, props); | |
// Read state only from initial mount because <select> updates value | |
// manually; we need the initial state only for server rendering | |
diff --git a/src/renderers/dom/client/wrappers/ReactDOMSelect.js b/src/renderers/dom/client/wrappers/ReactDOMSelect.js | |
index f0ac23f..2247fb6 100644 | |
--- a/src/renderers/dom/client/wrappers/ReactDOMSelect.js | |
+++ b/src/renderers/dom/client/wrappers/ReactDOMSelect.js | |
@@ -15,7 +15,6 @@ var LinkedValueUtils = require('LinkedValueUtils'); | |
var ReactDOMComponentTree = require('ReactDOMComponentTree'); | |
var ReactUpdates = require('ReactUpdates'); | |
-var assign = require('Object.assign'); | |
var warning = require('warning'); | |
var didWarnValueLink = false; | |
@@ -159,7 +158,7 @@ function updateOptions(inst, multiple, propValue) { | |
*/ | |
var ReactDOMSelect = { | |
getNativeProps: function(inst, props) { | |
- return assign({}, props, { | |
+ return Object.assign({}, props, { | |
onChange: inst._wrapperState.onChange, | |
value: undefined, | |
}); | |
diff --git a/src/renderers/dom/client/wrappers/ReactDOMTextarea.js b/src/renderers/dom/client/wrappers/ReactDOMTextarea.js | |
index ed5ac82..bf5508b 100644 | |
--- a/src/renderers/dom/client/wrappers/ReactDOMTextarea.js | |
+++ b/src/renderers/dom/client/wrappers/ReactDOMTextarea.js | |
@@ -16,7 +16,6 @@ var LinkedValueUtils = require('LinkedValueUtils'); | |
var ReactDOMComponentTree = require('ReactDOMComponentTree'); | |
var ReactUpdates = require('ReactUpdates'); | |
-var assign = require('Object.assign'); | |
var invariant = require('invariant'); | |
var warning = require('warning'); | |
@@ -68,7 +67,7 @@ var ReactDOMTextarea = { | |
// Always set children to the same thing. In IE9, the selection range will | |
// get reset if `textContent` is mutated. | |
- var nativeProps = assign({}, props, { | |
+ var nativeProps = Object.assign({}, props, { | |
defaultValue: undefined, | |
value: undefined, | |
children: inst._wrapperState.initialValue, | |
diff --git a/src/renderers/dom/server/ReactServerRenderingTransaction.js b/src/renderers/dom/server/ReactServerRenderingTransaction.js | |
index 6e585ef..176a550 100644 | |
--- a/src/renderers/dom/server/ReactServerRenderingTransaction.js | |
+++ b/src/renderers/dom/server/ReactServerRenderingTransaction.js | |
@@ -14,7 +14,6 @@ | |
var PooledClass = require('PooledClass'); | |
var Transaction = require('Transaction'); | |
-var assign = require('Object.assign'); | |
/** | |
* Executed within the scope of the `Transaction` instance. Consider these as | |
@@ -64,7 +63,7 @@ var Mixin = { | |
}; | |
-assign( | |
+Object.assign( | |
ReactServerRenderingTransaction.prototype, | |
Transaction.Mixin, | |
Mixin | |
diff --git a/src/renderers/dom/shared/CSSPropertyOperations.js b/src/renderers/dom/shared/CSSPropertyOperations.js | |
index 5044488..aac1b75 100644 | |
--- a/src/renderers/dom/shared/CSSPropertyOperations.js | |
+++ b/src/renderers/dom/shared/CSSPropertyOperations.js | |
@@ -52,7 +52,7 @@ if (__DEV__) { | |
var warnedStyleValues = {}; | |
var warnedForNaNValue = false; | |
- var warnHyphenatedStyleName = function(name) { | |
+ var warnHyphenatedStyleName = function(name, owner) { | |
if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { | |
return; | |
} | |
@@ -60,13 +60,14 @@ if (__DEV__) { | |
warnedStyleNames[name] = true; | |
warning( | |
false, | |
- 'Unsupported style property %s. Did you mean %s?', | |
+ 'Unsupported style property %s. Did you mean %s?%s', | |
name, | |
- camelizeStyleName(name) | |
+ camelizeStyleName(name), | |
+ checkRenderMessage(owner) | |
); | |
}; | |
- var warnBadVendoredStyleName = function(name) { | |
+ var warnBadVendoredStyleName = function(name, owner) { | |
if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { | |
return; | |
} | |
@@ -74,13 +75,14 @@ if (__DEV__) { | |
warnedStyleNames[name] = true; | |
warning( | |
false, | |
- 'Unsupported vendor-prefixed style property %s. Did you mean %s?', | |
+ 'Unsupported vendor-prefixed style property %s. Did you mean %s?%s', | |
name, | |
- name.charAt(0).toUpperCase() + name.slice(1) | |
+ name.charAt(0).toUpperCase() + name.slice(1), | |
+ checkRenderMessage(owner) | |
); | |
}; | |
- var warnStyleValueWithSemicolon = function(name, value) { | |
+ var warnStyleValueWithSemicolon = function(name, value, owner) { | |
if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) { | |
return; | |
} | |
@@ -88,14 +90,15 @@ if (__DEV__) { | |
warnedStyleValues[value] = true; | |
warning( | |
false, | |
- 'Style property values shouldn\'t contain a semicolon. ' + | |
+ 'Style property values shouldn\'t contain a semicolon.%s ' + | |
'Try "%s: %s" instead.', | |
+ checkRenderMessage(owner), | |
name, | |
value.replace(badStyleValueWithSemicolonPattern, '') | |
); | |
}; | |
- var warnStyleValueIsNaN = function(name, value) { | |
+ var warnStyleValueIsNaN = function(name, value, owner) { | |
if (warnedForNaNValue) { | |
return; | |
} | |
@@ -103,26 +106,42 @@ if (__DEV__) { | |
warnedForNaNValue = true; | |
warning( | |
false, | |
- '`NaN` is an invalid value for the `%s` css style property', | |
- name | |
+ '`NaN` is an invalid value for the `%s` css style property.%s', | |
+ name, | |
+ checkRenderMessage(owner) | |
); | |
}; | |
+ var checkRenderMessage = function(owner) { | |
+ if (owner) { | |
+ var name = owner.getName(); | |
+ if (name) { | |
+ return ' Check the render method of `' + name + '`.'; | |
+ } | |
+ } | |
+ return ''; | |
+ }; | |
+ | |
/** | |
* @param {string} name | |
* @param {*} value | |
+ * @param {ReactDOMComponent} component | |
*/ | |
- var warnValidStyle = function(name, value) { | |
+ var warnValidStyle = function(name, value, component) { | |
+ var owner; | |
+ if (component) { | |
+ owner = component._currentElement._owner; | |
+ } | |
if (name.indexOf('-') > -1) { | |
- warnHyphenatedStyleName(name); | |
+ warnHyphenatedStyleName(name, owner); | |
} else if (badVendoredStyleNamePattern.test(name)) { | |
- warnBadVendoredStyleName(name); | |
+ warnBadVendoredStyleName(name, owner); | |
} else if (badStyleValueWithSemicolonPattern.test(value)) { | |
- warnStyleValueWithSemicolon(name, value); | |
+ warnStyleValueWithSemicolon(name, value, owner); | |
} | |
if (typeof value === 'number' && isNaN(value)) { | |
- warnStyleValueIsNaN(name, value); | |
+ warnStyleValueIsNaN(name, value, owner); | |
} | |
}; | |
} | |
@@ -153,7 +172,7 @@ var CSSPropertyOperations = { | |
} | |
var styleValue = styles[styleName]; | |
if (__DEV__) { | |
- warnValidStyle(styleName, styleValue); | |
+ warnValidStyle(styleName, styleValue, component); | |
} | |
if (styleValue != null) { | |
serialized += processStyleName(styleName) + ':'; | |
@@ -170,6 +189,7 @@ var CSSPropertyOperations = { | |
* | |
* @param {DOMElement} node | |
* @param {object} styles | |
+ * @param {ReactDOMComponent} component | |
*/ | |
setValueForStyles: function(node, styles, component) { | |
var style = node.style; | |
@@ -178,7 +198,7 @@ var CSSPropertyOperations = { | |
continue; | |
} | |
if (__DEV__) { | |
- warnValidStyle(styleName, styles[styleName]); | |
+ warnValidStyle(styleName, styles[styleName], component); | |
} | |
var styleValue = dangerousStyleValue( | |
styleName, | |
diff --git a/src/renderers/dom/shared/DOMPropertyOperations.js b/src/renderers/dom/shared/DOMPropertyOperations.js | |
index 1ce9e29..6108e4d 100644 | |
--- a/src/renderers/dom/shared/DOMPropertyOperations.js | |
+++ b/src/renderers/dom/shared/DOMPropertyOperations.js | |
@@ -149,8 +149,10 @@ var DOMPropertyOperations = { | |
var propName = propertyInfo.propertyName; | |
// Must explicitly cast values for HAS_SIDE_EFFECTS-properties to the | |
// property type before comparing; only `value` does and is string. | |
+ // Must set `value` property if it is not null and not yet set. | |
if (!propertyInfo.hasSideEffects || | |
- ('' + node[propName]) !== ('' + value)) { | |
+ ('' + node[propName]) !== ('' + value) || | |
+ !node.hasAttribute(propertyInfo.attributeName)) { | |
// Contrary to `setAttribute`, object properties are properly | |
// `toString`ed by IE8/9. | |
node[propName] = value; | |
diff --git a/src/renderers/dom/shared/ReactDOMComponent.js b/src/renderers/dom/shared/ReactDOMComponent.js | |
index 21a4310..808706d 100644 | |
--- a/src/renderers/dom/shared/ReactDOMComponent.js | |
+++ b/src/renderers/dom/shared/ReactDOMComponent.js | |
@@ -35,7 +35,6 @@ var ReactDOMTextarea = require('ReactDOMTextarea'); | |
var ReactMultiChild = require('ReactMultiChild'); | |
var ReactPerf = require('ReactPerf'); | |
-var assign = require('Object.assign'); | |
var escapeTextContentForBrowser = require('escapeTextContentForBrowser'); | |
var invariant = require('invariant'); | |
var isEventSupported = require('isEventSupported'); | |
@@ -53,9 +52,14 @@ var registrationNameModules = EventPluginRegistry.registrationNameModules; | |
// For quickly matching children type, to test if can be treated as content. | |
var CONTENT_TYPES = {'string': true, 'number': true}; | |
-var CHILDREN = keyOf({children: null}); | |
var STYLE = keyOf({style: null}); | |
var HTML = keyOf({__html: null}); | |
+var RESERVED_PROPS = { | |
+ children: null, | |
+ dangerouslySetInnerHTML: null, | |
+ suppressContentEditableWarning: null, | |
+}; | |
+ | |
function getDeclarationErrorAddendum(internalInstance) { | |
if (internalInstance) { | |
@@ -182,6 +186,13 @@ function assertValidProps(component, props) { | |
'those nodes are unexpectedly modified or duplicated. This is ' + | |
'probably not intentional.' | |
); | |
+ warning( | |
+ props.onFocusIn == null && | |
+ props.onFocusOut == null, | |
+ 'React uses onFocus and onBlur instead of onFocusIn and onFocusOut. ' + | |
+ 'All React events are normalized to bubble, so onFocusIn and onFocusOut ' + | |
+ 'are not needed/supported by React.' | |
+ ); | |
} | |
invariant( | |
props.style == null || typeof props.style === 'object', | |
@@ -369,7 +380,7 @@ var newlineEatingTags = { | |
// For HTML, certain tags cannot have children. This has the same purpose as | |
// `omittedCloseTags` except that `menuitem` should still have its closing tag. | |
-var voidElementTags = assign({ | |
+var voidElementTags = Object.assign({ | |
'menuitem': true, | |
}, omittedCloseTags); | |
@@ -629,13 +640,13 @@ ReactDOMComponent.Mixin = { | |
// See `_updateDOMProperties`. style block | |
this._previousStyle = propValue; | |
} | |
- propValue = this._previousStyleCopy = assign({}, props.style); | |
+ propValue = this._previousStyleCopy = Object.assign({}, props.style); | |
} | |
propValue = CSSPropertyOperations.createMarkupForStyles(propValue, this); | |
} | |
var markup = null; | |
if (this._tag != null && isCustomComponent(this._tag, props)) { | |
- if (propKey !== CHILDREN) { | |
+ if (!RESERVED_PROPS.hasOwnProperty(propKey)) { | |
markup = DOMPropertyOperations.createMarkupForCustomAttribute(propKey, propValue); | |
} | |
} else { | |
@@ -875,7 +886,7 @@ ReactDOMComponent.Mixin = { | |
); | |
this._previousStyle = nextProp; | |
} | |
- nextProp = this._previousStyleCopy = assign({}, nextProp); | |
+ nextProp = this._previousStyleCopy = Object.assign({}, nextProp); | |
} else { | |
this._previousStyleCopy = null; | |
} | |
@@ -907,14 +918,13 @@ ReactDOMComponent.Mixin = { | |
deleteListener(this, propKey); | |
} | |
} else if (isCustomComponent(this._tag, nextProps)) { | |
- if (propKey === CHILDREN) { | |
- nextProp = null; | |
+ if (!RESERVED_PROPS.hasOwnProperty(propKey)) { | |
+ DOMPropertyOperations.setValueForAttribute( | |
+ getNode(this), | |
+ propKey, | |
+ nextProp | |
+ ); | |
} | |
- DOMPropertyOperations.setValueForAttribute( | |
- getNode(this), | |
- propKey, | |
- nextProp | |
- ); | |
} else if ( | |
DOMProperty.properties[propKey] || | |
DOMProperty.isCustomAttribute(propKey)) { | |
@@ -1053,7 +1063,7 @@ ReactPerf.measureMethods(ReactDOMComponent.Mixin, 'ReactDOMComponent', { | |
receiveComponent: 'receiveComponent', | |
}); | |
-assign( | |
+Object.assign( | |
ReactDOMComponent.prototype, | |
ReactDOMComponent.Mixin, | |
ReactMultiChild.Mixin | |
diff --git a/src/renderers/dom/shared/ReactDOMEmptyComponent.js b/src/renderers/dom/shared/ReactDOMEmptyComponent.js | |
index c15ec12..81f8940 100644 | |
--- a/src/renderers/dom/shared/ReactDOMEmptyComponent.js | |
+++ b/src/renderers/dom/shared/ReactDOMEmptyComponent.js | |
@@ -14,7 +14,6 @@ | |
var DOMLazyTree = require('DOMLazyTree'); | |
var ReactDOMComponentTree = require('ReactDOMComponentTree'); | |
-var assign = require('Object.assign'); | |
var ReactDOMEmptyComponent = function(instantiate) { | |
// ReactCompositeComponent uses this: | |
@@ -25,7 +24,7 @@ var ReactDOMEmptyComponent = function(instantiate) { | |
this._nativeContainerInfo = null; | |
this._domID = null; | |
}; | |
-assign(ReactDOMEmptyComponent.prototype, { | |
+Object.assign(ReactDOMEmptyComponent.prototype, { | |
mountComponent: function( | |
transaction, | |
nativeParent, | |
diff --git a/src/renderers/dom/shared/ReactDOMTextComponent.js b/src/renderers/dom/shared/ReactDOMTextComponent.js | |
index cba2353..9a69c7f 100644 | |
--- a/src/renderers/dom/shared/ReactDOMTextComponent.js | |
+++ b/src/renderers/dom/shared/ReactDOMTextComponent.js | |
@@ -16,7 +16,6 @@ var DOMLazyTree = require('DOMLazyTree'); | |
var ReactDOMComponentTree = require('ReactDOMComponentTree'); | |
var ReactPerf = require('ReactPerf'); | |
-var assign = require('Object.assign'); | |
var escapeTextContentForBrowser = require('escapeTextContentForBrowser'); | |
var invariant = require('invariant'); | |
var validateDOMNesting = require('validateDOMNesting'); | |
@@ -51,7 +50,7 @@ var ReactDOMTextComponent = function(text) { | |
this._commentNodes = null; | |
}; | |
-assign(ReactDOMTextComponent.prototype, { | |
+Object.assign(ReactDOMTextComponent.prototype, { | |
/** | |
* Creates the markup for this text node. This node is not intended to have | |
diff --git a/src/renderers/dom/shared/__tests__/CSSPropertyOperations-test.js b/src/renderers/dom/shared/__tests__/CSSPropertyOperations-test.js | |
index 075c29c..d33d2e6 100644 | |
--- a/src/renderers/dom/shared/__tests__/CSSPropertyOperations-test.js | |
+++ b/src/renderers/dom/shared/__tests__/CSSPropertyOperations-test.js | |
@@ -108,75 +108,116 @@ describe('CSSPropertyOperations', function() { | |
}); | |
it('should warn when using hyphenated style names', function() { | |
+ var Comp = React.createClass({ | |
+ displayName: 'Comp', | |
+ render: function() { | |
+ return <div style={{ 'background-color': 'crimson' }}/>; | |
+ }, | |
+ }); | |
spyOn(console, 'error'); | |
- | |
- expect(CSSPropertyOperations.createMarkupForStyles({ | |
- 'background-color': 'crimson', | |
- })).toBe('background-color:crimson;'); | |
- | |
+ var root = document.createElement('div'); | |
+ ReactDOM.render(<Comp />, root); | |
expect(console.error.argsForCall.length).toBe(1); | |
- expect(console.error.argsForCall[0][0]).toContain('backgroundColor'); | |
+ expect(console.error.argsForCall[0][0]).toEqual( | |
+ 'Warning: Unsupported style property background-color. Did you mean backgroundColor? ' + | |
+ 'Check the render method of `Comp`.' | |
+ ); | |
}); | |
it('should warn when updating hyphenated style names', function() { | |
+ var Comp = React.createClass({ | |
+ displayName: 'Comp', | |
+ render: function() { | |
+ return <div style={this.props.style} />; | |
+ }, | |
+ }); | |
spyOn(console, 'error'); | |
- | |
- var root = document.createElement('div'); | |
var styles = { | |
'-ms-transform': 'translate3d(0, 0, 0)', | |
'-webkit-transform': 'translate3d(0, 0, 0)', | |
}; | |
- | |
- ReactDOM.render(<div />, root); | |
- ReactDOM.render(<div style={styles} />, root); | |
+ var root = document.createElement('div'); | |
+ ReactDOM.render(<Comp />, root); | |
+ ReactDOM.render(<Comp style={styles} />, root); | |
expect(console.error.argsForCall.length).toBe(2); | |
- expect(console.error.argsForCall[0][0]).toContain('msTransform'); | |
- expect(console.error.argsForCall[1][0]).toContain('WebkitTransform'); | |
+ expect(console.error.argsForCall[0][0]).toEqual( | |
+ 'Warning: Unsupported style property -ms-transform. Did you mean msTransform? ' + | |
+ 'Check the render method of `Comp`.' | |
+ ); | |
+ expect(console.error.argsForCall[1][0]).toEqual( | |
+ 'Warning: Unsupported style property -webkit-transform. Did you mean WebkitTransform? ' + | |
+ 'Check the render method of `Comp`.' | |
+ ); | |
}); | |
it('warns when miscapitalizing vendored style names', function() { | |
- spyOn(console, 'error'); | |
- | |
- CSSPropertyOperations.createMarkupForStyles({ | |
- msTransform: 'translate3d(0, 0, 0)', | |
- oTransform: 'translate3d(0, 0, 0)', | |
- webkitTransform: 'translate3d(0, 0, 0)', | |
+ var Comp = React.createClass({ | |
+ displayName: 'Comp', | |
+ render: function() { | |
+ return (<div style={{ | |
+ msTransform: 'translate3d(0, 0, 0)', | |
+ oTransform: 'translate3d(0, 0, 0)', | |
+ webkitTransform: 'translate3d(0, 0, 0)', | |
+ }} />); | |
+ }, | |
}); | |
- | |
+ spyOn(console, 'error'); | |
+ var root = document.createElement('div'); | |
+ ReactDOM.render(<Comp />, root); | |
// msTransform is correct already and shouldn't warn | |
expect(console.error.argsForCall.length).toBe(2); | |
- expect(console.error.argsForCall[0][0]).toContain('oTransform'); | |
- expect(console.error.argsForCall[0][0]).toContain('OTransform'); | |
- expect(console.error.argsForCall[1][0]).toContain('webkitTransform'); | |
- expect(console.error.argsForCall[1][0]).toContain('WebkitTransform'); | |
+ expect(console.error.argsForCall[0][0]).toEqual( | |
+ 'Warning: Unsupported vendor-prefixed style property oTransform. ' + | |
+ 'Did you mean OTransform? Check the render method of `Comp`.' | |
+ ); | |
+ expect(console.error.argsForCall[1][0]).toEqual( | |
+ 'Warning: Unsupported vendor-prefixed style property webkitTransform. ' + | |
+ 'Did you mean WebkitTransform? Check the render method of `Comp`.' | |
+ ); | |
}); | |
it('should warn about style having a trailing semicolon', function() { | |
- spyOn(console, 'error'); | |
- | |
- CSSPropertyOperations.createMarkupForStyles({ | |
- fontFamily: 'Helvetica, arial', | |
- backgroundImage: 'url(foo;bar)', | |
- backgroundColor: 'blue;', | |
- color: 'red; ', | |
+ var Comp = React.createClass({ | |
+ displayName: 'Comp', | |
+ render: function() { | |
+ return (<div style={{ | |
+ fontFamily: 'Helvetica, arial', | |
+ backgroundImage: 'url(foo;bar)', | |
+ backgroundColor: 'blue;', | |
+ color: 'red; ', | |
+ }} />); | |
+ }, | |
}); | |
- | |
+ spyOn(console, 'error'); | |
+ var root = document.createElement('div'); | |
+ ReactDOM.render(<Comp />, root); | |
expect(console.error.calls.length).toBe(2); | |
- expect(console.error.argsForCall[0][0]).toContain('Try "backgroundColor: blue" instead'); | |
- expect(console.error.argsForCall[1][0]).toContain('Try "color: red" instead'); | |
+ expect(console.error.argsForCall[0][0]).toEqual( | |
+ 'Warning: Style property values shouldn\'t contain a semicolon. ' + | |
+ 'Check the render method of `Comp`. Try "backgroundColor: blue" instead.', | |
+ ); | |
+ expect(console.error.argsForCall[1][0]).toEqual( | |
+ 'Warning: Style property values shouldn\'t contain a semicolon. ' + | |
+ 'Check the render method of `Comp`. Try "color: red" instead.', | |
+ ); | |
}); | |
it('should warn about style containing a NaN value', function() { | |
- spyOn(console, 'error'); | |
- | |
- CSSPropertyOperations.createMarkupForStyles({ | |
- fontSize: NaN, | |
+ var Comp = React.createClass({ | |
+ displayName: 'Comp', | |
+ render: function() { | |
+ return <div style={{ fontSize: NaN }}/>; | |
+ }, | |
}); | |
+ spyOn(console, 'error'); | |
+ var root = document.createElement('div'); | |
+ ReactDOM.render(<Comp />, root); | |
expect(console.error.calls.length).toBe(1); | |
expect(console.error.argsForCall[0][0]).toEqual( | |
- 'Warning: `NaN` is an invalid value for the `fontSize` css style property' | |
+ 'Warning: `NaN` is an invalid value for the `fontSize` css style property. ' + | |
+ 'Check the render method of `Comp`.' | |
); | |
}); | |
}); | |
diff --git a/src/renderers/dom/shared/__tests__/DOMPropertyOperations-test.js b/src/renderers/dom/shared/__tests__/DOMPropertyOperations-test.js | |
index d6d7306..14b7228 100644 | |
--- a/src/renderers/dom/shared/__tests__/DOMPropertyOperations-test.js | |
+++ b/src/renderers/dom/shared/__tests__/DOMPropertyOperations-test.js | |
@@ -221,6 +221,14 @@ describe('DOMPropertyOperations', function() { | |
expect(stubNode.getAttribute('role')).toBe('<html>'); | |
}); | |
+ it('should not remove empty attributes for special properties', function() { | |
+ stubNode = document.createElement('input'); | |
+ DOMPropertyOperations.setValueForProperty(stubNode, 'value', ''); | |
+ // JSDOM does not behave correctly for attributes/properties | |
+ //expect(stubNode.getAttribute('value')).toBe(''); | |
+ expect(stubNode.value).toBe(''); | |
+ }); | |
+ | |
it('should remove for falsey boolean properties', function() { | |
DOMPropertyOperations.setValueForProperty( | |
stubNode, | |
diff --git a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js | |
index d349620..66eaa96 100644 | |
--- a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js | |
+++ b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js | |
@@ -11,7 +11,6 @@ | |
'use strict'; | |
-var assign = require('Object.assign'); | |
describe('ReactDOMComponent', function() { | |
var React; | |
@@ -198,7 +197,7 @@ describe('ReactDOMComponent', function() { | |
expect(console.error.argsForCall.length).toBe(1); | |
expect(console.error.argsForCall[0][0]).toEqual( | |
- 'Warning: `NaN` is an invalid value for the `fontSize` css style property', | |
+ 'Warning: `NaN` is an invalid value for the `fontSize` css style property.', | |
); | |
}); | |
@@ -236,16 +235,52 @@ describe('ReactDOMComponent', function() { | |
expect(stubStyle.display).toEqual(''); | |
}); | |
- it('should skip child object attribute on web components', function() { | |
+ it('should skip reserved props on web components', function() { | |
var container = document.createElement('div'); | |
- // Test initial render to null | |
- ReactDOM.render(<my-component children={['foo']} />, container); | |
+ ReactDOM.render( | |
+ <my-component | |
+ children={['foo']} | |
+ suppressContentEditableWarning={true} | |
+ />, | |
+ container | |
+ ); | |
expect(container.firstChild.hasAttribute('children')).toBe(false); | |
+ expect( | |
+ container.firstChild.hasAttribute('suppressContentEditableWarning') | |
+ ).toBe(false); | |
- // Test updates to null | |
- ReactDOM.render(<my-component children={['foo']} />, container); | |
+ ReactDOM.render( | |
+ <my-component | |
+ children={['bar']} | |
+ suppressContentEditableWarning={false} | |
+ />, | |
+ container | |
+ ); | |
expect(container.firstChild.hasAttribute('children')).toBe(false); | |
+ expect( | |
+ container.firstChild.hasAttribute('suppressContentEditableWarning') | |
+ ).toBe(false); | |
+ }); | |
+ | |
+ it('should skip dangerouslySetInnerHTML on web components', function() { | |
+ var container = document.createElement('div'); | |
+ | |
+ ReactDOM.render( | |
+ <my-component dangerouslySetInnerHTML={{__html: 'hi'}} />, | |
+ container | |
+ ); | |
+ expect( | |
+ container.firstChild.hasAttribute('dangerouslySetInnerHTML') | |
+ ).toBe(false); | |
+ | |
+ ReactDOM.render( | |
+ <my-component dangerouslySetInnerHTML={{__html: 'bye'}} />, | |
+ container | |
+ ); | |
+ expect( | |
+ container.firstChild.hasAttribute('dangerouslySetInnerHTML') | |
+ ).toBe(false); | |
}); | |
it('should remove attributes', function() { | |
@@ -478,10 +513,10 @@ describe('ReactDOMComponent', function() { | |
expect(nodeValueSetter.mock.calls.length).toBe(2); | |
ReactDOM.render(<div value="" />, container); | |
- expect(nodeValueSetter.mock.calls.length).toBe(2); | |
+ expect(nodeValueSetter.mock.calls.length).toBe(3); | |
ReactDOM.render(<div />, container); | |
- expect(nodeValueSetter.mock.calls.length).toBe(2); | |
+ expect(nodeValueSetter.mock.calls.length).toBe(3); | |
}); | |
it('should not incur unnecessary DOM mutations for boolean properties', function() { | |
@@ -587,7 +622,7 @@ describe('ReactDOMComponent', function() { | |
this._currentElement = {props: initialProps}; | |
this._rootNodeID = 'test'; | |
}; | |
- assign(NodeStub.prototype, ReactDOMComponent.Mixin); | |
+ Object.assign(NodeStub.prototype, ReactDOMComponent.Mixin); | |
genMarkup = function(props) { | |
var transaction = new ReactReconcileTransaction(); | |
@@ -636,7 +671,7 @@ describe('ReactDOMComponent', function() { | |
this._currentElement = {props: initialProps}; | |
this._rootNodeID = 'test'; | |
}; | |
- assign(NodeStub.prototype, ReactDOMComponent.Mixin); | |
+ Object.assign(NodeStub.prototype, ReactDOMComponent.Mixin); | |
genMarkup = function(props) { | |
var transaction = new ReactReconcileTransaction(); | |
@@ -1198,5 +1233,17 @@ describe('ReactDOMComponent', function() { | |
expect(console.error.argsForCall.length).toBe(1); | |
expect(console.error.argsForCall[0][0]).toContain('className'); | |
}); | |
+ | |
+ it('should warn about props that are no longer supported', function() { | |
+ spyOn(console, 'error'); | |
+ ReactTestUtils.renderIntoDocument(<div />); | |
+ expect(console.error.argsForCall.length).toBe(0); | |
+ | |
+ ReactTestUtils.renderIntoDocument(<div onFocusIn={() => {}} />); | |
+ expect(console.error.argsForCall.length).toBe(1); | |
+ | |
+ ReactTestUtils.renderIntoDocument(<div onFocusOut={() => {}} />); | |
+ expect(console.error.argsForCall.length).toBe(2); | |
+ }); | |
}); | |
}); | |
diff --git a/src/renderers/shared/event/EventPluginUtils.js b/src/renderers/shared/event/EventPluginUtils.js | |
index 5ca1e13..f7e8efe 100644 | |
--- a/src/renderers/shared/event/EventPluginUtils.js | |
+++ b/src/renderers/shared/event/EventPluginUtils.js | |
@@ -206,7 +206,7 @@ function executeDirectDispatch(event) { | |
); | |
event.currentTarget = EventPluginUtils.getNodeFromInstance(dispatchInstance); | |
var res = dispatchListener ? dispatchListener(event) : null; | |
- event.curentTarget = null; | |
+ event.currentTarget = null; | |
event._dispatchListeners = null; | |
event._dispatchInstances = null; | |
return res; | |
diff --git a/src/renderers/shared/event/__tests__/EventPluginRegistry-test.js b/src/renderers/shared/event/__tests__/EventPluginRegistry-test.js | |
index d781ba2..7f06e58 100644 | |
--- a/src/renderers/shared/event/__tests__/EventPluginRegistry-test.js | |
+++ b/src/renderers/shared/event/__tests__/EventPluginRegistry-test.js | |
@@ -11,7 +11,6 @@ | |
'use strict'; | |
-var assign = require('Object.assign'); | |
describe('EventPluginRegistry', function() { | |
var EventPluginRegistry; | |
@@ -22,7 +21,7 @@ describe('EventPluginRegistry', function() { | |
EventPluginRegistry._resetEventPlugins(); | |
createPlugin = function(properties) { | |
- return assign({extractEvents: function() {}}, properties); | |
+ return Object.assign({extractEvents: function() {}}, properties); | |
}; | |
}); | |
diff --git a/src/renderers/shared/reconciler/ReactCompositeComponent.js b/src/renderers/shared/reconciler/ReactCompositeComponent.js | |
index 9e63629..0472e1f 100644 | |
--- a/src/renderers/shared/reconciler/ReactCompositeComponent.js | |
+++ b/src/renderers/shared/reconciler/ReactCompositeComponent.js | |
@@ -24,7 +24,6 @@ var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames'); | |
var ReactReconciler = require('ReactReconciler'); | |
var ReactUpdateQueue = require('ReactUpdateQueue'); | |
-var assign = require('Object.assign'); | |
var emptyObject = require('emptyObject'); | |
var invariant = require('invariant'); | |
var shouldUpdateReactComponent = require('shouldUpdateReactComponent'); | |
@@ -526,7 +525,7 @@ var ReactCompositeComponentMixin = { | |
name | |
); | |
} | |
- return assign({}, currentContext, childContext); | |
+ return Object.assign({}, currentContext, childContext); | |
} | |
return currentContext; | |
}, | |
@@ -759,10 +758,10 @@ var ReactCompositeComponentMixin = { | |
return queue[0]; | |
} | |
- var nextState = assign({}, replace ? queue[0] : inst.state); | |
+ var nextState = Object.assign({}, replace ? queue[0] : inst.state); | |
for (var i = replace ? 1 : 0; i < queue.length; i++) { | |
var partial = queue[i]; | |
- assign( | |
+ Object.assign( | |
nextState, | |
typeof partial === 'function' ? | |
partial.call(inst, nextState, props, context) : | |
diff --git a/src/renderers/shared/reconciler/ReactDefaultBatchingStrategy.js b/src/renderers/shared/reconciler/ReactDefaultBatchingStrategy.js | |
index 2023f59..904dc1f 100644 | |
--- a/src/renderers/shared/reconciler/ReactDefaultBatchingStrategy.js | |
+++ b/src/renderers/shared/reconciler/ReactDefaultBatchingStrategy.js | |
@@ -14,7 +14,6 @@ | |
var ReactUpdates = require('ReactUpdates'); | |
var Transaction = require('Transaction'); | |
-var assign = require('Object.assign'); | |
var emptyFunction = require('emptyFunction'); | |
var RESET_BATCHED_UPDATES = { | |
@@ -35,7 +34,7 @@ function ReactDefaultBatchingStrategyTransaction() { | |
this.reinitializeTransaction(); | |
} | |
-assign( | |
+Object.assign( | |
ReactDefaultBatchingStrategyTransaction.prototype, | |
Transaction.Mixin, | |
{ | |
diff --git a/src/renderers/shared/reconciler/ReactNativeComponent.js b/src/renderers/shared/reconciler/ReactNativeComponent.js | |
index 42fe110..7f28034 100644 | |
--- a/src/renderers/shared/reconciler/ReactNativeComponent.js | |
+++ b/src/renderers/shared/reconciler/ReactNativeComponent.js | |
@@ -11,7 +11,6 @@ | |
'use strict'; | |
-var assign = require('Object.assign'); | |
var invariant = require('invariant'); | |
var autoGenerateWrapperClass = null; | |
@@ -34,7 +33,7 @@ var ReactNativeComponentInjection = { | |
// This accepts a keyed object with classes as values. Each key represents a | |
// tag. That particular tag will use this class instead of the generic one. | |
injectComponentClasses: function(componentClasses) { | |
- assign(tagToComponentClass, componentClasses); | |
+ Object.assign(tagToComponentClass, componentClasses); | |
}, | |
}; | |
diff --git a/src/renderers/shared/reconciler/ReactSimpleEmptyComponent.js b/src/renderers/shared/reconciler/ReactSimpleEmptyComponent.js | |
index e38fdcb..0565a01 100644 | |
--- a/src/renderers/shared/reconciler/ReactSimpleEmptyComponent.js | |
+++ b/src/renderers/shared/reconciler/ReactSimpleEmptyComponent.js | |
@@ -13,13 +13,12 @@ | |
var ReactReconciler = require('ReactReconciler'); | |
-var assign = require('Object.assign'); | |
var ReactSimpleEmptyComponent = function(placeholderElement, instantiate) { | |
this._currentElement = null; | |
this._renderedComponent = instantiate(placeholderElement); | |
}; | |
-assign(ReactSimpleEmptyComponent.prototype, { | |
+Object.assign(ReactSimpleEmptyComponent.prototype, { | |
mountComponent: function( | |
transaction, | |
nativeParent, | |
diff --git a/src/renderers/shared/reconciler/ReactUpdateQueue.js b/src/renderers/shared/reconciler/ReactUpdateQueue.js | |
index d2e7cad..65bdd49 100644 | |
--- a/src/renderers/shared/reconciler/ReactUpdateQueue.js | |
+++ b/src/renderers/shared/reconciler/ReactUpdateQueue.js | |
@@ -22,6 +22,19 @@ function enqueueUpdate(internalInstance) { | |
ReactUpdates.enqueueUpdate(internalInstance); | |
} | |
+function formatUnexpectedArgument(arg) { | |
+ var type = typeof arg; | |
+ if (type !== 'object') { | |
+ return type; | |
+ } | |
+ var displayName = arg.constructor && arg.constructor.name || type; | |
+ var keys = Object.keys(arg); | |
+ if (keys.length > 0 && keys.length < 20) { | |
+ return `${displayName} (keys: ${keys.join(', ')})`; | |
+ } | |
+ return displayName; | |
+} | |
+ | |
function getInternalInstanceReadyForUpdate(publicInstance, callerName) { | |
var internalInstance = ReactInstanceMap.get(publicInstance); | |
if (!internalInstance) { | |
@@ -103,17 +116,11 @@ var ReactUpdateQueue = { | |
* | |
* @param {ReactClass} publicInstance The instance to use as `this` context. | |
* @param {?function} callback Called after state is updated. | |
+ * @param {string} callerName Name of the calling function in the public API. | |
* @internal | |
*/ | |
- enqueueCallback: function(publicInstance, callback) { | |
- invariant( | |
- typeof callback === 'function', | |
- 'enqueueCallback(...): You called `setProps`, `replaceProps`, ' + | |
- '`setState`, `replaceState`, or `forceUpdate` with a callback of type ' + | |
- '%s. A function is expected', | |
- typeof callback === 'object' && Object.keys(callback).length && Object.keys(callback).length < 20 ? | |
- typeof callback + ' (keys: ' + Object.keys(callback) + ')' : typeof callback | |
- ); | |
+ enqueueCallback: function(publicInstance, callback, callerName) { | |
+ ReactUpdateQueue.validateCallback(callback, callerName); | |
var internalInstance = getInternalInstanceReadyForUpdate(publicInstance); | |
// Previously we would throw an error if we didn't have an internal | |
@@ -138,14 +145,6 @@ var ReactUpdateQueue = { | |
}, | |
enqueueCallbackInternal: function(internalInstance, callback) { | |
- invariant( | |
- typeof callback === 'function', | |
- 'enqueueCallback(...): You called `setProps`, `replaceProps`, ' + | |
- '`setState`, `replaceState`, or `forceUpdate` with a callback of type ' + | |
- '%s. A function is expected', | |
- typeof callback === 'object' && Object.keys(callback).length && Object.keys(callback).length < 20 ? | |
- typeof callback + ' (keys: ' + Object.keys(callback) + ')' : typeof callback | |
- ); | |
if (internalInstance._pendingCallbacks) { | |
internalInstance._pendingCallbacks.push(callback); | |
} else { | |
@@ -242,6 +241,16 @@ var ReactUpdateQueue = { | |
enqueueUpdate(internalInstance); | |
}, | |
+ validateCallback: function(callback, callerName) { | |
+ invariant( | |
+ !callback || typeof callback === 'function', | |
+ '%s(...): Expected the last optional `callback` argument to be a ' + | |
+ 'function. Instead received: %s.', | |
+ callerName, | |
+ formatUnexpectedArgument(callback) | |
+ ); | |
+ }, | |
+ | |
}; | |
module.exports = ReactUpdateQueue; | |
diff --git a/src/renderers/shared/reconciler/ReactUpdates.js b/src/renderers/shared/reconciler/ReactUpdates.js | |
index 3f67588..6fd1d2f 100644 | |
--- a/src/renderers/shared/reconciler/ReactUpdates.js | |
+++ b/src/renderers/shared/reconciler/ReactUpdates.js | |
@@ -18,7 +18,6 @@ var ReactPerf = require('ReactPerf'); | |
var ReactReconciler = require('ReactReconciler'); | |
var Transaction = require('Transaction'); | |
-var assign = require('Object.assign'); | |
var invariant = require('invariant'); | |
var dirtyComponents = []; | |
@@ -74,7 +73,7 @@ function ReactUpdatesFlushTransaction() { | |
); | |
} | |
-assign( | |
+Object.assign( | |
ReactUpdatesFlushTransaction.prototype, | |
Transaction.Mixin, | |
{ | |
diff --git a/src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js b/src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js | |
index 9d5b062..c33fb33 100644 | |
--- a/src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js | |
+++ b/src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js | |
@@ -68,8 +68,6 @@ describe('ReactCompositeComponent', function() { | |
<b></b>; | |
}, | |
}); | |
- | |
- spyOn(console, 'error'); | |
}); | |
it('should support module pattern components', function() { | |
@@ -123,7 +121,6 @@ describe('ReactCompositeComponent', function() { | |
container.innerHTML = markup; | |
ReactDOM.render(<Parent />, container); | |
- expect(console.error).not.toHaveBeenCalled(); | |
}); | |
it('should react to state changes from callbacks', function() { | |
@@ -173,6 +170,8 @@ describe('ReactCompositeComponent', function() { | |
}); | |
it('should auto bind methods and values correctly', function() { | |
+ spyOn(console, 'error'); | |
+ | |
var ComponentClass = React.createClass({ | |
getInitialState: function() { | |
return {valueToReturn: 'hi'}; | |
@@ -273,6 +272,8 @@ describe('ReactCompositeComponent', function() { | |
}); | |
it('should warn about `forceUpdate` on unmounted components', function() { | |
+ spyOn(console, 'error'); | |
+ | |
var container = document.createElement('div'); | |
document.body.appendChild(container); | |
@@ -303,6 +304,8 @@ describe('ReactCompositeComponent', function() { | |
}); | |
it('should warn about `setState` on unmounted components', function() { | |
+ spyOn(console, 'error'); | |
+ | |
var container = document.createElement('div'); | |
document.body.appendChild(container); | |
@@ -367,17 +370,16 @@ describe('ReactCompositeComponent', function() { | |
}); | |
var instance = ReactDOM.render(<Component />, container); | |
- | |
instance.setState({value: 1}); | |
- expect(console.error.calls.length).toBe(0); | |
ReactDOM.unmountComponentAtNode(container); | |
- expect(console.error.calls.length).toBe(0); | |
expect(cbCalled).toBe(false); | |
}); | |
it('should warn about `setState` in render', function() { | |
+ spyOn(console, 'error'); | |
+ | |
var container = document.createElement('div'); | |
var renderedState = -1; | |
@@ -425,6 +427,8 @@ describe('ReactCompositeComponent', function() { | |
}); | |
it('should warn about `setState` in getChildContext', function() { | |
+ spyOn(console, 'error'); | |
+ | |
var container = document.createElement('div'); | |
var renderPasses = 0; | |
@@ -499,6 +503,8 @@ describe('ReactCompositeComponent', function() { | |
}); | |
it('should warn when shouldComponentUpdate() returns undefined', function() { | |
+ spyOn(console, 'error'); | |
+ | |
var Component = React.createClass({ | |
getInitialState: function() { | |
return {bogus: false}; | |
@@ -524,6 +530,8 @@ describe('ReactCompositeComponent', function() { | |
}); | |
it('should warn when componentDidUnmount method is defined', function() { | |
+ spyOn(console, 'error'); | |
+ | |
var Component = React.createClass({ | |
componentDidUnmount: function() { | |
}, | |
@@ -659,8 +667,6 @@ describe('ReactCompositeComponent', function() { | |
parentInstance.setState({flag: true}); | |
expect(parentInstance.state.flag).toBe(true); | |
- expect(console.error.argsForCall.length).toBe(0); | |
- | |
reactComponentExpect(childInstance).scalarContextEqual({foo: 'bar', flag: true}); | |
}); | |
@@ -719,8 +725,6 @@ describe('ReactCompositeComponent', function() { | |
// We update <Parent /> while <Child /> is still a static prop relative to this update | |
wrapper.refs.parent.setState({flag: false}); | |
- expect(console.error.argsForCall.length).toBe(0); | |
- | |
expect(wrapper.refs.parent.state.flag).toEqual(false); | |
reactComponentExpect(wrapper.refs.child).scalarContextEqual({flag: false}); | |
@@ -840,8 +844,6 @@ describe('ReactCompositeComponent', function() { | |
}); | |
expect(parentInstance.state.flag).toBe(true); | |
- expect(console.error.argsForCall.length).toBe(0); | |
- | |
reactComponentExpect(childInstance).scalarContextEqual({foo: 'bar', depth: 0}); | |
}); | |
@@ -1036,6 +1038,8 @@ describe('ReactCompositeComponent', function() { | |
}); | |
it('should disallow nested render calls', function() { | |
+ spyOn(console, 'error'); | |
+ | |
var Inner = React.createClass({ | |
render: function() { | |
return <div />; | |
@@ -1176,8 +1180,6 @@ describe('ReactCompositeComponent', function() { | |
var div = document.createElement('div'); | |
ReactDOM.render(<Parent><Component /></Parent>, div); | |
- | |
- expect(console.error.argsForCall.length).toBe(0); | |
}); | |
it('should replace state', function() { | |
@@ -1270,15 +1272,11 @@ describe('ReactCompositeComponent', function() { | |
}); | |
ReactDOM.render(<Outer><Component /></Outer>, container); | |
- | |
- expect(console.error.calls.length).toBe(0); | |
- | |
ReactDOM.render(<Outer />, container); | |
- | |
- expect(console.error.calls.length).toBe(0); | |
}); | |
it('should warn when mutated props are passed', function() { | |
+ spyOn(console, 'error'); | |
var container = document.createElement('div'); | |
diff --git a/src/renderers/shared/reconciler/__tests__/ReactUpdates-test.js b/src/renderers/shared/reconciler/__tests__/ReactUpdates-test.js | |
index 22dddac..f59193d 100644 | |
--- a/src/renderers/shared/reconciler/__tests__/ReactUpdates-test.js | |
+++ b/src/renderers/shared/reconciler/__tests__/ReactUpdates-test.js | |
@@ -937,4 +937,91 @@ describe('ReactUpdates', function() { | |
ReactFeatureFlags.logTopLevelRenders = false; | |
} | |
}); | |
+ | |
+ it('throws in setState if the update callback is not a function', function() { | |
+ function Foo() { | |
+ this.a = 1; | |
+ this.b = 2; | |
+ } | |
+ var A = React.createClass({ | |
+ getInitialState: function() { | |
+ return {}; | |
+ }, | |
+ render: function() { | |
+ return <div />; | |
+ }, | |
+ }); | |
+ var component = ReactTestUtils.renderIntoDocument(<A />); | |
+ | |
+ expect(() => component.setState({}, 'no')).toThrow( | |
+ 'setState(...): Expected the last optional `callback` argument ' + | |
+ 'to be a function. Instead received: string.' | |
+ ); | |
+ expect(() => component.setState({}, {})).toThrow( | |
+ 'setState(...): Expected the last optional `callback` argument ' + | |
+ 'to be a function. Instead received: Object.' | |
+ ); | |
+ expect(() => component.setState({}, new Foo())).toThrow( | |
+ 'setState(...): Expected the last optional `callback` argument ' + | |
+ 'to be a function. Instead received: Foo (keys: a, b).' | |
+ ); | |
+ }); | |
+ | |
+ it('throws in replaceState if the update callback is not a function', function() { | |
+ function Foo() { | |
+ this.a = 1; | |
+ this.b = 2; | |
+ } | |
+ var A = React.createClass({ | |
+ getInitialState: function() { | |
+ return {}; | |
+ }, | |
+ render: function() { | |
+ return <div />; | |
+ }, | |
+ }); | |
+ var component = ReactTestUtils.renderIntoDocument(<A />); | |
+ | |
+ expect(() => component.replaceState({}, 'no')).toThrow( | |
+ 'replaceState(...): Expected the last optional `callback` argument ' + | |
+ 'to be a function. Instead received: string.' | |
+ ); | |
+ expect(() => component.replaceState({}, {})).toThrow( | |
+ 'replaceState(...): Expected the last optional `callback` argument ' + | |
+ 'to be a function. Instead received: Object.' | |
+ ); | |
+ expect(() => component.replaceState({}, new Foo())).toThrow( | |
+ 'replaceState(...): Expected the last optional `callback` argument ' + | |
+ 'to be a function. Instead received: Foo (keys: a, b).' | |
+ ); | |
+ }); | |
+ | |
+ it('throws in forceUpdate if the update callback is not a function', function() { | |
+ function Foo() { | |
+ this.a = 1; | |
+ this.b = 2; | |
+ } | |
+ var A = React.createClass({ | |
+ getInitialState: function() { | |
+ return {}; | |
+ }, | |
+ render: function() { | |
+ return <div />; | |
+ }, | |
+ }); | |
+ var component = ReactTestUtils.renderIntoDocument(<A />); | |
+ | |
+ expect(() => component.forceUpdate('no')).toThrow( | |
+ 'forceUpdate(...): Expected the last optional `callback` argument ' + | |
+ 'to be a function. Instead received: string.' | |
+ ); | |
+ expect(() => component.forceUpdate({})).toThrow( | |
+ 'forceUpdate(...): Expected the last optional `callback` argument ' + | |
+ 'to be a function. Instead received: Object.' | |
+ ); | |
+ expect(() => component.forceUpdate(new Foo())).toThrow( | |
+ 'forceUpdate(...): Expected the last optional `callback` argument ' + | |
+ 'to be a function. Instead received: Foo (keys: a, b).' | |
+ ); | |
+ }); | |
}); | |
diff --git a/src/renderers/shared/reconciler/instantiateReactComponent.js b/src/renderers/shared/reconciler/instantiateReactComponent.js | |
index cb0208f..796e037 100644 | |
--- a/src/renderers/shared/reconciler/instantiateReactComponent.js | |
+++ b/src/renderers/shared/reconciler/instantiateReactComponent.js | |
@@ -15,7 +15,6 @@ var ReactCompositeComponent = require('ReactCompositeComponent'); | |
var ReactEmptyComponent = require('ReactEmptyComponent'); | |
var ReactNativeComponent = require('ReactNativeComponent'); | |
-var assign = require('Object.assign'); | |
var invariant = require('invariant'); | |
var warning = require('warning'); | |
@@ -23,7 +22,7 @@ var warning = require('warning'); | |
var ReactCompositeComponentWrapper = function(element) { | |
this.construct(element); | |
}; | |
-assign( | |
+Object.assign( | |
ReactCompositeComponentWrapper.prototype, | |
ReactCompositeComponent.Mixin, | |
{ | |
diff --git a/src/shared/stubs/Object.assign.js b/src/shared/stubs/Object.assign.js | |
deleted file mode 100644 | |
index d72103c..0000000 | |
--- a/src/shared/stubs/Object.assign.js | |
+++ /dev/null | |
@@ -1,47 +0,0 @@ | |
-/** | |
- * Copyright 2014-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 Object.assign | |
- */ | |
- | |
-// https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign | |
- | |
-'use strict'; | |
- | |
-function assign(target, sources) { | |
- if (target == null) { | |
- throw new TypeError('Object.assign target cannot be null or undefined'); | |
- } | |
- | |
- var to = Object(target); | |
- var hasOwnProperty = Object.prototype.hasOwnProperty; | |
- | |
- for (var nextIndex = 1; nextIndex < arguments.length; nextIndex++) { | |
- var nextSource = arguments[nextIndex]; | |
- if (nextSource == null) { | |
- continue; | |
- } | |
- | |
- var from = Object(nextSource); | |
- | |
- // We don't currently support accessors nor proxies. Therefore this | |
- // copy cannot throw. If we ever supported this then we must handle | |
- // exceptions and side-effects. We don't support symbols so they won't | |
- // be transferred. | |
- | |
- for (var key in from) { | |
- if (hasOwnProperty.call(from, key)) { | |
- to[key] = from[key]; | |
- } | |
- } | |
- } | |
- | |
- return to; | |
-} | |
- | |
-module.exports = assign; | |
diff --git a/src/shared/utils/CallbackQueue.js b/src/shared/utils/CallbackQueue.js | |
index c594e30..647c388 100644 | |
--- a/src/shared/utils/CallbackQueue.js | |
+++ b/src/shared/utils/CallbackQueue.js | |
@@ -13,7 +13,6 @@ | |
var PooledClass = require('PooledClass'); | |
-var assign = require('Object.assign'); | |
var invariant = require('invariant'); | |
/** | |
@@ -32,7 +31,7 @@ function CallbackQueue() { | |
this._contexts = null; | |
} | |
-assign(CallbackQueue.prototype, { | |
+Object.assign(CallbackQueue.prototype, { | |
/** | |
* Enqueues a callback to be invoked when `notifyAll` is invoked. | |
diff --git a/src/shared/utils/__tests__/Transaction-test.js b/src/shared/utils/__tests__/Transaction-test.js | |
index 8385702..ee474a1 100644 | |
--- a/src/shared/utils/__tests__/Transaction-test.js | |
+++ b/src/shared/utils/__tests__/Transaction-test.js | |
@@ -11,7 +11,6 @@ | |
'use strict'; | |
-var assign = require('Object.assign'); | |
var Transaction; | |
@@ -46,7 +45,7 @@ describe('Transaction', function() { | |
this.secondCloseParam = INIT_ERRORED; // WILL be set to something else | |
this.lastCloseParam = INIT_ERRORED; // WON'T be set to something else | |
}; | |
- assign(TestTransaction.prototype, Transaction.Mixin); | |
+ Object.assign(TestTransaction.prototype, Transaction.Mixin); | |
TestTransaction.prototype.getTransactionWrappers = function() { | |
return [ | |
{ | |
@@ -97,7 +96,7 @@ describe('Transaction', function() { | |
this.secondCloseParam = INIT_ERRORED; // WILL be set to something else | |
this.lastCloseParam = INIT_ERRORED; // WILL be set to something else | |
}; | |
- assign(TestTransaction.prototype, Transaction.Mixin); | |
+ Object.assign(TestTransaction.prototype, Transaction.Mixin); | |
TestTransaction.prototype.getTransactionWrappers = function() { | |
return [ | |
{ | |
@@ -158,7 +157,7 @@ describe('Transaction', function() { | |
this.secondCloseParam = INIT_ERRORED; // WILL be set to something else | |
this.lastCloseParam = INIT_ERRORED; // WILL be set to something else | |
}; | |
- assign(TestTransaction.prototype, Transaction.Mixin); | |
+ Object.assign(TestTransaction.prototype, Transaction.Mixin); | |
// Now, none of the close/inits throw, but the operation we wrap will throw. | |
TestTransaction.prototype.getTransactionWrappers = function() { | |
return [ | |
@@ -222,7 +221,7 @@ describe('Transaction', function() { | |
var TestTransaction = function() { | |
this.reinitializeTransaction(); | |
}; | |
- assign(TestTransaction.prototype, Transaction.Mixin); | |
+ Object.assign(TestTransaction.prototype, Transaction.Mixin); | |
var exceptionMsg = 'This exception should throw.'; | |
TestTransaction.prototype.getTransactionWrappers = function() { | |
return [ | |
@@ -251,7 +250,7 @@ describe('Transaction', function() { | |
this.reinitializeTransaction(); | |
this.firstCloseParam = INIT_ERRORED; // WILL be set to something else | |
}; | |
- assign(TestTransaction.prototype, Transaction.Mixin); | |
+ Object.assign(TestTransaction.prototype, Transaction.Mixin); | |
TestTransaction.prototype.getTransactionWrappers = function() { | |
return [ | |
{ | |
@@ -279,7 +278,7 @@ describe('Transaction', function() { | |
var NestedTransaction = function() { | |
this.reinitializeTransaction(); | |
}; | |
- assign(NestedTransaction.prototype, Transaction.Mixin); | |
+ Object.assign(NestedTransaction.prototype, Transaction.Mixin); | |
NestedTransaction.prototype.getTransactionWrappers = function() { | |
return [ | |
{ | |
diff --git a/src/shared/utils/deprecated.js b/src/shared/utils/deprecated.js | |
index c34e0f4..fd8edec 100644 | |
--- a/src/shared/utils/deprecated.js | |
+++ b/src/shared/utils/deprecated.js | |
@@ -11,7 +11,6 @@ | |
'use strict'; | |
-var assign = require('Object.assign'); | |
var warning = require('warning'); | |
/** | |
@@ -48,7 +47,7 @@ function deprecated(fnName, newModule, newPackage, ctx, fn) { | |
}; | |
// We need to make sure all properties of the original fn are copied over. | |
// In particular, this is needed to support PropTypes | |
- return assign(newFn, fn); | |
+ return Object.assign(newFn, fn); | |
} | |
return fn; | |
diff --git a/src/test/ReactDefaultPerf.js b/src/test/ReactDefaultPerf.js | |
index 782f0e3..5cb43e9 100644 | |
--- a/src/test/ReactDefaultPerf.js | |
+++ b/src/test/ReactDefaultPerf.js | |
@@ -18,6 +18,7 @@ var ReactMount = require('ReactMount'); | |
var ReactPerf = require('ReactPerf'); | |
var performanceNow = require('performanceNow'); | |
+var warning = require('warning'); | |
function roundFloat(val) { | |
return Math.floor(val * 100) / 100; | |
@@ -51,6 +52,31 @@ function getID(inst) { | |
} | |
} | |
+function stripComplexValues(key, value) { | |
+ if (typeof value !== 'object' || Array.isArray(value) || value == null) { | |
+ return value; | |
+ } | |
+ var prototype = Object.getPrototypeOf(value); | |
+ if (!prototype || prototype === Object.prototype) { | |
+ return value; | |
+ } | |
+ return '<not serializable>'; | |
+} | |
+ | |
+// This implementation of ReactPerf is going away some time mid 15.x. | |
+// While we plan to keep most of the API, the actual format of measurements | |
+// will change dramatically. To signal this, we wrap them into an opaque-ish | |
+// object to discourage reaching into it until the API stabilizes. | |
+function wrapLegacyMeasurements(measurements) { | |
+ return { __unstable_this_format_will_change: measurements }; | |
+} | |
+function unwrapLegacyMeasurements(measurements) { | |
+ return measurements && measurements.__unstable_this_format_will_change || measurements; | |
+} | |
+ | |
+var warnedAboutPrintDOM = false; | |
+var warnedAboutGetMeasurementsSummaryMap = false; | |
+ | |
var ReactDefaultPerf = { | |
_allMeasurements: [], // last item in the list is the current one | |
_mountStack: [0], | |
@@ -71,11 +97,11 @@ var ReactDefaultPerf = { | |
}, | |
getLastMeasurements: function() { | |
- return ReactDefaultPerf._allMeasurements; | |
+ return wrapLegacyMeasurements(ReactDefaultPerf._allMeasurements); | |
}, | |
printExclusive: function(measurements) { | |
- measurements = measurements || ReactDefaultPerf._allMeasurements; | |
+ measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements); | |
var summary = ReactDefaultPerfAnalysis.getExclusiveSummary(measurements); | |
console.table(summary.map(function(item) { | |
return { | |
@@ -93,7 +119,7 @@ var ReactDefaultPerf = { | |
}, | |
printInclusive: function(measurements) { | |
- measurements = measurements || ReactDefaultPerf._allMeasurements; | |
+ measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements); | |
var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(measurements); | |
console.table(summary.map(function(item) { | |
return { | |
@@ -109,6 +135,17 @@ var ReactDefaultPerf = { | |
}, | |
getMeasurementsSummaryMap: function(measurements) { | |
+ warning( | |
+ warnedAboutGetMeasurementsSummaryMap, | |
+ '`ReactPerf.getMeasurementsSummaryMap(...)` is deprecated. Use ' + | |
+ '`ReactPerf.getWasted(...)` instead.' | |
+ ); | |
+ warnedAboutGetMeasurementsSummaryMap = true; | |
+ return ReactDefaultPerf.getWasted(measurements); | |
+ }, | |
+ | |
+ getWasted: function(measurements) { | |
+ measurements = unwrapLegacyMeasurements(measurements); | |
var summary = ReactDefaultPerfAnalysis.getInclusiveSummary( | |
measurements, | |
true | |
@@ -123,8 +160,8 @@ var ReactDefaultPerf = { | |
}, | |
printWasted: function(measurements) { | |
- measurements = measurements || ReactDefaultPerf._allMeasurements; | |
- console.table(ReactDefaultPerf.getMeasurementsSummaryMap(measurements)); | |
+ measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements); | |
+ console.table(ReactDefaultPerf.getWasted(measurements)); | |
console.log( | |
'Total time:', | |
ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms' | |
@@ -132,13 +169,23 @@ var ReactDefaultPerf = { | |
}, | |
printDOM: function(measurements) { | |
- measurements = measurements || ReactDefaultPerf._allMeasurements; | |
+ warning( | |
+ warnedAboutPrintDOM, | |
+ '`ReactPerf.printDOM(...)` is deprecated. Use ' + | |
+ '`ReactPerf.printOperations(...)` instead.' | |
+ ); | |
+ warnedAboutPrintDOM = true; | |
+ return ReactDefaultPerf.printOperations(measurements); | |
+ }, | |
+ | |
+ printOperations: function(measurements) { | |
+ measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements); | |
var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements); | |
console.table(summary.map(function(item) { | |
var result = {}; | |
result[DOMProperty.ID_ATTRIBUTE_NAME] = item.id; | |
result.type = item.type; | |
- result.args = JSON.stringify(item.args); | |
+ result.args = JSON.stringify(item.args, stripComplexValues); | |
return result; | |
})); | |
console.log( | |
diff --git a/src/test/ReactDefaultPerfAnalysis.js b/src/test/ReactDefaultPerfAnalysis.js | |
index 80452c4..bf7cb30 100644 | |
--- a/src/test/ReactDefaultPerfAnalysis.js | |
+++ b/src/test/ReactDefaultPerfAnalysis.js | |
@@ -11,7 +11,6 @@ | |
'use strict'; | |
-var assign = require('Object.assign'); | |
// Don't try to save users less than 1.2ms (a number I made up) | |
var DONT_CARE_THRESHOLD = 1.2; | |
@@ -28,7 +27,6 @@ var DOM_OPERATION_TYPES = { | |
'setValueForStyles': 'update styles', | |
'replaceNodeWithMarkup': 'replace', | |
'replaceDelimitedText': 'replace', | |
- 'updateTextContent': 'set textContent', | |
}; | |
function getTotalTime(measurements) { | |
@@ -66,7 +64,7 @@ function getExclusiveSummary(measurements) { | |
for (var i = 0; i < measurements.length; i++) { | |
var measurement = measurements[i]; | |
- var allIDs = assign( | |
+ var allIDs = Object.assign( | |
{}, | |
measurement.exclusive, | |
measurement.inclusive | |
@@ -118,7 +116,7 @@ function getInclusiveSummary(measurements, onlyClean) { | |
for (var i = 0; i < measurements.length; i++) { | |
var measurement = measurements[i]; | |
- var allIDs = assign( | |
+ var allIDs = Object.assign( | |
{}, | |
measurement.exclusive, | |
measurement.inclusive | |
@@ -186,7 +184,7 @@ function getUnchangedComponents(measurement) { | |
} | |
}); | |
}); | |
- var allIDs = assign({}, measurement.exclusive, measurement.inclusive); | |
+ var allIDs = Object.assign({}, measurement.exclusive, measurement.inclusive); | |
for (var id in allIDs) { | |
var isDirty = false; | |
diff --git a/src/test/ReactTestUtils.js b/src/test/ReactTestUtils.js | |
index 4f8e4eb..8cc0861 100644 | |
--- a/src/test/ReactTestUtils.js | |
+++ b/src/test/ReactTestUtils.js | |
@@ -25,7 +25,6 @@ var ReactInstanceMap = require('ReactInstanceMap'); | |
var ReactUpdates = require('ReactUpdates'); | |
var SyntheticEvent = require('SyntheticEvent'); | |
-var assign = require('Object.assign'); | |
var emptyObject = require('emptyObject'); | |
var findDOMNode = require('findDOMNode'); | |
var invariant = require('invariant'); | |
@@ -396,7 +395,7 @@ NoopInternalComponent.prototype = { | |
var ShallowComponentWrapper = function(element) { | |
this.construct(element); | |
}; | |
-assign( | |
+Object.assign( | |
ShallowComponentWrapper.prototype, | |
ReactCompositeComponent.Mixin, { | |
_instantiateReactComponent: function(element) { | |
@@ -499,7 +498,10 @@ function makeSimulator(eventType) { | |
fakeNativeEvent, | |
node | |
); | |
- assign(event, eventData); | |
+ // Since we aren't using pooling, always persist the event. This will make | |
+ // sure it's marked and won't warn when setting additional properties. | |
+ event.persist(); | |
+ Object.assign(event, eventData); | |
if (dispatchConfig.phasedRegistrationNames) { | |
EventPropagators.accumulateTwoPhaseDispatches(event); | |
@@ -560,7 +562,7 @@ buildSimulators(); | |
function makeNativeSimulator(eventType) { | |
return function(domComponentOrNode, nativeEventData) { | |
var fakeNativeEvent = new Event(eventType); | |
- assign(fakeNativeEvent, nativeEventData); | |
+ Object.assign(fakeNativeEvent, nativeEventData); | |
if (ReactTestUtils.isDOMComponent(domComponentOrNode)) { | |
ReactTestUtils.simulateNativeEventOnDOMComponent( | |
eventType, | |
diff --git a/src/test/__tests__/ReactDefaultPerf-test.js b/src/test/__tests__/ReactDefaultPerf-test.js | |
index 42c3251..cc16c88 100644 | |
--- a/src/test/__tests__/ReactDefaultPerf-test.js | |
+++ b/src/test/__tests__/ReactDefaultPerf-test.js | |
@@ -14,6 +14,7 @@ | |
describe('ReactDefaultPerf', function() { | |
var React; | |
var ReactDOM; | |
+ var ReactDOMFeatureFlags; | |
var ReactDefaultPerf; | |
var ReactTestUtils; | |
var ReactDefaultPerfAnalysis; | |
@@ -28,8 +29,14 @@ describe('ReactDefaultPerf', function() { | |
return now++; | |
}); | |
+ if (typeof console.table !== 'function') { | |
+ console.table = () => {}; | |
+ console.table.isFake = true; | |
+ } | |
+ | |
React = require('React'); | |
ReactDOM = require('ReactDOM'); | |
+ ReactDOMFeatureFlags = require('ReactDOMFeatureFlags'); | |
ReactDefaultPerf = require('ReactDefaultPerf'); | |
ReactTestUtils = require('ReactTestUtils'); | |
ReactDefaultPerfAnalysis = require('ReactDefaultPerfAnalysis'); | |
@@ -54,11 +61,17 @@ describe('ReactDefaultPerf', function() { | |
}); | |
}); | |
+ afterEach(function() { | |
+ if (console.table.isFake) { | |
+ delete console.table; | |
+ } | |
+ }); | |
+ | |
function measure(fn) { | |
ReactDefaultPerf.start(); | |
fn(); | |
ReactDefaultPerf.stop(); | |
- return ReactDefaultPerf.getLastMeasurements(); | |
+ return ReactDefaultPerf.getLastMeasurements().__unstable_this_format_will_change; | |
} | |
it('should count no-op update as waste', function() { | |
@@ -68,7 +81,7 @@ describe('ReactDefaultPerf', function() { | |
ReactDOM.render(<App />, container); | |
}); | |
- var summary = ReactDefaultPerf.getMeasurementsSummaryMap(measurements); | |
+ var summary = ReactDefaultPerf.getWasted(measurements); | |
expect(summary.length).toBe(2); | |
/*eslint-disable dot-notation */ | |
@@ -94,7 +107,7 @@ describe('ReactDefaultPerf', function() { | |
ReactDOM.render(<App flipSecond={true} />, container); | |
}); | |
- var summary = ReactDefaultPerf.getMeasurementsSummaryMap(measurements); | |
+ var summary = ReactDefaultPerf.getWasted(measurements); | |
expect(summary.length).toBe(1); | |
/*eslint-disable dot-notation */ | |
@@ -108,7 +121,7 @@ describe('ReactDefaultPerf', function() { | |
function expectNoWaste(fn) { | |
var measurements = measure(fn); | |
- var summary = ReactDefaultPerf.getMeasurementsSummaryMap(measurements); | |
+ var summary = ReactDefaultPerf.getWasted(measurements); | |
expect(summary).toEqual([]); | |
} | |
@@ -226,4 +239,49 @@ describe('ReactDefaultPerf', function() { | |
expect(summary).toEqual([]); | |
}); | |
+ it('should print a table after calling printOperations', function() { | |
+ var container = document.createElement('div'); | |
+ var measurements = measure(() => { | |
+ ReactDOM.render(<Div>hey</Div>, container); | |
+ }); | |
+ spyOn(console, 'table'); | |
+ ReactDefaultPerf.printOperations(measurements); | |
+ expect(console.table.calls.length).toBe(1); | |
+ expect(console.table.argsForCall[0][0]).toEqual([{ | |
+ 'data-reactid': '', | |
+ type: 'set innerHTML', | |
+ args: ReactDOMFeatureFlags.useCreateElement ? | |
+ '{"node":"<not serializable>","children":[],"html":null,"text":null}' : | |
+ '"<div data-reactroot=\\"\\" data-reactid=\\"1\\">hey</div>"', | |
+ }]); | |
+ }); | |
+ | |
+ it('warns once when using getMeasurementsSummaryMap', function() { | |
+ var measurements = measure(() => {}); | |
+ spyOn(console, 'error'); | |
+ ReactDefaultPerf.getMeasurementsSummaryMap(measurements); | |
+ expect(console.error.calls.length).toBe(1); | |
+ expect(console.error.argsForCall[0][0]).toContain( | |
+ '`ReactPerf.getMeasurementsSummaryMap(...)` is deprecated. Use ' + | |
+ '`ReactPerf.getWasted(...)` instead.' | |
+ ); | |
+ | |
+ ReactDefaultPerf.getMeasurementsSummaryMap(measurements); | |
+ expect(console.error.calls.length).toBe(1); | |
+ }); | |
+ | |
+ it('warns once when using printDOM', function() { | |
+ var measurements = measure(() => {}); | |
+ spyOn(console, 'error'); | |
+ ReactDefaultPerf.printDOM(measurements); | |
+ expect(console.error.calls.length).toBe(1); | |
+ expect(console.error.argsForCall[0][0]).toContain( | |
+ '`ReactPerf.printDOM(...)` is deprecated. Use ' + | |
+ '`ReactPerf.printOperations(...)` instead.' | |
+ ); | |
+ | |
+ ReactDefaultPerf.printDOM(measurements); | |
+ expect(console.error.calls.length).toBe(1); | |
+ }); | |
+ | |
}); | |
diff --git a/src/test/__tests__/ReactTestUtils-test.js b/src/test/__tests__/ReactTestUtils-test.js | |
index a7cf4ab..81fda9c 100644 | |
--- a/src/test/__tests__/ReactTestUtils-test.js | |
+++ b/src/test/__tests__/ReactTestUtils-test.js | |
@@ -474,6 +474,29 @@ describe('ReactTestUtils', function() { | |
expect(handler).not.toHaveBeenCalled(); | |
}); | |
+ it('should not warn when simulating events with extra properties', function() { | |
+ spyOn(console, 'error'); | |
+ | |
+ var CLIENT_X = 100; | |
+ | |
+ var Component = React.createClass({ | |
+ handleClick: function(e) { | |
+ expect(e.clientX).toBe(CLIENT_X); | |
+ }, | |
+ render: function() { | |
+ return <div onClick={this.handleClick} />; | |
+ }, | |
+ }); | |
+ | |
+ var element = document.createElement('div'); | |
+ var instance = ReactDOM.render(<Component />, element); | |
+ ReactTestUtils.Simulate.click( | |
+ ReactDOM.findDOMNode(instance), | |
+ {clientX: CLIENT_X} | |
+ ); | |
+ expect(console.error.calls.length).toBe(0); | |
+ }); | |
+ | |
it('can scry with stateless components involved', function() { | |
var Stateless = () => <div><hr /></div>; | |
var SomeComponent = React.createClass({ | |
diff --git a/src/test/reactComponentExpect.js b/src/test/reactComponentExpect.js | |
index ad0966c..0905387 100644 | |
--- a/src/test/reactComponentExpect.js | |
+++ b/src/test/reactComponentExpect.js | |
@@ -15,7 +15,6 @@ | |
var ReactInstanceMap = require('ReactInstanceMap'); | |
var ReactTestUtils = require('ReactTestUtils'); | |
-var assign = require('Object.assign'); | |
var invariant = require('invariant'); | |
function reactComponentExpect(instance) { | |
@@ -47,7 +46,7 @@ function reactComponentExpectInternal(internalInstance) { | |
this._instance = internalInstance; | |
} | |
-assign(reactComponentExpectInternal.prototype, { | |
+Object.assign(reactComponentExpectInternal.prototype, { | |
// Getters ------------------------------------------------------------------- | |
/** | |
diff --git a/src/umd/ReactUMDEntry.js b/src/umd/ReactUMDEntry.js | |
new file mode 100644 | |
index 0000000..dda6487 | |
--- /dev/null | |
+++ b/src/umd/ReactUMDEntry.js | |
@@ -0,0 +1,25 @@ | |
+/** | |
+ * 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 ReactUMDEntry | |
+ */ | |
+ | |
+'use strict'; | |
+ | |
+var ReactDOM = require('ReactDOM'); | |
+var ReactDOMServer = require('ReactDOMServer'); | |
+var React = require('React'); | |
+ | |
+ | |
+// `version` will be added here by ReactIsomorphic. | |
+var ReactUMDEntry = Object.assign({ | |
+ __SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactDOM, | |
+ __SECRET_DOM_SERVER_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactDOMServer, | |
+}, React); | |
+ | |
+module.exports = ReactUMDEntry; | |
diff --git a/src/umd/ReactWithAddonsUMDEntry.js b/src/umd/ReactWithAddonsUMDEntry.js | |
new file mode 100644 | |
index 0000000..cf59eb9 | |
--- /dev/null | |
+++ b/src/umd/ReactWithAddonsUMDEntry.js | |
@@ -0,0 +1,25 @@ | |
+/** | |
+ * 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 ReactWithAddonsUMDEntry | |
+ */ | |
+ | |
+'use strict'; | |
+ | |
+var ReactDOM = require('ReactDOM'); | |
+var ReactDOMServer = require('ReactDOMServer'); | |
+var ReactWithAddons = require('ReactWithAddons'); | |
+ | |
+ | |
+// `version` will be added here by ReactIsomorphic. | |
+var ReactWithAddonsUMDEntry = Object.assign({ | |
+ __SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactDOM, | |
+ __SECRET_DOM_SERVER_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactDOMServer, | |
+}, ReactWithAddons); | |
+ | |
+module.exports = ReactWithAddonsUMDEntry; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment