wallet-core/node_modules/react-dom/lib/ReactChildFiber.js
2017-05-03 15:35:00 +02:00

243 lines
8.8 KiB
JavaScript

/**
* 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.
*
*
*/
'use strict';
var REACT_ELEMENT_TYPE = require('./ReactElementSymbol');
var _require = require('./ReactCoroutine'),
REACT_COROUTINE_TYPE = _require.REACT_COROUTINE_TYPE,
REACT_YIELD_TYPE = _require.REACT_YIELD_TYPE;
var ReactFiber = require('./ReactFiber');
var ReactReifiedYield = require('./ReactReifiedYield');
var cloneFiber = ReactFiber.cloneFiber,
createFiberFromElement = ReactFiber.createFiberFromElement,
createFiberFromCoroutine = ReactFiber.createFiberFromCoroutine,
createFiberFromYield = ReactFiber.createFiberFromYield;
var createReifiedYield = ReactReifiedYield.createReifiedYield;
var isArray = Array.isArray;
function ChildReconciler(shouldClone) {
function createSubsequentChild(returnFiber, existingChild, previousSibling, newChildren, priority) {
if (typeof newChildren !== 'object' || newChildren === null) {
return previousSibling;
}
switch (newChildren.$$typeof) {
case REACT_ELEMENT_TYPE:
{
var element = newChildren;
if (existingChild && element.type === existingChild.type && element.key === existingChild.key) {
// TODO: This is not sufficient since previous siblings could be new.
// Will fix reconciliation properly later.
var clone = shouldClone ? cloneFiber(existingChild, priority) : existingChild;
if (!shouldClone) {
// TODO: This might be lowering the priority of nested unfinished work.
clone.pendingWorkPriority = priority;
}
clone.pendingProps = element.props;
clone.sibling = null;
clone['return'] = returnFiber;
previousSibling.sibling = clone;
return clone;
}
var child = createFiberFromElement(element, priority);
previousSibling.sibling = child;
child['return'] = returnFiber;
return child;
}
case REACT_COROUTINE_TYPE:
{
var coroutine = newChildren;
var _child = createFiberFromCoroutine(coroutine, priority);
previousSibling.sibling = _child;
_child['return'] = returnFiber;
return _child;
}
case REACT_YIELD_TYPE:
{
var yieldNode = newChildren;
var reifiedYield = createReifiedYield(yieldNode);
var _child2 = createFiberFromYield(yieldNode, priority);
_child2.output = reifiedYield;
previousSibling.sibling = _child2;
_child2['return'] = returnFiber;
return _child2;
}
}
if (isArray(newChildren)) {
var prev = previousSibling;
var existing = existingChild;
for (var i = 0; i < newChildren.length; i++) {
var nextExisting = existing && existing.sibling;
prev = createSubsequentChild(returnFiber, existing, prev, newChildren[i], priority);
if (prev && existing) {
// TODO: This is not correct because there could've been more
// than one sibling consumed but I don't want to return a tuple.
existing = nextExisting;
}
}
return prev;
} else {
// TODO: Throw for unknown children.
return previousSibling;
}
}
function createFirstChild(returnFiber, existingChild, newChildren, priority) {
if (typeof newChildren !== 'object' || newChildren === null) {
return null;
}
switch (newChildren.$$typeof) {
case REACT_ELEMENT_TYPE:
{
/* $FlowFixMe(>=0.31.0): This is an unsafe cast. Consider adding a type
* annotation to the `newChildren` param of this
* function.
*/
var element = newChildren;
if (existingChild && element.type === existingChild.type && element.key === existingChild.key) {
// Get the clone of the existing fiber.
var clone = shouldClone ? cloneFiber(existingChild, priority) : existingChild;
if (!shouldClone) {
// TODO: This might be lowering the priority of nested unfinished work.
clone.pendingWorkPriority = priority;
}
clone.pendingProps = element.props;
clone.sibling = null;
clone['return'] = returnFiber;
return clone;
}
var child = createFiberFromElement(element, priority);
child['return'] = returnFiber;
return child;
}
case REACT_COROUTINE_TYPE:
{
/* $FlowFixMe(>=0.31.0): No 'handler' property found in object type
*/
var coroutine = newChildren;
var _child3 = createFiberFromCoroutine(coroutine, priority);
_child3['return'] = returnFiber;
return _child3;
}
case REACT_YIELD_TYPE:
{
// A yield results in a fragment fiber whose output is the continuation.
// TODO: When there is only a single child, we can optimize this to avoid
// the fragment.
/* $FlowFixMe(>=0.31.0): No 'continuation' property found in object
* type
*/
var yieldNode = newChildren;
var reifiedYield = createReifiedYield(yieldNode);
var _child4 = createFiberFromYield(yieldNode, priority);
_child4.output = reifiedYield;
_child4['return'] = returnFiber;
return _child4;
}
}
if (isArray(newChildren)) {
var first = null;
var prev = null;
var existing = existingChild;
/* $FlowIssue(>=0.31.0) #12747709
*
* `Array.isArray` is matched syntactically for now until predicate
* support is complete.
*/
for (var i = 0; i < newChildren.length; i++) {
var nextExisting = existing && existing.sibling;
if (prev == null) {
prev = createFirstChild(returnFiber, existing, newChildren[i], priority);
first = prev;
} else {
prev = createSubsequentChild(returnFiber, existing, prev, newChildren[i], priority);
}
if (prev && existing) {
// TODO: This is not correct because there could've been more
// than one sibling consumed but I don't want to return a tuple.
existing = nextExisting;
}
}
return first;
} else {
// TODO: Throw for unknown children.
return null;
}
}
// TODO: This API won't work because we'll need to transfer the side-effects of
// unmounting children to the returnFiber.
function reconcileChildFibers(returnFiber, currentFirstChild, newChildren, priority) {
return createFirstChild(returnFiber, currentFirstChild, newChildren, priority);
}
return reconcileChildFibers;
}
exports.reconcileChildFibers = ChildReconciler(true);
exports.reconcileChildFibersInPlace = ChildReconciler(false);
function cloneSiblings(current, workInProgress, returnFiber) {
workInProgress['return'] = returnFiber;
while (current.sibling) {
current = current.sibling;
workInProgress = workInProgress.sibling = cloneFiber(current, current.pendingWorkPriority);
workInProgress['return'] = returnFiber;
}
workInProgress.sibling = null;
}
exports.cloneChildFibers = function (current, workInProgress) {
if (!workInProgress.child) {
return;
}
if (current && workInProgress.child === current.child) {
// We use workInProgress.child since that lets Flow know that it can't be
// null since we validated that already. However, as the line above suggests
// they're actually the same thing.
var currentChild = workInProgress.child;
// TODO: This used to reset the pending priority. Not sure if that is needed.
// workInProgress.pendingWorkPriority = current.pendingWorkPriority;
// TODO: The below priority used to be set to NoWork which would've
// dropped work. This is currently unobservable but will become
// observable when the first sibling has lower priority work remaining
// than the next sibling. At that point we should add tests that catches
// this.
var newChild = cloneFiber(currentChild, currentChild.pendingWorkPriority);
workInProgress.child = newChild;
cloneSiblings(currentChild, newChild, workInProgress);
}
// If there is no alternate, then we don't need to clone the children.
// If the children of the alternate fiber is a different set, then we don't
// need to clone. We need to reset the return fiber though since we'll
// traverse down into them.
var child = workInProgress.child;
while (child) {
child['return'] = workInProgress;
child = child.sibling;
}
};