diff --git a/CHANGELOG.md b/CHANGELOG.md index 3284aec191c..d4e0343e028 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## 0.12.2 (December 18, 2014) + +### React Core + +* Added support for more HTML attributes: `formAction`, `formEncType`, `formMethod`, `formTarget`, `marginHeight`, `marginWidth` +* Added `strokeOpacity` to the list of unitless CSS properties +* Removed trailing commas (allows npm module to be bundled and used in IE8) +* Fixed bug resulting in error when passing `undefined` to `React.createElement` - now there is a useful warning + +### React Tools + +* JSX-related transforms now always use double quotes for props and `displayName` + + ## 0.12.1 (November 18, 2014) ### React Tools diff --git a/README.md b/README.md index 9f4d89e35c6..328bf2d241a 100644 --- a/README.md +++ b/README.md @@ -35,12 +35,12 @@ The fastest way to get started is to serve JavaScript from the CDN (also availab ```html - + - + ``` -We've also built a [starter kit](http://facebook.github.io/react/downloads/react-0.12.1.zip) which might be useful if this is your first time using React. It includes a webpage with an example of using React with live code. +We've also built a [starter kit](http://facebook.github.io/react/downloads/react-0.12.2.zip) which might be useful if this is your first time using React. It includes a webpage with an example of using React with live code. If you'd like to use [bower](http://bower.io), it's as easy as: diff --git a/docs/_config.yml b/docs/_config.yml index 1a5f5b5ca1c..e15440e53dc 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -34,4 +34,4 @@ sass: sass_dir: _css gems: - jekyll-redirect-from -react_version: 0.12.1 +react_version: 0.12.2 diff --git a/docs/_js/jsx-compiler.js b/docs/_js/jsx-compiler.js index 28364eb88f9..a69bdd2176c 100644 --- a/docs/_js/jsx-compiler.js +++ b/docs/_js/jsx-compiler.js @@ -37,7 +37,7 @@ var CompilerPlayground = React.createClass({ ); - }, + } }); React.render( , diff --git a/docs/_posts/2014-12-18-react-v0.12.2.md b/docs/_posts/2014-12-18-react-v0.12.2.md new file mode 100644 index 00000000000..ab465d4afb6 --- /dev/null +++ b/docs/_posts/2014-12-18-react-v0.12.2.md @@ -0,0 +1,37 @@ +--- +title: React v0.12.2 +author: Paul O’Shannessy +--- + +We just shipped React v0.12.2, bringing the 0.12 branch up to date with a few small fixes that landed in master over the past 2 months. + +You may have noticed that we did not do an announcement for v0.12.1. That release was snuck out in anticipation of [Flow](http://flowtype.org/), with only transform-related changes. Namely we added a flag to the `jsx` executable which allowed you to safely transform Flow-based code to vanilla JS. If you didn't update for that release, you can safely skip it and move directly to v0.12.2. + +The release is available for download from the CDN: + +* **React** + Dev build with warnings: + Minified build for production: +* **React with Add-Ons** + Dev build with warnings: + Minified build for production: +* **In-Browser JSX transformer** + + +We've also published version `0.12.2` of the `react` and `react-tools` packages on npm and the `react` package on bower. `0.12.1` is also available in the same locations if need those. + +Please try these builds out and [file an issue on GitHub](https://github.com/facebook/react/issues/new) if you see anything awry. + +## Changelog + +### React Core + +* Added support for more HTML attributes: `formAction`, `formEncType`, `formMethod`, `formTarget`, `marginHeight`, `marginWidth` +* Added `strokeOpacity` to the list of unitless CSS properties +* Removed trailing commas (allows npm module to be bundled and used in IE8) +* Fixed bug resulting in error when passing `undefined` to `React.createElement` - now there is a useful warning + +### React Tools + +* JSX-related transforms now always use double quotes for props and `displayName` + diff --git a/docs/docs/ref-04-tags-and-attributes.md b/docs/docs/ref-04-tags-and-attributes.md index 25173e1cd91..5d629efd7a8 100644 --- a/docs/docs/ref-04-tags-and-attributes.md +++ b/docs/docs/ref-04-tags-and-attributes.md @@ -56,12 +56,13 @@ accept acceptCharset accessKey action allowFullScreen allowTransparency alt async autoComplete autoPlay cellPadding cellSpacing charSet checked classID className cols colSpan content contentEditable contextMenu controls coords crossOrigin data dateTime defer dir disabled download draggable encType form -formNoValidate frameBorder height hidden href hrefLang htmlFor httpEquiv icon -id label lang list loop manifest max maxLength media mediaGroup method min -multiple muted name noValidate open pattern placeholder poster preload -radioGroup readOnly rel required role rows rowSpan sandbox scope scrolling -seamless selected shape size sizes span spellCheck src srcDoc srcSet start step -style tabIndex target title type useMap value width wmode +formAction formEncType formMethod formNoValidate formTarget frameBorder height +hidden href hrefLang htmlFor httpEquiv icon id label lang list loop manifest +marginHeight marginWidth max maxLength media mediaGroup method min multiple +muted name noValidate open pattern placeholder poster preload radioGroup +readOnly rel required role rows rowSpan sandbox scope scrolling seamless +selected shape size sizes span spellCheck src srcDoc srcSet start step style +tabIndex target title type useMap value width wmode ``` In addition, the following non-standard attributes are supported: diff --git a/docs/downloads/react-0.12.2.zip b/docs/downloads/react-0.12.2.zip new file mode 100644 index 00000000000..669ae3f23bd Binary files /dev/null and b/docs/downloads/react-0.12.2.zip differ diff --git a/docs/tips/06-style-props-value-px.md b/docs/tips/06-style-props-value-px.md index cc61133ae38..aeb2cb3e3f9 100644 --- a/docs/tips/06-style-props-value-px.md +++ b/docs/tips/06-style-props-value-px.md @@ -29,6 +29,7 @@ Sometimes you _do_ want to keep the CSS properties unitless. Here's a list of pr - `opacity` - `order` - `orphans` +- `strokeOpacity` - `widows` - `zIndex` - `zoom` diff --git a/examples/basic-commonjs/package.json b/examples/basic-commonjs/package.json index d72927a4314..75f08e7289b 100644 --- a/examples/basic-commonjs/package.json +++ b/examples/basic-commonjs/package.json @@ -3,10 +3,10 @@ "description": "Basic example of using React with CommonJS", "main": "index.js", "devDependencies": { - "envify": "~1.2.1", - "react": "~0.10.0", - "reactify": "~0.13.1", - "browserify": "~3.44.2" + "browserify": "^6.3.3", + "envify": "^3.2.0", + "react": "^0.12.0", + "reactify": "^0.17.1" }, "scripts": { "build": "browserify --debug --transform reactify index.js > bundle.js" diff --git a/npm-react/package.json b/npm-react/package.json index 47433b2a204..5a49f16f4a3 100644 --- a/npm-react/package.json +++ b/npm-react/package.json @@ -1,7 +1,7 @@ { "name": "react", "description": "React is a JavaScript library for building user interfaces.", - "version": "0.12.1", + "version": "0.12.2", "keywords": [ "react" ], diff --git a/package.json b/package.json index 64b22097ea5..33b0e607dc5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "react-tools", "description": "A set of complementary tools to React, including the JSX transformer.", - "version": "0.12.1", + "version": "0.12.2", "keywords": [ "react", "jsx", diff --git a/src/browser/ui/React.js b/src/browser/ui/React.js index 8a9c6aa6c7e..9a142eb10aa 100644 --- a/src/browser/ui/React.js +++ b/src/browser/ui/React.js @@ -179,6 +179,6 @@ if (__DEV__) { // Version exists only in the open-source version of React, not in Facebook's // internal version. -React.version = '0.12.1'; +React.version = '0.12.2'; module.exports = React; diff --git a/src/browser/ui/dom/CSSProperty.js b/src/browser/ui/dom/CSSProperty.js index 3a8540d7b0b..b93c093ed18 100644 --- a/src/browser/ui/dom/CSSProperty.js +++ b/src/browser/ui/dom/CSSProperty.js @@ -16,7 +16,6 @@ */ var isUnitlessNumber = { columnCount: true, - fillOpacity: true, flex: true, flexGrow: true, flexShrink: true, @@ -28,7 +27,11 @@ var isUnitlessNumber = { orphans: true, widows: true, zIndex: true, - zoom: true + zoom: true, + + // SVG-related properties + fillOpacity: true, + strokeOpacity: true }; /** diff --git a/src/browser/ui/dom/HTMLDOMPropertyConfig.js b/src/browser/ui/dom/HTMLDOMPropertyConfig.js index 850f6e5bc26..9a8d218b12f 100644 --- a/src/browser/ui/dom/HTMLDOMPropertyConfig.js +++ b/src/browser/ui/dom/HTMLDOMPropertyConfig.js @@ -88,7 +88,11 @@ var HTMLDOMPropertyConfig = { draggable: null, encType: null, form: MUST_USE_ATTRIBUTE, + formAction: MUST_USE_ATTRIBUTE, + formEncType: MUST_USE_ATTRIBUTE, + formMethod: MUST_USE_ATTRIBUTE, formNoValidate: HAS_BOOLEAN_VALUE, + formTarget: MUST_USE_ATTRIBUTE, frameBorder: MUST_USE_ATTRIBUTE, height: MUST_USE_ATTRIBUTE, hidden: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, @@ -103,6 +107,8 @@ var HTMLDOMPropertyConfig = { list: MUST_USE_ATTRIBUTE, loop: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, manifest: MUST_USE_ATTRIBUTE, + marginHeight: null, + marginWidth: null, max: null, maxLength: MUST_USE_ATTRIBUTE, media: MUST_USE_ATTRIBUTE, diff --git a/src/core/ReactElement.js b/src/core/ReactElement.js index dd7c86ba31b..a45f51bcc1c 100644 --- a/src/core/ReactElement.js +++ b/src/core/ReactElement.js @@ -174,7 +174,7 @@ ReactElement.createElement = function(type, config, children) { } // Resolve default props - if (type.defaultProps) { + if (type && type.defaultProps) { var defaultProps = type.defaultProps; for (propName in defaultProps) { if (typeof props[propName] === 'undefined') { diff --git a/src/core/ReactElementValidator.js b/src/core/ReactElementValidator.js index a231f3c3c8c..99171b34a64 100644 --- a/src/core/ReactElementValidator.js +++ b/src/core/ReactElementValidator.js @@ -23,6 +23,7 @@ var ReactPropTypeLocations = require('ReactPropTypeLocations'); var ReactCurrentOwner = require('ReactCurrentOwner'); var monitorCodeUse = require('monitorCodeUse'); +var warning = require('warning'); /** * Warn if there's no key explicitly set on dynamic arrays of children or @@ -220,6 +221,15 @@ function checkPropTypes(componentName, propTypes, props, location) { var ReactElementValidator = { createElement: function(type, props, children) { + // We warn in this case but don't throw. We expect the element creation to + // succeed and there will likely be errors in render. + warning( + type != null, + 'React.createElement: type should not be null or undefined. It should ' + + 'be a string (for DOM elements) or a ReactClass (for composite ' + + 'components).' + ); + var element = ReactElement.createElement.apply(this, arguments); // The result can be nullish if a mock or a custom function is used. @@ -232,22 +242,24 @@ var ReactElementValidator = { validateChildKeys(arguments[i], type); } - var name = type.displayName; - if (type.propTypes) { - checkPropTypes( - name, - type.propTypes, - element.props, - ReactPropTypeLocations.prop - ); - } - if (type.contextTypes) { - checkPropTypes( - name, - type.contextTypes, - element._context, - ReactPropTypeLocations.context - ); + if (type) { + var name = type.displayName; + if (type.propTypes) { + checkPropTypes( + name, + type.propTypes, + element.props, + ReactPropTypeLocations.prop + ); + } + if (type.contextTypes) { + checkPropTypes( + name, + type.contextTypes, + element._context, + ReactPropTypeLocations.context + ); + } } return element; }, diff --git a/src/core/ReactNativeComponent.js b/src/core/ReactNativeComponent.js index ba485d61476..da329b93e95 100644 --- a/src/core/ReactNativeComponent.js +++ b/src/core/ReactNativeComponent.js @@ -63,7 +63,7 @@ function createInstanceForTag(tag, props, parentType) { var ReactNativeComponent = { createInstanceForTag: createInstanceForTag, - injection: ReactNativeComponentInjection, + injection: ReactNativeComponentInjection }; module.exports = ReactNativeComponent; diff --git a/src/core/__tests__/ReactCompositeComponent-test.js b/src/core/__tests__/ReactCompositeComponent-test.js index bfe8e423711..fc02f0f88a3 100644 --- a/src/core/__tests__/ReactCompositeComponent-test.js +++ b/src/core/__tests__/ReactCompositeComponent-test.js @@ -1483,4 +1483,25 @@ describe('ReactCompositeComponent', function() { ); }); + it('gives a helpful error when passing null or undefined', function() { + spyOn(console, 'warn'); + React.createElement(undefined); + React.createElement(null); + expect(console.warn.calls.length).toBe(2); + expect(console.warn.calls[0].args[0]).toBe( + 'Warning: React.createElement: type should not be null or undefined. ' + + 'It should be a string (for DOM elements) or a ReactClass (for ' + + 'composite components).' + ); + expect(console.warn.calls[1].args[0]).toBe( + 'Warning: React.createElement: type should not be null or undefined. ' + + 'It should be a string (for DOM elements) or a ReactClass (for ' + + 'composite components).' + ); + React.createElement('div'); + expect(console.warn.calls.length).toBe(2); + + expect(() => React.createElement(undefined)).not.toThrow() + }); + }); diff --git a/vendor/fbtransform/transforms/__tests__/react-displayName-test.js b/vendor/fbtransform/transforms/__tests__/react-displayName-test.js index f2ee384b8d6..d5b768ec462 100644 --- a/vendor/fbtransform/transforms/__tests__/react-displayName-test.js +++ b/vendor/fbtransform/transforms/__tests__/react-displayName-test.js @@ -24,7 +24,7 @@ describe('react displayName jsx', function() { var code = [ '"use strict";', 'var Whateva = React.createClass({', - ' displayName: \'Whateva\',', + ' displayName: "Whateva",', ' render: function() {', ' return null;', ' }', @@ -34,7 +34,7 @@ describe('react displayName jsx', function() { var result = [ '"use strict";', 'var Whateva = React.createClass({', - ' displayName: \'Whateva\',', + ' displayName: "Whateva",', ' render: function() {', ' return null;', ' }', @@ -54,7 +54,7 @@ describe('react displayName jsx', function() { ].join('\n'); var result = [ - 'var Component = React.createClass({displayName: \'Component\',', + 'var Component = React.createClass({displayName: "Component",', ' render: function() {', ' return null;', ' }', @@ -76,7 +76,7 @@ describe('react displayName jsx', function() { var result = [ 'var Component;', - 'Component = React.createClass({displayName: \'Component\',', + 'Component = React.createClass({displayName: "Component",', ' render: function() {', ' return null;', ' }', @@ -96,7 +96,7 @@ describe('react displayName jsx', function() { ].join('\n'); var result = [ - 'exports.Component = React.createClass({displayName: \'Component\',', + 'exports.Component = React.createClass({displayName: "Component",', ' render: function() {', ' return null;', ' }', @@ -119,7 +119,7 @@ describe('react displayName jsx', function() { var result = [ 'exports = {', - ' Component: React.createClass({displayName: \'Component\',', + ' Component: React.createClass({displayName: "Component",', ' render: function() {', ' return null;', ' }', diff --git a/vendor/fbtransform/transforms/reactDisplayName.js b/vendor/fbtransform/transforms/reactDisplayName.js index df8b728bbd7..4b2184e7d41 100644 --- a/vendor/fbtransform/transforms/reactDisplayName.js +++ b/vendor/fbtransform/transforms/reactDisplayName.js @@ -33,7 +33,7 @@ function addDisplayName(displayName, object, state) { if (safe) { utils.catchup(object['arguments'][0].range[0] + 1, state); - utils.append("displayName: '" + displayName + "',", state); + utils.append('displayName: "' + displayName + '",', state); } } } diff --git a/vendor/fbtransform/transforms/xjs.js b/vendor/fbtransform/transforms/xjs.js index 26f929e5346..0a3fa947797 100644 --- a/vendor/fbtransform/transforms/xjs.js +++ b/vendor/fbtransform/transforms/xjs.js @@ -231,7 +231,7 @@ function renderXJSExpressionContainer(traverse, object, isLast, path, state) { function quoteAttrName(attr) { // Quote invalid JS identifiers. if (!/^[a-z_$][a-z\d_$]*$/i.test(attr)) { - return "'" + attr + "'"; + return '"' + attr + '"'; } return attr; }