Skip to content

Commit

Permalink
Merge branch 'master' into new-docs
Browse files Browse the repository at this point in the history
  • Loading branch information
hramos committed Oct 17, 2016
2 parents b762759 + c2d5833 commit ee0197f
Show file tree
Hide file tree
Showing 25 changed files with 7,116 additions and 274 deletions.
1 change: 1 addition & 0 deletions .flowconfig
Expand Up @@ -7,6 +7,7 @@
<PROJECT_ROOT>/.*/__tests__/.*

# Ignore Docs
<PROJECT_ROOT>/docs/.*
<PROJECT_ROOT>/.*/docs/.*

[include]
Expand Down
11 changes: 7 additions & 4 deletions docs/README.md
Expand Up @@ -8,14 +8,17 @@ If you are working on the site, you will want to install and run a local copy of

### Dependencies

In order to use Jekyll, you will need to have Ruby installed.
In order to use Jekyll, you will need to have Ruby installed. macOS comes pre-installed with Ruby, but you may need to update RubyGems (via `gem update --system`).
Otherwise, [RVM](https://rvm.io/) and [rbenv](https://github.com/sstephenson/rbenv) are popular ways to install Ruby.

- [Ruby](http://www.ruby-lang.org/) (version >= 1.8.7)
- [RubyGems](http://rubygems.org/) (version >= 1.3.7)
- [Bundler](http://gembundler.com/)

Mac OS X comes pre-installed with Ruby, but you may need to update RubyGems (via `gem update --system`).
Otherwise, [RVM](https://rvm.io/) and [rbenv](https://github.com/sstephenson/rbenv) are popular ways to install Ruby.
The version of the Pygment syntax highlighter used by Jekyll requires Python 2.7.x (not 3.x). macOS comes pre-installed with Python 2.7, but you may need to install it on other OSs.

- [Python](https://www.python.org) (version 2.7.x)

Once you have RubyGems and installed Bundler (via `gem install bundler`), use it to install the dependencies:

```sh
Expand All @@ -26,7 +29,7 @@ $ npm install

### Instructions

The site requires React, so first make sure you've built the project (via `grunt`).
The site requires React, so first make sure you've built the project (via [`grunt`](http://gruntjs.com/getting-started)).

Use Jekyll to serve the website locally (by default, at `http://localhost:4000`):

Expand Down
6 changes: 3 additions & 3 deletions docs/contributing/implementation-notes.md
Expand Up @@ -404,7 +404,7 @@ The host internal instances need to store:
* The DOM node.
* All the child internal instances. Each of them can be either a `DOMComponent` or a `CompositeComponent`.

If you're struggling to imagine what how an internal instance tree is structured in more complex applications, [React DevTools](https://github.com/facebook/react-devtools) can give you a close approximation, as it highlights host instances with grey, and composite instances with purple:
If you're struggling to imagine how an internal instance tree is structured in more complex applications, [React DevTools](https://github.com/facebook/react-devtools) can give you a close approximation, as it highlights host instances with grey, and composite instances with purple:

<img src="/react/img/docs/implementation-notes-tree.png" width="500" alt="React DevTools tree" />

Expand Down Expand Up @@ -623,10 +623,10 @@ Instead, we have to unmount the existing internal instance and mount the new one
// Unmount the old child and mount a new child
prevRenderedComponent.unmount();
var nextRenderedComponent = instantiateComponent(nextRenderedElement);
var nextNode = renderedComponent.mount();
var nextNode = nextRenderedComponent.mount();

// Replace the reference to the child
this.renderedComponent = renderedComponent;
this.renderedComponent = nextRenderedComponent;

// Replace the old node with the new one
// Note: this is renderer-specific code and
Expand Down
Binary file added docs/downloads/react-15.4.0-rc.3.zip
Binary file not shown.
5 changes: 5 additions & 0 deletions gulpfile.js
Expand Up @@ -16,6 +16,7 @@ var del = require('del');
var merge = require('merge-stream');

var babelPluginModules = require('fbjs-scripts/babel-6/rewrite-modules');
var stripProvidesModule = require('fbjs-scripts/gulp/strip-provides-module');
var extractErrors = require('./scripts/error-codes/gulp-extract-errors');
var devExpressionWithCodes = require('./scripts/error-codes/dev-expression-with-codes');

Expand Down Expand Up @@ -201,23 +202,27 @@ gulp.task('react:modules', function() {
gulp
.src(paths.react.src)
.pipe(babel(babelOptsReact))
.pipe(stripProvidesModule())
.pipe(flatten())
.pipe(gulp.dest(paths.react.lib)),

gulp
.src(paths.reactDOM.src)
.pipe(babel(babelOptsReactDOM))
.pipe(stripProvidesModule())
.pipe(flatten())
.pipe(gulp.dest(paths.reactDOM.lib)),

gulp
.src(paths.reactNative.src)
.pipe(babel(babelOptsReactNative))
.pipe(stripProvidesModule())
.pipe(flatten())
.pipe(gulp.dest(paths.reactNative.lib)),

gulp
.src(paths.reactTestRenderer.src)
.pipe(stripProvidesModule())
.pipe(babel(babelOptsReactTestRenderer))
.pipe(flatten())
.pipe(gulp.dest(paths.reactTestRenderer.lib))
Expand Down
4 changes: 2 additions & 2 deletions src/addons/shallowCompare.js
Expand Up @@ -6,8 +6,8 @@
* 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 shallowCompare
*/
* @providesModule shallowCompare
*/

'use strict';

Expand Down
11 changes: 7 additions & 4 deletions src/renderers/dom/client/ReactMount.js
Expand Up @@ -170,11 +170,15 @@ function batchedMountComponentIntoNode(
* @internal
* @see {ReactMount.unmountComponentAtNode}
*/
function unmountComponentFromNode(instance, container, safely) {
function unmountComponentFromNode(instance, container) {
if (__DEV__) {
ReactInstrumentation.debugTool.onBeginFlush();
}
ReactReconciler.unmountComponent(instance, safely);
ReactReconciler.unmountComponent(
instance,
false /* safely */,
false /* skipLifecycle */
);
if (__DEV__) {
ReactInstrumentation.debugTool.onEndFlush();
}
Expand Down Expand Up @@ -618,8 +622,7 @@ var ReactMount = {
ReactUpdates.batchedUpdates(
unmountComponentFromNode,
prevComponent,
container,
false
container
);
return true;
},
Expand Down
4 changes: 2 additions & 2 deletions src/renderers/dom/client/renderSubtreeIntoContainer.js
Expand Up @@ -6,8 +6,8 @@
* 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 renderSubtreeIntoContainer
*/
* @providesModule renderSubtreeIntoContainer
*/

'use strict';

Expand Down
12 changes: 11 additions & 1 deletion src/renderers/dom/client/wrappers/ReactDOMInput.js
Expand Up @@ -213,7 +213,17 @@ var ReactDOMInput = {
}
} else {
if (props.value == null && props.defaultValue != null) {
node.defaultValue = '' + props.defaultValue;
// In Chrome, assigning defaultValue to certain input types triggers input validation.
// For number inputs, the display value loses trailing decimal points. For email inputs,
// Chrome raises "The specified value <x> is not a valid email address".
//
// Here we check to see if the defaultValue has actually changed, avoiding these problems
// when the user is inputting text
//
// https://github.com/facebook/react/issues/7253
if (node.defaultValue !== '' + props.defaultValue) {
node.defaultValue = '' + props.defaultValue;
}
}
if (props.checked == null && props.defaultChecked != null) {
node.defaultChecked = !!props.defaultChecked;
Expand Down
22 changes: 22 additions & 0 deletions src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js
Expand Up @@ -51,6 +51,28 @@ describe('ReactDOMInput', () => {
expect(node.value).toBe('0');
});

it('only assigns defaultValue if it changes', () => {
class Test extends React.Component {
render() {
return (<input defaultValue="0" />);
}
}

var component = ReactTestUtils.renderIntoDocument(<Test />);
var node = ReactDOM.findDOMNode(component);

Object.defineProperty(node, 'defaultValue', {
get() {
return '0';
},
set(value) {
throw new Error(`defaultValue was assigned ${value}, but it did not change!`);
},
});

component.forceUpdate();
});

it('should display "true" for `defaultValue` of `true`', () => {
var stub = <input type="text" defaultValue={true} />;
stub = ReactTestUtils.renderIntoDocument(stub);
Expand Down
5 changes: 3 additions & 2 deletions src/renderers/dom/server/ReactServerRendering.js
Expand Up @@ -12,7 +12,6 @@

var React = require('React');
var ReactDOMContainerInfo = require('ReactDOMContainerInfo');
var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');
var ReactInstrumentation = require('ReactInstrumentation');
var ReactMarkupChecksum = require('ReactMarkupChecksum');
var ReactReconciler = require('ReactReconciler');
Expand All @@ -33,7 +32,9 @@ var pendingTransactions = 0;
*/
function renderToStringImpl(element, makeStaticMarkup) {
var transaction;
var previousBatchingStrategy;
try {
previousBatchingStrategy = ReactUpdates.injection.getBatchingStrategy();
ReactUpdates.injection.injectBatchingStrategy(ReactServerBatchingStrategy);

transaction = ReactServerRenderingTransaction.getPooled(makeStaticMarkup);
Expand Down Expand Up @@ -67,7 +68,7 @@ function renderToStringImpl(element, makeStaticMarkup) {
// currently share these stateful modules.
if (!pendingTransactions) {
ReactUpdates.injection.injectBatchingStrategy(
ReactDefaultBatchingStrategy
previousBatchingStrategy
);
}
}
Expand Down
42 changes: 30 additions & 12 deletions src/renderers/dom/shared/ReactDOMComponent.js
Expand Up @@ -40,6 +40,7 @@ var shallowEqual = require('shallowEqual');
var inputValueTracking = require('inputValueTracking');
var validateDOMNesting = require('validateDOMNesting');
var warning = require('warning');
var didWarnShadyDOM = false;

var Flags = ReactDOMComponentFlags;
var deleteListener = EventPluginHub.deleteListener;
Expand Down Expand Up @@ -607,6 +608,7 @@ ReactDOMComponent.Mixin = {
}

var mountImage;
var type = this._currentElement.type;
if (transaction.useCreateElement) {
var ownerDocument = hostContainerInfo._ownerDocument;
var el;
Expand All @@ -615,29 +617,40 @@ ReactDOMComponent.Mixin = {
// Create the script via .innerHTML so its "parser-inserted" flag is
// set to true and it does not execute
var div = ownerDocument.createElement('div');
var type = this._currentElement.type;
div.innerHTML = `<${type}></${type}>`;
el = div.removeChild(div.firstChild);
} else if (props.is) {
el = ownerDocument.createElement(this._currentElement.type, props.is);
el = ownerDocument.createElement(type, props.is);
} else {
// Separate else branch instead of using `props.is || undefined` above becuase of a Firefox bug.
// See discussion in https://github.com/facebook/react/pull/6896
// and discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=1276240
el = ownerDocument.createElement(this._currentElement.type);
el = ownerDocument.createElement(type);
}
} else {
el = ownerDocument.createElementNS(
namespaceURI,
this._currentElement.type
type
);
}
var isCustomComponentTag = isCustomComponent(this._tag, props);
if (__DEV__ && isCustomComponentTag && !didWarnShadyDOM && el.shadyRoot) {
var owner = this._currentElement._owner;
var name = owner && owner.getName() || 'A component';
warning(
false,
'%s is using shady DOM. Using shady DOM with React can ' +
'cause things to break subtly.',
name
);
didWarnShadyDOM = true;
}
ReactDOMComponentTree.precacheNode(this, el);
this._flags |= Flags.hasCachedChildNodes;
if (!this._hostParent) {
DOMPropertyOperations.setAttributeForRoot(el);
}
this._updateDOMProperties(null, props, transaction);
this._updateDOMProperties(null, props, transaction, isCustomComponentTag);
var lazyTree = DOMLazyTree(el);
this._createInitialChildren(transaction, props, context, lazyTree);
mountImage = lazyTree;
Expand All @@ -647,8 +660,7 @@ ReactDOMComponent.Mixin = {
if (!tagContent && omittedCloseTags[this._tag]) {
mountImage = tagOpen + '/>';
} else {
mountImage =
tagOpen + '>' + tagContent + '</' + this._currentElement.type + '>';
mountImage = tagOpen + '>' + tagContent + '</' + type + '>';
}
}

Expand Down Expand Up @@ -902,7 +914,8 @@ ReactDOMComponent.Mixin = {
}

assertValidProps(this, nextProps);
this._updateDOMProperties(lastProps, nextProps, transaction);
var isCustomComponentTag = isCustomComponent(this._tag, nextProps);
this._updateDOMProperties(lastProps, nextProps, transaction, isCustomComponentTag);
this._updateDOMChildren(
lastProps,
nextProps,
Expand Down Expand Up @@ -944,7 +957,12 @@ ReactDOMComponent.Mixin = {
* @param {object} nextProps
* @param {?DOMElement} node
*/
_updateDOMProperties: function(lastProps, nextProps, transaction) {
_updateDOMProperties: function(
lastProps,
nextProps,
transaction,
isCustomComponentTag
) {
var propKey;
var styleName;
var styleUpdates;
Expand Down Expand Up @@ -1034,7 +1052,7 @@ ReactDOMComponent.Mixin = {
} else if (lastProp) {
deleteListener(this, propKey);
}
} else if (isCustomComponent(this._tag, nextProps)) {
} else if (isCustomComponentTag) {
if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
DOMPropertyOperations.setValueForAttribute(
getNode(this),
Expand Down Expand Up @@ -1137,7 +1155,7 @@ ReactDOMComponent.Mixin = {
*
* @internal
*/
unmountComponent: function(safely) {
unmountComponent: function(safely, skipLifecycle) {
switch (this._tag) {
case 'audio':
case 'form':
Expand Down Expand Up @@ -1179,7 +1197,7 @@ ReactDOMComponent.Mixin = {
break;
}

this.unmountChildren(safely);
this.unmountChildren(safely, skipLifecycle);
ReactDOMComponentTree.uncacheNode(this);
EventPluginHub.deleteAllListeners(this);
this._rootNodeID = 0;
Expand Down

0 comments on commit ee0197f

Please sign in to comment.